From 9de1d7c10d4732068d43219253fa8ceccd675754 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Thu, 21 Jul 2022 22:49:08 -0400 Subject: [PATCH 001/465] document memory orderings of `thread::{park, unpark}` --- library/std/src/thread/mod.rs | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index d28c7b58b20ba..32453b4d4a3cb 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -845,7 +845,7 @@ pub fn sleep(dur: Duration) { /// A call to `park` does not guarantee that the thread will remain parked /// forever, and callers should be prepared for this possibility. /// -/// # park and unpark +/// # `park` and `unpark` /// /// Every thread is equipped with some basic low-level blocking support, via the /// [`thread::park`][`park`] function and [`thread::Thread::unpark`][`unpark`] @@ -866,14 +866,6 @@ pub fn sleep(dur: Duration) { /// if it wasn't already. Because the token is initially absent, [`unpark`] /// followed by [`park`] will result in the second call returning immediately. /// -/// In other words, each [`Thread`] acts a bit like a spinlock that can be -/// locked and unlocked using `park` and `unpark`. -/// -/// Notice that being unblocked does not imply any synchronization with someone -/// that unparked this thread, it could also be spurious. -/// For example, it would be a valid, but inefficient, implementation to make both [`park`] and -/// [`unpark`] return immediately without doing anything. -/// /// The API is typically used by acquiring a handle to the current thread, /// placing that handle in a shared data structure so that other threads can /// find it, and then `park`ing in a loop. When some desired condition is met, another @@ -887,6 +879,23 @@ pub fn sleep(dur: Duration) { /// /// * It can be implemented very efficiently on many platforms. /// +/// # Memory Orderings +/// +/// Calls to `park` _synchronize-with_ calls to `unpark`, meaning that memory +/// operations performed before a call to `unpark` are made visible to the thread that +/// consumes the token and returns from `park`. Note that all `park` and `unpark` +/// operations for a given thread form a total order and `park` synchronizes-with +/// _all_ prior `unpark` operations. +/// +/// In atomic ordering terms, `unpark` performs a `Release` operation and `park` +/// performs the corresponding `Acquire` operation. Calls to `unpark` for the same +/// thread form a [release sequence]. +/// +/// Notice that being unblocked does not imply any synchronization with someone that +/// unparked this thread, it could also be spurious. For example, it would be a valid, +/// but inefficient, implementation to make both park and unpark return immediately +/// without doing anything. +/// /// # Examples /// /// ``` @@ -926,6 +935,7 @@ pub fn sleep(dur: Duration) { /// /// [`unpark`]: Thread::unpark /// [`thread::park_timeout`]: park_timeout +/// [release sequence]: https://en.cppreference.com/w/cpp/atomic/memory_order#Release_sequence #[stable(feature = "rust1", since = "1.0.0")] pub fn park() { // SAFETY: park_timeout is called on the parker owned by this thread. From 0646f0dda6332a1f7c185036f899b3350eb99a4a Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 16 Aug 2022 15:46:17 -0700 Subject: [PATCH 002/465] Move the cast_float_to_int fallback code to GCC Now that we require at least LLVM 13, that codegen backend is always using its intrinsic `fptosi.sat` and `fptoui.sat` conversions, so it doesn't need the manual implementation. However, the GCC backend still needs it, so we can move all of that code down there. --- src/builder.rs | 174 +++++++++++++++++++++++++++++++++++++++++++++++-- src/lib.rs | 1 + 2 files changed, 170 insertions(+), 5 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 4d40dd0994dd2..6994eeb00c3e2 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -15,8 +15,11 @@ use gccjit::{ Type, UnaryOp, }; +use rustc_apfloat::{ieee, Float, Round, Status}; use rustc_codegen_ssa::MemFlags; -use rustc_codegen_ssa::common::{AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope}; +use rustc_codegen_ssa::common::{ + AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind, +}; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{ @@ -31,6 +34,7 @@ use rustc_codegen_ssa::traits::{ StaticBuilderMethods, }; use rustc_data_structures::fx::FxHashSet; +use rustc_middle::bug; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_span::Span; @@ -1271,12 +1275,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { val } - fn fptoui_sat(&mut self, _val: RValue<'gcc>, _dest_ty: Type<'gcc>) -> Option> { - None + fn fptoui_sat(&mut self, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.fptoint_sat(false, val, dest_ty) } - fn fptosi_sat(&mut self, _val: RValue<'gcc>, _dest_ty: Type<'gcc>) -> Option> { - None + fn fptosi_sat(&mut self, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.fptoint_sat(true, val, dest_ty) } fn instrprof_increment(&mut self, _fn_name: RValue<'gcc>, _hash: RValue<'gcc>, _num_counters: RValue<'gcc>, _index: RValue<'gcc>) { @@ -1285,6 +1289,166 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { + fn fptoint_sat(&mut self, signed: bool, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + let src_ty = self.cx.val_ty(val); + let (float_ty, int_ty) = if self.cx.type_kind(src_ty) == TypeKind::Vector { + assert_eq!(self.cx.vector_length(src_ty), self.cx.vector_length(dest_ty)); + (self.cx.element_type(src_ty), self.cx.element_type(dest_ty)) + } else { + (src_ty, dest_ty) + }; + + // FIXME(jistone): the following was originally the fallback SSA implementation, before LLVM 13 + // added native `fptosi.sat` and `fptoui.sat` conversions, but it was used by GCC as well. + // Now that LLVM always relies on its own, the code has been moved to GCC, but the comments are + // still LLVM-specific. This should be updated, and use better GCC specifics if possible. + + let int_width = self.cx.int_width(int_ty); + let float_width = self.cx.float_width(float_ty); + // LLVM's fpto[su]i returns undef when the input val is infinite, NaN, or does not fit into the + // destination integer type after rounding towards zero. This `undef` value can cause UB in + // safe code (see issue #10184), so we implement a saturating conversion on top of it: + // Semantically, the mathematical value of the input is rounded towards zero to the next + // mathematical integer, and then the result is clamped into the range of the destination + // integer type. Positive and negative infinity are mapped to the maximum and minimum value of + // the destination integer type. NaN is mapped to 0. + // + // Define f_min and f_max as the largest and smallest (finite) floats that are exactly equal to + // a value representable in int_ty. + // They are exactly equal to int_ty::{MIN,MAX} if float_ty has enough significand bits. + // Otherwise, int_ty::MAX must be rounded towards zero, as it is one less than a power of two. + // int_ty::MIN, however, is either zero or a negative power of two and is thus exactly + // representable. Note that this only works if float_ty's exponent range is sufficiently large. + // f16 or 256 bit integers would break this property. Right now the smallest float type is f32 + // with exponents ranging up to 127, which is barely enough for i128::MIN = -2^127. + // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because + // we're rounding towards zero, we just get float_ty::MAX (which is always an integer). + // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX. + let int_max = |signed: bool, int_width: u64| -> u128 { + let shift_amount = 128 - int_width; + if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount } + }; + let int_min = |signed: bool, int_width: u64| -> i128 { + if signed { i128::MIN >> (128 - int_width) } else { 0 } + }; + + let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) { + let rounded_min = + ieee::Single::from_i128_r(int_min(signed, int_width), Round::TowardZero); + assert_eq!(rounded_min.status, Status::OK); + let rounded_max = + ieee::Single::from_u128_r(int_max(signed, int_width), Round::TowardZero); + assert!(rounded_max.value.is_finite()); + (rounded_min.value.to_bits(), rounded_max.value.to_bits()) + }; + let compute_clamp_bounds_double = |signed: bool, int_width: u64| -> (u128, u128) { + let rounded_min = + ieee::Double::from_i128_r(int_min(signed, int_width), Round::TowardZero); + assert_eq!(rounded_min.status, Status::OK); + let rounded_max = + ieee::Double::from_u128_r(int_max(signed, int_width), Round::TowardZero); + assert!(rounded_max.value.is_finite()); + (rounded_min.value.to_bits(), rounded_max.value.to_bits()) + }; + // To implement saturation, we perform the following steps: + // + // 1. Cast val to an integer with fpto[su]i. This may result in undef. + // 2. Compare val to f_min and f_max, and use the comparison results to select: + // a) int_ty::MIN if val < f_min or val is NaN + // b) int_ty::MAX if val > f_max + // c) the result of fpto[su]i otherwise + // 3. If val is NaN, return 0.0, otherwise return the result of step 2. + // + // This avoids resulting undef because values in range [f_min, f_max] by definition fit into the + // destination type. It creates an undef temporary, but *producing* undef is not UB. Our use of + // undef does not introduce any non-determinism either. + // More importantly, the above procedure correctly implements saturating conversion. + // Proof (sketch): + // If val is NaN, 0 is returned by definition. + // Otherwise, val is finite or infinite and thus can be compared with f_min and f_max. + // This yields three cases to consider: + // (1) if val in [f_min, f_max], the result of fpto[su]i is returned, which agrees with + // saturating conversion for inputs in that range. + // (2) if val > f_max, then val is larger than int_ty::MAX. This holds even if f_max is rounded + // (i.e., if f_max < int_ty::MAX) because in those cases, nextUp(f_max) is already larger + // than int_ty::MAX. Because val is larger than int_ty::MAX, the return value of int_ty::MAX + // is correct. + // (3) if val < f_min, then val is smaller than int_ty::MIN. As shown earlier, f_min exactly equals + // int_ty::MIN and therefore the return value of int_ty::MIN is correct. + // QED. + + let float_bits_to_llval = |bx: &mut Self, bits| { + let bits_llval = match float_width { + 32 => bx.cx().const_u32(bits as u32), + 64 => bx.cx().const_u64(bits as u64), + n => bug!("unsupported float width {}", n), + }; + bx.bitcast(bits_llval, float_ty) + }; + let (f_min, f_max) = match float_width { + 32 => compute_clamp_bounds_single(signed, int_width), + 64 => compute_clamp_bounds_double(signed, int_width), + n => bug!("unsupported float width {}", n), + }; + let f_min = float_bits_to_llval(self, f_min); + let f_max = float_bits_to_llval(self, f_max); + let int_max = self.cx.const_uint_big(int_ty, int_max(signed, int_width)); + let int_min = self.cx.const_uint_big(int_ty, int_min(signed, int_width) as u128); + let zero = self.cx.const_uint(int_ty, 0); + + // If we're working with vectors, constants must be "splatted": the constant is duplicated + // into each lane of the vector. The algorithm stays the same, we are just using the + // same constant across all lanes. + let maybe_splat = |bx: &mut Self, val| { + if bx.cx().type_kind(dest_ty) == TypeKind::Vector { + bx.vector_splat(bx.vector_length(dest_ty), val) + } else { + val + } + }; + let f_min = maybe_splat(self, f_min); + let f_max = maybe_splat(self, f_max); + let int_max = maybe_splat(self, int_max); + let int_min = maybe_splat(self, int_min); + let zero = maybe_splat(self, zero); + + // Step 1 ... + let fptosui_result = if signed { self.fptosi(val, dest_ty) } else { self.fptoui(val, dest_ty) }; + let less_or_nan = self.fcmp(RealPredicate::RealULT, val, f_min); + let greater = self.fcmp(RealPredicate::RealOGT, val, f_max); + + // Step 2: We use two comparisons and two selects, with %s1 being the + // result: + // %less_or_nan = fcmp ult %val, %f_min + // %greater = fcmp olt %val, %f_max + // %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result + // %s1 = select %greater, int_ty::MAX, %s0 + // Note that %less_or_nan uses an *unordered* comparison. This + // comparison is true if the operands are not comparable (i.e., if val is + // NaN). The unordered comparison ensures that s1 becomes int_ty::MIN if + // val is NaN. + // + // Performance note: Unordered comparison can be lowered to a "flipped" + // comparison and a negation, and the negation can be merged into the + // select. Therefore, it not necessarily any more expensive than an + // ordered ("normal") comparison. Whether these optimizations will be + // performed is ultimately up to the backend, but at least x86 does + // perform them. + let s0 = self.select(less_or_nan, int_min, fptosui_result); + let s1 = self.select(greater, int_max, s0); + + // Step 3: NaN replacement. + // For unsigned types, the above step already yielded int_ty::MIN == 0 if val is NaN. + // Therefore we only need to execute this step for signed integer types. + if signed { + // LLVM has no isNaN predicate, so we use (val == val) instead + let cmp = self.fcmp(RealPredicate::RealOEQ, val, val); + self.select(cmp, s1, zero) + } else { + s1 + } + } + #[cfg(feature="master")] pub fn shuffle_vector(&mut self, v1: RValue<'gcc>, v2: RValue<'gcc>, mask: RValue<'gcc>) -> RValue<'gcc> { let struct_type = mask.get_type().is_struct().expect("mask of struct type"); diff --git a/src/lib.rs b/src/lib.rs index 8a206c0368fcb..223466fb9b51f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,7 @@ #![warn(rust_2018_idioms)] #![warn(unused_lifetimes)] +extern crate rustc_apfloat; extern crate rustc_ast; extern crate rustc_codegen_ssa; extern crate rustc_data_structures; From 34d33f2299b30103a7cc640013e4d75fcdd77d1b Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 11 May 2022 22:01:53 +0400 Subject: [PATCH 003/465] Implement `ptr_mask` intrinsic in cg gcc --- src/intrinsic/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 5fbdedac0c45c..b0e7e5e1dd05c 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -309,6 +309,8 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { return; } + sym::ptr_mask => self.and(args[0].immediate(), args[1].immediate()), + _ if name_str.starts_with("simd_") => { match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { Ok(llval) => llval, From 1acc3b45e3c83423e12154a6c893941b2bb4ef7a Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 13 May 2022 17:08:44 +0400 Subject: [PATCH 004/465] Fix `ptr_mask` impl in cg gcc --- src/intrinsic/mod.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index b0e7e5e1dd05c..beb9a80014421 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -309,8 +309,18 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { return; } - sym::ptr_mask => self.and(args[0].immediate(), args[1].immediate()), + sym::ptr_mask => { + let usize_type = self.context.new_type::(); + let void_ptr_type = self.context.new_type::<*const ()>(); + let ptr = args[0].immediate(); + let mask = args[1].immediate(); + + let addr = self.bitcast(ptr, usize_type); + let masked = self.and(addr, mask); + self.bitcast(masked, void_ptr_type) + }, + _ if name_str.starts_with("simd_") => { match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { Ok(llval) => llval, From 93191f66dc4f4b5d11cb695277be13d38f3248d3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 25 Aug 2022 17:52:37 +1000 Subject: [PATCH 005/465] Box `CastTarget` within `PassMode`. Because `PassMode::Cast` is by far the largest variant, but is relatively rare. This requires making `PassMode` not impl `Copy`, and `Clone` is no longer necessary. This causes lots of sigil adjusting, but nothing very notable. --- src/abi.rs | 4 ++-- src/intrinsic/mod.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/abi.rs b/src/abi.rs index 0ed3e1fbe93f6..9b55db6a54764 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -133,7 +133,7 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { match self.ret.mode { PassMode::Ignore => cx.type_void(), PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx), - PassMode::Cast(cast) => cast.gcc_type(cx), + PassMode::Cast(ref cast) => cast.gcc_type(cx), PassMode::Indirect { .. } => { argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx))); cx.type_void() @@ -157,7 +157,7 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { PassMode::Indirect { extra_attrs: Some(_), .. } => { unimplemented!(); } - PassMode::Cast(cast) => cast.gcc_type(cx), + PassMode::Cast(ref cast) => cast.gcc_type(cx), PassMode::Indirect { extra_attrs: None, on_stack: true, .. } => { on_stack_param_indices.insert(argument_tys.len()); arg.memory_ty(cx) diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 5fbdedac0c45c..f4493776ea268 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -130,7 +130,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { sym::volatile_load | sym::unaligned_volatile_load => { let tp_ty = substs.type_at(0); let mut ptr = args[0].immediate(); - if let PassMode::Cast(ty) = fn_abi.ret.mode { + if let PassMode::Cast(ty) = &fn_abi.ret.mode { ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self))); } let load = self.volatile_load(ptr.get_type(), ptr); @@ -320,7 +320,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { }; if !fn_abi.ret.is_ignore() { - if let PassMode::Cast(ty) = fn_abi.ret.mode { + if let PassMode::Cast(ty) = &fn_abi.ret.mode { let ptr_llty = self.type_ptr_to(ty.gcc_type(self)); let ptr = self.pointercast(result.llval, ptr_llty); self.store(llval, ptr, result.align); @@ -416,7 +416,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { else if self.is_unsized_indirect() { bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); } - else if let PassMode::Cast(cast) = self.mode { + else if let PassMode::Cast(ref cast) = self.mode { // FIXME(eddyb): Figure out when the simpler Store is safe, clang // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. let can_store_through_cast_ptr = false; From f78592f1bcfba609cc83361dc39c795729292eb1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 25 Aug 2022 19:08:04 +1000 Subject: [PATCH 006/465] Change `FnAbi::args` to a boxed slice. --- src/abi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/abi.rs b/src/abi.rs index 9b55db6a54764..7f313583c82c8 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -140,7 +140,7 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } }; - for arg in &self.args { + for arg in self.args.iter() { // add padding if let Some(ty) = arg.pad { argument_tys.push(ty.gcc_type(cx)); From 5a6992916e8957927260171f8802b0d8b8809ec5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 26 Aug 2022 10:37:51 +1000 Subject: [PATCH 007/465] Simplify arg capacity calculations. Currently they try to be very precise. But they are wrong, i.e. they don't match what's happening in the loop below. This code isn't hot enough for it to matter that much. --- src/abi.rs | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/abi.rs b/src/abi.rs index 7f313583c82c8..87b730d29cdf2 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -107,26 +107,10 @@ pub trait FnAbiGccExt<'gcc, 'tcx> { impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec>, bool, FxHashSet) { let mut on_stack_param_indices = FxHashSet::default(); - let args_capacity: usize = self.args.iter().map(|arg| - if arg.pad.is_some() { - 1 - } - else { - 0 - } + - if let PassMode::Pair(_, _) = arg.mode { - 2 - } else { - 1 - } - ).sum(); + + // This capacity calculation is approximate. let mut argument_tys = Vec::with_capacity( - if let PassMode::Indirect { .. } = self.ret.mode { - 1 - } - else { - 0 - } + args_capacity, + self.args.len() + if let PassMode::Indirect { .. } = self.ret.mode { 1 } else { 0 } ); let return_ty = From d83636d3fac0c0c6b2498bd0699ad6848032f083 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 25 Aug 2022 19:18:01 +1000 Subject: [PATCH 008/465] Turn `ArgAbi::pad` into a `bool`. Because it's only ever set to `None` or `Some(Reg::i32())`. --- src/abi.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/abi.rs b/src/abi.rs index 87b730d29cdf2..3186b363e359f 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -126,8 +126,8 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { for arg in self.args.iter() { // add padding - if let Some(ty) = arg.pad { - argument_tys.push(ty.gcc_type(cx)); + if arg.pad_i32 { + argument_tys.push(Reg::i32().gcc_type(cx)); } let arg_ty = match arg.mode { From 89003418b391d0f260b2354472a9b788b8128b7b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 25 Aug 2022 22:19:38 +1000 Subject: [PATCH 009/465] Move `ArgAbi::pad_i32` into `PassMode::Cast`. Because it's only needed for that variant. This shrinks the types and clarifies the logic. --- src/abi.rs | 15 ++++++++------- src/intrinsic/mod.rs | 8 ++++---- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/abi.rs b/src/abi.rs index 3186b363e359f..848c34211ff61 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -117,7 +117,7 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { match self.ret.mode { PassMode::Ignore => cx.type_void(), PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx), - PassMode::Cast(ref cast) => cast.gcc_type(cx), + PassMode::Cast(ref cast, _) => cast.gcc_type(cx), PassMode::Indirect { .. } => { argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx))); cx.type_void() @@ -125,11 +125,6 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { }; for arg in self.args.iter() { - // add padding - if arg.pad_i32 { - argument_tys.push(Reg::i32().gcc_type(cx)); - } - let arg_ty = match arg.mode { PassMode::Ignore => continue, PassMode::Direct(_) => arg.layout.immediate_gcc_type(cx), @@ -141,7 +136,13 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { PassMode::Indirect { extra_attrs: Some(_), .. } => { unimplemented!(); } - PassMode::Cast(ref cast) => cast.gcc_type(cx), + PassMode::Cast(ref cast, pad_i32) => { + // add padding + if pad_i32 { + argument_tys.push(Reg::i32().gcc_type(cx)); + } + cast.gcc_type(cx) + } PassMode::Indirect { extra_attrs: None, on_stack: true, .. } => { on_stack_param_indices.insert(argument_tys.len()); arg.memory_ty(cx) diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index f4493776ea268..352fe7568eff0 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -130,7 +130,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { sym::volatile_load | sym::unaligned_volatile_load => { let tp_ty = substs.type_at(0); let mut ptr = args[0].immediate(); - if let PassMode::Cast(ty) = &fn_abi.ret.mode { + if let PassMode::Cast(ty, _) = &fn_abi.ret.mode { ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self))); } let load = self.volatile_load(ptr.get_type(), ptr); @@ -320,7 +320,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { }; if !fn_abi.ret.is_ignore() { - if let PassMode::Cast(ty) = &fn_abi.ret.mode { + if let PassMode::Cast(ty, _) = &fn_abi.ret.mode { let ptr_llty = self.type_ptr_to(ty.gcc_type(self)); let ptr = self.pointercast(result.llval, ptr_llty); self.store(llval, ptr, result.align); @@ -416,7 +416,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { else if self.is_unsized_indirect() { bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); } - else if let PassMode::Cast(ref cast) = self.mode { + else if let PassMode::Cast(ref cast, _) = self.mode { // FIXME(eddyb): Figure out when the simpler Store is safe, clang // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. let can_store_through_cast_ptr = false; @@ -481,7 +481,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { PassMode::Indirect { extra_attrs: Some(_), .. } => { OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst); }, - PassMode::Direct(_) | PassMode::Indirect { extra_attrs: None, .. } | PassMode::Cast(_) => { + PassMode::Direct(_) | PassMode::Indirect { extra_attrs: None, .. } | PassMode::Cast(..) => { let next_arg = next(); self.store(bx, next_arg, dst); }, From c32ad5c229e3b3812e555cfe43caa579a4a4aa8c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Aug 2022 14:11:19 -0400 Subject: [PATCH 010/465] =?UTF-8?q?interpret:=20rename=20relocation=20?= =?UTF-8?q?=E2=86=92=20provenance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/consts.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/consts.rs b/src/consts.rs index c0b8d21818f85..356c03ee3c189 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -127,7 +127,7 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> { // // We could remove this hack whenever we decide to drop macOS 10.10 support. if self.tcx.sess.target.options.is_like_osx { - // The `inspect` method is okay here because we checked relocations, and + // The `inspect` method is okay here because we checked for provenance, and // because we are doing this access to inspect the final interpreter state // (not as part of the interpreter execution). // @@ -296,17 +296,17 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAllocation<'tcx>) -> RValue<'gcc> { let alloc = alloc.inner(); - let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1); + let mut llvals = Vec::with_capacity(alloc.provenance().len() + 1); let dl = cx.data_layout(); let pointer_size = dl.pointer_size.bytes() as usize; let mut next_offset = 0; - for &(offset, alloc_id) in alloc.relocations().iter() { + for &(offset, alloc_id) in alloc.provenance().iter() { let offset = offset.bytes(); assert_eq!(offset as usize as u64, offset); let offset = offset as usize; if offset > next_offset { - // This `inspect` is okay since we have checked that it is not within a relocation, it + // This `inspect` is okay since we have checked that it is not within a pointer with provenance, it // is within the bounds of the allocation, and it doesn't affect interpreter execution // (we inspect the result after interpreter execution). Any undef byte is replaced with // some arbitrary byte value. @@ -319,7 +319,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl read_target_uint( dl.endian, // This `inspect` is okay since it is within the bounds of the allocation, it doesn't // affect interpreter execution (we inspect the result after interpreter execution), - // and we properly interpret the relocation as a relocation pointer offset. + // and we properly interpret the provenance as a relocation pointer offset. alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)), ) .expect("const_alloc_to_llvm: could not read relocation pointer") @@ -336,7 +336,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl } if alloc.len() >= next_offset { let range = next_offset..alloc.len(); - // This `inspect` is okay since we have check that it is after all relocations, it is + // This `inspect` is okay since we have check that it is after all provenance, it is // within the bounds of the allocation, and it doesn't affect interpreter execution (we // inspect the result after interpreter execution). Any undef byte is replaced with some // arbitrary byte value. From c3dce60ac783b997b7527c324b9c9ee30a6ccfd7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 6 Sep 2022 14:09:49 +0000 Subject: [PATCH 011/465] Remove dead broken code from const zst handling in backends --- src/common.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/common.rs b/src/common.rs index ccb6cbbc2c8a7..aa1c271c31cb4 100644 --- a/src/common.rs +++ b/src/common.rs @@ -158,10 +158,6 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { None } - fn zst_to_backend(&self, _ty: Type<'gcc>) -> RValue<'gcc> { - self.const_undef(self.type_ix(0)) - } - fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> { let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; match cv { From 23eae52d45ceace95215e696da13c6f9f57f90f0 Mon Sep 17 00:00:00 2001 From: Ellis Hoag Date: Fri, 26 Aug 2022 19:32:04 -0700 Subject: [PATCH 012/465] Add RanlibFailure --- src/archive.rs | 4 +++- src/errors.rs | 7 +++++++ src/lib.rs | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 src/errors.rs diff --git a/src/archive.rs b/src/archive.rs index f863abdcc97ec..14a69c194e4e4 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -1,6 +1,8 @@ use std::fs::File; use std::path::{Path, PathBuf}; +use crate::errors::RanlibFailure; + use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; use rustc_session::Session; @@ -181,7 +183,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { std::process::Command::new("ranlib").arg(output).status().expect("Couldn't run ranlib"); if !status.success() { - self.config.sess.fatal(&format!("Ranlib exited with code {:?}", status.code())); + self.config.sess.emit_fatal(RanlibFailure { exit_code: status.code() }); } any_members diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000000000..1a0e38fc0bb29 --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,7 @@ +use rustc_macros::SessionDiagnostic; + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::ranlib_failure)] +pub(crate) struct RanlibFailure { + pub exit_code: Option +} diff --git a/src/lib.rs b/src/lib.rs index 223466fb9b51f..fc10112e55ef9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,6 +25,7 @@ extern crate rustc_codegen_ssa; extern crate rustc_data_structures; extern crate rustc_errors; extern crate rustc_hir; +extern crate rustc_macros; extern crate rustc_metadata; extern crate rustc_middle; extern crate rustc_session; @@ -50,6 +51,7 @@ mod context; mod coverageinfo; mod debuginfo; mod declare; +mod errors; mod int; mod intrinsic; mod mono_item; From 7277046d84d53a9b31abb4ef8d5b448afa4725f1 Mon Sep 17 00:00:00 2001 From: Ellis Hoag Date: Fri, 26 Aug 2022 20:23:50 -0700 Subject: [PATCH 013/465] Add LinkageConstOrMutType --- src/consts.rs | 6 ++---- src/errors.rs | 8 ++++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/consts.rs b/src/consts.rs index 356c03ee3c189..81f533288677a 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -14,6 +14,7 @@ use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRan use crate::base; use crate::context::CodegenCx; +use crate::errors::LinkageConstOrMutType; use crate::type_of::LayoutGccExt; impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { @@ -368,10 +369,7 @@ fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &Codeg cx.layout_of(mt.ty).gcc_type(cx, true) } else { - cx.sess().span_fatal( - span, - "must have type `*const T` or `*mut T` due to `#[linkage]` attribute", - ) + cx.sess().emit_fatal(LinkageConstOrMutType { span: span }) }; // Declare a symbol `foo` with the desired linkage. let global1 = cx.declare_global_with_linkage(&sym, llty2, base::global_linkage_to_gcc(linkage)); diff --git a/src/errors.rs b/src/errors.rs index 1a0e38fc0bb29..456a60c6f90ba 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,7 +1,15 @@ use rustc_macros::SessionDiagnostic; +use rustc_span::Span; #[derive(SessionDiagnostic)] #[diag(codegen_gcc::ranlib_failure)] pub(crate) struct RanlibFailure { pub exit_code: Option } + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::linkage_const_or_mut_type)] +pub(crate) struct LinkageConstOrMutType { + #[primary_span] + pub span: Span +} From 7fc07caf6798dcb29f91a6a57fd63e3d3ffa34ee Mon Sep 17 00:00:00 2001 From: Ellis Hoag Date: Fri, 26 Aug 2022 20:44:44 -0700 Subject: [PATCH 014/465] Add UnwindingInlineAsm --- src/asm.rs | 3 ++- src/errors.rs | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/asm.rs b/src/asm.rs index 52fd66af0659d..007b001f213f8 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -12,6 +12,7 @@ use std::borrow::Cow; use crate::builder::Builder; use crate::context::CodegenCx; +use crate::errors::UnwindingInlineAsm; use crate::type_of::LayoutGccExt; use crate::callee::get_fn; @@ -109,7 +110,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, span: &[Span], _instance: Instance<'_>, _dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>) { if options.contains(InlineAsmOptions::MAY_UNWIND) { self.sess() - .struct_span_err(span[0], "GCC backend does not support unwinding from inline asm") + .create_err(UnwindingInlineAsm { span: span[0] }) .emit(); return; } diff --git a/src/errors.rs b/src/errors.rs index 456a60c6f90ba..e0c7dca8e3241 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -13,3 +13,10 @@ pub(crate) struct LinkageConstOrMutType { #[primary_span] pub span: Span } + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::unwinding_inline_asm)] +pub(crate) struct UnwindingInlineAsm { + #[primary_span] + pub span: Span +} From 33b58ebf22bed790dacf2ef82351a95883559b77 Mon Sep 17 00:00:00 2001 From: Ellis Hoag Date: Fri, 26 Aug 2022 20:50:37 -0700 Subject: [PATCH 015/465] Add LTONotSupported --- src/errors.rs | 4 ++++ src/lib.rs | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/errors.rs b/src/errors.rs index e0c7dca8e3241..1b2953952ef75 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -14,6 +14,10 @@ pub(crate) struct LinkageConstOrMutType { pub span: Span } +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::lto_not_supported)] +pub(crate) struct LTONotSupported {} + #[derive(SessionDiagnostic)] #[diag(codegen_gcc::unwinding_inline_asm)] pub(crate) struct UnwindingInlineAsm { diff --git a/src/lib.rs b/src/lib.rs index fc10112e55ef9..03f41d197b8f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,6 +61,7 @@ mod type_of; use std::any::Any; use std::sync::{Arc, Mutex}; +use crate::errors::LTONotSupported; use gccjit::{Context, OptimizationLevel, CType}; use rustc_ast::expand::allocator::AllocatorKind; use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen}; @@ -99,7 +100,7 @@ pub struct GccCodegenBackend { impl CodegenBackend for GccCodegenBackend { fn init(&self, sess: &Session) { if sess.lto() != Lto::No { - sess.warn("LTO is not supported. You may get a linker error."); + sess.emit_warning(LTONotSupported {}); } let temp_dir = TempDir::new().expect("cannot create temporary directory"); From 534ce39aac4881bf3ff4b41a359723f3075bf47a Mon Sep 17 00:00:00 2001 From: Ellis Hoag Date: Sat, 27 Aug 2022 15:19:16 -0700 Subject: [PATCH 016/465] Add LayoutSizeOverflow --- src/context.rs | 5 +++-- src/errors.rs | 8 ++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/context.rs b/src/context.rs index 478f6d893dd0f..187e4c689ec47 100644 --- a/src/context.rs +++ b/src/context.rs @@ -18,6 +18,7 @@ use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDat use rustc_target::spec::{HasTargetSpec, Target, TlsModel}; use crate::callee::get_fn; +use crate::errors::LayoutSizeOverflow; #[derive(Clone)] pub struct FuncSig<'gcc> { @@ -477,7 +478,7 @@ impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { if let LayoutError::SizeOverflow(_) = err { - self.sess().span_fatal(span, &err.to_string()) + self.sess().emit_fatal(LayoutSizeOverflow { span, error: err.to_string() }) } else { span_bug!(span, "failed to get layout for `{}`: {}", ty, err) } @@ -495,7 +496,7 @@ impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { fn_abi_request: FnAbiRequest<'tcx>, ) -> ! { if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err { - self.sess().span_fatal(span, &err.to_string()) + self.sess().emit_fatal(LayoutSizeOverflow { span, error: err.to_string() }) } else { match fn_abi_request { FnAbiRequest::OfFnPtr { sig, extra_args } => { diff --git a/src/errors.rs b/src/errors.rs index 1b2953952ef75..490a209ead05f 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -7,6 +7,14 @@ pub(crate) struct RanlibFailure { pub exit_code: Option } +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::layout_size_overflow)] +pub(crate) struct LayoutSizeOverflow { + #[primary_span] + pub span: Span, + pub error: String, +} + #[derive(SessionDiagnostic)] #[diag(codegen_gcc::linkage_const_or_mut_type)] pub(crate) struct LinkageConstOrMutType { From 1f3ae14c83aa6f4a7bb8c68cf2deab68b646cfe0 Mon Sep 17 00:00:00 2001 From: Ellis Hoag Date: Sat, 27 Aug 2022 15:21:46 -0700 Subject: [PATCH 017/465] Lint against untranslatable diagnostics in rustc_codegen_gcc --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 03f41d197b8f7..007d61ed51de8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,8 @@ #![recursion_limit="256"] #![warn(rust_2018_idioms)] #![warn(unused_lifetimes)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] extern crate rustc_apfloat; extern crate rustc_ast; From ff9bf7b6b3e5050d78ac3931b993b9a0fcbbad18 Mon Sep 17 00:00:00 2001 From: Ellis Hoag Date: Mon, 29 Aug 2022 20:22:03 -0700 Subject: [PATCH 018/465] remove IntoDiagnosticArg impl for Option --- src/archive.rs | 2 +- src/errors.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/archive.rs b/src/archive.rs index 14a69c194e4e4..77fbb2c500e81 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -183,7 +183,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { std::process::Command::new("ranlib").arg(output).status().expect("Couldn't run ranlib"); if !status.success() { - self.config.sess.emit_fatal(RanlibFailure { exit_code: status.code() }); + self.config.sess.emit_fatal(RanlibFailure { exit_code: format!("{:?}", status.code()) }); } any_members diff --git a/src/errors.rs b/src/errors.rs index 490a209ead05f..01de75976a323 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -4,7 +4,7 @@ use rustc_span::Span; #[derive(SessionDiagnostic)] #[diag(codegen_gcc::ranlib_failure)] pub(crate) struct RanlibFailure { - pub exit_code: Option + pub exit_code: String, } #[derive(SessionDiagnostic)] From d3bb849fe9d663a1de780824bb8d08d01d611114 Mon Sep 17 00:00:00 2001 From: Ellis Hoag Date: Wed, 31 Aug 2022 22:02:35 -0700 Subject: [PATCH 019/465] Add wrapper type for ExitCode for use in RanlibFailure --- src/archive.rs | 2 +- src/errors.rs | 24 +++++++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/archive.rs b/src/archive.rs index 77fbb2c500e81..ac0342f6b80a0 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -183,7 +183,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { std::process::Command::new("ranlib").arg(output).status().expect("Couldn't run ranlib"); if !status.success() { - self.config.sess.emit_fatal(RanlibFailure { exit_code: format!("{:?}", status.code()) }); + self.config.sess.emit_fatal(RanlibFailure::new(status.code())); } any_members diff --git a/src/errors.rs b/src/errors.rs index 01de75976a323..b5fc789c27918 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,10 +1,32 @@ +use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_macros::SessionDiagnostic; use rustc_span::Span; +use std::borrow::Cow; + +struct ExitCode { + pub exit_code: Option, +} + +impl IntoDiagnosticArg for ExitCode { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + match self.exit_code { + Some(t) => t.into_diagnostic_arg(), + None => DiagnosticArgValue::Str(Cow::Borrowed("None")), + } + } +} #[derive(SessionDiagnostic)] #[diag(codegen_gcc::ranlib_failure)] pub(crate) struct RanlibFailure { - pub exit_code: String, + exit_code: ExitCode, +} + +impl RanlibFailure { + pub fn new(exit_code: Option) -> Self { + let exit_code = ExitCode{ exit_code }; + RanlibFailure { exit_code } + } } #[derive(SessionDiagnostic)] From 70ab0548a0afbef84583e8efe189466d4bcbf213 Mon Sep 17 00:00:00 2001 From: Ellis Hoag Date: Wed, 31 Aug 2022 22:03:05 -0700 Subject: [PATCH 020/465] lint type --- src/errors.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/errors.rs b/src/errors.rs index b5fc789c27918..938c0a74af38a 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -46,7 +46,7 @@ pub(crate) struct LinkageConstOrMutType { #[derive(SessionDiagnostic)] #[diag(codegen_gcc::lto_not_supported)] -pub(crate) struct LTONotSupported {} +pub(crate) struct LTONotSupported; #[derive(SessionDiagnostic)] #[diag(codegen_gcc::unwinding_inline_asm)] From 059326c4bd30e573b961d2267a8cd74d84c05220 Mon Sep 17 00:00:00 2001 From: Ellis Hoag Date: Sun, 11 Sep 2022 16:43:18 -0700 Subject: [PATCH 021/465] Add monomorphization errors --- src/errors.rs | 198 +++++++++++++++++++++++++++++++++++++++- src/intrinsic/mod.rs | 13 +-- src/intrinsic/simd.rs | 203 +++++++++++++----------------------------- 3 files changed, 261 insertions(+), 153 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 938c0a74af38a..a70ebf62da3e9 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,6 +1,7 @@ use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_macros::SessionDiagnostic; -use rustc_span::Span; +use rustc_middle::ty::Ty; +use rustc_span::{Span, Symbol}; use std::borrow::Cow; struct ExitCode { @@ -29,6 +30,201 @@ impl RanlibFailure { } } +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::invalid_monomorphization_basic_integer, code = "E0511")] +pub(crate) struct InvalidMonomorphizationBasicInteger<'a> { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub ty: Ty<'a>, +} + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::invalid_monomorphization_invalid_float_vector, code = "E0511")] +pub(crate) struct InvalidMonomorphizationInvalidFloatVector<'a> { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub elem_ty: &'a str, + pub vec_ty: Ty<'a>, +} + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::invalid_monomorphization_not_float, code = "E0511")] +pub(crate) struct InvalidMonomorphizationNotFloat<'a> { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub ty: Ty<'a>, +} + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::invalid_monomorphization_unrecognized, code = "E0511")] +pub(crate) struct InvalidMonomorphizationUnrecognized { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::invalid_monomorphization_expected_signed_unsigned, code = "E0511")] +pub(crate) struct InvalidMonomorphizationExpectedSignedUnsigned<'a> { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub elem_ty: Ty<'a>, + pub vec_ty: Ty<'a>, +} + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::invalid_monomorphization_unsupported_element, code = "E0511")] +pub(crate) struct InvalidMonomorphizationUnsupportedElement<'a> { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub in_ty: Ty<'a>, + pub elem_ty: Ty<'a>, + pub ret_ty: Ty<'a>, +} + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::invalid_monomorphization_invalid_bitmask, code = "E0511")] +pub(crate) struct InvalidMonomorphizationInvalidBitmask<'a> { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub ty: Ty<'a>, + pub expected_int_bits: u64, + pub expected_bytes: u64, +} + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::invalid_monomorphization_simd_shuffle, code = "E0511")] +pub(crate) struct InvalidMonomorphizationSimdShuffle<'a> { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub ty: Ty<'a>, +} + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::invalid_monomorphization_expected_simd, code = "E0511")] +pub(crate) struct InvalidMonomorphizationExpectedSimd<'a> { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub position: &'a str, + pub found_ty: Ty<'a>, +} + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::invalid_monomorphization_mask_type, code = "E0511")] +pub(crate) struct InvalidMonomorphizationMaskType<'a> { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub ty: Ty<'a>, +} + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::invalid_monomorphization_return_length, code = "E0511")] +pub(crate) struct InvalidMonomorphizationReturnLength<'a> { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub in_len: u64, + pub ret_ty: Ty<'a>, + pub out_len: u64, +} + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::invalid_monomorphization_return_length_input_type, code = "E0511")] +pub(crate) struct InvalidMonomorphizationReturnLengthInputType<'a> { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub in_len: u64, + pub in_ty: Ty<'a>, + pub ret_ty: Ty<'a>, + pub out_len: u64, +} + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::invalid_monomorphization_return_element, code = "E0511")] +pub(crate) struct InvalidMonomorphizationReturnElement<'a> { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub in_elem: Ty<'a>, + pub in_ty: Ty<'a>, + pub ret_ty: Ty<'a>, + pub out_ty: Ty<'a>, +} + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::invalid_monomorphization_return_type, code = "E0511")] +pub(crate) struct InvalidMonomorphizationReturnType<'a> { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub in_elem: Ty<'a>, + pub in_ty: Ty<'a>, + pub ret_ty: Ty<'a>, +} + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::invalid_monomorphization_inserted_type, code = "E0511")] +pub(crate) struct InvalidMonomorphizationInsertedType<'a> { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub in_elem: Ty<'a>, + pub in_ty: Ty<'a>, + pub out_ty: Ty<'a>, +} + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::invalid_monomorphization_return_integer_type, code = "E0511")] +pub(crate) struct InvalidMonomorphizationReturnIntegerType<'a> { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub ret_ty: Ty<'a>, + pub out_ty: Ty<'a>, +} + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::invalid_monomorphization_mismatched_lengths, code = "E0511")] +pub(crate) struct InvalidMonomorphizationMismatchedLengths { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub m_len: u64, + pub v_len: u64, +} + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::invalid_monomorphization_unsupported_cast, code = "E0511")] +pub(crate) struct InvalidMonomorphizationUnsupportedCast<'a> { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub in_ty: Ty<'a>, + pub in_elem: Ty<'a>, + pub ret_ty: Ty<'a>, + pub out_elem: Ty<'a>, +} + +#[derive(SessionDiagnostic)] +#[diag(codegen_gcc::invalid_monomorphization_unsupported_operation, code = "E0511")] +pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub in_ty: Ty<'a>, + pub in_elem: Ty<'a>, +} + #[derive(SessionDiagnostic)] #[diag(codegen_gcc::layout_size_overflow)] pub(crate) struct LayoutSizeOverflow { diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 02cedd4646bbd..cc9c90c242709 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -4,7 +4,7 @@ mod simd; use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp, FunctionType}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::base::wants_msvc_seh; -use rustc_codegen_ssa::common::{IntPredicate, span_invalid_monomorphization_error}; +use rustc_codegen_ssa::common::IntPredicate; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{ArgAbiMethods, BaseTypeMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods}; @@ -20,6 +20,7 @@ use crate::abi::GccType; use crate::builder::Builder; use crate::common::{SignType, TypeReflection}; use crate::context::CodegenCx; +use crate::errors::InvalidMonomorphizationBasicInteger; use crate::type_of::LayoutGccExt; use crate::intrinsic::simd::generic_simd_intrinsic; @@ -242,15 +243,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { _ => bug!(), }, None => { - span_invalid_monomorphization_error( - tcx.sess, - span, - &format!( - "invalid monomorphization of `{}` intrinsic: \ - expected basic integer type, found `{}`", - name, ty - ), - ); + tcx.sess.emit_err(InvalidMonomorphizationBasicInteger { span, name, ty }); return; } } diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index 2401f3350186e..22bd0a1de8230 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -2,7 +2,7 @@ use std::cmp::Ordering; use gccjit::{BinaryOp, RValue, Type, ToRValue}; use rustc_codegen_ssa::base::compare_simd_types; -use rustc_codegen_ssa::common::{TypeKind, span_invalid_monomorphization_error}; +use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::mir::operand::OperandRef; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods}; @@ -14,43 +14,48 @@ use rustc_span::{Span, Symbol, sym}; use rustc_target::abi::Align; use crate::builder::Builder; +use crate::errors::{ + InvalidMonomorphizationInvalidFloatVector, + InvalidMonomorphizationNotFloat, + InvalidMonomorphizationUnrecognized, + InvalidMonomorphizationExpectedSignedUnsigned, + InvalidMonomorphizationUnsupportedElement, + InvalidMonomorphizationInvalidBitmask, + InvalidMonomorphizationSimdShuffle, + InvalidMonomorphizationExpectedSimd, + InvalidMonomorphizationMaskType, + InvalidMonomorphizationReturnLength, + InvalidMonomorphizationReturnLengthInputType, + InvalidMonomorphizationReturnElement, + InvalidMonomorphizationReturnType, + InvalidMonomorphizationInsertedType, + InvalidMonomorphizationReturnIntegerType, + InvalidMonomorphizationMismatchedLengths, + InvalidMonomorphizationUnsupportedCast, + InvalidMonomorphizationUnsupportedOperation +}; use crate::intrinsic; pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, name: Symbol, callee_ty: Ty<'tcx>, args: &[OperandRef<'tcx, RValue<'gcc>>], ret_ty: Ty<'tcx>, llret_ty: Type<'gcc>, span: Span) -> Result, ()> { // macros for error handling: - #[allow(unused_macro_rules)] - macro_rules! emit_error { - ($msg: tt) => { - emit_error!($msg, ) - }; - ($msg: tt, $($fmt: tt)*) => { - span_invalid_monomorphization_error( - bx.sess(), span, - &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg), - name, $($fmt)*)); - } - } - macro_rules! return_error { - ($($fmt: tt)*) => { + ($err:expr) => { { - emit_error!($($fmt)*); + bx.sess().emit_err($err); return Err(()); } } } - macro_rules! require { - ($cond: expr, $($fmt: tt)*) => { + ($cond:expr, $err:expr) => { if !$cond { - return_error!($($fmt)*); + return_error!($err); } - }; + } } - macro_rules! require_simd { ($ty: expr, $position: expr) => { - require!($ty.is_simd(), "expected SIMD {} type, found non-SIMD `{}`", $position, $ty) + require!($ty.is_simd(), InvalidMonomorphizationExpectedSimd { span, name, position: $position, found_ty: $ty }) }; } @@ -82,10 +87,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, bx.load(int_ty, ptr, Align::ONE) } _ => return_error!( - "invalid bitmask `{}`, expected `u{}` or `[u8; {}]`", - mask_ty, - expected_int_bits, - expected_bytes + InvalidMonomorphizationInvalidBitmask { span, name, ty: mask_ty, expected_int_bits, expected_bytes } ), }; @@ -127,18 +129,11 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); require!( in_len == out_len, - "expected return type with length {} (same as input type `{}`), \ - found `{}` with length {}", - in_len, - in_ty, - ret_ty, - out_len + InvalidMonomorphizationReturnLengthInputType { span, name, in_len, in_ty, ret_ty, out_len } ); require!( bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer, - "expected return type with integer elements, found `{}` with non-integer `{}`", - ret_ty, - out_ty + InvalidMonomorphizationReturnIntegerType {span, name, ret_ty, out_ty} ); return Ok(compare_simd_types( @@ -163,8 +158,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, }) } _ => return_error!( - "simd_shuffle index must be an array of `u32`, got `{}`", - args[2].layout.ty + InvalidMonomorphizationSimdShuffle { span, name, ty: args[2].layout.ty } ), } } @@ -179,19 +173,11 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); require!( out_len == n, - "expected return type of length {}, found `{}` with length {}", - n, - ret_ty, - out_len + InvalidMonomorphizationReturnLength { span, name, in_len: n, ret_ty, out_len } ); require!( in_elem == out_ty, - "expected return element type `{}` (element of input `{}`), \ - found `{}` with element type `{}`", - in_elem, - in_ty, - ret_ty, - out_ty + InvalidMonomorphizationReturnElement { span, name, in_elem, in_ty, ret_ty, out_ty } ); let vector = args[2].immediate(); @@ -207,10 +193,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, if name == sym::simd_insert { require!( in_elem == arg_tys[2], - "expected inserted type `{}` (element of input `{}`), found `{}`", - in_elem, - in_ty, - arg_tys[2] + InvalidMonomorphizationInsertedType { span, name, in_elem, in_ty, out_ty: arg_tys[2] } ); let vector = args[0].immediate(); let index = args[1].immediate(); @@ -263,10 +246,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, if name == sym::simd_extract { require!( ret_ty == in_elem, - "expected return type `{}` (element of input `{}`), found `{}`", - in_elem, - in_ty, - ret_ty + InvalidMonomorphizationReturnType { span, name, in_elem, in_ty, ret_ty } ); let vector = args[0].immediate(); return Ok(bx.context.new_vector_access(None, vector, args[1].immediate()).to_rvalue()); @@ -279,13 +259,11 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); require!( m_len == v_len, - "mismatched lengths: mask length `{}` != other vector length `{}`", - m_len, - v_len + InvalidMonomorphizationMismatchedLengths { span, name, m_len, v_len } ); match m_elem_ty.kind() { ty::Int(_) => {} - _ => return_error!("mask element type is `{}`, expected `i_`", m_elem_ty), + _ => return_error!(InvalidMonomorphizationMaskType { span, name, ty: m_elem_ty }), } return Ok(bx.vector_select(args[0].immediate(), args[1].immediate(), args[2].immediate())); } @@ -295,12 +273,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); require!( in_len == out_len, - "expected return type with length {} (same as input type `{}`), \ - found `{}` with length {}", - in_len, - in_ty, - ret_ty, - out_len + InvalidMonomorphizationReturnLengthInputType { span, name, in_len, in_ty, ret_ty, out_len } ); // casting cares about nominal type, not just structural type if in_elem == out_elem { @@ -412,13 +385,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, } _ => { /* Unsupported. Fallthrough. */ } } - require!( - false, - "unsupported cast from `{}` with element `{}` to `{}` with element `{}`", - in_ty, - in_elem, - ret_ty, - out_elem + return_error!( + InvalidMonomorphizationUnsupportedCast { span, name, in_ty, in_elem, ret_ty, out_elem } ); } @@ -431,10 +399,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, })* _ => {}, } - require!(false, - "unsupported operation on `{}` with element `{}`", - in_ty, - in_elem) + return_error!(InvalidMonomorphizationUnsupportedOperation { span, name, in_ty, in_elem }) })* } } @@ -448,23 +413,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, span: Span, args: &[OperandRef<'tcx, RValue<'gcc>>], ) -> Result, ()> { - macro_rules! emit_error { - ($msg: tt, $($fmt: tt)*) => { - span_invalid_monomorphization_error( - bx.sess(), span, - &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg), - name, $($fmt)*)); - } - } macro_rules! return_error { - ($($fmt: tt)*) => { + ($err:expr) => { { - emit_error!($($fmt)*); + bx.sess().emit_err($err); return Err(()); } } } - let (elem_ty_str, elem_ty) = if let ty::Float(f) = in_elem.kind() { let elem_ty = bx.cx.type_float_from_ty(*f); @@ -472,16 +428,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, 32 => ("f32", elem_ty), 64 => ("f64", elem_ty), _ => { - return_error!( - "unsupported element type `{}` of floating-point vector `{}`", - f.name_str(), - in_ty - ); + // Can we pass elem_ty directly? + return_error!(InvalidMonomorphizationInvalidFloatVector { span, name, elem_ty: f.name_str(), vec_ty: in_ty }); } } } else { - return_error!("`{}` is not a floating-point type", in_ty); + return_error!(InvalidMonomorphizationNotFloat { span, name, ty: in_ty }); }; let vec_ty = bx.cx.type_vector(elem_ty, in_len); @@ -504,7 +457,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)), sym::simd_round => ("round", bx.type_func(&[vec_ty], vec_ty)), sym::simd_trunc => ("trunc", bx.type_func(&[vec_ty], vec_ty)), - _ => return_error!("unrecognized intrinsic `{}`", name), + _ => return_error!(InvalidMonomorphizationUnrecognized { span, name }) }; let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str); let function = intrinsic::llvm::intrinsic(llvm_name, &bx.cx); @@ -557,10 +510,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, })* _ => {}, } - require!(false, - "unsupported operation on `{}` with element `{}`", - in_ty, - in_elem) + return_error!(InvalidMonomorphizationUnsupportedOperation { span, name, in_ty, in_elem }) })* } } @@ -579,12 +529,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_int_from_ty(i)), ty::Uint(i) => (false, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_uint_from_ty(i)), _ => { - return_error!( - "expected element type `{}` of vector type `{}` \ - to be a signed or unsigned integer type", - arg_tys[0].simd_size_and_type(bx.tcx()).1, - arg_tys[0] - ); + return_error!(InvalidMonomorphizationExpectedSignedUnsigned { + span, + name, + elem_ty: arg_tys[0].simd_size_and_type(bx.tcx()).1, + vec_ty: arg_tys[0], + }); } }; let builtin_name = @@ -617,10 +567,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, if name == sym::$name { require!( ret_ty == in_elem, - "expected return type `{}` (element of input `{}`), found `{}`", - in_elem, - in_ty, - ret_ty + InvalidMonomorphizationReturnType { span, name, in_elem, in_ty, ret_ty } ); return match in_elem.kind() { ty::Int(_) | ty::Uint(_) => { @@ -644,13 +591,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, Ok(bx.vector_reduce_op(args[0].immediate(), $vec_op)) } } - _ => return_error!( - "unsupported {} from `{}` with element `{}` to `{}`", - sym::$name, - in_ty, - in_elem, - ret_ty - ), + _ => return_error!(InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty }), }; } }; @@ -676,20 +617,11 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, if name == sym::$name { require!( ret_ty == in_elem, - "expected return type `{}` (element of input `{}`), found `{}`", - in_elem, - in_ty, - ret_ty + InvalidMonomorphizationReturnType { span, name, in_elem, in_ty, ret_ty } ); return match in_elem.kind() { ty::Int(_) | ty::Uint(_) | ty::Float(_) => Ok(bx.$reduction(args[0].immediate())), - _ => return_error!( - "unsupported {} from `{}` with element `{}` to `{}`", - sym::$name, - in_ty, - in_elem, - ret_ty - ), + _ => return_error!(InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty }), }; } }; @@ -704,22 +636,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, let input = if !$boolean { require!( ret_ty == in_elem, - "expected return type `{}` (element of input `{}`), found `{}`", - in_elem, - in_ty, - ret_ty + InvalidMonomorphizationReturnType { span, name, in_elem, in_ty, ret_ty } ); args[0].immediate() } else { match in_elem.kind() { ty::Int(_) | ty::Uint(_) => {} - _ => return_error!( - "unsupported {} from `{}` with element `{}` to `{}`", - sym::$name, - in_ty, - in_elem, - ret_ty - ), + _ => return_error!(InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty }), } // boolean reductions operate on vectors of i1s: @@ -733,11 +656,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, Ok(if !$boolean { r } else { bx.zext(r, bx.type_bool()) }) } _ => return_error!( - "unsupported {} from `{}` with element `{}` to `{}`", - sym::$name, - in_ty, - in_elem, - ret_ty + InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty } ), }; } From 5c839d995b09f5034dd73eaf0cbb276764d08e98 Mon Sep 17 00:00:00 2001 From: Ellis Hoag Date: Sun, 11 Sep 2022 17:34:51 -0700 Subject: [PATCH 022/465] impl SessionDiagnostic for LayoutError and Spanned --- src/context.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/context.rs b/src/context.rs index 187e4c689ec47..14de0cee28e9d 100644 --- a/src/context.rs +++ b/src/context.rs @@ -13,7 +13,7 @@ use rustc_middle::mir::mono::CodegenUnit; use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout, LayoutOfHelpers}; use rustc_session::Session; -use rustc_span::Span; +use rustc_span::{Span, source_map::respan}; use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx}; use rustc_target::spec::{HasTargetSpec, Target, TlsModel}; @@ -478,6 +478,23 @@ impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { if let LayoutError::SizeOverflow(_) = err { + let _ = respan(span, err); + // error: lifetime may not live long enough + // --> src/context.rs:483:13 + // | + // 475 | impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { + // | ---- ---- lifetime `'tcx` defined here + // | | + // | lifetime `'gcc` defined here + // ... + // 483 | self.sess().emit_fatal(respan(span, err)) + // | ^^^^^^^^^^^ argument requires that `'gcc` must outlive `'tcx` + // | + // = help: consider adding the following bound: `'gcc: 'tcx` + // = note: requirement occurs because of the type `CodegenCx<'_, '_>`, which makes the generic argument `'_` invariant + // = note: the struct `CodegenCx<'gcc, 'tcx>` is invariant over the parameter `'gcc` + // = help: see for more information about variance + // self.sess().emit_fatal(respan(span, err)) self.sess().emit_fatal(LayoutSizeOverflow { span, error: err.to_string() }) } else { span_bug!(span, "failed to get layout for `{}`: {}", ty, err) From 43b320657141da7f447c782c9ea93a072cfd67b3 Mon Sep 17 00:00:00 2001 From: Ellis Hoag Date: Sat, 24 Sep 2022 11:05:37 -0700 Subject: [PATCH 023/465] rebase and update trait names --- src/errors.rs | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index a70ebf62da3e9..a1c95e7a7f450 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,5 +1,5 @@ use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; -use rustc_macros::SessionDiagnostic; +use rustc_macros::Diagnostic; use rustc_middle::ty::Ty; use rustc_span::{Span, Symbol}; use std::borrow::Cow; @@ -17,7 +17,7 @@ impl IntoDiagnosticArg for ExitCode { } } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::ranlib_failure)] pub(crate) struct RanlibFailure { exit_code: ExitCode, @@ -30,7 +30,7 @@ impl RanlibFailure { } } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::invalid_monomorphization_basic_integer, code = "E0511")] pub(crate) struct InvalidMonomorphizationBasicInteger<'a> { #[primary_span] @@ -39,7 +39,7 @@ pub(crate) struct InvalidMonomorphizationBasicInteger<'a> { pub ty: Ty<'a>, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::invalid_monomorphization_invalid_float_vector, code = "E0511")] pub(crate) struct InvalidMonomorphizationInvalidFloatVector<'a> { #[primary_span] @@ -49,7 +49,7 @@ pub(crate) struct InvalidMonomorphizationInvalidFloatVector<'a> { pub vec_ty: Ty<'a>, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::invalid_monomorphization_not_float, code = "E0511")] pub(crate) struct InvalidMonomorphizationNotFloat<'a> { #[primary_span] @@ -58,7 +58,7 @@ pub(crate) struct InvalidMonomorphizationNotFloat<'a> { pub ty: Ty<'a>, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::invalid_monomorphization_unrecognized, code = "E0511")] pub(crate) struct InvalidMonomorphizationUnrecognized { #[primary_span] @@ -66,7 +66,7 @@ pub(crate) struct InvalidMonomorphizationUnrecognized { pub name: Symbol, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::invalid_monomorphization_expected_signed_unsigned, code = "E0511")] pub(crate) struct InvalidMonomorphizationExpectedSignedUnsigned<'a> { #[primary_span] @@ -76,7 +76,7 @@ pub(crate) struct InvalidMonomorphizationExpectedSignedUnsigned<'a> { pub vec_ty: Ty<'a>, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::invalid_monomorphization_unsupported_element, code = "E0511")] pub(crate) struct InvalidMonomorphizationUnsupportedElement<'a> { #[primary_span] @@ -87,7 +87,7 @@ pub(crate) struct InvalidMonomorphizationUnsupportedElement<'a> { pub ret_ty: Ty<'a>, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::invalid_monomorphization_invalid_bitmask, code = "E0511")] pub(crate) struct InvalidMonomorphizationInvalidBitmask<'a> { #[primary_span] @@ -98,7 +98,7 @@ pub(crate) struct InvalidMonomorphizationInvalidBitmask<'a> { pub expected_bytes: u64, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::invalid_monomorphization_simd_shuffle, code = "E0511")] pub(crate) struct InvalidMonomorphizationSimdShuffle<'a> { #[primary_span] @@ -107,7 +107,7 @@ pub(crate) struct InvalidMonomorphizationSimdShuffle<'a> { pub ty: Ty<'a>, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::invalid_monomorphization_expected_simd, code = "E0511")] pub(crate) struct InvalidMonomorphizationExpectedSimd<'a> { #[primary_span] @@ -117,7 +117,7 @@ pub(crate) struct InvalidMonomorphizationExpectedSimd<'a> { pub found_ty: Ty<'a>, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::invalid_monomorphization_mask_type, code = "E0511")] pub(crate) struct InvalidMonomorphizationMaskType<'a> { #[primary_span] @@ -126,7 +126,7 @@ pub(crate) struct InvalidMonomorphizationMaskType<'a> { pub ty: Ty<'a>, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::invalid_monomorphization_return_length, code = "E0511")] pub(crate) struct InvalidMonomorphizationReturnLength<'a> { #[primary_span] @@ -137,7 +137,7 @@ pub(crate) struct InvalidMonomorphizationReturnLength<'a> { pub out_len: u64, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::invalid_monomorphization_return_length_input_type, code = "E0511")] pub(crate) struct InvalidMonomorphizationReturnLengthInputType<'a> { #[primary_span] @@ -149,7 +149,7 @@ pub(crate) struct InvalidMonomorphizationReturnLengthInputType<'a> { pub out_len: u64, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::invalid_monomorphization_return_element, code = "E0511")] pub(crate) struct InvalidMonomorphizationReturnElement<'a> { #[primary_span] @@ -161,7 +161,7 @@ pub(crate) struct InvalidMonomorphizationReturnElement<'a> { pub out_ty: Ty<'a>, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::invalid_monomorphization_return_type, code = "E0511")] pub(crate) struct InvalidMonomorphizationReturnType<'a> { #[primary_span] @@ -172,7 +172,7 @@ pub(crate) struct InvalidMonomorphizationReturnType<'a> { pub ret_ty: Ty<'a>, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::invalid_monomorphization_inserted_type, code = "E0511")] pub(crate) struct InvalidMonomorphizationInsertedType<'a> { #[primary_span] @@ -183,7 +183,7 @@ pub(crate) struct InvalidMonomorphizationInsertedType<'a> { pub out_ty: Ty<'a>, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::invalid_monomorphization_return_integer_type, code = "E0511")] pub(crate) struct InvalidMonomorphizationReturnIntegerType<'a> { #[primary_span] @@ -193,7 +193,7 @@ pub(crate) struct InvalidMonomorphizationReturnIntegerType<'a> { pub out_ty: Ty<'a>, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::invalid_monomorphization_mismatched_lengths, code = "E0511")] pub(crate) struct InvalidMonomorphizationMismatchedLengths { #[primary_span] @@ -203,7 +203,7 @@ pub(crate) struct InvalidMonomorphizationMismatchedLengths { pub v_len: u64, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::invalid_monomorphization_unsupported_cast, code = "E0511")] pub(crate) struct InvalidMonomorphizationUnsupportedCast<'a> { #[primary_span] @@ -215,7 +215,7 @@ pub(crate) struct InvalidMonomorphizationUnsupportedCast<'a> { pub out_elem: Ty<'a>, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::invalid_monomorphization_unsupported_operation, code = "E0511")] pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> { #[primary_span] @@ -225,7 +225,7 @@ pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> { pub in_elem: Ty<'a>, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::layout_size_overflow)] pub(crate) struct LayoutSizeOverflow { #[primary_span] @@ -233,18 +233,18 @@ pub(crate) struct LayoutSizeOverflow { pub error: String, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::linkage_const_or_mut_type)] pub(crate) struct LinkageConstOrMutType { #[primary_span] pub span: Span } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::lto_not_supported)] pub(crate) struct LTONotSupported; -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(codegen_gcc::unwinding_inline_asm)] pub(crate) struct UnwindingInlineAsm { #[primary_span] From 0ae1e27b17cca88bdbdd5ffc84add51057d4cbf9 Mon Sep 17 00:00:00 2001 From: Ellis Hoag Date: Sat, 24 Sep 2022 11:36:16 -0700 Subject: [PATCH 024/465] fix lifetime error --- src/context.rs | 24 +++--------------------- src/errors.rs | 8 -------- 2 files changed, 3 insertions(+), 29 deletions(-) diff --git a/src/context.rs b/src/context.rs index 14de0cee28e9d..46ade33eb01cb 100644 --- a/src/context.rs +++ b/src/context.rs @@ -18,7 +18,6 @@ use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDat use rustc_target::spec::{HasTargetSpec, Target, TlsModel}; use crate::callee::get_fn; -use crate::errors::LayoutSizeOverflow; #[derive(Clone)] pub struct FuncSig<'gcc> { @@ -294,7 +293,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { self.is_native_int_type(typ) || self.is_non_native_int_type(typ) || typ.is_compatible_with(self.bool_type) } - pub fn sess(&self) -> &Session { + pub fn sess(&self) -> &'tcx Session { &self.tcx.sess } @@ -478,24 +477,7 @@ impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { if let LayoutError::SizeOverflow(_) = err { - let _ = respan(span, err); - // error: lifetime may not live long enough - // --> src/context.rs:483:13 - // | - // 475 | impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { - // | ---- ---- lifetime `'tcx` defined here - // | | - // | lifetime `'gcc` defined here - // ... - // 483 | self.sess().emit_fatal(respan(span, err)) - // | ^^^^^^^^^^^ argument requires that `'gcc` must outlive `'tcx` - // | - // = help: consider adding the following bound: `'gcc: 'tcx` - // = note: requirement occurs because of the type `CodegenCx<'_, '_>`, which makes the generic argument `'_` invariant - // = note: the struct `CodegenCx<'gcc, 'tcx>` is invariant over the parameter `'gcc` - // = help: see for more information about variance - // self.sess().emit_fatal(respan(span, err)) - self.sess().emit_fatal(LayoutSizeOverflow { span, error: err.to_string() }) + self.sess().emit_fatal(respan(span, err)) } else { span_bug!(span, "failed to get layout for `{}`: {}", ty, err) } @@ -513,7 +495,7 @@ impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { fn_abi_request: FnAbiRequest<'tcx>, ) -> ! { if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err { - self.sess().emit_fatal(LayoutSizeOverflow { span, error: err.to_string() }) + self.sess().emit_fatal(respan(span, err)) } else { match fn_abi_request { FnAbiRequest::OfFnPtr { sig, extra_args } => { diff --git a/src/errors.rs b/src/errors.rs index a1c95e7a7f450..eb8528104fac3 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -225,14 +225,6 @@ pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> { pub in_elem: Ty<'a>, } -#[derive(Diagnostic)] -#[diag(codegen_gcc::layout_size_overflow)] -pub(crate) struct LayoutSizeOverflow { - #[primary_span] - pub span: Span, - pub error: String, -} - #[derive(Diagnostic)] #[diag(codegen_gcc::linkage_const_or_mut_type)] pub(crate) struct LinkageConstOrMutType { From d1741f6d6225079ab1bc5f65bf19562069c48d5a Mon Sep 17 00:00:00 2001 From: Ellis Hoag Date: Sat, 24 Sep 2022 15:03:14 -0700 Subject: [PATCH 025/465] remove comment --- src/intrinsic/simd.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index 22bd0a1de8230..ffc85b773a276 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -428,7 +428,6 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, 32 => ("f32", elem_ty), 64 => ("f64", elem_ty), _ => { - // Can we pass elem_ty directly? return_error!(InvalidMonomorphizationInvalidFloatVector { span, name, elem_ty: f.name_str(), vec_ty: in_ty }); } } From 277b997adc88e197538827616778d0161ac7a714 Mon Sep 17 00:00:00 2001 From: Ellis Hoag Date: Mon, 26 Sep 2022 19:57:40 -0700 Subject: [PATCH 026/465] lint and remove unused diagnostic --- src/errors.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index eb8528104fac3..83f4af16612e7 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -4,13 +4,12 @@ use rustc_middle::ty::Ty; use rustc_span::{Span, Symbol}; use std::borrow::Cow; -struct ExitCode { - pub exit_code: Option, -} +struct ExitCode(Option); impl IntoDiagnosticArg for ExitCode { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - match self.exit_code { + let ExitCode(exit_code) = self; + match exit_code { Some(t) => t.into_diagnostic_arg(), None => DiagnosticArgValue::Str(Cow::Borrowed("None")), } @@ -25,8 +24,7 @@ pub(crate) struct RanlibFailure { impl RanlibFailure { pub fn new(exit_code: Option) -> Self { - let exit_code = ExitCode{ exit_code }; - RanlibFailure { exit_code } + RanlibFailure { exit_code: ExitCode(exit_code) } } } From 4d398832a5ac5318d2b32de3cca1d39dc4040f9a Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 24 Sep 2022 12:34:56 +0200 Subject: [PATCH 027/465] Stabilize bench_black_box --- tests/run/int.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run/int.rs b/tests/run/int.rs index 2b90e4ae8d82b..75779622b54cd 100644 --- a/tests/run/int.rs +++ b/tests/run/int.rs @@ -3,7 +3,7 @@ // Run-time: // status: 0 -#![feature(bench_black_box, const_black_box, core_intrinsics, start)] +#![feature(const_black_box, core_intrinsics, start)] #![no_std] From 5ae3bf2ed3848b626cb301b2fd3034affe47b7f7 Mon Sep 17 00:00:00 2001 From: Ellis Hoag Date: Wed, 28 Sep 2022 19:02:38 -0700 Subject: [PATCH 028/465] print when ranlib failed without an exit code --- src/errors.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/errors.rs b/src/errors.rs index 83f4af16612e7..d7816e395c8eb 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -11,7 +11,7 @@ impl IntoDiagnosticArg for ExitCode { let ExitCode(exit_code) = self; match exit_code { Some(t) => t.into_diagnostic_arg(), - None => DiagnosticArgValue::Str(Cow::Borrowed("None")), + None => DiagnosticArgValue::Str(Cow::Borrowed("")), } } } From 2db7a873de20de1a67f953304213442ca93e3d0f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 1 Oct 2022 16:34:45 +0000 Subject: [PATCH 029/465] Remove unused Context assoc type from WriteBackendMethods --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 007d61ed51de8..a70ed8084a9b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -210,7 +210,6 @@ impl WriteBackendMethods for GccCodegenBackend { type Module = GccContext; type TargetMachine = (); type ModuleBuffer = ModuleBuffer; - type Context = (); type ThinData = (); type ThinBuffer = ThinBuffer; From 29edc888bdaa55b0362523a70279fbde50622d84 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 1 Oct 2022 16:45:07 +0000 Subject: [PATCH 030/465] Remove several unused methods from MiscMethods --- src/context.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/context.rs b/src/context.rs index 46ade33eb01cb..62a61eb8548da 100644 --- a/src/context.rs +++ b/src/context.rs @@ -416,10 +416,6 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.codegen_unit } - fn used_statics(&self) -> &RefCell>> { - unimplemented!(); - } - fn set_frame_pointer_type(&self, _llfn: RValue<'gcc>) { // TODO(antoyo) } @@ -428,10 +424,6 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { // TODO(antoyo) } - fn create_used_variable(&self) { - unimplemented!(); - } - fn declare_c_main(&self, fn_type: Self::Type) -> Option { if self.get_declared_value("main").is_none() { Some(self.declare_cfn("main", fn_type)) @@ -443,14 +435,6 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { None } } - - fn compiler_used_statics(&self) -> &RefCell>> { - unimplemented!() - } - - fn create_compiler_used_variable(&self) { - unimplemented!() - } } impl<'gcc, 'tcx> HasTyCtxt<'tcx> for CodegenCx<'gcc, 'tcx> { From 69a065ef816acd1230a11bd2899e6f4e7e985e39 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 1 Oct 2022 16:45:33 +0000 Subject: [PATCH 031/465] Remove unused target_cpu and tune_cpu methods from ExtraBackendMethods --- src/lib.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a70ed8084a9b1..accd02ab00269 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -171,15 +171,6 @@ impl ExtraBackendMethods for GccCodegenBackend { Ok(()) }) } - - fn target_cpu<'b>(&self, _sess: &'b Session) -> &'b str { - unimplemented!(); - } - - fn tune_cpu<'b>(&self, _sess: &'b Session) -> Option<&'b str> { - None - // TODO(antoyo) - } } pub struct ModuleBuffer; From 3f43ee24075c50f8f1a1add793c037500a465d15 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 1 Oct 2022 17:01:31 +0000 Subject: [PATCH 032/465] Merge apply_attrs_callsite into call and invoke Some codegen backends are not able to apply callsite attrs after the fact. --- src/abi.rs | 4 ---- src/asm.rs | 2 +- src/builder.rs | 31 +++++++++++++++++++++++++++---- src/intrinsic/mod.rs | 6 +++--- src/intrinsic/simd.rs | 2 +- 5 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/abi.rs b/src/abi.rs index 848c34211ff61..6fb1cbfad8cd3 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -11,10 +11,6 @@ use crate::intrinsic::ArgAbiExt; use crate::type_of::LayoutGccExt; impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { - fn apply_attrs_callsite(&mut self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _callsite: Self::Value) { - // TODO(antoyo) - } - fn get_param(&mut self, index: usize) -> Self::Value { let func = self.current_func(); let param = func.get_param(index as i32); diff --git a/src/asm.rs b/src/asm.rs index 007b001f213f8..c346dbd63cca7 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -498,7 +498,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { if options.contains(InlineAsmOptions::NORETURN) { let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable"); let builtin_unreachable: RValue<'gcc> = unsafe { std::mem::transmute(builtin_unreachable) }; - self.call(self.type_void(), builtin_unreachable, &[], None); + self.call(self.type_void(), None, builtin_unreachable, &[], None); } // Write results to outputs. diff --git a/src/builder.rs b/src/builder.rs index 6994eeb00c3e2..e6fed9d35ca5f 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -444,11 +444,23 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.block.end_with_switch(None, value, default_block, &gcc_cases); } - fn invoke(&mut self, typ: Type<'gcc>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> { + fn invoke( + &mut self, + typ: Type<'gcc>, + fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, + func: RValue<'gcc>, + args: &[RValue<'gcc>], + then: Block<'gcc>, + catch: Block<'gcc>, + _funclet: Option<&Funclet>, + ) -> RValue<'gcc> { // TODO(bjorn3): Properly implement unwinding. - let call_site = self.call(typ, func, args, None); + let call_site = self.call(typ, None, func, args, None); let condition = self.context.new_rvalue_from_int(self.bool_type, 1); self.llbb().end_with_conditional(None, condition, then, catch); + if let Some(_fn_abi) = fn_abi { + // TODO(bjorn3): Apply function attributes + } call_site } @@ -1227,16 +1239,27 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // TODO(antoyo) } - fn call(&mut self, _typ: Type<'gcc>, func: RValue<'gcc>, args: &[RValue<'gcc>], funclet: Option<&Funclet>) -> RValue<'gcc> { + fn call( + &mut self, + _typ: Type<'gcc>, + fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, + func: RValue<'gcc>, + args: &[RValue<'gcc>], + funclet: Option<&Funclet>, + ) -> RValue<'gcc> { // FIXME(antoyo): remove when having a proper API. let gcc_func = unsafe { std::mem::transmute(func) }; - if self.functions.borrow().values().find(|value| **value == gcc_func).is_some() { + let call = if self.functions.borrow().values().find(|value| **value == gcc_func).is_some() { self.function_call(func, args, funclet) } else { // If it's a not function that was defined, it's a function pointer. self.function_ptr_call(func, args, funclet) + }; + if let Some(_fn_abi) = fn_abi { + // TODO(bjorn3): Apply function attributes } + call } fn zext(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index cc9c90c242709..49be6c649e652 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -100,7 +100,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { _ if simple.is_some() => { // FIXME(antoyo): remove this cast when the API supports function. let func = unsafe { std::mem::transmute(simple.expect("simple")) }; - self.call(self.type_void(), func, &args.iter().map(|arg| arg.immediate()).collect::>(), None) + self.call(self.type_void(), None, func, &args.iter().map(|arg| arg.immediate()).collect::>(), None) }, sym::likely => { self.expect(args[0].immediate(), true) @@ -341,7 +341,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { fn abort(&mut self) { let func = self.context.get_builtin_function("abort"); let func: RValue<'gcc> = unsafe { std::mem::transmute(func) }; - self.call(self.type_void(), func, &[], None); + self.call(self.type_void(), None, func, &[], None); } fn assume(&mut self, value: Self::Value) { @@ -1124,7 +1124,7 @@ fn try_intrinsic<'gcc, 'tcx>(bx: &mut Builder<'_, 'gcc, 'tcx>, try_func: RValue< // NOTE: the `|| true` here is to use the panic=abort strategy with panic=unwind too if bx.sess().panic_strategy() == PanicStrategy::Abort || true { // TODO(bjorn3): Properly implement unwinding and remove the `|| true` once this is done. - bx.call(bx.type_void(), try_func, &[data], None); + bx.call(bx.type_void(), None, try_func, &[data], None); // Return 0 unconditionally from the intrinsic call; // we can never unwind. let ret_align = bx.tcx.data_layout.i32_align.abi; diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index ffc85b773a276..12e416f62a4e0 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -461,7 +461,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str); let function = intrinsic::llvm::intrinsic(llvm_name, &bx.cx); let function: RValue<'gcc> = unsafe { std::mem::transmute(function) }; - let c = bx.call(fn_ty, function, &args.iter().map(|arg| arg.immediate()).collect::>(), None); + let c = bx.call(fn_ty, None, function, &args.iter().map(|arg| arg.immediate()).collect::>(), None); Ok(c) } From af0b18b454029cea852db105f15d443f4af1e2b1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 1 Oct 2022 17:34:21 +0000 Subject: [PATCH 033/465] Remove dynamic_alloca from BuilderMethods --- src/builder.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index e6fed9d35ca5f..15471ecdb03c7 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -655,10 +655,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.current_func().new_local(None, aligned_type, &format!("stack_var_{}", self.stack_var_count.get())).get_address(None) } - fn dynamic_alloca(&mut self, _ty: Type<'gcc>, _align: Align) -> RValue<'gcc> { - unimplemented!(); - } - fn array_alloca(&mut self, _ty: Type<'gcc>, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> { unimplemented!(); } From 413edf67713195ebbf57ba50aac84e9387559bbe Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 1 Oct 2022 18:22:46 +0000 Subject: [PATCH 034/465] Remove type argument of array_alloca and rename to byte_array_alloca --- src/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builder.rs b/src/builder.rs index 15471ecdb03c7..a314b7cc2152d 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -655,7 +655,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.current_func().new_local(None, aligned_type, &format!("stack_var_{}", self.stack_var_count.get())).get_address(None) } - fn array_alloca(&mut self, _ty: Type<'gcc>, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> { + fn byte_array_alloca(&mut self, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> { unimplemented!(); } From 1bae661dbc0b9fd3397e0df00b176bf13f346cff Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Wed, 5 Oct 2022 16:33:04 -0400 Subject: [PATCH 035/465] tidy Co-authored-by: yvt --- library/std/src/thread/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 32453b4d4a3cb..afa4e2fb16854 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -880,7 +880,7 @@ pub fn sleep(dur: Duration) { /// * It can be implemented very efficiently on many platforms. /// /// # Memory Orderings -/// +/// /// Calls to `park` _synchronize-with_ calls to `unpark`, meaning that memory /// operations performed before a call to `unpark` are made visible to the thread that /// consumes the token and returns from `park`. Note that all `park` and `unpark` @@ -890,7 +890,7 @@ pub fn sleep(dur: Duration) { /// In atomic ordering terms, `unpark` performs a `Release` operation and `park` /// performs the corresponding `Acquire` operation. Calls to `unpark` for the same /// thread form a [release sequence]. -/// +/// /// Notice that being unblocked does not imply any synchronization with someone that /// unparked this thread, it could also be spurious. For example, it would be a valid, /// but inefficient, implementation to make both park and unpark return immediately From 14e0e0fec386d42a8d980c63dd4ff3c11f6eeaf0 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 17 Oct 2022 22:38:37 +0100 Subject: [PATCH 036/465] Stabilize asm_sym --- tests/run/asm.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/run/asm.rs b/tests/run/asm.rs index 46abbb553bf2f..38c1eac7adf69 100644 --- a/tests/run/asm.rs +++ b/tests/run/asm.rs @@ -3,11 +3,12 @@ // Run-time: // status: 0 -#![feature(asm_const, asm_sym)] +#![feature(asm_const)] use std::arch::{asm, global_asm}; -global_asm!(" +global_asm!( + " .global add_asm add_asm: mov rax, rdi @@ -132,7 +133,9 @@ fn main() { assert_eq!(x, 43); // check sym fn - extern "C" fn foo() -> u64 { 42 } + extern "C" fn foo() -> u64 { + 42 + } let x: u64; unsafe { asm!("call {}", sym foo, lateout("rax") x); From d3b02e31866dc3011702182b6e3226268acf110d Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sat, 22 Oct 2022 11:07:54 +0200 Subject: [PATCH 037/465] Migrate all diagnostics --- src/errors.rs | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index d7816e395c8eb..15ad90f9043c0 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -17,7 +17,7 @@ impl IntoDiagnosticArg for ExitCode { } #[derive(Diagnostic)] -#[diag(codegen_gcc::ranlib_failure)] +#[diag(codegen_gcc_ranlib_failure)] pub(crate) struct RanlibFailure { exit_code: ExitCode, } @@ -29,7 +29,7 @@ impl RanlibFailure { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_basic_integer, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_basic_integer, code = "E0511")] pub(crate) struct InvalidMonomorphizationBasicInteger<'a> { #[primary_span] pub span: Span, @@ -38,7 +38,7 @@ pub(crate) struct InvalidMonomorphizationBasicInteger<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_invalid_float_vector, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_invalid_float_vector, code = "E0511")] pub(crate) struct InvalidMonomorphizationInvalidFloatVector<'a> { #[primary_span] pub span: Span, @@ -48,7 +48,7 @@ pub(crate) struct InvalidMonomorphizationInvalidFloatVector<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_not_float, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_not_float, code = "E0511")] pub(crate) struct InvalidMonomorphizationNotFloat<'a> { #[primary_span] pub span: Span, @@ -57,7 +57,7 @@ pub(crate) struct InvalidMonomorphizationNotFloat<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_unrecognized, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_unrecognized, code = "E0511")] pub(crate) struct InvalidMonomorphizationUnrecognized { #[primary_span] pub span: Span, @@ -65,7 +65,7 @@ pub(crate) struct InvalidMonomorphizationUnrecognized { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_expected_signed_unsigned, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_expected_signed_unsigned, code = "E0511")] pub(crate) struct InvalidMonomorphizationExpectedSignedUnsigned<'a> { #[primary_span] pub span: Span, @@ -75,7 +75,7 @@ pub(crate) struct InvalidMonomorphizationExpectedSignedUnsigned<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_unsupported_element, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_unsupported_element, code = "E0511")] pub(crate) struct InvalidMonomorphizationUnsupportedElement<'a> { #[primary_span] pub span: Span, @@ -86,7 +86,7 @@ pub(crate) struct InvalidMonomorphizationUnsupportedElement<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_invalid_bitmask, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_invalid_bitmask, code = "E0511")] pub(crate) struct InvalidMonomorphizationInvalidBitmask<'a> { #[primary_span] pub span: Span, @@ -97,7 +97,7 @@ pub(crate) struct InvalidMonomorphizationInvalidBitmask<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_simd_shuffle, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_simd_shuffle, code = "E0511")] pub(crate) struct InvalidMonomorphizationSimdShuffle<'a> { #[primary_span] pub span: Span, @@ -106,7 +106,7 @@ pub(crate) struct InvalidMonomorphizationSimdShuffle<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_expected_simd, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_expected_simd, code = "E0511")] pub(crate) struct InvalidMonomorphizationExpectedSimd<'a> { #[primary_span] pub span: Span, @@ -116,7 +116,7 @@ pub(crate) struct InvalidMonomorphizationExpectedSimd<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_mask_type, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_mask_type, code = "E0511")] pub(crate) struct InvalidMonomorphizationMaskType<'a> { #[primary_span] pub span: Span, @@ -125,7 +125,7 @@ pub(crate) struct InvalidMonomorphizationMaskType<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_return_length, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_return_length, code = "E0511")] pub(crate) struct InvalidMonomorphizationReturnLength<'a> { #[primary_span] pub span: Span, @@ -136,7 +136,7 @@ pub(crate) struct InvalidMonomorphizationReturnLength<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_return_length_input_type, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_return_length_input_type, code = "E0511")] pub(crate) struct InvalidMonomorphizationReturnLengthInputType<'a> { #[primary_span] pub span: Span, @@ -148,7 +148,7 @@ pub(crate) struct InvalidMonomorphizationReturnLengthInputType<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_return_element, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_return_element, code = "E0511")] pub(crate) struct InvalidMonomorphizationReturnElement<'a> { #[primary_span] pub span: Span, @@ -160,7 +160,7 @@ pub(crate) struct InvalidMonomorphizationReturnElement<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_return_type, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_return_type, code = "E0511")] pub(crate) struct InvalidMonomorphizationReturnType<'a> { #[primary_span] pub span: Span, @@ -171,7 +171,7 @@ pub(crate) struct InvalidMonomorphizationReturnType<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_inserted_type, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_inserted_type, code = "E0511")] pub(crate) struct InvalidMonomorphizationInsertedType<'a> { #[primary_span] pub span: Span, @@ -182,7 +182,7 @@ pub(crate) struct InvalidMonomorphizationInsertedType<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_return_integer_type, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_return_integer_type, code = "E0511")] pub(crate) struct InvalidMonomorphizationReturnIntegerType<'a> { #[primary_span] pub span: Span, @@ -192,7 +192,7 @@ pub(crate) struct InvalidMonomorphizationReturnIntegerType<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_mismatched_lengths, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_mismatched_lengths, code = "E0511")] pub(crate) struct InvalidMonomorphizationMismatchedLengths { #[primary_span] pub span: Span, @@ -202,7 +202,7 @@ pub(crate) struct InvalidMonomorphizationMismatchedLengths { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_unsupported_cast, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_unsupported_cast, code = "E0511")] pub(crate) struct InvalidMonomorphizationUnsupportedCast<'a> { #[primary_span] pub span: Span, @@ -214,7 +214,7 @@ pub(crate) struct InvalidMonomorphizationUnsupportedCast<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_unsupported_operation, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_unsupported_operation, code = "E0511")] pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> { #[primary_span] pub span: Span, @@ -224,18 +224,18 @@ pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::linkage_const_or_mut_type)] +#[diag(codegen_gcc_linkage_const_or_mut_type)] pub(crate) struct LinkageConstOrMutType { #[primary_span] pub span: Span } #[derive(Diagnostic)] -#[diag(codegen_gcc::lto_not_supported)] +#[diag(codegen_gcc_lto_not_supported)] pub(crate) struct LTONotSupported; #[derive(Diagnostic)] -#[diag(codegen_gcc::unwinding_inline_asm)] +#[diag(codegen_gcc_unwinding_inline_asm)] pub(crate) struct UnwindingInlineAsm { #[primary_span] pub span: Span From e30385bc06226bb823a1891e7f66bf069dee20a9 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Wed, 12 Oct 2022 14:44:01 -0700 Subject: [PATCH 038/465] Support raw-dylib functions being used inside inlined functions --- src/archive.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/archive.rs b/src/archive.rs index ac0342f6b80a0..f18ae7ea5e9b0 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -47,6 +47,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { _lib_name: &str, _dll_imports: &[DllImport], _tmpdir: &Path, + _is_direct_dependency: bool, ) -> PathBuf { unimplemented!(); } From 5a1c8e8e5c8b8a7e0a0d1a576be425226725d59b Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 14 Oct 2022 02:24:58 +0100 Subject: [PATCH 039/465] Rewrite implementation of `#[alloc_error_handler]` The new implementation doesn't use weak lang items and instead changes `#[alloc_error_handler]` to an attribute macro just like `#[global_allocator]`. The attribute will generate the `__rg_oom` function which is called by the compiler-generated `__rust_alloc_error_handler`. If no `__rg_oom` function is defined in any crate then the compiler shim will call `__rdl_oom` in the alloc crate which will simply panic. This also fixes link errors with `-C link-dead-code` with `default_alloc_error_handler`: `__rg_oom` was previously defined in the alloc crate and would attempt to reference the `oom` lang item, even if it didn't exist. This worked as long as `__rg_oom` was excluded from linking since it was not called. This is a prerequisite for the stabilization of `default_alloc_error_handler` (#102318). --- src/allocator.rs | 11 ++--------- src/lib.rs | 4 ++-- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/allocator.rs b/src/allocator.rs index 58efb81e80011..e2c9ffe9c1c30 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -7,7 +7,7 @@ use rustc_span::symbol::sym; use crate::GccContext; -pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) { +pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) { let context = &mods.context; let usize = match tcx.sess.target.pointer_width { @@ -90,14 +90,7 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam .collect(); let func = context.new_function(None, FunctionType::Exported, void, &args, name, false); - let kind = - if has_alloc_error_handler { - AllocatorKind::Global - } - else { - AllocatorKind::Default - }; - let callee = kind.fn_name(sym::oom); + let callee = alloc_error_handler_kind.fn_name(sym::oom); let args: Vec<_> = types.iter().enumerate() .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) .collect(); diff --git a/src/lib.rs b/src/lib.rs index accd02ab00269..dd0daf2c38b10 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -153,11 +153,11 @@ impl CodegenBackend for GccCodegenBackend { } impl ExtraBackendMethods for GccCodegenBackend { - fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) -> Self::Module { + fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) -> Self::Module { let mut mods = GccContext { context: Context::default(), }; - unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, has_alloc_error_handler); } + unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); } mods } From 87237cb69935730623917aa4674901270b938c26 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sun, 6 Nov 2022 14:01:46 +0530 Subject: [PATCH 040/465] Add type_array to BaseTypeMethods Moved type_array function to rustc_codegen_ssa::BaseTypeMethods trait. This allows using normal alloca function to create arrays as suggested in https://github.com/rust-lang/rust/pull/104022. Signed-off-by: Ayush Singh --- src/type_.rs | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/type_.rs b/src/type_.rs index 68bdb8d4e55f4..862ed62c68b2a 100644 --- a/src/type_.rs +++ b/src/type_.rs @@ -201,6 +201,27 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn val_ty(&self, value: RValue<'gcc>) -> Type<'gcc> { value.get_type() } + + fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> { + if let Some(struct_type) = ty.is_struct() { + if struct_type.get_field_count() == 0 { + // NOTE: since gccjit only supports i32 for the array size and libcore's tests uses a + // size of usize::MAX in test_binary_search, we workaround this by setting the size to + // zero for ZSTs. + // FIXME(antoyo): fix gccjit API. + len = 0; + } + } + + // NOTE: see note above. Some other test uses usize::MAX. + if len == u64::MAX { + len = 0; + } + + let len: i32 = len.try_into().expect("array len"); + + self.context.new_array_type(None, ty, len) + } } impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { @@ -227,27 +248,6 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { self.context.new_opaque_struct_type(None, name) } - pub fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> { - if let Some(struct_type) = ty.is_struct() { - if struct_type.get_field_count() == 0 { - // NOTE: since gccjit only supports i32 for the array size and libcore's tests uses a - // size of usize::MAX in test_binary_search, we workaround this by setting the size to - // zero for ZSTs. - // FIXME(antoyo): fix gccjit API. - len = 0; - } - } - - // NOTE: see note above. Some other test uses usize::MAX. - if len == u64::MAX { - len = 0; - } - - let len: i32 = len.try_into().expect("array len"); - - self.context.new_array_type(None, ty, len) - } - pub fn type_bool(&self) -> Type<'gcc> { self.context.new_type::() } From e876f43599acf69a094ecbbbc04c10d7d8f58356 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Nov 2022 14:15:20 +0100 Subject: [PATCH 041/465] fix cranelift and gcc --- src/consts.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/consts.rs b/src/consts.rs index 81f533288677a..111bfeb132203 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -297,12 +297,12 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAllocation<'tcx>) -> RValue<'gcc> { let alloc = alloc.inner(); - let mut llvals = Vec::with_capacity(alloc.provenance().len() + 1); + let mut llvals = Vec::with_capacity(alloc.provenance().ptrs().len() + 1); let dl = cx.data_layout(); let pointer_size = dl.pointer_size.bytes() as usize; let mut next_offset = 0; - for &(offset, alloc_id) in alloc.provenance().iter() { + for &(offset, alloc_id) in alloc.provenance().ptrs().iter() { let offset = offset.bytes(); assert_eq!(offset as usize as u64, offset); let offset = offset as usize; From 2596ab4d75abec169b96bae468ae752838602480 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 29 Oct 2022 23:36:47 -0400 Subject: [PATCH 042/465] Allow actual AVX512-related feature names in the case of some misleading aliases --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index dd0daf2c38b10..b9600da5c39df 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -315,10 +315,10 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec { false } /* - adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512gfni, - avx512ifma, avx512pf, avx512vaes, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpclmulqdq, - avx512vpopcntdq, bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm, - sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, xsave, xsavec, xsaveopt, xsaves + adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512ifma, + avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq, + bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm, + sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves */ //false }) From 358419cc25a86cfc48bbf30041f29b955bd2c881 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 13 Nov 2022 12:14:59 +0100 Subject: [PATCH 043/465] add is_sized method on Abi and Layout, and use it --- src/type_.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/type_.rs b/src/type_.rs index 862ed62c68b2a..bdf7318ce48c9 100644 --- a/src/type_.rs +++ b/src/type_.rs @@ -277,7 +277,7 @@ pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout offset = target_offset + field.size; prev_effective_align = effective_field_align; } - if !layout.is_unsized() && field_count > 0 { + if layout.is_sized() && field_count > 0 { if offset > layout.size { bug!("layout: {:#?} stride: {:?} offset: {:?}", layout, layout.size, offset); } From 695c76c45ac9819f2d3c0d3d93dd4f9eaf4041bd Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Tue, 15 Nov 2022 22:15:55 +0530 Subject: [PATCH 044/465] Use custom entry name in gcc This is a continuation of 9f0a8620bd7d325e6d42417b08daff3e55cb88f6 for gcc. Signed-off-by: Ayush Singh --- src/context.rs | 5 +++-- src/declare.rs | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/context.rs b/src/context.rs index 62a61eb8548da..2e71c3665daa7 100644 --- a/src/context.rs +++ b/src/context.rs @@ -425,8 +425,9 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } fn declare_c_main(&self, fn_type: Self::Type) -> Option { - if self.get_declared_value("main").is_none() { - Some(self.declare_cfn("main", fn_type)) + let entry_name = self.sess().target.entry_name.as_ref(); + if self.get_declared_value(entry_name).is_none() { + Some(self.declare_entry_fn(entry_name, fn_type, ())) } else { // If the symbol already exists, it is an error: for example, the user wrote diff --git a/src/declare.rs b/src/declare.rs index a619e2f771252..eae77508c973a 100644 --- a/src/declare.rs +++ b/src/declare.rs @@ -65,13 +65,13 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { global } - pub fn declare_cfn(&self, name: &str, _fn_type: Type<'gcc>) -> RValue<'gcc> { + pub fn declare_entry_fn(&self, name: &str, _fn_type: Type<'gcc>, callconv: () /*llvm::CCallConv*/) -> RValue<'gcc> { // TODO(antoyo): use the fn_type parameter. let const_string = self.context.new_type::().make_pointer().make_pointer(); let return_type = self.type_i32(); let variadic = false; self.linkage.set(FunctionType::Exported); - let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, &[self.type_i32(), const_string], variadic); + let func = declare_raw_fn(self, name, callconv, return_type, &[self.type_i32(), const_string], variadic); // NOTE: it is needed to set the current_func here as well, because get_fn() is not called // for the main function. *self.current_func.borrow_mut() = Some(func); From af8682b8b40b6c374912388315e7220a75dc16d9 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 1 Oct 2022 23:10:36 +0200 Subject: [PATCH 045/465] Introduce composite debuginfo. --- src/debuginfo.rs | 57 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/src/debuginfo.rs b/src/debuginfo.rs index 266759ed6cfa1..a81585d412846 100644 --- a/src/debuginfo.rs +++ b/src/debuginfo.rs @@ -4,8 +4,9 @@ use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods}; use rustc_middle::mir; use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; use rustc_span::{SourceFile, Span, Symbol}; -use rustc_target::abi::Size; use rustc_target::abi::call::FnAbi; +use rustc_target::abi::Size; +use std::ops::Range; use crate::builder::Builder; use crate::context::CodegenCx; @@ -13,7 +14,15 @@ use crate::context::CodegenCx; impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { // FIXME(eddyb) find a common convention for all of the debuginfo-related // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). - fn dbg_var_addr(&mut self, _dbg_var: Self::DIVariable, _scope_metadata: Self::DIScope, _variable_alloca: Self::Value, _direct_offset: Size, _indirect_offsets: &[Size]) { + fn dbg_var_addr( + &mut self, + _dbg_var: Self::DIVariable, + _scope_metadata: Self::DIScope, + _variable_alloca: Self::Value, + _direct_offset: Size, + _indirect_offsets: &[Size], + _fragment: Option>, + ) { unimplemented!(); } @@ -31,16 +40,31 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { } impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { - fn create_vtable_debuginfo(&self, _ty: Ty<'tcx>, _trait_ref: Option>, _vtable: Self::Value) { + fn create_vtable_debuginfo( + &self, + _ty: Ty<'tcx>, + _trait_ref: Option>, + _vtable: Self::Value, + ) { // TODO(antoyo) } - fn create_function_debug_context(&self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _llfn: RValue<'gcc>, _mir: &mir::Body<'tcx>) -> Option> { + fn create_function_debug_context( + &self, + _instance: Instance<'tcx>, + _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + _llfn: RValue<'gcc>, + _mir: &mir::Body<'tcx>, + ) -> Option> { // TODO(antoyo) None } - fn extend_scope_to_file(&self, _scope_metadata: Self::DIScope, _file: &SourceFile) -> Self::DIScope { + fn extend_scope_to_file( + &self, + _scope_metadata: Self::DIScope, + _file: &SourceFile, + ) -> Self::DIScope { unimplemented!(); } @@ -48,15 +72,32 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { // TODO(antoyo) } - fn create_dbg_var(&self, _variable_name: Symbol, _variable_type: Ty<'tcx>, _scope_metadata: Self::DIScope, _variable_kind: VariableKind, _span: Span) -> Self::DIVariable { + fn create_dbg_var( + &self, + _variable_name: Symbol, + _variable_type: Ty<'tcx>, + _scope_metadata: Self::DIScope, + _variable_kind: VariableKind, + _span: Span, + ) -> Self::DIVariable { unimplemented!(); } - fn dbg_scope_fn(&self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _maybe_definition_llfn: Option>) -> Self::DIScope { + fn dbg_scope_fn( + &self, + _instance: Instance<'tcx>, + _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + _maybe_definition_llfn: Option>, + ) -> Self::DIScope { unimplemented!(); } - fn dbg_loc(&self, _scope: Self::DIScope, _inlined_at: Option, _span: Span) -> Self::DILocation { + fn dbg_loc( + &self, + _scope: Self::DIScope, + _inlined_at: Option, + _span: Span, + ) -> Self::DILocation { unimplemented!(); } } From d01b63a09ab53ec37a41b51b6e30f0f44c44f43b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 9 Nov 2022 11:04:10 +1100 Subject: [PATCH 046/465] Use `&mut Bx` more. For the next commit, `FunctionCx::codegen_*_terminator` need to take a `&mut Bx` instead of consuming a `Bx`. This triggers a cascade of similar changes across multiple functions. The resulting code is more concise and replaces many `&mut bx` expressions with `bx`. --- src/builder.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index a314b7cc2152d..782f6856654a6 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -755,11 +755,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { OperandRef { val, layout: place.layout } } - fn write_operand_repeatedly(mut self, cg_elem: OperandRef<'tcx, RValue<'gcc>>, count: u64, dest: PlaceRef<'tcx, RValue<'gcc>>) -> Self { + fn write_operand_repeatedly(&mut self, cg_elem: OperandRef<'tcx, RValue<'gcc>>, count: u64, dest: PlaceRef<'tcx, RValue<'gcc>>) { let zero = self.const_usize(0); let count = self.const_usize(count); - let start = dest.project_index(&mut self, zero).llval; - let end = dest.project_index(&mut self, count).llval; + let start = dest.project_index(self, zero).llval; + let end = dest.project_index(self, count).llval; let header_bb = self.append_sibling_block("repeat_loop_header"); let body_bb = self.append_sibling_block("repeat_loop_body"); @@ -778,14 +778,13 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.switch_to_block(body_bb); let align = dest.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size); - cg_elem.val.store(&mut self, PlaceRef::new_sized_aligned(current_val, cg_elem.layout, align)); + cg_elem.val.store(self, PlaceRef::new_sized_aligned(current_val, cg_elem.layout, align)); let next = self.inbounds_gep(self.backend_type(cg_elem.layout), current.to_rvalue(), &[self.const_usize(1)]); self.llbb().add_assignment(None, current, next); self.br(header_bb); self.switch_to_block(next_bb); - self } fn range_metadata(&mut self, _load: RValue<'gcc>, _range: WrappingRange) { From 39511672e764f911df5e5ee9de79aa9b992a86c8 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 26 Nov 2022 09:54:54 +0000 Subject: [PATCH 047/465] Remove more redundant `all`s --- example/alloc_system.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/example/alloc_system.rs b/example/alloc_system.rs index 89661918d05a5..fd01fcf1fc82c 100644 --- a/example/alloc_system.rs +++ b/example/alloc_system.rs @@ -13,17 +13,17 @@ // The minimum alignment guaranteed by the architecture. This value is used to // add fast paths for low alignment values. -#[cfg(all(any(target_arch = "x86", +#[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "mips", target_arch = "powerpc", - target_arch = "powerpc64")))] + target_arch = "powerpc64"))] const MIN_ALIGN: usize = 8; -#[cfg(all(any(target_arch = "x86_64", +#[cfg(any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "mips64", target_arch = "s390x", - target_arch = "sparc64")))] + target_arch = "sparc64"))] const MIN_ALIGN: usize = 16; pub struct System; From 690085c2dab7e28851a0521e9513eafc5acb4e4e Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 28 May 2022 10:43:51 +0000 Subject: [PATCH 048/465] Rewrite LLVM's archive writer in Rust This allows it to be used by other codegen backends --- Cargo.lock | 14 ---- Cargo.toml | 4 -- src/archive.rs | 177 ++----------------------------------------------- src/errors.rs | 16 +---- 4 files changed, 8 insertions(+), 203 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6df2102470fe6..1cb219e12e04d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,12 +11,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "ar" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "450575f58f7bee32816abbff470cbc47797397c2a81e0eaced4b98436daf52e1" - [[package]] name = "bitflags" version = "1.3.2" @@ -212,10 +206,8 @@ dependencies = [ name = "rustc_codegen_gcc" version = "0.1.0" dependencies = [ - "ar", "gccjit", "lang_tester", - "target-lexicon", "tempfile", ] @@ -228,12 +220,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "target-lexicon" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d" - [[package]] name = "tempfile" version = "3.2.0" diff --git a/Cargo.toml b/Cargo.toml index 211d19a8dc890..1f3da2f799b78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,10 +27,6 @@ gccjit = { git = "https://github.com/antoyo/gccjit.rs" } # Local copy. #gccjit = { path = "../gccjit.rs" } -target-lexicon = "0.10.0" - -ar = "0.8.0" - [dev-dependencies] lang_tester = "0.3.9" tempfile = "3.1.0" diff --git a/src/archive.rs b/src/archive.rs index f18ae7ea5e9b0..11fa074f5ac79 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -1,44 +1,17 @@ -use std::fs::File; use std::path::{Path, PathBuf}; -use crate::errors::RanlibFailure; - -use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; +use rustc_codegen_ssa::back::archive::{ + get_native_object_symbols, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, +}; use rustc_session::Session; use rustc_session::cstore::DllImport; -struct ArchiveConfig<'a> { - sess: &'a Session, - use_native_ar: bool, - use_gnu_style_archive: bool, -} - -#[derive(Debug)] -enum ArchiveEntry { - FromArchive { - archive_index: usize, - entry_index: usize, - }, - File(PathBuf), -} - -pub struct ArArchiveBuilderBuilder; +pub(crate) struct ArArchiveBuilderBuilder; impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box + 'a> { - let config = ArchiveConfig { - sess, - use_native_ar: false, - // FIXME test for linux and System V derivatives instead - use_gnu_style_archive: sess.target.options.archive_format == "gnu", - }; - - Box::new(ArArchiveBuilder { - config, - src_archives: vec![], - entries: vec![], - }) + Box::new(ArArchiveBuilder::new(sess, get_native_object_symbols)) } fn create_dll_import_lib( @@ -49,144 +22,6 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { _tmpdir: &Path, _is_direct_dependency: bool, ) -> PathBuf { - unimplemented!(); - } -} - -pub struct ArArchiveBuilder<'a> { - config: ArchiveConfig<'a>, - src_archives: Vec<(PathBuf, ar::Archive)>, - // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at - // the end of an archive for linkers to not get confused. - entries: Vec<(String, ArchiveEntry)>, -} - -impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { - fn add_file(&mut self, file: &Path) { - self.entries.push(( - file.file_name().unwrap().to_str().unwrap().to_string(), - ArchiveEntry::File(file.to_owned()), - )); - } - - fn add_archive( - &mut self, - archive_path: &Path, - mut skip: Box bool + 'static>, - ) -> std::io::Result<()> { - let mut archive = ar::Archive::new(std::fs::File::open(&archive_path)?); - let archive_index = self.src_archives.len(); - - let mut i = 0; - while let Some(entry) = archive.next_entry() { - let entry = entry?; - let file_name = String::from_utf8(entry.header().identifier().to_vec()) - .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?; - if !skip(&file_name) { - self.entries - .push((file_name, ArchiveEntry::FromArchive { archive_index, entry_index: i })); - } - i += 1; - } - - self.src_archives.push((archive_path.to_owned(), archive)); - Ok(()) - } - - fn build(mut self: Box, output: &Path) -> bool { - use std::process::Command; - - fn add_file_using_ar(archive: &Path, file: &Path) { - Command::new("ar") - .arg("r") // add or replace file - .arg("-c") // silence created file message - .arg(archive) - .arg(&file) - .status() - .unwrap(); - } - - enum BuilderKind<'a> { - Bsd(ar::Builder), - Gnu(ar::GnuBuilder), - NativeAr(&'a Path), - } - - let mut builder = if self.config.use_native_ar { - BuilderKind::NativeAr(output) - } else if self.config.use_gnu_style_archive { - BuilderKind::Gnu(ar::GnuBuilder::new( - File::create(output).unwrap(), - self.entries - .iter() - .map(|(name, _)| name.as_bytes().to_vec()) - .collect(), - )) - } else { - BuilderKind::Bsd(ar::Builder::new(File::create(output).unwrap())) - }; - - let any_members = !self.entries.is_empty(); - - // Add all files - for (entry_name, entry) in self.entries.into_iter() { - match entry { - ArchiveEntry::FromArchive { - archive_index, - entry_index, - } => { - let (ref src_archive_path, ref mut src_archive) = - self.src_archives[archive_index]; - let entry = src_archive.jump_to_entry(entry_index).unwrap(); - let header = entry.header().clone(); - - match builder { - BuilderKind::Bsd(ref mut builder) => { - builder.append(&header, entry).unwrap() - } - BuilderKind::Gnu(ref mut builder) => { - builder.append(&header, entry).unwrap() - } - BuilderKind::NativeAr(archive_file) => { - Command::new("ar") - .arg("x") - .arg(src_archive_path) - .arg(&entry_name) - .status() - .unwrap(); - add_file_using_ar(archive_file, Path::new(&entry_name)); - std::fs::remove_file(entry_name).unwrap(); - } - } - } - ArchiveEntry::File(file) => - match builder { - BuilderKind::Bsd(ref mut builder) => { - builder - .append_file(entry_name.as_bytes(), &mut File::open(file).expect("file for bsd builder")) - .unwrap() - }, - BuilderKind::Gnu(ref mut builder) => { - builder - .append_file(entry_name.as_bytes(), &mut File::open(&file).expect(&format!("file {:?} for gnu builder", file))) - .unwrap() - }, - BuilderKind::NativeAr(archive_file) => add_file_using_ar(archive_file, &file), - }, - } - } - - // Finalize archive - std::mem::drop(builder); - - // Run ranlib to be able to link the archive - let status = - std::process::Command::new("ranlib").arg(output).status().expect("Couldn't run ranlib"); - - if !status.success() { - self.config.sess.emit_fatal(RanlibFailure::new(status.code())); - } - - any_members + unimplemented!("creating dll imports is not yet supported"); } } diff --git a/src/errors.rs b/src/errors.rs index 15ad90f9043c0..89fed7be13156 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -16,18 +16,6 @@ impl IntoDiagnosticArg for ExitCode { } } -#[derive(Diagnostic)] -#[diag(codegen_gcc_ranlib_failure)] -pub(crate) struct RanlibFailure { - exit_code: ExitCode, -} - -impl RanlibFailure { - pub fn new(exit_code: Option) -> Self { - RanlibFailure { exit_code: ExitCode(exit_code) } - } -} - #[derive(Diagnostic)] #[diag(codegen_gcc_invalid_monomorphization_basic_integer, code = "E0511")] pub(crate) struct InvalidMonomorphizationBasicInteger<'a> { @@ -227,7 +215,7 @@ pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> { #[diag(codegen_gcc_linkage_const_or_mut_type)] pub(crate) struct LinkageConstOrMutType { #[primary_span] - pub span: Span + pub span: Span, } #[derive(Diagnostic)] @@ -238,5 +226,5 @@ pub(crate) struct LTONotSupported; #[diag(codegen_gcc_unwinding_inline_asm)] pub(crate) struct UnwindingInlineAsm { #[primary_span] - pub span: Span + pub span: Span, } From 38dfdee36a19e58c6de61ba4792931596a233a6c Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 27 Nov 2022 11:15:06 +0000 Subject: [PATCH 049/465] Prefer doc comments over `//`-comments in compiler --- src/context.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/context.rs b/src/context.rs index 2e71c3665daa7..837708aeb0ea9 100644 --- a/src/context.rs +++ b/src/context.rs @@ -88,9 +88,9 @@ pub struct CodegenCx<'gcc, 'tcx> { pub vtables: RefCell, Option>), RValue<'gcc>>>, // TODO(antoyo): improve the SSA API to not require those. - // Mapping from function pointer type to indexes of on stack parameters. + /// Mapping from function pointer type to indexes of on stack parameters. pub on_stack_params: RefCell, FxHashSet>>, - // Mapping from function to indexes of on stack parameters. + /// Mapping from function to indexes of on stack parameters. pub on_stack_function_params: RefCell, FxHashSet>>, /// Cache of emitted const globals (value -> global) From 213ced1c43afaec00bd7b532e7b0aa25b205336e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 3 Dec 2022 18:27:18 +0000 Subject: [PATCH 050/465] Destruct landing_pad return value before passing it to cg_ssa --- src/builder.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 782f6856654a6..effb2de482751 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1119,18 +1119,18 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // TODO(antoyo) } - fn cleanup_landing_pad(&mut self, _ty: Type<'gcc>, _pers_fn: RValue<'gcc>) -> RValue<'gcc> { - let field1 = self.context.new_field(None, self.u8_type.make_pointer(), "landing_pad_field_1"); - let field2 = self.context.new_field(None, self.i32_type, "landing_pad_field_1"); - let struct_type = self.context.new_struct_type(None, "landing_pad", &[field1, field2]); - self.current_func().new_local(None, struct_type.as_type(), "landing_pad") - .to_rvalue() + fn cleanup_landing_pad(&mut self, _pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { + ( + self.current_func().new_local(None, self.u8_type.make_pointer(), "landing_pad0") + .to_rvalue(), + self.current_func().new_local(None, self.i32_type, "landing_pad1").to_rvalue(), + ) // TODO(antoyo): Properly implement unwinding. // the above is just to make the compilation work as it seems // rustc_codegen_ssa now calls the unwinding builder methods even on panic=abort. } - fn resume(&mut self, _exn: RValue<'gcc>) { + fn resume(&mut self, _exn0: RValue<'gcc>, _exn1: RValue<'gcc>) { // TODO(bjorn3): Properly implement unwinding. self.unreachable(); } From 6181cb2929890000dc63a3b59e60ff62b98770f9 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Wed, 23 Nov 2022 18:13:30 -0800 Subject: [PATCH 051/465] Move linkage type check to HIR analysis and fix semantics issues. This ensures that the error is printed even for unused variables, as well as unifying the handling between the LLVM and GCC backends. This also fixes unusual behavior around exported Rust-defined variables with linkage attributes. With the previous behavior, it appears to be impossible to define such a variable such that it can actually be imported and used by another crate. This is because on the importing side, the variable is required to be a pointer, but on the exporting side, the type checker rejects static variables of pointer type because they do not implement `Sync`. Even if it were possible to import such a type, it appears that code generation on the importing side would add an unexpected additional level of pointer indirection, which would break type safety. This highlighted that the semantics of linkage on Rust-defined variables is different to linkage on foreign items. As such, we now model the difference with two different codegen attributes: linkage for Rust-defined variables, and import_linkage for foreign items. This change gives semantics to the test src/test/ui/linkage-attr/auxiliary/def_illtyped_external.rs which was previously expected to fail to compile. Therefore, convert it into a test that is expected to successfully compile. The update to the GCC backend is speculative and untested. --- src/consts.rs | 27 ++++++--------------------- src/errors.rs | 7 ------- 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/src/consts.rs b/src/consts.rs index 111bfeb132203..ea8ab76114604 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -8,13 +8,11 @@ use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::mir::interpret::{self, ConstAllocation, ErrorHandled, Scalar as InterpScalar, read_target_uint}; -use rustc_span::Span; use rustc_span::def_id::DefId; use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRange}; use crate::base; use crate::context::CodegenCx; -use crate::errors::LinkageConstOrMutType; use crate::type_of::LayoutGccExt; impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { @@ -239,12 +237,12 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } Node::ForeignItem(&hir::ForeignItem { - span, + span: _, kind: hir::ForeignItemKind::Static(..), .. }) => { let fn_attrs = self.tcx.codegen_fn_attrs(def_id); - check_and_apply_linkage(&self, &fn_attrs, ty, sym, span) + check_and_apply_linkage(&self, &fn_attrs, ty, sym) } item => bug!("get_static: expected static, found {:?}", item), @@ -257,8 +255,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { //debug!("get_static: sym={} item_attr={:?}", sym, self.tcx.item_attrs(def_id)); let attrs = self.tcx.codegen_fn_attrs(def_id); - let span = self.tcx.def_span(def_id); - let global = check_and_apply_linkage(&self, &attrs, ty, sym, span); + let global = check_and_apply_linkage(&self, &attrs, ty, sym); let needs_dll_storage_attr = false; // TODO(antoyo) @@ -355,24 +352,12 @@ pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id Ok((const_alloc_to_gcc(cx, alloc), alloc)) } -fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &CodegenFnAttrs, ty: Ty<'tcx>, sym: &str, span: Span) -> LValue<'gcc> { +fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &CodegenFnAttrs, ty: Ty<'tcx>, sym: &str) -> LValue<'gcc> { let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); let llty = cx.layout_of(ty).gcc_type(cx, true); - if let Some(linkage) = attrs.linkage { - // If this is a static with a linkage specified, then we need to handle - // it a little specially. The typesystem prevents things like &T and - // extern "C" fn() from being non-null, so we can't just declare a - // static and call it a day. Some linkages (like weak) will make it such - // that the static actually has a null value. - let llty2 = - if let ty::RawPtr(ref mt) = ty.kind() { - cx.layout_of(mt.ty).gcc_type(cx, true) - } - else { - cx.sess().emit_fatal(LinkageConstOrMutType { span: span }) - }; + if let Some(linkage) = attrs.import_linkage { // Declare a symbol `foo` with the desired linkage. - let global1 = cx.declare_global_with_linkage(&sym, llty2, base::global_linkage_to_gcc(linkage)); + let global1 = cx.declare_global_with_linkage(&sym, cx.type_i8(), base::global_linkage_to_gcc(linkage)); // Declare an internal global `extern_with_linkage_foo` which // is initialized with the address of `foo`. If `foo` is diff --git a/src/errors.rs b/src/errors.rs index 89fed7be13156..d0ba7e2479111 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -211,13 +211,6 @@ pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> { pub in_elem: Ty<'a>, } -#[derive(Diagnostic)] -#[diag(codegen_gcc_linkage_const_or_mut_type)] -pub(crate) struct LinkageConstOrMutType { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(codegen_gcc_lto_not_supported)] pub(crate) struct LTONotSupported; From d5f7c20ce569481b7b74e0932dea8528fe84509a Mon Sep 17 00:00:00 2001 From: Ramon de C Valle Date: Mon, 21 Nov 2022 21:29:00 -0800 Subject: [PATCH 052/465] Add LLVM KCFI support to the Rust compiler This commit adds LLVM Kernel Control Flow Integrity (KCFI) support to the Rust compiler. It initially provides forward-edge control flow protection for operating systems kernels for Rust-compiled code only by aggregating function pointers in groups identified by their return and parameter types. (See llvm/llvm-project@cff5bef.) Forward-edge control flow protection for C or C++ and Rust -compiled code "mixed binaries" (i.e., for when C or C++ and Rust -compiled code share the same virtual address space) will be provided in later work as part of this project by identifying C char and integer type uses at the time types are encoded (see Type metadata in the design document in the tracking issue #89653). LLVM KCFI can be enabled with -Zsanitizer=kcfi. Co-authored-by: bjorn3 <17426603+bjorn3@users.noreply.github.com> --- src/type_.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/type_.rs b/src/type_.rs index bdf7318ce48c9..89a415cdb36cd 100644 --- a/src/type_.rs +++ b/src/type_.rs @@ -300,4 +300,8 @@ impl<'gcc, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'gcc, 'tcx> { // Unsupported. self.context.new_rvalue_from_int(self.int_type, 0) } + + fn set_kcfi_type_metadata(&self, _function: RValue<'gcc>, _kcfi_typeid: u32) { + // Unsupported. + } } From ac4e9caaf5c683b59d3367b42e1cf8c19dff2472 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 25 Mar 2022 02:44:16 -0400 Subject: [PATCH 053/465] Add `round_ties_even` to `f32` and `f64` --- src/intrinsic/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 49be6c649e652..35e650c65a081 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -68,6 +68,8 @@ fn get_simple_intrinsic<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, name: Symbol) -> sym::nearbyintf64 => "nearbyint", sym::roundf32 => "roundf", sym::roundf64 => "round", + sym::roundevenf32 => "roundevenf", + sym::roundevenf64 => "roundeven", sym::abort => "abort", _ => return None, }; From b4e9ba5cf3dc785ea1cbb8ff871194729ccb826b Mon Sep 17 00:00:00 2001 From: Jeremy Stucki Date: Tue, 20 Dec 2022 22:10:40 +0100 Subject: [PATCH 054/465] rustc: Remove needless lifetimes --- src/base.rs | 2 +- src/common.rs | 2 +- src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/base.rs b/src/base.rs index 8f9f6f98faf81..d464bd3d12a07 100644 --- a/src/base.rs +++ b/src/base.rs @@ -52,7 +52,7 @@ pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType { } } -pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol, supports_128bit_integers: bool) -> (ModuleCodegen, u64) { +pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_integers: bool) -> (ModuleCodegen, u64) { let prof_timer = tcx.prof.generic_activity("codegen_module"); let start_time = Instant::now(); diff --git a/src/common.rs b/src/common.rs index aa1c271c31cb4..d7df1347121ae 100644 --- a/src/common.rs +++ b/src/common.rs @@ -44,7 +44,7 @@ pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> context.new_array_constructor(None, typ, &elements) } -pub fn type_is_pointer<'gcc>(typ: Type<'gcc>) -> bool { +pub fn type_is_pointer(typ: Type) -> bool { typ.get_pointee().is_some() } diff --git a/src/lib.rs b/src/lib.rs index b9600da5c39df..bf1da38312f7d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -161,7 +161,7 @@ impl ExtraBackendMethods for GccCodegenBackend { mods } - fn compile_codegen_unit<'tcx>(&self, tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (ModuleCodegen, u64) { + fn compile_codegen_unit(&self, tcx: TyCtxt<'_>, cgu_name: Symbol) -> (ModuleCodegen, u64) { base::compile_codegen_unit(tcx, cgu_name, *self.supports_128bit_integers.lock().expect("lock")) } From 2d09c9bc948031e2ee8661915513a000bdc594ac Mon Sep 17 00:00:00 2001 From: Jeremy Stucki Date: Tue, 20 Dec 2022 22:34:42 +0100 Subject: [PATCH 055/465] Add missing anonymous lifetime --- src/common.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common.rs b/src/common.rs index d7df1347121ae..0afc56b4494d3 100644 --- a/src/common.rs +++ b/src/common.rs @@ -44,7 +44,7 @@ pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> context.new_array_constructor(None, typ, &elements) } -pub fn type_is_pointer(typ: Type) -> bool { +pub fn type_is_pointer(typ: Type<'_>) -> bool { typ.get_pointee().is_some() } From 6e8a0136f1d5d9e7e2f7d6bf1f599975f8c0c4c2 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Sun, 1 Jan 2023 14:34:22 -0500 Subject: [PATCH 056/465] improve wording of `thread::park` docs --- library/std/src/thread/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index afa4e2fb16854..07662e90c52bc 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -891,10 +891,9 @@ pub fn sleep(dur: Duration) { /// performs the corresponding `Acquire` operation. Calls to `unpark` for the same /// thread form a [release sequence]. /// -/// Notice that being unblocked does not imply any synchronization with someone that -/// unparked this thread, it could also be spurious. For example, it would be a valid, -/// but inefficient, implementation to make both park and unpark return immediately -/// without doing anything. +/// Note that being unblocked does not imply synchronization with a call to `unpark`, +/// the wakeup could also be spurious. For example, a valid, but inefficient, +/// implementation could have `park` and `unpark` return immediately without doing anything. /// /// # Examples /// From 26c010c941975b439ec366d0744061c2221d7c07 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 10 Dec 2022 20:31:01 +0000 Subject: [PATCH 057/465] Simplify some iterator combinators --- src/builder.rs | 2 +- src/context.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index effb2de482751..a92242b2615c1 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1244,7 +1244,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { ) -> RValue<'gcc> { // FIXME(antoyo): remove when having a proper API. let gcc_func = unsafe { std::mem::transmute(func) }; - let call = if self.functions.borrow().values().find(|value| **value == gcc_func).is_some() { + let call = if self.functions.borrow().values().any(|value| *value == gcc_func) { self.function_call(func, args, funclet) } else { diff --git a/src/context.rs b/src/context.rs index 837708aeb0ea9..4424b31c0542c 100644 --- a/src/context.rs +++ b/src/context.rs @@ -253,7 +253,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { pub fn rvalue_as_function(&self, value: RValue<'gcc>) -> Function<'gcc> { let function: Function<'gcc> = unsafe { std::mem::transmute(value) }; - debug_assert!(self.functions.borrow().values().find(|value| **value == function).is_some(), + debug_assert!(self.functions.borrow().values().any(|value| *value == function), "{:?} ({:?}) is not a function", value, value.get_type()); function } From 2671f378bcb846c4183abf783cd308ea4d7e4435 Mon Sep 17 00:00:00 2001 From: Albert Larsan <74931857+albertlarsan68@users.noreply.github.com> Date: Thu, 5 Jan 2023 09:45:44 +0100 Subject: [PATCH 058/465] Change `src/test` to `tests` in source files, fix tidy and tests --- test.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test.sh b/test.sh index 8b390f95a4b9b..c5ffb763673d2 100755 --- a/test.sh +++ b/test.sh @@ -253,25 +253,25 @@ rustc = "$HOME/.rustup/toolchains/$rust_toolchain-$TARGET_TRIPLE/bin/rustc" EOF rustc -V | cut -d' ' -f3 | tr -d '(' - git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(') src/test + git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(') tests - for test in $(rg -i --files-with-matches "//(\[\w+\])?~|// error-pattern:|// build-fail|// run-fail|-Cllvm-args" src/test/ui); do + for test in $(rg -i --files-with-matches "//(\[\w+\])?~|// error-pattern:|// build-fail|// run-fail|-Cllvm-args" tests/ui); do rm $test done - git checkout -- src/test/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed + git checkout -- tests/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed - rm -r src/test/ui/{abi*,extern/,panic-runtime/,panics/,unsized-locals/,proc-macro/,threads-sendsync/,thinlto/,borrowck/,test*,*lto*.rs} || true - for test in $(rg --files-with-matches "catch_unwind|should_panic|thread|lto" src/test/ui); do + rm -r tests/ui/{abi*,extern/,panic-runtime/,panics/,unsized-locals/,proc-macro/,threads-sendsync/,thinlto/,borrowck/,test*,*lto*.rs} || true + for test in $(rg --files-with-matches "catch_unwind|should_panic|thread|lto" tests/ui); do rm $test done - git checkout src/test/ui/type-alias-impl-trait/auxiliary/cross_crate_ice.rs - git checkout src/test/ui/type-alias-impl-trait/auxiliary/cross_crate_ice2.rs + git checkout tests/ui/type-alias-impl-trait/auxiliary/cross_crate_ice.rs + git checkout tests/ui/type-alias-impl-trait/auxiliary/cross_crate_ice2.rs RUSTC_ARGS="-Zpanic-abort-tests -Csymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot -Cpanic=abort" echo "[TEST] rustc test suite" - COMPILETEST_FORCE_STAGE0=1 ./x.py test --run always --stage 0 src/test/ui/ --rustc-args "$RUSTC_ARGS" + COMPILETEST_FORCE_STAGE0=1 ./x.py test --run always --stage 0 tests/ui/ --rustc-args "$RUSTC_ARGS" } function clean_ui_tests() { From 80d196d789fdd9adb43b474d9a3a74af4633937f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 11 Jan 2023 22:25:29 +0100 Subject: [PATCH 059/465] Update rustfmt for ast::ExprKind::FormatArgs. Rustfmt doesn't expand macros, so that's easy: FormatArgs nodes do not occur in the unexpanded AST. --- src/expr.rs | 5 ++++- src/utils.rs | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/expr.rs b/src/expr.rs index 414e767690bd0..cdbdcedd58fea 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -399,7 +399,10 @@ pub(crate) fn format_expr( } } ast::ExprKind::Underscore => Some("_".to_owned()), - ast::ExprKind::IncludedBytes(..) => unreachable!(), + ast::ExprKind::FormatArgs(..) | ast::ExprKind::IncludedBytes(..) => { + // These do not occur in the AST because macros aren't expanded. + unreachable!() + } ast::ExprKind::Err => None, }; diff --git a/src/utils.rs b/src/utils.rs index 3e884419f1a32..80dce525e3957 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -462,6 +462,7 @@ pub(crate) fn first_line_ends_with(s: &str, c: char) -> bool { pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr: &str) -> bool { match expr.kind { ast::ExprKind::MacCall(..) + | ast::ExprKind::FormatArgs(..) | ast::ExprKind::Call(..) | ast::ExprKind::MethodCall(..) | ast::ExprKind::Array(..) From 2791cc37e6f882f8ab7fa6c234885be652f930c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 15 Jan 2023 22:36:46 +0000 Subject: [PATCH 060/465] Teach parser to understand fake anonymous enum syntax Parse `-> Ty | OtherTy`. Parse type ascription in top level patterns. --- src/types.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/types.rs b/src/types.rs index c1991e8d2c808..f065ec680d724 100644 --- a/src/types.rs +++ b/src/types.rs @@ -839,7 +839,9 @@ impl Rewrite for ast::Ty { }) } ast::TyKind::CVarArgs => Some("...".to_owned()), - ast::TyKind::Err => Some(context.snippet(self.span).to_owned()), + ast::TyKind::AnonEnum(_) | ast::TyKind::Err => { + Some(context.snippet(self.span).to_owned()) + } ast::TyKind::Typeof(ref anon_const) => rewrite_call( context, "typeof", From 559b57e50a904e61ee43124f5032e1a03a5f2506 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 22 Jan 2023 23:03:58 -0500 Subject: [PATCH 061/465] abi: add `AddressSpace` field to `Primitive::Pointer` ...and remove it from `PointeeInfo`, which isn't meant for this. There are still various places (marked with FIXMEs) that assume all pointers have the same size and alignment. Fixing this requires parsing non-default address spaces in the data layout string, which will be done in a followup. --- src/builder.rs | 2 +- src/common.rs | 2 +- src/consts.rs | 16 ++++++++++++---- src/type_of.rs | 4 ++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index a92242b2615c1..e88c12716ecd3 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -709,7 +709,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { bx.range_metadata(load, vr); } } - abi::Pointer if vr.start < vr.end && !vr.contains(0) => { + abi::Pointer(_) if vr.start < vr.end && !vr.contains(0) => { bx.nonnull_metadata(load); } _ => {} diff --git a/src/common.rs b/src/common.rs index 0afc56b4494d3..c939da9cec3c2 100644 --- a/src/common.rs +++ b/src/common.rs @@ -211,7 +211,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let base_addr = self.const_bitcast(base_addr, self.usize_type); let offset = self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64); let ptr = self.const_bitcast(base_addr + offset, ptr_type); - if layout.primitive() != Pointer { + if !matches!(layout.primitive(), Pointer(_)) { self.const_bitcast(ptr.dereference(None).to_rvalue(), ty) } else { diff --git a/src/consts.rs b/src/consts.rs index ea8ab76114604..ba64b1f638942 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -7,9 +7,9 @@ use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs} use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::mir::interpret::{self, ConstAllocation, ErrorHandled, Scalar as InterpScalar, read_target_uint}; +use rustc_middle::mir::interpret::{self, ConstAllocation, ErrorHandled, GlobalAlloc, Scalar as InterpScalar, read_target_uint}; use rustc_span::def_id::DefId; -use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRange}; +use rustc_target::abi::{self, AddressSpace, Align, HasDataLayout, Primitive, Size, WrappingRange}; use crate::base; use crate::context::CodegenCx; @@ -322,13 +322,21 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl ) .expect("const_alloc_to_llvm: could not read relocation pointer") as u64; + + let address_space = match cx.tcx.global_alloc(alloc_id) { + GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space, + GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => { + AddressSpace::DATA + } + }; + llvals.push(cx.scalar_to_backend( InterpScalar::from_pointer( interpret::Pointer::new(alloc_id, Size::from_bytes(ptr_offset)), &cx.tcx, ), - abi::Scalar::Initialized { value: Primitive::Pointer, valid_range: WrappingRange::full(dl.pointer_size) }, - cx.type_i8p(), + abi::Scalar::Initialized { value: Primitive::Pointer(address_space), valid_range: WrappingRange::full(dl.pointer_size) }, + cx.type_i8p_ext(address_space), )); next_offset = offset + pointer_size; } diff --git a/src/type_of.rs b/src/type_of.rs index 524d10fb5e24d..1326af670cde4 100644 --- a/src/type_of.rs +++ b/src/type_of.rs @@ -253,7 +253,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { Int(i, false) => cx.type_from_unsigned_integer(i), F32 => cx.type_f32(), F64 => cx.type_f64(), - Pointer => { + Pointer(address_space) => { // If we know the alignment, pick something better than i8. let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) { @@ -262,7 +262,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { else { cx.type_i8() }; - cx.type_ptr_to(pointee) + cx.type_ptr_to_ext(pointee, address_space) } } } From 4e3ed18e1d3724f223bbdec5593263653b7158e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 23 Jan 2023 14:29:53 +0000 Subject: [PATCH 062/465] review comment: Remove AST AnonTy --- src/types.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/types.rs b/src/types.rs index f065ec680d724..c1991e8d2c808 100644 --- a/src/types.rs +++ b/src/types.rs @@ -839,9 +839,7 @@ impl Rewrite for ast::Ty { }) } ast::TyKind::CVarArgs => Some("...".to_owned()), - ast::TyKind::AnonEnum(_) | ast::TyKind::Err => { - Some(context.snippet(self.span).to_owned()) - } + ast::TyKind::Err => Some(context.snippet(self.span).to_owned()), ast::TyKind::Typeof(ref anon_const) => rewrite_call( context, "typeof", From 094b7f599cb1e3420021e496c72d9e1dd36043a0 Mon Sep 17 00:00:00 2001 From: Caleb Cartwright Date: Tue, 24 Jan 2023 14:16:03 -0600 Subject: [PATCH 063/465] Merge commit '1d8491b120223272b13451fc81265aa64f7f4d5b' into sync-from-rustfmt --- .github/workflows/check_diff.yml | 33 +++ .github/workflows/integration.yml | 4 - CHANGELOG.md | 28 ++- Cargo.lock | 4 +- Cargo.toml | 4 +- Configurations.md | 185 +++++++++++++++- Processes.md | 2 +- ci/build_and_test.bat | 1 + ci/build_and_test.sh | 1 + ci/check_diff.sh | 199 ++++++++++++++++++ ci/integration.sh | 18 +- config_proc_macro/Cargo.lock | 2 +- config_proc_macro/Cargo.toml | 2 +- config_proc_macro/src/attrs.rs | 27 ++- config_proc_macro/src/item_enum.rs | 40 +++- config_proc_macro/src/lib.rs | 13 ++ config_proc_macro/tests/smoke.rs | 1 + rust-toolchain | 4 +- src/attr.rs | 4 +- src/bin/main.rs | 2 +- src/cargo-fmt/main.rs | 12 +- src/cargo-fmt/test/mod.rs | 4 +- src/chains.rs | 120 ++++++++--- src/config/config_type.rs | 122 +++++++++-- src/config/macro_names.rs | 118 +++++++++++ src/config/mod.rs | 149 ++++++++++++- src/expr.rs | 9 +- src/imports.rs | 4 +- src/items.rs | 10 +- src/lists.rs | 16 +- src/macros.rs | 18 +- src/skip.rs | 79 +++++-- src/test/configuration_snippet.rs | 7 +- src/test/mod.rs | 6 +- src/types.rs | 44 +++- src/utils.rs | 5 +- src/visitor.rs | 13 +- tests/cargo-fmt/main.rs | 29 ++- tests/cargo-fmt/source/issue_3164/Cargo.toml | 8 + tests/cargo-fmt/source/issue_3164/src/main.rs | 13 ++ tests/config/small_tabs.toml | 2 +- .../issue-5198/lib/c/d/explanation.txt | 2 +- .../issue-5198/lib/explanation.txt | 2 +- tests/rustfmt/main.rs | 21 +- tests/source/cfg_if/detect/arch/x86.rs | 2 +- tests/source/comments_unicode.rs | 140 ++++++++++++ .../compressed.rs | 2 +- .../tall.rs | 2 +- .../vertical.rs | 2 +- tests/source/enum.rs | 2 +- tests/source/fn-custom-7.rs | 2 +- tests/source/fn-custom.rs | 2 +- tests/source/fn_args_layout-vertical.rs | 2 +- .../issue-3987/format_macro_bodies_true.rs | 26 +++ tests/source/issue-4643.rs | 23 ++ tests/source/issue-4689/one.rs | 149 +++++++++++++ tests/source/issue-4689/two.rs | 149 +++++++++++++ tests/source/issue_1306.rs | 29 +++ tests/source/issue_3245.rs | 4 + tests/source/issue_3561.rs | 6 + tests/source/skip_macro_invocations/all.rs | 11 + .../skip_macro_invocations/all_and_name.rs | 11 + tests/source/skip_macro_invocations/empty.rs | 11 + tests/source/skip_macro_invocations/name.rs | 11 + .../skip_macro_invocations/name_unknown.rs | 6 + tests/source/skip_macro_invocations/names.rs | 16 ++ .../path_qualified_invocation_mismatch.rs | 6 + .../path_qualified_match.rs | 6 + .../path_qualified_name_mismatch.rs | 6 + .../use_alias_examples.rs | 32 +++ tests/source/tuple.rs | 2 +- ...ts_should_not_imply_format_doc_comments.rs | 2 +- tests/target/cfg_if/detect/arch/x86.rs | 2 +- tests/target/comments_unicode.rs | 140 ++++++++++++ .../compressed.rs | 2 +- .../tall.rs | 2 +- .../vertical.rs | 2 +- tests/target/enum.rs | 2 +- tests/target/fn-custom-7.rs | 2 +- tests/target/fn-custom.rs | 2 +- tests/target/fn_args_layout-vertical.rs | 2 +- .../issue-2534/format_macro_matchers_false.rs | 6 + .../issue-2534/format_macro_matchers_true.rs | 6 + .../issue-3987/format_macro_bodies_false.rs | 26 +++ .../issue-3987/format_macro_bodies_true.rs | 21 ++ tests/target/issue-4643.rs | 19 ++ tests/target/issue-4689/one.rs | 150 +++++++++++++ tests/target/issue-4689/two.rs | 152 +++++++++++++ tests/target/issue-4791/issue_4928.rs | 2 +- tests/target/issue-5358.rs | 4 + tests/target/issue_1306.rs | 33 +++ tests/target/issue_3033.rs | 2 + tests/target/issue_3245.rs | 4 + tests/target/issue_3561.rs | 7 + tests/target/issue_4350.rs | 13 ++ tests/target/issue_5668.rs | 8 + tests/target/skip_macro_invocations/all.rs | 11 + .../skip_macro_invocations/all_and_name.rs | 11 + tests/target/skip_macro_invocations/empty.rs | 11 + tests/target/skip_macro_invocations/name.rs | 11 + .../skip_macro_invocations/name_unknown.rs | 6 + tests/target/skip_macro_invocations/names.rs | 16 ++ .../path_qualified_invocation_mismatch.rs | 6 + .../path_qualified_match.rs | 6 + .../path_qualified_name_mismatch.rs | 6 + .../use_alias_examples.rs | 32 +++ tests/target/tuple.rs | 2 +- ...ts_should_not_imply_format_doc_comments.rs | 2 +- 108 files changed, 2591 insertions(+), 187 deletions(-) create mode 100644 .github/workflows/check_diff.yml create mode 100755 ci/check_diff.sh create mode 100644 src/config/macro_names.rs create mode 100644 tests/cargo-fmt/source/issue_3164/Cargo.toml create mode 100644 tests/cargo-fmt/source/issue_3164/src/main.rs create mode 100644 tests/source/comments_unicode.rs rename tests/source/configs/{fn_args_layout => fn_params_layout}/compressed.rs (92%) rename tests/source/configs/{fn_args_layout => fn_params_layout}/tall.rs (93%) rename tests/source/configs/{fn_args_layout => fn_params_layout}/vertical.rs (92%) create mode 100644 tests/source/issue-3987/format_macro_bodies_true.rs create mode 100644 tests/source/issue-4643.rs create mode 100644 tests/source/issue-4689/one.rs create mode 100644 tests/source/issue-4689/two.rs create mode 100644 tests/source/issue_1306.rs create mode 100644 tests/source/issue_3245.rs create mode 100644 tests/source/issue_3561.rs create mode 100644 tests/source/skip_macro_invocations/all.rs create mode 100644 tests/source/skip_macro_invocations/all_and_name.rs create mode 100644 tests/source/skip_macro_invocations/empty.rs create mode 100644 tests/source/skip_macro_invocations/name.rs create mode 100644 tests/source/skip_macro_invocations/name_unknown.rs create mode 100644 tests/source/skip_macro_invocations/names.rs create mode 100644 tests/source/skip_macro_invocations/path_qualified_invocation_mismatch.rs create mode 100644 tests/source/skip_macro_invocations/path_qualified_match.rs create mode 100644 tests/source/skip_macro_invocations/path_qualified_name_mismatch.rs create mode 100644 tests/source/skip_macro_invocations/use_alias_examples.rs create mode 100644 tests/target/comments_unicode.rs rename tests/target/configs/{fn_args_layout => fn_params_layout}/compressed.rs (92%) rename tests/target/configs/{fn_args_layout => fn_params_layout}/tall.rs (94%) rename tests/target/configs/{fn_args_layout => fn_params_layout}/vertical.rs (94%) create mode 100644 tests/target/issue-2534/format_macro_matchers_false.rs create mode 100644 tests/target/issue-2534/format_macro_matchers_true.rs create mode 100644 tests/target/issue-3987/format_macro_bodies_false.rs create mode 100644 tests/target/issue-3987/format_macro_bodies_true.rs create mode 100644 tests/target/issue-4643.rs create mode 100644 tests/target/issue-4689/one.rs create mode 100644 tests/target/issue-4689/two.rs create mode 100644 tests/target/issue-5358.rs create mode 100644 tests/target/issue_1306.rs create mode 100644 tests/target/issue_3033.rs create mode 100644 tests/target/issue_3245.rs create mode 100644 tests/target/issue_3561.rs create mode 100644 tests/target/issue_4350.rs create mode 100644 tests/target/issue_5668.rs create mode 100644 tests/target/skip_macro_invocations/all.rs create mode 100644 tests/target/skip_macro_invocations/all_and_name.rs create mode 100644 tests/target/skip_macro_invocations/empty.rs create mode 100644 tests/target/skip_macro_invocations/name.rs create mode 100644 tests/target/skip_macro_invocations/name_unknown.rs create mode 100644 tests/target/skip_macro_invocations/names.rs create mode 100644 tests/target/skip_macro_invocations/path_qualified_invocation_mismatch.rs create mode 100644 tests/target/skip_macro_invocations/path_qualified_match.rs create mode 100644 tests/target/skip_macro_invocations/path_qualified_name_mismatch.rs create mode 100644 tests/target/skip_macro_invocations/use_alias_examples.rs diff --git a/.github/workflows/check_diff.yml b/.github/workflows/check_diff.yml new file mode 100644 index 0000000000000..8bfb5834519cd --- /dev/null +++ b/.github/workflows/check_diff.yml @@ -0,0 +1,33 @@ +name: Diff Check +on: + workflow_dispatch: + inputs: + clone_url: + description: 'Git url of a rustfmt fork to compare against the latest master rustfmt' + required: true + branch_name: + description: 'Name of the feature branch on the forked repo' + required: true + commit_hash: + description: 'Optional commit hash from the feature branch' + required: false + rustfmt_configs: + description: 'Optional comma separated list of rustfmt config options to pass when running the feature branch' + required: false + +jobs: + diff_check: + runs-on: ubuntu-latest + + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: install rustup + run: | + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh + sh rustup-init.sh -y --default-toolchain none + rustup target add x86_64-unknown-linux-gnu + + - name: check diff + run: bash ${GITHUB_WORKSPACE}/ci/check_diff.sh ${{ github.event.inputs.clone_url }} ${{ github.event.inputs.branch_name }} ${{ github.event.inputs.commit_hash }} ${{ github.event.inputs.rustfmt_configs }} diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 4d8899b434bbe..314ce0e84c61b 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -27,7 +27,6 @@ jobs: tempdir, futures-rs, rust-clippy, - failure, ] include: # Allowed Failures @@ -63,9 +62,6 @@ jobs: # Original comment was: temporal build failure due to breaking changes in the nightly compiler - integration: rust-semverver allow-failure: true - # Can be moved back to include section after https://github.com/rust-lang-nursery/failure/pull/298 is merged - - integration: failure - allow-failure: true steps: - name: checkout diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c1893bf8c387..60f961fa12ac8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,32 @@ ## [Unreleased] +## [1.5.2] 2023-01-24 + +### Fixed + +- Resolve issue when comments are found within const generic defaults in unit structs [#5668](https://github.com/rust-lang/rustfmt/issues/5668) +- Resolve issue when block comments are found within trait generics [#5358](https://github.com/rust-lang/rustfmt/issues/5358) +- Correctly handle alignment of comments containing unicode characters [#5504](https://github.com/rust-lang/rustfmt/issues/5504) +- Properly indent a single generic bound that requires being written across multiple lines [#4689](https://github.com/rust-lang/rustfmt/issues/4689) (n.b. this change is version gated and will only appear when the `version` configuration option is set to `Two`) + +### Changed + +- Renamed `fn_args_layout` configuration option to `fn_params_layout` [#4149](https://github.com/rust-lang/rustfmt/issues/4149). Note that `fn_args_layout` has only been soft deprecated: `fn_args_layout` will continue to work without issue, but rustfmt will display a warning to encourage users to switch to the new name + +### Added + +- New configuration option (`skip_macro_invocations`)[https://rust-lang.github.io/rustfmt/?version=master&search=#skip_macro_invocations] [#5347](https://github.com/rust-lang/rustfmt/pull/5347) that can be used to globally define a single enumerated list of macro calls that rustfmt should skip formatting. rustfmt [currently also supports this via a custom tool attribute](https://github.com/rust-lang/rustfmt#tips), however, these cannot be used in all contexts because [custom inner attributes are unstable](https://github.com/rust-lang/rust/issues/54726) + +### Misc + +- rustfmt now internally supports the ability to have both stable and unstable variants of a configuration option [#5378](https://github.com/rust-lang/rustfmt/issues/5378). This ability will allow the rustfmt team to make certain configuration options available on stable toolchains more quickly because we no longer have to wait for _every_ variant to be stable-ready before stabilizing _any_ variant. + +### Install/Download Options +- **rustup (nightly)** - nightly-2023-01-24 +- **GitHub Release Binaries** - [Release v1.5.2](https://github.com/rust-lang/rustfmt/releases/tag/v1.5.2) +- **Build from source** - [Tag v1.5.2](https://github.com/rust-lang/rustfmt/tree/v1.5.2), see instructions for how to [install rustfmt from source][install-from-source] + ## [1.5.1] 2022-06-24 **N.B** A bug was introduced in v1.5.0/nightly-2022-06-15 which modified formatting. If you happened to run rustfmt over your code with one of those ~10 nightlies it's possible you may have seen formatting changes, and you may see additional changes after this fix since that bug has now been reverted. @@ -840,7 +866,7 @@ from formatting an attribute #3665 - Fix formatting of raw string literals #2983 - Handle chain with try operators with spaces #2986 - Use correct shape in Visual tuple rewriting #2987 -- Impove formatting of arguments with `visual_style = "Visual"` option #2988 +- Improve formatting of arguments with `visual_style = "Visual"` option #2988 - Change `print_diff` to output the correct line number 992b179 - Propagate errors about failing to rewrite a macro 6f318e3 - Handle formatting of long function signature #3010 diff --git a/Cargo.lock b/Cargo.lock index 311df226da19d..24166d51c51fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -476,7 +476,7 @@ checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" [[package]] name = "rustfmt-config_proc_macro" -version = "0.2.0" +version = "0.3.0" dependencies = [ "proc-macro2", "quote", @@ -485,7 +485,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.5.1" +version = "1.5.2" dependencies = [ "annotate-snippets", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 7a4e02d69eddc..87ce59d0217e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustfmt-nightly" -version = "1.5.1" +version = "1.5.2" description = "Tool to find and fix Rust formatting issues" repository = "https://github.com/rust-lang/rustfmt" readme = "README.md" @@ -57,7 +57,7 @@ unicode-segmentation = "1.9" unicode-width = "0.1" unicode_categories = "0.1" -rustfmt-config_proc_macro = { version = "0.2", path = "config_proc_macro" } +rustfmt-config_proc_macro = { version = "0.3", path = "config_proc_macro" } # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` diff --git a/Configurations.md b/Configurations.md index 8b96b9d36892a..49e7e4e64892a 100644 --- a/Configurations.md +++ b/Configurations.md @@ -1,6 +1,6 @@ # Configuring Rustfmt -Rustfmt is designed to be very configurable. You can create a TOML file called `rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent directory and it will apply the options in that file. If none of these directories contain such a file, both your home directory and a directory called `rustfmt` in your [global config directory](https://docs.rs/dirs/1.0.4/dirs/fn.config_dir.html) (e.g. `.config/rustfmt/`) are checked as well. +Rustfmt is designed to be very configurable. You can create a TOML file called `rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent directory and it will apply the options in that file. If none of these directories contain such a file, both your home directory and a directory called `rustfmt` in your [global config directory](https://docs.rs/dirs/4.0.0/dirs/fn.config_dir.html) (e.g. `.config/rustfmt/`) are checked as well. A possible content of `rustfmt.toml` or `.rustfmt.toml` might look like this: @@ -425,7 +425,7 @@ fn example() { ## `comment_width` -Maximum length of comments. No effect unless`wrap_comments = true`. +Maximum length of comments. No effect unless `wrap_comments = true`. - **Default value**: `80` - **Possible values**: any positive integer @@ -589,7 +589,7 @@ doesn't get ignored when aligning. #### `0` (default): ```rust -enum Bar { +enum Foo { A = 0, Bb = 1, RandomLongVariantGoesHere = 10, @@ -645,7 +645,8 @@ trailing whitespaces. ## `fn_args_layout` -Control the layout of arguments in a function +This option is deprecated and has been renamed to `fn_params_layout` to better communicate that +it affects the layout of parameters in function signatures. - **Default value**: `"Tall"` - **Possible values**: `"Compressed"`, `"Tall"`, `"Vertical"` @@ -753,6 +754,8 @@ trait Lorem { } ``` +See also [`fn_params_layout`](#fn_params_layout) + ## `fn_call_width` Maximum width of the args of a function call before falling back to vertical formatting. @@ -765,6 +768,117 @@ By default this option is set as a percentage of [`max_width`](#max_width) provi See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics) +## `fn_params_layout` + +Control the layout of parameters in function signatures. + +- **Default value**: `"Tall"` +- **Possible values**: `"Compressed"`, `"Tall"`, `"Vertical"` +- **Stable**: Yes + +#### `"Tall"` (default): + +```rust +trait Lorem { + fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet); + + fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) { + // body + } + + fn lorem( + ipsum: Ipsum, + dolor: Dolor, + sit: Sit, + amet: Amet, + consectetur: Consectetur, + adipiscing: Adipiscing, + elit: Elit, + ); + + fn lorem( + ipsum: Ipsum, + dolor: Dolor, + sit: Sit, + amet: Amet, + consectetur: Consectetur, + adipiscing: Adipiscing, + elit: Elit, + ) { + // body + } +} +``` + +#### `"Compressed"`: + +```rust +trait Lorem { + fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet); + + fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) { + // body + } + + fn lorem( + ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: Consectetur, + adipiscing: Adipiscing, elit: Elit, + ); + + fn lorem( + ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: Consectetur, + adipiscing: Adipiscing, elit: Elit, + ) { + // body + } +} +``` + +#### `"Vertical"`: + +```rust +trait Lorem { + fn lorem( + ipsum: Ipsum, + dolor: Dolor, + sit: Sit, + amet: Amet, + ); + + fn lorem( + ipsum: Ipsum, + dolor: Dolor, + sit: Sit, + amet: Amet, + ) { + // body + } + + fn lorem( + ipsum: Ipsum, + dolor: Dolor, + sit: Sit, + amet: Amet, + consectetur: Consectetur, + adipiscing: Adipiscing, + elit: Elit, + ); + + fn lorem( + ipsum: Ipsum, + dolor: Dolor, + sit: Sit, + amet: Amet, + consectetur: Consectetur, + adipiscing: Adipiscing, + elit: Elit, + ) { + // body + } +} +``` + + ## `fn_single_line` Put single-expression functions on a single line @@ -1014,6 +1128,62 @@ macro_rules! foo { See also [`format_macro_matchers`](#format_macro_matchers). +## `skip_macro_invocations` + +Skip formatting the bodies of macro invocations with the following names. + +rustfmt will not format any macro invocation for macros with names set in this list. +Including the special value "*" will prevent any macro invocations from being formatted. + +Note: This option does not have any impact on how rustfmt formats macro definitions. + +- **Default value**: `[]` +- **Possible values**: a list of macro name idents, `["name_0", "name_1", ..., "*"]` +- **Stable**: No (tracking issue: [#5346](https://github.com/rust-lang/rustfmt/issues/5346)) + +#### `[]` (default): + +rustfmt will follow its standard approach to formatting macro invocations. + +No macro invocations will be skipped based on their name. More information about rustfmt's standard macro invocation formatting behavior can be found in [#5437](https://github.com/rust-lang/rustfmt/discussions/5437). + +```rust +lorem!( + const _: u8 = 0; +); + +ipsum!( + const _: u8 = 0; +); +``` + +#### `["lorem"]`: + +The named macro invocations will be skipped. + +```rust +lorem!( + const _: u8 = 0; +); + +ipsum!( + const _: u8 = 0; +); +``` + +#### `["*"]`: + +The special selector `*` will skip all macro invocations. + +```rust +lorem!( + const _: u8 = 0; +); + +ipsum!( + const _: u8 = 0; +); +``` ## `format_strings` @@ -1687,13 +1857,16 @@ pub enum Foo {} ## `imports_granularity` -How imports should be grouped into `use` statements. Imports will be merged or split to the configured level of granularity. +Controls how imports are structured in `use` statements. Imports will be merged or split to the configured level of granularity. + +Similar to other `import` related configuration options, this option operates within the bounds of user-defined groups of imports. See [`group_imports`](#group_imports) for more information on import groups. + +Note that rustfmt will not modify the granularity of imports containing comments if doing so could potentially lose or misplace said comments. - **Default value**: `Preserve` - **Possible values**: `Preserve`, `Crate`, `Module`, `Item`, `One` - **Stable**: No (tracking issue: [#4991](https://github.com/rust-lang/rustfmt/issues/4991)) -Note that rustfmt will not modify the granularity of imports containing comments if doing so could potentially lose or misplace said comments. #### `Preserve` (default): diff --git a/Processes.md b/Processes.md index f763b5714ce2c..61abc87eec9ff 100644 --- a/Processes.md +++ b/Processes.md @@ -2,7 +2,7 @@ This document outlines processes regarding management of rustfmt. # Stabilising an Option -In this Section, we describe how to stabilise an option of the rustfmt's configration. +In this Section, we describe how to stabilise an option of the rustfmt's configuration. ## Conditions diff --git a/ci/build_and_test.bat b/ci/build_and_test.bat index ef41017783feb..69dae1fff7b4d 100755 --- a/ci/build_and_test.bat +++ b/ci/build_and_test.bat @@ -1,4 +1,5 @@ set "RUSTFLAGS=-D warnings" +set "RUSTFMT_CI=1" :: Print version information rustc -Vv || exit /b 1 diff --git a/ci/build_and_test.sh b/ci/build_and_test.sh index 8fa0f67b0d021..94991853263ce 100755 --- a/ci/build_and_test.sh +++ b/ci/build_and_test.sh @@ -3,6 +3,7 @@ set -euo pipefail export RUSTFLAGS="-D warnings" +export RUSTFMT_CI=1 # Print version information rustc -Vv diff --git a/ci/check_diff.sh b/ci/check_diff.sh new file mode 100755 index 0000000000000..062c2dd8673ab --- /dev/null +++ b/ci/check_diff.sh @@ -0,0 +1,199 @@ +#!/bin/bash + +function print_usage() { + echo "usage check_diff REMOTE_REPO FEATURE_BRANCH [COMMIT_HASH] [OPTIONAL_RUSTFMT_CONFIGS]" +} + +if [ $# -le 1 ]; then + print_usage + exit 1 +fi + +REMOTE_REPO=$1 +FEATURE_BRANCH=$2 +OPTIONAL_COMMIT_HASH=$3 +OPTIONAL_RUSTFMT_CONFIGS=$4 + +# OUTPUT array used to collect all the status of running diffs on various repos +STATUSES=() + +# Clone a git repository and cd into it. +# +# Parameters: +# $1: git clone url +# $2: directory where the repo should be cloned +function clone_repo() { + GIT_TERMINAL_PROMPT=0 git clone --quiet $1 --depth 1 $2 && cd $2 +} + +# Initialize Git submoduels for the repo. +# +# Parameters +# $1: list of directories to initialize +function init_submodules() { + git submodule update --init $1 +} + +# Run rusfmt with the --check flag to see if a diff is produced. +# +# Parameters: +# $1: Path to a rustfmt binary +# $2: Output file path for the diff +# $3: Any additional configuration options to pass to rustfmt +# +# Globlas: +# $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4 +function create_diff() { + local config; + if [ -z "$3" ]; then + config="--config=error_on_line_overflow=false,error_on_unformatted=false" + else + config="--config=error_on_line_overflow=false,error_on_unformatted=false,$OPTIONAL_RUSTFMT_CONFIGS" + fi + + for i in `find . | grep "\.rs$"` + do + $1 --unstable-features --skip-children --check --color=always $config $i >> $2 2>/dev/null + done +} + +# Run the master rustfmt binary and the feature branch binary in the current directory and compare the diffs +# +# Parameters +# $1: Name of the repository (used for logging) +# +# Globlas: +# $RUSFMT_BIN: Path to the rustfmt master binary. Created when running `compile_rustfmt` +# $FEATURE_BIN: Path to the rustfmt feature binary. Created when running `compile_rustfmt` +# $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4 +function check_diff() { + echo "running rustfmt (master) on $1" + create_diff $RUSFMT_BIN rustfmt_diff.txt + + echo "running rustfmt (feature) on $1" + create_diff $FEATURE_BIN feature_diff.txt $OPTIONAL_RUSTFMT_CONFIGS + + echo "checking diff" + local diff; + # we don't add color to the diff since we added color when running rustfmt --check. + # tail -n + 6 removes the git diff header info + # cut -c 2- removes the leading diff characters("+","-"," ") from running git diff. + # Again, the diff output we care about was already added when we ran rustfmt --check + diff=$( + git --no-pager diff --color=never \ + --unified=0 --no-index rustfmt_diff.txt feature_diff.txt 2>&1 | tail -n +6 | cut -c 2- + ) + + if [ -z "$diff" ]; then + echo "no diff detected between rustfmt and the feture branch" + return 0 + else + echo "$diff" + return 1 + fi +} + +# Compiles and produces two rustfmt binaries. +# One for the current master, and another for the feature branch +# +# Parameters: +# $1: Directory where rustfmt will be cloned +# +# Globlas: +# $REMOTE_REPO: Clone URL to the rustfmt fork that we want to test +# $FEATURE_BRANCH: Name of the feature branch +# $OPTIONAL_COMMIT_HASH: Optional commit hash that will be checked out if provided +function compile_rustfmt() { + RUSTFMT_REPO="https://github.com/rust-lang/rustfmt.git" + clone_repo $RUSTFMT_REPO $1 + git remote add feature $REMOTE_REPO + git fetch feature $FEATURE_BRANCH + + cargo build --release --bin rustfmt && cp target/release/rustfmt $1/rustfmt + if [ -z "$OPTIONAL_COMMIT_HASH" ]; then + git switch $FEATURE_BRANCH + else + git switch $OPTIONAL_COMMIT_HASH --detach + fi + cargo build --release --bin rustfmt && cp target/release/rustfmt $1/feature_rustfmt + RUSFMT_BIN=$1/rustfmt + FEATURE_BIN=$1/feature_rustfmt +} + +# Check the diff for running rustfmt and the feature branch on all the .rs files in the repo. +# +# Parameters +# $1: Clone URL for the repo +# $2: Name of the repo (mostly used for logging) +# $3: Path to any submodules that should be initialized +function check_repo() { + WORKDIR=$(pwd) + REPO_URL=$1 + REPO_NAME=$2 + SUBMODULES=$3 + + local tmp_dir; + tmp_dir=$(mktemp -d -t $REPO_NAME-XXXXXXXX) + clone_repo $REPO_URL $tmp_dir + + if [ ! -z "$SUBMODULES" ]; then + init_submodules $SUBMODULES + fi + + check_diff $REPO_NAME + # append the status of running `check_diff` to the STATUSES array + STATUSES+=($?) + + echo "removing tmp_dir $tmp_dir" + rm -rf $tmp_dir + cd $WORKDIR +} + +function main() { + tmp_dir=$(mktemp -d -t rustfmt-XXXXXXXX) + echo Created tmp_dir $tmp_dir + + compile_rustfmt $tmp_dir + + # run checks + check_repo "https://github.com/rust-lang/rust.git" rust-lang-rust + check_repo "https://github.com/rust-lang/cargo.git" cargo + check_repo "https://github.com/rust-lang/miri.git" miri + check_repo "https://github.com/rust-lang/rust-analyzer.git" rust-analyzer + check_repo "https://github.com/bitflags/bitflags.git" bitflags + check_repo "https://github.com/rust-lang/log.git" log + check_repo "https://github.com/rust-lang/mdBook.git" mdBook + check_repo "https://github.com/rust-lang/packed_simd.git" packed_simd + check_repo "https://github.com/rust-lang/rust-semverver.git" check_repo + check_repo "https://github.com/Stebalien/tempfile.git" tempfile + check_repo "https://github.com/rust-lang/futures-rs.git" futures-rs + check_repo "https://github.com/dtolnay/anyhow.git" anyhow + check_repo "https://github.com/dtolnay/thiserror.git" thiserror + check_repo "https://github.com/dtolnay/syn.git" syn + check_repo "https://github.com/serde-rs/serde.git" serde + check_repo "https://github.com/rust-lang/rustlings.git" rustlings + check_repo "https://github.com/rust-lang/rustup.git" rustup + check_repo "https://github.com/SergioBenitez/Rocket.git" Rocket + check_repo "https://github.com/rustls/rustls.git" rustls + check_repo "https://github.com/rust-lang/rust-bindgen.git" rust-bindgen + check_repo "https://github.com/hyperium/hyper.git" hyper + check_repo "https://github.com/actix/actix.git" actix + check_repo "https://github.com/denoland/deno.git" denoland_deno + + # cleanup temp dir + echo removing tmp_dir $tmp_dir + rm -rf $tmp_dir + + # figure out the exit code + for status in ${STATUSES[@]} + do + if [ $status -eq 1 ]; then + echo "formatting diff found 💔" + return 1 + fi + done + + echo "no diff found 😊" +} + +main diff --git a/ci/integration.sh b/ci/integration.sh index 562d5d70c70ba..19d502bc5c7bd 100755 --- a/ci/integration.sh +++ b/ci/integration.sh @@ -91,14 +91,28 @@ case ${INTEGRATION} in cd - ;; crater) - git clone --depth=1 https://github.com/rust-lang-nursery/${INTEGRATION}.git + git clone --depth=1 https://github.com/rust-lang/${INTEGRATION}.git cd ${INTEGRATION} show_head check_fmt_with_lib_tests cd - ;; + bitflags) + git clone --depth=1 https://github.com/bitflags/${INTEGRATION}.git + cd ${INTEGRATION} + show_head + check_fmt_with_all_tests + cd - + ;; + error-chain | tempdir) + git clone --depth=1 https://github.com/rust-lang-deprecated/${INTEGRATION}.git + cd ${INTEGRATION} + show_head + check_fmt_with_all_tests + cd - + ;; *) - git clone --depth=1 https://github.com/rust-lang-nursery/${INTEGRATION}.git + git clone --depth=1 https://github.com/rust-lang/${INTEGRATION}.git cd ${INTEGRATION} show_head check_fmt_with_all_tests diff --git a/config_proc_macro/Cargo.lock b/config_proc_macro/Cargo.lock index ecf561f28fb6a..49f2f72a8d219 100644 --- a/config_proc_macro/Cargo.lock +++ b/config_proc_macro/Cargo.lock @@ -22,7 +22,7 @@ dependencies = [ [[package]] name = "rustfmt-config_proc_macro" -version = "0.2.0" +version = "0.3.0" dependencies = [ "proc-macro2", "quote", diff --git a/config_proc_macro/Cargo.toml b/config_proc_macro/Cargo.toml index a41b3a5e6bf88..d10d0469cc401 100644 --- a/config_proc_macro/Cargo.toml +++ b/config_proc_macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustfmt-config_proc_macro" -version = "0.2.0" +version = "0.3.0" edition = "2018" description = "A collection of procedural macros for rustfmt" license = "Apache-2.0/MIT" diff --git a/config_proc_macro/src/attrs.rs b/config_proc_macro/src/attrs.rs index 0baba046f9e91..dd18ff572cb1c 100644 --- a/config_proc_macro/src/attrs.rs +++ b/config_proc_macro/src/attrs.rs @@ -1,8 +1,10 @@ //! This module provides utilities for handling attributes on variants -//! of `config_type` enum. Currently there are two types of attributes -//! that could appear on the variants of `config_type` enum: `doc_hint` -//! and `value`. Both comes in the form of name-value pair whose value -//! is string literal. +//! of `config_type` enum. Currently there are the following attributes +//! that could appear on the variants of `config_type` enum: +//! +//! - `doc_hint`: name-value pair whose value is string literal +//! - `value`: name-value pair whose value is string literal +//! - `unstable_variant`: name only /// Returns the value of the first `doc_hint` attribute in the given slice or /// `None` if `doc_hint` attribute is not available. @@ -27,6 +29,11 @@ pub fn find_config_value(attrs: &[syn::Attribute]) -> Option { attrs.iter().filter_map(config_value).next() } +/// Returns `true` if the there is at least one `unstable` attribute in the given slice. +pub fn any_unstable_variant(attrs: &[syn::Attribute]) -> bool { + attrs.iter().any(is_unstable_variant) +} + /// Returns a string literal value if the given attribute is `value` /// attribute or `None` otherwise. pub fn config_value(attr: &syn::Attribute) -> Option { @@ -38,6 +45,11 @@ pub fn is_config_value(attr: &syn::Attribute) -> bool { is_attr_name_value(attr, "value") } +/// Returns `true` if the given attribute is an `unstable` attribute. +pub fn is_unstable_variant(attr: &syn::Attribute) -> bool { + is_attr_path(attr, "unstable_variant") +} + fn is_attr_name_value(attr: &syn::Attribute, name: &str) -> bool { attr.parse_meta().ok().map_or(false, |meta| match meta { syn::Meta::NameValue(syn::MetaNameValue { ref path, .. }) if path.is_ident(name) => true, @@ -45,6 +57,13 @@ fn is_attr_name_value(attr: &syn::Attribute, name: &str) -> bool { }) } +fn is_attr_path(attr: &syn::Attribute, name: &str) -> bool { + attr.parse_meta().ok().map_or(false, |meta| match meta { + syn::Meta::Path(path) if path.is_ident(name) => true, + _ => false, + }) +} + fn get_name_value_str_lit(attr: &syn::Attribute, name: &str) -> Option { attr.parse_meta().ok().and_then(|meta| match meta { syn::Meta::NameValue(syn::MetaNameValue { diff --git a/config_proc_macro/src/item_enum.rs b/config_proc_macro/src/item_enum.rs index dcee77a8549c5..731a7ea06077b 100644 --- a/config_proc_macro/src/item_enum.rs +++ b/config_proc_macro/src/item_enum.rs @@ -1,5 +1,6 @@ use proc_macro2::TokenStream; -use quote::quote; +use quote::{quote, quote_spanned}; +use syn::spanned::Spanned; use crate::attrs::*; use crate::utils::*; @@ -47,12 +48,23 @@ fn process_variant(variant: &syn::Variant) -> TokenStream { let metas = variant .attrs .iter() - .filter(|attr| !is_doc_hint(attr) && !is_config_value(attr)); + .filter(|attr| !is_doc_hint(attr) && !is_config_value(attr) && !is_unstable_variant(attr)); let attrs = fold_quote(metas, |meta| quote!(#meta)); let syn::Variant { ident, fields, .. } = variant; quote!(#attrs #ident #fields) } +/// Return the correct syntax to pattern match on the enum variant, discarding all +/// internal field data. +fn fields_in_variant(variant: &syn::Variant) -> TokenStream { + // With thanks to https://stackoverflow.com/a/65182902 + match &variant.fields { + syn::Fields::Unnamed(_) => quote_spanned! { variant.span() => (..) }, + syn::Fields::Unit => quote_spanned! { variant.span() => }, + syn::Fields::Named(_) => quote_spanned! { variant.span() => {..} }, + } +} + fn impl_doc_hint(ident: &syn::Ident, variants: &Variants) -> TokenStream { let doc_hint = variants .iter() @@ -60,12 +72,26 @@ fn impl_doc_hint(ident: &syn::Ident, variants: &Variants) -> TokenStream { .collect::>() .join("|"); let doc_hint = format!("[{}]", doc_hint); + + let variant_stables = variants + .iter() + .map(|v| (&v.ident, fields_in_variant(&v), !unstable_of_variant(v))); + let match_patterns = fold_quote(variant_stables, |(v, fields, stable)| { + quote! { + #ident::#v #fields => #stable, + } + }); quote! { use crate::config::ConfigType; impl ConfigType for #ident { fn doc_hint() -> String { #doc_hint.to_owned() } + fn stable_variant(&self) -> bool { + match self { + #match_patterns + } + } } } } @@ -123,13 +149,21 @@ fn impl_from_str(ident: &syn::Ident, variants: &Variants) -> TokenStream { } fn doc_hint_of_variant(variant: &syn::Variant) -> String { - find_doc_hint(&variant.attrs).unwrap_or(variant.ident.to_string()) + let mut text = find_doc_hint(&variant.attrs).unwrap_or(variant.ident.to_string()); + if unstable_of_variant(&variant) { + text.push_str(" (unstable)") + }; + text } fn config_value_of_variant(variant: &syn::Variant) -> String { find_config_value(&variant.attrs).unwrap_or(variant.ident.to_string()) } +fn unstable_of_variant(variant: &syn::Variant) -> bool { + any_unstable_variant(&variant.attrs) +} + fn impl_serde(ident: &syn::Ident, variants: &Variants) -> TokenStream { let arms = fold_quote(variants.iter(), |v| { let v_ident = &v.ident; diff --git a/config_proc_macro/src/lib.rs b/config_proc_macro/src/lib.rs index e772c53f42361..0c54c132c97d8 100644 --- a/config_proc_macro/src/lib.rs +++ b/config_proc_macro/src/lib.rs @@ -69,3 +69,16 @@ pub fn stable_only_test(_args: TokenStream, input: TokenStream) -> TokenStream { TokenStream::from_str("").unwrap() } } + +/// Used to conditionally output the TokenStream for tests that should be run as part of rustfmts +/// test suite, but should be ignored when running in the rust-lang/rust test suite. +#[proc_macro_attribute] +pub fn rustfmt_only_ci_test(_args: TokenStream, input: TokenStream) -> TokenStream { + if option_env!("RUSTFMT_CI").is_some() { + input + } else { + let mut token_stream = TokenStream::from_str("#[ignore]").unwrap(); + token_stream.extend(input); + token_stream + } +} diff --git a/config_proc_macro/tests/smoke.rs b/config_proc_macro/tests/smoke.rs index 940a8a0c251e4..c8a83e39c9efc 100644 --- a/config_proc_macro/tests/smoke.rs +++ b/config_proc_macro/tests/smoke.rs @@ -1,6 +1,7 @@ pub mod config { pub trait ConfigType: Sized { fn doc_hint() -> String; + fn stable_variant(&self) -> bool; } } diff --git a/rust-toolchain b/rust-toolchain index 2640a9e0ecc28..22283b3d62002 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-06-21" -components = ["rustc-dev"] +channel = "nightly-2023-01-24" +components = ["llvm-tools", "rustc-dev"] diff --git a/src/attr.rs b/src/attr.rs index c503eeeb9b3b9..5648e1254ed7c 100644 --- a/src/attr.rs +++ b/src/attr.rs @@ -336,7 +336,7 @@ impl Rewrite for ast::Attribute { } else { let should_skip = self .ident() - .map(|s| context.skip_context.skip_attribute(s.name.as_str())) + .map(|s| context.skip_context.attributes.skip(s.name.as_str())) .unwrap_or(false); let prefix = attr_prefix(self); @@ -390,7 +390,7 @@ impl Rewrite for [ast::Attribute] { // Determine if the source text is annotated with `#[rustfmt::skip::attributes(derive)]` // or `#![rustfmt::skip::attributes(derive)]` - let skip_derives = context.skip_context.skip_attribute("derive"); + let skip_derives = context.skip_context.attributes.skip("derive"); // This is not just a simple map because we need to handle doc comments // (where we take as many doc comment attributes as possible) and possibly diff --git a/src/bin/main.rs b/src/bin/main.rs index 8e871e61f2683..be64559e87745 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -136,7 +136,7 @@ fn make_opts() -> Options { "l", "files-with-diff", "Prints the names of mismatched files that were formatted. Prints the names of \ - files that would be formated when used with `--check` mode. ", + files that would be formatted when used with `--check` mode. ", ); opts.optmulti( "", diff --git a/src/cargo-fmt/main.rs b/src/cargo-fmt/main.rs index 9031d29b45f7f..2b714b68df00e 100644 --- a/src/cargo-fmt/main.rs +++ b/src/cargo-fmt/main.rs @@ -198,12 +198,10 @@ fn convert_message_format_to_rustfmt_args( Ok(()) } "human" => Ok(()), - _ => { - return Err(format!( - "invalid --message-format value: {}. Allowed values are: short|json|human", - message_format - )); - } + _ => Err(format!( + "invalid --message-format value: {}. Allowed values are: short|json|human", + message_format + )), } } @@ -215,7 +213,7 @@ fn print_usage_to_stderr(reason: &str) { .expect("failed to write to stderr"); } -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Verbosity { Verbose, Normal, diff --git a/src/cargo-fmt/test/mod.rs b/src/cargo-fmt/test/mod.rs index 56e52fbabb68b..696326e4f9406 100644 --- a/src/cargo-fmt/test/mod.rs +++ b/src/cargo-fmt/test/mod.rs @@ -70,9 +70,9 @@ fn mandatory_separator() { .is_err() ); assert!( - !Opts::command() + Opts::command() .try_get_matches_from(&["test", "--", "--emit"]) - .is_err() + .is_ok() ); } diff --git a/src/chains.rs b/src/chains.rs index a1a73cf4bd570..39b8d6878097d 100644 --- a/src/chains.rs +++ b/src/chains.rs @@ -70,10 +70,64 @@ use crate::rewrite::{Rewrite, RewriteContext}; use crate::shape::Shape; use crate::source_map::SpanUtils; use crate::utils::{ - self, first_line_width, last_line_extendable, last_line_width, mk_sp, rewrite_ident, - trimmed_last_line_width, wrap_str, + self, filtered_str_fits, first_line_width, last_line_extendable, last_line_width, mk_sp, + rewrite_ident, trimmed_last_line_width, wrap_str, }; +/// Provides the original input contents from the span +/// of a chain element with trailing spaces trimmed. +fn format_overflow_style(span: Span, context: &RewriteContext<'_>) -> Option { + context.snippet_provider.span_to_snippet(span).map(|s| { + s.lines() + .map(|l| l.trim_end()) + .collect::>() + .join("\n") + }) +} + +fn format_chain_item( + item: &ChainItem, + context: &RewriteContext<'_>, + rewrite_shape: Shape, + allow_overflow: bool, +) -> Option { + if allow_overflow { + item.rewrite(context, rewrite_shape) + .or_else(|| format_overflow_style(item.span, context)) + } else { + item.rewrite(context, rewrite_shape) + } +} + +fn get_block_child_shape( + prev_ends_with_block: bool, + context: &RewriteContext<'_>, + shape: Shape, +) -> Shape { + if prev_ends_with_block { + shape.block_indent(0) + } else { + shape.block_indent(context.config.tab_spaces()) + } + .with_max_width(context.config) +} + +fn get_visual_style_child_shape( + context: &RewriteContext<'_>, + shape: Shape, + offset: usize, + parent_overflowing: bool, +) -> Option { + if !parent_overflowing { + shape + .with_max_width(context.config) + .offset_left(offset) + .map(|s| s.visual_indent(0)) + } else { + Some(shape.visual_indent(offset)) + } +} + pub(crate) fn rewrite_chain( expr: &ast::Expr, context: &RewriteContext<'_>, @@ -496,6 +550,8 @@ struct ChainFormatterShared<'a> { // The number of children in the chain. This is not equal to `self.children.len()` // because `self.children` will change size as we process the chain. child_count: usize, + // Whether elements are allowed to overflow past the max_width limit + allow_overflow: bool, } impl<'a> ChainFormatterShared<'a> { @@ -505,6 +561,8 @@ impl<'a> ChainFormatterShared<'a> { rewrites: Vec::with_capacity(chain.children.len() + 1), fits_single_line: false, child_count: chain.children.len(), + // TODO(calebcartwright) + allow_overflow: false, } } @@ -517,6 +575,14 @@ impl<'a> ChainFormatterShared<'a> { } } + fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> { + for item in &self.children[..self.children.len() - 1] { + let rewrite = format_chain_item(item, context, child_shape, self.allow_overflow)?; + self.rewrites.push(rewrite); + } + Some(()) + } + // Rewrite the last child. The last child of a chain requires special treatment. We need to // know whether 'overflowing' the last child make a better formatting: // @@ -729,22 +795,12 @@ impl<'a> ChainFormatter for ChainFormatterBlock<'a> { } fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - Some( - if self.root_ends_with_block { - shape.block_indent(0) - } else { - shape.block_indent(context.config.tab_spaces()) - } - .with_max_width(context.config), - ) + let block_end = self.root_ends_with_block; + Some(get_block_child_shape(block_end, context, shape)) } fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> { - for item in &self.shared.children[..self.shared.children.len() - 1] { - let rewrite = item.rewrite(context, child_shape)?; - self.shared.rewrites.push(rewrite); - } - Some(()) + self.shared.format_children(context, child_shape) } fn format_last_child( @@ -808,15 +864,14 @@ impl<'a> ChainFormatter for ChainFormatterVisual<'a> { .visual_indent(self.offset) .sub_width(self.offset)?; let rewrite = item.rewrite(context, child_shape)?; - match wrap_str(rewrite, context.config.max_width(), shape) { - Some(rewrite) => root_rewrite.push_str(&rewrite), - None => { - // We couldn't fit in at the visual indent, try the last - // indent. - let rewrite = item.rewrite(context, parent_shape)?; - root_rewrite.push_str(&rewrite); - self.offset = 0; - } + if filtered_str_fits(&rewrite, context.config.max_width(), shape) { + root_rewrite.push_str(&rewrite); + } else { + // We couldn't fit in at the visual indent, try the last + // indent. + let rewrite = item.rewrite(context, parent_shape)?; + root_rewrite.push_str(&rewrite); + self.offset = 0; } self.shared.children = &self.shared.children[1..]; @@ -827,18 +882,17 @@ impl<'a> ChainFormatter for ChainFormatterVisual<'a> { } fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - shape - .with_max_width(context.config) - .offset_left(self.offset) - .map(|s| s.visual_indent(0)) + get_visual_style_child_shape( + context, + shape, + self.offset, + // TODO(calebcartwright): self.shared.permissibly_overflowing_parent, + false, + ) } fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> { - for item in &self.shared.children[..self.shared.children.len() - 1] { - let rewrite = item.rewrite(context, child_shape)?; - self.shared.rewrites.push(rewrite); - } - Some(()) + self.shared.format_children(context, child_shape) } fn format_last_child( diff --git a/src/config/config_type.rs b/src/config/config_type.rs index c5e61658ad1ed..54ca7676dfc8b 100644 --- a/src/config/config_type.rs +++ b/src/config/config_type.rs @@ -1,4 +1,5 @@ use crate::config::file_lines::FileLines; +use crate::config::macro_names::MacroSelectors; use crate::config::options::{IgnoreList, WidthHeuristics}; /// Trait for types that can be used in `Config`. @@ -6,6 +7,14 @@ pub(crate) trait ConfigType: Sized { /// Returns hint text for use in `Config::print_docs()`. For enum types, this is a /// pipe-separated list of variants; for other types it returns ``. fn doc_hint() -> String; + + /// Return `true` if the variant (i.e. value of this type) is stable. + /// + /// By default, return true for all values. Enums annotated with `#[config_type]` + /// are automatically implemented, based on the `#[unstable_variant]` annotation. + fn stable_variant(&self) -> bool { + true + } } impl ConfigType for bool { @@ -38,6 +47,12 @@ impl ConfigType for FileLines { } } +impl ConfigType for MacroSelectors { + fn doc_hint() -> String { + String::from("[, ...]") + } +} + impl ConfigType for WidthHeuristics { fn doc_hint() -> String { String::new() @@ -51,6 +66,13 @@ impl ConfigType for IgnoreList { } macro_rules! create_config { + // Options passed in to the macro. + // + // - $i: the ident name of the option + // - $ty: the type of the option value + // - $def: the default value of the option + // - $stb: true if the option is stable + // - $dstring: description of the option ($($i:ident: $ty:ty, $def:expr, $stb:expr, $( $dstring:expr ),+ );+ $(;)*) => ( #[cfg(test)] use std::collections::HashSet; @@ -61,9 +83,12 @@ macro_rules! create_config { #[derive(Clone)] #[allow(unreachable_pub)] pub struct Config { - // For each config item, we store a bool indicating whether it has - // been accessed and the value, and a bool whether the option was - // manually initialised, or taken from the default, + // For each config item, we store: + // + // - 0: true if the value has been access + // - 1: true if the option was manually initialized + // - 2: the option value + // - 3: true if the option is unstable $($i: (Cell, bool, $ty, bool)),+ } @@ -102,6 +127,7 @@ macro_rules! create_config { | "array_width" | "chain_width" => self.0.set_heuristics(), "merge_imports" => self.0.set_merge_imports(), + "fn_args_layout" => self.0.set_fn_args_layout(), &_ => (), } } @@ -143,24 +169,20 @@ macro_rules! create_config { fn fill_from_parsed_config(mut self, parsed: PartialConfig, dir: &Path) -> Config { $( - if let Some(val) = parsed.$i { - if self.$i.3 { + if let Some(option_value) = parsed.$i { + let option_stable = self.$i.3; + if $crate::config::config_type::is_stable_option_and_value( + stringify!($i), option_stable, &option_value + ) { self.$i.1 = true; - self.$i.2 = val; - } else { - if crate::is_nightly_channel!() { - self.$i.1 = true; - self.$i.2 = val; - } else { - eprintln!("Warning: can't set `{} = {:?}`, unstable features are only \ - available in nightly channel.", stringify!($i), val); - } + self.$i.2 = option_value; } } )+ self.set_heuristics(); self.set_ignore(dir); self.set_merge_imports(); + self.set_fn_args_layout(); self } @@ -221,12 +243,22 @@ macro_rules! create_config { match key { $( stringify!($i) => { - self.$i.1 = true; - self.$i.2 = val.parse::<$ty>() + let option_value = val.parse::<$ty>() .expect(&format!("Failed to parse override for {} (\"{}\") as a {}", stringify!($i), val, stringify!($ty))); + + // Users are currently allowed to set unstable + // options/variants via the `--config` options override. + // + // There is ongoing discussion about how to move forward here: + // https://github.com/rust-lang/rustfmt/pull/5379 + // + // For now, do not validate whether the option or value is stable, + // just always set it. + self.$i.1 = true; + self.$i.2 = option_value; } )+ _ => panic!("Unknown config key in override: {}", key) @@ -243,14 +275,21 @@ macro_rules! create_config { | "array_width" | "chain_width" => self.set_heuristics(), "merge_imports" => self.set_merge_imports(), + "fn_args_layout" => self.set_fn_args_layout(), &_ => (), } } #[allow(unreachable_pub)] pub fn is_hidden_option(name: &str) -> bool { - const HIDE_OPTIONS: [&str; 5] = - ["verbose", "verbose_diff", "file_lines", "width_heuristics", "merge_imports"]; + const HIDE_OPTIONS: [&str; 6] = [ + "verbose", + "verbose_diff", + "file_lines", + "width_heuristics", + "merge_imports", + "fn_args_layout" + ]; HIDE_OPTIONS.contains(&name) } @@ -400,6 +439,18 @@ macro_rules! create_config { } } + fn set_fn_args_layout(&mut self) { + if self.was_set().fn_args_layout() { + eprintln!( + "Warning: the `fn_args_layout` option is deprecated. \ + Use `fn_params_layout`. instead" + ); + if !self.was_set().fn_params_layout() { + self.fn_params_layout.2 = self.fn_args_layout(); + } + } + } + #[allow(unreachable_pub)] /// Returns `true` if the config key was explicitly set and is the default value. pub fn is_default(&self, key: &str) -> bool { @@ -424,3 +475,38 @@ macro_rules! create_config { } ) } + +pub(crate) fn is_stable_option_and_value( + option_name: &str, + option_stable: bool, + option_value: &T, +) -> bool +where + T: PartialEq + std::fmt::Debug + ConfigType, +{ + let nightly = crate::is_nightly_channel!(); + let variant_stable = option_value.stable_variant(); + match (nightly, option_stable, variant_stable) { + // Stable with an unstable option + (false, false, _) => { + eprintln!( + "Warning: can't set `{} = {:?}`, unstable features are only \ + available in nightly channel.", + option_name, option_value + ); + false + } + // Stable with a stable option, but an unstable variant + (false, true, false) => { + eprintln!( + "Warning: can't set `{} = {:?}`, unstable variants are only \ + available in nightly channel.", + option_name, option_value + ); + false + } + // Nightly: everything allowed + // Stable with stable option and variant: allowed + (true, _, _) | (false, true, true) => true, + } +} diff --git a/src/config/macro_names.rs b/src/config/macro_names.rs new file mode 100644 index 0000000000000..26ad78d6dcae8 --- /dev/null +++ b/src/config/macro_names.rs @@ -0,0 +1,118 @@ +//! This module contains types and functions to support formatting specific macros. + +use itertools::Itertools; +use std::{fmt, str}; + +use serde::{Deserialize, Serialize}; +use serde_json as json; +use thiserror::Error; + +/// Defines the name of a macro. +#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)] +pub struct MacroName(String); + +impl MacroName { + pub fn new(other: String) -> Self { + Self(other) + } +} + +impl fmt::Display for MacroName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl From for String { + fn from(other: MacroName) -> Self { + other.0 + } +} + +/// Defines a selector to match against a macro. +#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)] +pub enum MacroSelector { + Name(MacroName), + All, +} + +impl fmt::Display for MacroSelector { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Name(name) => name.fmt(f), + Self::All => write!(f, "*"), + } + } +} + +impl str::FromStr for MacroSelector { + type Err = std::convert::Infallible; + + fn from_str(s: &str) -> Result { + Ok(match s { + "*" => MacroSelector::All, + name => MacroSelector::Name(MacroName(name.to_owned())), + }) + } +} + +/// A set of macro selectors. +#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] +pub struct MacroSelectors(pub Vec); + +impl fmt::Display for MacroSelectors { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0.iter().format(", ")) + } +} + +#[derive(Error, Debug)] +pub enum MacroSelectorsError { + #[error("{0}")] + Json(json::Error), +} + +// This impl is needed for `Config::override_value` to work for use in tests. +impl str::FromStr for MacroSelectors { + type Err = MacroSelectorsError; + + fn from_str(s: &str) -> Result { + let raw: Vec<&str> = json::from_str(s).map_err(MacroSelectorsError::Json)?; + Ok(Self( + raw.into_iter() + .map(|raw| { + MacroSelector::from_str(raw).expect("MacroSelector from_str is infallible") + }) + .collect(), + )) + } +} + +#[cfg(test)] +mod test { + use super::*; + use std::str::FromStr; + + #[test] + fn macro_names_from_str() { + let macro_names = MacroSelectors::from_str(r#"["foo", "*", "bar"]"#).unwrap(); + assert_eq!( + macro_names, + MacroSelectors( + [ + MacroSelector::Name(MacroName("foo".to_owned())), + MacroSelector::All, + MacroSelector::Name(MacroName("bar".to_owned())) + ] + .into_iter() + .collect() + ) + ); + } + + #[test] + fn macro_names_display() { + let macro_names = MacroSelectors::from_str(r#"["foo", "*", "bar"]"#).unwrap(); + assert_eq!(format!("{}", macro_names), "foo, *, bar"); + } +} diff --git a/src/config/mod.rs b/src/config/mod.rs index f49c18d3a4603..14f27f3f8b692 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -13,15 +13,20 @@ pub use crate::config::file_lines::{FileLines, FileName, Range}; #[allow(unreachable_pub)] pub use crate::config::lists::*; #[allow(unreachable_pub)] +pub use crate::config::macro_names::{MacroSelector, MacroSelectors}; +#[allow(unreachable_pub)] pub use crate::config::options::*; #[macro_use] pub(crate) mod config_type; #[macro_use] +#[allow(unreachable_pub)] pub(crate) mod options; pub(crate) mod file_lines; +#[allow(unreachable_pub)] pub(crate) mod lists; +pub(crate) mod macro_names; // This macro defines configuration options used in rustfmt. Each option // is defined as follows: @@ -67,6 +72,8 @@ create_config! { format_macro_matchers: bool, false, false, "Format the metavariable matching patterns in macros"; format_macro_bodies: bool, true, false, "Format the bodies of macros"; + skip_macro_invocations: MacroSelectors, MacroSelectors::default(), false, + "Skip formatting the bodies of macros invoked with the following names."; hex_literal_case: HexLiteralCase, HexLiteralCase::Preserve, false, "Format hexadecimal integer literals"; @@ -119,7 +126,9 @@ create_config! { force_multiline_blocks: bool, false, false, "Force multiline closure bodies and match arms to be wrapped in a block"; fn_args_layout: Density, Density::Tall, true, - "Control the layout of arguments in a function"; + "(deprecated: use fn_params_layout instead)"; + fn_params_layout: Density, Density::Tall, true, + "Control the layout of parameters in function signatures."; brace_style: BraceStyle, BraceStyle::SameLineWhere, false, "Brace style for items"; control_brace_style: ControlBraceStyle, ControlBraceStyle::AlwaysSameLine, false, "Brace style for control flow constructs"; @@ -175,7 +184,7 @@ create_config! { make_backup: bool, false, false, "Backup changed files"; print_misformatted_file_names: bool, false, true, "Prints the names of mismatched files that were formatted. Prints the names of \ - files that would be formated when used with `--check` mode. "; + files that would be formatted when used with `--check` mode. "; } #[derive(Error, Debug)] @@ -191,6 +200,7 @@ impl PartialConfig { cloned.width_heuristics = None; cloned.print_misformatted_file_names = None; cloned.merge_imports = None; + cloned.fn_args_layout = None; ::toml::to_string(&cloned).map_err(ToTomlError) } @@ -403,11 +413,21 @@ mod test { use super::*; use std::str; + use crate::config::macro_names::MacroName; use rustfmt_config_proc_macro::{nightly_only_test, stable_only_test}; #[allow(dead_code)] mod mock { use super::super::*; + use rustfmt_config_proc_macro::config_type; + + #[config_type] + pub(crate) enum PartiallyUnstableOption { + V1, + V2, + #[unstable_variant] + V3, + } create_config! { // Options that are used by the generated functions @@ -427,6 +447,12 @@ mod test { "Merge imports"; merge_imports: bool, false, false, "(deprecated: use imports_granularity instead)"; + // fn_args_layout renamed to fn_params_layout + fn_args_layout: Density, Density::Tall, true, + "(deprecated: use fn_params_layout instead)"; + fn_params_layout: Density, Density::Tall, true, + "Control the layout of parameters in a function signatures."; + // Width Heuristics use_small_heuristics: Heuristics, Heuristics::Default, true, "Whether to use different formatting for items and \ @@ -451,6 +477,63 @@ mod test { // Options that are used by the tests stable_option: bool, false, true, "A stable option"; unstable_option: bool, false, false, "An unstable option"; + partially_unstable_option: PartiallyUnstableOption, PartiallyUnstableOption::V1, true, + "A partially unstable option"; + } + + #[cfg(test)] + mod partially_unstable_option { + use super::{Config, PartialConfig, PartiallyUnstableOption}; + use rustfmt_config_proc_macro::{nightly_only_test, stable_only_test}; + use std::path::Path; + + /// From the config file, we can fill with a stable variant + #[test] + fn test_from_toml_stable_value() { + let toml = r#" + partially_unstable_option = "V2" + "#; + let partial_config: PartialConfig = toml::from_str(toml).unwrap(); + let config = Config::default(); + let config = config.fill_from_parsed_config(partial_config, Path::new("")); + assert_eq!( + config.partially_unstable_option(), + PartiallyUnstableOption::V2 + ); + } + + /// From the config file, we cannot fill with an unstable variant (stable only) + #[stable_only_test] + #[test] + fn test_from_toml_unstable_value_on_stable() { + let toml = r#" + partially_unstable_option = "V3" + "#; + let partial_config: PartialConfig = toml::from_str(toml).unwrap(); + let config = Config::default(); + let config = config.fill_from_parsed_config(partial_config, Path::new("")); + assert_eq!( + config.partially_unstable_option(), + // default value from config, i.e. fill failed + PartiallyUnstableOption::V1 + ); + } + + /// From the config file, we can fill with an unstable variant (nightly only) + #[nightly_only_test] + #[test] + fn test_from_toml_unstable_value_on_nightly() { + let toml = r#" + partially_unstable_option = "V3" + "#; + let partial_config: PartialConfig = toml::from_str(toml).unwrap(); + let config = Config::default(); + let config = config.fill_from_parsed_config(partial_config, Path::new("")); + assert_eq!( + config.partially_unstable_option(), + PartiallyUnstableOption::V3 + ); + } } } @@ -489,6 +572,11 @@ mod test { assert_eq!(config.was_set().verbose(), false); } + const PRINT_DOCS_STABLE_OPTION: &str = "stable_option Default: false"; + const PRINT_DOCS_UNSTABLE_OPTION: &str = "unstable_option Default: false (unstable)"; + const PRINT_DOCS_PARTIALLY_UNSTABLE_OPTION: &str = + "partially_unstable_option [V1|V2|V3 (unstable)] Default: V1"; + #[test] fn test_print_docs_exclude_unstable() { use self::mock::Config; @@ -497,10 +585,9 @@ mod test { Config::print_docs(&mut output, false); let s = str::from_utf8(&output).unwrap(); - - assert_eq!(s.contains("stable_option"), true); - assert_eq!(s.contains("unstable_option"), false); - assert_eq!(s.contains("(unstable)"), false); + assert_eq!(s.contains(PRINT_DOCS_STABLE_OPTION), true); + assert_eq!(s.contains(PRINT_DOCS_UNSTABLE_OPTION), false); + assert_eq!(s.contains(PRINT_DOCS_PARTIALLY_UNSTABLE_OPTION), true); } #[test] @@ -511,9 +598,9 @@ mod test { Config::print_docs(&mut output, true); let s = str::from_utf8(&output).unwrap(); - assert_eq!(s.contains("stable_option"), true); - assert_eq!(s.contains("unstable_option"), true); - assert_eq!(s.contains("(unstable)"), true); + assert_eq!(s.contains(PRINT_DOCS_STABLE_OPTION), true); + assert_eq!(s.contains(PRINT_DOCS_UNSTABLE_OPTION), true); + assert_eq!(s.contains(PRINT_DOCS_PARTIALLY_UNSTABLE_OPTION), true); } #[test] @@ -541,6 +628,7 @@ normalize_doc_attributes = false format_strings = false format_macro_matchers = false format_macro_bodies = true +skip_macro_invocations = [] hex_literal_case = "Preserve" empty_item_single_line = true struct_lit_single_line = true @@ -567,7 +655,7 @@ enum_discrim_align_threshold = 0 match_arm_blocks = true match_arm_leading_pipes = "Never" force_multiline_blocks = false -fn_args_layout = "Tall" +fn_params_layout = "Tall" brace_style = "SameLineWhere" control_brace_style = "AlwaysSameLine" trailing_semicolon = true @@ -921,4 +1009,45 @@ make_backup = false assert_eq!(config.single_line_if_else_max_width(), 100); } } + + #[cfg(test)] + mod partially_unstable_option { + use super::mock::{Config, PartiallyUnstableOption}; + use super::*; + + /// From the command line, we can override with a stable variant. + #[test] + fn test_override_stable_value() { + let mut config = Config::default(); + config.override_value("partially_unstable_option", "V2"); + assert_eq!( + config.partially_unstable_option(), + PartiallyUnstableOption::V2 + ); + } + + /// From the command line, we can override with an unstable variant. + #[test] + fn test_override_unstable_value() { + let mut config = Config::default(); + config.override_value("partially_unstable_option", "V3"); + assert_eq!( + config.partially_unstable_option(), + PartiallyUnstableOption::V3 + ); + } + } + + #[test] + fn test_override_skip_macro_invocations() { + let mut config = Config::default(); + config.override_value("skip_macro_invocations", r#"["*", "println"]"#); + assert_eq!( + config.skip_macro_invocations(), + MacroSelectors(vec![ + MacroSelector::All, + MacroSelector::Name(MacroName::new("println".to_owned())) + ]) + ); + } } diff --git a/src/expr.rs b/src/expr.rs index 868ff045ab78b..0be4c3cf168cc 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -29,9 +29,9 @@ use crate::spanned::Spanned; use crate::string::{rewrite_string, StringFormat}; use crate::types::{rewrite_path, PathContext}; use crate::utils::{ - colon_spaces, contains_skip, count_newlines, first_line_ends_with, inner_attributes, - last_line_extendable, last_line_width, mk_sp, outer_attributes, semicolon_for_expr, - unicode_str_width, wrap_str, + colon_spaces, contains_skip, count_newlines, filtered_str_fits, first_line_ends_with, + inner_attributes, last_line_extendable, last_line_width, mk_sp, outer_attributes, + semicolon_for_expr, unicode_str_width, wrap_str, }; use crate::vertical::rewrite_with_alignment; use crate::visitor::FmtVisitor; @@ -2050,8 +2050,7 @@ fn choose_rhs( match (orig_rhs, new_rhs) { (Some(ref orig_rhs), Some(ref new_rhs)) - if wrap_str(new_rhs.clone(), context.config.max_width(), new_shape) - .is_none() => + if !filtered_str_fits(&new_rhs, context.config.max_width(), new_shape) => { Some(format!("{}{}", before_space_str, orig_rhs)) } diff --git a/src/imports.rs b/src/imports.rs index d9dc8d004aff4..339e5cef5af91 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -251,8 +251,8 @@ fn flatten_use_trees( use_trees: Vec, import_granularity: ImportGranularity, ) -> Vec { - // Return non-sorted single occurance of the use-trees text string; - // order is by first occurance of the use-tree. + // Return non-sorted single occurrence of the use-trees text string; + // order is by first occurrence of the use-tree. use_trees .into_iter() .flat_map(|tree| tree.flatten(import_granularity)) diff --git a/src/items.rs b/src/items.rs index a2a73f0a5fb3a..25e8a024857ce 100644 --- a/src/items.rs +++ b/src/items.rs @@ -1084,7 +1084,11 @@ pub(crate) fn format_trait( let item_snippet = context.snippet(item.span); if let Some(lo) = item_snippet.find('/') { // 1 = `{` - let comment_hi = body_lo - BytePos(1); + let comment_hi = if generics.params.len() > 0 { + generics.span.lo() - BytePos(1) + } else { + body_lo - BytePos(1) + }; let comment_lo = item.span.lo() + BytePos(lo as u32); if comment_lo < comment_hi { match recover_missing_comment_in_span( @@ -1241,7 +1245,7 @@ fn format_unit_struct( ) -> Option { let header_str = format_header(context, p.prefix, p.ident, p.vis, offset); let generics_str = if let Some(generics) = p.generics { - let hi = context.snippet_provider.span_before(p.span, ";"); + let hi = context.snippet_provider.span_before_last(p.span, ";"); format_generics( context, generics, @@ -2602,7 +2606,7 @@ fn rewrite_params( ¶m_items, context .config - .fn_args_layout() + .fn_params_layout() .to_list_tactic(param_items.len()), Separator::Comma, one_line_budget, diff --git a/src/lists.rs b/src/lists.rs index e87850507824f..a878e6cf9b2fc 100644 --- a/src/lists.rs +++ b/src/lists.rs @@ -297,9 +297,9 @@ where } else { inner_item.as_ref() }; - let mut item_last_line_width = item_last_line.len() + item_sep_len; + let mut item_last_line_width = unicode_str_width(item_last_line) + item_sep_len; if item_last_line.starts_with(&**indent_str) { - item_last_line_width -= indent_str.len(); + item_last_line_width -= unicode_str_width(indent_str); } if !item.is_substantial() { @@ -449,7 +449,7 @@ where } else if starts_with_newline(comment) { false } else { - comment.trim().contains('\n') || comment.trim().len() > width + comment.trim().contains('\n') || unicode_str_width(comment.trim()) > width }; rewrite_comment( @@ -465,7 +465,7 @@ where if !starts_with_newline(comment) { if formatting.align_comments { let mut comment_alignment = - post_comment_alignment(item_max_width, inner_item.len()); + post_comment_alignment(item_max_width, unicode_str_width(inner_item)); if first_line_width(&formatted_comment) + last_line_width(&result) + comment_alignment @@ -475,7 +475,7 @@ where item_max_width = None; formatted_comment = rewrite_post_comment(&mut item_max_width)?; comment_alignment = - post_comment_alignment(item_max_width, inner_item.len()); + post_comment_alignment(item_max_width, unicode_str_width(inner_item)); } for _ in 0..=comment_alignment { result.push(' '); @@ -533,7 +533,7 @@ where let mut first = true; for item in items.clone().into_iter().skip(i) { let item = item.as_ref(); - let inner_item_width = item.inner_as_ref().len(); + let inner_item_width = unicode_str_width(item.inner_as_ref()); if !first && (item.is_different_group() || item.post_comment.is_none() @@ -552,8 +552,8 @@ where max_width } -fn post_comment_alignment(item_max_width: Option, inner_item_len: usize) -> usize { - item_max_width.unwrap_or(0).saturating_sub(inner_item_len) +fn post_comment_alignment(item_max_width: Option, inner_item_width: usize) -> usize { + item_max_width.unwrap_or(0).saturating_sub(inner_item_width) } pub(crate) struct ListItems<'a, I, F1, F2, F3> diff --git a/src/macros.rs b/src/macros.rs index df94938803788..d58f7547fefb3 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -35,8 +35,8 @@ use crate::shape::{Indent, Shape}; use crate::source_map::SpanUtils; use crate::spanned::Spanned; use crate::utils::{ - format_visibility, indent_next_line, is_empty_line, mk_sp, remove_trailing_white_spaces, - rewrite_ident, trim_left_preserve_layout, wrap_str, NodeIdExt, + filtered_str_fits, format_visibility, indent_next_line, is_empty_line, mk_sp, + remove_trailing_white_spaces, rewrite_ident, trim_left_preserve_layout, NodeIdExt, }; use crate::visitor::FmtVisitor; @@ -157,7 +157,8 @@ pub(crate) fn rewrite_macro( ) -> Option { let should_skip = context .skip_context - .skip_macro(context.snippet(mac.path.span)); + .macros + .skip(context.snippet(mac.path.span)); if should_skip { None } else { @@ -1265,15 +1266,14 @@ impl MacroBranch { } } }; - let new_body = wrap_str( - new_body_snippet.snippet.to_string(), - config.max_width(), - shape, - )?; + + if !filtered_str_fits(&new_body_snippet.snippet, config.max_width(), shape) { + return None; + } // Indent the body since it is in a block. let indent_str = body_indent.to_string(&config); - let mut new_body = LineClasses::new(new_body.trim_end()) + let mut new_body = LineClasses::new(new_body_snippet.snippet.trim_end()) .enumerate() .fold( (String::new(), true), diff --git a/src/skip.rs b/src/skip.rs index 032922d421df7..68f85b2ade48a 100644 --- a/src/skip.rs +++ b/src/skip.rs @@ -2,33 +2,84 @@ use rustc_ast::ast; use rustc_ast_pretty::pprust; +use std::collections::HashSet; -/// Take care of skip name stack. You can update it by attributes slice or -/// by other context. Query this context to know if you need skip a block. +/// Track which blocks of code are to be skipped when formatting. +/// +/// You can update it by: +/// +/// - attributes slice +/// - manually feeding values into the underlying contexts +/// +/// Query this context to know if you need to skip a block. #[derive(Default, Clone)] pub(crate) struct SkipContext { - macros: Vec, - attributes: Vec, + pub(crate) macros: SkipNameContext, + pub(crate) attributes: SkipNameContext, } impl SkipContext { pub(crate) fn update_with_attrs(&mut self, attrs: &[ast::Attribute]) { - self.macros.append(&mut get_skip_names("macros", attrs)); - self.attributes - .append(&mut get_skip_names("attributes", attrs)); + self.macros.extend(get_skip_names("macros", attrs)); + self.attributes.extend(get_skip_names("attributes", attrs)); } - pub(crate) fn update(&mut self, mut other: SkipContext) { - self.macros.append(&mut other.macros); - self.attributes.append(&mut other.attributes); + pub(crate) fn update(&mut self, other: SkipContext) { + let SkipContext { macros, attributes } = other; + self.macros.update(macros); + self.attributes.update(attributes); + } +} + +/// Track which names to skip. +/// +/// Query this context with a string to know whether to skip it. +#[derive(Clone)] +pub(crate) enum SkipNameContext { + All, + Values(HashSet), +} + +impl Default for SkipNameContext { + fn default() -> Self { + Self::Values(Default::default()) + } +} + +impl Extend for SkipNameContext { + fn extend>(&mut self, iter: T) { + match self { + Self::All => {} + Self::Values(values) => values.extend(iter), + } + } +} + +impl SkipNameContext { + pub(crate) fn update(&mut self, other: Self) { + match (self, other) { + // If we're already skipping everything, nothing more can be added + (Self::All, _) => {} + // If we want to skip all, set it + (this, Self::All) => { + *this = Self::All; + } + // If we have some new values to skip, add them + (Self::Values(existing_values), Self::Values(new_values)) => { + existing_values.extend(new_values) + } + } } - pub(crate) fn skip_macro(&self, name: &str) -> bool { - self.macros.iter().any(|n| n == name) + pub(crate) fn skip(&self, name: &str) -> bool { + match self { + Self::All => true, + Self::Values(values) => values.contains(name), + } } - pub(crate) fn skip_attribute(&self, name: &str) -> bool { - self.attributes.iter().any(|n| n == name) + pub(crate) fn skip_all(&mut self) { + *self = Self::All; } } diff --git a/src/test/configuration_snippet.rs b/src/test/configuration_snippet.rs index c8fda7c8556db..c70b3c5facd50 100644 --- a/src/test/configuration_snippet.rs +++ b/src/test/configuration_snippet.rs @@ -27,8 +27,13 @@ impl ConfigurationSection { lazy_static! { static ref CONFIG_NAME_REGEX: regex::Regex = regex::Regex::new(r"^## `([^`]+)`").expect("failed creating configuration pattern"); + // Configuration values, which will be passed to `from_str`: + // + // - must be prefixed with `####` + // - must be wrapped in backticks + // - may by wrapped in double quotes (which will be stripped) static ref CONFIG_VALUE_REGEX: regex::Regex = - regex::Regex::new(r#"^#### `"?([^`"]+)"?`"#) + regex::Regex::new(r#"^#### `"?([^`]+?)"?`"#) .expect("failed creating configuration value pattern"); } diff --git a/src/test/mod.rs b/src/test/mod.rs index 6b5bc2b30dd5a..cfad4a8ed0e3e 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -982,11 +982,7 @@ fn rustfmt() -> PathBuf { assert!( me.is_file() || me.with_extension("exe").is_file(), "{}", - if cfg!(release) { - "no rustfmt bin, try running `cargo build --release` before testing" - } else { - "no rustfmt bin, try running `cargo build` before testing" - } + "no rustfmt bin, try running `cargo build` or `cargo build --release` before testing" ); me } diff --git a/src/types.rs b/src/types.rs index c1991e8d2c808..01e2fb6e61e15 100644 --- a/src/types.rs +++ b/src/types.rs @@ -941,6 +941,28 @@ fn join_bounds_inner( ast::GenericBound::Trait(..) => last_line_extendable(s), }; + // Whether a GenericBound item is a PathSegment segment that includes internal array + // that contains more than one item + let is_item_with_multi_items_array = |item: &ast::GenericBound| match item { + ast::GenericBound::Trait(ref poly_trait_ref, ..) => { + let segments = &poly_trait_ref.trait_ref.path.segments; + if segments.len() > 1 { + true + } else { + if let Some(args_in) = &segments[0].args { + matches!( + args_in.deref(), + ast::GenericArgs::AngleBracketed(bracket_args) + if bracket_args.args.len() > 1 + ) + } else { + false + } + } + } + _ => false, + }; + let result = items.iter().enumerate().try_fold( (String::new(), None, false), |(strs, prev_trailing_span, prev_extendable), (i, item)| { @@ -1035,10 +1057,24 @@ fn join_bounds_inner( }, )?; - if !force_newline - && items.len() > 1 - && (result.0.contains('\n') || result.0.len() > shape.width) - { + // Whether to retry with a forced newline: + // Only if result is not already multiline and did not exceed line width, + // and either there is more than one item; + // or the single item is of type `Trait`, + // and any of the internal arrays contains more than one item; + let retry_with_force_newline = match context.config.version() { + Version::One => { + !force_newline + && items.len() > 1 + && (result.0.contains('\n') || result.0.len() > shape.width) + } + Version::Two if force_newline => false, + Version::Two if (!result.0.contains('\n') && result.0.len() <= shape.width) => false, + Version::Two if items.len() > 1 => true, + Version::Two => is_item_with_multi_items_array(&items[0]), + }; + + if retry_with_force_newline { join_bounds_inner(context, shape, items, need_indent, true) } else { Some(result.0) diff --git a/src/utils.rs b/src/utils.rs index 3e884419f1a32..f681f55b37b9d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -384,14 +384,15 @@ macro_rules! skip_out_of_file_lines_range_visitor { // Wraps String in an Option. Returns Some when the string adheres to the // Rewrite constraints defined for the Rewrite trait and None otherwise. pub(crate) fn wrap_str(s: String, max_width: usize, shape: Shape) -> Option { - if is_valid_str(&filter_normal_code(&s), max_width, shape) { + if filtered_str_fits(&s, max_width, shape) { Some(s) } else { None } } -fn is_valid_str(snippet: &str, max_width: usize, shape: Shape) -> bool { +pub(crate) fn filtered_str_fits(snippet: &str, max_width: usize, shape: Shape) -> bool { + let snippet = &filter_normal_code(snippet); if !snippet.is_empty() { // First line must fits with `shape.width`. if first_line_width(snippet) > shape.width { diff --git a/src/visitor.rs b/src/visitor.rs index 9c3cc7820d299..f4d84d1381fc0 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -8,7 +8,7 @@ use rustc_span::{symbol, BytePos, Pos, Span}; use crate::attr::*; use crate::comment::{contains_comment, rewrite_comment, CodeCharKind, CommentCodeSlices}; use crate::config::Version; -use crate::config::{BraceStyle, Config}; +use crate::config::{BraceStyle, Config, MacroSelector}; use crate::coverage::transform_missing_snippet; use crate::items::{ format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item, rewrite_extern_crate, @@ -770,6 +770,15 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { snippet_provider: &'a SnippetProvider, report: FormatReport, ) -> FmtVisitor<'a> { + let mut skip_context = SkipContext::default(); + let mut macro_names = Vec::new(); + for macro_selector in config.skip_macro_invocations().0 { + match macro_selector { + MacroSelector::Name(name) => macro_names.push(name.to_string()), + MacroSelector::All => skip_context.macros.skip_all(), + } + } + skip_context.macros.extend(macro_names); FmtVisitor { parent_context: None, parse_sess: parse_session, @@ -784,7 +793,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { is_macro_def: false, macro_rewrite_failure: false, report, - skip_context: Default::default(), + skip_context, } } diff --git a/tests/cargo-fmt/main.rs b/tests/cargo-fmt/main.rs index 348876cd264fa..701c36fadeafa 100644 --- a/tests/cargo-fmt/main.rs +++ b/tests/cargo-fmt/main.rs @@ -4,6 +4,8 @@ use std::env; use std::path::Path; use std::process::Command; +use rustfmt_config_proc_macro::rustfmt_only_ci_test; + /// Run the cargo-fmt executable and return its output. fn cargo_fmt(args: &[&str]) -> (String, String) { let mut bin_dir = env::current_exe().unwrap(); @@ -47,7 +49,7 @@ macro_rules! assert_that { }; } -#[ignore] +#[rustfmt_only_ci_test] #[test] fn version() { assert_that!(&["--version"], starts_with("rustfmt ")); @@ -56,7 +58,7 @@ fn version() { assert_that!(&["--", "--version"], starts_with("rustfmt ")); } -#[ignore] +#[rustfmt_only_ci_test] #[test] fn print_config() { assert_that!( @@ -65,7 +67,7 @@ fn print_config() { ); } -#[ignore] +#[rustfmt_only_ci_test] #[test] fn rustfmt_help() { assert_that!(&["--", "--help"], contains("Format Rust code")); @@ -73,7 +75,7 @@ fn rustfmt_help() { assert_that!(&["--", "--help=config"], contains("Configuration Options:")); } -#[ignore] +#[rustfmt_only_ci_test] #[test] fn cargo_fmt_out_of_line_test_modules() { // See also https://github.com/rust-lang/rustfmt/issues/5119 @@ -96,3 +98,22 @@ fn cargo_fmt_out_of_line_test_modules() { assert!(stdout.contains(&format!("Diff in {}", path.display()))) } } + +#[rustfmt_only_ci_test] +#[test] +fn cargo_fmt_emits_error_on_line_overflow_true() { + // See also https://github.com/rust-lang/rustfmt/issues/3164 + let args = [ + "--check", + "--manifest-path", + "tests/cargo-fmt/source/issue_3164/Cargo.toml", + "--", + "--config", + "error_on_line_overflow=true", + ]; + + let (_stdout, stderr) = cargo_fmt(&args); + assert!(stderr.contains( + "line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option)" + )) +} diff --git a/tests/cargo-fmt/source/issue_3164/Cargo.toml b/tests/cargo-fmt/source/issue_3164/Cargo.toml new file mode 100644 index 0000000000000..580ef7e6e24fe --- /dev/null +++ b/tests/cargo-fmt/source/issue_3164/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "issue_3164" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/tests/cargo-fmt/source/issue_3164/src/main.rs b/tests/cargo-fmt/source/issue_3164/src/main.rs new file mode 100644 index 0000000000000..9330107ac8dc7 --- /dev/null +++ b/tests/cargo-fmt/source/issue_3164/src/main.rs @@ -0,0 +1,13 @@ +#[allow(unused_macros)] +macro_rules! foo { + ($id:ident) => { + macro_rules! bar { + ($id2:tt) => { + #[cfg(any(target_feature = $id2, target_feature = $id2, target_feature = $id2, target_feature = $id2, target_feature = $id2))] + fn $id() {} + }; + } + }; +} + +fn main() {} diff --git a/tests/config/small_tabs.toml b/tests/config/small_tabs.toml index c3cfd34317a37..4c37100894f83 100644 --- a/tests/config/small_tabs.toml +++ b/tests/config/small_tabs.toml @@ -3,7 +3,7 @@ comment_width = 80 tab_spaces = 2 newline_style = "Unix" brace_style = "SameLineWhere" -fn_args_layout = "Tall" +fn_params_layout = "Tall" trailing_comma = "Vertical" indent_style = "Block" reorder_imports = false diff --git a/tests/mod-resolver/issue-5198/lib/c/d/explanation.txt b/tests/mod-resolver/issue-5198/lib/c/d/explanation.txt index 92c9e3021431f..254102ebabdc2 100644 --- a/tests/mod-resolver/issue-5198/lib/c/d/explanation.txt +++ b/tests/mod-resolver/issue-5198/lib/c/d/explanation.txt @@ -9,7 +9,7 @@ The directory name './lib/c/d/' conflicts with the './lib/c/d.rs' file name. * mod g; Module resolution will fail if we look for './lib/c/d/e.rs' or './lib/c/d/e/mod.rs', -so we should fall back to looking for './lib/c/e.rs', which correctly finds the modlue, that +so we should fall back to looking for './lib/c/e.rs', which correctly finds the module, that rustfmt should format. './lib/c/d/f.rs' and './lib/c/d/g/mod.rs' exist at the default submodule paths so we should be able diff --git a/tests/mod-resolver/issue-5198/lib/explanation.txt b/tests/mod-resolver/issue-5198/lib/explanation.txt index d436a8076cd71..90464def8ebcc 100644 --- a/tests/mod-resolver/issue-5198/lib/explanation.txt +++ b/tests/mod-resolver/issue-5198/lib/explanation.txt @@ -9,7 +9,7 @@ The directory name './lib' conflicts with the './lib.rs' file name. * mod c; Module resolution will fail if we look for './lib/a.rs' or './lib/a/mod.rs', -so we should fall back to looking for './a.rs', which correctly finds the modlue that +so we should fall back to looking for './a.rs', which correctly finds the module that rustfmt should format. './lib/b.rs' and './lib/c/mod.rs' exist at the default submodule paths so we should be able diff --git a/tests/rustfmt/main.rs b/tests/rustfmt/main.rs index 4c6d52726f3fe..7ff301e80195a 100644 --- a/tests/rustfmt/main.rs +++ b/tests/rustfmt/main.rs @@ -5,6 +5,8 @@ use std::fs::remove_file; use std::path::Path; use std::process::Command; +use rustfmt_config_proc_macro::rustfmt_only_ci_test; + /// Run the rustfmt executable and return its output. fn rustfmt(args: &[&str]) -> (String, String) { let mut bin_dir = env::current_exe().unwrap(); @@ -47,7 +49,7 @@ macro_rules! assert_that { }; } -#[ignore] +#[rustfmt_only_ci_test] #[test] fn print_config() { assert_that!( @@ -76,7 +78,7 @@ fn print_config() { remove_file("minimal-config").unwrap(); } -#[ignore] +#[rustfmt_only_ci_test] #[test] fn inline_config() { // single invocation @@ -157,3 +159,18 @@ fn mod_resolution_error_path_attribute_does_not_exist() { // The path attribute points to a file that does not exist assert!(stderr.contains("does_not_exist.rs does not exist")); } + +#[test] +fn rustfmt_emits_error_on_line_overflow_true() { + // See also https://github.com/rust-lang/rustfmt/issues/3164 + let args = [ + "--config", + "error_on_line_overflow=true", + "tests/cargo-fmt/source/issue_3164/src/main.rs", + ]; + + let (_stdout, stderr) = rustfmt(&args); + assert!(stderr.contains( + "line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option)" + )) +} diff --git a/tests/source/cfg_if/detect/arch/x86.rs b/tests/source/cfg_if/detect/arch/x86.rs index d26f4ee894fad..131cbb855f163 100644 --- a/tests/source/cfg_if/detect/arch/x86.rs +++ b/tests/source/cfg_if/detect/arch/x86.rs @@ -329,7 +329,7 @@ pub enum Feature { tbm, /// POPCNT (Population Count) popcnt, - /// FXSR (Floating-point context fast save and restor) + /// FXSR (Floating-point context fast save and restore) fxsr, /// XSAVE (Save Processor Extended States) xsave, diff --git a/tests/source/comments_unicode.rs b/tests/source/comments_unicode.rs new file mode 100644 index 0000000000000..e65a245ba9343 --- /dev/null +++ b/tests/source/comments_unicode.rs @@ -0,0 +1,140 @@ +impl Default for WhitespaceCharacters { + fn default() -> Self { + Self { + space: '·', // U+00B7 + nbsp: '⍽', // U+237D + tab: '→', // U+2192 + newline: '⏎', // U+23CE + } + } +} + +const RAINBOWS: &[&str] = &[ + "rаinЬοѡ", // hue: 0 + "raіnЬοw", // hue: 2 + "rаіɴЬow", // hue: 2 + "raіɴЬoѡ", // hue: 8 + "ʀainЬow", // hue: 8 + "ʀaіɴboѡ", // hue: 8 + "ʀаіnbοw", // hue: 11 + "rainЬoѡ", // hue: 14 + "raіɴbow", // hue: 14 + "rаiɴЬow", // hue: 20 + "raіnЬow", // hue: 26 + "ʀaiɴbοw", // hue: 32 + "raіɴboѡ", // hue: 35 + "rаiɴbow", // hue: 35 + "rаіnbοw", // hue: 38 + "rаinЬow", // hue: 47 + "ʀaіnboѡ", // hue: 47 + "ʀaіnЬoѡ", // hue: 47 + "ʀаіɴbοw", // hue: 53 + "ʀaіnЬοѡ", // hue: 57 + "raiɴЬoѡ", // hue: 68 + "ʀainbοѡ", // hue: 68 + "ʀаinboѡ", // hue: 68 + "ʀаiɴbοw", // hue: 68 + "ʀаіnbow", // hue: 68 + "rаіnЬοѡ", // hue: 69 + "ʀainЬοw", // hue: 71 + "raiɴbow", // hue: 73 + "raіnЬoѡ", // hue: 74 + "rаіɴbοw", // hue: 77 + "raіnЬοѡ", // hue: 81 + "raiɴЬow", // hue: 83 + "ʀainbοw", // hue: 83 + "ʀаinbow", // hue: 83 + "ʀаiɴbοѡ", // hue: 83 + "ʀаіnboѡ", // hue: 83 + "ʀаіɴЬοѡ", // hue: 84 + "rainЬow", // hue: 85 + "ʀаiɴЬοw", // hue: 86 + "ʀаіnbοѡ", // hue: 89 + "ʀаіnЬοw", // hue: 92 + "rаiɴbοw", // hue: 95 + "ʀаіɴbοѡ", // hue: 98 + "ʀаiɴЬοѡ", // hue: 99 + "raіnbοw", // hue: 101 + "ʀаіɴЬοw", // hue: 101 + "ʀaiɴboѡ", // hue: 104 + "ʀаinbοѡ", // hue: 104 + "rаiɴbοѡ", // hue: 107 + "ʀаinЬοw", // hue: 107 + "rаiɴЬοw", // hue: 110 + "rаіnboѡ", // hue: 110 + "rаіnbοѡ", // hue: 113 + "ʀainЬοѡ", // hue: 114 + "rаіnЬοw", // hue: 116 + "ʀaіɴЬow", // hue: 116 + "rаinbοw", // hue: 122 + "ʀаіɴboѡ", // hue: 125 + "rаinbοѡ", // hue: 131 + "rainbow", // hue: 134 + "rаinЬοw", // hue: 134 + "ʀаiɴboѡ", // hue: 140 + "rainЬοѡ", // hue: 141 + "raіɴЬow", // hue: 143 + "ʀainЬoѡ", // hue: 143 + "ʀaіɴbow", // hue: 143 + "ʀainbow", // hue: 148 + "rаіɴboѡ", // hue: 149 + "ʀainboѡ", // hue: 155 + "ʀaіnbow", // hue: 155 + "ʀaіnЬow", // hue: 155 + "raiɴbοw", // hue: 158 + "ʀаiɴЬoѡ", // hue: 158 + "rainbοw", // hue: 160 + "rаinbow", // hue: 160 + "ʀaіɴbοѡ", // hue: 164 + "ʀаiɴbow", // hue: 164 + "ʀаіnЬoѡ", // hue: 164 + "ʀaiɴЬοѡ", // hue: 165 + "rаiɴboѡ", // hue: 167 + "ʀaіɴЬοw", // hue: 167 + "ʀaіɴЬοѡ", // hue: 171 + "raіnboѡ", // hue: 173 + "ʀаіɴЬoѡ", // hue: 173 + "rаіɴbοѡ", // hue: 176 + "ʀаinЬow", // hue: 176 + "rаiɴЬοѡ", // hue: 177 + "rаіɴЬοw", // hue: 179 + "ʀаinЬoѡ", // hue: 179 + "ʀаіɴbow", // hue: 179 + "rаiɴЬoѡ", // hue: 182 + "raіɴbοѡ", // hue: 188 + "rаіnЬoѡ", // hue: 188 + "raiɴЬοѡ", // hue: 189 + "raіɴЬοw", // hue: 191 + "ʀaіɴbοw", // hue: 191 + "ʀаіnЬow", // hue: 191 + "rainbοѡ", // hue: 194 + "rаinboѡ", // hue: 194 + "rаіnbow", // hue: 194 + "rainЬοw", // hue: 197 + "rаinЬoѡ", // hue: 206 + "rаіɴbow", // hue: 206 + "rаіɴЬοѡ", // hue: 210 + "ʀaiɴЬow", // hue: 212 + "raіɴbοw", // hue: 218 + "rаіnЬow", // hue: 218 + "ʀaiɴbοѡ", // hue: 221 + "ʀaiɴЬοw", // hue: 224 + "ʀaіnbοѡ", // hue: 227 + "raiɴboѡ", // hue: 230 + "ʀaіnbοw", // hue: 230 + "ʀaіnЬοw", // hue: 230 + "ʀаinЬοѡ", // hue: 231 + "rainboѡ", // hue: 232 + "raіnbow", // hue: 232 + "ʀаіɴЬow", // hue: 233 + "ʀaіɴЬoѡ", // hue: 239 + "ʀаіnЬοѡ", // hue: 246 + "raiɴbοѡ", // hue: 248 + "ʀаiɴЬow", // hue: 248 + "raіɴЬοѡ", // hue: 249 + "raiɴЬοw", // hue: 251 + "rаіɴЬoѡ", // hue: 251 + "ʀaiɴbow", // hue: 251 + "ʀаinbοw", // hue: 251 + "raіnbοѡ", // hue: 254 +]; diff --git a/tests/source/configs/fn_args_layout/compressed.rs b/tests/source/configs/fn_params_layout/compressed.rs similarity index 92% rename from tests/source/configs/fn_args_layout/compressed.rs rename to tests/source/configs/fn_params_layout/compressed.rs index 66a371c259f0c..eb573d3121f57 100644 --- a/tests/source/configs/fn_args_layout/compressed.rs +++ b/tests/source/configs/fn_params_layout/compressed.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Compressed +// rustfmt-fn_params_layout: Compressed // Function arguments density trait Lorem { diff --git a/tests/source/configs/fn_args_layout/tall.rs b/tests/source/configs/fn_params_layout/tall.rs similarity index 93% rename from tests/source/configs/fn_args_layout/tall.rs rename to tests/source/configs/fn_params_layout/tall.rs index f11e86fd3139c..4be34f0fe4ac1 100644 --- a/tests/source/configs/fn_args_layout/tall.rs +++ b/tests/source/configs/fn_params_layout/tall.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Tall +// rustfmt-fn_params_layout: Tall // Function arguments density trait Lorem { diff --git a/tests/source/configs/fn_args_layout/vertical.rs b/tests/source/configs/fn_params_layout/vertical.rs similarity index 92% rename from tests/source/configs/fn_args_layout/vertical.rs rename to tests/source/configs/fn_params_layout/vertical.rs index a23cc025225fb..674968023f997 100644 --- a/tests/source/configs/fn_args_layout/vertical.rs +++ b/tests/source/configs/fn_params_layout/vertical.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Vertical +// rustfmt-fn_params_layout: Vertical // Function arguments density trait Lorem { diff --git a/tests/source/enum.rs b/tests/source/enum.rs index 0ed9651abe722..a7b9616929cb0 100644 --- a/tests/source/enum.rs +++ b/tests/source/enum.rs @@ -36,7 +36,7 @@ enum StructLikeVariants { Normal(u32, String, ), StructLike { x: i32, // Test comment // Pre-comment - #[Attr50] y: SomeType, // Aanother Comment + #[Attr50] y: SomeType, // Another Comment }, SL { a: A } } diff --git a/tests/source/fn-custom-7.rs b/tests/source/fn-custom-7.rs index d5330196bf795..3ecd8701727ad 100644 --- a/tests/source/fn-custom-7.rs +++ b/tests/source/fn-custom-7.rs @@ -1,5 +1,5 @@ // rustfmt-normalize_comments: true -// rustfmt-fn_args_layout: Vertical +// rustfmt-fn_params_layout: Vertical // rustfmt-brace_style: AlwaysNextLine // Case with only one variable. diff --git a/tests/source/fn-custom.rs b/tests/source/fn-custom.rs index 77ced4c5e0e10..64ef0ecfaae49 100644 --- a/tests/source/fn-custom.rs +++ b/tests/source/fn-custom.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Compressed +// rustfmt-fn_params_layout: Compressed // Test some of the ways function signatures can be customised. // Test compressed layout of args. diff --git a/tests/source/fn_args_layout-vertical.rs b/tests/source/fn_args_layout-vertical.rs index 759bc83d01570..fd6e3f0442ec1 100644 --- a/tests/source/fn_args_layout-vertical.rs +++ b/tests/source/fn_args_layout-vertical.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Vertical +// rustfmt-fn_params_layout: Vertical // Empty list should stay on one line. fn do_bar( diff --git a/tests/source/issue-3987/format_macro_bodies_true.rs b/tests/source/issue-3987/format_macro_bodies_true.rs new file mode 100644 index 0000000000000..9af114fbe574d --- /dev/null +++ b/tests/source/issue-3987/format_macro_bodies_true.rs @@ -0,0 +1,26 @@ +// rustfmt-format_macro_bodies: true + +// with comments +macro_rules! macros { + () => {{ + Struct { + field: ( + 42 + //comment 1 + 42 + //comment 2 + ), + }; + }}; +} + +// without comments +macro_rules! macros { + () => {{ + Struct { + field: ( + 42 + + 42 + ), + }; + }}; +} diff --git a/tests/source/issue-4643.rs b/tests/source/issue-4643.rs new file mode 100644 index 0000000000000..382072d9004bf --- /dev/null +++ b/tests/source/issue-4643.rs @@ -0,0 +1,23 @@ +// output doesn't get corrupted when using comments within generic type parameters of a trait + +pub trait Something< + A, + // some comment + B, + C +> { + fn a(&self, x: A) -> i32; + fn b(&self, x: B) -> i32; + fn c(&self, x: C) -> i32; +} + +pub trait SomethingElse< + A, + /* some comment */ + B, + C +> { + fn a(&self, x: A) -> i32; + fn b(&self, x: B) -> i32; + fn c(&self, x: C) -> i32; +} diff --git a/tests/source/issue-4689/one.rs b/tests/source/issue-4689/one.rs new file mode 100644 index 0000000000000..d048eb10fb15c --- /dev/null +++ b/tests/source/issue-4689/one.rs @@ -0,0 +1,149 @@ +// rustfmt-version: One + +// Based on the issue description +pub trait PrettyPrinter<'tcx>: +Printer< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> +{ +// +} +pub trait PrettyPrinter<'tcx>: +Printer< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> + fmt::Write +{ +// +} +pub trait PrettyPrinter<'tcx>: +Printer< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> + fmt::Write1 + fmt::Write2 +{ +// +} +pub trait PrettyPrinter<'tcx>: +fmt::Write + Printer< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> +{ +// +} +pub trait PrettyPrinter<'tcx>: +fmt::Write + Printer1< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> + Printer2< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> +{ +// +} + +// Some test cases to ensure other cases formatting were not changed +fn f() -> Box< +FnMut() -> Thing< +WithType = LongItemName, +Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger, +>, +> { +} +fn f() -> Box< +FnMut() -> Thing< +WithType = LongItemName, +Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger, +> + fmt::Write1 ++ fmt::Write2, +> { +} + +fn foo(foo2: F) +where +F: Fn( +// this comment is deleted +) +{ +} +fn foo(foo2: F) +where +F: Fn( +// this comment is deleted +) + fmt::Write +{ +} + +fn elaborate_bounds(mut mk_cand: F) +where +F: for<> FnMut( +&mut ProbeContext<>, +ty::PolyTraitRefffffffffffffffffffffffffffffffff<>, +tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem, +), +{ +} +fn elaborate_bounds(mut mk_cand: F) +where +F: for<> FnMut( +&mut ProbeContext<>, +ty::PolyTraitRefffffffffffffffffffffffffffffffff<>, +tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem, +) + fmt::Write, +{ +} + +fn build_sorted_static_get_entry_names( +mut entries: entryyyyyyyy, +) -> ( +impl Fn( +AlphabeticalTraversal, +Seconddddddddddddddddddddddddddddddddddd +) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm ++ Sendddddddddddddddddddddddddddddddddddddddddddd +) { +} + +pub trait SomeTrait: +Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee ++ Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq +{ +} + +trait B = where +for<'b> &'b Self: Send ++ Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee ++ Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy; diff --git a/tests/source/issue-4689/two.rs b/tests/source/issue-4689/two.rs new file mode 100644 index 0000000000000..ea7feda825d46 --- /dev/null +++ b/tests/source/issue-4689/two.rs @@ -0,0 +1,149 @@ +// rustfmt-version: Two + +// Based on the issue description +pub trait PrettyPrinter<'tcx>: +Printer< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> +{ +// +} +pub trait PrettyPrinter<'tcx>: +Printer< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> + fmt::Write +{ +// +} +pub trait PrettyPrinter<'tcx>: +Printer< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> + fmt::Write1 + fmt::Write2 +{ +// +} +pub trait PrettyPrinter<'tcx>: +fmt::Write + Printer< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> +{ +// +} +pub trait PrettyPrinter<'tcx>: +fmt::Write + Printer1< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> + Printer2< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> +{ +// +} + +// Some test cases to ensure other cases formatting were not changed +fn f() -> Box< +FnMut() -> Thing< +WithType = LongItemName, +Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger, +>, +> { +} +fn f() -> Box< +FnMut() -> Thing< +WithType = LongItemName, +Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger, +> + fmt::Write1 ++ fmt::Write2, +> { +} + +fn foo(foo2: F) +where +F: Fn( +// this comment is deleted +) +{ +} +fn foo(foo2: F) +where +F: Fn( +// this comment is deleted +) + fmt::Write +{ +} + +fn elaborate_bounds(mut mk_cand: F) +where +F: for<> FnMut( +&mut ProbeContext<>, +ty::PolyTraitRefffffffffffffffffffffffffffffffff<>, +tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem, +), +{ +} +fn elaborate_bounds(mut mk_cand: F) +where +F: for<> FnMut( +&mut ProbeContext<>, +ty::PolyTraitRefffffffffffffffffffffffffffffffff<>, +tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem, +) + fmt::Write, +{ +} + +fn build_sorted_static_get_entry_names( +mut entries: entryyyyyyyy, +) -> ( +impl Fn( +AlphabeticalTraversal, +Seconddddddddddddddddddddddddddddddddddd +) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm ++ Sendddddddddddddddddddddddddddddddddddddddddddd +) { +} + +pub trait SomeTrait: +Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee ++ Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq +{ +} + +trait B = where +for<'b> &'b Self: Send ++ Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee ++ Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy; diff --git a/tests/source/issue_1306.rs b/tests/source/issue_1306.rs new file mode 100644 index 0000000000000..03b78e34108cc --- /dev/null +++ b/tests/source/issue_1306.rs @@ -0,0 +1,29 @@ +// rustfmt-max_width: 160 +// rustfmt-fn_call_width: 96 +// rustfmt-fn_args_layout: Compressed +// rustfmt-trailing_comma: Always +// rustfmt-wrap_comments: true + +fn foo() { + for elem in try!(gen_epub_book::ops::parse_descriptor_file(&mut try!(File::open(&opts.source_file.1).map_err(|_| { + gen_epub_book::Error::Io { + desc: "input file", + op: "open", + more: None, + } + })), + "input file")) { + println!("{}", elem); + } +} + +fn write_content() { + io::copy(try!(File::open(in_f).map_err(|_| { + Error::Io { + desc: "Content", + op: "open", + more: None, + } + })), + w); +} diff --git a/tests/source/issue_3245.rs b/tests/source/issue_3245.rs new file mode 100644 index 0000000000000..0279246ed6ac4 --- /dev/null +++ b/tests/source/issue_3245.rs @@ -0,0 +1,4 @@ +fn main() { + let x = 1; + ;let y = 3; +} diff --git a/tests/source/issue_3561.rs b/tests/source/issue_3561.rs new file mode 100644 index 0000000000000..8f6cd8f9fbce5 --- /dev/null +++ b/tests/source/issue_3561.rs @@ -0,0 +1,6 @@ +fn main() {;7 +} + +fn main() { + ;7 +} diff --git a/tests/source/skip_macro_invocations/all.rs b/tests/source/skip_macro_invocations/all.rs new file mode 100644 index 0000000000000..d0437ee10fd15 --- /dev/null +++ b/tests/source/skip_macro_invocations/all.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: ["*"] + +// Should skip this invocation +items!( + const _: u8 = 0; +); + +// Should skip this invocation +renamed_items!( + const _: u8 = 0; +); diff --git a/tests/source/skip_macro_invocations/all_and_name.rs b/tests/source/skip_macro_invocations/all_and_name.rs new file mode 100644 index 0000000000000..1f6722344fe3b --- /dev/null +++ b/tests/source/skip_macro_invocations/all_and_name.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: ["*","items"] + +// Should skip this invocation +items!( + const _: u8 = 0; +); + +// Should also skip this invocation, as the wildcard covers it +renamed_items!( + const _: u8 = 0; +); diff --git a/tests/source/skip_macro_invocations/empty.rs b/tests/source/skip_macro_invocations/empty.rs new file mode 100644 index 0000000000000..f3dd89dc4db33 --- /dev/null +++ b/tests/source/skip_macro_invocations/empty.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: [] + +// Should not skip this invocation +items!( + const _: u8 = 0; +); + +// Should not skip this invocation +renamed_items!( + const _: u8 = 0; +); diff --git a/tests/source/skip_macro_invocations/name.rs b/tests/source/skip_macro_invocations/name.rs new file mode 100644 index 0000000000000..7fa5d3a6f715a --- /dev/null +++ b/tests/source/skip_macro_invocations/name.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: ["items"] + +// Should skip this invocation +items!( + const _: u8 = 0; +); + +// Should not skip this invocation +renamed_items!( + const _: u8 = 0; +); diff --git a/tests/source/skip_macro_invocations/name_unknown.rs b/tests/source/skip_macro_invocations/name_unknown.rs new file mode 100644 index 0000000000000..d56695325240d --- /dev/null +++ b/tests/source/skip_macro_invocations/name_unknown.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["unknown"] + +// Should not skip this invocation +items!( + const _: u8 = 0; +); diff --git a/tests/source/skip_macro_invocations/names.rs b/tests/source/skip_macro_invocations/names.rs new file mode 100644 index 0000000000000..a920381a4552c --- /dev/null +++ b/tests/source/skip_macro_invocations/names.rs @@ -0,0 +1,16 @@ +// rustfmt-skip_macro_invocations: ["foo","bar"] + +// Should skip this invocation +foo!( + const _: u8 = 0; +); + +// Should skip this invocation +bar!( + const _: u8 = 0; +); + +// Should not skip this invocation +baz!( + const _: u8 = 0; +); diff --git a/tests/source/skip_macro_invocations/path_qualified_invocation_mismatch.rs b/tests/source/skip_macro_invocations/path_qualified_invocation_mismatch.rs new file mode 100644 index 0000000000000..61296869a5065 --- /dev/null +++ b/tests/source/skip_macro_invocations/path_qualified_invocation_mismatch.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["items"] + +// Should not skip this invocation +self::items!( + const _: u8 = 0; +); diff --git a/tests/source/skip_macro_invocations/path_qualified_match.rs b/tests/source/skip_macro_invocations/path_qualified_match.rs new file mode 100644 index 0000000000000..9398918a9e11e --- /dev/null +++ b/tests/source/skip_macro_invocations/path_qualified_match.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["self::items"] + +// Should skip this invocation +self::items!( + const _: u8 = 0; +); diff --git a/tests/source/skip_macro_invocations/path_qualified_name_mismatch.rs b/tests/source/skip_macro_invocations/path_qualified_name_mismatch.rs new file mode 100644 index 0000000000000..4e3eb542dbea4 --- /dev/null +++ b/tests/source/skip_macro_invocations/path_qualified_name_mismatch.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["self::items"] + +// Should not skip this invocation +items!( + const _: u8 = 0; +); diff --git a/tests/source/skip_macro_invocations/use_alias_examples.rs b/tests/source/skip_macro_invocations/use_alias_examples.rs new file mode 100644 index 0000000000000..43cb8015de58a --- /dev/null +++ b/tests/source/skip_macro_invocations/use_alias_examples.rs @@ -0,0 +1,32 @@ +// rustfmt-skip_macro_invocations: ["aaa","ccc"] + +// These tests demonstrate a realistic use case with use aliases. +// The use statements should not impact functionality in any way. + +use crate::{aaa, bbb, ddd}; + +// No use alias, invocation in list +// Should skip this invocation +aaa!( + const _: u8 = 0; +); + +// Use alias, invocation in list +// Should skip this invocation +use crate::bbb as ccc; +ccc!( + const _: u8 = 0; +); + +// Use alias, invocation not in list +// Should not skip this invocation +use crate::ddd as eee; +eee!( + const _: u8 = 0; +); + +// No use alias, invocation not in list +// Should not skip this invocation +fff!( + const _: u8 = 0; +); diff --git a/tests/source/tuple.rs b/tests/source/tuple.rs index 9a0f979fbca38..5189a7454f3a7 100644 --- a/tests/source/tuple.rs +++ b/tests/source/tuple.rs @@ -1,4 +1,4 @@ -// Test tuple litterals +// Test tuple literals fn foo() { let a = (a, a, a, a, a); diff --git a/tests/source/wrap_comments_should_not_imply_format_doc_comments.rs b/tests/source/wrap_comments_should_not_imply_format_doc_comments.rs index 78b3ce146f289..56064e4a4cccf 100644 --- a/tests/source/wrap_comments_should_not_imply_format_doc_comments.rs +++ b/tests/source/wrap_comments_should_not_imply_format_doc_comments.rs @@ -11,6 +11,6 @@ /// fn foo() {} -/// A long commment for wrapping +/// A long comment for wrapping /// This is a long long long long long long long long long long long long long long long long long long long long sentence. fn bar() {} diff --git a/tests/target/cfg_if/detect/arch/x86.rs b/tests/target/cfg_if/detect/arch/x86.rs index 02d5eed1c2923..47210cae2aaa0 100644 --- a/tests/target/cfg_if/detect/arch/x86.rs +++ b/tests/target/cfg_if/detect/arch/x86.rs @@ -314,7 +314,7 @@ pub enum Feature { tbm, /// POPCNT (Population Count) popcnt, - /// FXSR (Floating-point context fast save and restor) + /// FXSR (Floating-point context fast save and restore) fxsr, /// XSAVE (Save Processor Extended States) xsave, diff --git a/tests/target/comments_unicode.rs b/tests/target/comments_unicode.rs new file mode 100644 index 0000000000000..3e1b6b0a28fe4 --- /dev/null +++ b/tests/target/comments_unicode.rs @@ -0,0 +1,140 @@ +impl Default for WhitespaceCharacters { + fn default() -> Self { + Self { + space: '·', // U+00B7 + nbsp: '⍽', // U+237D + tab: '→', // U+2192 + newline: '⏎', // U+23CE + } + } +} + +const RAINBOWS: &[&str] = &[ + "rаinЬοѡ", // hue: 0 + "raіnЬοw", // hue: 2 + "rаіɴЬow", // hue: 2 + "raіɴЬoѡ", // hue: 8 + "ʀainЬow", // hue: 8 + "ʀaіɴboѡ", // hue: 8 + "ʀаіnbοw", // hue: 11 + "rainЬoѡ", // hue: 14 + "raіɴbow", // hue: 14 + "rаiɴЬow", // hue: 20 + "raіnЬow", // hue: 26 + "ʀaiɴbοw", // hue: 32 + "raіɴboѡ", // hue: 35 + "rаiɴbow", // hue: 35 + "rаіnbοw", // hue: 38 + "rаinЬow", // hue: 47 + "ʀaіnboѡ", // hue: 47 + "ʀaіnЬoѡ", // hue: 47 + "ʀаіɴbοw", // hue: 53 + "ʀaіnЬοѡ", // hue: 57 + "raiɴЬoѡ", // hue: 68 + "ʀainbοѡ", // hue: 68 + "ʀаinboѡ", // hue: 68 + "ʀаiɴbοw", // hue: 68 + "ʀаіnbow", // hue: 68 + "rаіnЬοѡ", // hue: 69 + "ʀainЬοw", // hue: 71 + "raiɴbow", // hue: 73 + "raіnЬoѡ", // hue: 74 + "rаіɴbοw", // hue: 77 + "raіnЬοѡ", // hue: 81 + "raiɴЬow", // hue: 83 + "ʀainbοw", // hue: 83 + "ʀаinbow", // hue: 83 + "ʀаiɴbοѡ", // hue: 83 + "ʀаіnboѡ", // hue: 83 + "ʀаіɴЬοѡ", // hue: 84 + "rainЬow", // hue: 85 + "ʀаiɴЬοw", // hue: 86 + "ʀаіnbοѡ", // hue: 89 + "ʀаіnЬοw", // hue: 92 + "rаiɴbοw", // hue: 95 + "ʀаіɴbοѡ", // hue: 98 + "ʀаiɴЬοѡ", // hue: 99 + "raіnbοw", // hue: 101 + "ʀаіɴЬοw", // hue: 101 + "ʀaiɴboѡ", // hue: 104 + "ʀаinbοѡ", // hue: 104 + "rаiɴbοѡ", // hue: 107 + "ʀаinЬοw", // hue: 107 + "rаiɴЬοw", // hue: 110 + "rаіnboѡ", // hue: 110 + "rаіnbοѡ", // hue: 113 + "ʀainЬοѡ", // hue: 114 + "rаіnЬοw", // hue: 116 + "ʀaіɴЬow", // hue: 116 + "rаinbοw", // hue: 122 + "ʀаіɴboѡ", // hue: 125 + "rаinbοѡ", // hue: 131 + "rainbow", // hue: 134 + "rаinЬοw", // hue: 134 + "ʀаiɴboѡ", // hue: 140 + "rainЬοѡ", // hue: 141 + "raіɴЬow", // hue: 143 + "ʀainЬoѡ", // hue: 143 + "ʀaіɴbow", // hue: 143 + "ʀainbow", // hue: 148 + "rаіɴboѡ", // hue: 149 + "ʀainboѡ", // hue: 155 + "ʀaіnbow", // hue: 155 + "ʀaіnЬow", // hue: 155 + "raiɴbοw", // hue: 158 + "ʀаiɴЬoѡ", // hue: 158 + "rainbοw", // hue: 160 + "rаinbow", // hue: 160 + "ʀaіɴbοѡ", // hue: 164 + "ʀаiɴbow", // hue: 164 + "ʀаіnЬoѡ", // hue: 164 + "ʀaiɴЬοѡ", // hue: 165 + "rаiɴboѡ", // hue: 167 + "ʀaіɴЬοw", // hue: 167 + "ʀaіɴЬοѡ", // hue: 171 + "raіnboѡ", // hue: 173 + "ʀаіɴЬoѡ", // hue: 173 + "rаіɴbοѡ", // hue: 176 + "ʀаinЬow", // hue: 176 + "rаiɴЬοѡ", // hue: 177 + "rаіɴЬοw", // hue: 179 + "ʀаinЬoѡ", // hue: 179 + "ʀаіɴbow", // hue: 179 + "rаiɴЬoѡ", // hue: 182 + "raіɴbοѡ", // hue: 188 + "rаіnЬoѡ", // hue: 188 + "raiɴЬοѡ", // hue: 189 + "raіɴЬοw", // hue: 191 + "ʀaіɴbοw", // hue: 191 + "ʀаіnЬow", // hue: 191 + "rainbοѡ", // hue: 194 + "rаinboѡ", // hue: 194 + "rаіnbow", // hue: 194 + "rainЬοw", // hue: 197 + "rаinЬoѡ", // hue: 206 + "rаіɴbow", // hue: 206 + "rаіɴЬοѡ", // hue: 210 + "ʀaiɴЬow", // hue: 212 + "raіɴbοw", // hue: 218 + "rаіnЬow", // hue: 218 + "ʀaiɴbοѡ", // hue: 221 + "ʀaiɴЬοw", // hue: 224 + "ʀaіnbοѡ", // hue: 227 + "raiɴboѡ", // hue: 230 + "ʀaіnbοw", // hue: 230 + "ʀaіnЬοw", // hue: 230 + "ʀаinЬοѡ", // hue: 231 + "rainboѡ", // hue: 232 + "raіnbow", // hue: 232 + "ʀаіɴЬow", // hue: 233 + "ʀaіɴЬoѡ", // hue: 239 + "ʀаіnЬοѡ", // hue: 246 + "raiɴbοѡ", // hue: 248 + "ʀаiɴЬow", // hue: 248 + "raіɴЬοѡ", // hue: 249 + "raiɴЬοw", // hue: 251 + "rаіɴЬoѡ", // hue: 251 + "ʀaiɴbow", // hue: 251 + "ʀаinbοw", // hue: 251 + "raіnbοѡ", // hue: 254 +]; diff --git a/tests/target/configs/fn_args_layout/compressed.rs b/tests/target/configs/fn_params_layout/compressed.rs similarity index 92% rename from tests/target/configs/fn_args_layout/compressed.rs rename to tests/target/configs/fn_params_layout/compressed.rs index f189446e25d44..ff32f0f1d5868 100644 --- a/tests/target/configs/fn_args_layout/compressed.rs +++ b/tests/target/configs/fn_params_layout/compressed.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Compressed +// rustfmt-fn_params_layout: Compressed // Function arguments density trait Lorem { diff --git a/tests/target/configs/fn_args_layout/tall.rs b/tests/target/configs/fn_params_layout/tall.rs similarity index 94% rename from tests/target/configs/fn_args_layout/tall.rs rename to tests/target/configs/fn_params_layout/tall.rs index 20f308973acbc..25a86799af0d8 100644 --- a/tests/target/configs/fn_args_layout/tall.rs +++ b/tests/target/configs/fn_params_layout/tall.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Tall +// rustfmt-fn_params_layout: Tall // Function arguments density trait Lorem { diff --git a/tests/target/configs/fn_args_layout/vertical.rs b/tests/target/configs/fn_params_layout/vertical.rs similarity index 94% rename from tests/target/configs/fn_args_layout/vertical.rs rename to tests/target/configs/fn_params_layout/vertical.rs index 6c695a75df9a2..7a0e42415f3b9 100644 --- a/tests/target/configs/fn_args_layout/vertical.rs +++ b/tests/target/configs/fn_params_layout/vertical.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Vertical +// rustfmt-fn_params_layout: Vertical // Function arguments density trait Lorem { diff --git a/tests/target/enum.rs b/tests/target/enum.rs index 9a25126b44ecb..70fc8ab376ccd 100644 --- a/tests/target/enum.rs +++ b/tests/target/enum.rs @@ -43,7 +43,7 @@ enum StructLikeVariants { x: i32, // Test comment // Pre-comment #[Attr50] - y: SomeType, // Aanother Comment + y: SomeType, // Another Comment }, SL { a: A, diff --git a/tests/target/fn-custom-7.rs b/tests/target/fn-custom-7.rs index 2c20ac5a75249..f6a1a90c3fc68 100644 --- a/tests/target/fn-custom-7.rs +++ b/tests/target/fn-custom-7.rs @@ -1,5 +1,5 @@ // rustfmt-normalize_comments: true -// rustfmt-fn_args_layout: Vertical +// rustfmt-fn_params_layout: Vertical // rustfmt-brace_style: AlwaysNextLine // Case with only one variable. diff --git a/tests/target/fn-custom.rs b/tests/target/fn-custom.rs index 2eb2a973d243d..506d9de34370b 100644 --- a/tests/target/fn-custom.rs +++ b/tests/target/fn-custom.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Compressed +// rustfmt-fn_params_layout: Compressed // Test some of the ways function signatures can be customised. // Test compressed layout of args. diff --git a/tests/target/fn_args_layout-vertical.rs b/tests/target/fn_args_layout-vertical.rs index da0ac981d872d..bfeca15c967ed 100644 --- a/tests/target/fn_args_layout-vertical.rs +++ b/tests/target/fn_args_layout-vertical.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Vertical +// rustfmt-fn_params_layout: Vertical // Empty list should stay on one line. fn do_bar() -> u8 { diff --git a/tests/target/issue-2534/format_macro_matchers_false.rs b/tests/target/issue-2534/format_macro_matchers_false.rs new file mode 100644 index 0000000000000..2038ed7f1d014 --- /dev/null +++ b/tests/target/issue-2534/format_macro_matchers_false.rs @@ -0,0 +1,6 @@ +// rustfmt-format_macro_matchers: false + +macro_rules! foo { + ($a:ident : $b:ty) => {}; + ($a:ident $b:ident $c:ident) => {}; +} diff --git a/tests/target/issue-2534/format_macro_matchers_true.rs b/tests/target/issue-2534/format_macro_matchers_true.rs new file mode 100644 index 0000000000000..01d939add4dc2 --- /dev/null +++ b/tests/target/issue-2534/format_macro_matchers_true.rs @@ -0,0 +1,6 @@ +// rustfmt-format_macro_matchers: true + +macro_rules! foo { + ($a:ident : $b:ty) => {}; + ($a:ident $b:ident $c:ident) => {}; +} diff --git a/tests/target/issue-3987/format_macro_bodies_false.rs b/tests/target/issue-3987/format_macro_bodies_false.rs new file mode 100644 index 0000000000000..1352b762e4509 --- /dev/null +++ b/tests/target/issue-3987/format_macro_bodies_false.rs @@ -0,0 +1,26 @@ +// rustfmt-format_macro_bodies: false + +// with comments +macro_rules! macros { + () => {{ + Struct { + field: ( + 42 + //comment 1 + 42 + //comment 2 + ), + }; + }}; +} + +// without comments +macro_rules! macros { + () => {{ + Struct { + field: ( + 42 + + 42 + ), + }; + }}; +} diff --git a/tests/target/issue-3987/format_macro_bodies_true.rs b/tests/target/issue-3987/format_macro_bodies_true.rs new file mode 100644 index 0000000000000..88d57159c859f --- /dev/null +++ b/tests/target/issue-3987/format_macro_bodies_true.rs @@ -0,0 +1,21 @@ +// rustfmt-format_macro_bodies: true + +// with comments +macro_rules! macros { + () => {{ + Struct { + field: ( + 42 + //comment 1 + 42 + //comment 2 + ), + }; + }}; +} + +// without comments +macro_rules! macros { + () => {{ + Struct { field: (42 + 42) }; + }}; +} diff --git a/tests/target/issue-4643.rs b/tests/target/issue-4643.rs new file mode 100644 index 0000000000000..ef99e4db382cb --- /dev/null +++ b/tests/target/issue-4643.rs @@ -0,0 +1,19 @@ +// output doesn't get corrupted when using comments within generic type parameters of a trait + +pub trait Something< + A, + // some comment + B, + C, +> +{ + fn a(&self, x: A) -> i32; + fn b(&self, x: B) -> i32; + fn c(&self, x: C) -> i32; +} + +pub trait SomethingElse { + fn a(&self, x: A) -> i32; + fn b(&self, x: B) -> i32; + fn c(&self, x: C) -> i32; +} diff --git a/tests/target/issue-4689/one.rs b/tests/target/issue-4689/one.rs new file mode 100644 index 0000000000000..7735e34f3b5ed --- /dev/null +++ b/tests/target/issue-4689/one.rs @@ -0,0 +1,150 @@ +// rustfmt-version: One + +// Based on the issue description +pub trait PrettyPrinter<'tcx>: + Printer< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, +> +{ + // +} +pub trait PrettyPrinter<'tcx>: + Printer< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > + fmt::Write +{ + // +} +pub trait PrettyPrinter<'tcx>: + Printer< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > + fmt::Write1 + + fmt::Write2 +{ + // +} +pub trait PrettyPrinter<'tcx>: + fmt::Write + + Printer< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > +{ + // +} +pub trait PrettyPrinter<'tcx>: + fmt::Write + + Printer1< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > + Printer2< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > +{ + // +} + +// Some test cases to ensure other cases formatting were not changed +fn f() -> Box< + FnMut() -> Thing< + WithType = LongItemName, + Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger, + >, +> { +} +fn f() -> Box< + FnMut() -> Thing< + WithType = LongItemName, + Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger, + > + fmt::Write1 + + fmt::Write2, +> { +} + +fn foo(foo2: F) +where + F: Fn( + // this comment is deleted + ), +{ +} +fn foo(foo2: F) +where + F: Fn( + // this comment is deleted + ) + fmt::Write, +{ +} + +fn elaborate_bounds(mut mk_cand: F) +where + F: FnMut( + &mut ProbeContext, + ty::PolyTraitRefffffffffffffffffffffffffffffffff, + tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem, + ), +{ +} +fn elaborate_bounds(mut mk_cand: F) +where + F: FnMut( + &mut ProbeContext, + ty::PolyTraitRefffffffffffffffffffffffffffffffff, + tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem, + ) + fmt::Write, +{ +} + +fn build_sorted_static_get_entry_names( + mut entries: entryyyyyyyy, +) -> (impl Fn( + AlphabeticalTraversal, + Seconddddddddddddddddddddddddddddddddddd, +) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm + + Sendddddddddddddddddddddddddddddddddddddddddddd) { +} + +pub trait SomeTrait: + Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee + + Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq +{ +} + +trait B = where + for<'b> &'b Self: Send + + Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee + + Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy; diff --git a/tests/target/issue-4689/two.rs b/tests/target/issue-4689/two.rs new file mode 100644 index 0000000000000..e3b5cd22810ba --- /dev/null +++ b/tests/target/issue-4689/two.rs @@ -0,0 +1,152 @@ +// rustfmt-version: Two + +// Based on the issue description +pub trait PrettyPrinter<'tcx>: + Printer< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > +{ + // +} +pub trait PrettyPrinter<'tcx>: + Printer< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > + fmt::Write +{ + // +} +pub trait PrettyPrinter<'tcx>: + Printer< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > + fmt::Write1 + + fmt::Write2 +{ + // +} +pub trait PrettyPrinter<'tcx>: + fmt::Write + + Printer< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > +{ + // +} +pub trait PrettyPrinter<'tcx>: + fmt::Write + + Printer1< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > + Printer2< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > +{ + // +} + +// Some test cases to ensure other cases formatting were not changed +fn f() -> Box< + FnMut() -> Thing< + WithType = LongItemName, + Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger, + >, +> { +} +fn f() -> Box< + FnMut() -> Thing< + WithType = LongItemName, + Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger, + > + fmt::Write1 + + fmt::Write2, +> { +} + +fn foo(foo2: F) +where + F: Fn( + // this comment is deleted + ), +{ +} +fn foo(foo2: F) +where + F: Fn( + // this comment is deleted + ) + fmt::Write, +{ +} + +fn elaborate_bounds(mut mk_cand: F) +where + F: FnMut( + &mut ProbeContext, + ty::PolyTraitRefffffffffffffffffffffffffffffffff, + tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem, + ), +{ +} +fn elaborate_bounds(mut mk_cand: F) +where + F: FnMut( + &mut ProbeContext, + ty::PolyTraitRefffffffffffffffffffffffffffffffff, + tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem, + ) + fmt::Write, +{ +} + +fn build_sorted_static_get_entry_names( + mut entries: entryyyyyyyy, +) -> ( + impl Fn( + AlphabeticalTraversal, + Seconddddddddddddddddddddddddddddddddddd, + ) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm + + Sendddddddddddddddddddddddddddddddddddddddddddd +) { +} + +pub trait SomeTrait: + Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee + + Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq +{ +} + +trait B = where + for<'b> &'b Self: Send + + Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee + + Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy; diff --git a/tests/target/issue-4791/issue_4928.rs b/tests/target/issue-4791/issue_4928.rs index 588656b535fa1..29f6bda90631b 100644 --- a/tests/target/issue-4791/issue_4928.rs +++ b/tests/target/issue-4791/issue_4928.rs @@ -1,7 +1,7 @@ // rustfmt-brace_style: SameLineWhere // rustfmt-comment_width: 100 // rustfmt-edition: 2018 -// rustfmt-fn_args_layout: Compressed +// rustfmt-fn_params_layout: Compressed // rustfmt-hard_tabs: false // rustfmt-match_block_trailing_comma: true // rustfmt-max_width: 100 diff --git a/tests/target/issue-5358.rs b/tests/target/issue-5358.rs new file mode 100644 index 0000000000000..d4bf4909ad76f --- /dev/null +++ b/tests/target/issue-5358.rs @@ -0,0 +1,4 @@ +// Test /* comment */ inside trait generics does not get duplicated. +trait Test {} + +trait TestTwo {} diff --git a/tests/target/issue_1306.rs b/tests/target/issue_1306.rs new file mode 100644 index 0000000000000..6bb514cdfe550 --- /dev/null +++ b/tests/target/issue_1306.rs @@ -0,0 +1,33 @@ +// rustfmt-max_width: 160 +// rustfmt-fn_call_width: 96 +// rustfmt-fn_args_layout: Compressed +// rustfmt-trailing_comma: Always +// rustfmt-wrap_comments: true + +fn foo() { + for elem in try!(gen_epub_book::ops::parse_descriptor_file( + &mut try!(File::open(&opts.source_file.1).map_err(|_| { + gen_epub_book::Error::Io { + desc: "input file", + op: "open", + more: None, + } + })), + "input file" + )) { + println!("{}", elem); + } +} + +fn write_content() { + io::copy( + try!(File::open(in_f).map_err(|_| { + Error::Io { + desc: "Content", + op: "open", + more: None, + } + })), + w, + ); +} diff --git a/tests/target/issue_3033.rs b/tests/target/issue_3033.rs new file mode 100644 index 0000000000000..e12249a6da6f3 --- /dev/null +++ b/tests/target/issue_3033.rs @@ -0,0 +1,2 @@ +use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerBinding:: + BluetoothRemoteGATTServerMethods; diff --git a/tests/target/issue_3245.rs b/tests/target/issue_3245.rs new file mode 100644 index 0000000000000..8f442f1181a59 --- /dev/null +++ b/tests/target/issue_3245.rs @@ -0,0 +1,4 @@ +fn main() { + let x = 1; + let y = 3; +} diff --git a/tests/target/issue_3561.rs b/tests/target/issue_3561.rs new file mode 100644 index 0000000000000..846a14d86a5ff --- /dev/null +++ b/tests/target/issue_3561.rs @@ -0,0 +1,7 @@ +fn main() { + 7 +} + +fn main() { + 7 +} diff --git a/tests/target/issue_4350.rs b/tests/target/issue_4350.rs new file mode 100644 index 0000000000000..a94c5c32188d2 --- /dev/null +++ b/tests/target/issue_4350.rs @@ -0,0 +1,13 @@ +//rustfmt-format_macro_bodies: true + +macro_rules! mto_text_left { + ($buf:ident, $n:ident, $pos:ident, $state:ident) => {{ + let cursor = loop { + state = match iter.next() { + None if $pos == DP::Start => break last_char_idx($buf), + None /*some comment */ => break 0, + }; + }; + Ok(saturate_cursor($buf, cursor)) + }}; +} diff --git a/tests/target/issue_5668.rs b/tests/target/issue_5668.rs new file mode 100644 index 0000000000000..bbd9a530b81c0 --- /dev/null +++ b/tests/target/issue_5668.rs @@ -0,0 +1,8 @@ +type Foo = impl Send; +struct Struct< + const C: usize = { + let _: Foo = (); + //~^ ERROR: mismatched types + 0 + }, +>; diff --git a/tests/target/skip_macro_invocations/all.rs b/tests/target/skip_macro_invocations/all.rs new file mode 100644 index 0000000000000..d0437ee10fd15 --- /dev/null +++ b/tests/target/skip_macro_invocations/all.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: ["*"] + +// Should skip this invocation +items!( + const _: u8 = 0; +); + +// Should skip this invocation +renamed_items!( + const _: u8 = 0; +); diff --git a/tests/target/skip_macro_invocations/all_and_name.rs b/tests/target/skip_macro_invocations/all_and_name.rs new file mode 100644 index 0000000000000..1f6722344fe3b --- /dev/null +++ b/tests/target/skip_macro_invocations/all_and_name.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: ["*","items"] + +// Should skip this invocation +items!( + const _: u8 = 0; +); + +// Should also skip this invocation, as the wildcard covers it +renamed_items!( + const _: u8 = 0; +); diff --git a/tests/target/skip_macro_invocations/empty.rs b/tests/target/skip_macro_invocations/empty.rs new file mode 100644 index 0000000000000..4a398cc59c6ee --- /dev/null +++ b/tests/target/skip_macro_invocations/empty.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: [] + +// Should not skip this invocation +items!( + const _: u8 = 0; +); + +// Should not skip this invocation +renamed_items!( + const _: u8 = 0; +); diff --git a/tests/target/skip_macro_invocations/name.rs b/tests/target/skip_macro_invocations/name.rs new file mode 100644 index 0000000000000..c4d577269c6f0 --- /dev/null +++ b/tests/target/skip_macro_invocations/name.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: ["items"] + +// Should skip this invocation +items!( + const _: u8 = 0; +); + +// Should not skip this invocation +renamed_items!( + const _: u8 = 0; +); diff --git a/tests/target/skip_macro_invocations/name_unknown.rs b/tests/target/skip_macro_invocations/name_unknown.rs new file mode 100644 index 0000000000000..7ab1440395c32 --- /dev/null +++ b/tests/target/skip_macro_invocations/name_unknown.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["unknown"] + +// Should not skip this invocation +items!( + const _: u8 = 0; +); diff --git a/tests/target/skip_macro_invocations/names.rs b/tests/target/skip_macro_invocations/names.rs new file mode 100644 index 0000000000000..c6b41ff93d79d --- /dev/null +++ b/tests/target/skip_macro_invocations/names.rs @@ -0,0 +1,16 @@ +// rustfmt-skip_macro_invocations: ["foo","bar"] + +// Should skip this invocation +foo!( + const _: u8 = 0; +); + +// Should skip this invocation +bar!( + const _: u8 = 0; +); + +// Should not skip this invocation +baz!( + const _: u8 = 0; +); diff --git a/tests/target/skip_macro_invocations/path_qualified_invocation_mismatch.rs b/tests/target/skip_macro_invocations/path_qualified_invocation_mismatch.rs new file mode 100644 index 0000000000000..6e372c726952a --- /dev/null +++ b/tests/target/skip_macro_invocations/path_qualified_invocation_mismatch.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["items"] + +// Should not skip this invocation +self::items!( + const _: u8 = 0; +); diff --git a/tests/target/skip_macro_invocations/path_qualified_match.rs b/tests/target/skip_macro_invocations/path_qualified_match.rs new file mode 100644 index 0000000000000..9398918a9e11e --- /dev/null +++ b/tests/target/skip_macro_invocations/path_qualified_match.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["self::items"] + +// Should skip this invocation +self::items!( + const _: u8 = 0; +); diff --git a/tests/target/skip_macro_invocations/path_qualified_name_mismatch.rs b/tests/target/skip_macro_invocations/path_qualified_name_mismatch.rs new file mode 100644 index 0000000000000..aa57a2a655c4a --- /dev/null +++ b/tests/target/skip_macro_invocations/path_qualified_name_mismatch.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["self::items"] + +// Should not skip this invocation +items!( + const _: u8 = 0; +); diff --git a/tests/target/skip_macro_invocations/use_alias_examples.rs b/tests/target/skip_macro_invocations/use_alias_examples.rs new file mode 100644 index 0000000000000..799dd8c08af15 --- /dev/null +++ b/tests/target/skip_macro_invocations/use_alias_examples.rs @@ -0,0 +1,32 @@ +// rustfmt-skip_macro_invocations: ["aaa","ccc"] + +// These tests demonstrate a realistic use case with use aliases. +// The use statements should not impact functionality in any way. + +use crate::{aaa, bbb, ddd}; + +// No use alias, invocation in list +// Should skip this invocation +aaa!( + const _: u8 = 0; +); + +// Use alias, invocation in list +// Should skip this invocation +use crate::bbb as ccc; +ccc!( + const _: u8 = 0; +); + +// Use alias, invocation not in list +// Should not skip this invocation +use crate::ddd as eee; +eee!( + const _: u8 = 0; +); + +// No use alias, invocation not in list +// Should not skip this invocation +fff!( + const _: u8 = 0; +); diff --git a/tests/target/tuple.rs b/tests/target/tuple.rs index 68bb2f3bc2850..24fcf8cfd7cf3 100644 --- a/tests/target/tuple.rs +++ b/tests/target/tuple.rs @@ -1,4 +1,4 @@ -// Test tuple litterals +// Test tuple literals fn foo() { let a = (a, a, a, a, a); diff --git a/tests/target/wrap_comments_should_not_imply_format_doc_comments.rs b/tests/target/wrap_comments_should_not_imply_format_doc_comments.rs index d61d4d7c216a3..6ccecc7e0bbe6 100644 --- a/tests/target/wrap_comments_should_not_imply_format_doc_comments.rs +++ b/tests/target/wrap_comments_should_not_imply_format_doc_comments.rs @@ -10,7 +10,7 @@ /// ``` fn foo() {} -/// A long commment for wrapping +/// A long comment for wrapping /// This is a long long long long long long long long long long long long long /// long long long long long long long sentence. fn bar() {} From 01241f8888d9ca82446179efd8a4fef71bb7bd40 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Wed, 25 Jan 2023 01:46:19 -0500 Subject: [PATCH 064/465] create and use GlobalAlloc::address_space --- src/consts.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/consts.rs b/src/consts.rs index ba64b1f638942..dc41cb761b59c 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -7,9 +7,9 @@ use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs} use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::mir::interpret::{self, ConstAllocation, ErrorHandled, GlobalAlloc, Scalar as InterpScalar, read_target_uint}; +use rustc_middle::mir::interpret::{self, ConstAllocation, ErrorHandled, Scalar as InterpScalar, read_target_uint}; use rustc_span::def_id::DefId; -use rustc_target::abi::{self, AddressSpace, Align, HasDataLayout, Primitive, Size, WrappingRange}; +use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRange}; use crate::base; use crate::context::CodegenCx; @@ -323,12 +323,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl .expect("const_alloc_to_llvm: could not read relocation pointer") as u64; - let address_space = match cx.tcx.global_alloc(alloc_id) { - GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space, - GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => { - AddressSpace::DATA - } - }; + let address_space = cx.tcx.global_alloc(alloc_id).address_space(cx); llvals.push(cx.scalar_to_backend( InterpScalar::from_pointer( From 567bd977230f3fe64781e9946b9f692919d30d38 Mon Sep 17 00:00:00 2001 From: Arthur Carcano <53921575+krtab@users.noreply.github.com> Date: Sat, 28 Jan 2023 22:16:46 +0100 Subject: [PATCH 065/465] Document which comments are excluded from wrapping (#5637) * Document which comments are excluded from wrapping Cf: https://github.com/rust-lang/rustfmt/issues/5634 * Add examples in wrap_commments doc * fix failling tests --- Configurations.md | 20 ++++++++++++++++++++ src/comment.rs | 2 ++ 2 files changed, 22 insertions(+) diff --git a/Configurations.md b/Configurations.md index 49e7e4e64892a..ac638ff91e6d4 100644 --- a/Configurations.md +++ b/Configurations.md @@ -2997,6 +2997,10 @@ See also [`brace_style`](#brace_style), [`control_brace_style`](#control_brace_s Break comments to fit on the line +Note that no wrapping will happen if: +1. The comment is the start of a markdown header doc comment +2. An URL was found in the comment + - **Default value**: `false` - **Possible values**: `true`, `false` - **Stable**: No (tracking issue: [#3347](https://github.com/rust-lang/rustfmt/issues/3347)) @@ -3011,6 +3015,11 @@ Break comments to fit on the line // commodo consequat. // Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + +// Information on the lorem ipsum can be found at the following url: https://en.wikipedia.org/wiki/Lorem_ipsum. Its text is: lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + +/// # This doc comment is a very long header (it starts with a '#'). Had it not been a header it would have been wrapped. But because it is a header, it will not be. That is because wrapping a markdown header breaks it. +struct Foo {} ``` #### `true`: @@ -3021,6 +3030,17 @@ Break comments to fit on the line // magna aliqua. Ut enim ad minim veniam, quis nostrud // exercitation ullamco laboris nisi ut aliquip ex ea // commodo consequat. + +// Lorem ipsum dolor sit amet, consectetur adipiscing elit, +// sed do eiusmod tempor incididunt ut labore et dolore +// magna aliqua. Ut enim ad minim veniam, quis nostrud +// exercitation ullamco laboris nisi ut aliquip ex ea +// commodo consequat. + +// Information on the lorem ipsum can be found at the following url: https://en.wikipedia.org/wiki/Lorem_ipsum. Its text is: lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + +/// # This doc comment is a very long header (it starts with a '#'). Had it not been a header it would have been wrapped. But because it is a header, it will not be. That is because wrapping a markdown header breaks it. +struct Foo {} ``` # Internal Options diff --git a/src/comment.rs b/src/comment.rs index 4d565afc1e026..261fa5e93d843 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -801,6 +801,8 @@ impl<'a> CommentRewrite<'a> { // 2) The comment is not the start of a markdown header doc comment // 3) The comment width exceeds the shape's width // 4) No URLS were found in the comment + // If this changes, the documentation in ../Configurations.md#wrap_comments + // should be changed accordingly. let should_wrap_comment = self.fmt.config.wrap_comments() && !is_markdown_header_doc_comment && unicode_str_width(line) > self.fmt.shape.width From bcfc57ec8a8fb1120b9b447df21cd07aac6c228d Mon Sep 17 00:00:00 2001 From: amab8901 <83634595+amab8901@users.noreply.github.com> Date: Sat, 28 Jan 2023 22:18:52 +0100 Subject: [PATCH 066/465] added tests (#5619) --- tests/source/issue-5586.rs | 164 ++++++++++++++++++++++++++++++++++ tests/target/issue-5586.rs | 177 +++++++++++++++++++++++++++++++++++++ 2 files changed, 341 insertions(+) create mode 100644 tests/source/issue-5586.rs create mode 100644 tests/target/issue-5586.rs diff --git a/tests/source/issue-5586.rs b/tests/source/issue-5586.rs new file mode 100644 index 0000000000000..9cf6c1d58ddc6 --- /dev/null +++ b/tests/source/issue-5586.rs @@ -0,0 +1,164 @@ +// rustfmt-version: Two +fn main() { + // sample 1 + { + { + { + { + { + let push_ident = + if let Some(&node_id) = subgraph_nodes.get(pull_to_push_idx) { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." +); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 2 + { + { + { + { + { + let push_ident = if let Some(&node_id) = + subgraph_nodes.get(pull_to_push_idx) + { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 3 + { + { + { + { + { + let push_ident = + if let Some(&node_id) = subgraph_nodes.get(pull_to_push_idx) { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 4 + {{{{{ + let push_ident = + if let Some(&node_id) = subgraph_nodes.get(pull_to_push_idx) { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + }}}}} + + // sample 5 + { + { + { + { + { + let push_ident = + if let Some(&node_id) = subgraph_nodes.get(pull_to_push_idx) { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 6 + { + { + { + { + { + let push_ident = if let Some(&node_id) = + subgraph_nodes.get(pull_to_push_idx) + { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 7 + { + { + { + { + { + let push_ident = + if let Some(&node_id) = subgraph_nodes.get(pull_to_push_idx) { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } +} diff --git a/tests/target/issue-5586.rs b/tests/target/issue-5586.rs new file mode 100644 index 0000000000000..7033ae975b3b5 --- /dev/null +++ b/tests/target/issue-5586.rs @@ -0,0 +1,177 @@ +// rustfmt-version: Two +fn main() { + // sample 1 + { + { + { + { + { + let push_ident = if let Some(&node_id) = + subgraph_nodes.get(pull_to_push_idx) + { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 2 + { + { + { + { + { + let push_ident = if let Some(&node_id) = + subgraph_nodes.get(pull_to_push_idx) + { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 3 + { + { + { + { + { + let push_ident = if let Some(&node_id) = + subgraph_nodes.get(pull_to_push_idx) + { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 4 + { + { + { + { + { + let push_ident = if let Some(&node_id) = + subgraph_nodes.get(pull_to_push_idx) + { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 5 + { + { + { + { + { + let push_ident = if let Some(&node_id) = + subgraph_nodes.get(pull_to_push_idx) + { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 6 + { + { + { + { + { + let push_ident = if let Some(&node_id) = + subgraph_nodes.get(pull_to_push_idx) + { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } + + // sample 7 + { + { + { + { + { + let push_ident = if let Some(&node_id) = + subgraph_nodes.get(pull_to_push_idx) + { + self.node_id_as_ident(node_id, false) + } else { + // Entire subgraph is pull (except for a single send/push handoff output). + assert_eq!( + 1, + send_ports.len(), + "If entire subgraph is pull, should have only one handoff output." + ); + send_ports[0].clone() + }; + } + } + } + } + } +} From b08130c59070bb9c95128341d712c0e02bba58d9 Mon Sep 17 00:00:00 2001 From: David Bar-On <61089727+davidBar-On@users.noreply.github.com> Date: Sun, 29 Jan 2023 20:55:14 +0200 Subject: [PATCH 067/465] Fix #5234 - handling of empty code block (#5601) --- src/comment.rs | 2 +- tests/source/issue-5234.rs | 51 ++++++++++++++++++++++++++++++++++++++ tests/target/issue-5234.rs | 47 +++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 tests/source/issue-5234.rs create mode 100644 tests/target/issue-5234.rs diff --git a/src/comment.rs b/src/comment.rs index 261fa5e93d843..0677fdc2b8994 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -726,7 +726,7 @@ impl<'a> CommentRewrite<'a> { let code_block = match self.code_block_attr.as_ref().unwrap() { CodeBlockAttribute::Rust if self.fmt.config.format_code_in_doc_comments() - && !self.code_block_buffer.is_empty() => + && !self.code_block_buffer.trim().is_empty() => { let mut config = self.fmt.config.clone(); config.set().wrap_comments(false); diff --git a/tests/source/issue-5234.rs b/tests/source/issue-5234.rs new file mode 100644 index 0000000000000..67266f485d3bf --- /dev/null +++ b/tests/source/issue-5234.rs @@ -0,0 +1,51 @@ +// rustfmt-format_code_in_doc_comments: true + +/// ``` +/// ``` +fn foo() {} + +/// ``` +///Something +/// ``` +fn foo() {} + +/// ``` +/// +/// ``` +fn foo() {} + + +/// /// ``` +fn foo() {} + +/// /// ``` +/// ``` +/// +/// ``` +/// ``` +fn foo() {} + +fn foo() { +/// ``` +/// +/// ``` +struct bar {} +} + +/// ``` +/// fn com(){ +/// let i = 5; +/// +/// let j = 6; +/// } +/// ``` +fn foo() {} + +fn foo() { +/// ``` +///fn com(){ +///let i = 5; +///} +/// ``` +struct bar {} +} diff --git a/tests/target/issue-5234.rs b/tests/target/issue-5234.rs new file mode 100644 index 0000000000000..7ee9e46d1efa7 --- /dev/null +++ b/tests/target/issue-5234.rs @@ -0,0 +1,47 @@ +// rustfmt-format_code_in_doc_comments: true + +/// ``` +/// ``` +fn foo() {} + +/// ``` +/// Something +/// ``` +fn foo() {} + +/// ``` +/// ``` +fn foo() {} + +/// /// ``` +fn foo() {} + +/// /// ``` +/// ``` +/// ``` +/// ``` +fn foo() {} + +fn foo() { + /// ``` + /// ``` + struct bar {} +} + +/// ``` +/// fn com() { +/// let i = 5; +/// +/// let j = 6; +/// } +/// ``` +fn foo() {} + +fn foo() { + /// ``` + /// fn com() { + /// let i = 5; + /// } + /// ``` + struct bar {} +} From 61d82acf53c62d19d366c47bead15b8fc67028bc Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Sun, 29 Jan 2023 22:43:40 +0000 Subject: [PATCH 068/465] refactor: fix typo in comment (#5581) --- src/bin/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index be64559e87745..8f5d980f561de 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -75,7 +75,7 @@ pub enum OperationError { #[error("{0}")] IoError(IoError), /// Attempt to use --emit with a mode which is not currently - /// supported with stdandard input. + /// supported with standard input. #[error("Emit mode {0} not supported with standard output.")] StdinBadEmit(EmitMode), } From 9cc0af54070f023fb52961160157313a09c55fb8 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 30 Jan 2023 07:44:58 +0900 Subject: [PATCH 069/465] Remove old CI config (#5572) * Remove old CI config Signed-off-by: Yuki Okushi * Replace outdated badges Signed-off-by: Yuki Okushi --------- Signed-off-by: Yuki Okushi --- .editorconfig | 3 -- .travis.yml | 77 --------------------------------------------------- README.md | 6 ++-- 3 files changed, 2 insertions(+), 84 deletions(-) delete mode 100644 .travis.yml diff --git a/.editorconfig b/.editorconfig index 5bb92df3e0432..ed6894e5c273d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -21,6 +21,3 @@ indent_size = unset indent_style = unset trim_trailing_whitespace = unset insert_final_newline = unset - -[appveyor.yml] -end_of_line = unset diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d699bd842eecc..0000000000000 --- a/.travis.yml +++ /dev/null @@ -1,77 +0,0 @@ -sudo: false -language: rust -rust: nightly -os: linux -cache: - directories: - - $HOME/.cargo - -addons: - apt: - packages: - - libcurl4-openssl-dev - - libelf-dev - - libdw-dev - -matrix: - include: - - env: DEPLOY=LINUX - - env: CFG_RELEASE_CHANNEL=beta - - os: osx - - env: INTEGRATION=bitflags - - env: INTEGRATION=chalk - - env: INTEGRATION=crater - - env: INTEGRATION=error-chain - - env: INTEGRATION=glob - - env: INTEGRATION=log - - env: INTEGRATION=mdbook - - env: INTEGRATION=packed_simd - - env: INTEGRATION=rust-semverver - - env: INTEGRATION=stdsimd TARGET=x86_64-unknown-linux-gnu - - env: INTEGRATION=tempdir - - env: INTEGRATION=futures-rs - allow_failures: - # Using old configuration option - - env: INTEGRATION=rand - # Doesn't build - keep this in allow_failures as it's fragile to breaking changes of rustc. - - env: INTEGRATION=rust-clippy - # Doesn't build - seems to be because of an option - - env: INTEGRATION=packed_simd - # Doesn't build - a temporal build failure due to breaking changes in the nightly compilre - - env: INTEGRATION=rust-semverver - # can be moved back to include section after https://github.com/rust-lang-nursery/failure/pull/298 is merged - - env: INTEGRATION=failure - # `cargo test` doesn't finish - disabling for now. - # - env: INTEGRATION=cargo - -script: - - | - if [ -z ${INTEGRATION} ]; then - export CFG_RELEASE_CHANNEL=nightly - export CFG_RELEASE=nightly - cargo build - cargo test - cargo test -- --ignored - else - ./ci/integration.sh - fi - -after_success: -- if [ -z ${INTEGRATION} ]; then travis-cargo coveralls --no-sudo; fi - -before_deploy: - # TODO: cross build - - cargo build --release --target=x86_64-unknown-linux-gnu - - tar czf rustfmt-x86_64-unknown-linux-gnu.tar.gz Contributing.md Design.md README.md -C target/x86_64-unknown-linux-gnu/release/rustfmt rustfmt - -deploy: - provider: releases - api_key: - secure: "your own encrypted key" - file: - - rustfmt-x86_64-unknown-linux-gnu.tar.gz - on: - repo: nrc/rustfmt - tags: true - condition: "$DEPLOY = LINUX" - skip_cleanup: true diff --git a/README.md b/README.md index 0f9652aecf9c2..ef835371b02a8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# rustfmt [![Build Status](https://travis-ci.com/rust-lang/rustfmt.svg?branch=master)](https://travis-ci.com/rust-lang/rustfmt) [![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-lang/rustfmt?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/rustfmt) [![crates.io](https://img.shields.io/crates/v/rustfmt-nightly.svg)](https://crates.io/crates/rustfmt-nightly) [![Travis Configuration Status](https://img.shields.io/travis/davidalber/rustfmt-travis.svg?label=travis%20example)](https://travis-ci.org/davidalber/rustfmt-travis) +# rustfmt [![linux](https://github.com/rust-lang/rustfmt/actions/workflows/linux.yml/badge.svg?event=push)](https://github.com/rust-lang/rustfmt/actions/workflows/linux.yml) [![mac](https://github.com/rust-lang/rustfmt/actions/workflows/mac.yml/badge.svg?event=push)](https://github.com/rust-lang/rustfmt/actions/workflows/mac.yml) [![windows](https://github.com/rust-lang/rustfmt/actions/workflows/windows.yml/badge.svg?event=push)](https://github.com/rust-lang/rustfmt/actions/workflows/windows.yml) [![crates.io](https://img.shields.io/crates/v/rustfmt-nightly.svg)](https://crates.io/crates/rustfmt-nightly) A tool for formatting Rust code according to style guidelines. @@ -7,9 +7,7 @@ If you'd like to help out (and you should, it's a fun project!), see Conduct](CODE_OF_CONDUCT.md). You can use rustfmt in Travis CI builds. We provide a minimal Travis CI -configuration (see [here](#checking-style-on-a-ci-server)) and verify its status -using another repository. The status of that repository's build is reported by -the "travis example" badge above. +configuration (see [here](#checking-style-on-a-ci-server)). ## Quick start From fb1a223eba3f31242f266b4936a8fe956b9d0e08 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 30 Jan 2023 07:45:26 +0900 Subject: [PATCH 070/465] Remove use of actions-rs (#5571) Signed-off-by: Yuki Okushi --- .github/workflows/upload-assets.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/upload-assets.yml b/.github/workflows/upload-assets.yml index 25699234a1ec3..7dfaa4b9204c2 100644 --- a/.github/workflows/upload-assets.yml +++ b/.github/workflows/upload-assets.yml @@ -46,10 +46,7 @@ jobs: shell: bash - name: Build release binaries - uses: actions-rs/cargo@v1 - with: - command: build - args: --release + run: cargo build --release - name: Build archive shell: bash From 846662cdb36b5e0663d2be533f5e4178705c982b Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Sat, 30 May 2020 09:36:44 -0700 Subject: [PATCH 071/465] Don't wrap comments that are part of a table Closes #4210 --- src/comment.rs | 15 ++++++++++++++- tests/target/issue-4210.rs | 15 +++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/target/issue-4210.rs diff --git a/src/comment.rs b/src/comment.rs index 0677fdc2b8994..7167783872f9f 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -806,7 +806,8 @@ impl<'a> CommentRewrite<'a> { let should_wrap_comment = self.fmt.config.wrap_comments() && !is_markdown_header_doc_comment && unicode_str_width(line) > self.fmt.shape.width - && !has_url(line); + && !has_url(line) + && !is_table_item(line); if should_wrap_comment { match rewrite_string(line, &self.fmt, self.max_width) { @@ -941,6 +942,18 @@ fn has_url(s: &str) -> bool { || REFERENCE_LINK_URL.is_match(s) } +/// Returns true if the given string may be part of a Markdown talble. +fn is_table_item(mut s: &str) -> bool { + // This function may return false positive, but should get its job done in most cases (i.e. + // markdown tables with two column delimiters). + s = s.trim_start(); + return s.starts_with('|') + && match s.rfind('|') { + Some(0) | None => false, + _ => true, + }; +} + /// Given the span, rewrite the missing comment inside it if available. /// Note that the given span must only include comments (or leading/trailing whitespaces). pub(crate) fn rewrite_missing_comment( diff --git a/tests/target/issue-4210.rs b/tests/target/issue-4210.rs new file mode 100644 index 0000000000000..e96ba1b3fd053 --- /dev/null +++ b/tests/target/issue-4210.rs @@ -0,0 +1,15 @@ +// rustfmt-wrap_comments: true + +/// Table that is > 80 symbols: +/// +/// | table | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | +/// |-------|-----------------------------------------------------------------------------| +/// | val | x | +pub struct Item; + +/// Table that is > 80 symbols: +/// +/// | table | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +/// |-------|----------------------------------------------------------------------------- +/// | val | x +pub struct Item; From 368a63305cea7a472fec37757bf962cdfc12be26 Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Sat, 10 Sep 2022 13:30:41 +0200 Subject: [PATCH 072/465] Fix typo --- src/comment.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/comment.rs b/src/comment.rs index 7167783872f9f..17b4af1717d8d 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -942,7 +942,7 @@ fn has_url(s: &str) -> bool { || REFERENCE_LINK_URL.is_match(s) } -/// Returns true if the given string may be part of a Markdown talble. +/// Returns true if the given string may be part of a Markdown table. fn is_table_item(mut s: &str) -> bool { // This function may return false positive, but should get its job done in most cases (i.e. // markdown tables with two column delimiters). From cdd0b56071cbc9247461bbd2e0551b46e653162f Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Sat, 10 Sep 2022 13:31:08 +0200 Subject: [PATCH 073/465] Test that both table headers and values are not wrapped --- tests/target/issue-4210.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/target/issue-4210.rs b/tests/target/issue-4210.rs index e96ba1b3fd053..3fd9663908260 100644 --- a/tests/target/issue-4210.rs +++ b/tests/target/issue-4210.rs @@ -7,9 +7,9 @@ /// | val | x | pub struct Item; -/// Table that is > 80 symbols: +/// Table value that is > 80 symbols: /// -/// | table | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -/// |-------|----------------------------------------------------------------------------- -/// | val | x -pub struct Item; +/// | table | heading +/// |----------|----------------------------------------------------------------------------- +/// | long val | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +pub struct Item2; From 3f36c997bf45eb7b6f101885241ae59ce00e72d9 Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Sat, 10 Sep 2022 13:31:26 +0200 Subject: [PATCH 074/465] Test that with all comment wrapping disabled table comments are not wrapped --- tests/target/issue-4210-disabled.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/target/issue-4210-disabled.rs diff --git a/tests/target/issue-4210-disabled.rs b/tests/target/issue-4210-disabled.rs new file mode 100644 index 0000000000000..3ba87aab8c543 --- /dev/null +++ b/tests/target/issue-4210-disabled.rs @@ -0,0 +1,15 @@ +// rustfmt-wrap_comments: false + +/// Table that is > 80 symbols: +/// +/// | table | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | +/// |-------|-----------------------------------------------------------------------------| +/// | val | x | +pub struct Item; + +/// Table value that is > 80 symbols: +/// +/// | table | heading +/// |----------|----------------------------------------------------------------------------- +/// | long val | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +pub struct Item2; From 9c6f7cb3c7fc81aba3fd22d8ad39faaee8168a9c Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 19 Aug 2022 14:48:15 +0100 Subject: [PATCH 075/465] session: diagnostic migration lint on more fns Apply the diagnostic migration lint to more functions on `Session`. Signed-off-by: David Wood --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index bf1da38312f7d..5ab87feb98b11 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -200,6 +200,7 @@ unsafe impl Sync for GccContext {} impl WriteBackendMethods for GccCodegenBackend { type Module = GccContext; type TargetMachine = (); + type TargetMachineError = (); type ModuleBuffer = ModuleBuffer; type ThinData = (); type ThinBuffer = ThinBuffer; From e2996a807b411218bb3dca0f2a0e420839cd3875 Mon Sep 17 00:00:00 2001 From: Thaqib <65588695+thaqibm@users.noreply.github.com> Date: Wed, 1 Feb 2023 22:26:12 -0500 Subject: [PATCH 076/465] Lists doc comments fix4041 (#5560) * add + start of an itemized line * add test * fix format * fix tests * update doc comment --- src/comment.rs | 5 +++-- tests/source/issue-4041.rs | 5 +++++ tests/target/issue-4041.rs | 6 ++++++ 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 tests/source/issue-4041.rs create mode 100644 tests/target/issue-4041.rs diff --git a/src/comment.rs b/src/comment.rs index 17b4af1717d8d..bc0e8774f4949 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -432,7 +432,7 @@ impl CodeBlockAttribute { /// Block that is formatted as an item. /// -/// An item starts with either a star `*` a dash `-` or a greater-than `>`. +/// An item starts with either a star `*` a dash `-` a greater-than `>` or a plus '+'. /// Different level of indentation are handled by shrinking the shape accordingly. struct ItemizedBlock { /// the lines that are identified as part of an itemized block @@ -449,7 +449,8 @@ impl ItemizedBlock { /// Returns `true` if the line is formatted as an item fn is_itemized_line(line: &str) -> bool { let trimmed = line.trim_start(); - trimmed.starts_with("* ") || trimmed.starts_with("- ") || trimmed.starts_with("> ") + let itemized_start = ["* ", "- ", "> ", "+ "]; + itemized_start.iter().any(|s| trimmed.starts_with(s)) } /// Creates a new ItemizedBlock described with the given line. diff --git a/tests/source/issue-4041.rs b/tests/source/issue-4041.rs new file mode 100644 index 0000000000000..274b80f1bc5da --- /dev/null +++ b/tests/source/issue-4041.rs @@ -0,0 +1,5 @@ +// rustfmt-wrap_comments: true +//! List: +//! - Sub list: +//! + very long #1 blah blah blah blah blah blah blah blah blah blah blah blah foo baar baxxxxxxxx long line 1231421230912i3091238192038 +//! + very long #2 blah blah blah blah blah blah blah blah blah blah blah blah diff --git a/tests/target/issue-4041.rs b/tests/target/issue-4041.rs new file mode 100644 index 0000000000000..e9c693836f2c6 --- /dev/null +++ b/tests/target/issue-4041.rs @@ -0,0 +1,6 @@ +// rustfmt-wrap_comments: true +//! List: +//! - Sub list: +//! + very long #1 blah blah blah blah blah blah blah blah blah blah blah blah +//! foo baar baxxxxxxxx long line 1231421230912i3091238192038 +//! + very long #2 blah blah blah blah blah blah blah blah blah blah blah blah From 5391847ea5a12262704657a0708b1674fb344403 Mon Sep 17 00:00:00 2001 From: Rajiv Sharma Date: Sun, 28 Aug 2022 00:36:16 +0100 Subject: [PATCH 077/465] Fix #5488 - prevent shorthand init for tuple struct Closes #5488 Fix for #5488. Before applying shorthand initialization for structs, check if identifier is a literal (e.g. tuple struct). If yes, then do not apply short hand initialization. Added test case to validate the changes for the fix. --- src/expr.rs | 6 ++++-- tests/source/issue-5488.rs | 17 +++++++++++++++++ tests/target/issue-5488.rs | 17 +++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 tests/source/issue-5488.rs create mode 100644 tests/target/issue-5488.rs diff --git a/src/expr.rs b/src/expr.rs index 0be4c3cf168cc..91f3cc81bae9a 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1723,9 +1723,11 @@ pub(crate) fn rewrite_field( let overhead = name.len() + separator.len(); let expr_shape = shape.offset_left(overhead)?; let expr = field.expr.rewrite(context, expr_shape); - + let is_lit = matches!(field.expr.kind, ast::ExprKind::Lit(_)); match expr { - Some(ref e) if e.as_str() == name && context.config.use_field_init_shorthand() => { + Some(ref e) + if !is_lit && e.as_str() == name && context.config.use_field_init_shorthand() => + { Some(attrs_str + name) } Some(e) => Some(format!("{}{}{}{}", attrs_str, name, separator, e)), diff --git a/tests/source/issue-5488.rs b/tests/source/issue-5488.rs new file mode 100644 index 0000000000000..d361632e29efd --- /dev/null +++ b/tests/source/issue-5488.rs @@ -0,0 +1,17 @@ +// rustfmt-use_field_init_shorthand: true + +struct MyStruct(u32); +struct AnotherStruct { + a: u32, +} + +fn main() { + // Since MyStruct is a tuple struct, it should not be shorthanded to + // MyStruct { 0 } even if use_field_init_shorthand is enabled. + let instance = MyStruct { 0: 0 }; + + // Since AnotherStruct is not a tuple struct, the shorthand should + // apply. + let a = 10; + let instance = AnotherStruct { a: a }; +} diff --git a/tests/target/issue-5488.rs b/tests/target/issue-5488.rs new file mode 100644 index 0000000000000..0cb37c56f393f --- /dev/null +++ b/tests/target/issue-5488.rs @@ -0,0 +1,17 @@ +// rustfmt-use_field_init_shorthand: true + +struct MyStruct(u32); +struct AnotherStruct { + a: u32, +} + +fn main() { + // Since MyStruct is a tuple struct, it should not be shorthanded to + // MyStruct { 0 } even if use_field_init_shorthand is enabled. + let instance = MyStruct { 0: 0 }; + + // Since AnotherStruct is not a tuple struct, the shorthand should + // apply. + let a = 10; + let instance = AnotherStruct { a }; +} From c6b822d85546f830f568bc4ff9b1d761d26964c1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 1 Feb 2023 12:58:04 +1100 Subject: [PATCH 078/465] Rename `Cursor`/`CursorRef` as `TokenTreeCursor`/`RefTokenTreeCursor`. This makes it clear they return token trees, and makes for a nice comparison against `TokenCursor` which returns tokens. --- src/macros.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index d58f7547fefb3..7978d8cba9541 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -13,7 +13,7 @@ use std::collections::HashMap; use std::panic::{catch_unwind, AssertUnwindSafe}; use rustc_ast::token::{BinOpToken, Delimiter, Token, TokenKind}; -use rustc_ast::tokenstream::{Cursor, TokenStream, TokenTree}; +use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor}; use rustc_ast::{ast, ptr}; use rustc_ast_pretty::pprust; use rustc_span::{ @@ -736,7 +736,7 @@ impl MacroArgParser { self.buf.clear(); } - fn add_meta_variable(&mut self, iter: &mut Cursor) -> Option<()> { + fn add_meta_variable(&mut self, iter: &mut TokenTreeCursor) -> Option<()> { match iter.next() { Some(TokenTree::Token( Token { @@ -768,7 +768,7 @@ impl MacroArgParser { &mut self, inner: Vec, delim: Delimiter, - iter: &mut Cursor, + iter: &mut TokenTreeCursor, ) -> Option<()> { let mut buffer = String::new(); let mut first = true; @@ -1121,7 +1121,7 @@ pub(crate) fn macro_style(mac: &ast::MacCall, context: &RewriteContext<'_>) -> D // Currently we do not attempt to parse any further than that. #[derive(new)] struct MacroParser { - toks: Cursor, + toks: TokenTreeCursor, } impl MacroParser { From 24f4ecec2595ab504994766d8cc60d2c11eaa369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 9 Feb 2023 10:16:00 +0000 Subject: [PATCH 079/465] Introduce `-Zterminal-urls` to use OSC8 for error codes Terminals supporting the OSC8 Hyperlink Extension can support inline anchors where the text is user defineable but clicking on it opens a browser to a specified URLs, just like `` does in HTML. https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda --- src/parse/session.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/parse/session.rs b/src/parse/session.rs index 6bfec79cd7030..9014026b0aa4a 100644 --- a/src/parse/session.rs +++ b/src/parse/session.rs @@ -4,7 +4,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use rustc_data_structures::sync::{Lrc, Send}; use rustc_errors::emitter::{Emitter, EmitterWriter}; use rustc_errors::translation::Translate; -use rustc_errors::{ColorConfig, Diagnostic, Handler, Level as DiagnosticLevel}; +use rustc_errors::{ColorConfig, Diagnostic, Handler, Level as DiagnosticLevel, TerminalUrl}; use rustc_session::parse::ParseSess as RawParseSess; use rustc_span::{ source_map::{FilePathMapping, SourceMap}, @@ -135,6 +135,7 @@ fn default_handler( None, false, false, + TerminalUrl::No, )) }; Handler::with_emitter( From 4238ce2195439ee080323cdd4e4906dfe3c3a6a6 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 14 Feb 2023 08:51:19 +0000 Subject: [PATCH 080/465] s/eval_usize/eval_target_usize/ for clarity --- src/intrinsic/simd.rs | 407 ++++++++++++++++++++++++------------------ 1 file changed, 233 insertions(+), 174 deletions(-) diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index 12e416f62a4e0..cb8168b407184 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -1,6 +1,6 @@ use std::cmp::Ordering; -use gccjit::{BinaryOp, RValue, Type, ToRValue}; +use gccjit::{BinaryOp, RValue, ToRValue, Type}; use rustc_codegen_ssa::base::compare_simd_types; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::mir::operand::OperandRef; @@ -10,52 +10,57 @@ use rustc_hir as hir; use rustc_middle::span_bug; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::{self, Ty}; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{sym, Span, Symbol}; use rustc_target::abi::Align; use crate::builder::Builder; use crate::errors::{ - InvalidMonomorphizationInvalidFloatVector, - InvalidMonomorphizationNotFloat, - InvalidMonomorphizationUnrecognized, - InvalidMonomorphizationExpectedSignedUnsigned, - InvalidMonomorphizationUnsupportedElement, - InvalidMonomorphizationInvalidBitmask, - InvalidMonomorphizationSimdShuffle, - InvalidMonomorphizationExpectedSimd, - InvalidMonomorphizationMaskType, - InvalidMonomorphizationReturnLength, - InvalidMonomorphizationReturnLengthInputType, - InvalidMonomorphizationReturnElement, - InvalidMonomorphizationReturnType, - InvalidMonomorphizationInsertedType, - InvalidMonomorphizationReturnIntegerType, - InvalidMonomorphizationMismatchedLengths, - InvalidMonomorphizationUnsupportedCast, - InvalidMonomorphizationUnsupportedOperation + InvalidMonomorphizationExpectedSignedUnsigned, InvalidMonomorphizationExpectedSimd, + InvalidMonomorphizationInsertedType, InvalidMonomorphizationInvalidBitmask, + InvalidMonomorphizationInvalidFloatVector, InvalidMonomorphizationMaskType, + InvalidMonomorphizationMismatchedLengths, InvalidMonomorphizationNotFloat, + InvalidMonomorphizationReturnElement, InvalidMonomorphizationReturnIntegerType, + InvalidMonomorphizationReturnLength, InvalidMonomorphizationReturnLengthInputType, + InvalidMonomorphizationReturnType, InvalidMonomorphizationSimdShuffle, + InvalidMonomorphizationUnrecognized, InvalidMonomorphizationUnsupportedCast, + InvalidMonomorphizationUnsupportedElement, InvalidMonomorphizationUnsupportedOperation, }; use crate::intrinsic; -pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, name: Symbol, callee_ty: Ty<'tcx>, args: &[OperandRef<'tcx, RValue<'gcc>>], ret_ty: Ty<'tcx>, llret_ty: Type<'gcc>, span: Span) -> Result, ()> { +pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( + bx: &mut Builder<'a, 'gcc, 'tcx>, + name: Symbol, + callee_ty: Ty<'tcx>, + args: &[OperandRef<'tcx, RValue<'gcc>>], + ret_ty: Ty<'tcx>, + llret_ty: Type<'gcc>, + span: Span, +) -> Result, ()> { // macros for error handling: macro_rules! return_error { - ($err:expr) => { - { - bx.sess().emit_err($err); - return Err(()); - } - } + ($err:expr) => {{ + bx.sess().emit_err($err); + return Err(()); + }}; } macro_rules! require { ($cond:expr, $err:expr) => { if !$cond { return_error!($err); } - } + }; } macro_rules! require_simd { ($ty: expr, $position: expr) => { - require!($ty.is_simd(), InvalidMonomorphizationExpectedSimd { span, name, position: $position, found_ty: $ty }) + require!( + $ty.is_simd(), + InvalidMonomorphizationExpectedSimd { + span, + name, + position: $position, + found_ty: $ty + } + ) }; } @@ -77,7 +82,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(), ty::Array(elem, len) if matches!(elem.kind(), ty::Uint(ty::UintTy::U8)) - && len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all()) + && len.try_eval_target_usize(bx.tcx, ty::ParamEnv::reveal_all()) == Some(expected_bytes) => { let place = PlaceRef::alloca(bx, args[0].layout); @@ -86,9 +91,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, let ptr = bx.pointercast(place.llval, bx.cx.type_ptr_to(int_ty)); bx.load(int_ty, ptr, Align::ONE) } - _ => return_error!( - InvalidMonomorphizationInvalidBitmask { span, name, ty: mask_ty, expected_int_bits, expected_bytes } - ), + _ => return_error!(InvalidMonomorphizationInvalidBitmask { + span, + name, + ty: mask_ty, + expected_int_bits, + expected_bytes + }), }; let arg1 = args[1].immediate(); @@ -129,11 +138,18 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); require!( in_len == out_len, - InvalidMonomorphizationReturnLengthInputType { span, name, in_len, in_ty, ret_ty, out_len } + InvalidMonomorphizationReturnLengthInputType { + span, + name, + in_len, + in_ty, + ret_ty, + out_len + } ); require!( bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer, - InvalidMonomorphizationReturnIntegerType {span, name, ret_ty, out_ty} + InvalidMonomorphizationReturnIntegerType { span, name, ret_ty, out_ty } ); return Ok(compare_simd_types( @@ -147,26 +163,26 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, } if let Some(stripped) = name.as_str().strip_prefix("simd_shuffle") { - let n: u64 = - if stripped.is_empty() { - // Make sure this is actually an array, since typeck only checks the length-suffixed - // version of this intrinsic. - match args[2].layout.ty.kind() { - ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => { - len.try_eval_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(|| { - span_bug!(span, "could not evaluate shuffle index array length") - }) - } - _ => return_error!( - InvalidMonomorphizationSimdShuffle { span, name, ty: args[2].layout.ty } - ), + let n: u64 = if stripped.is_empty() { + // Make sure this is actually an array, since typeck only checks the length-suffixed + // version of this intrinsic. + match args[2].layout.ty.kind() { + ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => { + len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else( + || span_bug!(span, "could not evaluate shuffle index array length"), + ) } + _ => return_error!(InvalidMonomorphizationSimdShuffle { + span, + name, + ty: args[2].layout.ty + }), } - else { - stripped.parse().unwrap_or_else(|_| { - span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?") - }) - }; + } else { + stripped.parse().unwrap_or_else(|_| { + span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?") + }) + }; require_simd!(ret_ty, "return"); @@ -182,14 +198,10 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, let vector = args[2].immediate(); - return Ok(bx.shuffle_vector( - args[0].immediate(), - args[1].immediate(), - vector, - )); + return Ok(bx.shuffle_vector(args[0].immediate(), args[1].immediate(), vector)); } - #[cfg(feature="master")] + #[cfg(feature = "master")] if name == sym::simd_insert { require!( in_elem == arg_tys[2], @@ -205,44 +217,44 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, // not be an l-value. So, call a builtin to set the element. // TODO(antoyo): perhaps we could create a new vector or maybe there's a GIMPLE instruction for that? // TODO(antoyo): don't use target specific builtins here. - let func_name = - match in_len { - 2 => { - if element_type == bx.i64_type { - "__builtin_ia32_vec_set_v2di" - } - else { - unimplemented!(); - } - }, - 4 => { - if element_type == bx.i32_type { - "__builtin_ia32_vec_set_v4si" - } - else { - unimplemented!(); - } - }, - 8 => { - if element_type == bx.i16_type { - "__builtin_ia32_vec_set_v8hi" - } - else { - unimplemented!(); - } - }, - _ => unimplemented!("Len: {}", in_len), - }; + let func_name = match in_len { + 2 => { + if element_type == bx.i64_type { + "__builtin_ia32_vec_set_v2di" + } else { + unimplemented!(); + } + } + 4 => { + if element_type == bx.i32_type { + "__builtin_ia32_vec_set_v4si" + } else { + unimplemented!(); + } + } + 8 => { + if element_type == bx.i16_type { + "__builtin_ia32_vec_set_v8hi" + } else { + unimplemented!(); + } + } + _ => unimplemented!("Len: {}", in_len), + }; let builtin = bx.context.get_target_builtin_function(func_name); let param1_type = builtin.get_param(0).to_rvalue().get_type(); // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. let vector = bx.cx.bitcast_if_needed(vector, param1_type); - let result = bx.context.new_call(None, builtin, &[vector, value, bx.context.new_cast(None, index, bx.int_type)]); + let result = bx.context.new_call( + None, + builtin, + &[vector, value, bx.context.new_cast(None, index, bx.int_type)], + ); // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. return Ok(bx.context.new_bitcast(None, result, vector.get_type())); } - #[cfg(feature="master")] + #[cfg(feature = "master")] if name == sym::simd_extract { require!( ret_ty == in_elem, @@ -273,7 +285,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); require!( in_len == out_len, - InvalidMonomorphizationReturnLengthInputType { span, name, in_len, in_ty, ret_ty, out_len } + InvalidMonomorphizationReturnLengthInputType { + span, + name, + in_len, + in_ty, + ret_ty, + out_len + } ); // casting cares about nominal type, not just structural type if in_elem == out_elem { @@ -322,19 +341,27 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, let cast_vec_element = |index| { let index = bx.context.new_rvalue_from_int(bx.int_type, index); - bx.context.new_cast(None, bx.context.new_array_access(None, array, index).to_rvalue(), out_type) + bx.context.new_cast( + None, + bx.context.new_array_access(None, array, index).to_rvalue(), + out_type, + ) }; - bx.context.new_rvalue_from_vector(None, vector_type, &[ - cast_vec_element(0), - cast_vec_element(1), - cast_vec_element(2), - cast_vec_element(3), - cast_vec_element(4), - cast_vec_element(5), - cast_vec_element(6), - cast_vec_element(7), - ]) + bx.context.new_rvalue_from_vector( + None, + vector_type, + &[ + cast_vec_element(0), + cast_vec_element(1), + cast_vec_element(2), + cast_vec_element(3), + cast_vec_element(4), + cast_vec_element(5), + cast_vec_element(6), + cast_vec_element(7), + ], + ) }; match (in_style, out_style) { @@ -385,9 +412,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, } _ => { /* Unsupported. Fallthrough. */ } } - return_error!( - InvalidMonomorphizationUnsupportedCast { span, name, in_ty, in_elem, ret_ty, out_elem } - ); + return_error!(InvalidMonomorphizationUnsupportedCast { + span, + name, + in_ty, + in_elem, + ret_ty, + out_elem + }); } macro_rules! arith_binary { @@ -414,54 +446,60 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, args: &[OperandRef<'tcx, RValue<'gcc>>], ) -> Result, ()> { macro_rules! return_error { - ($err:expr) => { - { - bx.sess().emit_err($err); - return Err(()); - } - } + ($err:expr) => {{ + bx.sess().emit_err($err); + return Err(()); + }}; } - let (elem_ty_str, elem_ty) = - if let ty::Float(f) = in_elem.kind() { - let elem_ty = bx.cx.type_float_from_ty(*f); - match f.bit_width() { - 32 => ("f32", elem_ty), - 64 => ("f64", elem_ty), - _ => { - return_error!(InvalidMonomorphizationInvalidFloatVector { span, name, elem_ty: f.name_str(), vec_ty: in_ty }); - } + let (elem_ty_str, elem_ty) = if let ty::Float(f) = in_elem.kind() { + let elem_ty = bx.cx.type_float_from_ty(*f); + match f.bit_width() { + 32 => ("f32", elem_ty), + 64 => ("f64", elem_ty), + _ => { + return_error!(InvalidMonomorphizationInvalidFloatVector { + span, + name, + elem_ty: f.name_str(), + vec_ty: in_ty + }); } } - else { - return_error!(InvalidMonomorphizationNotFloat { span, name, ty: in_ty }); - }; + } else { + return_error!(InvalidMonomorphizationNotFloat { span, name, ty: in_ty }); + }; let vec_ty = bx.cx.type_vector(elem_ty, in_len); - let (intr_name, fn_ty) = - match name { - sym::simd_ceil => ("ceil", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fabs => ("fabs", bx.type_func(&[vec_ty], vec_ty)), // TODO(antoyo): pand with 170141183420855150465331762880109871103 - sym::simd_fcos => ("cos", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fexp2 => ("exp2", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fexp => ("exp", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_flog10 => ("log10", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_flog2 => ("log2", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_flog => ("log", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_floor => ("floor", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fma => ("fma", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)), - sym::simd_fpowi => ("powi", bx.type_func(&[vec_ty, bx.type_i32()], vec_ty)), - sym::simd_fpow => ("pow", bx.type_func(&[vec_ty, vec_ty], vec_ty)), - sym::simd_fsin => ("sin", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_round => ("round", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_trunc => ("trunc", bx.type_func(&[vec_ty], vec_ty)), - _ => return_error!(InvalidMonomorphizationUnrecognized { span, name }) - }; + let (intr_name, fn_ty) = match name { + sym::simd_ceil => ("ceil", bx.type_func(&[vec_ty], vec_ty)), + sym::simd_fabs => ("fabs", bx.type_func(&[vec_ty], vec_ty)), // TODO(antoyo): pand with 170141183420855150465331762880109871103 + sym::simd_fcos => ("cos", bx.type_func(&[vec_ty], vec_ty)), + sym::simd_fexp2 => ("exp2", bx.type_func(&[vec_ty], vec_ty)), + sym::simd_fexp => ("exp", bx.type_func(&[vec_ty], vec_ty)), + sym::simd_flog10 => ("log10", bx.type_func(&[vec_ty], vec_ty)), + sym::simd_flog2 => ("log2", bx.type_func(&[vec_ty], vec_ty)), + sym::simd_flog => ("log", bx.type_func(&[vec_ty], vec_ty)), + sym::simd_floor => ("floor", bx.type_func(&[vec_ty], vec_ty)), + sym::simd_fma => ("fma", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)), + sym::simd_fpowi => ("powi", bx.type_func(&[vec_ty, bx.type_i32()], vec_ty)), + sym::simd_fpow => ("pow", bx.type_func(&[vec_ty, vec_ty], vec_ty)), + sym::simd_fsin => ("sin", bx.type_func(&[vec_ty], vec_ty)), + sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)), + sym::simd_round => ("round", bx.type_func(&[vec_ty], vec_ty)), + sym::simd_trunc => ("trunc", bx.type_func(&[vec_ty], vec_ty)), + _ => return_error!(InvalidMonomorphizationUnrecognized { span, name }), + }; let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str); let function = intrinsic::llvm::intrinsic(llvm_name, &bx.cx); let function: RValue<'gcc> = unsafe { std::mem::transmute(function) }; - let c = bx.call(fn_ty, None, function, &args.iter().map(|arg| arg.immediate()).collect::>(), None); + let c = bx.call( + fn_ty, + None, + function, + &args.iter().map(|arg| arg.immediate()).collect::>(), + None, + ); Ok(c) } @@ -518,7 +556,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, simd_neg: Int => neg, Float => fneg; } - #[cfg(feature="master")] + #[cfg(feature = "master")] if name == sym::simd_saturating_add || name == sym::simd_saturating_sub { let lhs = args[0].immediate(); let rhs = args[1].immediate(); @@ -536,18 +574,23 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, }); } }; - let builtin_name = - match (signed, is_add, in_len, elem_width) { - (true, true, 32, 8) => "__builtin_ia32_paddsb256", // TODO(antoyo): cast arguments to unsigned. - (false, true, 32, 8) => "__builtin_ia32_paddusb256", - (true, true, 16, 16) => "__builtin_ia32_paddsw256", - (false, true, 16, 16) => "__builtin_ia32_paddusw256", - (true, false, 16, 16) => "__builtin_ia32_psubsw256", - (false, false, 16, 16) => "__builtin_ia32_psubusw256", - (true, false, 32, 8) => "__builtin_ia32_psubsb256", - (false, false, 32, 8) => "__builtin_ia32_psubusb256", - _ => unimplemented!("signed: {}, is_add: {}, in_len: {}, elem_width: {}", signed, is_add, in_len, elem_width), - }; + let builtin_name = match (signed, is_add, in_len, elem_width) { + (true, true, 32, 8) => "__builtin_ia32_paddsb256", // TODO(antoyo): cast arguments to unsigned. + (false, true, 32, 8) => "__builtin_ia32_paddusb256", + (true, true, 16, 16) => "__builtin_ia32_paddsw256", + (false, true, 16, 16) => "__builtin_ia32_paddusw256", + (true, false, 16, 16) => "__builtin_ia32_psubsw256", + (false, false, 16, 16) => "__builtin_ia32_psubusw256", + (true, false, 32, 8) => "__builtin_ia32_psubsb256", + (false, false, 32, 8) => "__builtin_ia32_psubusb256", + _ => unimplemented!( + "signed: {}, is_add: {}, in_len: {}, elem_width: {}", + signed, + is_add, + in_len, + elem_width + ), + }; let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64); let func = bx.context.get_target_builtin_function(builtin_name); @@ -575,8 +618,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, // if overflow occurs, the result is the // mathematical result modulo 2^n: Ok(bx.$op(args[1].immediate(), r)) - } - else { + } else { Ok(bx.vector_reduce_op(args[0].immediate(), $vec_op)) } } @@ -585,12 +627,17 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, // ordered arithmetic reductions take an accumulator let acc = args[1].immediate(); Ok(bx.$float_reduce(acc, args[0].immediate())) - } - else { + } else { Ok(bx.vector_reduce_op(args[0].immediate(), $vec_op)) } } - _ => return_error!(InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty }), + _ => return_error!(InvalidMonomorphizationUnsupportedElement { + span, + name, + in_ty, + elem_ty: in_elem, + ret_ty + }), }; } }; @@ -603,13 +650,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, add, 0.0 // TODO: Use this argument. ); - arith_red!( - simd_reduce_mul_unordered: BinaryOp::Mult, - vector_reduce_fmul_fast, - false, - mul, - 1.0 - ); + arith_red!(simd_reduce_mul_unordered: BinaryOp::Mult, vector_reduce_fmul_fast, false, mul, 1.0); macro_rules! minmax_red { ($name:ident: $reduction:ident) => { @@ -619,8 +660,16 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, InvalidMonomorphizationReturnType { span, name, in_elem, in_ty, ret_ty } ); return match in_elem.kind() { - ty::Int(_) | ty::Uint(_) | ty::Float(_) => Ok(bx.$reduction(args[0].immediate())), - _ => return_error!(InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty }), + ty::Int(_) | ty::Uint(_) | ty::Float(_) => { + Ok(bx.$reduction(args[0].immediate())) + } + _ => return_error!(InvalidMonomorphizationUnsupportedElement { + span, + name, + in_ty, + elem_ty: in_elem, + ret_ty + }), }; } }; @@ -641,7 +690,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, } else { match in_elem.kind() { ty::Int(_) | ty::Uint(_) => {} - _ => return_error!(InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty }), + _ => return_error!(InvalidMonomorphizationUnsupportedElement { + span, + name, + in_ty, + elem_ty: in_elem, + ret_ty + }), } // boolean reductions operate on vectors of i1s: @@ -654,9 +709,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, let r = bx.vector_reduce_op(input, $op); Ok(if !$boolean { r } else { bx.zext(r, bx.type_bool()) }) } - _ => return_error!( - InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty } - ), + _ => return_error!(InvalidMonomorphizationUnsupportedElement { + span, + name, + in_ty, + elem_ty: in_elem, + ret_ty + }), }; } }; From 34f9ca28f2f4ae3ac462c6dcd862b513e107e459 Mon Sep 17 00:00:00 2001 From: Caleb Cartwright Date: Wed, 15 Feb 2023 22:24:03 -0600 Subject: [PATCH 081/465] fix: use correct span for struct generics --- src/items.rs | 2 +- tests/target/issue_5691.rs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/target/issue_5691.rs diff --git a/src/items.rs b/src/items.rs index 25e8a024857ce..3c5293b6bf5a7 100644 --- a/src/items.rs +++ b/src/items.rs @@ -1278,7 +1278,7 @@ pub(crate) fn format_struct_struct( let header_hi = struct_parts.ident.span.hi(); let body_lo = if let Some(generics) = struct_parts.generics { // Adjust the span to start at the end of the generic arguments before searching for the '{' - let span = span.with_lo(generics.span.hi()); + let span = span.with_lo(generics.where_clause.span.hi()); context.snippet_provider.span_after(span, "{") } else { context.snippet_provider.span_after(span, "{") diff --git a/tests/target/issue_5691.rs b/tests/target/issue_5691.rs new file mode 100644 index 0000000000000..e3aad15db0d5b --- /dev/null +++ b/tests/target/issue_5691.rs @@ -0,0 +1,16 @@ +struct S +where + [(); { num_slots!(C) }]:, { + /* An asterisk-based, or a double-slash-prefixed, comment here is + required to trigger the fmt bug. + + A single-line triple-slash-prefixed comment (with a field following it) is not enough - it will not trigger the fmt bug. + + Side note: If you have a combination of two, or all three of the + above mentioned types of comments here, some of them disappear + after `cargo fmt`. + + The bug gets triggered even if a field definition following the + (asterisk-based, or a double-slash-prefixed) comment, too. + */ +} From af75a2f7f10001da3f9d5fbda2d9cce458b7959d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 23 Nov 2022 11:55:16 +1100 Subject: [PATCH 082/465] Use `ThinVec` in various AST types. This commit changes the sequence parsers to produce `ThinVec`, which triggers numerous conversions. --- src/chains.rs | 4 +++- src/lib.rs | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/chains.rs b/src/chains.rs index 39b8d6878097d..cbe523c6c3ca9 100644 --- a/src/chains.rs +++ b/src/chains.rs @@ -74,6 +74,8 @@ use crate::utils::{ rewrite_ident, trimmed_last_line_width, wrap_str, }; +use thin_vec::ThinVec; + /// Provides the original input contents from the span /// of a chain element with trailing spaces trimmed. fn format_overflow_style(span: Span, context: &RewriteContext<'_>) -> Option { @@ -168,7 +170,7 @@ enum ChainItemKind { MethodCall( ast::PathSegment, Vec, - Vec>, + ThinVec>, ), StructField(symbol::Ident), TupleField(symbol::Ident, bool), diff --git a/src/lib.rs b/src/lib.rs index 0c27bcacfb83c..b27405efdb700 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,7 @@ extern crate rustc_expand; extern crate rustc_parse; extern crate rustc_session; extern crate rustc_span; +extern crate thin_vec; // Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta // files. From 23007fc9e4ad5666c65e8a598e2942c8329def0e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 30 Jan 2023 14:13:27 +1100 Subject: [PATCH 083/465] Use `ThinVec` in `ast::Block`. --- src/closures.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/closures.rs b/src/closures.rs index 8fd0fcf8f5c2c..340113866c4e2 100644 --- a/src/closures.rs +++ b/src/closures.rs @@ -1,5 +1,6 @@ use rustc_ast::{ast, ptr}; use rustc_span::Span; +use thin_vec::thin_vec; use crate::attr::get_attrs_from_stmt; use crate::config::lists::*; @@ -150,7 +151,7 @@ fn rewrite_closure_with_block( } let block = ast::Block { - stmts: vec![ast::Stmt { + stmts: thin_vec![ast::Stmt { id: ast::NodeId::root(), kind: ast::StmtKind::Expr(ptr::P(body.clone())), span: body.span, From 01ed9ddf0ef7a754235b6c1f92689e6f048282d0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 30 Jan 2023 15:39:22 +1100 Subject: [PATCH 084/465] Use `ThinVec` in a few more AST types. --- src/modules.rs | 13 +++++++------ src/parse/parser.rs | 3 ++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/modules.rs b/src/modules.rs index 7a0d1736c59a6..af9a154a6aea6 100644 --- a/src/modules.rs +++ b/src/modules.rs @@ -6,6 +6,7 @@ use rustc_ast::ast; use rustc_ast::visit::Visitor; use rustc_span::symbol::{self, sym, Symbol}; use rustc_span::Span; +use thin_vec::ThinVec; use thiserror::Error; use crate::attr::MetaVisitor; @@ -25,7 +26,7 @@ type FileModMap<'ast> = BTreeMap>; #[derive(Debug, Clone)] pub(crate) struct Module<'a> { ast_mod_kind: Option>, - pub(crate) items: Cow<'a, Vec>>, + pub(crate) items: Cow<'a, ThinVec>>, inner_attr: ast::AttrVec, pub(crate) span: Span, } @@ -34,7 +35,7 @@ impl<'a> Module<'a> { pub(crate) fn new( mod_span: Span, ast_mod_kind: Option>, - mod_items: Cow<'a, Vec>>, + mod_items: Cow<'a, ThinVec>>, mod_attrs: Cow<'a, ast::AttrVec>, ) -> Self { let inner_attr = mod_attrs @@ -157,7 +158,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> { Module::new( module_item.item.span, Some(Cow::Owned(sub_mod_kind.clone())), - Cow::Owned(vec![]), + Cow::Owned(ThinVec::new()), Cow::Owned(ast::AttrVec::new()), ), )?; @@ -169,7 +170,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> { /// Visit modules defined inside macro calls. fn visit_mod_outside_ast( &mut self, - items: Vec>, + items: ThinVec>, ) -> Result<(), ModuleResolutionError> { for item in items { if is_cfg_if(&item) { @@ -184,7 +185,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> { Module::new( span, Some(Cow::Owned(sub_mod_kind.clone())), - Cow::Owned(vec![]), + Cow::Owned(ThinVec::new()), Cow::Owned(ast::AttrVec::new()), ), )?; @@ -210,7 +211,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> { Module::new( span, Some(Cow::Borrowed(sub_mod_kind)), - Cow::Owned(vec![]), + Cow::Owned(ThinVec::new()), Cow::Borrowed(&item.attrs), ), )?; diff --git a/src/parse/parser.rs b/src/parse/parser.rs index e0bd065518b3d..7ab042506bd29 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -6,6 +6,7 @@ use rustc_ast::{ast, ptr}; use rustc_errors::Diagnostic; use rustc_parse::{new_parser_from_file, parser::Parser as RawParser}; use rustc_span::{sym, Span}; +use thin_vec::ThinVec; use crate::attr::first_attr_value_str_by_name; use crate::parse::session::ParseSess; @@ -109,7 +110,7 @@ impl<'a> Parser<'a> { sess: &'a ParseSess, path: &Path, span: Span, - ) -> Result<(ast::AttrVec, Vec>, Span), ParserError> { + ) -> Result<(ast::AttrVec, ThinVec>, Span), ParserError> { let result = catch_unwind(AssertUnwindSafe(|| { let mut parser = new_parser_from_file(sess.inner(), path, Some(span)); match parser.parse_mod(&TokenKind::Eof) { From 3e14bba40c78dec57fc87ff07581b11daf530b0c Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 13 Oct 2022 10:13:02 +0100 Subject: [PATCH 085/465] errors: generate typed identifiers in each crate Instead of loading the Fluent resources for every crate in `rustc_error_messages`, each crate generates typed identifiers for its own diagnostics and creates a static which are pulled together in the `rustc_driver` crate and provided to the diagnostic emitter. Signed-off-by: David Wood --- locales/en-US.ftl | 62 +++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 5 +++- 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 locales/en-US.ftl diff --git a/locales/en-US.ftl b/locales/en-US.ftl new file mode 100644 index 0000000000000..6101b28ab0cdd --- /dev/null +++ b/locales/en-US.ftl @@ -0,0 +1,62 @@ +codegen_gcc_unwinding_inline_asm = + GCC backend does not support unwinding from inline asm + +codegen_gcc_lto_not_supported = + LTO is not supported. You may get a linker error. + +codegen_gcc_invalid_monomorphization_basic_integer = + invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}` + +codegen_gcc_invalid_monomorphization_invalid_float_vector = + invalid monomorphization of `{$name}` intrinsic: unsupported element type `{$elem_ty}` of floating-point vector `{$vec_ty}` + +codegen_gcc_invalid_monomorphization_not_float = + invalid monomorphization of `{$name}` intrinsic: `{$ty}` is not a floating-point type + +codegen_gcc_invalid_monomorphization_unrecognized = + invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}` + +codegen_gcc_invalid_monomorphization_expected_signed_unsigned = + invalid monomorphization of `{$name}` intrinsic: expected element type `{$elem_ty}` of vector type `{$vec_ty}` to be a signed or unsigned integer type + +codegen_gcc_invalid_monomorphization_unsupported_element = + invalid monomorphization of `{$name}` intrinsic: unsupported {$name} from `{$in_ty}` with element `{$elem_ty}` to `{$ret_ty}` + +codegen_gcc_invalid_monomorphization_invalid_bitmask = + invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]` + +codegen_gcc_invalid_monomorphization_simd_shuffle = + invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}` + +codegen_gcc_invalid_monomorphization_expected_simd = + invalid monomorphization of `{$name}` intrinsic: expected SIMD {$expected_ty} type, found non-SIMD `{$found_ty}` + +codegen_gcc_invalid_monomorphization_mask_type = + invalid monomorphization of `{$name}` intrinsic: mask element type is `{$ty}`, expected `i_` + +codegen_gcc_invalid_monomorphization_return_length = + invalid monomorphization of `{$name}` intrinsic: expected return type of length {$in_len}, found `{$ret_ty}` with length {$out_len} + +codegen_gcc_invalid_monomorphization_return_length_input_type = + invalid monomorphization of `{$name}` intrinsic: expected return type with length {$in_len} (same as input type `{$in_ty}`), found `{$ret_ty}` with length {$out_len} + +codegen_gcc_invalid_monomorphization_return_element = + invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}` + +codegen_gcc_invalid_monomorphization_return_type = + invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` + +codegen_gcc_invalid_monomorphization_inserted_type = + invalid monomorphization of `{$name}` intrinsic: expected inserted type `{$in_elem}` (element of input `{$in_ty}`), found `{$out_ty}` + +codegen_gcc_invalid_monomorphization_return_integer_type = + invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}` + +codegen_gcc_invalid_monomorphization_mismatched_lengths = + invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}` + +codegen_gcc_invalid_monomorphization_unsupported_cast = + invalid monomorphization of `{$name}` intrinsic: unsupported cast from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}` with element `{$out_elem}` + +codegen_gcc_invalid_monomorphization_unsupported_operation = + invalid monomorphization of `{$name}` intrinsic: unsupported operation on `{$in_ty}` with element `{$in_elem}` diff --git a/src/lib.rs b/src/lib.rs index 5ab87feb98b11..546c892aae5af 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -73,7 +73,8 @@ use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModul use rustc_codegen_ssa::target_features::supported_target_features; use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{ErrorGuaranteed, Handler}; +use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, Handler, SubdiagnosticMessage}; +use rustc_macros::fluent_messages; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; @@ -84,6 +85,8 @@ use rustc_span::Symbol; use rustc_span::fatal_error::FatalError; use tempfile::TempDir; +fluent_messages! { "../locales/en-US.ftl" } + pub struct PrintOnPanic String>(pub F); impl String> Drop for PrintOnPanic { From 8b7f8116d62e53cfd2b700155e6851c026529819 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 13 Oct 2022 10:13:02 +0100 Subject: [PATCH 086/465] errors: generate typed identifiers in each crate Instead of loading the Fluent resources for every crate in `rustc_error_messages`, each crate generates typed identifiers for its own diagnostics and creates a static which are pulled together in the `rustc_driver` crate and provided to the diagnostic emitter. Signed-off-by: David Wood --- src/parse/session.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parse/session.rs b/src/parse/session.rs index 9014026b0aa4a..a7a363d47ba6a 100644 --- a/src/parse/session.rs +++ b/src/parse/session.rs @@ -124,7 +124,7 @@ fn default_handler( silent_emitter() } else { let fallback_bundle = - rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false); + rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES, false); Box::new(EmitterWriter::stderr( color_cfg, Some(source_map.clone()), From 984945a1176fef84d45eb9ff0a59dbdfd010890f Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 17 Oct 2022 14:11:26 +0100 Subject: [PATCH 087/465] various: translation resources from cg backend Extend `CodegenBackend` trait with a function returning the translation resources from the codegen backend, which can be added to the complete list of resources provided to the emitter. Signed-off-by: David Wood --- src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 546c892aae5af..44538b415283c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -103,6 +103,10 @@ pub struct GccCodegenBackend { } impl CodegenBackend for GccCodegenBackend { + fn locale_resource(&self) -> &'static str { + crate::DEFAULT_LOCALE_RESOURCE + } + fn init(&self, sess: &Session) { if sess.lto() != Lto::No { sess.emit_warning(LTONotSupported {}); From 386ea3770f39e41c8e3be7a05527484b11e23769 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 17 Oct 2022 14:11:26 +0100 Subject: [PATCH 088/465] various: translation resources from cg backend Extend `CodegenBackend` trait with a function returning the translation resources from the codegen backend, which can be added to the complete list of resources provided to the emitter. Signed-off-by: David Wood --- src/parse/session.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/parse/session.rs b/src/parse/session.rs index a7a363d47ba6a..a64963db6a7d0 100644 --- a/src/parse/session.rs +++ b/src/parse/session.rs @@ -123,8 +123,10 @@ fn default_handler( let emitter = if hide_parse_errors { silent_emitter() } else { - let fallback_bundle = - rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES, false); + let fallback_bundle = rustc_errors::fallback_fluent_bundle( + rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), + false, + ); Box::new(EmitterWriter::stderr( color_cfg, Some(source_map.clone()), From aefda5786e92a38c4bb1da0cc8abf0d2e0ee509b Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Wed, 22 Feb 2023 02:18:40 +0000 Subject: [PATCH 089/465] Remove type-traversal trait aliases --- src/callee.rs | 2 +- src/mono_item.rs | 2 +- src/type_of.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/callee.rs b/src/callee.rs index c1041125ecce7..9e3a22ee05d7c 100644 --- a/src/callee.rs +++ b/src/callee.rs @@ -1,6 +1,6 @@ use gccjit::{FunctionType, RValue}; use rustc_codegen_ssa::traits::BaseTypeMethods; -use rustc_middle::ty::{self, Instance, TypeVisitable}; +use rustc_middle::ty::{self, Instance, TypeVisitableExt}; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; use crate::abi::FnAbiGccExt; diff --git a/src/mono_item.rs b/src/mono_item.rs index 9468a1ef4bbbb..a7c868354fb27 100644 --- a/src/mono_item.rs +++ b/src/mono_item.rs @@ -1,7 +1,7 @@ use rustc_codegen_ssa::traits::PreDefineMethods; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::mono::{Linkage, Visibility}; -use rustc_middle::ty::{self, Instance, TypeVisitable}; +use rustc_middle::ty::{self, Instance, TypeVisitableExt}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; use rustc_span::def_id::DefId; diff --git a/src/type_of.rs b/src/type_of.rs index 1326af670cde4..ea2ce765053ff 100644 --- a/src/type_of.rs +++ b/src/type_of.rs @@ -3,7 +3,7 @@ use std::fmt::Write; use gccjit::{Struct, Type}; use crate::rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods}; use rustc_middle::bug; -use rustc_middle::ty::{self, Ty, TypeVisitable}; +use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_target::abi::{self, Abi, F32, F64, FieldsShape, Int, Integer, Pointer, PointeeInfo, Size, TyAbiInterface, Variants}; From 5b0dbc47d7645b6ed12a4a81ab4daf85d1fa3a0f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 17 Feb 2023 14:33:08 +1100 Subject: [PATCH 090/465] Rename many interner functions. (This is a large commit. The changes to `compiler/rustc_middle/src/ty/context.rs` are the most important ones.) The current naming scheme is a mess, with a mix of `_intern_`, `intern_` and `mk_` prefixes, with little consistency. In particular, in many cases it's easy to use an iterator interner when a (preferable) slice interner is available. The guiding principles of the new naming system: - No `_intern_` prefixes. - The `intern_` prefix is for internal operations. - The `mk_` prefix is for external operations. - For cases where there is a slice interner and an iterator interner, the former is `mk_foo` and the latter is `mk_foo_from_iter`. Also, `slice_interners!` and `direct_interners!` can now be `pub` or non-`pub`, which helps enforce the internal/external operations division. It's not perfect, but I think it's a clear improvement. The following lists show everything that was renamed. slice_interners - const_list - mk_const_list -> mk_const_list_from_iter - intern_const_list -> mk_const_list - substs - mk_substs -> mk_substs_from_iter - intern_substs -> mk_substs - check_substs -> check_and_mk_substs (this is a weird one) - canonical_var_infos - intern_canonical_var_infos -> mk_canonical_var_infos - poly_existential_predicates - mk_poly_existential_predicates -> mk_poly_existential_predicates_from_iter - intern_poly_existential_predicates -> mk_poly_existential_predicates - _intern_poly_existential_predicates -> intern_poly_existential_predicates - predicates - mk_predicates -> mk_predicates_from_iter - intern_predicates -> mk_predicates - _intern_predicates -> intern_predicates - projs - intern_projs -> mk_projs - place_elems - mk_place_elems -> mk_place_elems_from_iter - intern_place_elems -> mk_place_elems - bound_variable_kinds - mk_bound_variable_kinds -> mk_bound_variable_kinds_from_iter - intern_bound_variable_kinds -> mk_bound_variable_kinds direct_interners - region - intern_region (unchanged) - const - mk_const_internal -> intern_const - const_allocation - intern_const_alloc -> mk_const_alloc - layout - intern_layout -> mk_layout - adt_def - intern_adt_def -> mk_adt_def_from_data (unusual case, hard to avoid) - alloc_adt_def(!) -> mk_adt_def - external_constraints - intern_external_constraints -> mk_external_constraints Other - type_list - mk_type_list -> mk_type_list_from_iter - intern_type_list -> mk_type_list - tup - mk_tup -> mk_tup_from_iter - intern_tup -> mk_tup --- src/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context.rs b/src/context.rs index 4424b31c0542c..fc746fbd599f2 100644 --- a/src/context.rs +++ b/src/context.rs @@ -383,7 +383,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { tcx, ty::ParamEnv::reveal_all(), def_id, - tcx.intern_substs(&[]), + tcx.mk_substs(&[]), ) .unwrap().unwrap(), ), From ea83d6f4d83c53a7da67e995efbaba6ca394903a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 20 Feb 2023 14:52:23 +1100 Subject: [PATCH 091/465] Use `List::empty()` instead of `mk_substs(&[])`. --- src/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context.rs b/src/context.rs index fc746fbd599f2..457006319afb8 100644 --- a/src/context.rs +++ b/src/context.rs @@ -383,7 +383,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { tcx, ty::ParamEnv::reveal_all(), def_id, - tcx.mk_substs(&[]), + ty::List::empty(), ) .unwrap().unwrap(), ), From d725cfb6abd04691a3e5c91e4f2c0e3860561deb Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 5 Mar 2023 12:03:19 -0500 Subject: [PATCH 092/465] Merge commit '08a6d6e16b5efe217123e780398969946266268f' into sync-cg_gcc-2023-03-04 --- .github/workflows/ci.yml | 111 +- .github/workflows/release.yml | 111 + .github/workflows/stdarch.yml | 116 + Cargo.lock | 7 + Cargo.toml | 2 + Readme.md | 92 +- build_sysroot/build_sysroot.sh | 2 +- config.sh | 2 +- example/alloc_example.rs | 20 +- example/mini_core.rs | 68 +- example/mini_core_hello_world.rs | 2 + example/mod_bench.rs | 6 +- example/std_example.rs | 1 + failing-ui-tests.txt | 68 + failing-ui-tests12.txt | 39 + locales/en-US.ftl | 3 + ...1-Add-stdarch-Cargo.toml-for-testing.patch | 39 + patches/0001-Disable-examples.patch | 25 + ...022-core-Disable-not-compiling-tests.patch | 47 +- ...0024-core-Disable-portable-simd-test.patch | 28 - rust-toolchain | 2 +- rustc_patches/compile_test.patch | 14 - src/allocator.rs | 16 +- src/asm.rs | 211 +- src/attributes.rs | 112 + src/back/write.rs | 1 + src/base.rs | 45 +- src/builder.rs | 413 ++- src/callee.rs | 113 +- src/common.rs | 26 +- src/consts.rs | 171 +- src/context.rs | 83 +- src/declare.rs | 15 +- src/errors.rs | 6 + src/int.rs | 16 +- src/intrinsic/archs.rs | 2443 ++++++++++++++++- src/intrinsic/llvm.rs | 797 +++++- src/intrinsic/mod.rs | 156 +- src/intrinsic/simd.rs | 839 ++++-- src/lib.rs | 9 +- src/mono_item.rs | 40 +- src/type_.rs | 22 +- src/type_of.rs | 48 +- test.sh | 240 +- tests/lang_tests_common.rs | 6 +- tests/run/abort1.rs | 1 + tests/run/abort2.rs | 1 + tests/run/array.rs | 3 +- tests/run/assign.rs | 3 +- tests/run/closure.rs | 10 +- tests/run/condition.rs | 3 +- tests/run/fun_ptr.rs | 3 +- tests/run/int.rs | 16 +- tests/run/int_overflow.rs | 3 +- tests/run/mut_ref.rs | 3 +- tests/run/operations.rs | 3 +- tests/run/ptr_cast.rs | 3 +- tests/run/slice.rs | 1 + tests/run/static.rs | 1 + tools/check_intrinsics_duplicates.py | 67 + tools/generate_intrinsics.py | 91 +- 61 files changed, 5726 insertions(+), 1119 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/stdarch.yml create mode 100644 failing-ui-tests.txt create mode 100644 failing-ui-tests12.txt create mode 100644 patches/0001-Add-stdarch-Cargo.toml-for-testing.patch create mode 100644 patches/0001-Disable-examples.patch delete mode 100644 patches/0024-core-Disable-portable-simd-test.patch delete mode 100644 rustc_patches/compile_test.patch create mode 100644 src/attributes.rs create mode 100644 tools/check_intrinsics_duplicates.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ebdabe82610e..d2b7724a2215f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,36 +4,72 @@ on: - push - pull_request +permissions: + contents: read + +env: + # Enable backtraces for easier debugging + RUST_BACKTRACE: 1 + jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: - libgccjit_version: ["libgccjit.so", "libgccjit_without_int128.so", "libgccjit12.so"] + libgccjit_version: + - { gcc: "libgccjit.so", extra: "", env_extra: "", artifacts_branch: "master" } + - { gcc: "libgccjit_without_int128.so", extra: "", env_extra: "", artifacts_branch: "master-without-128bit-integers" } + - { gcc: "libgccjit12.so", extra: "--no-default-features", env_extra: "TEST_FLAGS='-Cpanic=abort -Zpanic-abort-tests'", artifacts_branch: "gcc12" } + commands: [ + "--mini-tests", + "--std-tests", + # FIXME: re-enable asm tests when GCC can emit in the right syntax. + # "--asm-tests", + "--test-libcore", + "--extended-rand-tests", + "--extended-regex-example-tests", + "--extended-regex-tests", + "--test-successful-rustc --nb-parts 2 --current-part 0", + "--test-successful-rustc --nb-parts 2 --current-part 1", + "--test-failing-rustc", + ] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: repository: llvm/llvm-project path: llvm - name: Install packages - run: sudo apt-get install ninja-build ripgrep + # `llvm-14-tools` is needed to install the `FileCheck` binary which is used for asm tests. + run: sudo apt-get install ninja-build ripgrep llvm-14-tools + + - name: Install libgccjit12 + if: matrix.libgccjit_version.gcc == 'libgccjit12.so' + run: sudo apt-get install libgccjit-12-dev - name: Download artifact + if: matrix.libgccjit_version.gcc != 'libgccjit12.so' uses: dawidd6/action-download-artifact@v2 with: workflow: main.yml - name: ${{ matrix.libgccjit_version }} + name: ${{ matrix.libgccjit_version.gcc }} path: gcc-build repo: antoyo/gcc + branch: ${{ matrix.libgccjit_version.artifacts_branch }} + event: push search_artifacts: true # Because, instead, the action only check the last job ran and that won't work since we want multiple artifacts. - name: Setup path to libgccjit + if: matrix.libgccjit_version.gcc == 'libgccjit12.so' + run: echo /usr/lib/gcc/x86_64-linux-gnu/12 > gcc_path + + - name: Setup path to libgccjit + if: matrix.libgccjit_version.gcc != 'libgccjit12.so' run: | echo $(readlink -f gcc-build) > gcc_path # NOTE: the filename is still libgccjit.so even when the artifact name is different. @@ -48,49 +84,44 @@ jobs: - name: Set RUST_COMPILER_RT_ROOT run: echo "RUST_COMPILER_RT_ROOT="${{ env.workspace }}/llvm/compiler-rt >> $GITHUB_ENV - # https://github.com/actions/cache/issues/133 - - name: Fixup owner of ~/.cargo/ - # Don't remove the trailing /. It is necessary to follow the symlink. - run: sudo chown -R $(whoami):$(id -ng) ~/.cargo/ - - name: Cache cargo installed crates - uses: actions/cache@v1.1.2 + uses: actions/cache@v3 with: path: ~/.cargo/bin key: cargo-installed-crates2-ubuntu-latest - name: Cache cargo registry - uses: actions/cache@v1 + uses: actions/cache@v3 with: path: ~/.cargo/registry key: ${{ runner.os }}-cargo-registry2-${{ hashFiles('**/Cargo.lock') }} - name: Cache cargo index - uses: actions/cache@v1 + uses: actions/cache@v3 with: path: ~/.cargo/git key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} - name: Cache cargo target dir - uses: actions/cache@v1.1.2 + uses: actions/cache@v3 with: path: target key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }} - - name: Build - if: matrix.libgccjit_version != 'libgccjit12.so' - run: | - ./prepare_build.sh - ./build.sh - cargo test - ./clean_all.sh + #- name: Cache rust repository + ## We only clone the rust repository for rustc tests + #if: ${{ contains(matrix.commands, 'rustc') }} + #uses: actions/cache@v3 + #id: cache-rust-repository + #with: + #path: rust + #key: ${{ runner.os }}-packages-${{ hashFiles('rust/.git/HEAD') }} - name: Build - if: matrix.libgccjit_version == 'libgccjit12.so' run: | ./prepare_build.sh - ./build.sh --no-default-features - cargo test --no-default-features + ${{ matrix.libgccjit_version.env_extra }} ./build.sh ${{ matrix.libgccjit_version.extra }} + ${{ matrix.libgccjit_version.env_extra }} cargo test ${{ matrix.libgccjit_version.extra }} ./clean_all.sh - name: Prepare dependencies @@ -106,26 +137,16 @@ jobs: command: build args: --release - - name: Test - if: matrix.libgccjit_version != 'libgccjit12.so' - run: | - # Enable backtraces for easier debugging - export RUST_BACKTRACE=1 - - # Reduce amount of benchmark runs as they are slow - export COMPILE_RUNS=2 - export RUN_RUNS=2 + - name: Add more failing tests for GCC 12 + if: ${{ matrix.libgccjit_version.gcc == 'libgccjit12.so' }} + run: cat failing-ui-tests12.txt >> failing-ui-tests.txt - ./test.sh --release - - - name: Test - if: matrix.libgccjit_version == 'libgccjit12.so' + - name: Run tests run: | - # Enable backtraces for easier debugging - export RUST_BACKTRACE=1 - - # Reduce amount of benchmark runs as they are slow - export COMPILE_RUNS=2 - export RUN_RUNS=2 + ${{ matrix.libgccjit_version.env_extra }} ./test.sh --release --clean --build-sysroot ${{ matrix.commands }} ${{ matrix.libgccjit_version.extra }} - ./test.sh --release --no-default-features + duplicates: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: python tools/check_intrinsics_duplicates.py diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000000..c4e99469bc20b --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,111 @@ +name: CI with sysroot compiled in release mode + +on: + - push + - pull_request + +permissions: + contents: read + +env: + # Enable backtraces for easier debugging + RUST_BACKTRACE: 1 + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + libgccjit_version: + - { gcc: "libgccjit.so", artifacts_branch: "master" } + commands: [ + "--test-successful-rustc --nb-parts 2 --current-part 0", + "--test-successful-rustc --nb-parts 2 --current-part 1", + ] + + steps: + - uses: actions/checkout@v3 + + - uses: actions/checkout@v3 + with: + repository: llvm/llvm-project + path: llvm + + - name: Install packages + run: sudo apt-get install ninja-build ripgrep + + - name: Download artifact + uses: dawidd6/action-download-artifact@v2 + with: + workflow: main.yml + name: ${{ matrix.libgccjit_version.gcc }} + path: gcc-build + repo: antoyo/gcc + branch: ${{ matrix.libgccjit_version.artifacts_branch }} + event: push + search_artifacts: true # Because, instead, the action only check the last job ran and that won't work since we want multiple artifacts. + + - name: Setup path to libgccjit + run: | + echo $(readlink -f gcc-build) > gcc_path + # NOTE: the filename is still libgccjit.so even when the artifact name is different. + ln gcc-build/libgccjit.so gcc-build/libgccjit.so.0 + + - name: Set env + run: | + echo "LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV + echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV + + - name: Set RUST_COMPILER_RT_ROOT + run: echo "RUST_COMPILER_RT_ROOT="${{ env.workspace }}/llvm/compiler-rt >> $GITHUB_ENV + + - name: Cache cargo installed crates + uses: actions/cache@v3 + with: + path: ~/.cargo/bin + key: cargo-installed-crates2-ubuntu-latest + + - name: Cache cargo registry + uses: actions/cache@v3 + with: + path: ~/.cargo/registry + key: ${{ runner.os }}-cargo-registry2-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache cargo index + uses: actions/cache@v3 + with: + path: ~/.cargo/git + key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache cargo target dir + uses: actions/cache@v3 + with: + path: target + key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }} + + - name: Build + run: | + ./prepare_build.sh + ./build.sh --release --release-sysroot + cargo test + ./clean_all.sh + + - name: Prepare dependencies + run: | + git config --global user.email "user@example.com" + git config --global user.name "User" + ./prepare.sh + + # Compile is a separate step, as the actions-rs/cargo action supports error annotations + - name: Compile + uses: actions-rs/cargo@v1.0.3 + with: + command: build + args: --release + + - name: Run tests + run: | + ./test.sh --release --clean --release-sysroot --build-sysroot ${{ matrix.commands }} diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml new file mode 100644 index 0000000000000..42fb35e738ffd --- /dev/null +++ b/.github/workflows/stdarch.yml @@ -0,0 +1,116 @@ +name: stdarch tests with sysroot compiled in release mode + +on: + - push + - pull_request + +permissions: + contents: read + +env: + # Enable backtraces for easier debugging + RUST_BACKTRACE: 1 + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + libgccjit_version: + - { gcc: "libgccjit.so", artifacts_branch: "master" } + commands: [ + "--test-successful-rustc --nb-parts 2 --current-part 0", + "--test-successful-rustc --nb-parts 2 --current-part 1", + ] + + steps: + - uses: actions/checkout@v3 + + - uses: actions/checkout@v3 + with: + repository: llvm/llvm-project + path: llvm + + - name: Install packages + run: sudo apt-get install ninja-build ripgrep + + - name: Download artifact + uses: dawidd6/action-download-artifact@v2 + with: + workflow: main.yml + name: ${{ matrix.libgccjit_version.gcc }} + path: gcc-build + repo: antoyo/gcc + branch: ${{ matrix.libgccjit_version.artifacts_branch }} + event: push + search_artifacts: true # Because, instead, the action only check the last job ran and that won't work since we want multiple artifacts. + + - name: Setup path to libgccjit + run: | + echo $(readlink -f gcc-build) > gcc_path + # NOTE: the filename is still libgccjit.so even when the artifact name is different. + ln gcc-build/libgccjit.so gcc-build/libgccjit.so.0 + + - name: Set env + run: | + echo "LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV + echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV + + - name: Set RUST_COMPILER_RT_ROOT + run: echo "RUST_COMPILER_RT_ROOT="${{ env.workspace }}/llvm/compiler-rt >> $GITHUB_ENV + + - name: Cache cargo installed crates + uses: actions/cache@v3 + with: + path: ~/.cargo/bin + key: cargo-installed-crates2-ubuntu-latest + + - name: Cache cargo registry + uses: actions/cache@v3 + with: + path: ~/.cargo/registry + key: ${{ runner.os }}-cargo-registry2-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache cargo index + uses: actions/cache@v3 + with: + path: ~/.cargo/git + key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache cargo target dir + uses: actions/cache@v3 + with: + path: target + key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }} + + - name: Build + run: | + ./prepare_build.sh + ./build.sh --release --release-sysroot + cargo test + ./clean_all.sh + + - name: Prepare dependencies + run: | + git config --global user.email "user@example.com" + git config --global user.name "User" + ./prepare.sh + + # Compile is a separate step, as the actions-rs/cargo action supports error annotations + - name: Compile + uses: actions-rs/cargo@v1.0.3 + with: + command: build + args: --release + + - name: Run tests + run: | + ./test.sh --release --clean --release-sysroot --build-sysroot --mini-tests --std-tests --test-libcore + + - name: Run stdarch tests + run: | + cd build_sysroot/sysroot_src/library/stdarch/ + CHANNEL=release TARGET=x86_64-unknown-linux-gnu ../../../../cargo.sh test diff --git a/Cargo.lock b/Cargo.lock index 1cb219e12e04d..65e7619755901 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -208,6 +208,7 @@ version = "0.1.0" dependencies = [ "gccjit", "lang_tester", + "smallvec", "tempfile", ] @@ -220,6 +221,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + [[package]] name = "tempfile" version = "3.2.0" diff --git a/Cargo.toml b/Cargo.toml index 1f3da2f799b78..81066d9ce1f0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,8 @@ gccjit = { git = "https://github.com/antoyo/gccjit.rs" } # Local copy. #gccjit = { path = "../gccjit.rs" } +smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } + [dev-dependencies] lang_tester = "0.3.9" tempfile = "3.1.0" diff --git a/Readme.md b/Readme.md index fe23a26769663..bb74194389254 100644 --- a/Readme.md +++ b/Readme.md @@ -1,5 +1,7 @@ # WIP libgccjit codegen backend for rust +[![Chat on IRC](https://img.shields.io/badge/irc.libera.chat-%23rustc__codegen__gcc-blue.svg)](https://web.libera.chat/#rustc_codegen_gcc) + This is a GCC codegen for rustc, which means it can be loaded by the existing rustc frontend, but benefits from GCC: more architectures are supported and GCC's optimizations are used. **Despite its name, libgccjit can be used for ahead-of-time compilation, as is used here.** @@ -16,21 +18,61 @@ The patches in [this repository](https://github.com/antoyo/libgccjit-patches) ne (Those patches should work when applied on master, but in case it doesn't work, they are known to work when applied on 079c23cfe079f203d5df83fea8e92a60c7d7e878.) You can also use my [fork of gcc](https://github.com/antoyo/gcc) which already includes these patches.** +To build it (most of these instructions come from [here](https://gcc.gnu.org/onlinedocs/jit/internals/index.html), so don't hesitate to take a look there if you encounter an issue): + +```bash +$ git clone https://github.com/antoyo/gcc +$ sudo apt install flex libmpfr-dev libgmp-dev libmpc3 libmpc-dev +$ mkdir gcc-build gcc-install +$ cd gcc-build +$ ../gcc/configure \ + --enable-host-shared \ + --enable-languages=jit \ + --enable-checking=release \ # it enables extra checks which allow to find bugs + --disable-bootstrap \ + --disable-multilib \ + --prefix=$(pwd)/../gcc-install +$ make -j4 # You can replace `4` with another number depending on how many cores you have. +``` + +If you want to run libgccjit tests, you will need to also enable the C++ language in the `configure`: + +```bash +--enable-languages=jit,c++ +``` + +Then to run libgccjit tests: + +```bash +$ cd gcc # from the `gcc-build` folder +$ make check-jit +# To run one specific test: +$ make check-jit RUNTESTFLAGS="-v -v -v jit.exp=jit.dg/test-asm.cc" +``` + **Put the path to your custom build of libgccjit in the file `gcc_path`.** ```bash -$ git clone https://github.com/rust-lang/rustc_codegen_gcc.git -$ cd rustc_codegen_gcc +$ dirname $(readlink -f `find . -name libgccjit.so`) > gcc_path +``` + +You also need to set RUST_COMPILER_RT_ROOT: + +```bash $ git clone https://github.com/llvm/llvm-project llvm --depth 1 --single-branch $ export RUST_COMPILER_RT_ROOT="$PWD/llvm/compiler-rt" -$ ./prepare_build.sh # download and patch sysroot src -$ ./build.sh --release ``` -To run the tests: +Then you can run commands like this: ```bash $ ./prepare.sh # download and patch sysroot src and install hyperfine for benchmarking +$ LIBRARY_PATH=$(cat gcc_path) LD_LIBRARY_PATH=$(cat gcc_path) ./build.sh --release +``` + +To run the tests: + +```bash $ ./test.sh --release ``` @@ -120,13 +162,52 @@ To print a debug representation of a tree: debug_tree(expr); ``` +(defined in print-tree.h) + +To print a debug reprensentation of a gimple struct: + +```c +debug_gimple_stmt(gimple_struct) +``` + To get the `rustc` command to run in `gdb`, add the `--verbose` flag to `cargo build`. +To have the correct file paths in `gdb` instead of `/usr/src/debug/gcc/libstdc++-v3/libsupc++/eh_personality.cc`: + +Maybe by calling the following at the beginning of gdb: + +``` +set substitute-path /usr/src/debug/gcc /path/to/gcc-repo/gcc +``` + +TODO(antoyo): but that's not what I remember I was doing. + ### How to use a custom-build rustc * Build the stage2 compiler (`rustup toolchain link debug-current build/x86_64-unknown-linux-gnu/stage2`). * Clean and rebuild the codegen with `debug-current` in the file `rust-toolchain`. +### How to install a forked git-subtree + +Using git-subtree with `rustc` requires a patched git to make it work. +The PR that is needed is [here](https://github.com/gitgitgadget/git/pull/493). +Use the following instructions to install it: + +``` +git clone git@github.com:tqc/git.git +cd git +git checkout tqc/subtree +make +make install +cd contrib/subtree +make +cp git-subtree ~/bin +``` + +### How to use [mem-trace](https://github.com/antoyo/mem-trace) + +`rustc` needs to be built without `jemalloc` so that `mem-trace` can overload `malloc` since `jemalloc` is linked statically, so a `LD_PRELOAD`-ed library won't a chance to intercept the calls to `malloc`. + ### How to build a cross-compiling libgccjit #### Building libgccjit @@ -142,6 +223,5 @@ To get the `rustc` command to run in `gdb`, add the `--verbose` flag to `cargo b * Since rustc doesn't support this architecture yet, set it back to `TARGET_TRIPLE="mips-unknown-linux-gnu"` (or another target having the same attributes). Alternatively, create a [target specification file](https://book.avr-rust.com/005.1-the-target-specification-json-file.html) (note that the `arch` specified in this file must be supported by the rust compiler). * Set `linker='-Clinker=m68k-linux-gcc'`. * Set the path to the cross-compiling libgccjit in `gcc_path`. - * Disable the 128-bit integer types if the target doesn't support them by using `let i128_type = context.new_type::();` in `context.rs` (same for u128_type). * Comment the line: `context.add_command_line_option("-masm=intel");` in src/base.rs. * (might not be necessary) Disable the compilation of libstd.so (and possibly libcore.so?). diff --git a/build_sysroot/build_sysroot.sh b/build_sysroot/build_sysroot.sh index f293192a099de..9d692d599f6be 100755 --- a/build_sysroot/build_sysroot.sh +++ b/build_sysroot/build_sysroot.sh @@ -16,7 +16,7 @@ rm Cargo.lock test_target/Cargo.lock 2>/dev/null || true rm -r sysroot/ 2>/dev/null || true # Build libs -export RUSTFLAGS="$RUSTFLAGS -Z force-unstable-if-unmarked -Cpanic=abort" +export RUSTFLAGS="$RUSTFLAGS -Z force-unstable-if-unmarked" if [[ "$1" == "--release" ]]; then sysroot_channel='release' RUSTFLAGS="$RUSTFLAGS -Zmir-opt-level=3" cargo build --target $TARGET_TRIPLE --release diff --git a/config.sh b/config.sh index b25e215fb9ee9..166e83901c4f9 100644 --- a/config.sh +++ b/config.sh @@ -38,7 +38,7 @@ if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then fi fi -export RUSTFLAGS="$CG_RUSTFLAGS $linker -Cpanic=abort -Csymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zpanic-abort-tests -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot" +export RUSTFLAGS="$CG_RUSTFLAGS $linker -Csymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot $TEST_FLAGS" # FIXME(antoyo): remove once the atomic shim is gone if [[ `uname` == 'Darwin' ]]; then diff --git a/example/alloc_example.rs b/example/alloc_example.rs index 74ea7ec4ede69..c80348ca54970 100644 --- a/example/alloc_example.rs +++ b/example/alloc_example.rs @@ -1,4 +1,4 @@ -#![feature(start, box_syntax, core_intrinsics, alloc_error_handler)] +#![feature(start, box_syntax, core_intrinsics, alloc_error_handler, lang_items)] #![no_std] extern crate alloc; @@ -18,16 +18,22 @@ extern "C" { #[panic_handler] fn panic_handler(_: &core::panic::PanicInfo) -> ! { - unsafe { - core::intrinsics::abort(); - } + core::intrinsics::abort(); } #[alloc_error_handler] fn alloc_error_handler(_: alloc::alloc::Layout) -> ! { - unsafe { - core::intrinsics::abort(); - } + core::intrinsics::abort(); +} + +#[lang = "eh_personality"] +fn eh_personality() -> ! { + loop {} +} + +#[no_mangle] +unsafe extern "C" fn _Unwind_Resume() { + core::intrinsics::unreachable(); } #[start] diff --git a/example/mini_core.rs b/example/mini_core.rs index ddcbb0d9fc7e8..637b8dc53fefd 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -1,6 +1,6 @@ #![feature( no_core, lang_items, intrinsics, unboxed_closures, type_ascription, extern_types, - untagged_unions, decl_macro, rustc_attrs, transparent_unions, auto_traits, + decl_macro, rustc_attrs, transparent_unions, auto_traits, thread_local )] #![no_core] @@ -17,6 +17,9 @@ pub trait Sized {} #[lang = "destruct"] pub trait Destruct {} +#[lang = "tuple_trait"] +pub trait Tuple {} + #[lang = "unsize"] pub trait Unsize {} @@ -39,14 +42,14 @@ impl<'a, T: ?Sized+Unsize, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut impl, U: ?Sized> DispatchFromDyn<*const U> for *const T {} // *mut T -> *mut U impl, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {} -impl, U: ?Sized> DispatchFromDyn> for Box {} +impl, U: ?Sized> DispatchFromDyn> for Box {} #[lang = "receiver"] pub trait Receiver {} impl Receiver for &T {} impl Receiver for &mut T {} -impl Receiver for Box {} +impl Receiver for Box {} #[lang = "copy"] pub unsafe trait Copy {} @@ -396,7 +399,7 @@ pub struct PhantomData; #[lang = "fn_once"] #[rustc_paren_sugar] -pub trait FnOnce { +pub trait FnOnce { #[lang = "fn_once_output"] type Output; @@ -405,13 +408,21 @@ pub trait FnOnce { #[lang = "fn_mut"] #[rustc_paren_sugar] -pub trait FnMut: FnOnce { +pub trait FnMut: FnOnce { extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; } #[lang = "panic"] #[track_caller] -pub fn panic(_msg: &str) -> ! { +pub fn panic(_msg: &'static str) -> ! { + unsafe { + libc::puts("Panicking\n\0" as *const str as *const u8); + intrinsics::abort(); + } +} + +#[lang = "panic_cannot_unwind"] +fn panic_cannot_unwind() -> ! { unsafe { libc::puts("Panicking\n\0" as *const str as *const u8); intrinsics::abort(); @@ -450,17 +461,32 @@ pub trait Deref { pub trait Allocator { } +impl Allocator for () {} + pub struct Global; impl Allocator for Global {} +#[repr(transparent)] +#[rustc_layout_scalar_valid_range_start(1)] +#[rustc_nonnull_optimization_guaranteed] +pub struct NonNull(pub *const T); + +impl CoerceUnsized> for NonNull where T: Unsize {} +impl DispatchFromDyn> for NonNull where T: Unsize {} + +pub struct Unique { + pub pointer: NonNull, + pub _marker: PhantomData, +} + +impl CoerceUnsized> for Unique where T: Unsize {} +impl DispatchFromDyn> for Unique where T: Unsize {} + #[lang = "owned_box"] -pub struct Box< - T: ?Sized, - A: Allocator = Global, ->(*mut T, A); +pub struct Box(Unique, A); -impl, U: ?Sized> CoerceUnsized> for Box {} +impl, U: ?Sized, A: Allocator> CoerceUnsized> for Box {} impl Drop for Box { fn drop(&mut self) { @@ -468,7 +494,7 @@ impl Drop for Box { } } -impl Deref for Box { +impl Deref for Box { type Target = T; fn deref(&self) -> &Self::Target { @@ -482,8 +508,8 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { } #[lang = "box_free"] -unsafe fn box_free(ptr: *mut T, alloc: A) { - libc::free(ptr as *mut u8); +unsafe fn box_free(ptr: Unique, _alloc: ()) { + libc::free(ptr.pointer.0 as *mut u8); } #[lang = "drop"] @@ -505,17 +531,25 @@ pub union MaybeUninit { } pub mod intrinsics { + use crate::Sized; + extern "rust-intrinsic" { + #[rustc_safe_intrinsic] pub fn abort() -> !; + #[rustc_safe_intrinsic] pub fn size_of() -> usize; - pub fn size_of_val(val: *const T) -> usize; + pub fn size_of_val(val: *const T) -> usize; + #[rustc_safe_intrinsic] pub fn min_align_of() -> usize; - pub fn min_align_of_val(val: *const T) -> usize; + pub fn min_align_of_val(val: *const T) -> usize; pub fn copy(src: *const T, dst: *mut T, count: usize); pub fn transmute(e: T) -> U; pub fn ctlz_nonzero(x: T) -> T; - pub fn needs_drop() -> bool; + #[rustc_safe_intrinsic] + pub fn needs_drop() -> bool; + #[rustc_safe_intrinsic] pub fn bitreverse(x: T) -> T; + #[rustc_safe_intrinsic] pub fn bswap(x: T) -> T; pub fn write_bytes(dst: *mut T, val: u8, count: usize); pub fn unreachable() -> !; diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index 14fd9eeffa6ac..993a31e68eabc 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -85,6 +85,7 @@ fn start( main: fn() -> T, argc: isize, argv: *const *const u8, + _sigpipe: u8, ) -> isize { if argc == 3 { unsafe { puts(*argv); } @@ -228,6 +229,7 @@ fn main() { } as Box; const FUNC_REF: Option = Some(main); + #[allow(unreachable_code)] match FUNC_REF { Some(_) => {}, None => assert!(false), diff --git a/example/mod_bench.rs b/example/mod_bench.rs index 2e2b0052dee8b..95bcad2cd173e 100644 --- a/example/mod_bench.rs +++ b/example/mod_bench.rs @@ -6,9 +6,7 @@ extern {} #[panic_handler] fn panic_handler(_: &core::panic::PanicInfo) -> ! { - unsafe { - core::intrinsics::abort(); - } + core::intrinsics::abort(); } #[lang="eh_personality"] @@ -32,6 +30,6 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize { #[inline(never)] fn black_box(i: u32) { if i != 1 { - unsafe { core::intrinsics::abort(); } + core::intrinsics::abort(); } } diff --git a/example/std_example.rs b/example/std_example.rs index 31069058aea34..5c171c49fd194 100644 --- a/example/std_example.rs +++ b/example/std_example.rs @@ -1,5 +1,6 @@ #![feature(core_intrinsics, generators, generator_trait, is_sorted)] +#[cfg(feature="master")] use std::arch::x86_64::*; use std::io::Write; use std::ops::Generator; diff --git a/failing-ui-tests.txt b/failing-ui-tests.txt new file mode 100644 index 0000000000000..8539e27ea6a58 --- /dev/null +++ b/failing-ui-tests.txt @@ -0,0 +1,68 @@ +tests/ui/allocator/custom-in-block.rs +tests/ui/allocator/custom-in-submodule.rs +tests/ui/allocator/custom.rs +tests/ui/allocator/hygiene.rs +tests/ui/allocator/no_std-alloc-error-handler-custom.rs +tests/ui/allocator/no_std-alloc-error-handler-default.rs +tests/ui/allocator/xcrate-use.rs +tests/ui/allocator/xcrate-use2.rs +tests/ui/asm/may_unwind.rs +tests/ui/asm/x86_64/multiple-clobber-abi.rs +tests/ui/debuginfo/debuginfo-emit-llvm-ir-and-split-debuginfo.rs +tests/ui/functions-closures/parallel-codegen-closures.rs +tests/ui/linkage-attr/linkage1.rs +tests/ui/lto/dylib-works.rs +tests/ui/numbers-arithmetic/saturating-float-casts.rs +tests/ui/polymorphization/promoted-function.rs +tests/ui/process/nofile-limit.rs +tests/ui/sepcomp/sepcomp-cci.rs +tests/ui/sepcomp/sepcomp-extern.rs +tests/ui/sepcomp/sepcomp-fns-backwards.rs +tests/ui/sepcomp/sepcomp-fns.rs +tests/ui/sepcomp/sepcomp-statics.rs +tests/ui/simd/intrinsic/generic-arithmetic-pass.rs +tests/ui/sse2.rs +tests/ui/target-feature/missing-plusminus.rs +tests/ui/asm/x86_64/may_unwind.rs +tests/ui/backtrace.rs +tests/ui/catch-unwind-bang.rs +tests/ui/cfg/cfg-panic-abort.rs +tests/ui/drop/dynamic-drop-async.rs +tests/ui/drop/repeat-drop.rs +tests/ui/fmt/format-args-capture.rs +tests/ui/generator/panic-drops-resume.rs +tests/ui/generator/panic-drops.rs +tests/ui/intrinsics/panic-uninitialized-zeroed.rs +tests/ui/iterators/iter-sum-overflow-debug.rs +tests/ui/iterators/iter-sum-overflow-overflow-checks.rs +tests/ui/mir/mir_calls_to_shims.rs +tests/ui/mir/mir_drop_order.rs +tests/ui/mir/mir_let_chains_drop_order.rs +tests/ui/oom_unwind.rs +tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs +tests/ui/panic-runtime/abort.rs +tests/ui/panic-runtime/link-to-abort.rs +tests/ui/unwind-no-uwtable.rs +tests/ui/parser/unclosed-delimiter-in-dep.rs +tests/ui/runtime/rt-explody-panic-payloads.rs +tests/ui/simd/intrinsic/ptr-cast.rs +tests/ui/binding/fn-arg-incomplete-pattern-drop-order.rs +tests/ui/consts/missing_span_in_backtrace.rs +tests/ui/drop/dynamic-drop.rs +tests/ui/dyn-star/box.rs +tests/ui/issues/issue-40883.rs +tests/ui/issues/issue-43853.rs +tests/ui/issues/issue-47364.rs +tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs +tests/ui/rfc-2091-track-caller/std-panic-locations.rs +tests/ui/rfcs/rfc1857-drop-order.rs +tests/ui/simd/issue-17170.rs +tests/ui/simd/issue-39720.rs +tests/ui/simd/issue-89193.rs +tests/ui/statics/issue-91050-1.rs +tests/ui/statics/issue-91050-2.rs +tests/ui/alloc-error/default-alloc-error-hook.rs +tests/ui/generator/panic-safe.rs +tests/ui/issues/issue-14875.rs +tests/ui/issues/issue-29948.rs +tests/ui/panic-while-printing.rs diff --git a/failing-ui-tests12.txt b/failing-ui-tests12.txt new file mode 100644 index 0000000000000..8c27bd8b8ca89 --- /dev/null +++ b/failing-ui-tests12.txt @@ -0,0 +1,39 @@ +tests/ui/asm/x86_64/issue-96797.rs +tests/ui/intrinsics/const-eval-select-x86_64.rs +tests/ui/packed/packed-struct-drop-aligned.rs +tests/ui/packed/packed-struct-generic-layout.rs +tests/ui/packed/packed-struct-layout.rs +tests/ui/packed/packed-struct-optimized-enum.rs +tests/ui/packed/packed-struct-size.rs +tests/ui/packed/packed-struct-vec.rs +tests/ui/packed/packed-tuple-struct-layout.rs +tests/ui/simd/array-type.rs +tests/ui/simd/intrinsic/float-minmax-pass.rs +tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs +tests/ui/simd/intrinsic/generic-as.rs +tests/ui/simd/intrinsic/generic-cast-pass.rs +tests/ui/simd/intrinsic/generic-cast-pointer-width.rs +tests/ui/simd/intrinsic/generic-comparison-pass.rs +tests/ui/simd/intrinsic/generic-elements-pass.rs +tests/ui/simd/intrinsic/generic-reduction-pass.rs +tests/ui/simd/intrinsic/generic-select-pass.rs +tests/ui/simd/intrinsic/inlining-issue67557-ice.rs +tests/ui/simd/intrinsic/inlining-issue67557.rs +tests/ui/simd/monomorphize-shuffle-index.rs +tests/ui/simd/shuffle.rs +tests/ui/simd/simd-bitmask.rs +tests/ui/generator/resume-after-return.rs +tests/ui/iterators/iter-step-overflow-debug.rs +tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs +tests/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs +tests/ui/privacy/reachable-unnameable-items.rs +tests/ui/rfc-1937-termination-trait/termination-trait-in-test.rs +tests/ui/async-await/async-fn-size-moved-locals.rs +tests/ui/async-await/async-fn-size-uninit-locals.rs +tests/ui/cfg/cfg-panic.rs +tests/ui/generator/size-moved-locals.rs +tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs +tests/ui/simd/intrinsic/generic-gather-pass.rs +tests/ui/simd/issue-85915-simd-ptrs.rs +tests/ui/issues/issue-68010-large-zst-consts.rs +tests/ui/rust-2018/proc-macro-crate-in-paths.rs diff --git a/locales/en-US.ftl b/locales/en-US.ftl index 6101b28ab0cdd..2181d49eeef6b 100644 --- a/locales/en-US.ftl +++ b/locales/en-US.ftl @@ -60,3 +60,6 @@ codegen_gcc_invalid_monomorphization_unsupported_cast = codegen_gcc_invalid_monomorphization_unsupported_operation = invalid monomorphization of `{$name}` intrinsic: unsupported operation on `{$in_ty}` with element `{$in_elem}` + +codegen_gcc_invalid_minimum_alignment = + invalid minimum global alignment: {$err} diff --git a/patches/0001-Add-stdarch-Cargo.toml-for-testing.patch b/patches/0001-Add-stdarch-Cargo.toml-for-testing.patch new file mode 100644 index 0000000000000..93c63b5dcacfd --- /dev/null +++ b/patches/0001-Add-stdarch-Cargo.toml-for-testing.patch @@ -0,0 +1,39 @@ +From c3821e02fbd6cb5ad6e06d759fccdc9073712375 Mon Sep 17 00:00:00 2001 +From: Antoni Boucher +Date: Tue, 7 Jun 2022 21:40:13 -0400 +Subject: [PATCH] Add stdarch Cargo.toml for testing + +--- + library/stdarch/Cargo.toml | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + create mode 100644 library/stdarch/Cargo.toml + +diff --git a/library/stdarch/Cargo.toml b/library/stdarch/Cargo.toml +new file mode 100644 +index 0000000..fbe0a95 +--- /dev/null ++++ b/library/stdarch/Cargo.toml +@@ -0,0 +1,20 @@ ++[workspace] ++members = [ ++ "crates/core_arch", ++ "crates/std_detect", ++ "crates/stdarch-gen", ++ "examples/" ++] ++exclude = [ ++ "crates/wasm-assert-instr-tests" ++] ++ ++[profile.release] ++debug = true ++opt-level = 3 ++incremental = true ++ ++[profile.bench] ++debug = 1 ++opt-level = 3 ++incremental = true +-- +2.26.2.7.g19db9cfb68.dirty + diff --git a/patches/0001-Disable-examples.patch b/patches/0001-Disable-examples.patch new file mode 100644 index 0000000000000..1b71df1ca8df2 --- /dev/null +++ b/patches/0001-Disable-examples.patch @@ -0,0 +1,25 @@ +From a2d53a324a02c04b76c0e9d39dc15cd443a3b8b2 Mon Sep 17 00:00:00 2001 +From: Antoni Boucher +Date: Fri, 25 Nov 2022 11:18:11 -0500 +Subject: [PATCH] Disable examples + +--- + library/stdarch/Cargo.toml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/library/stdarch/Cargo.toml b/library/stdarch/Cargo.toml +index fbe0a95..748d72d 100644 +--- a/library/stdarch/Cargo.toml ++++ b/library/stdarch/Cargo.toml +@@ -3,7 +3,7 @@ members = [ + "crates/core_arch", + "crates/std_detect", + "crates/stdarch-gen", +- "examples/" ++ #"examples/" + ] + exclude = [ + "crates/wasm-assert-instr-tests" +-- +2.26.2.7.g19db9cfb68.dirty + diff --git a/patches/0022-core-Disable-not-compiling-tests.patch b/patches/0022-core-Disable-not-compiling-tests.patch index 301b3f9bde4dd..4db56fa3bd2c7 100644 --- a/patches/0022-core-Disable-not-compiling-tests.patch +++ b/patches/0022-core-Disable-not-compiling-tests.patch @@ -18,7 +18,7 @@ new file mode 100644 index 0000000..46fd999 --- /dev/null +++ b/library/core/tests/Cargo.toml -@@ -0,0 +1,8 @@ +@@ -0,0 +1,12 @@ +[package] +name = "core" +version = "0.0.0" @@ -27,37 +27,18 @@ index 0000000..46fd999 +[lib] +name = "coretests" +path = "lib.rs" -diff --git a/library/core/tests/num/flt2dec/mod.rs b/library/core/tests/num/flt2dec/mod.rs -index a35897e..f0bf645 100644 ---- a/library/core/tests/num/flt2dec/mod.rs -+++ b/library/core/tests/num/flt2dec/mod.rs -@@ -13,7 +13,6 @@ mod strategy { - mod dragon; - mod grisu; - } --mod random; - - pub fn decode_finite(v: T) -> Decoded { - match decode(v).1 { -diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs -index 6609bc3..241b497 100644 ---- a/library/core/tests/slice.rs -+++ b/library/core/tests/slice.rs -@@ -1209,6 +1209,7 @@ fn brute_force_rotate_test_1() { - } - } - -+/* - #[test] - #[cfg(not(target_arch = "wasm32"))] - fn sort_unstable() { -@@ -1394,6 +1395,7 @@ fn partition_at_index() { - v.select_nth_unstable(0); - assert!(v == [0xDEADBEEF]); - } -+*/ - - #[test] - #[should_panic(expected = "index 0 greater than length of slice")] ++ ++[dependencies] ++rand = { version = "0.8.5", default-features = false } ++rand_xorshift = { version = "0.3.0", default-features = false } +diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs +index 42a26ae..5ac1042 100644 +--- a/library/core/tests/lib.rs ++++ b/library/core/tests/lib.rs +@@ -1,3 +1,4 @@ ++#![cfg(test)] + #![feature(alloc_layout_extra)] + #![feature(array_chunks)] + #![feature(array_methods)] -- 2.21.0 (Apple Git-122) diff --git a/patches/0024-core-Disable-portable-simd-test.patch b/patches/0024-core-Disable-portable-simd-test.patch deleted file mode 100644 index c59a40df03988..0000000000000 --- a/patches/0024-core-Disable-portable-simd-test.patch +++ /dev/null @@ -1,28 +0,0 @@ -From b1ae000f6da1abd3b8e9b80c40bc11c89b8ae93c Mon Sep 17 00:00:00 2001 -From: bjorn3 -Date: Thu, 30 Dec 2021 16:54:40 +0100 -Subject: [PATCH] [core] Disable portable-simd test - ---- - library/core/tests/lib.rs | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs -index 06c7be0..359e2e7 100644 ---- a/library/core/tests/lib.rs -+++ b/library/core/tests/lib.rs -@@ -75,7 +75,6 @@ - #![feature(never_type)] - #![feature(unwrap_infallible)] --#![feature(portable_simd)] - #![feature(ptr_metadata)] - #![feature(once_cell)] - #![feature(option_result_contains)] -@@ -127,7 +126,6 @@ mod pin; - mod pin_macro; - mod ptr; - mod result; --mod simd; - mod slice; - mod str; - mod str_lossy; diff --git a/rust-toolchain b/rust-toolchain index b20aeb979ad78..933ecd45baadb 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-06-06" +channel = "nightly-2023-03-02" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/rustc_patches/compile_test.patch b/rustc_patches/compile_test.patch deleted file mode 100644 index 59143eac37b3f..0000000000000 --- a/rustc_patches/compile_test.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs -index 887d27fd6dca4..2c2239f2b83d1 100644 ---- a/src/tools/compiletest/src/header.rs -+++ b/src/tools/compiletest/src/header.rs -@@ -806,8 +806,8 @@ pub fn make_test_description( - cfg: Option<&str>, - ) -> test::TestDesc { - let mut ignore = false; - #[cfg(not(bootstrap))] -- let ignore_message: Option = None; -+ let ignore_message: Option<&str> = None; - let mut should_fail = false; - - let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some(); diff --git a/src/allocator.rs b/src/allocator.rs index e2c9ffe9c1c30..4bad33ee879ee 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -1,3 +1,5 @@ +#[cfg(feature="master")] +use gccjit::FnAttribute; use gccjit::{FunctionType, GlobalKind, ToRValue}; use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS}; use rustc_middle::bug; @@ -50,7 +52,8 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, name, false); if tcx.sess.target.options.default_hidden_visibility { - // TODO(antoyo): set visibility. + #[cfg(feature="master")] + func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); } if tcx.sess.must_emit_unwind_tables() { // TODO(antoyo): emit unwind tables. @@ -61,7 +64,8 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) .collect(); let callee = context.new_function(None, FunctionType::Extern, output.unwrap_or(void), &args, callee, false); - // TODO(antoyo): set visibility. + #[cfg(feature="master")] + callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); let block = func.new_block("entry"); @@ -90,12 +94,18 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam .collect(); let func = context.new_function(None, FunctionType::Exported, void, &args, name, false); + if tcx.sess.target.default_hidden_visibility { + #[cfg(feature="master")] + func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); + } + let callee = alloc_error_handler_kind.fn_name(sym::oom); let args: Vec<_> = types.iter().enumerate() .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) .collect(); let callee = context.new_function(None, FunctionType::Extern, void, &args, callee, false); - //llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden); + #[cfg(feature="master")] + callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); let block = func.new_block("entry"); diff --git a/src/asm.rs b/src/asm.rs index c346dbd63cca7..41e9d61a10e50 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -157,7 +157,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { use ConstraintOrRegister::*; let (constraint, ty) = match (reg_to_gcc(reg), place) { - (Constraint(constraint), Some(place)) => (constraint, place.layout.gcc_type(self.cx, false)), + (Constraint(constraint), Some(place)) => (constraint, place.layout.gcc_type(self.cx)), // When `reg` is a class and not an explicit register but the out place is not specified, // we need to create an unused output variable to assign the output to. This var // needs to be of a type that's "compatible" with the register class, but specific type @@ -226,7 +226,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // This decision is also backed by the fact that LLVM needs in and out // values to be of *exactly the same type*, not just "compatible". // I'm not sure if GCC is so picky too, but better safe than sorry. - let ty = in_value.layout.gcc_type(self.cx, false); + let ty = in_value.layout.gcc_type(self.cx); let tmp_var = self.current_func().new_local(None, ty, "output_register"); // If the out_place is None (i.e `inout(reg) _` syntax was used), we translate @@ -286,7 +286,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { continue }; - let ty = out_place.layout.gcc_type(self.cx, false); + let ty = out_place.layout.gcc_type(self.cx); let tmp_var = self.current_func().new_local(None, ty, "output_register"); tmp_var.set_register_name(reg_name); @@ -306,7 +306,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // `in("explicit register") var` InlineAsmOperandRef::In { reg, value } => { if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) { - let ty = value.layout.gcc_type(self.cx, false); + let ty = value.layout.gcc_type(self.cx); let reg_var = self.current_func().new_local(None, ty, "input_register"); reg_var.set_register_name(reg_name); self.llbb().add_assignment(None, reg_var, value.immediate()); @@ -325,7 +325,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => { if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) { // See explanation in the first pass. - let ty = in_value.layout.gcc_type(self.cx, false); + let ty = in_value.layout.gcc_type(self.cx); let tmp_var = self.current_func().new_local(None, ty, "output_register"); tmp_var.set_register_name(reg_name); @@ -353,8 +353,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { inputs.push(AsmInOperand { constraint: "X".into(), rust_idx, - val: self.cx.rvalue_as_function(get_fn(self.cx, instance)) - .get_address(None), + val: get_fn(self.cx, instance).get_address(None), }); } @@ -382,15 +381,19 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { for piece in template { match *piece { InlineAsmTemplatePiece::String(ref string) => { - // TODO(@Commeownist): switch to `Iterator::intersperse` once it's stable - let mut iter = string.split('%'); - if let Some(s) = iter.next() { - template_str.push_str(s); - } - - for s in iter { - template_str.push_str("%%"); - template_str.push_str(s); + for char in string.chars() { + // TODO(antoyo): might also need to escape | if rustc doesn't do it. + let escaped_char = + match char { + '%' => "%%", + '{' => "%{", + '}' => "%}", + _ => { + template_str.push(char); + continue; + }, + }; + template_str.push_str(escaped_char); } } InlineAsmTemplatePiece::Placeholder { operand_idx, modifier, span: _ } => { @@ -565,39 +568,52 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { _ => unimplemented!(), } }, + // They can be retrieved from https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html InlineAsmRegOrRegClass::RegClass(reg) => match reg { - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => unimplemented!(), - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => unimplemented!(), - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => unimplemented!(), - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => unimplemented!(), - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => unimplemented!(), + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r", + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => "w", + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x", + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { + unreachable!("clobber-only") + } + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => "r", InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) => unimplemented!(), - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => unimplemented!(), - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => unimplemented!(), - InlineAsmRegClass::Avr(_) => unimplemented!(), - InlineAsmRegClass::Bpf(_) => unimplemented!(), - InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => unimplemented!(), - InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => unimplemented!(), - InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => unimplemented!(), - InlineAsmRegClass::Msp430(_) => unimplemented!(), - InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => unimplemented!(), - InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => unimplemented!(), - InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => unimplemented!(), - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => unimplemented!(), - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => unimplemented!(), - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => unimplemented!(), + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "t", + InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_upper) => "d", + InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) => "r", + InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => "w", + InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e", + InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w", + InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "d", // more specific than "r" + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f", + InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r", + // https://github.com/gcc-mirror/gcc/blob/master/gcc/config/nvptx/nvptx.md -> look for + // "define_constraint". + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h", + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r", + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l", + + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b", + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f", InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { unreachable!("clobber-only") }, - InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => unimplemented!(), - InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => unimplemented!(), - InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => unimplemented!(), + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f", + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => { + unreachable!("clobber-only") + } InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r", InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q", InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "q", @@ -605,16 +621,18 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x", InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v", InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "Yk", - InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => unimplemented!(), - InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(), InlineAsmRegClass::X86( - X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg | X86InlineAsmRegClass::tmm_reg, + X86InlineAsmRegClass::kreg0 + | X86InlineAsmRegClass::x87_reg + | X86InlineAsmRegClass::mmx_reg + | X86InlineAsmRegClass::tmm_reg, ) => unreachable!("clobber-only"), InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("GCC backend does not support SPIR-V") } - InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => unimplemented!(), - InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => unimplemented!(), + InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r", + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f", InlineAsmRegClass::Err => unreachable!(), } }; @@ -692,21 +710,23 @@ impl<'gcc, 'tcx> AsmMethods<'tcx> for CodegenCx<'gcc, 'tcx> { && options.contains(InlineAsmOptions::ATT_SYNTAX); // Build the template string - let mut template_str = String::new(); + let mut template_str = ".pushsection .text\n".to_owned(); + if att_dialect { + template_str.push_str(".att_syntax\n"); + } for piece in template { match *piece { InlineAsmTemplatePiece::String(ref string) => { - for line in string.lines() { + let mut index = 0; + while index < string.len() { // NOTE: gcc does not allow inline comment, so remove them. - let line = - if let Some(index) = line.rfind("//") { - &line[..index] - } - else { - line - }; - template_str.push_str(line); - template_str.push('\n'); + let comment_index = string[index..].find("//") + .map(|comment_index| comment_index + index) + .unwrap_or(string.len()); + template_str.push_str(&string[index..comment_index]); + index = string[comment_index..].find('\n') + .map(|index| index + comment_index) + .unwrap_or(string.len()); } }, InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: _ } => { @@ -719,6 +739,8 @@ impl<'gcc, 'tcx> AsmMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } GlobalAsmOperandRef::SymFn { instance } => { + let function = get_fn(self, instance); + self.add_used_function(function); // TODO(@Amanieu): Additional mangling is needed on // some targets to add a leading underscore (Mach-O) // or byte count suffixes (x86 Windows). @@ -727,6 +749,7 @@ impl<'gcc, 'tcx> AsmMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } GlobalAsmOperandRef::SymStatic { def_id } => { + // TODO(antoyo): set the global variable as used. // TODO(@Amanieu): Additional mangling is needed on // some targets to add a leading underscore (Mach-O). let instance = Instance::mono(self.tcx, def_id); @@ -738,48 +761,51 @@ impl<'gcc, 'tcx> AsmMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } } - let template_str = - if att_dialect { - format!(".att_syntax\n\t{}\n\t.intel_syntax noprefix", template_str) - } - else { - template_str - }; + if att_dialect { + template_str.push_str("\n\t.intel_syntax noprefix"); + } // NOTE: seems like gcc will put the asm in the wrong section, so set it to .text manually. - let template_str = format!(".pushsection .text\n{}\n.popsection", template_str); + template_str.push_str("\n.popsection"); self.context.add_top_level_asm(None, &template_str); } } fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option) -> Option { + // The modifiers can be retrieved from + // https://gcc.gnu.org/onlinedocs/gcc/Modifiers.html#Modifiers match reg { InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => modifier, - InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => modifier, InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { - unimplemented!() + if modifier == Some('v') { None } else { modifier } + } + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { + unreachable!("clobber-only") } - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => unimplemented!(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => None, InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => unimplemented!(), + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => None, InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) => unimplemented!(), + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) => Some('P'), InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => { - unimplemented!() + if modifier.is_none() { + Some('q') + } else { + modifier + } } - InlineAsmRegClass::Avr(_) => unimplemented!(), - InlineAsmRegClass::Bpf(_) => unimplemented!(), - InlineAsmRegClass::Hexagon(_) => unimplemented!(), - InlineAsmRegClass::Mips(_) => unimplemented!(), - InlineAsmRegClass::Msp430(_) => unimplemented!(), - InlineAsmRegClass::Nvptx(_) => unimplemented!(), - InlineAsmRegClass::PowerPC(_) => unimplemented!(), + InlineAsmRegClass::Hexagon(_) => None, + InlineAsmRegClass::Mips(_) => None, + InlineAsmRegClass::Nvptx(_) => None, + InlineAsmRegClass::PowerPC(_) => None, InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) - | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => unimplemented!(), - InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => unimplemented!(), + | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None, + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => { + unreachable!("clobber-only") + } InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) | InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => match modifier { None => if arch == InlineAsmArch::X86_64 { Some('q') } else { Some('k') }, @@ -803,16 +829,29 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option _ => unreachable!(), }, InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None, - InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => None, - InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg | X86InlineAsmRegClass::tmm_reg) => { + InlineAsmRegClass::X86( + X86InlineAsmRegClass::x87_reg + | X86InlineAsmRegClass::mmx_reg + | X86InlineAsmRegClass::kreg0 + | X86InlineAsmRegClass::tmm_reg, + ) => { unreachable!("clobber-only") } - InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(), + InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None, + InlineAsmRegClass::Bpf(_) => None, + InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) + | InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) + | InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => match modifier { + Some('h') => Some('B'), + Some('l') => Some('A'), + _ => None, + }, + InlineAsmRegClass::Avr(_) => None, + InlineAsmRegClass::S390x(_) => None, + InlineAsmRegClass::Msp430(_) => None, InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("LLVM backend does not support SPIR-V") - }, - InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => unimplemented!(), - InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => unimplemented!(), + } InlineAsmRegClass::Err => unreachable!(), } } diff --git a/src/attributes.rs b/src/attributes.rs new file mode 100644 index 0000000000000..243a1a36dd09d --- /dev/null +++ b/src/attributes.rs @@ -0,0 +1,112 @@ +#[cfg(feature="master")] +use gccjit::FnAttribute; +use gccjit::Function; +use rustc_attr::InstructionSetAttr; +use rustc_codegen_ssa::target_features::tied_target_features; +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::ty; +use rustc_session::Session; +use rustc_span::symbol::sym; +use smallvec::{smallvec, SmallVec}; + +use crate::context::CodegenCx; + +// Given a map from target_features to whether they are enabled or disabled, +// ensure only valid combinations are allowed. +pub fn check_tied_features(sess: &Session, features: &FxHashMap<&str, bool>) -> Option<&'static [&'static str]> { + for tied in tied_target_features(sess) { + // Tied features must be set to the same value, or not set at all + let mut tied_iter = tied.iter(); + let enabled = features.get(tied_iter.next().unwrap()); + if tied_iter.any(|feature| enabled != features.get(feature)) { + return Some(tied); + } + } + None +} + +// TODO(antoyo): maybe move to a new module gcc_util. +// To find a list of GCC's names, check https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html +fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> { + let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch }; + match (arch, s) { + ("x86", "sse4.2") => smallvec!["sse4.2", "crc32"], + ("x86", "pclmulqdq") => smallvec!["pclmul"], + ("x86", "rdrand") => smallvec!["rdrnd"], + ("x86", "bmi1") => smallvec!["bmi"], + ("x86", "cmpxchg16b") => smallvec!["cx16"], + ("x86", "avx512vaes") => smallvec!["vaes"], + ("x86", "avx512gfni") => smallvec!["gfni"], + ("x86", "avx512vpclmulqdq") => smallvec!["vpclmulqdq"], + // NOTE: seems like GCC requires 'avx512bw' for 'avx512vbmi2'. + ("x86", "avx512vbmi2") => smallvec!["avx512vbmi2", "avx512bw"], + // NOTE: seems like GCC requires 'avx512bw' for 'avx512bitalg'. + ("x86", "avx512bitalg") => smallvec!["avx512bitalg", "avx512bw"], + ("aarch64", "rcpc2") => smallvec!["rcpc-immo"], + ("aarch64", "dpb") => smallvec!["ccpp"], + ("aarch64", "dpb2") => smallvec!["ccdp"], + ("aarch64", "frintts") => smallvec!["fptoint"], + ("aarch64", "fcma") => smallvec!["complxnum"], + ("aarch64", "pmuv3") => smallvec!["perfmon"], + ("aarch64", "paca") => smallvec!["pauth"], + ("aarch64", "pacg") => smallvec!["pauth"], + // Rust ties fp and neon together. In LLVM neon implicitly enables fp, + // but we manually enable neon when a feature only implicitly enables fp + ("aarch64", "f32mm") => smallvec!["f32mm", "neon"], + ("aarch64", "f64mm") => smallvec!["f64mm", "neon"], + ("aarch64", "fhm") => smallvec!["fp16fml", "neon"], + ("aarch64", "fp16") => smallvec!["fullfp16", "neon"], + ("aarch64", "jsconv") => smallvec!["jsconv", "neon"], + ("aarch64", "sve") => smallvec!["sve", "neon"], + ("aarch64", "sve2") => smallvec!["sve2", "neon"], + ("aarch64", "sve2-aes") => smallvec!["sve2-aes", "neon"], + ("aarch64", "sve2-sm4") => smallvec!["sve2-sm4", "neon"], + ("aarch64", "sve2-sha3") => smallvec!["sve2-sha3", "neon"], + ("aarch64", "sve2-bitperm") => smallvec!["sve2-bitperm", "neon"], + (_, s) => smallvec![s], + } +} + +/// Composite function which sets GCC attributes for function depending on its AST (`#[attribute]`) +/// attributes. +pub fn from_fn_attrs<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + #[cfg_attr(not(feature="master"), allow(unused_variables))] + func: Function<'gcc>, + instance: ty::Instance<'tcx>, +) { + let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id()); + + let function_features = + codegen_fn_attrs.target_features.iter().map(|features| features.as_str()).collect::>(); + + if let Some(features) = check_tied_features(cx.tcx.sess, &function_features.iter().map(|features| (*features, true)).collect()) { + let span = cx.tcx + .get_attr(instance.def_id(), sym::target_feature) + .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span); + let msg = format!("the target features {} must all be either enabled or disabled together", features.join(", ")); + let mut err = cx.tcx.sess.struct_span_err(span, &msg); + err.help("add the missing features in a `target_feature` attribute"); + err.emit(); + return; + } + + let mut function_features = function_features + .iter() + .flat_map(|feat| to_gcc_features(cx.tcx.sess, feat).into_iter()) + .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x { + InstructionSetAttr::ArmA32 => "-thumb-mode", // TODO(antoyo): support removing feature. + InstructionSetAttr::ArmT32 => "thumb-mode", + })) + .collect::>(); + + // TODO(antoyo): check if we really need global backend features. (Maybe they could be applied + // globally?) + let mut global_features = cx.tcx.global_backend_features(()).iter().map(|s| s.as_str()); + function_features.extend(&mut global_features); + let target_features = function_features.join(","); + if !target_features.is_empty() { + #[cfg(feature="master")] + func.add_attribute(FnAttribute::Target(&target_features)); + } +} diff --git a/src/back/write.rs b/src/back/write.rs index efcf18d31eb09..5f54ac4ebc69a 100644 --- a/src/back/write.rs +++ b/src/back/write.rs @@ -57,6 +57,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext, _diag_han if env::var("CG_GCCJIT_DUMP_TO_FILE").as_deref() == Ok("1") { let _ = fs::create_dir("/tmp/gccjit_dumps"); let path = &format!("/tmp/gccjit_dumps/{}.c", module.name); + context.set_debug_info(true); context.dump_to_file(path, true); } context.compile_to_file(OutputKind::ObjectFile, obj_out.to_str().expect("path to str")); diff --git a/src/base.rs b/src/base.rs index d464bd3d12a07..dcd560b3dcd95 100644 --- a/src/base.rs +++ b/src/base.rs @@ -8,6 +8,8 @@ use gccjit::{ }; use rustc_middle::dep_graph; use rustc_middle::ty::TyCtxt; +#[cfg(feature="master")] +use rustc_middle::mir::mono::Visibility; use rustc_middle::mir::mono::Linkage; use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; use rustc_codegen_ssa::base::maybe_create_entry_wrapper; @@ -20,6 +22,15 @@ use crate::GccContext; use crate::builder::Builder; use crate::context::CodegenCx; +#[cfg(feature="master")] +pub fn visibility_to_gcc(linkage: Visibility) -> gccjit::Visibility { + match linkage { + Visibility::Default => gccjit::Visibility::Default, + Visibility::Hidden => gccjit::Visibility::Hidden, + Visibility::Protected => gccjit::Visibility::Protected, + } +} + pub fn global_linkage_to_gcc(linkage: Linkage) -> GlobalKind { match linkage { Linkage::External => GlobalKind::Imported, @@ -76,16 +87,34 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_i // Instantiate monomorphizations without filling out definitions yet... //let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str()); let context = Context::default(); + + context.add_command_line_option("-fexceptions"); + context.add_driver_option("-fexceptions"); + // TODO(antoyo): only set on x86 platforms. context.add_command_line_option("-masm=intel"); // TODO(antoyo): only add the following cli argument if the feature is supported. context.add_command_line_option("-msse2"); context.add_command_line_option("-mavx2"); - context.add_command_line_option("-msha"); - context.add_command_line_option("-mpclmul"); // FIXME(antoyo): the following causes an illegal instruction on vmovdqu64 in std_example on my CPU. // Only add if the CPU supports it. - //context.add_command_line_option("-mavx512f"); + context.add_command_line_option("-msha"); + context.add_command_line_option("-mpclmul"); + context.add_command_line_option("-mfma"); + context.add_command_line_option("-mfma4"); + context.add_command_line_option("-m64"); + context.add_command_line_option("-mbmi"); + context.add_command_line_option("-mgfni"); + //context.add_command_line_option("-mavxvnni"); // The CI doesn't support this option. + context.add_command_line_option("-mf16c"); + context.add_command_line_option("-maes"); + context.add_command_line_option("-mxsavec"); + context.add_command_line_option("-mbmi2"); + context.add_command_line_option("-mrtm"); + context.add_command_line_option("-mvaes"); + context.add_command_line_option("-mvpclmulqdq"); + context.add_command_line_option("-mavx"); + for arg in &tcx.sess.opts.cg.llvm_args { context.add_command_line_option(arg); } @@ -95,12 +124,20 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_i context.add_command_line_option("-fno-semantic-interposition"); // NOTE: Rust relies on LLVM not doing TBAA (https://github.com/rust-lang/unsafe-code-guidelines/issues/292). context.add_command_line_option("-fno-strict-aliasing"); + // NOTE: Rust relies on LLVM doing wrapping on overflow. + context.add_command_line_option("-fwrapv"); if tcx.sess.opts.unstable_opts.function_sections.unwrap_or(tcx.sess.target.function_sections) { context.add_command_line_option("-ffunction-sections"); context.add_command_line_option("-fdata-sections"); } + if env::var("CG_GCCJIT_DUMP_RTL").as_deref() == Ok("1") { + context.add_command_line_option("-fdump-rtl-vregs"); + } + if env::var("CG_GCCJIT_DUMP_TREE_ALL").as_deref() == Ok("1") { + context.add_command_line_option("-fdump-tree-all"); + } if env::var("CG_GCCJIT_DUMP_CODE").as_deref() == Ok("1") { context.set_dump_code_on_compile(true); } @@ -115,7 +152,7 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_i context.set_keep_intermediates(true); } - // TODO(bjorn3): Remove once unwinding is properly implemented + // NOTE: The codegen generates unrechable blocks. context.set_allow_unreachable_blocks(true); { diff --git a/src/builder.rs b/src/builder.rs index e88c12716ecd3..a3c8142bea2db 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -217,7 +217,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let actual_ty = actual_val.get_type(); if expected_ty != actual_ty { - if !actual_ty.is_vector() && !expected_ty.is_vector() && actual_ty.is_integral() && expected_ty.is_integral() && actual_ty.get_size() != expected_ty.get_size() { + if !actual_ty.is_vector() && !expected_ty.is_vector() && (actual_ty.is_integral() && expected_ty.is_integral()) || (actual_ty.get_pointee().is_some() && expected_ty.get_pointee().is_some()) { self.context.new_cast(None, actual_val, expected_ty) } else if on_stack_param_indices.contains(&index) { @@ -226,6 +226,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { else { assert!(!((actual_ty.is_vector() && !expected_ty.is_vector()) || (!actual_ty.is_vector() && expected_ty.is_vector())), "{:?} ({}) -> {:?} ({}), index: {:?}[{}]", actual_ty, actual_ty.is_vector(), expected_ty, expected_ty.is_vector(), func_ptr, index); // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. + // TODO: remove bitcast now that vector types can be compared? self.bitcast(actual_val, expected_ty) } } @@ -279,21 +280,30 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } fn function_ptr_call(&mut self, func_ptr: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> { - let args = self.check_ptr_call("call", func_ptr, args); + let gcc_func = func_ptr.get_type().dyncast_function_ptr_type().expect("function ptr"); + let func_name = format!("{:?}", func_ptr); + let previous_arg_count = args.len(); + let orig_args = args; + let args = { + let function_address_names = self.function_address_names.borrow(); + let original_function_name = function_address_names.get(&func_ptr); + llvm::adjust_intrinsic_arguments(&self, gcc_func, args.into(), &func_name, original_function_name) + }; + let args_adjusted = args.len() != previous_arg_count; + let args = self.check_ptr_call("call", func_ptr, &*args); // gccjit requires to use the result of functions, even when it's not used. // That's why we assign the result to a local or call add_eval(). - let gcc_func = func_ptr.get_type().dyncast_function_ptr_type().expect("function ptr"); let return_type = gcc_func.get_return_type(); let void_type = self.context.new_type::<()>(); let current_func = self.block.get_function(); if return_type != void_type { unsafe { RETURN_VALUE_COUNT += 1 }; - let result = current_func.new_local(None, return_type, &format!("ptrReturnValue{}", unsafe { RETURN_VALUE_COUNT })); - let func_name = format!("{:?}", func_ptr); - let args = llvm::adjust_intrinsic_arguments(&self, gcc_func, args, &func_name); - self.block.add_assignment(None, result, self.cx.context.new_call_through_ptr(None, func_ptr, &args)); + let return_value = self.cx.context.new_call_through_ptr(None, func_ptr, &args); + let return_value = llvm::adjust_intrinsic_return_value(&self, return_value, &func_name, &args, args_adjusted, orig_args); + let result = current_func.new_local(None, return_value.get_type(), &format!("ptrReturnValue{}", unsafe { RETURN_VALUE_COUNT })); + self.block.add_assignment(None, result, return_value); result.to_rvalue() } else { @@ -366,10 +376,10 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> { } } -impl<'gcc, 'tcx> Deref for Builder<'_, 'gcc, 'tcx> { +impl<'a, 'gcc, 'tcx> Deref for Builder<'a, 'gcc, 'tcx> { type Target = CodegenCx<'gcc, 'tcx>; - fn deref(&self) -> &Self::Target { + fn deref<'b>(&'b self) -> &'a Self::Target { self.cx } } @@ -387,7 +397,7 @@ impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> { } impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { - fn build(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Self { + fn build(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Builder<'a, 'gcc, 'tcx> { Builder::with_cx(cx, block) } @@ -444,17 +454,36 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.block.end_with_switch(None, value, default_block, &gcc_cases); } - fn invoke( - &mut self, - typ: Type<'gcc>, - fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, - func: RValue<'gcc>, - args: &[RValue<'gcc>], - then: Block<'gcc>, - catch: Block<'gcc>, - _funclet: Option<&Funclet>, - ) -> RValue<'gcc> { - // TODO(bjorn3): Properly implement unwinding. + #[cfg(feature="master")] + fn invoke(&mut self, typ: Type<'gcc>, _fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> { + let try_block = self.current_func().new_block("try"); + + let current_block = self.block.clone(); + self.block = try_block; + let call = self.call(typ, None, func, args, None); // TODO(antoyo): use funclet here? + self.block = current_block; + + let return_value = self.current_func() + .new_local(None, call.get_type(), "invokeResult"); + + try_block.add_assignment(None, return_value, call); + + try_block.end_with_jump(None, then); + + if self.cleanup_blocks.borrow().contains(&catch) { + self.block.add_try_finally(None, try_block, catch); + } + else { + self.block.add_try_catch(None, try_block, catch); + } + + self.block.end_with_jump(None, then); + + return_value.to_rvalue() + } + + #[cfg(not(feature="master"))] + fn invoke(&mut self, typ: Type<'gcc>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> { let call_site = self.call(typ, None, func, args, None); let condition = self.context.new_rvalue_from_int(self.bool_type, 1); self.llbb().end_with_conditional(None, condition, then, catch); @@ -542,6 +571,31 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn frem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): add check in libgccjit since using the binary operator % causes the following error: + // during RTL pass: expand + // libgccjit.so: error: in expmed_mode_index, at expmed.h:240 + // 0x7f0101d58dc6 expmed_mode_index + // ../../../gcc/gcc/expmed.h:240 + // 0x7f0101d58e35 expmed_op_cost_ptr + // ../../../gcc/gcc/expmed.h:262 + // 0x7f0101d594a1 sdiv_cost_ptr + // ../../../gcc/gcc/expmed.h:531 + // 0x7f0101d594f3 sdiv_cost + // ../../../gcc/gcc/expmed.h:549 + // 0x7f0101d6af7e expand_divmod(int, tree_code, machine_mode, rtx_def*, rtx_def*, rtx_def*, int, optab_methods) + // ../../../gcc/gcc/expmed.cc:4356 + // 0x7f0101d94f9e expand_expr_divmod + // ../../../gcc/gcc/expr.cc:8929 + // 0x7f0101d97a26 expand_expr_real_2(separate_ops*, rtx_def*, machine_mode, expand_modifier) + // ../../../gcc/gcc/expr.cc:9566 + // 0x7f0101bef6ef expand_gimple_stmt_1 + // ../../../gcc/gcc/cfgexpand.cc:3967 + // 0x7f0101bef910 expand_gimple_stmt + // ../../../gcc/gcc/cfgexpand.cc:4028 + // 0x7f0101bf6ee7 expand_gimple_basic_block + // ../../../gcc/gcc/cfgexpand.cc:6069 + // 0x7f0101bf9194 execute + // ../../../gcc/gcc/cfgexpand.cc:6795 if a.get_type().is_compatible_with(self.cx.float_type) { let fmodf = self.context.get_builtin_function("fmodf"); // FIXME(antoyo): this seems to produce the wrong result. @@ -616,24 +670,29 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { a * b } - fn fadd_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> { - unimplemented!(); + fn fadd_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { + // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. + lhs + rhs } - fn fsub_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> { - unimplemented!(); + fn fsub_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { + // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. + lhs - rhs } - fn fmul_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> { - unimplemented!(); + fn fmul_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { + // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. + lhs * rhs } - fn fdiv_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> { - unimplemented!(); + fn fdiv_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { + // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. + lhs / rhs } - fn frem_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> { - unimplemented!(); + fn frem_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { + // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. + self.frem(lhs, rhs) } fn checked_binop(&mut self, oop: OverflowOp, typ: Ty<'_>, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value) { @@ -722,7 +781,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } else if place.layout.is_gcc_immediate() { let load = self.load( - place.layout.gcc_type(self, false), + place.layout.gcc_type(self), place.llval, place.align, ); @@ -733,7 +792,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi { let b_offset = a.size(self).align_to(b.align(self).abi); - let pair_type = place.layout.gcc_type(self, false); + let pair_type = place.layout.gcc_type(self); let mut load = |i, scalar: &abi::Scalar, align| { let llptr = self.struct_gep(pair_type, place.llval, i as u64); @@ -833,26 +892,31 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn gep(&mut self, _typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> { - let mut result = ptr; + let ptr_type = ptr.get_type(); + let mut pointee_type = ptr.get_type(); + // NOTE: we cannot use array indexing here like in inbounds_gep because array indexing is + // always considered in bounds in GCC (TODO(antoyo): to be verified). + // So, we have to cast to a number. + let mut result = self.context.new_bitcast(None, ptr, self.sizet_type); + // FIXME(antoyo): if there were more than 1 index, this code is probably wrong and would + // require dereferencing the pointer. for index in indices { - result = self.context.new_array_access(None, result, *index).get_address(None).to_rvalue(); + pointee_type = pointee_type.get_pointee().expect("pointee type"); + let pointee_size = self.context.new_rvalue_from_int(index.get_type(), pointee_type.get_size() as i32); + result = result + self.gcc_int_cast(*index * pointee_size, self.sizet_type); } - result + self.context.new_bitcast(None, result, ptr_type) } fn inbounds_gep(&mut self, _typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> { - // FIXME(antoyo): would be safer if doing the same thing (loop) as gep. - // TODO(antoyo): specify inbounds somehow. - match indices.len() { - 1 => { - self.context.new_array_access(None, ptr, indices[0]).get_address(None) - }, - 2 => { - let array = ptr.dereference(None); // TODO(antoyo): assert that first index is 0? - self.context.new_array_access(None, array, indices[1]).get_address(None) - }, - _ => unimplemented!(), + // NOTE: array indexing is always considered in bounds in GCC (TODO(antoyo): to be verified). + let mut indices = indices.into_iter(); + let index = indices.next().expect("first index in inbounds_gep"); + let mut result = self.context.new_array_access(None, ptr, *index); + for index in indices { + result = self.context.new_array_access(None, result, *index); } + result.get_address(None) } fn struct_gep(&mut self, value_type: Type<'gcc>, ptr: RValue<'gcc>, idx: u64) -> RValue<'gcc> { @@ -1034,8 +1098,19 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { unimplemented!(); } - fn extract_element(&mut self, _vec: RValue<'gcc>, _idx: RValue<'gcc>) -> RValue<'gcc> { - unimplemented!(); + #[cfg(feature="master")] + fn extract_element(&mut self, vec: RValue<'gcc>, idx: RValue<'gcc>) -> RValue<'gcc> { + self.context.new_vector_access(None, vec, idx).to_rvalue() + } + + #[cfg(not(feature="master"))] + fn extract_element(&mut self, vec: RValue<'gcc>, idx: RValue<'gcc>) -> RValue<'gcc> { + let vector_type = vec.get_type().unqualified().dyncast_vector().expect("Called extract_element on a non-vector type"); + let element_type = vector_type.get_element_type(); + let vec_num_units = vector_type.get_num_units(); + let array_type = self.context.new_array_type(None, element_type, vec_num_units as u64); + let array = self.context.new_bitcast(None, vec, array_type).to_rvalue(); + self.context.new_array_access(None, array, idx).to_rvalue() } fn vector_splat(&mut self, _num_elts: usize, _elt: RValue<'gcc>) -> RValue<'gcc> { @@ -1116,22 +1191,52 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn set_personality_fn(&mut self, _personality: RValue<'gcc>) { - // TODO(antoyo) + #[cfg(feature="master")] + { + let personality = self.rvalue_as_function(_personality); + self.current_func().set_personality_function(personality); + } + } + + #[cfg(feature="master")] + fn cleanup_landing_pad(&mut self, pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { + self.set_personality_fn(pers_fn); + + // NOTE: insert the current block in a variable so that a later call to invoke knows to + // generate a try/finally instead of a try/catch for this block. + self.cleanup_blocks.borrow_mut().insert(self.block); + + let eh_pointer_builtin = self.cx.context.get_target_builtin_function("__builtin_eh_pointer"); + let zero = self.cx.context.new_rvalue_zero(self.int_type); + let ptr = self.cx.context.new_call(None, eh_pointer_builtin, &[zero]); + + let value1_type = self.u8_type.make_pointer(); + let ptr = self.cx.context.new_cast(None, ptr, value1_type); + let value1 = ptr; + let value2 = zero; // TODO(antoyo): set the proper value here (the type of exception?). + + (value1, value2) } + #[cfg(not(feature="master"))] fn cleanup_landing_pad(&mut self, _pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { - ( - self.current_func().new_local(None, self.u8_type.make_pointer(), "landing_pad0") - .to_rvalue(), - self.current_func().new_local(None, self.i32_type, "landing_pad1").to_rvalue(), - ) - // TODO(antoyo): Properly implement unwinding. - // the above is just to make the compilation work as it seems - // rustc_codegen_ssa now calls the unwinding builder methods even on panic=abort. + let value1 = self.current_func().new_local(None, self.u8_type.make_pointer(), "landing_pad0") + .to_rvalue(); + let value2 = self.current_func().new_local(None, self.i32_type, "landing_pad1").to_rvalue(); + (value1, value2) + } + + #[cfg(feature="master")] + fn resume(&mut self, exn0: RValue<'gcc>, _exn1: RValue<'gcc>) { + let exn_type = exn0.get_type(); + let exn = self.context.new_cast(None, exn0, exn_type); + let unwind_resume = self.context.get_target_builtin_function("__builtin_unwind_resume"); + self.llbb().add_eval(None, self.context.new_call(None, unwind_resume, &[exn])); + self.unreachable(); } + #[cfg(not(feature="master"))] fn resume(&mut self, _exn0: RValue<'gcc>, _exn1: RValue<'gcc>) { - // TODO(bjorn3): Properly implement unwinding. self.unreachable(); } @@ -1160,6 +1265,15 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn atomic_cmpxchg(&mut self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> { let expected = self.current_func().new_local(None, cmp.get_type(), "expected"); self.llbb().add_assignment(None, expected, cmp); + // NOTE: gcc doesn't support a failure memory model that is stronger than the success + // memory model. + let order = + if failure_order as i32 > order as i32 { + failure_order + } + else { + order + }; let success = self.compare_exchange(dst, expected, src, order, failure_order, weak); let pair_type = self.cx.type_struct(&[src.get_type(), self.bool_type], false); @@ -1469,7 +1583,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { #[cfg(feature="master")] pub fn shuffle_vector(&mut self, v1: RValue<'gcc>, v2: RValue<'gcc>, mask: RValue<'gcc>) -> RValue<'gcc> { - let struct_type = mask.get_type().is_struct().expect("mask of struct type"); + let struct_type = mask.get_type().is_struct().expect("mask should be of struct type"); // TODO(antoyo): use a recursive unqualified() here. let vector_type = v1.get_type().unqualified().dyncast_vector().expect("vector type"); @@ -1501,22 +1615,17 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { vector_elements.push(self.context.new_rvalue_zero(mask_element_type)); } - let array_type = self.context.new_array_type(None, element_type, vec_num_units as i32); let result_type = self.context.new_vector_type(element_type, mask_num_units as u64); let (v1, v2) = if vec_num_units < mask_num_units { // NOTE: the mask needs to be the same length as the input vectors, so join the 2 // vectors and create a dummy second vector. - // TODO(antoyo): switch to using new_vector_access. - let array = self.context.new_bitcast(None, v1, array_type); let mut elements = vec![]; for i in 0..vec_num_units { - elements.push(self.context.new_array_access(None, array, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); + elements.push(self.context.new_vector_access(None, v1, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); } - // TODO(antoyo): switch to using new_vector_access. - let array = self.context.new_bitcast(None, v2, array_type); for i in 0..(mask_num_units - vec_num_units) { - elements.push(self.context.new_array_access(None, array, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); + elements.push(self.context.new_vector_access(None, v2, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); } let v1 = self.context.new_rvalue_from_vector(None, result_type, &elements); let zero = self.context.new_rvalue_zero(element_type); @@ -1536,10 +1645,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // NOTE: if padding was added, only select the number of elements of the masks to // remove that padding in the result. let mut elements = vec![]; - // TODO(antoyo): switch to using new_vector_access. - let array = self.context.new_bitcast(None, result, array_type); for i in 0..mask_num_units { - elements.push(self.context.new_array_access(None, array, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); + elements.push(self.context.new_vector_access(None, result, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue()); } self.context.new_rvalue_from_vector(None, result_type, &elements) } @@ -1558,18 +1665,20 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { where F: Fn(RValue<'gcc>, RValue<'gcc>, &'gcc Context<'gcc>) -> RValue<'gcc> { let vector_type = src.get_type().unqualified().dyncast_vector().expect("vector type"); + let element_type = vector_type.get_element_type(); + let mask_element_type = self.type_ix(element_type.get_size() as u64 * 8); let element_count = vector_type.get_num_units(); let mut vector_elements = vec![]; for i in 0..element_count { vector_elements.push(i); } - let mask_type = self.context.new_vector_type(self.int_type, element_count as u64); + let mask_type = self.context.new_vector_type(mask_element_type, element_count as u64); let mut shift = 1; let mut res = src; while shift < element_count { let vector_elements: Vec<_> = vector_elements.iter() - .map(|i| self.context.new_rvalue_from_int(self.int_type, ((i + shift) % element_count) as i32)) + .map(|i| self.context.new_rvalue_from_int(mask_element_type, ((i + shift) % element_count) as i32)) .collect(); let mask = self.context.new_rvalue_from_vector(None, mask_type, &vector_elements); let shifted = self.context.new_rvalue_vector_perm(None, res, res, mask); @@ -1581,7 +1690,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } #[cfg(not(feature="master"))] - pub fn vector_reduce(&mut self, src: RValue<'gcc>, op: F) -> RValue<'gcc> + pub fn vector_reduce(&mut self, _src: RValue<'gcc>, _op: F) -> RValue<'gcc> where F: Fn(RValue<'gcc>, RValue<'gcc>, &'gcc Context<'gcc>) -> RValue<'gcc> { unimplemented!(); @@ -1595,15 +1704,47 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { unimplemented!(); } + #[cfg(feature="master")] + pub fn vector_reduce_fadd(&mut self, acc: RValue<'gcc>, src: RValue<'gcc>) -> RValue<'gcc> { + let vector_type = src.get_type().unqualified().dyncast_vector().expect("vector type"); + let element_count = vector_type.get_num_units(); + (0..element_count).into_iter() + .map(|i| self.context + .new_vector_access(None, src, self.context.new_rvalue_from_int(self.int_type, i as _)) + .to_rvalue()) + .fold(acc, |x, i| x + i) + } + + #[cfg(not(feature="master"))] + pub fn vector_reduce_fadd(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + pub fn vector_reduce_fmul_fast(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> { unimplemented!(); } + #[cfg(feature="master")] + pub fn vector_reduce_fmul(&mut self, acc: RValue<'gcc>, src: RValue<'gcc>) -> RValue<'gcc> { + let vector_type = src.get_type().unqualified().dyncast_vector().expect("vector type"); + let element_count = vector_type.get_num_units(); + (0..element_count).into_iter() + .map(|i| self.context + .new_vector_access(None, src, self.context.new_rvalue_from_int(self.int_type, i as _)) + .to_rvalue()) + .fold(acc, |x, i| x * i) + } + + #[cfg(not(feature="master"))] + pub fn vector_reduce_fmul(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!() + } + // Inspired by Hacker's Delight min implementation. pub fn vector_reduce_min(&mut self, src: RValue<'gcc>) -> RValue<'gcc> { self.vector_reduce(src, |a, b, context| { let differences_or_zeros = difference_or_zero(a, b, context); - context.new_binary_op(None, BinaryOp::Minus, a.get_type(), a, differences_or_zeros) + context.new_binary_op(None, BinaryOp::Plus, b.get_type(), b, differences_or_zeros) }) } @@ -1611,38 +1752,148 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { pub fn vector_reduce_max(&mut self, src: RValue<'gcc>) -> RValue<'gcc> { self.vector_reduce(src, |a, b, context| { let differences_or_zeros = difference_or_zero(a, b, context); - context.new_binary_op(None, BinaryOp::Plus, b.get_type(), b, differences_or_zeros) + context.new_binary_op(None, BinaryOp::Minus, a.get_type(), a, differences_or_zeros) }) } + fn vector_extremum(&mut self, a: RValue<'gcc>, b: RValue<'gcc>, direction: ExtremumOperation) -> RValue<'gcc> { + let vector_type = a.get_type(); + + // mask out the NaNs in b and replace them with the corresponding lane in a, so when a and + // b get compared & spliced together, we get the numeric values instead of NaNs. + let b_nan_mask = self.context.new_comparison(None, ComparisonOp::NotEquals, b, b); + let mask_type = b_nan_mask.get_type(); + let b_nan_mask_inverted = self.context.new_unary_op(None, UnaryOp::BitwiseNegate, mask_type, b_nan_mask); + let a_cast = self.context.new_bitcast(None, a, mask_type); + let b_cast = self.context.new_bitcast(None, b, mask_type); + let res = (b_nan_mask & a_cast) | (b_nan_mask_inverted & b_cast); + let b = self.context.new_bitcast(None, res, vector_type); + + // now do the actual comparison + let comparison_op = match direction { + ExtremumOperation::Min => ComparisonOp::LessThan, + ExtremumOperation::Max => ComparisonOp::GreaterThan, + }; + let cmp = self.context.new_comparison(None, comparison_op, a, b); + let cmp_inverted = self.context.new_unary_op(None, UnaryOp::BitwiseNegate, cmp.get_type(), cmp); + let res = (cmp & a_cast) | (cmp_inverted & res); + self.context.new_bitcast(None, res, vector_type) + } + + pub fn vector_fmin(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + self.vector_extremum(a, b, ExtremumOperation::Min) + } + + #[cfg(feature="master")] + pub fn vector_reduce_fmin(&mut self, src: RValue<'gcc>) -> RValue<'gcc> { + let vector_type = src.get_type().unqualified().dyncast_vector().expect("vector type"); + let element_count = vector_type.get_num_units(); + let mut acc = self.context.new_vector_access(None, src, self.context.new_rvalue_zero(self.int_type)).to_rvalue(); + for i in 1..element_count { + let elem = self.context + .new_vector_access(None, src, self.context.new_rvalue_from_int(self.int_type, i as _)) + .to_rvalue(); + let cmp = self.context.new_comparison(None, ComparisonOp::LessThan, acc, elem); + acc = self.select(cmp, acc, elem); + } + acc + } + + #[cfg(not(feature="master"))] + pub fn vector_reduce_fmin(&mut self, _src: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + pub fn vector_fmax(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + self.vector_extremum(a, b, ExtremumOperation::Max) + } + + #[cfg(feature="master")] + pub fn vector_reduce_fmax(&mut self, src: RValue<'gcc>) -> RValue<'gcc> { + let vector_type = src.get_type().unqualified().dyncast_vector().expect("vector type"); + let element_count = vector_type.get_num_units(); + let mut acc = self.context.new_vector_access(None, src, self.context.new_rvalue_zero(self.int_type)).to_rvalue(); + for i in 1..element_count { + let elem = self.context + .new_vector_access(None, src, self.context.new_rvalue_from_int(self.int_type, i as _)) + .to_rvalue(); + let cmp = self.context.new_comparison(None, ComparisonOp::GreaterThan, acc, elem); + acc = self.select(cmp, acc, elem); + } + acc + } + + #[cfg(not(feature="master"))] + pub fn vector_reduce_fmax(&mut self, _src: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + pub fn vector_select(&mut self, cond: RValue<'gcc>, then_val: RValue<'gcc>, else_val: RValue<'gcc>) -> RValue<'gcc> { // cond is a vector of integers, not of bools. - let cond_type = cond.get_type(); - let vector_type = cond_type.unqualified().dyncast_vector().expect("vector type"); + let vector_type = cond.get_type().unqualified().dyncast_vector().expect("vector type"); let num_units = vector_type.get_num_units(); let element_type = vector_type.get_element_type(); + + #[cfg(feature="master")] + let (cond, element_type) = { + let then_val_vector_type = then_val.get_type().dyncast_vector().expect("vector type"); + let then_val_element_type = then_val_vector_type.get_element_type(); + let then_val_element_size = then_val_element_type.get_size(); + + // NOTE: the mask needs to be of the same size as the other arguments in order for the & + // operation to work. + if then_val_element_size != element_type.get_size() { + let new_element_type = self.type_ix(then_val_element_size as u64 * 8); + let new_vector_type = self.context.new_vector_type(new_element_type, num_units as u64); + let cond = self.context.convert_vector(None, cond, new_vector_type); + (cond, new_element_type) + } + else { + (cond, element_type) + } + }; + + let cond_type = cond.get_type(); + let zeros = vec![self.context.new_rvalue_zero(element_type); num_units]; let zeros = self.context.new_rvalue_from_vector(None, cond_type, &zeros); + let result_type = then_val.get_type(); + let masks = self.context.new_comparison(None, ComparisonOp::NotEquals, cond, zeros); + // NOTE: masks is a vector of integers, but the values can be vectors of floats, so use bitcast to make + // the & operation work. + let then_val = self.bitcast_if_needed(then_val, masks.get_type()); let then_vals = masks & then_val; - let ones = vec![self.context.new_rvalue_one(element_type); num_units]; - let ones = self.context.new_rvalue_from_vector(None, cond_type, &ones); - let inverted_masks = masks + ones; + let minus_ones = vec![self.context.new_rvalue_from_int(element_type, -1); num_units]; + let minus_ones = self.context.new_rvalue_from_vector(None, cond_type, &minus_ones); + let inverted_masks = masks ^ minus_ones; // NOTE: sometimes, the type of else_val can be different than the type of then_val in // libgccjit (vector of int vs vector of int32_t), but they should be the same for the AND // operation to work. + // TODO: remove bitcast now that vector types can be compared? let else_val = self.context.new_bitcast(None, else_val, then_val.get_type()); let else_vals = inverted_masks & else_val; - then_vals | else_vals + let res = then_vals | else_vals; + self.bitcast_if_needed(res, result_type) } } fn difference_or_zero<'gcc>(a: RValue<'gcc>, b: RValue<'gcc>, context: &'gcc Context<'gcc>) -> RValue<'gcc> { let difference = a - b; let masks = context.new_comparison(None, ComparisonOp::GreaterThanEquals, b, a); + // NOTE: masks is a vector of integers, but the values can be vectors of floats, so use bitcast to make + // the & operation work. + let a_type = a.get_type(); + let masks = + if masks.get_type() != a_type { + context.new_bitcast(None, masks, a_type) + } + else { + masks + }; difference & masks } diff --git a/src/callee.rs b/src/callee.rs index 9e3a22ee05d7c..ba1e86562089e 100644 --- a/src/callee.rs +++ b/src/callee.rs @@ -1,9 +1,10 @@ -use gccjit::{FunctionType, RValue}; -use rustc_codegen_ssa::traits::BaseTypeMethods; +#[cfg(feature="master")] +use gccjit::{FnAttribute, Visibility}; +use gccjit::{FunctionType, Function}; use rustc_middle::ty::{self, Instance, TypeVisitableExt}; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; -use crate::abi::FnAbiGccExt; +use crate::attributes; use crate::context::CodegenCx; /// Codegens a reference to a fn/method item, monomorphizing and @@ -13,22 +14,26 @@ use crate::context::CodegenCx; /// /// - `cx`: the crate context /// - `instance`: the instance to be instantiated -pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) -> RValue<'gcc> { +pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) -> Function<'gcc> { let tcx = cx.tcx(); assert!(!instance.substs.needs_infer()); assert!(!instance.substs.has_escaping_bound_vars()); + let sym = tcx.symbol_name(instance).name; + if let Some(&func) = cx.function_instances.borrow().get(&instance) { return func; } - let sym = tcx.symbol_name(instance).name; - let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty()); let func = - if let Some(func) = cx.get_declared_value(&sym) { + if let Some(_func) = cx.get_declared_value(&sym) { + // FIXME(antoyo): we never reach this because get_declared_value only returns global variables + // and here we try to get a function. + unreachable!(); + /* // Create a fn pointer with the new signature. let ptrty = fn_abi.ptr_to_gcc_type(cx); @@ -61,13 +66,105 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) } else { func - } + }*/ } else { cx.linkage.set(FunctionType::Extern); let func = cx.declare_fn(&sym, &fn_abi); + attributes::from_fn_attrs(cx, func, instance); + + let instance_def_id = instance.def_id(); + // TODO(antoyo): set linkage and attributes. + + // Apply an appropriate linkage/visibility value to our item that we + // just declared. + // + // This is sort of subtle. Inside our codegen unit we started off + // compilation by predefining all our own `MonoItem` instances. That + // is, everything we're codegenning ourselves is already defined. That + // means that anything we're actually codegenning in this codegen unit + // will have hit the above branch in `get_declared_value`. As a result, + // we're guaranteed here that we're declaring a symbol that won't get + // defined, or in other words we're referencing a value from another + // codegen unit or even another crate. + // + // So because this is a foreign value we blanket apply an external + // linkage directive because it's coming from a different object file. + // The visibility here is where it gets tricky. This symbol could be + // referencing some foreign crate or foreign library (an `extern` + // block) in which case we want to leave the default visibility. We may + // also, though, have multiple codegen units. It could be a + // monomorphization, in which case its expected visibility depends on + // whether we are sharing generics or not. The important thing here is + // that the visibility we apply to the declaration is the same one that + // has been applied to the definition (wherever that definition may be). + let is_generic = instance.substs.non_erasable_generics().next().is_some(); + + if is_generic { + // This is a monomorphization. Its expected visibility depends + // on whether we are in share-generics mode. + + if cx.tcx.sess.opts.share_generics() { + // We are in share_generics mode. + + if let Some(instance_def_id) = instance_def_id.as_local() { + // This is a definition from the current crate. If the + // definition is unreachable for downstream crates or + // the current crate does not re-export generics, the + // definition of the instance will have been declared + // as `hidden`. + if cx.tcx.is_unreachable_local_definition(instance_def_id) + || !cx.tcx.local_crate_exports_generics() + { + #[cfg(feature="master")] + func.add_attribute(FnAttribute::Visibility(Visibility::Hidden)); + } + } else { + // This is a monomorphization of a generic function + // defined in an upstream crate. + if instance.upstream_monomorphization(tcx).is_some() { + // This is instantiated in another crate. It cannot + // be `hidden`. + } else { + // This is a local instantiation of an upstream definition. + // If the current crate does not re-export it + // (because it is a C library or an executable), it + // will have been declared `hidden`. + if !cx.tcx.local_crate_exports_generics() { + #[cfg(feature="master")] + func.add_attribute(FnAttribute::Visibility(Visibility::Hidden)); + } + } + } + } else { + // When not sharing generics, all instances are in the same + // crate and have hidden visibility + #[cfg(feature="master")] + func.add_attribute(FnAttribute::Visibility(Visibility::Hidden)); + } + } else { + // This is a non-generic function + if cx.tcx.is_codegened_item(instance_def_id) { + // This is a function that is instantiated in the local crate + + if instance_def_id.is_local() { + // This is function that is defined in the local crate. + // If it is not reachable, it is hidden. + if !cx.tcx.is_reachable_non_generic(instance_def_id) { + #[cfg(feature="master")] + func.add_attribute(FnAttribute::Visibility(Visibility::Hidden)); + } + } else { + // This is a function from an upstream crate that has + // been instantiated here. These are always hidden. + #[cfg(feature="master")] + func.add_attribute(FnAttribute::Visibility(Visibility::Hidden)); + } + } + } + func }; diff --git a/src/common.rs b/src/common.rs index c939da9cec3c2..76fc7bd222e1e 100644 --- a/src/common.rs +++ b/src/common.rs @@ -36,7 +36,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> RValue<'gcc> { let context = &cx.context; let byte_type = context.new_type::(); - let typ = context.new_array_type(None, byte_type, bytes.len() as i32); + let typ = context.new_array_type(None, byte_type, bytes.len() as u64); let elements: Vec<_> = bytes.iter() .map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32)) @@ -115,8 +115,8 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.const_uint(self.usize_type, i) } - fn const_u8(&self, _i: u8) -> RValue<'gcc> { - unimplemented!(); + fn const_u8(&self, i: u8) -> RValue<'gcc> { + self.const_uint(self.type_u8(), i as u64) } fn const_real(&self, typ: Type<'gcc>, val: f64) -> RValue<'gcc> { @@ -133,7 +133,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { .1; let len = s.len(); let cs = self.const_ptrcast(str_global.get_address(None), - self.type_ptr_to(self.layout_of(self.tcx.types.str_).gcc_type(self, true)), + self.type_ptr_to(self.layout_of(self.tcx.types.str_).gcc_type(self)), ); (cs, self.const_usize(len as u64)) } @@ -174,8 +174,18 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } let value = self.const_uint_big(self.type_ix(bitsize), data); - // TODO(bjorn3): assert size is correct - self.const_bitcast(value, ty) + let bytesize = layout.size(self).bytes(); + if bitsize > 1 && ty.is_integral() && bytesize as u32 == ty.get_size() { + // NOTE: since the intrinsic _xabort is called with a bitcast, which + // is non-const, but expects a constant, do a normal cast instead of a bitcast. + // FIXME(antoyo): fix bitcast to work in constant contexts. + // TODO(antoyo): perhaps only use bitcast for pointers? + self.context.new_cast(None, value, ty) + } + else { + // TODO(bjorn3): assert size is correct + self.const_bitcast(value, ty) + } } Scalar::Ptr(ptr, _size) => { let (alloc_id, offset) = ptr.into_parts(); @@ -227,11 +237,11 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn from_const_alloc(&self, layout: TyAndLayout<'tcx>, alloc: ConstAllocation<'tcx>, offset: Size) -> PlaceRef<'tcx, RValue<'gcc>> { assert_eq!(alloc.inner().align, layout.align.abi); - let ty = self.type_ptr_to(layout.gcc_type(self, true)); + let ty = self.type_ptr_to(layout.gcc_type(self)); let value = if layout.size == Size::ZERO { let value = self.const_usize(alloc.inner().align.bytes()); - self.context.new_cast(None, value, ty) + self.const_bitcast(value, ty) } else { let init = const_alloc_to_gcc(self, alloc); diff --git a/src/consts.rs b/src/consts.rs index dc41cb761b59c..792ab8f890d8f 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -1,8 +1,8 @@ -use gccjit::{GlobalKind, LValue, RValue, ToRValue, Type}; +#[cfg(feature = "master")] +use gccjit::FnAttribute; +use gccjit::{Function, GlobalKind, LValue, RValue, ToRValue, Type}; use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, DerivedTypeMethods, StaticMethods}; -use rustc_hir as hir; -use rustc_hir::Node; -use rustc_middle::{bug, span_bug}; +use rustc_middle::span_bug; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::{self, Instance, Ty}; @@ -13,6 +13,7 @@ use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRan use crate::base; use crate::context::CodegenCx; +use crate::errors::InvalidMinimumAlignment; use crate::type_of::LayoutGccExt; impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { @@ -30,6 +31,21 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } } +fn set_global_alignment<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, gv: LValue<'gcc>, mut align: Align) { + // The target may require greater alignment for globals than the type does. + // Note: GCC and Clang also allow `__attribute__((aligned))` on variables, + // which can force it to be smaller. Rust doesn't support this yet. + if let Some(min) = cx.sess().target.min_global_align { + match Align::from_bits(min) { + Ok(min) => align = align.max(min), + Err(err) => { + cx.sess().emit_err(InvalidMinimumAlignment { err }); + } + } + } + gv.set_alignment(align.bytes() as i32); +} + impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> { fn static_addr_of(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> { // TODO(antoyo): implement a proper rvalue comparison in libgccjit instead of doing the @@ -79,9 +95,9 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> { let instance = Instance::mono(self.tcx, def_id); let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); - let gcc_type = self.layout_of(ty).gcc_type(self, true); + let gcc_type = self.layout_of(ty).gcc_type(self); - // TODO(antoyo): set alignment. + set_global_alignment(self, global, self.align_of(ty)); let value = self.bitcast_if_needed(value, gcc_type); global.global_set_initializer_rvalue(value); @@ -158,12 +174,19 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> { // TODO(antoyo) } - fn add_compiler_used_global(&self, _global: RValue<'gcc>) { - // TODO(antoyo) + fn add_compiler_used_global(&self, global: RValue<'gcc>) { + // NOTE: seems like GCC does not make the distinction between compiler.used and used. + self.add_used_global(global); } } impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + #[cfg_attr(not(feature="master"), allow(unused_variables))] + pub fn add_used_function(&self, function: Function<'gcc>) { + #[cfg(feature = "master")] + function.add_attribute(FnAttribute::Used); + } + pub fn static_addr_of_mut(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> { let global = match kind { @@ -208,82 +231,59 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let sym = self.tcx.symbol_name(instance).name; let global = - if let Some(def_id) = def_id.as_local() { - let id = self.tcx.hir().local_def_id_to_hir_id(def_id); - let llty = self.layout_of(ty).gcc_type(self, true); - // FIXME: refactor this to work without accessing the HIR - let global = match self.tcx.hir().get(id) { - Node::Item(&hir::Item { span, kind: hir::ItemKind::Static(..), .. }) => { - if let Some(global) = self.get_declared_value(&sym) { - if self.val_ty(global) != self.type_ptr_to(llty) { - span_bug!(span, "Conflicting types for static"); - } - } - - let is_tls = fn_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); - let global = self.declare_global( - &sym, - llty, - GlobalKind::Exported, - is_tls, - fn_attrs.link_section, - ); - - if !self.tcx.is_reachable_non_generic(def_id) { - // TODO(antoyo): set visibility. - } - - global - } - - Node::ForeignItem(&hir::ForeignItem { - span: _, - kind: hir::ForeignItemKind::Static(..), - .. - }) => { - let fn_attrs = self.tcx.codegen_fn_attrs(def_id); - check_and_apply_linkage(&self, &fn_attrs, ty, sym) - } - - item => bug!("get_static: expected static, found {:?}", item), - }; + if def_id.is_local() && !self.tcx.is_foreign_item(def_id) { + let llty = self.layout_of(ty).gcc_type(self); + if let Some(global) = self.get_declared_value(sym) { + if self.val_ty(global) != self.type_ptr_to(llty) { + span_bug!(self.tcx.def_span(def_id), "Conflicting types for static"); + } + } - global + let is_tls = fn_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); + let global = self.declare_global( + &sym, + llty, + GlobalKind::Exported, + is_tls, + fn_attrs.link_section, + ); + + if !self.tcx.is_reachable_non_generic(def_id) { + // TODO(antoyo): set visibility. } - else { - // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? - //debug!("get_static: sym={} item_attr={:?}", sym, self.tcx.item_attrs(def_id)); - - let attrs = self.tcx.codegen_fn_attrs(def_id); - let global = check_and_apply_linkage(&self, &attrs, ty, sym); - - let needs_dll_storage_attr = false; // TODO(antoyo) - - // If this assertion triggers, there's something wrong with commandline - // argument validation. - debug_assert!( - !(self.tcx.sess.opts.cg.linker_plugin_lto.enabled() - && self.tcx.sess.target.options.is_like_msvc - && self.tcx.sess.opts.cg.prefer_dynamic) - ); - - if needs_dll_storage_attr { - // This item is external but not foreign, i.e., it originates from an external Rust - // crate. Since we don't know whether this crate will be linked dynamically or - // statically in the final application, we always mark such symbols as 'dllimport'. - // If final linkage happens to be static, we rely on compiler-emitted __imp_ stubs - // to make things work. - // - // However, in some scenarios we defer emission of statics to downstream - // crates, so there are cases where a static with an upstream DefId - // is actually present in the current crate. We can find out via the - // is_codegened_item query. - if !self.tcx.is_codegened_item(def_id) { - unimplemented!(); - } + + global + } else { + check_and_apply_linkage(&self, &fn_attrs, ty, sym) + }; + + if !def_id.is_local() { + let needs_dll_storage_attr = false; // TODO(antoyo) + + // If this assertion triggers, there's something wrong with commandline + // argument validation. + debug_assert!( + !(self.tcx.sess.opts.cg.linker_plugin_lto.enabled() + && self.tcx.sess.target.options.is_like_msvc + && self.tcx.sess.opts.cg.prefer_dynamic) + ); + + if needs_dll_storage_attr { + // This item is external but not foreign, i.e., it originates from an external Rust + // crate. Since we don't know whether this crate will be linked dynamically or + // statically in the final application, we always mark such symbols as 'dllimport'. + // If final linkage happens to be static, we rely on compiler-emitted __imp_ stubs + // to make things work. + // + // However, in some scenarios we defer emission of statics to downstream + // crates, so there are cases where a static with an upstream DefId + // is actually present in the current crate. We can find out via the + // is_codegened_item query. + if !self.tcx.is_codegened_item(def_id) { + unimplemented!(); } - global - }; + } + } // TODO(antoyo): set dll storage class. @@ -357,7 +357,7 @@ pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &CodegenFnAttrs, ty: Ty<'tcx>, sym: &str) -> LValue<'gcc> { let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); - let llty = cx.layout_of(ty).gcc_type(cx, true); + let gcc_type = cx.layout_of(ty).gcc_type(cx); if let Some(linkage) = attrs.import_linkage { // Declare a symbol `foo` with the desired linkage. let global1 = cx.declare_global_with_linkage(&sym, cx.type_i8(), base::global_linkage_to_gcc(linkage)); @@ -370,9 +370,10 @@ fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &Codeg // zero. let mut real_name = "_rust_extern_with_linkage_".to_string(); real_name.push_str(&sym); - let global2 = cx.define_global(&real_name, llty, is_tls, attrs.link_section); + let global2 = cx.define_global(&real_name, gcc_type, is_tls, attrs.link_section); // TODO(antoyo): set linkage. - global2.global_set_initializer_rvalue(global1.get_address(None)); + let value = cx.const_ptrcast(global1.get_address(None), gcc_type); + global2.global_set_initializer_rvalue(value); // TODO(antoyo): use global_set_initializer() when it will work. global2 } @@ -386,6 +387,6 @@ fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &Codeg // don't do this then linker errors can be generated where the linker // complains that one object files has a thread local version of the // symbol and another one doesn't. - cx.declare_global(&sym, llty, GlobalKind::Imported, is_tls, attrs.link_section) + cx.declare_global(&sym, gcc_type, GlobalKind::Imported, is_tls, attrs.link_section) } } diff --git a/src/context.rs b/src/context.rs index 457006319afb8..661681bdb50f2 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,9 +1,10 @@ use std::cell::{Cell, RefCell}; -use gccjit::{Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, RValue, Struct, Type}; +use gccjit::{Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, RValue, Type}; use rustc_codegen_ssa::base::wants_msvc_seh; use rustc_codegen_ssa::traits::{ BackendTypes, + BaseTypeMethods, MiscMethods, }; use rustc_data_structures::base_n; @@ -11,7 +12,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::span_bug; use rustc_middle::mir::mono::CodegenUnit; use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}; -use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout, LayoutOfHelpers}; +use rustc_middle::ty::layout::{FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout, LayoutOfHelpers}; use rustc_session::Session; use rustc_span::{Span, source_map::respan}; use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx}; @@ -33,6 +34,7 @@ pub struct CodegenCx<'gcc, 'tcx> { // TODO(bjorn3): Can this field be removed? pub current_func: RefCell>>, pub normal_function_addresses: RefCell>>, + pub function_address_names: RefCell, String>>, pub functions: RefCell>>, pub intrinsics: RefCell>>, @@ -78,12 +80,10 @@ pub struct CodegenCx<'gcc, 'tcx> { pub struct_types: RefCell>, Type<'gcc>>>, - pub types_with_fields_to_set: RefCell, (Struct<'gcc>, TyAndLayout<'tcx>)>>, - /// Cache instances of monomorphic and polymorphic items pub instances: RefCell, LValue<'gcc>>>, /// Cache function instances of monomorphic and polymorphic items - pub function_instances: RefCell, RValue<'gcc>>>, + pub function_instances: RefCell, Function<'gcc>>>, /// Cache generated vtables pub vtables: RefCell, Option>), RValue<'gcc>>>, @@ -110,6 +110,7 @@ pub struct CodegenCx<'gcc, 'tcx> { local_gen_sym_counter: Cell, eh_personality: Cell>>, + pub rust_try_fn: Cell, Function<'gcc>)>>, pub pointee_infos: RefCell, Size), Option>>, @@ -119,6 +120,8 @@ pub struct CodegenCx<'gcc, 'tcx> { /// they can be dereferenced later. /// FIXME(antoyo): fix the rustc API to avoid having this hack. pub structs_as_pointer: RefCell>>, + + pub cleanup_blocks: RefCell>>, } impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { @@ -194,6 +197,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { context, current_func: RefCell::new(None), normal_function_addresses: Default::default(), + function_address_names: Default::default(), functions: RefCell::new(functions), intrinsics: RefCell::new(FxHashMap::default()), @@ -243,11 +247,12 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { types: Default::default(), tcx, struct_types: Default::default(), - types_with_fields_to_set: Default::default(), local_gen_sym_counter: Cell::new(0), eh_personality: Cell::new(None), + rust_try_fn: Cell::new(None), pointee_infos: Default::default(), structs_as_pointer: Default::default(), + cleanup_blocks: Default::default(), } } @@ -327,8 +332,9 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn get_fn(&self, instance: Instance<'tcx>) -> RValue<'gcc> { let func = get_fn(self, instance); - *self.current_func.borrow_mut() = Some(self.rvalue_as_function(func)); - func + *self.current_func.borrow_mut() = Some(func); + // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API. + unsafe { std::mem::transmute(func) } } fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> { @@ -339,8 +345,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.intrinsics.borrow()[func_name].clone() } else { - let func = get_fn(self, instance); - self.rvalue_as_function(func) + get_fn(self, instance) }; let ptr = func.get_address(None); @@ -348,6 +353,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { // FIXME(antoyo): the rustc API seems to call get_fn_addr() when not needed (e.g. for FFI). self.normal_function_addresses.borrow_mut().insert(ptr); + self.function_address_names.borrow_mut().insert(ptr, func_name.to_string()); ptr } @@ -377,31 +383,40 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { return llpersonality; } let tcx = self.tcx; - let llfn = match tcx.lang_items().eh_personality() { - Some(def_id) if !wants_msvc_seh(self.sess()) => self.get_fn_addr( - ty::Instance::resolve( - tcx, - ty::ParamEnv::reveal_all(), - def_id, - ty::List::empty(), - ) - .unwrap().unwrap(), - ), - _ => { - let _name = if wants_msvc_seh(self.sess()) { - "__CxxFrameHandler3" - } else { - "rust_eh_personality" - }; - //let func = self.declare_func(name, self.type_i32(), &[], true); - // FIXME(antoyo): this hack should not be needed. That will probably be removed when - // unwinding support is added. - self.context.new_rvalue_from_int(self.int_type, 0) - } - }; + let func = + match tcx.lang_items().eh_personality() { + Some(def_id) if !wants_msvc_seh(self.sess()) => { + let instance = + ty::Instance::resolve( + tcx, + ty::ParamEnv::reveal_all(), + def_id, + ty::List::empty(), + ) + .unwrap().unwrap(); + + let symbol_name = tcx.symbol_name(instance).name; + let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); + self.linkage.set(FunctionType::Extern); + let func = self.declare_fn(symbol_name, &fn_abi); + let func: RValue<'gcc> = unsafe { std::mem::transmute(func) }; + func + }, + _ => { + let name = + if wants_msvc_seh(self.sess()) { + "__CxxFrameHandler3" + } + else { + "rust_eh_personality" + }; + let func = self.declare_func(name, self.type_i32(), &[], true); + unsafe { std::mem::transmute(func) } + } + }; // TODO(antoyo): apply target cpu attributes. - self.eh_personality.set(Some(llfn)); - llfn + self.eh_personality.set(Some(func)); + func } fn sess(&self) -> &Session { diff --git a/src/declare.rs b/src/declare.rs index eae77508c973a..4748e7e4be2a3 100644 --- a/src/declare.rs +++ b/src/declare.rs @@ -38,12 +38,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { global } - /*pub fn declare_func(&self, name: &str, return_type: Type<'gcc>, params: &[Type<'gcc>], variadic: bool) -> RValue<'gcc> { - self.linkage.set(FunctionType::Exported); - let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic); - // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API. - unsafe { std::mem::transmute(func) } - }*/ + pub fn declare_func(&self, name: &str, return_type: Type<'gcc>, params: &[Type<'gcc>], variadic: bool) -> Function<'gcc> { + self.linkage.set(FunctionType::Extern); + declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic) + } pub fn declare_global(&self, name: &str, ty: Type<'gcc>, global_kind: GlobalKind, is_tls: bool, link_section: Option) -> LValue<'gcc> { let global = self.context.new_global(None, global_kind, ty, name); @@ -79,12 +77,11 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { unsafe { std::mem::transmute(func) } } - pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> RValue<'gcc> { + pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Function<'gcc> { let (return_type, params, variadic, on_stack_param_indices) = fn_abi.gcc_type(self); let func = declare_raw_fn(self, name, () /*fn_abi.llvm_cconv()*/, return_type, ¶ms, variadic); self.on_stack_function_params.borrow_mut().insert(func, on_stack_param_indices); - // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API. - unsafe { std::mem::transmute(func) } + func } pub fn define_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option) -> LValue<'gcc> { diff --git a/src/errors.rs b/src/errors.rs index d0ba7e2479111..5ea39606c086d 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -221,3 +221,9 @@ pub(crate) struct UnwindingInlineAsm { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(codegen_gcc_invalid_minimum_alignment)] +pub(crate) struct InvalidMinimumAlignment { + pub err: String, +} diff --git a/src/int.rs b/src/int.rs index 0c5dab0046684..0cf1204791d33 100644 --- a/src/int.rs +++ b/src/int.rs @@ -389,18 +389,22 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { }; self.context.new_comparison(None, op, cmp, self.context.new_rvalue_from_int(self.int_type, limit)) } + else if a_type.get_pointee().is_some() && b_type.get_pointee().is_some() { + // NOTE: gcc cannot compare pointers to different objects, but rustc does that, so cast them to usize. + lhs = self.context.new_bitcast(None, lhs, self.usize_type); + rhs = self.context.new_bitcast(None, rhs, self.usize_type); + self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs) + } else { - let left_type = lhs.get_type(); - let right_type = rhs.get_type(); - if left_type != right_type { + if a_type != b_type { // NOTE: because libgccjit cannot compare function pointers. - if left_type.dyncast_function_ptr_type().is_some() && right_type.dyncast_function_ptr_type().is_some() { + if a_type.dyncast_function_ptr_type().is_some() && b_type.dyncast_function_ptr_type().is_some() { lhs = self.context.new_cast(None, lhs, self.usize_type.make_pointer()); rhs = self.context.new_cast(None, rhs, self.usize_type.make_pointer()); } // NOTE: hack because we try to cast a vector type to the same vector type. - else if format!("{:?}", left_type) != format!("{:?}", right_type) { - rhs = self.context.new_cast(None, rhs, left_type); + else if format!("{:?}", a_type) != format!("{:?}", b_type) { + rhs = self.context.new_cast(None, rhs, a_type); } } self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs) diff --git a/src/intrinsic/archs.rs b/src/intrinsic/archs.rs index fb6c38fa07265..8a4559355ea67 100644 --- a/src/intrinsic/archs.rs +++ b/src/intrinsic/archs.rs @@ -34,6 +34,7 @@ match name { "llvm.aarch64.dmb" => "__builtin_arm_dmb", "llvm.aarch64.dsb" => "__builtin_arm_dsb", "llvm.aarch64.isb" => "__builtin_arm_isb", + "llvm.aarch64.prefetch" => "__builtin_arm_prefetch", "llvm.aarch64.sve.aesd" => "__builtin_sve_svaesd_u8", "llvm.aarch64.sve.aese" => "__builtin_sve_svaese_u8", "llvm.aarch64.sve.aesimc" => "__builtin_sve_svaesimc_u8", @@ -58,13 +59,22 @@ match name { "llvm.amdgcn.cubema" => "__builtin_amdgcn_cubema", "llvm.amdgcn.cubesc" => "__builtin_amdgcn_cubesc", "llvm.amdgcn.cubetc" => "__builtin_amdgcn_cubetc", + "llvm.amdgcn.cvt.f32.bf8" => "__builtin_amdgcn_cvt_f32_bf8", + "llvm.amdgcn.cvt.f32.fp8" => "__builtin_amdgcn_cvt_f32_fp8", + "llvm.amdgcn.cvt.pk.bf8.f32" => "__builtin_amdgcn_cvt_pk_bf8_f32", + "llvm.amdgcn.cvt.pk.f32.bf8" => "__builtin_amdgcn_cvt_pk_f32_bf8", + "llvm.amdgcn.cvt.pk.f32.fp8" => "__builtin_amdgcn_cvt_pk_f32_fp8", + "llvm.amdgcn.cvt.pk.fp8.f32" => "__builtin_amdgcn_cvt_pk_fp8_f32", "llvm.amdgcn.cvt.pk.i16" => "__builtin_amdgcn_cvt_pk_i16", "llvm.amdgcn.cvt.pk.u16" => "__builtin_amdgcn_cvt_pk_u16", "llvm.amdgcn.cvt.pk.u8.f32" => "__builtin_amdgcn_cvt_pk_u8_f32", "llvm.amdgcn.cvt.pknorm.i16" => "__builtin_amdgcn_cvt_pknorm_i16", "llvm.amdgcn.cvt.pknorm.u16" => "__builtin_amdgcn_cvt_pknorm_u16", "llvm.amdgcn.cvt.pkrtz" => "__builtin_amdgcn_cvt_pkrtz", + "llvm.amdgcn.cvt.sr.bf8.f32" => "__builtin_amdgcn_cvt_sr_bf8_f32", + "llvm.amdgcn.cvt.sr.fp8.f32" => "__builtin_amdgcn_cvt_sr_fp8_f32", "llvm.amdgcn.dispatch.id" => "__builtin_amdgcn_dispatch_id", + "llvm.amdgcn.ds.add.gs.reg.rtn" => "__builtin_amdgcn_ds_add_gs_reg_rtn", "llvm.amdgcn.ds.bpermute" => "__builtin_amdgcn_ds_bpermute", "llvm.amdgcn.ds.fadd.v2bf16" => "__builtin_amdgcn_ds_atomic_fadd_v2bf16", "llvm.amdgcn.ds.gws.barrier" => "__builtin_amdgcn_ds_gws_barrier", @@ -74,12 +84,16 @@ match name { "llvm.amdgcn.ds.gws.sema.release.all" => "__builtin_amdgcn_ds_gws_sema_release_all", "llvm.amdgcn.ds.gws.sema.v" => "__builtin_amdgcn_ds_gws_sema_v", "llvm.amdgcn.ds.permute" => "__builtin_amdgcn_ds_permute", + "llvm.amdgcn.ds.sub.gs.reg.rtn" => "__builtin_amdgcn_ds_sub_gs_reg_rtn", "llvm.amdgcn.ds.swizzle" => "__builtin_amdgcn_ds_swizzle", "llvm.amdgcn.endpgm" => "__builtin_amdgcn_endpgm", "llvm.amdgcn.fdot2" => "__builtin_amdgcn_fdot2", - "llvm.amdgcn.fmed3" => "__builtin_amdgcn_fmed3", + "llvm.amdgcn.fdot2.bf16.bf16" => "__builtin_amdgcn_fdot2_bf16_bf16", + "llvm.amdgcn.fdot2.f16.f16" => "__builtin_amdgcn_fdot2_f16_f16", + "llvm.amdgcn.fdot2.f32.bf16" => "__builtin_amdgcn_fdot2_f32_bf16", "llvm.amdgcn.fmul.legacy" => "__builtin_amdgcn_fmul_legacy", "llvm.amdgcn.groupstaticsize" => "__builtin_amdgcn_groupstaticsize", + "llvm.amdgcn.iglp.opt" => "__builtin_amdgcn_iglp_opt", "llvm.amdgcn.implicit.buffer.ptr" => "__builtin_amdgcn_implicit_buffer_ptr", "llvm.amdgcn.implicitarg.ptr" => "__builtin_amdgcn_implicitarg_ptr", "llvm.amdgcn.interp.mov" => "__builtin_amdgcn_interp_mov", @@ -93,11 +107,51 @@ match name { "llvm.amdgcn.lerp" => "__builtin_amdgcn_lerp", "llvm.amdgcn.mbcnt.hi" => "__builtin_amdgcn_mbcnt_hi", "llvm.amdgcn.mbcnt.lo" => "__builtin_amdgcn_mbcnt_lo", + "llvm.amdgcn.mfma.f32.16x16x16bf16.1k" => "__builtin_amdgcn_mfma_f32_16x16x16bf16_1k", + "llvm.amdgcn.mfma.f32.16x16x16f16" => "__builtin_amdgcn_mfma_f32_16x16x16f16", + "llvm.amdgcn.mfma.f32.16x16x1f32" => "__builtin_amdgcn_mfma_f32_16x16x1f32", + "llvm.amdgcn.mfma.f32.16x16x2bf16" => "__builtin_amdgcn_mfma_f32_16x16x2bf16", + "llvm.amdgcn.mfma.f32.16x16x32.bf8.bf8" => "__builtin_amdgcn_mfma_f32_16x16x32_bf8_bf8", + "llvm.amdgcn.mfma.f32.16x16x32.bf8.fp8" => "__builtin_amdgcn_mfma_f32_16x16x32_bf8_fp8", + "llvm.amdgcn.mfma.f32.16x16x32.fp8.bf8" => "__builtin_amdgcn_mfma_f32_16x16x32_fp8_bf8", + "llvm.amdgcn.mfma.f32.16x16x32.fp8.fp8" => "__builtin_amdgcn_mfma_f32_16x16x32_fp8_fp8", + "llvm.amdgcn.mfma.f32.16x16x4bf16.1k" => "__builtin_amdgcn_mfma_f32_16x16x4bf16_1k", + "llvm.amdgcn.mfma.f32.16x16x4f16" => "__builtin_amdgcn_mfma_f32_16x16x4f16", + "llvm.amdgcn.mfma.f32.16x16x4f32" => "__builtin_amdgcn_mfma_f32_16x16x4f32", + "llvm.amdgcn.mfma.f32.16x16x8.xf32" => "__builtin_amdgcn_mfma_f32_16x16x8_xf32", + "llvm.amdgcn.mfma.f32.16x16x8bf16" => "__builtin_amdgcn_mfma_f32_16x16x8bf16", + "llvm.amdgcn.mfma.f32.32x32x16.bf8.bf8" => "__builtin_amdgcn_mfma_f32_32x32x16_bf8_bf8", + "llvm.amdgcn.mfma.f32.32x32x16.bf8.fp8" => "__builtin_amdgcn_mfma_f32_32x32x16_bf8_fp8", + "llvm.amdgcn.mfma.f32.32x32x16.fp8.bf8" => "__builtin_amdgcn_mfma_f32_32x32x16_fp8_bf8", + "llvm.amdgcn.mfma.f32.32x32x16.fp8.fp8" => "__builtin_amdgcn_mfma_f32_32x32x16_fp8_fp8", + "llvm.amdgcn.mfma.f32.32x32x1f32" => "__builtin_amdgcn_mfma_f32_32x32x1f32", + "llvm.amdgcn.mfma.f32.32x32x2bf16" => "__builtin_amdgcn_mfma_f32_32x32x2bf16", + "llvm.amdgcn.mfma.f32.32x32x2f32" => "__builtin_amdgcn_mfma_f32_32x32x2f32", + "llvm.amdgcn.mfma.f32.32x32x4.xf32" => "__builtin_amdgcn_mfma_f32_32x32x4_xf32", + "llvm.amdgcn.mfma.f32.32x32x4bf16" => "__builtin_amdgcn_mfma_f32_32x32x4bf16", + "llvm.amdgcn.mfma.f32.32x32x4bf16.1k" => "__builtin_amdgcn_mfma_f32_32x32x4bf16_1k", + "llvm.amdgcn.mfma.f32.32x32x4f16" => "__builtin_amdgcn_mfma_f32_32x32x4f16", + "llvm.amdgcn.mfma.f32.32x32x8bf16.1k" => "__builtin_amdgcn_mfma_f32_32x32x8bf16_1k", + "llvm.amdgcn.mfma.f32.32x32x8f16" => "__builtin_amdgcn_mfma_f32_32x32x8f16", + "llvm.amdgcn.mfma.f32.4x4x1f32" => "__builtin_amdgcn_mfma_f32_4x4x1f32", + "llvm.amdgcn.mfma.f32.4x4x2bf16" => "__builtin_amdgcn_mfma_f32_4x4x2bf16", + "llvm.amdgcn.mfma.f32.4x4x4bf16.1k" => "__builtin_amdgcn_mfma_f32_4x4x4bf16_1k", + "llvm.amdgcn.mfma.f32.4x4x4f16" => "__builtin_amdgcn_mfma_f32_4x4x4f16", + "llvm.amdgcn.mfma.f64.16x16x4f64" => "__builtin_amdgcn_mfma_f64_16x16x4f64", + "llvm.amdgcn.mfma.f64.4x4x4f64" => "__builtin_amdgcn_mfma_f64_4x4x4f64", + "llvm.amdgcn.mfma.i32.16x16x16i8" => "__builtin_amdgcn_mfma_i32_16x16x16i8", + "llvm.amdgcn.mfma.i32.16x16x32.i8" => "__builtin_amdgcn_mfma_i32_16x16x32_i8", + "llvm.amdgcn.mfma.i32.16x16x4i8" => "__builtin_amdgcn_mfma_i32_16x16x4i8", + "llvm.amdgcn.mfma.i32.32x32x16.i8" => "__builtin_amdgcn_mfma_i32_32x32x16_i8", + "llvm.amdgcn.mfma.i32.32x32x4i8" => "__builtin_amdgcn_mfma_i32_32x32x4i8", + "llvm.amdgcn.mfma.i32.32x32x8i8" => "__builtin_amdgcn_mfma_i32_32x32x8i8", + "llvm.amdgcn.mfma.i32.4x4x4i8" => "__builtin_amdgcn_mfma_i32_4x4x4i8", "llvm.amdgcn.mqsad.pk.u16.u8" => "__builtin_amdgcn_mqsad_pk_u16_u8", "llvm.amdgcn.mqsad.u32.u8" => "__builtin_amdgcn_mqsad_u32_u8", "llvm.amdgcn.msad.u8" => "__builtin_amdgcn_msad_u8", "llvm.amdgcn.perm" => "__builtin_amdgcn_perm", "llvm.amdgcn.permlane16" => "__builtin_amdgcn_permlane16", + "llvm.amdgcn.permlane64" => "__builtin_amdgcn_permlane64", "llvm.amdgcn.permlanex16" => "__builtin_amdgcn_permlanex16", "llvm.amdgcn.qsad.pk.u16.u8" => "__builtin_amdgcn_qsad_pk_u16_u8", "llvm.amdgcn.queue.ptr" => "__builtin_amdgcn_queue_ptr", @@ -122,19 +176,40 @@ match name { "llvm.amdgcn.s.setprio" => "__builtin_amdgcn_s_setprio", "llvm.amdgcn.s.setreg" => "__builtin_amdgcn_s_setreg", "llvm.amdgcn.s.sleep" => "__builtin_amdgcn_s_sleep", + "llvm.amdgcn.s.wait.event.export.ready" => "__builtin_amdgcn_s_wait_event_export_ready", "llvm.amdgcn.s.waitcnt" => "__builtin_amdgcn_s_waitcnt", "llvm.amdgcn.sad.hi.u8" => "__builtin_amdgcn_sad_hi_u8", "llvm.amdgcn.sad.u16" => "__builtin_amdgcn_sad_u16", "llvm.amdgcn.sad.u8" => "__builtin_amdgcn_sad_u8", "llvm.amdgcn.sched.barrier" => "__builtin_amdgcn_sched_barrier", + "llvm.amdgcn.sched.group.barrier" => "__builtin_amdgcn_sched_group_barrier", "llvm.amdgcn.sdot2" => "__builtin_amdgcn_sdot2", "llvm.amdgcn.sdot4" => "__builtin_amdgcn_sdot4", "llvm.amdgcn.sdot8" => "__builtin_amdgcn_sdot8", + "llvm.amdgcn.smfmac.f32.16x16x32.bf16" => "__builtin_amdgcn_smfmac_f32_16x16x32_bf16", + "llvm.amdgcn.smfmac.f32.16x16x32.f16" => "__builtin_amdgcn_smfmac_f32_16x16x32_f16", + "llvm.amdgcn.smfmac.f32.16x16x64.bf8.bf8" => "__builtin_amdgcn_smfmac_f32_16x16x64_bf8_bf8", + "llvm.amdgcn.smfmac.f32.16x16x64.bf8.fp8" => "__builtin_amdgcn_smfmac_f32_16x16x64_bf8_fp8", + "llvm.amdgcn.smfmac.f32.16x16x64.fp8.bf8" => "__builtin_amdgcn_smfmac_f32_16x16x64_fp8_bf8", + "llvm.amdgcn.smfmac.f32.16x16x64.fp8.fp8" => "__builtin_amdgcn_smfmac_f32_16x16x64_fp8_fp8", + "llvm.amdgcn.smfmac.f32.32x32x16.bf16" => "__builtin_amdgcn_smfmac_f32_32x32x16_bf16", + "llvm.amdgcn.smfmac.f32.32x32x16.f16" => "__builtin_amdgcn_smfmac_f32_32x32x16_f16", + "llvm.amdgcn.smfmac.f32.32x32x32.bf8.bf8" => "__builtin_amdgcn_smfmac_f32_32x32x32_bf8_bf8", + "llvm.amdgcn.smfmac.f32.32x32x32.bf8.fp8" => "__builtin_amdgcn_smfmac_f32_32x32x32_bf8_fp8", + "llvm.amdgcn.smfmac.f32.32x32x32.fp8.bf8" => "__builtin_amdgcn_smfmac_f32_32x32x32_fp8_bf8", + "llvm.amdgcn.smfmac.f32.32x32x32.fp8.fp8" => "__builtin_amdgcn_smfmac_f32_32x32x32_fp8_fp8", + "llvm.amdgcn.smfmac.i32.16x16x64.i8" => "__builtin_amdgcn_smfmac_i32_16x16x64_i8", + "llvm.amdgcn.smfmac.i32.32x32x32.i8" => "__builtin_amdgcn_smfmac_i32_32x32x32_i8", + "llvm.amdgcn.sudot4" => "__builtin_amdgcn_sudot4", + "llvm.amdgcn.sudot8" => "__builtin_amdgcn_sudot8", "llvm.amdgcn.udot2" => "__builtin_amdgcn_udot2", "llvm.amdgcn.udot4" => "__builtin_amdgcn_udot4", "llvm.amdgcn.udot8" => "__builtin_amdgcn_udot8", "llvm.amdgcn.wave.barrier" => "__builtin_amdgcn_wave_barrier", "llvm.amdgcn.wavefrontsize" => "__builtin_amdgcn_wavefrontsize", + "llvm.amdgcn.workgroup.id.x" => "__builtin_amdgcn_workgroup_id_x", + "llvm.amdgcn.workgroup.id.y" => "__builtin_amdgcn_workgroup_id_y", + "llvm.amdgcn.workgroup.id.z" => "__builtin_amdgcn_workgroup_id_z", "llvm.amdgcn.writelane" => "__builtin_amdgcn_writelane", // arm "llvm.arm.cdp" => "__builtin_arm_cdp", @@ -249,6 +324,8 @@ match name { "llvm.bpf.pseudo" => "__builtin_bpf_pseudo", // cuda "llvm.cuda.syncthreads" => "__syncthreads", + // dx + "llvm.dx.create.handle" => "__builtin_hlsl_create_handle", // hexagon "llvm.hexagon.A2.abs" => "__builtin_HEXAGON_A2_abs", "llvm.hexagon.A2.absp" => "__builtin_HEXAGON_A2_absp", @@ -459,6 +536,11 @@ match name { "llvm.hexagon.A4.vrminuw" => "__builtin_HEXAGON_A4_vrminuw", "llvm.hexagon.A4.vrminw" => "__builtin_HEXAGON_A4_vrminw", "llvm.hexagon.A5.vaddhubs" => "__builtin_HEXAGON_A5_vaddhubs", + "llvm.hexagon.A6.vcmpbeq.notany" => "__builtin_HEXAGON_A6_vcmpbeq_notany", + "llvm.hexagon.A7.clip" => "__builtin_HEXAGON_A7_clip", + "llvm.hexagon.A7.croundd.ri" => "__builtin_HEXAGON_A7_croundd_ri", + "llvm.hexagon.A7.croundd.rr" => "__builtin_HEXAGON_A7_croundd_rr", + "llvm.hexagon.A7.vclip" => "__builtin_HEXAGON_A7_vclip", "llvm.hexagon.C2.all8" => "__builtin_HEXAGON_C2_all8", "llvm.hexagon.C2.and" => "__builtin_HEXAGON_C2_and", "llvm.hexagon.C2.andn" => "__builtin_HEXAGON_C2_andn", @@ -557,6 +639,10 @@ match name { "llvm.hexagon.F2.dfmax" => "__builtin_HEXAGON_F2_dfmax", "llvm.hexagon.F2.dfmin" => "__builtin_HEXAGON_F2_dfmin", "llvm.hexagon.F2.dfmpy" => "__builtin_HEXAGON_F2_dfmpy", + "llvm.hexagon.F2.dfmpyfix" => "__builtin_HEXAGON_F2_dfmpyfix", + "llvm.hexagon.F2.dfmpyhh" => "__builtin_HEXAGON_F2_dfmpyhh", + "llvm.hexagon.F2.dfmpylh" => "__builtin_HEXAGON_F2_dfmpylh", + "llvm.hexagon.F2.dfmpyll" => "__builtin_HEXAGON_F2_dfmpyll", "llvm.hexagon.F2.dfsub" => "__builtin_HEXAGON_F2_dfsub", "llvm.hexagon.F2.sfadd" => "__builtin_HEXAGON_F2_sfadd", "llvm.hexagon.F2.sfclass" => "__builtin_HEXAGON_F2_sfclass", @@ -578,6 +664,8 @@ match name { "llvm.hexagon.F2.sfmin" => "__builtin_HEXAGON_F2_sfmin", "llvm.hexagon.F2.sfmpy" => "__builtin_HEXAGON_F2_sfmpy", "llvm.hexagon.F2.sfsub" => "__builtin_HEXAGON_F2_sfsub", + "llvm.hexagon.L2.loadw.locked" => "__builtin_HEXAGON_L2_loadw_locked", + "llvm.hexagon.L4.loadd.locked" => "__builtin__HEXAGON_L4_loadd_locked", "llvm.hexagon.M2.acci" => "__builtin_HEXAGON_M2_acci", "llvm.hexagon.M2.accii" => "__builtin_HEXAGON_M2_accii", "llvm.hexagon.M2.cmaci.s0" => "__builtin_HEXAGON_M2_cmaci_s0", @@ -646,6 +734,7 @@ match name { "llvm.hexagon.M2.mmpyul.rs1" => "__builtin_HEXAGON_M2_mmpyul_rs1", "llvm.hexagon.M2.mmpyul.s0" => "__builtin_HEXAGON_M2_mmpyul_s0", "llvm.hexagon.M2.mmpyul.s1" => "__builtin_HEXAGON_M2_mmpyul_s1", + "llvm.hexagon.M2.mnaci" => "__builtin_HEXAGON_M2_mnaci", "llvm.hexagon.M2.mpy.acc.hh.s0" => "__builtin_HEXAGON_M2_mpy_acc_hh_s0", "llvm.hexagon.M2.mpy.acc.hh.s1" => "__builtin_HEXAGON_M2_mpy_acc_hh_s1", "llvm.hexagon.M2.mpy.acc.hl.s0" => "__builtin_HEXAGON_M2_mpy_acc_hl_s0", @@ -894,6 +983,24 @@ match name { "llvm.hexagon.M5.vrmpybuu" => "__builtin_HEXAGON_M5_vrmpybuu", "llvm.hexagon.M6.vabsdiffb" => "__builtin_HEXAGON_M6_vabsdiffb", "llvm.hexagon.M6.vabsdiffub" => "__builtin_HEXAGON_M6_vabsdiffub", + "llvm.hexagon.M7.dcmpyiw" => "__builtin_HEXAGON_M7_dcmpyiw", + "llvm.hexagon.M7.dcmpyiw.acc" => "__builtin_HEXAGON_M7_dcmpyiw_acc", + "llvm.hexagon.M7.dcmpyiwc" => "__builtin_HEXAGON_M7_dcmpyiwc", + "llvm.hexagon.M7.dcmpyiwc.acc" => "__builtin_HEXAGON_M7_dcmpyiwc_acc", + "llvm.hexagon.M7.dcmpyrw" => "__builtin_HEXAGON_M7_dcmpyrw", + "llvm.hexagon.M7.dcmpyrw.acc" => "__builtin_HEXAGON_M7_dcmpyrw_acc", + "llvm.hexagon.M7.dcmpyrwc" => "__builtin_HEXAGON_M7_dcmpyrwc", + "llvm.hexagon.M7.dcmpyrwc.acc" => "__builtin_HEXAGON_M7_dcmpyrwc_acc", + "llvm.hexagon.M7.vdmpy" => "__builtin_HEXAGON_M7_vdmpy", + "llvm.hexagon.M7.vdmpy.acc" => "__builtin_HEXAGON_M7_vdmpy_acc", + "llvm.hexagon.M7.wcmpyiw" => "__builtin_HEXAGON_M7_wcmpyiw", + "llvm.hexagon.M7.wcmpyiw.rnd" => "__builtin_HEXAGON_M7_wcmpyiw_rnd", + "llvm.hexagon.M7.wcmpyiwc" => "__builtin_HEXAGON_M7_wcmpyiwc", + "llvm.hexagon.M7.wcmpyiwc.rnd" => "__builtin_HEXAGON_M7_wcmpyiwc_rnd", + "llvm.hexagon.M7.wcmpyrw" => "__builtin_HEXAGON_M7_wcmpyrw", + "llvm.hexagon.M7.wcmpyrw.rnd" => "__builtin_HEXAGON_M7_wcmpyrw_rnd", + "llvm.hexagon.M7.wcmpyrwc" => "__builtin_HEXAGON_M7_wcmpyrwc", + "llvm.hexagon.M7.wcmpyrwc.rnd" => "__builtin_HEXAGON_M7_wcmpyrwc_rnd", "llvm.hexagon.S2.addasl.rrri" => "__builtin_HEXAGON_S2_addasl_rrri", "llvm.hexagon.S2.asl.i.p" => "__builtin_HEXAGON_S2_asl_i_p", "llvm.hexagon.S2.asl.i.p.acc" => "__builtin_HEXAGON_S2_asl_i_p_acc", @@ -1023,6 +1130,7 @@ match name { "llvm.hexagon.S2.lsr.r.r.or" => "__builtin_HEXAGON_S2_lsr_r_r_or", "llvm.hexagon.S2.lsr.r.vh" => "__builtin_HEXAGON_S2_lsr_r_vh", "llvm.hexagon.S2.lsr.r.vw" => "__builtin_HEXAGON_S2_lsr_r_vw", + "llvm.hexagon.S2.mask" => "__builtin_HEXAGON_S2_mask", "llvm.hexagon.S2.packhl" => "__builtin_HEXAGON_S2_packhl", "llvm.hexagon.S2.parityp" => "__builtin_HEXAGON_S2_parityp", "llvm.hexagon.S2.setbit.i" => "__builtin_HEXAGON_S2_setbit_i", @@ -1031,6 +1139,12 @@ match name { "llvm.hexagon.S2.shuffeh" => "__builtin_HEXAGON_S2_shuffeh", "llvm.hexagon.S2.shuffob" => "__builtin_HEXAGON_S2_shuffob", "llvm.hexagon.S2.shuffoh" => "__builtin_HEXAGON_S2_shuffoh", + "llvm.hexagon.S2.storerb.pbr" => "__builtin_brev_stb", + "llvm.hexagon.S2.storerd.pbr" => "__builtin_brev_std", + "llvm.hexagon.S2.storerf.pbr" => "__builtin_brev_sthhi", + "llvm.hexagon.S2.storerh.pbr" => "__builtin_brev_sth", + "llvm.hexagon.S2.storeri.pbr" => "__builtin_brev_stw", + "llvm.hexagon.S2.storew.locked" => "__builtin_HEXAGON_S2_storew_locked", "llvm.hexagon.S2.svsathb" => "__builtin_HEXAGON_S2_svsathb", "llvm.hexagon.S2.svsathub" => "__builtin_HEXAGON_S2_svsathub", "llvm.hexagon.S2.tableidxb.goodsyntax" => "__builtin_HEXAGON_S2_tableidxb_goodsyntax", @@ -1089,6 +1203,7 @@ match name { "llvm.hexagon.S4.ori.asl.ri" => "__builtin_HEXAGON_S4_ori_asl_ri", "llvm.hexagon.S4.ori.lsr.ri" => "__builtin_HEXAGON_S4_ori_lsr_ri", "llvm.hexagon.S4.parity" => "__builtin_HEXAGON_S4_parity", + "llvm.hexagon.S4.stored.locked" => "__builtin_HEXAGON_S4_stored_locked", "llvm.hexagon.S4.subaddi" => "__builtin_HEXAGON_S4_subaddi", "llvm.hexagon.S4.subi.asl.ri" => "__builtin_HEXAGON_S4_subi_asl_ri", "llvm.hexagon.S4.subi.lsr.ri" => "__builtin_HEXAGON_S4_subi_lsr_ri", @@ -1126,8 +1241,56 @@ match name { "llvm.hexagon.V6.hi.128B" => "__builtin_HEXAGON_V6_hi_128B", "llvm.hexagon.V6.lo" => "__builtin_HEXAGON_V6_lo", "llvm.hexagon.V6.lo.128B" => "__builtin_HEXAGON_V6_lo_128B", + "llvm.hexagon.V6.lvsplatb" => "__builtin_HEXAGON_V6_lvsplatb", + "llvm.hexagon.V6.lvsplatb.128B" => "__builtin_HEXAGON_V6_lvsplatb_128B", + "llvm.hexagon.V6.lvsplath" => "__builtin_HEXAGON_V6_lvsplath", + "llvm.hexagon.V6.lvsplath.128B" => "__builtin_HEXAGON_V6_lvsplath_128B", "llvm.hexagon.V6.lvsplatw" => "__builtin_HEXAGON_V6_lvsplatw", "llvm.hexagon.V6.lvsplatw.128B" => "__builtin_HEXAGON_V6_lvsplatw_128B", + "llvm.hexagon.V6.pred.and" => "__builtin_HEXAGON_V6_pred_and", + "llvm.hexagon.V6.pred.and.128B" => "__builtin_HEXAGON_V6_pred_and_128B", + "llvm.hexagon.V6.pred.and.n" => "__builtin_HEXAGON_V6_pred_and_n", + "llvm.hexagon.V6.pred.and.n.128B" => "__builtin_HEXAGON_V6_pred_and_n_128B", + "llvm.hexagon.V6.pred.not" => "__builtin_HEXAGON_V6_pred_not", + "llvm.hexagon.V6.pred.not.128B" => "__builtin_HEXAGON_V6_pred_not_128B", + "llvm.hexagon.V6.pred.or" => "__builtin_HEXAGON_V6_pred_or", + "llvm.hexagon.V6.pred.or.128B" => "__builtin_HEXAGON_V6_pred_or_128B", + "llvm.hexagon.V6.pred.or.n" => "__builtin_HEXAGON_V6_pred_or_n", + "llvm.hexagon.V6.pred.or.n.128B" => "__builtin_HEXAGON_V6_pred_or_n_128B", + "llvm.hexagon.V6.pred.scalar2" => "__builtin_HEXAGON_V6_pred_scalar2", + "llvm.hexagon.V6.pred.scalar2.128B" => "__builtin_HEXAGON_V6_pred_scalar2_128B", + "llvm.hexagon.V6.pred.scalar2v2" => "__builtin_HEXAGON_V6_pred_scalar2v2", + "llvm.hexagon.V6.pred.scalar2v2.128B" => "__builtin_HEXAGON_V6_pred_scalar2v2_128B", + "llvm.hexagon.V6.pred.xor" => "__builtin_HEXAGON_V6_pred_xor", + "llvm.hexagon.V6.pred.xor.128B" => "__builtin_HEXAGON_V6_pred_xor_128B", + "llvm.hexagon.V6.shuffeqh" => "__builtin_HEXAGON_V6_shuffeqh", + "llvm.hexagon.V6.shuffeqh.128B" => "__builtin_HEXAGON_V6_shuffeqh_128B", + "llvm.hexagon.V6.shuffeqw" => "__builtin_HEXAGON_V6_shuffeqw", + "llvm.hexagon.V6.shuffeqw.128B" => "__builtin_HEXAGON_V6_shuffeqw_128B", + "llvm.hexagon.V6.v6mpyhubs10" => "__builtin_HEXAGON_V6_v6mpyhubs10", + "llvm.hexagon.V6.v6mpyhubs10.128B" => "__builtin_HEXAGON_V6_v6mpyhubs10_128B", + "llvm.hexagon.V6.v6mpyhubs10.vxx" => "__builtin_HEXAGON_V6_v6mpyhubs10_vxx", + "llvm.hexagon.V6.v6mpyhubs10.vxx.128B" => "__builtin_HEXAGON_V6_v6mpyhubs10_vxx_128B", + "llvm.hexagon.V6.v6mpyvubs10" => "__builtin_HEXAGON_V6_v6mpyvubs10", + "llvm.hexagon.V6.v6mpyvubs10.128B" => "__builtin_HEXAGON_V6_v6mpyvubs10_128B", + "llvm.hexagon.V6.v6mpyvubs10.vxx" => "__builtin_HEXAGON_V6_v6mpyvubs10_vxx", + "llvm.hexagon.V6.v6mpyvubs10.vxx.128B" => "__builtin_HEXAGON_V6_v6mpyvubs10_vxx_128B", + "llvm.hexagon.V6.vS32b.nqpred.ai" => "__builtin_HEXAGON_V6_vS32b_nqpred_ai", + "llvm.hexagon.V6.vS32b.nqpred.ai.128B" => "__builtin_HEXAGON_V6_vS32b_nqpred_ai_128B", + "llvm.hexagon.V6.vS32b.nt.nqpred.ai" => "__builtin_HEXAGON_V6_vS32b_nt_nqpred_ai", + "llvm.hexagon.V6.vS32b.nt.nqpred.ai.128B" => "__builtin_HEXAGON_V6_vS32b_nt_nqpred_ai_128B", + "llvm.hexagon.V6.vS32b.nt.qpred.ai" => "__builtin_HEXAGON_V6_vS32b_nt_qpred_ai", + "llvm.hexagon.V6.vS32b.nt.qpred.ai.128B" => "__builtin_HEXAGON_V6_vS32b_nt_qpred_ai_128B", + "llvm.hexagon.V6.vS32b.qpred.ai" => "__builtin_HEXAGON_V6_vS32b_qpred_ai", + "llvm.hexagon.V6.vS32b.qpred.ai.128B" => "__builtin_HEXAGON_V6_vS32b_qpred_ai_128B", + "llvm.hexagon.V6.vabs.hf" => "__builtin_HEXAGON_V6_vabs_hf", + "llvm.hexagon.V6.vabs.hf.128B" => "__builtin_HEXAGON_V6_vabs_hf_128B", + "llvm.hexagon.V6.vabs.sf" => "__builtin_HEXAGON_V6_vabs_sf", + "llvm.hexagon.V6.vabs.sf.128B" => "__builtin_HEXAGON_V6_vabs_sf_128B", + "llvm.hexagon.V6.vabsb" => "__builtin_HEXAGON_V6_vabsb", + "llvm.hexagon.V6.vabsb.128B" => "__builtin_HEXAGON_V6_vabsb_128B", + "llvm.hexagon.V6.vabsb.sat" => "__builtin_HEXAGON_V6_vabsb_sat", + "llvm.hexagon.V6.vabsb.sat.128B" => "__builtin_HEXAGON_V6_vabsb_sat_128B", "llvm.hexagon.V6.vabsdiffh" => "__builtin_HEXAGON_V6_vabsdiffh", "llvm.hexagon.V6.vabsdiffh.128B" => "__builtin_HEXAGON_V6_vabsdiffh_128B", "llvm.hexagon.V6.vabsdiffub" => "__builtin_HEXAGON_V6_vabsdiffub", @@ -1144,36 +1307,90 @@ match name { "llvm.hexagon.V6.vabsw.128B" => "__builtin_HEXAGON_V6_vabsw_128B", "llvm.hexagon.V6.vabsw.sat" => "__builtin_HEXAGON_V6_vabsw_sat", "llvm.hexagon.V6.vabsw.sat.128B" => "__builtin_HEXAGON_V6_vabsw_sat_128B", + "llvm.hexagon.V6.vadd.hf" => "__builtin_HEXAGON_V6_vadd_hf", + "llvm.hexagon.V6.vadd.hf.128B" => "__builtin_HEXAGON_V6_vadd_hf_128B", + "llvm.hexagon.V6.vadd.hf.hf" => "__builtin_HEXAGON_V6_vadd_hf_hf", + "llvm.hexagon.V6.vadd.hf.hf.128B" => "__builtin_HEXAGON_V6_vadd_hf_hf_128B", + "llvm.hexagon.V6.vadd.qf16" => "__builtin_HEXAGON_V6_vadd_qf16", + "llvm.hexagon.V6.vadd.qf16.128B" => "__builtin_HEXAGON_V6_vadd_qf16_128B", + "llvm.hexagon.V6.vadd.qf16.mix" => "__builtin_HEXAGON_V6_vadd_qf16_mix", + "llvm.hexagon.V6.vadd.qf16.mix.128B" => "__builtin_HEXAGON_V6_vadd_qf16_mix_128B", + "llvm.hexagon.V6.vadd.qf32" => "__builtin_HEXAGON_V6_vadd_qf32", + "llvm.hexagon.V6.vadd.qf32.128B" => "__builtin_HEXAGON_V6_vadd_qf32_128B", + "llvm.hexagon.V6.vadd.qf32.mix" => "__builtin_HEXAGON_V6_vadd_qf32_mix", + "llvm.hexagon.V6.vadd.qf32.mix.128B" => "__builtin_HEXAGON_V6_vadd_qf32_mix_128B", + "llvm.hexagon.V6.vadd.sf" => "__builtin_HEXAGON_V6_vadd_sf", + "llvm.hexagon.V6.vadd.sf.128B" => "__builtin_HEXAGON_V6_vadd_sf_128B", + "llvm.hexagon.V6.vadd.sf.bf" => "__builtin_HEXAGON_V6_vadd_sf_bf", + "llvm.hexagon.V6.vadd.sf.bf.128B" => "__builtin_HEXAGON_V6_vadd_sf_bf_128B", + "llvm.hexagon.V6.vadd.sf.hf" => "__builtin_HEXAGON_V6_vadd_sf_hf", + "llvm.hexagon.V6.vadd.sf.hf.128B" => "__builtin_HEXAGON_V6_vadd_sf_hf_128B", + "llvm.hexagon.V6.vadd.sf.sf" => "__builtin_HEXAGON_V6_vadd_sf_sf", + "llvm.hexagon.V6.vadd.sf.sf.128B" => "__builtin_HEXAGON_V6_vadd_sf_sf_128B", "llvm.hexagon.V6.vaddb" => "__builtin_HEXAGON_V6_vaddb", "llvm.hexagon.V6.vaddb.128B" => "__builtin_HEXAGON_V6_vaddb_128B", "llvm.hexagon.V6.vaddb.dv" => "__builtin_HEXAGON_V6_vaddb_dv", "llvm.hexagon.V6.vaddb.dv.128B" => "__builtin_HEXAGON_V6_vaddb_dv_128B", + "llvm.hexagon.V6.vaddbnq" => "__builtin_HEXAGON_V6_vaddbnq", + "llvm.hexagon.V6.vaddbnq.128B" => "__builtin_HEXAGON_V6_vaddbnq_128B", + "llvm.hexagon.V6.vaddbq" => "__builtin_HEXAGON_V6_vaddbq", + "llvm.hexagon.V6.vaddbq.128B" => "__builtin_HEXAGON_V6_vaddbq_128B", + "llvm.hexagon.V6.vaddbsat" => "__builtin_HEXAGON_V6_vaddbsat", + "llvm.hexagon.V6.vaddbsat.128B" => "__builtin_HEXAGON_V6_vaddbsat_128B", + "llvm.hexagon.V6.vaddbsat.dv" => "__builtin_HEXAGON_V6_vaddbsat_dv", + "llvm.hexagon.V6.vaddbsat.dv.128B" => "__builtin_HEXAGON_V6_vaddbsat_dv_128B", + "llvm.hexagon.V6.vaddcarrysat" => "__builtin_HEXAGON_V6_vaddcarrysat", + "llvm.hexagon.V6.vaddcarrysat.128B" => "__builtin_HEXAGON_V6_vaddcarrysat_128B", + "llvm.hexagon.V6.vaddclbh" => "__builtin_HEXAGON_V6_vaddclbh", + "llvm.hexagon.V6.vaddclbh.128B" => "__builtin_HEXAGON_V6_vaddclbh_128B", + "llvm.hexagon.V6.vaddclbw" => "__builtin_HEXAGON_V6_vaddclbw", + "llvm.hexagon.V6.vaddclbw.128B" => "__builtin_HEXAGON_V6_vaddclbw_128B", "llvm.hexagon.V6.vaddh" => "__builtin_HEXAGON_V6_vaddh", "llvm.hexagon.V6.vaddh.128B" => "__builtin_HEXAGON_V6_vaddh_128B", "llvm.hexagon.V6.vaddh.dv" => "__builtin_HEXAGON_V6_vaddh_dv", "llvm.hexagon.V6.vaddh.dv.128B" => "__builtin_HEXAGON_V6_vaddh_dv_128B", + "llvm.hexagon.V6.vaddhnq" => "__builtin_HEXAGON_V6_vaddhnq", + "llvm.hexagon.V6.vaddhnq.128B" => "__builtin_HEXAGON_V6_vaddhnq_128B", + "llvm.hexagon.V6.vaddhq" => "__builtin_HEXAGON_V6_vaddhq", + "llvm.hexagon.V6.vaddhq.128B" => "__builtin_HEXAGON_V6_vaddhq_128B", "llvm.hexagon.V6.vaddhsat" => "__builtin_HEXAGON_V6_vaddhsat", "llvm.hexagon.V6.vaddhsat.128B" => "__builtin_HEXAGON_V6_vaddhsat_128B", "llvm.hexagon.V6.vaddhsat.dv" => "__builtin_HEXAGON_V6_vaddhsat_dv", "llvm.hexagon.V6.vaddhsat.dv.128B" => "__builtin_HEXAGON_V6_vaddhsat_dv_128B", "llvm.hexagon.V6.vaddhw" => "__builtin_HEXAGON_V6_vaddhw", "llvm.hexagon.V6.vaddhw.128B" => "__builtin_HEXAGON_V6_vaddhw_128B", + "llvm.hexagon.V6.vaddhw.acc" => "__builtin_HEXAGON_V6_vaddhw_acc", + "llvm.hexagon.V6.vaddhw.acc.128B" => "__builtin_HEXAGON_V6_vaddhw_acc_128B", "llvm.hexagon.V6.vaddubh" => "__builtin_HEXAGON_V6_vaddubh", "llvm.hexagon.V6.vaddubh.128B" => "__builtin_HEXAGON_V6_vaddubh_128B", + "llvm.hexagon.V6.vaddubh.acc" => "__builtin_HEXAGON_V6_vaddubh_acc", + "llvm.hexagon.V6.vaddubh.acc.128B" => "__builtin_HEXAGON_V6_vaddubh_acc_128B", "llvm.hexagon.V6.vaddubsat" => "__builtin_HEXAGON_V6_vaddubsat", "llvm.hexagon.V6.vaddubsat.128B" => "__builtin_HEXAGON_V6_vaddubsat_128B", "llvm.hexagon.V6.vaddubsat.dv" => "__builtin_HEXAGON_V6_vaddubsat_dv", "llvm.hexagon.V6.vaddubsat.dv.128B" => "__builtin_HEXAGON_V6_vaddubsat_dv_128B", + "llvm.hexagon.V6.vaddububb.sat" => "__builtin_HEXAGON_V6_vaddububb_sat", + "llvm.hexagon.V6.vaddububb.sat.128B" => "__builtin_HEXAGON_V6_vaddububb_sat_128B", "llvm.hexagon.V6.vadduhsat" => "__builtin_HEXAGON_V6_vadduhsat", "llvm.hexagon.V6.vadduhsat.128B" => "__builtin_HEXAGON_V6_vadduhsat_128B", "llvm.hexagon.V6.vadduhsat.dv" => "__builtin_HEXAGON_V6_vadduhsat_dv", "llvm.hexagon.V6.vadduhsat.dv.128B" => "__builtin_HEXAGON_V6_vadduhsat_dv_128B", "llvm.hexagon.V6.vadduhw" => "__builtin_HEXAGON_V6_vadduhw", "llvm.hexagon.V6.vadduhw.128B" => "__builtin_HEXAGON_V6_vadduhw_128B", + "llvm.hexagon.V6.vadduhw.acc" => "__builtin_HEXAGON_V6_vadduhw_acc", + "llvm.hexagon.V6.vadduhw.acc.128B" => "__builtin_HEXAGON_V6_vadduhw_acc_128B", + "llvm.hexagon.V6.vadduwsat" => "__builtin_HEXAGON_V6_vadduwsat", + "llvm.hexagon.V6.vadduwsat.128B" => "__builtin_HEXAGON_V6_vadduwsat_128B", + "llvm.hexagon.V6.vadduwsat.dv" => "__builtin_HEXAGON_V6_vadduwsat_dv", + "llvm.hexagon.V6.vadduwsat.dv.128B" => "__builtin_HEXAGON_V6_vadduwsat_dv_128B", "llvm.hexagon.V6.vaddw" => "__builtin_HEXAGON_V6_vaddw", "llvm.hexagon.V6.vaddw.128B" => "__builtin_HEXAGON_V6_vaddw_128B", "llvm.hexagon.V6.vaddw.dv" => "__builtin_HEXAGON_V6_vaddw_dv", "llvm.hexagon.V6.vaddw.dv.128B" => "__builtin_HEXAGON_V6_vaddw_dv_128B", + "llvm.hexagon.V6.vaddwnq" => "__builtin_HEXAGON_V6_vaddwnq", + "llvm.hexagon.V6.vaddwnq.128B" => "__builtin_HEXAGON_V6_vaddwnq_128B", + "llvm.hexagon.V6.vaddwq" => "__builtin_HEXAGON_V6_vaddwq", + "llvm.hexagon.V6.vaddwq.128B" => "__builtin_HEXAGON_V6_vaddwq_128B", "llvm.hexagon.V6.vaddwsat" => "__builtin_HEXAGON_V6_vaddwsat", "llvm.hexagon.V6.vaddwsat.128B" => "__builtin_HEXAGON_V6_vaddwsat_128B", "llvm.hexagon.V6.vaddwsat.dv" => "__builtin_HEXAGON_V6_vaddwsat_dv", @@ -1184,8 +1401,26 @@ match name { "llvm.hexagon.V6.valignbi.128B" => "__builtin_HEXAGON_V6_valignbi_128B", "llvm.hexagon.V6.vand" => "__builtin_HEXAGON_V6_vand", "llvm.hexagon.V6.vand.128B" => "__builtin_HEXAGON_V6_vand_128B", + "llvm.hexagon.V6.vandnqrt" => "__builtin_HEXAGON_V6_vandnqrt", + "llvm.hexagon.V6.vandnqrt.128B" => "__builtin_HEXAGON_V6_vandnqrt_128B", + "llvm.hexagon.V6.vandnqrt.acc" => "__builtin_HEXAGON_V6_vandnqrt_acc", + "llvm.hexagon.V6.vandnqrt.acc.128B" => "__builtin_HEXAGON_V6_vandnqrt_acc_128B", + "llvm.hexagon.V6.vandqrt" => "__builtin_HEXAGON_V6_vandqrt", + "llvm.hexagon.V6.vandqrt.128B" => "__builtin_HEXAGON_V6_vandqrt_128B", + "llvm.hexagon.V6.vandqrt.acc" => "__builtin_HEXAGON_V6_vandqrt_acc", + "llvm.hexagon.V6.vandqrt.acc.128B" => "__builtin_HEXAGON_V6_vandqrt_acc_128B", + "llvm.hexagon.V6.vandvnqv" => "__builtin_HEXAGON_V6_vandvnqv", + "llvm.hexagon.V6.vandvnqv.128B" => "__builtin_HEXAGON_V6_vandvnqv_128B", + "llvm.hexagon.V6.vandvqv" => "__builtin_HEXAGON_V6_vandvqv", + "llvm.hexagon.V6.vandvqv.128B" => "__builtin_HEXAGON_V6_vandvqv_128B", + "llvm.hexagon.V6.vandvrt" => "__builtin_HEXAGON_V6_vandvrt", + "llvm.hexagon.V6.vandvrt.128B" => "__builtin_HEXAGON_V6_vandvrt_128B", + "llvm.hexagon.V6.vandvrt.acc" => "__builtin_HEXAGON_V6_vandvrt_acc", + "llvm.hexagon.V6.vandvrt.acc.128B" => "__builtin_HEXAGON_V6_vandvrt_acc_128B", "llvm.hexagon.V6.vaslh" => "__builtin_HEXAGON_V6_vaslh", "llvm.hexagon.V6.vaslh.128B" => "__builtin_HEXAGON_V6_vaslh_128B", + "llvm.hexagon.V6.vaslh.acc" => "__builtin_HEXAGON_V6_vaslh_acc", + "llvm.hexagon.V6.vaslh.acc.128B" => "__builtin_HEXAGON_V6_vaslh_acc_128B", "llvm.hexagon.V6.vaslhv" => "__builtin_HEXAGON_V6_vaslhv", "llvm.hexagon.V6.vaslhv.128B" => "__builtin_HEXAGON_V6_vaslhv_128B", "llvm.hexagon.V6.vaslw" => "__builtin_HEXAGON_V6_vaslw", @@ -1194,16 +1429,38 @@ match name { "llvm.hexagon.V6.vaslw.acc.128B" => "__builtin_HEXAGON_V6_vaslw_acc_128B", "llvm.hexagon.V6.vaslwv" => "__builtin_HEXAGON_V6_vaslwv", "llvm.hexagon.V6.vaslwv.128B" => "__builtin_HEXAGON_V6_vaslwv_128B", + "llvm.hexagon.V6.vasr.into" => "__builtin_HEXAGON_V6_vasr_into", + "llvm.hexagon.V6.vasr.into.128B" => "__builtin_HEXAGON_V6_vasr_into_128B", "llvm.hexagon.V6.vasrh" => "__builtin_HEXAGON_V6_vasrh", "llvm.hexagon.V6.vasrh.128B" => "__builtin_HEXAGON_V6_vasrh_128B", + "llvm.hexagon.V6.vasrh.acc" => "__builtin_HEXAGON_V6_vasrh_acc", + "llvm.hexagon.V6.vasrh.acc.128B" => "__builtin_HEXAGON_V6_vasrh_acc_128B", "llvm.hexagon.V6.vasrhbrndsat" => "__builtin_HEXAGON_V6_vasrhbrndsat", "llvm.hexagon.V6.vasrhbrndsat.128B" => "__builtin_HEXAGON_V6_vasrhbrndsat_128B", + "llvm.hexagon.V6.vasrhbsat" => "__builtin_HEXAGON_V6_vasrhbsat", + "llvm.hexagon.V6.vasrhbsat.128B" => "__builtin_HEXAGON_V6_vasrhbsat_128B", "llvm.hexagon.V6.vasrhubrndsat" => "__builtin_HEXAGON_V6_vasrhubrndsat", "llvm.hexagon.V6.vasrhubrndsat.128B" => "__builtin_HEXAGON_V6_vasrhubrndsat_128B", "llvm.hexagon.V6.vasrhubsat" => "__builtin_HEXAGON_V6_vasrhubsat", "llvm.hexagon.V6.vasrhubsat.128B" => "__builtin_HEXAGON_V6_vasrhubsat_128B", "llvm.hexagon.V6.vasrhv" => "__builtin_HEXAGON_V6_vasrhv", "llvm.hexagon.V6.vasrhv.128B" => "__builtin_HEXAGON_V6_vasrhv_128B", + "llvm.hexagon.V6.vasruhubrndsat" => "__builtin_HEXAGON_V6_vasruhubrndsat", + "llvm.hexagon.V6.vasruhubrndsat.128B" => "__builtin_HEXAGON_V6_vasruhubrndsat_128B", + "llvm.hexagon.V6.vasruhubsat" => "__builtin_HEXAGON_V6_vasruhubsat", + "llvm.hexagon.V6.vasruhubsat.128B" => "__builtin_HEXAGON_V6_vasruhubsat_128B", + "llvm.hexagon.V6.vasruwuhrndsat" => "__builtin_HEXAGON_V6_vasruwuhrndsat", + "llvm.hexagon.V6.vasruwuhrndsat.128B" => "__builtin_HEXAGON_V6_vasruwuhrndsat_128B", + "llvm.hexagon.V6.vasruwuhsat" => "__builtin_HEXAGON_V6_vasruwuhsat", + "llvm.hexagon.V6.vasruwuhsat.128B" => "__builtin_HEXAGON_V6_vasruwuhsat_128B", + "llvm.hexagon.V6.vasrvuhubrndsat" => "__builtin_HEXAGON_V6_vasrvuhubrndsat", + "llvm.hexagon.V6.vasrvuhubrndsat.128B" => "__builtin_HEXAGON_V6_vasrvuhubrndsat_128B", + "llvm.hexagon.V6.vasrvuhubsat" => "__builtin_HEXAGON_V6_vasrvuhubsat", + "llvm.hexagon.V6.vasrvuhubsat.128B" => "__builtin_HEXAGON_V6_vasrvuhubsat_128B", + "llvm.hexagon.V6.vasrvwuhrndsat" => "__builtin_HEXAGON_V6_vasrvwuhrndsat", + "llvm.hexagon.V6.vasrvwuhrndsat.128B" => "__builtin_HEXAGON_V6_vasrvwuhrndsat_128B", + "llvm.hexagon.V6.vasrvwuhsat" => "__builtin_HEXAGON_V6_vasrvwuhsat", + "llvm.hexagon.V6.vasrvwuhsat.128B" => "__builtin_HEXAGON_V6_vasrvwuhsat_128B", "llvm.hexagon.V6.vasrw" => "__builtin_HEXAGON_V6_vasrw", "llvm.hexagon.V6.vasrw.128B" => "__builtin_HEXAGON_V6_vasrw_128B", "llvm.hexagon.V6.vasrw.acc" => "__builtin_HEXAGON_V6_vasrw_acc", @@ -1214,14 +1471,22 @@ match name { "llvm.hexagon.V6.vasrwhrndsat.128B" => "__builtin_HEXAGON_V6_vasrwhrndsat_128B", "llvm.hexagon.V6.vasrwhsat" => "__builtin_HEXAGON_V6_vasrwhsat", "llvm.hexagon.V6.vasrwhsat.128B" => "__builtin_HEXAGON_V6_vasrwhsat_128B", + "llvm.hexagon.V6.vasrwuhrndsat" => "__builtin_HEXAGON_V6_vasrwuhrndsat", + "llvm.hexagon.V6.vasrwuhrndsat.128B" => "__builtin_HEXAGON_V6_vasrwuhrndsat_128B", "llvm.hexagon.V6.vasrwuhsat" => "__builtin_HEXAGON_V6_vasrwuhsat", "llvm.hexagon.V6.vasrwuhsat.128B" => "__builtin_HEXAGON_V6_vasrwuhsat_128B", "llvm.hexagon.V6.vasrwv" => "__builtin_HEXAGON_V6_vasrwv", "llvm.hexagon.V6.vasrwv.128B" => "__builtin_HEXAGON_V6_vasrwv_128B", "llvm.hexagon.V6.vassign" => "__builtin_HEXAGON_V6_vassign", "llvm.hexagon.V6.vassign.128B" => "__builtin_HEXAGON_V6_vassign_128B", + "llvm.hexagon.V6.vassign.fp" => "__builtin_HEXAGON_V6_vassign_fp", + "llvm.hexagon.V6.vassign.fp.128B" => "__builtin_HEXAGON_V6_vassign_fp_128B", "llvm.hexagon.V6.vassignp" => "__builtin_HEXAGON_V6_vassignp", "llvm.hexagon.V6.vassignp.128B" => "__builtin_HEXAGON_V6_vassignp_128B", + "llvm.hexagon.V6.vavgb" => "__builtin_HEXAGON_V6_vavgb", + "llvm.hexagon.V6.vavgb.128B" => "__builtin_HEXAGON_V6_vavgb_128B", + "llvm.hexagon.V6.vavgbrnd" => "__builtin_HEXAGON_V6_vavgbrnd", + "llvm.hexagon.V6.vavgbrnd.128B" => "__builtin_HEXAGON_V6_vavgbrnd_128B", "llvm.hexagon.V6.vavgh" => "__builtin_HEXAGON_V6_vavgh", "llvm.hexagon.V6.vavgh.128B" => "__builtin_HEXAGON_V6_vavgh_128B", "llvm.hexagon.V6.vavghrnd" => "__builtin_HEXAGON_V6_vavghrnd", @@ -1234,6 +1499,10 @@ match name { "llvm.hexagon.V6.vavguh.128B" => "__builtin_HEXAGON_V6_vavguh_128B", "llvm.hexagon.V6.vavguhrnd" => "__builtin_HEXAGON_V6_vavguhrnd", "llvm.hexagon.V6.vavguhrnd.128B" => "__builtin_HEXAGON_V6_vavguhrnd_128B", + "llvm.hexagon.V6.vavguw" => "__builtin_HEXAGON_V6_vavguw", + "llvm.hexagon.V6.vavguw.128B" => "__builtin_HEXAGON_V6_vavguw_128B", + "llvm.hexagon.V6.vavguwrnd" => "__builtin_HEXAGON_V6_vavguwrnd", + "llvm.hexagon.V6.vavguwrnd.128B" => "__builtin_HEXAGON_V6_vavguwrnd_128B", "llvm.hexagon.V6.vavgw" => "__builtin_HEXAGON_V6_vavgw", "llvm.hexagon.V6.vavgw.128B" => "__builtin_HEXAGON_V6_vavgw_128B", "llvm.hexagon.V6.vavgwrnd" => "__builtin_HEXAGON_V6_vavgwrnd", @@ -1244,8 +1513,46 @@ match name { "llvm.hexagon.V6.vcl0w.128B" => "__builtin_HEXAGON_V6_vcl0w_128B", "llvm.hexagon.V6.vcombine" => "__builtin_HEXAGON_V6_vcombine", "llvm.hexagon.V6.vcombine.128B" => "__builtin_HEXAGON_V6_vcombine_128B", + "llvm.hexagon.V6.vconv.h.hf" => "__builtin_HEXAGON_V6_vconv_h_hf", + "llvm.hexagon.V6.vconv.h.hf.128B" => "__builtin_HEXAGON_V6_vconv_h_hf_128B", + "llvm.hexagon.V6.vconv.hf.h" => "__builtin_HEXAGON_V6_vconv_hf_h", + "llvm.hexagon.V6.vconv.hf.h.128B" => "__builtin_HEXAGON_V6_vconv_hf_h_128B", + "llvm.hexagon.V6.vconv.hf.qf16" => "__builtin_HEXAGON_V6_vconv_hf_qf16", + "llvm.hexagon.V6.vconv.hf.qf16.128B" => "__builtin_HEXAGON_V6_vconv_hf_qf16_128B", + "llvm.hexagon.V6.vconv.hf.qf32" => "__builtin_HEXAGON_V6_vconv_hf_qf32", + "llvm.hexagon.V6.vconv.hf.qf32.128B" => "__builtin_HEXAGON_V6_vconv_hf_qf32_128B", + "llvm.hexagon.V6.vconv.sf.qf32" => "__builtin_HEXAGON_V6_vconv_sf_qf32", + "llvm.hexagon.V6.vconv.sf.qf32.128B" => "__builtin_HEXAGON_V6_vconv_sf_qf32_128B", + "llvm.hexagon.V6.vconv.sf.w" => "__builtin_HEXAGON_V6_vconv_sf_w", + "llvm.hexagon.V6.vconv.sf.w.128B" => "__builtin_HEXAGON_V6_vconv_sf_w_128B", + "llvm.hexagon.V6.vconv.w.sf" => "__builtin_HEXAGON_V6_vconv_w_sf", + "llvm.hexagon.V6.vconv.w.sf.128B" => "__builtin_HEXAGON_V6_vconv_w_sf_128B", + "llvm.hexagon.V6.vcvt.b.hf" => "__builtin_HEXAGON_V6_vcvt_b_hf", + "llvm.hexagon.V6.vcvt.b.hf.128B" => "__builtin_HEXAGON_V6_vcvt_b_hf_128B", + "llvm.hexagon.V6.vcvt.bf.sf" => "__builtin_HEXAGON_V6_vcvt_bf_sf", + "llvm.hexagon.V6.vcvt.bf.sf.128B" => "__builtin_HEXAGON_V6_vcvt_bf_sf_128B", + "llvm.hexagon.V6.vcvt.h.hf" => "__builtin_HEXAGON_V6_vcvt_h_hf", + "llvm.hexagon.V6.vcvt.h.hf.128B" => "__builtin_HEXAGON_V6_vcvt_h_hf_128B", + "llvm.hexagon.V6.vcvt.hf.b" => "__builtin_HEXAGON_V6_vcvt_hf_b", + "llvm.hexagon.V6.vcvt.hf.b.128B" => "__builtin_HEXAGON_V6_vcvt_hf_b_128B", + "llvm.hexagon.V6.vcvt.hf.h" => "__builtin_HEXAGON_V6_vcvt_hf_h", + "llvm.hexagon.V6.vcvt.hf.h.128B" => "__builtin_HEXAGON_V6_vcvt_hf_h_128B", + "llvm.hexagon.V6.vcvt.hf.sf" => "__builtin_HEXAGON_V6_vcvt_hf_sf", + "llvm.hexagon.V6.vcvt.hf.sf.128B" => "__builtin_HEXAGON_V6_vcvt_hf_sf_128B", + "llvm.hexagon.V6.vcvt.hf.ub" => "__builtin_HEXAGON_V6_vcvt_hf_ub", + "llvm.hexagon.V6.vcvt.hf.ub.128B" => "__builtin_HEXAGON_V6_vcvt_hf_ub_128B", + "llvm.hexagon.V6.vcvt.hf.uh" => "__builtin_HEXAGON_V6_vcvt_hf_uh", + "llvm.hexagon.V6.vcvt.hf.uh.128B" => "__builtin_HEXAGON_V6_vcvt_hf_uh_128B", + "llvm.hexagon.V6.vcvt.sf.hf" => "__builtin_HEXAGON_V6_vcvt_sf_hf", + "llvm.hexagon.V6.vcvt.sf.hf.128B" => "__builtin_HEXAGON_V6_vcvt_sf_hf_128B", + "llvm.hexagon.V6.vcvt.ub.hf" => "__builtin_HEXAGON_V6_vcvt_ub_hf", + "llvm.hexagon.V6.vcvt.ub.hf.128B" => "__builtin_HEXAGON_V6_vcvt_ub_hf_128B", + "llvm.hexagon.V6.vcvt.uh.hf" => "__builtin_HEXAGON_V6_vcvt_uh_hf", + "llvm.hexagon.V6.vcvt.uh.hf.128B" => "__builtin_HEXAGON_V6_vcvt_uh_hf_128B", "llvm.hexagon.V6.vd0" => "__builtin_HEXAGON_V6_vd0", "llvm.hexagon.V6.vd0.128B" => "__builtin_HEXAGON_V6_vd0_128B", + "llvm.hexagon.V6.vdd0" => "__builtin_HEXAGON_V6_vdd0", + "llvm.hexagon.V6.vdd0.128B" => "__builtin_HEXAGON_V6_vdd0_128B", "llvm.hexagon.V6.vdealb" => "__builtin_HEXAGON_V6_vdealb", "llvm.hexagon.V6.vdealb.128B" => "__builtin_HEXAGON_V6_vdealb_128B", "llvm.hexagon.V6.vdealb4w" => "__builtin_HEXAGON_V6_vdealb4w", @@ -1256,6 +1563,10 @@ match name { "llvm.hexagon.V6.vdealvdd.128B" => "__builtin_HEXAGON_V6_vdealvdd_128B", "llvm.hexagon.V6.vdelta" => "__builtin_HEXAGON_V6_vdelta", "llvm.hexagon.V6.vdelta.128B" => "__builtin_HEXAGON_V6_vdelta_128B", + "llvm.hexagon.V6.vdmpy.sf.hf" => "__builtin_HEXAGON_V6_vdmpy_sf_hf", + "llvm.hexagon.V6.vdmpy.sf.hf.128B" => "__builtin_HEXAGON_V6_vdmpy_sf_hf_128B", + "llvm.hexagon.V6.vdmpy.sf.hf.acc" => "__builtin_HEXAGON_V6_vdmpy_sf_hf_acc", + "llvm.hexagon.V6.vdmpy.sf.hf.acc.128B" => "__builtin_HEXAGON_V6_vdmpy_sf_hf_acc_128B", "llvm.hexagon.V6.vdmpybus" => "__builtin_HEXAGON_V6_vdmpybus", "llvm.hexagon.V6.vdmpybus.128B" => "__builtin_HEXAGON_V6_vdmpybus_128B", "llvm.hexagon.V6.vdmpybus.acc" => "__builtin_HEXAGON_V6_vdmpybus_acc", @@ -1296,12 +1607,134 @@ match name { "llvm.hexagon.V6.vdsaduh.128B" => "__builtin_HEXAGON_V6_vdsaduh_128B", "llvm.hexagon.V6.vdsaduh.acc" => "__builtin_HEXAGON_V6_vdsaduh_acc", "llvm.hexagon.V6.vdsaduh.acc.128B" => "__builtin_HEXAGON_V6_vdsaduh_acc_128B", + "llvm.hexagon.V6.veqb" => "__builtin_HEXAGON_V6_veqb", + "llvm.hexagon.V6.veqb.128B" => "__builtin_HEXAGON_V6_veqb_128B", + "llvm.hexagon.V6.veqb.and" => "__builtin_HEXAGON_V6_veqb_and", + "llvm.hexagon.V6.veqb.and.128B" => "__builtin_HEXAGON_V6_veqb_and_128B", + "llvm.hexagon.V6.veqb.or" => "__builtin_HEXAGON_V6_veqb_or", + "llvm.hexagon.V6.veqb.or.128B" => "__builtin_HEXAGON_V6_veqb_or_128B", + "llvm.hexagon.V6.veqb.xor" => "__builtin_HEXAGON_V6_veqb_xor", + "llvm.hexagon.V6.veqb.xor.128B" => "__builtin_HEXAGON_V6_veqb_xor_128B", + "llvm.hexagon.V6.veqh" => "__builtin_HEXAGON_V6_veqh", + "llvm.hexagon.V6.veqh.128B" => "__builtin_HEXAGON_V6_veqh_128B", + "llvm.hexagon.V6.veqh.and" => "__builtin_HEXAGON_V6_veqh_and", + "llvm.hexagon.V6.veqh.and.128B" => "__builtin_HEXAGON_V6_veqh_and_128B", + "llvm.hexagon.V6.veqh.or" => "__builtin_HEXAGON_V6_veqh_or", + "llvm.hexagon.V6.veqh.or.128B" => "__builtin_HEXAGON_V6_veqh_or_128B", + "llvm.hexagon.V6.veqh.xor" => "__builtin_HEXAGON_V6_veqh_xor", + "llvm.hexagon.V6.veqh.xor.128B" => "__builtin_HEXAGON_V6_veqh_xor_128B", + "llvm.hexagon.V6.veqw" => "__builtin_HEXAGON_V6_veqw", + "llvm.hexagon.V6.veqw.128B" => "__builtin_HEXAGON_V6_veqw_128B", + "llvm.hexagon.V6.veqw.and" => "__builtin_HEXAGON_V6_veqw_and", + "llvm.hexagon.V6.veqw.and.128B" => "__builtin_HEXAGON_V6_veqw_and_128B", + "llvm.hexagon.V6.veqw.or" => "__builtin_HEXAGON_V6_veqw_or", + "llvm.hexagon.V6.veqw.or.128B" => "__builtin_HEXAGON_V6_veqw_or_128B", + "llvm.hexagon.V6.veqw.xor" => "__builtin_HEXAGON_V6_veqw_xor", + "llvm.hexagon.V6.veqw.xor.128B" => "__builtin_HEXAGON_V6_veqw_xor_128B", + "llvm.hexagon.V6.vfmax.hf" => "__builtin_HEXAGON_V6_vfmax_hf", + "llvm.hexagon.V6.vfmax.hf.128B" => "__builtin_HEXAGON_V6_vfmax_hf_128B", + "llvm.hexagon.V6.vfmax.sf" => "__builtin_HEXAGON_V6_vfmax_sf", + "llvm.hexagon.V6.vfmax.sf.128B" => "__builtin_HEXAGON_V6_vfmax_sf_128B", + "llvm.hexagon.V6.vfmin.hf" => "__builtin_HEXAGON_V6_vfmin_hf", + "llvm.hexagon.V6.vfmin.hf.128B" => "__builtin_HEXAGON_V6_vfmin_hf_128B", + "llvm.hexagon.V6.vfmin.sf" => "__builtin_HEXAGON_V6_vfmin_sf", + "llvm.hexagon.V6.vfmin.sf.128B" => "__builtin_HEXAGON_V6_vfmin_sf_128B", + "llvm.hexagon.V6.vfneg.hf" => "__builtin_HEXAGON_V6_vfneg_hf", + "llvm.hexagon.V6.vfneg.hf.128B" => "__builtin_HEXAGON_V6_vfneg_hf_128B", + "llvm.hexagon.V6.vfneg.sf" => "__builtin_HEXAGON_V6_vfneg_sf", + "llvm.hexagon.V6.vfneg.sf.128B" => "__builtin_HEXAGON_V6_vfneg_sf_128B", + "llvm.hexagon.V6.vgathermh" => "__builtin_HEXAGON_V6_vgathermh", + "llvm.hexagon.V6.vgathermh.128B" => "__builtin_HEXAGON_V6_vgathermh_128B", + "llvm.hexagon.V6.vgathermhq" => "__builtin_HEXAGON_V6_vgathermhq", + "llvm.hexagon.V6.vgathermhq.128B" => "__builtin_HEXAGON_V6_vgathermhq_128B", + "llvm.hexagon.V6.vgathermhw" => "__builtin_HEXAGON_V6_vgathermhw", + "llvm.hexagon.V6.vgathermhw.128B" => "__builtin_HEXAGON_V6_vgathermhw_128B", + "llvm.hexagon.V6.vgathermhwq" => "__builtin_HEXAGON_V6_vgathermhwq", + "llvm.hexagon.V6.vgathermhwq.128B" => "__builtin_HEXAGON_V6_vgathermhwq_128B", + "llvm.hexagon.V6.vgathermw" => "__builtin_HEXAGON_V6_vgathermw", + "llvm.hexagon.V6.vgathermw.128B" => "__builtin_HEXAGON_V6_vgathermw_128B", + "llvm.hexagon.V6.vgathermwq" => "__builtin_HEXAGON_V6_vgathermwq", + "llvm.hexagon.V6.vgathermwq.128B" => "__builtin_HEXAGON_V6_vgathermwq_128B", + "llvm.hexagon.V6.vgtb" => "__builtin_HEXAGON_V6_vgtb", + "llvm.hexagon.V6.vgtb.128B" => "__builtin_HEXAGON_V6_vgtb_128B", + "llvm.hexagon.V6.vgtb.and" => "__builtin_HEXAGON_V6_vgtb_and", + "llvm.hexagon.V6.vgtb.and.128B" => "__builtin_HEXAGON_V6_vgtb_and_128B", + "llvm.hexagon.V6.vgtb.or" => "__builtin_HEXAGON_V6_vgtb_or", + "llvm.hexagon.V6.vgtb.or.128B" => "__builtin_HEXAGON_V6_vgtb_or_128B", + "llvm.hexagon.V6.vgtb.xor" => "__builtin_HEXAGON_V6_vgtb_xor", + "llvm.hexagon.V6.vgtb.xor.128B" => "__builtin_HEXAGON_V6_vgtb_xor_128B", + "llvm.hexagon.V6.vgtbf" => "__builtin_HEXAGON_V6_vgtbf", + "llvm.hexagon.V6.vgtbf.128B" => "__builtin_HEXAGON_V6_vgtbf_128B", + "llvm.hexagon.V6.vgtbf.and" => "__builtin_HEXAGON_V6_vgtbf_and", + "llvm.hexagon.V6.vgtbf.and.128B" => "__builtin_HEXAGON_V6_vgtbf_and_128B", + "llvm.hexagon.V6.vgtbf.or" => "__builtin_HEXAGON_V6_vgtbf_or", + "llvm.hexagon.V6.vgtbf.or.128B" => "__builtin_HEXAGON_V6_vgtbf_or_128B", + "llvm.hexagon.V6.vgtbf.xor" => "__builtin_HEXAGON_V6_vgtbf_xor", + "llvm.hexagon.V6.vgtbf.xor.128B" => "__builtin_HEXAGON_V6_vgtbf_xor_128B", + "llvm.hexagon.V6.vgth" => "__builtin_HEXAGON_V6_vgth", + "llvm.hexagon.V6.vgth.128B" => "__builtin_HEXAGON_V6_vgth_128B", + "llvm.hexagon.V6.vgth.and" => "__builtin_HEXAGON_V6_vgth_and", + "llvm.hexagon.V6.vgth.and.128B" => "__builtin_HEXAGON_V6_vgth_and_128B", + "llvm.hexagon.V6.vgth.or" => "__builtin_HEXAGON_V6_vgth_or", + "llvm.hexagon.V6.vgth.or.128B" => "__builtin_HEXAGON_V6_vgth_or_128B", + "llvm.hexagon.V6.vgth.xor" => "__builtin_HEXAGON_V6_vgth_xor", + "llvm.hexagon.V6.vgth.xor.128B" => "__builtin_HEXAGON_V6_vgth_xor_128B", + "llvm.hexagon.V6.vgthf" => "__builtin_HEXAGON_V6_vgthf", + "llvm.hexagon.V6.vgthf.128B" => "__builtin_HEXAGON_V6_vgthf_128B", + "llvm.hexagon.V6.vgthf.and" => "__builtin_HEXAGON_V6_vgthf_and", + "llvm.hexagon.V6.vgthf.and.128B" => "__builtin_HEXAGON_V6_vgthf_and_128B", + "llvm.hexagon.V6.vgthf.or" => "__builtin_HEXAGON_V6_vgthf_or", + "llvm.hexagon.V6.vgthf.or.128B" => "__builtin_HEXAGON_V6_vgthf_or_128B", + "llvm.hexagon.V6.vgthf.xor" => "__builtin_HEXAGON_V6_vgthf_xor", + "llvm.hexagon.V6.vgthf.xor.128B" => "__builtin_HEXAGON_V6_vgthf_xor_128B", + "llvm.hexagon.V6.vgtsf" => "__builtin_HEXAGON_V6_vgtsf", + "llvm.hexagon.V6.vgtsf.128B" => "__builtin_HEXAGON_V6_vgtsf_128B", + "llvm.hexagon.V6.vgtsf.and" => "__builtin_HEXAGON_V6_vgtsf_and", + "llvm.hexagon.V6.vgtsf.and.128B" => "__builtin_HEXAGON_V6_vgtsf_and_128B", + "llvm.hexagon.V6.vgtsf.or" => "__builtin_HEXAGON_V6_vgtsf_or", + "llvm.hexagon.V6.vgtsf.or.128B" => "__builtin_HEXAGON_V6_vgtsf_or_128B", + "llvm.hexagon.V6.vgtsf.xor" => "__builtin_HEXAGON_V6_vgtsf_xor", + "llvm.hexagon.V6.vgtsf.xor.128B" => "__builtin_HEXAGON_V6_vgtsf_xor_128B", + "llvm.hexagon.V6.vgtub" => "__builtin_HEXAGON_V6_vgtub", + "llvm.hexagon.V6.vgtub.128B" => "__builtin_HEXAGON_V6_vgtub_128B", + "llvm.hexagon.V6.vgtub.and" => "__builtin_HEXAGON_V6_vgtub_and", + "llvm.hexagon.V6.vgtub.and.128B" => "__builtin_HEXAGON_V6_vgtub_and_128B", + "llvm.hexagon.V6.vgtub.or" => "__builtin_HEXAGON_V6_vgtub_or", + "llvm.hexagon.V6.vgtub.or.128B" => "__builtin_HEXAGON_V6_vgtub_or_128B", + "llvm.hexagon.V6.vgtub.xor" => "__builtin_HEXAGON_V6_vgtub_xor", + "llvm.hexagon.V6.vgtub.xor.128B" => "__builtin_HEXAGON_V6_vgtub_xor_128B", + "llvm.hexagon.V6.vgtuh" => "__builtin_HEXAGON_V6_vgtuh", + "llvm.hexagon.V6.vgtuh.128B" => "__builtin_HEXAGON_V6_vgtuh_128B", + "llvm.hexagon.V6.vgtuh.and" => "__builtin_HEXAGON_V6_vgtuh_and", + "llvm.hexagon.V6.vgtuh.and.128B" => "__builtin_HEXAGON_V6_vgtuh_and_128B", + "llvm.hexagon.V6.vgtuh.or" => "__builtin_HEXAGON_V6_vgtuh_or", + "llvm.hexagon.V6.vgtuh.or.128B" => "__builtin_HEXAGON_V6_vgtuh_or_128B", + "llvm.hexagon.V6.vgtuh.xor" => "__builtin_HEXAGON_V6_vgtuh_xor", + "llvm.hexagon.V6.vgtuh.xor.128B" => "__builtin_HEXAGON_V6_vgtuh_xor_128B", + "llvm.hexagon.V6.vgtuw" => "__builtin_HEXAGON_V6_vgtuw", + "llvm.hexagon.V6.vgtuw.128B" => "__builtin_HEXAGON_V6_vgtuw_128B", + "llvm.hexagon.V6.vgtuw.and" => "__builtin_HEXAGON_V6_vgtuw_and", + "llvm.hexagon.V6.vgtuw.and.128B" => "__builtin_HEXAGON_V6_vgtuw_and_128B", + "llvm.hexagon.V6.vgtuw.or" => "__builtin_HEXAGON_V6_vgtuw_or", + "llvm.hexagon.V6.vgtuw.or.128B" => "__builtin_HEXAGON_V6_vgtuw_or_128B", + "llvm.hexagon.V6.vgtuw.xor" => "__builtin_HEXAGON_V6_vgtuw_xor", + "llvm.hexagon.V6.vgtuw.xor.128B" => "__builtin_HEXAGON_V6_vgtuw_xor_128B", + "llvm.hexagon.V6.vgtw" => "__builtin_HEXAGON_V6_vgtw", + "llvm.hexagon.V6.vgtw.128B" => "__builtin_HEXAGON_V6_vgtw_128B", + "llvm.hexagon.V6.vgtw.and" => "__builtin_HEXAGON_V6_vgtw_and", + "llvm.hexagon.V6.vgtw.and.128B" => "__builtin_HEXAGON_V6_vgtw_and_128B", + "llvm.hexagon.V6.vgtw.or" => "__builtin_HEXAGON_V6_vgtw_or", + "llvm.hexagon.V6.vgtw.or.128B" => "__builtin_HEXAGON_V6_vgtw_or_128B", + "llvm.hexagon.V6.vgtw.xor" => "__builtin_HEXAGON_V6_vgtw_xor", + "llvm.hexagon.V6.vgtw.xor.128B" => "__builtin_HEXAGON_V6_vgtw_xor_128B", "llvm.hexagon.V6.vinsertwr" => "__builtin_HEXAGON_V6_vinsertwr", "llvm.hexagon.V6.vinsertwr.128B" => "__builtin_HEXAGON_V6_vinsertwr_128B", "llvm.hexagon.V6.vlalignb" => "__builtin_HEXAGON_V6_vlalignb", "llvm.hexagon.V6.vlalignb.128B" => "__builtin_HEXAGON_V6_vlalignb_128B", "llvm.hexagon.V6.vlalignbi" => "__builtin_HEXAGON_V6_vlalignbi", "llvm.hexagon.V6.vlalignbi.128B" => "__builtin_HEXAGON_V6_vlalignbi_128B", + "llvm.hexagon.V6.vlsrb" => "__builtin_HEXAGON_V6_vlsrb", + "llvm.hexagon.V6.vlsrb.128B" => "__builtin_HEXAGON_V6_vlsrb_128B", "llvm.hexagon.V6.vlsrh" => "__builtin_HEXAGON_V6_vlsrh", "llvm.hexagon.V6.vlsrh.128B" => "__builtin_HEXAGON_V6_vlsrh_128B", "llvm.hexagon.V6.vlsrhv" => "__builtin_HEXAGON_V6_vlsrhv", @@ -1310,6 +1743,8 @@ match name { "llvm.hexagon.V6.vlsrw.128B" => "__builtin_HEXAGON_V6_vlsrw_128B", "llvm.hexagon.V6.vlsrwv" => "__builtin_HEXAGON_V6_vlsrwv", "llvm.hexagon.V6.vlsrwv.128B" => "__builtin_HEXAGON_V6_vlsrwv_128B", + "llvm.hexagon.V6.vlut4" => "__builtin_HEXAGON_V6_vlut4", + "llvm.hexagon.V6.vlut4.128B" => "__builtin_HEXAGON_V6_vlut4_128B", "llvm.hexagon.V6.vlutb" => "__builtin_HEXAGON_V6_vlutb", "llvm.hexagon.V6.vlutb.128B" => "__builtin_HEXAGON_V6_vlutb_128B", "llvm.hexagon.V6.vlutb.acc" => "__builtin_HEXAGON_V6_vlutb_acc", @@ -1320,12 +1755,32 @@ match name { "llvm.hexagon.V6.vlutb.dv.acc.128B" => "__builtin_HEXAGON_V6_vlutb_dv_acc_128B", "llvm.hexagon.V6.vlutvvb" => "__builtin_HEXAGON_V6_vlutvvb", "llvm.hexagon.V6.vlutvvb.128B" => "__builtin_HEXAGON_V6_vlutvvb_128B", + "llvm.hexagon.V6.vlutvvb.nm" => "__builtin_HEXAGON_V6_vlutvvb_nm", + "llvm.hexagon.V6.vlutvvb.nm.128B" => "__builtin_HEXAGON_V6_vlutvvb_nm_128B", "llvm.hexagon.V6.vlutvvb.oracc" => "__builtin_HEXAGON_V6_vlutvvb_oracc", "llvm.hexagon.V6.vlutvvb.oracc.128B" => "__builtin_HEXAGON_V6_vlutvvb_oracc_128B", + "llvm.hexagon.V6.vlutvvb.oracci" => "__builtin_HEXAGON_V6_vlutvvb_oracci", + "llvm.hexagon.V6.vlutvvb.oracci.128B" => "__builtin_HEXAGON_V6_vlutvvb_oracci_128B", + "llvm.hexagon.V6.vlutvvbi" => "__builtin_HEXAGON_V6_vlutvvbi", + "llvm.hexagon.V6.vlutvvbi.128B" => "__builtin_HEXAGON_V6_vlutvvbi_128B", "llvm.hexagon.V6.vlutvwh" => "__builtin_HEXAGON_V6_vlutvwh", "llvm.hexagon.V6.vlutvwh.128B" => "__builtin_HEXAGON_V6_vlutvwh_128B", + "llvm.hexagon.V6.vlutvwh.nm" => "__builtin_HEXAGON_V6_vlutvwh_nm", + "llvm.hexagon.V6.vlutvwh.nm.128B" => "__builtin_HEXAGON_V6_vlutvwh_nm_128B", "llvm.hexagon.V6.vlutvwh.oracc" => "__builtin_HEXAGON_V6_vlutvwh_oracc", "llvm.hexagon.V6.vlutvwh.oracc.128B" => "__builtin_HEXAGON_V6_vlutvwh_oracc_128B", + "llvm.hexagon.V6.vlutvwh.oracci" => "__builtin_HEXAGON_V6_vlutvwh_oracci", + "llvm.hexagon.V6.vlutvwh.oracci.128B" => "__builtin_HEXAGON_V6_vlutvwh_oracci_128B", + "llvm.hexagon.V6.vlutvwhi" => "__builtin_HEXAGON_V6_vlutvwhi", + "llvm.hexagon.V6.vlutvwhi.128B" => "__builtin_HEXAGON_V6_vlutvwhi_128B", + "llvm.hexagon.V6.vmax.bf" => "__builtin_HEXAGON_V6_vmax_bf", + "llvm.hexagon.V6.vmax.bf.128B" => "__builtin_HEXAGON_V6_vmax_bf_128B", + "llvm.hexagon.V6.vmax.hf" => "__builtin_HEXAGON_V6_vmax_hf", + "llvm.hexagon.V6.vmax.hf.128B" => "__builtin_HEXAGON_V6_vmax_hf_128B", + "llvm.hexagon.V6.vmax.sf" => "__builtin_HEXAGON_V6_vmax_sf", + "llvm.hexagon.V6.vmax.sf.128B" => "__builtin_HEXAGON_V6_vmax_sf_128B", + "llvm.hexagon.V6.vmaxb" => "__builtin_HEXAGON_V6_vmaxb", + "llvm.hexagon.V6.vmaxb.128B" => "__builtin_HEXAGON_V6_vmaxb_128B", "llvm.hexagon.V6.vmaxh" => "__builtin_HEXAGON_V6_vmaxh", "llvm.hexagon.V6.vmaxh.128B" => "__builtin_HEXAGON_V6_vmaxh_128B", "llvm.hexagon.V6.vmaxub" => "__builtin_HEXAGON_V6_vmaxub", @@ -1334,6 +1789,14 @@ match name { "llvm.hexagon.V6.vmaxuh.128B" => "__builtin_HEXAGON_V6_vmaxuh_128B", "llvm.hexagon.V6.vmaxw" => "__builtin_HEXAGON_V6_vmaxw", "llvm.hexagon.V6.vmaxw.128B" => "__builtin_HEXAGON_V6_vmaxw_128B", + "llvm.hexagon.V6.vmin.bf" => "__builtin_HEXAGON_V6_vmin_bf", + "llvm.hexagon.V6.vmin.bf.128B" => "__builtin_HEXAGON_V6_vmin_bf_128B", + "llvm.hexagon.V6.vmin.hf" => "__builtin_HEXAGON_V6_vmin_hf", + "llvm.hexagon.V6.vmin.hf.128B" => "__builtin_HEXAGON_V6_vmin_hf_128B", + "llvm.hexagon.V6.vmin.sf" => "__builtin_HEXAGON_V6_vmin_sf", + "llvm.hexagon.V6.vmin.sf.128B" => "__builtin_HEXAGON_V6_vmin_sf_128B", + "llvm.hexagon.V6.vminb" => "__builtin_HEXAGON_V6_vminb", + "llvm.hexagon.V6.vminb.128B" => "__builtin_HEXAGON_V6_vminb_128B", "llvm.hexagon.V6.vminh" => "__builtin_HEXAGON_V6_vminh", "llvm.hexagon.V6.vminh.128B" => "__builtin_HEXAGON_V6_vminh_128B", "llvm.hexagon.V6.vminub" => "__builtin_HEXAGON_V6_vminub", @@ -1348,12 +1811,56 @@ match name { "llvm.hexagon.V6.vmpabus.acc.128B" => "__builtin_HEXAGON_V6_vmpabus_acc_128B", "llvm.hexagon.V6.vmpabusv" => "__builtin_HEXAGON_V6_vmpabusv", "llvm.hexagon.V6.vmpabusv.128B" => "__builtin_HEXAGON_V6_vmpabusv_128B", + "llvm.hexagon.V6.vmpabuu" => "__builtin_HEXAGON_V6_vmpabuu", + "llvm.hexagon.V6.vmpabuu.128B" => "__builtin_HEXAGON_V6_vmpabuu_128B", + "llvm.hexagon.V6.vmpabuu.acc" => "__builtin_HEXAGON_V6_vmpabuu_acc", + "llvm.hexagon.V6.vmpabuu.acc.128B" => "__builtin_HEXAGON_V6_vmpabuu_acc_128B", "llvm.hexagon.V6.vmpabuuv" => "__builtin_HEXAGON_V6_vmpabuuv", "llvm.hexagon.V6.vmpabuuv.128B" => "__builtin_HEXAGON_V6_vmpabuuv_128B", "llvm.hexagon.V6.vmpahb" => "__builtin_HEXAGON_V6_vmpahb", "llvm.hexagon.V6.vmpahb.128B" => "__builtin_HEXAGON_V6_vmpahb_128B", "llvm.hexagon.V6.vmpahb.acc" => "__builtin_HEXAGON_V6_vmpahb_acc", "llvm.hexagon.V6.vmpahb.acc.128B" => "__builtin_HEXAGON_V6_vmpahb_acc_128B", + "llvm.hexagon.V6.vmpahhsat" => "__builtin_HEXAGON_V6_vmpahhsat", + "llvm.hexagon.V6.vmpahhsat.128B" => "__builtin_HEXAGON_V6_vmpahhsat_128B", + "llvm.hexagon.V6.vmpauhb" => "__builtin_HEXAGON_V6_vmpauhb", + "llvm.hexagon.V6.vmpauhb.128B" => "__builtin_HEXAGON_V6_vmpauhb_128B", + "llvm.hexagon.V6.vmpauhb.acc" => "__builtin_HEXAGON_V6_vmpauhb_acc", + "llvm.hexagon.V6.vmpauhb.acc.128B" => "__builtin_HEXAGON_V6_vmpauhb_acc_128B", + "llvm.hexagon.V6.vmpauhuhsat" => "__builtin_HEXAGON_V6_vmpauhuhsat", + "llvm.hexagon.V6.vmpauhuhsat.128B" => "__builtin_HEXAGON_V6_vmpauhuhsat_128B", + "llvm.hexagon.V6.vmpsuhuhsat" => "__builtin_HEXAGON_V6_vmpsuhuhsat", + "llvm.hexagon.V6.vmpsuhuhsat.128B" => "__builtin_HEXAGON_V6_vmpsuhuhsat_128B", + "llvm.hexagon.V6.vmpy.hf.hf" => "__builtin_HEXAGON_V6_vmpy_hf_hf", + "llvm.hexagon.V6.vmpy.hf.hf.128B" => "__builtin_HEXAGON_V6_vmpy_hf_hf_128B", + "llvm.hexagon.V6.vmpy.hf.hf.acc" => "__builtin_HEXAGON_V6_vmpy_hf_hf_acc", + "llvm.hexagon.V6.vmpy.hf.hf.acc.128B" => "__builtin_HEXAGON_V6_vmpy_hf_hf_acc_128B", + "llvm.hexagon.V6.vmpy.qf16" => "__builtin_HEXAGON_V6_vmpy_qf16", + "llvm.hexagon.V6.vmpy.qf16.128B" => "__builtin_HEXAGON_V6_vmpy_qf16_128B", + "llvm.hexagon.V6.vmpy.qf16.hf" => "__builtin_HEXAGON_V6_vmpy_qf16_hf", + "llvm.hexagon.V6.vmpy.qf16.hf.128B" => "__builtin_HEXAGON_V6_vmpy_qf16_hf_128B", + "llvm.hexagon.V6.vmpy.qf16.mix.hf" => "__builtin_HEXAGON_V6_vmpy_qf16_mix_hf", + "llvm.hexagon.V6.vmpy.qf16.mix.hf.128B" => "__builtin_HEXAGON_V6_vmpy_qf16_mix_hf_128B", + "llvm.hexagon.V6.vmpy.qf32" => "__builtin_HEXAGON_V6_vmpy_qf32", + "llvm.hexagon.V6.vmpy.qf32.128B" => "__builtin_HEXAGON_V6_vmpy_qf32_128B", + "llvm.hexagon.V6.vmpy.qf32.hf" => "__builtin_HEXAGON_V6_vmpy_qf32_hf", + "llvm.hexagon.V6.vmpy.qf32.hf.128B" => "__builtin_HEXAGON_V6_vmpy_qf32_hf_128B", + "llvm.hexagon.V6.vmpy.qf32.mix.hf" => "__builtin_HEXAGON_V6_vmpy_qf32_mix_hf", + "llvm.hexagon.V6.vmpy.qf32.mix.hf.128B" => "__builtin_HEXAGON_V6_vmpy_qf32_mix_hf_128B", + "llvm.hexagon.V6.vmpy.qf32.qf16" => "__builtin_HEXAGON_V6_vmpy_qf32_qf16", + "llvm.hexagon.V6.vmpy.qf32.qf16.128B" => "__builtin_HEXAGON_V6_vmpy_qf32_qf16_128B", + "llvm.hexagon.V6.vmpy.qf32.sf" => "__builtin_HEXAGON_V6_vmpy_qf32_sf", + "llvm.hexagon.V6.vmpy.qf32.sf.128B" => "__builtin_HEXAGON_V6_vmpy_qf32_sf_128B", + "llvm.hexagon.V6.vmpy.sf.bf" => "__builtin_HEXAGON_V6_vmpy_sf_bf", + "llvm.hexagon.V6.vmpy.sf.bf.128B" => "__builtin_HEXAGON_V6_vmpy_sf_bf_128B", + "llvm.hexagon.V6.vmpy.sf.bf.acc" => "__builtin_HEXAGON_V6_vmpy_sf_bf_acc", + "llvm.hexagon.V6.vmpy.sf.bf.acc.128B" => "__builtin_HEXAGON_V6_vmpy_sf_bf_acc_128B", + "llvm.hexagon.V6.vmpy.sf.hf" => "__builtin_HEXAGON_V6_vmpy_sf_hf", + "llvm.hexagon.V6.vmpy.sf.hf.128B" => "__builtin_HEXAGON_V6_vmpy_sf_hf_128B", + "llvm.hexagon.V6.vmpy.sf.hf.acc" => "__builtin_HEXAGON_V6_vmpy_sf_hf_acc", + "llvm.hexagon.V6.vmpy.sf.hf.acc.128B" => "__builtin_HEXAGON_V6_vmpy_sf_hf_acc_128B", + "llvm.hexagon.V6.vmpy.sf.sf" => "__builtin_HEXAGON_V6_vmpy_sf_sf", + "llvm.hexagon.V6.vmpy.sf.sf.128B" => "__builtin_HEXAGON_V6_vmpy_sf_sf_128B", "llvm.hexagon.V6.vmpybus" => "__builtin_HEXAGON_V6_vmpybus", "llvm.hexagon.V6.vmpybus.128B" => "__builtin_HEXAGON_V6_vmpybus_128B", "llvm.hexagon.V6.vmpybus.acc" => "__builtin_HEXAGON_V6_vmpybus_acc", @@ -1368,8 +1875,12 @@ match name { "llvm.hexagon.V6.vmpybv.acc.128B" => "__builtin_HEXAGON_V6_vmpybv_acc_128B", "llvm.hexagon.V6.vmpyewuh" => "__builtin_HEXAGON_V6_vmpyewuh", "llvm.hexagon.V6.vmpyewuh.128B" => "__builtin_HEXAGON_V6_vmpyewuh_128B", + "llvm.hexagon.V6.vmpyewuh.64" => "__builtin_HEXAGON_V6_vmpyewuh_64", + "llvm.hexagon.V6.vmpyewuh.64.128B" => "__builtin_HEXAGON_V6_vmpyewuh_64_128B", "llvm.hexagon.V6.vmpyh" => "__builtin_HEXAGON_V6_vmpyh", "llvm.hexagon.V6.vmpyh.128B" => "__builtin_HEXAGON_V6_vmpyh_128B", + "llvm.hexagon.V6.vmpyh.acc" => "__builtin_HEXAGON_V6_vmpyh_acc", + "llvm.hexagon.V6.vmpyh.acc.128B" => "__builtin_HEXAGON_V6_vmpyh_acc_128B", "llvm.hexagon.V6.vmpyhsat.acc" => "__builtin_HEXAGON_V6_vmpyhsat_acc", "llvm.hexagon.V6.vmpyhsat.acc.128B" => "__builtin_HEXAGON_V6_vmpyhsat_acc_128B", "llvm.hexagon.V6.vmpyhsrs" => "__builtin_HEXAGON_V6_vmpyhsrs", @@ -1412,8 +1923,14 @@ match name { "llvm.hexagon.V6.vmpyiwh.128B" => "__builtin_HEXAGON_V6_vmpyiwh_128B", "llvm.hexagon.V6.vmpyiwh.acc" => "__builtin_HEXAGON_V6_vmpyiwh_acc", "llvm.hexagon.V6.vmpyiwh.acc.128B" => "__builtin_HEXAGON_V6_vmpyiwh_acc_128B", + "llvm.hexagon.V6.vmpyiwub" => "__builtin_HEXAGON_V6_vmpyiwub", + "llvm.hexagon.V6.vmpyiwub.128B" => "__builtin_HEXAGON_V6_vmpyiwub_128B", + "llvm.hexagon.V6.vmpyiwub.acc" => "__builtin_HEXAGON_V6_vmpyiwub_acc", + "llvm.hexagon.V6.vmpyiwub.acc.128B" => "__builtin_HEXAGON_V6_vmpyiwub_acc_128B", "llvm.hexagon.V6.vmpyowh" => "__builtin_HEXAGON_V6_vmpyowh", "llvm.hexagon.V6.vmpyowh.128B" => "__builtin_HEXAGON_V6_vmpyowh_128B", + "llvm.hexagon.V6.vmpyowh.64.acc" => "__builtin_HEXAGON_V6_vmpyowh_64_acc", + "llvm.hexagon.V6.vmpyowh.64.acc.128B" => "__builtin_HEXAGON_V6_vmpyowh_64_acc_128B", "llvm.hexagon.V6.vmpyowh.rnd" => "__builtin_HEXAGON_V6_vmpyowh_rnd", "llvm.hexagon.V6.vmpyowh.rnd.128B" => "__builtin_HEXAGON_V6_vmpyowh_rnd_128B", "llvm.hexagon.V6.vmpyowh.rnd.sacc" => "__builtin_HEXAGON_V6_vmpyowh_rnd_sacc", @@ -1432,10 +1949,20 @@ match name { "llvm.hexagon.V6.vmpyuh.128B" => "__builtin_HEXAGON_V6_vmpyuh_128B", "llvm.hexagon.V6.vmpyuh.acc" => "__builtin_HEXAGON_V6_vmpyuh_acc", "llvm.hexagon.V6.vmpyuh.acc.128B" => "__builtin_HEXAGON_V6_vmpyuh_acc_128B", + "llvm.hexagon.V6.vmpyuhe" => "__builtin_HEXAGON_V6_vmpyuhe", + "llvm.hexagon.V6.vmpyuhe.128B" => "__builtin_HEXAGON_V6_vmpyuhe_128B", + "llvm.hexagon.V6.vmpyuhe.acc" => "__builtin_HEXAGON_V6_vmpyuhe_acc", + "llvm.hexagon.V6.vmpyuhe.acc.128B" => "__builtin_HEXAGON_V6_vmpyuhe_acc_128B", "llvm.hexagon.V6.vmpyuhv" => "__builtin_HEXAGON_V6_vmpyuhv", "llvm.hexagon.V6.vmpyuhv.128B" => "__builtin_HEXAGON_V6_vmpyuhv_128B", "llvm.hexagon.V6.vmpyuhv.acc" => "__builtin_HEXAGON_V6_vmpyuhv_acc", "llvm.hexagon.V6.vmpyuhv.acc.128B" => "__builtin_HEXAGON_V6_vmpyuhv_acc_128B", + "llvm.hexagon.V6.vmpyuhvs" => "__builtin_HEXAGON_V6_vmpyuhvs", + "llvm.hexagon.V6.vmpyuhvs.128B" => "__builtin_HEXAGON_V6_vmpyuhvs_128B", + "llvm.hexagon.V6.vmux" => "__builtin_HEXAGON_V6_vmux", + "llvm.hexagon.V6.vmux.128B" => "__builtin_HEXAGON_V6_vmux_128B", + "llvm.hexagon.V6.vnavgb" => "__builtin_HEXAGON_V6_vnavgb", + "llvm.hexagon.V6.vnavgb.128B" => "__builtin_HEXAGON_V6_vnavgb_128B", "llvm.hexagon.V6.vnavgh" => "__builtin_HEXAGON_V6_vnavgh", "llvm.hexagon.V6.vnavgh.128B" => "__builtin_HEXAGON_V6_vnavgh_128B", "llvm.hexagon.V6.vnavgub" => "__builtin_HEXAGON_V6_vnavgub", @@ -1468,8 +1995,18 @@ match name { "llvm.hexagon.V6.vpackwuh.sat.128B" => "__builtin_HEXAGON_V6_vpackwuh_sat_128B", "llvm.hexagon.V6.vpopcounth" => "__builtin_HEXAGON_V6_vpopcounth", "llvm.hexagon.V6.vpopcounth.128B" => "__builtin_HEXAGON_V6_vpopcounth_128B", + "llvm.hexagon.V6.vprefixqb" => "__builtin_HEXAGON_V6_vprefixqb", + "llvm.hexagon.V6.vprefixqb.128B" => "__builtin_HEXAGON_V6_vprefixqb_128B", + "llvm.hexagon.V6.vprefixqh" => "__builtin_HEXAGON_V6_vprefixqh", + "llvm.hexagon.V6.vprefixqh.128B" => "__builtin_HEXAGON_V6_vprefixqh_128B", + "llvm.hexagon.V6.vprefixqw" => "__builtin_HEXAGON_V6_vprefixqw", + "llvm.hexagon.V6.vprefixqw.128B" => "__builtin_HEXAGON_V6_vprefixqw_128B", "llvm.hexagon.V6.vrdelta" => "__builtin_HEXAGON_V6_vrdelta", "llvm.hexagon.V6.vrdelta.128B" => "__builtin_HEXAGON_V6_vrdelta_128B", + "llvm.hexagon.V6.vrmpybub.rtt" => "__builtin_HEXAGON_V6_vrmpybub_rtt", + "llvm.hexagon.V6.vrmpybub.rtt.128B" => "__builtin_HEXAGON_V6_vrmpybub_rtt_128B", + "llvm.hexagon.V6.vrmpybub.rtt.acc" => "__builtin_HEXAGON_V6_vrmpybub_rtt_acc", + "llvm.hexagon.V6.vrmpybub.rtt.acc.128B" => "__builtin_HEXAGON_V6_vrmpybub_rtt_acc_128B", "llvm.hexagon.V6.vrmpybus" => "__builtin_HEXAGON_V6_vrmpybus", "llvm.hexagon.V6.vrmpybus.128B" => "__builtin_HEXAGON_V6_vrmpybus_128B", "llvm.hexagon.V6.vrmpybus.acc" => "__builtin_HEXAGON_V6_vrmpybus_acc", @@ -1490,6 +2027,10 @@ match name { "llvm.hexagon.V6.vrmpyub.128B" => "__builtin_HEXAGON_V6_vrmpyub_128B", "llvm.hexagon.V6.vrmpyub.acc" => "__builtin_HEXAGON_V6_vrmpyub_acc", "llvm.hexagon.V6.vrmpyub.acc.128B" => "__builtin_HEXAGON_V6_vrmpyub_acc_128B", + "llvm.hexagon.V6.vrmpyub.rtt" => "__builtin_HEXAGON_V6_vrmpyub_rtt", + "llvm.hexagon.V6.vrmpyub.rtt.128B" => "__builtin_HEXAGON_V6_vrmpyub_rtt_128B", + "llvm.hexagon.V6.vrmpyub.rtt.acc" => "__builtin_HEXAGON_V6_vrmpyub_rtt_acc", + "llvm.hexagon.V6.vrmpyub.rtt.acc.128B" => "__builtin_HEXAGON_V6_vrmpyub_rtt_acc_128B", "llvm.hexagon.V6.vrmpyubi" => "__builtin_HEXAGON_V6_vrmpyubi", "llvm.hexagon.V6.vrmpyubi.128B" => "__builtin_HEXAGON_V6_vrmpyubi_128B", "llvm.hexagon.V6.vrmpyubi.acc" => "__builtin_HEXAGON_V6_vrmpyubi_acc", @@ -1500,10 +2041,16 @@ match name { "llvm.hexagon.V6.vrmpyubv.acc.128B" => "__builtin_HEXAGON_V6_vrmpyubv_acc_128B", "llvm.hexagon.V6.vror" => "__builtin_HEXAGON_V6_vror", "llvm.hexagon.V6.vror.128B" => "__builtin_HEXAGON_V6_vror_128B", + "llvm.hexagon.V6.vrotr" => "__builtin_HEXAGON_V6_vrotr", + "llvm.hexagon.V6.vrotr.128B" => "__builtin_HEXAGON_V6_vrotr_128B", "llvm.hexagon.V6.vroundhb" => "__builtin_HEXAGON_V6_vroundhb", "llvm.hexagon.V6.vroundhb.128B" => "__builtin_HEXAGON_V6_vroundhb_128B", "llvm.hexagon.V6.vroundhub" => "__builtin_HEXAGON_V6_vroundhub", "llvm.hexagon.V6.vroundhub.128B" => "__builtin_HEXAGON_V6_vroundhub_128B", + "llvm.hexagon.V6.vrounduhub" => "__builtin_HEXAGON_V6_vrounduhub", + "llvm.hexagon.V6.vrounduhub.128B" => "__builtin_HEXAGON_V6_vrounduhub_128B", + "llvm.hexagon.V6.vrounduwuh" => "__builtin_HEXAGON_V6_vrounduwuh", + "llvm.hexagon.V6.vrounduwuh.128B" => "__builtin_HEXAGON_V6_vrounduwuh_128B", "llvm.hexagon.V6.vroundwh" => "__builtin_HEXAGON_V6_vroundwh", "llvm.hexagon.V6.vroundwh.128B" => "__builtin_HEXAGON_V6_vroundwh_128B", "llvm.hexagon.V6.vroundwuh" => "__builtin_HEXAGON_V6_vroundwuh", @@ -1512,12 +2059,34 @@ match name { "llvm.hexagon.V6.vrsadubi.128B" => "__builtin_HEXAGON_V6_vrsadubi_128B", "llvm.hexagon.V6.vrsadubi.acc" => "__builtin_HEXAGON_V6_vrsadubi_acc", "llvm.hexagon.V6.vrsadubi.acc.128B" => "__builtin_HEXAGON_V6_vrsadubi_acc_128B", + "llvm.hexagon.V6.vsatdw" => "__builtin_HEXAGON_V6_vsatdw", + "llvm.hexagon.V6.vsatdw.128B" => "__builtin_HEXAGON_V6_vsatdw_128B", "llvm.hexagon.V6.vsathub" => "__builtin_HEXAGON_V6_vsathub", "llvm.hexagon.V6.vsathub.128B" => "__builtin_HEXAGON_V6_vsathub_128B", + "llvm.hexagon.V6.vsatuwuh" => "__builtin_HEXAGON_V6_vsatuwuh", + "llvm.hexagon.V6.vsatuwuh.128B" => "__builtin_HEXAGON_V6_vsatuwuh_128B", "llvm.hexagon.V6.vsatwh" => "__builtin_HEXAGON_V6_vsatwh", "llvm.hexagon.V6.vsatwh.128B" => "__builtin_HEXAGON_V6_vsatwh_128B", "llvm.hexagon.V6.vsb" => "__builtin_HEXAGON_V6_vsb", "llvm.hexagon.V6.vsb.128B" => "__builtin_HEXAGON_V6_vsb_128B", + "llvm.hexagon.V6.vscattermh" => "__builtin_HEXAGON_V6_vscattermh", + "llvm.hexagon.V6.vscattermh.128B" => "__builtin_HEXAGON_V6_vscattermh_128B", + "llvm.hexagon.V6.vscattermh.add" => "__builtin_HEXAGON_V6_vscattermh_add", + "llvm.hexagon.V6.vscattermh.add.128B" => "__builtin_HEXAGON_V6_vscattermh_add_128B", + "llvm.hexagon.V6.vscattermhq" => "__builtin_HEXAGON_V6_vscattermhq", + "llvm.hexagon.V6.vscattermhq.128B" => "__builtin_HEXAGON_V6_vscattermhq_128B", + "llvm.hexagon.V6.vscattermhw" => "__builtin_HEXAGON_V6_vscattermhw", + "llvm.hexagon.V6.vscattermhw.128B" => "__builtin_HEXAGON_V6_vscattermhw_128B", + "llvm.hexagon.V6.vscattermhw.add" => "__builtin_HEXAGON_V6_vscattermhw_add", + "llvm.hexagon.V6.vscattermhw.add.128B" => "__builtin_HEXAGON_V6_vscattermhw_add_128B", + "llvm.hexagon.V6.vscattermhwq" => "__builtin_HEXAGON_V6_vscattermhwq", + "llvm.hexagon.V6.vscattermhwq.128B" => "__builtin_HEXAGON_V6_vscattermhwq_128B", + "llvm.hexagon.V6.vscattermw" => "__builtin_HEXAGON_V6_vscattermw", + "llvm.hexagon.V6.vscattermw.128B" => "__builtin_HEXAGON_V6_vscattermw_128B", + "llvm.hexagon.V6.vscattermw.add" => "__builtin_HEXAGON_V6_vscattermw_add", + "llvm.hexagon.V6.vscattermw.add.128B" => "__builtin_HEXAGON_V6_vscattermw_add_128B", + "llvm.hexagon.V6.vscattermwq" => "__builtin_HEXAGON_V6_vscattermwq", + "llvm.hexagon.V6.vscattermwq.128B" => "__builtin_HEXAGON_V6_vscattermwq_128B", "llvm.hexagon.V6.vsh" => "__builtin_HEXAGON_V6_vsh", "llvm.hexagon.V6.vsh.128B" => "__builtin_HEXAGON_V6_vsh_128B", "llvm.hexagon.V6.vshufeh" => "__builtin_HEXAGON_V6_vshufeh", @@ -1538,14 +2107,46 @@ match name { "llvm.hexagon.V6.vshufoeh.128B" => "__builtin_HEXAGON_V6_vshufoeh_128B", "llvm.hexagon.V6.vshufoh" => "__builtin_HEXAGON_V6_vshufoh", "llvm.hexagon.V6.vshufoh.128B" => "__builtin_HEXAGON_V6_vshufoh_128B", + "llvm.hexagon.V6.vsub.hf" => "__builtin_HEXAGON_V6_vsub_hf", + "llvm.hexagon.V6.vsub.hf.128B" => "__builtin_HEXAGON_V6_vsub_hf_128B", + "llvm.hexagon.V6.vsub.hf.hf" => "__builtin_HEXAGON_V6_vsub_hf_hf", + "llvm.hexagon.V6.vsub.hf.hf.128B" => "__builtin_HEXAGON_V6_vsub_hf_hf_128B", + "llvm.hexagon.V6.vsub.qf16" => "__builtin_HEXAGON_V6_vsub_qf16", + "llvm.hexagon.V6.vsub.qf16.128B" => "__builtin_HEXAGON_V6_vsub_qf16_128B", + "llvm.hexagon.V6.vsub.qf16.mix" => "__builtin_HEXAGON_V6_vsub_qf16_mix", + "llvm.hexagon.V6.vsub.qf16.mix.128B" => "__builtin_HEXAGON_V6_vsub_qf16_mix_128B", + "llvm.hexagon.V6.vsub.qf32" => "__builtin_HEXAGON_V6_vsub_qf32", + "llvm.hexagon.V6.vsub.qf32.128B" => "__builtin_HEXAGON_V6_vsub_qf32_128B", + "llvm.hexagon.V6.vsub.qf32.mix" => "__builtin_HEXAGON_V6_vsub_qf32_mix", + "llvm.hexagon.V6.vsub.qf32.mix.128B" => "__builtin_HEXAGON_V6_vsub_qf32_mix_128B", + "llvm.hexagon.V6.vsub.sf" => "__builtin_HEXAGON_V6_vsub_sf", + "llvm.hexagon.V6.vsub.sf.128B" => "__builtin_HEXAGON_V6_vsub_sf_128B", + "llvm.hexagon.V6.vsub.sf.bf" => "__builtin_HEXAGON_V6_vsub_sf_bf", + "llvm.hexagon.V6.vsub.sf.bf.128B" => "__builtin_HEXAGON_V6_vsub_sf_bf_128B", + "llvm.hexagon.V6.vsub.sf.hf" => "__builtin_HEXAGON_V6_vsub_sf_hf", + "llvm.hexagon.V6.vsub.sf.hf.128B" => "__builtin_HEXAGON_V6_vsub_sf_hf_128B", + "llvm.hexagon.V6.vsub.sf.sf" => "__builtin_HEXAGON_V6_vsub_sf_sf", + "llvm.hexagon.V6.vsub.sf.sf.128B" => "__builtin_HEXAGON_V6_vsub_sf_sf_128B", "llvm.hexagon.V6.vsubb" => "__builtin_HEXAGON_V6_vsubb", "llvm.hexagon.V6.vsubb.128B" => "__builtin_HEXAGON_V6_vsubb_128B", "llvm.hexagon.V6.vsubb.dv" => "__builtin_HEXAGON_V6_vsubb_dv", "llvm.hexagon.V6.vsubb.dv.128B" => "__builtin_HEXAGON_V6_vsubb_dv_128B", + "llvm.hexagon.V6.vsubbnq" => "__builtin_HEXAGON_V6_vsubbnq", + "llvm.hexagon.V6.vsubbnq.128B" => "__builtin_HEXAGON_V6_vsubbnq_128B", + "llvm.hexagon.V6.vsubbq" => "__builtin_HEXAGON_V6_vsubbq", + "llvm.hexagon.V6.vsubbq.128B" => "__builtin_HEXAGON_V6_vsubbq_128B", + "llvm.hexagon.V6.vsubbsat" => "__builtin_HEXAGON_V6_vsubbsat", + "llvm.hexagon.V6.vsubbsat.128B" => "__builtin_HEXAGON_V6_vsubbsat_128B", + "llvm.hexagon.V6.vsubbsat.dv" => "__builtin_HEXAGON_V6_vsubbsat_dv", + "llvm.hexagon.V6.vsubbsat.dv.128B" => "__builtin_HEXAGON_V6_vsubbsat_dv_128B", "llvm.hexagon.V6.vsubh" => "__builtin_HEXAGON_V6_vsubh", "llvm.hexagon.V6.vsubh.128B" => "__builtin_HEXAGON_V6_vsubh_128B", "llvm.hexagon.V6.vsubh.dv" => "__builtin_HEXAGON_V6_vsubh_dv", "llvm.hexagon.V6.vsubh.dv.128B" => "__builtin_HEXAGON_V6_vsubh_dv_128B", + "llvm.hexagon.V6.vsubhnq" => "__builtin_HEXAGON_V6_vsubhnq", + "llvm.hexagon.V6.vsubhnq.128B" => "__builtin_HEXAGON_V6_vsubhnq_128B", + "llvm.hexagon.V6.vsubhq" => "__builtin_HEXAGON_V6_vsubhq", + "llvm.hexagon.V6.vsubhq.128B" => "__builtin_HEXAGON_V6_vsubhq_128B", "llvm.hexagon.V6.vsubhsat" => "__builtin_HEXAGON_V6_vsubhsat", "llvm.hexagon.V6.vsubhsat.128B" => "__builtin_HEXAGON_V6_vsubhsat_128B", "llvm.hexagon.V6.vsubhsat.dv" => "__builtin_HEXAGON_V6_vsubhsat_dv", @@ -1558,20 +2159,32 @@ match name { "llvm.hexagon.V6.vsububsat.128B" => "__builtin_HEXAGON_V6_vsububsat_128B", "llvm.hexagon.V6.vsububsat.dv" => "__builtin_HEXAGON_V6_vsububsat_dv", "llvm.hexagon.V6.vsububsat.dv.128B" => "__builtin_HEXAGON_V6_vsububsat_dv_128B", + "llvm.hexagon.V6.vsubububb.sat" => "__builtin_HEXAGON_V6_vsubububb_sat", + "llvm.hexagon.V6.vsubububb.sat.128B" => "__builtin_HEXAGON_V6_vsubububb_sat_128B", "llvm.hexagon.V6.vsubuhsat" => "__builtin_HEXAGON_V6_vsubuhsat", "llvm.hexagon.V6.vsubuhsat.128B" => "__builtin_HEXAGON_V6_vsubuhsat_128B", "llvm.hexagon.V6.vsubuhsat.dv" => "__builtin_HEXAGON_V6_vsubuhsat_dv", "llvm.hexagon.V6.vsubuhsat.dv.128B" => "__builtin_HEXAGON_V6_vsubuhsat_dv_128B", "llvm.hexagon.V6.vsubuhw" => "__builtin_HEXAGON_V6_vsubuhw", "llvm.hexagon.V6.vsubuhw.128B" => "__builtin_HEXAGON_V6_vsubuhw_128B", + "llvm.hexagon.V6.vsubuwsat" => "__builtin_HEXAGON_V6_vsubuwsat", + "llvm.hexagon.V6.vsubuwsat.128B" => "__builtin_HEXAGON_V6_vsubuwsat_128B", + "llvm.hexagon.V6.vsubuwsat.dv" => "__builtin_HEXAGON_V6_vsubuwsat_dv", + "llvm.hexagon.V6.vsubuwsat.dv.128B" => "__builtin_HEXAGON_V6_vsubuwsat_dv_128B", "llvm.hexagon.V6.vsubw" => "__builtin_HEXAGON_V6_vsubw", "llvm.hexagon.V6.vsubw.128B" => "__builtin_HEXAGON_V6_vsubw_128B", "llvm.hexagon.V6.vsubw.dv" => "__builtin_HEXAGON_V6_vsubw_dv", "llvm.hexagon.V6.vsubw.dv.128B" => "__builtin_HEXAGON_V6_vsubw_dv_128B", + "llvm.hexagon.V6.vsubwnq" => "__builtin_HEXAGON_V6_vsubwnq", + "llvm.hexagon.V6.vsubwnq.128B" => "__builtin_HEXAGON_V6_vsubwnq_128B", + "llvm.hexagon.V6.vsubwq" => "__builtin_HEXAGON_V6_vsubwq", + "llvm.hexagon.V6.vsubwq.128B" => "__builtin_HEXAGON_V6_vsubwq_128B", "llvm.hexagon.V6.vsubwsat" => "__builtin_HEXAGON_V6_vsubwsat", "llvm.hexagon.V6.vsubwsat.128B" => "__builtin_HEXAGON_V6_vsubwsat_128B", "llvm.hexagon.V6.vsubwsat.dv" => "__builtin_HEXAGON_V6_vsubwsat_dv", "llvm.hexagon.V6.vsubwsat.dv.128B" => "__builtin_HEXAGON_V6_vsubwsat_dv_128B", + "llvm.hexagon.V6.vswap" => "__builtin_HEXAGON_V6_vswap", + "llvm.hexagon.V6.vswap.128B" => "__builtin_HEXAGON_V6_vswap_128B", "llvm.hexagon.V6.vtmpyb" => "__builtin_HEXAGON_V6_vtmpyb", "llvm.hexagon.V6.vtmpyb.128B" => "__builtin_HEXAGON_V6_vtmpyb_128B", "llvm.hexagon.V6.vtmpyb.acc" => "__builtin_HEXAGON_V6_vtmpyb_acc", @@ -1602,6 +2215,19 @@ match name { "llvm.hexagon.V6.vzb.128B" => "__builtin_HEXAGON_V6_vzb_128B", "llvm.hexagon.V6.vzh" => "__builtin_HEXAGON_V6_vzh", "llvm.hexagon.V6.vzh.128B" => "__builtin_HEXAGON_V6_vzh_128B", + "llvm.hexagon.Y2.dccleana" => "__builtin_HEXAGON_Y2_dccleana", + "llvm.hexagon.Y2.dccleaninva" => "__builtin_HEXAGON_Y2_dccleaninva", + "llvm.hexagon.Y2.dcfetch" => "__builtin_HEXAGON_Y2_dcfetch", + "llvm.hexagon.Y2.dcinva" => "__builtin_HEXAGON_Y2_dcinva", + "llvm.hexagon.Y2.dczeroa" => "__builtin_HEXAGON_Y2_dczeroa", + "llvm.hexagon.Y4.l2fetch" => "__builtin_HEXAGON_Y4_l2fetch", + "llvm.hexagon.Y5.l2fetch" => "__builtin_HEXAGON_Y5_l2fetch", + "llvm.hexagon.Y6.dmlink" => "__builtin_HEXAGON_Y6_dmlink", + "llvm.hexagon.Y6.dmpause" => "__builtin_HEXAGON_Y6_dmpause", + "llvm.hexagon.Y6.dmpoll" => "__builtin_HEXAGON_Y6_dmpoll", + "llvm.hexagon.Y6.dmresume" => "__builtin_HEXAGON_Y6_dmresume", + "llvm.hexagon.Y6.dmstart" => "__builtin_HEXAGON_Y6_dmstart", + "llvm.hexagon.Y6.dmwait" => "__builtin_HEXAGON_Y6_dmwait", "llvm.hexagon.brev.ldb" => "__builtin_brev_ldb", "llvm.hexagon.brev.ldd" => "__builtin_brev_ldd", "llvm.hexagon.brev.ldh" => "__builtin_brev_ldh", @@ -1626,6 +2252,8 @@ match name { "llvm.hexagon.circ.stw" => "__builtin_circ_stw", "llvm.hexagon.mm256i.vaddw" => "__builtin__mm256i_vaddw", "llvm.hexagon.prefetch" => "__builtin_HEXAGON_prefetch", + "llvm.hexagon.vmemcpy" => "__builtin_hexagon_vmemcpy", + "llvm.hexagon.vmemset" => "__builtin_hexagon_vmemset", // mips "llvm.mips.absq.s.ph" => "__builtin_mips_absq_s_ph", "llvm.mips.absq.s.qb" => "__builtin_mips_absq_s_qb", @@ -2299,6 +2927,8 @@ match name { "llvm.mips.xor.v" => "__builtin_msa_xor_v", "llvm.mips.xori.b" => "__builtin_msa_xori_b", // nvvm + "llvm.nvvm.abs.bf16" => "__nvvm_abs_bf16", + "llvm.nvvm.abs.bf16x2" => "__nvvm_abs_bf16x2", "llvm.nvvm.abs.i" => "__nvvm_abs_i", "llvm.nvvm.abs.ll" => "__nvvm_abs_ll", "llvm.nvvm.add.rm.d" => "__nvvm_add_rm_d", @@ -2314,8 +2944,13 @@ match name { "llvm.nvvm.add.rz.f" => "__nvvm_add_rz_f", "llvm.nvvm.add.rz.ftz.f" => "__nvvm_add_rz_ftz_f", "llvm.nvvm.bar.sync" => "__nvvm_bar_sync", - "llvm.nvvm.barrier0" => "__nvvm_bar0", - // [DUPLICATE]: "llvm.nvvm.barrier0" => "__syncthreads", + "llvm.nvvm.bar.warp.sync" => "__nvvm_bar_warp_sync", + "llvm.nvvm.barrier" => "__nvvm_bar", + "llvm.nvvm.barrier.n" => "__nvvm_bar_n", + "llvm.nvvm.barrier.sync" => "__nvvm_barrier_sync", + "llvm.nvvm.barrier.sync.cnt" => "__nvvm_barrier_sync_cnt", + "llvm.nvvm.barrier0" => "__syncthreads", + // [DUPLICATE]: "llvm.nvvm.barrier0" => "__nvvm_bar0", "llvm.nvvm.barrier0.and" => "__nvvm_bar0_and", "llvm.nvvm.barrier0.or" => "__nvvm_bar0_or", "llvm.nvvm.barrier0.popc" => "__nvvm_bar0_popc", @@ -2332,6 +2967,17 @@ match name { "llvm.nvvm.clz.ll" => "__nvvm_clz_ll", "llvm.nvvm.cos.approx.f" => "__nvvm_cos_approx_f", "llvm.nvvm.cos.approx.ftz.f" => "__nvvm_cos_approx_ftz_f", + "llvm.nvvm.cp.async.ca.shared.global.16" => "__nvvm_cp_async_ca_shared_global_16", + "llvm.nvvm.cp.async.ca.shared.global.4" => "__nvvm_cp_async_ca_shared_global_4", + "llvm.nvvm.cp.async.ca.shared.global.8" => "__nvvm_cp_async_ca_shared_global_8", + "llvm.nvvm.cp.async.cg.shared.global.16" => "__nvvm_cp_async_cg_shared_global_16", + "llvm.nvvm.cp.async.commit.group" => "__nvvm_cp_async_commit_group", + "llvm.nvvm.cp.async.mbarrier.arrive" => "__nvvm_cp_async_mbarrier_arrive", + "llvm.nvvm.cp.async.mbarrier.arrive.noinc" => "__nvvm_cp_async_mbarrier_arrive_noinc", + "llvm.nvvm.cp.async.mbarrier.arrive.noinc.shared" => "__nvvm_cp_async_mbarrier_arrive_noinc_shared", + "llvm.nvvm.cp.async.mbarrier.arrive.shared" => "__nvvm_cp_async_mbarrier_arrive_shared", + "llvm.nvvm.cp.async.wait.all" => "__nvvm_cp_async_wait_all", + "llvm.nvvm.cp.async.wait.group" => "__nvvm_cp_async_wait_group", "llvm.nvvm.d2f.rm" => "__nvvm_d2f_rm", "llvm.nvvm.d2f.rm.ftz" => "__nvvm_d2f_rm_ftz", "llvm.nvvm.d2f.rn" => "__nvvm_d2f_rn", @@ -2374,7 +3020,13 @@ match name { "llvm.nvvm.div.rz.ftz.f" => "__nvvm_div_rz_ftz_f", "llvm.nvvm.ex2.approx.d" => "__nvvm_ex2_approx_d", "llvm.nvvm.ex2.approx.f" => "__nvvm_ex2_approx_f", + "llvm.nvvm.ex2.approx.f16" => "__nvvm_ex2_approx_f16", + "llvm.nvvm.ex2.approx.f16x2" => "__nvvm_ex2_approx_f16x2", "llvm.nvvm.ex2.approx.ftz.f" => "__nvvm_ex2_approx_ftz_f", + "llvm.nvvm.f2bf16.rn" => "__nvvm_f2bf16_rn", + "llvm.nvvm.f2bf16.rn.relu" => "__nvvm_f2bf16_rn_relu", + "llvm.nvvm.f2bf16.rz" => "__nvvm_f2bf16_rz", + "llvm.nvvm.f2bf16.rz.relu" => "__nvvm_f2bf16_rz_relu", "llvm.nvvm.f2h.rn" => "__nvvm_f2h_rn", "llvm.nvvm.f2h.rn.ftz" => "__nvvm_f2h_rn_ftz", "llvm.nvvm.f2i.rm" => "__nvvm_f2i_rm", @@ -2393,6 +3045,7 @@ match name { "llvm.nvvm.f2ll.rp.ftz" => "__nvvm_f2ll_rp_ftz", "llvm.nvvm.f2ll.rz" => "__nvvm_f2ll_rz", "llvm.nvvm.f2ll.rz.ftz" => "__nvvm_f2ll_rz_ftz", + "llvm.nvvm.f2tf32.rna" => "__nvvm_f2tf32_rna", "llvm.nvvm.f2ui.rm" => "__nvvm_f2ui_rm", "llvm.nvvm.f2ui.rm.ftz" => "__nvvm_f2ui_rm_ftz", "llvm.nvvm.f2ui.rn" => "__nvvm_f2ui_rn", @@ -2412,27 +3065,112 @@ match name { "llvm.nvvm.fabs.d" => "__nvvm_fabs_d", "llvm.nvvm.fabs.f" => "__nvvm_fabs_f", "llvm.nvvm.fabs.ftz.f" => "__nvvm_fabs_ftz_f", + "llvm.nvvm.ff2bf16x2.rn" => "__nvvm_ff2bf16x2_rn", + "llvm.nvvm.ff2bf16x2.rn.relu" => "__nvvm_ff2bf16x2_rn_relu", + "llvm.nvvm.ff2bf16x2.rz" => "__nvvm_ff2bf16x2_rz", + "llvm.nvvm.ff2bf16x2.rz.relu" => "__nvvm_ff2bf16x2_rz_relu", + "llvm.nvvm.ff2f16x2.rn" => "__nvvm_ff2f16x2_rn", + "llvm.nvvm.ff2f16x2.rn.relu" => "__nvvm_ff2f16x2_rn_relu", + "llvm.nvvm.ff2f16x2.rz" => "__nvvm_ff2f16x2_rz", + "llvm.nvvm.ff2f16x2.rz.relu" => "__nvvm_ff2f16x2_rz_relu", "llvm.nvvm.floor.d" => "__nvvm_floor_d", "llvm.nvvm.floor.f" => "__nvvm_floor_f", "llvm.nvvm.floor.ftz.f" => "__nvvm_floor_ftz_f", "llvm.nvvm.fma.rm.d" => "__nvvm_fma_rm_d", "llvm.nvvm.fma.rm.f" => "__nvvm_fma_rm_f", "llvm.nvvm.fma.rm.ftz.f" => "__nvvm_fma_rm_ftz_f", + "llvm.nvvm.fma.rn.bf16" => "__nvvm_fma_rn_bf16", + "llvm.nvvm.fma.rn.bf16x2" => "__nvvm_fma_rn_bf16x2", "llvm.nvvm.fma.rn.d" => "__nvvm_fma_rn_d", "llvm.nvvm.fma.rn.f" => "__nvvm_fma_rn_f", + "llvm.nvvm.fma.rn.f16" => "__nvvm_fma_rn_f16", + "llvm.nvvm.fma.rn.f16x2" => "__nvvm_fma_rn_f16x2", "llvm.nvvm.fma.rn.ftz.f" => "__nvvm_fma_rn_ftz_f", + "llvm.nvvm.fma.rn.ftz.f16" => "__nvvm_fma_rn_ftz_f16", + "llvm.nvvm.fma.rn.ftz.f16x2" => "__nvvm_fma_rn_ftz_f16x2", + "llvm.nvvm.fma.rn.ftz.relu.f16" => "__nvvm_fma_rn_ftz_relu_f16", + "llvm.nvvm.fma.rn.ftz.relu.f16x2" => "__nvvm_fma_rn_ftz_relu_f16x2", + "llvm.nvvm.fma.rn.ftz.sat.f16" => "__nvvm_fma_rn_ftz_sat_f16", + "llvm.nvvm.fma.rn.ftz.sat.f16x2" => "__nvvm_fma_rn_ftz_sat_f16x2", + "llvm.nvvm.fma.rn.relu.bf16" => "__nvvm_fma_rn_relu_bf16", + "llvm.nvvm.fma.rn.relu.bf16x2" => "__nvvm_fma_rn_relu_bf16x2", + "llvm.nvvm.fma.rn.relu.f16" => "__nvvm_fma_rn_relu_f16", + "llvm.nvvm.fma.rn.relu.f16x2" => "__nvvm_fma_rn_relu_f16x2", + "llvm.nvvm.fma.rn.sat.f16" => "__nvvm_fma_rn_sat_f16", + "llvm.nvvm.fma.rn.sat.f16x2" => "__nvvm_fma_rn_sat_f16x2", "llvm.nvvm.fma.rp.d" => "__nvvm_fma_rp_d", "llvm.nvvm.fma.rp.f" => "__nvvm_fma_rp_f", "llvm.nvvm.fma.rp.ftz.f" => "__nvvm_fma_rp_ftz_f", "llvm.nvvm.fma.rz.d" => "__nvvm_fma_rz_d", "llvm.nvvm.fma.rz.f" => "__nvvm_fma_rz_f", "llvm.nvvm.fma.rz.ftz.f" => "__nvvm_fma_rz_ftz_f", + "llvm.nvvm.fmax.bf16" => "__nvvm_fmax_bf16", + "llvm.nvvm.fmax.bf16x2" => "__nvvm_fmax_bf16x2", "llvm.nvvm.fmax.d" => "__nvvm_fmax_d", "llvm.nvvm.fmax.f" => "__nvvm_fmax_f", + "llvm.nvvm.fmax.f16" => "__nvvm_fmax_f16", + "llvm.nvvm.fmax.f16x2" => "__nvvm_fmax_f16x2", "llvm.nvvm.fmax.ftz.f" => "__nvvm_fmax_ftz_f", + "llvm.nvvm.fmax.ftz.f16" => "__nvvm_fmax_ftz_f16", + "llvm.nvvm.fmax.ftz.f16x2" => "__nvvm_fmax_ftz_f16x2", + "llvm.nvvm.fmax.ftz.nan.f" => "__nvvm_fmax_ftz_nan_f", + "llvm.nvvm.fmax.ftz.nan.f16" => "__nvvm_fmax_ftz_nan_f16", + "llvm.nvvm.fmax.ftz.nan.f16x2" => "__nvvm_fmax_ftz_nan_f16x2", + "llvm.nvvm.fmax.ftz.nan.xorsign.abs.f" => "__nvvm_fmax_ftz_nan_xorsign_abs_f", + "llvm.nvvm.fmax.ftz.nan.xorsign.abs.f16" => "__nvvm_fmax_ftz_nan_xorsign_abs_f16", + "llvm.nvvm.fmax.ftz.nan.xorsign.abs.f16x2" => "__nvvm_fmax_ftz_nan_xorsign_abs_f16x2", + "llvm.nvvm.fmax.ftz.xorsign.abs.f" => "__nvvm_fmax_ftz_xorsign_abs_f", + "llvm.nvvm.fmax.ftz.xorsign.abs.f16" => "__nvvm_fmax_ftz_xorsign_abs_f16", + "llvm.nvvm.fmax.ftz.xorsign.abs.f16x2" => "__nvvm_fmax_ftz_xorsign_abs_f16x2", + "llvm.nvvm.fmax.nan.bf16" => "__nvvm_fmax_nan_bf16", + "llvm.nvvm.fmax.nan.bf16x2" => "__nvvm_fmax_nan_bf16x2", + "llvm.nvvm.fmax.nan.f" => "__nvvm_fmax_nan_f", + "llvm.nvvm.fmax.nan.f16" => "__nvvm_fmax_nan_f16", + "llvm.nvvm.fmax.nan.f16x2" => "__nvvm_fmax_nan_f16x2", + "llvm.nvvm.fmax.nan.xorsign.abs.bf16" => "__nvvm_fmax_nan_xorsign_abs_bf16", + "llvm.nvvm.fmax.nan.xorsign.abs.bf16x2" => "__nvvm_fmax_nan_xorsign_abs_bf16x2", + "llvm.nvvm.fmax.nan.xorsign.abs.f" => "__nvvm_fmax_nan_xorsign_abs_f", + "llvm.nvvm.fmax.nan.xorsign.abs.f16" => "__nvvm_fmax_nan_xorsign_abs_f16", + "llvm.nvvm.fmax.nan.xorsign.abs.f16x2" => "__nvvm_fmax_nan_xorsign_abs_f16x2", + "llvm.nvvm.fmax.xorsign.abs.bf16" => "__nvvm_fmax_xorsign_abs_bf16", + "llvm.nvvm.fmax.xorsign.abs.bf16x2" => "__nvvm_fmax_xorsign_abs_bf16x2", + "llvm.nvvm.fmax.xorsign.abs.f" => "__nvvm_fmax_xorsign_abs_f", + "llvm.nvvm.fmax.xorsign.abs.f16" => "__nvvm_fmax_xorsign_abs_f16", + "llvm.nvvm.fmax.xorsign.abs.f16x2" => "__nvvm_fmax_xorsign_abs_f16x2", + "llvm.nvvm.fmin.bf16" => "__nvvm_fmin_bf16", + "llvm.nvvm.fmin.bf16x2" => "__nvvm_fmin_bf16x2", "llvm.nvvm.fmin.d" => "__nvvm_fmin_d", "llvm.nvvm.fmin.f" => "__nvvm_fmin_f", + "llvm.nvvm.fmin.f16" => "__nvvm_fmin_f16", + "llvm.nvvm.fmin.f16x2" => "__nvvm_fmin_f16x2", "llvm.nvvm.fmin.ftz.f" => "__nvvm_fmin_ftz_f", + "llvm.nvvm.fmin.ftz.f16" => "__nvvm_fmin_ftz_f16", + "llvm.nvvm.fmin.ftz.f16x2" => "__nvvm_fmin_ftz_f16x2", + "llvm.nvvm.fmin.ftz.nan.f" => "__nvvm_fmin_ftz_nan_f", + "llvm.nvvm.fmin.ftz.nan.f16" => "__nvvm_fmin_ftz_nan_f16", + "llvm.nvvm.fmin.ftz.nan.f16x2" => "__nvvm_fmin_ftz_nan_f16x2", + "llvm.nvvm.fmin.ftz.nan.xorsign.abs.f" => "__nvvm_fmin_ftz_nan_xorsign_abs_f", + "llvm.nvvm.fmin.ftz.nan.xorsign.abs.f16" => "__nvvm_fmin_ftz_nan_xorsign_abs_f16", + "llvm.nvvm.fmin.ftz.nan.xorsign.abs.f16x2" => "__nvvm_fmin_ftz_nan_xorsign_abs_f16x2", + "llvm.nvvm.fmin.ftz.xorsign.abs.f" => "__nvvm_fmin_ftz_xorsign_abs_f", + "llvm.nvvm.fmin.ftz.xorsign.abs.f16" => "__nvvm_fmin_ftz_xorsign_abs_f16", + "llvm.nvvm.fmin.ftz.xorsign.abs.f16x2" => "__nvvm_fmin_ftz_xorsign_abs_f16x2", + "llvm.nvvm.fmin.nan.bf16" => "__nvvm_fmin_nan_bf16", + "llvm.nvvm.fmin.nan.bf16x2" => "__nvvm_fmin_nan_bf16x2", + "llvm.nvvm.fmin.nan.f" => "__nvvm_fmin_nan_f", + "llvm.nvvm.fmin.nan.f16" => "__nvvm_fmin_nan_f16", + "llvm.nvvm.fmin.nan.f16x2" => "__nvvm_fmin_nan_f16x2", + "llvm.nvvm.fmin.nan.xorsign.abs.bf16" => "__nvvm_fmin_nan_xorsign_abs_bf16", + "llvm.nvvm.fmin.nan.xorsign.abs.bf16x2" => "__nvvm_fmin_nan_xorsign_abs_bf16x2", + "llvm.nvvm.fmin.nan.xorsign.abs.f" => "__nvvm_fmin_nan_xorsign_abs_f", + "llvm.nvvm.fmin.nan.xorsign.abs.f16" => "__nvvm_fmin_nan_xorsign_abs_f16", + "llvm.nvvm.fmin.nan.xorsign.abs.f16x2" => "__nvvm_fmin_nan_xorsign_abs_f16x2", + "llvm.nvvm.fmin.xorsign.abs.bf16" => "__nvvm_fmin_xorsign_abs_bf16", + "llvm.nvvm.fmin.xorsign.abs.bf16x2" => "__nvvm_fmin_xorsign_abs_bf16x2", + "llvm.nvvm.fmin.xorsign.abs.f" => "__nvvm_fmin_xorsign_abs_f", + "llvm.nvvm.fmin.xorsign.abs.f16" => "__nvvm_fmin_xorsign_abs_f16", + "llvm.nvvm.fmin.xorsign.abs.f16x2" => "__nvvm_fmin_xorsign_abs_f16x2", + "llvm.nvvm.fns" => "__nvvm_fns", "llvm.nvvm.h2f" => "__nvvm_h2f", "llvm.nvvm.i2d.rm" => "__nvvm_i2d_rm", "llvm.nvvm.i2d.rn" => "__nvvm_i2d_rn", @@ -2461,10 +3199,27 @@ match name { "llvm.nvvm.ll2f.rp" => "__nvvm_ll2f_rp", "llvm.nvvm.ll2f.rz" => "__nvvm_ll2f_rz", "llvm.nvvm.lohi.i2d" => "__nvvm_lohi_i2d", + "llvm.nvvm.match.any.sync.i32" => "__nvvm_match_any_sync_i32", + "llvm.nvvm.match.any.sync.i64" => "__nvvm_match_any_sync_i64", "llvm.nvvm.max.i" => "__nvvm_max_i", "llvm.nvvm.max.ll" => "__nvvm_max_ll", "llvm.nvvm.max.ui" => "__nvvm_max_ui", "llvm.nvvm.max.ull" => "__nvvm_max_ull", + "llvm.nvvm.mbarrier.arrive" => "__nvvm_mbarrier_arrive", + "llvm.nvvm.mbarrier.arrive.drop" => "__nvvm_mbarrier_arrive_drop", + "llvm.nvvm.mbarrier.arrive.drop.noComplete" => "__nvvm_mbarrier_arrive_drop_noComplete", + "llvm.nvvm.mbarrier.arrive.drop.noComplete.shared" => "__nvvm_mbarrier_arrive_drop_noComplete_shared", + "llvm.nvvm.mbarrier.arrive.drop.shared" => "__nvvm_mbarrier_arrive_drop_shared", + "llvm.nvvm.mbarrier.arrive.noComplete" => "__nvvm_mbarrier_arrive_noComplete", + "llvm.nvvm.mbarrier.arrive.noComplete.shared" => "__nvvm_mbarrier_arrive_noComplete_shared", + "llvm.nvvm.mbarrier.arrive.shared" => "__nvvm_mbarrier_arrive_shared", + "llvm.nvvm.mbarrier.init" => "__nvvm_mbarrier_init", + "llvm.nvvm.mbarrier.init.shared" => "__nvvm_mbarrier_init_shared", + "llvm.nvvm.mbarrier.inval" => "__nvvm_mbarrier_inval", + "llvm.nvvm.mbarrier.inval.shared" => "__nvvm_mbarrier_inval_shared", + "llvm.nvvm.mbarrier.pending.count" => "__nvvm_mbarrier_pending_count", + "llvm.nvvm.mbarrier.test.wait" => "__nvvm_mbarrier_test_wait", + "llvm.nvvm.mbarrier.test.wait.shared" => "__nvvm_mbarrier_test_wait_shared", "llvm.nvvm.membar.cta" => "__nvvm_membar_cta", "llvm.nvvm.membar.gl" => "__nvvm_membar_gl", "llvm.nvvm.membar.sys" => "__nvvm_membar_sys", @@ -2490,10 +3245,13 @@ match name { "llvm.nvvm.mulhi.ll" => "__nvvm_mulhi_ll", "llvm.nvvm.mulhi.ui" => "__nvvm_mulhi_ui", "llvm.nvvm.mulhi.ull" => "__nvvm_mulhi_ull", + "llvm.nvvm.neg.bf16" => "__nvvm_neg_bf16", + "llvm.nvvm.neg.bf16x2" => "__nvvm_neg_bf16x2", "llvm.nvvm.popc.i" => "__nvvm_popc_i", "llvm.nvvm.popc.ll" => "__nvvm_popc_ll", "llvm.nvvm.prmt" => "__nvvm_prmt", "llvm.nvvm.rcp.approx.ftz.d" => "__nvvm_rcp_approx_ftz_d", + "llvm.nvvm.rcp.approx.ftz.f" => "__nvvm_rcp_approx_ftz_f", "llvm.nvvm.rcp.rm.d" => "__nvvm_rcp_rm_d", "llvm.nvvm.rcp.rm.f" => "__nvvm_rcp_rm_f", "llvm.nvvm.rcp.rm.ftz.f" => "__nvvm_rcp_rm_ftz_f", @@ -2506,8 +3264,11 @@ match name { "llvm.nvvm.rcp.rz.d" => "__nvvm_rcp_rz_d", "llvm.nvvm.rcp.rz.f" => "__nvvm_rcp_rz_f", "llvm.nvvm.rcp.rz.ftz.f" => "__nvvm_rcp_rz_ftz_f", - "llvm.nvvm.read.ptx.sreg.clock" => "__nvvm_read_ptx_sreg_", - "llvm.nvvm.read.ptx.sreg.clock64" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.clock" => "__nvvm_read_ptx_sreg_clock", + // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.clock" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.clock64" => "__nvvm_read_ptx_sreg_clock64", + // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.clock64" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.ctaid.w" => "__nvvm_read_ptx_sreg_ctaid_w", "llvm.nvvm.read.ptx.sreg.ctaid.x" => "__nvvm_read_ptx_sreg_ctaid_x", "llvm.nvvm.read.ptx.sreg.ctaid.y" => "__nvvm_read_ptx_sreg_ctaid_y", "llvm.nvvm.read.ptx.sreg.ctaid.z" => "__nvvm_read_ptx_sreg_ctaid_z", @@ -2543,32 +3304,58 @@ match name { "llvm.nvvm.read.ptx.sreg.envreg7" => "__nvvm_read_ptx_sreg_envreg7", "llvm.nvvm.read.ptx.sreg.envreg8" => "__nvvm_read_ptx_sreg_envreg8", "llvm.nvvm.read.ptx.sreg.envreg9" => "__nvvm_read_ptx_sreg_envreg9", - "llvm.nvvm.read.ptx.sreg.gridid" => "__nvvm_read_ptx_sreg_", - "llvm.nvvm.read.ptx.sreg.laneid" => "__nvvm_read_ptx_sreg_", - "llvm.nvvm.read.ptx.sreg.lanemask.eq" => "__nvvm_read_ptx_sreg_", - "llvm.nvvm.read.ptx.sreg.lanemask.ge" => "__nvvm_read_ptx_sreg_", - "llvm.nvvm.read.ptx.sreg.lanemask.gt" => "__nvvm_read_ptx_sreg_", - "llvm.nvvm.read.ptx.sreg.lanemask.le" => "__nvvm_read_ptx_sreg_", - "llvm.nvvm.read.ptx.sreg.lanemask.lt" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.gridid" => "__nvvm_read_ptx_sreg_gridid", + // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.gridid" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.laneid" => "__nvvm_read_ptx_sreg_laneid", + // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.laneid" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.lanemask.eq" => "__nvvm_read_ptx_sreg_lanemask_eq", + // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.lanemask.eq" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.lanemask.ge" => "__nvvm_read_ptx_sreg_lanemask_ge", + // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.lanemask.ge" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.lanemask.gt" => "__nvvm_read_ptx_sreg_lanemask_gt", + // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.lanemask.gt" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.lanemask.le" => "__nvvm_read_ptx_sreg_lanemask_le", + // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.lanemask.le" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.lanemask.lt" => "__nvvm_read_ptx_sreg_lanemask_lt", + // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.lanemask.lt" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.nctaid.w" => "__nvvm_read_ptx_sreg_nctaid_w", "llvm.nvvm.read.ptx.sreg.nctaid.x" => "__nvvm_read_ptx_sreg_nctaid_x", "llvm.nvvm.read.ptx.sreg.nctaid.y" => "__nvvm_read_ptx_sreg_nctaid_y", "llvm.nvvm.read.ptx.sreg.nctaid.z" => "__nvvm_read_ptx_sreg_nctaid_z", - "llvm.nvvm.read.ptx.sreg.nsmid" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.nsmid" => "__nvvm_read_ptx_sreg_nsmid", + // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.nsmid" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.ntid.w" => "__nvvm_read_ptx_sreg_ntid_w", "llvm.nvvm.read.ptx.sreg.ntid.x" => "__nvvm_read_ptx_sreg_ntid_x", "llvm.nvvm.read.ptx.sreg.ntid.y" => "__nvvm_read_ptx_sreg_ntid_y", "llvm.nvvm.read.ptx.sreg.ntid.z" => "__nvvm_read_ptx_sreg_ntid_z", - "llvm.nvvm.read.ptx.sreg.nwarpid" => "__nvvm_read_ptx_sreg_", - "llvm.nvvm.read.ptx.sreg.pm0" => "__nvvm_read_ptx_sreg_", - "llvm.nvvm.read.ptx.sreg.pm1" => "__nvvm_read_ptx_sreg_", - "llvm.nvvm.read.ptx.sreg.pm2" => "__nvvm_read_ptx_sreg_", - "llvm.nvvm.read.ptx.sreg.pm3" => "__nvvm_read_ptx_sreg_", - "llvm.nvvm.read.ptx.sreg.smid" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.nwarpid" => "__nvvm_read_ptx_sreg_nwarpid", + // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.nwarpid" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.pm0" => "__nvvm_read_ptx_sreg_pm0", + // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.pm0" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.pm1" => "__nvvm_read_ptx_sreg_pm1", + // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.pm1" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.pm2" => "__nvvm_read_ptx_sreg_pm2", + // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.pm2" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.pm3" => "__nvvm_read_ptx_sreg_pm3", + // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.pm3" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.smid" => "__nvvm_read_ptx_sreg_smid", + // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.smid" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.tid.w" => "__nvvm_read_ptx_sreg_tid_w", "llvm.nvvm.read.ptx.sreg.tid.x" => "__nvvm_read_ptx_sreg_tid_x", "llvm.nvvm.read.ptx.sreg.tid.y" => "__nvvm_read_ptx_sreg_tid_y", "llvm.nvvm.read.ptx.sreg.tid.z" => "__nvvm_read_ptx_sreg_tid_z", - "llvm.nvvm.read.ptx.sreg.warpid" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.read.ptx.sreg.warpid" => "__nvvm_read_ptx_sreg_warpid", + // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.warpid" => "__nvvm_read_ptx_sreg_", "llvm.nvvm.read.ptx.sreg.warpsize" => "__nvvm_read_ptx_sreg_warpsize", // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.warpsize" => "__nvvm_read_ptx_sreg_", + "llvm.nvvm.redux.sync.add" => "__nvvm_redux_sync_add", + "llvm.nvvm.redux.sync.and" => "__nvvm_redux_sync_and", + "llvm.nvvm.redux.sync.max" => "__nvvm_redux_sync_max", + "llvm.nvvm.redux.sync.min" => "__nvvm_redux_sync_min", + "llvm.nvvm.redux.sync.or" => "__nvvm_redux_sync_or", + "llvm.nvvm.redux.sync.umax" => "__nvvm_redux_sync_umax", + "llvm.nvvm.redux.sync.umin" => "__nvvm_redux_sync_umin", + "llvm.nvvm.redux.sync.xor" => "__nvvm_redux_sync_xor", "llvm.nvvm.rotate.b32" => "__nvvm_rotate_b32", "llvm.nvvm.rotate.b64" => "__nvvm_rotate_b64", "llvm.nvvm.rotate.right.b64" => "__nvvm_rotate_right_b64", @@ -2589,6 +3376,14 @@ match name { "llvm.nvvm.shfl.down.i32" => "__nvvm_shfl_down_i32", "llvm.nvvm.shfl.idx.f32" => "__nvvm_shfl_idx_f32", "llvm.nvvm.shfl.idx.i32" => "__nvvm_shfl_idx_i32", + "llvm.nvvm.shfl.sync.bfly.f32" => "__nvvm_shfl_sync_bfly_f32", + "llvm.nvvm.shfl.sync.bfly.i32" => "__nvvm_shfl_sync_bfly_i32", + "llvm.nvvm.shfl.sync.down.f32" => "__nvvm_shfl_sync_down_f32", + "llvm.nvvm.shfl.sync.down.i32" => "__nvvm_shfl_sync_down_i32", + "llvm.nvvm.shfl.sync.idx.f32" => "__nvvm_shfl_sync_idx_f32", + "llvm.nvvm.shfl.sync.idx.i32" => "__nvvm_shfl_sync_idx_i32", + "llvm.nvvm.shfl.sync.up.f32" => "__nvvm_shfl_sync_up_f32", + "llvm.nvvm.shfl.sync.up.i32" => "__nvvm_shfl_sync_up_i32", "llvm.nvvm.shfl.up.f32" => "__nvvm_shfl_up_f32", "llvm.nvvm.shfl.up.i32" => "__nvvm_shfl_up_i32", "llvm.nvvm.sin.approx.f" => "__nvvm_sin_approx_f", @@ -2852,6 +3647,14 @@ match name { "llvm.nvvm.ull2f.rn" => "__nvvm_ull2f_rn", "llvm.nvvm.ull2f.rp" => "__nvvm_ull2f_rp", "llvm.nvvm.ull2f.rz" => "__nvvm_ull2f_rz", + "llvm.nvvm.vote.all" => "__nvvm_vote_all", + "llvm.nvvm.vote.all.sync" => "__nvvm_vote_all_sync", + "llvm.nvvm.vote.any" => "__nvvm_vote_any", + "llvm.nvvm.vote.any.sync" => "__nvvm_vote_any_sync", + "llvm.nvvm.vote.ballot" => "__nvvm_vote_ballot", + "llvm.nvvm.vote.ballot.sync" => "__nvvm_vote_ballot_sync", + "llvm.nvvm.vote.uni" => "__nvvm_vote_uni", + "llvm.nvvm.vote.uni.sync" => "__nvvm_vote_uni_sync", // ppc "llvm.ppc.addex" => "__builtin_ppc_addex", "llvm.ppc.addf128.round.to.odd" => "__builtin_addf128_round_to_odd", @@ -2881,6 +3684,10 @@ match name { "llvm.ppc.altivec.mtvsrhm" => "__builtin_altivec_mtvsrhm", "llvm.ppc.altivec.mtvsrqm" => "__builtin_altivec_mtvsrqm", "llvm.ppc.altivec.mtvsrwm" => "__builtin_altivec_mtvsrwm", + "llvm.ppc.altivec.vabsdub" => "__builtin_altivec_vabsdub", + "llvm.ppc.altivec.vabsduh" => "__builtin_altivec_vabsduh", + "llvm.ppc.altivec.vabsduw" => "__builtin_altivec_vabsduw", + "llvm.ppc.altivec.vaddcuq" => "__builtin_altivec_vaddcuq", "llvm.ppc.altivec.vaddcuw" => "__builtin_altivec_vaddcuw", "llvm.ppc.altivec.vaddecuq" => "__builtin_altivec_vaddecuq", "llvm.ppc.altivec.vaddeuqm" => "__builtin_altivec_vaddeuqm", @@ -2963,6 +3770,12 @@ match name { "llvm.ppc.altivec.vctuxs" => "__builtin_altivec_vctuxs", "llvm.ppc.altivec.vctzdm" => "__builtin_altivec_vctzdm", "llvm.ppc.altivec.vctzlsbb" => "__builtin_altivec_vctzlsbb", + "llvm.ppc.altivec.vdivesd" => "__builtin_altivec_vdivesd", + "llvm.ppc.altivec.vdivesq" => "__builtin_altivec_vdivesq", + "llvm.ppc.altivec.vdivesw" => "__builtin_altivec_vdivesw", + "llvm.ppc.altivec.vdiveud" => "__builtin_altivec_vdiveud", + "llvm.ppc.altivec.vdiveuq" => "__builtin_altivec_vdiveuq", + "llvm.ppc.altivec.vdiveuw" => "__builtin_altivec_vdiveuw", "llvm.ppc.altivec.vexpandbm" => "__builtin_altivec_vexpandbm", "llvm.ppc.altivec.vexpanddm" => "__builtin_altivec_vexpanddm", "llvm.ppc.altivec.vexpandhm" => "__builtin_altivec_vexpandhm", @@ -3036,15 +3849,23 @@ match name { "llvm.ppc.altivec.vmsumuhm" => "__builtin_altivec_vmsumuhm", "llvm.ppc.altivec.vmsumuhs" => "__builtin_altivec_vmsumuhs", "llvm.ppc.altivec.vmulesb" => "__builtin_altivec_vmulesb", + "llvm.ppc.altivec.vmulesd" => "__builtin_altivec_vmulesd", "llvm.ppc.altivec.vmulesh" => "__builtin_altivec_vmulesh", "llvm.ppc.altivec.vmulesw" => "__builtin_altivec_vmulesw", "llvm.ppc.altivec.vmuleub" => "__builtin_altivec_vmuleub", + "llvm.ppc.altivec.vmuleud" => "__builtin_altivec_vmuleud", "llvm.ppc.altivec.vmuleuh" => "__builtin_altivec_vmuleuh", "llvm.ppc.altivec.vmuleuw" => "__builtin_altivec_vmuleuw", + "llvm.ppc.altivec.vmulhsd" => "__builtin_altivec_vmulhsd", + "llvm.ppc.altivec.vmulhsw" => "__builtin_altivec_vmulhsw", + "llvm.ppc.altivec.vmulhud" => "__builtin_altivec_vmulhud", + "llvm.ppc.altivec.vmulhuw" => "__builtin_altivec_vmulhuw", "llvm.ppc.altivec.vmulosb" => "__builtin_altivec_vmulosb", + "llvm.ppc.altivec.vmulosd" => "__builtin_altivec_vmulosd", "llvm.ppc.altivec.vmulosh" => "__builtin_altivec_vmulosh", "llvm.ppc.altivec.vmulosw" => "__builtin_altivec_vmulosw", "llvm.ppc.altivec.vmuloub" => "__builtin_altivec_vmuloub", + "llvm.ppc.altivec.vmuloud" => "__builtin_altivec_vmuloud", "llvm.ppc.altivec.vmulouh" => "__builtin_altivec_vmulouh", "llvm.ppc.altivec.vmulouw" => "__builtin_altivec_vmulouw", "llvm.ppc.altivec.vnmsubfp" => "__builtin_altivec_vnmsubfp", @@ -3071,8 +3892,14 @@ match name { "llvm.ppc.altivec.vrfiz" => "__builtin_altivec_vrfiz", "llvm.ppc.altivec.vrlb" => "__builtin_altivec_vrlb", "llvm.ppc.altivec.vrld" => "__builtin_altivec_vrld", + "llvm.ppc.altivec.vrldmi" => "__builtin_altivec_vrldmi", + "llvm.ppc.altivec.vrldnm" => "__builtin_altivec_vrldnm", "llvm.ppc.altivec.vrlh" => "__builtin_altivec_vrlh", + "llvm.ppc.altivec.vrlqmi" => "__builtin_altivec_vrlqmi", + "llvm.ppc.altivec.vrlqnm" => "__builtin_altivec_vrlqnm", "llvm.ppc.altivec.vrlw" => "__builtin_altivec_vrlw", + "llvm.ppc.altivec.vrlwmi" => "__builtin_altivec_vrlwmi", + "llvm.ppc.altivec.vrlwnm" => "__builtin_altivec_vrlwnm", "llvm.ppc.altivec.vrsqrtefp" => "__builtin_altivec_vrsqrtefp", "llvm.ppc.altivec.vsel" => "__builtin_altivec_vsel_4si", "llvm.ppc.altivec.vsl" => "__builtin_altivec_vsl", @@ -3080,6 +3907,7 @@ match name { "llvm.ppc.altivec.vsldbi" => "__builtin_altivec_vsldbi", "llvm.ppc.altivec.vslh" => "__builtin_altivec_vslh", "llvm.ppc.altivec.vslo" => "__builtin_altivec_vslo", + "llvm.ppc.altivec.vslv" => "__builtin_altivec_vslv", "llvm.ppc.altivec.vslw" => "__builtin_altivec_vslw", "llvm.ppc.altivec.vsr" => "__builtin_altivec_vsr", "llvm.ppc.altivec.vsrab" => "__builtin_altivec_vsrab", @@ -3089,6 +3917,7 @@ match name { "llvm.ppc.altivec.vsrdbi" => "__builtin_altivec_vsrdbi", "llvm.ppc.altivec.vsrh" => "__builtin_altivec_vsrh", "llvm.ppc.altivec.vsro" => "__builtin_altivec_vsro", + "llvm.ppc.altivec.vsrv" => "__builtin_altivec_vsrv", "llvm.ppc.altivec.vsrw" => "__builtin_altivec_vsrw", "llvm.ppc.altivec.vstribl" => "__builtin_altivec_vstribl", "llvm.ppc.altivec.vstribl.p" => "__builtin_altivec_vstribl_p", @@ -3098,6 +3927,7 @@ match name { "llvm.ppc.altivec.vstrihl.p" => "__builtin_altivec_vstrihl_p", "llvm.ppc.altivec.vstrihr" => "__builtin_altivec_vstrihr", "llvm.ppc.altivec.vstrihr.p" => "__builtin_altivec_vstrihr_p", + "llvm.ppc.altivec.vsubcuq" => "__builtin_altivec_vsubcuq", "llvm.ppc.altivec.vsubcuw" => "__builtin_altivec_vsubcuw", "llvm.ppc.altivec.vsubecuq" => "__builtin_altivec_vsubecuq", "llvm.ppc.altivec.vsubeuqm" => "__builtin_altivec_vsubeuqm", @@ -3165,6 +3995,8 @@ match name { "llvm.ppc.fmaf128.round.to.odd" => "__builtin_fmaf128_round_to_odd", "llvm.ppc.fmsub" => "__builtin_ppc_fmsub", "llvm.ppc.fmsubs" => "__builtin_ppc_fmsubs", + "llvm.ppc.fnabs" => "__builtin_ppc_fnabs", + "llvm.ppc.fnabss" => "__builtin_ppc_fnabss", "llvm.ppc.fnmadd" => "__builtin_ppc_fnmadd", "llvm.ppc.fnmadds" => "__builtin_ppc_fnmadds", "llvm.ppc.fre" => "__builtin_ppc_fre", @@ -3341,8 +4173,24 @@ match name { "llvm.ppc.vsx.xvcmpgtdp.p" => "__builtin_vsx_xvcmpgtdp_p", "llvm.ppc.vsx.xvcmpgtsp" => "__builtin_vsx_xvcmpgtsp", "llvm.ppc.vsx.xvcmpgtsp.p" => "__builtin_vsx_xvcmpgtsp_p", + "llvm.ppc.vsx.xvcvbf16spn" => "__builtin_vsx_xvcvbf16spn", + "llvm.ppc.vsx.xvcvdpsp" => "__builtin_vsx_xvcvdpsp", + "llvm.ppc.vsx.xvcvdpsxws" => "__builtin_vsx_xvcvdpsxws", + "llvm.ppc.vsx.xvcvdpuxws" => "__builtin_vsx_xvcvdpuxws", + "llvm.ppc.vsx.xvcvhpsp" => "__builtin_vsx_xvcvhpsp", + "llvm.ppc.vsx.xvcvspbf16" => "__builtin_vsx_xvcvspbf16", + "llvm.ppc.vsx.xvcvspdp" => "__builtin_vsx_xvcvspdp", + "llvm.ppc.vsx.xvcvsphp" => "__builtin_vsx_xvcvsphp", + "llvm.ppc.vsx.xvcvspsxds" => "__builtin_vsx_xvcvspsxds", + "llvm.ppc.vsx.xvcvspuxds" => "__builtin_vsx_xvcvspuxds", + "llvm.ppc.vsx.xvcvsxdsp" => "__builtin_vsx_xvcvsxdsp", + "llvm.ppc.vsx.xvcvsxwdp" => "__builtin_vsx_xvcvsxwdp", + "llvm.ppc.vsx.xvcvuxdsp" => "__builtin_vsx_xvcvuxdsp", + "llvm.ppc.vsx.xvcvuxwdp" => "__builtin_vsx_xvcvuxwdp", "llvm.ppc.vsx.xvdivdp" => "__builtin_vsx_xvdivdp", "llvm.ppc.vsx.xvdivsp" => "__builtin_vsx_xvdivsp", + "llvm.ppc.vsx.xviexpdp" => "__builtin_vsx_xviexpdp", + "llvm.ppc.vsx.xviexpsp" => "__builtin_vsx_xviexpsp", "llvm.ppc.vsx.xvmaxdp" => "__builtin_vsx_xvmaxdp", "llvm.ppc.vsx.xvmaxsp" => "__builtin_vsx_xvmaxsp", "llvm.ppc.vsx.xvmindp" => "__builtin_vsx_xvmindp", @@ -3351,10 +4199,28 @@ match name { "llvm.ppc.vsx.xvresp" => "__builtin_vsx_xvresp", "llvm.ppc.vsx.xvrsqrtedp" => "__builtin_vsx_xvrsqrtedp", "llvm.ppc.vsx.xvrsqrtesp" => "__builtin_vsx_xvrsqrtesp", + "llvm.ppc.vsx.xvtdivdp" => "__builtin_vsx_xvtdivdp", + "llvm.ppc.vsx.xvtdivsp" => "__builtin_vsx_xvtdivsp", + "llvm.ppc.vsx.xvtlsbb" => "__builtin_vsx_xvtlsbb", + "llvm.ppc.vsx.xvtsqrtdp" => "__builtin_vsx_xvtsqrtdp", + "llvm.ppc.vsx.xvtsqrtsp" => "__builtin_vsx_xvtsqrtsp", + "llvm.ppc.vsx.xvtstdcdp" => "__builtin_vsx_xvtstdcdp", + "llvm.ppc.vsx.xvtstdcsp" => "__builtin_vsx_xvtstdcsp", + "llvm.ppc.vsx.xvxexpdp" => "__builtin_vsx_xvxexpdp", + "llvm.ppc.vsx.xvxexpsp" => "__builtin_vsx_xvxexpsp", + "llvm.ppc.vsx.xvxsigdp" => "__builtin_vsx_xvxsigdp", + "llvm.ppc.vsx.xvxsigsp" => "__builtin_vsx_xvxsigsp", "llvm.ppc.vsx.xxblendvb" => "__builtin_vsx_xxblendvb", "llvm.ppc.vsx.xxblendvd" => "__builtin_vsx_xxblendvd", "llvm.ppc.vsx.xxblendvh" => "__builtin_vsx_xxblendvh", "llvm.ppc.vsx.xxblendvw" => "__builtin_vsx_xxblendvw", + "llvm.ppc.vsx.xxeval" => "__builtin_vsx_xxeval", + "llvm.ppc.vsx.xxextractuw" => "__builtin_vsx_xxextractuw", + "llvm.ppc.vsx.xxgenpcvbm" => "__builtin_vsx_xxgenpcvbm", + "llvm.ppc.vsx.xxgenpcvdm" => "__builtin_vsx_xxgenpcvdm", + "llvm.ppc.vsx.xxgenpcvhm" => "__builtin_vsx_xxgenpcvhm", + "llvm.ppc.vsx.xxgenpcvwm" => "__builtin_vsx_xxgenpcvwm", + "llvm.ppc.vsx.xxinsertw" => "__builtin_vsx_xxinsertw", "llvm.ppc.vsx.xxleqv" => "__builtin_vsx_xxleqv", "llvm.ppc.vsx.xxpermx" => "__builtin_vsx_xxpermx", // ptx @@ -3376,6 +4242,19 @@ match name { "llvm.ptx.read.pm3" => "__builtin_ptx_read_pm3", "llvm.ptx.read.smid" => "__builtin_ptx_read_smid", "llvm.ptx.read.warpid" => "__builtin_ptx_read_warpid", + // r600 + "llvm.r600.group.barrier" => "__builtin_r600_group_barrier", + "llvm.r600.implicitarg.ptr" => "__builtin_r600_implicitarg_ptr", + "llvm.r600.rat.store.typed" => "__builtin_r600_rat_store_typed", + "llvm.r600.read.global.size.x" => "__builtin_r600_read_global_size_x", + "llvm.r600.read.global.size.y" => "__builtin_r600_read_global_size_y", + "llvm.r600.read.global.size.z" => "__builtin_r600_read_global_size_z", + "llvm.r600.read.ngroups.x" => "__builtin_r600_read_ngroups_x", + "llvm.r600.read.ngroups.y" => "__builtin_r600_read_ngroups_y", + "llvm.r600.read.ngroups.z" => "__builtin_r600_read_ngroups_z", + "llvm.r600.read.tgid.x" => "__builtin_r600_read_tgid_x", + "llvm.r600.read.tgid.y" => "__builtin_r600_read_tgid_y", + "llvm.r600.read.tgid.z" => "__builtin_r600_read_tgid_z", // s390 "llvm.s390.efpc" => "__builtin_s390_efpc", "llvm.s390.etnd" => "__builtin_tx_nesting_depth", @@ -3383,29 +4262,1426 @@ match name { "llvm.s390.ppa.txassist" => "__builtin_tx_assist", "llvm.s390.sfpc" => "__builtin_s390_sfpc", "llvm.s390.tend" => "__builtin_tend", + "llvm.s390.vaccb" => "__builtin_s390_vaccb", + "llvm.s390.vacccq" => "__builtin_s390_vacccq", + "llvm.s390.vaccf" => "__builtin_s390_vaccf", + "llvm.s390.vaccg" => "__builtin_s390_vaccg", + "llvm.s390.vacch" => "__builtin_s390_vacch", + "llvm.s390.vaccq" => "__builtin_s390_vaccq", + "llvm.s390.vacq" => "__builtin_s390_vacq", + "llvm.s390.vaq" => "__builtin_s390_vaq", + "llvm.s390.vavgb" => "__builtin_s390_vavgb", + "llvm.s390.vavgf" => "__builtin_s390_vavgf", + "llvm.s390.vavgg" => "__builtin_s390_vavgg", + "llvm.s390.vavgh" => "__builtin_s390_vavgh", + "llvm.s390.vavglb" => "__builtin_s390_vavglb", + "llvm.s390.vavglf" => "__builtin_s390_vavglf", + "llvm.s390.vavglg" => "__builtin_s390_vavglg", + "llvm.s390.vavglh" => "__builtin_s390_vavglh", + "llvm.s390.vbperm" => "__builtin_s390_vbperm", "llvm.s390.vcfn" => "__builtin_s390_vcfn", + "llvm.s390.vcksm" => "__builtin_s390_vcksm", "llvm.s390.vclfnhs" => "__builtin_s390_vclfnhs", "llvm.s390.vclfnls" => "__builtin_s390_vclfnls", "llvm.s390.vcnf" => "__builtin_s390_vcnf", "llvm.s390.vcrnfs" => "__builtin_s390_vcrnfs", + "llvm.s390.verimb" => "__builtin_s390_verimb", + "llvm.s390.verimf" => "__builtin_s390_verimf", + "llvm.s390.verimg" => "__builtin_s390_verimg", + "llvm.s390.verimh" => "__builtin_s390_verimh", + "llvm.s390.verllb" => "__builtin_s390_verllb", + "llvm.s390.verllf" => "__builtin_s390_verllf", + "llvm.s390.verllg" => "__builtin_s390_verllg", + "llvm.s390.verllh" => "__builtin_s390_verllh", + "llvm.s390.verllvb" => "__builtin_s390_verllvb", + "llvm.s390.verllvf" => "__builtin_s390_verllvf", + "llvm.s390.verllvg" => "__builtin_s390_verllvg", + "llvm.s390.verllvh" => "__builtin_s390_verllvh", + "llvm.s390.vfaeb" => "__builtin_s390_vfaeb", + "llvm.s390.vfaef" => "__builtin_s390_vfaef", + "llvm.s390.vfaeh" => "__builtin_s390_vfaeh", + "llvm.s390.vfaezb" => "__builtin_s390_vfaezb", + "llvm.s390.vfaezf" => "__builtin_s390_vfaezf", + "llvm.s390.vfaezh" => "__builtin_s390_vfaezh", + "llvm.s390.vfeeb" => "__builtin_s390_vfeeb", + "llvm.s390.vfeef" => "__builtin_s390_vfeef", + "llvm.s390.vfeeh" => "__builtin_s390_vfeeh", + "llvm.s390.vfeezb" => "__builtin_s390_vfeezb", + "llvm.s390.vfeezf" => "__builtin_s390_vfeezf", + "llvm.s390.vfeezh" => "__builtin_s390_vfeezh", + "llvm.s390.vfeneb" => "__builtin_s390_vfeneb", + "llvm.s390.vfenef" => "__builtin_s390_vfenef", + "llvm.s390.vfeneh" => "__builtin_s390_vfeneh", + "llvm.s390.vfenezb" => "__builtin_s390_vfenezb", + "llvm.s390.vfenezf" => "__builtin_s390_vfenezf", + "llvm.s390.vfenezh" => "__builtin_s390_vfenezh", + "llvm.s390.vgfmab" => "__builtin_s390_vgfmab", + "llvm.s390.vgfmaf" => "__builtin_s390_vgfmaf", + "llvm.s390.vgfmag" => "__builtin_s390_vgfmag", + "llvm.s390.vgfmah" => "__builtin_s390_vgfmah", + "llvm.s390.vgfmb" => "__builtin_s390_vgfmb", + "llvm.s390.vgfmf" => "__builtin_s390_vgfmf", + "llvm.s390.vgfmg" => "__builtin_s390_vgfmg", + "llvm.s390.vgfmh" => "__builtin_s390_vgfmh", + "llvm.s390.vistrb" => "__builtin_s390_vistrb", + "llvm.s390.vistrf" => "__builtin_s390_vistrf", + "llvm.s390.vistrh" => "__builtin_s390_vistrh", "llvm.s390.vlbb" => "__builtin_s390_vlbb", "llvm.s390.vll" => "__builtin_s390_vll", "llvm.s390.vlrl" => "__builtin_s390_vlrl", + "llvm.s390.vmaeb" => "__builtin_s390_vmaeb", + "llvm.s390.vmaef" => "__builtin_s390_vmaef", + "llvm.s390.vmaeh" => "__builtin_s390_vmaeh", + "llvm.s390.vmahb" => "__builtin_s390_vmahb", + "llvm.s390.vmahf" => "__builtin_s390_vmahf", + "llvm.s390.vmahh" => "__builtin_s390_vmahh", + "llvm.s390.vmaleb" => "__builtin_s390_vmaleb", + "llvm.s390.vmalef" => "__builtin_s390_vmalef", + "llvm.s390.vmaleh" => "__builtin_s390_vmaleh", + "llvm.s390.vmalhb" => "__builtin_s390_vmalhb", + "llvm.s390.vmalhf" => "__builtin_s390_vmalhf", + "llvm.s390.vmalhh" => "__builtin_s390_vmalhh", + "llvm.s390.vmalob" => "__builtin_s390_vmalob", + "llvm.s390.vmalof" => "__builtin_s390_vmalof", + "llvm.s390.vmaloh" => "__builtin_s390_vmaloh", + "llvm.s390.vmaob" => "__builtin_s390_vmaob", + "llvm.s390.vmaof" => "__builtin_s390_vmaof", + "llvm.s390.vmaoh" => "__builtin_s390_vmaoh", + "llvm.s390.vmeb" => "__builtin_s390_vmeb", + "llvm.s390.vmef" => "__builtin_s390_vmef", + "llvm.s390.vmeh" => "__builtin_s390_vmeh", + "llvm.s390.vmhb" => "__builtin_s390_vmhb", + "llvm.s390.vmhf" => "__builtin_s390_vmhf", + "llvm.s390.vmhh" => "__builtin_s390_vmhh", + "llvm.s390.vmleb" => "__builtin_s390_vmleb", + "llvm.s390.vmlef" => "__builtin_s390_vmlef", + "llvm.s390.vmleh" => "__builtin_s390_vmleh", + "llvm.s390.vmlhb" => "__builtin_s390_vmlhb", + "llvm.s390.vmlhf" => "__builtin_s390_vmlhf", + "llvm.s390.vmlhh" => "__builtin_s390_vmlhh", + "llvm.s390.vmlob" => "__builtin_s390_vmlob", + "llvm.s390.vmlof" => "__builtin_s390_vmlof", + "llvm.s390.vmloh" => "__builtin_s390_vmloh", + "llvm.s390.vmob" => "__builtin_s390_vmob", + "llvm.s390.vmof" => "__builtin_s390_vmof", + "llvm.s390.vmoh" => "__builtin_s390_vmoh", "llvm.s390.vmslg" => "__builtin_s390_vmslg", "llvm.s390.vpdi" => "__builtin_s390_vpdi", "llvm.s390.vperm" => "__builtin_s390_vperm", + "llvm.s390.vpklsf" => "__builtin_s390_vpklsf", + "llvm.s390.vpklsg" => "__builtin_s390_vpklsg", + "llvm.s390.vpklsh" => "__builtin_s390_vpklsh", + "llvm.s390.vpksf" => "__builtin_s390_vpksf", + "llvm.s390.vpksg" => "__builtin_s390_vpksg", + "llvm.s390.vpksh" => "__builtin_s390_vpksh", + "llvm.s390.vsbcbiq" => "__builtin_s390_vsbcbiq", + "llvm.s390.vsbiq" => "__builtin_s390_vsbiq", + "llvm.s390.vscbib" => "__builtin_s390_vscbib", + "llvm.s390.vscbif" => "__builtin_s390_vscbif", + "llvm.s390.vscbig" => "__builtin_s390_vscbig", + "llvm.s390.vscbih" => "__builtin_s390_vscbih", + "llvm.s390.vscbiq" => "__builtin_s390_vscbiq", + "llvm.s390.vsl" => "__builtin_s390_vsl", + "llvm.s390.vslb" => "__builtin_s390_vslb", "llvm.s390.vsld" => "__builtin_s390_vsld", "llvm.s390.vsldb" => "__builtin_s390_vsldb", + "llvm.s390.vsq" => "__builtin_s390_vsq", + "llvm.s390.vsra" => "__builtin_s390_vsra", + "llvm.s390.vsrab" => "__builtin_s390_vsrab", "llvm.s390.vsrd" => "__builtin_s390_vsrd", + "llvm.s390.vsrl" => "__builtin_s390_vsrl", + "llvm.s390.vsrlb" => "__builtin_s390_vsrlb", "llvm.s390.vstl" => "__builtin_s390_vstl", + "llvm.s390.vstrcb" => "__builtin_s390_vstrcb", + "llvm.s390.vstrcf" => "__builtin_s390_vstrcf", + "llvm.s390.vstrch" => "__builtin_s390_vstrch", + "llvm.s390.vstrczb" => "__builtin_s390_vstrczb", + "llvm.s390.vstrczf" => "__builtin_s390_vstrczf", + "llvm.s390.vstrczh" => "__builtin_s390_vstrczh", "llvm.s390.vstrl" => "__builtin_s390_vstrl", + "llvm.s390.vsumb" => "__builtin_s390_vsumb", + "llvm.s390.vsumgf" => "__builtin_s390_vsumgf", + "llvm.s390.vsumgh" => "__builtin_s390_vsumgh", + "llvm.s390.vsumh" => "__builtin_s390_vsumh", + "llvm.s390.vsumqf" => "__builtin_s390_vsumqf", + "llvm.s390.vsumqg" => "__builtin_s390_vsumqg", + "llvm.s390.vtm" => "__builtin_s390_vtm", + "llvm.s390.vuphb" => "__builtin_s390_vuphb", + "llvm.s390.vuphf" => "__builtin_s390_vuphf", + "llvm.s390.vuphh" => "__builtin_s390_vuphh", + "llvm.s390.vuplb" => "__builtin_s390_vuplb", + "llvm.s390.vuplf" => "__builtin_s390_vuplf", + "llvm.s390.vuplhb" => "__builtin_s390_vuplhb", + "llvm.s390.vuplhf" => "__builtin_s390_vuplhf", + "llvm.s390.vuplhh" => "__builtin_s390_vuplhh", + "llvm.s390.vuplhw" => "__builtin_s390_vuplhw", + "llvm.s390.vupllb" => "__builtin_s390_vupllb", + "llvm.s390.vupllf" => "__builtin_s390_vupllf", + "llvm.s390.vupllh" => "__builtin_s390_vupllh", // ve + "llvm.ve.vl.andm.MMM" => "__builtin_ve_vl_andm_MMM", + "llvm.ve.vl.andm.mmm" => "__builtin_ve_vl_andm_mmm", + "llvm.ve.vl.eqvm.MMM" => "__builtin_ve_vl_eqvm_MMM", + "llvm.ve.vl.eqvm.mmm" => "__builtin_ve_vl_eqvm_mmm", "llvm.ve.vl.extract.vm512l" => "__builtin_ve_vl_extract_vm512l", "llvm.ve.vl.extract.vm512u" => "__builtin_ve_vl_extract_vm512u", + "llvm.ve.vl.fencec.s" => "__builtin_ve_vl_fencec_s", + "llvm.ve.vl.fencei" => "__builtin_ve_vl_fencei", + "llvm.ve.vl.fencem.s" => "__builtin_ve_vl_fencem_s", + "llvm.ve.vl.fidcr.sss" => "__builtin_ve_vl_fidcr_sss", "llvm.ve.vl.insert.vm512l" => "__builtin_ve_vl_insert_vm512l", "llvm.ve.vl.insert.vm512u" => "__builtin_ve_vl_insert_vm512u", + "llvm.ve.vl.lcr.sss" => "__builtin_ve_vl_lcr_sss", + "llvm.ve.vl.lsv.vvss" => "__builtin_ve_vl_lsv_vvss", + "llvm.ve.vl.lvm.MMss" => "__builtin_ve_vl_lvm_MMss", + "llvm.ve.vl.lvm.mmss" => "__builtin_ve_vl_lvm_mmss", + "llvm.ve.vl.lvsd.svs" => "__builtin_ve_vl_lvsd_svs", + "llvm.ve.vl.lvsl.svs" => "__builtin_ve_vl_lvsl_svs", + "llvm.ve.vl.lvss.svs" => "__builtin_ve_vl_lvss_svs", + "llvm.ve.vl.lzvm.sml" => "__builtin_ve_vl_lzvm_sml", + "llvm.ve.vl.negm.MM" => "__builtin_ve_vl_negm_MM", + "llvm.ve.vl.negm.mm" => "__builtin_ve_vl_negm_mm", + "llvm.ve.vl.nndm.MMM" => "__builtin_ve_vl_nndm_MMM", + "llvm.ve.vl.nndm.mmm" => "__builtin_ve_vl_nndm_mmm", + "llvm.ve.vl.orm.MMM" => "__builtin_ve_vl_orm_MMM", + "llvm.ve.vl.orm.mmm" => "__builtin_ve_vl_orm_mmm", "llvm.ve.vl.pack.f32a" => "__builtin_ve_vl_pack_f32a", "llvm.ve.vl.pack.f32p" => "__builtin_ve_vl_pack_f32p", + "llvm.ve.vl.pcvm.sml" => "__builtin_ve_vl_pcvm_sml", + "llvm.ve.vl.pfchv.ssl" => "__builtin_ve_vl_pfchv_ssl", + "llvm.ve.vl.pfchvnc.ssl" => "__builtin_ve_vl_pfchvnc_ssl", + "llvm.ve.vl.pvadds.vsvMvl" => "__builtin_ve_vl_pvadds_vsvMvl", + "llvm.ve.vl.pvadds.vsvl" => "__builtin_ve_vl_pvadds_vsvl", + "llvm.ve.vl.pvadds.vsvvl" => "__builtin_ve_vl_pvadds_vsvvl", + "llvm.ve.vl.pvadds.vvvMvl" => "__builtin_ve_vl_pvadds_vvvMvl", + "llvm.ve.vl.pvadds.vvvl" => "__builtin_ve_vl_pvadds_vvvl", + "llvm.ve.vl.pvadds.vvvvl" => "__builtin_ve_vl_pvadds_vvvvl", + "llvm.ve.vl.pvaddu.vsvMvl" => "__builtin_ve_vl_pvaddu_vsvMvl", + "llvm.ve.vl.pvaddu.vsvl" => "__builtin_ve_vl_pvaddu_vsvl", + "llvm.ve.vl.pvaddu.vsvvl" => "__builtin_ve_vl_pvaddu_vsvvl", + "llvm.ve.vl.pvaddu.vvvMvl" => "__builtin_ve_vl_pvaddu_vvvMvl", + "llvm.ve.vl.pvaddu.vvvl" => "__builtin_ve_vl_pvaddu_vvvl", + "llvm.ve.vl.pvaddu.vvvvl" => "__builtin_ve_vl_pvaddu_vvvvl", + "llvm.ve.vl.pvand.vsvMvl" => "__builtin_ve_vl_pvand_vsvMvl", + "llvm.ve.vl.pvand.vsvl" => "__builtin_ve_vl_pvand_vsvl", + "llvm.ve.vl.pvand.vsvvl" => "__builtin_ve_vl_pvand_vsvvl", + "llvm.ve.vl.pvand.vvvMvl" => "__builtin_ve_vl_pvand_vvvMvl", + "llvm.ve.vl.pvand.vvvl" => "__builtin_ve_vl_pvand_vvvl", + "llvm.ve.vl.pvand.vvvvl" => "__builtin_ve_vl_pvand_vvvvl", + "llvm.ve.vl.pvbrd.vsMvl" => "__builtin_ve_vl_pvbrd_vsMvl", + "llvm.ve.vl.pvbrd.vsl" => "__builtin_ve_vl_pvbrd_vsl", + "llvm.ve.vl.pvbrd.vsvl" => "__builtin_ve_vl_pvbrd_vsvl", + "llvm.ve.vl.pvbrv.vvMvl" => "__builtin_ve_vl_pvbrv_vvMvl", + "llvm.ve.vl.pvbrv.vvl" => "__builtin_ve_vl_pvbrv_vvl", + "llvm.ve.vl.pvbrv.vvvl" => "__builtin_ve_vl_pvbrv_vvvl", + "llvm.ve.vl.pvbrvlo.vvl" => "__builtin_ve_vl_pvbrvlo_vvl", + "llvm.ve.vl.pvbrvlo.vvmvl" => "__builtin_ve_vl_pvbrvlo_vvmvl", + "llvm.ve.vl.pvbrvlo.vvvl" => "__builtin_ve_vl_pvbrvlo_vvvl", + "llvm.ve.vl.pvbrvup.vvl" => "__builtin_ve_vl_pvbrvup_vvl", + "llvm.ve.vl.pvbrvup.vvmvl" => "__builtin_ve_vl_pvbrvup_vvmvl", + "llvm.ve.vl.pvbrvup.vvvl" => "__builtin_ve_vl_pvbrvup_vvvl", + "llvm.ve.vl.pvcmps.vsvMvl" => "__builtin_ve_vl_pvcmps_vsvMvl", + "llvm.ve.vl.pvcmps.vsvl" => "__builtin_ve_vl_pvcmps_vsvl", + "llvm.ve.vl.pvcmps.vsvvl" => "__builtin_ve_vl_pvcmps_vsvvl", + "llvm.ve.vl.pvcmps.vvvMvl" => "__builtin_ve_vl_pvcmps_vvvMvl", + "llvm.ve.vl.pvcmps.vvvl" => "__builtin_ve_vl_pvcmps_vvvl", + "llvm.ve.vl.pvcmps.vvvvl" => "__builtin_ve_vl_pvcmps_vvvvl", + "llvm.ve.vl.pvcmpu.vsvMvl" => "__builtin_ve_vl_pvcmpu_vsvMvl", + "llvm.ve.vl.pvcmpu.vsvl" => "__builtin_ve_vl_pvcmpu_vsvl", + "llvm.ve.vl.pvcmpu.vsvvl" => "__builtin_ve_vl_pvcmpu_vsvvl", + "llvm.ve.vl.pvcmpu.vvvMvl" => "__builtin_ve_vl_pvcmpu_vvvMvl", + "llvm.ve.vl.pvcmpu.vvvl" => "__builtin_ve_vl_pvcmpu_vvvl", + "llvm.ve.vl.pvcmpu.vvvvl" => "__builtin_ve_vl_pvcmpu_vvvvl", + "llvm.ve.vl.pvcvtsw.vvl" => "__builtin_ve_vl_pvcvtsw_vvl", + "llvm.ve.vl.pvcvtsw.vvvl" => "__builtin_ve_vl_pvcvtsw_vvvl", + "llvm.ve.vl.pvcvtws.vvMvl" => "__builtin_ve_vl_pvcvtws_vvMvl", + "llvm.ve.vl.pvcvtws.vvl" => "__builtin_ve_vl_pvcvtws_vvl", + "llvm.ve.vl.pvcvtws.vvvl" => "__builtin_ve_vl_pvcvtws_vvvl", + "llvm.ve.vl.pvcvtwsrz.vvMvl" => "__builtin_ve_vl_pvcvtwsrz_vvMvl", + "llvm.ve.vl.pvcvtwsrz.vvl" => "__builtin_ve_vl_pvcvtwsrz_vvl", + "llvm.ve.vl.pvcvtwsrz.vvvl" => "__builtin_ve_vl_pvcvtwsrz_vvvl", + "llvm.ve.vl.pveqv.vsvMvl" => "__builtin_ve_vl_pveqv_vsvMvl", + "llvm.ve.vl.pveqv.vsvl" => "__builtin_ve_vl_pveqv_vsvl", + "llvm.ve.vl.pveqv.vsvvl" => "__builtin_ve_vl_pveqv_vsvvl", + "llvm.ve.vl.pveqv.vvvMvl" => "__builtin_ve_vl_pveqv_vvvMvl", + "llvm.ve.vl.pveqv.vvvl" => "__builtin_ve_vl_pveqv_vvvl", + "llvm.ve.vl.pveqv.vvvvl" => "__builtin_ve_vl_pveqv_vvvvl", + "llvm.ve.vl.pvfadd.vsvMvl" => "__builtin_ve_vl_pvfadd_vsvMvl", + "llvm.ve.vl.pvfadd.vsvl" => "__builtin_ve_vl_pvfadd_vsvl", + "llvm.ve.vl.pvfadd.vsvvl" => "__builtin_ve_vl_pvfadd_vsvvl", + "llvm.ve.vl.pvfadd.vvvMvl" => "__builtin_ve_vl_pvfadd_vvvMvl", + "llvm.ve.vl.pvfadd.vvvl" => "__builtin_ve_vl_pvfadd_vvvl", + "llvm.ve.vl.pvfadd.vvvvl" => "__builtin_ve_vl_pvfadd_vvvvl", + "llvm.ve.vl.pvfcmp.vsvMvl" => "__builtin_ve_vl_pvfcmp_vsvMvl", + "llvm.ve.vl.pvfcmp.vsvl" => "__builtin_ve_vl_pvfcmp_vsvl", + "llvm.ve.vl.pvfcmp.vsvvl" => "__builtin_ve_vl_pvfcmp_vsvvl", + "llvm.ve.vl.pvfcmp.vvvMvl" => "__builtin_ve_vl_pvfcmp_vvvMvl", + "llvm.ve.vl.pvfcmp.vvvl" => "__builtin_ve_vl_pvfcmp_vvvl", + "llvm.ve.vl.pvfcmp.vvvvl" => "__builtin_ve_vl_pvfcmp_vvvvl", + "llvm.ve.vl.pvfmad.vsvvMvl" => "__builtin_ve_vl_pvfmad_vsvvMvl", + "llvm.ve.vl.pvfmad.vsvvl" => "__builtin_ve_vl_pvfmad_vsvvl", + "llvm.ve.vl.pvfmad.vsvvvl" => "__builtin_ve_vl_pvfmad_vsvvvl", + "llvm.ve.vl.pvfmad.vvsvMvl" => "__builtin_ve_vl_pvfmad_vvsvMvl", + "llvm.ve.vl.pvfmad.vvsvl" => "__builtin_ve_vl_pvfmad_vvsvl", + "llvm.ve.vl.pvfmad.vvsvvl" => "__builtin_ve_vl_pvfmad_vvsvvl", + "llvm.ve.vl.pvfmad.vvvvMvl" => "__builtin_ve_vl_pvfmad_vvvvMvl", + "llvm.ve.vl.pvfmad.vvvvl" => "__builtin_ve_vl_pvfmad_vvvvl", + "llvm.ve.vl.pvfmad.vvvvvl" => "__builtin_ve_vl_pvfmad_vvvvvl", + "llvm.ve.vl.pvfmax.vsvMvl" => "__builtin_ve_vl_pvfmax_vsvMvl", + "llvm.ve.vl.pvfmax.vsvl" => "__builtin_ve_vl_pvfmax_vsvl", + "llvm.ve.vl.pvfmax.vsvvl" => "__builtin_ve_vl_pvfmax_vsvvl", + "llvm.ve.vl.pvfmax.vvvMvl" => "__builtin_ve_vl_pvfmax_vvvMvl", + "llvm.ve.vl.pvfmax.vvvl" => "__builtin_ve_vl_pvfmax_vvvl", + "llvm.ve.vl.pvfmax.vvvvl" => "__builtin_ve_vl_pvfmax_vvvvl", + "llvm.ve.vl.pvfmin.vsvMvl" => "__builtin_ve_vl_pvfmin_vsvMvl", + "llvm.ve.vl.pvfmin.vsvl" => "__builtin_ve_vl_pvfmin_vsvl", + "llvm.ve.vl.pvfmin.vsvvl" => "__builtin_ve_vl_pvfmin_vsvvl", + "llvm.ve.vl.pvfmin.vvvMvl" => "__builtin_ve_vl_pvfmin_vvvMvl", + "llvm.ve.vl.pvfmin.vvvl" => "__builtin_ve_vl_pvfmin_vvvl", + "llvm.ve.vl.pvfmin.vvvvl" => "__builtin_ve_vl_pvfmin_vvvvl", + "llvm.ve.vl.pvfmkaf.Ml" => "__builtin_ve_vl_pvfmkaf_Ml", + "llvm.ve.vl.pvfmkat.Ml" => "__builtin_ve_vl_pvfmkat_Ml", + "llvm.ve.vl.pvfmkseq.MvMl" => "__builtin_ve_vl_pvfmkseq_MvMl", + "llvm.ve.vl.pvfmkseq.Mvl" => "__builtin_ve_vl_pvfmkseq_Mvl", + "llvm.ve.vl.pvfmkseqnan.MvMl" => "__builtin_ve_vl_pvfmkseqnan_MvMl", + "llvm.ve.vl.pvfmkseqnan.Mvl" => "__builtin_ve_vl_pvfmkseqnan_Mvl", + "llvm.ve.vl.pvfmksge.MvMl" => "__builtin_ve_vl_pvfmksge_MvMl", + "llvm.ve.vl.pvfmksge.Mvl" => "__builtin_ve_vl_pvfmksge_Mvl", + "llvm.ve.vl.pvfmksgenan.MvMl" => "__builtin_ve_vl_pvfmksgenan_MvMl", + "llvm.ve.vl.pvfmksgenan.Mvl" => "__builtin_ve_vl_pvfmksgenan_Mvl", + "llvm.ve.vl.pvfmksgt.MvMl" => "__builtin_ve_vl_pvfmksgt_MvMl", + "llvm.ve.vl.pvfmksgt.Mvl" => "__builtin_ve_vl_pvfmksgt_Mvl", + "llvm.ve.vl.pvfmksgtnan.MvMl" => "__builtin_ve_vl_pvfmksgtnan_MvMl", + "llvm.ve.vl.pvfmksgtnan.Mvl" => "__builtin_ve_vl_pvfmksgtnan_Mvl", + "llvm.ve.vl.pvfmksle.MvMl" => "__builtin_ve_vl_pvfmksle_MvMl", + "llvm.ve.vl.pvfmksle.Mvl" => "__builtin_ve_vl_pvfmksle_Mvl", + "llvm.ve.vl.pvfmkslenan.MvMl" => "__builtin_ve_vl_pvfmkslenan_MvMl", + "llvm.ve.vl.pvfmkslenan.Mvl" => "__builtin_ve_vl_pvfmkslenan_Mvl", + "llvm.ve.vl.pvfmksloeq.mvl" => "__builtin_ve_vl_pvfmksloeq_mvl", + "llvm.ve.vl.pvfmksloeq.mvml" => "__builtin_ve_vl_pvfmksloeq_mvml", + "llvm.ve.vl.pvfmksloeqnan.mvl" => "__builtin_ve_vl_pvfmksloeqnan_mvl", + "llvm.ve.vl.pvfmksloeqnan.mvml" => "__builtin_ve_vl_pvfmksloeqnan_mvml", + "llvm.ve.vl.pvfmksloge.mvl" => "__builtin_ve_vl_pvfmksloge_mvl", + "llvm.ve.vl.pvfmksloge.mvml" => "__builtin_ve_vl_pvfmksloge_mvml", + "llvm.ve.vl.pvfmkslogenan.mvl" => "__builtin_ve_vl_pvfmkslogenan_mvl", + "llvm.ve.vl.pvfmkslogenan.mvml" => "__builtin_ve_vl_pvfmkslogenan_mvml", + "llvm.ve.vl.pvfmkslogt.mvl" => "__builtin_ve_vl_pvfmkslogt_mvl", + "llvm.ve.vl.pvfmkslogt.mvml" => "__builtin_ve_vl_pvfmkslogt_mvml", + "llvm.ve.vl.pvfmkslogtnan.mvl" => "__builtin_ve_vl_pvfmkslogtnan_mvl", + "llvm.ve.vl.pvfmkslogtnan.mvml" => "__builtin_ve_vl_pvfmkslogtnan_mvml", + "llvm.ve.vl.pvfmkslole.mvl" => "__builtin_ve_vl_pvfmkslole_mvl", + "llvm.ve.vl.pvfmkslole.mvml" => "__builtin_ve_vl_pvfmkslole_mvml", + "llvm.ve.vl.pvfmkslolenan.mvl" => "__builtin_ve_vl_pvfmkslolenan_mvl", + "llvm.ve.vl.pvfmkslolenan.mvml" => "__builtin_ve_vl_pvfmkslolenan_mvml", + "llvm.ve.vl.pvfmkslolt.mvl" => "__builtin_ve_vl_pvfmkslolt_mvl", + "llvm.ve.vl.pvfmkslolt.mvml" => "__builtin_ve_vl_pvfmkslolt_mvml", + "llvm.ve.vl.pvfmksloltnan.mvl" => "__builtin_ve_vl_pvfmksloltnan_mvl", + "llvm.ve.vl.pvfmksloltnan.mvml" => "__builtin_ve_vl_pvfmksloltnan_mvml", + "llvm.ve.vl.pvfmkslonan.mvl" => "__builtin_ve_vl_pvfmkslonan_mvl", + "llvm.ve.vl.pvfmkslonan.mvml" => "__builtin_ve_vl_pvfmkslonan_mvml", + "llvm.ve.vl.pvfmkslone.mvl" => "__builtin_ve_vl_pvfmkslone_mvl", + "llvm.ve.vl.pvfmkslone.mvml" => "__builtin_ve_vl_pvfmkslone_mvml", + "llvm.ve.vl.pvfmkslonenan.mvl" => "__builtin_ve_vl_pvfmkslonenan_mvl", + "llvm.ve.vl.pvfmkslonenan.mvml" => "__builtin_ve_vl_pvfmkslonenan_mvml", + "llvm.ve.vl.pvfmkslonum.mvl" => "__builtin_ve_vl_pvfmkslonum_mvl", + "llvm.ve.vl.pvfmkslonum.mvml" => "__builtin_ve_vl_pvfmkslonum_mvml", + "llvm.ve.vl.pvfmkslt.MvMl" => "__builtin_ve_vl_pvfmkslt_MvMl", + "llvm.ve.vl.pvfmkslt.Mvl" => "__builtin_ve_vl_pvfmkslt_Mvl", + "llvm.ve.vl.pvfmksltnan.MvMl" => "__builtin_ve_vl_pvfmksltnan_MvMl", + "llvm.ve.vl.pvfmksltnan.Mvl" => "__builtin_ve_vl_pvfmksltnan_Mvl", + "llvm.ve.vl.pvfmksnan.MvMl" => "__builtin_ve_vl_pvfmksnan_MvMl", + "llvm.ve.vl.pvfmksnan.Mvl" => "__builtin_ve_vl_pvfmksnan_Mvl", + "llvm.ve.vl.pvfmksne.MvMl" => "__builtin_ve_vl_pvfmksne_MvMl", + "llvm.ve.vl.pvfmksne.Mvl" => "__builtin_ve_vl_pvfmksne_Mvl", + "llvm.ve.vl.pvfmksnenan.MvMl" => "__builtin_ve_vl_pvfmksnenan_MvMl", + "llvm.ve.vl.pvfmksnenan.Mvl" => "__builtin_ve_vl_pvfmksnenan_Mvl", + "llvm.ve.vl.pvfmksnum.MvMl" => "__builtin_ve_vl_pvfmksnum_MvMl", + "llvm.ve.vl.pvfmksnum.Mvl" => "__builtin_ve_vl_pvfmksnum_Mvl", + "llvm.ve.vl.pvfmksupeq.mvl" => "__builtin_ve_vl_pvfmksupeq_mvl", + "llvm.ve.vl.pvfmksupeq.mvml" => "__builtin_ve_vl_pvfmksupeq_mvml", + "llvm.ve.vl.pvfmksupeqnan.mvl" => "__builtin_ve_vl_pvfmksupeqnan_mvl", + "llvm.ve.vl.pvfmksupeqnan.mvml" => "__builtin_ve_vl_pvfmksupeqnan_mvml", + "llvm.ve.vl.pvfmksupge.mvl" => "__builtin_ve_vl_pvfmksupge_mvl", + "llvm.ve.vl.pvfmksupge.mvml" => "__builtin_ve_vl_pvfmksupge_mvml", + "llvm.ve.vl.pvfmksupgenan.mvl" => "__builtin_ve_vl_pvfmksupgenan_mvl", + "llvm.ve.vl.pvfmksupgenan.mvml" => "__builtin_ve_vl_pvfmksupgenan_mvml", + "llvm.ve.vl.pvfmksupgt.mvl" => "__builtin_ve_vl_pvfmksupgt_mvl", + "llvm.ve.vl.pvfmksupgt.mvml" => "__builtin_ve_vl_pvfmksupgt_mvml", + "llvm.ve.vl.pvfmksupgtnan.mvl" => "__builtin_ve_vl_pvfmksupgtnan_mvl", + "llvm.ve.vl.pvfmksupgtnan.mvml" => "__builtin_ve_vl_pvfmksupgtnan_mvml", + "llvm.ve.vl.pvfmksuple.mvl" => "__builtin_ve_vl_pvfmksuple_mvl", + "llvm.ve.vl.pvfmksuple.mvml" => "__builtin_ve_vl_pvfmksuple_mvml", + "llvm.ve.vl.pvfmksuplenan.mvl" => "__builtin_ve_vl_pvfmksuplenan_mvl", + "llvm.ve.vl.pvfmksuplenan.mvml" => "__builtin_ve_vl_pvfmksuplenan_mvml", + "llvm.ve.vl.pvfmksuplt.mvl" => "__builtin_ve_vl_pvfmksuplt_mvl", + "llvm.ve.vl.pvfmksuplt.mvml" => "__builtin_ve_vl_pvfmksuplt_mvml", + "llvm.ve.vl.pvfmksupltnan.mvl" => "__builtin_ve_vl_pvfmksupltnan_mvl", + "llvm.ve.vl.pvfmksupltnan.mvml" => "__builtin_ve_vl_pvfmksupltnan_mvml", + "llvm.ve.vl.pvfmksupnan.mvl" => "__builtin_ve_vl_pvfmksupnan_mvl", + "llvm.ve.vl.pvfmksupnan.mvml" => "__builtin_ve_vl_pvfmksupnan_mvml", + "llvm.ve.vl.pvfmksupne.mvl" => "__builtin_ve_vl_pvfmksupne_mvl", + "llvm.ve.vl.pvfmksupne.mvml" => "__builtin_ve_vl_pvfmksupne_mvml", + "llvm.ve.vl.pvfmksupnenan.mvl" => "__builtin_ve_vl_pvfmksupnenan_mvl", + "llvm.ve.vl.pvfmksupnenan.mvml" => "__builtin_ve_vl_pvfmksupnenan_mvml", + "llvm.ve.vl.pvfmksupnum.mvl" => "__builtin_ve_vl_pvfmksupnum_mvl", + "llvm.ve.vl.pvfmksupnum.mvml" => "__builtin_ve_vl_pvfmksupnum_mvml", + "llvm.ve.vl.pvfmkweq.MvMl" => "__builtin_ve_vl_pvfmkweq_MvMl", + "llvm.ve.vl.pvfmkweq.Mvl" => "__builtin_ve_vl_pvfmkweq_Mvl", + "llvm.ve.vl.pvfmkweqnan.MvMl" => "__builtin_ve_vl_pvfmkweqnan_MvMl", + "llvm.ve.vl.pvfmkweqnan.Mvl" => "__builtin_ve_vl_pvfmkweqnan_Mvl", + "llvm.ve.vl.pvfmkwge.MvMl" => "__builtin_ve_vl_pvfmkwge_MvMl", + "llvm.ve.vl.pvfmkwge.Mvl" => "__builtin_ve_vl_pvfmkwge_Mvl", + "llvm.ve.vl.pvfmkwgenan.MvMl" => "__builtin_ve_vl_pvfmkwgenan_MvMl", + "llvm.ve.vl.pvfmkwgenan.Mvl" => "__builtin_ve_vl_pvfmkwgenan_Mvl", + "llvm.ve.vl.pvfmkwgt.MvMl" => "__builtin_ve_vl_pvfmkwgt_MvMl", + "llvm.ve.vl.pvfmkwgt.Mvl" => "__builtin_ve_vl_pvfmkwgt_Mvl", + "llvm.ve.vl.pvfmkwgtnan.MvMl" => "__builtin_ve_vl_pvfmkwgtnan_MvMl", + "llvm.ve.vl.pvfmkwgtnan.Mvl" => "__builtin_ve_vl_pvfmkwgtnan_Mvl", + "llvm.ve.vl.pvfmkwle.MvMl" => "__builtin_ve_vl_pvfmkwle_MvMl", + "llvm.ve.vl.pvfmkwle.Mvl" => "__builtin_ve_vl_pvfmkwle_Mvl", + "llvm.ve.vl.pvfmkwlenan.MvMl" => "__builtin_ve_vl_pvfmkwlenan_MvMl", + "llvm.ve.vl.pvfmkwlenan.Mvl" => "__builtin_ve_vl_pvfmkwlenan_Mvl", + "llvm.ve.vl.pvfmkwloeq.mvl" => "__builtin_ve_vl_pvfmkwloeq_mvl", + "llvm.ve.vl.pvfmkwloeq.mvml" => "__builtin_ve_vl_pvfmkwloeq_mvml", + "llvm.ve.vl.pvfmkwloeqnan.mvl" => "__builtin_ve_vl_pvfmkwloeqnan_mvl", + "llvm.ve.vl.pvfmkwloeqnan.mvml" => "__builtin_ve_vl_pvfmkwloeqnan_mvml", + "llvm.ve.vl.pvfmkwloge.mvl" => "__builtin_ve_vl_pvfmkwloge_mvl", + "llvm.ve.vl.pvfmkwloge.mvml" => "__builtin_ve_vl_pvfmkwloge_mvml", + "llvm.ve.vl.pvfmkwlogenan.mvl" => "__builtin_ve_vl_pvfmkwlogenan_mvl", + "llvm.ve.vl.pvfmkwlogenan.mvml" => "__builtin_ve_vl_pvfmkwlogenan_mvml", + "llvm.ve.vl.pvfmkwlogt.mvl" => "__builtin_ve_vl_pvfmkwlogt_mvl", + "llvm.ve.vl.pvfmkwlogt.mvml" => "__builtin_ve_vl_pvfmkwlogt_mvml", + "llvm.ve.vl.pvfmkwlogtnan.mvl" => "__builtin_ve_vl_pvfmkwlogtnan_mvl", + "llvm.ve.vl.pvfmkwlogtnan.mvml" => "__builtin_ve_vl_pvfmkwlogtnan_mvml", + "llvm.ve.vl.pvfmkwlole.mvl" => "__builtin_ve_vl_pvfmkwlole_mvl", + "llvm.ve.vl.pvfmkwlole.mvml" => "__builtin_ve_vl_pvfmkwlole_mvml", + "llvm.ve.vl.pvfmkwlolenan.mvl" => "__builtin_ve_vl_pvfmkwlolenan_mvl", + "llvm.ve.vl.pvfmkwlolenan.mvml" => "__builtin_ve_vl_pvfmkwlolenan_mvml", + "llvm.ve.vl.pvfmkwlolt.mvl" => "__builtin_ve_vl_pvfmkwlolt_mvl", + "llvm.ve.vl.pvfmkwlolt.mvml" => "__builtin_ve_vl_pvfmkwlolt_mvml", + "llvm.ve.vl.pvfmkwloltnan.mvl" => "__builtin_ve_vl_pvfmkwloltnan_mvl", + "llvm.ve.vl.pvfmkwloltnan.mvml" => "__builtin_ve_vl_pvfmkwloltnan_mvml", + "llvm.ve.vl.pvfmkwlonan.mvl" => "__builtin_ve_vl_pvfmkwlonan_mvl", + "llvm.ve.vl.pvfmkwlonan.mvml" => "__builtin_ve_vl_pvfmkwlonan_mvml", + "llvm.ve.vl.pvfmkwlone.mvl" => "__builtin_ve_vl_pvfmkwlone_mvl", + "llvm.ve.vl.pvfmkwlone.mvml" => "__builtin_ve_vl_pvfmkwlone_mvml", + "llvm.ve.vl.pvfmkwlonenan.mvl" => "__builtin_ve_vl_pvfmkwlonenan_mvl", + "llvm.ve.vl.pvfmkwlonenan.mvml" => "__builtin_ve_vl_pvfmkwlonenan_mvml", + "llvm.ve.vl.pvfmkwlonum.mvl" => "__builtin_ve_vl_pvfmkwlonum_mvl", + "llvm.ve.vl.pvfmkwlonum.mvml" => "__builtin_ve_vl_pvfmkwlonum_mvml", + "llvm.ve.vl.pvfmkwlt.MvMl" => "__builtin_ve_vl_pvfmkwlt_MvMl", + "llvm.ve.vl.pvfmkwlt.Mvl" => "__builtin_ve_vl_pvfmkwlt_Mvl", + "llvm.ve.vl.pvfmkwltnan.MvMl" => "__builtin_ve_vl_pvfmkwltnan_MvMl", + "llvm.ve.vl.pvfmkwltnan.Mvl" => "__builtin_ve_vl_pvfmkwltnan_Mvl", + "llvm.ve.vl.pvfmkwnan.MvMl" => "__builtin_ve_vl_pvfmkwnan_MvMl", + "llvm.ve.vl.pvfmkwnan.Mvl" => "__builtin_ve_vl_pvfmkwnan_Mvl", + "llvm.ve.vl.pvfmkwne.MvMl" => "__builtin_ve_vl_pvfmkwne_MvMl", + "llvm.ve.vl.pvfmkwne.Mvl" => "__builtin_ve_vl_pvfmkwne_Mvl", + "llvm.ve.vl.pvfmkwnenan.MvMl" => "__builtin_ve_vl_pvfmkwnenan_MvMl", + "llvm.ve.vl.pvfmkwnenan.Mvl" => "__builtin_ve_vl_pvfmkwnenan_Mvl", + "llvm.ve.vl.pvfmkwnum.MvMl" => "__builtin_ve_vl_pvfmkwnum_MvMl", + "llvm.ve.vl.pvfmkwnum.Mvl" => "__builtin_ve_vl_pvfmkwnum_Mvl", + "llvm.ve.vl.pvfmkwupeq.mvl" => "__builtin_ve_vl_pvfmkwupeq_mvl", + "llvm.ve.vl.pvfmkwupeq.mvml" => "__builtin_ve_vl_pvfmkwupeq_mvml", + "llvm.ve.vl.pvfmkwupeqnan.mvl" => "__builtin_ve_vl_pvfmkwupeqnan_mvl", + "llvm.ve.vl.pvfmkwupeqnan.mvml" => "__builtin_ve_vl_pvfmkwupeqnan_mvml", + "llvm.ve.vl.pvfmkwupge.mvl" => "__builtin_ve_vl_pvfmkwupge_mvl", + "llvm.ve.vl.pvfmkwupge.mvml" => "__builtin_ve_vl_pvfmkwupge_mvml", + "llvm.ve.vl.pvfmkwupgenan.mvl" => "__builtin_ve_vl_pvfmkwupgenan_mvl", + "llvm.ve.vl.pvfmkwupgenan.mvml" => "__builtin_ve_vl_pvfmkwupgenan_mvml", + "llvm.ve.vl.pvfmkwupgt.mvl" => "__builtin_ve_vl_pvfmkwupgt_mvl", + "llvm.ve.vl.pvfmkwupgt.mvml" => "__builtin_ve_vl_pvfmkwupgt_mvml", + "llvm.ve.vl.pvfmkwupgtnan.mvl" => "__builtin_ve_vl_pvfmkwupgtnan_mvl", + "llvm.ve.vl.pvfmkwupgtnan.mvml" => "__builtin_ve_vl_pvfmkwupgtnan_mvml", + "llvm.ve.vl.pvfmkwuple.mvl" => "__builtin_ve_vl_pvfmkwuple_mvl", + "llvm.ve.vl.pvfmkwuple.mvml" => "__builtin_ve_vl_pvfmkwuple_mvml", + "llvm.ve.vl.pvfmkwuplenan.mvl" => "__builtin_ve_vl_pvfmkwuplenan_mvl", + "llvm.ve.vl.pvfmkwuplenan.mvml" => "__builtin_ve_vl_pvfmkwuplenan_mvml", + "llvm.ve.vl.pvfmkwuplt.mvl" => "__builtin_ve_vl_pvfmkwuplt_mvl", + "llvm.ve.vl.pvfmkwuplt.mvml" => "__builtin_ve_vl_pvfmkwuplt_mvml", + "llvm.ve.vl.pvfmkwupltnan.mvl" => "__builtin_ve_vl_pvfmkwupltnan_mvl", + "llvm.ve.vl.pvfmkwupltnan.mvml" => "__builtin_ve_vl_pvfmkwupltnan_mvml", + "llvm.ve.vl.pvfmkwupnan.mvl" => "__builtin_ve_vl_pvfmkwupnan_mvl", + "llvm.ve.vl.pvfmkwupnan.mvml" => "__builtin_ve_vl_pvfmkwupnan_mvml", + "llvm.ve.vl.pvfmkwupne.mvl" => "__builtin_ve_vl_pvfmkwupne_mvl", + "llvm.ve.vl.pvfmkwupne.mvml" => "__builtin_ve_vl_pvfmkwupne_mvml", + "llvm.ve.vl.pvfmkwupnenan.mvl" => "__builtin_ve_vl_pvfmkwupnenan_mvl", + "llvm.ve.vl.pvfmkwupnenan.mvml" => "__builtin_ve_vl_pvfmkwupnenan_mvml", + "llvm.ve.vl.pvfmkwupnum.mvl" => "__builtin_ve_vl_pvfmkwupnum_mvl", + "llvm.ve.vl.pvfmkwupnum.mvml" => "__builtin_ve_vl_pvfmkwupnum_mvml", + "llvm.ve.vl.pvfmsb.vsvvMvl" => "__builtin_ve_vl_pvfmsb_vsvvMvl", + "llvm.ve.vl.pvfmsb.vsvvl" => "__builtin_ve_vl_pvfmsb_vsvvl", + "llvm.ve.vl.pvfmsb.vsvvvl" => "__builtin_ve_vl_pvfmsb_vsvvvl", + "llvm.ve.vl.pvfmsb.vvsvMvl" => "__builtin_ve_vl_pvfmsb_vvsvMvl", + "llvm.ve.vl.pvfmsb.vvsvl" => "__builtin_ve_vl_pvfmsb_vvsvl", + "llvm.ve.vl.pvfmsb.vvsvvl" => "__builtin_ve_vl_pvfmsb_vvsvvl", + "llvm.ve.vl.pvfmsb.vvvvMvl" => "__builtin_ve_vl_pvfmsb_vvvvMvl", + "llvm.ve.vl.pvfmsb.vvvvl" => "__builtin_ve_vl_pvfmsb_vvvvl", + "llvm.ve.vl.pvfmsb.vvvvvl" => "__builtin_ve_vl_pvfmsb_vvvvvl", + "llvm.ve.vl.pvfmul.vsvMvl" => "__builtin_ve_vl_pvfmul_vsvMvl", + "llvm.ve.vl.pvfmul.vsvl" => "__builtin_ve_vl_pvfmul_vsvl", + "llvm.ve.vl.pvfmul.vsvvl" => "__builtin_ve_vl_pvfmul_vsvvl", + "llvm.ve.vl.pvfmul.vvvMvl" => "__builtin_ve_vl_pvfmul_vvvMvl", + "llvm.ve.vl.pvfmul.vvvl" => "__builtin_ve_vl_pvfmul_vvvl", + "llvm.ve.vl.pvfmul.vvvvl" => "__builtin_ve_vl_pvfmul_vvvvl", + "llvm.ve.vl.pvfnmad.vsvvMvl" => "__builtin_ve_vl_pvfnmad_vsvvMvl", + "llvm.ve.vl.pvfnmad.vsvvl" => "__builtin_ve_vl_pvfnmad_vsvvl", + "llvm.ve.vl.pvfnmad.vsvvvl" => "__builtin_ve_vl_pvfnmad_vsvvvl", + "llvm.ve.vl.pvfnmad.vvsvMvl" => "__builtin_ve_vl_pvfnmad_vvsvMvl", + "llvm.ve.vl.pvfnmad.vvsvl" => "__builtin_ve_vl_pvfnmad_vvsvl", + "llvm.ve.vl.pvfnmad.vvsvvl" => "__builtin_ve_vl_pvfnmad_vvsvvl", + "llvm.ve.vl.pvfnmad.vvvvMvl" => "__builtin_ve_vl_pvfnmad_vvvvMvl", + "llvm.ve.vl.pvfnmad.vvvvl" => "__builtin_ve_vl_pvfnmad_vvvvl", + "llvm.ve.vl.pvfnmad.vvvvvl" => "__builtin_ve_vl_pvfnmad_vvvvvl", + "llvm.ve.vl.pvfnmsb.vsvvMvl" => "__builtin_ve_vl_pvfnmsb_vsvvMvl", + "llvm.ve.vl.pvfnmsb.vsvvl" => "__builtin_ve_vl_pvfnmsb_vsvvl", + "llvm.ve.vl.pvfnmsb.vsvvvl" => "__builtin_ve_vl_pvfnmsb_vsvvvl", + "llvm.ve.vl.pvfnmsb.vvsvMvl" => "__builtin_ve_vl_pvfnmsb_vvsvMvl", + "llvm.ve.vl.pvfnmsb.vvsvl" => "__builtin_ve_vl_pvfnmsb_vvsvl", + "llvm.ve.vl.pvfnmsb.vvsvvl" => "__builtin_ve_vl_pvfnmsb_vvsvvl", + "llvm.ve.vl.pvfnmsb.vvvvMvl" => "__builtin_ve_vl_pvfnmsb_vvvvMvl", + "llvm.ve.vl.pvfnmsb.vvvvl" => "__builtin_ve_vl_pvfnmsb_vvvvl", + "llvm.ve.vl.pvfnmsb.vvvvvl" => "__builtin_ve_vl_pvfnmsb_vvvvvl", + "llvm.ve.vl.pvfsub.vsvMvl" => "__builtin_ve_vl_pvfsub_vsvMvl", + "llvm.ve.vl.pvfsub.vsvl" => "__builtin_ve_vl_pvfsub_vsvl", + "llvm.ve.vl.pvfsub.vsvvl" => "__builtin_ve_vl_pvfsub_vsvvl", + "llvm.ve.vl.pvfsub.vvvMvl" => "__builtin_ve_vl_pvfsub_vvvMvl", + "llvm.ve.vl.pvfsub.vvvl" => "__builtin_ve_vl_pvfsub_vvvl", + "llvm.ve.vl.pvfsub.vvvvl" => "__builtin_ve_vl_pvfsub_vvvvl", + "llvm.ve.vl.pvldz.vvMvl" => "__builtin_ve_vl_pvldz_vvMvl", + "llvm.ve.vl.pvldz.vvl" => "__builtin_ve_vl_pvldz_vvl", + "llvm.ve.vl.pvldz.vvvl" => "__builtin_ve_vl_pvldz_vvvl", + "llvm.ve.vl.pvldzlo.vvl" => "__builtin_ve_vl_pvldzlo_vvl", + "llvm.ve.vl.pvldzlo.vvmvl" => "__builtin_ve_vl_pvldzlo_vvmvl", + "llvm.ve.vl.pvldzlo.vvvl" => "__builtin_ve_vl_pvldzlo_vvvl", + "llvm.ve.vl.pvldzup.vvl" => "__builtin_ve_vl_pvldzup_vvl", + "llvm.ve.vl.pvldzup.vvmvl" => "__builtin_ve_vl_pvldzup_vvmvl", + "llvm.ve.vl.pvldzup.vvvl" => "__builtin_ve_vl_pvldzup_vvvl", + "llvm.ve.vl.pvmaxs.vsvMvl" => "__builtin_ve_vl_pvmaxs_vsvMvl", + "llvm.ve.vl.pvmaxs.vsvl" => "__builtin_ve_vl_pvmaxs_vsvl", + "llvm.ve.vl.pvmaxs.vsvvl" => "__builtin_ve_vl_pvmaxs_vsvvl", + "llvm.ve.vl.pvmaxs.vvvMvl" => "__builtin_ve_vl_pvmaxs_vvvMvl", + "llvm.ve.vl.pvmaxs.vvvl" => "__builtin_ve_vl_pvmaxs_vvvl", + "llvm.ve.vl.pvmaxs.vvvvl" => "__builtin_ve_vl_pvmaxs_vvvvl", + "llvm.ve.vl.pvmins.vsvMvl" => "__builtin_ve_vl_pvmins_vsvMvl", + "llvm.ve.vl.pvmins.vsvl" => "__builtin_ve_vl_pvmins_vsvl", + "llvm.ve.vl.pvmins.vsvvl" => "__builtin_ve_vl_pvmins_vsvvl", + "llvm.ve.vl.pvmins.vvvMvl" => "__builtin_ve_vl_pvmins_vvvMvl", + "llvm.ve.vl.pvmins.vvvl" => "__builtin_ve_vl_pvmins_vvvl", + "llvm.ve.vl.pvmins.vvvvl" => "__builtin_ve_vl_pvmins_vvvvl", + "llvm.ve.vl.pvor.vsvMvl" => "__builtin_ve_vl_pvor_vsvMvl", + "llvm.ve.vl.pvor.vsvl" => "__builtin_ve_vl_pvor_vsvl", + "llvm.ve.vl.pvor.vsvvl" => "__builtin_ve_vl_pvor_vsvvl", + "llvm.ve.vl.pvor.vvvMvl" => "__builtin_ve_vl_pvor_vvvMvl", + "llvm.ve.vl.pvor.vvvl" => "__builtin_ve_vl_pvor_vvvl", + "llvm.ve.vl.pvor.vvvvl" => "__builtin_ve_vl_pvor_vvvvl", + "llvm.ve.vl.pvpcnt.vvMvl" => "__builtin_ve_vl_pvpcnt_vvMvl", + "llvm.ve.vl.pvpcnt.vvl" => "__builtin_ve_vl_pvpcnt_vvl", + "llvm.ve.vl.pvpcnt.vvvl" => "__builtin_ve_vl_pvpcnt_vvvl", + "llvm.ve.vl.pvpcntlo.vvl" => "__builtin_ve_vl_pvpcntlo_vvl", + "llvm.ve.vl.pvpcntlo.vvmvl" => "__builtin_ve_vl_pvpcntlo_vvmvl", + "llvm.ve.vl.pvpcntlo.vvvl" => "__builtin_ve_vl_pvpcntlo_vvvl", + "llvm.ve.vl.pvpcntup.vvl" => "__builtin_ve_vl_pvpcntup_vvl", + "llvm.ve.vl.pvpcntup.vvmvl" => "__builtin_ve_vl_pvpcntup_vvmvl", + "llvm.ve.vl.pvpcntup.vvvl" => "__builtin_ve_vl_pvpcntup_vvvl", + "llvm.ve.vl.pvrcp.vvl" => "__builtin_ve_vl_pvrcp_vvl", + "llvm.ve.vl.pvrcp.vvvl" => "__builtin_ve_vl_pvrcp_vvvl", + "llvm.ve.vl.pvrsqrt.vvl" => "__builtin_ve_vl_pvrsqrt_vvl", + "llvm.ve.vl.pvrsqrt.vvvl" => "__builtin_ve_vl_pvrsqrt_vvvl", + "llvm.ve.vl.pvrsqrtnex.vvl" => "__builtin_ve_vl_pvrsqrtnex_vvl", + "llvm.ve.vl.pvrsqrtnex.vvvl" => "__builtin_ve_vl_pvrsqrtnex_vvvl", + "llvm.ve.vl.pvseq.vl" => "__builtin_ve_vl_pvseq_vl", + "llvm.ve.vl.pvseq.vvl" => "__builtin_ve_vl_pvseq_vvl", + "llvm.ve.vl.pvseqlo.vl" => "__builtin_ve_vl_pvseqlo_vl", + "llvm.ve.vl.pvseqlo.vvl" => "__builtin_ve_vl_pvseqlo_vvl", + "llvm.ve.vl.pvsequp.vl" => "__builtin_ve_vl_pvsequp_vl", + "llvm.ve.vl.pvsequp.vvl" => "__builtin_ve_vl_pvsequp_vvl", + "llvm.ve.vl.pvsla.vvsMvl" => "__builtin_ve_vl_pvsla_vvsMvl", + "llvm.ve.vl.pvsla.vvsl" => "__builtin_ve_vl_pvsla_vvsl", + "llvm.ve.vl.pvsla.vvsvl" => "__builtin_ve_vl_pvsla_vvsvl", + "llvm.ve.vl.pvsla.vvvMvl" => "__builtin_ve_vl_pvsla_vvvMvl", + "llvm.ve.vl.pvsla.vvvl" => "__builtin_ve_vl_pvsla_vvvl", + "llvm.ve.vl.pvsla.vvvvl" => "__builtin_ve_vl_pvsla_vvvvl", + "llvm.ve.vl.pvsll.vvsMvl" => "__builtin_ve_vl_pvsll_vvsMvl", + "llvm.ve.vl.pvsll.vvsl" => "__builtin_ve_vl_pvsll_vvsl", + "llvm.ve.vl.pvsll.vvsvl" => "__builtin_ve_vl_pvsll_vvsvl", + "llvm.ve.vl.pvsll.vvvMvl" => "__builtin_ve_vl_pvsll_vvvMvl", + "llvm.ve.vl.pvsll.vvvl" => "__builtin_ve_vl_pvsll_vvvl", + "llvm.ve.vl.pvsll.vvvvl" => "__builtin_ve_vl_pvsll_vvvvl", + "llvm.ve.vl.pvsra.vvsMvl" => "__builtin_ve_vl_pvsra_vvsMvl", + "llvm.ve.vl.pvsra.vvsl" => "__builtin_ve_vl_pvsra_vvsl", + "llvm.ve.vl.pvsra.vvsvl" => "__builtin_ve_vl_pvsra_vvsvl", + "llvm.ve.vl.pvsra.vvvMvl" => "__builtin_ve_vl_pvsra_vvvMvl", + "llvm.ve.vl.pvsra.vvvl" => "__builtin_ve_vl_pvsra_vvvl", + "llvm.ve.vl.pvsra.vvvvl" => "__builtin_ve_vl_pvsra_vvvvl", + "llvm.ve.vl.pvsrl.vvsMvl" => "__builtin_ve_vl_pvsrl_vvsMvl", + "llvm.ve.vl.pvsrl.vvsl" => "__builtin_ve_vl_pvsrl_vvsl", + "llvm.ve.vl.pvsrl.vvsvl" => "__builtin_ve_vl_pvsrl_vvsvl", + "llvm.ve.vl.pvsrl.vvvMvl" => "__builtin_ve_vl_pvsrl_vvvMvl", + "llvm.ve.vl.pvsrl.vvvl" => "__builtin_ve_vl_pvsrl_vvvl", + "llvm.ve.vl.pvsrl.vvvvl" => "__builtin_ve_vl_pvsrl_vvvvl", + "llvm.ve.vl.pvsubs.vsvMvl" => "__builtin_ve_vl_pvsubs_vsvMvl", + "llvm.ve.vl.pvsubs.vsvl" => "__builtin_ve_vl_pvsubs_vsvl", + "llvm.ve.vl.pvsubs.vsvvl" => "__builtin_ve_vl_pvsubs_vsvvl", + "llvm.ve.vl.pvsubs.vvvMvl" => "__builtin_ve_vl_pvsubs_vvvMvl", + "llvm.ve.vl.pvsubs.vvvl" => "__builtin_ve_vl_pvsubs_vvvl", + "llvm.ve.vl.pvsubs.vvvvl" => "__builtin_ve_vl_pvsubs_vvvvl", + "llvm.ve.vl.pvsubu.vsvMvl" => "__builtin_ve_vl_pvsubu_vsvMvl", + "llvm.ve.vl.pvsubu.vsvl" => "__builtin_ve_vl_pvsubu_vsvl", + "llvm.ve.vl.pvsubu.vsvvl" => "__builtin_ve_vl_pvsubu_vsvvl", + "llvm.ve.vl.pvsubu.vvvMvl" => "__builtin_ve_vl_pvsubu_vvvMvl", + "llvm.ve.vl.pvsubu.vvvl" => "__builtin_ve_vl_pvsubu_vvvl", + "llvm.ve.vl.pvsubu.vvvvl" => "__builtin_ve_vl_pvsubu_vvvvl", + "llvm.ve.vl.pvxor.vsvMvl" => "__builtin_ve_vl_pvxor_vsvMvl", + "llvm.ve.vl.pvxor.vsvl" => "__builtin_ve_vl_pvxor_vsvl", + "llvm.ve.vl.pvxor.vsvvl" => "__builtin_ve_vl_pvxor_vsvvl", + "llvm.ve.vl.pvxor.vvvMvl" => "__builtin_ve_vl_pvxor_vvvMvl", + "llvm.ve.vl.pvxor.vvvl" => "__builtin_ve_vl_pvxor_vvvl", + "llvm.ve.vl.pvxor.vvvvl" => "__builtin_ve_vl_pvxor_vvvvl", + "llvm.ve.vl.scr.sss" => "__builtin_ve_vl_scr_sss", + "llvm.ve.vl.svm.sMs" => "__builtin_ve_vl_svm_sMs", + "llvm.ve.vl.svm.sms" => "__builtin_ve_vl_svm_sms", + "llvm.ve.vl.svob" => "__builtin_ve_vl_svob", + "llvm.ve.vl.tovm.sml" => "__builtin_ve_vl_tovm_sml", + "llvm.ve.vl.tscr.ssss" => "__builtin_ve_vl_tscr_ssss", + "llvm.ve.vl.vaddsl.vsvl" => "__builtin_ve_vl_vaddsl_vsvl", + "llvm.ve.vl.vaddsl.vsvmvl" => "__builtin_ve_vl_vaddsl_vsvmvl", + "llvm.ve.vl.vaddsl.vsvvl" => "__builtin_ve_vl_vaddsl_vsvvl", + "llvm.ve.vl.vaddsl.vvvl" => "__builtin_ve_vl_vaddsl_vvvl", + "llvm.ve.vl.vaddsl.vvvmvl" => "__builtin_ve_vl_vaddsl_vvvmvl", + "llvm.ve.vl.vaddsl.vvvvl" => "__builtin_ve_vl_vaddsl_vvvvl", + "llvm.ve.vl.vaddswsx.vsvl" => "__builtin_ve_vl_vaddswsx_vsvl", + "llvm.ve.vl.vaddswsx.vsvmvl" => "__builtin_ve_vl_vaddswsx_vsvmvl", + "llvm.ve.vl.vaddswsx.vsvvl" => "__builtin_ve_vl_vaddswsx_vsvvl", + "llvm.ve.vl.vaddswsx.vvvl" => "__builtin_ve_vl_vaddswsx_vvvl", + "llvm.ve.vl.vaddswsx.vvvmvl" => "__builtin_ve_vl_vaddswsx_vvvmvl", + "llvm.ve.vl.vaddswsx.vvvvl" => "__builtin_ve_vl_vaddswsx_vvvvl", + "llvm.ve.vl.vaddswzx.vsvl" => "__builtin_ve_vl_vaddswzx_vsvl", + "llvm.ve.vl.vaddswzx.vsvmvl" => "__builtin_ve_vl_vaddswzx_vsvmvl", + "llvm.ve.vl.vaddswzx.vsvvl" => "__builtin_ve_vl_vaddswzx_vsvvl", + "llvm.ve.vl.vaddswzx.vvvl" => "__builtin_ve_vl_vaddswzx_vvvl", + "llvm.ve.vl.vaddswzx.vvvmvl" => "__builtin_ve_vl_vaddswzx_vvvmvl", + "llvm.ve.vl.vaddswzx.vvvvl" => "__builtin_ve_vl_vaddswzx_vvvvl", + "llvm.ve.vl.vaddul.vsvl" => "__builtin_ve_vl_vaddul_vsvl", + "llvm.ve.vl.vaddul.vsvmvl" => "__builtin_ve_vl_vaddul_vsvmvl", + "llvm.ve.vl.vaddul.vsvvl" => "__builtin_ve_vl_vaddul_vsvvl", + "llvm.ve.vl.vaddul.vvvl" => "__builtin_ve_vl_vaddul_vvvl", + "llvm.ve.vl.vaddul.vvvmvl" => "__builtin_ve_vl_vaddul_vvvmvl", + "llvm.ve.vl.vaddul.vvvvl" => "__builtin_ve_vl_vaddul_vvvvl", + "llvm.ve.vl.vadduw.vsvl" => "__builtin_ve_vl_vadduw_vsvl", + "llvm.ve.vl.vadduw.vsvmvl" => "__builtin_ve_vl_vadduw_vsvmvl", + "llvm.ve.vl.vadduw.vsvvl" => "__builtin_ve_vl_vadduw_vsvvl", + "llvm.ve.vl.vadduw.vvvl" => "__builtin_ve_vl_vadduw_vvvl", + "llvm.ve.vl.vadduw.vvvmvl" => "__builtin_ve_vl_vadduw_vvvmvl", + "llvm.ve.vl.vadduw.vvvvl" => "__builtin_ve_vl_vadduw_vvvvl", + "llvm.ve.vl.vand.vsvl" => "__builtin_ve_vl_vand_vsvl", + "llvm.ve.vl.vand.vsvmvl" => "__builtin_ve_vl_vand_vsvmvl", + "llvm.ve.vl.vand.vsvvl" => "__builtin_ve_vl_vand_vsvvl", + "llvm.ve.vl.vand.vvvl" => "__builtin_ve_vl_vand_vvvl", + "llvm.ve.vl.vand.vvvmvl" => "__builtin_ve_vl_vand_vvvmvl", + "llvm.ve.vl.vand.vvvvl" => "__builtin_ve_vl_vand_vvvvl", + "llvm.ve.vl.vbrdd.vsl" => "__builtin_ve_vl_vbrdd_vsl", + "llvm.ve.vl.vbrdd.vsmvl" => "__builtin_ve_vl_vbrdd_vsmvl", + "llvm.ve.vl.vbrdd.vsvl" => "__builtin_ve_vl_vbrdd_vsvl", + "llvm.ve.vl.vbrdl.vsl" => "__builtin_ve_vl_vbrdl_vsl", + "llvm.ve.vl.vbrdl.vsmvl" => "__builtin_ve_vl_vbrdl_vsmvl", + "llvm.ve.vl.vbrdl.vsvl" => "__builtin_ve_vl_vbrdl_vsvl", + "llvm.ve.vl.vbrds.vsl" => "__builtin_ve_vl_vbrds_vsl", + "llvm.ve.vl.vbrds.vsmvl" => "__builtin_ve_vl_vbrds_vsmvl", + "llvm.ve.vl.vbrds.vsvl" => "__builtin_ve_vl_vbrds_vsvl", + "llvm.ve.vl.vbrdw.vsl" => "__builtin_ve_vl_vbrdw_vsl", + "llvm.ve.vl.vbrdw.vsmvl" => "__builtin_ve_vl_vbrdw_vsmvl", + "llvm.ve.vl.vbrdw.vsvl" => "__builtin_ve_vl_vbrdw_vsvl", + "llvm.ve.vl.vbrv.vvl" => "__builtin_ve_vl_vbrv_vvl", + "llvm.ve.vl.vbrv.vvmvl" => "__builtin_ve_vl_vbrv_vvmvl", + "llvm.ve.vl.vbrv.vvvl" => "__builtin_ve_vl_vbrv_vvvl", + "llvm.ve.vl.vcmpsl.vsvl" => "__builtin_ve_vl_vcmpsl_vsvl", + "llvm.ve.vl.vcmpsl.vsvmvl" => "__builtin_ve_vl_vcmpsl_vsvmvl", + "llvm.ve.vl.vcmpsl.vsvvl" => "__builtin_ve_vl_vcmpsl_vsvvl", + "llvm.ve.vl.vcmpsl.vvvl" => "__builtin_ve_vl_vcmpsl_vvvl", + "llvm.ve.vl.vcmpsl.vvvmvl" => "__builtin_ve_vl_vcmpsl_vvvmvl", + "llvm.ve.vl.vcmpsl.vvvvl" => "__builtin_ve_vl_vcmpsl_vvvvl", + "llvm.ve.vl.vcmpswsx.vsvl" => "__builtin_ve_vl_vcmpswsx_vsvl", + "llvm.ve.vl.vcmpswsx.vsvmvl" => "__builtin_ve_vl_vcmpswsx_vsvmvl", + "llvm.ve.vl.vcmpswsx.vsvvl" => "__builtin_ve_vl_vcmpswsx_vsvvl", + "llvm.ve.vl.vcmpswsx.vvvl" => "__builtin_ve_vl_vcmpswsx_vvvl", + "llvm.ve.vl.vcmpswsx.vvvmvl" => "__builtin_ve_vl_vcmpswsx_vvvmvl", + "llvm.ve.vl.vcmpswsx.vvvvl" => "__builtin_ve_vl_vcmpswsx_vvvvl", + "llvm.ve.vl.vcmpswzx.vsvl" => "__builtin_ve_vl_vcmpswzx_vsvl", + "llvm.ve.vl.vcmpswzx.vsvmvl" => "__builtin_ve_vl_vcmpswzx_vsvmvl", + "llvm.ve.vl.vcmpswzx.vsvvl" => "__builtin_ve_vl_vcmpswzx_vsvvl", + "llvm.ve.vl.vcmpswzx.vvvl" => "__builtin_ve_vl_vcmpswzx_vvvl", + "llvm.ve.vl.vcmpswzx.vvvmvl" => "__builtin_ve_vl_vcmpswzx_vvvmvl", + "llvm.ve.vl.vcmpswzx.vvvvl" => "__builtin_ve_vl_vcmpswzx_vvvvl", + "llvm.ve.vl.vcmpul.vsvl" => "__builtin_ve_vl_vcmpul_vsvl", + "llvm.ve.vl.vcmpul.vsvmvl" => "__builtin_ve_vl_vcmpul_vsvmvl", + "llvm.ve.vl.vcmpul.vsvvl" => "__builtin_ve_vl_vcmpul_vsvvl", + "llvm.ve.vl.vcmpul.vvvl" => "__builtin_ve_vl_vcmpul_vvvl", + "llvm.ve.vl.vcmpul.vvvmvl" => "__builtin_ve_vl_vcmpul_vvvmvl", + "llvm.ve.vl.vcmpul.vvvvl" => "__builtin_ve_vl_vcmpul_vvvvl", + "llvm.ve.vl.vcmpuw.vsvl" => "__builtin_ve_vl_vcmpuw_vsvl", + "llvm.ve.vl.vcmpuw.vsvmvl" => "__builtin_ve_vl_vcmpuw_vsvmvl", + "llvm.ve.vl.vcmpuw.vsvvl" => "__builtin_ve_vl_vcmpuw_vsvvl", + "llvm.ve.vl.vcmpuw.vvvl" => "__builtin_ve_vl_vcmpuw_vvvl", + "llvm.ve.vl.vcmpuw.vvvmvl" => "__builtin_ve_vl_vcmpuw_vvvmvl", + "llvm.ve.vl.vcmpuw.vvvvl" => "__builtin_ve_vl_vcmpuw_vvvvl", + "llvm.ve.vl.vcp.vvmvl" => "__builtin_ve_vl_vcp_vvmvl", + "llvm.ve.vl.vcvtdl.vvl" => "__builtin_ve_vl_vcvtdl_vvl", + "llvm.ve.vl.vcvtdl.vvvl" => "__builtin_ve_vl_vcvtdl_vvvl", + "llvm.ve.vl.vcvtds.vvl" => "__builtin_ve_vl_vcvtds_vvl", + "llvm.ve.vl.vcvtds.vvvl" => "__builtin_ve_vl_vcvtds_vvvl", + "llvm.ve.vl.vcvtdw.vvl" => "__builtin_ve_vl_vcvtdw_vvl", + "llvm.ve.vl.vcvtdw.vvvl" => "__builtin_ve_vl_vcvtdw_vvvl", + "llvm.ve.vl.vcvtld.vvl" => "__builtin_ve_vl_vcvtld_vvl", + "llvm.ve.vl.vcvtld.vvmvl" => "__builtin_ve_vl_vcvtld_vvmvl", + "llvm.ve.vl.vcvtld.vvvl" => "__builtin_ve_vl_vcvtld_vvvl", + "llvm.ve.vl.vcvtldrz.vvl" => "__builtin_ve_vl_vcvtldrz_vvl", + "llvm.ve.vl.vcvtldrz.vvmvl" => "__builtin_ve_vl_vcvtldrz_vvmvl", + "llvm.ve.vl.vcvtldrz.vvvl" => "__builtin_ve_vl_vcvtldrz_vvvl", + "llvm.ve.vl.vcvtsd.vvl" => "__builtin_ve_vl_vcvtsd_vvl", + "llvm.ve.vl.vcvtsd.vvvl" => "__builtin_ve_vl_vcvtsd_vvvl", + "llvm.ve.vl.vcvtsw.vvl" => "__builtin_ve_vl_vcvtsw_vvl", + "llvm.ve.vl.vcvtsw.vvvl" => "__builtin_ve_vl_vcvtsw_vvvl", + "llvm.ve.vl.vcvtwdsx.vvl" => "__builtin_ve_vl_vcvtwdsx_vvl", + "llvm.ve.vl.vcvtwdsx.vvmvl" => "__builtin_ve_vl_vcvtwdsx_vvmvl", + "llvm.ve.vl.vcvtwdsx.vvvl" => "__builtin_ve_vl_vcvtwdsx_vvvl", + "llvm.ve.vl.vcvtwdsxrz.vvl" => "__builtin_ve_vl_vcvtwdsxrz_vvl", + "llvm.ve.vl.vcvtwdsxrz.vvmvl" => "__builtin_ve_vl_vcvtwdsxrz_vvmvl", + "llvm.ve.vl.vcvtwdsxrz.vvvl" => "__builtin_ve_vl_vcvtwdsxrz_vvvl", + "llvm.ve.vl.vcvtwdzx.vvl" => "__builtin_ve_vl_vcvtwdzx_vvl", + "llvm.ve.vl.vcvtwdzx.vvmvl" => "__builtin_ve_vl_vcvtwdzx_vvmvl", + "llvm.ve.vl.vcvtwdzx.vvvl" => "__builtin_ve_vl_vcvtwdzx_vvvl", + "llvm.ve.vl.vcvtwdzxrz.vvl" => "__builtin_ve_vl_vcvtwdzxrz_vvl", + "llvm.ve.vl.vcvtwdzxrz.vvmvl" => "__builtin_ve_vl_vcvtwdzxrz_vvmvl", + "llvm.ve.vl.vcvtwdzxrz.vvvl" => "__builtin_ve_vl_vcvtwdzxrz_vvvl", + "llvm.ve.vl.vcvtwssx.vvl" => "__builtin_ve_vl_vcvtwssx_vvl", + "llvm.ve.vl.vcvtwssx.vvmvl" => "__builtin_ve_vl_vcvtwssx_vvmvl", + "llvm.ve.vl.vcvtwssx.vvvl" => "__builtin_ve_vl_vcvtwssx_vvvl", + "llvm.ve.vl.vcvtwssxrz.vvl" => "__builtin_ve_vl_vcvtwssxrz_vvl", + "llvm.ve.vl.vcvtwssxrz.vvmvl" => "__builtin_ve_vl_vcvtwssxrz_vvmvl", + "llvm.ve.vl.vcvtwssxrz.vvvl" => "__builtin_ve_vl_vcvtwssxrz_vvvl", + "llvm.ve.vl.vcvtwszx.vvl" => "__builtin_ve_vl_vcvtwszx_vvl", + "llvm.ve.vl.vcvtwszx.vvmvl" => "__builtin_ve_vl_vcvtwszx_vvmvl", + "llvm.ve.vl.vcvtwszx.vvvl" => "__builtin_ve_vl_vcvtwszx_vvvl", + "llvm.ve.vl.vcvtwszxrz.vvl" => "__builtin_ve_vl_vcvtwszxrz_vvl", + "llvm.ve.vl.vcvtwszxrz.vvmvl" => "__builtin_ve_vl_vcvtwszxrz_vvmvl", + "llvm.ve.vl.vcvtwszxrz.vvvl" => "__builtin_ve_vl_vcvtwszxrz_vvvl", + "llvm.ve.vl.vdivsl.vsvl" => "__builtin_ve_vl_vdivsl_vsvl", + "llvm.ve.vl.vdivsl.vsvmvl" => "__builtin_ve_vl_vdivsl_vsvmvl", + "llvm.ve.vl.vdivsl.vsvvl" => "__builtin_ve_vl_vdivsl_vsvvl", + "llvm.ve.vl.vdivsl.vvsl" => "__builtin_ve_vl_vdivsl_vvsl", + "llvm.ve.vl.vdivsl.vvsmvl" => "__builtin_ve_vl_vdivsl_vvsmvl", + "llvm.ve.vl.vdivsl.vvsvl" => "__builtin_ve_vl_vdivsl_vvsvl", + "llvm.ve.vl.vdivsl.vvvl" => "__builtin_ve_vl_vdivsl_vvvl", + "llvm.ve.vl.vdivsl.vvvmvl" => "__builtin_ve_vl_vdivsl_vvvmvl", + "llvm.ve.vl.vdivsl.vvvvl" => "__builtin_ve_vl_vdivsl_vvvvl", + "llvm.ve.vl.vdivswsx.vsvl" => "__builtin_ve_vl_vdivswsx_vsvl", + "llvm.ve.vl.vdivswsx.vsvmvl" => "__builtin_ve_vl_vdivswsx_vsvmvl", + "llvm.ve.vl.vdivswsx.vsvvl" => "__builtin_ve_vl_vdivswsx_vsvvl", + "llvm.ve.vl.vdivswsx.vvsl" => "__builtin_ve_vl_vdivswsx_vvsl", + "llvm.ve.vl.vdivswsx.vvsmvl" => "__builtin_ve_vl_vdivswsx_vvsmvl", + "llvm.ve.vl.vdivswsx.vvsvl" => "__builtin_ve_vl_vdivswsx_vvsvl", + "llvm.ve.vl.vdivswsx.vvvl" => "__builtin_ve_vl_vdivswsx_vvvl", + "llvm.ve.vl.vdivswsx.vvvmvl" => "__builtin_ve_vl_vdivswsx_vvvmvl", + "llvm.ve.vl.vdivswsx.vvvvl" => "__builtin_ve_vl_vdivswsx_vvvvl", + "llvm.ve.vl.vdivswzx.vsvl" => "__builtin_ve_vl_vdivswzx_vsvl", + "llvm.ve.vl.vdivswzx.vsvmvl" => "__builtin_ve_vl_vdivswzx_vsvmvl", + "llvm.ve.vl.vdivswzx.vsvvl" => "__builtin_ve_vl_vdivswzx_vsvvl", + "llvm.ve.vl.vdivswzx.vvsl" => "__builtin_ve_vl_vdivswzx_vvsl", + "llvm.ve.vl.vdivswzx.vvsmvl" => "__builtin_ve_vl_vdivswzx_vvsmvl", + "llvm.ve.vl.vdivswzx.vvsvl" => "__builtin_ve_vl_vdivswzx_vvsvl", + "llvm.ve.vl.vdivswzx.vvvl" => "__builtin_ve_vl_vdivswzx_vvvl", + "llvm.ve.vl.vdivswzx.vvvmvl" => "__builtin_ve_vl_vdivswzx_vvvmvl", + "llvm.ve.vl.vdivswzx.vvvvl" => "__builtin_ve_vl_vdivswzx_vvvvl", + "llvm.ve.vl.vdivul.vsvl" => "__builtin_ve_vl_vdivul_vsvl", + "llvm.ve.vl.vdivul.vsvmvl" => "__builtin_ve_vl_vdivul_vsvmvl", + "llvm.ve.vl.vdivul.vsvvl" => "__builtin_ve_vl_vdivul_vsvvl", + "llvm.ve.vl.vdivul.vvsl" => "__builtin_ve_vl_vdivul_vvsl", + "llvm.ve.vl.vdivul.vvsmvl" => "__builtin_ve_vl_vdivul_vvsmvl", + "llvm.ve.vl.vdivul.vvsvl" => "__builtin_ve_vl_vdivul_vvsvl", + "llvm.ve.vl.vdivul.vvvl" => "__builtin_ve_vl_vdivul_vvvl", + "llvm.ve.vl.vdivul.vvvmvl" => "__builtin_ve_vl_vdivul_vvvmvl", + "llvm.ve.vl.vdivul.vvvvl" => "__builtin_ve_vl_vdivul_vvvvl", + "llvm.ve.vl.vdivuw.vsvl" => "__builtin_ve_vl_vdivuw_vsvl", + "llvm.ve.vl.vdivuw.vsvmvl" => "__builtin_ve_vl_vdivuw_vsvmvl", + "llvm.ve.vl.vdivuw.vsvvl" => "__builtin_ve_vl_vdivuw_vsvvl", + "llvm.ve.vl.vdivuw.vvsl" => "__builtin_ve_vl_vdivuw_vvsl", + "llvm.ve.vl.vdivuw.vvsmvl" => "__builtin_ve_vl_vdivuw_vvsmvl", + "llvm.ve.vl.vdivuw.vvsvl" => "__builtin_ve_vl_vdivuw_vvsvl", + "llvm.ve.vl.vdivuw.vvvl" => "__builtin_ve_vl_vdivuw_vvvl", + "llvm.ve.vl.vdivuw.vvvmvl" => "__builtin_ve_vl_vdivuw_vvvmvl", + "llvm.ve.vl.vdivuw.vvvvl" => "__builtin_ve_vl_vdivuw_vvvvl", + "llvm.ve.vl.veqv.vsvl" => "__builtin_ve_vl_veqv_vsvl", + "llvm.ve.vl.veqv.vsvmvl" => "__builtin_ve_vl_veqv_vsvmvl", + "llvm.ve.vl.veqv.vsvvl" => "__builtin_ve_vl_veqv_vsvvl", + "llvm.ve.vl.veqv.vvvl" => "__builtin_ve_vl_veqv_vvvl", + "llvm.ve.vl.veqv.vvvmvl" => "__builtin_ve_vl_veqv_vvvmvl", + "llvm.ve.vl.veqv.vvvvl" => "__builtin_ve_vl_veqv_vvvvl", + "llvm.ve.vl.vex.vvmvl" => "__builtin_ve_vl_vex_vvmvl", + "llvm.ve.vl.vfaddd.vsvl" => "__builtin_ve_vl_vfaddd_vsvl", + "llvm.ve.vl.vfaddd.vsvmvl" => "__builtin_ve_vl_vfaddd_vsvmvl", + "llvm.ve.vl.vfaddd.vsvvl" => "__builtin_ve_vl_vfaddd_vsvvl", + "llvm.ve.vl.vfaddd.vvvl" => "__builtin_ve_vl_vfaddd_vvvl", + "llvm.ve.vl.vfaddd.vvvmvl" => "__builtin_ve_vl_vfaddd_vvvmvl", + "llvm.ve.vl.vfaddd.vvvvl" => "__builtin_ve_vl_vfaddd_vvvvl", + "llvm.ve.vl.vfadds.vsvl" => "__builtin_ve_vl_vfadds_vsvl", + "llvm.ve.vl.vfadds.vsvmvl" => "__builtin_ve_vl_vfadds_vsvmvl", + "llvm.ve.vl.vfadds.vsvvl" => "__builtin_ve_vl_vfadds_vsvvl", + "llvm.ve.vl.vfadds.vvvl" => "__builtin_ve_vl_vfadds_vvvl", + "llvm.ve.vl.vfadds.vvvmvl" => "__builtin_ve_vl_vfadds_vvvmvl", + "llvm.ve.vl.vfadds.vvvvl" => "__builtin_ve_vl_vfadds_vvvvl", + "llvm.ve.vl.vfcmpd.vsvl" => "__builtin_ve_vl_vfcmpd_vsvl", + "llvm.ve.vl.vfcmpd.vsvmvl" => "__builtin_ve_vl_vfcmpd_vsvmvl", + "llvm.ve.vl.vfcmpd.vsvvl" => "__builtin_ve_vl_vfcmpd_vsvvl", + "llvm.ve.vl.vfcmpd.vvvl" => "__builtin_ve_vl_vfcmpd_vvvl", + "llvm.ve.vl.vfcmpd.vvvmvl" => "__builtin_ve_vl_vfcmpd_vvvmvl", + "llvm.ve.vl.vfcmpd.vvvvl" => "__builtin_ve_vl_vfcmpd_vvvvl", + "llvm.ve.vl.vfcmps.vsvl" => "__builtin_ve_vl_vfcmps_vsvl", + "llvm.ve.vl.vfcmps.vsvmvl" => "__builtin_ve_vl_vfcmps_vsvmvl", + "llvm.ve.vl.vfcmps.vsvvl" => "__builtin_ve_vl_vfcmps_vsvvl", + "llvm.ve.vl.vfcmps.vvvl" => "__builtin_ve_vl_vfcmps_vvvl", + "llvm.ve.vl.vfcmps.vvvmvl" => "__builtin_ve_vl_vfcmps_vvvmvl", + "llvm.ve.vl.vfcmps.vvvvl" => "__builtin_ve_vl_vfcmps_vvvvl", + "llvm.ve.vl.vfdivd.vsvl" => "__builtin_ve_vl_vfdivd_vsvl", + "llvm.ve.vl.vfdivd.vsvmvl" => "__builtin_ve_vl_vfdivd_vsvmvl", + "llvm.ve.vl.vfdivd.vsvvl" => "__builtin_ve_vl_vfdivd_vsvvl", + "llvm.ve.vl.vfdivd.vvvl" => "__builtin_ve_vl_vfdivd_vvvl", + "llvm.ve.vl.vfdivd.vvvmvl" => "__builtin_ve_vl_vfdivd_vvvmvl", + "llvm.ve.vl.vfdivd.vvvvl" => "__builtin_ve_vl_vfdivd_vvvvl", + "llvm.ve.vl.vfdivs.vsvl" => "__builtin_ve_vl_vfdivs_vsvl", + "llvm.ve.vl.vfdivs.vsvmvl" => "__builtin_ve_vl_vfdivs_vsvmvl", + "llvm.ve.vl.vfdivs.vsvvl" => "__builtin_ve_vl_vfdivs_vsvvl", + "llvm.ve.vl.vfdivs.vvvl" => "__builtin_ve_vl_vfdivs_vvvl", + "llvm.ve.vl.vfdivs.vvvmvl" => "__builtin_ve_vl_vfdivs_vvvmvl", + "llvm.ve.vl.vfdivs.vvvvl" => "__builtin_ve_vl_vfdivs_vvvvl", + "llvm.ve.vl.vfmadd.vsvvl" => "__builtin_ve_vl_vfmadd_vsvvl", + "llvm.ve.vl.vfmadd.vsvvmvl" => "__builtin_ve_vl_vfmadd_vsvvmvl", + "llvm.ve.vl.vfmadd.vsvvvl" => "__builtin_ve_vl_vfmadd_vsvvvl", + "llvm.ve.vl.vfmadd.vvsvl" => "__builtin_ve_vl_vfmadd_vvsvl", + "llvm.ve.vl.vfmadd.vvsvmvl" => "__builtin_ve_vl_vfmadd_vvsvmvl", + "llvm.ve.vl.vfmadd.vvsvvl" => "__builtin_ve_vl_vfmadd_vvsvvl", + "llvm.ve.vl.vfmadd.vvvvl" => "__builtin_ve_vl_vfmadd_vvvvl", + "llvm.ve.vl.vfmadd.vvvvmvl" => "__builtin_ve_vl_vfmadd_vvvvmvl", + "llvm.ve.vl.vfmadd.vvvvvl" => "__builtin_ve_vl_vfmadd_vvvvvl", + "llvm.ve.vl.vfmads.vsvvl" => "__builtin_ve_vl_vfmads_vsvvl", + "llvm.ve.vl.vfmads.vsvvmvl" => "__builtin_ve_vl_vfmads_vsvvmvl", + "llvm.ve.vl.vfmads.vsvvvl" => "__builtin_ve_vl_vfmads_vsvvvl", + "llvm.ve.vl.vfmads.vvsvl" => "__builtin_ve_vl_vfmads_vvsvl", + "llvm.ve.vl.vfmads.vvsvmvl" => "__builtin_ve_vl_vfmads_vvsvmvl", + "llvm.ve.vl.vfmads.vvsvvl" => "__builtin_ve_vl_vfmads_vvsvvl", + "llvm.ve.vl.vfmads.vvvvl" => "__builtin_ve_vl_vfmads_vvvvl", + "llvm.ve.vl.vfmads.vvvvmvl" => "__builtin_ve_vl_vfmads_vvvvmvl", + "llvm.ve.vl.vfmads.vvvvvl" => "__builtin_ve_vl_vfmads_vvvvvl", + "llvm.ve.vl.vfmaxd.vsvl" => "__builtin_ve_vl_vfmaxd_vsvl", + "llvm.ve.vl.vfmaxd.vsvmvl" => "__builtin_ve_vl_vfmaxd_vsvmvl", + "llvm.ve.vl.vfmaxd.vsvvl" => "__builtin_ve_vl_vfmaxd_vsvvl", + "llvm.ve.vl.vfmaxd.vvvl" => "__builtin_ve_vl_vfmaxd_vvvl", + "llvm.ve.vl.vfmaxd.vvvmvl" => "__builtin_ve_vl_vfmaxd_vvvmvl", + "llvm.ve.vl.vfmaxd.vvvvl" => "__builtin_ve_vl_vfmaxd_vvvvl", + "llvm.ve.vl.vfmaxs.vsvl" => "__builtin_ve_vl_vfmaxs_vsvl", + "llvm.ve.vl.vfmaxs.vsvmvl" => "__builtin_ve_vl_vfmaxs_vsvmvl", + "llvm.ve.vl.vfmaxs.vsvvl" => "__builtin_ve_vl_vfmaxs_vsvvl", + "llvm.ve.vl.vfmaxs.vvvl" => "__builtin_ve_vl_vfmaxs_vvvl", + "llvm.ve.vl.vfmaxs.vvvmvl" => "__builtin_ve_vl_vfmaxs_vvvmvl", + "llvm.ve.vl.vfmaxs.vvvvl" => "__builtin_ve_vl_vfmaxs_vvvvl", + "llvm.ve.vl.vfmind.vsvl" => "__builtin_ve_vl_vfmind_vsvl", + "llvm.ve.vl.vfmind.vsvmvl" => "__builtin_ve_vl_vfmind_vsvmvl", + "llvm.ve.vl.vfmind.vsvvl" => "__builtin_ve_vl_vfmind_vsvvl", + "llvm.ve.vl.vfmind.vvvl" => "__builtin_ve_vl_vfmind_vvvl", + "llvm.ve.vl.vfmind.vvvmvl" => "__builtin_ve_vl_vfmind_vvvmvl", + "llvm.ve.vl.vfmind.vvvvl" => "__builtin_ve_vl_vfmind_vvvvl", + "llvm.ve.vl.vfmins.vsvl" => "__builtin_ve_vl_vfmins_vsvl", + "llvm.ve.vl.vfmins.vsvmvl" => "__builtin_ve_vl_vfmins_vsvmvl", + "llvm.ve.vl.vfmins.vsvvl" => "__builtin_ve_vl_vfmins_vsvvl", + "llvm.ve.vl.vfmins.vvvl" => "__builtin_ve_vl_vfmins_vvvl", + "llvm.ve.vl.vfmins.vvvmvl" => "__builtin_ve_vl_vfmins_vvvmvl", + "llvm.ve.vl.vfmins.vvvvl" => "__builtin_ve_vl_vfmins_vvvvl", + "llvm.ve.vl.vfmkdeq.mvl" => "__builtin_ve_vl_vfmkdeq_mvl", + "llvm.ve.vl.vfmkdeq.mvml" => "__builtin_ve_vl_vfmkdeq_mvml", + "llvm.ve.vl.vfmkdeqnan.mvl" => "__builtin_ve_vl_vfmkdeqnan_mvl", + "llvm.ve.vl.vfmkdeqnan.mvml" => "__builtin_ve_vl_vfmkdeqnan_mvml", + "llvm.ve.vl.vfmkdge.mvl" => "__builtin_ve_vl_vfmkdge_mvl", + "llvm.ve.vl.vfmkdge.mvml" => "__builtin_ve_vl_vfmkdge_mvml", + "llvm.ve.vl.vfmkdgenan.mvl" => "__builtin_ve_vl_vfmkdgenan_mvl", + "llvm.ve.vl.vfmkdgenan.mvml" => "__builtin_ve_vl_vfmkdgenan_mvml", + "llvm.ve.vl.vfmkdgt.mvl" => "__builtin_ve_vl_vfmkdgt_mvl", + "llvm.ve.vl.vfmkdgt.mvml" => "__builtin_ve_vl_vfmkdgt_mvml", + "llvm.ve.vl.vfmkdgtnan.mvl" => "__builtin_ve_vl_vfmkdgtnan_mvl", + "llvm.ve.vl.vfmkdgtnan.mvml" => "__builtin_ve_vl_vfmkdgtnan_mvml", + "llvm.ve.vl.vfmkdle.mvl" => "__builtin_ve_vl_vfmkdle_mvl", + "llvm.ve.vl.vfmkdle.mvml" => "__builtin_ve_vl_vfmkdle_mvml", + "llvm.ve.vl.vfmkdlenan.mvl" => "__builtin_ve_vl_vfmkdlenan_mvl", + "llvm.ve.vl.vfmkdlenan.mvml" => "__builtin_ve_vl_vfmkdlenan_mvml", + "llvm.ve.vl.vfmkdlt.mvl" => "__builtin_ve_vl_vfmkdlt_mvl", + "llvm.ve.vl.vfmkdlt.mvml" => "__builtin_ve_vl_vfmkdlt_mvml", + "llvm.ve.vl.vfmkdltnan.mvl" => "__builtin_ve_vl_vfmkdltnan_mvl", + "llvm.ve.vl.vfmkdltnan.mvml" => "__builtin_ve_vl_vfmkdltnan_mvml", + "llvm.ve.vl.vfmkdnan.mvl" => "__builtin_ve_vl_vfmkdnan_mvl", + "llvm.ve.vl.vfmkdnan.mvml" => "__builtin_ve_vl_vfmkdnan_mvml", + "llvm.ve.vl.vfmkdne.mvl" => "__builtin_ve_vl_vfmkdne_mvl", + "llvm.ve.vl.vfmkdne.mvml" => "__builtin_ve_vl_vfmkdne_mvml", + "llvm.ve.vl.vfmkdnenan.mvl" => "__builtin_ve_vl_vfmkdnenan_mvl", + "llvm.ve.vl.vfmkdnenan.mvml" => "__builtin_ve_vl_vfmkdnenan_mvml", + "llvm.ve.vl.vfmkdnum.mvl" => "__builtin_ve_vl_vfmkdnum_mvl", + "llvm.ve.vl.vfmkdnum.mvml" => "__builtin_ve_vl_vfmkdnum_mvml", + "llvm.ve.vl.vfmklaf.ml" => "__builtin_ve_vl_vfmklaf_ml", + "llvm.ve.vl.vfmklat.ml" => "__builtin_ve_vl_vfmklat_ml", + "llvm.ve.vl.vfmkleq.mvl" => "__builtin_ve_vl_vfmkleq_mvl", + "llvm.ve.vl.vfmkleq.mvml" => "__builtin_ve_vl_vfmkleq_mvml", + "llvm.ve.vl.vfmkleqnan.mvl" => "__builtin_ve_vl_vfmkleqnan_mvl", + "llvm.ve.vl.vfmkleqnan.mvml" => "__builtin_ve_vl_vfmkleqnan_mvml", + "llvm.ve.vl.vfmklge.mvl" => "__builtin_ve_vl_vfmklge_mvl", + "llvm.ve.vl.vfmklge.mvml" => "__builtin_ve_vl_vfmklge_mvml", + "llvm.ve.vl.vfmklgenan.mvl" => "__builtin_ve_vl_vfmklgenan_mvl", + "llvm.ve.vl.vfmklgenan.mvml" => "__builtin_ve_vl_vfmklgenan_mvml", + "llvm.ve.vl.vfmklgt.mvl" => "__builtin_ve_vl_vfmklgt_mvl", + "llvm.ve.vl.vfmklgt.mvml" => "__builtin_ve_vl_vfmklgt_mvml", + "llvm.ve.vl.vfmklgtnan.mvl" => "__builtin_ve_vl_vfmklgtnan_mvl", + "llvm.ve.vl.vfmklgtnan.mvml" => "__builtin_ve_vl_vfmklgtnan_mvml", + "llvm.ve.vl.vfmklle.mvl" => "__builtin_ve_vl_vfmklle_mvl", + "llvm.ve.vl.vfmklle.mvml" => "__builtin_ve_vl_vfmklle_mvml", + "llvm.ve.vl.vfmkllenan.mvl" => "__builtin_ve_vl_vfmkllenan_mvl", + "llvm.ve.vl.vfmkllenan.mvml" => "__builtin_ve_vl_vfmkllenan_mvml", + "llvm.ve.vl.vfmkllt.mvl" => "__builtin_ve_vl_vfmkllt_mvl", + "llvm.ve.vl.vfmkllt.mvml" => "__builtin_ve_vl_vfmkllt_mvml", + "llvm.ve.vl.vfmklltnan.mvl" => "__builtin_ve_vl_vfmklltnan_mvl", + "llvm.ve.vl.vfmklltnan.mvml" => "__builtin_ve_vl_vfmklltnan_mvml", + "llvm.ve.vl.vfmklnan.mvl" => "__builtin_ve_vl_vfmklnan_mvl", + "llvm.ve.vl.vfmklnan.mvml" => "__builtin_ve_vl_vfmklnan_mvml", + "llvm.ve.vl.vfmklne.mvl" => "__builtin_ve_vl_vfmklne_mvl", + "llvm.ve.vl.vfmklne.mvml" => "__builtin_ve_vl_vfmklne_mvml", + "llvm.ve.vl.vfmklnenan.mvl" => "__builtin_ve_vl_vfmklnenan_mvl", + "llvm.ve.vl.vfmklnenan.mvml" => "__builtin_ve_vl_vfmklnenan_mvml", + "llvm.ve.vl.vfmklnum.mvl" => "__builtin_ve_vl_vfmklnum_mvl", + "llvm.ve.vl.vfmklnum.mvml" => "__builtin_ve_vl_vfmklnum_mvml", + "llvm.ve.vl.vfmkseq.mvl" => "__builtin_ve_vl_vfmkseq_mvl", + "llvm.ve.vl.vfmkseq.mvml" => "__builtin_ve_vl_vfmkseq_mvml", + "llvm.ve.vl.vfmkseqnan.mvl" => "__builtin_ve_vl_vfmkseqnan_mvl", + "llvm.ve.vl.vfmkseqnan.mvml" => "__builtin_ve_vl_vfmkseqnan_mvml", + "llvm.ve.vl.vfmksge.mvl" => "__builtin_ve_vl_vfmksge_mvl", + "llvm.ve.vl.vfmksge.mvml" => "__builtin_ve_vl_vfmksge_mvml", + "llvm.ve.vl.vfmksgenan.mvl" => "__builtin_ve_vl_vfmksgenan_mvl", + "llvm.ve.vl.vfmksgenan.mvml" => "__builtin_ve_vl_vfmksgenan_mvml", + "llvm.ve.vl.vfmksgt.mvl" => "__builtin_ve_vl_vfmksgt_mvl", + "llvm.ve.vl.vfmksgt.mvml" => "__builtin_ve_vl_vfmksgt_mvml", + "llvm.ve.vl.vfmksgtnan.mvl" => "__builtin_ve_vl_vfmksgtnan_mvl", + "llvm.ve.vl.vfmksgtnan.mvml" => "__builtin_ve_vl_vfmksgtnan_mvml", + "llvm.ve.vl.vfmksle.mvl" => "__builtin_ve_vl_vfmksle_mvl", + "llvm.ve.vl.vfmksle.mvml" => "__builtin_ve_vl_vfmksle_mvml", + "llvm.ve.vl.vfmkslenan.mvl" => "__builtin_ve_vl_vfmkslenan_mvl", + "llvm.ve.vl.vfmkslenan.mvml" => "__builtin_ve_vl_vfmkslenan_mvml", + "llvm.ve.vl.vfmkslt.mvl" => "__builtin_ve_vl_vfmkslt_mvl", + "llvm.ve.vl.vfmkslt.mvml" => "__builtin_ve_vl_vfmkslt_mvml", + "llvm.ve.vl.vfmksltnan.mvl" => "__builtin_ve_vl_vfmksltnan_mvl", + "llvm.ve.vl.vfmksltnan.mvml" => "__builtin_ve_vl_vfmksltnan_mvml", + "llvm.ve.vl.vfmksnan.mvl" => "__builtin_ve_vl_vfmksnan_mvl", + "llvm.ve.vl.vfmksnan.mvml" => "__builtin_ve_vl_vfmksnan_mvml", + "llvm.ve.vl.vfmksne.mvl" => "__builtin_ve_vl_vfmksne_mvl", + "llvm.ve.vl.vfmksne.mvml" => "__builtin_ve_vl_vfmksne_mvml", + "llvm.ve.vl.vfmksnenan.mvl" => "__builtin_ve_vl_vfmksnenan_mvl", + "llvm.ve.vl.vfmksnenan.mvml" => "__builtin_ve_vl_vfmksnenan_mvml", + "llvm.ve.vl.vfmksnum.mvl" => "__builtin_ve_vl_vfmksnum_mvl", + "llvm.ve.vl.vfmksnum.mvml" => "__builtin_ve_vl_vfmksnum_mvml", + "llvm.ve.vl.vfmkweq.mvl" => "__builtin_ve_vl_vfmkweq_mvl", + "llvm.ve.vl.vfmkweq.mvml" => "__builtin_ve_vl_vfmkweq_mvml", + "llvm.ve.vl.vfmkweqnan.mvl" => "__builtin_ve_vl_vfmkweqnan_mvl", + "llvm.ve.vl.vfmkweqnan.mvml" => "__builtin_ve_vl_vfmkweqnan_mvml", + "llvm.ve.vl.vfmkwge.mvl" => "__builtin_ve_vl_vfmkwge_mvl", + "llvm.ve.vl.vfmkwge.mvml" => "__builtin_ve_vl_vfmkwge_mvml", + "llvm.ve.vl.vfmkwgenan.mvl" => "__builtin_ve_vl_vfmkwgenan_mvl", + "llvm.ve.vl.vfmkwgenan.mvml" => "__builtin_ve_vl_vfmkwgenan_mvml", + "llvm.ve.vl.vfmkwgt.mvl" => "__builtin_ve_vl_vfmkwgt_mvl", + "llvm.ve.vl.vfmkwgt.mvml" => "__builtin_ve_vl_vfmkwgt_mvml", + "llvm.ve.vl.vfmkwgtnan.mvl" => "__builtin_ve_vl_vfmkwgtnan_mvl", + "llvm.ve.vl.vfmkwgtnan.mvml" => "__builtin_ve_vl_vfmkwgtnan_mvml", + "llvm.ve.vl.vfmkwle.mvl" => "__builtin_ve_vl_vfmkwle_mvl", + "llvm.ve.vl.vfmkwle.mvml" => "__builtin_ve_vl_vfmkwle_mvml", + "llvm.ve.vl.vfmkwlenan.mvl" => "__builtin_ve_vl_vfmkwlenan_mvl", + "llvm.ve.vl.vfmkwlenan.mvml" => "__builtin_ve_vl_vfmkwlenan_mvml", + "llvm.ve.vl.vfmkwlt.mvl" => "__builtin_ve_vl_vfmkwlt_mvl", + "llvm.ve.vl.vfmkwlt.mvml" => "__builtin_ve_vl_vfmkwlt_mvml", + "llvm.ve.vl.vfmkwltnan.mvl" => "__builtin_ve_vl_vfmkwltnan_mvl", + "llvm.ve.vl.vfmkwltnan.mvml" => "__builtin_ve_vl_vfmkwltnan_mvml", + "llvm.ve.vl.vfmkwnan.mvl" => "__builtin_ve_vl_vfmkwnan_mvl", + "llvm.ve.vl.vfmkwnan.mvml" => "__builtin_ve_vl_vfmkwnan_mvml", + "llvm.ve.vl.vfmkwne.mvl" => "__builtin_ve_vl_vfmkwne_mvl", + "llvm.ve.vl.vfmkwne.mvml" => "__builtin_ve_vl_vfmkwne_mvml", + "llvm.ve.vl.vfmkwnenan.mvl" => "__builtin_ve_vl_vfmkwnenan_mvl", + "llvm.ve.vl.vfmkwnenan.mvml" => "__builtin_ve_vl_vfmkwnenan_mvml", + "llvm.ve.vl.vfmkwnum.mvl" => "__builtin_ve_vl_vfmkwnum_mvl", + "llvm.ve.vl.vfmkwnum.mvml" => "__builtin_ve_vl_vfmkwnum_mvml", + "llvm.ve.vl.vfmsbd.vsvvl" => "__builtin_ve_vl_vfmsbd_vsvvl", + "llvm.ve.vl.vfmsbd.vsvvmvl" => "__builtin_ve_vl_vfmsbd_vsvvmvl", + "llvm.ve.vl.vfmsbd.vsvvvl" => "__builtin_ve_vl_vfmsbd_vsvvvl", + "llvm.ve.vl.vfmsbd.vvsvl" => "__builtin_ve_vl_vfmsbd_vvsvl", + "llvm.ve.vl.vfmsbd.vvsvmvl" => "__builtin_ve_vl_vfmsbd_vvsvmvl", + "llvm.ve.vl.vfmsbd.vvsvvl" => "__builtin_ve_vl_vfmsbd_vvsvvl", + "llvm.ve.vl.vfmsbd.vvvvl" => "__builtin_ve_vl_vfmsbd_vvvvl", + "llvm.ve.vl.vfmsbd.vvvvmvl" => "__builtin_ve_vl_vfmsbd_vvvvmvl", + "llvm.ve.vl.vfmsbd.vvvvvl" => "__builtin_ve_vl_vfmsbd_vvvvvl", + "llvm.ve.vl.vfmsbs.vsvvl" => "__builtin_ve_vl_vfmsbs_vsvvl", + "llvm.ve.vl.vfmsbs.vsvvmvl" => "__builtin_ve_vl_vfmsbs_vsvvmvl", + "llvm.ve.vl.vfmsbs.vsvvvl" => "__builtin_ve_vl_vfmsbs_vsvvvl", + "llvm.ve.vl.vfmsbs.vvsvl" => "__builtin_ve_vl_vfmsbs_vvsvl", + "llvm.ve.vl.vfmsbs.vvsvmvl" => "__builtin_ve_vl_vfmsbs_vvsvmvl", + "llvm.ve.vl.vfmsbs.vvsvvl" => "__builtin_ve_vl_vfmsbs_vvsvvl", + "llvm.ve.vl.vfmsbs.vvvvl" => "__builtin_ve_vl_vfmsbs_vvvvl", + "llvm.ve.vl.vfmsbs.vvvvmvl" => "__builtin_ve_vl_vfmsbs_vvvvmvl", + "llvm.ve.vl.vfmsbs.vvvvvl" => "__builtin_ve_vl_vfmsbs_vvvvvl", + "llvm.ve.vl.vfmuld.vsvl" => "__builtin_ve_vl_vfmuld_vsvl", + "llvm.ve.vl.vfmuld.vsvmvl" => "__builtin_ve_vl_vfmuld_vsvmvl", + "llvm.ve.vl.vfmuld.vsvvl" => "__builtin_ve_vl_vfmuld_vsvvl", + "llvm.ve.vl.vfmuld.vvvl" => "__builtin_ve_vl_vfmuld_vvvl", + "llvm.ve.vl.vfmuld.vvvmvl" => "__builtin_ve_vl_vfmuld_vvvmvl", + "llvm.ve.vl.vfmuld.vvvvl" => "__builtin_ve_vl_vfmuld_vvvvl", + "llvm.ve.vl.vfmuls.vsvl" => "__builtin_ve_vl_vfmuls_vsvl", + "llvm.ve.vl.vfmuls.vsvmvl" => "__builtin_ve_vl_vfmuls_vsvmvl", + "llvm.ve.vl.vfmuls.vsvvl" => "__builtin_ve_vl_vfmuls_vsvvl", + "llvm.ve.vl.vfmuls.vvvl" => "__builtin_ve_vl_vfmuls_vvvl", + "llvm.ve.vl.vfmuls.vvvmvl" => "__builtin_ve_vl_vfmuls_vvvmvl", + "llvm.ve.vl.vfmuls.vvvvl" => "__builtin_ve_vl_vfmuls_vvvvl", + "llvm.ve.vl.vfnmadd.vsvvl" => "__builtin_ve_vl_vfnmadd_vsvvl", + "llvm.ve.vl.vfnmadd.vsvvmvl" => "__builtin_ve_vl_vfnmadd_vsvvmvl", + "llvm.ve.vl.vfnmadd.vsvvvl" => "__builtin_ve_vl_vfnmadd_vsvvvl", + "llvm.ve.vl.vfnmadd.vvsvl" => "__builtin_ve_vl_vfnmadd_vvsvl", + "llvm.ve.vl.vfnmadd.vvsvmvl" => "__builtin_ve_vl_vfnmadd_vvsvmvl", + "llvm.ve.vl.vfnmadd.vvsvvl" => "__builtin_ve_vl_vfnmadd_vvsvvl", + "llvm.ve.vl.vfnmadd.vvvvl" => "__builtin_ve_vl_vfnmadd_vvvvl", + "llvm.ve.vl.vfnmadd.vvvvmvl" => "__builtin_ve_vl_vfnmadd_vvvvmvl", + "llvm.ve.vl.vfnmadd.vvvvvl" => "__builtin_ve_vl_vfnmadd_vvvvvl", + "llvm.ve.vl.vfnmads.vsvvl" => "__builtin_ve_vl_vfnmads_vsvvl", + "llvm.ve.vl.vfnmads.vsvvmvl" => "__builtin_ve_vl_vfnmads_vsvvmvl", + "llvm.ve.vl.vfnmads.vsvvvl" => "__builtin_ve_vl_vfnmads_vsvvvl", + "llvm.ve.vl.vfnmads.vvsvl" => "__builtin_ve_vl_vfnmads_vvsvl", + "llvm.ve.vl.vfnmads.vvsvmvl" => "__builtin_ve_vl_vfnmads_vvsvmvl", + "llvm.ve.vl.vfnmads.vvsvvl" => "__builtin_ve_vl_vfnmads_vvsvvl", + "llvm.ve.vl.vfnmads.vvvvl" => "__builtin_ve_vl_vfnmads_vvvvl", + "llvm.ve.vl.vfnmads.vvvvmvl" => "__builtin_ve_vl_vfnmads_vvvvmvl", + "llvm.ve.vl.vfnmads.vvvvvl" => "__builtin_ve_vl_vfnmads_vvvvvl", + "llvm.ve.vl.vfnmsbd.vsvvl" => "__builtin_ve_vl_vfnmsbd_vsvvl", + "llvm.ve.vl.vfnmsbd.vsvvmvl" => "__builtin_ve_vl_vfnmsbd_vsvvmvl", + "llvm.ve.vl.vfnmsbd.vsvvvl" => "__builtin_ve_vl_vfnmsbd_vsvvvl", + "llvm.ve.vl.vfnmsbd.vvsvl" => "__builtin_ve_vl_vfnmsbd_vvsvl", + "llvm.ve.vl.vfnmsbd.vvsvmvl" => "__builtin_ve_vl_vfnmsbd_vvsvmvl", + "llvm.ve.vl.vfnmsbd.vvsvvl" => "__builtin_ve_vl_vfnmsbd_vvsvvl", + "llvm.ve.vl.vfnmsbd.vvvvl" => "__builtin_ve_vl_vfnmsbd_vvvvl", + "llvm.ve.vl.vfnmsbd.vvvvmvl" => "__builtin_ve_vl_vfnmsbd_vvvvmvl", + "llvm.ve.vl.vfnmsbd.vvvvvl" => "__builtin_ve_vl_vfnmsbd_vvvvvl", + "llvm.ve.vl.vfnmsbs.vsvvl" => "__builtin_ve_vl_vfnmsbs_vsvvl", + "llvm.ve.vl.vfnmsbs.vsvvmvl" => "__builtin_ve_vl_vfnmsbs_vsvvmvl", + "llvm.ve.vl.vfnmsbs.vsvvvl" => "__builtin_ve_vl_vfnmsbs_vsvvvl", + "llvm.ve.vl.vfnmsbs.vvsvl" => "__builtin_ve_vl_vfnmsbs_vvsvl", + "llvm.ve.vl.vfnmsbs.vvsvmvl" => "__builtin_ve_vl_vfnmsbs_vvsvmvl", + "llvm.ve.vl.vfnmsbs.vvsvvl" => "__builtin_ve_vl_vfnmsbs_vvsvvl", + "llvm.ve.vl.vfnmsbs.vvvvl" => "__builtin_ve_vl_vfnmsbs_vvvvl", + "llvm.ve.vl.vfnmsbs.vvvvmvl" => "__builtin_ve_vl_vfnmsbs_vvvvmvl", + "llvm.ve.vl.vfnmsbs.vvvvvl" => "__builtin_ve_vl_vfnmsbs_vvvvvl", + "llvm.ve.vl.vfrmaxdfst.vvl" => "__builtin_ve_vl_vfrmaxdfst_vvl", + "llvm.ve.vl.vfrmaxdfst.vvvl" => "__builtin_ve_vl_vfrmaxdfst_vvvl", + "llvm.ve.vl.vfrmaxdlst.vvl" => "__builtin_ve_vl_vfrmaxdlst_vvl", + "llvm.ve.vl.vfrmaxdlst.vvvl" => "__builtin_ve_vl_vfrmaxdlst_vvvl", + "llvm.ve.vl.vfrmaxsfst.vvl" => "__builtin_ve_vl_vfrmaxsfst_vvl", + "llvm.ve.vl.vfrmaxsfst.vvvl" => "__builtin_ve_vl_vfrmaxsfst_vvvl", + "llvm.ve.vl.vfrmaxslst.vvl" => "__builtin_ve_vl_vfrmaxslst_vvl", + "llvm.ve.vl.vfrmaxslst.vvvl" => "__builtin_ve_vl_vfrmaxslst_vvvl", + "llvm.ve.vl.vfrmindfst.vvl" => "__builtin_ve_vl_vfrmindfst_vvl", + "llvm.ve.vl.vfrmindfst.vvvl" => "__builtin_ve_vl_vfrmindfst_vvvl", + "llvm.ve.vl.vfrmindlst.vvl" => "__builtin_ve_vl_vfrmindlst_vvl", + "llvm.ve.vl.vfrmindlst.vvvl" => "__builtin_ve_vl_vfrmindlst_vvvl", + "llvm.ve.vl.vfrminsfst.vvl" => "__builtin_ve_vl_vfrminsfst_vvl", + "llvm.ve.vl.vfrminsfst.vvvl" => "__builtin_ve_vl_vfrminsfst_vvvl", + "llvm.ve.vl.vfrminslst.vvl" => "__builtin_ve_vl_vfrminslst_vvl", + "llvm.ve.vl.vfrminslst.vvvl" => "__builtin_ve_vl_vfrminslst_vvvl", + "llvm.ve.vl.vfsqrtd.vvl" => "__builtin_ve_vl_vfsqrtd_vvl", + "llvm.ve.vl.vfsqrtd.vvvl" => "__builtin_ve_vl_vfsqrtd_vvvl", + "llvm.ve.vl.vfsqrts.vvl" => "__builtin_ve_vl_vfsqrts_vvl", + "llvm.ve.vl.vfsqrts.vvvl" => "__builtin_ve_vl_vfsqrts_vvvl", + "llvm.ve.vl.vfsubd.vsvl" => "__builtin_ve_vl_vfsubd_vsvl", + "llvm.ve.vl.vfsubd.vsvmvl" => "__builtin_ve_vl_vfsubd_vsvmvl", + "llvm.ve.vl.vfsubd.vsvvl" => "__builtin_ve_vl_vfsubd_vsvvl", + "llvm.ve.vl.vfsubd.vvvl" => "__builtin_ve_vl_vfsubd_vvvl", + "llvm.ve.vl.vfsubd.vvvmvl" => "__builtin_ve_vl_vfsubd_vvvmvl", + "llvm.ve.vl.vfsubd.vvvvl" => "__builtin_ve_vl_vfsubd_vvvvl", + "llvm.ve.vl.vfsubs.vsvl" => "__builtin_ve_vl_vfsubs_vsvl", + "llvm.ve.vl.vfsubs.vsvmvl" => "__builtin_ve_vl_vfsubs_vsvmvl", + "llvm.ve.vl.vfsubs.vsvvl" => "__builtin_ve_vl_vfsubs_vsvvl", + "llvm.ve.vl.vfsubs.vvvl" => "__builtin_ve_vl_vfsubs_vvvl", + "llvm.ve.vl.vfsubs.vvvmvl" => "__builtin_ve_vl_vfsubs_vvvmvl", + "llvm.ve.vl.vfsubs.vvvvl" => "__builtin_ve_vl_vfsubs_vvvvl", + "llvm.ve.vl.vfsumd.vvl" => "__builtin_ve_vl_vfsumd_vvl", + "llvm.ve.vl.vfsumd.vvml" => "__builtin_ve_vl_vfsumd_vvml", + "llvm.ve.vl.vfsums.vvl" => "__builtin_ve_vl_vfsums_vvl", + "llvm.ve.vl.vfsums.vvml" => "__builtin_ve_vl_vfsums_vvml", + "llvm.ve.vl.vgt.vvssl" => "__builtin_ve_vl_vgt_vvssl", + "llvm.ve.vl.vgt.vvssml" => "__builtin_ve_vl_vgt_vvssml", + "llvm.ve.vl.vgt.vvssmvl" => "__builtin_ve_vl_vgt_vvssmvl", + "llvm.ve.vl.vgt.vvssvl" => "__builtin_ve_vl_vgt_vvssvl", + "llvm.ve.vl.vgtlsx.vvssl" => "__builtin_ve_vl_vgtlsx_vvssl", + "llvm.ve.vl.vgtlsx.vvssml" => "__builtin_ve_vl_vgtlsx_vvssml", + "llvm.ve.vl.vgtlsx.vvssmvl" => "__builtin_ve_vl_vgtlsx_vvssmvl", + "llvm.ve.vl.vgtlsx.vvssvl" => "__builtin_ve_vl_vgtlsx_vvssvl", + "llvm.ve.vl.vgtlsxnc.vvssl" => "__builtin_ve_vl_vgtlsxnc_vvssl", + "llvm.ve.vl.vgtlsxnc.vvssml" => "__builtin_ve_vl_vgtlsxnc_vvssml", + "llvm.ve.vl.vgtlsxnc.vvssmvl" => "__builtin_ve_vl_vgtlsxnc_vvssmvl", + "llvm.ve.vl.vgtlsxnc.vvssvl" => "__builtin_ve_vl_vgtlsxnc_vvssvl", + "llvm.ve.vl.vgtlzx.vvssl" => "__builtin_ve_vl_vgtlzx_vvssl", + "llvm.ve.vl.vgtlzx.vvssml" => "__builtin_ve_vl_vgtlzx_vvssml", + "llvm.ve.vl.vgtlzx.vvssmvl" => "__builtin_ve_vl_vgtlzx_vvssmvl", + "llvm.ve.vl.vgtlzx.vvssvl" => "__builtin_ve_vl_vgtlzx_vvssvl", + "llvm.ve.vl.vgtlzxnc.vvssl" => "__builtin_ve_vl_vgtlzxnc_vvssl", + "llvm.ve.vl.vgtlzxnc.vvssml" => "__builtin_ve_vl_vgtlzxnc_vvssml", + "llvm.ve.vl.vgtlzxnc.vvssmvl" => "__builtin_ve_vl_vgtlzxnc_vvssmvl", + "llvm.ve.vl.vgtlzxnc.vvssvl" => "__builtin_ve_vl_vgtlzxnc_vvssvl", + "llvm.ve.vl.vgtnc.vvssl" => "__builtin_ve_vl_vgtnc_vvssl", + "llvm.ve.vl.vgtnc.vvssml" => "__builtin_ve_vl_vgtnc_vvssml", + "llvm.ve.vl.vgtnc.vvssmvl" => "__builtin_ve_vl_vgtnc_vvssmvl", + "llvm.ve.vl.vgtnc.vvssvl" => "__builtin_ve_vl_vgtnc_vvssvl", + "llvm.ve.vl.vgtu.vvssl" => "__builtin_ve_vl_vgtu_vvssl", + "llvm.ve.vl.vgtu.vvssml" => "__builtin_ve_vl_vgtu_vvssml", + "llvm.ve.vl.vgtu.vvssmvl" => "__builtin_ve_vl_vgtu_vvssmvl", + "llvm.ve.vl.vgtu.vvssvl" => "__builtin_ve_vl_vgtu_vvssvl", + "llvm.ve.vl.vgtunc.vvssl" => "__builtin_ve_vl_vgtunc_vvssl", + "llvm.ve.vl.vgtunc.vvssml" => "__builtin_ve_vl_vgtunc_vvssml", + "llvm.ve.vl.vgtunc.vvssmvl" => "__builtin_ve_vl_vgtunc_vvssmvl", + "llvm.ve.vl.vgtunc.vvssvl" => "__builtin_ve_vl_vgtunc_vvssvl", + "llvm.ve.vl.vld.vssl" => "__builtin_ve_vl_vld_vssl", + "llvm.ve.vl.vld.vssvl" => "__builtin_ve_vl_vld_vssvl", + "llvm.ve.vl.vld2d.vssl" => "__builtin_ve_vl_vld2d_vssl", + "llvm.ve.vl.vld2d.vssvl" => "__builtin_ve_vl_vld2d_vssvl", + "llvm.ve.vl.vld2dnc.vssl" => "__builtin_ve_vl_vld2dnc_vssl", + "llvm.ve.vl.vld2dnc.vssvl" => "__builtin_ve_vl_vld2dnc_vssvl", + "llvm.ve.vl.vldl2dsx.vssl" => "__builtin_ve_vl_vldl2dsx_vssl", + "llvm.ve.vl.vldl2dsx.vssvl" => "__builtin_ve_vl_vldl2dsx_vssvl", + "llvm.ve.vl.vldl2dsxnc.vssl" => "__builtin_ve_vl_vldl2dsxnc_vssl", + "llvm.ve.vl.vldl2dsxnc.vssvl" => "__builtin_ve_vl_vldl2dsxnc_vssvl", + "llvm.ve.vl.vldl2dzx.vssl" => "__builtin_ve_vl_vldl2dzx_vssl", + "llvm.ve.vl.vldl2dzx.vssvl" => "__builtin_ve_vl_vldl2dzx_vssvl", + "llvm.ve.vl.vldl2dzxnc.vssl" => "__builtin_ve_vl_vldl2dzxnc_vssl", + "llvm.ve.vl.vldl2dzxnc.vssvl" => "__builtin_ve_vl_vldl2dzxnc_vssvl", + "llvm.ve.vl.vldlsx.vssl" => "__builtin_ve_vl_vldlsx_vssl", + "llvm.ve.vl.vldlsx.vssvl" => "__builtin_ve_vl_vldlsx_vssvl", + "llvm.ve.vl.vldlsxnc.vssl" => "__builtin_ve_vl_vldlsxnc_vssl", + "llvm.ve.vl.vldlsxnc.vssvl" => "__builtin_ve_vl_vldlsxnc_vssvl", + "llvm.ve.vl.vldlzx.vssl" => "__builtin_ve_vl_vldlzx_vssl", + "llvm.ve.vl.vldlzx.vssvl" => "__builtin_ve_vl_vldlzx_vssvl", + "llvm.ve.vl.vldlzxnc.vssl" => "__builtin_ve_vl_vldlzxnc_vssl", + "llvm.ve.vl.vldlzxnc.vssvl" => "__builtin_ve_vl_vldlzxnc_vssvl", + "llvm.ve.vl.vldnc.vssl" => "__builtin_ve_vl_vldnc_vssl", + "llvm.ve.vl.vldnc.vssvl" => "__builtin_ve_vl_vldnc_vssvl", + "llvm.ve.vl.vldu.vssl" => "__builtin_ve_vl_vldu_vssl", + "llvm.ve.vl.vldu.vssvl" => "__builtin_ve_vl_vldu_vssvl", + "llvm.ve.vl.vldu2d.vssl" => "__builtin_ve_vl_vldu2d_vssl", + "llvm.ve.vl.vldu2d.vssvl" => "__builtin_ve_vl_vldu2d_vssvl", + "llvm.ve.vl.vldu2dnc.vssl" => "__builtin_ve_vl_vldu2dnc_vssl", + "llvm.ve.vl.vldu2dnc.vssvl" => "__builtin_ve_vl_vldu2dnc_vssvl", + "llvm.ve.vl.vldunc.vssl" => "__builtin_ve_vl_vldunc_vssl", + "llvm.ve.vl.vldunc.vssvl" => "__builtin_ve_vl_vldunc_vssvl", + "llvm.ve.vl.vldz.vvl" => "__builtin_ve_vl_vldz_vvl", + "llvm.ve.vl.vldz.vvmvl" => "__builtin_ve_vl_vldz_vvmvl", + "llvm.ve.vl.vldz.vvvl" => "__builtin_ve_vl_vldz_vvvl", + "llvm.ve.vl.vmaxsl.vsvl" => "__builtin_ve_vl_vmaxsl_vsvl", + "llvm.ve.vl.vmaxsl.vsvmvl" => "__builtin_ve_vl_vmaxsl_vsvmvl", + "llvm.ve.vl.vmaxsl.vsvvl" => "__builtin_ve_vl_vmaxsl_vsvvl", + "llvm.ve.vl.vmaxsl.vvvl" => "__builtin_ve_vl_vmaxsl_vvvl", + "llvm.ve.vl.vmaxsl.vvvmvl" => "__builtin_ve_vl_vmaxsl_vvvmvl", + "llvm.ve.vl.vmaxsl.vvvvl" => "__builtin_ve_vl_vmaxsl_vvvvl", + "llvm.ve.vl.vmaxswsx.vsvl" => "__builtin_ve_vl_vmaxswsx_vsvl", + "llvm.ve.vl.vmaxswsx.vsvmvl" => "__builtin_ve_vl_vmaxswsx_vsvmvl", + "llvm.ve.vl.vmaxswsx.vsvvl" => "__builtin_ve_vl_vmaxswsx_vsvvl", + "llvm.ve.vl.vmaxswsx.vvvl" => "__builtin_ve_vl_vmaxswsx_vvvl", + "llvm.ve.vl.vmaxswsx.vvvmvl" => "__builtin_ve_vl_vmaxswsx_vvvmvl", + "llvm.ve.vl.vmaxswsx.vvvvl" => "__builtin_ve_vl_vmaxswsx_vvvvl", + "llvm.ve.vl.vmaxswzx.vsvl" => "__builtin_ve_vl_vmaxswzx_vsvl", + "llvm.ve.vl.vmaxswzx.vsvmvl" => "__builtin_ve_vl_vmaxswzx_vsvmvl", + "llvm.ve.vl.vmaxswzx.vsvvl" => "__builtin_ve_vl_vmaxswzx_vsvvl", + "llvm.ve.vl.vmaxswzx.vvvl" => "__builtin_ve_vl_vmaxswzx_vvvl", + "llvm.ve.vl.vmaxswzx.vvvmvl" => "__builtin_ve_vl_vmaxswzx_vvvmvl", + "llvm.ve.vl.vmaxswzx.vvvvl" => "__builtin_ve_vl_vmaxswzx_vvvvl", + "llvm.ve.vl.vminsl.vsvl" => "__builtin_ve_vl_vminsl_vsvl", + "llvm.ve.vl.vminsl.vsvmvl" => "__builtin_ve_vl_vminsl_vsvmvl", + "llvm.ve.vl.vminsl.vsvvl" => "__builtin_ve_vl_vminsl_vsvvl", + "llvm.ve.vl.vminsl.vvvl" => "__builtin_ve_vl_vminsl_vvvl", + "llvm.ve.vl.vminsl.vvvmvl" => "__builtin_ve_vl_vminsl_vvvmvl", + "llvm.ve.vl.vminsl.vvvvl" => "__builtin_ve_vl_vminsl_vvvvl", + "llvm.ve.vl.vminswsx.vsvl" => "__builtin_ve_vl_vminswsx_vsvl", + "llvm.ve.vl.vminswsx.vsvmvl" => "__builtin_ve_vl_vminswsx_vsvmvl", + "llvm.ve.vl.vminswsx.vsvvl" => "__builtin_ve_vl_vminswsx_vsvvl", + "llvm.ve.vl.vminswsx.vvvl" => "__builtin_ve_vl_vminswsx_vvvl", + "llvm.ve.vl.vminswsx.vvvmvl" => "__builtin_ve_vl_vminswsx_vvvmvl", + "llvm.ve.vl.vminswsx.vvvvl" => "__builtin_ve_vl_vminswsx_vvvvl", + "llvm.ve.vl.vminswzx.vsvl" => "__builtin_ve_vl_vminswzx_vsvl", + "llvm.ve.vl.vminswzx.vsvmvl" => "__builtin_ve_vl_vminswzx_vsvmvl", + "llvm.ve.vl.vminswzx.vsvvl" => "__builtin_ve_vl_vminswzx_vsvvl", + "llvm.ve.vl.vminswzx.vvvl" => "__builtin_ve_vl_vminswzx_vvvl", + "llvm.ve.vl.vminswzx.vvvmvl" => "__builtin_ve_vl_vminswzx_vvvmvl", + "llvm.ve.vl.vminswzx.vvvvl" => "__builtin_ve_vl_vminswzx_vvvvl", + "llvm.ve.vl.vmrg.vsvml" => "__builtin_ve_vl_vmrg_vsvml", + "llvm.ve.vl.vmrg.vsvmvl" => "__builtin_ve_vl_vmrg_vsvmvl", + "llvm.ve.vl.vmrg.vvvml" => "__builtin_ve_vl_vmrg_vvvml", + "llvm.ve.vl.vmrg.vvvmvl" => "__builtin_ve_vl_vmrg_vvvmvl", + "llvm.ve.vl.vmrgw.vsvMl" => "__builtin_ve_vl_vmrgw_vsvMl", + "llvm.ve.vl.vmrgw.vsvMvl" => "__builtin_ve_vl_vmrgw_vsvMvl", + "llvm.ve.vl.vmrgw.vvvMl" => "__builtin_ve_vl_vmrgw_vvvMl", + "llvm.ve.vl.vmrgw.vvvMvl" => "__builtin_ve_vl_vmrgw_vvvMvl", + "llvm.ve.vl.vmulsl.vsvl" => "__builtin_ve_vl_vmulsl_vsvl", + "llvm.ve.vl.vmulsl.vsvmvl" => "__builtin_ve_vl_vmulsl_vsvmvl", + "llvm.ve.vl.vmulsl.vsvvl" => "__builtin_ve_vl_vmulsl_vsvvl", + "llvm.ve.vl.vmulsl.vvvl" => "__builtin_ve_vl_vmulsl_vvvl", + "llvm.ve.vl.vmulsl.vvvmvl" => "__builtin_ve_vl_vmulsl_vvvmvl", + "llvm.ve.vl.vmulsl.vvvvl" => "__builtin_ve_vl_vmulsl_vvvvl", + "llvm.ve.vl.vmulslw.vsvl" => "__builtin_ve_vl_vmulslw_vsvl", + "llvm.ve.vl.vmulslw.vsvvl" => "__builtin_ve_vl_vmulslw_vsvvl", + "llvm.ve.vl.vmulslw.vvvl" => "__builtin_ve_vl_vmulslw_vvvl", + "llvm.ve.vl.vmulslw.vvvvl" => "__builtin_ve_vl_vmulslw_vvvvl", + "llvm.ve.vl.vmulswsx.vsvl" => "__builtin_ve_vl_vmulswsx_vsvl", + "llvm.ve.vl.vmulswsx.vsvmvl" => "__builtin_ve_vl_vmulswsx_vsvmvl", + "llvm.ve.vl.vmulswsx.vsvvl" => "__builtin_ve_vl_vmulswsx_vsvvl", + "llvm.ve.vl.vmulswsx.vvvl" => "__builtin_ve_vl_vmulswsx_vvvl", + "llvm.ve.vl.vmulswsx.vvvmvl" => "__builtin_ve_vl_vmulswsx_vvvmvl", + "llvm.ve.vl.vmulswsx.vvvvl" => "__builtin_ve_vl_vmulswsx_vvvvl", + "llvm.ve.vl.vmulswzx.vsvl" => "__builtin_ve_vl_vmulswzx_vsvl", + "llvm.ve.vl.vmulswzx.vsvmvl" => "__builtin_ve_vl_vmulswzx_vsvmvl", + "llvm.ve.vl.vmulswzx.vsvvl" => "__builtin_ve_vl_vmulswzx_vsvvl", + "llvm.ve.vl.vmulswzx.vvvl" => "__builtin_ve_vl_vmulswzx_vvvl", + "llvm.ve.vl.vmulswzx.vvvmvl" => "__builtin_ve_vl_vmulswzx_vvvmvl", + "llvm.ve.vl.vmulswzx.vvvvl" => "__builtin_ve_vl_vmulswzx_vvvvl", + "llvm.ve.vl.vmulul.vsvl" => "__builtin_ve_vl_vmulul_vsvl", + "llvm.ve.vl.vmulul.vsvmvl" => "__builtin_ve_vl_vmulul_vsvmvl", + "llvm.ve.vl.vmulul.vsvvl" => "__builtin_ve_vl_vmulul_vsvvl", + "llvm.ve.vl.vmulul.vvvl" => "__builtin_ve_vl_vmulul_vvvl", + "llvm.ve.vl.vmulul.vvvmvl" => "__builtin_ve_vl_vmulul_vvvmvl", + "llvm.ve.vl.vmulul.vvvvl" => "__builtin_ve_vl_vmulul_vvvvl", + "llvm.ve.vl.vmuluw.vsvl" => "__builtin_ve_vl_vmuluw_vsvl", + "llvm.ve.vl.vmuluw.vsvmvl" => "__builtin_ve_vl_vmuluw_vsvmvl", + "llvm.ve.vl.vmuluw.vsvvl" => "__builtin_ve_vl_vmuluw_vsvvl", + "llvm.ve.vl.vmuluw.vvvl" => "__builtin_ve_vl_vmuluw_vvvl", + "llvm.ve.vl.vmuluw.vvvmvl" => "__builtin_ve_vl_vmuluw_vvvmvl", + "llvm.ve.vl.vmuluw.vvvvl" => "__builtin_ve_vl_vmuluw_vvvvl", + "llvm.ve.vl.vmv.vsvl" => "__builtin_ve_vl_vmv_vsvl", + "llvm.ve.vl.vmv.vsvmvl" => "__builtin_ve_vl_vmv_vsvmvl", + "llvm.ve.vl.vmv.vsvvl" => "__builtin_ve_vl_vmv_vsvvl", + "llvm.ve.vl.vor.vsvl" => "__builtin_ve_vl_vor_vsvl", + "llvm.ve.vl.vor.vsvmvl" => "__builtin_ve_vl_vor_vsvmvl", + "llvm.ve.vl.vor.vsvvl" => "__builtin_ve_vl_vor_vsvvl", + "llvm.ve.vl.vor.vvvl" => "__builtin_ve_vl_vor_vvvl", + "llvm.ve.vl.vor.vvvmvl" => "__builtin_ve_vl_vor_vvvmvl", + "llvm.ve.vl.vor.vvvvl" => "__builtin_ve_vl_vor_vvvvl", + "llvm.ve.vl.vpcnt.vvl" => "__builtin_ve_vl_vpcnt_vvl", + "llvm.ve.vl.vpcnt.vvmvl" => "__builtin_ve_vl_vpcnt_vvmvl", + "llvm.ve.vl.vpcnt.vvvl" => "__builtin_ve_vl_vpcnt_vvvl", + "llvm.ve.vl.vrand.vvl" => "__builtin_ve_vl_vrand_vvl", + "llvm.ve.vl.vrand.vvml" => "__builtin_ve_vl_vrand_vvml", + "llvm.ve.vl.vrcpd.vvl" => "__builtin_ve_vl_vrcpd_vvl", + "llvm.ve.vl.vrcpd.vvvl" => "__builtin_ve_vl_vrcpd_vvvl", + "llvm.ve.vl.vrcps.vvl" => "__builtin_ve_vl_vrcps_vvl", + "llvm.ve.vl.vrcps.vvvl" => "__builtin_ve_vl_vrcps_vvvl", + "llvm.ve.vl.vrmaxslfst.vvl" => "__builtin_ve_vl_vrmaxslfst_vvl", + "llvm.ve.vl.vrmaxslfst.vvvl" => "__builtin_ve_vl_vrmaxslfst_vvvl", + "llvm.ve.vl.vrmaxsllst.vvl" => "__builtin_ve_vl_vrmaxsllst_vvl", + "llvm.ve.vl.vrmaxsllst.vvvl" => "__builtin_ve_vl_vrmaxsllst_vvvl", + "llvm.ve.vl.vrmaxswfstsx.vvl" => "__builtin_ve_vl_vrmaxswfstsx_vvl", + "llvm.ve.vl.vrmaxswfstsx.vvvl" => "__builtin_ve_vl_vrmaxswfstsx_vvvl", + "llvm.ve.vl.vrmaxswfstzx.vvl" => "__builtin_ve_vl_vrmaxswfstzx_vvl", + "llvm.ve.vl.vrmaxswfstzx.vvvl" => "__builtin_ve_vl_vrmaxswfstzx_vvvl", + "llvm.ve.vl.vrmaxswlstsx.vvl" => "__builtin_ve_vl_vrmaxswlstsx_vvl", + "llvm.ve.vl.vrmaxswlstsx.vvvl" => "__builtin_ve_vl_vrmaxswlstsx_vvvl", + "llvm.ve.vl.vrmaxswlstzx.vvl" => "__builtin_ve_vl_vrmaxswlstzx_vvl", + "llvm.ve.vl.vrmaxswlstzx.vvvl" => "__builtin_ve_vl_vrmaxswlstzx_vvvl", + "llvm.ve.vl.vrminslfst.vvl" => "__builtin_ve_vl_vrminslfst_vvl", + "llvm.ve.vl.vrminslfst.vvvl" => "__builtin_ve_vl_vrminslfst_vvvl", + "llvm.ve.vl.vrminsllst.vvl" => "__builtin_ve_vl_vrminsllst_vvl", + "llvm.ve.vl.vrminsllst.vvvl" => "__builtin_ve_vl_vrminsllst_vvvl", + "llvm.ve.vl.vrminswfstsx.vvl" => "__builtin_ve_vl_vrminswfstsx_vvl", + "llvm.ve.vl.vrminswfstsx.vvvl" => "__builtin_ve_vl_vrminswfstsx_vvvl", + "llvm.ve.vl.vrminswfstzx.vvl" => "__builtin_ve_vl_vrminswfstzx_vvl", + "llvm.ve.vl.vrminswfstzx.vvvl" => "__builtin_ve_vl_vrminswfstzx_vvvl", + "llvm.ve.vl.vrminswlstsx.vvl" => "__builtin_ve_vl_vrminswlstsx_vvl", + "llvm.ve.vl.vrminswlstsx.vvvl" => "__builtin_ve_vl_vrminswlstsx_vvvl", + "llvm.ve.vl.vrminswlstzx.vvl" => "__builtin_ve_vl_vrminswlstzx_vvl", + "llvm.ve.vl.vrminswlstzx.vvvl" => "__builtin_ve_vl_vrminswlstzx_vvvl", + "llvm.ve.vl.vror.vvl" => "__builtin_ve_vl_vror_vvl", + "llvm.ve.vl.vror.vvml" => "__builtin_ve_vl_vror_vvml", + "llvm.ve.vl.vrsqrtd.vvl" => "__builtin_ve_vl_vrsqrtd_vvl", + "llvm.ve.vl.vrsqrtd.vvvl" => "__builtin_ve_vl_vrsqrtd_vvvl", + "llvm.ve.vl.vrsqrtdnex.vvl" => "__builtin_ve_vl_vrsqrtdnex_vvl", + "llvm.ve.vl.vrsqrtdnex.vvvl" => "__builtin_ve_vl_vrsqrtdnex_vvvl", + "llvm.ve.vl.vrsqrts.vvl" => "__builtin_ve_vl_vrsqrts_vvl", + "llvm.ve.vl.vrsqrts.vvvl" => "__builtin_ve_vl_vrsqrts_vvvl", + "llvm.ve.vl.vrsqrtsnex.vvl" => "__builtin_ve_vl_vrsqrtsnex_vvl", + "llvm.ve.vl.vrsqrtsnex.vvvl" => "__builtin_ve_vl_vrsqrtsnex_vvvl", + "llvm.ve.vl.vrxor.vvl" => "__builtin_ve_vl_vrxor_vvl", + "llvm.ve.vl.vrxor.vvml" => "__builtin_ve_vl_vrxor_vvml", + "llvm.ve.vl.vsc.vvssl" => "__builtin_ve_vl_vsc_vvssl", + "llvm.ve.vl.vsc.vvssml" => "__builtin_ve_vl_vsc_vvssml", + "llvm.ve.vl.vscl.vvssl" => "__builtin_ve_vl_vscl_vvssl", + "llvm.ve.vl.vscl.vvssml" => "__builtin_ve_vl_vscl_vvssml", + "llvm.ve.vl.vsclnc.vvssl" => "__builtin_ve_vl_vsclnc_vvssl", + "llvm.ve.vl.vsclnc.vvssml" => "__builtin_ve_vl_vsclnc_vvssml", + "llvm.ve.vl.vsclncot.vvssl" => "__builtin_ve_vl_vsclncot_vvssl", + "llvm.ve.vl.vsclncot.vvssml" => "__builtin_ve_vl_vsclncot_vvssml", + "llvm.ve.vl.vsclot.vvssl" => "__builtin_ve_vl_vsclot_vvssl", + "llvm.ve.vl.vsclot.vvssml" => "__builtin_ve_vl_vsclot_vvssml", + "llvm.ve.vl.vscnc.vvssl" => "__builtin_ve_vl_vscnc_vvssl", + "llvm.ve.vl.vscnc.vvssml" => "__builtin_ve_vl_vscnc_vvssml", + "llvm.ve.vl.vscncot.vvssl" => "__builtin_ve_vl_vscncot_vvssl", + "llvm.ve.vl.vscncot.vvssml" => "__builtin_ve_vl_vscncot_vvssml", + "llvm.ve.vl.vscot.vvssl" => "__builtin_ve_vl_vscot_vvssl", + "llvm.ve.vl.vscot.vvssml" => "__builtin_ve_vl_vscot_vvssml", + "llvm.ve.vl.vscu.vvssl" => "__builtin_ve_vl_vscu_vvssl", + "llvm.ve.vl.vscu.vvssml" => "__builtin_ve_vl_vscu_vvssml", + "llvm.ve.vl.vscunc.vvssl" => "__builtin_ve_vl_vscunc_vvssl", + "llvm.ve.vl.vscunc.vvssml" => "__builtin_ve_vl_vscunc_vvssml", + "llvm.ve.vl.vscuncot.vvssl" => "__builtin_ve_vl_vscuncot_vvssl", + "llvm.ve.vl.vscuncot.vvssml" => "__builtin_ve_vl_vscuncot_vvssml", + "llvm.ve.vl.vscuot.vvssl" => "__builtin_ve_vl_vscuot_vvssl", + "llvm.ve.vl.vscuot.vvssml" => "__builtin_ve_vl_vscuot_vvssml", + "llvm.ve.vl.vseq.vl" => "__builtin_ve_vl_vseq_vl", + "llvm.ve.vl.vseq.vvl" => "__builtin_ve_vl_vseq_vvl", + "llvm.ve.vl.vsfa.vvssl" => "__builtin_ve_vl_vsfa_vvssl", + "llvm.ve.vl.vsfa.vvssmvl" => "__builtin_ve_vl_vsfa_vvssmvl", + "llvm.ve.vl.vsfa.vvssvl" => "__builtin_ve_vl_vsfa_vvssvl", + "llvm.ve.vl.vshf.vvvsl" => "__builtin_ve_vl_vshf_vvvsl", + "llvm.ve.vl.vshf.vvvsvl" => "__builtin_ve_vl_vshf_vvvsvl", + "llvm.ve.vl.vslal.vvsl" => "__builtin_ve_vl_vslal_vvsl", + "llvm.ve.vl.vslal.vvsmvl" => "__builtin_ve_vl_vslal_vvsmvl", + "llvm.ve.vl.vslal.vvsvl" => "__builtin_ve_vl_vslal_vvsvl", + "llvm.ve.vl.vslal.vvvl" => "__builtin_ve_vl_vslal_vvvl", + "llvm.ve.vl.vslal.vvvmvl" => "__builtin_ve_vl_vslal_vvvmvl", + "llvm.ve.vl.vslal.vvvvl" => "__builtin_ve_vl_vslal_vvvvl", + "llvm.ve.vl.vslawsx.vvsl" => "__builtin_ve_vl_vslawsx_vvsl", + "llvm.ve.vl.vslawsx.vvsmvl" => "__builtin_ve_vl_vslawsx_vvsmvl", + "llvm.ve.vl.vslawsx.vvsvl" => "__builtin_ve_vl_vslawsx_vvsvl", + "llvm.ve.vl.vslawsx.vvvl" => "__builtin_ve_vl_vslawsx_vvvl", + "llvm.ve.vl.vslawsx.vvvmvl" => "__builtin_ve_vl_vslawsx_vvvmvl", + "llvm.ve.vl.vslawsx.vvvvl" => "__builtin_ve_vl_vslawsx_vvvvl", + "llvm.ve.vl.vslawzx.vvsl" => "__builtin_ve_vl_vslawzx_vvsl", + "llvm.ve.vl.vslawzx.vvsmvl" => "__builtin_ve_vl_vslawzx_vvsmvl", + "llvm.ve.vl.vslawzx.vvsvl" => "__builtin_ve_vl_vslawzx_vvsvl", + "llvm.ve.vl.vslawzx.vvvl" => "__builtin_ve_vl_vslawzx_vvvl", + "llvm.ve.vl.vslawzx.vvvmvl" => "__builtin_ve_vl_vslawzx_vvvmvl", + "llvm.ve.vl.vslawzx.vvvvl" => "__builtin_ve_vl_vslawzx_vvvvl", + "llvm.ve.vl.vsll.vvsl" => "__builtin_ve_vl_vsll_vvsl", + "llvm.ve.vl.vsll.vvsmvl" => "__builtin_ve_vl_vsll_vvsmvl", + "llvm.ve.vl.vsll.vvsvl" => "__builtin_ve_vl_vsll_vvsvl", + "llvm.ve.vl.vsll.vvvl" => "__builtin_ve_vl_vsll_vvvl", + "llvm.ve.vl.vsll.vvvmvl" => "__builtin_ve_vl_vsll_vvvmvl", + "llvm.ve.vl.vsll.vvvvl" => "__builtin_ve_vl_vsll_vvvvl", + "llvm.ve.vl.vsral.vvsl" => "__builtin_ve_vl_vsral_vvsl", + "llvm.ve.vl.vsral.vvsmvl" => "__builtin_ve_vl_vsral_vvsmvl", + "llvm.ve.vl.vsral.vvsvl" => "__builtin_ve_vl_vsral_vvsvl", + "llvm.ve.vl.vsral.vvvl" => "__builtin_ve_vl_vsral_vvvl", + "llvm.ve.vl.vsral.vvvmvl" => "__builtin_ve_vl_vsral_vvvmvl", + "llvm.ve.vl.vsral.vvvvl" => "__builtin_ve_vl_vsral_vvvvl", + "llvm.ve.vl.vsrawsx.vvsl" => "__builtin_ve_vl_vsrawsx_vvsl", + "llvm.ve.vl.vsrawsx.vvsmvl" => "__builtin_ve_vl_vsrawsx_vvsmvl", + "llvm.ve.vl.vsrawsx.vvsvl" => "__builtin_ve_vl_vsrawsx_vvsvl", + "llvm.ve.vl.vsrawsx.vvvl" => "__builtin_ve_vl_vsrawsx_vvvl", + "llvm.ve.vl.vsrawsx.vvvmvl" => "__builtin_ve_vl_vsrawsx_vvvmvl", + "llvm.ve.vl.vsrawsx.vvvvl" => "__builtin_ve_vl_vsrawsx_vvvvl", + "llvm.ve.vl.vsrawzx.vvsl" => "__builtin_ve_vl_vsrawzx_vvsl", + "llvm.ve.vl.vsrawzx.vvsmvl" => "__builtin_ve_vl_vsrawzx_vvsmvl", + "llvm.ve.vl.vsrawzx.vvsvl" => "__builtin_ve_vl_vsrawzx_vvsvl", + "llvm.ve.vl.vsrawzx.vvvl" => "__builtin_ve_vl_vsrawzx_vvvl", + "llvm.ve.vl.vsrawzx.vvvmvl" => "__builtin_ve_vl_vsrawzx_vvvmvl", + "llvm.ve.vl.vsrawzx.vvvvl" => "__builtin_ve_vl_vsrawzx_vvvvl", + "llvm.ve.vl.vsrl.vvsl" => "__builtin_ve_vl_vsrl_vvsl", + "llvm.ve.vl.vsrl.vvsmvl" => "__builtin_ve_vl_vsrl_vvsmvl", + "llvm.ve.vl.vsrl.vvsvl" => "__builtin_ve_vl_vsrl_vvsvl", + "llvm.ve.vl.vsrl.vvvl" => "__builtin_ve_vl_vsrl_vvvl", + "llvm.ve.vl.vsrl.vvvmvl" => "__builtin_ve_vl_vsrl_vvvmvl", + "llvm.ve.vl.vsrl.vvvvl" => "__builtin_ve_vl_vsrl_vvvvl", + "llvm.ve.vl.vst.vssl" => "__builtin_ve_vl_vst_vssl", + "llvm.ve.vl.vst.vssml" => "__builtin_ve_vl_vst_vssml", + "llvm.ve.vl.vst2d.vssl" => "__builtin_ve_vl_vst2d_vssl", + "llvm.ve.vl.vst2d.vssml" => "__builtin_ve_vl_vst2d_vssml", + "llvm.ve.vl.vst2dnc.vssl" => "__builtin_ve_vl_vst2dnc_vssl", + "llvm.ve.vl.vst2dnc.vssml" => "__builtin_ve_vl_vst2dnc_vssml", + "llvm.ve.vl.vst2dncot.vssl" => "__builtin_ve_vl_vst2dncot_vssl", + "llvm.ve.vl.vst2dncot.vssml" => "__builtin_ve_vl_vst2dncot_vssml", + "llvm.ve.vl.vst2dot.vssl" => "__builtin_ve_vl_vst2dot_vssl", + "llvm.ve.vl.vst2dot.vssml" => "__builtin_ve_vl_vst2dot_vssml", + "llvm.ve.vl.vstl.vssl" => "__builtin_ve_vl_vstl_vssl", + "llvm.ve.vl.vstl.vssml" => "__builtin_ve_vl_vstl_vssml", + "llvm.ve.vl.vstl2d.vssl" => "__builtin_ve_vl_vstl2d_vssl", + "llvm.ve.vl.vstl2d.vssml" => "__builtin_ve_vl_vstl2d_vssml", + "llvm.ve.vl.vstl2dnc.vssl" => "__builtin_ve_vl_vstl2dnc_vssl", + "llvm.ve.vl.vstl2dnc.vssml" => "__builtin_ve_vl_vstl2dnc_vssml", + "llvm.ve.vl.vstl2dncot.vssl" => "__builtin_ve_vl_vstl2dncot_vssl", + "llvm.ve.vl.vstl2dncot.vssml" => "__builtin_ve_vl_vstl2dncot_vssml", + "llvm.ve.vl.vstl2dot.vssl" => "__builtin_ve_vl_vstl2dot_vssl", + "llvm.ve.vl.vstl2dot.vssml" => "__builtin_ve_vl_vstl2dot_vssml", + "llvm.ve.vl.vstlnc.vssl" => "__builtin_ve_vl_vstlnc_vssl", + "llvm.ve.vl.vstlnc.vssml" => "__builtin_ve_vl_vstlnc_vssml", + "llvm.ve.vl.vstlncot.vssl" => "__builtin_ve_vl_vstlncot_vssl", + "llvm.ve.vl.vstlncot.vssml" => "__builtin_ve_vl_vstlncot_vssml", + "llvm.ve.vl.vstlot.vssl" => "__builtin_ve_vl_vstlot_vssl", + "llvm.ve.vl.vstlot.vssml" => "__builtin_ve_vl_vstlot_vssml", + "llvm.ve.vl.vstnc.vssl" => "__builtin_ve_vl_vstnc_vssl", + "llvm.ve.vl.vstnc.vssml" => "__builtin_ve_vl_vstnc_vssml", + "llvm.ve.vl.vstncot.vssl" => "__builtin_ve_vl_vstncot_vssl", + "llvm.ve.vl.vstncot.vssml" => "__builtin_ve_vl_vstncot_vssml", + "llvm.ve.vl.vstot.vssl" => "__builtin_ve_vl_vstot_vssl", + "llvm.ve.vl.vstot.vssml" => "__builtin_ve_vl_vstot_vssml", + "llvm.ve.vl.vstu.vssl" => "__builtin_ve_vl_vstu_vssl", + "llvm.ve.vl.vstu.vssml" => "__builtin_ve_vl_vstu_vssml", + "llvm.ve.vl.vstu2d.vssl" => "__builtin_ve_vl_vstu2d_vssl", + "llvm.ve.vl.vstu2d.vssml" => "__builtin_ve_vl_vstu2d_vssml", + "llvm.ve.vl.vstu2dnc.vssl" => "__builtin_ve_vl_vstu2dnc_vssl", + "llvm.ve.vl.vstu2dnc.vssml" => "__builtin_ve_vl_vstu2dnc_vssml", + "llvm.ve.vl.vstu2dncot.vssl" => "__builtin_ve_vl_vstu2dncot_vssl", + "llvm.ve.vl.vstu2dncot.vssml" => "__builtin_ve_vl_vstu2dncot_vssml", + "llvm.ve.vl.vstu2dot.vssl" => "__builtin_ve_vl_vstu2dot_vssl", + "llvm.ve.vl.vstu2dot.vssml" => "__builtin_ve_vl_vstu2dot_vssml", + "llvm.ve.vl.vstunc.vssl" => "__builtin_ve_vl_vstunc_vssl", + "llvm.ve.vl.vstunc.vssml" => "__builtin_ve_vl_vstunc_vssml", + "llvm.ve.vl.vstuncot.vssl" => "__builtin_ve_vl_vstuncot_vssl", + "llvm.ve.vl.vstuncot.vssml" => "__builtin_ve_vl_vstuncot_vssml", + "llvm.ve.vl.vstuot.vssl" => "__builtin_ve_vl_vstuot_vssl", + "llvm.ve.vl.vstuot.vssml" => "__builtin_ve_vl_vstuot_vssml", + "llvm.ve.vl.vsubsl.vsvl" => "__builtin_ve_vl_vsubsl_vsvl", + "llvm.ve.vl.vsubsl.vsvmvl" => "__builtin_ve_vl_vsubsl_vsvmvl", + "llvm.ve.vl.vsubsl.vsvvl" => "__builtin_ve_vl_vsubsl_vsvvl", + "llvm.ve.vl.vsubsl.vvvl" => "__builtin_ve_vl_vsubsl_vvvl", + "llvm.ve.vl.vsubsl.vvvmvl" => "__builtin_ve_vl_vsubsl_vvvmvl", + "llvm.ve.vl.vsubsl.vvvvl" => "__builtin_ve_vl_vsubsl_vvvvl", + "llvm.ve.vl.vsubswsx.vsvl" => "__builtin_ve_vl_vsubswsx_vsvl", + "llvm.ve.vl.vsubswsx.vsvmvl" => "__builtin_ve_vl_vsubswsx_vsvmvl", + "llvm.ve.vl.vsubswsx.vsvvl" => "__builtin_ve_vl_vsubswsx_vsvvl", + "llvm.ve.vl.vsubswsx.vvvl" => "__builtin_ve_vl_vsubswsx_vvvl", + "llvm.ve.vl.vsubswsx.vvvmvl" => "__builtin_ve_vl_vsubswsx_vvvmvl", + "llvm.ve.vl.vsubswsx.vvvvl" => "__builtin_ve_vl_vsubswsx_vvvvl", + "llvm.ve.vl.vsubswzx.vsvl" => "__builtin_ve_vl_vsubswzx_vsvl", + "llvm.ve.vl.vsubswzx.vsvmvl" => "__builtin_ve_vl_vsubswzx_vsvmvl", + "llvm.ve.vl.vsubswzx.vsvvl" => "__builtin_ve_vl_vsubswzx_vsvvl", + "llvm.ve.vl.vsubswzx.vvvl" => "__builtin_ve_vl_vsubswzx_vvvl", + "llvm.ve.vl.vsubswzx.vvvmvl" => "__builtin_ve_vl_vsubswzx_vvvmvl", + "llvm.ve.vl.vsubswzx.vvvvl" => "__builtin_ve_vl_vsubswzx_vvvvl", + "llvm.ve.vl.vsubul.vsvl" => "__builtin_ve_vl_vsubul_vsvl", + "llvm.ve.vl.vsubul.vsvmvl" => "__builtin_ve_vl_vsubul_vsvmvl", + "llvm.ve.vl.vsubul.vsvvl" => "__builtin_ve_vl_vsubul_vsvvl", + "llvm.ve.vl.vsubul.vvvl" => "__builtin_ve_vl_vsubul_vvvl", + "llvm.ve.vl.vsubul.vvvmvl" => "__builtin_ve_vl_vsubul_vvvmvl", + "llvm.ve.vl.vsubul.vvvvl" => "__builtin_ve_vl_vsubul_vvvvl", + "llvm.ve.vl.vsubuw.vsvl" => "__builtin_ve_vl_vsubuw_vsvl", + "llvm.ve.vl.vsubuw.vsvmvl" => "__builtin_ve_vl_vsubuw_vsvmvl", + "llvm.ve.vl.vsubuw.vsvvl" => "__builtin_ve_vl_vsubuw_vsvvl", + "llvm.ve.vl.vsubuw.vvvl" => "__builtin_ve_vl_vsubuw_vvvl", + "llvm.ve.vl.vsubuw.vvvmvl" => "__builtin_ve_vl_vsubuw_vvvmvl", + "llvm.ve.vl.vsubuw.vvvvl" => "__builtin_ve_vl_vsubuw_vvvvl", + "llvm.ve.vl.vsuml.vvl" => "__builtin_ve_vl_vsuml_vvl", + "llvm.ve.vl.vsuml.vvml" => "__builtin_ve_vl_vsuml_vvml", + "llvm.ve.vl.vsumwsx.vvl" => "__builtin_ve_vl_vsumwsx_vvl", + "llvm.ve.vl.vsumwsx.vvml" => "__builtin_ve_vl_vsumwsx_vvml", + "llvm.ve.vl.vsumwzx.vvl" => "__builtin_ve_vl_vsumwzx_vvl", + "llvm.ve.vl.vsumwzx.vvml" => "__builtin_ve_vl_vsumwzx_vvml", + "llvm.ve.vl.vxor.vsvl" => "__builtin_ve_vl_vxor_vsvl", + "llvm.ve.vl.vxor.vsvmvl" => "__builtin_ve_vl_vxor_vsvmvl", + "llvm.ve.vl.vxor.vsvvl" => "__builtin_ve_vl_vxor_vsvvl", + "llvm.ve.vl.vxor.vvvl" => "__builtin_ve_vl_vxor_vvvl", + "llvm.ve.vl.vxor.vvvmvl" => "__builtin_ve_vl_vxor_vvvmvl", + "llvm.ve.vl.vxor.vvvvl" => "__builtin_ve_vl_vxor_vvvvl", + "llvm.ve.vl.xorm.MMM" => "__builtin_ve_vl_xorm_MMM", + "llvm.ve.vl.xorm.mmm" => "__builtin_ve_vl_xorm_mmm", // x86 "llvm.x86.3dnow.pavgusb" => "__builtin_ia32_pavgusb", "llvm.x86.3dnow.pf2id" => "__builtin_ia32_pf2id", @@ -3430,6 +5706,10 @@ match name { "llvm.x86.3dnowa.pfnacc" => "__builtin_ia32_pfnacc", "llvm.x86.3dnowa.pfpnacc" => "__builtin_ia32_pfpnacc", "llvm.x86.3dnowa.pi2fw" => "__builtin_ia32_pi2fw", + "llvm.x86.aadd32" => "__builtin_ia32_aadd32", + "llvm.x86.aadd64" => "__builtin_ia32_aadd64", + "llvm.x86.aand32" => "__builtin_ia32_aand32", + "llvm.x86.aand64" => "__builtin_ia32_aand64", "llvm.x86.addcarry.u32" => "__builtin_ia32_addcarry_u32", "llvm.x86.addcarry.u64" => "__builtin_ia32_addcarry_u64", "llvm.x86.addcarryx.u32" => "__builtin_ia32_addcarryx_u32", @@ -3448,6 +5728,8 @@ match name { "llvm.x86.aesni.aesenclast.512" => "__builtin_ia32_aesenclast512", "llvm.x86.aesni.aesimc" => "__builtin_ia32_aesimc128", "llvm.x86.aesni.aeskeygenassist" => "__builtin_ia32_aeskeygenassist128", + "llvm.x86.aor32" => "__builtin_ia32_aor32", + "llvm.x86.aor64" => "__builtin_ia32_aor64", "llvm.x86.avx.addsub.pd.256" => "__builtin_ia32_addsubpd256", "llvm.x86.avx.addsub.ps.256" => "__builtin_ia32_addsubps256", "llvm.x86.avx.blend.pd.256" => "__builtin_ia32_blendpd256", @@ -3660,6 +5942,18 @@ match name { "llvm.x86.avx2.vbroadcast.ss.ps.256" => "__builtin_ia32_vbroadcastss_ps256", "llvm.x86.avx2.vextracti128" => "__builtin_ia32_extract128i256", "llvm.x86.avx2.vinserti128" => "__builtin_ia32_insert128i256", + "llvm.x86.avx2.vpdpbssd.128" => "__builtin_ia32_vpdpbssd128", + "llvm.x86.avx2.vpdpbssd.256" => "__builtin_ia32_vpdpbssd256", + "llvm.x86.avx2.vpdpbssds.128" => "__builtin_ia32_vpdpbssds128", + "llvm.x86.avx2.vpdpbssds.256" => "__builtin_ia32_vpdpbssds256", + "llvm.x86.avx2.vpdpbsud.128" => "__builtin_ia32_vpdpbsud128", + "llvm.x86.avx2.vpdpbsud.256" => "__builtin_ia32_vpdpbsud256", + "llvm.x86.avx2.vpdpbsuds.128" => "__builtin_ia32_vpdpbsuds128", + "llvm.x86.avx2.vpdpbsuds.256" => "__builtin_ia32_vpdpbsuds256", + "llvm.x86.avx2.vpdpbuud.128" => "__builtin_ia32_vpdpbuud128", + "llvm.x86.avx2.vpdpbuud.256" => "__builtin_ia32_vpdpbuud256", + "llvm.x86.avx2.vpdpbuuds.128" => "__builtin_ia32_vpdpbuuds128", + "llvm.x86.avx2.vpdpbuuds.256" => "__builtin_ia32_vpdpbuuds256", "llvm.x86.avx2.vperm2i128" => "__builtin_ia32_permti256", "llvm.x86.avx512.add.pd.512" => "__builtin_ia32_addpd512", "llvm.x86.avx512.add.ps.512" => "__builtin_ia32_addps512", @@ -3779,8 +6073,8 @@ match name { "llvm.x86.avx512.mask.add.ps.128" => "__builtin_ia32_addps128_mask", "llvm.x86.avx512.mask.add.ps.256" => "__builtin_ia32_addps256_mask", "llvm.x86.avx512.mask.add.ps.512" => "__builtin_ia32_addps512_mask", - "llvm.x86.avx512.mask.add.sd.round" => "__builtin_ia32_addsd_round_mask", - "llvm.x86.avx512.mask.add.ss.round" => "__builtin_ia32_addss_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.add.sd.round" => "__builtin_ia32_addsd_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.add.ss.round" => "__builtin_ia32_addss_round_mask", "llvm.x86.avx512.mask.and.pd.128" => "__builtin_ia32_andpd128_mask", "llvm.x86.avx512.mask.and.pd.256" => "__builtin_ia32_andpd256_mask", "llvm.x86.avx512.mask.and.pd.512" => "__builtin_ia32_andpd512_mask", @@ -3894,8 +6188,8 @@ match name { "llvm.x86.avx512.mask.cvtqq2ps.128" => "__builtin_ia32_cvtqq2ps128_mask", "llvm.x86.avx512.mask.cvtqq2ps.256" => "__builtin_ia32_cvtqq2ps256_mask", "llvm.x86.avx512.mask.cvtqq2ps.512" => "__builtin_ia32_cvtqq2ps512_mask", - "llvm.x86.avx512.mask.cvtsd2ss.round" => "__builtin_ia32_cvtsd2ss_round_mask", - "llvm.x86.avx512.mask.cvtss2sd.round" => "__builtin_ia32_cvtss2sd_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.cvtsd2ss.round" => "__builtin_ia32_cvtsd2ss_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.cvtss2sd.round" => "__builtin_ia32_cvtss2sd_round_mask", "llvm.x86.avx512.mask.cvttpd2dq.128" => "__builtin_ia32_cvttpd2dq128_mask", "llvm.x86.avx512.mask.cvttpd2dq.256" => "__builtin_ia32_cvttpd2dq256_mask", "llvm.x86.avx512.mask.cvttpd2dq.512" => "__builtin_ia32_cvttpd2dq512_mask", @@ -3941,8 +6235,8 @@ match name { "llvm.x86.avx512.mask.div.ps.128" => "__builtin_ia32_divps_mask", "llvm.x86.avx512.mask.div.ps.256" => "__builtin_ia32_divps256_mask", "llvm.x86.avx512.mask.div.ps.512" => "__builtin_ia32_divps512_mask", - "llvm.x86.avx512.mask.div.sd.round" => "__builtin_ia32_divsd_round_mask", - "llvm.x86.avx512.mask.div.ss.round" => "__builtin_ia32_divss_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.div.sd.round" => "__builtin_ia32_divsd_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.div.ss.round" => "__builtin_ia32_divss_round_mask", "llvm.x86.avx512.mask.expand.d.128" => "__builtin_ia32_expandsi128_mask", "llvm.x86.avx512.mask.expand.d.256" => "__builtin_ia32_expandsi256_mask", "llvm.x86.avx512.mask.expand.d.512" => "__builtin_ia32_expandsi512_mask", @@ -3989,16 +6283,16 @@ match name { "llvm.x86.avx512.mask.getexp.ps.128" => "__builtin_ia32_getexpps128_mask", "llvm.x86.avx512.mask.getexp.ps.256" => "__builtin_ia32_getexpps256_mask", "llvm.x86.avx512.mask.getexp.ps.512" => "__builtin_ia32_getexpps512_mask", - "llvm.x86.avx512.mask.getexp.sd" => "__builtin_ia32_getexpsd128_round_mask", - "llvm.x86.avx512.mask.getexp.ss" => "__builtin_ia32_getexpss128_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.getexp.sd" => "__builtin_ia32_getexpsd128_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.getexp.ss" => "__builtin_ia32_getexpss128_round_mask", "llvm.x86.avx512.mask.getmant.pd.128" => "__builtin_ia32_getmantpd128_mask", "llvm.x86.avx512.mask.getmant.pd.256" => "__builtin_ia32_getmantpd256_mask", "llvm.x86.avx512.mask.getmant.pd.512" => "__builtin_ia32_getmantpd512_mask", "llvm.x86.avx512.mask.getmant.ps.128" => "__builtin_ia32_getmantps128_mask", "llvm.x86.avx512.mask.getmant.ps.256" => "__builtin_ia32_getmantps256_mask", "llvm.x86.avx512.mask.getmant.ps.512" => "__builtin_ia32_getmantps512_mask", - "llvm.x86.avx512.mask.getmant.sd" => "__builtin_ia32_getmantsd_round_mask", - "llvm.x86.avx512.mask.getmant.ss" => "__builtin_ia32_getmantss_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.getmant.sd" => "__builtin_ia32_getmantsd_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.getmant.ss" => "__builtin_ia32_getmantss_round_mask", "llvm.x86.avx512.mask.insertf32x4.256" => "__builtin_ia32_insertf32x4_256_mask", "llvm.x86.avx512.mask.insertf32x4.512" => "__builtin_ia32_insertf32x4_mask", "llvm.x86.avx512.mask.insertf32x8.512" => "__builtin_ia32_insertf32x8_mask", @@ -4023,16 +6317,16 @@ match name { "llvm.x86.avx512.mask.max.ps.128" => "__builtin_ia32_maxps_mask", "llvm.x86.avx512.mask.max.ps.256" => "__builtin_ia32_maxps256_mask", "llvm.x86.avx512.mask.max.ps.512" => "__builtin_ia32_maxps512_mask", - "llvm.x86.avx512.mask.max.sd.round" => "__builtin_ia32_maxsd_round_mask", - "llvm.x86.avx512.mask.max.ss.round" => "__builtin_ia32_maxss_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.max.sd.round" => "__builtin_ia32_maxsd_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.max.ss.round" => "__builtin_ia32_maxss_round_mask", "llvm.x86.avx512.mask.min.pd.128" => "__builtin_ia32_minpd_mask", "llvm.x86.avx512.mask.min.pd.256" => "__builtin_ia32_minpd256_mask", "llvm.x86.avx512.mask.min.pd.512" => "__builtin_ia32_minpd512_mask", "llvm.x86.avx512.mask.min.ps.128" => "__builtin_ia32_minps_mask", "llvm.x86.avx512.mask.min.ps.256" => "__builtin_ia32_minps256_mask", "llvm.x86.avx512.mask.min.ps.512" => "__builtin_ia32_minps512_mask", - "llvm.x86.avx512.mask.min.sd.round" => "__builtin_ia32_minsd_round_mask", - "llvm.x86.avx512.mask.min.ss.round" => "__builtin_ia32_minss_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.min.sd.round" => "__builtin_ia32_minsd_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.min.ss.round" => "__builtin_ia32_minss_round_mask", "llvm.x86.avx512.mask.move.sd" => "__builtin_ia32_movsd_mask", "llvm.x86.avx512.mask.move.ss" => "__builtin_ia32_movss_mask", "llvm.x86.avx512.mask.mul.pd.128" => "__builtin_ia32_mulpd_mask", @@ -4041,8 +6335,8 @@ match name { "llvm.x86.avx512.mask.mul.ps.128" => "__builtin_ia32_mulps_mask", "llvm.x86.avx512.mask.mul.ps.256" => "__builtin_ia32_mulps256_mask", "llvm.x86.avx512.mask.mul.ps.512" => "__builtin_ia32_mulps512_mask", - "llvm.x86.avx512.mask.mul.sd.round" => "__builtin_ia32_mulsd_round_mask", - "llvm.x86.avx512.mask.mul.ss.round" => "__builtin_ia32_mulss_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.mul.sd.round" => "__builtin_ia32_mulsd_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.mul.ss.round" => "__builtin_ia32_mulss_round_mask", "llvm.x86.avx512.mask.or.pd.128" => "__builtin_ia32_orpd128_mask", "llvm.x86.avx512.mask.or.pd.256" => "__builtin_ia32_orpd256_mask", "llvm.x86.avx512.mask.or.pd.512" => "__builtin_ia32_orpd512_mask", @@ -4527,8 +6821,8 @@ match name { "llvm.x86.avx512.mask.range.ps.128" => "__builtin_ia32_rangeps128_mask", "llvm.x86.avx512.mask.range.ps.256" => "__builtin_ia32_rangeps256_mask", "llvm.x86.avx512.mask.range.ps.512" => "__builtin_ia32_rangeps512_mask", - "llvm.x86.avx512.mask.range.sd" => "__builtin_ia32_rangesd128_round_mask", - "llvm.x86.avx512.mask.range.ss" => "__builtin_ia32_rangess128_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.range.sd" => "__builtin_ia32_rangesd128_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.range.ss" => "__builtin_ia32_rangess128_round_mask", "llvm.x86.avx512.mask.reduce.pd.128" => "__builtin_ia32_reducepd128_mask", "llvm.x86.avx512.mask.reduce.pd.256" => "__builtin_ia32_reducepd256_mask", "llvm.x86.avx512.mask.reduce.pd.512" => "__builtin_ia32_reducepd512_mask", @@ -4543,16 +6837,16 @@ match name { "llvm.x86.avx512.mask.rndscale.ps.128" => "__builtin_ia32_rndscaleps_128_mask", "llvm.x86.avx512.mask.rndscale.ps.256" => "__builtin_ia32_rndscaleps_256_mask", "llvm.x86.avx512.mask.rndscale.ps.512" => "__builtin_ia32_rndscaleps_mask", - "llvm.x86.avx512.mask.rndscale.sd" => "__builtin_ia32_rndscalesd_round_mask", - "llvm.x86.avx512.mask.rndscale.ss" => "__builtin_ia32_rndscaless_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.rndscale.sd" => "__builtin_ia32_rndscalesd_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.rndscale.ss" => "__builtin_ia32_rndscaless_round_mask", "llvm.x86.avx512.mask.scalef.pd.128" => "__builtin_ia32_scalefpd128_mask", "llvm.x86.avx512.mask.scalef.pd.256" => "__builtin_ia32_scalefpd256_mask", "llvm.x86.avx512.mask.scalef.pd.512" => "__builtin_ia32_scalefpd512_mask", "llvm.x86.avx512.mask.scalef.ps.128" => "__builtin_ia32_scalefps128_mask", "llvm.x86.avx512.mask.scalef.ps.256" => "__builtin_ia32_scalefps256_mask", "llvm.x86.avx512.mask.scalef.ps.512" => "__builtin_ia32_scalefps512_mask", - "llvm.x86.avx512.mask.scalef.sd" => "__builtin_ia32_scalefsd_round_mask", - "llvm.x86.avx512.mask.scalef.ss" => "__builtin_ia32_scalefss_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.scalef.sd" => "__builtin_ia32_scalefsd_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.scalef.ss" => "__builtin_ia32_scalefss_round_mask", "llvm.x86.avx512.mask.shuf.f32x4" => "__builtin_ia32_shuf_f32x4_mask", "llvm.x86.avx512.mask.shuf.f32x4.256" => "__builtin_ia32_shuf_f32x4_256_mask", "llvm.x86.avx512.mask.shuf.f64x2" => "__builtin_ia32_shuf_f64x2_mask", @@ -4573,8 +6867,8 @@ match name { "llvm.x86.avx512.mask.sqrt.ps.128" => "__builtin_ia32_sqrtps128_mask", "llvm.x86.avx512.mask.sqrt.ps.256" => "__builtin_ia32_sqrtps256_mask", "llvm.x86.avx512.mask.sqrt.ps.512" => "__builtin_ia32_sqrtps512_mask", - "llvm.x86.avx512.mask.sqrt.sd" => "__builtin_ia32_sqrtsd_round_mask", - "llvm.x86.avx512.mask.sqrt.ss" => "__builtin_ia32_sqrtss_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.sqrt.sd" => "__builtin_ia32_sqrtsd_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.sqrt.ss" => "__builtin_ia32_sqrtss_round_mask", "llvm.x86.avx512.mask.store.ss" => "__builtin_ia32_storess_mask", "llvm.x86.avx512.mask.storeu.d.512" => "__builtin_ia32_storedqusi512_mask", "llvm.x86.avx512.mask.storeu.pd.512" => "__builtin_ia32_storeupd512_mask", @@ -4586,8 +6880,8 @@ match name { "llvm.x86.avx512.mask.sub.ps.128" => "__builtin_ia32_subps128_mask", "llvm.x86.avx512.mask.sub.ps.256" => "__builtin_ia32_subps256_mask", "llvm.x86.avx512.mask.sub.ps.512" => "__builtin_ia32_subps512_mask", - "llvm.x86.avx512.mask.sub.sd.round" => "__builtin_ia32_subsd_round_mask", - "llvm.x86.avx512.mask.sub.ss.round" => "__builtin_ia32_subss_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.sub.sd.round" => "__builtin_ia32_subsd_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.mask.sub.ss.round" => "__builtin_ia32_subss_round_mask", "llvm.x86.avx512.mask.valign.d.128" => "__builtin_ia32_alignd128_mask", "llvm.x86.avx512.mask.valign.d.256" => "__builtin_ia32_alignd256_mask", "llvm.x86.avx512.mask.valign.d.512" => "__builtin_ia32_alignd512_mask", @@ -4905,9 +7199,9 @@ match name { "llvm.x86.avx512.rcp14.ss" => "__builtin_ia32_rcp14ss_mask", "llvm.x86.avx512.rcp28.pd" => "__builtin_ia32_rcp28pd_mask", "llvm.x86.avx512.rcp28.ps" => "__builtin_ia32_rcp28ps_mask", - "llvm.x86.avx512.rcp28.sd" => "__builtin_ia32_rcp28sd_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.rcp28.sd" => "__builtin_ia32_rcp28sd_round_mask", // [DUPLICATE]: "llvm.x86.avx512.rcp28.sd" => "__builtin_ia32_rcp28sd_mask", - "llvm.x86.avx512.rcp28.ss" => "__builtin_ia32_rcp28ss_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.rcp28.ss" => "__builtin_ia32_rcp28ss_round_mask", // [DUPLICATE]: "llvm.x86.avx512.rcp28.ss" => "__builtin_ia32_rcp28ss_mask", "llvm.x86.avx512.rndscale.sd" => "__builtin_ia32_rndscalesd", "llvm.x86.avx512.rndscale.ss" => "__builtin_ia32_rndscaless", @@ -4921,9 +7215,9 @@ match name { "llvm.x86.avx512.rsqrt14.ss" => "__builtin_ia32_rsqrt14ss_mask", "llvm.x86.avx512.rsqrt28.pd" => "__builtin_ia32_rsqrt28pd_mask", "llvm.x86.avx512.rsqrt28.ps" => "__builtin_ia32_rsqrt28ps_mask", - "llvm.x86.avx512.rsqrt28.sd" => "__builtin_ia32_rsqrt28sd_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.rsqrt28.sd" => "__builtin_ia32_rsqrt28sd_round_mask", // [DUPLICATE]: "llvm.x86.avx512.rsqrt28.sd" => "__builtin_ia32_rsqrt28sd_mask", - "llvm.x86.avx512.rsqrt28.ss" => "__builtin_ia32_rsqrt28ss_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512.rsqrt28.ss" => "__builtin_ia32_rsqrt28ss_round_mask", // [DUPLICATE]: "llvm.x86.avx512.rsqrt28.ss" => "__builtin_ia32_rsqrt28ss_mask", "llvm.x86.avx512.scatter.dpd.512" => "__builtin_ia32_scattersiv8df", "llvm.x86.avx512.scatter.dpi.512" => "__builtin_ia32_scattersiv16si", @@ -5021,21 +7315,21 @@ match name { "llvm.x86.avx512bf16.dpbf16ps.512" => "__builtin_ia32_dpbf16ps_512", "llvm.x86.avx512fp16.add.ph.512" => "__builtin_ia32_addph512", "llvm.x86.avx512fp16.div.ph.512" => "__builtin_ia32_divph512", - "llvm.x86.avx512fp16.mask.add.sh.round" => "__builtin_ia32_addsh_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512fp16.mask.add.sh.round" => "__builtin_ia32_addsh_round_mask", "llvm.x86.avx512fp16.mask.cmp.sh" => "__builtin_ia32_cmpsh_mask", - "llvm.x86.avx512fp16.mask.div.sh.round" => "__builtin_ia32_divsh_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512fp16.mask.div.sh.round" => "__builtin_ia32_divsh_round_mask", "llvm.x86.avx512fp16.mask.fpclass.sh" => "__builtin_ia32_fpclasssh_mask", "llvm.x86.avx512fp16.mask.getexp.ph.128" => "__builtin_ia32_getexpph128_mask", "llvm.x86.avx512fp16.mask.getexp.ph.256" => "__builtin_ia32_getexpph256_mask", "llvm.x86.avx512fp16.mask.getexp.ph.512" => "__builtin_ia32_getexpph512_mask", - "llvm.x86.avx512fp16.mask.getexp.sh" => "__builtin_ia32_getexpsh128_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512fp16.mask.getexp.sh" => "__builtin_ia32_getexpsh128_round_mask", "llvm.x86.avx512fp16.mask.getmant.ph.128" => "__builtin_ia32_getmantph128_mask", "llvm.x86.avx512fp16.mask.getmant.ph.256" => "__builtin_ia32_getmantph256_mask", "llvm.x86.avx512fp16.mask.getmant.ph.512" => "__builtin_ia32_getmantph512_mask", - "llvm.x86.avx512fp16.mask.getmant.sh" => "__builtin_ia32_getmantsh_round_mask", - "llvm.x86.avx512fp16.mask.max.sh.round" => "__builtin_ia32_maxsh_round_mask", - "llvm.x86.avx512fp16.mask.min.sh.round" => "__builtin_ia32_minsh_round_mask", - "llvm.x86.avx512fp16.mask.mul.sh.round" => "__builtin_ia32_mulsh_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512fp16.mask.getmant.sh" => "__builtin_ia32_getmantsh_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512fp16.mask.max.sh.round" => "__builtin_ia32_maxsh_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512fp16.mask.min.sh.round" => "__builtin_ia32_minsh_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512fp16.mask.mul.sh.round" => "__builtin_ia32_mulsh_round_mask", "llvm.x86.avx512fp16.mask.rcp.ph.128" => "__builtin_ia32_rcpph128_mask", "llvm.x86.avx512fp16.mask.rcp.ph.256" => "__builtin_ia32_rcpph256_mask", "llvm.x86.avx512fp16.mask.rcp.ph.512" => "__builtin_ia32_rcpph512_mask", @@ -5047,7 +7341,7 @@ match name { "llvm.x86.avx512fp16.mask.rndscale.ph.128" => "__builtin_ia32_rndscaleph_128_mask", "llvm.x86.avx512fp16.mask.rndscale.ph.256" => "__builtin_ia32_rndscaleph_256_mask", "llvm.x86.avx512fp16.mask.rndscale.ph.512" => "__builtin_ia32_rndscaleph_mask", - "llvm.x86.avx512fp16.mask.rndscale.sh" => "__builtin_ia32_rndscalesh_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512fp16.mask.rndscale.sh" => "__builtin_ia32_rndscalesh_round_mask", "llvm.x86.avx512fp16.mask.rsqrt.ph.128" => "__builtin_ia32_rsqrtph128_mask", "llvm.x86.avx512fp16.mask.rsqrt.ph.256" => "__builtin_ia32_rsqrtph256_mask", "llvm.x86.avx512fp16.mask.rsqrt.ph.512" => "__builtin_ia32_rsqrtph512_mask", @@ -5055,8 +7349,8 @@ match name { "llvm.x86.avx512fp16.mask.scalef.ph.128" => "__builtin_ia32_scalefph128_mask", "llvm.x86.avx512fp16.mask.scalef.ph.256" => "__builtin_ia32_scalefph256_mask", "llvm.x86.avx512fp16.mask.scalef.ph.512" => "__builtin_ia32_scalefph512_mask", - "llvm.x86.avx512fp16.mask.scalef.sh" => "__builtin_ia32_scalefsh_round_mask", - "llvm.x86.avx512fp16.mask.sub.sh.round" => "__builtin_ia32_subsh_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512fp16.mask.scalef.sh" => "__builtin_ia32_scalefsh_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512fp16.mask.sub.sh.round" => "__builtin_ia32_subsh_round_mask", "llvm.x86.avx512fp16.mask.vcvtdq2ph.128" => "__builtin_ia32_vcvtdq2ph128_mask", "llvm.x86.avx512fp16.mask.vcvtpd2ph.128" => "__builtin_ia32_vcvtpd2ph128_mask", "llvm.x86.avx512fp16.mask.vcvtpd2ph.256" => "__builtin_ia32_vcvtpd2ph256_mask", @@ -5090,10 +7384,10 @@ match name { "llvm.x86.avx512fp16.mask.vcvtps2phx.512" => "__builtin_ia32_vcvtps2phx512_mask", "llvm.x86.avx512fp16.mask.vcvtqq2ph.128" => "__builtin_ia32_vcvtqq2ph128_mask", "llvm.x86.avx512fp16.mask.vcvtqq2ph.256" => "__builtin_ia32_vcvtqq2ph256_mask", - "llvm.x86.avx512fp16.mask.vcvtsd2sh.round" => "__builtin_ia32_vcvtsd2sh_round_mask", - "llvm.x86.avx512fp16.mask.vcvtsh2sd.round" => "__builtin_ia32_vcvtsh2sd_round_mask", - "llvm.x86.avx512fp16.mask.vcvtsh2ss.round" => "__builtin_ia32_vcvtsh2ss_round_mask", - "llvm.x86.avx512fp16.mask.vcvtss2sh.round" => "__builtin_ia32_vcvtss2sh_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512fp16.mask.vcvtsd2sh.round" => "__builtin_ia32_vcvtsd2sh_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512fp16.mask.vcvtsh2sd.round" => "__builtin_ia32_vcvtsh2sd_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512fp16.mask.vcvtsh2ss.round" => "__builtin_ia32_vcvtsh2ss_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx512fp16.mask.vcvtss2sh.round" => "__builtin_ia32_vcvtss2sh_round_mask", "llvm.x86.avx512fp16.mask.vcvttph2dq.128" => "__builtin_ia32_vcvttph2dq128_mask", "llvm.x86.avx512fp16.mask.vcvttph2dq.256" => "__builtin_ia32_vcvttph2dq256_mask", "llvm.x86.avx512fp16.mask.vcvttph2dq.512" => "__builtin_ia32_vcvttph2dq512_mask", @@ -5162,6 +7456,8 @@ match name { "llvm.x86.avx512fp16.vcvtusi642sh" => "__builtin_ia32_vcvtusi642sh", "llvm.x86.avx512fp16.vfmaddsub.ph.128" => "__builtin_ia32_vfmaddsubph", "llvm.x86.avx512fp16.vfmaddsub.ph.256" => "__builtin_ia32_vfmaddsubph256", + "llvm.x86.axor32" => "__builtin_ia32_axor32", + "llvm.x86.axor64" => "__builtin_ia32_axor64", "llvm.x86.bmi.bextr.32" => "__builtin_ia32_bextr_u32", "llvm.x86.bmi.bextr.64" => "__builtin_ia32_bextr_u64", "llvm.x86.bmi.bzhi.32" => "__builtin_ia32_bzhi_si", @@ -5176,6 +7472,8 @@ match name { "llvm.x86.clui" => "__builtin_ia32_clui", "llvm.x86.clwb" => "__builtin_ia32_clwb", "llvm.x86.clzero" => "__builtin_ia32_clzero", + "llvm.x86.cmpccxadd32" => "__builtin_ia32_cmpccxadd32", + "llvm.x86.cmpccxadd64" => "__builtin_ia32_cmpccxadd64", "llvm.x86.directstore32" => "__builtin_ia32_directstore_u32", "llvm.x86.directstore64" => "__builtin_ia32_directstore_u64", "llvm.x86.enqcmd" => "__builtin_ia32_enqcmd", @@ -5329,6 +7627,7 @@ match name { "llvm.x86.rdpid" => "__builtin_ia32_rdpid", "llvm.x86.rdpkru" => "__builtin_ia32_rdpkru", "llvm.x86.rdpmc" => "__builtin_ia32_rdpmc", + "llvm.x86.rdpru" => "__builtin_ia32_rdpru", "llvm.x86.rdsspd" => "__builtin_ia32_rdsspd", "llvm.x86.rdsspq" => "__builtin_ia32_rdsspq", "llvm.x86.rdtsc" => "__builtin_ia32_rdtsc", @@ -5606,6 +7905,8 @@ match name { "llvm.x86.tdpbusd.internal" => "__builtin_ia32_tdpbusd_internal", "llvm.x86.tdpbuud" => "__builtin_ia32_tdpbuud", "llvm.x86.tdpbuud.internal" => "__builtin_ia32_tdpbuud_internal", + "llvm.x86.tdpfp16ps" => "__builtin_ia32_tdpfp16ps", + "llvm.x86.tdpfp16ps.internal" => "__builtin_ia32_tdpfp16ps_internal", "llvm.x86.testui" => "__builtin_ia32_testui", "llvm.x86.tileloadd64" => "__builtin_ia32_tileloadd64", "llvm.x86.tileloadd64.internal" => "__builtin_ia32_tileloadd64_internal", @@ -5619,6 +7920,20 @@ match name { "llvm.x86.tpause" => "__builtin_ia32_tpause", "llvm.x86.umonitor" => "__builtin_ia32_umonitor", "llvm.x86.umwait" => "__builtin_ia32_umwait", + "llvm.x86.vbcstnebf162ps128" => "__builtin_ia32_vbcstnebf162ps128", + "llvm.x86.vbcstnebf162ps256" => "__builtin_ia32_vbcstnebf162ps256", + "llvm.x86.vbcstnesh2ps128" => "__builtin_ia32_vbcstnesh2ps128", + "llvm.x86.vbcstnesh2ps256" => "__builtin_ia32_vbcstnesh2ps256", + "llvm.x86.vcvtneebf162ps128" => "__builtin_ia32_vcvtneebf162ps128", + "llvm.x86.vcvtneebf162ps256" => "__builtin_ia32_vcvtneebf162ps256", + "llvm.x86.vcvtneeph2ps128" => "__builtin_ia32_vcvtneeph2ps128", + "llvm.x86.vcvtneeph2ps256" => "__builtin_ia32_vcvtneeph2ps256", + "llvm.x86.vcvtneobf162ps128" => "__builtin_ia32_vcvtneobf162ps128", + "llvm.x86.vcvtneobf162ps256" => "__builtin_ia32_vcvtneobf162ps256", + "llvm.x86.vcvtneoph2ps128" => "__builtin_ia32_vcvtneoph2ps128", + "llvm.x86.vcvtneoph2ps256" => "__builtin_ia32_vcvtneoph2ps256", + "llvm.x86.vcvtneps2bf16128" => "__builtin_ia32_vcvtneps2bf16128", + "llvm.x86.vcvtneps2bf16256" => "__builtin_ia32_vcvtneps2bf16256", "llvm.x86.vcvtph2ps.128" => "__builtin_ia32_vcvtph2ps", "llvm.x86.vcvtph2ps.256" => "__builtin_ia32_vcvtph2ps256", "llvm.x86.vcvtps2ph.128" => "__builtin_ia32_vcvtps2ph", diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index 1b089f08f764a..0edec566be309 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -1,159 +1,387 @@ use std::borrow::Cow; -use gccjit::{Function, FunctionPtrType, RValue, ToRValue}; +use gccjit::{Function, FunctionPtrType, RValue, ToRValue, UnaryOp}; +use rustc_codegen_ssa::traits::BuilderMethods; use crate::{context::CodegenCx, builder::Builder}; -pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc, 'tcx>, gcc_func: FunctionPtrType<'gcc>, mut args: Cow<'b, [RValue<'gcc>]>, func_name: &str) -> Cow<'b, [RValue<'gcc>]> { +pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc, 'tcx>, gcc_func: FunctionPtrType<'gcc>, mut args: Cow<'b, [RValue<'gcc>]>, func_name: &str, original_function_name: Option<&String>) -> Cow<'b, [RValue<'gcc>]> { // Some LLVM intrinsics do not map 1-to-1 to GCC intrinsics, so we add the missing // arguments here. if gcc_func.get_param_count() != args.len() { match &*func_name { - "__builtin_ia32_pmuldq512_mask" | "__builtin_ia32_pmuludq512_mask" - // FIXME(antoyo): the following intrinsics has 4 (or 5) arguments according to the doc, but is defined with 2 (or 3) arguments in library/stdarch/crates/core_arch/src/x86/avx512f.rs. + // NOTE: the following intrinsics have a different number of parameters in LLVM and GCC. + "__builtin_ia32_prold512_mask" | "__builtin_ia32_pmuldq512_mask" | "__builtin_ia32_pmuludq512_mask" | "__builtin_ia32_pmaxsd512_mask" | "__builtin_ia32_pmaxsq512_mask" | "__builtin_ia32_pmaxsq256_mask" - | "__builtin_ia32_pmaxsq128_mask" | "__builtin_ia32_maxps512_mask" | "__builtin_ia32_maxpd512_mask" - | "__builtin_ia32_pmaxud512_mask" | "__builtin_ia32_pmaxuq512_mask" | "__builtin_ia32_pmaxuq256_mask" - | "__builtin_ia32_pmaxuq128_mask" + | "__builtin_ia32_pmaxsq128_mask" | "__builtin_ia32_pmaxud512_mask" | "__builtin_ia32_pmaxuq512_mask" | "__builtin_ia32_pminsd512_mask" | "__builtin_ia32_pminsq512_mask" | "__builtin_ia32_pminsq256_mask" - | "__builtin_ia32_pminsq128_mask" | "__builtin_ia32_minps512_mask" | "__builtin_ia32_minpd512_mask" - | "__builtin_ia32_pminud512_mask" | "__builtin_ia32_pminuq512_mask" | "__builtin_ia32_pminuq256_mask" - | "__builtin_ia32_pminuq128_mask" | "__builtin_ia32_sqrtps512_mask" | "__builtin_ia32_sqrtpd512_mask" + | "__builtin_ia32_pminsq128_mask" | "__builtin_ia32_pminud512_mask" | "__builtin_ia32_pminuq512_mask" + | "__builtin_ia32_prolq512_mask" | "__builtin_ia32_prorq512_mask" | "__builtin_ia32_pslldi512_mask" + | "__builtin_ia32_psrldi512_mask" | "__builtin_ia32_psllqi512_mask" | "__builtin_ia32_psrlqi512_mask" + | "__builtin_ia32_pslld512_mask" | "__builtin_ia32_psrld512_mask" | "__builtin_ia32_psllq512_mask" + | "__builtin_ia32_psrlq512_mask" | "__builtin_ia32_psrad512_mask" | "__builtin_ia32_psraq512_mask" + | "__builtin_ia32_psradi512_mask" | "__builtin_ia32_psraqi512_mask" | "__builtin_ia32_psrav16si_mask" + | "__builtin_ia32_psrav8di_mask" | "__builtin_ia32_prolvd512_mask" | "__builtin_ia32_prorvd512_mask" + | "__builtin_ia32_prolvq512_mask" | "__builtin_ia32_prorvq512_mask" | "__builtin_ia32_psllv16si_mask" + | "__builtin_ia32_psrlv16si_mask" | "__builtin_ia32_psllv8di_mask" | "__builtin_ia32_psrlv8di_mask" + | "__builtin_ia32_permvarsi512_mask" | "__builtin_ia32_vpermilvarps512_mask" + | "__builtin_ia32_vpermilvarpd512_mask" | "__builtin_ia32_permvardi512_mask" + | "__builtin_ia32_permvarsf512_mask" | "__builtin_ia32_permvarqi512_mask" + | "__builtin_ia32_permvarqi256_mask" | "__builtin_ia32_permvarqi128_mask" + | "__builtin_ia32_vpmultishiftqb512_mask" | "__builtin_ia32_vpmultishiftqb256_mask" + | "__builtin_ia32_vpmultishiftqb128_mask" => { - // TODO: refactor by separating those intrinsics outside of this branch. - let add_before_last_arg = - match &*func_name { - "__builtin_ia32_maxps512_mask" | "__builtin_ia32_maxpd512_mask" - | "__builtin_ia32_minps512_mask" | "__builtin_ia32_minpd512_mask" - | "__builtin_ia32_sqrtps512_mask" | "__builtin_ia32_sqrtpd512_mask" => true, - _ => false, - }; - let new_first_arg_is_zero = - match &*func_name { - "__builtin_ia32_pmaxuq256_mask" | "__builtin_ia32_pmaxuq128_mask" - | "__builtin_ia32_pminuq256_mask" | "__builtin_ia32_pminuq128_mask" => true, - _ => false - }; - let arg3_index = - match &*func_name { - "__builtin_ia32_sqrtps512_mask" | "__builtin_ia32_sqrtpd512_mask" => 1, - _ => 2, - }; - let mut new_args = args.to_vec(); - let arg3_type = gcc_func.get_param_type(arg3_index); - let first_arg = - if new_first_arg_is_zero { - let vector_type = arg3_type.dyncast_vector().expect("vector type"); - let zero = builder.context.new_rvalue_zero(vector_type.get_element_type()); - let num_units = vector_type.get_num_units(); - builder.context.new_rvalue_from_vector(None, arg3_type, &vec![zero; num_units]) - } - else { - builder.current_func().new_local(None, arg3_type, "undefined_for_intrinsic").to_rvalue() - }; - if add_before_last_arg { - new_args.insert(new_args.len() - 1, first_arg); - } - else { - new_args.push(first_arg); - } - let arg4_index = - match &*func_name { - "__builtin_ia32_sqrtps512_mask" | "__builtin_ia32_sqrtpd512_mask" => 2, - _ => 3, - }; - let arg4_type = gcc_func.get_param_type(arg4_index); - let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); - if add_before_last_arg { - new_args.insert(new_args.len() - 1, minus_one); - } - else { - new_args.push(minus_one); + let mut new_args = args.to_vec(); + let arg3_type = gcc_func.get_param_type(2); + let first_arg = builder.current_func().new_local(None, arg3_type, "undefined_for_intrinsic").to_rvalue(); + new_args.push(first_arg); + let arg4_type = gcc_func.get_param_type(3); + let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); + new_args.push(minus_one); + args = new_args.into(); + }, + "__builtin_ia32_pmaxuq256_mask" | "__builtin_ia32_pmaxuq128_mask" | "__builtin_ia32_pminuq256_mask" + | "__builtin_ia32_pminuq128_mask" | "__builtin_ia32_prold256_mask" | "__builtin_ia32_prold128_mask" + | "__builtin_ia32_prord512_mask" | "__builtin_ia32_prord256_mask" | "__builtin_ia32_prord128_mask" + | "__builtin_ia32_prolq256_mask" | "__builtin_ia32_prolq128_mask" | "__builtin_ia32_prorq256_mask" + | "__builtin_ia32_prorq128_mask" | "__builtin_ia32_psraq256_mask" | "__builtin_ia32_psraq128_mask" + | "__builtin_ia32_psraqi256_mask" | "__builtin_ia32_psraqi128_mask" | "__builtin_ia32_psravq256_mask" + | "__builtin_ia32_psravq128_mask" | "__builtin_ia32_prolvd256_mask" | "__builtin_ia32_prolvd128_mask" + | "__builtin_ia32_prorvd256_mask" | "__builtin_ia32_prorvd128_mask" | "__builtin_ia32_prolvq256_mask" + | "__builtin_ia32_prolvq128_mask" | "__builtin_ia32_prorvq256_mask" | "__builtin_ia32_prorvq128_mask" + | "__builtin_ia32_permvardi256_mask" | "__builtin_ia32_permvardf512_mask" | "__builtin_ia32_permvardf256_mask" + | "__builtin_ia32_pmulhuw512_mask" | "__builtin_ia32_pmulhw512_mask" | "__builtin_ia32_pmulhrsw512_mask" + | "__builtin_ia32_pmaxuw512_mask" | "__builtin_ia32_pmaxub512_mask" | "__builtin_ia32_pmaxsw512_mask" + | "__builtin_ia32_pmaxsb512_mask" | "__builtin_ia32_pminuw512_mask" | "__builtin_ia32_pminub512_mask" + | "__builtin_ia32_pminsw512_mask" | "__builtin_ia32_pminsb512_mask" + | "__builtin_ia32_pmaddwd512_mask" | "__builtin_ia32_pmaddubsw512_mask" | "__builtin_ia32_packssdw512_mask" + | "__builtin_ia32_packsswb512_mask" | "__builtin_ia32_packusdw512_mask" | "__builtin_ia32_packuswb512_mask" + | "__builtin_ia32_pavgw512_mask" | "__builtin_ia32_pavgb512_mask" | "__builtin_ia32_psllw512_mask" + | "__builtin_ia32_psllwi512_mask" | "__builtin_ia32_psllv32hi_mask" | "__builtin_ia32_psrlw512_mask" + | "__builtin_ia32_psrlwi512_mask" | "__builtin_ia32_psllv16hi_mask" | "__builtin_ia32_psllv8hi_mask" + | "__builtin_ia32_psrlv32hi_mask" | "__builtin_ia32_psraw512_mask" | "__builtin_ia32_psrawi512_mask" + | "__builtin_ia32_psrlv16hi_mask" | "__builtin_ia32_psrlv8hi_mask" | "__builtin_ia32_psrav32hi_mask" + | "__builtin_ia32_permvarhi512_mask" | "__builtin_ia32_pshufb512_mask" | "__builtin_ia32_psrav16hi_mask" + | "__builtin_ia32_psrav8hi_mask" | "__builtin_ia32_permvarhi256_mask" | "__builtin_ia32_permvarhi128_mask" + => { + let mut new_args = args.to_vec(); + let arg3_type = gcc_func.get_param_type(2); + let vector_type = arg3_type.dyncast_vector().expect("vector type"); + let zero = builder.context.new_rvalue_zero(vector_type.get_element_type()); + let num_units = vector_type.get_num_units(); + let first_arg = builder.context.new_rvalue_from_vector(None, arg3_type, &vec![zero; num_units]); + new_args.push(first_arg); + let arg4_type = gcc_func.get_param_type(3); + let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); + new_args.push(minus_one); + args = new_args.into(); + }, + "__builtin_ia32_dbpsadbw512_mask" | "__builtin_ia32_dbpsadbw256_mask" | "__builtin_ia32_dbpsadbw128_mask" => { + let mut new_args = args.to_vec(); + let arg4_type = gcc_func.get_param_type(3); + let vector_type = arg4_type.dyncast_vector().expect("vector type"); + let zero = builder.context.new_rvalue_zero(vector_type.get_element_type()); + let num_units = vector_type.get_num_units(); + let first_arg = builder.context.new_rvalue_from_vector(None, arg4_type, &vec![zero; num_units]); + new_args.push(first_arg); + let arg5_type = gcc_func.get_param_type(4); + let minus_one = builder.context.new_rvalue_from_int(arg5_type, -1); + new_args.push(minus_one); + args = new_args.into(); + }, + "__builtin_ia32_vplzcntd_512_mask" | "__builtin_ia32_vplzcntd_256_mask" | "__builtin_ia32_vplzcntd_128_mask" + | "__builtin_ia32_vplzcntq_512_mask" | "__builtin_ia32_vplzcntq_256_mask" | "__builtin_ia32_vplzcntq_128_mask" => { + let mut new_args = args.to_vec(); + // Remove last arg as it doesn't seem to be used in GCC and is always false. + new_args.pop(); + let arg2_type = gcc_func.get_param_type(1); + let vector_type = arg2_type.dyncast_vector().expect("vector type"); + let zero = builder.context.new_rvalue_zero(vector_type.get_element_type()); + let num_units = vector_type.get_num_units(); + let first_arg = builder.context.new_rvalue_from_vector(None, arg2_type, &vec![zero; num_units]); + new_args.push(first_arg); + let arg3_type = gcc_func.get_param_type(2); + let minus_one = builder.context.new_rvalue_from_int(arg3_type, -1); + new_args.push(minus_one); + args = new_args.into(); + }, + "__builtin_ia32_vpconflictsi_512_mask" | "__builtin_ia32_vpconflictsi_256_mask" + | "__builtin_ia32_vpconflictsi_128_mask" | "__builtin_ia32_vpconflictdi_512_mask" + | "__builtin_ia32_vpconflictdi_256_mask" | "__builtin_ia32_vpconflictdi_128_mask" => { + let mut new_args = args.to_vec(); + let arg2_type = gcc_func.get_param_type(1); + let vector_type = arg2_type.dyncast_vector().expect("vector type"); + let zero = builder.context.new_rvalue_zero(vector_type.get_element_type()); + let num_units = vector_type.get_num_units(); + let first_arg = builder.context.new_rvalue_from_vector(None, arg2_type, &vec![zero; num_units]); + new_args.push(first_arg); + let arg3_type = gcc_func.get_param_type(2); + let minus_one = builder.context.new_rvalue_from_int(arg3_type, -1); + new_args.push(minus_one); + args = new_args.into(); + }, + "__builtin_ia32_pternlogd512_mask" | "__builtin_ia32_pternlogd256_mask" + | "__builtin_ia32_pternlogd128_mask" | "__builtin_ia32_pternlogq512_mask" + | "__builtin_ia32_pternlogq256_mask" | "__builtin_ia32_pternlogq128_mask" => { + let mut new_args = args.to_vec(); + let arg5_type = gcc_func.get_param_type(4); + let minus_one = builder.context.new_rvalue_from_int(arg5_type, -1); + new_args.push(minus_one); + args = new_args.into(); + }, + "__builtin_ia32_vfmaddps512_mask" | "__builtin_ia32_vfmaddpd512_mask" => { + let mut new_args = args.to_vec(); + + let mut last_arg = None; + if args.len() == 4 { + last_arg = new_args.pop(); + } + + let arg4_type = gcc_func.get_param_type(3); + let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); + new_args.push(minus_one); + + if args.len() == 3 { + // Both llvm.fma.v16f32 and llvm.x86.avx512.vfmadd.ps.512 maps to + // the same GCC intrinsic, but the former has 3 parameters and the + // latter has 4 so it doesn't require this additional argument. + let arg5_type = gcc_func.get_param_type(4); + new_args.push(builder.context.new_rvalue_from_int(arg5_type, 4)); + } + + if let Some(last_arg) = last_arg { + new_args.push(last_arg); + } + + args = new_args.into(); + }, + "__builtin_ia32_addps512_mask" | "__builtin_ia32_addpd512_mask" + | "__builtin_ia32_subps512_mask" | "__builtin_ia32_subpd512_mask" + | "__builtin_ia32_mulps512_mask" | "__builtin_ia32_mulpd512_mask" + | "__builtin_ia32_divps512_mask" | "__builtin_ia32_divpd512_mask" + | "__builtin_ia32_maxps512_mask" | "__builtin_ia32_maxpd512_mask" + | "__builtin_ia32_minps512_mask" | "__builtin_ia32_minpd512_mask" => { + let mut new_args = args.to_vec(); + let last_arg = new_args.pop().expect("last arg"); + let arg3_type = gcc_func.get_param_type(2); + let undefined = builder.current_func().new_local(None, arg3_type, "undefined_for_intrinsic").to_rvalue(); + new_args.push(undefined); + let arg4_type = gcc_func.get_param_type(3); + let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); + new_args.push(minus_one); + new_args.push(last_arg); + args = new_args.into(); + }, + "__builtin_ia32_vfmaddsubps512_mask" | "__builtin_ia32_vfmaddsubpd512_mask" => { + let mut new_args = args.to_vec(); + let last_arg = new_args.pop().expect("last arg"); + let arg4_type = gcc_func.get_param_type(3); + let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); + new_args.push(minus_one); + new_args.push(last_arg); + args = new_args.into(); + }, + "__builtin_ia32_vpermi2vard512_mask" | "__builtin_ia32_vpermi2vard256_mask" + | "__builtin_ia32_vpermi2vard128_mask" | "__builtin_ia32_vpermi2varq512_mask" + | "__builtin_ia32_vpermi2varq256_mask" | "__builtin_ia32_vpermi2varq128_mask" + | "__builtin_ia32_vpermi2varps512_mask" | "__builtin_ia32_vpermi2varps256_mask" + | "__builtin_ia32_vpermi2varps128_mask" | "__builtin_ia32_vpermi2varpd512_mask" + | "__builtin_ia32_vpermi2varpd256_mask" | "__builtin_ia32_vpermi2varpd128_mask" | "__builtin_ia32_vpmadd52huq512_mask" + | "__builtin_ia32_vpmadd52luq512_mask" | "__builtin_ia32_vpmadd52huq256_mask" | "__builtin_ia32_vpmadd52luq256_mask" + | "__builtin_ia32_vpmadd52huq128_mask" + => { + let mut new_args = args.to_vec(); + let arg4_type = gcc_func.get_param_type(3); + let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); + new_args.push(minus_one); + args = new_args.into(); + }, + "__builtin_ia32_cvtdq2ps512_mask" | "__builtin_ia32_cvtudq2ps512_mask" + | "__builtin_ia32_sqrtps512_mask" | "__builtin_ia32_sqrtpd512_mask" => { + let mut new_args = args.to_vec(); + let last_arg = new_args.pop().expect("last arg"); + let arg2_type = gcc_func.get_param_type(1); + let undefined = builder.current_func().new_local(None, arg2_type, "undefined_for_intrinsic").to_rvalue(); + new_args.push(undefined); + let arg3_type = gcc_func.get_param_type(2); + let minus_one = builder.context.new_rvalue_from_int(arg3_type, -1); + new_args.push(minus_one); + new_args.push(last_arg); + args = new_args.into(); + }, + "__builtin_ia32_stmxcsr" => { + args = vec![].into(); + }, + "__builtin_ia32_addcarryx_u64" | "__builtin_ia32_sbb_u64" | "__builtin_ia32_addcarryx_u32" | "__builtin_ia32_sbb_u32" => { + let mut new_args = args.to_vec(); + let arg2_type = gcc_func.get_param_type(1); + let variable = builder.current_func().new_local(None, arg2_type, "addcarryResult"); + new_args.push(variable.get_address(None)); + args = new_args.into(); + }, + "__builtin_ia32_vpermt2varqi512_mask" | "__builtin_ia32_vpermt2varqi256_mask" + | "__builtin_ia32_vpermt2varqi128_mask" | "__builtin_ia32_vpermt2varhi512_mask" + | "__builtin_ia32_vpermt2varhi256_mask" | "__builtin_ia32_vpermt2varhi128_mask" + => { + let new_args = args.to_vec(); + let arg4_type = gcc_func.get_param_type(3); + let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); + args = vec![new_args[1], new_args[0], new_args[2], minus_one].into(); + }, + "__builtin_ia32_xrstor" | "__builtin_ia32_xsavec" => { + let new_args = args.to_vec(); + let thirty_two = builder.context.new_rvalue_from_int(new_args[1].get_type(), 32); + let arg2 = new_args[1] << thirty_two | new_args[2]; + let arg2_type = gcc_func.get_param_type(1); + let arg2 = builder.context.new_cast(None, arg2, arg2_type); + args = vec![new_args[0], arg2].into(); + }, + "__builtin_prefetch" => { + let mut new_args = args.to_vec(); + new_args.pop(); + args = new_args.into(); + }, + _ => (), + } + } + else { + match &*func_name { + "__builtin_ia32_rndscaless_mask_round" | "__builtin_ia32_rndscalesd_mask_round" => { + let new_args = args.to_vec(); + let arg3_type = gcc_func.get_param_type(2); + let arg3 = builder.context.new_cast(None, new_args[4], arg3_type); + let arg4_type = gcc_func.get_param_type(3); + let arg4 = builder.context.new_bitcast(None, new_args[2], arg4_type); + args = vec![new_args[0], new_args[1], arg3, arg4, new_args[3], new_args[5]].into(); + }, + // NOTE: the LLVM intrinsic receives 3 floats, but the GCC builtin requires 3 vectors. + // FIXME: the intrinsics like _mm_mask_fmadd_sd should probably directly call the GCC + // instrinsic to avoid this. + "__builtin_ia32_vfmaddss3_round" => { + let new_args = args.to_vec(); + let arg1_type = gcc_func.get_param_type(0); + let arg2_type = gcc_func.get_param_type(1); + let arg3_type = gcc_func.get_param_type(2); + let a = builder.context.new_rvalue_from_vector(None, arg1_type, &[new_args[0]; 4]); + let b = builder.context.new_rvalue_from_vector(None, arg2_type, &[new_args[1]; 4]); + let c = builder.context.new_rvalue_from_vector(None, arg3_type, &[new_args[2]; 4]); + args = vec![a, b, c, new_args[3]].into(); + }, + "__builtin_ia32_vfmaddsd3_round" => { + let new_args = args.to_vec(); + let arg1_type = gcc_func.get_param_type(0); + let arg2_type = gcc_func.get_param_type(1); + let arg3_type = gcc_func.get_param_type(2); + let a = builder.context.new_rvalue_from_vector(None, arg1_type, &[new_args[0]; 2]); + let b = builder.context.new_rvalue_from_vector(None, arg2_type, &[new_args[1]; 2]); + let c = builder.context.new_rvalue_from_vector(None, arg3_type, &[new_args[2]; 2]); + args = vec![a, b, c, new_args[3]].into(); + }, + "__builtin_ia32_vfmaddsubpd256" | "__builtin_ia32_vfmaddsubps" | "__builtin_ia32_vfmaddsubps256" + | "__builtin_ia32_vfmaddsubpd" => { + if let Some(original_function_name) = original_function_name { + match &**original_function_name { + "llvm.x86.fma.vfmsubadd.pd.256" | "llvm.x86.fma.vfmsubadd.ps" | "llvm.x86.fma.vfmsubadd.ps.256" + | "llvm.x86.fma.vfmsubadd.pd" => { + // NOTE: since both llvm.x86.fma.vfmsubadd.ps and llvm.x86.fma.vfmaddsub.ps maps to + // __builtin_ia32_vfmaddsubps, only add minus if this comes from a + // subadd LLVM intrinsic, e.g. _mm256_fmsubadd_pd. + let mut new_args = args.to_vec(); + let arg3 = &mut new_args[2]; + *arg3 = builder.context.new_unary_op(None, UnaryOp::Minus, arg3.get_type(), *arg3); + args = new_args.into(); + }, + _ => (), } - args = new_args.into(); - }, - "__builtin_ia32_pternlogd512_mask" | "__builtin_ia32_pternlogd256_mask" - | "__builtin_ia32_pternlogd128_mask" | "__builtin_ia32_pternlogq512_mask" - | "__builtin_ia32_pternlogq256_mask" | "__builtin_ia32_pternlogq128_mask" => { - let mut new_args = args.to_vec(); - let arg5_type = gcc_func.get_param_type(4); - let minus_one = builder.context.new_rvalue_from_int(arg5_type, -1); - new_args.push(minus_one); - args = new_args.into(); - }, - "__builtin_ia32_vfmaddps512_mask" | "__builtin_ia32_vfmaddpd512_mask" => { - let mut new_args = args.to_vec(); - - let mut last_arg = None; - if args.len() == 4 { - last_arg = new_args.pop(); - } - - let arg4_type = gcc_func.get_param_type(3); - let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); - new_args.push(minus_one); - - if args.len() == 3 { - // Both llvm.fma.v16f32 and llvm.x86.avx512.vfmadd.ps.512 maps to - // the same GCC intrinsic, but the former has 3 parameters and the - // latter has 4 so it doesn't require this additional argument. - let arg5_type = gcc_func.get_param_type(4); - new_args.push(builder.context.new_rvalue_from_int(arg5_type, 4)); - } - - if let Some(last_arg) = last_arg { - new_args.push(last_arg); - } - - args = new_args.into(); - }, - "__builtin_ia32_addps512_mask" | "__builtin_ia32_addpd512_mask" - | "__builtin_ia32_subps512_mask" | "__builtin_ia32_subpd512_mask" - | "__builtin_ia32_mulps512_mask" | "__builtin_ia32_mulpd512_mask" - | "__builtin_ia32_divps512_mask" | "__builtin_ia32_divpd512_mask" => { - let mut new_args = args.to_vec(); - let last_arg = new_args.pop().expect("last arg"); - let arg3_type = gcc_func.get_param_type(2); - let undefined = builder.current_func().new_local(None, arg3_type, "undefined_for_intrinsic").to_rvalue(); - new_args.push(undefined); - let arg4_type = gcc_func.get_param_type(3); - let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); - new_args.push(minus_one); - new_args.push(last_arg); - args = new_args.into(); - }, - "__builtin_ia32_vfmaddsubps512_mask" | "__builtin_ia32_vfmaddsubpd512_mask" => { - let mut new_args = args.to_vec(); - let last_arg = new_args.pop().expect("last arg"); - let arg4_type = gcc_func.get_param_type(3); - let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); - new_args.push(minus_one); - new_args.push(last_arg); - args = new_args.into(); - }, - _ => (), + } + }, + "__builtin_ia32_ldmxcsr" => { + // The builtin __builtin_ia32_ldmxcsr takes an integer value while llvm.x86.sse.ldmxcsr takes a pointer, + // so dereference the pointer. + let mut new_args = args.to_vec(); + let uint_ptr_type = builder.uint_type.make_pointer(); + let arg1 = builder.context.new_cast(None, args[0], uint_ptr_type); + new_args[0] = arg1.dereference(None).to_rvalue(); + args = new_args.into(); + }, + "__builtin_ia32_rcp14sd_mask" | "__builtin_ia32_rcp14ss_mask" | "__builtin_ia32_rsqrt14sd_mask" + | "__builtin_ia32_rsqrt14ss_mask" => { + let new_args = args.to_vec(); + args = vec![new_args[1], new_args[0], new_args[2], new_args[3]].into(); + }, + "__builtin_ia32_sqrtsd_mask_round" | "__builtin_ia32_sqrtss_mask_round" => { + let new_args = args.to_vec(); + args = vec![new_args[1], new_args[0], new_args[2], new_args[3], new_args[4]].into(); + }, + _ => (), } } args } +pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc, 'tcx>, mut return_value: RValue<'gcc>, func_name: &str, args: &[RValue<'gcc>], args_adjusted: bool, orig_args: &[RValue<'gcc>]) -> RValue<'gcc> { + match func_name { + "__builtin_ia32_vfmaddss3_round" | "__builtin_ia32_vfmaddsd3_round" => { + #[cfg(feature="master")] + { + let zero = builder.context.new_rvalue_zero(builder.int_type); + return_value = builder.context.new_vector_access(None, return_value, zero).to_rvalue(); + } + }, + "__builtin_ia32_addcarryx_u64" | "__builtin_ia32_sbb_u64" | "__builtin_ia32_addcarryx_u32" | "__builtin_ia32_sbb_u32" => { + // Both llvm.x86.addcarry.32 and llvm.x86.addcarryx.u32 points to the same GCC builtin, + // but only the former requires adjusting the return value. + // Those 2 LLVM intrinsics differ by their argument count, that's why we check if the + // arguments were adjusted. + if args_adjusted { + let last_arg = args.last().expect("last arg"); + let field1 = builder.context.new_field(None, builder.u8_type, "carryFlag"); + let field2 = builder.context.new_field(None, args[1].get_type(), "carryResult"); + let struct_type = builder.context.new_struct_type(None, "addcarryResult", &[field1, field2]); + return_value = builder.context.new_struct_constructor(None, struct_type.as_type(), None, &[return_value, last_arg.dereference(None).to_rvalue()]); + } + }, + "__builtin_ia32_stmxcsr" => { + // The builtin __builtin_ia32_stmxcsr returns a value while llvm.x86.sse.stmxcsr writes + // the result in its pointer argument. + // We removed the argument since __builtin_ia32_stmxcsr takes no arguments, so we need + // to get back the original argument to get the pointer we need to write the result to. + let uint_ptr_type = builder.uint_type.make_pointer(); + let ptr = builder.context.new_cast(None, orig_args[0], uint_ptr_type); + builder.llbb().add_assignment(None, ptr.dereference(None), return_value); + // The return value was assigned to the result pointer above. In order to not call the + // builtin twice, we overwrite the return value with a dummy value. + return_value = builder.context.new_rvalue_zero(builder.int_type); + }, + _ => (), + } + + return_value +} + pub fn ignore_arg_cast(func_name: &str, index: usize, args_len: usize) -> bool { - // NOTE: these intrinsics have missing parameters before the last one, so ignore the - // last argument type check. // FIXME(antoyo): find a way to refactor in order to avoid this hack. match func_name { + // NOTE: these intrinsics have missing parameters before the last one, so ignore the + // last argument type check. "__builtin_ia32_maxps512_mask" | "__builtin_ia32_maxpd512_mask" | "__builtin_ia32_minps512_mask" | "__builtin_ia32_minpd512_mask" | "__builtin_ia32_sqrtps512_mask" | "__builtin_ia32_sqrtpd512_mask" | "__builtin_ia32_addps512_mask" | "__builtin_ia32_addpd512_mask" | "__builtin_ia32_subps512_mask" | "__builtin_ia32_subpd512_mask" | "__builtin_ia32_mulps512_mask" | "__builtin_ia32_mulpd512_mask" | "__builtin_ia32_divps512_mask" | "__builtin_ia32_divpd512_mask" - | "__builtin_ia32_vfmaddsubps512_mask" | "__builtin_ia32_vfmaddsubpd512_mask" => { + | "__builtin_ia32_vfmaddsubps512_mask" | "__builtin_ia32_vfmaddsubpd512_mask" + | "__builtin_ia32_cvtdq2ps512_mask" | "__builtin_ia32_cvtudq2ps512_mask" => { if index == args_len - 1 { return true; } }, + "__builtin_ia32_rndscaless_mask_round" | "__builtin_ia32_rndscalesd_mask_round" => { + if index == 2 || index == 3 { + return true; + } + }, "__builtin_ia32_vfmaddps512_mask" | "__builtin_ia32_vfmaddpd512_mask" => { // Since there are two LLVM intrinsics that map to each of these GCC builtins and only // one of them has a missing parameter before the last one, we check the number of @@ -162,6 +390,14 @@ pub fn ignore_arg_cast(func_name: &str, index: usize, args_len: usize) -> bool { return true; } }, + // NOTE: the LLVM intrinsic receives 3 floats, but the GCC builtin requires 3 vectors. + "__builtin_ia32_vfmaddss3_round" | "__builtin_ia32_vfmaddsd3_round" => return true, + "__builtin_ia32_vplzcntd_512_mask" | "__builtin_ia32_vplzcntd_256_mask" | "__builtin_ia32_vplzcntd_128_mask" + | "__builtin_ia32_vplzcntq_512_mask" | "__builtin_ia32_vplzcntq_256_mask" | "__builtin_ia32_vplzcntq_128_mask" => { + if index == args_len - 1 { + return true; + } + }, _ => (), } @@ -171,7 +407,7 @@ pub fn ignore_arg_cast(func_name: &str, index: usize, args_len: usize) -> bool { #[cfg(not(feature="master"))] pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function<'gcc> { match name { - "llvm.x86.xgetbv" => { + "llvm.x86.xgetbv" | "llvm.x86.sse2.pause" => { let gcc_name = "__builtin_trap"; let func = cx.context.get_builtin_function(gcc_name); cx.functions.borrow_mut().insert(gcc_name.to_string(), func); @@ -183,24 +419,26 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function #[cfg(feature="master")] pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function<'gcc> { + match name { + "llvm.prefetch" => { + let gcc_name = "__builtin_prefetch"; + let func = cx.context.get_builtin_function(gcc_name); + cx.functions.borrow_mut().insert(gcc_name.to_string(), func); + return func + }, + _ => (), + } + let gcc_name = match name { "llvm.x86.xgetbv" => "__builtin_ia32_xgetbv", // NOTE: this doc specifies the equivalent GCC builtins: http://huonw.github.io/llvmint/llvmint/x86/index.html "llvm.sqrt.v2f64" => "__builtin_ia32_sqrtpd", "llvm.x86.avx512.pmul.dq.512" => "__builtin_ia32_pmuldq512_mask", "llvm.x86.avx512.pmulu.dq.512" => "__builtin_ia32_pmuludq512_mask", - "llvm.x86.avx512.mask.pmaxs.q.256" => "__builtin_ia32_pmaxsq256_mask", - "llvm.x86.avx512.mask.pmaxs.q.128" => "__builtin_ia32_pmaxsq128_mask", "llvm.x86.avx512.max.ps.512" => "__builtin_ia32_maxps512_mask", "llvm.x86.avx512.max.pd.512" => "__builtin_ia32_maxpd512_mask", - "llvm.x86.avx512.mask.pmaxu.q.256" => "__builtin_ia32_pmaxuq256_mask", - "llvm.x86.avx512.mask.pmaxu.q.128" => "__builtin_ia32_pmaxuq128_mask", - "llvm.x86.avx512.mask.pmins.q.256" => "__builtin_ia32_pminsq256_mask", - "llvm.x86.avx512.mask.pmins.q.128" => "__builtin_ia32_pminsq128_mask", "llvm.x86.avx512.min.ps.512" => "__builtin_ia32_minps512_mask", "llvm.x86.avx512.min.pd.512" => "__builtin_ia32_minpd512_mask", - "llvm.x86.avx512.mask.pminu.q.256" => "__builtin_ia32_pminuq256_mask", - "llvm.x86.avx512.mask.pminu.q.128" => "__builtin_ia32_pminuq128_mask", "llvm.fma.v16f32" => "__builtin_ia32_vfmaddps512_mask", "llvm.fma.v8f64" => "__builtin_ia32_vfmaddpd512_mask", "llvm.x86.avx512.vfmaddsub.ps.512" => "__builtin_ia32_vfmaddsubps512_mask", @@ -221,6 +459,153 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512.div.pd.512" => "__builtin_ia32_divpd512_mask", "llvm.x86.avx512.vfmadd.ps.512" => "__builtin_ia32_vfmaddps512_mask", "llvm.x86.avx512.vfmadd.pd.512" => "__builtin_ia32_vfmaddpd512_mask", + "llvm.x86.avx512.sitofp.round.v16f32.v16i32" => "__builtin_ia32_cvtdq2ps512_mask", + "llvm.x86.avx512.uitofp.round.v16f32.v16i32" => "__builtin_ia32_cvtudq2ps512_mask", + "llvm.x86.avx512.mask.ucmp.d.512" => "__builtin_ia32_ucmpd512_mask", + "llvm.x86.avx512.mask.ucmp.d.256" => "__builtin_ia32_ucmpd256_mask", + "llvm.x86.avx512.mask.ucmp.d.128" => "__builtin_ia32_ucmpd128_mask", + "llvm.x86.avx512.mask.cmp.d.512" => "__builtin_ia32_cmpd512_mask", + "llvm.x86.avx512.mask.cmp.d.256" => "__builtin_ia32_cmpd256_mask", + "llvm.x86.avx512.mask.cmp.d.128" => "__builtin_ia32_cmpd128_mask", + "llvm.x86.avx512.mask.ucmp.q.512" => "__builtin_ia32_ucmpq512_mask", + "llvm.x86.avx512.mask.ucmp.q.256" => "__builtin_ia32_ucmpq256_mask", + "llvm.x86.avx512.mask.ucmp.q.128" => "__builtin_ia32_ucmpq128_mask", + "llvm.x86.avx512.mask.cmp.q.512" => "__builtin_ia32_cmpq512_mask", + "llvm.x86.avx512.mask.cmp.q.256" => "__builtin_ia32_cmpq256_mask", + "llvm.x86.avx512.mask.cmp.q.128" => "__builtin_ia32_cmpq128_mask", + "llvm.x86.avx512.mask.max.ss.round" => "__builtin_ia32_maxss_mask_round", + "llvm.x86.avx512.mask.max.sd.round" => "__builtin_ia32_maxsd_mask_round", + "llvm.x86.avx512.mask.min.ss.round" => "__builtin_ia32_minss_mask_round", + "llvm.x86.avx512.mask.min.sd.round" => "__builtin_ia32_minsd_mask_round", + "llvm.x86.avx512.mask.sqrt.ss" => "__builtin_ia32_sqrtss_mask_round", + "llvm.x86.avx512.mask.sqrt.sd" => "__builtin_ia32_sqrtsd_mask_round", + "llvm.x86.avx512.mask.getexp.ss" => "__builtin_ia32_getexpss_mask_round", + "llvm.x86.avx512.mask.getexp.sd" => "__builtin_ia32_getexpsd_mask_round", + "llvm.x86.avx512.mask.getmant.ss" => "__builtin_ia32_getmantss_mask_round", + "llvm.x86.avx512.mask.getmant.sd" => "__builtin_ia32_getmantsd_mask_round", + "llvm.x86.avx512.mask.rndscale.ss" => "__builtin_ia32_rndscaless_mask_round", + "llvm.x86.avx512.mask.rndscale.sd" => "__builtin_ia32_rndscalesd_mask_round", + "llvm.x86.avx512.mask.scalef.ss" => "__builtin_ia32_scalefss_mask_round", + "llvm.x86.avx512.mask.scalef.sd" => "__builtin_ia32_scalefsd_mask_round", + "llvm.x86.avx512.vfmadd.f32" => "__builtin_ia32_vfmaddss3_round", + "llvm.x86.avx512.vfmadd.f64" => "__builtin_ia32_vfmaddsd3_round", + "llvm.ceil.v4f64" => "__builtin_ia32_ceilpd256", + "llvm.ceil.v8f32" => "__builtin_ia32_ceilps256", + "llvm.floor.v4f64" => "__builtin_ia32_floorpd256", + "llvm.floor.v8f32" => "__builtin_ia32_floorps256", + "llvm.sqrt.v4f64" => "__builtin_ia32_sqrtpd256", + "llvm.x86.sse.stmxcsr" => "__builtin_ia32_stmxcsr", + "llvm.x86.sse.ldmxcsr" => "__builtin_ia32_ldmxcsr", + "llvm.ctpop.v16i32" => "__builtin_ia32_vpopcountd_v16si", + "llvm.ctpop.v8i32" => "__builtin_ia32_vpopcountd_v8si", + "llvm.ctpop.v4i32" => "__builtin_ia32_vpopcountd_v4si", + "llvm.ctpop.v8i64" => "__builtin_ia32_vpopcountq_v8di", + "llvm.ctpop.v4i64" => "__builtin_ia32_vpopcountq_v4di", + "llvm.ctpop.v2i64" => "__builtin_ia32_vpopcountq_v2di", + "llvm.x86.addcarry.64" => "__builtin_ia32_addcarryx_u64", + "llvm.x86.subborrow.64" => "__builtin_ia32_sbb_u64", + "llvm.floor.v2f64" => "__builtin_ia32_floorpd", + "llvm.floor.v4f32" => "__builtin_ia32_floorps", + "llvm.ceil.v2f64" => "__builtin_ia32_ceilpd", + "llvm.ceil.v4f32" => "__builtin_ia32_ceilps", + "llvm.fma.v2f64" => "__builtin_ia32_vfmaddpd", + "llvm.fma.v4f64" => "__builtin_ia32_vfmaddpd256", + "llvm.fma.v4f32" => "__builtin_ia32_vfmaddps", + "llvm.fma.v8f32" => "__builtin_ia32_vfmaddps256", + "llvm.ctlz.v16i32" => "__builtin_ia32_vplzcntd_512_mask", + "llvm.ctlz.v8i32" => "__builtin_ia32_vplzcntd_256_mask", + "llvm.ctlz.v4i32" => "__builtin_ia32_vplzcntd_128_mask", + "llvm.ctlz.v8i64" => "__builtin_ia32_vplzcntq_512_mask", + "llvm.ctlz.v4i64" => "__builtin_ia32_vplzcntq_256_mask", + "llvm.ctlz.v2i64" => "__builtin_ia32_vplzcntq_128_mask", + "llvm.ctpop.v32i16" => "__builtin_ia32_vpopcountw_v32hi", + "llvm.x86.fma.vfmsub.sd" => "__builtin_ia32_vfmsubsd3", + "llvm.x86.fma.vfmsub.ss" => "__builtin_ia32_vfmsubss3", + "llvm.x86.fma.vfmsubadd.pd" => "__builtin_ia32_vfmaddsubpd", + "llvm.x86.fma.vfmsubadd.pd.256" => "__builtin_ia32_vfmaddsubpd256", + "llvm.x86.fma.vfmsubadd.ps" => "__builtin_ia32_vfmaddsubps", + "llvm.x86.fma.vfmsubadd.ps.256" => "__builtin_ia32_vfmaddsubps256", + "llvm.x86.fma.vfnmadd.sd" => "__builtin_ia32_vfnmaddsd3", + "llvm.x86.fma.vfnmadd.ss" => "__builtin_ia32_vfnmaddss3", + "llvm.x86.fma.vfnmsub.sd" => "__builtin_ia32_vfnmsubsd3", + "llvm.x86.fma.vfnmsub.ss" => "__builtin_ia32_vfnmsubss3", + "llvm.x86.avx512.conflict.d.512" => "__builtin_ia32_vpconflictsi_512_mask", + "llvm.x86.avx512.conflict.d.256" => "__builtin_ia32_vpconflictsi_256_mask", + "llvm.x86.avx512.conflict.d.128" => "__builtin_ia32_vpconflictsi_128_mask", + "llvm.x86.avx512.conflict.q.512" => "__builtin_ia32_vpconflictdi_512_mask", + "llvm.x86.avx512.conflict.q.256" => "__builtin_ia32_vpconflictdi_256_mask", + "llvm.x86.avx512.conflict.q.128" => "__builtin_ia32_vpconflictdi_128_mask", + "llvm.x86.avx512.vpermi2var.qi.512" => "__builtin_ia32_vpermt2varqi512_mask", + "llvm.x86.avx512.vpermi2var.qi.256" => "__builtin_ia32_vpermt2varqi256_mask", + "llvm.x86.avx512.vpermi2var.qi.128" => "__builtin_ia32_vpermt2varqi128_mask", + "llvm.x86.avx512.permvar.qi.512" => "__builtin_ia32_permvarqi512_mask", + "llvm.x86.avx512.permvar.qi.256" => "__builtin_ia32_permvarqi256_mask", + "llvm.x86.avx512.permvar.qi.128" => "__builtin_ia32_permvarqi128_mask", + "llvm.x86.avx512.pmultishift.qb.512" => "__builtin_ia32_vpmultishiftqb512_mask", + "llvm.x86.avx512.pmultishift.qb.256" => "__builtin_ia32_vpmultishiftqb256_mask", + "llvm.x86.avx512.pmultishift.qb.128" => "__builtin_ia32_vpmultishiftqb128_mask", + "llvm.ctpop.v16i16" => "__builtin_ia32_vpopcountw_v16hi", + "llvm.ctpop.v8i16" => "__builtin_ia32_vpopcountw_v8hi", + "llvm.ctpop.v64i8" => "__builtin_ia32_vpopcountb_v64qi", + "llvm.ctpop.v32i8" => "__builtin_ia32_vpopcountb_v32qi", + "llvm.ctpop.v16i8" => "__builtin_ia32_vpopcountb_v16qi", + "llvm.x86.avx512.mask.vpshufbitqmb.512" => "__builtin_ia32_vpshufbitqmb512_mask", + "llvm.x86.avx512.mask.vpshufbitqmb.256" => "__builtin_ia32_vpshufbitqmb256_mask", + "llvm.x86.avx512.mask.vpshufbitqmb.128" => "__builtin_ia32_vpshufbitqmb128_mask", + "llvm.x86.avx512.mask.ucmp.w.512" => "__builtin_ia32_ucmpw512_mask", + "llvm.x86.avx512.mask.ucmp.w.256" => "__builtin_ia32_ucmpw256_mask", + "llvm.x86.avx512.mask.ucmp.w.128" => "__builtin_ia32_ucmpw128_mask", + "llvm.x86.avx512.mask.ucmp.b.512" => "__builtin_ia32_ucmpb512_mask", + "llvm.x86.avx512.mask.ucmp.b.256" => "__builtin_ia32_ucmpb256_mask", + "llvm.x86.avx512.mask.ucmp.b.128" => "__builtin_ia32_ucmpb128_mask", + "llvm.x86.avx512.mask.cmp.w.512" => "__builtin_ia32_cmpw512_mask", + "llvm.x86.avx512.mask.cmp.w.256" => "__builtin_ia32_cmpw256_mask", + "llvm.x86.avx512.mask.cmp.w.128" => "__builtin_ia32_cmpw128_mask", + "llvm.x86.avx512.mask.cmp.b.512" => "__builtin_ia32_cmpb512_mask", + "llvm.x86.avx512.mask.cmp.b.256" => "__builtin_ia32_cmpb256_mask", + "llvm.x86.avx512.mask.cmp.b.128" => "__builtin_ia32_cmpb128_mask", + "llvm.x86.xrstor" => "__builtin_ia32_xrstor", + "llvm.x86.xsavec" => "__builtin_ia32_xsavec", + "llvm.x86.addcarry.32" => "__builtin_ia32_addcarryx_u32", + "llvm.x86.subborrow.32" => "__builtin_ia32_sbb_u32", + "llvm.x86.avx512.mask.compress.store.w.512" => "__builtin_ia32_compressstoreuhi512_mask", + "llvm.x86.avx512.mask.compress.store.w.256" => "__builtin_ia32_compressstoreuhi256_mask", + "llvm.x86.avx512.mask.compress.store.w.128" => "__builtin_ia32_compressstoreuhi128_mask", + "llvm.x86.avx512.mask.compress.store.b.512" => "__builtin_ia32_compressstoreuqi512_mask", + "llvm.x86.avx512.mask.compress.store.b.256" => "__builtin_ia32_compressstoreuqi256_mask", + "llvm.x86.avx512.mask.compress.store.b.128" => "__builtin_ia32_compressstoreuqi128_mask", + "llvm.x86.avx512.mask.compress.w.512" => "__builtin_ia32_compresshi512_mask", + "llvm.x86.avx512.mask.compress.w.256" => "__builtin_ia32_compresshi256_mask", + "llvm.x86.avx512.mask.compress.w.128" => "__builtin_ia32_compresshi128_mask", + "llvm.x86.avx512.mask.compress.b.512" => "__builtin_ia32_compressqi512_mask", + "llvm.x86.avx512.mask.compress.b.256" => "__builtin_ia32_compressqi256_mask", + "llvm.x86.avx512.mask.compress.b.128" => "__builtin_ia32_compressqi128_mask", + "llvm.x86.avx512.mask.expand.w.512" => "__builtin_ia32_expandhi512_mask", + "llvm.x86.avx512.mask.expand.w.256" => "__builtin_ia32_expandhi256_mask", + "llvm.x86.avx512.mask.expand.w.128" => "__builtin_ia32_expandhi128_mask", + "llvm.x86.avx512.mask.expand.b.512" => "__builtin_ia32_expandqi512_mask", + "llvm.x86.avx512.mask.expand.b.256" => "__builtin_ia32_expandqi256_mask", + "llvm.x86.avx512.mask.expand.b.128" => "__builtin_ia32_expandqi128_mask", + "llvm.fshl.v8i64" => "__builtin_ia32_vpshldv_v8di", + "llvm.fshl.v4i64" => "__builtin_ia32_vpshldv_v4di", + "llvm.fshl.v2i64" => "__builtin_ia32_vpshldv_v2di", + "llvm.fshl.v16i32" => "__builtin_ia32_vpshldv_v16si", + "llvm.fshl.v8i32" => "__builtin_ia32_vpshldv_v8si", + "llvm.fshl.v4i32" => "__builtin_ia32_vpshldv_v4si", + "llvm.fshl.v32i16" => "__builtin_ia32_vpshldv_v32hi", + "llvm.fshl.v16i16" => "__builtin_ia32_vpshldv_v16hi", + "llvm.fshl.v8i16" => "__builtin_ia32_vpshldv_v8hi", + "llvm.fshr.v8i64" => "__builtin_ia32_vpshrdv_v8di", + "llvm.fshr.v4i64" => "__builtin_ia32_vpshrdv_v4di", + "llvm.fshr.v2i64" => "__builtin_ia32_vpshrdv_v2di", + "llvm.fshr.v16i32" => "__builtin_ia32_vpshrdv_v16si", + "llvm.fshr.v8i32" => "__builtin_ia32_vpshrdv_v8si", + "llvm.fshr.v4i32" => "__builtin_ia32_vpshrdv_v4si", + "llvm.fshr.v32i16" => "__builtin_ia32_vpshrdv_v32hi", + "llvm.fshr.v16i16" => "__builtin_ia32_vpshrdv_v16hi", + "llvm.fshr.v8i16" => "__builtin_ia32_vpshrdv_v8hi", + "llvm.x86.fma.vfmadd.sd" => "__builtin_ia32_vfmaddsd3", + "llvm.x86.fma.vfmadd.ss" => "__builtin_ia32_vfmaddss3", // The above doc points to unknown builtins for the following, so override them: "llvm.x86.avx2.gather.d.d" => "__builtin_ia32_gathersiv4si", @@ -239,7 +624,151 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx2.gather.q.q.256" => "__builtin_ia32_gatherdiv4di", "llvm.x86.avx2.gather.q.pd" => "__builtin_ia32_gatherdiv2df", "llvm.x86.avx2.gather.q.pd.256" => "__builtin_ia32_gatherdiv4df", - "" => "", + "llvm.x86.avx512.pslli.d.512" => "__builtin_ia32_pslldi512_mask", + "llvm.x86.avx512.psrli.d.512" => "__builtin_ia32_psrldi512_mask", + "llvm.x86.avx512.pslli.q.512" => "__builtin_ia32_psllqi512_mask", + "llvm.x86.avx512.psrli.q.512" => "__builtin_ia32_psrlqi512_mask", + "llvm.x86.avx512.psll.d.512" => "__builtin_ia32_pslld512_mask", + "llvm.x86.avx512.psrl.d.512" => "__builtin_ia32_psrld512_mask", + "llvm.x86.avx512.psll.q.512" => "__builtin_ia32_psllq512_mask", + "llvm.x86.avx512.psrl.q.512" => "__builtin_ia32_psrlq512_mask", + "llvm.x86.avx512.psra.d.512" => "__builtin_ia32_psrad512_mask", + "llvm.x86.avx512.psra.q.512" => "__builtin_ia32_psraq512_mask", + "llvm.x86.avx512.psra.q.256" => "__builtin_ia32_psraq256_mask", + "llvm.x86.avx512.psra.q.128" => "__builtin_ia32_psraq128_mask", + "llvm.x86.avx512.psrai.d.512" => "__builtin_ia32_psradi512_mask", + "llvm.x86.avx512.psrai.q.512" => "__builtin_ia32_psraqi512_mask", + "llvm.x86.avx512.psrai.q.256" => "__builtin_ia32_psraqi256_mask", + "llvm.x86.avx512.psrai.q.128" => "__builtin_ia32_psraqi128_mask", + "llvm.x86.avx512.psrav.d.512" => "__builtin_ia32_psrav16si_mask", + "llvm.x86.avx512.psrav.q.512" => "__builtin_ia32_psrav8di_mask", + "llvm.x86.avx512.psrav.q.256" => "__builtin_ia32_psravq256_mask", + "llvm.x86.avx512.psrav.q.128" => "__builtin_ia32_psravq128_mask", + "llvm.x86.avx512.psllv.d.512" => "__builtin_ia32_psllv16si_mask", + "llvm.x86.avx512.psrlv.d.512" => "__builtin_ia32_psrlv16si_mask", + "llvm.x86.avx512.psllv.q.512" => "__builtin_ia32_psllv8di_mask", + "llvm.x86.avx512.psrlv.q.512" => "__builtin_ia32_psrlv8di_mask", + "llvm.x86.avx512.permvar.si.512" => "__builtin_ia32_permvarsi512_mask", + "llvm.x86.avx512.vpermilvar.ps.512" => "__builtin_ia32_vpermilvarps512_mask", + "llvm.x86.avx512.vpermilvar.pd.512" => "__builtin_ia32_vpermilvarpd512_mask", + "llvm.x86.avx512.permvar.di.512" => "__builtin_ia32_permvardi512_mask", + "llvm.x86.avx512.permvar.di.256" => "__builtin_ia32_permvardi256_mask", + "llvm.x86.avx512.permvar.sf.512" => "__builtin_ia32_permvarsf512_mask", + "llvm.x86.avx512.permvar.df.512" => "__builtin_ia32_permvardf512_mask", + "llvm.x86.avx512.permvar.df.256" => "__builtin_ia32_permvardf256_mask", + "llvm.x86.avx512.vpermi2var.d.512" => "__builtin_ia32_vpermi2vard512_mask", + "llvm.x86.avx512.vpermi2var.d.256" => "__builtin_ia32_vpermi2vard256_mask", + "llvm.x86.avx512.vpermi2var.d.128" => "__builtin_ia32_vpermi2vard128_mask", + "llvm.x86.avx512.vpermi2var.q.512" => "__builtin_ia32_vpermi2varq512_mask", + "llvm.x86.avx512.vpermi2var.q.256" => "__builtin_ia32_vpermi2varq256_mask", + "llvm.x86.avx512.vpermi2var.q.128" => "__builtin_ia32_vpermi2varq128_mask", + "llvm.x86.avx512.vpermi2var.ps.512" => "__builtin_ia32_vpermi2varps512_mask", + "llvm.x86.avx512.vpermi2var.ps.256" => "__builtin_ia32_vpermi2varps256_mask", + "llvm.x86.avx512.vpermi2var.ps.128" => "__builtin_ia32_vpermi2varps128_mask", + "llvm.x86.avx512.vpermi2var.pd.512" => "__builtin_ia32_vpermi2varpd512_mask", + "llvm.x86.avx512.vpermi2var.pd.256" => "__builtin_ia32_vpermi2varpd256_mask", + "llvm.x86.avx512.vpermi2var.pd.128" => "__builtin_ia32_vpermi2varpd128_mask", + "llvm.x86.avx512.mask.add.ss.round" => "__builtin_ia32_addss_mask_round", + "llvm.x86.avx512.mask.add.sd.round" => "__builtin_ia32_addsd_mask_round", + "llvm.x86.avx512.mask.sub.ss.round" => "__builtin_ia32_subss_mask_round", + "llvm.x86.avx512.mask.sub.sd.round" => "__builtin_ia32_subsd_mask_round", + "llvm.x86.avx512.mask.mul.ss.round" => "__builtin_ia32_mulss_mask_round", + "llvm.x86.avx512.mask.mul.sd.round" => "__builtin_ia32_mulsd_mask_round", + "llvm.x86.avx512.mask.div.ss.round" => "__builtin_ia32_divss_mask_round", + "llvm.x86.avx512.mask.div.sd.round" => "__builtin_ia32_divsd_mask_round", + "llvm.x86.avx512.mask.cvtss2sd.round" => "__builtin_ia32_cvtss2sd_mask_round", + "llvm.x86.avx512.mask.cvtsd2ss.round" => "__builtin_ia32_cvtsd2ss_mask_round", + "llvm.x86.avx512.mask.range.ss" => "__builtin_ia32_rangess128_mask_round", + "llvm.x86.avx512.mask.range.sd" => "__builtin_ia32_rangesd128_mask_round", + "llvm.x86.avx512.rcp28.ss" => "__builtin_ia32_rcp28ss_mask_round", + "llvm.x86.avx512.rcp28.sd" => "__builtin_ia32_rcp28sd_mask_round", + "llvm.x86.avx512.rsqrt28.ss" => "__builtin_ia32_rsqrt28ss_mask_round", + "llvm.x86.avx512.rsqrt28.sd" => "__builtin_ia32_rsqrt28sd_mask_round", + "llvm.x86.avx512fp16.mask.add.sh.round" => "__builtin_ia32_addsh_mask_round", + "llvm.x86.avx512fp16.mask.div.sh.round" => "__builtin_ia32_divsh_mask_round", + "llvm.x86.avx512fp16.mask.getmant.sh" => "__builtin_ia32_getmantsh_mask_round", + "llvm.x86.avx512fp16.mask.max.sh.round" => "__builtin_ia32_maxsh_mask_round", + "llvm.x86.avx512fp16.mask.min.sh.round" => "__builtin_ia32_minsh_mask_round", + "llvm.x86.avx512fp16.mask.mul.sh.round" => "__builtin_ia32_mulsh_mask_round", + "llvm.x86.avx512fp16.mask.rndscale.sh" => "__builtin_ia32_rndscalesh_mask_round", + "llvm.x86.avx512fp16.mask.scalef.sh" => "__builtin_ia32_scalefsh_mask_round", + "llvm.x86.avx512fp16.mask.sub.sh.round" => "__builtin_ia32_subsh_mask_round", + "llvm.x86.avx512fp16.mask.vcvtsd2sh.round" => "__builtin_ia32_vcvtsd2sh_mask_round", + "llvm.x86.avx512fp16.mask.vcvtsh2sd.round" => "__builtin_ia32_vcvtsh2sd_mask_round", + "llvm.x86.avx512fp16.mask.vcvtsh2ss.round" => "__builtin_ia32_vcvtsh2ss_mask_round", + "llvm.x86.avx512fp16.mask.vcvtss2sh.round" => "__builtin_ia32_vcvtss2sh_mask_round", + "llvm.x86.aesni.aesenc.256" => "__builtin_ia32_vaesenc_v32qi", + "llvm.x86.aesni.aesenclast.256" => "__builtin_ia32_vaesenclast_v32qi", + "llvm.x86.aesni.aesdec.256" => "__builtin_ia32_vaesdec_v32qi", + "llvm.x86.aesni.aesdeclast.256" => "__builtin_ia32_vaesdeclast_v32qi", + "llvm.x86.aesni.aesenc.512" => "__builtin_ia32_vaesenc_v64qi", + "llvm.x86.aesni.aesenclast.512" => "__builtin_ia32_vaesenclast_v64qi", + "llvm.x86.aesni.aesdec.512" => "__builtin_ia32_vaesdec_v64qi", + "llvm.x86.aesni.aesdeclast.512" => "__builtin_ia32_vaesdeclast_v64qi", + "llvm.x86.avx512bf16.cvtne2ps2bf16.128" => "__builtin_ia32_cvtne2ps2bf16_v8bf", + "llvm.x86.avx512bf16.cvtne2ps2bf16.256" => "__builtin_ia32_cvtne2ps2bf16_v16bf", + "llvm.x86.avx512bf16.cvtne2ps2bf16.512" => "__builtin_ia32_cvtne2ps2bf16_v32bf", + "llvm.x86.avx512bf16.cvtneps2bf16.256" => "__builtin_ia32_cvtneps2bf16_v8sf", + "llvm.x86.avx512bf16.cvtneps2bf16.512" => "__builtin_ia32_cvtneps2bf16_v16sf", + "llvm.x86.avx512bf16.dpbf16ps.128" => "__builtin_ia32_dpbf16ps_v4sf", + "llvm.x86.avx512bf16.dpbf16ps.256" => "__builtin_ia32_dpbf16ps_v8sf", + "llvm.x86.avx512bf16.dpbf16ps.512" => "__builtin_ia32_dpbf16ps_v16sf", + "llvm.x86.pclmulqdq.512" => "__builtin_ia32_vpclmulqdq_v8di", + "llvm.x86.pclmulqdq.256" => "__builtin_ia32_vpclmulqdq_v4di", + "llvm.x86.avx512.pmulhu.w.512" => "__builtin_ia32_pmulhuw512_mask", + "llvm.x86.avx512.pmulh.w.512" => "__builtin_ia32_pmulhw512_mask", + "llvm.x86.avx512.pmul.hr.sw.512" => "__builtin_ia32_pmulhrsw512_mask", + "llvm.x86.avx512.pmaddw.d.512" => "__builtin_ia32_pmaddwd512_mask", + "llvm.x86.avx512.pmaddubs.w.512" => "__builtin_ia32_pmaddubsw512_mask", + "llvm.x86.avx512.packssdw.512" => "__builtin_ia32_packssdw512_mask", + "llvm.x86.avx512.packsswb.512" => "__builtin_ia32_packsswb512_mask", + "llvm.x86.avx512.packusdw.512" => "__builtin_ia32_packusdw512_mask", + "llvm.x86.avx512.packuswb.512" => "__builtin_ia32_packuswb512_mask", + "llvm.x86.avx512.pavg.w.512" => "__builtin_ia32_pavgw512_mask", + "llvm.x86.avx512.pavg.b.512" => "__builtin_ia32_pavgb512_mask", + "llvm.x86.avx512.psll.w.512" => "__builtin_ia32_psllw512_mask", + "llvm.x86.avx512.pslli.w.512" => "__builtin_ia32_psllwi512_mask", + "llvm.x86.avx512.psllv.w.512" => "__builtin_ia32_psllv32hi_mask", + "llvm.x86.avx512.psllv.w.256" => "__builtin_ia32_psllv16hi_mask", + "llvm.x86.avx512.psllv.w.128" => "__builtin_ia32_psllv8hi_mask", + "llvm.x86.avx512.psrl.w.512" => "__builtin_ia32_psrlw512_mask", + "llvm.x86.avx512.psrli.w.512" => "__builtin_ia32_psrlwi512_mask", + "llvm.x86.avx512.psrlv.w.512" => "__builtin_ia32_psrlv32hi_mask", + "llvm.x86.avx512.psrlv.w.256" => "__builtin_ia32_psrlv16hi_mask", + "llvm.x86.avx512.psrlv.w.128" => "__builtin_ia32_psrlv8hi_mask", + "llvm.x86.avx512.psra.w.512" => "__builtin_ia32_psraw512_mask", + "llvm.x86.avx512.psrai.w.512" => "__builtin_ia32_psrawi512_mask", + "llvm.x86.avx512.psrav.w.512" => "__builtin_ia32_psrav32hi_mask", + "llvm.x86.avx512.psrav.w.256" => "__builtin_ia32_psrav16hi_mask", + "llvm.x86.avx512.psrav.w.128" => "__builtin_ia32_psrav8hi_mask", + "llvm.x86.avx512.vpermi2var.hi.512" => "__builtin_ia32_vpermt2varhi512_mask", + "llvm.x86.avx512.vpermi2var.hi.256" => "__builtin_ia32_vpermt2varhi256_mask", + "llvm.x86.avx512.vpermi2var.hi.128" => "__builtin_ia32_vpermt2varhi128_mask", + "llvm.x86.avx512.permvar.hi.512" => "__builtin_ia32_permvarhi512_mask", + "llvm.x86.avx512.permvar.hi.256" => "__builtin_ia32_permvarhi256_mask", + "llvm.x86.avx512.permvar.hi.128" => "__builtin_ia32_permvarhi128_mask", + "llvm.x86.avx512.pshuf.b.512" => "__builtin_ia32_pshufb512_mask", + "llvm.x86.avx512.dbpsadbw.512" => "__builtin_ia32_dbpsadbw512_mask", + "llvm.x86.avx512.dbpsadbw.256" => "__builtin_ia32_dbpsadbw256_mask", + "llvm.x86.avx512.dbpsadbw.128" => "__builtin_ia32_dbpsadbw128_mask", + "llvm.x86.avx512.vpmadd52h.uq.512" => "__builtin_ia32_vpmadd52huq512_mask", + "llvm.x86.avx512.vpmadd52l.uq.512" => "__builtin_ia32_vpmadd52luq512_mask", + "llvm.x86.avx512.vpmadd52h.uq.256" => "__builtin_ia32_vpmadd52huq256_mask", + "llvm.x86.avx512.vpmadd52l.uq.256" => "__builtin_ia32_vpmadd52luq256_mask", + "llvm.x86.avx512.vpmadd52h.uq.128" => "__builtin_ia32_vpmadd52huq128_mask", + "llvm.x86.avx512.vpdpwssd.512" => "__builtin_ia32_vpdpwssd_v16si", + "llvm.x86.avx512.vpdpwssd.256" => "__builtin_ia32_vpdpwssd_v8si", + "llvm.x86.avx512.vpdpwssd.128" => "__builtin_ia32_vpdpwssd_v4si", + "llvm.x86.avx512.vpdpwssds.512" => "__builtin_ia32_vpdpwssds_v16si", + "llvm.x86.avx512.vpdpwssds.256" => "__builtin_ia32_vpdpwssds_v8si", + "llvm.x86.avx512.vpdpwssds.128" => "__builtin_ia32_vpdpwssds_v4si", + "llvm.x86.avx512.vpdpbusd.512" => "__builtin_ia32_vpdpbusd_v16si", + "llvm.x86.avx512.vpdpbusd.256" => "__builtin_ia32_vpdpbusd_v8si", + "llvm.x86.avx512.vpdpbusd.128" => "__builtin_ia32_vpdpbusd_v4si", + "llvm.x86.avx512.vpdpbusds.512" => "__builtin_ia32_vpdpbusds_v16si", + "llvm.x86.avx512.vpdpbusds.256" => "__builtin_ia32_vpdpbusds_v8si", + "llvm.x86.avx512.vpdpbusds.128" => "__builtin_ia32_vpdpbusds_v4si", + // NOTE: this file is generated by https://github.com/GuillaumeGomez/llvmint/blob/master/generate_list.py _ => include!("archs.rs"), }; diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 49be6c649e652..2590e0e3af444 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -1,6 +1,9 @@ pub mod llvm; mod simd; +#[cfg(feature="master")] +use std::iter; + use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp, FunctionType}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::base::wants_msvc_seh; @@ -8,15 +11,23 @@ use rustc_codegen_ssa::common::IntPredicate; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{ArgAbiMethods, BaseTypeMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods}; +#[cfg(feature="master")] +use rustc_codegen_ssa::traits::{DerivedTypeMethods, MiscMethods}; use rustc_middle::bug; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::ty::layout::LayoutOf; +#[cfg(feature="master")] +use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; use rustc_span::{Span, Symbol, symbol::kw, sym}; use rustc_target::abi::HasDataLayout; use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; use rustc_target::spec::PanicStrategy; +#[cfg(feature="master")] +use rustc_target::spec::abi::Abi; use crate::abi::GccType; +#[cfg(feature="master")] +use crate::abi::FnAbiGccExt; use crate::builder::Builder; use crate::common::{SignType, TypeReflection}; use crate::context::CodegenCx; @@ -91,7 +102,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let name = tcx.item_name(def_id); let name_str = name.as_str(); - let llret_ty = self.layout_of(ret_ty).gcc_type(self, true); + let llret_ty = self.layout_of(ret_ty).gcc_type(self); let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); let simple = get_simple_intrinsic(self, name); @@ -404,7 +415,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { /// Gets the LLVM type for a place of the original Rust type of /// this argument/return, i.e., the result of `type_of::type_of`. fn memory_ty(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { - self.layout.gcc_type(cx, true) + self.layout.gcc_type(cx) } /// Stores a direct/indirect value described by this ArgAbi into a @@ -1120,10 +1131,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } } -fn try_intrinsic<'gcc, 'tcx>(bx: &mut Builder<'_, 'gcc, 'tcx>, try_func: RValue<'gcc>, data: RValue<'gcc>, _catch_func: RValue<'gcc>, dest: RValue<'gcc>) { - // NOTE: the `|| true` here is to use the panic=abort strategy with panic=unwind too - if bx.sess().panic_strategy() == PanicStrategy::Abort || true { - // TODO(bjorn3): Properly implement unwinding and remove the `|| true` once this is done. +fn try_intrinsic<'a, 'b, 'gcc, 'tcx>(bx: &'b mut Builder<'a, 'gcc, 'tcx>, try_func: RValue<'gcc>, data: RValue<'gcc>, _catch_func: RValue<'gcc>, dest: RValue<'gcc>) { + if bx.sess().panic_strategy() == PanicStrategy::Abort { bx.call(bx.type_void(), None, try_func, &[data], None); // Return 0 unconditionally from the intrinsic call; // we can never unwind. @@ -1134,6 +1143,141 @@ fn try_intrinsic<'gcc, 'tcx>(bx: &mut Builder<'_, 'gcc, 'tcx>, try_func: RValue< unimplemented!(); } else { + #[cfg(feature="master")] + codegen_gnu_try(bx, try_func, data, _catch_func, dest); + #[cfg(not(feature="master"))] unimplemented!(); } } + +// Definition of the standard `try` function for Rust using the GNU-like model +// of exceptions (e.g., the normal semantics of LLVM's `landingpad` and `invoke` +// instructions). +// +// This codegen is a little surprising because we always call a shim +// function instead of inlining the call to `invoke` manually here. This is done +// because in LLVM we're only allowed to have one personality per function +// definition. The call to the `try` intrinsic is being inlined into the +// function calling it, and that function may already have other personality +// functions in play. By calling a shim we're guaranteed that our shim will have +// the right personality function. +#[cfg(feature="master")] +fn codegen_gnu_try<'gcc>(bx: &mut Builder<'_, 'gcc, '_>, try_func: RValue<'gcc>, data: RValue<'gcc>, catch_func: RValue<'gcc>, dest: RValue<'gcc>) { + let cx: &CodegenCx<'gcc, '_> = bx.cx; + let (llty, func) = get_rust_try_fn(cx, &mut |mut bx| { + // Codegens the shims described above: + // + // bx: + // invoke %try_func(%data) normal %normal unwind %catch + // + // normal: + // ret 0 + // + // catch: + // (%ptr, _) = landingpad + // call %catch_func(%data, %ptr) + // ret 1 + let then = bx.append_sibling_block("then"); + let catch = bx.append_sibling_block("catch"); + + let func = bx.current_func(); + let try_func = func.get_param(0).to_rvalue(); + let data = func.get_param(1).to_rvalue(); + let catch_func = func.get_param(2).to_rvalue(); + let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void()); + + let current_block = bx.block.clone(); + + bx.switch_to_block(then); + bx.ret(bx.const_i32(0)); + + // Type indicator for the exception being thrown. + // + // The value is a pointer to the exception object + // being thrown. + bx.switch_to_block(catch); + bx.set_personality_fn(bx.eh_personality()); + + let eh_pointer_builtin = bx.cx.context.get_target_builtin_function("__builtin_eh_pointer"); + let zero = bx.cx.context.new_rvalue_zero(bx.int_type); + let ptr = bx.cx.context.new_call(None, eh_pointer_builtin, &[zero]); + let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void()); + bx.call(catch_ty, None, catch_func, &[data, ptr], None); + bx.ret(bx.const_i32(1)); + + // NOTE: the blocks must be filled before adding the try/catch, otherwise gcc will not + // generate a try/catch. + // FIXME(antoyo): add a check in the libgccjit API to prevent this. + bx.switch_to_block(current_block); + bx.invoke(try_func_ty, None, try_func, &[data], then, catch, None); + }); + + let func = unsafe { std::mem::transmute(func) }; + + // Note that no invoke is used here because by definition this function + // can't panic (that's what it's catching). + let ret = bx.call(llty, None, func, &[try_func, data, catch_func], None); + let i32_align = bx.tcx().data_layout.i32_align.abi; + bx.store(ret, dest, i32_align); +} + + +// Helper function used to get a handle to the `__rust_try` function used to +// catch exceptions. +// +// This function is only generated once and is then cached. +#[cfg(feature="master")] +fn get_rust_try_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, codegen: &mut dyn FnMut(Builder<'a, 'gcc, 'tcx>)) -> (Type<'gcc>, Function<'gcc>) { + if let Some(llfn) = cx.rust_try_fn.get() { + return llfn; + } + + // Define the type up front for the signature of the rust_try function. + let tcx = cx.tcx; + let i8p = tcx.mk_mut_ptr(tcx.types.i8); + // `unsafe fn(*mut i8) -> ()` + let try_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig( + iter::once(i8p), + tcx.mk_unit(), + false, + rustc_hir::Unsafety::Unsafe, + Abi::Rust, + ))); + // `unsafe fn(*mut i8, *mut i8) -> ()` + let catch_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig( + [i8p, i8p].iter().cloned(), + tcx.mk_unit(), + false, + rustc_hir::Unsafety::Unsafe, + Abi::Rust, + ))); + // `unsafe fn(unsafe fn(*mut i8) -> (), *mut i8, unsafe fn(*mut i8, *mut i8) -> ()) -> i32` + let rust_fn_sig = ty::Binder::dummy(cx.tcx.mk_fn_sig( + [try_fn_ty, i8p, catch_fn_ty], + tcx.types.i32, + false, + rustc_hir::Unsafety::Unsafe, + Abi::Rust, + )); + let rust_try = gen_fn(cx, "__rust_try", rust_fn_sig, codegen); + cx.rust_try_fn.set(Some(rust_try)); + rust_try +} + +// Helper function to give a Block to a closure to codegen a shim function. +// This is currently primarily used for the `try` intrinsic functions above. +#[cfg(feature="master")] +fn gen_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, name: &str, rust_fn_sig: ty::PolyFnSig<'tcx>, codegen: &mut dyn FnMut(Builder<'a, 'gcc, 'tcx>)) -> (Type<'gcc>, Function<'gcc>) { + let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty()); + let (typ, _, _, _) = fn_abi.gcc_type(cx); + // FIXME(eddyb) find a nicer way to do this. + cx.linkage.set(FunctionType::Internal); + let func = cx.declare_fn(name, fn_abi); + let func_val = unsafe { std::mem::transmute(func) }; + cx.set_frame_pointer_type(func_val); + cx.apply_target_cpu_attr(func_val); + let block = Builder::append_block(cx, func_val, "entry-block"); + let bx = Builder::build(cx, block); + codegen(bx); + (typ, func) +} diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index cb8168b407184..b59c3a64f5728 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -1,8 +1,13 @@ -use std::cmp::Ordering; +#[cfg(feature="master")] +use gccjit::{ComparisonOp, UnaryOp}; +use gccjit::ToRValue; +use gccjit::{BinaryOp, RValue, Type}; -use gccjit::{BinaryOp, RValue, ToRValue, Type}; use rustc_codegen_ssa::base::compare_simd_types; -use rustc_codegen_ssa::common::TypeKind; +use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; +#[cfg(feature="master")] +use rustc_codegen_ssa::errors::ExpectedPointerMutability; +use rustc_codegen_ssa::errors::InvalidMonomorphization; use rustc_codegen_ssa::mir::operand::OperandRef; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods}; @@ -14,18 +19,21 @@ use rustc_span::{sym, Span, Symbol}; use rustc_target::abi::Align; use crate::builder::Builder; +#[cfg(feature="master")] +use crate::context::CodegenCx; +#[cfg(feature="master")] +use crate::errors::{InvalidMonomorphizationExpectedSignedUnsigned, InvalidMonomorphizationInsertedType}; use crate::errors::{ - InvalidMonomorphizationExpectedSignedUnsigned, InvalidMonomorphizationExpectedSimd, - InvalidMonomorphizationInsertedType, InvalidMonomorphizationInvalidBitmask, + InvalidMonomorphizationExpectedSimd, + InvalidMonomorphizationInvalidBitmask, InvalidMonomorphizationInvalidFloatVector, InvalidMonomorphizationMaskType, InvalidMonomorphizationMismatchedLengths, InvalidMonomorphizationNotFloat, InvalidMonomorphizationReturnElement, InvalidMonomorphizationReturnIntegerType, InvalidMonomorphizationReturnLength, InvalidMonomorphizationReturnLengthInputType, InvalidMonomorphizationReturnType, InvalidMonomorphizationSimdShuffle, - InvalidMonomorphizationUnrecognized, InvalidMonomorphizationUnsupportedCast, - InvalidMonomorphizationUnsupportedElement, InvalidMonomorphizationUnsupportedOperation, + InvalidMonomorphizationUnrecognized, InvalidMonomorphizationUnsupportedElement, + InvalidMonomorphizationUnsupportedOperation, }; -use crate::intrinsic; pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( bx: &mut Builder<'a, 'gcc, 'tcx>, @@ -105,14 +113,19 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let arg1_vector_type = arg1_type.unqualified().dyncast_vector().expect("vector type"); let arg1_element_type = arg1_vector_type.get_element_type(); + // NOTE: since the arguments can be vectors of floats, make sure the mask is a vector of + // integer. + let mask_element_type = bx.type_ix(arg1_element_type.get_size() as u64 * 8); + let vector_mask_type = bx.context.new_vector_type(mask_element_type, arg1_vector_type.get_num_units() as u64); + let mut elements = vec![]; let one = bx.context.new_rvalue_one(mask.get_type()); for _ in 0..len { - let element = bx.context.new_cast(None, mask & one, arg1_element_type); + let element = bx.context.new_cast(None, mask & one, mask_element_type); elements.push(element); mask = mask >> one; } - let vector_mask = bx.context.new_rvalue_from_vector(None, arg1_type, &elements); + let vector_mask = bx.context.new_rvalue_from_vector(None, vector_mask_type, &elements); return Ok(bx.vector_select(vector_mask, arg1, args[2].immediate())); } @@ -210,48 +223,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let vector = args[0].immediate(); let index = args[1].immediate(); let value = args[2].immediate(); - // TODO(antoyo): use a recursive unqualified() here. - let vector_type = vector.get_type().unqualified().dyncast_vector().expect("vector type"); - let element_type = vector_type.get_element_type(); - // NOTE: we cannot cast to an array and assign to its element here because the value might - // not be an l-value. So, call a builtin to set the element. - // TODO(antoyo): perhaps we could create a new vector or maybe there's a GIMPLE instruction for that? - // TODO(antoyo): don't use target specific builtins here. - let func_name = match in_len { - 2 => { - if element_type == bx.i64_type { - "__builtin_ia32_vec_set_v2di" - } else { - unimplemented!(); - } - } - 4 => { - if element_type == bx.i32_type { - "__builtin_ia32_vec_set_v4si" - } else { - unimplemented!(); - } - } - 8 => { - if element_type == bx.i16_type { - "__builtin_ia32_vec_set_v8hi" - } else { - unimplemented!(); - } - } - _ => unimplemented!("Len: {}", in_len), - }; - let builtin = bx.context.get_target_builtin_function(func_name); - let param1_type = builtin.get_param(0).to_rvalue().get_type(); - // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. - let vector = bx.cx.bitcast_if_needed(vector, param1_type); - let result = bx.context.new_call( - None, - builtin, - &[vector, value, bx.context.new_cast(None, index, bx.int_type)], - ); - // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. - return Ok(bx.context.new_bitcast(None, result, vector.get_type())); + let variable = bx.current_func().new_local(None, vector.get_type(), "new_vector"); + bx.llbb().add_assignment(None, variable, vector); + let lvalue = bx.context.new_vector_access(None, variable.to_rvalue(), index); + // TODO(antoyo): if simd_insert is constant, use BIT_REF. + bx.llbb().add_assignment(None, lvalue, value); + return Ok(variable.to_rvalue()); } #[cfg(feature = "master")] @@ -280,7 +257,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return Ok(bx.vector_select(args[0].immediate(), args[1].immediate(), args[2].immediate())); } - if name == sym::simd_cast { + #[cfg(feature="master")] + if name == sym::simd_cast || name == sym::simd_as { require_simd!(ret_ty, "return"); let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); require!( @@ -301,125 +279,40 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( enum Style { Float, - Int(/* is signed? */ bool), + Int, Unsupported, } - let (in_style, in_width) = match in_elem.kind() { - // vectors of pointer-sized integers should've been - // disallowed before here, so this unwrap is safe. - ty::Int(i) => ( - Style::Int(true), - i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(), - ), - ty::Uint(u) => ( - Style::Int(false), - u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(), - ), - ty::Float(f) => (Style::Float, f.bit_width()), - _ => (Style::Unsupported, 0), - }; - let (out_style, out_width) = match out_elem.kind() { - ty::Int(i) => ( - Style::Int(true), - i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(), - ), - ty::Uint(u) => ( - Style::Int(false), - u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(), - ), - ty::Float(f) => (Style::Float, f.bit_width()), - _ => (Style::Unsupported, 0), - }; - - let extend = |in_type, out_type| { - let vector_type = bx.context.new_vector_type(out_type, 8); - let vector = args[0].immediate(); - let array_type = bx.context.new_array_type(None, in_type, 8); - // TODO(antoyo): switch to using new_vector_access or __builtin_convertvector for vector casting. - let array = bx.context.new_bitcast(None, vector, array_type); - - let cast_vec_element = |index| { - let index = bx.context.new_rvalue_from_int(bx.int_type, index); - bx.context.new_cast( - None, - bx.context.new_array_access(None, array, index).to_rvalue(), - out_type, - ) + let in_style = + match in_elem.kind() { + ty::Int(_) | ty::Uint(_) => Style::Int, + ty::Float(_) => Style::Float, + _ => Style::Unsupported, }; - bx.context.new_rvalue_from_vector( - None, - vector_type, - &[ - cast_vec_element(0), - cast_vec_element(1), - cast_vec_element(2), - cast_vec_element(3), - cast_vec_element(4), - cast_vec_element(5), - cast_vec_element(6), - cast_vec_element(7), - ], - ) - }; + let out_style = + match out_elem.kind() { + ty::Int(_) | ty::Uint(_) => Style::Int, + ty::Float(_) => Style::Float, + _ => Style::Unsupported, + }; match (in_style, out_style) { - (Style::Int(in_is_signed), Style::Int(_)) => { - return Ok(match in_width.cmp(&out_width) { - Ordering::Greater => bx.trunc(args[0].immediate(), llret_ty), - Ordering::Equal => args[0].immediate(), - Ordering::Less => { - if in_is_signed { - match (in_width, out_width) { - // FIXME(antoyo): the function _mm_cvtepi8_epi16 should directly - // call an intrinsic equivalent to __builtin_ia32_pmovsxbw128 so that - // we can generate a call to it. - (8, 16) => extend(bx.i8_type, bx.i16_type), - (8, 32) => extend(bx.i8_type, bx.i32_type), - (8, 64) => extend(bx.i8_type, bx.i64_type), - (16, 32) => extend(bx.i16_type, bx.i32_type), - (32, 64) => extend(bx.i32_type, bx.i64_type), - (16, 64) => extend(bx.i16_type, bx.i64_type), - _ => unimplemented!("in: {}, out: {}", in_width, out_width), - } - } else { - match (in_width, out_width) { - (8, 16) => extend(bx.u8_type, bx.u16_type), - (8, 32) => extend(bx.u8_type, bx.u32_type), - (8, 64) => extend(bx.u8_type, bx.u64_type), - (16, 32) => extend(bx.u16_type, bx.u32_type), - (16, 64) => extend(bx.u16_type, bx.u64_type), - (32, 64) => extend(bx.u32_type, bx.u64_type), - _ => unimplemented!("in: {}, out: {}", in_width, out_width), - } - } + (Style::Unsupported, Style::Unsupported) => { + require!( + false, + InvalidMonomorphization::UnsupportedCast { + span, + name, + in_ty, + in_elem, + ret_ty, + out_elem } - }); - } - (Style::Int(_), Style::Float) => { - // TODO: add support for internal functions in libgccjit to get access to IFN_VEC_CONVERT which is - // doing like __builtin_convertvector? - // Or maybe provide convert_vector as an API since it might not easy to get the - // types of internal functions. - unimplemented!(); - } - (Style::Float, Style::Int(_)) => { - unimplemented!(); - } - (Style::Float, Style::Float) => { - unimplemented!(); - } - _ => { /* Unsupported. Fallthrough. */ } + ); + }, + _ => return Ok(bx.context.convert_vector(None, args[0].immediate(), llret_ty)), } - return_error!(InvalidMonomorphizationUnsupportedCast { - span, - name, - in_ty, - in_elem, - ret_ty, - out_elem - }); } macro_rules! arith_binary { @@ -436,6 +329,71 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( } } + if name == sym::simd_bitmask { + // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a + // vector mask and returns the most significant bit (MSB) of each lane in the form + // of either: + // * an unsigned integer + // * an array of `u8` + // If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits. + // + // The bit order of the result depends on the byte endianness, LSB-first for little + // endian and MSB-first for big endian. + + let vector = args[0].immediate(); + let vector_type = vector.get_type().dyncast_vector().expect("vector type"); + let elem_type = vector_type.get_element_type(); + + let expected_int_bits = in_len.max(8); + let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64); + + // FIXME(antoyo): that's not going to work for masks bigger than 128 bits. + let result_type = bx.type_ix(expected_int_bits); + let mut result = bx.context.new_rvalue_zero(result_type); + + let elem_size = elem_type.get_size() * 8; + let sign_shift = bx.context.new_rvalue_from_int(elem_type, elem_size as i32 - 1); + let one = bx.context.new_rvalue_one(elem_type); + + let mut shift = 0; + for i in 0..in_len { + let elem = bx.extract_element(vector, bx.context.new_rvalue_from_int(bx.int_type, i as i32)); + let shifted = elem >> sign_shift; + let masked = shifted & one; + result = result | (bx.context.new_cast(None, masked, result_type) << bx.context.new_rvalue_from_int(result_type, shift)); + shift += 1; + } + + match ret_ty.kind() { + ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => { + // Zero-extend iN to the bitmask type: + return Ok(result); + } + ty::Array(elem, len) + if matches!(elem.kind(), ty::Uint(ty::UintTy::U8)) + && len.try_eval_target_usize(bx.tcx, ty::ParamEnv::reveal_all()) + == Some(expected_bytes) => + { + // Zero-extend iN to the array length: + let ze = bx.zext(result, bx.type_ix(expected_bytes * 8)); + + // Convert the integer to a byte array + let ptr = bx.alloca(bx.type_ix(expected_bytes * 8), Align::ONE); + bx.store(ze, ptr, Align::ONE); + let array_ty = bx.type_array(bx.type_i8(), expected_bytes); + let ptr = bx.pointercast(ptr, bx.cx.type_ptr_to(array_ty)); + return Ok(bx.load(array_ty, ptr, Align::ONE)); + } + _ => return_error!(InvalidMonomorphization::CannotReturn { + span, + name, + ret_ty, + expected_int_bits, + expected_bytes + }), + } + } + fn simd_simple_float_intrinsic<'gcc, 'tcx>( name: Symbol, in_elem: Ty<'_>, @@ -451,55 +409,66 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return Err(()); }}; } - let (elem_ty_str, elem_ty) = if let ty::Float(f) = in_elem.kind() { - let elem_ty = bx.cx.type_float_from_ty(*f); - match f.bit_width() { - 32 => ("f32", elem_ty), - 64 => ("f64", elem_ty), - _ => { - return_error!(InvalidMonomorphizationInvalidFloatVector { - span, - name, - elem_ty: f.name_str(), - vec_ty: in_ty - }); + let (elem_ty_str, elem_ty) = + if let ty::Float(f) = in_elem.kind() { + let elem_ty = bx.cx.type_float_from_ty(*f); + match f.bit_width() { + 32 => ("f", elem_ty), + 64 => ("", elem_ty), + _ => { + return_error!(InvalidMonomorphizationInvalidFloatVector { span, name, elem_ty: f.name_str(), vec_ty: in_ty }); + } } } - } else { - return_error!(InvalidMonomorphizationNotFloat { span, name, ty: in_ty }); - }; + else { + return_error!(InvalidMonomorphizationNotFloat { span, name, ty: in_ty }); + }; let vec_ty = bx.cx.type_vector(elem_ty, in_len); - let (intr_name, fn_ty) = match name { - sym::simd_ceil => ("ceil", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fabs => ("fabs", bx.type_func(&[vec_ty], vec_ty)), // TODO(antoyo): pand with 170141183420855150465331762880109871103 - sym::simd_fcos => ("cos", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fexp2 => ("exp2", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fexp => ("exp", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_flog10 => ("log10", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_flog2 => ("log2", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_flog => ("log", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_floor => ("floor", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fma => ("fma", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)), - sym::simd_fpowi => ("powi", bx.type_func(&[vec_ty, bx.type_i32()], vec_ty)), - sym::simd_fpow => ("pow", bx.type_func(&[vec_ty, vec_ty], vec_ty)), - sym::simd_fsin => ("sin", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_round => ("round", bx.type_func(&[vec_ty], vec_ty)), - sym::simd_trunc => ("trunc", bx.type_func(&[vec_ty], vec_ty)), - _ => return_error!(InvalidMonomorphizationUnrecognized { span, name }), - }; - let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str); - let function = intrinsic::llvm::intrinsic(llvm_name, &bx.cx); - let function: RValue<'gcc> = unsafe { std::mem::transmute(function) }; - let c = bx.call( - fn_ty, - None, - function, - &args.iter().map(|arg| arg.immediate()).collect::>(), - None, - ); + let intr_name = + match name { + sym::simd_ceil => "ceil", + sym::simd_fabs => "fabs", // TODO(antoyo): pand with 170141183420855150465331762880109871103 + sym::simd_fcos => "cos", + sym::simd_fexp2 => "exp2", + sym::simd_fexp => "exp", + sym::simd_flog10 => "log10", + sym::simd_flog2 => "log2", + sym::simd_flog => "log", + sym::simd_floor => "floor", + sym::simd_fma => "fma", + sym::simd_fpowi => "__builtin_powi", + sym::simd_fpow => "pow", + sym::simd_fsin => "sin", + sym::simd_fsqrt => "sqrt", + sym::simd_round => "round", + sym::simd_trunc => "trunc", + _ => return_error!(InvalidMonomorphizationUnrecognized { span, name }) + }; + let builtin_name = format!("{}{}", intr_name, elem_ty_str); + let funcs = bx.cx.functions.borrow(); + let function = funcs.get(&builtin_name).unwrap_or_else(|| panic!("unable to find builtin function {}", builtin_name)); + + // TODO(antoyo): add platform-specific behavior here for architectures that have these + // intrinsics as instructions (for instance, gpus) + let mut vector_elements = vec![]; + for i in 0..in_len { + let index = bx.context.new_rvalue_from_long(bx.ulong_type, i as i64); + // we have to treat fpowi specially, since fpowi's second argument is always an i32 + let arguments = if name == sym::simd_fpowi { + vec![ + bx.extract_element(args[0].immediate(), index).to_rvalue(), + args[1].immediate(), + ] + } else { + args.iter() + .map(|arg| bx.extract_element(arg.immediate(), index).to_rvalue()) + .collect() + }; + vector_elements.push(bx.context.new_call(None, *function, &arguments)); + } + let c = bx.context.new_rvalue_from_vector(None, vec_ty, &vector_elements); Ok(c) } @@ -525,6 +494,297 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args); } + #[cfg(feature="master")] + fn vector_ty<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, elem_ty: Ty<'tcx>, vec_len: u64) -> Type<'gcc> { + // FIXME: use cx.layout_of(ty).llvm_type() ? + let elem_ty = match *elem_ty.kind() { + ty::Int(v) => cx.type_int_from_ty(v), + ty::Uint(v) => cx.type_uint_from_ty(v), + ty::Float(v) => cx.type_float_from_ty(v), + _ => unreachable!(), + }; + cx.type_vector(elem_ty, vec_len) + } + + #[cfg(feature="master")] + fn gather<'a, 'gcc, 'tcx>(default: RValue<'gcc>, pointers: RValue<'gcc>, mask: RValue<'gcc>, pointer_count: usize, bx: &mut Builder<'a, 'gcc, 'tcx>, in_len: u64, underlying_ty: Ty<'tcx>, invert: bool) -> RValue<'gcc> { + let vector_type = + if pointer_count > 1 { + bx.context.new_vector_type(bx.usize_type, in_len) + } + else { + vector_ty(bx, underlying_ty, in_len) + }; + let elem_type = vector_type.dyncast_vector().expect("vector type").get_element_type(); + + let mut values = vec![]; + for i in 0..in_len { + let index = bx.context.new_rvalue_from_long(bx.i32_type, i as i64); + let int = bx.context.new_vector_access(None, pointers, index).to_rvalue(); + + let ptr_type = elem_type.make_pointer(); + let ptr = bx.context.new_bitcast(None, int, ptr_type); + let value = ptr.dereference(None).to_rvalue(); + values.push(value); + } + + let vector = bx.context.new_rvalue_from_vector(None, vector_type, &values); + + let mut mask_types = vec![]; + let mut mask_values = vec![]; + for i in 0..in_len { + let index = bx.context.new_rvalue_from_long(bx.i32_type, i as i64); + mask_types.push(bx.context.new_field(None, bx.i32_type, "m")); + let mask_value = bx.context.new_vector_access(None, mask, index).to_rvalue(); + let masked = bx.context.new_rvalue_from_int(bx.i32_type, in_len as i32) & mask_value; + let value = index + masked; + mask_values.push(value); + } + let mask_type = bx.context.new_struct_type(None, "mask_type", &mask_types); + let mask = bx.context.new_struct_constructor(None, mask_type.as_type(), None, &mask_values); + + if invert { + bx.shuffle_vector(vector, default, mask) + } + else { + bx.shuffle_vector(default, vector, mask) + } + } + + #[cfg(feature="master")] + if name == sym::simd_gather { + // simd_gather(values: , pointers: , + // mask: ) -> + // * N: number of elements in the input vectors + // * T: type of the element to load + // * M: any integer width is supported, will be truncated to i1 + + // All types must be simd vector types + require_simd!(in_ty, "first"); + require_simd!(arg_tys[1], "second"); + require_simd!(arg_tys[2], "third"); + require_simd!(ret_ty, "return"); + + // Of the same length: + let (out_len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); + let (out_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx()); + require!( + in_len == out_len, + InvalidMonomorphization::SecondArgumentLength { + span, + name, + in_len, + in_ty, + arg_ty: arg_tys[1], + out_len + } + ); + require!( + in_len == out_len2, + InvalidMonomorphization::ThirdArgumentLength { + span, + name, + in_len, + in_ty, + arg_ty: arg_tys[2], + out_len: out_len2 + } + ); + + // The return type must match the first argument type + require!( + ret_ty == in_ty, + InvalidMonomorphization::ExpectedReturnType { span, name, in_ty, ret_ty } + ); + + // This counts how many pointers + fn ptr_count(t: Ty<'_>) -> usize { + match t.kind() { + ty::RawPtr(p) => 1 + ptr_count(p.ty), + _ => 0, + } + } + + // Non-ptr type + fn non_ptr(t: Ty<'_>) -> Ty<'_> { + match t.kind() { + ty::RawPtr(p) => non_ptr(p.ty), + _ => t, + } + } + + // The second argument must be a simd vector with an element type that's a pointer + // to the element type of the first argument + let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx()); + let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx()); + let (pointer_count, underlying_ty) = match element_ty1.kind() { + ty::RawPtr(p) if p.ty == in_elem => (ptr_count(element_ty1), non_ptr(element_ty1)), + _ => { + require!( + false, + InvalidMonomorphization::ExpectedElementType { + span, + name, + expected_element: element_ty1, + second_arg: arg_tys[1], + in_elem, + in_ty, + mutability: ExpectedPointerMutability::Not, + } + ); + unreachable!(); + } + }; + assert!(pointer_count > 0); + assert_eq!(pointer_count - 1, ptr_count(element_ty0)); + assert_eq!(underlying_ty, non_ptr(element_ty0)); + + // The element type of the third argument must be a signed integer type of any width: + let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx()); + match element_ty2.kind() { + ty::Int(_) => (), + _ => { + require!( + false, + InvalidMonomorphization::ThirdArgElementType { + span, + name, + expected_element: element_ty2, + third_arg: arg_tys[2] + } + ); + } + } + + return Ok(gather(args[0].immediate(), args[1].immediate(), args[2].immediate(), pointer_count, bx, in_len, underlying_ty, false)); + } + + #[cfg(feature="master")] + if name == sym::simd_scatter { + // simd_scatter(values: , pointers: , + // mask: ) -> () + // * N: number of elements in the input vectors + // * T: type of the element to load + // * M: any integer width is supported, will be truncated to i1 + + // All types must be simd vector types + require_simd!(in_ty, "first"); + require_simd!(arg_tys[1], "second"); + require_simd!(arg_tys[2], "third"); + + // Of the same length: + let (element_len1, _) = arg_tys[1].simd_size_and_type(bx.tcx()); + let (element_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx()); + require!( + in_len == element_len1, + InvalidMonomorphization::SecondArgumentLength { + span, + name, + in_len, + in_ty, + arg_ty: arg_tys[1], + out_len: element_len1 + } + ); + require!( + in_len == element_len2, + InvalidMonomorphization::ThirdArgumentLength { + span, + name, + in_len, + in_ty, + arg_ty: arg_tys[2], + out_len: element_len2 + } + ); + + // This counts how many pointers + fn ptr_count(t: Ty<'_>) -> usize { + match t.kind() { + ty::RawPtr(p) => 1 + ptr_count(p.ty), + _ => 0, + } + } + + // Non-ptr type + fn non_ptr(t: Ty<'_>) -> Ty<'_> { + match t.kind() { + ty::RawPtr(p) => non_ptr(p.ty), + _ => t, + } + } + + // The second argument must be a simd vector with an element type that's a pointer + // to the element type of the first argument + let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx()); + let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx()); + let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx()); + let (pointer_count, underlying_ty) = match element_ty1.kind() { + ty::RawPtr(p) if p.ty == in_elem && p.mutbl == hir::Mutability::Mut => { + (ptr_count(element_ty1), non_ptr(element_ty1)) + } + _ => { + require!( + false, + InvalidMonomorphization::ExpectedElementType { + span, + name, + expected_element: element_ty1, + second_arg: arg_tys[1], + in_elem, + in_ty, + mutability: ExpectedPointerMutability::Mut, + } + ); + unreachable!(); + } + }; + assert!(pointer_count > 0); + assert_eq!(pointer_count - 1, ptr_count(element_ty0)); + assert_eq!(underlying_ty, non_ptr(element_ty0)); + + // The element type of the third argument must be a signed integer type of any width: + match element_ty2.kind() { + ty::Int(_) => (), + _ => { + require!( + false, + InvalidMonomorphization::ThirdArgElementType { + span, + name, + expected_element: element_ty2, + third_arg: arg_tys[2] + } + ); + } + } + + let result = gather(args[0].immediate(), args[1].immediate(), args[2].immediate(), pointer_count, bx, in_len, underlying_ty, true); + + let pointers = args[1].immediate(); + + let vector_type = + if pointer_count > 1 { + bx.context.new_vector_type(bx.usize_type, in_len) + } + else { + vector_ty(bx, underlying_ty, in_len) + }; + let elem_type = vector_type.dyncast_vector().expect("vector type").get_element_type(); + + for i in 0..in_len { + let index = bx.context.new_rvalue_from_int(bx.int_type, i as i32); + let value = bx.context.new_vector_access(None, result, index); + + let int = bx.context.new_vector_access(None, pointers, index).to_rvalue(); + let ptr_type = elem_type.make_pointer(); + let ptr = bx.context.new_bitcast(None, int, ptr_type); + bx.llbb().add_assignment(None, ptr.dereference(None), value); + } + + return Ok(bx.context.new_rvalue_zero(bx.i32_type)); + } + arith_binary! { simd_add: Uint, Int => add, Float => fadd; simd_sub: Uint, Int => sub, Float => fsub; @@ -536,6 +796,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( simd_and: Uint, Int => and; simd_or: Uint, Int => or; // FIXME(antoyo): calling `or` might not work on vectors. simd_xor: Uint, Int => xor; + simd_fmin: Float => vector_fmin; + simd_fmax: Float => vector_fmax; } macro_rules! arith_unary { @@ -562,10 +824,11 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let rhs = args[1].immediate(); let is_add = name == sym::simd_saturating_add; let ptr_bits = bx.tcx().data_layout.pointer_size.bits() as _; - let (signed, elem_width, elem_ty) = match *in_elem.kind() { - ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_int_from_ty(i)), - ty::Uint(i) => (false, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_uint_from_ty(i)), - _ => { + let (signed, elem_width, elem_ty) = + match *in_elem.kind() { + ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits) / 8, bx.cx.type_int_from_ty(i)), + ty::Uint(i) => (false, i.bit_width().unwrap_or(ptr_bits) / 8, bx.cx.type_uint_from_ty(i)), + _ => { return_error!(InvalidMonomorphizationExpectedSignedUnsigned { span, name, @@ -574,33 +837,78 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( }); } }; - let builtin_name = match (signed, is_add, in_len, elem_width) { - (true, true, 32, 8) => "__builtin_ia32_paddsb256", // TODO(antoyo): cast arguments to unsigned. - (false, true, 32, 8) => "__builtin_ia32_paddusb256", - (true, true, 16, 16) => "__builtin_ia32_paddsw256", - (false, true, 16, 16) => "__builtin_ia32_paddusw256", - (true, false, 16, 16) => "__builtin_ia32_psubsw256", - (false, false, 16, 16) => "__builtin_ia32_psubusw256", - (true, false, 32, 8) => "__builtin_ia32_psubsb256", - (false, false, 32, 8) => "__builtin_ia32_psubusb256", - _ => unimplemented!( - "signed: {}, is_add: {}, in_len: {}, elem_width: {}", - signed, - is_add, - in_len, - elem_width - ), - }; - let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64); - - let func = bx.context.get_target_builtin_function(builtin_name); - let param1_type = func.get_param(0).to_rvalue().get_type(); - let param2_type = func.get_param(1).to_rvalue().get_type(); - let lhs = bx.cx.bitcast_if_needed(lhs, param1_type); - let rhs = bx.cx.bitcast_if_needed(rhs, param2_type); - let result = bx.context.new_call(None, func, &[lhs, rhs]); - // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. - return Ok(bx.context.new_bitcast(None, result, vec_ty)); + + let result = + match (signed, is_add) { + (false, true) => { + let res = lhs + rhs; + let cmp = bx.context.new_comparison(None, ComparisonOp::LessThan, res, lhs); + res | cmp + }, + (true, true) => { + // Algorithm from: https://codereview.stackexchange.com/questions/115869/saturated-signed-addition + // TODO(antoyo): improve using conditional operators if possible. + let arg_type = lhs.get_type(); + // TODO(antoyo): convert lhs and rhs to unsigned. + let sum = lhs + rhs; + let vector_type = arg_type.dyncast_vector().expect("vector type"); + let unit = vector_type.get_num_units(); + let a = bx.context.new_rvalue_from_int(elem_ty, ((elem_width as i32) << 3) - 1); + let width = bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![a; unit]); + + let xor1 = lhs ^ rhs; + let xor2 = lhs ^ sum; + let and = bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, xor1) & xor2; + let mask = and >> width; + + let one = bx.context.new_rvalue_one(elem_ty); + let ones = bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![one; unit]); + let shift1 = ones << width; + let shift2 = sum >> width; + let mask_min = shift1 ^ shift2; + + let and1 = bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, mask) & sum; + let and2 = mask & mask_min; + + and1 + and2 + }, + (false, false) => { + let res = lhs - rhs; + let cmp = bx.context.new_comparison(None, ComparisonOp::LessThanEquals, res, lhs); + res & cmp + }, + (true, false) => { + let arg_type = lhs.get_type(); + // TODO(antoyo): this uses the same algorithm from saturating add, but add the + // negative of the right operand. Find a proper subtraction algorithm. + let rhs = bx.context.new_unary_op(None, UnaryOp::Minus, arg_type, rhs); + + // TODO(antoyo): convert lhs and rhs to unsigned. + let sum = lhs + rhs; + let vector_type = arg_type.dyncast_vector().expect("vector type"); + let unit = vector_type.get_num_units(); + let a = bx.context.new_rvalue_from_int(elem_ty, ((elem_width as i32) << 3) - 1); + let width = bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![a; unit]); + + let xor1 = lhs ^ rhs; + let xor2 = lhs ^ sum; + let and = bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, xor1) & xor2; + let mask = and >> width; + + let one = bx.context.new_rvalue_one(elem_ty); + let ones = bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![one; unit]); + let shift1 = ones << width; + let shift2 = sum >> width; + let mask_min = shift1 ^ shift2; + + let and1 = bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, mask) & sum; + let and2 = mask & mask_min; + + and1 + and2 + } + }; + + return Ok(result); } macro_rules! arith_red { @@ -650,33 +958,50 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( add, 0.0 // TODO: Use this argument. ); - arith_red!(simd_reduce_mul_unordered: BinaryOp::Mult, vector_reduce_fmul_fast, false, mul, 1.0); + arith_red!( + simd_reduce_mul_unordered: BinaryOp::Mult, + vector_reduce_fmul_fast, + false, + mul, + 1.0 + ); + arith_red!( + simd_reduce_add_ordered: BinaryOp::Plus, + vector_reduce_fadd, + true, + add, + 0.0 + ); + arith_red!( + simd_reduce_mul_ordered: BinaryOp::Mult, + vector_reduce_fmul, + true, + mul, + 1.0 + ); + macro_rules! minmax_red { - ($name:ident: $reduction:ident) => { + ($name:ident: $int_red:ident, $float_red:ident) => { if name == sym::$name { require!( ret_ty == in_elem, InvalidMonomorphizationReturnType { span, name, in_elem, in_ty, ret_ty } ); return match in_elem.kind() { - ty::Int(_) | ty::Uint(_) | ty::Float(_) => { - Ok(bx.$reduction(args[0].immediate())) - } - _ => return_error!(InvalidMonomorphizationUnsupportedElement { - span, - name, - in_ty, - elem_ty: in_elem, - ret_ty - }), + ty::Int(_) | ty::Uint(_) => Ok(bx.$int_red(args[0].immediate())), + ty::Float(_) => Ok(bx.$float_red(args[0].immediate())), + _ => return_error!(InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty }), }; } }; } - minmax_red!(simd_reduce_min: vector_reduce_min); - minmax_red!(simd_reduce_max: vector_reduce_max); + minmax_red!(simd_reduce_min: vector_reduce_min, vector_reduce_fmin); + minmax_red!(simd_reduce_max: vector_reduce_max, vector_reduce_fmax); + // TODO(sadlerap): revisit these intrinsics to generate more optimal reductions + minmax_red!(simd_reduce_min_nanless: vector_reduce_min, vector_reduce_fmin); + minmax_red!(simd_reduce_max_nanless: vector_reduce_max, vector_reduce_fmax); macro_rules! bitwise_red { ($name:ident : $op:expr, $boolean:expr) => { @@ -699,15 +1024,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( }), } - // boolean reductions operate on vectors of i1s: - let i1 = bx.type_i1(); - let i1xn = bx.type_vector(i1, in_len as u64); - bx.trunc(args[0].immediate(), i1xn) + args[0].immediate() }; return match in_elem.kind() { ty::Int(_) | ty::Uint(_) => { let r = bx.vector_reduce_op(input, $op); - Ok(if !$boolean { r } else { bx.zext(r, bx.type_bool()) }) + Ok(if !$boolean { r } else { bx.icmp(IntPredicate::IntNE, r, bx.context.new_rvalue_zero(r.get_type())) }) } _ => return_error!(InvalidMonomorphizationUnsupportedElement { span, @@ -723,6 +1045,9 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( bitwise_red!(simd_reduce_and: BinaryOp::BitwiseAnd, false); bitwise_red!(simd_reduce_or: BinaryOp::BitwiseOr, false); + bitwise_red!(simd_reduce_xor: BinaryOp::BitwiseXor, false); + bitwise_red!(simd_reduce_all: BinaryOp::BitwiseAnd, true); + bitwise_red!(simd_reduce_any: BinaryOp::BitwiseOr, true); unimplemented!("simd {}", name); } diff --git a/src/lib.rs b/src/lib.rs index 44538b415283c..1b7feb5f8a18e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ /* * TODO(antoyo): implement equality in libgccjit based on https://zpz.github.io/blog/overloading-equality-operator-in-cpp-class-hierarchy/ (for type equality?) * TODO(antoyo): support #[inline] attributes. - * TODO(antoyo): support LTO (gcc's equivalent to Thin LTO is enabled by -fwhopr: https://stackoverflow.com/questions/64954525/does-gcc-have-thin-lto). + * TODO(antoyo): support LTO (gcc's equivalent to Full LTO is -flto -flto-partition=one — https://documentation.suse.com/sbp/all/html/SBP-GCC-10/index.html). * * TODO(antoyo): remove the patches. */ @@ -23,6 +23,7 @@ extern crate rustc_apfloat; extern crate rustc_ast; +extern crate rustc_attr; extern crate rustc_codegen_ssa; extern crate rustc_data_structures; extern crate rustc_errors; @@ -43,6 +44,7 @@ mod abi; mod allocator; mod archive; mod asm; +mod attributes; mod back; mod base; mod builder; @@ -314,9 +316,12 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec { .filter(|_feature| { // TODO(antoyo): implement a way to get enabled feature in libgccjit. // Probably using the equivalent of __builtin_cpu_supports. + // TODO(antoyo): maybe use whatever outputs the following command: + // gcc -march=native -Q --help=target #[cfg(feature="master")] { - _feature.contains("sse") || _feature.contains("avx") + // NOTE: the CPU in the CI doesn't support sse4a, so disable it to make the stdarch tests pass in the CI. + (_feature.contains("sse") || _feature.contains("avx")) && !_feature.contains("avx512") && !_feature.contains("sse4a") } #[cfg(not(feature="master"))] { diff --git a/src/mono_item.rs b/src/mono_item.rs index a7c868354fb27..c1f6340866cac 100644 --- a/src/mono_item.rs +++ b/src/mono_item.rs @@ -1,38 +1,66 @@ +#[cfg(feature="master")] +use gccjit::{VarAttribute, FnAttribute}; use rustc_codegen_ssa::traits::PreDefineMethods; +use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::mono::{Linkage, Visibility}; use rustc_middle::ty::{self, Instance, TypeVisitableExt}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; -use rustc_span::def_id::DefId; +use crate::attributes; use crate::base; use crate::context::CodegenCx; use crate::type_of::LayoutGccExt; impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> { - fn predefine_static(&self, def_id: DefId, _linkage: Linkage, _visibility: Visibility, symbol_name: &str) { + #[cfg_attr(not(feature="master"), allow(unused_variables))] + fn predefine_static(&self, def_id: DefId, _linkage: Linkage, visibility: Visibility, symbol_name: &str) { let attrs = self.tcx.codegen_fn_attrs(def_id); let instance = Instance::mono(self.tcx, def_id); let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); - let gcc_type = self.layout_of(ty).gcc_type(self, true); + let gcc_type = self.layout_of(ty).gcc_type(self); let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); let global = self.define_global(symbol_name, gcc_type, is_tls, attrs.link_section); + #[cfg(feature="master")] + global.add_attribute(VarAttribute::Visibility(base::visibility_to_gcc(visibility))); - // TODO(antoyo): set linkage and visibility. + // TODO(antoyo): set linkage. self.instances.borrow_mut().insert(instance, global); } - fn predefine_fn(&self, instance: Instance<'tcx>, linkage: Linkage, _visibility: Visibility, symbol_name: &str) { + #[cfg_attr(not(feature="master"), allow(unused_variables))] + fn predefine_fn(&self, instance: Instance<'tcx>, linkage: Linkage, visibility: Visibility, symbol_name: &str) { assert!(!instance.substs.needs_infer()); let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); self.linkage.set(base::linkage_to_gcc(linkage)); - let _decl = self.declare_fn(symbol_name, &fn_abi); + let decl = self.declare_fn(symbol_name, &fn_abi); //let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); + attributes::from_fn_attrs(self, decl, instance); + + // If we're compiling the compiler-builtins crate, e.g., the equivalent of + // compiler-rt, then we want to implicitly compile everything with hidden + // visibility as we're going to link this object all over the place but + // don't want the symbols to get exported. + if linkage != Linkage::Internal + && linkage != Linkage::Private + && self.tcx.is_compiler_builtins(LOCAL_CRATE) + { + #[cfg(feature="master")] + decl.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); + } + else { + #[cfg(feature="master")] + decl.add_attribute(FnAttribute::Visibility(base::visibility_to_gcc(visibility))); + } + // TODO(antoyo): call set_link_section() to allow initializing argc/argv. // TODO(antoyo): set unique comdat. // TODO(antoyo): use inline attribute from there in linkage.set() above. + + self.functions.borrow_mut().insert(symbol_name.to_string(), decl); + self.function_instances.borrow_mut().insert(instance, unsafe { std::mem::transmute(decl) }); } } diff --git a/src/type_.rs b/src/type_.rs index 89a415cdb36cd..daa661f35c4c1 100644 --- a/src/type_.rs +++ b/src/type_.rs @@ -1,5 +1,3 @@ -use std::convert::TryInto; - use gccjit::{RValue, Struct, Type}; use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, TypeMembershipMethods}; use rustc_codegen_ssa::common::TypeKind; @@ -202,8 +200,9 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { value.get_type() } - fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> { - if let Some(struct_type) = ty.is_struct() { + fn type_array(&self, ty: Type<'gcc>, len: u64) -> Type<'gcc> { + // TODO: remove this as well? + /*if let Some(struct_type) = ty.is_struct() { if struct_type.get_field_count() == 0 { // NOTE: since gccjit only supports i32 for the array size and libcore's tests uses a // size of usize::MAX in test_binary_search, we workaround this by setting the size to @@ -211,14 +210,7 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { // FIXME(antoyo): fix gccjit API. len = 0; } - } - - // NOTE: see note above. Some other test uses usize::MAX. - if len == u64::MAX { - len = 0; - } - - let len: i32 = len.try_into().expect("array len"); + }*/ self.context.new_array_type(None, ty, len) } @@ -247,10 +239,6 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { pub fn type_named_struct(&self, name: &str) -> Struct<'gcc> { self.context.new_opaque_struct_type(None, name) } - - pub fn type_bool(&self) -> Type<'gcc> { - self.context.new_type::() - } } pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>) -> (Vec>, bool) { @@ -273,7 +261,7 @@ pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout assert_eq!(offset.align_to(padding_align) + padding, target_offset); result.push(cx.type_padding_filler(padding, padding_align)); - result.push(field.gcc_type(cx, !field.ty.is_any_ptr())); // FIXME(antoyo): might need to check if the type is inside another, like Box. + result.push(field.gcc_type(cx)); offset = target_offset + field.size; prev_effective_align = effective_field_align; } diff --git a/src/type_of.rs b/src/type_of.rs index ea2ce765053ff..5df8c1a209db2 100644 --- a/src/type_of.rs +++ b/src/type_of.rs @@ -6,7 +6,7 @@ use rustc_middle::bug; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_target::abi::{self, Abi, F32, F64, FieldsShape, Int, Integer, Pointer, PointeeInfo, Size, TyAbiInterface, Variants}; +use rustc_target::abi::{self, Abi, Align, F32, F64, FieldsShape, Int, Integer, Pointer, PointeeInfo, Size, TyAbiInterface, Variants}; use rustc_target::abi::call::{CastTarget, FnAbi, Reg}; use crate::abi::{FnAbiGccExt, GccType}; @@ -50,11 +50,25 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } } -pub fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>, defer: &mut Option<(Struct<'gcc>, TyAndLayout<'tcx>)>) -> Type<'gcc> { +impl<'a, 'tcx> CodegenCx<'a, 'tcx> { + pub fn align_of(&self, ty: Ty<'tcx>) -> Align { + self.layout_of(ty).align.abi + } +} + +fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>, defer: &mut Option<(Struct<'gcc>, TyAndLayout<'tcx>)>) -> Type<'gcc> { match layout.abi { Abi::Scalar(_) => bug!("handled elsewhere"), Abi::Vector { ref element, count } => { let element = layout.scalar_gcc_type_at(cx, element, Size::ZERO); + let element = + // NOTE: gcc doesn't allow pointer types in vectors. + if element.get_pointee().is_some() { + cx.usize_type + } + else { + element + }; return cx.context.new_vector_type(element, count); }, Abi::ScalarPair(..) => { @@ -114,7 +128,7 @@ pub fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLa }, } } - FieldsShape::Array { count, .. } => cx.type_array(layout.field(cx, 0).gcc_type(cx, true), count), + FieldsShape::Array { count, .. } => cx.type_array(layout.field(cx, 0).gcc_type(cx), count), FieldsShape::Arbitrary { .. } => match name { None => { @@ -133,7 +147,7 @@ pub fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLa pub trait LayoutGccExt<'tcx> { fn is_gcc_immediate(&self) -> bool; fn is_gcc_scalar_pair(&self) -> bool; - fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, set_fields: bool) -> Type<'gcc>; + fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc>; fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize, immediate: bool) -> Type<'gcc>; @@ -168,8 +182,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { /// with the inner-most trailing unsized field using the "minimal unit" /// of that field's type - this is useful for taking the address of /// that field and ensuring the struct has the right alignment. - //TODO(antoyo): do we still need the set_fields parameter? - fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, set_fields: bool) -> Type<'gcc> { + fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { if let Abi::Scalar(ref scalar) = self.abi { // Use a different cache for scalars because pointers to DSTs // can be either fat or thin (data pointers of fat pointers). @@ -179,10 +192,10 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { let ty = match *self.ty.kind() { ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { - cx.type_ptr_to(cx.layout_of(ty).gcc_type(cx, set_fields)) + cx.type_ptr_to(cx.layout_of(ty).gcc_type(cx)) } ty::Adt(def, _) if def.is_box() => { - cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).gcc_type(cx, true)) + cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).gcc_type(cx)) } ty::FnPtr(sig) => cx.fn_ptr_backend_type(&cx.fn_abi_of_fn_ptr(sig, ty::List::empty())), _ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO), @@ -199,13 +212,6 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { }; let cached_type = cx.types.borrow().get(&(self.ty, variant_index)).cloned(); if let Some(ty) = cached_type { - let type_to_set_fields = cx.types_with_fields_to_set.borrow_mut().remove(&ty); - if let Some((struct_type, layout)) = type_to_set_fields { - // Since we might be trying to generate a type containing another type which is not - // completely generated yet, we deferred setting the fields until now. - let (fields, packed) = struct_fields(cx, layout); - cx.set_struct_body(struct_type, &fields, packed); - } return ty; } @@ -222,7 +228,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { if let Some(v) = variant_index { layout = layout.for_variant(cx, v); } - layout.gcc_type(cx, true) + layout.gcc_type(cx) } else { uncached_gcc_type(cx, *self, &mut defer) @@ -230,9 +236,9 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { cx.types.borrow_mut().insert((self.ty, variant_index), ty); - if let Some((ty, layout)) = defer { + if let Some((deferred_ty, layout)) = defer { let (fields, packed) = struct_fields(cx, layout); - cx.set_struct_body(ty, &fields, packed); + cx.set_struct_body(deferred_ty, &fields, packed); } ty @@ -244,7 +250,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { return cx.type_i1(); } } - self.gcc_type(cx, true) + self.gcc_type(cx) } fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc> { @@ -273,7 +279,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { // pointee types, to avoid bitcasting every `OperandRef::deref`. match self.ty.kind() { ty::Ref(..) | ty::RawPtr(_) => { - return self.field(cx, index).gcc_type(cx, true); + return self.field(cx, index).gcc_type(cx); } // only wide pointer boxes are handled as pointers // thin pointer boxes with scalar allocators are handled by the general logic below @@ -343,7 +349,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Type<'gcc> { - layout.gcc_type(self, true) + layout.gcc_type(self) } fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Type<'gcc> { diff --git a/test.sh b/test.sh index c5ffb763673d2..6139892aefca7 100755 --- a/test.sh +++ b/test.sh @@ -17,17 +17,20 @@ export LIBRARY_PATH="$GCC_PATH" flags= gcc_master_branch=1 channel="debug" -func=all +funcs=() build_only=0 +nb_parts=0 +current_part=0 while [[ $# -gt 0 ]]; do case $1 in --release) codegen_channel=release + channel="release" shift ;; --release-sysroot) - sysroot_channel=release + sysroot_channel="--release" shift ;; --no-default-features) @@ -40,43 +43,83 @@ while [[ $# -gt 0 ]]; do flags="$flags --features $1" shift ;; - --release) - channel="release" + "--test-rustc") + funcs+=(test_rustc) shift ;; - "--test-rustc") - func=test_rustc + "--test-successful-rustc") + funcs+=(test_successful_rustc) + shift + ;; + "--test-failing-rustc") + funcs+=(test_failing_rustc) shift ;; "--test-libcore") - func=test_libcore + funcs+=(test_libcore) shift ;; "--clean-ui-tests") - func=clean_ui_tests + funcs+=(clean_ui_tests) + shift + ;; + "--clean") + funcs+=(clean) shift ;; "--std-tests") - func=std_tests + funcs+=(std_tests) + shift + ;; + + "--asm-tests") + funcs+=(asm_tests) shift ;; "--extended-tests") - func=extended_sysroot_tests + funcs+=(extended_sysroot_tests) + shift + ;; + "--extended-rand-tests") + funcs+=(extended_rand_tests) + shift + ;; + "--extended-regex-example-tests") + funcs+=(extended_regex_example_tests) + shift + ;; + "--extended-regex-tests") + funcs+=(extended_regex_tests) + shift + ;; + + "--mini-tests") + funcs+=(mini_tests) shift ;; "--build-sysroot") - func=build_sysroot + funcs+=(build_sysroot) shift ;; "--build") build_only=1 shift ;; + "--nb-parts") + shift + nb_parts=$1 + shift + ;; + "--current-part") + shift + current_part=$1 + shift + ;; *) echo "Unknown option $1" exit 1 @@ -87,7 +130,6 @@ done if [[ $channel == "release" ]]; then export CHANNEL='release' CARGO_INCREMENTAL=1 cargo rustc --release $flags - shift else echo $LD_LIBRARY_PATH export CHANNEL='debug' @@ -95,6 +137,7 @@ else fi if (( $build_only == 1 )); then + echo "Since it's 'build-only', exiting..." exit fi @@ -119,7 +162,7 @@ function mini_tests() { function build_sysroot() { echo "[BUILD] sysroot" - time ./build_sysroot/build_sysroot.sh + time ./build_sysroot/build_sysroot.sh $sysroot_channel } function std_tests() { @@ -148,17 +191,57 @@ function std_tests() { $RUN_WRAPPER ./target/out/std_example --target $TARGET_TRIPLE echo "[AOT] subslice-patterns-const-eval" - $RUSTC example/subslice-patterns-const-eval.rs --crate-type bin -Cpanic=abort --target $TARGET_TRIPLE + $RUSTC example/subslice-patterns-const-eval.rs --crate-type bin $TEST_FLAGS --target $TARGET_TRIPLE $RUN_WRAPPER ./target/out/subslice-patterns-const-eval echo "[AOT] track-caller-attribute" - $RUSTC example/track-caller-attribute.rs --crate-type bin -Cpanic=abort --target $TARGET_TRIPLE + $RUSTC example/track-caller-attribute.rs --crate-type bin $TEST_FLAGS --target $TARGET_TRIPLE $RUN_WRAPPER ./target/out/track-caller-attribute echo "[BUILD] mod_bench" $RUSTC example/mod_bench.rs --crate-type bin --target $TARGET_TRIPLE } +function setup_rustc() { + rust_toolchain=$(cat rust-toolchain | grep channel | sed 's/channel = "\(.*\)"/\1/') + + git clone https://github.com/rust-lang/rust.git || true + cd rust + git fetch + git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(') + export RUSTFLAGS= + + rm config.toml || true + + cat > config.toml < res.txt diff -u res.txt examples/regexdna-output.txt + popd +} + +function extended_regex_tests() { + if (( $gcc_master_branch == 0 )); then + return + fi + pushd regex echo "[TEST] rust-lang/regex tests" + export CG_RUSTFLAGS="--cap-lints warn" # newer aho_corasick versions throw a deprecation warning ../cargo.sh test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q popd } -function test_rustc() { - echo - echo "[TEST] rust-lang/rust" - - rust_toolchain=$(cat rust-toolchain | grep channel | sed 's/channel = "\(.*\)"/\1/') - - git clone https://github.com/rust-lang/rust.git || true - cd rust - git fetch - git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(') - export RUSTFLAGS= - - git apply ../rustc_patches/compile_test.patch || true +function extended_sysroot_tests() { + #pushd simple-raytracer + #echo "[BENCH COMPILE] ebobby/simple-raytracer" + #hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "cargo clean" \ + #"RUSTC=rustc RUSTFLAGS='' cargo build" \ + #"../cargo.sh build" - rm config.toml || true + #echo "[BENCH RUN] ebobby/simple-raytracer" + #cp ./target/debug/main ./raytracer_cg_gcc + #hyperfine --runs "${RUN_RUNS:-10}" ./raytracer_cg_llvm ./raytracer_cg_gcc + #popd - cat > config.toml < ui_tests + # To ensure it'll be always the same sub files, we sort the content. + sort ui_tests -o ui_tests + count=$((`wc -l < ui_tests` / $nb_parts)) + # We increment the number of tests by one because if this is an odd number, we would skip + # one test. + count=$((count + 1)) + split -d -l $count -a 1 ui_tests ui_tests.split + # Removing all tests. + find tests/ui -type f -name '*.rs' -not -path "*/auxiliary/*" -delete + # Putting back only the ones we want to test. + xargs -a "ui_tests.split$current_part" -d'\n' git checkout -- + fi echo "[TEST] rustc test suite" COMPILETEST_FORCE_STAGE0=1 ./x.py test --run always --stage 0 tests/ui/ --rustc-args "$RUSTC_ARGS" } +function test_failing_rustc() { + test_rustc "1" +} + +function test_successful_rustc() { + test_rustc "0" +} + function clean_ui_tests() { - find rust/build/x86_64-unknown-linux-gnu/test/ui/ -name stamp -exec rm -rf {} \; + find rust/build/x86_64-unknown-linux-gnu/test/ui/ -name stamp -delete } function all() { @@ -283,9 +403,17 @@ function all() { mini_tests build_sysroot std_tests + #asm_tests test_libcore extended_sysroot_tests test_rustc } -$func +if [ ${#funcs[@]} -eq 0 ]; then + echo "No command passed, running '--all'..." + all +else + for t in ${funcs[@]}; do + $t + done +fi diff --git a/tests/lang_tests_common.rs b/tests/lang_tests_common.rs index 8e378177e2457..06de26f7efc9f 100644 --- a/tests/lang_tests_common.rs +++ b/tests/lang_tests_common.rs @@ -46,11 +46,15 @@ pub fn main_inner(profile: Profile) { &format!("-Zcodegen-backend={}/target/debug/librustc_codegen_gcc.so", current_dir), "--sysroot", &format!("{}/build_sysroot/sysroot/", current_dir), "-Zno-parallel-llvm", - "-C", "panic=abort", "-C", "link-arg=-lc", "-o", exe.to_str().expect("to_str"), path.to_str().expect("to_str"), ]); + if let Some(flags) = option_env!("TEST_FLAGS") { + for flag in flags.split_whitespace() { + compiler.arg(&flag); + } + } match profile { Profile::Debug => {} Profile::Release => { diff --git a/tests/run/abort1.rs b/tests/run/abort1.rs index 291af5993aa25..25041d93e748a 100644 --- a/tests/run/abort1.rs +++ b/tests/run/abort1.rs @@ -33,6 +33,7 @@ mod intrinsics { use super::Sized; extern "rust-intrinsic" { + #[rustc_safe_intrinsic] pub fn abort() -> !; } } diff --git a/tests/run/abort2.rs b/tests/run/abort2.rs index 3c87c567892b5..e7443c8dbe5b2 100644 --- a/tests/run/abort2.rs +++ b/tests/run/abort2.rs @@ -33,6 +33,7 @@ mod intrinsics { use super::Sized; extern "rust-intrinsic" { + #[rustc_safe_intrinsic] pub fn abort() -> !; } } diff --git a/tests/run/array.rs b/tests/run/array.rs index 8b621d8a3530f..49b28d98f2fec 100644 --- a/tests/run/array.rs +++ b/tests/run/array.rs @@ -79,7 +79,7 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { #[lang = "panic"] #[track_caller] #[no_mangle] -pub fn panic(_msg: &str) -> ! { +pub fn panic(_msg: &'static str) -> ! { unsafe { libc::puts("Panicking\0" as *const str as *const u8); intrinsics::abort(); @@ -105,6 +105,7 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { mod intrinsics { extern "rust-intrinsic" { + #[rustc_safe_intrinsic] pub fn abort() -> !; } } diff --git a/tests/run/assign.rs b/tests/run/assign.rs index eb38a8a383575..427c1a2503397 100644 --- a/tests/run/assign.rs +++ b/tests/run/assign.rs @@ -57,6 +57,7 @@ mod libc { mod intrinsics { extern "rust-intrinsic" { + #[rustc_safe_intrinsic] pub fn abort() -> !; } } @@ -64,7 +65,7 @@ mod intrinsics { #[lang = "panic"] #[track_caller] #[no_mangle] -pub fn panic(_msg: &str) -> ! { +pub fn panic(_msg: &'static str) -> ! { unsafe { libc::puts("Panicking\0" as *const str as *const u8); libc::fflush(libc::stdout); diff --git a/tests/run/closure.rs b/tests/run/closure.rs index 7121a5f0d5221..8daa681abf7da 100644 --- a/tests/run/closure.rs +++ b/tests/run/closure.rs @@ -97,10 +97,14 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { mod intrinsics { extern "rust-intrinsic" { + #[rustc_safe_intrinsic] pub fn abort() -> !; } } +#[lang = "tuple_trait"] +pub trait Tuple {} + #[lang = "unsize"] pub trait Unsize {} @@ -114,7 +118,7 @@ impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} #[lang = "fn_once"] #[rustc_paren_sugar] -pub trait FnOnce { +pub trait FnOnce { #[lang = "fn_once_output"] type Output; @@ -123,7 +127,7 @@ pub trait FnOnce { #[lang = "fn_mut"] #[rustc_paren_sugar] -pub trait FnMut: FnOnce { +pub trait FnMut: FnOnce { extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; } @@ -177,7 +181,7 @@ impl Add for isize { #[lang = "panic"] #[track_caller] #[no_mangle] -pub fn panic(_msg: &str) -> ! { +pub fn panic(_msg: &'static str) -> ! { unsafe { libc::puts("Panicking\0" as *const str as *const u8); intrinsics::abort(); diff --git a/tests/run/condition.rs b/tests/run/condition.rs index 6a2e2d5bb11a9..b7a13081deae0 100644 --- a/tests/run/condition.rs +++ b/tests/run/condition.rs @@ -82,7 +82,7 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { #[lang = "panic"] #[track_caller] #[no_mangle] -pub fn panic(_msg: &str) -> ! { +pub fn panic(_msg: &'static str) -> ! { unsafe { libc::puts("Panicking\0" as *const str as *const u8); intrinsics::abort(); @@ -108,6 +108,7 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { mod intrinsics { extern "rust-intrinsic" { + #[rustc_safe_intrinsic] pub fn abort() -> !; } } diff --git a/tests/run/fun_ptr.rs b/tests/run/fun_ptr.rs index a226fff79e51b..8a196f774c82b 100644 --- a/tests/run/fun_ptr.rs +++ b/tests/run/fun_ptr.rs @@ -76,7 +76,7 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { #[lang = "panic"] #[track_caller] #[no_mangle] -pub fn panic(_msg: &str) -> ! { +pub fn panic(_msg: &'static str) -> ! { unsafe { libc::puts("Panicking\0" as *const str as *const u8); intrinsics::abort(); @@ -102,6 +102,7 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { mod intrinsics { extern "rust-intrinsic" { + #[rustc_safe_intrinsic] pub fn abort() -> !; } } diff --git a/tests/run/int.rs b/tests/run/int.rs index 75779622b54cd..bfe73c38435a3 100644 --- a/tests/run/int.rs +++ b/tests/run/int.rs @@ -3,22 +3,14 @@ // Run-time: // status: 0 -#![feature(const_black_box, core_intrinsics, start)] - -#![no_std] - -#[panic_handler] -fn panic_handler(_: &core::panic::PanicInfo) -> ! { - core::intrinsics::abort(); -} +#![feature(const_black_box)] /* * Code */ -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { - use core::hint::black_box; +fn main() { + use std::hint::black_box; macro_rules! check { ($ty:ty, $expr:expr) => { @@ -335,6 +327,4 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize { const VAL5: T = 73236519889708027473620326106273939584_i128; check_ops128!(); } - - 0 } diff --git a/tests/run/int_overflow.rs b/tests/run/int_overflow.rs index ea2c5add962ae..c3fcb3c0a2a06 100644 --- a/tests/run/int_overflow.rs +++ b/tests/run/int_overflow.rs @@ -55,6 +55,7 @@ mod libc { mod intrinsics { extern "rust-intrinsic" { + #[rustc_safe_intrinsic] pub fn abort() -> !; } } @@ -62,7 +63,7 @@ mod intrinsics { #[lang = "panic"] #[track_caller] #[no_mangle] -pub fn panic(_msg: &str) -> ! { +pub fn panic(_msg: &'static str) -> ! { unsafe { // Panicking is expected iff overflow checking is enabled. #[cfg(debug_assertions)] diff --git a/tests/run/mut_ref.rs b/tests/run/mut_ref.rs index 52de20021f3e0..2a2ea8b8bf0ab 100644 --- a/tests/run/mut_ref.rs +++ b/tests/run/mut_ref.rs @@ -59,6 +59,7 @@ mod libc { mod intrinsics { extern "rust-intrinsic" { + #[rustc_safe_intrinsic] pub fn abort() -> !; } } @@ -66,7 +67,7 @@ mod intrinsics { #[lang = "panic"] #[track_caller] #[no_mangle] -pub fn panic(_msg: &str) -> ! { +pub fn panic(_msg: &'static str) -> ! { unsafe { libc::puts("Panicking\0" as *const str as *const u8); libc::fflush(libc::stdout); diff --git a/tests/run/operations.rs b/tests/run/operations.rs index e078b37b4aba9..67b9f241dbbb3 100644 --- a/tests/run/operations.rs +++ b/tests/run/operations.rs @@ -65,6 +65,7 @@ mod libc { mod intrinsics { extern "rust-intrinsic" { + #[rustc_safe_intrinsic] pub fn abort() -> !; } } @@ -72,7 +73,7 @@ mod intrinsics { #[lang = "panic"] #[track_caller] #[no_mangle] -pub fn panic(_msg: &str) -> ! { +pub fn panic(_msg: &'static str) -> ! { unsafe { libc::puts("Panicking\0" as *const str as *const u8); libc::fflush(libc::stdout); diff --git a/tests/run/ptr_cast.rs b/tests/run/ptr_cast.rs index 6ac099ea145c2..da8a8295d564c 100644 --- a/tests/run/ptr_cast.rs +++ b/tests/run/ptr_cast.rs @@ -76,7 +76,7 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { #[lang = "panic"] #[track_caller] #[no_mangle] -pub fn panic(_msg: &str) -> ! { +pub fn panic(_msg: &'static str) -> ! { unsafe { libc::puts("Panicking\0" as *const str as *const u8); intrinsics::abort(); @@ -102,6 +102,7 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { mod intrinsics { extern "rust-intrinsic" { + #[rustc_safe_intrinsic] pub fn abort() -> !; } } diff --git a/tests/run/slice.rs b/tests/run/slice.rs index ad9258ed0bdeb..96f1c4792e58f 100644 --- a/tests/run/slice.rs +++ b/tests/run/slice.rs @@ -102,6 +102,7 @@ mod intrinsics { use super::Sized; extern "rust-intrinsic" { + #[rustc_safe_intrinsic] pub fn abort() -> !; } } diff --git a/tests/run/static.rs b/tests/run/static.rs index 294add968449a..19201f1df2667 100644 --- a/tests/run/static.rs +++ b/tests/run/static.rs @@ -45,6 +45,7 @@ mod intrinsics { use super::Sized; extern "rust-intrinsic" { + #[rustc_safe_intrinsic] pub fn abort() -> !; } } diff --git a/tools/check_intrinsics_duplicates.py b/tools/check_intrinsics_duplicates.py new file mode 100644 index 0000000000000..c09fb3c759f3b --- /dev/null +++ b/tools/check_intrinsics_duplicates.py @@ -0,0 +1,67 @@ +import sys + + +def check_duplicates(): + auto_content = "" + manual_content = "" + + with open("src/intrinsic/llvm.rs", "r", encoding="utf8") as f: + manual_content = f.read() + with open("src/intrinsic/archs.rs", "r", encoding="utf8") as f: + auto_content = f.read() + + intrinsics_map = {} + for line in auto_content.splitlines(): + line = line.strip() + if not line.startswith('"'): + continue + parts = line.split('"') + if len(parts) != 5: + continue + intrinsics_map[parts[1]] = parts[3] + + if len(intrinsics_map) == 0: + print("No intrinsics found in auto code... Aborting.") + return 1 + print("Found {} intrinsics in auto code".format(len(intrinsics_map))) + errors = [] + lines = manual_content.splitlines() + pos = 0 + found = 0 + while pos < len(lines): + line = lines[pos].strip() + # This is our marker. + if line == "let gcc_name = match name {": + while pos < len(lines): + line = lines[pos].strip() + pos += 1 + if line == "};": + # We're done! + if found == 0: + print("No intrinsics found in manual code even though we found the " + "marker... Aborting...") + return 1 + for error in errors: + print("ERROR => {}".format(error)) + return 1 if len(errors) != 0 else 0 + parts = line.split('"') + if len(parts) != 5: + continue + found += 1 + if parts[1] in intrinsics_map: + if parts[3] != intrinsics_map[parts[1]]: + print("Same intrinsics (`{}` at line {}) but different GCC " + "translations: `{}` != `{}`".format( + parts[1], pos, intrinsics_map[parts[1]], parts[3])) + else: + errors.append("Duplicated intrinsics: `{}` at line {}. Please remove it " + " from manual code".format(parts[1], pos)) + # Weird but whatever... + return 1 if len(errors) != 0 else 0 + pos += 1 + print("No intrinsics found in manual code... Aborting") + return 1 + + +if __name__ == "__main__": + sys.exit(check_duplicates()) diff --git a/tools/generate_intrinsics.py b/tools/generate_intrinsics.py index 849c6e9c98164..6188924b0d50a 100644 --- a/tools/generate_intrinsics.py +++ b/tools/generate_intrinsics.py @@ -13,7 +13,7 @@ def run_command(command, cwd=None): sys.exit(1) -def clone_repository(repo_name, path, repo_url, sub_path=None): +def clone_repository(repo_name, path, repo_url, sub_paths=None): if os.path.exists(path): while True: choice = input("There is already a `{}` folder, do you want to update it? [y/N]".format(path)) @@ -27,12 +27,12 @@ def clone_repository(repo_name, path, repo_url, sub_path=None): else: print("Didn't understand answer...") print("Cloning {} repository...".format(repo_name)) - if sub_path is None: + if sub_paths is None: run_command(["git", "clone", repo_url, "--depth", "1", path]) else: run_command(["git", "clone", repo_url, "--filter=tree:0", "--no-checkout", path]) run_command(["git", "sparse-checkout", "init"], cwd=path) - run_command(["git", "sparse-checkout", "set", "add", sub_path], cwd=path) + run_command(["git", "sparse-checkout", "set", *sub_paths], cwd=path) run_command(["git", "checkout"], cwd=path) @@ -40,56 +40,45 @@ def append_intrinsic(array, intrinsic_name, translation): array.append((intrinsic_name, translation)) -def extract_instrinsics(intrinsics, file): - print("Extracting intrinsics from `{}`...".format(file)) - with open(file, "r", encoding="utf8") as f: - content = f.read() +def convert_to_string(content): + if content.__class__.__name__ == 'bytes': + return content.decode('utf-8') + return content - lines = content.splitlines() + +def extract_instrinsics_from_llvm(llvm_path, intrinsics): + p = subprocess.Popen( + ["llvm-tblgen", "llvm/IR/Intrinsics.td"], + cwd=os.path.join(llvm_path, "llvm/include"), + stdout=subprocess.PIPE) + output, err = p.communicate() + lines = convert_to_string(output).splitlines() pos = 0 - current_arch = None while pos < len(lines): - line = lines[pos].strip() - if line.startswith("let TargetPrefix ="): - current_arch = line.split('"')[1].strip() - if len(current_arch) == 0: - current_arch = None - elif current_arch is None: - pass - elif line == "}": - current_arch = None - elif line.startswith("def "): - content = "" - while not content.endswith(";") and not content.endswith("}") and pos < len(lines): - line = lines[pos].split(" // ")[0].strip() - content += line - pos += 1 - entries = re.findall('GCCBuiltin<"(\\w+)">', content) - if len(entries) > 0: - intrinsic = content.split("def ")[1].strip().split(":")[0].strip() - intrinsic = intrinsic.split("_") - if len(intrinsic) < 2 or intrinsic[0] != "int": - continue - intrinsic[0] = "llvm" - intrinsic = ".".join(intrinsic) - if current_arch not in intrinsics: - intrinsics[current_arch] = [] - for entry in entries: - append_intrinsic(intrinsics[current_arch], intrinsic, entry) + line = lines[pos] + if not line.startswith("def "): + pos += 1 continue - pos += 1 - continue - print("Done!") - - -def extract_instrinsics_from_llvm(llvm_path, intrinsics): - files = [] - intrinsics_path = os.path.join(llvm_path, "llvm/include/llvm/IR") - for (dirpath, dirnames, filenames) in walk(intrinsics_path): - files.extend([os.path.join(intrinsics_path, f) for f in filenames if f.endswith(".td")]) - - for file in files: - extract_instrinsics(intrinsics, file) + intrinsic = line.split(" ")[1].strip() + content = line + while pos < len(lines): + line = lines[pos].split(" // ")[0].strip() + content += line + pos += 1 + if line == "}": + break + entries = re.findall('string ClangBuiltinName = "(\\w+)";', content) + current_arch = re.findall('string TargetPrefix = "(\\w+)";', content) + if len(entries) == 1 and len(current_arch) == 1: + current_arch = current_arch[0] + intrinsic = intrinsic.split("_") + if len(intrinsic) < 2 or intrinsic[0] != "int": + continue + intrinsic[0] = "llvm" + intrinsic = ".".join(intrinsic) + if current_arch not in intrinsics: + intrinsics[current_arch] = [] + append_intrinsic(intrinsics[current_arch], intrinsic, entries[0]) def append_translation(json_data, p, array): @@ -193,6 +182,8 @@ def update_intrinsics(llvm_path, llvmint, llvmint2): for entry in intrinsics[arch]: if entry[2] == True: # if it is a duplicate out.write(' // [DUPLICATE]: "{}" => "{}",\n'.format(entry[0], entry[1])) + elif "_round_mask" in entry[1]: + out.write(' // [INVALID CONVERSION]: "{}" => "{}",\n'.format(entry[0], entry[1])) else: out.write(' "{}" => "{}",\n'.format(entry[0], entry[1])) out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {}", name),\n') @@ -219,7 +210,7 @@ def main(): "llvm-project", llvm_path, "https://github.com/llvm/llvm-project", - sub_path="llvm/include/llvm/IR", + sub_paths=["llvm/include/llvm/IR", "llvm/include/llvm/CodeGen/"], ) clone_repository( "llvmint", From 94538736a80df08c8344a4e6fe5b91de6a1b7843 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 5 Mar 2023 12:16:33 -0500 Subject: [PATCH 093/465] Update gccjit --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 65e7619755901..80e5741894088 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,7 +35,7 @@ dependencies = [ [[package]] name = "gccjit" version = "1.0.0" -source = "git+https://github.com/antoyo/gccjit.rs#bdb86fb5092895ff5589726b33250010c64d93f6" +source = "git+https://github.com/antoyo/gccjit.rs#eefb8c662d61477f34b7c32d26bcda5f1ef08432" dependencies = [ "gccjit_sys", ] @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "gccjit_sys" version = "0.0.1" -source = "git+https://github.com/antoyo/gccjit.rs#bdb86fb5092895ff5589726b33250010c64d93f6" +source = "git+https://github.com/antoyo/gccjit.rs#eefb8c662d61477f34b7c32d26bcda5f1ef08432" dependencies = [ "libc 0.1.12", ] From cf9c2f840f56eda73c7abd79fe3b94117f0926fb Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 5 Mar 2023 12:31:16 -0500 Subject: [PATCH 094/465] Fix for diagnostics --- locales/en-US.ftl | 3 +++ src/attributes.rs | 11 ++++++----- src/errors.rs | 9 +++++++++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/locales/en-US.ftl b/locales/en-US.ftl index 2181d49eeef6b..0a94a08f8dca8 100644 --- a/locales/en-US.ftl +++ b/locales/en-US.ftl @@ -63,3 +63,6 @@ codegen_gcc_invalid_monomorphization_unsupported_operation = codegen_gcc_invalid_minimum_alignment = invalid minimum global alignment: {$err} + +codegen_gcc_tied_target_features = the target features {$features} must all be either enabled or disabled together + .help = add the missing features in a `target_feature` attribute diff --git a/src/attributes.rs b/src/attributes.rs index 243a1a36dd09d..db841b1b52408 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -9,7 +9,7 @@ use rustc_session::Session; use rustc_span::symbol::sym; use smallvec::{smallvec, SmallVec}; -use crate::context::CodegenCx; +use crate::{context::CodegenCx, errors::TiedTargetFeatures}; // Given a map from target_features to whether they are enabled or disabled, // ensure only valid combinations are allowed. @@ -84,10 +84,11 @@ pub fn from_fn_attrs<'gcc, 'tcx>( let span = cx.tcx .get_attr(instance.def_id(), sym::target_feature) .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span); - let msg = format!("the target features {} must all be either enabled or disabled together", features.join(", ")); - let mut err = cx.tcx.sess.struct_span_err(span, &msg); - err.help("add the missing features in a `target_feature` attribute"); - err.emit(); + cx.tcx.sess.create_err(TiedTargetFeatures { + features: features.join(", "), + span, + }) + .emit(); return; } diff --git a/src/errors.rs b/src/errors.rs index 5ea39606c086d..9305bd1e043d5 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -227,3 +227,12 @@ pub(crate) struct UnwindingInlineAsm { pub(crate) struct InvalidMinimumAlignment { pub err: String, } + +#[derive(Diagnostic)] +#[diag(codegen_gcc_tied_target_features)] +#[help] +pub(crate) struct TiedTargetFeatures { + #[primary_span] + pub span: Span, + pub features: String, +} From 8652bbb0728fb60137c96caa9af7e5bfb1617923 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 17 Nov 2022 10:33:10 +0100 Subject: [PATCH 095/465] replace legacy copyright annotations in submodules --- example/alloc_system.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/example/alloc_system.rs b/example/alloc_system.rs index fd01fcf1fc82c..9ec18da90d819 100644 --- a/example/alloc_system.rs +++ b/example/alloc_system.rs @@ -1,12 +1,6 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. +// SPDX-License-Identifier: MIT OR Apache-2.0 +// SPDX-FileCopyrightText: The Rust Project Developers (see https://thanks.rust-lang.org) + #![no_std] #![feature(allocator_api, rustc_private)] #![cfg_attr(any(unix, target_os = "redox"), feature(libc))] From fe93911ebcdc2f9c95e0d40e138fa2f7a3932093 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 3 Mar 2023 00:18:38 +0100 Subject: [PATCH 096/465] Simplify message paths This makes it easier to open the messages file while developing on features. The commit was the result of automatted changes: for p in compiler/rustc_*; do mv $p/locales/en-US.ftl $p/messages.ftl; rmdir $p/locales; done for p in compiler/rustc_*; do sed -i "s#\.\./locales/en-US.ftl#../messages.ftl#" $p/src/lib.rs; done --- locales/en-US.ftl => messages.ftl | 0 src/lib.rs | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename locales/en-US.ftl => messages.ftl (100%) diff --git a/locales/en-US.ftl b/messages.ftl similarity index 100% rename from locales/en-US.ftl rename to messages.ftl diff --git a/src/lib.rs b/src/lib.rs index 1b7feb5f8a18e..0b661505acc00 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -87,7 +87,7 @@ use rustc_span::Symbol; use rustc_span::fatal_error::FatalError; use tempfile::TempDir; -fluent_messages! { "../locales/en-US.ftl" } +fluent_messages! { "../messages.ftl" } pub struct PrintOnPanic String>(pub F); From a5ba6e025f9c37dc3b9f0943355974288f0c4da9 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 27 Feb 2023 13:07:44 +0000 Subject: [PATCH 097/465] Remove uses of `box_syntax` in rustc and tools --- tests/source/expr.rs | 11 ----------- tests/target/configs/combine_control_expr/false.rs | 6 ------ tests/target/configs/combine_control_expr/true.rs | 6 ------ tests/target/expr.rs | 14 -------------- 4 files changed, 37 deletions(-) diff --git a/tests/source/expr.rs b/tests/source/expr.rs index 21f8a4a43668a..879c551ea4909 100644 --- a/tests/source/expr.rs +++ b/tests/source/expr.rs @@ -3,7 +3,6 @@ // Test expressions fn foo() -> bool { - let boxed: Box = box 5; let referenced = &5 ; let very_long_variable_name = ( a + first + simple + test ); @@ -132,12 +131,6 @@ fn qux() { } } -fn issue227() { - { - let handler = box DocumentProgressHandler::new(addr, DocumentProgressTask::DOMContentLoaded); - } -} - fn issue184(source: &str) { for c in source.chars() { if index < 'a' { @@ -413,10 +406,6 @@ fn issue2704() { .concat(&requires1) .concat(&requires2) .distinct_total()); - let requires = requires.set(box requires0 - .concat(&requires1) - .concat(&requires2) - .distinct_total()); let requires = requires.set(requires0 .concat(&requires1) .concat(&requires2) diff --git a/tests/target/configs/combine_control_expr/false.rs b/tests/target/configs/combine_control_expr/false.rs index 5ada9b1dd1485..0ab8202493746 100644 --- a/tests/target/configs/combine_control_expr/false.rs +++ b/tests/target/configs/combine_control_expr/false.rs @@ -108,12 +108,6 @@ fn main() { bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, )); - // Box - foo(box Bar { - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, - bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, - }); - // Unary foo(!bar( aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, diff --git a/tests/target/configs/combine_control_expr/true.rs b/tests/target/configs/combine_control_expr/true.rs index 52acd26492add..aa41e021fb7ab 100644 --- a/tests/target/configs/combine_control_expr/true.rs +++ b/tests/target/configs/combine_control_expr/true.rs @@ -96,12 +96,6 @@ fn main() { bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, )); - // Box - foo(box Bar { - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, - bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, - }); - // Unary foo(!bar( aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, diff --git a/tests/target/expr.rs b/tests/target/expr.rs index 84df802bc70f9..187a1dc976a46 100644 --- a/tests/target/expr.rs +++ b/tests/target/expr.rs @@ -3,7 +3,6 @@ // Test expressions fn foo() -> bool { - let boxed: Box = box 5; let referenced = &5; let very_long_variable_name = (a + first + simple + test); @@ -179,13 +178,6 @@ fn qux() { } } -fn issue227() { - { - let handler = - box DocumentProgressHandler::new(addr, DocumentProgressTask::DOMContentLoaded); - } -} - fn issue184(source: &str) { for c in source.chars() { if index < 'a' { @@ -454,12 +446,6 @@ fn issue2704() { .concat(&requires2) .distinct_total(), ); - let requires = requires.set( - box requires0 - .concat(&requires1) - .concat(&requires2) - .distinct_total(), - ); let requires = requires.set( requires0 .concat(&requires1) From ee38de5155b1526fa0b0b3cf118376259ac9d5b7 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 27 Feb 2023 13:07:44 +0000 Subject: [PATCH 098/465] Remove uses of `box_syntax` in rustc and tools --- example/alloc_example.rs | 4 ++-- example/mini_core_hello_world.rs | 8 ++++---- example/mod_bench.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/example/alloc_example.rs b/example/alloc_example.rs index c80348ca54970..754e7931412da 100644 --- a/example/alloc_example.rs +++ b/example/alloc_example.rs @@ -1,4 +1,4 @@ -#![feature(start, box_syntax, core_intrinsics, alloc_error_handler, lang_items)] +#![feature(start, core_intrinsics, alloc_error_handler, lang_items)] #![no_std] extern crate alloc; @@ -38,7 +38,7 @@ unsafe extern "C" fn _Unwind_Resume() { #[start] fn main(_argc: isize, _argv: *const *const u8) -> isize { - let world: Box<&str> = box "Hello World!\0"; + let world: Box<&str> = Box::new("Hello World!\0"); unsafe { puts(*world as *const str as *const u8); } diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index 993a31e68eabc..cff26077740b0 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -1,7 +1,7 @@ // Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs #![feature( - no_core, unboxed_closures, start, lang_items, box_syntax, never_type, linkage, + no_core, unboxed_closures, start, lang_items, never_type, linkage, extern_types, thread_local )] #![no_core] @@ -163,7 +163,7 @@ fn main() { let ptr: *const u8 = hello as *const [u8] as *const u8; puts(ptr); - let world: Box<&str> = box "World!\0"; + let world: Box<&str> = Box::new("World!\0"); puts(*world as *const str as *const u8); world as Box; @@ -223,10 +223,10 @@ fn main() { } } - let _ = box NoisyDrop { + let _ = Box::new(NoisyDrop { text: "Boxed outer got dropped!\0", inner: NoisyDropInner, - } as Box; + }) as Box; const FUNC_REF: Option = Some(main); #[allow(unreachable_code)] diff --git a/example/mod_bench.rs b/example/mod_bench.rs index 95bcad2cd173e..5e2e7f25a2c08 100644 --- a/example/mod_bench.rs +++ b/example/mod_bench.rs @@ -1,4 +1,4 @@ -#![feature(start, box_syntax, core_intrinsics, lang_items)] +#![feature(start, core_intrinsics, lang_items)] #![no_std] #[link(name = "c")] From 4e658cc01ef5190445016ea951e21a2d0ae02a33 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 27 Feb 2023 13:17:29 +0000 Subject: [PATCH 099/465] Remove `box_syntax` from AST and use in tools --- src/closures.rs | 2 -- src/expr.rs | 5 ----- src/matches.rs | 1 - src/utils.rs | 1 - 4 files changed, 9 deletions(-) diff --git a/src/closures.rs b/src/closures.rs index 340113866c4e2..c95e9a97b43d3 100644 --- a/src/closures.rs +++ b/src/closures.rs @@ -195,7 +195,6 @@ fn rewrite_closure_expr( | ast::ExprKind::Struct(..) => true, ast::ExprKind::AddrOf(_, _, ref expr) - | ast::ExprKind::Box(ref expr) | ast::ExprKind::Try(ref expr) | ast::ExprKind::Unary(_, ref expr) | ast::ExprKind::Cast(ref expr, _) => allow_multi_line(expr), @@ -441,7 +440,6 @@ fn is_block_closure_forced_inner(expr: &ast::Expr, version: Version) -> bool { ast::ExprKind::If(..) | ast::ExprKind::While(..) | ast::ExprKind::ForLoop(..) => true, ast::ExprKind::Loop(..) if version == Version::Two => true, ast::ExprKind::AddrOf(_, _, ref expr) - | ast::ExprKind::Box(ref expr) | ast::ExprKind::Try(ref expr) | ast::ExprKind::Unary(_, ref expr) | ast::ExprKind::Cast(ref expr, _) => is_block_closure_forced_inner(expr, version), diff --git a/src/expr.rs b/src/expr.rs index 3f0f217f8907d..7273402ec760f 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -236,7 +236,6 @@ pub(crate) fn format_expr( ast::ExprKind::Yeet(Some(ref expr)) => { rewrite_unary_prefix(context, "do yeet ", &**expr, shape) } - ast::ExprKind::Box(ref expr) => rewrite_unary_prefix(context, "box ", &**expr, shape), ast::ExprKind::AddrOf(borrow_kind, mutability, ref expr) => { rewrite_expr_addrof(context, borrow_kind, mutability, expr, shape) } @@ -1299,7 +1298,6 @@ pub(crate) fn is_simple_expr(expr: &ast::Expr) -> bool { ast::ExprKind::Lit(..) => true, ast::ExprKind::Path(ref qself, ref path) => qself.is_none() && path.segments.len() <= 1, ast::ExprKind::AddrOf(_, _, ref expr) - | ast::ExprKind::Box(ref expr) | ast::ExprKind::Cast(ref expr, _) | ast::ExprKind::Field(ref expr, _) | ast::ExprKind::Try(ref expr) @@ -1361,7 +1359,6 @@ pub(crate) fn can_be_overflowed_expr( // Handle unary-like expressions ast::ExprKind::AddrOf(_, _, ref expr) - | ast::ExprKind::Box(ref expr) | ast::ExprKind::Try(ref expr) | ast::ExprKind::Unary(_, ref expr) | ast::ExprKind::Cast(ref expr, _) => can_be_overflowed_expr(context, expr, args_len), @@ -1373,7 +1370,6 @@ pub(crate) fn is_nested_call(expr: &ast::Expr) -> bool { match expr.kind { ast::ExprKind::Call(..) | ast::ExprKind::MacCall(..) => true, ast::ExprKind::AddrOf(_, _, ref expr) - | ast::ExprKind::Box(ref expr) | ast::ExprKind::Try(ref expr) | ast::ExprKind::Unary(_, ref expr) | ast::ExprKind::Cast(ref expr, _) => is_nested_call(expr), @@ -2133,7 +2129,6 @@ pub(crate) fn is_method_call(expr: &ast::Expr) -> bool { match expr.kind { ast::ExprKind::MethodCall(..) => true, ast::ExprKind::AddrOf(_, _, ref expr) - | ast::ExprKind::Box(ref expr) | ast::ExprKind::Cast(ref expr, _) | ast::ExprKind::Try(ref expr) | ast::ExprKind::Unary(_, ref expr) => is_method_call(expr), diff --git a/src/matches.rs b/src/matches.rs index 85d9c5d2b9bbf..aac5e59b8603a 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -592,7 +592,6 @@ fn can_flatten_block_around_this(body: &ast::Expr) -> bool { | ast::ExprKind::Struct(..) | ast::ExprKind::Tup(..) => true, ast::ExprKind::AddrOf(_, _, ref expr) - | ast::ExprKind::Box(ref expr) | ast::ExprKind::Try(ref expr) | ast::ExprKind::Unary(_, ref expr) | ast::ExprKind::Index(ref expr, _) diff --git a/src/utils.rs b/src/utils.rs index 1e89f3ae75f81..a26375ee64384 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -492,7 +492,6 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Assign(..) | ast::ExprKind::AssignOp(..) | ast::ExprKind::Await(..) - | ast::ExprKind::Box(..) | ast::ExprKind::Break(..) | ast::ExprKind::Cast(..) | ast::ExprKind::Continue(..) From 0c115bf8b8a6973711cb4e8b3c0f62e2551c20a5 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 16 Mar 2023 14:56:02 +0100 Subject: [PATCH 100/465] Use poison instead of undef In cases where it is legal, we should prefer poison values over undef values. This replaces undef with poison for aggregate construction and for uninhabited types. There are more places where we can likely use poison, but I wanted to stay conservative to start with. In particular the aggregate case is important for newer LLVM versions, which are not able to handle an undef base value during early optimization due to poison-propagation concerns. --- src/common.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/common.rs b/src/common.rs index 76fc7bd222e1e..ac04b61a30672 100644 --- a/src/common.rs +++ b/src/common.rs @@ -73,6 +73,11 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } } + fn const_poison(&self, typ: Type<'gcc>) -> RValue<'gcc> { + // No distinction between undef and poison. + self.const_undef(typ) + } + fn const_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> { self.gcc_int(typ, int) } From 3ef194c14cda52c36110a02d7b812371d7b99884 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Tue, 31 Jan 2023 22:13:25 +0100 Subject: [PATCH 101/465] Remove the `NodeId` of `ast::ExprKind::Async` --- src/expr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/expr.rs b/src/expr.rs index 7273402ec760f..ac96bedf2fe86 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -366,7 +366,7 @@ pub(crate) fn format_expr( )) } } - ast::ExprKind::Async(capture_by, _node_id, ref block) => { + ast::ExprKind::Async(capture_by, ref block) => { let mover = if capture_by == ast::CaptureBy::Value { "move " } else { From 809dd77b8001f69bd5202f73d016f9ac8426b69e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 19 Mar 2023 21:32:34 +0400 Subject: [PATCH 102/465] rustc: Remove unused `Session` argument from some attribute functions --- src/attr.rs | 16 +--------------- src/parse/parser.rs | 5 ++--- src/reorder.rs | 4 ++-- 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/attr.rs b/src/attr.rs index 5648e1254ed7c..22e45082a9f71 100644 --- a/src/attr.rs +++ b/src/attr.rs @@ -2,7 +2,7 @@ use rustc_ast::ast; use rustc_ast::HasAttrs; -use rustc_span::{symbol::sym, Span, Symbol}; +use rustc_span::{symbol::sym, Span}; use self::doc_comment::DocCommentFormatter; use crate::comment::{contains_comment, rewrite_doc_comment, CommentStyle}; @@ -19,20 +19,6 @@ use crate::utils::{count_newlines, mk_sp}; mod doc_comment; -pub(crate) fn contains_name(attrs: &[ast::Attribute], name: Symbol) -> bool { - attrs.iter().any(|attr| attr.has_name(name)) -} - -pub(crate) fn first_attr_value_str_by_name( - attrs: &[ast::Attribute], - name: Symbol, -) -> Option { - attrs - .iter() - .find(|attr| attr.has_name(name)) - .and_then(|attr| attr.value_str()) -} - /// Returns attributes on the given statement. pub(crate) fn get_attrs_from_stmt(stmt: &ast::Stmt) -> &[ast::Attribute] { stmt.attrs() diff --git a/src/parse/parser.rs b/src/parse/parser.rs index 7ab042506bd29..6bc53159b38ba 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -2,13 +2,12 @@ use std::panic::{catch_unwind, AssertUnwindSafe}; use std::path::{Path, PathBuf}; use rustc_ast::token::TokenKind; -use rustc_ast::{ast, ptr}; +use rustc_ast::{ast, attr, ptr}; use rustc_errors::Diagnostic; use rustc_parse::{new_parser_from_file, parser::Parser as RawParser}; use rustc_span::{sym, Span}; use thin_vec::ThinVec; -use crate::attr::first_attr_value_str_by_name; use crate::parse::session::ParseSess; use crate::Input; @@ -93,7 +92,7 @@ pub(crate) enum ParserError { impl<'a> Parser<'a> { pub(crate) fn submod_path_from_attr(attrs: &[ast::Attribute], path: &Path) -> Option { - let path_sym = first_attr_value_str_by_name(attrs, sym::path)?; + let path_sym = attr::first_attr_value_str_by_name(attrs, sym::path)?; let path_str = path_sym.as_str(); // On windows, the base path might have the form diff --git a/src/reorder.rs b/src/reorder.rs index 9e4a668aa4930..3bddf4c1b6a41 100644 --- a/src/reorder.rs +++ b/src/reorder.rs @@ -8,7 +8,7 @@ use std::cmp::{Ord, Ordering}; -use rustc_ast::ast; +use rustc_ast::{ast, attr}; use rustc_span::{symbol::sym, Span}; use crate::config::{Config, GroupImportsTactic}; @@ -167,7 +167,7 @@ fn rewrite_reorderable_or_regroupable_items( } fn contains_macro_use_attr(item: &ast::Item) -> bool { - crate::attr::contains_name(&item.attrs, sym::macro_use) + attr::contains_name(&item.attrs, sym::macro_use) } /// Divides imports into three groups, corresponding to standard, external From 77a9effd3dde6eabcda086ccd36dd1bfb5fb88ab Mon Sep 17 00:00:00 2001 From: Arpan Kapoor Date: Fri, 24 Mar 2023 13:06:20 +0530 Subject: [PATCH 103/465] Optimize bitreverse codegen --- example/mini_core_hello_world.rs | 5 + src/intrinsic/mod.rs | 159 +++++++------------------------ 2 files changed, 40 insertions(+), 124 deletions(-) diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index 993a31e68eabc..4dff341e67d02 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -168,6 +168,11 @@ fn main() { world as Box; assert_eq!(intrinsics::bitreverse(0b10101000u8), 0b00010101u8); + assert_eq!(intrinsics::bitreverse(0xddccu16), 0x33bbu16); + assert_eq!(intrinsics::bitreverse(0xffee_ddccu32), 0x33bb77ffu32); + assert_eq!(intrinsics::bitreverse(0x1234_5678_ffee_ddccu64), 0x33bb77ff1e6a2c48u64); + // != cannot be applied to type u128? + // assert_eq!(intrinsics::bitreverse(0x1234_5678_ffee_ddcc_1234_5678_ffee_ddccu128), 0x33bb77ff1e6a2c4833bb77ff1e6a2c48u128); assert_eq!(intrinsics::bswap(0xabu8), 0xabu8); assert_eq!(intrinsics::bswap(0xddccu16), 0xccddu16); diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 2590e0e3af444..6f856e481bca7 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -549,141 +549,52 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let context = &self.cx.context; let result = match width { - 8 => { - // First step. - let left = self.and(value, context.new_rvalue_from_int(typ, 0xF0)); - let left = self.lshr(left, context.new_rvalue_from_int(typ, 4)); - let right = self.and(value, context.new_rvalue_from_int(typ, 0x0F)); - let right = self.shl(right, context.new_rvalue_from_int(typ, 4)); - let step1 = self.or(left, right); - - // Second step. - let left = self.and(step1, context.new_rvalue_from_int(typ, 0xCC)); - let left = self.lshr(left, context.new_rvalue_from_int(typ, 2)); - let right = self.and(step1, context.new_rvalue_from_int(typ, 0x33)); - let right = self.shl(right, context.new_rvalue_from_int(typ, 2)); - let step2 = self.or(left, right); - - // Third step. - let left = self.and(step2, context.new_rvalue_from_int(typ, 0xAA)); - let left = self.lshr(left, context.new_rvalue_from_int(typ, 1)); - let right = self.and(step2, context.new_rvalue_from_int(typ, 0x55)); - let right = self.shl(right, context.new_rvalue_from_int(typ, 1)); - let step3 = self.or(left, right); - - step3 - }, - 16 => { - // First step. - let left = self.and(value, context.new_rvalue_from_int(typ, 0x5555)); - let left = self.shl(left, context.new_rvalue_from_int(typ, 1)); - let right = self.and(value, context.new_rvalue_from_int(typ, 0xAAAA)); - let right = self.lshr(right, context.new_rvalue_from_int(typ, 1)); - let step1 = self.or(left, right); - - // Second step. - let left = self.and(step1, context.new_rvalue_from_int(typ, 0x3333)); - let left = self.shl(left, context.new_rvalue_from_int(typ, 2)); - let right = self.and(step1, context.new_rvalue_from_int(typ, 0xCCCC)); - let right = self.lshr(right, context.new_rvalue_from_int(typ, 2)); - let step2 = self.or(left, right); - - // Third step. - let left = self.and(step2, context.new_rvalue_from_int(typ, 0x0F0F)); - let left = self.shl(left, context.new_rvalue_from_int(typ, 4)); - let right = self.and(step2, context.new_rvalue_from_int(typ, 0xF0F0)); - let right = self.lshr(right, context.new_rvalue_from_int(typ, 4)); - let step3 = self.or(left, right); - - // Fourth step. - let left = self.and(step3, context.new_rvalue_from_int(typ, 0x00FF)); - let left = self.shl(left, context.new_rvalue_from_int(typ, 8)); - let right = self.and(step3, context.new_rvalue_from_int(typ, 0xFF00)); - let right = self.lshr(right, context.new_rvalue_from_int(typ, 8)); - let step4 = self.or(left, right); + 8 | 16 | 32 | 64 => { + let mask = ((1u128 << width) - 1) as u64; + let (m0, m1, m2) = if width > 16 { + ( + context.new_rvalue_from_long(typ, (0x5555555555555555u64 & mask) as i64), + context.new_rvalue_from_long(typ, (0x3333333333333333u64 & mask) as i64), + context.new_rvalue_from_long(typ, (0x0f0f0f0f0f0f0f0fu64 & mask) as i64), + ) + } else { + ( + context.new_rvalue_from_int(typ, (0x5555u64 & mask) as i32), + context.new_rvalue_from_int(typ, (0x3333u64 & mask) as i32), + context.new_rvalue_from_int(typ, (0x0f0fu64 & mask) as i32), + ) + }; + let one = context.new_rvalue_from_int(typ, 1); + let two = context.new_rvalue_from_int(typ, 2); + let four = context.new_rvalue_from_int(typ, 4); - step4 - }, - 32 => { - // TODO(antoyo): Refactor with other implementations. // First step. - let left = self.and(value, context.new_rvalue_from_long(typ, 0x55555555)); - let left = self.shl(left, context.new_rvalue_from_long(typ, 1)); - let right = self.and(value, context.new_rvalue_from_long(typ, 0xAAAAAAAA)); - let right = self.lshr(right, context.new_rvalue_from_long(typ, 1)); + let left = self.lshr(value, one); + let left = self.and(left, m0); + let right = self.and(value, m0); + let right = self.shl(right, one); let step1 = self.or(left, right); // Second step. - let left = self.and(step1, context.new_rvalue_from_long(typ, 0x33333333)); - let left = self.shl(left, context.new_rvalue_from_long(typ, 2)); - let right = self.and(step1, context.new_rvalue_from_long(typ, 0xCCCCCCCC)); - let right = self.lshr(right, context.new_rvalue_from_long(typ, 2)); + let left = self.lshr(step1, two); + let left = self.and(left, m1); + let right = self.and(step1, m1); + let right = self.shl(right, two); let step2 = self.or(left, right); // Third step. - let left = self.and(step2, context.new_rvalue_from_long(typ, 0x0F0F0F0F)); - let left = self.shl(left, context.new_rvalue_from_long(typ, 4)); - let right = self.and(step2, context.new_rvalue_from_long(typ, 0xF0F0F0F0)); - let right = self.lshr(right, context.new_rvalue_from_long(typ, 4)); + let left = self.lshr(step2, four); + let left = self.and(left, m2); + let right = self.and(step2, m2); + let right = self.shl(right, four); let step3 = self.or(left, right); // Fourth step. - let left = self.and(step3, context.new_rvalue_from_long(typ, 0x00FF00FF)); - let left = self.shl(left, context.new_rvalue_from_long(typ, 8)); - let right = self.and(step3, context.new_rvalue_from_long(typ, 0xFF00FF00)); - let right = self.lshr(right, context.new_rvalue_from_long(typ, 8)); - let step4 = self.or(left, right); - - // Fifth step. - let left = self.and(step4, context.new_rvalue_from_long(typ, 0x0000FFFF)); - let left = self.shl(left, context.new_rvalue_from_long(typ, 16)); - let right = self.and(step4, context.new_rvalue_from_long(typ, 0xFFFF0000)); - let right = self.lshr(right, context.new_rvalue_from_long(typ, 16)); - let step5 = self.or(left, right); - - step5 - }, - 64 => { - // First step. - let left = self.shl(value, context.new_rvalue_from_long(typ, 32)); - let right = self.lshr(value, context.new_rvalue_from_long(typ, 32)); - let step1 = self.or(left, right); - - // Second step. - let left = self.and(step1, context.new_rvalue_from_long(typ, 0x0001FFFF0001FFFF)); - let left = self.shl(left, context.new_rvalue_from_long(typ, 15)); - let right = self.and(step1, context.new_rvalue_from_long(typ, 0xFFFE0000FFFE0000u64 as i64)); // TODO(antoyo): transmute the number instead? - let right = self.lshr(right, context.new_rvalue_from_long(typ, 17)); - let step2 = self.or(left, right); - - // Third step. - let left = self.lshr(step2, context.new_rvalue_from_long(typ, 10)); - let left = self.xor(step2, left); - let temp = self.and(left, context.new_rvalue_from_long(typ, 0x003F801F003F801F)); - - let left = self.shl(temp, context.new_rvalue_from_long(typ, 10)); - let left = self.or(temp, left); - let step3 = self.xor(left, step2); - - // Fourth step. - let left = self.lshr(step3, context.new_rvalue_from_long(typ, 4)); - let left = self.xor(step3, left); - let temp = self.and(left, context.new_rvalue_from_long(typ, 0x0E0384210E038421)); - - let left = self.shl(temp, context.new_rvalue_from_long(typ, 4)); - let left = self.or(temp, left); - let step4 = self.xor(left, step3); - - // Fifth step. - let left = self.lshr(step4, context.new_rvalue_from_long(typ, 2)); - let left = self.xor(step4, left); - let temp = self.and(left, context.new_rvalue_from_long(typ, 0x2248884222488842)); - - let left = self.shl(temp, context.new_rvalue_from_long(typ, 2)); - let left = self.or(temp, left); - let step5 = self.xor(left, step4); - - step5 + if width == 8 { + step3 + } else { + self.gcc_bswap(step3, width) + } }, 128 => { // TODO(antoyo): find a more efficient implementation? From 6e1a79c6a4630d1cd0bd143919ffac3c598f0e3d Mon Sep 17 00:00:00 2001 From: Arpan Kapoor Date: Sun, 26 Mar 2023 13:19:57 +0530 Subject: [PATCH 104/465] Add u128 PartialEq impl in mini_core.rs --- example/mini_core.rs | 11 +++++++++++ example/mini_core_hello_world.rs | 3 +-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/example/mini_core.rs b/example/mini_core.rs index 637b8dc53fefd..018bbaf025da4 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -59,6 +59,7 @@ unsafe impl Copy for u8 {} unsafe impl Copy for u16 {} unsafe impl Copy for u32 {} unsafe impl Copy for u64 {} +unsafe impl Copy for u128 {} unsafe impl Copy for usize {} unsafe impl Copy for i8 {} unsafe impl Copy for i16 {} @@ -79,6 +80,7 @@ unsafe impl Sync for u8 {} unsafe impl Sync for u16 {} unsafe impl Sync for u32 {} unsafe impl Sync for u64 {} +unsafe impl Sync for u128 {} unsafe impl Sync for usize {} unsafe impl Sync for i8 {} unsafe impl Sync for i16 {} @@ -294,6 +296,15 @@ impl PartialEq for u64 { } } +impl PartialEq for u128 { + fn eq(&self, other: &u128) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &u128) -> bool { + (*self) != (*other) + } +} + impl PartialEq for usize { fn eq(&self, other: &usize) -> bool { (*self) == (*other) diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index 4dff341e67d02..ad244814208fa 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -171,8 +171,7 @@ fn main() { assert_eq!(intrinsics::bitreverse(0xddccu16), 0x33bbu16); assert_eq!(intrinsics::bitreverse(0xffee_ddccu32), 0x33bb77ffu32); assert_eq!(intrinsics::bitreverse(0x1234_5678_ffee_ddccu64), 0x33bb77ff1e6a2c48u64); - // != cannot be applied to type u128? - // assert_eq!(intrinsics::bitreverse(0x1234_5678_ffee_ddcc_1234_5678_ffee_ddccu128), 0x33bb77ff1e6a2c4833bb77ff1e6a2c48u128); + assert_eq!(intrinsics::bitreverse(0x1234_5678_ffee_ddcc_1234_5678_ffee_ddccu128), 0x33bb77ff1e6a2c4833bb77ff1e6a2c48u128); assert_eq!(intrinsics::bswap(0xabu8), 0xabu8); assert_eq!(intrinsics::bswap(0xddccu16), 0xccddu16); From 68b8500235fe2641afa6a36f1786a9d5d5105065 Mon Sep 17 00:00:00 2001 From: Arpan Kapoor Date: Mon, 27 Mar 2023 20:33:05 +0530 Subject: [PATCH 105/465] move u128 test to std_example --- example/mini_core.rs | 11 ----------- example/mini_core_hello_world.rs | 1 - example/std_example.rs | 1 + 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/example/mini_core.rs b/example/mini_core.rs index 018bbaf025da4..637b8dc53fefd 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -59,7 +59,6 @@ unsafe impl Copy for u8 {} unsafe impl Copy for u16 {} unsafe impl Copy for u32 {} unsafe impl Copy for u64 {} -unsafe impl Copy for u128 {} unsafe impl Copy for usize {} unsafe impl Copy for i8 {} unsafe impl Copy for i16 {} @@ -80,7 +79,6 @@ unsafe impl Sync for u8 {} unsafe impl Sync for u16 {} unsafe impl Sync for u32 {} unsafe impl Sync for u64 {} -unsafe impl Sync for u128 {} unsafe impl Sync for usize {} unsafe impl Sync for i8 {} unsafe impl Sync for i16 {} @@ -296,15 +294,6 @@ impl PartialEq for u64 { } } -impl PartialEq for u128 { - fn eq(&self, other: &u128) -> bool { - (*self) == (*other) - } - fn ne(&self, other: &u128) -> bool { - (*self) != (*other) - } -} - impl PartialEq for usize { fn eq(&self, other: &usize) -> bool { (*self) == (*other) diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index ad244814208fa..1c8ca6b9d7c85 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -171,7 +171,6 @@ fn main() { assert_eq!(intrinsics::bitreverse(0xddccu16), 0x33bbu16); assert_eq!(intrinsics::bitreverse(0xffee_ddccu32), 0x33bb77ffu32); assert_eq!(intrinsics::bitreverse(0x1234_5678_ffee_ddccu64), 0x33bb77ff1e6a2c48u64); - assert_eq!(intrinsics::bitreverse(0x1234_5678_ffee_ddcc_1234_5678_ffee_ddccu128), 0x33bb77ff1e6a2c4833bb77ff1e6a2c48u128); assert_eq!(intrinsics::bswap(0xabu8), 0xabu8); assert_eq!(intrinsics::bswap(0xddccu16), 0xccddu16); diff --git a/example/std_example.rs b/example/std_example.rs index 5c171c49fd194..18f2ddcde126b 100644 --- a/example/std_example.rs +++ b/example/std_example.rs @@ -58,6 +58,7 @@ fn main() { assert_eq!(0b0000000000000000000000000010000010000000000000000000000000000000_0000000000100000000000000000000000001000000000000100000000000000u128.leading_zeros(), 26); assert_eq!(0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128.trailing_zeros(), 7); + assert_eq!(0x1234_5678_ffee_ddcc_1234_5678_ffee_ddccu128.reverse_bits(), 0x33bb77ff1e6a2c4833bb77ff1e6a2c48u128); let _d = 0i128.checked_div(2i128); let _d = 0u128.checked_div(2u128); From 2bfd89d91b11bba295ad727f27d417eb40616968 Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Thu, 30 Mar 2023 18:30:56 +0200 Subject: [PATCH 106/465] Update gccjit and remove libc 0.1 dependency --- Cargo.lock | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 80e5741894088..0f2e152f8ce56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,7 +35,7 @@ dependencies = [ [[package]] name = "gccjit" version = "1.0.0" -source = "git+https://github.com/antoyo/gccjit.rs#eefb8c662d61477f34b7c32d26bcda5f1ef08432" +source = "git+https://github.com/antoyo/gccjit.rs#fe242b7eb26980e6c78859d51c8d4cc1e43381a3" dependencies = [ "gccjit_sys", ] @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "gccjit_sys" version = "0.0.1" -source = "git+https://github.com/antoyo/gccjit.rs#eefb8c662d61477f34b7c32d26bcda5f1ef08432" +source = "git+https://github.com/antoyo/gccjit.rs#fe242b7eb26980e6c78859d51c8d4cc1e43381a3" dependencies = [ - "libc 0.1.12", + "libc", ] [[package]] @@ -64,7 +64,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if", - "libc 0.2.112", + "libc", "wasi", ] @@ -74,7 +74,7 @@ version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ - "libc 0.2.112", + "libc", ] [[package]] @@ -85,7 +85,7 @@ checksum = "96bd995a092cac79868250589869b5a5d656b02a02bd74c8ebdc566dc7203090" dependencies = [ "fm", "getopts", - "libc 0.2.112", + "libc", "num_cpus", "termcolor", "threadpool", @@ -93,12 +93,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "libc" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122" - [[package]] name = "libc" version = "0.2.112" @@ -118,7 +112,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" dependencies = [ "hermit-abi", - "libc 0.2.112", + "libc", ] [[package]] @@ -133,7 +127,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ - "libc 0.2.112", + "libc", "rand_chacha", "rand_core", "rand_hc", @@ -234,7 +228,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if", - "libc 0.2.112", + "libc", "rand", "redox_syscall", "remove_dir_all", @@ -271,7 +265,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" dependencies = [ - "libc 0.2.112", + "libc", ] [[package]] From 475396a03c767a4a3a7e7d3be62f91751c2ba85e Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Thu, 30 Mar 2023 13:00:18 -0400 Subject: [PATCH 107/465] Prevent ICE when calling parse_attribute in parse_cfg_if_inner Fixes 5728 Previously we were ignoring the diagnostic error, which lead to the ICE. Now we properly cancel the error. --- src/parse/macros/cfg_if.rs | 5 ++++- tests/rustfmt/main.rs | 12 ++++++++++++ tests/target/issue_5728.rs | 5 +++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 tests/target/issue_5728.rs diff --git a/src/parse/macros/cfg_if.rs b/src/parse/macros/cfg_if.rs index ace1a76b3fe7d..ac03409a7844b 100644 --- a/src/parse/macros/cfg_if.rs +++ b/src/parse/macros/cfg_if.rs @@ -44,7 +44,10 @@ fn parse_cfg_if_inner<'a>( // See also https://github.com/rust-lang/rust/pull/79433 parser .parse_attribute(rustc_parse::parser::attr::InnerAttrPolicy::Permitted) - .map_err(|_| "Failed to parse attributes")?; + .map_err(|e| { + e.cancel(); + "Failed to parse attributes" + })?; } if !parser.eat(&TokenKind::OpenDelim(Delimiter::Brace)) { diff --git a/tests/rustfmt/main.rs b/tests/rustfmt/main.rs index 7ff301e80195a..f00b0e09604fe 100644 --- a/tests/rustfmt/main.rs +++ b/tests/rustfmt/main.rs @@ -174,3 +174,15 @@ fn rustfmt_emits_error_on_line_overflow_true() { "line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option)" )) } + +#[test] +#[allow(non_snake_case)] +fn dont_emit_ICE() { + let files = ["tests/target/issue_5728.rs"]; + + for file in files { + let args = [file]; + let (_stdout, stderr) = rustfmt(&args); + assert!(!stderr.contains("thread 'main' panicked")); + } +} diff --git a/tests/target/issue_5728.rs b/tests/target/issue_5728.rs new file mode 100644 index 0000000000000..e1355416faf43 --- /dev/null +++ b/tests/target/issue_5728.rs @@ -0,0 +1,5 @@ +cfg_if::cfg_if! { + if #[cfg(windows)] { + } else if #(&cpus) { + } else [libc::CTL_HW, libc::HW_NCPU, 0, 0] +} From a3b2bfc2db33ec3bed266404e6391c145e000df0 Mon Sep 17 00:00:00 2001 From: Greg Jandl Date: Mon, 27 Mar 2023 12:02:02 -0500 Subject: [PATCH 108/465] Honor --color option when emitting errors Fixes issue 5717. --- src/parse/session.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/parse/session.rs b/src/parse/session.rs index 6bfec79cd7030..1956e1b8cd74f 100644 --- a/src/parse/session.rs +++ b/src/parse/session.rs @@ -12,6 +12,7 @@ use rustc_span::{ }; use crate::config::file_lines::LineRange; +use crate::config::options::Color; use crate::ignore_path::IgnorePathSet; use crate::parse::parser::{ModError, ModulePathSuccess}; use crate::source_map::LineRangeUtils; @@ -107,15 +108,26 @@ impl Emitter for SilentOnIgnoredFilesEmitter { } } +impl From for ColorConfig { + fn from(color: Color) -> Self { + match color { + Color::Auto => ColorConfig::Auto, + Color::Always => ColorConfig::Always, + Color::Never => ColorConfig::Never, + } + } +} + fn default_handler( source_map: Lrc, ignore_path_set: Lrc, can_reset: Lrc, hide_parse_errors: bool, + color: Color, ) -> Handler { let supports_color = term::stderr().map_or(false, |term| term.supports_color()); - let color_cfg = if supports_color { - ColorConfig::Auto + let emit_color = if supports_color { + ColorConfig::from(color) } else { ColorConfig::Never }; @@ -126,7 +138,7 @@ fn default_handler( let fallback_bundle = rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false); Box::new(EmitterWriter::stderr( - color_cfg, + emit_color, Some(source_map.clone()), None, fallback_bundle, @@ -164,6 +176,7 @@ impl ParseSess { Lrc::clone(&ignore_path_set), Lrc::clone(&can_reset_errors), config.hide_parse_errors(), + config.color(), ); let parse_sess = RawParseSess::with_span_handler(handler, source_map); From c2890ec2d7f1cd7d8af262ffe9177094756f84b0 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 29 Mar 2023 08:37:47 +0000 Subject: [PATCH 109/465] rust-analyzer guided enum variant structification --- src/items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/items.rs b/src/items.rs index 25e8a024857ce..520bb5278001f 100644 --- a/src/items.rs +++ b/src/items.rs @@ -1805,7 +1805,7 @@ pub(crate) struct StaticParts<'a> { impl<'a> StaticParts<'a> { pub(crate) fn from_item(item: &'a ast::Item) -> Self { let (defaultness, prefix, ty, mutability, expr) = match item.kind { - ast::ItemKind::Static(ref ty, mutability, ref expr) => { + ast::ItemKind::Static(ast::Static(ref ty, mutability, ref expr)) => { (None, "static", ty, mutability, expr) } ast::ItemKind::Const(defaultness, ref ty, ref expr) => { From ced3cd8d40b7dcb5756c246309598e309b4fdbcd Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 29 Mar 2023 08:50:04 +0000 Subject: [PATCH 110/465] rust-analyzer guided tuple field to named field --- src/items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/items.rs b/src/items.rs index 520bb5278001f..6cbe68ae39848 100644 --- a/src/items.rs +++ b/src/items.rs @@ -1805,7 +1805,7 @@ pub(crate) struct StaticParts<'a> { impl<'a> StaticParts<'a> { pub(crate) fn from_item(item: &'a ast::Item) -> Self { let (defaultness, prefix, ty, mutability, expr) = match item.kind { - ast::ItemKind::Static(ast::Static(ref ty, mutability, ref expr)) => { + ast::ItemKind::Static(ast::Static { ref ty, mutability, ref expr}) => { (None, "static", ty, mutability, expr) } ast::ItemKind::Const(defaultness, ref ty, ref expr) => { From 3ecb9ed53c3cc50f5e7ec6d03b2998bf69adea11 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 29 Mar 2023 09:20:45 +0000 Subject: [PATCH 111/465] Split out ast::ItemKind::Const into its own struct --- src/items.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/items.rs b/src/items.rs index 6cbe68ae39848..0dc8a4e937f2a 100644 --- a/src/items.rs +++ b/src/items.rs @@ -1808,7 +1808,7 @@ impl<'a> StaticParts<'a> { ast::ItemKind::Static(ast::Static { ref ty, mutability, ref expr}) => { (None, "static", ty, mutability, expr) } - ast::ItemKind::Const(defaultness, ref ty, ref expr) => { + ast::ItemKind::Const(ast::ConstItem { defaultness, ref ty, ref expr}) => { (Some(defaultness), "const", ty, ast::Mutability::Not, expr) } _ => unreachable!(), @@ -1827,8 +1827,8 @@ impl<'a> StaticParts<'a> { pub(crate) fn from_trait_item(ti: &'a ast::AssocItem) -> Self { let (defaultness, ty, expr_opt) = match ti.kind { - ast::AssocItemKind::Const(defaultness, ref ty, ref expr_opt) => { - (defaultness, ty, expr_opt) + ast::AssocItemKind::Const(ast::ConstItem {defaultness, ref ty, ref expr}) => { + (defaultness, ty, expr) } _ => unreachable!(), }; @@ -1846,7 +1846,7 @@ impl<'a> StaticParts<'a> { pub(crate) fn from_impl_item(ii: &'a ast::AssocItem) -> Self { let (defaultness, ty, expr) = match ii.kind { - ast::AssocItemKind::Const(defaultness, ref ty, ref expr) => (defaultness, ty, expr), + ast::AssocItemKind::Const(ast::ConstItem { defaultness, ref ty, ref expr}) => (defaultness, ty, expr), _ => unreachable!(), }; StaticParts { From f1781396bf125b46b679d3bf9499c0b9278607f9 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 29 Mar 2023 12:34:05 +0000 Subject: [PATCH 112/465] box a bunch of large types --- src/items.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/items.rs b/src/items.rs index 0dc8a4e937f2a..43779cfaecd3a 100644 --- a/src/items.rs +++ b/src/items.rs @@ -1804,13 +1804,15 @@ pub(crate) struct StaticParts<'a> { impl<'a> StaticParts<'a> { pub(crate) fn from_item(item: &'a ast::Item) -> Self { - let (defaultness, prefix, ty, mutability, expr) = match item.kind { - ast::ItemKind::Static(ast::Static { ref ty, mutability, ref expr}) => { - (None, "static", ty, mutability, expr) - } - ast::ItemKind::Const(ast::ConstItem { defaultness, ref ty, ref expr}) => { - (Some(defaultness), "const", ty, ast::Mutability::Not, expr) - } + let (defaultness, prefix, ty, mutability, expr) = match &item.kind { + ast::ItemKind::Static(s) => (None, "static", &s.ty, s.mutability, &s.expr), + ast::ItemKind::Const(c) => ( + Some(c.defaultness), + "const", + &c.ty, + ast::Mutability::Not, + &c.expr, + ), _ => unreachable!(), }; StaticParts { @@ -1826,10 +1828,8 @@ impl<'a> StaticParts<'a> { } pub(crate) fn from_trait_item(ti: &'a ast::AssocItem) -> Self { - let (defaultness, ty, expr_opt) = match ti.kind { - ast::AssocItemKind::Const(ast::ConstItem {defaultness, ref ty, ref expr}) => { - (defaultness, ty, expr) - } + let (defaultness, ty, expr_opt) = match &ti.kind { + ast::AssocItemKind::Const(c) => (c.defaultness, &c.ty, &c.expr), _ => unreachable!(), }; StaticParts { @@ -1845,8 +1845,8 @@ impl<'a> StaticParts<'a> { } pub(crate) fn from_impl_item(ii: &'a ast::AssocItem) -> Self { - let (defaultness, ty, expr) = match ii.kind { - ast::AssocItemKind::Const(ast::ConstItem { defaultness, ref ty, ref expr}) => (defaultness, ty, expr), + let (defaultness, ty, expr) = match &ii.kind { + ast::AssocItemKind::Const(c) => (c.defaultness, &c.ty, &c.expr), _ => unreachable!(), }; StaticParts { From 7e2e5054a6dd0a4d40b6e28309919287ff48efbd Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 5 Apr 2023 16:30:21 +0200 Subject: [PATCH 113/465] Update gccjit dependency version --- Cargo.lock | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac0fc0eeb7e94..6e94c03a15404 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,7 +35,7 @@ dependencies = [ [[package]] name = "gccjit" version = "1.0.0" -source = "git+https://github.com/antoyo/gccjit.rs#eefb8c662d61477f34b7c32d26bcda5f1ef08432" +source = "git+https://github.com/antoyo/gccjit.rs#98a29ddd64f662beb5d11810434fbeaad4a1856c" dependencies = [ "gccjit_sys", ] @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "gccjit_sys" version = "0.0.1" -source = "git+https://github.com/antoyo/gccjit.rs#eefb8c662d61477f34b7c32d26bcda5f1ef08432" +source = "git+https://github.com/antoyo/gccjit.rs#98a29ddd64f662beb5d11810434fbeaad4a1856c" dependencies = [ - "libc 0.1.12", + "libc", ] [[package]] @@ -64,7 +64,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if", - "libc 0.2.112", + "libc", "wasi", ] @@ -74,7 +74,7 @@ version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ - "libc 0.2.112", + "libc", ] [[package]] @@ -85,7 +85,7 @@ checksum = "96bd995a092cac79868250589869b5a5d656b02a02bd74c8ebdc566dc7203090" dependencies = [ "fm", "getopts", - "libc 0.2.112", + "libc", "num_cpus", "termcolor", "threadpool", @@ -93,12 +93,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "libc" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122" - [[package]] name = "libc" version = "0.2.112" @@ -118,7 +112,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" dependencies = [ "hermit-abi", - "libc 0.2.112", + "libc", ] [[package]] @@ -133,7 +127,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ - "libc 0.2.112", + "libc", "rand_chacha", "rand_core", "rand_hc", @@ -234,7 +228,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if", - "libc 0.2.112", + "libc", "rand", "redox_syscall", "remove_dir_all", @@ -271,7 +265,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" dependencies = [ - "libc 0.2.112", + "libc", ] [[package]] From b769ad26b08f65e9d741d8b720b9bfb8038a2808 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 5 Apr 2023 16:20:20 +0200 Subject: [PATCH 114/465] Add `llvm` folder to .gitignore file --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 12ed56675639c..c5ed7de200c24 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,5 @@ benchmarks tools/llvm-project tools/llvmint tools/llvmint-2 +# The `llvm` folder is generated by the `tools/generate_intrinsics.py` script to update intrinsics. +llvm From 98482ad1e4b690f349509460f2e05333a05822b1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 5 Apr 2023 16:17:45 +0200 Subject: [PATCH 115/465] Regen intrinsics --- src/intrinsic/archs.rs | 50 ++++-------------------------------------- 1 file changed, 4 insertions(+), 46 deletions(-) diff --git a/src/intrinsic/archs.rs b/src/intrinsic/archs.rs index 8a4559355ea67..8cd8d1bfb429f 100644 --- a/src/intrinsic/archs.rs +++ b/src/intrinsic/archs.rs @@ -3020,8 +3020,6 @@ match name { "llvm.nvvm.div.rz.ftz.f" => "__nvvm_div_rz_ftz_f", "llvm.nvvm.ex2.approx.d" => "__nvvm_ex2_approx_d", "llvm.nvvm.ex2.approx.f" => "__nvvm_ex2_approx_f", - "llvm.nvvm.ex2.approx.f16" => "__nvvm_ex2_approx_f16", - "llvm.nvvm.ex2.approx.f16x2" => "__nvvm_ex2_approx_f16x2", "llvm.nvvm.ex2.approx.ftz.f" => "__nvvm_ex2_approx_ftz_f", "llvm.nvvm.f2bf16.rn" => "__nvvm_f2bf16_rn", "llvm.nvvm.f2bf16.rn.relu" => "__nvvm_f2bf16_rn_relu", @@ -3083,21 +3081,9 @@ match name { "llvm.nvvm.fma.rn.bf16x2" => "__nvvm_fma_rn_bf16x2", "llvm.nvvm.fma.rn.d" => "__nvvm_fma_rn_d", "llvm.nvvm.fma.rn.f" => "__nvvm_fma_rn_f", - "llvm.nvvm.fma.rn.f16" => "__nvvm_fma_rn_f16", - "llvm.nvvm.fma.rn.f16x2" => "__nvvm_fma_rn_f16x2", "llvm.nvvm.fma.rn.ftz.f" => "__nvvm_fma_rn_ftz_f", - "llvm.nvvm.fma.rn.ftz.f16" => "__nvvm_fma_rn_ftz_f16", - "llvm.nvvm.fma.rn.ftz.f16x2" => "__nvvm_fma_rn_ftz_f16x2", - "llvm.nvvm.fma.rn.ftz.relu.f16" => "__nvvm_fma_rn_ftz_relu_f16", - "llvm.nvvm.fma.rn.ftz.relu.f16x2" => "__nvvm_fma_rn_ftz_relu_f16x2", - "llvm.nvvm.fma.rn.ftz.sat.f16" => "__nvvm_fma_rn_ftz_sat_f16", - "llvm.nvvm.fma.rn.ftz.sat.f16x2" => "__nvvm_fma_rn_ftz_sat_f16x2", "llvm.nvvm.fma.rn.relu.bf16" => "__nvvm_fma_rn_relu_bf16", "llvm.nvvm.fma.rn.relu.bf16x2" => "__nvvm_fma_rn_relu_bf16x2", - "llvm.nvvm.fma.rn.relu.f16" => "__nvvm_fma_rn_relu_f16", - "llvm.nvvm.fma.rn.relu.f16x2" => "__nvvm_fma_rn_relu_f16x2", - "llvm.nvvm.fma.rn.sat.f16" => "__nvvm_fma_rn_sat_f16", - "llvm.nvvm.fma.rn.sat.f16x2" => "__nvvm_fma_rn_sat_f16x2", "llvm.nvvm.fma.rp.d" => "__nvvm_fma_rp_d", "llvm.nvvm.fma.rp.f" => "__nvvm_fma_rp_f", "llvm.nvvm.fma.rp.ftz.f" => "__nvvm_fma_rp_ftz_f", @@ -3108,68 +3094,36 @@ match name { "llvm.nvvm.fmax.bf16x2" => "__nvvm_fmax_bf16x2", "llvm.nvvm.fmax.d" => "__nvvm_fmax_d", "llvm.nvvm.fmax.f" => "__nvvm_fmax_f", - "llvm.nvvm.fmax.f16" => "__nvvm_fmax_f16", - "llvm.nvvm.fmax.f16x2" => "__nvvm_fmax_f16x2", "llvm.nvvm.fmax.ftz.f" => "__nvvm_fmax_ftz_f", - "llvm.nvvm.fmax.ftz.f16" => "__nvvm_fmax_ftz_f16", - "llvm.nvvm.fmax.ftz.f16x2" => "__nvvm_fmax_ftz_f16x2", "llvm.nvvm.fmax.ftz.nan.f" => "__nvvm_fmax_ftz_nan_f", - "llvm.nvvm.fmax.ftz.nan.f16" => "__nvvm_fmax_ftz_nan_f16", - "llvm.nvvm.fmax.ftz.nan.f16x2" => "__nvvm_fmax_ftz_nan_f16x2", "llvm.nvvm.fmax.ftz.nan.xorsign.abs.f" => "__nvvm_fmax_ftz_nan_xorsign_abs_f", - "llvm.nvvm.fmax.ftz.nan.xorsign.abs.f16" => "__nvvm_fmax_ftz_nan_xorsign_abs_f16", - "llvm.nvvm.fmax.ftz.nan.xorsign.abs.f16x2" => "__nvvm_fmax_ftz_nan_xorsign_abs_f16x2", "llvm.nvvm.fmax.ftz.xorsign.abs.f" => "__nvvm_fmax_ftz_xorsign_abs_f", - "llvm.nvvm.fmax.ftz.xorsign.abs.f16" => "__nvvm_fmax_ftz_xorsign_abs_f16", - "llvm.nvvm.fmax.ftz.xorsign.abs.f16x2" => "__nvvm_fmax_ftz_xorsign_abs_f16x2", "llvm.nvvm.fmax.nan.bf16" => "__nvvm_fmax_nan_bf16", "llvm.nvvm.fmax.nan.bf16x2" => "__nvvm_fmax_nan_bf16x2", "llvm.nvvm.fmax.nan.f" => "__nvvm_fmax_nan_f", - "llvm.nvvm.fmax.nan.f16" => "__nvvm_fmax_nan_f16", - "llvm.nvvm.fmax.nan.f16x2" => "__nvvm_fmax_nan_f16x2", "llvm.nvvm.fmax.nan.xorsign.abs.bf16" => "__nvvm_fmax_nan_xorsign_abs_bf16", "llvm.nvvm.fmax.nan.xorsign.abs.bf16x2" => "__nvvm_fmax_nan_xorsign_abs_bf16x2", "llvm.nvvm.fmax.nan.xorsign.abs.f" => "__nvvm_fmax_nan_xorsign_abs_f", - "llvm.nvvm.fmax.nan.xorsign.abs.f16" => "__nvvm_fmax_nan_xorsign_abs_f16", - "llvm.nvvm.fmax.nan.xorsign.abs.f16x2" => "__nvvm_fmax_nan_xorsign_abs_f16x2", "llvm.nvvm.fmax.xorsign.abs.bf16" => "__nvvm_fmax_xorsign_abs_bf16", "llvm.nvvm.fmax.xorsign.abs.bf16x2" => "__nvvm_fmax_xorsign_abs_bf16x2", "llvm.nvvm.fmax.xorsign.abs.f" => "__nvvm_fmax_xorsign_abs_f", - "llvm.nvvm.fmax.xorsign.abs.f16" => "__nvvm_fmax_xorsign_abs_f16", - "llvm.nvvm.fmax.xorsign.abs.f16x2" => "__nvvm_fmax_xorsign_abs_f16x2", "llvm.nvvm.fmin.bf16" => "__nvvm_fmin_bf16", "llvm.nvvm.fmin.bf16x2" => "__nvvm_fmin_bf16x2", "llvm.nvvm.fmin.d" => "__nvvm_fmin_d", "llvm.nvvm.fmin.f" => "__nvvm_fmin_f", - "llvm.nvvm.fmin.f16" => "__nvvm_fmin_f16", - "llvm.nvvm.fmin.f16x2" => "__nvvm_fmin_f16x2", "llvm.nvvm.fmin.ftz.f" => "__nvvm_fmin_ftz_f", - "llvm.nvvm.fmin.ftz.f16" => "__nvvm_fmin_ftz_f16", - "llvm.nvvm.fmin.ftz.f16x2" => "__nvvm_fmin_ftz_f16x2", "llvm.nvvm.fmin.ftz.nan.f" => "__nvvm_fmin_ftz_nan_f", - "llvm.nvvm.fmin.ftz.nan.f16" => "__nvvm_fmin_ftz_nan_f16", - "llvm.nvvm.fmin.ftz.nan.f16x2" => "__nvvm_fmin_ftz_nan_f16x2", "llvm.nvvm.fmin.ftz.nan.xorsign.abs.f" => "__nvvm_fmin_ftz_nan_xorsign_abs_f", - "llvm.nvvm.fmin.ftz.nan.xorsign.abs.f16" => "__nvvm_fmin_ftz_nan_xorsign_abs_f16", - "llvm.nvvm.fmin.ftz.nan.xorsign.abs.f16x2" => "__nvvm_fmin_ftz_nan_xorsign_abs_f16x2", "llvm.nvvm.fmin.ftz.xorsign.abs.f" => "__nvvm_fmin_ftz_xorsign_abs_f", - "llvm.nvvm.fmin.ftz.xorsign.abs.f16" => "__nvvm_fmin_ftz_xorsign_abs_f16", - "llvm.nvvm.fmin.ftz.xorsign.abs.f16x2" => "__nvvm_fmin_ftz_xorsign_abs_f16x2", "llvm.nvvm.fmin.nan.bf16" => "__nvvm_fmin_nan_bf16", "llvm.nvvm.fmin.nan.bf16x2" => "__nvvm_fmin_nan_bf16x2", "llvm.nvvm.fmin.nan.f" => "__nvvm_fmin_nan_f", - "llvm.nvvm.fmin.nan.f16" => "__nvvm_fmin_nan_f16", - "llvm.nvvm.fmin.nan.f16x2" => "__nvvm_fmin_nan_f16x2", "llvm.nvvm.fmin.nan.xorsign.abs.bf16" => "__nvvm_fmin_nan_xorsign_abs_bf16", "llvm.nvvm.fmin.nan.xorsign.abs.bf16x2" => "__nvvm_fmin_nan_xorsign_abs_bf16x2", "llvm.nvvm.fmin.nan.xorsign.abs.f" => "__nvvm_fmin_nan_xorsign_abs_f", - "llvm.nvvm.fmin.nan.xorsign.abs.f16" => "__nvvm_fmin_nan_xorsign_abs_f16", - "llvm.nvvm.fmin.nan.xorsign.abs.f16x2" => "__nvvm_fmin_nan_xorsign_abs_f16x2", "llvm.nvvm.fmin.xorsign.abs.bf16" => "__nvvm_fmin_xorsign_abs_bf16", "llvm.nvvm.fmin.xorsign.abs.bf16x2" => "__nvvm_fmin_xorsign_abs_bf16x2", "llvm.nvvm.fmin.xorsign.abs.f" => "__nvvm_fmin_xorsign_abs_f", - "llvm.nvvm.fmin.xorsign.abs.f16" => "__nvvm_fmin_xorsign_abs_f16", - "llvm.nvvm.fmin.xorsign.abs.f16x2" => "__nvvm_fmin_xorsign_abs_f16x2", "llvm.nvvm.fns" => "__nvvm_fns", "llvm.nvvm.h2f" => "__nvvm_h2f", "llvm.nvvm.i2d.rm" => "__nvvm_i2d_rm", @@ -7895,6 +7849,10 @@ match name { "llvm.x86.subborrow.u64" => "__builtin_ia32_subborrow_u64", "llvm.x86.tbm.bextri.u32" => "__builtin_ia32_bextri_u32", "llvm.x86.tbm.bextri.u64" => "__builtin_ia32_bextri_u64", + "llvm.x86.tcmmimfp16ps" => "__builtin_ia32_tcmmimfp16ps", + "llvm.x86.tcmmimfp16ps.internal" => "__builtin_ia32_tcmmimfp16ps_internal", + "llvm.x86.tcmmrlfp16ps" => "__builtin_ia32_tcmmrlfp16ps", + "llvm.x86.tcmmrlfp16ps.internal" => "__builtin_ia32_tcmmrlfp16ps_internal", "llvm.x86.tdpbf16ps" => "__builtin_ia32_tdpbf16ps", "llvm.x86.tdpbf16ps.internal" => "__builtin_ia32_tdpbf16ps_internal", "llvm.x86.tdpbssd" => "__builtin_ia32_tdpbssd", From 65a20d3f711e8cb6ea418fb7948a9c4a054d5bc8 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 5 Apr 2023 22:22:42 -0400 Subject: [PATCH 116/465] Fix vpshrd llvm instrinsics --- src/intrinsic/llvm.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index 0edec566be309..f28348380d7bc 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -313,6 +313,13 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc let new_args = args.to_vec(); args = vec![new_args[1], new_args[0], new_args[2], new_args[3], new_args[4]].into(); }, + "__builtin_ia32_vpshrdv_v8di" | "__builtin_ia32_vpshrdv_v4di" | "__builtin_ia32_vpshrdv_v2di" | + "__builtin_ia32_vpshrdv_v16si" | "__builtin_ia32_vpshrdv_v8si" | "__builtin_ia32_vpshrdv_v4si" | + "__builtin_ia32_vpshrdv_v32hi" | "__builtin_ia32_vpshrdv_v16hi" | "__builtin_ia32_vpshrdv_v8hi" => { + // The first two arguments are reversed, compared to LLVM. + let new_args = args.to_vec(); + args = vec![new_args[1], new_args[0], new_args[2]].into(); + }, _ => (), } } From 556ab2628384398dedbc6b7700b1fd7899336c3d Mon Sep 17 00:00:00 2001 From: zhaixiaojuan Date: Tue, 28 Mar 2023 16:18:12 +0800 Subject: [PATCH 117/465] Define MIN_ALIGN for loongarch64 --- example/alloc_system.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/example/alloc_system.rs b/example/alloc_system.rs index 9ec18da90d819..046903fe5aca4 100644 --- a/example/alloc_system.rs +++ b/example/alloc_system.rs @@ -15,6 +15,7 @@ const MIN_ALIGN: usize = 8; #[cfg(any(target_arch = "x86_64", target_arch = "aarch64", + target_arch = "loongarch64", target_arch = "mips64", target_arch = "s390x", target_arch = "sparc64"))] From a6d7ab5b00e1b74bf77cab783c23c805f144b43f Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 8 Apr 2023 12:39:58 -0400 Subject: [PATCH 118/465] Run emulated stdarch tests in the CI --- .github/workflows/stdarch.yml | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml index 42fb35e738ffd..556c644483320 100644 --- a/.github/workflows/stdarch.yml +++ b/.github/workflows/stdarch.yml @@ -20,9 +20,9 @@ jobs: matrix: libgccjit_version: - { gcc: "libgccjit.so", artifacts_branch: "master" } - commands: [ - "--test-successful-rustc --nb-parts 2 --current-part 0", - "--test-successful-rustc --nb-parts 2 --current-part 1", + cargo_runner: [ + "sde -future -rtm_mode full --", + "", ] steps: @@ -36,6 +36,20 @@ jobs: - name: Install packages run: sudo apt-get install ninja-build ripgrep + - name: Install Intel Software Development Emulator + if: ${{ matrix.cargo_runner }} + run: | + mkdir intel-sde + cd intel-sde + dir=sde-external-9.14.0-2022-10-25-lin + file=$dir.tar.xz + wget https://downloadmirror.intel.com/751535/$file + tar xvf $file + sudo mkdir /usr/share/intel-sde + sudo cp -r $dir/* /usr/share/intel-sde + sudo ln -s /usr/share/intel-sde/sde /usr/bin/sde + sudo ln -s /usr/share/intel-sde/sde64 /usr/bin/sde64 + - name: Download artifact uses: dawidd6/action-download-artifact@v2 with: @@ -91,6 +105,10 @@ jobs: ./prepare_build.sh ./build.sh --release --release-sysroot cargo test + + - name: Clean + if: ${{ !matrix.cargo_runner }} + run: | ./clean_all.sh - name: Prepare dependencies @@ -107,10 +125,18 @@ jobs: args: --release - name: Run tests + if: ${{ !matrix.cargo_runner }} run: | ./test.sh --release --clean --release-sysroot --build-sysroot --mini-tests --std-tests --test-libcore - name: Run stdarch tests + if: ${{ !matrix.cargo_runner }} run: | cd build_sysroot/sysroot_src/library/stdarch/ CHANNEL=release TARGET=x86_64-unknown-linux-gnu ../../../../cargo.sh test + + - name: Run stdarch tests + if: ${{ matrix.cargo_runner }} + run: | + cd build_sysroot/sysroot_src/library/stdarch/ + STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu ../../../../cargo.sh test -- --skip rtm --skip tbm --skip sse4a From e9868ef8df9817802a0aaf0695e83c1e45783842 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Tue, 11 Apr 2023 13:20:41 -0400 Subject: [PATCH 119/465] clarify wording around spurious wakeups from `thread::park` --- library/std/src/thread/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 07662e90c52bc..0f8b9c7668815 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -891,8 +891,8 @@ pub fn sleep(dur: Duration) { /// performs the corresponding `Acquire` operation. Calls to `unpark` for the same /// thread form a [release sequence]. /// -/// Note that being unblocked does not imply synchronization with a call to `unpark`, -/// the wakeup could also be spurious. For example, a valid, but inefficient, +/// Note that being unblocked does not imply a call was made to `unpark`, because +/// wakeups can also be spurious. For example, a valid, but inefficient, /// implementation could have `park` and `unpark` return immediately without doing anything. /// /// # Examples From 387718fedcd4a235c9f2a439f2d655a43e950f21 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Wed, 5 Apr 2023 18:42:36 -0700 Subject: [PATCH 120/465] Add inline assembly support for m68k --- src/asm.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/asm.rs b/src/asm.rs index 41e9d61a10e50..65de02b356712 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -593,6 +593,9 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r", InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w", InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => "a", + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => "d", InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "d", // more specific than "r" InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f", InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r", @@ -664,6 +667,9 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl InlineAsmRegClass::Avr(_) => unimplemented!(), InlineAsmRegClass::Bpf(_) => unimplemented!(), InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(), + InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => cx.type_i32(), InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(), InlineAsmRegClass::Msp430(_) => unimplemented!(), @@ -849,6 +855,7 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option InlineAsmRegClass::Avr(_) => None, InlineAsmRegClass::S390x(_) => None, InlineAsmRegClass::Msp430(_) => None, + InlineAsmRegClass::M68k(_) => None, InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("LLVM backend does not support SPIR-V") } From 5f30b63b3bbed424565ae175f84ce94d49480962 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 22 Mar 2023 23:43:20 +0000 Subject: [PATCH 121/465] Remove #[alloc_error_handler] from the compiler and library --- example/alloc_example.rs | 7 +------ src/allocator.rs | 34 +--------------------------------- src/lib.rs | 4 ++-- 3 files changed, 4 insertions(+), 41 deletions(-) diff --git a/example/alloc_example.rs b/example/alloc_example.rs index 754e7931412da..faff1dca23f3f 100644 --- a/example/alloc_example.rs +++ b/example/alloc_example.rs @@ -1,4 +1,4 @@ -#![feature(start, core_intrinsics, alloc_error_handler, lang_items)] +#![feature(start, core_intrinsics, lang_items)] #![no_std] extern crate alloc; @@ -21,11 +21,6 @@ fn panic_handler(_: &core::panic::PanicInfo) -> ! { core::intrinsics::abort(); } -#[alloc_error_handler] -fn alloc_error_handler(_: alloc::alloc::Layout) -> ! { - core::intrinsics::abort(); -} - #[lang = "eh_personality"] fn eh_personality() -> ! { loop {} diff --git a/src/allocator.rs b/src/allocator.rs index 4bad33ee879ee..e90db44ece1fc 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -5,11 +5,10 @@ use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::config::OomStrategy; -use rustc_span::symbol::sym; use crate::GccContext; -pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) { +pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind) { let context = &mods.context; let usize = match tcx.sess.target.pointer_width { @@ -87,37 +86,6 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam // as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643 } - let types = [usize, usize]; - let name = "__rust_alloc_error_handler".to_string(); - let args: Vec<_> = types.iter().enumerate() - .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) - .collect(); - let func = context.new_function(None, FunctionType::Exported, void, &args, name, false); - - if tcx.sess.target.default_hidden_visibility { - #[cfg(feature="master")] - func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); - } - - let callee = alloc_error_handler_kind.fn_name(sym::oom); - let args: Vec<_> = types.iter().enumerate() - .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) - .collect(); - let callee = context.new_function(None, FunctionType::Extern, void, &args, callee, false); - #[cfg(feature="master")] - callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); - - let block = func.new_block("entry"); - - let args = args - .iter() - .enumerate() - .map(|(i, _)| func.get_param(i as i32).to_rvalue()) - .collect::>(); - let _ret = context.new_call(None, callee, &args); - //llvm::LLVMSetTailCall(ret, True); - block.end_with_void_return(None); - let name = OomStrategy::SYMBOL.to_string(); let global = context.new_global(None, GlobalKind::Exported, i8, name); let value = tcx.sess.opts.unstable_opts.oom.should_panic(); diff --git a/src/lib.rs b/src/lib.rs index 0b661505acc00..be710fefe49cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -162,11 +162,11 @@ impl CodegenBackend for GccCodegenBackend { } impl ExtraBackendMethods for GccCodegenBackend { - fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) -> Self::Module { + fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind) -> Self::Module { let mut mods = GccContext { context: Context::default(), }; - unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); } + unsafe { allocator::codegen(tcx, &mut mods, module_name, kind); } mods } From b93041af0a3100feb8785a6ff17b242c21d1a6f8 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 16 Apr 2023 14:12:42 -0400 Subject: [PATCH 122/465] Add support for inline attribute --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- src/attributes.rs | 39 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 ++ 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6e94c03a15404..3c5357eec1057 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,7 +35,7 @@ dependencies = [ [[package]] name = "gccjit" version = "1.0.0" -source = "git+https://github.com/antoyo/gccjit.rs#98a29ddd64f662beb5d11810434fbeaad4a1856c" +source = "git+https://github.com/antoyo/gccjit.rs#d6e52626cfc6f487094a5d5ac66302baf3439984" dependencies = [ "gccjit_sys", ] @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "gccjit_sys" version = "0.0.1" -source = "git+https://github.com/antoyo/gccjit.rs#98a29ddd64f662beb5d11810434fbeaad4a1856c" +source = "git+https://github.com/antoyo/gccjit.rs#d6e52626cfc6f487094a5d5ac66302baf3439984" dependencies = [ "libc", ] diff --git a/Cargo.toml b/Cargo.toml index 81066d9ce1f0a..7285e3eaf5198 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ master = ["gccjit/master"] gccjit = { git = "https://github.com/antoyo/gccjit.rs" } # Local copy. -#gccjit = { path = "../gccjit.rs" } +# gccjit = { path = "../gccjit.rs" } smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } diff --git a/src/attributes.rs b/src/attributes.rs index 243a1a36dd09d..23c1f886e09e6 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -2,9 +2,13 @@ use gccjit::FnAttribute; use gccjit::Function; use rustc_attr::InstructionSetAttr; +#[cfg(feature="master")] +use rustc_attr::InlineAttr; use rustc_codegen_ssa::target_features::tied_target_features; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty; +#[cfg(feature="master")] +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_session::Session; use rustc_span::symbol::sym; use smallvec::{smallvec, SmallVec}; @@ -67,6 +71,24 @@ fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> { } } +/// Get GCC attribute for the provided inline heuristic. +#[cfg(feature="master")] +#[inline] +fn inline_attr<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, inline: InlineAttr) -> Option> { + match inline { + InlineAttr::Hint => Some(FnAttribute::Inline), + InlineAttr::Always => Some(FnAttribute::AlwaysInline), + InlineAttr::Never => { + if cx.sess().target.arch != "amdgpu" { + Some(FnAttribute::NoInline) + } else { + None + } + } + InlineAttr::None => None, + } +} + /// Composite function which sets GCC attributes for function depending on its AST (`#[attribute]`) /// attributes. pub fn from_fn_attrs<'gcc, 'tcx>( @@ -77,6 +99,23 @@ pub fn from_fn_attrs<'gcc, 'tcx>( ) { let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id()); + #[cfg(feature="master")] + { + let inline = + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { + InlineAttr::Never + } + else if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) { + InlineAttr::Hint + } + else { + codegen_fn_attrs.inline + }; + if let Some(attr) = inline_attr(cx, inline) { + func.add_attribute(attr); + } + } + let function_features = codegen_fn_attrs.target_features.iter().map(|features| features.as_str()).collect::>(); diff --git a/src/lib.rs b/src/lib.rs index 1b7feb5f8a18e..3b26e248fc26f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -110,6 +110,8 @@ impl CodegenBackend for GccCodegenBackend { } fn init(&self, sess: &Session) { + #[cfg(feature="master")] + gccjit::set_global_personality_function_name(b"rust_eh_personality\0"); if sess.lto() != Lto::No { sess.emit_warning(LTONotSupported {}); } From f40e4da5d99527ac8bed14e6c877e84f1a6a3851 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 16 Apr 2023 14:33:00 +0200 Subject: [PATCH 123/465] Add `rustc_fluent_macro` to decouple fluent from `rustc_macros` Fluent, with all the icu4x it brings in, takes quite some time to compile. `fluent_messages!` is only needed in further downstream rustc crates, but is blocking more upstream crates like `rustc_index`. By splitting it out, we allow `rustc_macros` to be compiled earlier, which speeds up `x check compiler` by about 5 seconds (and even more after the needless dependency on `serde_json` is removed from `rustc_data_structures`). --- src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 0b661505acc00..1cabb05de975b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,6 +27,7 @@ extern crate rustc_attr; extern crate rustc_codegen_ssa; extern crate rustc_data_structures; extern crate rustc_errors; +extern crate rustc_fluent_macro; extern crate rustc_hir; extern crate rustc_macros; extern crate rustc_metadata; @@ -76,7 +77,7 @@ use rustc_codegen_ssa::target_features::supported_target_features; use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, Handler, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; From 84385bff42c9f823e83e64c3c9c61311feee608c Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Sun, 11 Sep 2022 00:37:49 -0700 Subject: [PATCH 124/465] offset_of --- src/expr.rs | 1 + src/utils.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/expr.rs b/src/expr.rs index ac96bedf2fe86..b76e3a2a87c99 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -345,6 +345,7 @@ pub(crate) fn format_expr( // Style Guide RFC for InlineAsm variant pending // https://github.com/rust-dev-tools/fmt-rfcs/issues/152 ast::ExprKind::InlineAsm(..) => Some(context.snippet(expr.span).to_owned()), + ast::ExprKind::OffsetOf(..) => Some(context.snippet(expr.span).to_owned()), ast::ExprKind::TryBlock(ref block) => { if let rw @ Some(_) = rewrite_single_line_block(context, "try ", block, Some(&expr.attrs), None, shape) diff --git a/src/utils.rs b/src/utils.rs index a26375ee64384..ca1716574071b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -499,6 +499,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Field(..) | ast::ExprKind::IncludedBytes(..) | ast::ExprKind::InlineAsm(..) + | ast::ExprKind::OffsetOf(..) | ast::ExprKind::Let(..) | ast::ExprKind::Path(..) | ast::ExprKind::Range(..) From ecfdec44df08f118c641c4076238f07a7f437fe6 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Fri, 21 Apr 2023 01:44:17 -0700 Subject: [PATCH 125/465] minor tweaks --- src/expr.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index b76e3a2a87c99..a0882eff707f2 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -345,7 +345,6 @@ pub(crate) fn format_expr( // Style Guide RFC for InlineAsm variant pending // https://github.com/rust-dev-tools/fmt-rfcs/issues/152 ast::ExprKind::InlineAsm(..) => Some(context.snippet(expr.span).to_owned()), - ast::ExprKind::OffsetOf(..) => Some(context.snippet(expr.span).to_owned()), ast::ExprKind::TryBlock(ref block) => { if let rw @ Some(_) = rewrite_single_line_block(context, "try ", block, Some(&expr.attrs), None, shape) @@ -400,7 +399,7 @@ pub(crate) fn format_expr( } } ast::ExprKind::Underscore => Some("_".to_owned()), - ast::ExprKind::FormatArgs(..) | ast::ExprKind::IncludedBytes(..) => { + ast::ExprKind::FormatArgs(..) | ast::ExprKind::IncludedBytes(..) | ast::ExprKind::OffsetOf(..) => { // These do not occur in the AST because macros aren't expanded. unreachable!() } From f4c9b4c26f7d28416031129f300b9a9bb5e68641 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Fri, 21 Apr 2023 08:59:30 -0700 Subject: [PATCH 126/465] rustfmt fmt --- src/expr.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/expr.rs b/src/expr.rs index a0882eff707f2..824e42191364f 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -399,7 +399,9 @@ pub(crate) fn format_expr( } } ast::ExprKind::Underscore => Some("_".to_owned()), - ast::ExprKind::FormatArgs(..) | ast::ExprKind::IncludedBytes(..) | ast::ExprKind::OffsetOf(..) => { + ast::ExprKind::FormatArgs(..) + | ast::ExprKind::IncludedBytes(..) + | ast::ExprKind::OffsetOf(..) => { // These do not occur in the AST because macros aren't expanded. unreachable!() } From 94735c7a5ce85c4afa75006a704844fcf637a1ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Tue, 25 Apr 2023 00:08:35 +0200 Subject: [PATCH 127/465] Revert "Remove #[alloc_error_handler] from the compiler and library" This reverts commit abc0660118cc95f47445fd33502a11dd448f5968. --- example/alloc_example.rs | 7 ++++++- src/allocator.rs | 34 +++++++++++++++++++++++++++++++++- src/lib.rs | 4 ++-- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/example/alloc_example.rs b/example/alloc_example.rs index faff1dca23f3f..754e7931412da 100644 --- a/example/alloc_example.rs +++ b/example/alloc_example.rs @@ -1,4 +1,4 @@ -#![feature(start, core_intrinsics, lang_items)] +#![feature(start, core_intrinsics, alloc_error_handler, lang_items)] #![no_std] extern crate alloc; @@ -21,6 +21,11 @@ fn panic_handler(_: &core::panic::PanicInfo) -> ! { core::intrinsics::abort(); } +#[alloc_error_handler] +fn alloc_error_handler(_: alloc::alloc::Layout) -> ! { + core::intrinsics::abort(); +} + #[lang = "eh_personality"] fn eh_personality() -> ! { loop {} diff --git a/src/allocator.rs b/src/allocator.rs index e90db44ece1fc..4bad33ee879ee 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -5,10 +5,11 @@ use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::config::OomStrategy; +use rustc_span::symbol::sym; use crate::GccContext; -pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind) { +pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) { let context = &mods.context; let usize = match tcx.sess.target.pointer_width { @@ -86,6 +87,37 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam // as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643 } + let types = [usize, usize]; + let name = "__rust_alloc_error_handler".to_string(); + let args: Vec<_> = types.iter().enumerate() + .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) + .collect(); + let func = context.new_function(None, FunctionType::Exported, void, &args, name, false); + + if tcx.sess.target.default_hidden_visibility { + #[cfg(feature="master")] + func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); + } + + let callee = alloc_error_handler_kind.fn_name(sym::oom); + let args: Vec<_> = types.iter().enumerate() + .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) + .collect(); + let callee = context.new_function(None, FunctionType::Extern, void, &args, callee, false); + #[cfg(feature="master")] + callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); + + let block = func.new_block("entry"); + + let args = args + .iter() + .enumerate() + .map(|(i, _)| func.get_param(i as i32).to_rvalue()) + .collect::>(); + let _ret = context.new_call(None, callee, &args); + //llvm::LLVMSetTailCall(ret, True); + block.end_with_void_return(None); + let name = OomStrategy::SYMBOL.to_string(); let global = context.new_global(None, GlobalKind::Exported, i8, name); let value = tcx.sess.opts.unstable_opts.oom.should_panic(); diff --git a/src/lib.rs b/src/lib.rs index 1a20dbcebd40d..1cabb05de975b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -163,11 +163,11 @@ impl CodegenBackend for GccCodegenBackend { } impl ExtraBackendMethods for GccCodegenBackend { - fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind) -> Self::Module { + fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) -> Self::Module { let mut mods = GccContext { context: Context::default(), }; - unsafe { allocator::codegen(tcx, &mut mods, module_name, kind); } + unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); } mods } From 7ec90e307793c5e8bd5a50e9556fdf92c6d8147d Mon Sep 17 00:00:00 2001 From: zhaixiaojuan Date: Fri, 19 Aug 2022 17:41:56 +0800 Subject: [PATCH 128/465] Add loongarch64 asm! support --- src/asm.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/asm.rs b/src/asm.rs index 65de02b356712..738cdb6f119f2 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -593,6 +593,8 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r", InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w", InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f", InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r", InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => "a", InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => "d", @@ -667,6 +669,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl InlineAsmRegClass::Avr(_) => unimplemented!(), InlineAsmRegClass::Bpf(_) => unimplemented!(), InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => cx.type_f32(), InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(), InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => cx.type_i32(), @@ -804,6 +808,7 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option } } InlineAsmRegClass::Hexagon(_) => None, + InlineAsmRegClass::LoongArch(_) => None, InlineAsmRegClass::Mips(_) => None, InlineAsmRegClass::Nvptx(_) => None, InlineAsmRegClass::PowerPC(_) => None, From f04da2218c5a88c77496744fa74c4616b41bf357 Mon Sep 17 00:00:00 2001 From: Albert Larsan <74931857+albertlarsan68@users.noreply.github.com> Date: Wed, 4 Jan 2023 14:16:55 +0100 Subject: [PATCH 129/465] Make `{Arc,Rc,Weak}::ptr_eq` ignore pointer metadata --- library/alloc/src/rc.rs | 10 +++++----- library/alloc/src/sync.rs | 10 +++++----- .../clippy/clippy_lints/src/unnamed_address.rs | 4 +--- src/tools/clippy/clippy_utils/src/paths.rs | 2 -- .../tests/ui/vtable_address_comparisons.rs | 12 ++++++------ .../tests/ui/vtable_address_comparisons.stderr | 18 +----------------- 6 files changed, 18 insertions(+), 38 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index cf93a40496fdf..3bfa1526a3d5a 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1169,7 +1169,7 @@ impl Rc { #[inline] #[stable(feature = "ptr_eq", since = "1.17.0")] /// Returns `true` if the two `Rc`s point to the same allocation in a vein similar to - /// [`ptr::eq`]. See [that function][`ptr::eq`] for caveats when comparing `dyn Trait` pointers. + /// [`ptr::eq`]. This function ignores the metadata of `dyn Trait` pointers. /// /// # Examples /// @@ -1184,7 +1184,7 @@ impl Rc { /// assert!(!Rc::ptr_eq(&five, &other_five)); /// ``` pub fn ptr_eq(this: &Self, other: &Self) -> bool { - this.ptr.as_ptr() == other.ptr.as_ptr() + this.ptr.as_ptr() as *const () == other.ptr.as_ptr() as *const () } } @@ -2468,8 +2468,8 @@ impl Weak { } /// Returns `true` if the two `Weak`s point to the same allocation similar to [`ptr::eq`], or if - /// both don't point to any allocation (because they were created with `Weak::new()`). See [that - /// function][`ptr::eq`] for caveats when comparing `dyn Trait` pointers. + /// both don't point to any allocation (because they were created with `Weak::new()`). However, + /// this function ignores the metadata of `dyn Trait` pointers. /// /// # Notes /// @@ -2510,7 +2510,7 @@ impl Weak { #[must_use] #[stable(feature = "weak_ptr_eq", since = "1.39.0")] pub fn ptr_eq(&self, other: &Self) -> bool { - self.ptr.as_ptr() == other.ptr.as_ptr() + ptr::eq(self.ptr.as_ptr() as *const (), other.ptr.as_ptr() as *const ()) } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 5bfe537bc830f..ef2148e9e1414 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1263,7 +1263,7 @@ impl Arc { } /// Returns `true` if the two `Arc`s point to the same allocation in a vein similar to - /// [`ptr::eq`]. See [that function][`ptr::eq`] for caveats when comparing `dyn Trait` pointers. + /// [`ptr::eq`]. This function ignores the metadata of `dyn Trait` pointers. /// /// # Examples /// @@ -1283,7 +1283,7 @@ impl Arc { #[must_use] #[stable(feature = "ptr_eq", since = "1.17.0")] pub fn ptr_eq(this: &Self, other: &Self) -> bool { - this.ptr.as_ptr() == other.ptr.as_ptr() + this.ptr.as_ptr() as *const () == other.ptr.as_ptr() as *const () } } @@ -2243,8 +2243,8 @@ impl Weak { } /// Returns `true` if the two `Weak`s point to the same allocation similar to [`ptr::eq`], or if - /// both don't point to any allocation (because they were created with `Weak::new()`). See [that - /// function][`ptr::eq`] for caveats when comparing `dyn Trait` pointers. + /// both don't point to any allocation (because they were created with `Weak::new()`). However, + /// this function ignores the metadata of `dyn Trait` pointers. /// /// # Notes /// @@ -2287,7 +2287,7 @@ impl Weak { #[must_use] #[stable(feature = "weak_ptr_eq", since = "1.39.0")] pub fn ptr_eq(&self, other: &Self) -> bool { - self.ptr.as_ptr() == other.ptr.as_ptr() + ptr::eq(self.ptr.as_ptr() as *const (), other.ptr.as_ptr() as *const ()) } } diff --git a/src/tools/clippy/clippy_lints/src/unnamed_address.rs b/src/tools/clippy/clippy_lints/src/unnamed_address.rs index 0bcafde658a43..0f5cdb6aaea17 100644 --- a/src/tools/clippy/clippy_lints/src/unnamed_address.rs +++ b/src/tools/clippy/clippy_lints/src/unnamed_address.rs @@ -96,9 +96,7 @@ impl LateLintPass<'_> for UnnamedAddress { if let ExprKind::Call(func, [ref _left, ref _right]) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::PTR_EQ) || - match_def_path(cx, def_id, &paths::RC_PTR_EQ) || - match_def_path(cx, def_id, &paths::ARC_PTR_EQ); + if match_def_path(cx, def_id, &paths::PTR_EQ); let ty_param = cx.typeck_results().node_substs(func.hir_id).type_at(0); if ty_param.is_trait(); then { diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index 9be2d0eae80aa..126356c968263 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -15,7 +15,6 @@ pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [ ]; #[cfg(feature = "internal")] pub const DIAGNOSTIC_BUILDER: [&str; 3] = ["rustc_errors", "diagnostic_builder", "DiagnosticBuilder"]; -pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"]; pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"]; pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"]; pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "BTreeSet", "iter"]; @@ -93,7 +92,6 @@ pub const PTR_WRITE_UNALIGNED: [&str; 3] = ["core", "ptr", "write_unaligned"]; pub const PTR_WRITE_VOLATILE: [&str; 3] = ["core", "ptr", "write_volatile"]; pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"]; pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"]; -pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"]; pub const REFCELL_REF: [&str; 3] = ["core", "cell", "Ref"]; pub const REFCELL_REFMUT: [&str; 3] = ["core", "cell", "RefMut"]; pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"]; diff --git a/src/tools/clippy/tests/ui/vtable_address_comparisons.rs b/src/tools/clippy/tests/ui/vtable_address_comparisons.rs index a9a4a0f5a6b5c..99c3f468f04a7 100644 --- a/src/tools/clippy/tests/ui/vtable_address_comparisons.rs +++ b/src/tools/clippy/tests/ui/vtable_address_comparisons.rs @@ -23,12 +23,6 @@ fn main() { let b = &1 as &dyn Debug; ptr::eq(a, b); - let a: Rc = Rc::new(1); - Rc::ptr_eq(&a, &a); - - let a: Arc = Arc::new(1); - Arc::ptr_eq(&a, &a); - // These should be fine: let a = &1; ptr::eq(a, a); @@ -39,6 +33,12 @@ fn main() { let a = Arc::new(1); Arc::ptr_eq(&a, &a); + let a: Rc = Rc::new(1); + Rc::ptr_eq(&a, &a); + + let a: Arc = Arc::new(1); + Arc::ptr_eq(&a, &a); + let a: &[u8] = b""; ptr::eq(a, a); } diff --git a/src/tools/clippy/tests/ui/vtable_address_comparisons.stderr b/src/tools/clippy/tests/ui/vtable_address_comparisons.stderr index 14748f583f0cd..7b866d274d586 100644 --- a/src/tools/clippy/tests/ui/vtable_address_comparisons.stderr +++ b/src/tools/clippy/tests/ui/vtable_address_comparisons.stderr @@ -63,21 +63,5 @@ LL | ptr::eq(a, b); | = help: consider extracting and comparing data pointers only -error: comparing trait object pointers compares a non-unique vtable address - --> $DIR/vtable_address_comparisons.rs:27:5 - | -LL | Rc::ptr_eq(&a, &a); - | ^^^^^^^^^^^^^^^^^^ - | - = help: consider extracting and comparing data pointers only - -error: comparing trait object pointers compares a non-unique vtable address - --> $DIR/vtable_address_comparisons.rs:30:5 - | -LL | Arc::ptr_eq(&a, &a); - | ^^^^^^^^^^^^^^^^^^^ - | - = help: consider extracting and comparing data pointers only - -error: aborting due to 10 previous errors +error: aborting due to 8 previous errors From 43f2b1696f7a02892b5408cc0292f0eb8ddecb6d Mon Sep 17 00:00:00 2001 From: Boxy Date: Thu, 27 Apr 2023 08:34:11 +0100 Subject: [PATCH 130/465] rename `needs_infer` to `has_infer` --- src/callee.rs | 2 +- src/mono_item.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/callee.rs b/src/callee.rs index ba1e86562089e..433b2585f82a8 100644 --- a/src/callee.rs +++ b/src/callee.rs @@ -17,7 +17,7 @@ use crate::context::CodegenCx; pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) -> Function<'gcc> { let tcx = cx.tcx(); - assert!(!instance.substs.needs_infer()); + assert!(!instance.substs.has_infer()); assert!(!instance.substs.has_escaping_bound_vars()); let sym = tcx.symbol_name(instance).name; diff --git a/src/mono_item.rs b/src/mono_item.rs index c1f6340866cac..342b830cedb12 100644 --- a/src/mono_item.rs +++ b/src/mono_item.rs @@ -31,7 +31,7 @@ impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> { #[cfg_attr(not(feature="master"), allow(unused_variables))] fn predefine_fn(&self, instance: Instance<'tcx>, linkage: Linkage, visibility: Visibility, symbol_name: &str) { - assert!(!instance.substs.needs_infer()); + assert!(!instance.substs.has_infer()); let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); self.linkage.set(base::linkage_to_gcc(linkage)); From 6b9c151686baf6705b4bcfb6ce3db86bc817a9b3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 25 Apr 2023 18:59:16 +0000 Subject: [PATCH 131/465] Tweak await span --- src/chains.rs | 4 ++-- src/expr.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/chains.rs b/src/chains.rs index cbe523c6c3ca9..0afce7cf65962 100644 --- a/src/chains.rs +++ b/src/chains.rs @@ -232,7 +232,7 @@ impl ChainItemKind { let span = mk_sp(nested.span.hi(), field.span.hi()); (kind, span) } - ast::ExprKind::Await(ref nested) => { + ast::ExprKind::Await(ref nested, _) => { let span = mk_sp(nested.span.hi(), expr.span.hi()); (ChainItemKind::Await, span) } @@ -459,7 +459,7 @@ impl Chain { ast::ExprKind::MethodCall(ref call) => Some(Self::convert_try(&call.receiver, context)), ast::ExprKind::Field(ref subexpr, _) | ast::ExprKind::Try(ref subexpr) - | ast::ExprKind::Await(ref subexpr) => Some(Self::convert_try(subexpr, context)), + | ast::ExprKind::Await(ref subexpr, _) => Some(Self::convert_try(subexpr, context)), _ => None, } } diff --git a/src/expr.rs b/src/expr.rs index 824e42191364f..5dc628adb0c6f 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -218,7 +218,7 @@ pub(crate) fn format_expr( ast::ExprKind::Try(..) | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) - | ast::ExprKind::Await(_) => rewrite_chain(expr, context, shape), + | ast::ExprKind::Await(_, _) => rewrite_chain(expr, context, shape), ast::ExprKind::MacCall(ref mac) => { rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|| { wrap_str( @@ -1889,7 +1889,7 @@ impl<'ast> RhsAssignKind<'ast> { ast::ExprKind::Try(..) | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) - | ast::ExprKind::Await(_) + | ast::ExprKind::Await(_, _) ) } _ => false, From a44c7ea5923caa8f908ae0fdd6563033a7ad88da Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Thu, 27 Apr 2023 20:20:18 +0200 Subject: [PATCH 132/465] fix broken markdown --- src/config/options.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/options.rs b/src/config/options.rs index 257a17b2703a9..408017d2432c9 100644 --- a/src/config/options.rs +++ b/src/config/options.rs @@ -18,7 +18,7 @@ pub enum NewlineStyle { Auto, /// Force CRLF (`\r\n`). Windows, - /// Force CR (`\n). + /// Force CR (`\n`). Unix, /// `\r\n` in Windows, `\n` on other platforms. Native, From a74d2d7440003ada5c88fc75c4eb468335afa618 Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 15 Mar 2023 07:10:59 +0800 Subject: [PATCH 133/465] fix tests --- tests/source/type-ascription.rs | 10 ++++----- .../configs/format_macro_bodies/true.rs | 8 ++----- .../configs/format_macro_matchers/false.rs | 8 ++----- .../configs/format_macro_matchers/true.rs | 8 ++----- tests/target/macros.rs | 22 ++++++++----------- tests/target/type-ascription.rs | 11 +++++----- tests/target/type.rs | 2 +- 7 files changed, 27 insertions(+), 42 deletions(-) diff --git a/tests/source/type-ascription.rs b/tests/source/type-ascription.rs index 4874094ccc4c4..fbdde272cb62f 100644 --- a/tests/source/type-ascription.rs +++ b/tests/source/type-ascription.rs @@ -1,10 +1,10 @@ - +// #101728, we remove type ascription, so this test case is changed to `var as ty` fn main() { - let xxxxxxxxxxx = yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy : SomeTrait; + let xxxxxxxxxxx = yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy as SomeTrait; - let xxxxxxxxxxxxxxx = yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; + let xxxxxxxxxxxxxxx = yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy as AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; - let z = funk(yyyyyyyyyyyyyyy, zzzzzzzzzzzzzzzz, wwwwww): AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; + let z = funk(yyyyyyyyyyyyyyy, zzzzzzzzzzzzzzzz, wwwwww) as AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; - x : u32 - 1u32 / 10f32 : u32 + let _ = x as u32 - 1u32 / (10f32 as u32); } diff --git a/tests/target/configs/format_macro_bodies/true.rs b/tests/target/configs/format_macro_bodies/true.rs index 9dc2524c38961..17ac1498c932c 100644 --- a/tests/target/configs/format_macro_bodies/true.rs +++ b/tests/target/configs/format_macro_bodies/true.rs @@ -1,10 +1,6 @@ // rustfmt-format_macro_bodies: true macro_rules! foo { - ($a: ident : $b: ty) => { - $a(42): $b; - }; - ($a: ident $b: ident $c: ident) => { - $a = $b + $c; - }; + ($a: ident : $b: ty) => { $a(42): $b; }; + ($a: ident $b: ident $c: ident) => { $a=$b+$c; }; } diff --git a/tests/target/configs/format_macro_matchers/false.rs b/tests/target/configs/format_macro_matchers/false.rs index 3966d21be7563..01ecac9879d69 100644 --- a/tests/target/configs/format_macro_matchers/false.rs +++ b/tests/target/configs/format_macro_matchers/false.rs @@ -1,10 +1,6 @@ // rustfmt-format_macro_matchers: false macro_rules! foo { - ($a: ident : $b: ty) => { - $a(42): $b; - }; - ($a: ident $b: ident $c: ident) => { - $a = $b + $c; - }; + ($a: ident : $b: ty) => { $a(42): $b; }; + ($a: ident $b: ident $c: ident) => { $a=$b+$c; }; } diff --git a/tests/target/configs/format_macro_matchers/true.rs b/tests/target/configs/format_macro_matchers/true.rs index e113af96f26be..fa0442e228ac8 100644 --- a/tests/target/configs/format_macro_matchers/true.rs +++ b/tests/target/configs/format_macro_matchers/true.rs @@ -1,10 +1,6 @@ // rustfmt-format_macro_matchers: true macro_rules! foo { - ($a:ident : $b:ty) => { - $a(42): $b; - }; - ($a:ident $b:ident $c:ident) => { - $a = $b + $c; - }; + ($a: ident : $b: ty) => { $a(42): $b; }; + ($a: ident $b: ident $c: ident) => { $a=$b+$c; }; } diff --git a/tests/target/macros.rs b/tests/target/macros.rs index e930b5037d930..7b4574349df3e 100644 --- a/tests/target/macros.rs +++ b/tests/target/macros.rs @@ -122,7 +122,7 @@ fn main() { 20, 21, 22); // #1092 - chain!(input, a: take!(max_size), || []); + chain!(input, a:take!(max_size), || []); // #2727 foo!("bar"); @@ -156,17 +156,13 @@ fn issue1178() { } fn issue1739() { - sql_function!( - add_rss_item, - add_rss_item_t, - ( - a: types::Integer, - b: types::Timestamptz, - c: types::Text, - d: types::Text, - e: types::Text - ) - ); + sql_function!(add_rss_item, + add_rss_item_t, + (a: types::Integer, + b: types::Timestamptz, + c: types::Text, + d: types::Text, + e: types::Text)); w.slice_mut(s![ .., @@ -232,7 +228,7 @@ fn issue_3174() { "debugMessage": debug.message, }) } else { - json!({ "errorKind": format!("{:?}", error.err_kind()) }) + json!({"errorKind": format!("{:?}", error.err_kind())}) }; } diff --git a/tests/target/type-ascription.rs b/tests/target/type-ascription.rs index a2f082ba4b497..99dc033686478 100644 --- a/tests/target/type-ascription.rs +++ b/tests/target/type-ascription.rs @@ -1,12 +1,13 @@ +// #101728, we remove type ascription, so this test case is changed to `var as ty` fn main() { let xxxxxxxxxxx = - yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy: SomeTrait; + yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy as SomeTrait; let xxxxxxxxxxxxxxx = - yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; + yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy as AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; - let z = funk(yyyyyyyyyyyyyyy, zzzzzzzzzzzzzzzz, wwwwww): - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; + let z = funk(yyyyyyyyyyyyyyy, zzzzzzzzzzzzzzzz, wwwwww) + as AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; - x: u32 - 1u32 / 10f32: u32 + let _ = x as u32 - 1u32 / (10f32 as u32); } diff --git a/tests/target/type.rs b/tests/target/type.rs index 38cf909c2587a..c789ecb055a7d 100644 --- a/tests/target/type.rs +++ b/tests/target/type.rs @@ -129,7 +129,7 @@ fn issue3117() { fn issue3139() { assert_eq!( to_json_value(&None::).unwrap(), - json!({ "test": None:: }) + json!( { "test": None :: } ) ); } From 9d20134a781b4b61b45276ab6f104c3dcbe9dc82 Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 4 Apr 2023 11:41:53 +0800 Subject: [PATCH 134/465] remove rustfmt testcase for type ascription --- tests/source/type-ascription.rs | 10 ---------- tests/target/type-ascription.rs | 13 ------------- 2 files changed, 23 deletions(-) delete mode 100644 tests/source/type-ascription.rs delete mode 100644 tests/target/type-ascription.rs diff --git a/tests/source/type-ascription.rs b/tests/source/type-ascription.rs deleted file mode 100644 index fbdde272cb62f..0000000000000 --- a/tests/source/type-ascription.rs +++ /dev/null @@ -1,10 +0,0 @@ -// #101728, we remove type ascription, so this test case is changed to `var as ty` -fn main() { - let xxxxxxxxxxx = yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy as SomeTrait; - - let xxxxxxxxxxxxxxx = yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy as AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; - - let z = funk(yyyyyyyyyyyyyyy, zzzzzzzzzzzzzzzz, wwwwww) as AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; - - let _ = x as u32 - 1u32 / (10f32 as u32); -} diff --git a/tests/target/type-ascription.rs b/tests/target/type-ascription.rs deleted file mode 100644 index 99dc033686478..0000000000000 --- a/tests/target/type-ascription.rs +++ /dev/null @@ -1,13 +0,0 @@ -// #101728, we remove type ascription, so this test case is changed to `var as ty` -fn main() { - let xxxxxxxxxxx = - yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy as SomeTrait; - - let xxxxxxxxxxxxxxx = - yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy as AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; - - let z = funk(yyyyyyyyyyyyyyy, zzzzzzzzzzzzzzzz, wwwwww) - as AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; - - let _ = x as u32 - 1u32 / (10f32 as u32); -} From 34a71f67d1e28fe0bf13593e26b682d097678875 Mon Sep 17 00:00:00 2001 From: jyn Date: Sat, 29 Apr 2023 06:29:07 -0500 Subject: [PATCH 135/465] Make the BUG_REPORT_URL configurable by tools This greatly simplifies how hard it is to set a custom bug report url; previously tools had to copy the entire hook implementation. - Switch clippy to the new hook This also adds a `extra_info` callback so clippy can include its own version number, which differs from rustc's. - Call `install_ice_hook` in rustfmt --- src/bin/main.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/bin/main.rs b/src/bin/main.rs index be64559e87745..47846424b06e4 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,3 +1,5 @@ +#![feature(rustc_private)] + use anyhow::{format_err, Result}; use io::Error as IoError; @@ -19,7 +21,14 @@ use crate::rustfmt::{ FormatReportFormatterBuilder, Input, Session, Verbosity, }; +const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rustfmt/issues/new?labels=bug"; + +// N.B. these crates are loaded from the sysroot, so they need extern crate. +extern crate rustc_driver; + fn main() { + rustc_driver::install_ice_hook(BUG_REPORT_URL, |_| ()); + env_logger::Builder::from_env("RUSTFMT_LOG").init(); let opts = make_opts(); From 8e330f9d5bb92b24afde750480b5d70d6c892da5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 25 Apr 2023 06:02:49 +0000 Subject: [PATCH 136/465] Make tools happy --- src/types.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/types.rs b/src/types.rs index 01e2fb6e61e15..9ebe38cc25f7f 100644 --- a/src/types.rs +++ b/src/types.rs @@ -552,6 +552,8 @@ impl Rewrite for ast::GenericBound { ast::TraitBoundModifier::MaybeConstMaybe => poly_trait_ref .rewrite(context, shape.offset_left(8)?) .map(|s| format!("~const ?{}", s)), + rustc_ast::TraitBoundModifier::Negative + | rustc_ast::TraitBoundModifier::MaybeConstNegative => None, }; rewrite.map(|s| if has_paren { format!("({})", s) } else { s }) } From 8ed5d5de3d4e2cf94ddd00cee922d8533d23c1dd Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 26 Apr 2023 22:37:36 +0000 Subject: [PATCH 137/465] Rustfmt support for negative bounds, test --- src/types.rs | 8 ++++++-- tests/target/negative-bounds.rs | 11 +++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 tests/target/negative-bounds.rs diff --git a/src/types.rs b/src/types.rs index 9ebe38cc25f7f..f548388ed8ba2 100644 --- a/src/types.rs +++ b/src/types.rs @@ -552,8 +552,12 @@ impl Rewrite for ast::GenericBound { ast::TraitBoundModifier::MaybeConstMaybe => poly_trait_ref .rewrite(context, shape.offset_left(8)?) .map(|s| format!("~const ?{}", s)), - rustc_ast::TraitBoundModifier::Negative - | rustc_ast::TraitBoundModifier::MaybeConstNegative => None, + ast::TraitBoundModifier::Negative => poly_trait_ref + .rewrite(context, shape.offset_left(1)?) + .map(|s| format!("!{}", s)), + ast::TraitBoundModifier::MaybeConstNegative => poly_trait_ref + .rewrite(context, shape.offset_left(8)?) + .map(|s| format!("~const !{}", s)), }; rewrite.map(|s| if has_paren { format!("({})", s) } else { s }) } diff --git a/tests/target/negative-bounds.rs b/tests/target/negative-bounds.rs new file mode 100644 index 0000000000000..4fb35cccf6684 --- /dev/null +++ b/tests/target/negative-bounds.rs @@ -0,0 +1,11 @@ +fn negative() +where + i32: !Copy, +{ +} + +fn maybe_const_negative() +where + i32: ~const !Copy, +{ +} From 0d183f8e74eca11bf525cb98cfe0de7789b90c8f Mon Sep 17 00:00:00 2001 From: Ramon de C Valle Date: Mon, 12 Dec 2022 22:42:44 -0800 Subject: [PATCH 138/465] Add cross-language LLVM CFI support to the Rust compiler This commit adds cross-language LLVM Control Flow Integrity (CFI) support to the Rust compiler by adding the `-Zsanitizer-cfi-normalize-integers` option to be used with Clang `-fsanitize-cfi-icall-normalize-integers` for normalizing integer types (see https://reviews.llvm.org/D139395). It provides forward-edge control flow protection for C or C++ and Rust -compiled code "mixed binaries" (i.e., for when C or C++ and Rust -compiled code share the same virtual address space). For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, see design document in the tracking issue #89653. Cross-language LLVM CFI can be enabled with -Zsanitizer=cfi and -Zsanitizer-cfi-normalize-integers, and requires proper (i.e., non-rustc) LTO (i.e., -Clinker-plugin-lto). --- src/asm.rs | 2 +- src/builder.rs | 10 ++++++---- src/intrinsic/mod.rs | 14 +++++++------- src/type_.rs | 12 ------------ 4 files changed, 14 insertions(+), 24 deletions(-) diff --git a/src/asm.rs b/src/asm.rs index 65de02b356712..cfbb3057a619a 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -501,7 +501,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { if options.contains(InlineAsmOptions::NORETURN) { let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable"); let builtin_unreachable: RValue<'gcc> = unsafe { std::mem::transmute(builtin_unreachable) }; - self.call(self.type_void(), None, builtin_unreachable, &[], None); + self.call(self.type_void(), None, None, builtin_unreachable, &[], None); } // Write results to outputs. diff --git a/src/builder.rs b/src/builder.rs index a3c8142bea2db..a66ddb6a09f2b 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -35,6 +35,7 @@ use rustc_codegen_ssa::traits::{ }; use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_span::Span; @@ -455,12 +456,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } #[cfg(feature="master")] - fn invoke(&mut self, typ: Type<'gcc>, _fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> { + fn invoke(&mut self, typ: Type<'gcc>, fn_attrs: Option<&CodegenFnAttrs>, _fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> { let try_block = self.current_func().new_block("try"); let current_block = self.block.clone(); self.block = try_block; - let call = self.call(typ, None, func, args, None); // TODO(antoyo): use funclet here? + let call = self.call(typ, fn_attrs, None, func, args, None); // TODO(antoyo): use funclet here? self.block = current_block; let return_value = self.current_func() @@ -483,8 +484,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } #[cfg(not(feature="master"))] - fn invoke(&mut self, typ: Type<'gcc>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> { - let call_site = self.call(typ, None, func, args, None); + fn invoke(&mut self, typ: Type<'gcc>, fn_attrs: &CodegenFnAttrs, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> { + let call_site = self.call(typ, fn_attrs, None, func, args, None); let condition = self.context.new_rvalue_from_int(self.bool_type, 1); self.llbb().end_with_conditional(None, condition, then, catch); if let Some(_fn_abi) = fn_abi { @@ -1351,6 +1352,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn call( &mut self, _typ: Type<'gcc>, + _fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 94dc8c9e93b0d..6017687474726 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -113,7 +113,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { _ if simple.is_some() => { // FIXME(antoyo): remove this cast when the API supports function. let func = unsafe { std::mem::transmute(simple.expect("simple")) }; - self.call(self.type_void(), None, func, &args.iter().map(|arg| arg.immediate()).collect::>(), None) + self.call(self.type_void(), None, None, func, &args.iter().map(|arg| arg.immediate()).collect::>(), None) }, sym::likely => { self.expect(args[0].immediate(), true) @@ -326,7 +326,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let masked = self.and(addr, mask); self.bitcast(masked, void_ptr_type) }, - + _ if name_str.starts_with("simd_") => { match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { Ok(llval) => llval, @@ -354,7 +354,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { fn abort(&mut self) { let func = self.context.get_builtin_function("abort"); let func: RValue<'gcc> = unsafe { std::mem::transmute(func) }; - self.call(self.type_void(), None, func, &[], None); + self.call(self.type_void(), None, None, func, &[], None); } fn assume(&mut self, value: Self::Value) { @@ -1135,7 +1135,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { fn try_intrinsic<'a, 'b, 'gcc, 'tcx>(bx: &'b mut Builder<'a, 'gcc, 'tcx>, try_func: RValue<'gcc>, data: RValue<'gcc>, _catch_func: RValue<'gcc>, dest: RValue<'gcc>) { if bx.sess().panic_strategy() == PanicStrategy::Abort { - bx.call(bx.type_void(), None, try_func, &[data], None); + bx.call(bx.type_void(), None, None, try_func, &[data], None); // Return 0 unconditionally from the intrinsic call; // we can never unwind. let ret_align = bx.tcx.data_layout.i32_align.abi; @@ -1204,21 +1204,21 @@ fn codegen_gnu_try<'gcc>(bx: &mut Builder<'_, 'gcc, '_>, try_func: RValue<'gcc>, let zero = bx.cx.context.new_rvalue_zero(bx.int_type); let ptr = bx.cx.context.new_call(None, eh_pointer_builtin, &[zero]); let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void()); - bx.call(catch_ty, None, catch_func, &[data, ptr], None); + bx.call(catch_ty, None, None, catch_func, &[data, ptr], None); bx.ret(bx.const_i32(1)); // NOTE: the blocks must be filled before adding the try/catch, otherwise gcc will not // generate a try/catch. // FIXME(antoyo): add a check in the libgccjit API to prevent this. bx.switch_to_block(current_block); - bx.invoke(try_func_ty, None, try_func, &[data], then, catch, None); + bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None); }); let func = unsafe { std::mem::transmute(func) }; // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). - let ret = bx.call(llty, None, func, &[try_func, data, catch_func], None); + let ret = bx.call(llty, None, None, func, &[try_func, data, catch_func], None); let i32_align = bx.tcx().data_layout.i32_align.abi; bx.store(ret, dest, i32_align); } diff --git a/src/type_.rs b/src/type_.rs index daa661f35c4c1..521b64ad34d15 100644 --- a/src/type_.rs +++ b/src/type_.rs @@ -280,16 +280,4 @@ pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout } impl<'gcc, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'gcc, 'tcx> { - fn set_type_metadata(&self, _function: RValue<'gcc>, _typeid: String) { - // Unsupported. - } - - fn typeid_metadata(&self, _typeid: String) -> RValue<'gcc> { - // Unsupported. - self.context.new_rvalue_from_int(self.int_type, 0) - } - - fn set_kcfi_type_metadata(&self, _function: RValue<'gcc>, _kcfi_typeid: u32) { - // Unsupported. - } } From 77375ab81447300542d5533db3189bb1a38bcb93 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 6 Nov 2022 21:24:20 +0000 Subject: [PATCH 139/465] Use `landingpad filter` to encode aborting landing pad --- src/builder.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/builder.rs b/src/builder.rs index a66ddb6a09f2b..5fba09d795ce8 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1227,6 +1227,10 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { (value1, value2) } + fn filter_landing_pad(&mut self, pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { + self.cleanup_landing_pad(pers_fn) + } + #[cfg(feature="master")] fn resume(&mut self, exn0: RValue<'gcc>, _exn1: RValue<'gcc>) { let exn_type = exn0.get_type(); From 59177fcb60cdccd7c6e5958f36bd4d2300fafcda Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 8 Apr 2023 13:12:24 +0100 Subject: [PATCH 140/465] Add todo for filter landing pad --- src/builder.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/builder.rs b/src/builder.rs index 5fba09d795ce8..869344ce92d7d 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1228,6 +1228,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn filter_landing_pad(&mut self, pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { + // TODO(antoyo): generate the correct landing pad self.cleanup_landing_pad(pers_fn) } From 35836b326b600728f1b4e8724d38fb8e469119c1 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 3 Jul 2021 16:46:41 +0200 Subject: [PATCH 141/465] Don't use an allocator shim for `#[global_allocator]` This makes it possible to use liballoc/libstd in combination with `--emit obj` if you use `#[global_allocator]`. Making it work for the default libstd allocator would require weak functions, which are not well supported on all systems. --- src/allocator.rs | 119 ++++++++++++++++++++++++----------------------- 1 file changed, 61 insertions(+), 58 deletions(-) diff --git a/src/allocator.rs b/src/allocator.rs index 4bad33ee879ee..f4105b91e9848 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -1,11 +1,12 @@ #[cfg(feature="master")] use gccjit::FnAttribute; use gccjit::{FunctionType, GlobalKind, ToRValue}; -use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS}; +use rustc_ast::expand::allocator::{ + alloc_error_handler_name, AllocatorKind, AllocatorTy, ALLOCATOR_METHODS, +}; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::config::OomStrategy; -use rustc_span::symbol::sym; use crate::GccContext; @@ -22,69 +23,71 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam let i8p = i8.make_pointer(); let void = context.new_type::<()>(); - for method in ALLOCATOR_METHODS { - let mut types = Vec::with_capacity(method.inputs.len()); - for ty in method.inputs.iter() { - match *ty { - AllocatorTy::Layout => { - types.push(usize); - types.push(usize); + if kind == AllocatorKind::Default { + for method in ALLOCATOR_METHODS { + let mut types = Vec::with_capacity(method.inputs.len()); + for ty in method.inputs.iter() { + match *ty { + AllocatorTy::Layout => { + types.push(usize); + types.push(usize); + } + AllocatorTy::Ptr => types.push(i8p), + AllocatorTy::Usize => types.push(usize), + + AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"), } - AllocatorTy::Ptr => types.push(i8p), - AllocatorTy::Usize => types.push(usize), - - AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"), } - } - let output = match method.output { - AllocatorTy::ResultPtr => Some(i8p), - AllocatorTy::Unit => None, + let output = match method.output { + AllocatorTy::ResultPtr => Some(i8p), + AllocatorTy::Unit => None, - AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { - panic!("invalid allocator output") - } - }; - let name = format!("__rust_{}", method.name); + AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { + panic!("invalid allocator output") + } + }; + let name = format!("__rust_{}", method.name); + + let args: Vec<_> = types.iter().enumerate() + .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) + .collect(); + let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, name, false); - let args: Vec<_> = types.iter().enumerate() - .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) - .collect(); - let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, name, false); + if tcx.sess.target.options.default_hidden_visibility { + #[cfg(feature="master")] + func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); + } + if tcx.sess.must_emit_unwind_tables() { + // TODO(antoyo): emit unwind tables. + } - if tcx.sess.target.options.default_hidden_visibility { + let callee = AllocatorKind::Default.fn_name(method.name); + let args: Vec<_> = types.iter().enumerate() + .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) + .collect(); + let callee = context.new_function(None, FunctionType::Extern, output.unwrap_or(void), &args, callee, false); #[cfg(feature="master")] - func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); - } - if tcx.sess.must_emit_unwind_tables() { - // TODO(antoyo): emit unwind tables. - } + callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); + + let block = func.new_block("entry"); + + let args = args + .iter() + .enumerate() + .map(|(i, _)| func.get_param(i as i32).to_rvalue()) + .collect::>(); + let ret = context.new_call(None, callee, &args); + //llvm::LLVMSetTailCall(ret, True); + if output.is_some() { + block.end_with_return(None, ret); + } + else { + block.end_with_void_return(None); + } - let callee = kind.fn_name(method.name); - let args: Vec<_> = types.iter().enumerate() - .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) - .collect(); - let callee = context.new_function(None, FunctionType::Extern, output.unwrap_or(void), &args, callee, false); - #[cfg(feature="master")] - callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); - - let block = func.new_block("entry"); - - let args = args - .iter() - .enumerate() - .map(|(i, _)| func.get_param(i as i32).to_rvalue()) - .collect::>(); - let ret = context.new_call(None, callee, &args); - //llvm::LLVMSetTailCall(ret, True); - if output.is_some() { - block.end_with_return(None, ret); - } - else { - block.end_with_void_return(None); + // TODO(@Commeownist): Check if we need to emit some extra debugging info in certain circumstances + // as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643 } - - // TODO(@Commeownist): Check if we need to emit some extra debugging info in certain circumstances - // as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643 } let types = [usize, usize]; @@ -99,7 +102,7 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); } - let callee = alloc_error_handler_kind.fn_name(sym::oom); + let callee = alloc_error_handler_name(alloc_error_handler_kind); let args: Vec<_> = types.iter().enumerate() .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) .collect(); From c50427ba86aadcbec86bf9b35f0c32ee818c7705 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 3 Jul 2021 17:50:53 +0200 Subject: [PATCH 142/465] Split AllocatorKind::fn_name in global_fn_name and default_fn_name --- src/allocator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/allocator.rs b/src/allocator.rs index f4105b91e9848..fe143aaad5fe7 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -2,7 +2,7 @@ use gccjit::FnAttribute; use gccjit::{FunctionType, GlobalKind, ToRValue}; use rustc_ast::expand::allocator::{ - alloc_error_handler_name, AllocatorKind, AllocatorTy, ALLOCATOR_METHODS, + alloc_error_handler_name, default_fn_name, AllocatorKind, AllocatorTy, ALLOCATOR_METHODS, }; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; @@ -61,7 +61,7 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam // TODO(antoyo): emit unwind tables. } - let callee = AllocatorKind::Default.fn_name(method.name); + let callee = default_fn_name(method.name); let args: Vec<_> = types.iter().enumerate() .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) .collect(); From 2be697f60d53fe321a74fb99d3cde452a94eb3da Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 6 Jul 2021 18:56:01 +0200 Subject: [PATCH 143/465] Use global_fn_name instead of format! --- src/allocator.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/allocator.rs b/src/allocator.rs index fe143aaad5fe7..ff68de8c8f1dd 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -2,7 +2,8 @@ use gccjit::FnAttribute; use gccjit::{FunctionType, GlobalKind, ToRValue}; use rustc_ast::expand::allocator::{ - alloc_error_handler_name, default_fn_name, AllocatorKind, AllocatorTy, ALLOCATOR_METHODS, + alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy, + ALLOCATOR_METHODS, }; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; @@ -46,7 +47,7 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam panic!("invalid allocator output") } }; - let name = format!("__rust_{}", method.name); + let name = global_fn_name(method.name); let args: Vec<_> = types.iter().enumerate() .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) From da466a2adc6aa4a1250a7022d216b35ef25e3fbd Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 10 Sep 2022 11:33:44 +0000 Subject: [PATCH 144/465] Prevent insta-stable no alloc shim support You will need to add the following as replacement for the old __rust_* definitions when not using the alloc shim. #[no_mangle] static __rust_no_alloc_shim_is_unstable: u8 = 0; --- src/allocator.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/allocator.rs b/src/allocator.rs index ff68de8c8f1dd..13f88192bbc90 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -3,7 +3,7 @@ use gccjit::FnAttribute; use gccjit::{FunctionType, GlobalKind, ToRValue}; use rustc_ast::expand::allocator::{ alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy, - ALLOCATOR_METHODS, + ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE, }; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; @@ -127,4 +127,9 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam let value = tcx.sess.opts.unstable_opts.oom.should_panic(); let value = context.new_rvalue_from_int(i8, value as i32); global.global_set_initializer_rvalue(value); + + let name = NO_ALLOC_SHIM_IS_UNSTABLE.to_string(); + let global = context.new_global(None, GlobalKind::Exported, i8, name); + let value = context.new_rvalue_from_int(i8, 0); + global.global_set_initializer_rvalue(value); } From e5b58425f67107e59aa062ecd1be250e0bbd4c8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 15 May 2023 06:24:45 +0200 Subject: [PATCH 145/465] Move expansion of query macros in rustc_middle to rustc_middle::query --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 1cabb05de975b..442ce0ea54209 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,8 +80,8 @@ use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, Handler, SubdiagnosticMes use rustc_fluent_macro::fluent_messages; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_middle::ty::query::Providers; use rustc_session::config::{Lto, OptLevel, OutputFilenames}; use rustc_session::Session; use rustc_span::Symbol; From a512e98028bf830e1ebc0fa018d210801c86793c Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 25 May 2023 09:17:59 -0400 Subject: [PATCH 146/465] Set visibility of global --- src/consts.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/consts.rs b/src/consts.rs index 792ab8f890d8f..56513c29ce09b 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -1,5 +1,5 @@ #[cfg(feature = "master")] -use gccjit::FnAttribute; +use gccjit::{FnAttribute, VarAttribute, Visibility}; use gccjit::{Function, GlobalKind, LValue, RValue, ToRValue, Type}; use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, DerivedTypeMethods, StaticMethods}; use rustc_middle::span_bug; @@ -249,7 +249,8 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { ); if !self.tcx.is_reachable_non_generic(def_id) { - // TODO(antoyo): set visibility. + #[cfg(feature = "master")] + global.add_attribute(VarAttribute::Visibility(Visibility::Hidden)); } global From d9d12d7c369f96e76bbe93224d8774a333c4b1b1 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Tue, 23 May 2023 01:51:25 +0000 Subject: [PATCH 147/465] Ensure Fluent messages are in alphabetical order --- messages.ftl | 66 ++++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/messages.ftl b/messages.ftl index 0a94a08f8dca8..97bc8ef9d1bba 100644 --- a/messages.ftl +++ b/messages.ftl @@ -1,68 +1,68 @@ -codegen_gcc_unwinding_inline_asm = - GCC backend does not support unwinding from inline asm - -codegen_gcc_lto_not_supported = - LTO is not supported. You may get a linker error. +codegen_gcc_invalid_minimum_alignment = + invalid minimum global alignment: {$err} codegen_gcc_invalid_monomorphization_basic_integer = invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}` -codegen_gcc_invalid_monomorphization_invalid_float_vector = - invalid monomorphization of `{$name}` intrinsic: unsupported element type `{$elem_ty}` of floating-point vector `{$vec_ty}` - -codegen_gcc_invalid_monomorphization_not_float = - invalid monomorphization of `{$name}` intrinsic: `{$ty}` is not a floating-point type - -codegen_gcc_invalid_monomorphization_unrecognized = - invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}` - codegen_gcc_invalid_monomorphization_expected_signed_unsigned = invalid monomorphization of `{$name}` intrinsic: expected element type `{$elem_ty}` of vector type `{$vec_ty}` to be a signed or unsigned integer type -codegen_gcc_invalid_monomorphization_unsupported_element = - invalid monomorphization of `{$name}` intrinsic: unsupported {$name} from `{$in_ty}` with element `{$elem_ty}` to `{$ret_ty}` +codegen_gcc_invalid_monomorphization_expected_simd = + invalid monomorphization of `{$name}` intrinsic: expected SIMD {$expected_ty} type, found non-SIMD `{$found_ty}` + +codegen_gcc_invalid_monomorphization_inserted_type = + invalid monomorphization of `{$name}` intrinsic: expected inserted type `{$in_elem}` (element of input `{$in_ty}`), found `{$out_ty}` codegen_gcc_invalid_monomorphization_invalid_bitmask = invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]` -codegen_gcc_invalid_monomorphization_simd_shuffle = - invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}` - -codegen_gcc_invalid_monomorphization_expected_simd = - invalid monomorphization of `{$name}` intrinsic: expected SIMD {$expected_ty} type, found non-SIMD `{$found_ty}` +codegen_gcc_invalid_monomorphization_invalid_float_vector = + invalid monomorphization of `{$name}` intrinsic: unsupported element type `{$elem_ty}` of floating-point vector `{$vec_ty}` codegen_gcc_invalid_monomorphization_mask_type = invalid monomorphization of `{$name}` intrinsic: mask element type is `{$ty}`, expected `i_` +codegen_gcc_invalid_monomorphization_mismatched_lengths = + invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}` + +codegen_gcc_invalid_monomorphization_not_float = + invalid monomorphization of `{$name}` intrinsic: `{$ty}` is not a floating-point type + +codegen_gcc_invalid_monomorphization_return_element = + invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}` + +codegen_gcc_invalid_monomorphization_return_integer_type = + invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}` + codegen_gcc_invalid_monomorphization_return_length = invalid monomorphization of `{$name}` intrinsic: expected return type of length {$in_len}, found `{$ret_ty}` with length {$out_len} codegen_gcc_invalid_monomorphization_return_length_input_type = invalid monomorphization of `{$name}` intrinsic: expected return type with length {$in_len} (same as input type `{$in_ty}`), found `{$ret_ty}` with length {$out_len} -codegen_gcc_invalid_monomorphization_return_element = - invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}` - codegen_gcc_invalid_monomorphization_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` -codegen_gcc_invalid_monomorphization_inserted_type = - invalid monomorphization of `{$name}` intrinsic: expected inserted type `{$in_elem}` (element of input `{$in_ty}`), found `{$out_ty}` - -codegen_gcc_invalid_monomorphization_return_integer_type = - invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}` +codegen_gcc_invalid_monomorphization_simd_shuffle = + invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}` -codegen_gcc_invalid_monomorphization_mismatched_lengths = - invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}` +codegen_gcc_invalid_monomorphization_unrecognized = + invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}` codegen_gcc_invalid_monomorphization_unsupported_cast = invalid monomorphization of `{$name}` intrinsic: unsupported cast from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}` with element `{$out_elem}` +codegen_gcc_invalid_monomorphization_unsupported_element = + invalid monomorphization of `{$name}` intrinsic: unsupported {$name} from `{$in_ty}` with element `{$elem_ty}` to `{$ret_ty}` + codegen_gcc_invalid_monomorphization_unsupported_operation = invalid monomorphization of `{$name}` intrinsic: unsupported operation on `{$in_ty}` with element `{$in_elem}` -codegen_gcc_invalid_minimum_alignment = - invalid minimum global alignment: {$err} +codegen_gcc_lto_not_supported = + LTO is not supported. You may get a linker error. codegen_gcc_tied_target_features = the target features {$features} must all be either enabled or disabled together .help = add the missing features in a `target_feature` attribute + +codegen_gcc_unwinding_inline_asm = + GCC backend does not support unwinding from inline asm From 80efecf18caf639184315645f3abdae19e3ee5af Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 19 May 2023 15:48:43 +0000 Subject: [PATCH 148/465] Stop creating intermediate places just to immediate convert them to operands --- src/common.rs | 42 +++++++++++++++++++----------------------- src/consts.rs | 17 +---------------- 2 files changed, 20 insertions(+), 39 deletions(-) diff --git a/src/common.rs b/src/common.rs index ac04b61a30672..bad87db47323e 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,17 +1,15 @@ use gccjit::LValue; use gccjit::{RValue, Type, ToRValue}; -use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{ BaseTypeMethods, ConstMethods, - DerivedTypeMethods, MiscMethods, StaticMethods, }; use rustc_middle::mir::Mutability; -use rustc_middle::ty::layout::{TyAndLayout, LayoutOf}; +use rustc_middle::ty::layout::{LayoutOf}; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; -use rustc_target::abi::{self, HasDataLayout, Pointer, Size}; +use rustc_target::abi::{self, HasDataLayout, Pointer}; use crate::consts::const_alloc_to_gcc; use crate::context::CodegenCx; @@ -240,28 +238,26 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { const_alloc_to_gcc(self, alloc) } - fn from_const_alloc(&self, layout: TyAndLayout<'tcx>, alloc: ConstAllocation<'tcx>, offset: Size) -> PlaceRef<'tcx, RValue<'gcc>> { - assert_eq!(alloc.inner().align, layout.align.abi); - let ty = self.type_ptr_to(layout.gcc_type(self)); - let value = - if layout.size == Size::ZERO { - let value = self.const_usize(alloc.inner().align.bytes()); - self.const_bitcast(value, ty) - } - else { - let init = const_alloc_to_gcc(self, alloc); - let base_addr = self.static_addr_of(init, alloc.inner().align, None); - - let array = self.const_bitcast(base_addr, self.type_i8p()); - let value = self.context.new_array_access(None, array, self.const_usize(offset.bytes())).get_address(None); - self.const_bitcast(value, ty) - }; - PlaceRef::new_sized(value, layout) - } - fn const_ptrcast(&self, val: RValue<'gcc>, ty: Type<'gcc>) -> RValue<'gcc> { self.context.new_cast(None, val, ty) } + + fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> { + if value.get_type() == self.bool_type.make_pointer() { + if let Some(pointee) = typ.get_pointee() { + if pointee.dyncast_vector().is_some() { + panic!() + } + } + } + // NOTE: since bitcast makes a value non-constant, don't bitcast if not necessary as some + // SIMD builtins require a constant value. + self.bitcast_if_needed(value, typ) + } + + fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { + self.context.new_array_access(None, base_addr, self.const_usize(offset.bytes())).get_address(None) + } } pub trait SignType<'gcc, 'tcx> { diff --git a/src/consts.rs b/src/consts.rs index 792ab8f890d8f..873f652e6f147 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -1,6 +1,6 @@ #[cfg(feature = "master")] use gccjit::FnAttribute; -use gccjit::{Function, GlobalKind, LValue, RValue, ToRValue, Type}; +use gccjit::{Function, GlobalKind, LValue, RValue, ToRValue}; use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, DerivedTypeMethods, StaticMethods}; use rustc_middle::span_bug; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; @@ -16,21 +16,6 @@ use crate::context::CodegenCx; use crate::errors::InvalidMinimumAlignment; use crate::type_of::LayoutGccExt; -impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { - pub fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> { - if value.get_type() == self.bool_type.make_pointer() { - if let Some(pointee) = typ.get_pointee() { - if pointee.dyncast_vector().is_some() { - panic!() - } - } - } - // NOTE: since bitcast makes a value non-constant, don't bitcast if not necessary as some - // SIMD builtins require a constant value. - self.bitcast_if_needed(value, typ) - } -} - fn set_global_alignment<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, gv: LValue<'gcc>, mut align: Align) { // The target may require greater alignment for globals than the type does. // Note: GCC and Clang also allow `__attribute__((aligned))` on variables, From 67f1c3cd16f91ef104aa2ad1227a038b8951c71e Mon Sep 17 00:00:00 2001 From: David Lattimore Date: Wed, 17 May 2023 16:47:24 +1000 Subject: [PATCH 149/465] autopublish: Offset version number The workflow is currently failing because it's trying to publish 0.0.16, while the last version published was 0.0.149. --- .github/workflows/autopublish.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/autopublish.yaml b/.github/workflows/autopublish.yaml index 7090c94d93cce..15cedab127264 100644 --- a/.github/workflows/autopublish.yaml +++ b/.github/workflows/autopublish.yaml @@ -28,7 +28,7 @@ jobs: - name: Publish Crates env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} - PATCH: ${{ github.run_number }} + RUN_NUMBER: ${{ github.run_number }} shell: bash run: | git config --global user.email "runner@gha.local" @@ -53,4 +53,4 @@ jobs: # Remove library crates from the workspaces so we don't auto-publish them as well sed -i 's/ "lib\/\*",//' ./Cargo.toml find crates/rust-analyzer -type f -name '*.rs' -exec sed -i 's/rust_analyzer/ra_ap_rust_analyzer/g' {} + - cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$PATCH + cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$(($RUN_NUMBER + 133)) From 3d0a0dccae89da3ef057dda6e84d480f7888eee9 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 7 May 2023 03:00:41 -0700 Subject: [PATCH 150/465] Add a distinct `OperandValue::ZeroSized` variant for ZSTs These tend to have special handling in a bunch of places anyway, so the variant helps remember that. And I think it's easier to grok than non-Scalar Aggregates sometimes being `Immediates` (like I got wrong and caused 109992). As a minor bonus, it means we don't need to generate poison LLVM values for them to pass around in `OperandValue::Immediate`s. --- src/builder.rs | 2 +- src/type_of.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 869344ce92d7d..f9ea0f004564b 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -758,7 +758,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { assert_eq!(place.llextra.is_some(), place.layout.is_unsized()); if place.layout.is_zst() { - return OperandRef::new_zst(self, place.layout); + return OperandRef::zero_sized(place.layout); } fn scalar_load_metadata<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, load: RValue<'gcc>, scalar: &abi::Scalar) { diff --git a/src/type_of.rs b/src/type_of.rs index 5df8c1a209db2..30a3fe67b8543 100644 --- a/src/type_of.rs +++ b/src/type_of.rs @@ -159,8 +159,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { fn is_gcc_immediate(&self) -> bool { match self.abi { Abi::Scalar(_) | Abi::Vector { .. } => true, - Abi::ScalarPair(..) => false, - Abi::Uninhabited | Abi::Aggregate { .. } => self.is_zst(), + Abi::ScalarPair(..) | Abi::Uninhabited | Abi::Aggregate { .. } => false, } } From f16ca93dedd8f4b314e0276a2bbab011af1c9112 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 17 May 2023 10:30:14 +0000 Subject: [PATCH 151/465] Use translatable diagnostics in `rustc_const_eval` --- src/consts.rs | 2 +- src/context.rs | 15 +++------------ 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/consts.rs b/src/consts.rs index 873f652e6f147..33e3b0baa9236 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -24,7 +24,7 @@ fn set_global_alignment<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, gv: LValue<'gcc> match Align::from_bits(min) { Ok(min) => align = align.max(min), Err(err) => { - cx.sess().emit_err(InvalidMinimumAlignment { err }); + cx.sess().emit_err(InvalidMinimumAlignment { err: err.to_string() }); } } } diff --git a/src/context.rs b/src/context.rs index 661681bdb50f2..08507e19652b4 100644 --- a/src/context.rs +++ b/src/context.rs @@ -477,7 +477,7 @@ impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { if let LayoutError::SizeOverflow(_) = err { - self.sess().emit_fatal(respan(span, err)) + self.sess().emit_fatal(respan(span, err.into_diagnostic())) } else { span_bug!(span, "failed to get layout for `{}`: {}", ty, err) } @@ -499,21 +499,12 @@ impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { } else { match fn_abi_request { FnAbiRequest::OfFnPtr { sig, extra_args } => { - span_bug!( - span, - "`fn_abi_of_fn_ptr({}, {:?})` failed: {}", - sig, - extra_args, - err - ); + span_bug!(span, "`fn_abi_of_fn_ptr({sig}, {extra_args:?})` failed: {err:?}"); } FnAbiRequest::OfInstance { instance, extra_args } => { span_bug!( span, - "`fn_abi_of_instance({}, {:?})` failed: {}", - instance, - extra_args, - err + "`fn_abi_of_instance({instance}, {extra_args:?})` failed: {err:?}" ); } } From 2c6b9792955336ad25feb64cf040fd9be5dccb7c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 2 Jun 2023 16:22:50 +0200 Subject: [PATCH 152/465] Regen intrinsics with latest LLVM version --- src/intrinsic/archs.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/intrinsic/archs.rs b/src/intrinsic/archs.rs index 8cd8d1bfb429f..3fc1dfdb44754 100644 --- a/src/intrinsic/archs.rs +++ b/src/intrinsic/archs.rs @@ -2967,10 +2967,6 @@ match name { "llvm.nvvm.clz.ll" => "__nvvm_clz_ll", "llvm.nvvm.cos.approx.f" => "__nvvm_cos_approx_f", "llvm.nvvm.cos.approx.ftz.f" => "__nvvm_cos_approx_ftz_f", - "llvm.nvvm.cp.async.ca.shared.global.16" => "__nvvm_cp_async_ca_shared_global_16", - "llvm.nvvm.cp.async.ca.shared.global.4" => "__nvvm_cp_async_ca_shared_global_4", - "llvm.nvvm.cp.async.ca.shared.global.8" => "__nvvm_cp_async_ca_shared_global_8", - "llvm.nvvm.cp.async.cg.shared.global.16" => "__nvvm_cp_async_cg_shared_global_16", "llvm.nvvm.cp.async.commit.group" => "__nvvm_cp_async_commit_group", "llvm.nvvm.cp.async.mbarrier.arrive" => "__nvvm_cp_async_mbarrier_arrive", "llvm.nvvm.cp.async.mbarrier.arrive.noinc" => "__nvvm_cp_async_mbarrier_arrive_noinc", From fe8f862757bd45c12f785bc3ca2f467ee1369092 Mon Sep 17 00:00:00 2001 From: ponyii Date: Tue, 23 May 2023 00:05:55 +0400 Subject: [PATCH 153/465] made the `add_missing_impl_members` and `add_missing_default_members` assists transform lifetimes --- crates/hir/src/lib.rs | 11 ++- .../src/handlers/add_missing_impl_members.rs | 53 ++++++++++++ crates/ide-db/src/path_transform.rs | 81 +++++++++++++------ 3 files changed, 116 insertions(+), 29 deletions(-) diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 2db4b483b69d4..1fc18767d6cb3 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2637,14 +2637,19 @@ impl GenericDef { Either::Right(x) => GenericParam::TypeParam(x), } }); - let lt_params = generics + self.lifetime_params(db).into_iter().chain(ty_params).collect() + } + + pub fn lifetime_params(self, db: &dyn HirDatabase) -> Vec { + let generics = db.generic_params(self.into()); + generics .lifetimes .iter() .map(|(local_id, _)| LifetimeParam { id: LifetimeParamId { parent: self.into(), local_id }, }) - .map(GenericParam::LifetimeParam); - lt_params.chain(ty_params).collect() + .map(GenericParam::LifetimeParam) + .collect() } pub fn type_params(self, db: &dyn HirDatabase) -> Vec { diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 6340feda452e1..ae5118e950abe 100644 --- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -365,6 +365,59 @@ impl Foo for S { ); } + #[test] + fn test_lifetime_substitution() { + check_assist( + add_missing_impl_members, + r#" +pub trait Trait<'a, 'b, A, B, C> { + fn foo(&self, one: &'a A, anoter: &'b B) -> &'a C; +} + +impl<'x, 'y, T, V, U> Trait<'x, 'y, T, V, U> for () {$0}"#, + r#" +pub trait Trait<'a, 'b, A, B, C> { + fn foo(&self, one: &'a A, anoter: &'b B) -> &'a C; +} + +impl<'x, 'y, T, V, U> Trait<'x, 'y, T, V, U> for () { + fn foo(&self, one: &'x T, anoter: &'y V) -> &'x U { + ${0:todo!()} + } +}"#, + ); + } + + #[test] + fn test_lifetime_substitution_with_body() { + check_assist( + add_missing_default_members, + r#" +pub trait Trait<'a, 'b, A, B, C: Default> { + fn foo(&self, _one: &'a A, _anoter: &'b B) -> (C, &'a i32) { + let value: &'a i32 = &0; + (C::default(), value) + } +} + +impl<'x, 'y, T, V, U: Default> Trait<'x, 'y, T, V, U> for () {$0}"#, + r#" +pub trait Trait<'a, 'b, A, B, C: Default> { + fn foo(&self, _one: &'a A, _anoter: &'b B) -> (C, &'a i32) { + let value: &'a i32 = &0; + (C::default(), value) + } +} + +impl<'x, 'y, T, V, U: Default> Trait<'x, 'y, T, V, U> for () { + $0fn foo(&self, _one: &'x T, _anoter: &'y V) -> (U, &'x i32) { + let value: &'x i32 = &0; + (::default(), value) + } +}"#, + ); + } + #[test] fn test_cursor_after_empty_impl_def() { check_assist( diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs index 0ee627a44c68e..fe8ffc4354a86 100644 --- a/crates/ide-db/src/path_transform.rs +++ b/crates/ide-db/src/path_transform.rs @@ -9,6 +9,14 @@ use syntax::{ ted, SyntaxNode, }; +#[derive(Default)] +struct Substs { + types: Vec, + lifetimes: Vec, +} + +type LifetimeName = String; + /// `PathTransform` substitutes path in SyntaxNodes in bulk. /// /// This is mostly useful for IDE code generation. If you paste some existing @@ -34,7 +42,7 @@ use syntax::{ /// ``` pub struct PathTransform<'a> { generic_def: Option, - substs: Vec, + substs: Substs, target_scope: &'a SemanticsScope<'a>, source_scope: &'a SemanticsScope<'a>, } @@ -72,7 +80,7 @@ impl<'a> PathTransform<'a> { target_scope: &'a SemanticsScope<'a>, source_scope: &'a SemanticsScope<'a>, ) -> PathTransform<'a> { - PathTransform { source_scope, target_scope, generic_def: None, substs: Vec::new() } + PathTransform { source_scope, target_scope, generic_def: None, substs: Substs::default() } } pub fn apply(&self, syntax: &SyntaxNode) { @@ -91,11 +99,11 @@ impl<'a> PathTransform<'a> { let target_module = self.target_scope.module(); let source_module = self.source_scope.module(); let skip = match self.generic_def { - // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky + // this is a trait impl, so we need to skip the first type parameter (i.e. Self) -- this is a bit hacky Some(hir::GenericDef::Trait(_)) => 1, _ => 0, }; - let substs_by_param: FxHashMap<_, _> = self + let type_substs: FxHashMap<_, _> = self .generic_def .into_iter() .flat_map(|it| it.type_params(db)) @@ -106,31 +114,35 @@ impl<'a> PathTransform<'a> { // can still hit those trailing values and check if they actually have // a default type. If they do, go for that type from `hir` to `ast` so // the resulting change can be applied correctly. - .zip(self.substs.iter().map(Some).chain(std::iter::repeat(None))) + .zip(self.substs.types.iter().map(Some).chain(std::iter::repeat(None))) .filter_map(|(k, v)| match k.split(db) { - Either::Left(_) => None, + Either::Left(_) => None, // FIXME: map const types too Either::Right(t) => match v { - Some(v) => Some((k, v.clone())), + Some(v) => Some((k, v.ty()?.clone())), None => { let default = t.default(db)?; - Some(( - k, - ast::make::ty( - &default - .display_source_code(db, source_module.into(), false) - .ok()?, - ), - )) + let v = ast::make::ty( + &default.display_source_code(db, source_module.into(), false).ok()?, + ); + Some((k, v)) } }, }) .collect(); - Ctx { substs: substs_by_param, target_module, source_scope: self.source_scope } + let lifetime_substs: FxHashMap<_, _> = self + .generic_def + .into_iter() + .flat_map(|it| it.lifetime_params(db)) + .zip(self.substs.lifetimes.clone()) + .filter_map(|(k, v)| Some((k.name(db).to_string(), v.lifetime()?))) + .collect(); + Ctx { type_substs, lifetime_substs, target_module, source_scope: self.source_scope } } } struct Ctx<'a> { - substs: FxHashMap, + type_substs: FxHashMap, + lifetime_substs: FxHashMap, target_module: hir::Module, source_scope: &'a SemanticsScope<'a>, } @@ -152,7 +164,24 @@ impl<'a> Ctx<'a> { for path in paths { self.transform_path(path); } + + item.preorder() + .filter_map(|event| match event { + syntax::WalkEvent::Enter(_) => None, + syntax::WalkEvent::Leave(node) => Some(node), + }) + .filter_map(ast::Lifetime::cast) + .for_each(|lifetime| { + if let Some(subst) = self.lifetime_substs.get(&lifetime.syntax().text().to_string()) + { + ted::replace( + lifetime.syntax(), + subst.clone_subtree().clone_for_update().syntax(), + ); + } + }); } + fn transform_path(&self, path: ast::Path) -> Option<()> { if path.qualifier().is_some() { return None; @@ -169,7 +198,7 @@ impl<'a> Ctx<'a> { match resolution { hir::PathResolution::TypeParam(tp) => { - if let Some(subst) = self.substs.get(&tp.merge()) { + if let Some(subst) = self.type_substs.get(&tp.merge()) { let parent = path.syntax().parent()?; if let Some(parent) = ast::Path::cast(parent.clone()) { // Path inside path means that there is an associated @@ -250,7 +279,7 @@ impl<'a> Ctx<'a> { // FIXME: It would probably be nicer if we could get this via HIR (i.e. get the // trait ref, and then go from the types in the substs back to the syntax). -fn get_syntactic_substs(impl_def: ast::Impl) -> Option> { +fn get_syntactic_substs(impl_def: ast::Impl) -> Option { let target_trait = impl_def.trait_()?; let path_type = match target_trait { ast::Type::PathType(path) => path, @@ -261,13 +290,13 @@ fn get_syntactic_substs(impl_def: ast::Impl) -> Option> { get_type_args_from_arg_list(generic_arg_list) } -fn get_type_args_from_arg_list(generic_arg_list: ast::GenericArgList) -> Option> { - let mut result = Vec::new(); - for generic_arg in generic_arg_list.generic_args() { - if let ast::GenericArg::TypeArg(type_arg) = generic_arg { - result.push(type_arg.ty()?) - } - } +fn get_type_args_from_arg_list(generic_arg_list: ast::GenericArgList) -> Option { + let mut result = Substs::default(); + generic_arg_list.generic_args().for_each(|generic_arg| match generic_arg { + ast::GenericArg::TypeArg(type_arg) => result.types.push(type_arg), + ast::GenericArg::LifetimeArg(l_arg) => result.lifetimes.push(l_arg), + _ => (), // FIXME: don't filter out const params + }); Some(result) } From 7f45cccda44341e87404834ccd13618f9cac3c2b Mon Sep 17 00:00:00 2001 From: ponyii Date: Sun, 28 May 2023 21:15:57 +0400 Subject: [PATCH 154/465] lifetime transformation: refactoring & a new test --- crates/hir/src/lib.rs | 9 ++++--- .../src/completions/item_list/trait_impl.rs | 27 +++++++++++++++++++ crates/ide-db/src/path_transform.rs | 19 ++++++++----- 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 1fc18767d6cb3..604b1cb5228d5 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2637,10 +2637,14 @@ impl GenericDef { Either::Right(x) => GenericParam::TypeParam(x), } }); - self.lifetime_params(db).into_iter().chain(ty_params).collect() + self.lifetime_params(db) + .into_iter() + .map(GenericParam::LifetimeParam) + .chain(ty_params) + .collect() } - pub fn lifetime_params(self, db: &dyn HirDatabase) -> Vec { + pub fn lifetime_params(self, db: &dyn HirDatabase) -> Vec { let generics = db.generic_params(self.into()); generics .lifetimes @@ -2648,7 +2652,6 @@ impl GenericDef { .map(|(local_id, _)| LifetimeParam { id: LifetimeParamId { parent: self.into(), local_id }, }) - .map(GenericParam::LifetimeParam) .collect() } diff --git a/crates/ide-completion/src/completions/item_list/trait_impl.rs b/crates/ide-completion/src/completions/item_list/trait_impl.rs index 7de1bf2dc131f..664aa7b8397ea 100644 --- a/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -833,6 +833,33 @@ impl Test for () { ); } + #[test] + fn fn_with_lifetimes() { + check_edit( + "fn foo", + r#" +trait Test<'a, 'b, T> { + fn foo(&self, a: &'a T, b: &'b T) -> &'a T; +} + +impl<'x, 'y, A> Test<'x, 'y, A> for () { + t$0 +} +"#, + r#" +trait Test<'a, 'b, T> { + fn foo(&self, a: &'a T, b: &'b T) -> &'a T; +} + +impl<'x, 'y, A> Test<'x, 'y, A> for () { + fn foo(&self, a: &'x A, b: &'y A) -> &'x A { + $0 +} +} +"#, + ); + } + #[test] fn complete_without_name() { let test = |completion: &str, hint: &str, completed: &str, next_sibling: &str| { diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs index fe8ffc4354a86..6afd61e84dc62 100644 --- a/crates/ide-db/src/path_transform.rs +++ b/crates/ide-db/src/path_transform.rs @@ -10,7 +10,7 @@ use syntax::{ }; #[derive(Default)] -struct Substs { +struct AstSubsts { types: Vec, lifetimes: Vec, } @@ -42,7 +42,7 @@ type LifetimeName = String; /// ``` pub struct PathTransform<'a> { generic_def: Option, - substs: Substs, + substs: AstSubsts, target_scope: &'a SemanticsScope<'a>, source_scope: &'a SemanticsScope<'a>, } @@ -80,7 +80,12 @@ impl<'a> PathTransform<'a> { target_scope: &'a SemanticsScope<'a>, source_scope: &'a SemanticsScope<'a>, ) -> PathTransform<'a> { - PathTransform { source_scope, target_scope, generic_def: None, substs: Substs::default() } + PathTransform { + source_scope, + target_scope, + generic_def: None, + substs: AstSubsts::default(), + } } pub fn apply(&self, syntax: &SyntaxNode) { @@ -134,7 +139,7 @@ impl<'a> PathTransform<'a> { .into_iter() .flat_map(|it| it.lifetime_params(db)) .zip(self.substs.lifetimes.clone()) - .filter_map(|(k, v)| Some((k.name(db).to_string(), v.lifetime()?))) + .filter_map(|(k, v)| Some((k.name(db).display(db.upcast()).to_string(), v.lifetime()?))) .collect(); Ctx { type_substs, lifetime_substs, target_module, source_scope: self.source_scope } } @@ -279,7 +284,7 @@ impl<'a> Ctx<'a> { // FIXME: It would probably be nicer if we could get this via HIR (i.e. get the // trait ref, and then go from the types in the substs back to the syntax). -fn get_syntactic_substs(impl_def: ast::Impl) -> Option { +fn get_syntactic_substs(impl_def: ast::Impl) -> Option { let target_trait = impl_def.trait_()?; let path_type = match target_trait { ast::Type::PathType(path) => path, @@ -290,8 +295,8 @@ fn get_syntactic_substs(impl_def: ast::Impl) -> Option { get_type_args_from_arg_list(generic_arg_list) } -fn get_type_args_from_arg_list(generic_arg_list: ast::GenericArgList) -> Option { - let mut result = Substs::default(); +fn get_type_args_from_arg_list(generic_arg_list: ast::GenericArgList) -> Option { + let mut result = AstSubsts::default(); generic_arg_list.generic_args().for_each(|generic_arg| match generic_arg { ast::GenericArg::TypeArg(type_arg) => result.types.push(type_arg), ast::GenericArg::LifetimeArg(l_arg) => result.lifetimes.push(l_arg), From 8430ec5e50ba477ad6e55e4e80987f6c32525b23 Mon Sep 17 00:00:00 2001 From: Andrew Xie Date: Fri, 7 Apr 2023 15:56:33 -0400 Subject: [PATCH 155/465] Updated cranelift codegen to reflect modified trait signature --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 442ce0ea54209..ea013c4428cce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,7 +75,7 @@ use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig, use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; use rustc_codegen_ssa::target_features::supported_target_features; use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, Handler, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_metadata::EncodedMetadata; @@ -137,7 +137,7 @@ impl CodegenBackend for GccCodegenBackend { Box::new(res) } - fn join_codegen(&self, ongoing_codegen: Box, sess: &Session, _outputs: &OutputFilenames) -> Result<(CodegenResults, FxHashMap), ErrorGuaranteed> { + fn join_codegen(&self, ongoing_codegen: Box, sess: &Session, _outputs: &OutputFilenames) -> Result<(CodegenResults, FxIndexMap), ErrorGuaranteed> { let (codegen_results, work_products) = ongoing_codegen .downcast::>() .expect("Expected GccCodegenBackend's OngoingCodegen, found Box") From e6e72bf9d5a9f47d565cd12cb3386ce3503dbc61 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Sun, 4 Jun 2023 22:38:17 -0400 Subject: [PATCH 156/465] Migrate `add_missing_impl_members` to mutable ast `replace_derive_with_manual_impl` was slightly since it used `add_trait_assoc_items_to_impl` (which was also used by `add_missing_impl_members`) --- .../src/handlers/add_missing_impl_members.rs | 48 ++++++++----------- .../replace_derive_with_manual_impl.rs | 12 +++-- crates/ide-assists/src/utils.rs | 10 ++-- 3 files changed, 33 insertions(+), 37 deletions(-) diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 6340feda452e1..0ddd12faab181 100644 --- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -4,10 +4,7 @@ use syntax::ast::{self, make, AstNode}; use crate::{ assist_context::{AssistContext, Assists}, - utils::{ - add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body, render_snippet, - Cursor, DefaultMethods, - }, + utils::{add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body, DefaultMethods}, AssistId, AssistKind, }; @@ -130,7 +127,8 @@ fn add_missing_impl_members_inner( } let target = impl_def.syntax().text_range(); - acc.add(AssistId(assist_id, AssistKind::QuickFix), label, target, |builder| { + acc.add(AssistId(assist_id, AssistKind::QuickFix), label, target, |edit| { + let new_impl_def = edit.make_mut(impl_def.clone()); let missing_items = missing_items .into_iter() .map(|it| { @@ -142,38 +140,34 @@ fn add_missing_impl_members_inner( it.clone_for_update() }) .collect(); - let (new_impl_def, first_new_item) = add_trait_assoc_items_to_impl( + let first_new_item = add_trait_assoc_items_to_impl( &ctx.sema, missing_items, trait_, - impl_def.clone(), + &new_impl_def, target_scope, ); - match ctx.config.snippet_cap { - None => builder.replace(target, new_impl_def.to_string()), - Some(cap) => { - let mut cursor = Cursor::Before(first_new_item.syntax()); - let placeholder; - if let DefaultMethods::No = mode { - if let ast::AssocItem::Fn(func) = &first_new_item { - if try_gen_trait_body(ctx, func, trait_ref, &impl_def).is_none() { - if let Some(m) = - func.syntax().descendants().find_map(ast::MacroCall::cast) - { - if m.syntax().text() == "todo!()" { - placeholder = m; - cursor = Cursor::Replace(placeholder.syntax()); - } + + if let Some(cap) = ctx.config.snippet_cap { + let mut placeholder = None; + if let DefaultMethods::No = mode { + if let ast::AssocItem::Fn(func) = &first_new_item { + if try_gen_trait_body(ctx, func, trait_ref, &impl_def).is_none() { + if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) + { + if m.syntax().text() == "todo!()" { + placeholder = Some(m); } } } } - builder.replace_snippet( - cap, - target, - render_snippet(cap, new_impl_def.syntax(), cursor), - ) } + + if let Some(macro_call) = placeholder { + edit.add_placeholder_snippet(cap, macro_call); + } else { + edit.add_tabstop_before(cap, first_new_item); + }; }; }) } diff --git a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index 36ac8c71d8154..1b0a8e0a8dae3 100644 --- a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -182,7 +182,11 @@ fn impl_def_from_trait( let impl_def = { use syntax::ast::Impl; let text = generate_trait_impl_text(adt, trait_path.to_string().as_str(), ""); - let parse = syntax::SourceFile::parse(&text); + // FIXME: `generate_trait_impl_text` currently generates two newlines + // at the front, but these leading newlines should really instead be + // inserted at the same time the impl is inserted + assert_eq!(&text[..2], "\n\n", "`generate_trait_impl_text` output changed"); + let parse = syntax::SourceFile::parse(&text[2..]); let node = match parse.tree().syntax().descendants().find_map(Impl::cast) { Some(it) => it, None => { @@ -193,7 +197,7 @@ fn impl_def_from_trait( ) } }; - let node = node.clone_subtree(); + let node = node.clone_for_update(); assert_eq!(node.syntax().text_range().start(), 0.into()); node }; @@ -209,8 +213,8 @@ fn impl_def_from_trait( it.clone_for_update() }) .collect(); - let (impl_def, first_assoc_item) = - add_trait_assoc_items_to_impl(sema, trait_items, trait_, impl_def, target_scope); + let first_assoc_item = + add_trait_assoc_items_to_impl(sema, trait_items, trait_, &impl_def, target_scope); // Generate a default `impl` function body for the derived trait. if let ast::AssocItem::Fn(ref func) = first_assoc_item { diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs index 8f7ea26306c42..cc4a7f3c0adbe 100644 --- a/crates/ide-assists/src/utils.rs +++ b/crates/ide-assists/src/utils.rs @@ -132,9 +132,9 @@ pub fn add_trait_assoc_items_to_impl( sema: &Semantics<'_, RootDatabase>, items: Vec, trait_: hir::Trait, - impl_: ast::Impl, + impl_: &ast::Impl, target_scope: hir::SemanticsScope<'_>, -) -> (ast::Impl, ast::AssocItem) { +) -> ast::AssocItem { let source_scope = sema.scope_for_def(trait_); let transform = PathTransform::trait_impl(&target_scope, &source_scope, trait_, impl_.clone()); @@ -147,9 +147,7 @@ pub fn add_trait_assoc_items_to_impl( assoc_item }); - let res = impl_.clone_for_update(); - - let assoc_item_list = res.get_or_create_assoc_item_list(); + let assoc_item_list = impl_.get_or_create_assoc_item_list(); let mut first_item = None; for item in items { first_item.get_or_insert_with(|| item.clone()); @@ -172,7 +170,7 @@ pub fn add_trait_assoc_items_to_impl( assoc_item_list.add_item(item) } - (res, first_item.unwrap()) + first_item.unwrap() } #[derive(Clone, Copy, Debug)] From dd5f05590ebef5038fac0d23dc0cb422c2e58363 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Sun, 4 Jun 2023 23:30:48 -0400 Subject: [PATCH 157/465] Migrate `extract_type_alias` to mutable ast --- .../src/handlers/extract_type_alias.rs | 49 +++++++++++-------- crates/syntax/src/ast/make.rs | 6 +-- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/crates/ide-assists/src/handlers/extract_type_alias.rs b/crates/ide-assists/src/handlers/extract_type_alias.rs index b310c2db9fab0..71b45d88cb8c5 100644 --- a/crates/ide-assists/src/handlers/extract_type_alias.rs +++ b/crates/ide-assists/src/handlers/extract_type_alias.rs @@ -1,6 +1,9 @@ use either::Either; use ide_db::syntax_helpers::node_ext::walk_ty; -use syntax::ast::{self, edit::IndentLevel, make, AstNode, HasGenericParams, HasName}; +use syntax::{ + ast::{self, edit::IndentLevel, make, AstNode, HasGenericParams, HasName}, + ted, +}; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -34,14 +37,16 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> || item.syntax(), |impl_| impl_.as_ref().either(AstNode::syntax, AstNode::syntax), ); - let insert_pos = node.text_range().start(); let target = ty.syntax().text_range(); acc.add( AssistId("extract_type_alias", AssistKind::RefactorExtract), "Extract type as type alias", target, - |builder| { + |edit| { + let node = edit.make_syntax_mut(node.clone()); + let target_ty = edit.make_mut(ty.clone()); + let mut known_generics = match item.generic_param_list() { Some(it) => it.generic_params().collect(), None => Vec::new(), @@ -56,27 +61,29 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> let generic_params = generics.map(|it| make::generic_param_list(it.into_iter().cloned())); + // Replace original type with the alias let ty_args = generic_params .as_ref() .map_or(String::new(), |it| it.to_generic_args().to_string()); - let replacement = format!("Type{ty_args}"); - builder.replace(target, replacement); - - let indent = IndentLevel::from_node(node); - let generic_params = generic_params.map_or(String::new(), |it| it.to_string()); - match ctx.config.snippet_cap { - Some(cap) => { - builder.insert_snippet( - cap, - insert_pos, - format!("type $0Type{generic_params} = {ty};\n\n{indent}"), - ); - } - None => { - builder.insert( - insert_pos, - format!("type Type{generic_params} = {ty};\n\n{indent}"), - ); + // FIXME: replace with a `ast::make` constructor + let new_ty = make::ty(&format!("Type{ty_args}")).clone_for_update(); + ted::replace(target_ty.syntax(), new_ty.syntax()); + + // Insert new alias + let indent = IndentLevel::from_node(&node); + let ty_alias = make::ty_alias("Type", generic_params, None, None, Some((ty, None))) + .clone_for_update(); + ted::insert_all( + ted::Position::before(node), + vec![ + ty_alias.syntax().clone().into(), + make::tokens::whitespace(&format!("\n\n{indent}")).into(), + ], + ); + + if let Some(cap) = ctx.config.snippet_cap { + if let Some(name) = ty_alias.name() { + edit.add_tabstop_before(cap, name); } } }, diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index a07561e79a28b..3c2b7e56b0653 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -166,7 +166,7 @@ pub fn ty_alias( assignment: Option<(ast::Type, Option)>, ) -> ast::TypeAlias { let mut s = String::new(); - s.push_str(&format!("type {} ", ident)); + s.push_str(&format!("type {}", ident)); if let Some(list) = generic_param_list { s.push_str(&list.to_string()); @@ -182,9 +182,9 @@ pub fn ty_alias( if let Some(exp) = assignment { if let Some(cl) = exp.1 { - s.push_str(&format!("= {} {}", &exp.0.to_string(), &cl.to_string())); + s.push_str(&format!(" = {} {}", &exp.0.to_string(), &cl.to_string())); } else { - s.push_str(&format!("= {}", &exp.0.to_string())); + s.push_str(&format!(" = {}", &exp.0.to_string())); } } From c48062fe2ab9a2d913d1985a6b0aec4bf936bfc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 5 Jun 2023 12:04:23 +0300 Subject: [PATCH 158/465] Merge commit 'aa9bc8612514d216f84eec218dfd19ab83f3598a' into sync-from-ra --- .github/actions/github-release/README.md | 2 +- .github/workflows/autopublish.yaml | 2 +- .github/workflows/ci.yaml | 53 +- .github/workflows/publish-libs.yaml | 6 +- .github/workflows/release.yaml | 2 +- .vscode/launch.json | 2 +- Cargo.lock | 422 +- Cargo.toml | 18 +- bench_data/glorious_old_parser | 2 +- crates/base-db/Cargo.toml | 4 + crates/base-db/src/change.rs | 23 +- crates/base-db/src/fixture.rs | 84 +- crates/base-db/src/input.rs | 321 +- crates/base-db/src/lib.rs | 29 +- crates/cfg/src/lib.rs | 2 +- crates/flycheck/Cargo.toml | 5 +- crates/flycheck/src/lib.rs | 10 +- crates/hir-def/Cargo.toml | 3 +- crates/hir-def/src/attr.rs | 241 +- .../src/{builtin_attr.rs => attr/builtin.rs} | 166 +- crates/hir-def/src/attr/tests.rs | 40 + crates/hir-def/src/body.rs | 370 +- crates/hir-def/src/body/lower.rs | 1058 +- crates/hir-def/src/body/pretty.rs | 137 +- crates/hir-def/src/body/scope.rs | 68 +- crates/hir-def/src/body/tests/block.rs | 4 +- crates/hir-def/src/builtin_type.rs | 10 +- crates/hir-def/src/child_by_source.rs | 6 +- crates/hir-def/src/data.rs | 246 +- crates/hir-def/src/{ => data}/adt.rs | 73 +- crates/hir-def/src/db.rs | 51 +- crates/hir-def/src/dyn_map.rs | 2 + crates/hir-def/src/{ => dyn_map}/keys.rs | 0 crates/hir-def/src/expander.rs | 211 + crates/hir-def/src/find_path.rs | 9 +- crates/hir-def/src/generics.rs | 48 +- crates/hir-def/src/{expr.rs => hir.rs} | 148 +- crates/hir-def/src/{ => hir}/type_ref.rs | 28 +- crates/hir-def/src/import_map.rs | 98 +- crates/hir-def/src/item_scope.rs | 10 +- crates/hir-def/src/item_tree.rs | 17 +- crates/hir-def/src/item_tree/lower.rs | 30 +- crates/hir-def/src/item_tree/pretty.rs | 91 +- crates/hir-def/src/item_tree/tests.rs | 14 +- crates/hir-def/src/lang_item.rs | 293 +- crates/hir-def/src/layout.rs | 97 - crates/hir-def/src/lib.rs | 154 +- crates/hir-def/src/lower.rs | 45 + .../builtin_derive_macro.rs | 300 +- .../macro_expansion_tests/builtin_fn_macro.rs | 101 +- .../hir-def/src/macro_expansion_tests/mbe.rs | 131 +- .../src/macro_expansion_tests/mbe/matching.rs | 7 +- .../macro_expansion_tests/mbe/metavar_expr.rs | 311 + .../macro_expansion_tests/mbe/regression.rs | 20 +- .../mbe/tt_conversion.rs | 2 +- .../mod.rs} | 85 +- crates/hir-def/src/nameres.rs | 275 +- crates/hir-def/src/nameres/attr_resolution.rs | 21 +- crates/hir-def/src/nameres/collector.rs | 609 +- crates/hir-def/src/nameres/diagnostics.rs | 31 +- crates/hir-def/src/nameres/mod_resolution.rs | 18 +- crates/hir-def/src/nameres/path_resolution.rs | 141 +- crates/hir-def/src/nameres/proc_macro.rs | 2 +- crates/hir-def/src/nameres/tests.rs | 3 +- .../hir-def/src/nameres/tests/incremental.rs | 17 +- crates/hir-def/src/nameres/tests/macros.rs | 256 +- .../src/nameres/tests/mod_resolution.rs | 2 +- crates/hir-def/src/path.rs | 89 +- crates/hir-def/src/path/lower.rs | 19 +- crates/hir-def/src/pretty.rs | 80 +- crates/hir-def/src/resolver.rs | 114 +- crates/hir-def/src/src.rs | 10 +- crates/hir-def/src/test_db.rs | 31 +- crates/hir-def/src/visibility.rs | 3 +- crates/hir-expand/Cargo.toml | 1 + crates/hir-expand/src/ast_id_map.rs | 9 +- crates/hir-expand/src/attrs.rs | 141 +- crates/hir-expand/src/builtin_attr_macro.rs | 2 +- crates/hir-expand/src/builtin_derive_macro.rs | 681 +- crates/hir-expand/src/builtin_fn_macro.rs | 220 +- crates/hir-expand/src/db.rs | 242 +- crates/hir-expand/src/eager.rs | 202 +- crates/hir-expand/src/fixup.rs | 4 +- crates/hir-expand/src/hygiene.rs | 13 +- crates/hir-expand/src/lib.rs | 164 +- crates/hir-expand/src/mod_path.rs | 102 +- crates/hir-expand/src/name.rs | 80 +- crates/hir-expand/src/proc_macro.rs | 44 +- crates/hir-expand/src/quote.rs | 6 + crates/hir-ty/Cargo.toml | 4 +- crates/hir-ty/src/autoderef.rs | 64 +- crates/hir-ty/src/builder.rs | 50 +- crates/hir-ty/src/chalk_db.rs | 145 +- crates/hir-ty/src/chalk_ext.rs | 55 +- crates/hir-ty/src/consteval.rs | 97 +- crates/hir-ty/src/consteval/tests.rs | 1548 +- .../hir-ty/src/consteval/tests/intrinsics.rs | 377 + crates/hir-ty/src/db.rs | 114 +- crates/hir-ty/src/diagnostics/decl_check.rs | 43 +- crates/hir-ty/src/diagnostics/expr.rs | 6 +- crates/hir-ty/src/diagnostics/match_check.rs | 51 +- .../match_check/deconstruct_pat.rs | 12 +- .../src/diagnostics/match_check/pat_util.rs | 2 +- .../src/diagnostics/match_check/usefulness.rs | 2 +- crates/hir-ty/src/diagnostics/unsafe_check.rs | 4 +- crates/hir-ty/src/display.rs | 630 +- crates/hir-ty/src/infer.rs | 501 +- crates/hir-ty/src/infer/closure.rs | 932 +- crates/hir-ty/src/infer/coerce.rs | 64 +- crates/hir-ty/src/infer/expr.rs | 460 +- crates/hir-ty/src/infer/mutability.rs | 218 + crates/hir-ty/src/infer/pat.rs | 59 +- crates/hir-ty/src/infer/path.rs | 112 +- crates/hir-ty/src/infer/unify.rs | 157 +- crates/hir-ty/src/inhabitedness.rs | 30 +- crates/hir-ty/src/interner.rs | 145 +- crates/hir-ty/src/lang_items.rs | 68 +- crates/hir-ty/src/layout.rs | 150 +- crates/hir-ty/src/layout/adt.rs | 106 +- crates/hir-ty/src/layout/target.rs | 3 +- crates/hir-ty/src/layout/tests.rs | 165 +- crates/hir-ty/src/layout/tests/closure.rs | 257 + crates/hir-ty/src/lib.rs | 85 +- crates/hir-ty/src/lower.rs | 210 +- crates/hir-ty/src/method_resolution.rs | 303 +- crates/hir-ty/src/mir.rs | 343 +- crates/hir-ty/src/mir/borrowck.rs | 266 +- crates/hir-ty/src/mir/eval.rs | 2201 ++- crates/hir-ty/src/mir/eval/shim.rs | 792 + crates/hir-ty/src/mir/eval/tests.rs | 676 + crates/hir-ty/src/mir/lower.rs | 1793 ++- crates/hir-ty/src/mir/lower/as_place.rs | 163 +- .../hir-ty/src/mir/lower/pattern_matching.rs | 617 + crates/hir-ty/src/mir/monomorphization.rs | 351 + crates/hir-ty/src/mir/pretty.rs | 182 +- crates/hir-ty/src/test_db.rs | 20 +- crates/hir-ty/src/tests.rs | 43 +- crates/hir-ty/src/tests/coercion.rs | 111 +- crates/hir-ty/src/tests/incremental.rs | 8 +- crates/hir-ty/src/tests/macros.rs | 59 +- crates/hir-ty/src/tests/method_resolution.rs | 74 +- crates/hir-ty/src/tests/never_type.rs | 47 + crates/hir-ty/src/tests/patterns.rs | 43 +- crates/hir-ty/src/tests/regression.rs | 211 +- crates/hir-ty/src/tests/simple.rs | 350 +- crates/hir-ty/src/tests/traits.rs | 383 +- crates/hir-ty/src/tls.rs | 22 +- crates/hir-ty/src/traits.rs | 55 +- crates/hir-ty/src/utils.rs | 126 +- crates/hir/Cargo.toml | 1 + crates/hir/src/attrs.rs | 8 +- crates/hir/src/db.rs | 4 +- crates/hir/src/diagnostics.rs | 59 +- crates/hir/src/display.rs | 72 +- crates/hir/src/from_id.rs | 2 +- crates/hir/src/lib.rs | 710 +- crates/hir/src/semantics.rs | 48 +- crates/hir/src/semantics/source_to_def.rs | 10 +- crates/hir/src/source_analyzer.rs | 89 +- crates/hir/src/symbols.rs | 296 +- .../src/handlers/add_explicit_type.rs | 2 +- .../src/handlers/add_missing_impl_members.rs | 177 +- .../src/handlers/add_missing_match_arms.rs | 2 +- .../src/handlers/add_return_type.rs | 6 +- .../ide-assists/src/handlers/auto_import.rs | 6 +- .../src/handlers/convert_bool_then.rs | 2 +- .../handlers/convert_iter_for_each_to_for.rs | 2 +- .../src/handlers/convert_let_else_to_match.rs | 161 +- .../src/handlers/convert_match_to_let_else.rs | 37 +- .../convert_named_struct_to_tuple_struct.rs | 248 +- .../convert_nested_function_to_closure.rs | 209 + .../src/handlers/convert_to_guarded_return.rs | 2 +- .../convert_tuple_struct_to_named_struct.rs | 3 +- .../src/handlers/destructure_tuple_binding.rs | 2 +- .../src/handlers/expand_glob_import.rs | 2 +- .../src/handlers/extract_function.rs | 185 +- .../src/handlers/extract_module.rs | 11 +- .../extract_struct_from_enum_variant.rs | 4 +- .../src/handlers/extract_variable.rs | 58 +- .../src/handlers/fix_visibility.rs | 11 +- .../src/handlers/generate_constant.rs | 9 +- .../src/handlers/generate_delegate_methods.rs | 130 +- .../src/handlers/generate_deref.rs | 6 +- .../src/handlers/generate_derive.rs | 41 +- .../generate_documentation_template.rs | 4 +- .../src/handlers/generate_enum_variant.rs | 2 +- .../src/handlers/generate_function.rs | 23 +- .../src/handlers/generate_getter.rs | 2 +- .../ide-assists/src/handlers/generate_new.rs | 6 +- .../ide-assists/src/handlers/inline_macro.rs | 47 +- .../src/handlers/introduce_named_generic.rs | 30 +- .../src/handlers/introduce_named_lifetime.rs | 4 +- .../src/handlers/merge_match_arms.rs | 28 +- .../src/handlers/move_const_to_impl.rs | 2 +- .../src/handlers/move_from_mod_rs.rs | 2 +- .../src/handlers/move_module_to_file.rs | 2 +- .../src/handlers/move_to_mod_rs.rs | 2 +- .../src/handlers/promote_local_to_const.rs | 14 +- .../src/handlers/pull_assignment_up.rs | 4 +- .../src/handlers/qualify_method_call.rs | 4 +- .../ide-assists/src/handlers/qualify_path.rs | 10 +- crates/ide-assists/src/handlers/raw_string.rs | 1 + .../src/handlers/remove_parentheses.rs | 2 +- .../src/handlers/remove_unused_param.rs | 2 +- .../src/handlers/reorder_fields.rs | 7 +- .../src/handlers/reorder_impl_items.rs | 43 +- .../replace_derive_with_manual_impl.rs | 2 +- .../replace_named_generic_with_impl.rs | 351 + .../src/handlers/replace_string_with_char.rs | 4 +- .../handlers/replace_try_expr_with_match.rs | 6 +- .../replace_turbofish_with_explicit_type.rs | 2 +- crates/ide-assists/src/handlers/sort_items.rs | 111 +- .../ide-assists/src/handlers/unwrap_block.rs | 8 +- .../src/handlers/unwrap_result_return_type.rs | 119 +- crates/ide-assists/src/lib.rs | 6 +- crates/ide-assists/src/tests.rs | 7 +- crates/ide-assists/src/tests/generated.rs | 46 +- crates/ide-assists/src/tests/sourcegen.rs | 2 - crates/ide-assists/src/utils.rs | 19 +- crates/ide-assists/src/utils/suggest_name.rs | 4 +- crates/ide-completion/src/completions.rs | 132 +- .../src/completions/attribute.rs | 8 +- .../src/completions/attribute/cfg.rs | 6 +- .../src/completions/attribute/derive.rs | 8 +- .../src/completions/attribute/lint.rs | 2 +- .../src/completions/attribute/repr.rs | 2 +- crates/ide-completion/src/completions/dot.rs | 39 +- .../src/completions/env_vars.rs | 6 +- crates/ide-completion/src/completions/expr.rs | 18 +- .../src/completions/extern_abi.rs | 4 +- .../src/completions/flyimport.rs | 84 +- .../src/completions/fn_param.rs | 10 +- .../src/completions/format_string.rs | 2 +- .../src/completions/item_list.rs | 6 +- .../src/completions/item_list/trait_impl.rs | 41 +- .../src/completions/lifetime.rs | 1 + crates/ide-completion/src/completions/mod_.rs | 4 +- .../ide-completion/src/completions/pattern.rs | 8 +- .../ide-completion/src/completions/postfix.rs | 47 +- .../src/completions/postfix/format_like.rs | 2 +- .../ide-completion/src/completions/record.rs | 4 +- .../ide-completion/src/completions/snippet.rs | 14 +- crates/ide-completion/src/completions/type.rs | 12 +- crates/ide-completion/src/completions/use_.rs | 13 +- crates/ide-completion/src/completions/vis.rs | 2 +- crates/ide-completion/src/context.rs | 45 +- crates/ide-completion/src/context/analysis.rs | 6 +- crates/ide-completion/src/item.rs | 49 +- crates/ide-completion/src/lib.rs | 6 +- crates/ide-completion/src/render.rs | 52 +- crates/ide-completion/src/render/const_.rs | 2 +- crates/ide-completion/src/render/function.rs | 11 +- crates/ide-completion/src/render/literal.rs | 8 +- crates/ide-completion/src/render/macro_.rs | 6 +- crates/ide-completion/src/render/pattern.rs | 9 +- .../ide-completion/src/render/type_alias.rs | 2 +- .../src/render/union_literal.rs | 20 +- crates/ide-completion/src/render/variant.rs | 6 +- crates/ide-completion/src/tests.rs | 22 +- crates/ide-completion/src/tests/expression.rs | 111 +- crates/ide-completion/src/tests/flyimport.rs | 56 + crates/ide-completion/src/tests/item_list.rs | 54 +- crates/ide-completion/src/tests/pattern.rs | 60 +- crates/ide-completion/src/tests/predicate.rs | 42 +- .../ide-completion/src/tests/proc_macros.rs | 4 +- crates/ide-completion/src/tests/special.rs | 291 + crates/ide-completion/src/tests/type_pos.rs | 52 +- crates/ide-completion/src/tests/use_tree.rs | 47 + crates/ide-db/Cargo.toml | 4 + crates/ide-db/src/apply_change.rs | 5 +- crates/ide-db/src/assists.rs | 2 +- crates/ide-db/src/defs.rs | 23 +- crates/ide-db/src/generated/lints.rs | 4 +- crates/ide-db/src/helpers.rs | 2 +- crates/ide-db/src/imports/import_assets.rs | 4 +- crates/ide-db/src/items_locator.rs | 34 +- crates/ide-db/src/lib.rs | 225 +- crates/ide-db/src/line_index.rs | 314 - crates/ide-db/src/path_transform.rs | 4 +- crates/ide-db/src/rename.rs | 35 +- crates/ide-db/src/search.rs | 33 +- crates/ide-db/src/source_change.rs | 125 +- crates/ide-db/src/symbol_index.rs | 103 +- .../src/syntax_helpers/format_string.rs | 2 +- .../src/syntax_helpers/format_string_exprs.rs | 2 +- .../insert_whitespace_into_node.rs | 4 +- crates/ide-db/src/syntax_helpers/node_ext.rs | 4 +- .../ide-db/src/test_data/test_doc_alias.txt | 202 + .../test_symbol_index_collection.txt | 238 +- crates/ide-db/src/tests/line_index.rs | 49 + crates/ide-db/src/traits.rs | 18 +- crates/ide-db/src/use_trivial_constructor.rs | 4 +- .../src/handlers/break_outside_of_loop.rs | 41 +- .../src/handlers/incorrect_case.rs | 4 +- .../src/handlers/macro_error.rs | 45 + .../src/handlers/missing_fields.rs | 10 +- .../src/handlers/missing_match_arms.rs | 18 +- .../src/handlers/missing_unsafe.rs | 7 +- .../src/handlers/moved_out_of_ref.rs | 175 + .../src/handlers/mutability_errors.rs | 474 +- .../src/handlers/no_such_field.rs | 4 +- .../src/handlers/private_assoc_item.rs | 6 +- .../src/handlers/private_field.rs | 4 +- .../replace_filter_map_next_with_find_map.rs | 4 +- .../src/handlers/type_mismatch.rs | 145 +- .../src/handlers/typed_hole.rs | 232 + .../src/handlers/undeclared_label.rs | 88 + .../src/handlers/unlinked_file.rs | 30 +- .../src/handlers/unreachable_label.rs | 91 + .../src/handlers/unresolved_field.rs | 6 +- .../src/handlers/unresolved_macro_call.rs | 2 +- .../src/handlers/unresolved_method.rs | 4 +- .../src/handlers/unresolved_module.rs | 2 +- .../src/handlers/unresolved_proc_macro.rs | 24 +- crates/ide-diagnostics/src/lib.rs | 47 +- crates/ide-diagnostics/src/tests.rs | 36 +- crates/ide-ssr/Cargo.toml | 2 + crates/ide-ssr/src/lib.rs | 9 +- crates/ide-ssr/src/replacing.rs | 18 +- crates/ide-ssr/src/tests.rs | 2 +- crates/ide/Cargo.toml | 2 + crates/ide/src/call_hierarchy.rs | 8 +- crates/ide/src/doc_links.rs | 177 +- crates/ide/src/doc_links/tests.rs | 152 +- crates/ide/src/expand_macro.rs | 85 +- crates/ide/src/extend_selection.rs | 2 +- crates/ide/src/fetch_crates.rs | 42 + crates/ide/src/file_structure.rs | 2 +- crates/ide/src/fixture.rs | 15 +- crates/ide/src/goto_definition.rs | 54 +- crates/ide/src/goto_type_definition.rs | 89 +- crates/ide/src/highlight_related.rs | 351 +- crates/ide/src/hover.rs | 44 +- crates/ide/src/hover/render.rs | 333 +- crates/ide/src/hover/tests.rs | 854 +- crates/ide/src/inlay_hints.rs | 146 +- crates/ide/src/inlay_hints/adjustment.rs | 113 +- crates/ide/src/inlay_hints/bind_pat.rs | 450 +- crates/ide/src/inlay_hints/binding_mode.rs | 27 +- crates/ide/src/inlay_hints/chaining.rs | 93 +- crates/ide/src/inlay_hints/closing_brace.rs | 8 +- .../ide/src/inlay_hints/closure_captures.rs | 207 + crates/ide/src/inlay_hints/closure_ret.rs | 80 +- crates/ide/src/inlay_hints/discriminant.rs | 144 +- crates/ide/src/inlay_hints/fn_lifetime_fn.rs | 14 +- crates/ide/src/inlay_hints/implicit_static.rs | 6 +- crates/ide/src/inlay_hints/param_name.rs | 17 +- crates/ide/src/interpret_function.rs | 46 + crates/ide/src/lib.rs | 59 +- crates/ide/src/moniker.rs | 122 +- crates/ide/src/navigation_target.rs | 213 +- crates/ide/src/prime_caches.rs | 11 +- crates/ide/src/references.rs | 26 +- crates/ide/src/runnables.rs | 46 +- crates/ide/src/shuffle_crate_graph.rs | 11 +- crates/ide/src/signature_help.rs | 502 +- crates/ide/src/ssr.rs | 3 +- crates/ide/src/static_index.rs | 4 +- crates/ide/src/status.rs | 241 +- crates/ide/src/syntax_highlighting.rs | 160 +- crates/ide/src/syntax_highlighting/escape.rs | 24 +- .../ide/src/syntax_highlighting/highlight.rs | 10 +- crates/ide/src/syntax_highlighting/inject.rs | 29 +- crates/ide/src/syntax_highlighting/tags.rs | 8 +- .../test_data/highlight_doctest.html | 6 +- .../test_data/highlight_extern_crate.html | 2 +- .../test_data/highlight_general.html | 6 +- .../test_data/highlight_injection.html | 24 +- .../test_data/highlight_keywords.html | 2 +- .../test_data/highlight_macros.html | 28 +- .../test_data/highlight_strings.html | 121 +- .../test_data/highlight_unsafe.html | 10 +- crates/ide/src/syntax_highlighting/tests.rs | 13 +- crates/ide/src/syntax_tree.rs | 6 +- crates/ide/src/view_crate_graph.rs | 10 +- crates/ide/src/view_item_tree.rs | 2 +- crates/intern/Cargo.toml | 1 + crates/intern/src/lib.rs | 95 +- crates/limit/src/lib.rs | 1 + crates/mbe/src/benchmark.rs | 15 +- crates/mbe/src/expander.rs | 5 +- crates/mbe/src/expander/matcher.rs | 34 +- crates/mbe/src/expander/transcriber.rs | 128 +- crates/mbe/src/lib.rs | 49 +- crates/mbe/src/parser.rs | 36 +- crates/mbe/src/syntax_bridge.rs | 74 +- crates/mbe/src/tt_iter.rs | 7 - crates/parser/Cargo.toml | 2 +- crates/parser/src/grammar.rs | 15 +- crates/parser/src/grammar/expressions.rs | 91 +- crates/parser/src/grammar/expressions/atom.rs | 13 + crates/parser/src/grammar/generic_args.rs | 26 +- crates/parser/src/grammar/items.rs | 2 +- crates/parser/src/grammar/paths.rs | 1 + crates/parser/src/grammar/patterns.rs | 103 +- crates/parser/src/grammar/types.rs | 22 +- crates/parser/src/lexed_str.rs | 56 +- crates/parser/src/lib.rs | 2 + crates/parser/src/parser.rs | 2 +- crates/parser/src/shortcuts.rs | 6 +- crates/parser/src/syntax_kind/generated.rs | 4 +- crates/parser/src/tests/prefix_entries.rs | 3 +- .../err/unclosed_raw_byte_string_at_eof.rast | 2 +- ...sed_raw_byte_string_with_ascii_escape.rast | 2 +- .../unclosed_raw_byte_string_with_ferris.rast | 2 +- .../unclosed_raw_byte_string_with_slash.rast | 2 +- ...unclosed_raw_byte_string_with_slash_n.rast | 2 +- .../unclosed_raw_byte_string_with_space.rast | 2 +- ...d_raw_byte_string_with_unicode_escape.rast | 2 +- .../lexer/err/unclosed_raw_string_at_eof.rast | 2 +- ...unclosed_raw_string_with_ascii_escape.rast | 2 +- .../err/unclosed_raw_string_with_ferris.rast | 2 +- .../err/unclosed_raw_string_with_slash.rast | 2 +- .../err/unclosed_raw_string_with_slash_n.rast | 2 +- .../err/unclosed_raw_string_with_space.rast | 2 +- ...closed_raw_string_with_unicode_escape.rast | 2 +- .../err/unstarted_raw_byte_string_at_eof.rast | 2 +- .../unstarted_raw_byte_string_with_ascii.rast | 2 +- .../err/unstarted_raw_string_at_eof.rast | 2 +- .../err/unstarted_raw_string_with_ascii.rast | 2 +- ...or.rast => 0027_incomplete_where_for.rast} | 0 ...re_for.rs => 0027_incomplete_where_for.rs} | 0 ...ast => 0047_repeated_extern_modifier.rast} | 0 ...er.rs => 0047_repeated_extern_modifier.rs} | 0 .../0018_crate_visibility_empty_recover.rast | 18 + .../0018_crate_visibility_empty_recover.rs | 1 + .../err/0019_tuple_expr_leading_comma.rast | 24 + .../err/0019_tuple_expr_leading_comma.rs | 3 + .../err/0020_tuple_pat_leading_comma.rast | 26 + .../err/0020_tuple_pat_leading_comma.rs | 3 + .../parser/inline/ok/0085_expr_literals.rast | 24 + .../parser/inline/ok/0085_expr_literals.rs | 2 + .../inline/ok/0156_const_block_pat.rast | 120 + .../parser/inline/ok/0156_const_block_pat.rs | 8 + .../inline/ok/0196_pub_tuple_field.rast | 39 + .../parser/inline/ok/0196_pub_tuple_field.rs | 2 + .../ok/0202_typepathfn_with_coloncolon.rast | 38 + .../ok/0202_typepathfn_with_coloncolon.rs | 1 + .../inline/ok/0207_exclusive_range_pat.rast | 58 + .../inline/ok/0207_exclusive_range_pat.rs | 6 + .../0208_associated_return_type_bounds.rast | 102 + .../ok/0208_associated_return_type_bounds.rs | 1 + ..._bare_dyn_types_with_leading_lifetime.rast | 58 + ...08_bare_dyn_types_with_leading_lifetime.rs | 2 + ..._dyn_types_with_paren_as_generic_args.rast | 175 + ...re_dyn_types_with_paren_as_generic_args.rs | 4 + .../ok/0028_operator_binding_power.rast | 269 + .../parser/ok/0028_operator_binding_power.rs | 13 + .../test_data/parser/ok/0045_block_attrs.rast | 2 +- .../test_data/parser/ok/0045_block_attrs.rs | 2 +- .../ok/0072_destructuring_assignment.rast | 76 +- .../ok/0072_destructuring_assignment.rs | 2 +- crates/paths/Cargo.toml | 2 +- crates/paths/src/lib.rs | 16 + crates/proc-macro-api/Cargo.toml | 5 +- crates/proc-macro-api/src/lib.rs | 37 +- crates/proc-macro-api/src/msg.rs | 10 +- crates/proc-macro-api/src/msg/flat.rs | 60 +- crates/proc-macro-api/src/process.rs | 28 +- crates/proc-macro-srv-cli/Cargo.toml | 1 + crates/proc-macro-srv-cli/src/main.rs | 38 +- crates/proc-macro-srv/Cargo.toml | 1 + .../proc-macro-srv/src/abis/abi_1_63/mod.rs | 106 - .../abis/abi_1_63/proc_macro/bridge/buffer.rs | 156 - .../abis/abi_1_63/proc_macro/bridge/client.rs | 510 - .../abi_1_63/proc_macro/bridge/closure.rs | 32 - .../abis/abi_1_63/proc_macro/bridge/handle.rs | 89 - .../abis/abi_1_63/proc_macro/bridge/mod.rs | 451 - .../abis/abi_1_63/proc_macro/bridge/rpc.rs | 304 - .../abi_1_63/proc_macro/bridge/scoped_cell.rs | 81 - .../proc_macro/bridge/selfless_reify.rs | 83 - .../abis/abi_1_63/proc_macro/bridge/server.rs | 332 - .../abis/abi_1_63/proc_macro/diagnostic.rs | 166 - .../src/abis/abi_1_63/proc_macro/mod.rs | 1106 -- .../src/abis/abi_1_63/proc_macro/quote.rs | 139 - .../src/abis/abi_1_63/ra_server.rs | 840 - crates/proc-macro-srv/src/abis/mod.rs | 146 - crates/proc-macro-srv/src/cli.rs | 34 - crates/proc-macro-srv/src/dylib.rs | 28 +- crates/proc-macro-srv/src/lib.rs | 57 +- .../abi_sysroot/mod.rs => proc_macros.rs} | 81 +- .../abi_sysroot/ra_server.rs => server.rs} | 50 +- .../ra_server => server}/symbol.rs | 16 +- .../ra_server => server}/token_stream.rs | 16 +- crates/proc-macro-srv/src/tests/utils.rs | 4 +- crates/profile/Cargo.toml | 2 +- crates/profile/src/memory_usage.rs | 6 + crates/project-model/Cargo.toml | 6 +- crates/project-model/src/build_scripts.rs | 29 +- crates/project-model/src/cargo_workspace.rs | 92 +- crates/project-model/src/cfg_flag.rs | 8 + crates/project-model/src/lib.rs | 2 +- crates/project-model/src/manifest_path.rs | 4 + crates/project-model/src/project_json.rs | 39 +- crates/project-model/src/sysroot.rs | 64 +- .../project-model/src/target_data_layout.rs | 2 +- crates/project-model/src/tests.rs | 1881 +-- crates/project-model/src/workspace.rs | 651 +- .../cargo_hello_world_project_model.txt | 344 + ...project_model_with_selective_overrides.txt | 344 + ..._project_model_with_wildcard_overrides.txt | 340 + ...rust_project_hello_world_project_model.txt | 462 + .../test_data/regex-metadata.json | 6420 ++++++++ .../test_data/ripgrep-metadata.json | 12816 ++++++++++++++++ crates/rust-analyzer/Cargo.toml | 25 +- crates/rust-analyzer/src/bin/main.rs | 100 +- crates/rust-analyzer/src/caps.rs | 11 +- crates/rust-analyzer/src/cargo_target_spec.rs | 18 +- .../rust-analyzer/src/cli/analysis_stats.rs | 133 +- crates/rust-analyzer/src/cli/flags.rs | 13 +- crates/rust-analyzer/src/cli/load_cargo.rs | 74 +- crates/rust-analyzer/src/cli/scip.rs | 19 +- crates/rust-analyzer/src/config.rs | 293 +- crates/rust-analyzer/src/diagnostics.rs | 17 +- .../rust-analyzer/src/diagnostics/to_proto.rs | 43 +- crates/rust-analyzer/src/dispatch.rs | 60 +- crates/rust-analyzer/src/from_proto.rs | 22 +- crates/rust-analyzer/src/global_state.rs | 103 +- .../src/handlers/notification.rs | 334 + .../src/{handlers.rs => handlers/request.rs} | 233 +- .../src/integrated_benchmarks.rs | 9 +- crates/rust-analyzer/src/lib.rs | 6 +- crates/rust-analyzer/src/line_index.rs | 3 +- crates/rust-analyzer/src/lsp_ext.rs | 71 +- crates/rust-analyzer/src/lsp_utils.rs | 38 +- crates/rust-analyzer/src/main_loop.rs | 625 +- crates/rust-analyzer/src/markdown.rs | 10 +- crates/rust-analyzer/src/op_queue.rs | 14 +- crates/rust-analyzer/src/reload.rs | 286 +- crates/rust-analyzer/src/semantic_tokens.rs | 59 +- crates/rust-analyzer/src/task_pool.rs | 33 +- crates/rust-analyzer/src/to_proto.rs | 167 +- crates/rust-analyzer/tests/slow-tests/main.rs | 76 +- .../rust-analyzer/tests/slow-tests/support.rs | 32 +- crates/rust-analyzer/tests/slow-tests/tidy.rs | 2 + crates/sourcegen/src/lib.rs | 26 +- crates/stdx/Cargo.toml | 2 + crates/stdx/src/hash.rs | 80 - crates/stdx/src/lib.rs | 2 +- crates/stdx/src/thread.rs | 102 + crates/stdx/src/thread/intent.rs | 287 + crates/stdx/src/thread/pool.rs | 92 + crates/syntax/Cargo.toml | 8 +- crates/syntax/rust.ungram | 8 +- crates/syntax/src/ast/edit_in_place.rs | 17 + crates/syntax/src/ast/expr_ext.rs | 7 +- crates/syntax/src/ast/generated/nodes.rs | 3 + crates/syntax/src/ast/generated/tokens.rs | 21 + crates/syntax/src/ast/make.rs | 155 +- crates/syntax/src/ast/token_ext.rs | 71 +- crates/syntax/src/lib.rs | 3 +- crates/syntax/src/parsing/reparsing.rs | 8 +- crates/syntax/src/tests/ast_src.rs | 3 +- crates/syntax/src/tests/sourcegen_ast.rs | 10 +- crates/syntax/src/token_text.rs | 7 + crates/syntax/src/validation.rs | 56 +- .../test_data/parser/fuzz-failures/0000.rs | 4 +- crates/test-utils/Cargo.toml | 2 +- crates/test-utils/src/fixture.rs | 92 +- crates/test-utils/src/lib.rs | 4 +- crates/test-utils/src/minicore.rs | 532 +- crates/text-edit/Cargo.toml | 2 +- crates/text-edit/src/lib.rs | 52 + crates/tt/Cargo.toml | 2 +- crates/tt/src/lib.rs | 6 + crates/vfs-notify/Cargo.toml | 2 +- crates/vfs-notify/src/lib.rs | 4 +- crates/vfs/Cargo.toml | 1 + crates/vfs/src/file_set.rs | 4 +- crates/vfs/src/lib.rs | 23 +- crates/vfs/src/vfs_path.rs | 5 +- docs/dev/lsp-extensions.md | 69 +- docs/user/generated_config.adoc | 66 +- docs/user/manual.adoc | 17 +- editors/code/package.json | 208 +- .../rustdoc.markdown.injection.tmGrammar.json | 36 + editors/code/src/client.ts | 98 +- editors/code/src/commands.ts | 149 +- editors/code/src/config.ts | 9 +- editors/code/src/ctx.ts | 103 +- editors/code/src/debug.ts | 9 +- editors/code/src/dependencies_provider.ts | 148 + editors/code/src/lsp_ext.ts | 45 +- editors/code/src/main.ts | 7 +- editors/code/src/run.ts | 2 +- editors/code/src/tasks.ts | 2 +- editors/code/src/toolchain.ts | 7 +- editors/code/src/util.ts | 13 + lib/README.md | 7 +- lib/la-arena/src/lib.rs | 118 +- lib/la-arena/src/map.rs | 70 +- lib/line-index/Cargo.toml | 11 + lib/line-index/src/lib.rs | 237 + lib/line-index/src/tests.rs | 11 + lib/line-index/tests/it.rs | 62 + lib/lsp-server/Cargo.toml | 4 +- lib/lsp-server/src/error.rs | 2 +- lib/lsp-server/src/lib.rs | 70 + 598 files changed, 57728 insertions(+), 17647 deletions(-) rename crates/hir-def/src/{builtin_attr.rs => attr/builtin.rs} (83%) create mode 100644 crates/hir-def/src/attr/tests.rs rename crates/hir-def/src/{ => data}/adt.rs (89%) rename crates/hir-def/src/{ => dyn_map}/keys.rs (100%) create mode 100644 crates/hir-def/src/expander.rs rename crates/hir-def/src/{expr.rs => hir.rs} (76%) rename crates/hir-def/src/{ => hir}/type_ref.rs (96%) delete mode 100644 crates/hir-def/src/layout.rs create mode 100644 crates/hir-def/src/lower.rs create mode 100644 crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs rename crates/hir-def/src/{macro_expansion_tests.rs => macro_expansion_tests/mod.rs} (86%) create mode 100644 crates/hir-ty/src/consteval/tests/intrinsics.rs create mode 100644 crates/hir-ty/src/infer/mutability.rs create mode 100644 crates/hir-ty/src/layout/tests/closure.rs create mode 100644 crates/hir-ty/src/mir/eval/shim.rs create mode 100644 crates/hir-ty/src/mir/eval/tests.rs create mode 100644 crates/hir-ty/src/mir/lower/pattern_matching.rs create mode 100644 crates/hir-ty/src/mir/monomorphization.rs create mode 100644 crates/ide-assists/src/handlers/convert_nested_function_to_closure.rs create mode 100644 crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs delete mode 100644 crates/ide-db/src/line_index.rs create mode 100644 crates/ide-db/src/test_data/test_doc_alias.txt create mode 100644 crates/ide-db/src/tests/line_index.rs create mode 100644 crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs create mode 100644 crates/ide-diagnostics/src/handlers/typed_hole.rs create mode 100644 crates/ide-diagnostics/src/handlers/undeclared_label.rs create mode 100644 crates/ide-diagnostics/src/handlers/unreachable_label.rs create mode 100644 crates/ide/src/fetch_crates.rs create mode 100644 crates/ide/src/inlay_hints/closure_captures.rs create mode 100644 crates/ide/src/interpret_function.rs rename crates/parser/test_data/parser/err/{0027_incomplere_where_for.rast => 0027_incomplete_where_for.rast} (100%) rename crates/parser/test_data/parser/err/{0027_incomplere_where_for.rs => 0027_incomplete_where_for.rs} (100%) rename crates/parser/test_data/parser/err/{0047_repated_extern_modifier.rast => 0047_repeated_extern_modifier.rast} (100%) rename crates/parser/test_data/parser/err/{0047_repated_extern_modifier.rs => 0047_repeated_extern_modifier.rs} (100%) create mode 100644 crates/parser/test_data/parser/inline/err/0018_crate_visibility_empty_recover.rast create mode 100644 crates/parser/test_data/parser/inline/err/0018_crate_visibility_empty_recover.rs create mode 100644 crates/parser/test_data/parser/inline/err/0019_tuple_expr_leading_comma.rast create mode 100644 crates/parser/test_data/parser/inline/err/0019_tuple_expr_leading_comma.rs create mode 100644 crates/parser/test_data/parser/inline/err/0020_tuple_pat_leading_comma.rast create mode 100644 crates/parser/test_data/parser/inline/err/0020_tuple_pat_leading_comma.rs create mode 100644 crates/parser/test_data/parser/inline/ok/0207_exclusive_range_pat.rast create mode 100644 crates/parser/test_data/parser/inline/ok/0207_exclusive_range_pat.rs create mode 100644 crates/parser/test_data/parser/inline/ok/0208_associated_return_type_bounds.rast create mode 100644 crates/parser/test_data/parser/inline/ok/0208_associated_return_type_bounds.rs create mode 100644 crates/parser/test_data/parser/inline/ok/0208_bare_dyn_types_with_leading_lifetime.rast create mode 100644 crates/parser/test_data/parser/inline/ok/0208_bare_dyn_types_with_leading_lifetime.rs create mode 100644 crates/parser/test_data/parser/inline/ok/0209_bare_dyn_types_with_paren_as_generic_args.rast create mode 100644 crates/parser/test_data/parser/inline/ok/0209_bare_dyn_types_with_paren_as_generic_args.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_63/mod.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/buffer.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/client.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/closure.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/handle.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/mod.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/rpc.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/scoped_cell.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/selfless_reify.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/server.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/diagnostic.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/quote.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_63/ra_server.rs delete mode 100644 crates/proc-macro-srv/src/abis/mod.rs delete mode 100644 crates/proc-macro-srv/src/cli.rs rename crates/proc-macro-srv/src/{abis/abi_sysroot/mod.rs => proc_macros.rs} (52%) rename crates/proc-macro-srv/src/{abis/abi_sysroot/ra_server.rs => server.rs} (91%) rename crates/proc-macro-srv/src/{abis/abi_sysroot/ra_server => server}/symbol.rs (58%) rename crates/proc-macro-srv/src/{abis/abi_sysroot/ra_server => server}/token_stream.rs (93%) create mode 100644 crates/project-model/test_data/output/cargo_hello_world_project_model.txt create mode 100644 crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt create mode 100644 crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt create mode 100644 crates/project-model/test_data/output/rust_project_hello_world_project_model.txt create mode 100644 crates/project-model/test_data/regex-metadata.json create mode 100644 crates/project-model/test_data/ripgrep-metadata.json create mode 100644 crates/rust-analyzer/src/handlers/notification.rs rename crates/rust-analyzer/src/{handlers.rs => handlers/request.rs} (91%) delete mode 100644 crates/stdx/src/hash.rs create mode 100644 crates/stdx/src/thread.rs create mode 100644 crates/stdx/src/thread/intent.rs create mode 100644 crates/stdx/src/thread/pool.rs create mode 100644 editors/code/rustdoc.markdown.injection.tmGrammar.json create mode 100644 editors/code/src/dependencies_provider.ts create mode 100644 lib/line-index/Cargo.toml create mode 100644 lib/line-index/src/lib.rs create mode 100644 lib/line-index/src/tests.rs create mode 100644 lib/line-index/tests/it.rs diff --git a/.github/actions/github-release/README.md b/.github/actions/github-release/README.md index 7b50d002001ee..c8ff3ec6e52c8 100644 --- a/.github/actions/github-release/README.md +++ b/.github/actions/github-release/README.md @@ -10,7 +10,7 @@ perform github releases but they all tend to have their set of drawbacks. Additionally nothing handles deleting releases which we need for our rolling `dev` release. -To handle all this this action rolls-its-own implementation using the +To handle all this, this action rolls its own implementation using the actions/toolkit repository and packages published there. These run in a Docker container and take various inputs to orchestrate the release from the build. diff --git a/.github/workflows/autopublish.yaml b/.github/workflows/autopublish.yaml index 279f86b458dff..7090c94d93cce 100644 --- a/.github/workflows/autopublish.yaml +++ b/.github/workflows/autopublish.yaml @@ -32,7 +32,7 @@ jobs: shell: bash run: | git config --global user.email "runner@gha.local" - git config --global user.name "Github Action" + git config --global user.name "GitHub Action" rm Cargo.lock # Fix names for crates that were published before switch to kebab-case. cargo workspaces rename --from base-db base_db diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bb77324378a40..622da105fdd44 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,12 +18,35 @@ env: RUSTUP_MAX_RETRIES: 10 jobs: + changes: + runs-on: ubuntu-latest + permissions: + pull-requests: read + outputs: + typescript: ${{ steps.filter.outputs.typescript }} + steps: + - uses: actions/checkout@v3 + - uses: dorny/paths-filter@4067d885736b84de7c414f582ac45897079b0a78 + id: filter + with: + filters: | + typescript: + - 'editors/code/**' + proc_macros: + - 'crates/proc-macro-api/**' + - 'crates/proc-macro-srv/**' + - 'crates/proc-macro-srv-cli/**' + - 'crates/proc-macro-test/**' + rust: + needs: changes if: github.repository == 'rust-lang/rust-analyzer' name: Rust runs-on: ${{ matrix.os }} env: CC: deny_c + RUST_CHANNEL: "${{ needs.changes.outputs.proc_macros == 'true' && 'nightly' || 'stable'}}" + USE_SYSROOT_ABI: "${{ needs.changes.outputs.proc_macros == 'true' && '--features sysroot-abi' || ''}}" strategy: fail-fast: false @@ -35,30 +58,31 @@ jobs: uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} - fetch-depth: 20 - name: Install Rust toolchain run: | - rustup update --no-self-update stable + rustup update --no-self-update ${{ env.RUST_CHANNEL }} rustup component add rustfmt rust-src - name: Cache Dependencies - uses: Swatinem/rust-cache@76686c56f2b581d1bb5bda44b51f7e24bd9b8b8e + uses: Swatinem/rust-cache@988c164c3d0e93c4dbab36aaf5bbeb77425b2894 + with: + key: ${{ env.RUST_CHANNEL }} - name: Bump opt-level if: matrix.os == 'ubuntu-latest' run: sed -i '/\[profile.dev]/a opt-level=1' Cargo.toml - name: Compile (tests) - run: cargo test --no-run --locked + run: cargo test --no-run --locked ${{ env.USE_SYSROOT_ABI }} # It's faster to `test` before `build` ¯\_(ツ)_/¯ - name: Compile (rust-analyzer) if: matrix.os == 'ubuntu-latest' - run: cargo build --quiet + run: cargo build --quiet ${{ env.USE_SYSROOT_ABI }} - name: Test - run: cargo test -- --nocapture --quiet + run: cargo test ${{ env.USE_SYSROOT_ABI }} -- --nocapture --quiet - name: Run analysis-stats on rust-analyzer if: matrix.os == 'ubuntu-latest' @@ -90,7 +114,7 @@ jobs: rustup target add ${{ env.targets }} ${{ env.targets_ide }} - name: Cache Dependencies - uses: Swatinem/rust-cache@76686c56f2b581d1bb5bda44b51f7e24bd9b8b8e + uses: Swatinem/rust-cache@988c164c3d0e93c4dbab36aaf5bbeb77425b2894 - name: Check run: | @@ -102,6 +126,7 @@ jobs: done typescript: + needs: changes if: github.repository == 'rust-lang/rust-analyzer' name: TypeScript strategy: @@ -114,18 +139,21 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v3 + if: needs.changes.outputs.typescript == 'true' - name: Install Nodejs uses: actions/setup-node@v3 with: node-version: 16 + if: needs.changes.outputs.typescript == 'true' - name: Install xvfb - if: matrix.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-latest' && needs.changes.outputs.typescript == 'true' run: sudo apt-get install -y xvfb - run: npm ci working-directory: ./editors/code + if: needs.changes.outputs.typescript == 'true' # - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; } # if: runner.os == 'Linux' @@ -133,16 +161,17 @@ jobs: - run: npm run lint working-directory: ./editors/code + if: needs.changes.outputs.typescript == 'true' - name: Run VS Code tests (Linux) - if: matrix.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-latest' && needs.changes.outputs.typescript == 'true' env: VSCODE_CLI: 1 run: xvfb-run npm test working-directory: ./editors/code - name: Run VS Code tests (Windows) - if: matrix.os == 'windows-latest' + if: matrix.os == 'windows-latest' && needs.changes.outputs.typescript == 'true' env: VSCODE_CLI: 1 run: npm test @@ -150,9 +179,11 @@ jobs: - run: npm run pretest working-directory: ./editors/code + if: needs.changes.outputs.typescript == 'true' - run: npm run package --scripts-prepend-node-path working-directory: ./editors/code + if: needs.changes.outputs.typescript == 'true' end-success: name: bors build finished @@ -165,7 +196,7 @@ jobs: end-failure: name: bors build finished - if: github.event.pusher.name == 'bors' && (failure() || cancelled()) + if: github.event.pusher.name == 'bors' && !success() runs-on: ubuntu-latest needs: [rust, rust-cross, typescript] steps: diff --git a/.github/workflows/publish-libs.yaml b/.github/workflows/publish-libs.yaml index 1b843fff1a4a1..6d026c9ad910b 100644 --- a/.github/workflows/publish-libs.yaml +++ b/.github/workflows/publish-libs.yaml @@ -3,9 +3,9 @@ on: workflow_dispatch: push: branches: - - main + - master paths: - - 'lib/**' + - "lib/**" jobs: publish-libs: @@ -29,7 +29,7 @@ jobs: shell: bash run: | git config --global user.email "runner@gha.local" - git config --global user.name "Github Action" + git config --global user.name "GitHub Action" # Remove r-a crates from the workspaces so we don't auto-publish them as well sed -i 's/ "crates\/\*"//' ./Cargo.toml cargo workspaces publish --yes --exact --from-git --no-git-commit --allow-dirty diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 48f4c6b55ed90..43681c785fdc0 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -270,7 +270,7 @@ jobs: - name: Publish Extension (Code Marketplace, nightly) if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer') working-directory: ./editors/code - run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix + run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix --pre-release - name: Publish Extension (OpenVSX, nightly) if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer') diff --git a/.vscode/launch.json b/.vscode/launch.json index 1e21214ffc4bc..c353737a35a83 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -72,7 +72,7 @@ }, { // Used for testing the extension with a local build of the LSP server (in `target/release`) - // with all other extendions loaded. + // with all other extensions loaded. "name": "Run With Extensions", "type": "extensionHost", "request": "launch", diff --git a/Cargo.lock b/Cargo.lock index 25242c6028a47..322a67383b030 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,18 +19,18 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "always-assert" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf688625d06217d5b1bb0ea9d9c44a1635fd0ee3534466388d18203174f4d11" +checksum = "4436e0292ab1bb631b42973c61205e704475fe8126af845c8d923c0996328127" dependencies = [ "log", ] [[package]] name = "anyhow" -version = "1.0.68" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" +checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" [[package]] name = "anymap" @@ -40,9 +40,9 @@ checksum = "8f1f8f5a6f3d50d89e3797d7593a50f96bb2aaa20ca0cc7be1fb673232c91d72" [[package]] name = "arbitrary" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0224938f92e7aef515fac2ff2d18bd1115c1394ddf4a092e0c87e8be9499ee5" +checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" [[package]] name = "arrayvec" @@ -87,12 +87,14 @@ name = "base-db" version = "0.0.0" dependencies = [ "cfg", + "la-arena", "profile", "rustc-hash", "salsa", "stdx", "syntax", "test-utils", + "triomphe", "tt", "vfs", ] @@ -103,6 +105,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c70beb79cbb5ce9c4f8e20849978f34225931f665bb49efa6982875a4d5facb3" + [[package]] name = "byteorder" version = "1.4.3" @@ -111,9 +119,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "camino" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77df041dc383319cc661b428b6961a005db4d6808d5e12536931b1ca9556055" +checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" dependencies = [ "serde", ] @@ -129,9 +137,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.15.2" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982a0cf6a99c350d7246035613882e376d58cebe571785abc5da4f648d53ac0a" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ "camino", "cargo-platform", @@ -143,9 +151,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg" @@ -185,7 +193,7 @@ version = "0.89.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "473b480241695428c14e8f84f1c9a47ef232450a50faf3a4041e5c9dc11e0a3b" dependencies = [ - "bitflags", + "bitflags 1.3.2", "chalk-derive", "lazy_static", ] @@ -221,9 +229,9 @@ dependencies = [ [[package]] name = "command-group" -version = "2.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "026c3922235f9f7d78f21251a026f3acdeb7cce3deba107fe09a4bfa63d850a2" +checksum = "5080df6b0f0ecb76cab30808f00d937ba725cebe266a3da8cd89dff92f2a9916" dependencies = [ "nix", "winapi", @@ -257,9 +265,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if", "crossbeam-utils", @@ -267,9 +275,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -278,22 +286,22 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.13" +version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset 0.7.1", + "memoffset", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.14" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" dependencies = [ "cfg-if", ] @@ -313,9 +321,9 @@ dependencies = [ [[package]] name = "derive_arbitrary" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf460bbff5f571bfc762da5102729f59f338be7db17a21fade44c5c4f5005350" +checksum = "f3cdeb9ec472d588e539a818b2dee436825730da08ad0017c4b1a17676bdc8b7" dependencies = [ "proc-macro2", "quote", @@ -342,24 +350,24 @@ checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1" [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "ena" -version = "0.14.0" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" dependencies = [ "log", ] [[package]] name = "expect-test" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d4661aca38d826eb7c72fe128e4238220616de4c0cc00db7bfc38e2e1364dd3" +checksum = "30d9eafeadd538e68fb28016364c9732d78e420b9ff8853fa5e4058861e9f8d3" dependencies = [ "dissimilar", "once_cell", @@ -400,7 +408,6 @@ dependencies = [ "cargo_metadata", "command-group", "crossbeam-channel", - "jod-thread", "paths", "rustc-hash", "serde", @@ -419,12 +426,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fs_extra" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" - [[package]] name = "fsevent-sys" version = "4.1.0" @@ -442,9 +443,9 @@ checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" [[package]] name = "gimli" -version = "0.27.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" [[package]] name = "hashbrown" @@ -497,6 +498,7 @@ dependencies = [ "smallvec", "stdx", "syntax", + "triomphe", "tt", ] @@ -507,7 +509,7 @@ dependencies = [ "anymap", "arrayvec", "base-db", - "bitflags", + "bitflags 2.1.0", "cfg", "cov-mark", "dashmap", @@ -533,6 +535,7 @@ dependencies = [ "syntax", "test-utils", "tracing", + "triomphe", "tt", ] @@ -557,6 +560,7 @@ dependencies = [ "stdx", "syntax", "tracing", + "triomphe", "tt", ] @@ -566,7 +570,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags", + "bitflags 2.1.0", "chalk-derive", "chalk-ir", "chalk-recursive", @@ -582,6 +586,7 @@ dependencies = [ "itertools", "la-arena", "limit", + "nohash-hasher", "once_cell", "profile", "project-model", @@ -594,6 +599,7 @@ dependencies = [ "tracing", "tracing-subscriber", "tracing-tree", + "triomphe", "typed-arena", ] @@ -603,7 +609,7 @@ version = "0.0.20221221" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adabaadad9aa7576f97af02241cdf5554d62fb3d51a84cb05d77ba28edd3013f" dependencies = [ - "bitflags", + "bitflags 1.3.2", "hkalbasi-rustc-ap-rustc_index", "tracing", ] @@ -644,6 +650,7 @@ dependencies = [ "ide-diagnostics", "ide-ssr", "itertools", + "nohash-hasher", "oorandom", "profile", "pulldown-cmark", @@ -655,6 +662,7 @@ dependencies = [ "text-edit", "toolchain", "tracing", + "triomphe", "url", ] @@ -710,7 +718,9 @@ dependencies = [ "indexmap", "itertools", "limit", + "line-index", "memchr", + "nohash-hasher", "once_cell", "oorandom", "parser", @@ -723,6 +733,7 @@ dependencies = [ "test-utils", "text-edit", "tracing", + "triomphe", "xshell", ] @@ -755,11 +766,13 @@ dependencies = [ "hir", "ide-db", "itertools", + "nohash-hasher", "parser", "stdx", "syntax", "test-utils", "text-edit", + "triomphe", ] [[package]] @@ -774,9 +787,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown", @@ -788,7 +801,7 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" dependencies = [ - "bitflags", + "bitflags 1.3.2", "inotify-sys", "libc", ] @@ -819,6 +832,7 @@ dependencies = [ "hashbrown", "once_cell", "rustc-hash", + "triomphe", ] [[package]] @@ -832,9 +846,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "jod-thread" @@ -858,7 +872,7 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8367585489f01bc55dd27404dcf56b95e6da061a256a666ab23be9ba96a2e587" dependencies = [ - "bitflags", + "bitflags 1.3.2", "libc", ] @@ -874,9 +888,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" [[package]] name = "libloading" @@ -890,9 +904,9 @@ dependencies = [ [[package]] name = "libmimalloc-sys" -version = "0.1.30" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8c7cbf8b89019683667e347572e6d55a7df7ea36b0c4ce69961b0cde67b174" +checksum = "43a558e3d911bc3c7bfc8c78bc580b404d6e51c1cefbf656e176a94b49b0df40" dependencies = [ "cc", "libc", @@ -902,6 +916,14 @@ dependencies = [ name = "limit" version = "0.0.0" +[[package]] +name = "line-index" +version = "0.1.0-pre.1" +dependencies = [ + "nohash-hasher", + "text-size", +] + [[package]] name = "lock_api" version = "0.4.9" @@ -938,7 +960,7 @@ version = "0.94.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b63735a13a1f9cd4f4835223d828ed9c2e35c8c5e61837774399f558b6a1237" dependencies = [ - "bitflags", + "bitflags 1.3.2", "serde", "serde_json", "serde_repr", @@ -977,36 +999,27 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memmap2" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ "libc", ] [[package]] name = "memoffset" -version = "0.6.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" dependencies = [ "autocfg", ] [[package]] name = "mimalloc" -version = "0.1.34" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dcb174b18635f7561a0c6c9fc2ce57218ac7523cf72c50af80e2d79ab8f3ba1" +checksum = "3d88dad3f985ec267a3fcb7a1726f5cb1a7e8cad8b646e70a84f967210df23da" dependencies = [ "libmimalloc-sys", ] @@ -1047,19 +1060,25 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", "static_assertions", ] +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "notify" -version = "5.0.0" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2c66da08abae1c024c01d635253e402341b4060a12e99b31c7594063bf490a" +checksum = "58ea850aa68a06e48fdb069c0ec44d0d64c8dbffa49bf3b6f7f0a901fdea1ba9" dependencies = [ - "bitflags", + "bitflags 1.3.2", "crossbeam-channel", "filetime", "fsevent-sys", @@ -1068,7 +1087,7 @@ dependencies = [ "libc", "mio", "walkdir", - "winapi", + "windows-sys", ] [[package]] @@ -1093,18 +1112,18 @@ dependencies = [ [[package]] name = "object" -version = "0.30.2" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b8c786513eb403643f2a88c244c2aaa270ef2153f55094587d0c48a3cf22a83" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.17.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "oorandom" @@ -1173,16 +1192,16 @@ dependencies = [ "drop_bomb", "expect-test", "limit", - "rustc-ap-rustc_lexer", + "ra-ap-rustc_lexer", "sourcegen", "stdx", ] [[package]] name = "paste" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" [[package]] name = "paths" @@ -1242,6 +1261,7 @@ dependencies = [ "snap", "stdx", "tracing", + "triomphe", "tt", ] @@ -1257,6 +1277,7 @@ dependencies = [ "paths", "proc-macro-api", "proc-macro-test", + "stdx", "tt", ] @@ -1264,6 +1285,7 @@ dependencies = [ name = "proc-macro-srv-cli" version = "0.0.0" dependencies = [ + "proc-macro-api", "proc-macro-srv", ] @@ -1282,9 +1304,9 @@ version = "0.0.0" [[package]] name = "proc-macro2" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] @@ -1312,6 +1334,7 @@ dependencies = [ "cargo_metadata", "cfg", "expect-test", + "itertools", "la-arena", "paths", "profile", @@ -1322,6 +1345,7 @@ dependencies = [ "stdx", "toolchain", "tracing", + "triomphe", ] [[package]] @@ -1350,7 +1374,7 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63" dependencies = [ - "bitflags", + "bitflags 1.3.2", "memchr", "unicase", ] @@ -1366,18 +1390,28 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] +[[package]] +name = "ra-ap-rustc_lexer" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1c145702ed3f237918e512685185dc8a4d0edc3a5326c63d20361d8ba9b45b3" +dependencies = [ + "unic-emoji-char", + "unicode-xid", +] + [[package]] name = "rayon" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ "either", "rayon-core", @@ -1385,9 +1419,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -1401,14 +1435,14 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] name = "regex" -version = "1.7.1" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" dependencies = [ "regex-syntax", ] @@ -1424,19 +1458,19 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "rowan" -version = "0.15.10" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5811547e7ba31e903fe48c8ceab10d40d70a101f3d15523c847cce91aa71f332" +checksum = "64449cfef9483a475ed56ae30e2da5ee96448789fb2aa240a04beb6a055078bf" dependencies = [ "countme", "hashbrown", - "memoffset 0.6.5", + "memoffset", "rustc-hash", "text-size", ] @@ -1451,6 +1485,7 @@ dependencies = [ "crossbeam-channel", "dissimilar", "expect-test", + "filetime", "flycheck", "hir", "hir-def", @@ -1459,16 +1494,17 @@ dependencies = [ "ide-db", "ide-ssr", "itertools", - "jod-thread", "lsp-server", "lsp-types", "mbe", "mimalloc", + "mio", + "nohash-hasher", "num_cpus", "oorandom", "parking_lot 0.12.1", + "parking_lot_core 0.9.6", "proc-macro-api", - "proc-macro-srv", "profile", "project-model", "rayon", @@ -1476,17 +1512,19 @@ dependencies = [ "scip", "serde", "serde_json", + "serde_repr", "sourcegen", "stdx", "syntax", "test-utils", - "threadpool", + "thiserror", "tikv-jemallocator", "toolchain", "tracing", "tracing-log", "tracing-subscriber", "tracing-tree", + "triomphe", "tt", "vfs", "vfs-notify", @@ -1495,20 +1533,11 @@ dependencies = [ "xshell", ] -[[package]] -name = "rustc-ap-rustc_lexer" -version = "727.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f40f26e7abdcd3b982f36c09a634cc6187988fbf6ec466c91f8d30a12ac0237" -dependencies = [ - "unicode-xid", -] - [[package]] name = "rustc-demangle" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b" [[package]] name = "rustc-hash" @@ -1518,9 +1547,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "ryu" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "salsa" @@ -1583,27 +1612,27 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "semver" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.152" +version = "1.0.156" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.156" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d" dependencies = [ "proc-macro2", "quote", @@ -1612,9 +1641,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.91" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "indexmap", "itoa", @@ -1624,9 +1653,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a5ec9fa74a20ebbe5d9ac23dac1fc96ba0ecfe9f50f2843b52e537b10fbcb4e" +checksum = "395627de918015623b32e7669714206363a7fc00382bf477e72c1f7533e8eafc" dependencies = [ "proc-macro2", "quote", @@ -1650,9 +1679,9 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "smol_str" -version = "0.1.23" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7475118a28b7e3a2e157ce0131ba8c5526ea96e90ee601d9f6bb2e286a35ab44" +checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" dependencies = [ "serde", ] @@ -1682,6 +1711,8 @@ version = "0.0.0" dependencies = [ "always-assert", "backtrace", + "crossbeam-channel", + "jod-thread", "libc", "miow", "winapi", @@ -1689,9 +1720,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -1724,15 +1755,16 @@ dependencies = [ "proc-macro2", "profile", "quote", + "ra-ap-rustc_lexer", "rayon", "rowan", - "rustc-ap-rustc_lexer", "rustc-hash", "smol_str", "sourcegen", "stdx", "test-utils", "text-edit", + "triomphe", "ungrammar", ] @@ -1763,18 +1795,18 @@ checksum = "288cb548dbe72b652243ea797201f3d481a0609a967980fcc5b2315ea811560a" [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" dependencies = [ "proc-macro2", "quote", @@ -1783,22 +1815,14 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] -[[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", -] - [[package]] name = "tikv-jemalloc-ctl" version = "0.5.0" @@ -1812,12 +1836,11 @@ dependencies = [ [[package]] name = "tikv-jemalloc-sys" -version = "0.5.2+5.3.0-patched" +version = "0.5.3+5.3.0-patched" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec45c14da997d0925c7835883e4d5c181f196fa142f8c19d7643d1e9af2592c3" +checksum = "a678df20055b43e57ef8cddde41cdfda9a3c1a060b67f4c5836dfb1d78543ba8" dependencies = [ "cc", - "fs_extra", "libc", ] @@ -1833,9 +1856,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.17" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" dependencies = [ "serde", "time-core", @@ -1858,9 +1881,9 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "toolchain" @@ -1942,6 +1965,12 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "triomphe" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1ee9bd9239c339d714d657fac840c6d2a4f9c45f4f9ec7b0975113458be78db" + [[package]] name = "tt" version = "0.0.0" @@ -1962,6 +1991,47 @@ version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e5df347f0bf3ec1d670aad6ca5c6a1859cd9ea61d2113125794654ccced68f" +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-emoji-char" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + [[package]] name = "unicase" version = "2.6.0" @@ -1973,15 +2043,15 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.10" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-normalization" @@ -1994,9 +2064,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-xid" @@ -2034,6 +2104,7 @@ version = "0.0.0" dependencies = [ "fst", "indexmap", + "nohash-hasher", "paths", "rustc-hash", "stdx", @@ -2044,9 +2115,9 @@ name = "vfs-notify" version = "0.0.0" dependencies = [ "crossbeam-channel", - "jod-thread", "notify", "paths", + "stdx", "tracing", "vfs", "walkdir", @@ -2054,12 +2125,11 @@ dependencies = [ [[package]] name = "walkdir" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" dependencies = [ "same-file", - "winapi", "winapi-util", ] @@ -2117,45 +2187,45 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_i686_gnu" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_msvc" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_msvc" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "write-json" diff --git a/Cargo.toml b/Cargo.toml index 333f03ce2ffe5..3050cf764a4c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = ["xtask/", "lib/*", "crates/*"] exclude = ["crates/proc-macro-test/imp"] +resolver = "2" [workspace.package] rust-version = "1.66" @@ -74,5 +75,20 @@ toolchain = { path = "./crates/toolchain", version = "0.0.0" } tt = { path = "./crates/tt", version = "0.0.0" } vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } +line-index = { version = "0.1.0-pre.1", path = "./lib/line-index" } + # non-local crates -smallvec = { version = "1.10.0", features = ["const_new", "union", "const_generics"] } +smallvec = { version = "1.10.0", features = [ + "const_new", + "union", + "const_generics", +] } +smol_str = "0.2.0" +nohash-hasher = "0.2.0" +text-size = "1.1.0" +# the following crates are pinned to prevent us from pulling in syn 2 until all our dependencies have moved +serde = { version = "=1.0.156", features = ["derive"] } +serde_json = "1.0.94" +triomphe = { version = "0.1.8", default-features = false, features = ["std"] } + +rustc_lexer = { version = "0.1.0", package = "ra-ap-rustc_lexer" } diff --git a/bench_data/glorious_old_parser b/bench_data/glorious_old_parser index 764893daa12ad..f593f2b2955ac 100644 --- a/bench_data/glorious_old_parser +++ b/bench_data/glorious_old_parser @@ -3808,7 +3808,7 @@ impl<'a> Parser<'a> { if self.eat_keyword(keywords::Else) || !cond.returns() { let sp = self.sess.source_map().next_point(lo); let mut err = self.diagnostic() - .struct_span_err(sp, "missing condition for `if` statemement"); + .struct_span_err(sp, "missing condition for `if` statement"); err.span_label(sp, "expected if condition here"); return Err(err) } diff --git a/crates/base-db/Cargo.toml b/crates/base-db/Cargo.toml index f6a1075c190a8..6001772c86ee4 100644 --- a/crates/base-db/Cargo.toml +++ b/crates/base-db/Cargo.toml @@ -15,6 +15,10 @@ doctest = false salsa = "0.17.0-pre.2" rustc-hash = "1.1.0" +triomphe.workspace = true + +la-arena = { version = "0.3.0", path = "../../lib/la-arena" } + # local deps cfg.workspace = true profile.workspace = true diff --git a/crates/base-db/src/change.rs b/crates/base-db/src/change.rs index b57f2345767d0..6a3b36b231280 100644 --- a/crates/base-db/src/change.rs +++ b/crates/base-db/src/change.rs @@ -1,19 +1,21 @@ //! Defines a unit of change that can applied to the database to get the next //! state. Changes are transactional. -use std::{fmt, sync::Arc}; +use std::fmt; use salsa::Durability; +use triomphe::Arc; use vfs::FileId; -use crate::{CrateGraph, SourceDatabaseExt, SourceRoot, SourceRootId}; +use crate::{CrateGraph, ProcMacros, SourceDatabaseExt, SourceRoot, SourceRootId}; /// Encapsulate a bunch of raw `.set` calls on the database. #[derive(Default)] pub struct Change { pub roots: Option>, - pub files_changed: Vec<(FileId, Option>)>, + pub files_changed: Vec<(FileId, Option>)>, pub crate_graph: Option, + pub proc_macros: Option, } impl fmt::Debug for Change { @@ -33,7 +35,7 @@ impl fmt::Debug for Change { } impl Change { - pub fn new() -> Change { + pub fn new() -> Self { Change::default() } @@ -41,7 +43,7 @@ impl Change { self.roots = Some(roots); } - pub fn change_file(&mut self, file_id: FileId, new_text: Option>) { + pub fn change_file(&mut self, file_id: FileId, new_text: Option>) { self.files_changed.push((file_id, new_text)) } @@ -49,6 +51,10 @@ impl Change { self.crate_graph = Some(graph); } + pub fn set_proc_macros(&mut self, proc_macros: ProcMacros) { + self.proc_macros = Some(proc_macros); + } + pub fn apply(self, db: &mut dyn SourceDatabaseExt) { let _p = profile::span("RootDatabase::apply_change"); if let Some(roots) = self.roots { @@ -67,11 +73,14 @@ impl Change { let source_root = db.source_root(source_root_id); let durability = durability(&source_root); // XXX: can't actually remove the file, just reset the text - let text = text.unwrap_or_default(); + let text = text.unwrap_or_else(|| Arc::from("")); db.set_file_text_with_durability(file_id, text, durability) } if let Some(crate_graph) = self.crate_graph { - db.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH) + db.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH); + } + if let Some(proc_macros) = self.proc_macros { + db.set_proc_macros_with_durability(Arc::new(proc_macros), Durability::HIGH); } } } diff --git a/crates/base-db/src/fixture.rs b/crates/base-db/src/fixture.rs index 8a7e9dfadfed2..5b11343173b30 100644 --- a/crates/base-db/src/fixture.rs +++ b/crates/base-db/src/fixture.rs @@ -1,24 +1,27 @@ //! A set of high-level utility fixture methods to use in tests. -use std::{mem, str::FromStr, sync::Arc}; +use std::{mem, str::FromStr, sync}; use cfg::CfgOptions; use rustc_hash::FxHashMap; use test_utils::{ - extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER, ESCAPED_CURSOR_MARKER, + extract_range_or_offset, Fixture, FixtureWithProjectMeta, RangeOrOffset, CURSOR_MARKER, + ESCAPED_CURSOR_MARKER, }; +use triomphe::Arc; use tt::token_id::{Leaf, Subtree, TokenTree}; use vfs::{file_set::FileSet, VfsPath}; use crate::{ input::{CrateName, CrateOrigin, LangCrateOrigin}, Change, CrateDisplayName, CrateGraph, CrateId, Dependency, Edition, Env, FileId, FilePosition, - FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, SourceDatabaseExt, - SourceRoot, SourceRootId, + FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacros, ReleaseChannel, + SourceDatabaseExt, SourceRoot, SourceRootId, }; pub const WORKSPACE: SourceRootId = SourceRootId(0); pub trait WithFixture: Default + SourceDatabaseExt + 'static { + #[track_caller] fn with_single_file(ra_fixture: &str) -> (Self, FileId) { let fixture = ChangeFixture::parse(ra_fixture); let mut db = Self::default(); @@ -27,6 +30,7 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { (db, fixture.files[0]) } + #[track_caller] fn with_many_files(ra_fixture: &str) -> (Self, Vec) { let fixture = ChangeFixture::parse(ra_fixture); let mut db = Self::default(); @@ -35,6 +39,7 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { (db, fixture.files) } + #[track_caller] fn with_files(ra_fixture: &str) -> Self { let fixture = ChangeFixture::parse(ra_fixture); let mut db = Self::default(); @@ -43,6 +48,7 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { db } + #[track_caller] fn with_files_extra_proc_macros( ra_fixture: &str, proc_macros: Vec<(String, ProcMacro)>, @@ -54,18 +60,21 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { db } + #[track_caller] fn with_position(ra_fixture: &str) -> (Self, FilePosition) { let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture); let offset = range_or_offset.expect_offset(); (db, FilePosition { file_id, offset }) } + #[track_caller] fn with_range(ra_fixture: &str) -> (Self, FileRange) { let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture); let range = range_or_offset.expect_range(); (db, FileRange { file_id, range }) } + #[track_caller] fn with_range_or_offset(ra_fixture: &str) -> (Self, FileId, RangeOrOffset) { let fixture = ChangeFixture::parse(ra_fixture); let mut db = Self::default(); @@ -100,9 +109,16 @@ impl ChangeFixture { pub fn parse_with_proc_macros( ra_fixture: &str, - mut proc_macros: Vec<(String, ProcMacro)>, + mut proc_macro_defs: Vec<(String, ProcMacro)>, ) -> ChangeFixture { - let (mini_core, proc_macro_names, fixture) = Fixture::parse(ra_fixture); + let FixtureWithProjectMeta { fixture, mini_core, proc_macro_names, toolchain } = + FixtureWithProjectMeta::parse(ra_fixture); + let toolchain = toolchain + .map(|it| { + ReleaseChannel::from_str(&it) + .unwrap_or_else(|| panic!("unknown release channel found: {it}")) + }) + .unwrap_or(ReleaseChannel::Stable); let mut change = Change::new(); let mut files = Vec::new(); @@ -157,16 +173,16 @@ impl ChangeFixture { meta.edition, Some(crate_name.clone().into()), version, - meta.cfg.clone(), meta.cfg, + Default::default(), meta.env, - Ok(Vec::new()), false, origin, meta.target_data_layout .as_deref() .map(Arc::from) .ok_or_else(|| "target_data_layout unset".into()), + Some(toolchain), ); let prev = crates.insert(crate_name.clone(), crate_id); assert!(prev.is_none()); @@ -182,7 +198,7 @@ impl ChangeFixture { default_target_data_layout = meta.target_data_layout; } - change.change_file(file_id, Some(Arc::new(text))); + change.change_file(file_id, Some(Arc::from(text))); let path = VfsPath::new_virtual_path(meta.path); file_set.insert(file_id, path); files.push(file_id); @@ -197,15 +213,15 @@ impl ChangeFixture { Edition::CURRENT, Some(CrateName::new("test").unwrap().into()), None, - default_cfg.clone(), default_cfg, + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, default_target_data_layout .map(|x| x.into()) .ok_or_else(|| "target_data_layout unset".into()), + Some(toolchain), ); } else { for (from, to, prelude) in crate_deps { @@ -232,7 +248,7 @@ impl ChangeFixture { fs.insert(core_file, VfsPath::new_virtual_path("/sysroot/core/lib.rs".to_string())); roots.push(SourceRoot::new_library(fs)); - change.change_file(core_file, Some(Arc::new(mini_core.source_code()))); + change.change_file(core_file, Some(Arc::from(mini_core.source_code()))); let all_crates = crate_graph.crates_in_topological_order(); @@ -241,13 +257,13 @@ impl ChangeFixture { Edition::Edition2021, Some(CrateDisplayName::from_canonical_name("core".to_string())), None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, CrateOrigin::Lang(LangCrateOrigin::Core), target_layout.clone(), + Some(toolchain), ); for krate in all_crates { @@ -257,12 +273,13 @@ impl ChangeFixture { } } + let mut proc_macros = ProcMacros::default(); if !proc_macro_names.is_empty() { let proc_lib_file = file_id; file_id.0 += 1; - proc_macros.extend(default_test_proc_macros()); - let (proc_macro, source) = filter_test_proc_macros(&proc_macro_names, proc_macros); + proc_macro_defs.extend(default_test_proc_macros()); + let (proc_macro, source) = filter_test_proc_macros(&proc_macro_names, proc_macro_defs); let mut fs = FileSet::default(); fs.insert( proc_lib_file, @@ -270,7 +287,7 @@ impl ChangeFixture { ); roots.push(SourceRoot::new_library(fs)); - change.change_file(proc_lib_file, Some(Arc::new(source))); + change.change_file(proc_lib_file, Some(Arc::from(source))); let all_crates = crate_graph.crates_in_topological_order(); @@ -279,14 +296,15 @@ impl ChangeFixture { Edition::Edition2021, Some(CrateDisplayName::from_canonical_name("proc_macros".to_string())), None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(proc_macro), true, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, target_layout, + Some(toolchain), ); + proc_macros.insert(proc_macros_crate, Ok(proc_macro)); for krate in all_crates { crate_graph @@ -305,6 +323,7 @@ impl ChangeFixture { roots.push(root); change.set_roots(roots); change.set_crate_graph(crate_graph); + change.set_proc_macros(proc_macros); ChangeFixture { file_position, files, change } } @@ -323,7 +342,7 @@ pub fn identity(_attr: TokenStream, item: TokenStream) -> TokenStream { ProcMacro { name: "identity".into(), kind: crate::ProcMacroKind::Attr, - expander: Arc::new(IdentityProcMacroExpander), + expander: sync::Arc::new(IdentityProcMacroExpander), }, ), ( @@ -337,7 +356,7 @@ pub fn derive_identity(item: TokenStream) -> TokenStream { ProcMacro { name: "DeriveIdentity".into(), kind: crate::ProcMacroKind::CustomDerive, - expander: Arc::new(IdentityProcMacroExpander), + expander: sync::Arc::new(IdentityProcMacroExpander), }, ), ( @@ -351,7 +370,7 @@ pub fn input_replace(attr: TokenStream, _item: TokenStream) -> TokenStream { ProcMacro { name: "input_replace".into(), kind: crate::ProcMacroKind::Attr, - expander: Arc::new(AttributeInputReplaceProcMacroExpander), + expander: sync::Arc::new(AttributeInputReplaceProcMacroExpander), }, ), ( @@ -365,7 +384,7 @@ pub fn mirror(input: TokenStream) -> TokenStream { ProcMacro { name: "mirror".into(), kind: crate::ProcMacroKind::FuncLike, - expander: Arc::new(MirrorProcMacroExpander), + expander: sync::Arc::new(MirrorProcMacroExpander), }, ), ( @@ -379,7 +398,7 @@ pub fn shorten(input: TokenStream) -> TokenStream { ProcMacro { name: "shorten".into(), kind: crate::ProcMacroKind::FuncLike, - expander: Arc::new(ShortenProcMacroExpander), + expander: sync::Arc::new(ShortenProcMacroExpander), }, ), ] @@ -428,7 +447,7 @@ fn parse_crate(crate_str: String) -> (String, CrateOrigin, Option) { let (version, origin) = match b.split_once(':') { Some(("CratesIo", data)) => match data.split_once(',') { Some((version, url)) => { - (version, CrateOrigin::CratesIo { repo: Some(url.to_owned()), name: None }) + (version, CrateOrigin::Local { repo: Some(url.to_owned()), name: None }) } _ => panic!("Bad crates.io parameter: {data}"), }, @@ -436,10 +455,9 @@ fn parse_crate(crate_str: String) -> (String, CrateOrigin, Option) { }; (a.to_owned(), origin, Some(version.to_string())) } else { - let crate_origin = match &*crate_str { - "std" => CrateOrigin::Lang(LangCrateOrigin::Std), - "core" => CrateOrigin::Lang(LangCrateOrigin::Core), - _ => CrateOrigin::CratesIo { repo: None, name: None }, + let crate_origin = match LangCrateOrigin::from(&*crate_str) { + LangCrateOrigin::Other => CrateOrigin::Local { repo: None, name: None }, + origin => CrateOrigin::Lang(origin), }; (crate_str, crate_origin, None) } diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index 43388e915b5d3..e8d521b42f868 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -6,14 +6,20 @@ //! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how //! actual IO is done and lowered to input. -use std::{fmt, ops, panic::RefUnwindSafe, str::FromStr, sync::Arc}; +use std::{fmt, mem, ops, panic::RefUnwindSafe, str::FromStr, sync}; use cfg::CfgOptions; -use rustc_hash::FxHashMap; -use stdx::hash::{NoHashHashMap, NoHashHashSet}; +use la_arena::{Arena, Idx}; +use rustc_hash::{FxHashMap, FxHashSet}; use syntax::SmolStr; +use triomphe::Arc; use tt::token_id::Subtree; -use vfs::{file_set::FileSet, AnchoredPath, FileId, VfsPath}; +use vfs::{file_set::FileSet, AbsPathBuf, AnchoredPath, FileId, VfsPath}; + +// Map from crate id to the name of the crate and path of the proc-macro. If the value is `None`, +// then the crate for the proc-macro hasn't been build yet as the build data is missing. +pub type ProcMacroPaths = FxHashMap, AbsPathBuf), String>>; +pub type ProcMacros = FxHashMap; /// Files are grouped into source roots. A source root is a directory on the /// file systems which is watched for changes. Typically it corresponds to a @@ -79,17 +85,22 @@ impl SourceRoot { /// /// `CrateGraph` is `!Serialize` by design, see /// -#[derive(Debug, Clone, Default /* Serialize, Deserialize */)] +#[derive(Clone, Default)] pub struct CrateGraph { - arena: NoHashHashMap, + arena: Arena, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct CrateId(pub u32); +impl fmt::Debug for CrateGraph { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_map() + .entries(self.arena.iter().map(|(id, data)| (u32::from(id.into_raw()), data))) + .finish() + } +} -impl stdx::hash::NoHashHashable for CrateId {} +pub type CrateId = Idx; -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct CrateName(SmolStr); impl CrateName { @@ -130,8 +141,12 @@ impl ops::Deref for CrateName { /// Origin of the crates. It is used in emitting monikers. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum CrateOrigin { - /// Crates that are from crates.io official registry, - CratesIo { repo: Option, name: Option }, + /// Crates that are from the rustc workspace + Rustc { name: String }, + /// Crates that are workspace members, + Local { repo: Option, name: Option }, + /// Crates that are non member libraries. + Library { repo: Option, name: String }, /// Crates that are provided by the language, like std, core, proc-macro, ... Lang(LangCrateOrigin), } @@ -173,7 +188,7 @@ impl fmt::Display for LangCrateOrigin { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct CrateDisplayName { // The name we use to display various paths (with `_`). crate_name: CrateName, @@ -249,10 +264,36 @@ pub type TargetLayoutLoadResult = Result, Arc>; pub struct ProcMacro { pub name: SmolStr, pub kind: ProcMacroKind, - pub expander: Arc, + pub expander: sync::Arc, } -#[derive(Debug, Clone)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum ReleaseChannel { + Stable, + Beta, + Nightly, +} + +impl ReleaseChannel { + pub fn as_str(self) -> &'static str { + match self { + ReleaseChannel::Stable => "stable", + ReleaseChannel::Beta => "beta", + ReleaseChannel::Nightly => "nightly", + } + } + + pub fn from_str(str: &str) -> Option { + Some(match str { + "" => ReleaseChannel::Stable, + "nightly" => ReleaseChannel::Nightly, + _ if str.starts_with("beta") => ReleaseChannel::Beta, + _ => return None, + }) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] pub struct CrateData { pub root_file_id: FileId, pub edition: Edition, @@ -265,13 +306,15 @@ pub struct CrateData { /// `Dependency` matters), this name should only be used for UI. pub display_name: Option, pub cfg_options: CfgOptions, - pub potential_cfg_options: CfgOptions, - pub target_layout: TargetLayoutLoadResult, + /// The cfg options that could be used by the crate + pub potential_cfg_options: Option, pub env: Env, pub dependencies: Vec, - pub proc_macro: ProcMacroLoadResult, pub origin: CrateOrigin, pub is_proc_macro: bool, + // FIXME: These things should not be per crate! These are more per workspace crate graph level things + pub target_layout: TargetLayoutLoadResult, + pub channel: Option, } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -290,7 +333,7 @@ pub struct Env { entries: FxHashMap, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Dependency { pub crate_id: CrateId, pub name: CrateName, @@ -320,12 +363,12 @@ impl CrateGraph { display_name: Option, version: Option, cfg_options: CfgOptions, - potential_cfg_options: CfgOptions, + potential_cfg_options: Option, env: Env, - proc_macro: ProcMacroLoadResult, is_proc_macro: bool, origin: CrateOrigin, target_layout: Result, Arc>, + channel: Option, ) -> CrateId { let data = CrateData { root_file_id, @@ -335,16 +378,44 @@ impl CrateGraph { cfg_options, potential_cfg_options, env, - proc_macro, dependencies: Vec::new(), origin, target_layout, is_proc_macro, + channel, }; - let crate_id = CrateId(self.arena.len() as u32); - let prev = self.arena.insert(crate_id, data); - assert!(prev.is_none()); - crate_id + self.arena.alloc(data) + } + + /// Remove the crate from crate graph. If any crates depend on this crate, the dependency would be replaced + /// with the second input. + pub fn remove_and_replace( + &mut self, + id: CrateId, + replace_with: CrateId, + ) -> Result<(), CyclicDependenciesError> { + for (x, data) in self.arena.iter() { + if x == id { + continue; + } + for edge in &data.dependencies { + if edge.crate_id == id { + self.check_cycle_after_dependency(edge.crate_id, replace_with)?; + } + } + } + // if everything was ok, start to replace + for (x, data) in self.arena.iter_mut() { + if x == id { + continue; + } + for edge in &mut data.dependencies { + if edge.crate_id == id { + edge.crate_id = replace_with; + } + } + } + Ok(()) } pub fn add_dep( @@ -354,17 +425,26 @@ impl CrateGraph { ) -> Result<(), CyclicDependenciesError> { let _p = profile::span("add_dep"); - // Check if adding a dep from `from` to `to` creates a cycle. To figure - // that out, look for a path in the *opposite* direction, from `to` to - // `from`. - if let Some(path) = self.find_path(&mut NoHashHashSet::default(), dep.crate_id, from) { + self.check_cycle_after_dependency(from, dep.crate_id)?; + + self.arena[from].add_dep(dep); + Ok(()) + } + + /// Check if adding a dep from `from` to `to` creates a cycle. To figure + /// that out, look for a path in the *opposite* direction, from `to` to + /// `from`. + fn check_cycle_after_dependency( + &self, + from: CrateId, + to: CrateId, + ) -> Result<(), CyclicDependenciesError> { + if let Some(path) = self.find_path(&mut FxHashSet::default(), to, from) { let path = path.into_iter().map(|it| (it, self[it].display_name.clone())).collect(); let err = CyclicDependenciesError { path }; - assert!(err.from().0 == from && err.to().0 == dep.crate_id); + assert!(err.from().0 == from && err.to().0 == to); return Err(err); } - - self.arena.get_mut(&from).unwrap().add_dep(dep); Ok(()) } @@ -373,14 +453,14 @@ impl CrateGraph { } pub fn iter(&self) -> impl Iterator + '_ { - self.arena.keys().copied() + self.arena.iter().map(|(idx, _)| idx) } /// Returns an iterator over all transitive dependencies of the given crate, /// including the crate itself. pub fn transitive_deps(&self, of: CrateId) -> impl Iterator { let mut worklist = vec![of]; - let mut deps = NoHashHashSet::default(); + let mut deps = FxHashSet::default(); while let Some(krate) = worklist.pop() { if !deps.insert(krate) { @@ -397,11 +477,11 @@ impl CrateGraph { /// including the crate itself. pub fn transitive_rev_deps(&self, of: CrateId) -> impl Iterator { let mut worklist = vec![of]; - let mut rev_deps = NoHashHashSet::default(); + let mut rev_deps = FxHashSet::default(); rev_deps.insert(of); - let mut inverted_graph = NoHashHashMap::<_, Vec<_>>::default(); - self.arena.iter().for_each(|(&krate, data)| { + let mut inverted_graph = FxHashMap::<_, Vec<_>>::default(); + self.arena.iter().for_each(|(krate, data)| { data.dependencies .iter() .for_each(|dep| inverted_graph.entry(dep.crate_id).or_default().push(krate)) @@ -424,9 +504,9 @@ impl CrateGraph { /// come before the crate itself). pub fn crates_in_topological_order(&self) -> Vec { let mut res = Vec::new(); - let mut visited = NoHashHashSet::default(); + let mut visited = FxHashSet::default(); - for krate in self.arena.keys().copied() { + for krate in self.iter() { go(self, &mut visited, &mut res, krate); } @@ -434,7 +514,7 @@ impl CrateGraph { fn go( graph: &CrateGraph, - visited: &mut NoHashHashSet, + visited: &mut FxHashSet, res: &mut Vec, source: CrateId, ) { @@ -450,31 +530,56 @@ impl CrateGraph { // FIXME: this only finds one crate with the given root; we could have multiple pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option { - let (&crate_id, _) = + let (crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.root_file_id == file_id)?; Some(crate_id) } + pub fn sort_deps(&mut self) { + self.arena + .iter_mut() + .for_each(|(_, data)| data.dependencies.sort_by_key(|dep| dep.crate_id)); + } + /// Extends this crate graph by adding a complete disjoint second crate - /// graph. + /// graph and adjust the ids in the [`ProcMacroPaths`] accordingly. /// - /// The ids of the crates in the `other` graph are shifted by the return - /// amount. - pub fn extend(&mut self, other: CrateGraph) -> u32 { - let start = self.arena.len() as u32; - self.arena.extend(other.arena.into_iter().map(|(id, mut data)| { - let new_id = id.shift(start); - for dep in &mut data.dependencies { - dep.crate_id = dep.crate_id.shift(start); + /// This will deduplicate the crates of the graph where possible. + /// Note that for deduplication to fully work, `self`'s crate dependencies must be sorted by crate id. + /// If the crate dependencies were sorted, the resulting graph from this `extend` call will also have the crate dependencies sorted. + pub fn extend(&mut self, mut other: CrateGraph, proc_macros: &mut ProcMacroPaths) { + let topo = other.crates_in_topological_order(); + let mut id_map: FxHashMap = FxHashMap::default(); + + for topo in topo { + let crate_data = &mut other.arena[topo]; + crate_data.dependencies.iter_mut().for_each(|dep| dep.crate_id = id_map[&dep.crate_id]); + crate_data.dependencies.sort_by_key(|dep| dep.crate_id); + + let res = self.arena.iter().find_map( + |(id, data)| { + if data == crate_data { + Some(id) + } else { + None + } + }, + ); + if let Some(res) = res { + id_map.insert(topo, res); + } else { + let id = self.arena.alloc(crate_data.clone()); + id_map.insert(topo, id); } - (new_id, data) - })); - start + } + + *proc_macros = + mem::take(proc_macros).into_iter().map(|(id, macros)| (id_map[&id], macros)).collect(); } fn find_path( &self, - visited: &mut NoHashHashSet, + visited: &mut FxHashSet, from: CrateId, to: CrateId, ) -> Option> { @@ -500,14 +605,14 @@ impl CrateGraph { // Work around for https://github.com/rust-lang/rust-analyzer/issues/6038. // As hacky as it gets. pub fn patch_cfg_if(&mut self) -> bool { - let cfg_if = self.hacky_find_crate("cfg_if"); - let std = self.hacky_find_crate("std"); + // we stupidly max by version in an attempt to have all duplicated std's depend on the same cfg_if so that deduplication still works + let cfg_if = + self.hacky_find_crate("cfg_if").max_by_key(|&it| self.arena[it].version.clone()); + let std = self.hacky_find_crate("std").next(); match (cfg_if, std) { (Some(cfg_if), Some(std)) => { - self.arena.get_mut(&cfg_if).unwrap().dependencies.clear(); - self.arena - .get_mut(&std) - .unwrap() + self.arena[cfg_if].dependencies.clear(); + self.arena[std] .dependencies .push(Dependency::new(CrateName::new("cfg_if").unwrap(), cfg_if)); true @@ -516,21 +621,15 @@ impl CrateGraph { } } - fn hacky_find_crate(&self, display_name: &str) -> Option { - self.iter().find(|it| self[*it].display_name.as_deref() == Some(display_name)) + fn hacky_find_crate<'a>(&'a self, display_name: &'a str) -> impl Iterator + 'a { + self.iter().filter(move |it| self[*it].display_name.as_deref() == Some(display_name)) } } impl ops::Index for CrateGraph { type Output = CrateData; fn index(&self, crate_id: CrateId) -> &CrateData { - &self.arena[&crate_id] - } -} - -impl CrateId { - fn shift(self, amount: u32) -> CrateId { - CrateId(self.0 + amount) + &self.arena[crate_id] } } @@ -632,7 +731,7 @@ impl fmt::Display for CyclicDependenciesError { mod tests { use crate::CrateOrigin; - use super::{CfgOptions, CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId}; + use super::{CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId}; #[test] fn detect_cyclic_dependency_indirect() { @@ -642,39 +741,39 @@ mod tests { Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); let crate2 = graph.add_crate_root( FileId(2u32), Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); let crate3 = graph.add_crate_root( FileId(3u32), Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); assert!(graph .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) @@ -695,26 +794,26 @@ mod tests { Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); let crate2 = graph.add_crate_root( FileId(2u32), Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); assert!(graph .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) @@ -732,39 +831,39 @@ mod tests { Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); let crate2 = graph.add_crate_root( FileId(2u32), Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); let crate3 = graph.add_crate_root( FileId(3u32), Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); assert!(graph .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) @@ -782,26 +881,26 @@ mod tests { Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); let crate2 = graph.add_crate_root( FileId(2u32), Edition2018, None, None, - CfgOptions::default(), - CfgOptions::default(), + Default::default(), + Default::default(), Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); assert!(graph .add_dep( diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index 9720db9d8ace3..af204e44e6ee1 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs @@ -6,18 +6,19 @@ mod input; mod change; pub mod fixture; -use std::{panic, sync::Arc}; +use std::panic; -use stdx::hash::NoHashHashSet; +use rustc_hash::FxHashSet; use syntax::{ast, Parse, SourceFile, TextRange, TextSize}; +use triomphe::Arc; pub use crate::{ change::Change, input::{ CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env, LangCrateOrigin, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, - ProcMacroId, ProcMacroKind, ProcMacroLoadResult, SourceRoot, SourceRootId, - TargetLayoutLoadResult, + ProcMacroId, ProcMacroKind, ProcMacroLoadResult, ProcMacroPaths, ProcMacros, + ReleaseChannel, SourceRoot, SourceRootId, TargetLayoutLoadResult, }, }; pub use salsa::{self, Cancelled}; @@ -53,13 +54,13 @@ pub struct FileRange { pub range: TextRange, } -pub const DEFAULT_LRU_CAP: usize = 128; +pub const DEFAULT_PARSE_LRU_CAP: usize = 128; pub trait FileLoader { /// Text of the file. - fn file_text(&self, file_id: FileId) -> Arc; + fn file_text(&self, file_id: FileId) -> Arc; fn resolve_path(&self, path: AnchoredPath<'_>) -> Option; - fn relevant_crates(&self, file_id: FileId) -> Arc>; + fn relevant_crates(&self, file_id: FileId) -> Arc>; } /// Database which stores all significant input facts: source code and project @@ -73,6 +74,10 @@ pub trait SourceDatabase: FileLoader + std::fmt::Debug { /// The crate graph. #[salsa::input] fn crate_graph(&self) -> Arc; + + /// The crate graph. + #[salsa::input] + fn proc_macros(&self) -> Arc; } fn parse_query(db: &dyn SourceDatabase, file_id: FileId) -> Parse { @@ -86,7 +91,7 @@ fn parse_query(db: &dyn SourceDatabase, file_id: FileId) -> Parse Arc; + fn file_text(&self, file_id: FileId) -> Arc; /// Path to a file, relative to the root of its source root. /// Source root of the file. #[salsa::input] @@ -95,10 +100,10 @@ pub trait SourceDatabaseExt: SourceDatabase { #[salsa::input] fn source_root(&self, id: SourceRootId) -> Arc; - fn source_root_crates(&self, id: SourceRootId) -> Arc>; + fn source_root_crates(&self, id: SourceRootId) -> Arc>; } -fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc> { +fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc> { let graph = db.crate_graph(); let res = graph .iter() @@ -114,7 +119,7 @@ fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc(pub T); impl FileLoader for FileLoaderDelegate<&'_ T> { - fn file_text(&self, file_id: FileId) -> Arc { + fn file_text(&self, file_id: FileId) -> Arc { SourceDatabaseExt::file_text(self.0, file_id) } fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { @@ -124,7 +129,7 @@ impl FileLoader for FileLoaderDelegate<&'_ T> { source_root.resolve_path(path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc> { let _p = profile::span("relevant_crates"); let source_root = self.0.file_source_root(file_id); self.0.source_root_crates(source_root) diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs index 30709c968dacf..495119d5519c3 100644 --- a/crates/cfg/src/lib.rs +++ b/crates/cfg/src/lib.rs @@ -86,7 +86,7 @@ impl CfgOptions { } } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Default, Clone, Debug, PartialEq, Eq)] pub struct CfgDiff { // Invariants: No duplicates, no atom that's both in `enable` and `disable`. enable: Vec, diff --git a/crates/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml index 609d18c4eea33..3f6671b1c43dd 100644 --- a/crates/flycheck/Cargo.toml +++ b/crates/flycheck/Cargo.toml @@ -16,9 +16,8 @@ crossbeam-channel = "0.5.5" tracing = "0.1.37" cargo_metadata = "0.15.0" rustc-hash = "1.1.0" -serde = { version = "1.0.137", features = ["derive"] } -serde_json = "1.0.86" -jod-thread = "0.1.2" +serde_json.workspace = true +serde.workspace = true command-group = "2.0.1" # local deps diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index accb14a51deb9..fbb943ccb99dd 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -77,7 +77,7 @@ impl fmt::Display for FlycheckConfig { pub struct FlycheckHandle { // XXX: drop order is significant sender: Sender, - _thread: jod_thread::JoinHandle, + _thread: stdx::thread::JoinHandle, id: usize, } @@ -90,7 +90,7 @@ impl FlycheckHandle { ) -> FlycheckHandle { let actor = FlycheckActor::new(id, sender, config, workspace_root); let (sender, receiver) = unbounded::(); - let thread = jod_thread::Builder::new() + let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) .name("Flycheck".to_owned()) .spawn(move || actor.run(receiver)) .expect("failed to spawn thread"); @@ -395,7 +395,7 @@ struct CargoHandle { /// The handle to the actual cargo process. As we cannot cancel directly from with /// a read syscall dropping and therefore terminating the process is our best option. child: JodGroupChild, - thread: jod_thread::JoinHandle>, + thread: stdx::thread::JoinHandle>, receiver: Receiver, } @@ -409,7 +409,7 @@ impl CargoHandle { let (sender, receiver) = unbounded(); let actor = CargoActor::new(sender, stdout, stderr); - let thread = jod_thread::Builder::new() + let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) .name("CargoHandle".to_owned()) .spawn(move || actor.run()) .expect("failed to spawn thread"); @@ -485,7 +485,7 @@ impl CargoActor { error.push_str(line); error.push('\n'); - return false; + false }; let output = streaming_output( self.stdout, diff --git a/crates/hir-def/Cargo.toml b/crates/hir-def/Cargo.toml index 31d4018d2b6ab..83c7051646ed8 100644 --- a/crates/hir-def/Cargo.toml +++ b/crates/hir-def/Cargo.toml @@ -14,7 +14,7 @@ doctest = false [dependencies] anymap = "1.0.0-beta.2" arrayvec = "0.7.2" -bitflags = "1.3.2" +bitflags = "2.1.0" cov-mark = "2.0.0-pre.1" # We need to freeze the version of the crate, as the raw-api feature is considered unstable dashmap = { version = "=5.4.0", features = ["raw-api"] } @@ -29,6 +29,7 @@ once_cell = "1.17.0" rustc-hash = "1.1.0" smallvec.workspace = true tracing = "0.1.35" +triomphe.workspace = true rustc_abi = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_abi", default-features = false } rustc_index = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_index", default-features = false } diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index 200072c172ebe..bab3bbc2329a9 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -1,6 +1,11 @@ //! A higher level attributes based on TokenTree, with also some shortcuts. -use std::{hash::Hash, ops, sync::Arc}; +pub mod builtin; + +#[cfg(test)] +mod tests; + +use std::{hash::Hash, ops}; use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; @@ -16,14 +21,16 @@ use syntax::{ ast::{self, HasAttrs, IsString}, AstPtr, AstToken, SmolStr, TextRange, TextSize, }; +use triomphe::Arc; use crate::{ db::DefDatabase, item_tree::{AttrOwner, Fields, ItemTreeId, ItemTreeNode}, + lang_item::LangItem, nameres::{ModuleOrigin, ModuleSource}, src::{HasChildSource, HasSource}, - AdtId, AttrDefId, EnumId, GenericParamId, LocalEnumVariantId, LocalFieldId, Lookup, MacroId, - VariantId, + AdtId, AssocItemLoc, AttrDefId, EnumId, GenericParamId, ItemLoc, LocalEnumVariantId, + LocalFieldId, Lookup, MacroId, VariantId, }; /// Holds documentation @@ -88,6 +95,7 @@ impl Attrs { db: &dyn DefDatabase, e: EnumId, ) -> Arc> { + let _p = profile::span("variants_attrs_query"); // FIXME: There should be some proper form of mapping between item tree enum variant ids and hir enum variant ids let mut res = ArenaMap::default(); @@ -114,6 +122,7 @@ impl Attrs { db: &dyn DefDatabase, v: VariantId, ) -> Arc> { + let _p = profile::span("fields_attrs_query"); // FIXME: There should be some proper form of mapping between item tree field ids and hir field ids let mut res = ArenaMap::default(); @@ -175,13 +184,13 @@ impl Attrs { Arc::new(res) } +} +impl Attrs { pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { AttrQuery { attrs: self, key } } -} -impl Attrs { pub fn cfg(&self) -> Option { let mut cfgs = self.by_key("cfg").tt_values().map(CfgExpr::parse); let first = cfgs.next()?; @@ -193,6 +202,7 @@ impl Attrs { None => Some(first), } } + pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool { match self.cfg() { None => true, @@ -204,6 +214,10 @@ impl Attrs { self.by_key("lang").string_value() } + pub fn lang_item(&self) -> Option { + self.by_key("lang").string_value().and_then(|it| LangItem::from_str(it)) + } + pub fn docs(&self) -> Option { let docs = self.by_key("doc").attrs().filter_map(|attr| attr.string_value()); let indent = doc_indent(self); @@ -238,6 +252,14 @@ impl Attrs { }) } + pub fn doc_exprs(&self) -> impl Iterator + '_ { + self.by_key("doc").tt_values().map(DocExpr::parse) + } + + pub fn doc_aliases(&self) -> impl Iterator + '_ { + self.doc_exprs().flat_map(|doc_expr| doc_expr.aliases().to_vec()) + } + pub fn is_proc_macro(&self) -> bool { self.by_key("proc_macro").exists() } @@ -249,10 +271,120 @@ impl Attrs { pub fn is_proc_macro_derive(&self) -> bool { self.by_key("proc_macro_derive").exists() } + + pub fn is_unstable(&self) -> bool { + self.by_key("unstable").exists() + } +} + +use std::slice::Iter as SliceIter; +#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] +pub enum DocAtom { + /// eg. `#[doc(hidden)]` + Flag(SmolStr), + /// eg. `#[doc(alias = "x")]` + /// + /// Note that a key can have multiple values that are all considered "active" at the same time. + /// For example, `#[doc(alias = "x")]` and `#[doc(alias = "y")]`. + KeyValue { key: SmolStr, value: SmolStr }, +} + +// Adapted from `CfgExpr` parsing code +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +// #[cfg_attr(test, derive(derive_arbitrary::Arbitrary))] +pub enum DocExpr { + Invalid, + /// eg. `#[doc(hidden)]`, `#[doc(alias = "x")]` + Atom(DocAtom), + /// eg. `#[doc(alias("x", "y"))]` + Alias(Vec), +} + +impl From for DocExpr { + fn from(atom: DocAtom) -> Self { + DocExpr::Atom(atom) + } +} + +impl DocExpr { + fn parse(tt: &tt::Subtree) -> DocExpr { + next_doc_expr(&mut tt.token_trees.iter()).unwrap_or(DocExpr::Invalid) + } + + pub fn aliases(&self) -> &[SmolStr] { + match self { + DocExpr::Atom(DocAtom::KeyValue { key, value }) if key == "alias" => { + std::slice::from_ref(value) + } + DocExpr::Alias(aliases) => aliases, + _ => &[], + } + } +} + +fn next_doc_expr(it: &mut SliceIter<'_, tt::TokenTree>) -> Option { + let name = match it.next() { + None => return None, + Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) => ident.text.clone(), + Some(_) => return Some(DocExpr::Invalid), + }; + + // Peek + let ret = match it.as_slice().first() { + Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) if punct.char == '=' => { + match it.as_slice().get(1) { + Some(tt::TokenTree::Leaf(tt::Leaf::Literal(literal))) => { + it.next(); + it.next(); + // FIXME: escape? raw string? + let value = + SmolStr::new(literal.text.trim_start_matches('"').trim_end_matches('"')); + DocAtom::KeyValue { key: name, value }.into() + } + _ => return Some(DocExpr::Invalid), + } + } + Some(tt::TokenTree::Subtree(subtree)) => { + it.next(); + let subs = parse_comma_sep(subtree); + match name.as_str() { + "alias" => DocExpr::Alias(subs), + _ => DocExpr::Invalid, + } + } + _ => DocAtom::Flag(name).into(), + }; + + // Eat comma separator + if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = it.as_slice().first() { + if punct.char == ',' { + it.next(); + } + } + Some(ret) +} + +fn parse_comma_sep(subtree: &tt::Subtree) -> Vec { + subtree + .token_trees + .iter() + .filter_map(|tt| match tt { + tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => { + // FIXME: escape? raw string? + Some(SmolStr::new(lit.text.trim_start_matches('"').trim_end_matches('"'))) + } + _ => None, + }) + .collect() } impl AttrsWithOwner { - pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Self { + pub(crate) fn attrs_with_owner(db: &dyn DefDatabase, owner: AttrDefId) -> Self { + Self { attrs: db.attrs(owner), owner } + } + + pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { + let _p = profile::span("attrs_query"); // FIXME: this should use `Trace` to avoid duplication in `source_map` below let raw_attrs = match def { AttrDefId::ModuleId(module) => { @@ -286,31 +418,29 @@ impl AttrsWithOwner { } } AttrDefId::FieldId(it) => { - return Self { attrs: db.fields_attrs(it.parent)[it.local_id].clone(), owner: def }; + return db.fields_attrs(it.parent)[it.local_id].clone(); } AttrDefId::EnumVariantId(it) => { - return Self { - attrs: db.variants_attrs(it.parent)[it.local_id].clone(), - owner: def, - }; + return db.variants_attrs(it.parent)[it.local_id].clone(); } + // FIXME: DRY this up AttrDefId::AdtId(it) => match it { - AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db), + AdtId::StructId(it) => attrs_from_item_tree_loc(db, it), + AdtId::EnumId(it) => attrs_from_item_tree_loc(db, it), + AdtId::UnionId(it) => attrs_from_item_tree_loc(db, it), }, - AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AttrDefId::TraitAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), + AttrDefId::TraitId(it) => attrs_from_item_tree_loc(db, it), + AttrDefId::TraitAliasId(it) => attrs_from_item_tree_loc(db, it), AttrDefId::MacroId(it) => match it { - MacroId::Macro2Id(it) => attrs_from_item_tree(it.lookup(db).id, db), - MacroId::MacroRulesId(it) => attrs_from_item_tree(it.lookup(db).id, db), - MacroId::ProcMacroId(it) => attrs_from_item_tree(it.lookup(db).id, db), + MacroId::Macro2Id(it) => attrs_from_item_tree(db, it.lookup(db).id), + MacroId::MacroRulesId(it) => attrs_from_item_tree(db, it.lookup(db).id), + MacroId::ProcMacroId(it) => attrs_from_item_tree(db, it.lookup(db).id), }, - AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db), - AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), + AttrDefId::ImplId(it) => attrs_from_item_tree_loc(db, it), + AttrDefId::ConstId(it) => attrs_from_item_tree_assoc(db, it), + AttrDefId::StaticId(it) => attrs_from_item_tree_assoc(db, it), + AttrDefId::FunctionId(it) => attrs_from_item_tree_assoc(db, it), + AttrDefId::TypeAliasId(it) => attrs_from_item_tree_assoc(db, it), AttrDefId::GenericParamId(it) => match it { GenericParamId::ConstParamId(it) => { let src = it.parent().child_source(db); @@ -331,11 +461,11 @@ impl AttrsWithOwner { RawAttrs::from_attrs_owner(db.upcast(), src.with_value(&src.value[it.local_id])) } }, - AttrDefId::ExternBlockId(it) => attrs_from_item_tree(it.lookup(db).id, db), + AttrDefId::ExternBlockId(it) => attrs_from_item_tree_loc(db, it), }; let attrs = raw_attrs.filter(db.upcast(), def.krate(db)); - Self { attrs: Attrs(attrs), owner: def } + Attrs(attrs) } pub fn source_map(&self, db: &dyn DefDatabase) -> AttrSourceMap { @@ -371,7 +501,7 @@ impl AttrsWithOwner { AttrDefId::FieldId(id) => { let map = db.fields_attrs_source_map(id.parent); let file_id = id.parent.file_id(db); - let root = db.parse_or_expand(file_id).unwrap(); + let root = db.parse_or_expand(file_id); let owner = match &map[id.local_id] { Either::Left(it) => ast::AnyHasAttrs::new(it.to_node(&root)), Either::Right(it) => ast::AnyHasAttrs::new(it.to_node(&root)), @@ -379,28 +509,28 @@ impl AttrsWithOwner { InFile::new(file_id, owner) } AttrDefId::AdtId(adt) => match adt { - AdtId::StructId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AdtId::UnionId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), + AdtId::StructId(id) => any_has_attrs(db, id), + AdtId::UnionId(id) => any_has_attrs(db, id), + AdtId::EnumId(id) => any_has_attrs(db, id), }, - AttrDefId::FunctionId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), + AttrDefId::FunctionId(id) => any_has_attrs(db, id), AttrDefId::EnumVariantId(id) => { let map = db.variants_attrs_source_map(id.parent); let file_id = id.parent.lookup(db).id.file_id(); - let root = db.parse_or_expand(file_id).unwrap(); + let root = db.parse_or_expand(file_id); InFile::new(file_id, ast::AnyHasAttrs::new(map[id.local_id].to_node(&root))) } - AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AttrDefId::TraitAliasId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - AttrDefId::TypeAliasId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), + AttrDefId::StaticId(id) => any_has_attrs(db, id), + AttrDefId::ConstId(id) => any_has_attrs(db, id), + AttrDefId::TraitId(id) => any_has_attrs(db, id), + AttrDefId::TraitAliasId(id) => any_has_attrs(db, id), + AttrDefId::TypeAliasId(id) => any_has_attrs(db, id), AttrDefId::MacroId(id) => match id { - MacroId::Macro2Id(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - MacroId::MacroRulesId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), - MacroId::ProcMacroId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), + MacroId::Macro2Id(id) => any_has_attrs(db, id), + MacroId::MacroRulesId(id) => any_has_attrs(db, id), + MacroId::ProcMacroId(id) => any_has_attrs(db, id), }, - AttrDefId::ImplId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), + AttrDefId::ImplId(id) => any_has_attrs(db, id), AttrDefId::GenericParamId(id) => match id { GenericParamId::ConstParamId(id) => id .parent() @@ -415,7 +545,7 @@ impl AttrsWithOwner { .child_source(db) .map(|source| ast::AnyHasAttrs::new(source[id.local_id].clone())), }, - AttrDefId::ExternBlockId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), + AttrDefId::ExternBlockId(id) => any_has_attrs(db, id), }; AttrSourceMap::new(owner.as_ref().map(|node| node as &dyn HasAttrs)) @@ -635,19 +765,42 @@ impl<'attr> AttrQuery<'attr> { .nth(2); match name { - Some(tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal{ref text, ..}))) => Some(text), + Some(tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal{ ref text, ..}))) => Some(text), _ => None } }) } } -fn attrs_from_item_tree(id: ItemTreeId, db: &dyn DefDatabase) -> RawAttrs { +fn any_has_attrs( + db: &dyn DefDatabase, + id: impl Lookup>, +) -> InFile { + id.lookup(db).source(db).map(ast::AnyHasAttrs::new) +} + +fn attrs_from_item_tree(db: &dyn DefDatabase, id: ItemTreeId) -> RawAttrs { let tree = id.item_tree(db); let mod_item = N::id_to_mod_item(id.value); tree.raw_attrs(mod_item.into()).clone() } +fn attrs_from_item_tree_loc( + db: &dyn DefDatabase, + lookup: impl Lookup>, +) -> RawAttrs { + let id = lookup.lookup(db).id; + attrs_from_item_tree(db, id) +} + +fn attrs_from_item_tree_assoc( + db: &dyn DefDatabase, + lookup: impl Lookup>, +) -> RawAttrs { + let id = lookup.lookup(db).id; + attrs_from_item_tree(db, id) +} + pub(crate) fn variants_attrs_source_map( db: &dyn DefDatabase, def: EnumId, diff --git a/crates/hir-def/src/builtin_attr.rs b/crates/hir-def/src/attr/builtin.rs similarity index 83% rename from crates/hir-def/src/builtin_attr.rs rename to crates/hir-def/src/attr/builtin.rs index 142b12290194e..cead64a33749f 100644 --- a/crates/hir-def/src/builtin_attr.rs +++ b/crates/hir-def/src/attr/builtin.rs @@ -2,7 +2,7 @@ //! //! The actual definitions were copied from rustc's `compiler/rustc_feature/src/builtin_attrs.rs`. //! -//! It was last synchronized with upstream commit c1a2db3372a4d6896744919284f3287650a38ab7. +//! It was last synchronized with upstream commit e29821ff85a2a3000d226f99f62f89464028d5d6. //! //! The macros were adjusted to only expand to the attribute name, since that is all we need to do //! name resolution, and `BUILTIN_ATTRIBUTES` is almost entirely unchanged from the original, to @@ -108,7 +108,7 @@ macro_rules! experimental { }; } -/// "Inert" built-in attributes that have a special meaning to rustc or rustdoc. +/// Attributes that have a special meaning to rustc or rustdoc. #[rustfmt::skip] pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ // ========================================================================== @@ -123,7 +123,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ ungated!(ignore, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing), ungated!( should_panic, Normal, - template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), FutureWarnFollowing, + template!(Word, List: r#"expected = "reason""#, NameValueStr: "reason"), FutureWarnFollowing, ), // FIXME(Centril): This can be used on stable but shouldn't. ungated!(reexport_test_harness_main, CrateLevel, template!(NameValueStr: "name"), ErrorFollowing), @@ -142,20 +142,24 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ // Lints: ungated!( - warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk + warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + DuplicatesOk, @only_local: true, ), ungated!( - allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk + allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + DuplicatesOk, @only_local: true, ), gated!( expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk, lint_reasons, experimental!(expect) ), ungated!( - forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk + forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + DuplicatesOk, @only_local: true, ), ungated!( - deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk + deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + DuplicatesOk, @only_local: true, ), ungated!(must_use, Normal, template!(Word, NameValueStr: "reason"), FutureWarnFollowing), gated!( @@ -181,16 +185,17 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ // ABI, linking, symbols, and FFI ungated!( link, Normal, - template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...""#), + template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated""#), DuplicatesOk, ), ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), ungated!(no_link, Normal, template!(Word), WarnFollowing), - ungated!(repr, Normal, template!(List: "C"), DuplicatesOk), + ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, @only_local: true), ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true), ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, @only_local: true), + ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding), // Limits: ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing), @@ -201,6 +206,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ ), // Entry point: + gated!(unix_sigpipe, Normal, template!(Word, NameValueStr: "inherit|sig_ign|sig_dfl"), ErrorFollowing, experimental!(unix_sigpipe)), ungated!(start, Normal, template!(Word), WarnFollowing), ungated!(no_start, CrateLevel, template!(Word), WarnFollowing), ungated!(no_main, CrateLevel, template!(Word), WarnFollowing), @@ -222,11 +228,15 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing, @only_local: true), ungated!(cold, Normal, template!(Word), WarnFollowing, @only_local: true), ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing), - ungated!(target_feature, Normal, template!(List: r#"enable = "name""#), DuplicatesOk), + ungated!( + target_feature, Normal, template!(List: r#"enable = "name""#), + DuplicatesOk, @only_local: true, + ), ungated!(track_caller, Normal, template!(Word), WarnFollowing), + ungated!(instruction_set, Normal, template!(List: "set"), ErrorPreceding), gated!( no_sanitize, Normal, - template!(List: "address, memory, thread"), DuplicatesOk, + template!(List: "address, kcfi, memory, thread"), DuplicatesOk, experimental!(no_sanitize) ), gated!(no_coverage, Normal, template!(Word), WarnFollowing, experimental!(no_coverage)), @@ -235,25 +245,23 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string"), DuplicatesOk ), + // Debugging + ungated!( + debugger_visualizer, Normal, + template!(List: r#"natvis_file = "...", gdb_script_file = "...""#), DuplicatesOk + ), + // ========================================================================== // Unstable attributes: // ========================================================================== - // RFC #3191: #[debugger_visualizer] support - gated!( - debugger_visualizer, Normal, template!(List: r#"natvis_file = "...", gdb_script_file = "...""#), - DuplicatesOk, experimental!(debugger_visualizer) - ), - // Linking: - gated!(naked, Normal, template!(Word), WarnFollowing, @only_local: true, naked_functions, experimental!(naked)), gated!( - link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, raw_dylib, - experimental!(link_ordinal) + naked, Normal, template!(Word), WarnFollowing, @only_local: true, + naked_functions, experimental!(naked) ), // Plugins: - // XXX Modified for use in rust-analyzer // BuiltinAttribute { // name: sym::plugin, // only_local: false, @@ -270,10 +278,6 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ // cfg_fn!(plugin) // ), // }, - BuiltinAttribute { - name: "plugin", - template: template!(List: "name"), - }, // Testing: gated!( @@ -282,7 +286,8 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ ), // RFC #1268 gated!( - marker, Normal, template!(Word), WarnFollowing, marker_trait_attr, experimental!(marker) + marker, Normal, template!(Word), WarnFollowing, @only_local: true, + marker_trait_attr, experimental!(marker) ), gated!( thread_local, Normal, template!(Word), WarnFollowing, @@ -294,21 +299,12 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ optimize, Normal, template!(List: "size|speed"), ErrorPreceding, optimize_attribute, experimental!(optimize), ), - // RFC 2867 - gated!( - instruction_set, Normal, template!(List: "set"), ErrorPreceding, - isa_attribute, experimental!(instruction_set) - ), gated!( ffi_returns_twice, Normal, template!(Word), WarnFollowing, experimental!(ffi_returns_twice) ), gated!(ffi_pure, Normal, template!(Word), WarnFollowing, experimental!(ffi_pure)), gated!(ffi_const, Normal, template!(Word), WarnFollowing, experimental!(ffi_const)), - gated!( - register_attr, CrateLevel, template!(List: "attr1, attr2, ..."), DuplicatesOk, - experimental!(register_attr), - ), gated!( register_tool, CrateLevel, template!(List: "tool1, tool2, ..."), DuplicatesOk, experimental!(register_tool), @@ -321,7 +317,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ // RFC 2632 gated!( const_trait, Normal, template!(Word), WarnFollowing, const_trait_impl, - "`const` is a temporary placeholder for marking a trait that is suitable for `const` \ + "`const_trait` is a temporary placeholder for marking a trait that is suitable for `const` \ `impls` and all default bodies as `const`, which may be removed or renamed in the \ future." ), @@ -331,22 +327,47 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ experimental!(deprecated_safe), ), + // `#[collapse_debuginfo]` + gated!( + collapse_debuginfo, Normal, template!(Word), WarnFollowing, + experimental!(collapse_debuginfo) + ), + + // RFC 2397 + gated!(do_not_recommend, Normal, template!(Word), WarnFollowing, experimental!(do_not_recommend)), + + // `#[cfi_encoding = ""]` + gated!( + cfi_encoding, Normal, template!(NameValueStr: "encoding"), ErrorPreceding, + experimental!(cfi_encoding) + ), + // ========================================================================== // Internal attributes: Stability, deprecation, and unsafe: // ========================================================================== - ungated!(feature, CrateLevel, template!(List: "name1, name2, ..."), DuplicatesOk), + ungated!( + feature, CrateLevel, + template!(List: "name1, name2, ..."), DuplicatesOk, @only_local: true, + ), // DuplicatesOk since it has its own validation ungated!( - stable, Normal, template!(List: r#"feature = "name", since = "version""#), DuplicatesOk, + stable, Normal, + template!(List: r#"feature = "name", since = "version""#), DuplicatesOk, @only_local: true, ), ungated!( unstable, Normal, template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk, ), ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk), - ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk), - ungated!(rustc_safe_intrinsic, Normal, template!(List: r#"feature = "name""#), DuplicatesOk), + ungated!( + rustc_const_stable, Normal, + template!(List: r#"feature = "name""#), DuplicatesOk, @only_local: true, + ), + ungated!( + rustc_default_body_unstable, Normal, + template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk + ), gated!( allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, "allow_internal_unstable side-steps feature gating and stability checks", @@ -360,6 +381,10 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ allow_internal_unsafe, Normal, template!(Word), WarnFollowing, "allow_internal_unsafe side-steps the unsafe_code lint", ), + ungated!(rustc_safe_intrinsic, Normal, template!(Word), DuplicatesOk), + rustc_attr!(rustc_allowed_through_unstable_modules, Normal, template!(Word), WarnFollowing, + "rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \ + through unstable paths"), // ========================================================================== // Internal attributes: Type system related: @@ -377,10 +402,9 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(rustc_allocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), rustc_attr!(rustc_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), - gated!( - alloc_error_handler, Normal, template!(Word), WarnFollowing, - experimental!(alloc_error_handler) - ), + rustc_attr!(rustc_reallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), + rustc_attr!(rustc_deallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), + rustc_attr!(rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), gated!( default_lib_allocator, Normal, template!(Word), WarnFollowing, allocator_internals, experimental!(default_lib_allocator), @@ -461,6 +485,12 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ // Used by the `rustc::untranslatable_diagnostic` and `rustc::diagnostic_outside_of_impl` lints // to assist in changes to diagnostic APIs. rustc_attr!(rustc_lint_diagnostics, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), + // Used by the `rustc::bad_opt_access` lint to identify `DebuggingOptions` and `CodegenOptions` + // types (as well as any others in future). + rustc_attr!(rustc_lint_opt_ty, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), + // Used by the `rustc::bad_opt_access` lint on fields + // types (as well as any others in future). + rustc_attr!(rustc_lint_opt_deny_field_access, Normal, template!(List: "message"), WarnFollowing, INTERNAL_UNSTABLE), // ========================================================================== // Internal attributes, Const related: @@ -504,18 +534,25 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ "language items are subject to change", ), rustc_attr!( - rustc_pass_by_value, Normal, - template!(Word), ErrorFollowing, + rustc_pass_by_value, Normal, template!(Word), ErrorFollowing, "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference." ), rustc_attr!( rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, @only_local: true, "#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`." ), + rustc_attr!( + rustc_coinductive, AttributeType::Normal, template!(Word), WarnFollowing, @only_local: true, + "#![rustc_coinductive] changes a trait to be coinductive, allowing cycles in the trait solver." + ), rustc_attr!( rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: true, "#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl." ), + rustc_attr!( + rustc_deny_explicit_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: false, + "#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls" + ), rustc_attr!( rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word), ErrorFollowing, "#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \ @@ -527,24 +564,20 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ and it is only intended to be used in `alloc`." ), - // modified for r-a - // BuiltinAttribute { - // name: sym::rustc_diagnostic_item, - // // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`. - // only_local: false, - // type_: Normal, - // template: template!(NameValueStr: "name"), - // duplicates: ErrorFollowing, - // gate: Gated( - // Stability::Unstable, - // sym::rustc_attrs, - // "diagnostic items compiler internal support for linting", - // cfg_fn!(rustc_attrs), - // ), - // }, BuiltinAttribute { + // name: sym::rustc_diagnostic_item, name: "rustc_diagnostic_item", + // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`. + // only_local: false, + // type_: Normal, template: template!(NameValueStr: "name"), + // duplicates: ErrorFollowing, + // gate: Gated( + // Stability::Unstable, + // sym::rustc_attrs, + // "diagnostic items compiler internal support for linting", + // cfg_fn!(rustc_attrs), + // ), }, gated!( // Used in resolve: @@ -568,7 +601,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ for reserving for `for From for T` impl" ), rustc_attr!( - rustc_test_marker, Normal, template!(Word), WarnFollowing, + rustc_test_marker, Normal, template!(NameValueStr: "name"), WarnFollowing, "the `#[rustc_test_marker]` attribute is used internally to track tests", ), rustc_attr!( @@ -594,11 +627,16 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ definition of a trait, it's currently in experimental form and should be changed before \ being exposed outside of the std" ), + rustc_attr!( + rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing, + r#"`rustc_doc_primitive` is a rustc internal attribute"#, + ), // ========================================================================== // Internal attributes, Testing: // ========================================================================== + rustc_attr!(TEST, rustc_effective_visibility, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_outlives, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing), @@ -639,6 +677,10 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(TEST, rustc_polymorphize_error, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_def_path, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ..."), DuplicatesOk), + gated!( + custom_mir, Normal, template!(List: r#"dialect = "...", phase = "...""#), + ErrorFollowing, "the `#[custom_mir]` attribute is just used for the Rust test suite", + ), rustc_attr!(TEST, rustc_dump_program_clauses, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_dump_env_program_clauses, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_object_lifetime_default, Normal, template!(Word), WarnFollowing), diff --git a/crates/hir-def/src/attr/tests.rs b/crates/hir-def/src/attr/tests.rs new file mode 100644 index 0000000000000..e4c8d446af7bd --- /dev/null +++ b/crates/hir-def/src/attr/tests.rs @@ -0,0 +1,40 @@ +//! This module contains tests for doc-expression parsing. +//! Currently, it tests `#[doc(hidden)]` and `#[doc(alias)]`. + +use mbe::syntax_node_to_token_tree; +use syntax::{ast, AstNode}; + +use crate::attr::{DocAtom, DocExpr}; + +fn assert_parse_result(input: &str, expected: DocExpr) { + let (tt, _) = { + let source_file = ast::SourceFile::parse(input).ok().unwrap(); + let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); + syntax_node_to_token_tree(tt.syntax()) + }; + let cfg = DocExpr::parse(&tt); + assert_eq!(cfg, expected); +} + +#[test] +fn test_doc_expr_parser() { + assert_parse_result("#![doc(hidden)]", DocAtom::Flag("hidden".into()).into()); + + assert_parse_result( + r#"#![doc(alias = "foo")]"#, + DocAtom::KeyValue { key: "alias".into(), value: "foo".into() }.into(), + ); + + assert_parse_result(r#"#![doc(alias("foo"))]"#, DocExpr::Alias(["foo".into()].into())); + assert_parse_result( + r#"#![doc(alias("foo", "bar", "baz"))]"#, + DocExpr::Alias(["foo".into(), "bar".into(), "baz".into()].into()), + ); + + assert_parse_result( + r#" + #[doc(alias("Bar", "Qux"))] + struct Foo;"#, + DocExpr::Alias(["Bar".into(), "Qux".into()].into()), + ); +} diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index b70e658efd79c..36626ed1a9b1f 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -6,267 +6,30 @@ mod tests; pub mod scope; mod pretty; -use std::{ops::Index, sync::Arc}; +use std::ops::Index; use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; -use drop_bomb::DropBomb; use either::Either; -use hir_expand::{ - attrs::RawAttrs, hygiene::Hygiene, ExpandError, ExpandResult, HirFileId, InFile, MacroCallId, -}; +use hir_expand::{name::Name, HirFileId, InFile}; use la_arena::{Arena, ArenaMap}; -use limit::Limit; use profile::Count; use rustc_hash::FxHashMap; -use syntax::{ast, AstPtr, SyntaxNode, SyntaxNodePtr}; +use syntax::{ast, AstPtr, SyntaxNodePtr}; +use triomphe::Arc; use crate::{ - attr::Attrs, db::DefDatabase, - expr::{ + expander::Expander, + hir::{ dummy_expr_id, Binding, BindingId, Expr, ExprId, Label, LabelId, Pat, PatId, RecordFieldPat, }, - item_scope::BuiltinShadowMode, - macro_id_to_def_id, nameres::DefMap, path::{ModPath, Path}, src::{HasChildSource, HasSource}, - AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, MacroId, ModuleId, - UnresolvedMacro, + BlockId, DefWithBodyId, HasModule, Lookup, }; -pub use lower::LowerCtx; - -/// A subset of Expander that only deals with cfg attributes. We only need it to -/// avoid cyclic queries in crate def map during enum processing. -#[derive(Debug)] -pub(crate) struct CfgExpander { - cfg_options: CfgOptions, - hygiene: Hygiene, - krate: CrateId, -} - -#[derive(Debug)] -pub struct Expander { - cfg_expander: CfgExpander, - def_map: Arc, - current_file_id: HirFileId, - module: LocalModuleId, - /// `recursion_depth == usize::MAX` indicates that the recursion limit has been reached. - recursion_depth: usize, -} - -impl CfgExpander { - pub(crate) fn new( - db: &dyn DefDatabase, - current_file_id: HirFileId, - krate: CrateId, - ) -> CfgExpander { - let hygiene = Hygiene::new(db.upcast(), current_file_id); - let cfg_options = db.crate_graph()[krate].cfg_options.clone(); - CfgExpander { cfg_options, hygiene, krate } - } - - pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs { - Attrs::filter(db, self.krate, RawAttrs::new(db.upcast(), owner, &self.hygiene)) - } - - pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> bool { - let attrs = self.parse_attrs(db, owner); - attrs.is_cfg_enabled(&self.cfg_options) - } -} - -impl Expander { - pub fn new(db: &dyn DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander { - let cfg_expander = CfgExpander::new(db, current_file_id, module.krate); - let def_map = module.def_map(db); - Expander { - cfg_expander, - def_map, - current_file_id, - module: module.local_id, - recursion_depth: 0, - } - } - - pub fn enter_expand( - &mut self, - db: &dyn DefDatabase, - macro_call: ast::MacroCall, - ) -> Result>, UnresolvedMacro> { - let mut unresolved_macro_err = None; - - let result = self.within_limit(db, |this| { - let macro_call = InFile::new(this.current_file_id, ¯o_call); - - let resolver = - |path| this.resolve_path_as_macro(db, &path).map(|it| macro_id_to_def_id(db, it)); - - let mut err = None; - let call_id = match macro_call.as_call_id_with_errors( - db, - this.def_map.krate(), - resolver, - &mut |e| { - err.get_or_insert(e); - }, - ) { - Ok(call_id) => call_id, - Err(resolve_err) => { - unresolved_macro_err = Some(resolve_err); - return ExpandResult { value: None, err: None }; - } - }; - ExpandResult { value: call_id.ok(), err } - }); - - if let Some(err) = unresolved_macro_err { - Err(err) - } else { - Ok(result) - } - } - - pub fn enter_expand_id( - &mut self, - db: &dyn DefDatabase, - call_id: MacroCallId, - ) -> ExpandResult> { - self.within_limit(db, |_this| ExpandResult::ok(Some(call_id))) - } - - fn enter_expand_inner( - db: &dyn DefDatabase, - call_id: MacroCallId, - mut err: Option, - ) -> ExpandResult> { - if err.is_none() { - err = db.macro_expand_error(call_id); - } - - let file_id = call_id.as_file(); - - let raw_node = match db.parse_or_expand(file_id) { - Some(it) => it, - None => { - // Only `None` if the macro expansion produced no usable AST. - if err.is_none() { - tracing::warn!("no error despite `parse_or_expand` failing"); - } - - return ExpandResult::only_err(err.unwrap_or_else(|| { - ExpandError::Other("failed to parse macro invocation".into()) - })); - } - }; - - ExpandResult { value: Some((file_id, raw_node)), err } - } - - pub fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { - self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); - self.current_file_id = mark.file_id; - if self.recursion_depth == usize::MAX { - // Recursion limit has been reached somewhere in the macro expansion tree. Reset the - // depth only when we get out of the tree. - if !self.current_file_id.is_macro() { - self.recursion_depth = 0; - } - } else { - self.recursion_depth -= 1; - } - mark.bomb.defuse(); - } - - pub(crate) fn to_source(&self, value: T) -> InFile { - InFile { file_id: self.current_file_id, value } - } - - pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs { - self.cfg_expander.parse_attrs(db, owner) - } - - pub(crate) fn cfg_options(&self) -> &CfgOptions { - &self.cfg_expander.cfg_options - } - - pub fn current_file_id(&self) -> HirFileId { - self.current_file_id - } - - fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option { - let ctx = LowerCtx::with_hygiene(db, &self.cfg_expander.hygiene); - Path::from_src(path, &ctx) - } - - fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option { - self.def_map.resolve_path(db, self.module, path, BuiltinShadowMode::Other).0.take_macros() - } - - fn recursion_limit(&self, db: &dyn DefDatabase) -> Limit { - let limit = db.crate_limits(self.cfg_expander.krate).recursion_limit as _; - - #[cfg(not(test))] - return Limit::new(limit); - - // Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug - #[cfg(test)] - return Limit::new(std::cmp::min(32, limit)); - } - - fn within_limit( - &mut self, - db: &dyn DefDatabase, - op: F, - ) -> ExpandResult> - where - F: FnOnce(&mut Self) -> ExpandResult>, - { - if self.recursion_depth == usize::MAX { - // Recursion limit has been reached somewhere in the macro expansion tree. We should - // stop expanding other macro calls in this tree, or else this may result in - // exponential number of macro expansions, leading to a hang. - // - // The overflow error should have been reported when it occurred (see the next branch), - // so don't return overflow error here to avoid diagnostics duplication. - cov_mark::hit!(overflow_but_not_me); - return ExpandResult::only_err(ExpandError::RecursionOverflowPosioned); - } else if self.recursion_limit(db).check(self.recursion_depth + 1).is_err() { - self.recursion_depth = usize::MAX; - cov_mark::hit!(your_stack_belongs_to_me); - return ExpandResult::only_err(ExpandError::Other( - "reached recursion limit during macro expansion".into(), - )); - } - - let ExpandResult { value, err } = op(self); - let Some(call_id) = value else { - return ExpandResult { value: None, err }; - }; - - Self::enter_expand_inner(db, call_id, err).map(|value| { - value.and_then(|(new_file_id, node)| { - let node = T::cast(node)?; - - self.recursion_depth += 1; - self.cfg_expander.hygiene = Hygiene::new(db.upcast(), new_file_id); - let old_file_id = std::mem::replace(&mut self.current_file_id, new_file_id); - let mark = - Mark { file_id: old_file_id, bomb: DropBomb::new("expansion mark dropped") }; - Some((mark, node)) - }) - }) - } -} - -#[derive(Debug)] -pub struct Mark { - file_id: HirFileId, - bomb: DropBomb, -} - /// The body of an item (function, const etc.). #[derive(Debug, Eq, PartialEq)] pub struct Body { @@ -343,6 +106,8 @@ pub enum BodyDiagnostic { MacroError { node: InFile>, message: String }, UnresolvedProcMacro { node: InFile>, krate: CrateId }, UnresolvedMacroCall { node: InFile>, path: ModPath }, + UnreachableLabel { node: InFile>, name: Name }, + UndeclaredLabel { node: InFile>, name: Name }, } impl Body { @@ -353,45 +118,54 @@ impl Body { let _p = profile::span("body_with_source_map_query"); let mut params = None; - let (file_id, module, body) = match def { - DefWithBodyId::FunctionId(f) => { - let f = f.lookup(db); - let src = f.source(db); - params = src.value.param_list().map(|param_list| { - let item_tree = f.id.item_tree(db); - let func = &item_tree[f.id.value]; - let krate = f.container.module(db).krate; - let crate_graph = db.crate_graph(); + let (file_id, module, body, is_async_fn) = { + match def { + DefWithBodyId::FunctionId(f) => { + let data = db.function_data(f); + let f = f.lookup(db); + let src = f.source(db); + params = src.value.param_list().map(|param_list| { + let item_tree = f.id.item_tree(db); + let func = &item_tree[f.id.value]; + let krate = f.container.module(db).krate; + let crate_graph = db.crate_graph(); + ( + param_list, + func.params.clone().map(move |param| { + item_tree + .attrs(db, krate, param.into()) + .is_cfg_enabled(&crate_graph[krate].cfg_options) + }), + ) + }); ( - param_list, - func.params.clone().map(move |param| { - item_tree - .attrs(db, krate, param.into()) - .is_cfg_enabled(&crate_graph[krate].cfg_options) - }), + src.file_id, + f.module(db), + src.value.body().map(ast::Expr::from), + data.has_async_kw(), ) - }); - (src.file_id, f.module(db), src.value.body().map(ast::Expr::from)) - } - DefWithBodyId::ConstId(c) => { - let c = c.lookup(db); - let src = c.source(db); - (src.file_id, c.module(db), src.value.body()) - } - DefWithBodyId::StaticId(s) => { - let s = s.lookup(db); - let src = s.source(db); - (src.file_id, s.module(db), src.value.body()) - } - DefWithBodyId::VariantId(v) => { - let e = v.parent.lookup(db); - let src = v.parent.child_source(db); - let variant = &src.value[v.local_id]; - (src.file_id, e.container, variant.expr()) + } + DefWithBodyId::ConstId(c) => { + let c = c.lookup(db); + let src = c.source(db); + (src.file_id, c.module(db), src.value.body(), false) + } + DefWithBodyId::StaticId(s) => { + let s = s.lookup(db); + let src = s.source(db); + (src.file_id, s.module(db), src.value.body(), false) + } + DefWithBodyId::VariantId(v) => { + let e = v.parent.lookup(db); + let src = v.parent.child_source(db); + let variant = &src.value[v.local_id]; + (src.file_id, e.container, variant.expr(), false) + } } }; let expander = Expander::new(db, file_id, module); - let (mut body, source_map) = Body::new(db, expander, params, body); + let (mut body, source_map) = + Body::new(db, def, expander, params, body, module.krate, is_async_fn); body.shrink_to_fit(); (Arc::new(body), Arc::new(source_map)) @@ -406,22 +180,32 @@ impl Body { &'a self, db: &'a dyn DefDatabase, ) -> impl Iterator)> + '_ { - self.block_scopes - .iter() - .map(move |&block| (block, db.block_def_map(block).expect("block ID without DefMap"))) + self.block_scopes.iter().map(move |&block| (block, db.block_def_map(block))) } pub fn pretty_print(&self, db: &dyn DefDatabase, owner: DefWithBodyId) -> String { pretty::print_body_hir(db, self, owner) } + pub fn pretty_print_expr( + &self, + db: &dyn DefDatabase, + owner: DefWithBodyId, + expr: ExprId, + ) -> String { + pretty::print_expr_hir(db, self, owner, expr) + } + fn new( db: &dyn DefDatabase, + owner: DefWithBodyId, expander: Expander, params: Option<(ast::ParamList, impl Iterator)>, body: Option, + krate: CrateId, + is_async_fn: bool, ) -> (Body, BodySourceMap) { - lower::lower(db, expander, params, body) + lower::lower(db, owner, expander, params, body, krate, is_async_fn) } fn shrink_to_fit(&mut self) { @@ -437,15 +221,14 @@ impl Body { pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) { self.walk_pats(pat_id, &mut |pat| { - if let Pat::Bind { id, .. } = pat { + if let Pat::Bind { id, .. } = &self[pat] { f(*id); } }); } - pub fn walk_pats(&self, pat_id: PatId, f: &mut impl FnMut(&Pat)) { + pub fn walk_pats_shallow(&self, pat_id: PatId, mut f: impl FnMut(PatId)) { let pat = &self[pat_id]; - f(pat); match pat { Pat::Range { .. } | Pat::Lit(..) @@ -455,23 +238,28 @@ impl Body { | Pat::Missing => {} &Pat::Bind { subpat, .. } => { if let Some(subpat) = subpat { - self.walk_pats(subpat, f); + f(subpat); } } Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => { - args.iter().copied().for_each(|p| self.walk_pats(p, f)); + args.iter().copied().for_each(|p| f(p)); } - Pat::Ref { pat, .. } => self.walk_pats(*pat, f), + Pat::Ref { pat, .. } => f(*pat), Pat::Slice { prefix, slice, suffix } => { let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter()); - total_iter.copied().for_each(|p| self.walk_pats(p, f)); + total_iter.copied().for_each(|p| f(p)); } Pat::Record { args, .. } => { - args.iter().for_each(|RecordFieldPat { pat, .. }| self.walk_pats(*pat, f)); + args.iter().for_each(|RecordFieldPat { pat, .. }| f(*pat)); } - Pat::Box { inner } => self.walk_pats(*inner, f), + Pat::Box { inner } => f(*inner), } } + + pub fn walk_pats(&self, pat_id: PatId, f: &mut impl FnMut(PatId)) { + f(pat_id); + self.walk_pats_shallow(pat_id, |p| self.walk_pats(p, f)); + } } impl Default for Body { diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index fedaf39559858..7b88e525bf184 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -1,88 +1,62 @@ //! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr` //! representation. -use std::{mem, sync::Arc}; +use std::mem; +use base_db::CrateId; use either::Either; use hir_expand::{ ast_id_map::AstIdMap, - hygiene::Hygiene, name::{name, AsName, Name}, - AstId, ExpandError, HirFileId, InFile, + AstId, ExpandError, InFile, }; use intern::Interned; use la_arena::Arena; -use once_cell::unsync::OnceCell; use profile::Count; use rustc_hash::FxHashMap; use smallvec::SmallVec; use syntax::{ ast::{ - self, ArrayExprKind, AstChildren, HasArgList, HasLoopBody, HasName, LiteralKind, + self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasLoopBody, HasName, SlicePatComponents, }, AstNode, AstPtr, SyntaxNodePtr, }; +use triomphe::Arc; use crate::{ - adt::StructKind, - body::{Body, BodySourceMap, Expander, ExprPtr, LabelPtr, LabelSource, PatPtr}, - body::{BodyDiagnostic, ExprSource, PatSource}, - builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, + body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, LabelPtr, PatPtr}, + data::adt::StructKind, db::DefDatabase, - expr::{ - dummy_expr_id, Array, Binding, BindingAnnotation, BindingId, ClosureKind, Expr, ExprId, - FloatTypeWrapper, Label, LabelId, Literal, MatchArm, Movability, Pat, PatId, - RecordFieldPat, RecordLitField, Statement, + expander::Expander, + hir::{ + dummy_expr_id, Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, + ClosureKind, Expr, ExprId, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability, + Pat, PatId, RecordFieldPat, RecordLitField, Statement, }, item_scope::BuiltinShadowMode, + lang_item::LangItem, + lower::LowerCtx, + nameres::{DefMap, MacroSubNs}, path::{GenericArgs, Path}, type_ref::{Mutability, Rawness, TypeRef}, - AdtId, BlockId, BlockLoc, ModuleDefId, UnresolvedMacro, + AdtId, BlockId, BlockLoc, DefWithBodyId, ModuleDefId, UnresolvedMacro, }; -pub struct LowerCtx<'a> { - pub db: &'a dyn DefDatabase, - hygiene: Hygiene, - ast_id_map: Option<(HirFileId, OnceCell>)>, -} - -impl<'a> LowerCtx<'a> { - pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self { - LowerCtx { - db, - hygiene: Hygiene::new(db.upcast(), file_id), - ast_id_map: Some((file_id, OnceCell::new())), - } - } - - pub fn with_hygiene(db: &'a dyn DefDatabase, hygiene: &Hygiene) -> Self { - LowerCtx { db, hygiene: hygiene.clone(), ast_id_map: None } - } - - pub(crate) fn hygiene(&self) -> &Hygiene { - &self.hygiene - } - - pub(crate) fn lower_path(&self, ast: ast::Path) -> Option { - Path::from_src(ast, self) - } - - pub(crate) fn ast_id(&self, item: &N) -> Option> { - let &(file_id, ref ast_id_map) = self.ast_id_map.as_ref()?; - let ast_id_map = ast_id_map.get_or_init(|| self.db.ast_id_map(file_id)); - Some(InFile::new(file_id, ast_id_map.ast_id(item))) - } -} - pub(super) fn lower( db: &dyn DefDatabase, + owner: DefWithBodyId, expander: Expander, params: Option<(ast::ParamList, impl Iterator)>, body: Option, + krate: CrateId, + is_async_fn: bool, ) -> (Body, BodySourceMap) { ExprCollector { db, + owner, + krate, + def_map: expander.module.def_map(db), source_map: BodySourceMap::default(), ast_id_map: db.ast_id_map(expander.current_file_id), body: Body { @@ -96,25 +70,79 @@ pub(super) fn lower( _c: Count::new(), }, expander, + current_try_block_label: None, is_lowering_assignee_expr: false, is_lowering_generator: false, + label_ribs: Vec::new(), + current_binding_owner: None, } - .collect(params, body) + .collect(params, body, is_async_fn) } struct ExprCollector<'a> { db: &'a dyn DefDatabase, expander: Expander, + owner: DefWithBodyId, + def_map: Arc, ast_id_map: Arc, + krate: CrateId, body: Body, source_map: BodySourceMap, + is_lowering_assignee_expr: bool, is_lowering_generator: bool, + + current_try_block_label: Option, + // points to the expression that a try expression will target (replaces current_try_block_label) + // catch_scope: Option, + // points to the expression that an unlabeled control flow will target + // loop_scope: Option, + // needed to diagnose non label control flow in while conditions + // is_in_loop_condition: bool, + + // resolution + label_ribs: Vec, + current_binding_owner: Option, +} + +#[derive(Clone, Debug)] +struct LabelRib { + kind: RibKind, + // Once we handle macro hygiene this will need to be a map + label: Option<(Name, LabelId)>, +} + +impl LabelRib { + fn new(kind: RibKind) -> Self { + LabelRib { kind, label: None } + } + fn new_normal(label: (Name, LabelId)) -> Self { + LabelRib { kind: RibKind::Normal, label: Some(label) } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum RibKind { + Normal, + Closure, + Constant, +} + +impl RibKind { + /// This rib forbids referring to labels defined in upwards ribs. + fn is_label_barrier(self) -> bool { + match self { + RibKind::Normal => false, + RibKind::Closure | RibKind::Constant => true, + } + } } #[derive(Debug, Default)] struct BindingList { map: FxHashMap, + is_used: FxHashMap, + reject_new: bool, } impl BindingList { @@ -124,7 +152,27 @@ impl BindingList { name: Name, mode: BindingAnnotation, ) -> BindingId { - *self.map.entry(name).or_insert_with_key(|n| ec.alloc_binding(n.clone(), mode)) + let id = *self.map.entry(name).or_insert_with_key(|n| ec.alloc_binding(n.clone(), mode)); + if ec.body.bindings[id].mode != mode { + ec.body.bindings[id].problems = Some(BindingProblems::BoundInconsistently); + } + self.check_is_used(ec, id); + id + } + + fn check_is_used(&mut self, ec: &mut ExprCollector<'_>, id: BindingId) { + match self.is_used.get(&id) { + None => { + if self.reject_new { + ec.body.bindings[id].problems = Some(BindingProblems::NotBoundAcrossAll); + } + } + Some(true) => { + ec.body.bindings[id].problems = Some(BindingProblems::BoundMoreThanOnce); + } + Some(false) => {} + } + self.is_used.insert(id, true); } } @@ -133,6 +181,7 @@ impl ExprCollector<'_> { mut self, param_list: Option<(ast::ParamList, impl Iterator)>, body: Option, + is_async_fn: bool, ) -> (Body, BodySourceMap) { if let Some((param_list, mut attr_enabled)) = param_list { if let Some(self_param) = @@ -152,72 +201,35 @@ impl ExprCollector<'_> { self.body.params.push(param_pat); } - for pat in param_list - .params() - .zip(attr_enabled) - .filter_map(|(param, enabled)| param.pat().filter(|_| enabled)) + for (param, _) in param_list.params().zip(attr_enabled).filter(|(_, enabled)| *enabled) { - let param_pat = self.collect_pat(pat); + let param_pat = self.collect_pat_top(param.pat()); self.body.params.push(param_pat); } }; + self.body.body_expr = self.with_label_rib(RibKind::Closure, |this| { + if is_async_fn { + match body { + Some(e) => { + let expr = this.collect_expr(e); + this.alloc_expr_desugared(Expr::Async { + id: None, + statements: Box::new([]), + tail: Some(expr), + }) + } + None => this.missing_expr(), + } + } else { + this.collect_expr_opt(body) + } + }); - self.body.body_expr = self.collect_expr_opt(body); (self.body, self.source_map) } fn ctx(&self) -> LowerCtx<'_> { - LowerCtx::new(self.db, self.expander.current_file_id) - } - - fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId { - let src = self.expander.to_source(ptr); - let id = self.make_expr(expr, src.clone()); - self.source_map.expr_map.insert(src, id); - id - } - // desugared exprs don't have ptr, that's wrong and should be fixed - // somehow. - fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId { - self.body.exprs.alloc(expr) - } - fn missing_expr(&mut self) -> ExprId { - self.alloc_expr_desugared(Expr::Missing) - } - fn make_expr(&mut self, expr: Expr, src: ExprSource) -> ExprId { - let id = self.body.exprs.alloc(expr); - self.source_map.expr_map_back.insert(id, src); - id - } - - fn alloc_binding(&mut self, name: Name, mode: BindingAnnotation) -> BindingId { - self.body.bindings.alloc(Binding { name, mode, definitions: SmallVec::new() }) - } - fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { - let src = self.expander.to_source(ptr); - let id = self.make_pat(pat, src.clone()); - self.source_map.pat_map.insert(src, id); - id - } - fn missing_pat(&mut self) -> PatId { - self.body.pats.alloc(Pat::Missing) - } - fn make_pat(&mut self, pat: Pat, src: PatSource) -> PatId { - let id = self.body.pats.alloc(pat); - self.source_map.pat_map_back.insert(id, src); - id - } - - fn alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId { - let src = self.expander.to_source(ptr); - let id = self.make_label(label, src.clone()); - self.source_map.label_map.insert(src, id); - id - } - fn make_label(&mut self, label: Label, src: LabelSource) -> LabelId { - let id = self.body.labels.alloc(label); - self.source_map.label_map_back.insert(id, src); - id + self.expander.ctx(self.db) } fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { @@ -229,6 +241,7 @@ impl ExprCollector<'_> { let syntax_ptr = AstPtr::new(&expr); self.check_cfg(&expr)?; + // FIXME: Move some of these arms out into separate methods for clarity Some(match expr { ast::Expr::IfExpr(e) => { let then_branch = self.collect_block_opt(e.then_branch()); @@ -246,18 +259,12 @@ impl ExprCollector<'_> { self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr) } ast::Expr::LetExpr(e) => { - let pat = self.collect_pat_opt(e.pat()); + let pat = self.collect_pat_top(e.pat()); let expr = self.collect_expr_opt(e.expr()); self.alloc_expr(Expr::Let { pat, expr }, syntax_ptr) } ast::Expr::BlockExpr(e) => match e.modifier() { - Some(ast::BlockModifier::Try(_)) => { - self.collect_block_(e, |id, statements, tail| Expr::TryBlock { - id, - statements, - tail, - }) - } + Some(ast::BlockModifier::Try(_)) => self.desugar_try_block(e), Some(ast::BlockModifier::Unsafe(_)) => { self.collect_block_(e, |id, statements, tail| Expr::Unsafe { id, @@ -267,50 +274,74 @@ impl ExprCollector<'_> { } Some(ast::BlockModifier::Label(label)) => { let label = self.collect_label(label); - self.collect_block_(e, |id, statements, tail| Expr::Block { - id, - statements, - tail, - label: Some(label), + self.with_labeled_rib(label, |this| { + this.collect_block_(e, |id, statements, tail| Expr::Block { + id, + statements, + tail, + label: Some(label), + }) + }) + } + Some(ast::BlockModifier::Async(_)) => { + self.with_label_rib(RibKind::Closure, |this| { + this.collect_block_(e, |id, statements, tail| Expr::Async { + id, + statements, + tail, + }) + }) + } + Some(ast::BlockModifier::Const(_)) => { + self.with_label_rib(RibKind::Constant, |this| { + let (result_expr_id, prev_binding_owner) = + this.initialize_binding_owner(syntax_ptr); + let inner_expr = this.collect_block(e); + let x = this.db.intern_anonymous_const((this.owner, inner_expr)); + this.body.exprs[result_expr_id] = Expr::Const(x); + this.current_binding_owner = prev_binding_owner; + result_expr_id }) } - Some(ast::BlockModifier::Async(_)) => self - .collect_block_(e, |id, statements, tail| Expr::Async { id, statements, tail }), - Some(ast::BlockModifier::Const(_)) => self - .collect_block_(e, |id, statements, tail| Expr::Const { id, statements, tail }), None => self.collect_block(e), }, ast::Expr::LoopExpr(e) => { let label = e.label().map(|label| self.collect_label(label)); - let body = self.collect_block_opt(e.loop_body()); + let body = self.collect_labelled_block_opt(label, e.loop_body()); self.alloc_expr(Expr::Loop { body, label }, syntax_ptr) } ast::Expr::WhileExpr(e) => { let label = e.label().map(|label| self.collect_label(label)); - let body = self.collect_block_opt(e.loop_body()); - + let body = self.collect_labelled_block_opt(label, e.loop_body()); let condition = self.collect_expr_opt(e.condition()); self.alloc_expr(Expr::While { condition, body, label }, syntax_ptr) } - ast::Expr::ForExpr(e) => { - let label = e.label().map(|label| self.collect_label(label)); - let iterable = self.collect_expr_opt(e.iterable()); - let pat = self.collect_pat_opt(e.pat()); - let body = self.collect_block_opt(e.loop_body()); - self.alloc_expr(Expr::For { iterable, pat, body, label }, syntax_ptr) - } + ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e), ast::Expr::CallExpr(e) => { - let callee = self.collect_expr_opt(e.expr()); - let args = if let Some(arg_list) = e.arg_list() { - arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect() - } else { - Box::default() + let is_rustc_box = { + let attrs = e.attrs(); + attrs.filter_map(|x| x.as_simple_atom()).any(|x| x == "rustc_box") }; - self.alloc_expr( - Expr::Call { callee, args, is_assignee_expr: self.is_lowering_assignee_expr }, - syntax_ptr, - ) + if is_rustc_box { + let expr = self.collect_expr_opt(e.arg_list().and_then(|x| x.args().next())); + self.alloc_expr(Expr::Box { expr }, syntax_ptr) + } else { + let callee = self.collect_expr_opt(e.expr()); + let args = if let Some(arg_list) = e.arg_list() { + arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect() + } else { + Box::default() + }; + self.alloc_expr( + Expr::Call { + callee, + args, + is_assignee_expr: self.is_lowering_assignee_expr, + }, + syntax_ptr, + ) + } } ast::Expr::MethodCallExpr(e) => { let receiver = self.collect_expr_opt(e.receiver()); @@ -336,7 +367,7 @@ impl ExprCollector<'_> { .arms() .filter_map(|arm| { self.check_cfg(&arm).map(|()| MatchArm { - pat: self.collect_pat_opt(arm.pat()), + pat: self.collect_pat_top(arm.pat()), expr: self.collect_expr_opt(arm.expr()), guard: arm .guard() @@ -357,16 +388,20 @@ impl ExprCollector<'_> { .unwrap_or(Expr::Missing); self.alloc_expr(path, syntax_ptr) } - ast::Expr::ContinueExpr(e) => self.alloc_expr( - Expr::Continue { label: e.lifetime().map(|l| Name::new_lifetime(&l)) }, - syntax_ptr, - ), + ast::Expr::ContinueExpr(e) => { + let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| { + self.source_map.diagnostics.push(e); + None + }); + self.alloc_expr(Expr::Continue { label }, syntax_ptr) + } ast::Expr::BreakExpr(e) => { + let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| { + self.source_map.diagnostics.push(e); + None + }); let expr = e.expr().map(|e| self.collect_expr(e)); - self.alloc_expr( - Expr::Break { expr, label: e.lifetime().map(|l| Name::new_lifetime(&l)) }, - syntax_ptr, - ) + self.alloc_expr(Expr::Break { expr, label }, syntax_ptr) } ast::Expr::ParenExpr(e) => { let inner = self.collect_expr_opt(e.expr()); @@ -437,10 +472,7 @@ impl ExprCollector<'_> { let expr = self.collect_expr_opt(e.expr()); self.alloc_expr(Expr::Await { expr }, syntax_ptr) } - ast::Expr::TryExpr(e) => { - let expr = self.collect_expr_opt(e.expr()); - self.alloc_expr(Expr::Try { expr }, syntax_ptr) - } + ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e), ast::Expr::CastExpr(e) => { let expr = self.collect_expr_opt(e.expr()); let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty())); @@ -470,14 +502,16 @@ impl ExprCollector<'_> { None => self.alloc_expr(Expr::Missing, syntax_ptr), } } - ast::Expr::ClosureExpr(e) => { + ast::Expr::ClosureExpr(e) => self.with_label_rib(RibKind::Closure, |this| { + let (result_expr_id, prev_binding_owner) = + this.initialize_binding_owner(syntax_ptr); let mut args = Vec::new(); let mut arg_types = Vec::new(); if let Some(pl) = e.param_list() { for param in pl.params() { - let pat = self.collect_pat_opt(param.pat()); + let pat = this.collect_pat_top(param.pat()); let type_ref = - param.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it))); + param.ty().map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it))); args.push(pat); arg_types.push(type_ref); } @@ -485,14 +519,14 @@ impl ExprCollector<'_> { let ret_type = e .ret_type() .and_then(|r| r.ty()) - .map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it))); + .map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it))); - let prev_is_lowering_generator = self.is_lowering_generator; - self.is_lowering_generator = false; + let prev_is_lowering_generator = mem::take(&mut this.is_lowering_generator); + let prev_try_block_label = this.current_try_block_label.take(); - let body = self.collect_expr_opt(e.body()); + let body = this.collect_expr_opt(e.body()); - let closure_kind = if self.is_lowering_generator { + let closure_kind = if this.is_lowering_generator { let movability = if e.static_token().is_some() { Movability::Static } else { @@ -504,19 +538,21 @@ impl ExprCollector<'_> { } else { ClosureKind::Closure }; - self.is_lowering_generator = prev_is_lowering_generator; - - self.alloc_expr( - Expr::Closure { - args: args.into(), - arg_types: arg_types.into(), - ret_type, - body, - closure_kind, - }, - syntax_ptr, - ) - } + let capture_by = + if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref }; + this.is_lowering_generator = prev_is_lowering_generator; + this.current_binding_owner = prev_binding_owner; + this.current_try_block_label = prev_try_block_label; + this.body.exprs[result_expr_id] = Expr::Closure { + args: args.into(), + arg_types: arg_types.into(), + ret_type, + body, + closure_kind, + capture_by, + }; + result_expr_id + }), ast::Expr::BinExpr(e) => { let op = e.op_kind(); if let Some(ast::BinaryOp::Assignment { op: None }) = op { @@ -528,9 +564,18 @@ impl ExprCollector<'_> { self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr) } ast::Expr::TupleExpr(e) => { - let exprs = e.fields().map(|expr| self.collect_expr(expr)).collect(); + let mut exprs: Vec<_> = e.fields().map(|expr| self.collect_expr(expr)).collect(); + // if there is a leading comma, the user is most likely to type out a leading expression + // so we insert a missing expression at the beginning for IDE features + if comma_follows_token(e.l_paren_token()) { + exprs.insert(0, self.missing_expr()); + } + self.alloc_expr( - Expr::Tuple { exprs, is_assignee_expr: self.is_lowering_assignee_expr }, + Expr::Tuple { + exprs: exprs.into_boxed_slice(), + is_assignee_expr: self.is_lowering_assignee_expr, + }, syntax_ptr, ) } @@ -555,7 +600,17 @@ impl ExprCollector<'_> { } ArrayExprKind::Repeat { initializer, repeat } => { let initializer = self.collect_expr_opt(initializer); - let repeat = self.collect_expr_opt(repeat); + let repeat = self.with_label_rib(RibKind::Constant, |this| { + if let Some(repeat) = repeat { + let syntax_ptr = AstPtr::new(&repeat); + this.collect_as_a_binding_owner_bad( + |this| this.collect_expr(repeat), + syntax_ptr, + ) + } else { + this.missing_expr() + } + }); self.alloc_expr( Expr::Array(Array::Repeat { initializer, repeat }), syntax_ptr, @@ -601,6 +656,244 @@ impl ExprCollector<'_> { }) } + fn initialize_binding_owner( + &mut self, + syntax_ptr: AstPtr, + ) -> (ExprId, Option) { + let result_expr_id = self.alloc_expr(Expr::Missing, syntax_ptr); + let prev_binding_owner = self.current_binding_owner.take(); + self.current_binding_owner = Some(result_expr_id); + (result_expr_id, prev_binding_owner) + } + + /// FIXME: This function is bad. It will produce a dangling `Missing` expr which wastes memory. Currently + /// it is used only for const blocks and repeat expressions, which are also hacky and ideally should have + /// their own body. Don't add more usage for this function so that we can remove this function after + /// separating those bodies. + fn collect_as_a_binding_owner_bad( + &mut self, + job: impl FnOnce(&mut ExprCollector<'_>) -> ExprId, + syntax_ptr: AstPtr, + ) -> ExprId { + let (id, prev_owner) = self.initialize_binding_owner(syntax_ptr); + let tmp = job(self); + self.body.exprs[id] = mem::replace(&mut self.body.exprs[tmp], Expr::Missing); + self.current_binding_owner = prev_owner; + id + } + + /// Desugar `try { ; }` into `': { ; ::std::ops::Try::from_output() }`, + /// `try { ; }` into `': { ; ::std::ops::Try::from_output(()) }` + /// and save the `` to use it as a break target for desugaring of the `?` operator. + fn desugar_try_block(&mut self, e: BlockExpr) -> ExprId { + let Some(try_from_output) = LangItem::TryTraitFromOutput.path(self.db, self.krate) else { + return self.collect_block(e); + }; + let label = self.alloc_label_desugared(Label { name: Name::generate_new_name() }); + let old_label = self.current_try_block_label.replace(label); + + let (btail, expr_id) = self.with_labeled_rib(label, |this| { + let mut btail = None; + let block = this.collect_block_(e, |id, statements, tail| { + btail = tail; + Expr::Block { id, statements, tail, label: Some(label) } + }); + (btail, block) + }); + + let callee = self.alloc_expr_desugared(Expr::Path(try_from_output)); + let next_tail = match btail { + Some(tail) => self.alloc_expr_desugared(Expr::Call { + callee, + args: Box::new([tail]), + is_assignee_expr: false, + }), + None => { + let unit = self.alloc_expr_desugared(Expr::Tuple { + exprs: Box::new([]), + is_assignee_expr: false, + }); + self.alloc_expr_desugared(Expr::Call { + callee, + args: Box::new([unit]), + is_assignee_expr: false, + }) + } + }; + let Expr::Block { tail, .. } = &mut self.body.exprs[expr_id] else { + unreachable!("block was lowered to non-block"); + }; + *tail = Some(next_tail); + self.current_try_block_label = old_label; + expr_id + } + + /// Desugar `ast::ForExpr` from: `[opt_ident]: for in ` into: + /// ```ignore (pseudo-rust) + /// match IntoIterator::into_iter() { + /// mut iter => { + /// [opt_ident]: loop { + /// match Iterator::next(&mut iter) { + /// None => break, + /// Some() => , + /// }; + /// } + /// } + /// } + /// ``` + fn collect_for_loop(&mut self, syntax_ptr: AstPtr, e: ast::ForExpr) -> ExprId { + let (into_iter_fn, iter_next_fn, option_some, option_none) = 'if_chain: { + if let Some(into_iter_fn) = LangItem::IntoIterIntoIter.path(self.db, self.krate) { + if let Some(iter_next_fn) = LangItem::IteratorNext.path(self.db, self.krate) { + if let Some(option_some) = LangItem::OptionSome.path(self.db, self.krate) { + if let Some(option_none) = LangItem::OptionNone.path(self.db, self.krate) { + break 'if_chain (into_iter_fn, iter_next_fn, option_some, option_none); + } + } + } + } + // Some of the needed lang items are missing, so we can't desugar + return self.alloc_expr(Expr::Missing, syntax_ptr); + }; + let head = self.collect_expr_opt(e.iterable()); + let into_iter_fn_expr = self.alloc_expr(Expr::Path(into_iter_fn), syntax_ptr.clone()); + let iterator = self.alloc_expr( + Expr::Call { + callee: into_iter_fn_expr, + args: Box::new([head]), + is_assignee_expr: false, + }, + syntax_ptr.clone(), + ); + let none_arm = MatchArm { + pat: self.alloc_pat_desugared(Pat::Path(Box::new(option_none))), + guard: None, + expr: self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr.clone()), + }; + let some_pat = Pat::TupleStruct { + path: Some(Box::new(option_some)), + args: Box::new([self.collect_pat_top(e.pat())]), + ellipsis: None, + }; + let label = e.label().map(|label| self.collect_label(label)); + let some_arm = MatchArm { + pat: self.alloc_pat_desugared(some_pat), + guard: None, + expr: self.with_opt_labeled_rib(label, |this| { + this.collect_expr_opt(e.loop_body().map(|x| x.into())) + }), + }; + let iter_name = Name::generate_new_name(); + let iter_binding = self.alloc_binding(iter_name.clone(), BindingAnnotation::Mutable); + let iter_expr = self.alloc_expr(Expr::Path(Path::from(iter_name)), syntax_ptr.clone()); + let iter_expr_mut = self.alloc_expr( + Expr::Ref { expr: iter_expr, rawness: Rawness::Ref, mutability: Mutability::Mut }, + syntax_ptr.clone(), + ); + let iter_next_fn_expr = self.alloc_expr(Expr::Path(iter_next_fn), syntax_ptr.clone()); + let iter_next_expr = self.alloc_expr( + Expr::Call { + callee: iter_next_fn_expr, + args: Box::new([iter_expr_mut]), + is_assignee_expr: false, + }, + syntax_ptr.clone(), + ); + let loop_inner = self.alloc_expr( + Expr::Match { expr: iter_next_expr, arms: Box::new([none_arm, some_arm]) }, + syntax_ptr.clone(), + ); + let loop_outer = + self.alloc_expr(Expr::Loop { body: loop_inner, label }, syntax_ptr.clone()); + let iter_pat = self.alloc_pat_desugared(Pat::Bind { id: iter_binding, subpat: None }); + self.alloc_expr( + Expr::Match { + expr: iterator, + arms: Box::new([MatchArm { pat: iter_pat, guard: None, expr: loop_outer }]), + }, + syntax_ptr.clone(), + ) + } + + /// Desugar `ast::TryExpr` from: `?` into: + /// ```ignore (pseudo-rust) + /// match Try::branch() { + /// ControlFlow::Continue(val) => val, + /// ControlFlow::Break(residual) => + /// // If there is an enclosing `try {...}`: + /// break 'catch_target Try::from_residual(residual), + /// // Otherwise: + /// return Try::from_residual(residual), + /// } + /// ``` + fn collect_try_operator(&mut self, syntax_ptr: AstPtr, e: ast::TryExpr) -> ExprId { + let (try_branch, cf_continue, cf_break, try_from_residual) = 'if_chain: { + if let Some(try_branch) = LangItem::TryTraitBranch.path(self.db, self.krate) { + if let Some(cf_continue) = LangItem::ControlFlowContinue.path(self.db, self.krate) { + if let Some(cf_break) = LangItem::ControlFlowBreak.path(self.db, self.krate) { + if let Some(try_from_residual) = + LangItem::TryTraitFromResidual.path(self.db, self.krate) + { + break 'if_chain (try_branch, cf_continue, cf_break, try_from_residual); + } + } + } + } + // Some of the needed lang items are missing, so we can't desugar + return self.alloc_expr(Expr::Missing, syntax_ptr); + }; + let operand = self.collect_expr_opt(e.expr()); + let try_branch = self.alloc_expr(Expr::Path(try_branch), syntax_ptr.clone()); + let expr = self.alloc_expr( + Expr::Call { callee: try_branch, args: Box::new([operand]), is_assignee_expr: false }, + syntax_ptr.clone(), + ); + let continue_name = Name::generate_new_name(); + let continue_binding = + self.alloc_binding(continue_name.clone(), BindingAnnotation::Unannotated); + let continue_bpat = + self.alloc_pat_desugared(Pat::Bind { id: continue_binding, subpat: None }); + self.add_definition_to_binding(continue_binding, continue_bpat); + let continue_arm = MatchArm { + pat: self.alloc_pat_desugared(Pat::TupleStruct { + path: Some(Box::new(cf_continue)), + args: Box::new([continue_bpat]), + ellipsis: None, + }), + guard: None, + expr: self.alloc_expr(Expr::Path(Path::from(continue_name)), syntax_ptr.clone()), + }; + let break_name = Name::generate_new_name(); + let break_binding = self.alloc_binding(break_name.clone(), BindingAnnotation::Unannotated); + let break_bpat = self.alloc_pat_desugared(Pat::Bind { id: break_binding, subpat: None }); + self.add_definition_to_binding(break_binding, break_bpat); + let break_arm = MatchArm { + pat: self.alloc_pat_desugared(Pat::TupleStruct { + path: Some(Box::new(cf_break)), + args: Box::new([break_bpat]), + ellipsis: None, + }), + guard: None, + expr: { + let x = self.alloc_expr(Expr::Path(Path::from(break_name)), syntax_ptr.clone()); + let callee = self.alloc_expr(Expr::Path(try_from_residual), syntax_ptr.clone()); + let result = self.alloc_expr( + Expr::Call { callee, args: Box::new([x]), is_assignee_expr: false }, + syntax_ptr.clone(), + ); + self.alloc_expr( + match self.current_try_block_label { + Some(label) => Expr::Break { expr: Some(result), label: Some(label) }, + None => Expr::Return { expr: Some(result) }, + }, + syntax_ptr.clone(), + ) + }, + }; + let arms = Box::new([continue_arm, break_arm]); + self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr) + } + fn collect_macro_call( &mut self, mcall: ast::MacroCall, @@ -616,7 +909,19 @@ impl ExprCollector<'_> { let outer_file = self.expander.current_file_id; let macro_call_ptr = self.expander.to_source(AstPtr::new(&mcall)); - let res = self.expander.enter_expand(self.db, mcall); + let module = self.expander.module.local_id; + let res = self.expander.enter_expand(self.db, mcall, |path| { + self.def_map + .resolve_path( + self.db, + module, + &path, + crate::item_scope::BuiltinShadowMode::Other, + Some(MacroSubNs::Bang), + ) + .0 + .take_macros() + }); let res = match res { Ok(res) => res, @@ -639,7 +944,7 @@ impl ExprCollector<'_> { krate: *krate, }); } - Some(ExpandError::RecursionOverflowPosioned) => { + Some(ExpandError::RecursionOverflowPoisoned) => { // Recursion limit has been reached in the macro expansion tree, but not in // this very macro call. Don't add diagnostics to avoid duplication. } @@ -663,7 +968,11 @@ impl ExprCollector<'_> { self.db.ast_id_map(self.expander.current_file_id), ); - let id = collector(self, Some(expansion)); + if record_diagnostics { + // FIXME: Report parse errors here + } + + let id = collector(self, Some(expansion.tree())); self.ast_id_map = prev_ast_id_map; self.expander.exit(self.db, mark); id @@ -720,7 +1029,7 @@ impl ExprCollector<'_> { if self.check_cfg(&stmt).is_none() { return; } - let pat = self.collect_pat_opt(stmt.pat()); + let pat = self.collect_pat_top(stmt.pat()); let type_ref = stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it))); let initializer = stmt.initializer().map(|e| self.collect_expr(e)); @@ -763,22 +1072,36 @@ impl ExprCollector<'_> { fn collect_block_( &mut self, block: ast::BlockExpr, - mk_block: impl FnOnce(BlockId, Box<[Statement]>, Option) -> Expr, + mk_block: impl FnOnce(Option, Box<[Statement]>, Option) -> Expr, ) -> ExprId { - let file_local_id = self.ast_id_map.ast_id(&block); - let ast_id = AstId::new(self.expander.current_file_id, file_local_id); - let block_loc = - BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) }; - let block_id = self.db.intern_block(block_loc); - - let (module, def_map) = match self.db.block_def_map(block_id) { - Some(def_map) => { - self.body.block_scopes.push(block_id); - (def_map.root(), def_map) - } - None => (self.expander.module, self.expander.def_map.clone()), + let block_has_items = { + let statement_has_item = block.statements().any(|stmt| match stmt { + ast::Stmt::Item(_) => true, + // Macro calls can be both items and expressions. The syntax library always treats + // them as expressions here, so we undo that. + ast::Stmt::ExprStmt(es) => matches!(es.expr(), Some(ast::Expr::MacroExpr(_))), + _ => false, + }); + statement_has_item || matches!(block.tail_expr(), Some(ast::Expr::MacroExpr(_))) + }; + + let block_id = if block_has_items { + let file_local_id = self.ast_id_map.ast_id(&block); + let ast_id = AstId::new(self.expander.current_file_id, file_local_id); + Some(self.db.intern_block(BlockLoc { ast_id, module: self.expander.module })) + } else { + None }; - let prev_def_map = mem::replace(&mut self.expander.def_map, def_map); + + let (module, def_map) = + match block_id.map(|block_id| (self.db.block_def_map(block_id), block_id)) { + Some((def_map, block_id)) => { + self.body.block_scopes.push(block_id); + (def_map.module_id(DefMap::ROOT), def_map) + } + None => (self.expander.module, self.def_map.clone()), + }; + let prev_def_map = mem::replace(&mut self.def_map, def_map); let prev_local_module = mem::replace(&mut self.expander.module, module); let mut statements = Vec::new(); @@ -800,7 +1123,7 @@ impl ExprCollector<'_> { let expr_id = self .alloc_expr(mk_block(block_id, statements.into_boxed_slice(), tail), syntax_node_ptr); - self.expander.def_map = prev_def_map; + self.def_map = prev_def_map; self.expander.module = prev_local_module; expr_id } @@ -812,43 +1135,46 @@ impl ExprCollector<'_> { } } - fn collect_label(&mut self, ast_label: ast::Label) -> LabelId { - let label = Label { - name: ast_label.lifetime().as_ref().map_or_else(Name::missing, Name::new_lifetime), - }; - self.alloc_label(label, AstPtr::new(&ast_label)) + fn collect_labelled_block_opt( + &mut self, + label: Option, + expr: Option, + ) -> ExprId { + match label { + Some(label) => self.with_labeled_rib(label, |this| this.collect_block_opt(expr)), + None => self.collect_block_opt(expr), + } } - fn collect_pat(&mut self, pat: ast::Pat) -> PatId { - self.collect_pat_(pat, &mut BindingList::default()) - } + // region: patterns - fn collect_pat_opt(&mut self, pat: Option) -> PatId { + fn collect_pat_top(&mut self, pat: Option) -> PatId { match pat { - Some(pat) => self.collect_pat(pat), + Some(pat) => self.collect_pat(pat, &mut BindingList::default()), None => self.missing_pat(), } } - fn collect_pat_(&mut self, pat: ast::Pat, binding_list: &mut BindingList) -> PatId { + fn collect_pat(&mut self, pat: ast::Pat, binding_list: &mut BindingList) -> PatId { let pattern = match &pat { ast::Pat::IdentPat(bp) => { let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); let annotation = BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some()); - let subpat = bp.pat().map(|subpat| self.collect_pat_(subpat, binding_list)); + let subpat = bp.pat().map(|subpat| self.collect_pat(subpat, binding_list)); let is_simple_ident_pat = annotation == BindingAnnotation::Unannotated && subpat.is_none(); let (binding, pattern) = if is_simple_ident_pat { // This could also be a single-segment path pattern. To // decide that, we need to try resolving the name. - let (resolved, _) = self.expander.def_map.resolve_path( + let (resolved, _) = self.def_map.resolve_path( self.db, - self.expander.module, + self.expander.module.local_id, &name.clone().into(), BuiltinShadowMode::Other, + None, ); match resolved.take_values() { Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())), @@ -887,11 +1213,15 @@ impl ExprCollector<'_> { ast::Pat::TupleStructPat(p) => { let path = p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); - let (args, ellipsis) = self.collect_tuple_pat(p.fields(), binding_list); + let (args, ellipsis) = self.collect_tuple_pat( + p.fields(), + comma_follows_token(p.l_paren_token()), + binding_list, + ); Pat::TupleStruct { path, args, ellipsis } } ast::Pat::RefPat(p) => { - let pat = self.collect_pat_opt_(p.pat(), binding_list); + let pat = self.collect_pat_opt(p.pat(), binding_list); let mutability = Mutability::from_mutable(p.mut_token().is_some()); Pat::Ref { pat, mutability } } @@ -900,13 +1230,42 @@ impl ExprCollector<'_> { p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); path.map(Pat::Path).unwrap_or(Pat::Missing) } - ast::Pat::OrPat(p) => { - let pats = p.pats().map(|p| self.collect_pat_(p, binding_list)).collect(); - Pat::Or(pats) + ast::Pat::OrPat(p) => 'b: { + let prev_is_used = mem::take(&mut binding_list.is_used); + let prev_reject_new = mem::take(&mut binding_list.reject_new); + let mut pats = Vec::with_capacity(p.pats().count()); + let mut it = p.pats(); + let Some(first) = it.next() else { + break 'b Pat::Or(Box::new([])); + }; + pats.push(self.collect_pat(first, binding_list)); + binding_list.reject_new = true; + for rest in it { + for (_, x) in binding_list.is_used.iter_mut() { + *x = false; + } + pats.push(self.collect_pat(rest, binding_list)); + for (&id, &x) in binding_list.is_used.iter() { + if !x { + self.body.bindings[id].problems = + Some(BindingProblems::NotBoundAcrossAll); + } + } + } + binding_list.reject_new = prev_reject_new; + let current_is_used = mem::replace(&mut binding_list.is_used, prev_is_used); + for (id, _) in current_is_used.into_iter() { + binding_list.check_is_used(self, id); + } + Pat::Or(pats.into()) } - ast::Pat::ParenPat(p) => return self.collect_pat_opt_(p.pat(), binding_list), + ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat(), binding_list), ast::Pat::TuplePat(p) => { - let (args, ellipsis) = self.collect_tuple_pat(p.fields(), binding_list); + let (args, ellipsis) = self.collect_tuple_pat( + p.fields(), + comma_follows_token(p.l_paren_token()), + binding_list, + ); Pat::Tuple { args, ellipsis } } ast::Pat::WildcardPat(_) => Pat::Wild, @@ -919,7 +1278,7 @@ impl ExprCollector<'_> { .fields() .filter_map(|f| { let ast_pat = f.pat()?; - let pat = self.collect_pat_(ast_pat, binding_list); + let pat = self.collect_pat(ast_pat, binding_list); let name = f.field_name()?.as_name(); Some(RecordFieldPat { name, pat }) }) @@ -938,26 +1297,18 @@ impl ExprCollector<'_> { // FIXME properly handle `RestPat` Pat::Slice { - prefix: prefix - .into_iter() - .map(|p| self.collect_pat_(p, binding_list)) - .collect(), - slice: slice.map(|p| self.collect_pat_(p, binding_list)), - suffix: suffix - .into_iter() - .map(|p| self.collect_pat_(p, binding_list)) - .collect(), + prefix: prefix.into_iter().map(|p| self.collect_pat(p, binding_list)).collect(), + slice: slice.map(|p| self.collect_pat(p, binding_list)), + suffix: suffix.into_iter().map(|p| self.collect_pat(p, binding_list)).collect(), } } - ast::Pat::LiteralPat(lit) => { - if let Some(ast_lit) = lit.literal() { - let expr = Expr::Literal(ast_lit.kind().into()); - let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit)); - let expr_id = self.alloc_expr(expr, expr_ptr); - Pat::Lit(expr_id) - } else { - Pat::Missing - } + #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5676 + ast::Pat::LiteralPat(lit) => 'b: { + let Some((hir_lit, ast_lit)) = pat_literal_to_hir(lit) else { break 'b Pat::Missing }; + let expr = Expr::Literal(hir_lit); + let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit)); + let expr_id = self.alloc_expr(expr, expr_ptr); + Pat::Lit(expr_id) } ast::Pat::RestPat(_) => { // `RestPat` requires special handling and should not be mapped @@ -969,12 +1320,18 @@ impl ExprCollector<'_> { Pat::Missing } ast::Pat::BoxPat(boxpat) => { - let inner = self.collect_pat_opt_(boxpat.pat(), binding_list); + let inner = self.collect_pat_opt(boxpat.pat(), binding_list); Pat::Box { inner } } ast::Pat::ConstBlockPat(const_block_pat) => { - if let Some(expr) = const_block_pat.block_expr() { - let expr_id = self.collect_block(expr); + if let Some(block) = const_block_pat.block_expr() { + let expr_id = self.with_label_rib(RibKind::Constant, |this| { + let syntax_ptr = AstPtr::new(&block.clone().into()); + this.collect_as_a_binding_owner_bad( + |this| this.collect_block(block), + syntax_ptr, + ) + }); Pat::ConstBlock(expr_id) } else { Pat::Missing @@ -986,23 +1343,45 @@ impl ExprCollector<'_> { let src = self.expander.to_source(Either::Left(AstPtr::new(&pat))); let pat = self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| { - this.collect_pat_opt_(expanded_pat, binding_list) + this.collect_pat_opt(expanded_pat, binding_list) }); self.source_map.pat_map.insert(src, pat); return pat; } None => Pat::Missing, }, - // FIXME: implement - ast::Pat::RangePat(_) => Pat::Missing, + // FIXME: implement in a way that also builds source map and calculates assoc resolutions in type inference. + ast::Pat::RangePat(p) => { + let mut range_part_lower = |p: Option| { + p.and_then(|x| match &x { + ast::Pat::LiteralPat(x) => { + Some(Box::new(LiteralOrConst::Literal(pat_literal_to_hir(x)?.0))) + } + ast::Pat::IdentPat(p) => { + let name = + p.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); + Some(Box::new(LiteralOrConst::Const(name.into()))) + } + ast::Pat::PathPat(p) => p + .path() + .and_then(|path| self.expander.parse_path(self.db, path)) + .map(LiteralOrConst::Const) + .map(Box::new), + _ => None, + }) + }; + let start = range_part_lower(p.start()); + let end = range_part_lower(p.end()); + Pat::Range { start, end } + } }; let ptr = AstPtr::new(&pat); self.alloc_pat(pattern, Either::Left(ptr)) } - fn collect_pat_opt_(&mut self, pat: Option, binding_list: &mut BindingList) -> PatId { + fn collect_pat_opt(&mut self, pat: Option, binding_list: &mut BindingList) -> PatId { match pat { - Some(pat) => self.collect_pat_(pat, binding_list), + Some(pat) => self.collect_pat(pat, binding_list), None => self.missing_pat(), } } @@ -1010,20 +1389,28 @@ impl ExprCollector<'_> { fn collect_tuple_pat( &mut self, args: AstChildren, + has_leading_comma: bool, binding_list: &mut BindingList, ) -> (Box<[PatId]>, Option) { // Find the location of the `..`, if there is one. Note that we do not // consider the possibility of there being multiple `..` here. let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::RestPat(_))); // We want to skip the `..` pattern here, since we account for it above. - let args = args + let mut args: Vec<_> = args .filter(|p| !matches!(p, ast::Pat::RestPat(_))) - .map(|p| self.collect_pat_(p, binding_list)) + .map(|p| self.collect_pat(p, binding_list)) .collect(); + // if there is a leading comma, the user is most likely to type out a leading pattern + // so we insert a missing pattern at the beginning for IDE features + if has_leading_comma { + args.insert(0, self.missing_pat()); + } - (args, ellipsis) + (args.into_boxed_slice(), ellipsis) } + // endregion: patterns + /// Returns `None` (and emits diagnostics) when `owner` if `#[cfg]`d out, and `Some(())` when /// not. fn check_cfg(&mut self, owner: &dyn ast::HasAttrs) -> Option<()> { @@ -1051,42 +1438,147 @@ impl ExprCollector<'_> { fn add_definition_to_binding(&mut self, binding_id: BindingId, pat_id: PatId) { self.body.bindings[binding_id].definitions.push(pat_id); } -} -impl From for Literal { - fn from(ast_lit_kind: ast::LiteralKind) -> Self { - match ast_lit_kind { - // FIXME: these should have actual values filled in, but unsure on perf impact - LiteralKind::IntNumber(lit) => { - if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) { - Literal::Float( - FloatTypeWrapper::new(lit.float_value().unwrap_or(Default::default())), - builtin, - ) - } else if let builtin @ Some(_) = lit.suffix().and_then(BuiltinInt::from_suffix) { - Literal::Int(lit.value().unwrap_or(0) as i128, builtin) - } else { - let builtin = lit.suffix().and_then(BuiltinUint::from_suffix); - Literal::Uint(lit.value().unwrap_or(0), builtin) + // region: labels + + fn collect_label(&mut self, ast_label: ast::Label) -> LabelId { + let label = Label { + name: ast_label.lifetime().as_ref().map_or_else(Name::missing, Name::new_lifetime), + }; + self.alloc_label(label, AstPtr::new(&ast_label)) + } + + fn resolve_label( + &self, + lifetime: Option, + ) -> Result, BodyDiagnostic> { + let Some(lifetime) = lifetime else { + return Ok(None) + }; + let name = Name::new_lifetime(&lifetime); + + for (rib_idx, rib) in self.label_ribs.iter().enumerate().rev() { + if let Some((label_name, id)) = &rib.label { + if *label_name == name { + return if self.is_label_valid_from_rib(rib_idx) { + Ok(Some(*id)) + } else { + Err(BodyDiagnostic::UnreachableLabel { + name, + node: InFile::new( + self.expander.current_file_id, + AstPtr::new(&lifetime), + ), + }) + }; } } - LiteralKind::FloatNumber(lit) => { - let ty = lit.suffix().and_then(BuiltinFloat::from_suffix); - Literal::Float(FloatTypeWrapper::new(lit.value().unwrap_or(Default::default())), ty) - } - LiteralKind::ByteString(bs) => { - let text = bs.value().map(Box::from).unwrap_or_else(Default::default); - Literal::ByteString(text) - } - LiteralKind::String(s) => { - let text = s.value().map(Box::from).unwrap_or_else(Default::default); - Literal::String(text) - } - LiteralKind::Byte(b) => { - Literal::Uint(b.value().unwrap_or_default() as u128, Some(BuiltinUint::U8)) - } - LiteralKind::Char(c) => Literal::Char(c.value().unwrap_or_default()), - LiteralKind::Bool(val) => Literal::Bool(val), } + + Err(BodyDiagnostic::UndeclaredLabel { + name, + node: InFile::new(self.expander.current_file_id, AstPtr::new(&lifetime)), + }) } + + fn is_label_valid_from_rib(&self, rib_index: usize) -> bool { + !self.label_ribs[rib_index + 1..].iter().any(|rib| rib.kind.is_label_barrier()) + } + + fn with_label_rib(&mut self, kind: RibKind, f: impl FnOnce(&mut Self) -> T) -> T { + self.label_ribs.push(LabelRib::new(kind)); + let res = f(self); + self.label_ribs.pop(); + res + } + + fn with_labeled_rib(&mut self, label: LabelId, f: impl FnOnce(&mut Self) -> T) -> T { + self.label_ribs.push(LabelRib::new_normal((self.body[label].name.clone(), label))); + let res = f(self); + self.label_ribs.pop(); + res + } + + fn with_opt_labeled_rib( + &mut self, + label: Option, + f: impl FnOnce(&mut Self) -> T, + ) -> T { + match label { + None => f(self), + Some(label) => self.with_labeled_rib(label, f), + } + } + // endregion: labels +} + +fn pat_literal_to_hir(lit: &ast::LiteralPat) -> Option<(Literal, ast::Literal)> { + let ast_lit = lit.literal()?; + let mut hir_lit: Literal = ast_lit.kind().into(); + if lit.minus_token().is_some() { + let Some(h) = hir_lit.negate() else { + return None; + }; + hir_lit = h; + } + Some((hir_lit, ast_lit)) +} + +impl ExprCollector<'_> { + fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId { + let src = self.expander.to_source(ptr); + let id = self.body.exprs.alloc(expr); + self.source_map.expr_map_back.insert(id, src.clone()); + self.source_map.expr_map.insert(src, id); + id + } + // FIXME: desugared exprs don't have ptr, that's wrong and should be fixed somehow. + fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId { + self.body.exprs.alloc(expr) + } + fn missing_expr(&mut self) -> ExprId { + self.alloc_expr_desugared(Expr::Missing) + } + + fn alloc_binding(&mut self, name: Name, mode: BindingAnnotation) -> BindingId { + self.body.bindings.alloc(Binding { + name, + mode, + definitions: SmallVec::new(), + owner: self.current_binding_owner, + problems: None, + }) + } + + fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { + let src = self.expander.to_source(ptr); + let id = self.body.pats.alloc(pat); + self.source_map.pat_map_back.insert(id, src.clone()); + self.source_map.pat_map.insert(src, id); + id + } + // FIXME: desugared pats don't have ptr, that's wrong and should be fixed somehow. + fn alloc_pat_desugared(&mut self, pat: Pat) -> PatId { + self.body.pats.alloc(pat) + } + fn missing_pat(&mut self) -> PatId { + self.body.pats.alloc(Pat::Missing) + } + + fn alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId { + let src = self.expander.to_source(ptr); + let id = self.body.labels.alloc(label); + self.source_map.label_map_back.insert(id, src.clone()); + self.source_map.label_map.insert(src, id); + id + } + // FIXME: desugared labels don't have ptr, that's wrong and should be fixed somehow. + fn alloc_label_desugared(&mut self, label: Label) -> LabelId { + self.body.labels.alloc(label) + } +} + +fn comma_follows_token(t: Option) -> bool { + (|| syntax::algo::skip_trivia_token(t?.next_token()?, syntax::Direction::Next))() + .map_or(false, |it| it.kind() == syntax::T![,]) } diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs index 5a9b825a2530b..88380aa355d16 100644 --- a/crates/hir-def/src/body/pretty.rs +++ b/crates/hir-def/src/body/pretty.rs @@ -2,10 +2,14 @@ use std::fmt::{self, Write}; +use hir_expand::db::ExpandDatabase; use syntax::ast::HasName; use crate::{ - expr::{Array, BindingAnnotation, BindingId, ClosureKind, Literal, Movability, Statement}, + hir::{ + Array, BindingAnnotation, BindingId, CaptureBy, ClosureKind, Literal, LiteralOrConst, + Movability, Statement, + }, pretty::{print_generic_args, print_path, print_type_ref}, type_ref::TypeRef, }; @@ -13,47 +17,70 @@ use crate::{ use super::*; pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBodyId) -> String { - let needs_semi; let header = match owner { DefWithBodyId::FunctionId(it) => { - needs_semi = false; let item_tree_id = it.lookup(db).id; - format!("fn {}(…) ", item_tree_id.item_tree(db)[item_tree_id.value].name) + format!( + "fn {}", + item_tree_id.item_tree(db)[item_tree_id.value].name.display(db.upcast()) + ) } DefWithBodyId::StaticId(it) => { - needs_semi = true; let item_tree_id = it.lookup(db).id; - format!("static {} = ", item_tree_id.item_tree(db)[item_tree_id.value].name) + format!( + "static {} = ", + item_tree_id.item_tree(db)[item_tree_id.value].name.display(db.upcast()) + ) } DefWithBodyId::ConstId(it) => { - needs_semi = true; let item_tree_id = it.lookup(db).id; let name = match &item_tree_id.item_tree(db)[item_tree_id.value].name { - Some(name) => name.to_string(), + Some(name) => name.display(db.upcast()).to_string(), None => "_".to_string(), }; format!("const {name} = ") } DefWithBodyId::VariantId(it) => { - needs_semi = false; let src = it.parent.child_source(db); let variant = &src.value[it.local_id]; - let name = match &variant.name() { + match &variant.name() { Some(name) => name.to_string(), None => "_".to_string(), - }; - format!("{name}") + } } }; - let mut p = Printer { body, buf: header, indent_level: 0, needs_indent: false }; + let mut p = + Printer { db: db.upcast(), body, buf: header, indent_level: 0, needs_indent: false }; + if let DefWithBodyId::FunctionId(it) = owner { + p.buf.push('('); + body.params.iter().zip(&db.function_data(it).params).for_each(|(¶m, ty)| { + p.print_pat(param); + p.buf.push(':'); + p.print_type_ref(ty); + }); + p.buf.push(')'); + p.buf.push(' '); + } p.print_expr(body.body_expr); - if needs_semi { + if matches!(owner, DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_)) { p.buf.push(';'); } p.buf } +pub(super) fn print_expr_hir( + db: &dyn DefDatabase, + body: &Body, + _owner: DefWithBodyId, + expr: ExprId, +) -> String { + let mut p = + Printer { db: db.upcast(), body, buf: String::new(), indent_level: 0, needs_indent: false }; + p.print_expr(expr); + p.buf +} + macro_rules! w { ($dst:expr, $($arg:tt)*) => { { let _ = write!($dst, $($arg)*); } @@ -70,6 +97,7 @@ macro_rules! wln { } struct Printer<'a> { + db: &'a dyn ExpandDatabase, body: &'a Body, buf: String, indent_level: usize, @@ -144,29 +172,19 @@ impl<'a> Printer<'a> { } Expr::Loop { body, label } => { if let Some(lbl) = label { - w!(self, "{}: ", self.body[*lbl].name); + w!(self, "{}: ", self.body[*lbl].name.display(self.db)); } w!(self, "loop "); self.print_expr(*body); } Expr::While { condition, body, label } => { if let Some(lbl) = label { - w!(self, "{}: ", self.body[*lbl].name); + w!(self, "{}: ", self.body[*lbl].name.display(self.db)); } w!(self, "while "); self.print_expr(*condition); self.print_expr(*body); } - Expr::For { iterable, pat, body, label } => { - if let Some(lbl) = label { - w!(self, "{}: ", self.body[*lbl].name); - } - w!(self, "for "); - self.print_pat(*pat); - w!(self, " in "); - self.print_expr(*iterable); - self.print_expr(*body); - } Expr::Call { callee, args, is_assignee_expr: _ } => { self.print_expr(*callee); w!(self, "("); @@ -182,10 +200,10 @@ impl<'a> Printer<'a> { } Expr::MethodCall { receiver, method_name, args, generic_args } => { self.print_expr(*receiver); - w!(self, ".{}", method_name); + w!(self, ".{}", method_name.display(self.db)); if let Some(args) = generic_args { w!(self, "::<"); - print_generic_args(args, self).unwrap(); + print_generic_args(self.db, args, self).unwrap(); w!(self, ">"); } w!(self, "("); @@ -219,14 +237,14 @@ impl<'a> Printer<'a> { } Expr::Continue { label } => { w!(self, "continue"); - if let Some(label) = label { - w!(self, " {}", label); + if let Some(lbl) = label { + w!(self, " {}", self.body[*lbl].name.display(self.db)); } } Expr::Break { expr, label } => { w!(self, "break"); - if let Some(label) = label { - w!(self, " {}", label); + if let Some(lbl) = label { + w!(self, " {}", self.body[*lbl].name.display(self.db)); } if let Some(expr) = expr { self.whitespace(); @@ -265,7 +283,7 @@ impl<'a> Printer<'a> { w!(self, "{{"); self.indented(|p| { for field in &**fields { - w!(p, "{}: ", field.name); + w!(p, "{}: ", field.name.display(self.db)); p.print_expr(field.expr); wln!(p, ","); } @@ -282,16 +300,12 @@ impl<'a> Printer<'a> { } Expr::Field { expr, name } => { self.print_expr(*expr); - w!(self, ".{}", name); + w!(self, ".{}", name.display(self.db)); } Expr::Await { expr } => { self.print_expr(*expr); w!(self, ".await"); } - Expr::Try { expr } => { - self.print_expr(*expr); - w!(self, "?"); - } Expr::Cast { expr, type_ref } => { self.print_expr(*expr); w!(self, " as "); @@ -359,7 +373,7 @@ impl<'a> Printer<'a> { self.print_expr(*index); w!(self, "]"); } - Expr::Closure { args, arg_types, ret_type, body, closure_kind } => { + Expr::Closure { args, arg_types, ret_type, body, closure_kind, capture_by } => { match closure_kind { ClosureKind::Generator(Movability::Static) => { w!(self, "static "); @@ -369,6 +383,12 @@ impl<'a> Printer<'a> { } _ => (), } + match capture_by { + CaptureBy::Value => { + w!(self, "move "); + } + CaptureBy::Ref => (), + } w!(self, "|"); for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() { if i != 0 { @@ -418,20 +438,17 @@ impl<'a> Printer<'a> { } Expr::Literal(lit) => self.print_literal(lit), Expr::Block { id: _, statements, tail, label } => { - let label = label.map(|lbl| format!("{}: ", self.body[lbl].name)); + let label = label.map(|lbl| format!("{}: ", self.body[lbl].name.display(self.db))); self.print_block(label.as_deref(), statements, tail); } Expr::Unsafe { id: _, statements, tail } => { self.print_block(Some("unsafe "), statements, tail); } - Expr::TryBlock { id: _, statements, tail } => { - self.print_block(Some("try "), statements, tail); - } Expr::Async { id: _, statements, tail } => { self.print_block(Some("async "), statements, tail); } - Expr::Const { id: _, statements, tail } => { - self.print_block(Some("const "), statements, tail); + Expr::Const(id) => { + w!(self, "const {{ /* {id:?} */ }}"); } } } @@ -439,7 +456,7 @@ impl<'a> Printer<'a> { fn print_block( &mut self, label: Option<&str>, - statements: &Box<[Statement]>, + statements: &[Statement], tail: &Option>, ) { self.whitespace(); @@ -449,7 +466,7 @@ impl<'a> Printer<'a> { w!(self, "{{"); if !statements.is_empty() || tail.is_some() { self.indented(|p| { - for stmt in &**statements { + for stmt in statements { p.print_stmt(stmt); } if let Some(tail) = tail { @@ -497,7 +514,7 @@ impl<'a> Printer<'a> { w!(self, " {{"); self.indented(|p| { for arg in args.iter() { - w!(p, "{}: ", arg.name); + w!(p, "{}: ", arg.name.display(self.db)); p.print_pat(arg.pat); wln!(p, ","); } @@ -508,9 +525,13 @@ impl<'a> Printer<'a> { w!(self, "}}"); } Pat::Range { start, end } => { - self.print_expr(*start); - w!(self, "..."); - self.print_expr(*end); + if let Some(start) = start { + self.print_literal_or_const(start); + } + w!(self, "..="); + if let Some(end) = end { + self.print_literal_or_const(end); + } } Pat::Slice { prefix, slice, suffix } => { w!(self, "["); @@ -601,10 +622,18 @@ impl<'a> Printer<'a> { } } + fn print_literal_or_const(&mut self, literal_or_const: &LiteralOrConst) { + match literal_or_const { + LiteralOrConst::Literal(l) => self.print_literal(l), + LiteralOrConst::Const(c) => self.print_path(c), + } + } + fn print_literal(&mut self, literal: &Literal) { match literal { Literal::String(it) => w!(self, "{:?}", it), Literal::ByteString(it) => w!(self, "\"{}\"", it.escape_ascii()), + Literal::CString(it) => w!(self, "\"{}\\0\"", it), Literal::Char(it) => w!(self, "'{}'", it.escape_debug()), Literal::Bool(it) => w!(self, "{}", it), Literal::Int(i, suffix) => { @@ -629,11 +658,11 @@ impl<'a> Printer<'a> { } fn print_type_ref(&mut self, ty: &TypeRef) { - print_type_ref(ty, self).unwrap(); + print_type_ref(self.db, ty, self).unwrap(); } fn print_path(&mut self, path: &Path) { - print_path(path, self).unwrap(); + print_path(self.db, path, self).unwrap(); } fn print_binding(&mut self, id: BindingId) { @@ -644,6 +673,6 @@ impl<'a> Printer<'a> { BindingAnnotation::Ref => "ref ", BindingAnnotation::RefMut => "ref mut ", }; - w!(self, "{}{}", mode, name); + w!(self, "{}{}", mode, name.display(self.db)); } } diff --git a/crates/hir-def/src/body/scope.rs b/crates/hir-def/src/body/scope.rs index 12fc1f116d7da..69741c445fbae 100644 --- a/crates/hir-def/src/body/scope.rs +++ b/crates/hir-def/src/body/scope.rs @@ -1,14 +1,13 @@ //! Name resolution for expressions. -use std::sync::Arc; - use hir_expand::name::Name; -use la_arena::{Arena, Idx}; +use la_arena::{Arena, Idx, IdxRange, RawIdx}; use rustc_hash::FxHashMap; +use triomphe::Arc; use crate::{ body::Body, db::DefDatabase, - expr::{Binding, BindingId, Expr, ExprId, LabelId, Pat, PatId, Statement}, + hir::{Binding, BindingId, Expr, ExprId, LabelId, Pat, PatId, Statement}, BlockId, DefWithBodyId, }; @@ -17,6 +16,7 @@ pub type ScopeId = Idx; #[derive(Debug, PartialEq, Eq)] pub struct ExprScopes { scopes: Arena, + scope_entries: Arena, scope_by_expr: FxHashMap, } @@ -41,7 +41,7 @@ pub struct ScopeData { parent: Option, block: Option, label: Option<(LabelId, Name)>, - entries: Vec, + entries: IdxRange, } impl ExprScopes { @@ -53,7 +53,7 @@ impl ExprScopes { } pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { - &self.scopes[scope].entries + &self.scope_entries[self.scopes[scope].entries.clone()] } /// If `scope` refers to a block expression scope, returns the corresponding `BlockId`. @@ -85,10 +85,17 @@ impl ExprScopes { } } +fn empty_entries(idx: usize) -> IdxRange { + IdxRange::new(Idx::from_raw(RawIdx::from(idx as u32))..Idx::from_raw(RawIdx::from(idx as u32))) +} + impl ExprScopes { fn new(body: &Body) -> ExprScopes { - let mut scopes = - ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() }; + let mut scopes = ExprScopes { + scopes: Arena::default(), + scope_entries: Arena::default(), + scope_by_expr: FxHashMap::default(), + }; let mut root = scopes.root_scope(); scopes.add_params_bindings(body, root, &body.params); compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root); @@ -96,7 +103,12 @@ impl ExprScopes { } fn root_scope(&mut self) -> ScopeId { - self.scopes.alloc(ScopeData { parent: None, block: None, label: None, entries: vec![] }) + self.scopes.alloc(ScopeData { + parent: None, + block: None, + label: None, + entries: empty_entries(self.scope_entries.len()), + }) } fn new_scope(&mut self, parent: ScopeId) -> ScopeId { @@ -104,32 +116,38 @@ impl ExprScopes { parent: Some(parent), block: None, label: None, - entries: vec![], + entries: empty_entries(self.scope_entries.len()), }) } fn new_labeled_scope(&mut self, parent: ScopeId, label: Option<(LabelId, Name)>) -> ScopeId { - self.scopes.alloc(ScopeData { parent: Some(parent), block: None, label, entries: vec![] }) + self.scopes.alloc(ScopeData { + parent: Some(parent), + block: None, + label, + entries: empty_entries(self.scope_entries.len()), + }) } fn new_block_scope( &mut self, parent: ScopeId, - block: BlockId, + block: Option, label: Option<(LabelId, Name)>, ) -> ScopeId { self.scopes.alloc(ScopeData { parent: Some(parent), - block: Some(block), + block, label, - entries: vec![], + entries: empty_entries(self.scope_entries.len()), }) } fn add_bindings(&mut self, body: &Body, scope: ScopeId, binding: BindingId) { let Binding { name, .. } = &body.bindings[binding]; - let entry = ScopeEntry { name: name.clone(), binding }; - self.scopes[scope].entries.push(entry); + let entry = self.scope_entries.alloc(ScopeEntry { name: name.clone(), binding }); + self.scopes[scope].entries = + IdxRange::new_inclusive(self.scopes[scope].entries.start()..=entry); } fn add_pat_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { @@ -150,9 +168,9 @@ impl ExprScopes { } fn shrink_to_fit(&mut self) { - let ExprScopes { scopes, scope_by_expr } = self; + let ExprScopes { scopes, scope_entries, scope_by_expr } = self; scopes.shrink_to_fit(); - scopes.values_mut().for_each(|it| it.entries.shrink_to_fit()); + scope_entries.shrink_to_fit(); scope_by_expr.shrink_to_fit(); } } @@ -200,22 +218,16 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope scopes.set_scope(expr, scope); compute_block_scopes(statements, *tail, body, scopes, &mut scope); } - Expr::Unsafe { id, statements, tail } - | Expr::Async { id, statements, tail } - | Expr::Const { id, statements, tail } - | Expr::TryBlock { id, statements, tail } => { + Expr::Const(_) => { + // FIXME: This is broken. + } + Expr::Unsafe { id, statements, tail } | Expr::Async { id, statements, tail } => { let mut scope = scopes.new_block_scope(*scope, *id, None); // Overwrite the old scope for the block expr, so that every block scope can be found // via the block itself (important for blocks that only contain items, no expressions). scopes.set_scope(expr, scope); compute_block_scopes(statements, *tail, body, scopes, &mut scope); } - Expr::For { iterable, pat, body: body_expr, label } => { - compute_expr_scopes(*iterable, body, scopes, scope); - let mut scope = scopes.new_labeled_scope(*scope, make_label(label)); - scopes.add_pat_bindings(body, scope, *pat); - compute_expr_scopes(*body_expr, body, scopes, &mut scope); - } Expr::While { condition, body: body_expr, label } => { let mut scope = scopes.new_labeled_scope(*scope, make_label(label)); compute_expr_scopes(*condition, body, scopes, &mut scope); diff --git a/crates/hir-def/src/body/tests/block.rs b/crates/hir-def/src/body/tests/block.rs index 77ac221e590c5..6e77744f21539 100644 --- a/crates/hir-def/src/body/tests/block.rs +++ b/crates/hir-def/src/body/tests/block.rs @@ -148,8 +148,8 @@ fn f() { } "#, expect![[r#" - BlockId(1) in ModuleId { krate: CrateId(0), block: Some(BlockId(0)), local_id: Idx::(1) } - BlockId(0) in ModuleId { krate: CrateId(0), block: None, local_id: Idx::(0) } + BlockId(1) in BlockRelativeModuleId { block: Some(BlockId(0)), local_id: Idx::(1) } + BlockId(0) in BlockRelativeModuleId { block: None, local_id: Idx::(0) } crate scope "#]], ); diff --git a/crates/hir-def/src/builtin_type.rs b/crates/hir-def/src/builtin_type.rs index dd69c3ab47315..61b2481978e27 100644 --- a/crates/hir-def/src/builtin_type.rs +++ b/crates/hir-def/src/builtin_type.rs @@ -106,8 +106,14 @@ impl AsName for BuiltinType { impl fmt::Display for BuiltinType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let type_name = self.as_name(); - type_name.fmt(f) + match self { + BuiltinType::Char => f.write_str("char"), + BuiltinType::Bool => f.write_str("bool"), + BuiltinType::Str => f.write_str("str"), + BuiltinType::Int(it) => it.fmt(f), + BuiltinType::Uint(it) => it.fmt(f), + BuiltinType::Float(it) => it.fmt(f), + } } } diff --git a/crates/hir-def/src/child_by_source.rs b/crates/hir-def/src/child_by_source.rs index 68b57acca2adc..bb79e28f2673a 100644 --- a/crates/hir-def/src/child_by_source.rs +++ b/crates/hir-def/src/child_by_source.rs @@ -10,9 +10,9 @@ use syntax::ast::HasDocComments; use crate::{ db::DefDatabase, - dyn_map::DynMap, + dyn_map::{keys, DynMap}, item_scope::ItemScope, - keys, + nameres::DefMap, src::{HasChildSource, HasSource}, AdtId, AssocItemId, DefWithBodyId, EnumId, EnumVariantId, FieldId, ImplId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, VariantId, @@ -206,7 +206,7 @@ impl ChildBySource for DefWithBodyId { for (_, def_map) in body.blocks(db) { // All block expressions are merged into the same map, because they logically all add // inner items to the containing `DefWithBodyId`. - def_map[def_map.root()].scope.child_by_source_to(db, res, file_id); + def_map[DefMap::ROOT].scope.child_by_source_to(db, res, file_id); } } } diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index 1633a33bedde8..40e6a4308784c 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -1,22 +1,28 @@ //! Contains basic data about various HIR declarations. -use std::sync::Arc; +pub mod adt; -use hir_expand::{name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroDefKind}; +use hir_expand::{ + name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefKind, +}; use intern::Interned; use smallvec::SmallVec; -use syntax::ast; +use syntax::{ast, Parse}; +use triomphe::Arc; use crate::{ attr::Attrs, - body::{Expander, Mark}, db::DefDatabase, - item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, ModItem, Param, TreeId}, + expander::{Expander, Mark}, + item_tree::{ + self, AssocItem, FnFlags, ItemTree, ItemTreeId, MacroCall, ModItem, Param, TreeId, + }, + macro_call_as_call_id, macro_id_to_def_id, nameres::{ attr_resolution::ResolvedAttr, diagnostics::DefDiagnostic, proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroKind}, - DefMap, + DefMap, MacroSubNs, }, type_ref::{TraitRef, TypeBound, TypeRef}, visibility::RawVisibility, @@ -28,9 +34,8 @@ use crate::{ #[derive(Debug, Clone, PartialEq, Eq)] pub struct FunctionData { pub name: Name, - pub params: Vec<(Option, Interned)>, + pub params: Vec>, pub ret_type: Interned, - pub async_ret_type: Option>, pub attrs: Attrs, pub visibility: RawVisibility, pub abi: Option>, @@ -43,16 +48,16 @@ impl FunctionData { pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc { let loc = func.lookup(db); let krate = loc.container.module(db).krate; - let crate_graph = db.crate_graph(); - let cfg_options = &crate_graph[krate].cfg_options; let item_tree = loc.id.item_tree(db); let func = &item_tree[loc.id.value]; let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container { - db.trait_data(trait_id).visibility.clone() + trait_vis(db, trait_id) } else { item_tree[func.visibility].clone() }; + let crate_graph = db.crate_graph(); + let cfg_options = &crate_graph[krate].cfg_options; let enabled_params = func .params .clone() @@ -99,12 +104,11 @@ impl FunctionData { params: enabled_params .clone() .filter_map(|id| match &item_tree[id] { - Param::Normal(name, ty) => Some((name.clone(), ty.clone())), + Param::Normal(ty) => Some(ty.clone()), Param::Varargs => None, }) .collect(), ret_type: func.ret_type.clone(), - async_ret_type: func.async_ret_type.clone(), attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()), visibility, abi: func.abi.clone(), @@ -188,7 +192,7 @@ impl TypeAliasData { let item_tree = loc.id.item_tree(db); let typ = &item_tree[loc.id.value]; let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container { - db.trait_data(trait_id).visibility.clone() + trait_vis(db, trait_id) } else { item_tree[typ.visibility].clone() }; @@ -471,7 +475,7 @@ impl ConstData { let item_tree = loc.id.item_tree(db); let konst = &item_tree[loc.id.value]; let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container { - db.trait_data(trait_id).visibility.clone() + trait_vis(db, trait_id) } else { item_tree[konst.visibility].clone() }; @@ -519,7 +523,7 @@ struct AssocItemCollector<'a> { db: &'a dyn DefDatabase, module_id: ModuleId, def_map: Arc, - inactive_diagnostics: Vec, + diagnostics: Vec, container: ItemContainerId, expander: Expander, @@ -542,7 +546,7 @@ impl<'a> AssocItemCollector<'a> { expander: Expander::new(db, file_id, module_id), items: Vec::new(), attr_calls: Vec::new(), - inactive_diagnostics: Vec::new(), + diagnostics: Vec::new(), } } @@ -556,11 +560,10 @@ impl<'a> AssocItemCollector<'a> { ( self.items, if self.attr_calls.is_empty() { None } else { Some(Box::new(self.attr_calls)) }, - self.inactive_diagnostics, + self.diagnostics, ) } - // FIXME: proc-macro diagnostics fn collect(&mut self, item_tree: &ItemTree, tree_id: TreeId, assoc_items: &[AssocItem]) { let container = self.container; self.items.reserve(assoc_items.len()); @@ -568,7 +571,7 @@ impl<'a> AssocItemCollector<'a> { 'items: for &item in assoc_items { let attrs = item_tree.attrs(self.db, self.module_id.krate, ModItem::from(item).into()); if !attrs.is_cfg_enabled(self.expander.cfg_options()) { - self.inactive_diagnostics.push(DefDiagnostic::unconfigured_code( + self.diagnostics.push(DefDiagnostic::unconfigured_code( self.module_id.local_id, InFile::new(self.expander.current_file_id(), item.ast_id(item_tree).upcast()), attrs.cfg().unwrap(), @@ -582,84 +585,164 @@ impl<'a> AssocItemCollector<'a> { AstId::new(self.expander.current_file_id(), item.ast_id(item_tree).upcast()); let ast_id_with_path = AstIdWithPath { path: (*attr.path).clone(), ast_id }; - if let Ok(ResolvedAttr::Macro(call_id)) = self.def_map.resolve_attr_macro( + match self.def_map.resolve_attr_macro( self.db, self.module_id.local_id, ast_id_with_path, attr, ) { - self.attr_calls.push((ast_id, call_id)); - // If proc attribute macro expansion is disabled, skip expanding it here - if !self.db.enable_proc_attr_macros() { - continue 'attrs; - } - let loc = self.db.lookup_intern_macro_call(call_id); - if let MacroDefKind::ProcMacro(exp, ..) = loc.def.kind { - // If there's no expander for the proc macro (e.g. the - // proc macro is ignored, or building the proc macro - // crate failed), skip expansion like we would if it was - // disabled. This is analogous to the handling in - // `DefCollector::collect_macros`. - if exp.is_dummy() { + Ok(ResolvedAttr::Macro(call_id)) => { + self.attr_calls.push((ast_id, call_id)); + // If proc attribute macro expansion is disabled, skip expanding it here + if !self.db.expand_proc_attr_macros() { continue 'attrs; } - } - match self.expander.enter_expand_id::(self.db, call_id) { - ExpandResult { value: Some((mark, _)), .. } => { - self.collect_macro_items(mark); - continue 'items; + let loc = self.db.lookup_intern_macro_call(call_id); + if let MacroDefKind::ProcMacro(exp, ..) = loc.def.kind { + // If there's no expander for the proc macro (e.g. the + // proc macro is ignored, or building the proc macro + // crate failed), skip expansion like we would if it was + // disabled. This is analogous to the handling in + // `DefCollector::collect_macros`. + if exp.is_dummy() { + continue 'attrs; + } } - ExpandResult { .. } => {} + + let res = + self.expander.enter_expand_id::(self.db, call_id); + self.collect_macro_items(res, &|| loc.kind.clone()); + continue 'items; + } + Ok(_) => (), + Err(_) => { + self.diagnostics.push(DefDiagnostic::unresolved_macro_call( + self.module_id.local_id, + MacroCallKind::Attr { + ast_id, + attr_args: Arc::new((tt::Subtree::empty(), Default::default())), + invoc_attr_index: attr.id, + }, + attr.path().clone(), + )); } } } - match item { - AssocItem::Function(id) => { - let item = &item_tree[id]; + self.collect_item(item_tree, tree_id, container, item); + } + } - let def = - FunctionLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db); - self.items.push((item.name.clone(), def.into())); - } - AssocItem::Const(id) => { - let item = &item_tree[id]; - - let name = match item.name.clone() { - Some(name) => name, - None => continue, - }; - let def = - ConstLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db); - self.items.push((name, def.into())); - } - AssocItem::TypeAlias(id) => { - let item = &item_tree[id]; + fn collect_item( + &mut self, + item_tree: &ItemTree, + tree_id: TreeId, + container: ItemContainerId, + item: AssocItem, + ) { + match item { + AssocItem::Function(id) => { + let item = &item_tree[id]; - let def = TypeAliasLoc { container, id: ItemTreeId::new(tree_id, id) } - .intern(self.db); - self.items.push((item.name.clone(), def.into())); - } - AssocItem::MacroCall(call) => { - if let Some(root) = self.db.parse_or_expand(self.expander.current_file_id()) { - let call = &item_tree[call]; - - let ast_id_map = self.db.ast_id_map(self.expander.current_file_id()); - let call = ast_id_map.get(call.ast_id).to_node(&root); - let _cx = - stdx::panic_context::enter(format!("collect_items MacroCall: {call}")); - let res = self.expander.enter_expand::(self.db, call); - - if let Ok(ExpandResult { value: Some((mark, _)), .. }) = res { - self.collect_macro_items(mark); - } + let def = + FunctionLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db); + self.items.push((item.name.clone(), def.into())); + } + AssocItem::Const(id) => { + let item = &item_tree[id]; + let Some(name) = item.name.clone() else { return }; + let def = ConstLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db); + self.items.push((name, def.into())); + } + AssocItem::TypeAlias(id) => { + let item = &item_tree[id]; + + let def = + TypeAliasLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db); + self.items.push((item.name.clone(), def.into())); + } + AssocItem::MacroCall(call) => { + let file_id = self.expander.current_file_id(); + let MacroCall { ast_id, expand_to, ref path } = item_tree[call]; + let module = self.expander.module.local_id; + + let resolver = |path| { + self.def_map + .resolve_path( + self.db, + module, + &path, + crate::item_scope::BuiltinShadowMode::Other, + Some(MacroSubNs::Bang), + ) + .0 + .take_macros() + .map(|it| macro_id_to_def_id(self.db, it)) + }; + match macro_call_as_call_id( + self.db.upcast(), + &AstIdWithPath::new(file_id, ast_id, Clone::clone(path)), + expand_to, + self.expander.module.krate(), + resolver, + ) { + Ok(Some(call_id)) => { + let res = + self.expander.enter_expand_id::(self.db, call_id); + self.collect_macro_items(res, &|| hir_expand::MacroCallKind::FnLike { + ast_id: InFile::new(file_id, ast_id), + expand_to: hir_expand::ExpandTo::Items, + }); + } + Ok(None) => (), + Err(_) => { + self.diagnostics.push(DefDiagnostic::unresolved_macro_call( + self.module_id.local_id, + MacroCallKind::FnLike { + ast_id: InFile::new(file_id, ast_id), + expand_to, + }, + Clone::clone(path), + )); } } } } } - fn collect_macro_items(&mut self, mark: Mark) { + fn collect_macro_items( + &mut self, + ExpandResult { value, err }: ExpandResult)>>, + error_call_kind: &dyn Fn() -> hir_expand::MacroCallKind, + ) { + let Some((mark, parse)) = value else { return }; + + if let Some(err) = err { + let diag = match err { + // why is this reported here? + hir_expand::ExpandError::UnresolvedProcMacro(krate) => { + DefDiagnostic::unresolved_proc_macro( + self.module_id.local_id, + error_call_kind(), + krate, + ) + } + _ => DefDiagnostic::macro_error( + self.module_id.local_id, + error_call_kind(), + err.to_string(), + ), + }; + self.diagnostics.push(diag); + } + if let errors @ [_, ..] = parse.errors() { + self.diagnostics.push(DefDiagnostic::macro_expansion_parse_error( + self.module_id.local_id, + error_call_kind(), + errors.into(), + )); + } + let tree_id = item_tree::TreeId::new(self.expander.current_file_id(), None); let item_tree = tree_id.item_tree(self.db); let iter: SmallVec<[_; 2]> = @@ -670,3 +753,10 @@ impl<'a> AssocItemCollector<'a> { self.expander.exit(self.db, mark); } } + +fn trait_vis(db: &dyn DefDatabase, trait_id: TraitId) -> RawVisibility { + let ItemLoc { id: tree_id, .. } = trait_id.lookup(db); + let item_tree = tree_id.item_tree(db); + let tr_def = &item_tree[tree_id.value]; + item_tree[tr_def.visibility].clone() +} diff --git a/crates/hir-def/src/adt.rs b/crates/hir-def/src/data/adt.rs similarity index 89% rename from crates/hir-def/src/adt.rs rename to crates/hir-def/src/data/adt.rs index b336f59ffee31..6db5abccc9210 100644 --- a/crates/hir-def/src/adt.rs +++ b/crates/hir-def/src/data/adt.rs @@ -1,8 +1,7 @@ //! Defines hir-level representation of structs, enums and unions -use std::sync::Arc; - use base_db::CrateId; +use bitflags::bitflags; use cfg::CfgOptions; use either::Either; @@ -12,15 +11,17 @@ use hir_expand::{ }; use intern::Interned; use la_arena::{Arena, ArenaMap}; -use rustc_abi::{Integer, IntegerType}; +use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions}; use syntax::ast::{self, HasName, HasVisibility}; +use triomphe::Arc; use crate::{ - body::{CfgExpander, LowerCtx}, builtin_type::{BuiltinInt, BuiltinUint}, db::DefDatabase, + expander::CfgExpander, item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId}, - layout::{Align, ReprFlags, ReprOptions}, + lang_item::LangItem, + lower::LowerCtx, nameres::diagnostics::DefDiagnostic, src::HasChildSource, src::HasSource, @@ -39,8 +40,27 @@ pub struct StructData { pub variant_data: Arc, pub repr: Option, pub visibility: RawVisibility, - pub rustc_has_incoherent_inherent_impls: bool, - pub fundamental: bool, + pub flags: StructFlags, +} + +bitflags! { +#[derive(Debug, Clone, PartialEq, Eq)] + pub struct StructFlags: u8 { + const NO_FLAGS = 0; + /// Indicates whether the struct is `PhantomData`. + const IS_PHANTOM_DATA = 1 << 2; + /// Indicates whether the struct has a `#[fundamental]` attribute. + const IS_FUNDAMENTAL = 1 << 3; + // FIXME: should this be a flag? + /// Indicates whether the struct has a `#[rustc_has_incoherent_inherent_impls]` attribute. + const IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL = 1 << 4; + /// Indicates whether this struct is `Box`. + const IS_BOX = 1 << 5; + /// Indicates whether this struct is `ManuallyDrop`. + const IS_MANUALLY_DROP = 1 << 6; + /// Indicates whether this struct is `UnsafeCell`. + const IS_UNSAFE_CELL = 1 << 7; + } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -174,10 +194,25 @@ impl StructData { let item_tree = loc.id.item_tree(db); let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone(); + let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()); - let rustc_has_incoherent_inherent_impls = - attrs.by_key("rustc_has_incoherent_inherent_impls").exists(); - let fundamental = attrs.by_key("fundamental").exists(); + + let mut flags = StructFlags::NO_FLAGS; + if attrs.by_key("rustc_has_incoherent_inherent_impls").exists() { + flags |= StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL; + } + if attrs.by_key("fundamental").exists() { + flags |= StructFlags::IS_FUNDAMENTAL; + } + if let Some(lang) = attrs.lang_item() { + match lang { + LangItem::PhantomData => flags |= StructFlags::IS_PHANTOM_DATA, + LangItem::OwnedBox => flags |= StructFlags::IS_BOX, + LangItem::ManuallyDrop => flags |= StructFlags::IS_MANUALLY_DROP, + LangItem::UnsafeCell => flags |= StructFlags::IS_UNSAFE_CELL, + _ => (), + } + } let strukt = &item_tree[loc.id.value]; let (variant_data, diagnostics) = lower_fields( @@ -196,8 +231,7 @@ impl StructData { variant_data: Arc::new(variant_data), repr, visibility: item_tree[strukt.visibility].clone(), - rustc_has_incoherent_inherent_impls, - fundamental, + flags, }), diagnostics.into(), ) @@ -218,9 +252,13 @@ impl StructData { let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone(); let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()); - let rustc_has_incoherent_inherent_impls = - attrs.by_key("rustc_has_incoherent_inherent_impls").exists(); - let fundamental = attrs.by_key("fundamental").exists(); + let mut flags = StructFlags::NO_FLAGS; + if attrs.by_key("rustc_has_incoherent_inherent_impls").exists() { + flags |= StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL; + } + if attrs.by_key("fundamental").exists() { + flags |= StructFlags::IS_FUNDAMENTAL; + } let union = &item_tree[loc.id.value]; let (variant_data, diagnostics) = lower_fields( @@ -239,8 +277,7 @@ impl StructData { variant_data: Arc::new(variant_data), repr, visibility: item_tree[union.visibility].clone(), - rustc_has_incoherent_inherent_impls, - fundamental, + flags, }), diagnostics.into(), ) @@ -436,7 +473,7 @@ fn lower_struct( trace: &mut Trace>, ast: &InFile, ) -> StructKind { - let ctx = LowerCtx::new(db, ast.file_id); + let ctx = LowerCtx::new(db, &expander.hygiene(), ast.file_id); match &ast.value { ast::StructKind::Tuple(fl) => { diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 9371fc14dd8a0..6d18e3f56cabc 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -1,32 +1,32 @@ //! Defines database & queries for name resolution. -use std::sync::Arc; - use base_db::{salsa, CrateId, SourceDatabase, Upcast}; use either::Either; use hir_expand::{db::ExpandDatabase, HirFileId}; use intern::Interned; use la_arena::ArenaMap; use syntax::{ast, AstPtr}; +use triomphe::Arc; use crate::{ - adt::{EnumData, StructData}, attr::{Attrs, AttrsWithOwner}, body::{scope::ExprScopes, Body, BodySourceMap}, data::{ + adt::{EnumData, StructData}, ConstData, FunctionData, ImplData, Macro2Data, MacroRulesData, ProcMacroData, StaticData, TraitAliasData, TraitData, TypeAliasData, }, generics::GenericParams, + hir::ExprId, import_map::ImportMap, item_tree::{AttrOwner, ItemTree}, lang_item::{LangItem, LangItemTarget, LangItems}, nameres::{diagnostics::DefDiagnostic, DefMap}, visibility::{self, Visibility}, - AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, ExternBlockId, - ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, - LocalFieldId, Macro2Id, Macro2Loc, MacroRulesId, MacroRulesLoc, ProcMacroId, ProcMacroLoc, - StaticId, StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, - TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, VariantId, + AnonymousConstId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, + EnumLoc, ExternBlockId, ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, + LocalEnumVariantId, LocalFieldId, Macro2Id, Macro2Loc, MacroRulesId, MacroRulesLoc, + ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitAliasId, + TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, VariantId, }; #[salsa::query_group(InternDatabaseStorage)] @@ -61,12 +61,14 @@ pub trait InternDatabase: SourceDatabase { fn intern_proc_macro(&self, loc: ProcMacroLoc) -> ProcMacroId; #[salsa::interned] fn intern_macro_rules(&self, loc: MacroRulesLoc) -> MacroRulesId; + #[salsa::interned] + fn intern_anonymous_const(&self, id: (DefWithBodyId, ExprId)) -> AnonymousConstId; } #[salsa::query_group(DefDatabaseStorage)] pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast { #[salsa::input] - fn enable_proc_attr_macros(&self) -> bool; + fn expand_proc_attr_macros(&self) -> bool; #[salsa::invoke(ItemTree::file_item_tree_query)] fn file_item_tree(&self, file_id: HirFileId) -> Arc; @@ -94,7 +96,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast Option>; + fn block_def_map(&self, block: BlockId) -> Arc; + + // region:data #[salsa::invoke(StructData::struct_data_query)] fn struct_data(&self, id: StructId) -> Arc; @@ -151,6 +155,8 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast Arc; + // endregion:data + #[salsa::invoke(Body::body_with_source_map_query)] fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc, Arc); @@ -163,6 +169,8 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast Interned; + // region:attrs + #[salsa::invoke(Attrs::variants_attrs_query)] fn variants_attrs(&self, def: EnumId) -> Arc>; @@ -182,10 +190,13 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast Arc, AstPtr>>>; #[salsa::invoke(AttrsWithOwner::attrs_query)] - fn attrs(&self, def: AttrDefId) -> AttrsWithOwner; + fn attrs(&self, def: AttrDefId) -> Attrs; - #[salsa::invoke(LangItems::crate_lang_items_query)] - fn crate_lang_items(&self, krate: CrateId) -> Arc; + #[salsa::transparent] + #[salsa::invoke(AttrsWithOwner::attrs_with_owner)] + fn attrs_with_owner(&self, def: AttrDefId) -> AttrsWithOwner; + + // endregion:attrs #[salsa::invoke(LangItems::lang_item_query)] fn lang_item(&self, start_crate: CrateId, item: LangItem) -> Option; @@ -193,6 +204,8 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast Arc; + // region:visibilities + #[salsa::invoke(visibility::field_visibilities_query)] fn field_visibilities(&self, var: VariantId) -> Arc>; @@ -203,9 +216,17 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast Visibility; + // endregion:visibilities + + #[salsa::invoke(LangItems::crate_lang_items_query)] + fn crate_lang_items(&self, krate: CrateId) -> Arc; + #[salsa::transparent] fn crate_limits(&self, crate_id: CrateId) -> CrateLimits; + #[salsa::transparent] + fn recursion_limit(&self, crate_id: CrateId) -> u32; + fn crate_supports_no_std(&self, crate_id: CrateId) -> bool; } @@ -228,6 +249,10 @@ fn crate_limits(db: &dyn DefDatabase, crate_id: CrateId) -> CrateLimits { } } +fn recursion_limit(db: &dyn DefDatabase, crate_id: CrateId) -> u32 { + db.crate_limits(crate_id).recursion_limit +} + fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: CrateId) -> bool { let file = db.crate_graph()[crate_id].root_file_id; let item_tree = db.file_item_tree(file.into()); diff --git a/crates/hir-def/src/dyn_map.rs b/crates/hir-def/src/dyn_map.rs index 166aa04da044f..63138aa6ad78f 100644 --- a/crates/hir-def/src/dyn_map.rs +++ b/crates/hir-def/src/dyn_map.rs @@ -21,6 +21,8 @@ //! //! This is a work of fiction. Any similarities to Kotlin's `BindingContext` are //! a coincidence. +pub mod keys; + use std::{ hash::Hash, marker::PhantomData, diff --git a/crates/hir-def/src/keys.rs b/crates/hir-def/src/dyn_map/keys.rs similarity index 100% rename from crates/hir-def/src/keys.rs rename to crates/hir-def/src/dyn_map/keys.rs diff --git a/crates/hir-def/src/expander.rs b/crates/hir-def/src/expander.rs new file mode 100644 index 0000000000000..34ed1e72f2001 --- /dev/null +++ b/crates/hir-def/src/expander.rs @@ -0,0 +1,211 @@ +//! Macro expansion utilities. + +use base_db::CrateId; +use cfg::CfgOptions; +use drop_bomb::DropBomb; +use hir_expand::{ + attrs::RawAttrs, hygiene::Hygiene, mod_path::ModPath, ExpandError, ExpandResult, HirFileId, + InFile, MacroCallId, UnresolvedMacro, +}; +use limit::Limit; +use syntax::{ast, Parse, SyntaxNode}; + +use crate::{ + attr::Attrs, db::DefDatabase, lower::LowerCtx, macro_id_to_def_id, path::Path, AsMacroCall, + MacroId, ModuleId, +}; + +/// A subset of Expander that only deals with cfg attributes. We only need it to +/// avoid cyclic queries in crate def map during enum processing. +#[derive(Debug)] +pub(crate) struct CfgExpander { + cfg_options: CfgOptions, + hygiene: Hygiene, + krate: CrateId, +} + +#[derive(Debug)] +pub struct Expander { + cfg_expander: CfgExpander, + pub(crate) current_file_id: HirFileId, + pub(crate) module: ModuleId, + /// `recursion_depth == usize::MAX` indicates that the recursion limit has been reached. + recursion_depth: u32, + recursion_limit: Limit, +} + +impl CfgExpander { + pub(crate) fn new( + db: &dyn DefDatabase, + current_file_id: HirFileId, + krate: CrateId, + ) -> CfgExpander { + let hygiene = Hygiene::new(db.upcast(), current_file_id); + let cfg_options = db.crate_graph()[krate].cfg_options.clone(); + CfgExpander { cfg_options, hygiene, krate } + } + + pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs { + Attrs::filter(db, self.krate, RawAttrs::new(db.upcast(), owner, &self.hygiene)) + } + + pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> bool { + let attrs = self.parse_attrs(db, owner); + attrs.is_cfg_enabled(&self.cfg_options) + } + + pub(crate) fn hygiene(&self) -> &Hygiene { + &self.hygiene + } +} + +impl Expander { + pub fn new(db: &dyn DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander { + let cfg_expander = CfgExpander::new(db, current_file_id, module.krate); + let recursion_limit = db.recursion_limit(module.krate); + #[cfg(not(test))] + let recursion_limit = Limit::new(recursion_limit as usize); + // Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug + #[cfg(test)] + let recursion_limit = Limit::new(std::cmp::min(32, recursion_limit as usize)); + Expander { cfg_expander, current_file_id, module, recursion_depth: 0, recursion_limit } + } + + pub fn enter_expand( + &mut self, + db: &dyn DefDatabase, + macro_call: ast::MacroCall, + resolver: impl Fn(ModPath) -> Option, + ) -> Result)>>, UnresolvedMacro> { + // FIXME: within_limit should support this, instead of us having to extract the error + let mut unresolved_macro_err = None; + + let result = self.within_limit(db, |this| { + let macro_call = InFile::new(this.current_file_id, ¯o_call); + match macro_call.as_call_id_with_errors(db.upcast(), this.module.krate(), |path| { + resolver(path).map(|it| macro_id_to_def_id(db, it)) + }) { + Ok(call_id) => call_id, + Err(resolve_err) => { + unresolved_macro_err = Some(resolve_err); + ExpandResult { value: None, err: None } + } + } + }); + + if let Some(err) = unresolved_macro_err { + Err(err) + } else { + Ok(result) + } + } + + pub fn enter_expand_id( + &mut self, + db: &dyn DefDatabase, + call_id: MacroCallId, + ) -> ExpandResult)>> { + self.within_limit(db, |_this| ExpandResult::ok(Some(call_id))) + } + + fn enter_expand_inner( + db: &dyn DefDatabase, + call_id: MacroCallId, + error: Option, + ) -> ExpandResult>>> { + let file_id = call_id.as_file(); + let ExpandResult { value, err } = db.parse_or_expand_with_err(file_id); + + ExpandResult { value: Some(InFile::new(file_id, value)), err: error.or(err) } + } + + pub fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { + self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); + self.current_file_id = mark.file_id; + if self.recursion_depth == u32::MAX { + // Recursion limit has been reached somewhere in the macro expansion tree. Reset the + // depth only when we get out of the tree. + if !self.current_file_id.is_macro() { + self.recursion_depth = 0; + } + } else { + self.recursion_depth -= 1; + } + mark.bomb.defuse(); + } + + pub fn ctx<'a>(&self, db: &'a dyn DefDatabase) -> LowerCtx<'a> { + LowerCtx::new(db, &self.cfg_expander.hygiene, self.current_file_id) + } + + pub(crate) fn to_source(&self, value: T) -> InFile { + InFile { file_id: self.current_file_id, value } + } + + pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs { + self.cfg_expander.parse_attrs(db, owner) + } + + pub(crate) fn cfg_options(&self) -> &CfgOptions { + &self.cfg_expander.cfg_options + } + + pub fn current_file_id(&self) -> HirFileId { + self.current_file_id + } + + pub(crate) fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option { + let ctx = LowerCtx::with_hygiene(db, &self.cfg_expander.hygiene); + Path::from_src(path, &ctx) + } + + fn within_limit( + &mut self, + db: &dyn DefDatabase, + op: F, + ) -> ExpandResult)>> + where + F: FnOnce(&mut Self) -> ExpandResult>, + { + if self.recursion_depth == u32::MAX { + // Recursion limit has been reached somewhere in the macro expansion tree. We should + // stop expanding other macro calls in this tree, or else this may result in + // exponential number of macro expansions, leading to a hang. + // + // The overflow error should have been reported when it occurred (see the next branch), + // so don't return overflow error here to avoid diagnostics duplication. + cov_mark::hit!(overflow_but_not_me); + return ExpandResult::only_err(ExpandError::RecursionOverflowPoisoned); + } else if self.recursion_limit.check(self.recursion_depth as usize + 1).is_err() { + self.recursion_depth = u32::MAX; + cov_mark::hit!(your_stack_belongs_to_me); + return ExpandResult::only_err(ExpandError::Other( + "reached recursion limit during macro expansion".into(), + )); + } + + let ExpandResult { value, err } = op(self); + let Some(call_id) = value else { + return ExpandResult { value: None, err }; + }; + + Self::enter_expand_inner(db, call_id, err).map(|value| { + value.and_then(|InFile { file_id, value }| { + let parse = value.cast::()?; + + self.recursion_depth += 1; + self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id); + let old_file_id = std::mem::replace(&mut self.current_file_id, file_id); + let mark = + Mark { file_id: old_file_id, bomb: DropBomb::new("expansion mark dropped") }; + Some((mark, parse)) + }) + }) + } +} + +#[derive(Debug)] +pub struct Mark { + file_id: HirFileId, + bomb: DropBomb, +} diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs index 3f43923208371..e8cc2eab4617e 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -42,7 +42,7 @@ const MAX_PATH_LEN: usize = 15; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum PrefixKind { /// Causes paths to always start with either `self`, `super`, `crate` or a crate-name. - /// This is the same as plain, just that paths will start with `self` iprepended f the path + /// This is the same as plain, just that paths will start with `self` prepended if the path /// starts with an identifier that is not a crate. BySelf, /// Causes paths to ignore imports in the local module. @@ -81,7 +81,7 @@ fn find_path_inner( } let def_map = from.def_map(db); - let crate_root = def_map.crate_root(db); + let crate_root = def_map.crate_root(); // - if the item is a module, jump straight to module search if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item { let mut visited_modules = FxHashSet::default(); @@ -183,7 +183,7 @@ fn find_path_for_module( // - if the item is the crate root of a dependency crate, return the name from the extern prelude let root_def_map = crate_root.def_map(db); - for (name, &def_id) in root_def_map.extern_prelude() { + for (name, def_id) in root_def_map.extern_prelude() { if module_id == def_id { let name = scope_name.unwrap_or_else(|| name.clone()); @@ -454,7 +454,7 @@ fn find_local_import_locations( worklist.push(ancestor); } - let def_map = def_map.crate_root(db).def_map(db); + let def_map = def_map.crate_root().def_map(db); let mut seen: FxHashSet<_> = FxHashSet::default(); @@ -543,6 +543,7 @@ mod tests { module.local_id, &mod_path, crate::item_scope::BuiltinShadowMode::Module, + None, ) .0 .take_types() diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs index e4912fa8a64a4..f19c3f028f42f 100644 --- a/crates/hir-def/src/generics.rs +++ b/crates/hir-def/src/generics.rs @@ -12,16 +12,17 @@ use hir_expand::{ use intern::Interned; use la_arena::{Arena, ArenaMap, Idx}; use once_cell::unsync::Lazy; -use std::ops::DerefMut; use stdx::impl_from; use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds}; +use triomphe::Arc; use crate::{ - body::{Expander, LowerCtx}, child_by_source::ChildBySource, db::DefDatabase, - dyn_map::DynMap, - keys, + dyn_map::{keys, DynMap}, + expander::Expander, + lower::LowerCtx, + nameres::{DefMap, MacroSubNs}, src::{HasChildSource, HasSource}, type_ref::{LifetimeRef, TypeBound, TypeRef}, AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId, @@ -153,7 +154,6 @@ impl GenericParams { def: GenericDefId, ) -> Interned { let _p = profile::span("generic_params_query"); - macro_rules! id_to_generics { ($id:ident) => {{ let id = $id.lookup(db).id; @@ -176,8 +176,10 @@ impl GenericParams { // Don't create an `Expander` nor call `loc.source(db)` if not needed since this // causes a reparse after the `ItemTree` has been created. - let mut expander = Lazy::new(|| Expander::new(db, loc.source(db).file_id, module)); - for (_, param) in &func_data.params { + let mut expander = Lazy::new(|| { + (module.def_map(db), Expander::new(db, loc.source(db).file_id, module)) + }); + for param in &func_data.params { generic_params.fill_implicit_impl_trait_args(db, &mut expander, param); } @@ -329,7 +331,7 @@ impl GenericParams { pub(crate) fn fill_implicit_impl_trait_args( &mut self, db: &dyn DefDatabase, - expander: &mut impl DerefMut, + exp: &mut Lazy<(Arc, Expander), impl FnOnce() -> (Arc, Expander)>, type_ref: &TypeRef, ) { type_ref.walk(&mut |type_ref| { @@ -349,14 +351,28 @@ impl GenericParams { } if let TypeRef::Macro(mc) = type_ref { let macro_call = mc.to_node(db.upcast()); - match expander.enter_expand::(db, macro_call) { - Ok(ExpandResult { value: Some((mark, expanded)), .. }) => { - let ctx = LowerCtx::new(db, expander.current_file_id()); - let type_ref = TypeRef::from_ast(&ctx, expanded); - self.fill_implicit_impl_trait_args(db, expander, &type_ref); - expander.exit(db, mark); - } - _ => {} + let (def_map, expander) = &mut **exp; + + let module = expander.module.local_id; + let resolver = |path| { + def_map + .resolve_path( + db, + module, + &path, + crate::item_scope::BuiltinShadowMode::Other, + Some(MacroSubNs::Bang), + ) + .0 + .take_macros() + }; + if let Ok(ExpandResult { value: Some((mark, expanded)), .. }) = + expander.enter_expand(db, macro_call, resolver) + { + let ctx = expander.ctx(db); + let type_ref = TypeRef::from_ast(&ctx, expanded.tree()); + self.fill_implicit_impl_trait_args(db, &mut *exp, &type_ref); + exp.1.exit(db, mark); } } }); diff --git a/crates/hir-def/src/expr.rs b/crates/hir-def/src/hir.rs similarity index 76% rename from crates/hir-def/src/expr.rs rename to crates/hir-def/src/hir.rs index 19fa6b25419e1..4ad8a7aa8eb12 100644 --- a/crates/hir-def/src/expr.rs +++ b/crates/hir-def/src/hir.rs @@ -12,26 +12,29 @@ //! //! See also a neighboring `body` module. +pub mod type_ref; + use std::fmt; use hir_expand::name::Name; use intern::Interned; use la_arena::{Idx, RawIdx}; use smallvec::SmallVec; +use syntax::ast; use crate::{ builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, path::{GenericArgs, Path}, type_ref::{Mutability, Rawness, TypeRef}, - BlockId, + AnonymousConstId, BlockId, }; pub use syntax::ast::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp}; -pub type ExprId = Idx; - pub type BindingId = Idx; +pub type ExprId = Idx; + /// FIXME: this is a hacky function which should be removed pub(crate) fn dummy_expr_id() -> ExprId { ExprId::from_raw(RawIdx::from(u32::MAX)) @@ -82,6 +85,7 @@ impl fmt::Display for FloatTypeWrapper { pub enum Literal { String(Box), ByteString(Box<[u8]>), + CString(Box), Char(char), Bool(bool), Int(i128, Option), @@ -92,6 +96,66 @@ pub enum Literal { Float(FloatTypeWrapper, Option), } +#[derive(Debug, Clone, Eq, PartialEq)] +/// Used in range patterns. +pub enum LiteralOrConst { + Literal(Literal), + Const(Path), +} + +impl Literal { + pub fn negate(self) -> Option { + if let Literal::Int(i, k) = self { + Some(Literal::Int(-i, k)) + } else { + None + } + } +} + +impl From for Literal { + fn from(ast_lit_kind: ast::LiteralKind) -> Self { + use ast::LiteralKind; + match ast_lit_kind { + // FIXME: these should have actual values filled in, but unsure on perf impact + LiteralKind::IntNumber(lit) => { + if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) { + Literal::Float( + FloatTypeWrapper::new(lit.float_value().unwrap_or(Default::default())), + builtin, + ) + } else if let builtin @ Some(_) = lit.suffix().and_then(BuiltinUint::from_suffix) { + Literal::Uint(lit.value().unwrap_or(0), builtin) + } else { + let builtin = lit.suffix().and_then(BuiltinInt::from_suffix); + Literal::Int(lit.value().unwrap_or(0) as i128, builtin) + } + } + LiteralKind::FloatNumber(lit) => { + let ty = lit.suffix().and_then(BuiltinFloat::from_suffix); + Literal::Float(FloatTypeWrapper::new(lit.value().unwrap_or(Default::default())), ty) + } + LiteralKind::ByteString(bs) => { + let text = bs.value().map(Box::from).unwrap_or_else(Default::default); + Literal::ByteString(text) + } + LiteralKind::String(s) => { + let text = s.value().map(Box::from).unwrap_or_else(Default::default); + Literal::String(text) + } + LiteralKind::CString(s) => { + let text = s.value().map(Box::from).unwrap_or_else(Default::default); + Literal::CString(text) + } + LiteralKind::Byte(b) => { + Literal::Uint(b.value().unwrap_or_default() as u128, Some(BuiltinUint::U8)) + } + LiteralKind::Char(c) => Literal::Char(c.value().unwrap_or_default()), + LiteralKind::Bool(val) => Literal::Bool(val), + } + } +} + #[derive(Debug, Clone, Eq, PartialEq)] pub enum Expr { /// This is produced if the syntax tree does not have a required expression piece. @@ -107,28 +171,19 @@ pub enum Expr { expr: ExprId, }, Block { - id: BlockId, + id: Option, statements: Box<[Statement]>, tail: Option, label: Option, }, - TryBlock { - id: BlockId, - statements: Box<[Statement]>, - tail: Option, - }, Async { - id: BlockId, - statements: Box<[Statement]>, - tail: Option, - }, - Const { - id: BlockId, + id: Option, statements: Box<[Statement]>, tail: Option, }, + Const(AnonymousConstId), Unsafe { - id: BlockId, + id: Option, statements: Box<[Statement]>, tail: Option, }, @@ -141,12 +196,6 @@ pub enum Expr { body: ExprId, label: Option, }, - For { - iterable: ExprId, - pat: PatId, - body: ExprId, - label: Option, - }, Call { callee: ExprId, args: Box<[ExprId]>, @@ -163,11 +212,11 @@ pub enum Expr { arms: Box<[MatchArm]>, }, Continue { - label: Option, + label: Option, }, Break { expr: Option, - label: Option, + label: Option, }, Return { expr: Option, @@ -192,9 +241,6 @@ pub enum Expr { Await { expr: ExprId, }, - Try { - expr: ExprId, - }, Cast { expr: ExprId, type_ref: Interned, @@ -231,6 +277,7 @@ pub enum Expr { ret_type: Option>, body: ExprId, closure_kind: ClosureKind, + capture_by: CaptureBy, }, Tuple { exprs: Box<[ExprId]>, @@ -248,6 +295,14 @@ pub enum ClosureKind { Async, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CaptureBy { + /// `move |x| y + x`. + Value, + /// `move` keyword was not specified. + Ref, +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Movability { Static, @@ -302,11 +357,10 @@ impl Expr { Expr::Let { expr, .. } => { f(*expr); } + Expr::Const(_) => (), Expr::Block { statements, tail, .. } - | Expr::TryBlock { statements, tail, .. } | Expr::Unsafe { statements, tail, .. } - | Expr::Async { statements, tail, .. } - | Expr::Const { statements, tail, .. } => { + | Expr::Async { statements, tail, .. } => { for stmt in statements.iter() { match stmt { Statement::Let { initializer, else_branch, .. } => { @@ -329,10 +383,6 @@ impl Expr { f(*condition); f(*body); } - Expr::For { iterable, body, .. } => { - f(*iterable); - f(*body); - } Expr::Call { callee, args, .. } => { f(*callee); args.iter().copied().for_each(f); @@ -383,7 +433,6 @@ impl Expr { } Expr::Field { expr, .. } | Expr::Await { expr } - | Expr::Try { expr } | Expr::Cast { expr, .. } | Expr::Ref { expr, .. } | Expr::UnaryOp { expr, .. } @@ -437,11 +486,38 @@ impl BindingAnnotation { } } +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum BindingProblems { + /// https://doc.rust-lang.org/stable/error_codes/E0416.html + BoundMoreThanOnce, + /// https://doc.rust-lang.org/stable/error_codes/E0409.html + BoundInconsistently, + /// https://doc.rust-lang.org/stable/error_codes/E0408.html + NotBoundAcrossAll, +} + #[derive(Debug, Clone, Eq, PartialEq)] pub struct Binding { pub name: Name, pub mode: BindingAnnotation, pub definitions: SmallVec<[PatId; 1]>, + /// Id of the closure/generator that owns this binding. If it is owned by the + /// top level expression, this field would be `None`. + pub owner: Option, + pub problems: Option, +} + +impl Binding { + pub fn is_upvar(&self, relative_to: ExprId) -> bool { + match self.owner { + Some(x) => { + // We assign expression ids in a way that outer closures will receive + // a lower id + x.into_raw() < relative_to.into_raw() + } + None => true, + } + } } #[derive(Debug, Clone, Eq, PartialEq)] @@ -458,7 +534,7 @@ pub enum Pat { Tuple { args: Box<[PatId]>, ellipsis: Option }, Or(Box<[PatId]>), Record { path: Option>, args: Box<[RecordFieldPat]>, ellipsis: bool }, - Range { start: ExprId, end: ExprId }, + Range { start: Option>, end: Option> }, Slice { prefix: Box<[PatId]>, slice: Option, suffix: Box<[PatId]> }, Path(Box), Lit(ExprId), diff --git a/crates/hir-def/src/type_ref.rs b/crates/hir-def/src/hir/type_ref.rs similarity index 96% rename from crates/hir-def/src/type_ref.rs rename to crates/hir-def/src/hir/type_ref.rs index 8e30f429a9f80..0573c9a6f8af4 100644 --- a/crates/hir-def/src/type_ref.rs +++ b/crates/hir-def/src/hir/type_ref.rs @@ -1,9 +1,11 @@ //! HIR for references to types. Paths in these are not yet resolved. They can //! be directly created from an ast::TypeRef, without further queries. +use core::fmt; use std::fmt::Write; use hir_expand::{ + db::ExpandDatabase, name::{AsName, Name}, AstId, }; @@ -11,9 +13,9 @@ use intern::Interned; use syntax::ast::{self, HasName}; use crate::{ - body::LowerCtx, builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, - expr::Literal, + hir::Literal, + lower::LowerCtx, path::Path, }; @@ -383,15 +385,6 @@ pub enum ConstRefOrPath { Path(Name), } -impl std::fmt::Display for ConstRefOrPath { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - ConstRefOrPath::Scalar(s) => s.fmt(f), - ConstRefOrPath::Path(n) => n.fmt(f), - } - } -} - impl ConstRefOrPath { pub(crate) fn from_expr_opt(expr: Option) -> Self { match expr { @@ -400,6 +393,19 @@ impl ConstRefOrPath { } } + pub fn display<'a>(&'a self, db: &'a dyn ExpandDatabase) -> impl fmt::Display + 'a { + struct Display<'a>(&'a dyn ExpandDatabase, &'a ConstRefOrPath); + impl fmt::Display for Display<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.1 { + ConstRefOrPath::Scalar(s) => s.fmt(f), + ConstRefOrPath::Path(n) => n.display(self.0).fmt(f), + } + } + } + Display(db, self) + } + // FIXME: as per the comments on `TypeRef::Array`, this evaluation should not happen at this // parse stage. fn from_expr(expr: ast::Expr) -> Self { diff --git a/crates/hir-def/src/import_map.rs b/crates/hir-def/src/import_map.rs index 4f1f6000db0e3..48532655e04b1 100644 --- a/crates/hir-def/src/import_map.rs +++ b/crates/hir-def/src/import_map.rs @@ -1,6 +1,6 @@ //! A map of all publicly exported items in a crate. -use std::{fmt, hash::BuildHasherDefault, sync::Arc}; +use std::{fmt, hash::BuildHasherDefault}; use base_db::CrateId; use fst::{self, Streamer}; @@ -8,10 +8,11 @@ use hir_expand::name::Name; use indexmap::{map::Entry, IndexMap}; use itertools::Itertools; use rustc_hash::{FxHashSet, FxHasher}; +use triomphe::Arc; use crate::{ - db::DefDatabase, item_scope::ItemInNs, visibility::Visibility, AssocItemId, ModuleDefId, - ModuleId, TraitId, + db::DefDatabase, item_scope::ItemInNs, nameres::DefMap, visibility::Visibility, AssocItemId, + ModuleDefId, ModuleId, TraitId, }; type FxIndexMap = IndexMap>; @@ -32,13 +33,23 @@ pub struct ImportPath { pub segments: Vec, } -impl fmt::Display for ImportPath { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.segments.iter().format("::"), f) +impl ImportPath { + pub fn display<'a>(&'a self, db: &'a dyn DefDatabase) -> impl fmt::Display + 'a { + struct Display<'a> { + db: &'a dyn DefDatabase, + path: &'a ImportPath, + } + impl fmt::Display for Display<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt( + &self.path.segments.iter().map(|it| it.display(self.db.upcast())).format("::"), + f, + ) + } + } + Display { db, path: self } } -} -impl ImportPath { fn len(&self) -> usize { self.segments.len() } @@ -75,7 +86,7 @@ impl ImportMap { let mut importables = import_map .map .iter() - .map(|(item, info)| (item, fst_path(&info.path))) + .map(|(item, info)| (item, fst_path(db, &info.path))) .collect::>(); importables.sort_by(|(_, fst_path), (_, fst_path2)| fst_path.cmp(fst_path2)); @@ -112,6 +123,25 @@ impl ImportMap { self.map.get(&item) } + #[cfg(test)] + fn fmt_for_test(&self, db: &dyn DefDatabase) -> String { + let mut importable_paths: Vec<_> = self + .map + .iter() + .map(|(item, info)| { + let ns = match item { + ItemInNs::Types(_) => "t", + ItemInNs::Values(_) => "v", + ItemInNs::Macros(_) => "m", + }; + format!("- {} ({ns})", info.path.display(db)) + }) + .collect(); + + importable_paths.sort(); + importable_paths.join("\n") + } + fn collect_trait_assoc_items( &mut self, db: &dyn DefDatabase, @@ -153,7 +183,7 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMap { // We look only into modules that are public(ly reexported), starting with the crate root. let empty = ImportPath { segments: vec![] }; - let root = def_map.module_id(def_map.root()); + let root = def_map.module_id(DefMap::ROOT); let mut worklist = vec![(root, empty)]; while let Some((module, mod_path)) = worklist.pop() { let ext_def_map; @@ -233,13 +263,10 @@ impl fmt::Debug for ImportMap { let mut importable_paths: Vec<_> = self .map .iter() - .map(|(item, info)| { - let ns = match item { - ItemInNs::Types(_) => "t", - ItemInNs::Values(_) => "v", - ItemInNs::Macros(_) => "m", - }; - format!("- {} ({ns})", info.path) + .map(|(item, _)| match item { + ItemInNs::Types(it) => format!("- {it:?} (t)",), + ItemInNs::Values(it) => format!("- {it:?} (v)",), + ItemInNs::Macros(it) => format!("- {it:?} (m)",), }) .collect(); @@ -248,9 +275,9 @@ impl fmt::Debug for ImportMap { } } -fn fst_path(path: &ImportPath) -> String { +fn fst_path(db: &dyn DefDatabase, path: &ImportPath) -> String { let _p = profile::span("fst_path"); - let mut s = path.to_string(); + let mut s = path.display(db).to_string(); s.make_ascii_lowercase(); s } @@ -343,7 +370,12 @@ impl Query { self } - fn import_matches(&self, import: &ImportInfo, enforce_lowercase: bool) -> bool { + fn import_matches( + &self, + db: &dyn DefDatabase, + import: &ImportInfo, + enforce_lowercase: bool, + ) -> bool { let _p = profile::span("import_map::Query::import_matches"); if import.is_trait_assoc_item { if self.exclude_import_kinds.contains(&ImportKind::AssociatedItem) { @@ -354,9 +386,9 @@ impl Query { } let mut input = if import.is_trait_assoc_item || self.name_only { - import.path.segments.last().unwrap().to_string() + import.path.segments.last().unwrap().display(db.upcast()).to_string() } else { - import.path.to_string() + import.path.display(db).to_string() }; if enforce_lowercase || !self.case_sensitive { input.make_ascii_lowercase(); @@ -421,25 +453,27 @@ pub fn search_dependencies( let importables = &import_map.importables[indexed_value.value as usize..]; let common_importable_data = &import_map.map[&importables[0]]; - if !query.import_matches(common_importable_data, true) { + if !query.import_matches(db, common_importable_data, true) { continue; } // Path shared by the importable items in this group. - let common_importables_path_fst = fst_path(&common_importable_data.path); + let common_importables_path_fst = fst_path(db, &common_importable_data.path); // Add the items from this `ModPath` group. Those are all subsequent items in // `importables` whose paths match `path`. let iter = importables .iter() .copied() - .take_while(|item| common_importables_path_fst == fst_path(&import_map.map[item].path)) + .take_while(|item| { + common_importables_path_fst == fst_path(db, &import_map.map[item].path) + }) .filter(|&item| match item_import_kind(item) { Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind), None => true, }) .filter(|item| { !query.case_sensitive // we've already checked the common importables path case-insensitively - || query.import_matches(&import_map.map[item], false) + || query.import_matches(db, &import_map.map[item], false) }); res.extend(iter); @@ -472,7 +506,7 @@ mod tests { use base_db::{fixture::WithFixture, SourceDatabase, Upcast}; use expect_test::{expect, Expect}; - use crate::{test_db::TestDB, ItemContainerId, Lookup}; + use crate::{db::DefDatabase, test_db::TestDB, ItemContainerId, Lookup}; use super::*; @@ -496,7 +530,7 @@ mod tests { let (path, mark) = match assoc_item_path(&db, &dependency_imports, dependency) { Some(assoc_item_path) => (assoc_item_path, "a"), None => ( - dependency_imports.path_of(dependency)?.to_string(), + dependency_imports.path_of(dependency)?.display(&db).to_string(), match dependency { ItemInNs::Types(ModuleDefId::FunctionId(_)) | ItemInNs::Values(ModuleDefId::FunctionId(_)) => "f", @@ -547,7 +581,11 @@ mod tests { None } })?; - return Some(format!("{}::{assoc_item_name}", dependency_imports.path_of(trait_)?)); + return Some(format!( + "{}::{}", + dependency_imports.path_of(trait_)?.display(db), + assoc_item_name.display(db.upcast()) + )); } None } @@ -587,7 +625,7 @@ mod tests { let map = db.import_map(krate); - Some(format!("{name}:\n{map:?}\n")) + Some(format!("{name}:\n{}\n", map.fmt_for_test(db.upcast()))) }) .sorted() .collect::(); diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index 991e447033fe7..3ed321d189d36 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -4,7 +4,7 @@ use std::collections::hash_map::Entry; use base_db::CrateId; -use hir_expand::{attrs::AttrId, name::Name, AstId, MacroCallId}; +use hir_expand::{attrs::AttrId, db::ExpandDatabase, name::Name, AstId, MacroCallId}; use itertools::Itertools; use once_cell::sync::Lazy; use profile::Count; @@ -358,12 +358,16 @@ impl ItemScope { } } - pub(crate) fn dump(&self, buf: &mut String) { + pub(crate) fn dump(&self, db: &dyn ExpandDatabase, buf: &mut String) { let mut entries: Vec<_> = self.resolutions().collect(); entries.sort_by_key(|(name, _)| name.clone()); for (name, def) in entries { - format_to!(buf, "{}:", name.map_or("_".to_string(), |name| name.to_string())); + format_to!( + buf, + "{}:", + name.map_or("_".to_string(), |name| name.display(db).to_string()) + ); if def.types.is_some() { buf.push_str(" t"); diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 9da5b2d47c877..590ed64af5d80 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -40,7 +40,6 @@ use std::{ hash::{Hash, Hasher}, marker::PhantomData, ops::Index, - sync::Arc, }; use ast::{AstNode, HasName, StructKind}; @@ -60,6 +59,7 @@ use rustc_hash::FxHashMap; use smallvec::SmallVec; use stdx::never; use syntax::{ast, match_ast, SyntaxKind}; +use triomphe::Arc; use crate::{ attr::Attrs, @@ -101,16 +101,14 @@ pub struct ItemTree { top_level: SmallVec<[ModItem; 1]>, attrs: FxHashMap, + // FIXME: Remove this indirection, an item tree is almost always non-empty? data: Option>, } impl ItemTree { pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc { let _p = profile::span("file_item_tree_query").detail(|| format!("{file_id:?}")); - let syntax = match db.parse_or_expand(file_id) { - Some(node) => node, - None => return Default::default(), - }; + let syntax = db.parse_or_expand(file_id); if never!(syntax.kind() == SyntaxKind::ERROR, "{:?} from {:?} {}", file_id, syntax, syntax) { // FIXME: not 100% sure why these crop up, but return an empty tree to avoid a panic @@ -169,8 +167,8 @@ impl ItemTree { Attrs::filter(db, krate, self.raw_attrs(of).clone()) } - pub fn pretty_print(&self) -> String { - pretty::print_item_tree(self) + pub fn pretty_print(&self, db: &dyn DefDatabase) -> String { + pretty::print_item_tree(db.upcast(), self) } fn data(&self) -> &ItemTreeData { @@ -600,19 +598,18 @@ pub struct Function { pub abi: Option>, pub params: IdxRange, pub ret_type: Interned, - pub async_ret_type: Option>, pub ast_id: FileAstId, pub(crate) flags: FnFlags, } #[derive(Debug, Clone, Eq, PartialEq)] pub enum Param { - Normal(Option, Interned), + Normal(Interned), Varargs, } bitflags::bitflags! { - #[derive(Default)] + #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] pub(crate) struct FnFlags: u8 { const HAS_SELF_PARAM = 1 << 0; const HAS_BODY = 1 << 1; diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index 77b186f8e3fe6..46633667ed3e2 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -1,6 +1,6 @@ //! AST -> `ItemTree` lowering code. -use std::{collections::hash_map::Entry, sync::Arc}; +use std::collections::hash_map::Entry; use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId}; use syntax::ast::{self, HasModuleItem, HasTypeBounds}; @@ -20,7 +20,7 @@ pub(super) struct Ctx<'a> { db: &'a dyn DefDatabase, tree: ItemTree, source_ast_id_map: Arc, - body_ctx: crate::body::LowerCtx<'a>, + body_ctx: crate::lower::LowerCtx<'a>, } impl<'a> Ctx<'a> { @@ -29,7 +29,7 @@ impl<'a> Ctx<'a> { db, tree: ItemTree::default(), source_ast_id_map: db.ast_id_map(file), - body_ctx: crate::body::LowerCtx::new(db, file), + body_ctx: crate::lower::LowerCtx::with_file_id(db, file), } } @@ -293,7 +293,7 @@ impl<'a> Ctx<'a> { } }; let ty = Interned::new(self_type); - let idx = self.data().params.alloc(Param::Normal(None, ty)); + let idx = self.data().params.alloc(Param::Normal(ty)); self.add_attrs( idx.into(), RawAttrs::new(self.db.upcast(), &self_param, self.hygiene()), @@ -306,19 +306,7 @@ impl<'a> Ctx<'a> { None => { let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty()); let ty = Interned::new(type_ref); - let mut pat = param.pat(); - // FIXME: This really shouldn't be here, in fact FunctionData/ItemTree's function shouldn't know about - // pattern names at all - let name = 'name: loop { - match pat { - Some(ast::Pat::RefPat(ref_pat)) => pat = ref_pat.pat(), - Some(ast::Pat::IdentPat(ident)) => { - break 'name ident.name().map(|it| it.as_name()) - } - _ => break 'name None, - } - }; - self.data().params.alloc(Param::Normal(name, ty)) + self.data().params.alloc(Param::Normal(ty)) } }; self.add_attrs(idx.into(), RawAttrs::new(self.db.upcast(), ¶m, self.hygiene())); @@ -336,13 +324,12 @@ impl<'a> Ctx<'a> { None => TypeRef::unit(), }; - let (ret_type, async_ret_type) = if func.async_token().is_some() { - let async_ret_type = ret_type.clone(); + let ret_type = if func.async_token().is_some() { let future_impl = desugar_future_path(ret_type); let ty_bound = Interned::new(TypeBound::Path(future_impl, TraitBoundModifier::None)); - (TypeRef::ImplTrait(vec![ty_bound]), Some(async_ret_type)) + TypeRef::ImplTrait(vec![ty_bound]) } else { - (ret_type, None) + ret_type }; let abi = func.abi().map(lower_abi); @@ -376,7 +363,6 @@ impl<'a> Ctx<'a> { abi, params, ret_type: Interned::new(ret_type), - async_ret_type: async_ret_type.map(Interned::new), ast_id, flags, }; diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs index 5f29997964b9c..e873316a578c0 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -2,6 +2,8 @@ use std::fmt::{self, Write}; +use hir_expand::db::ExpandDatabase; + use crate::{ generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget}, pretty::{print_path, print_type_bounds, print_type_ref}, @@ -10,8 +12,8 @@ use crate::{ use super::*; -pub(super) fn print_item_tree(tree: &ItemTree) -> String { - let mut p = Printer { tree, buf: String::new(), indent_level: 0, needs_indent: true }; +pub(super) fn print_item_tree(db: &dyn ExpandDatabase, tree: &ItemTree) -> String { + let mut p = Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true }; if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) { p.print_attrs(attrs, true); @@ -43,6 +45,7 @@ macro_rules! wln { } struct Printer<'a> { + db: &'a dyn ExpandDatabase, tree: &'a ItemTree, buf: String, indent_level: usize, @@ -88,7 +91,7 @@ impl<'a> Printer<'a> { self, "#{}[{}{}]", inner, - attr.path, + attr.path.display(self.db), attr.input.as_ref().map(|it| it.to_string()).unwrap_or_default(), ); } @@ -102,7 +105,7 @@ impl<'a> Printer<'a> { fn print_visibility(&mut self, vis: RawVisibilityId) { match &self.tree[vis] { - RawVisibility::Module(path) => w!(self, "pub({}) ", path), + RawVisibility::Module(path) => w!(self, "pub({}) ", path.display(self.db)), RawVisibility::Public => w!(self, "pub "), }; } @@ -117,7 +120,7 @@ impl<'a> Printer<'a> { let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field]; this.print_attrs_of(field); this.print_visibility(*visibility); - w!(this, "{}: ", name); + w!(this, "{}: ", name.display(self.db)); this.print_type_ref(type_ref); wln!(this, ","); } @@ -131,7 +134,7 @@ impl<'a> Printer<'a> { let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field]; this.print_attrs_of(field); this.print_visibility(*visibility); - w!(this, "{}: ", name); + w!(this, "{}: ", name.display(self.db)); this.print_type_ref(type_ref); wln!(this, ","); } @@ -164,20 +167,20 @@ impl<'a> Printer<'a> { fn print_use_tree(&mut self, use_tree: &UseTree) { match &use_tree.kind { UseTreeKind::Single { path, alias } => { - w!(self, "{}", path); + w!(self, "{}", path.display(self.db)); if let Some(alias) = alias { w!(self, " as {}", alias); } } UseTreeKind::Glob { path } => { if let Some(path) = path { - w!(self, "{}::", path); + w!(self, "{}::", path.display(self.db)); } w!(self, "*"); } UseTreeKind::Prefixed { prefix, list } => { if let Some(prefix) = prefix { - w!(self, "{}::", prefix); + w!(self, "{}::", prefix.display(self.db)); } w!(self, "{{"); for (i, tree) in list.iter().enumerate() { @@ -205,7 +208,7 @@ impl<'a> Printer<'a> { ModItem::ExternCrate(it) => { let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it]; self.print_visibility(*visibility); - w!(self, "extern crate {}", name); + w!(self, "extern crate {}", name.display(self.db)); if let Some(alias) = alias { w!(self, " as {}", alias); } @@ -233,7 +236,6 @@ impl<'a> Printer<'a> { abi, params, ret_type, - async_ret_type: _, ast_id: _, flags, } = &self.tree[it]; @@ -253,26 +255,20 @@ impl<'a> Printer<'a> { if let Some(abi) = abi { w!(self, "extern \"{}\" ", abi); } - w!(self, "fn {}", name); + w!(self, "fn {}", name.display(self.db)); self.print_generic_params(explicit_generic_params); w!(self, "("); if !params.is_empty() { self.indented(|this| { - for (i, param) in params.clone().enumerate() { + for param in params.clone() { this.print_attrs_of(param); match &this.tree[param] { - Param::Normal(name, ty) => { - match name { - Some(name) => w!(this, "{}: ", name), - None => w!(this, "_: "), + Param::Normal(ty) => { + if flags.contains(FnFlags::HAS_SELF_PARAM) { + w!(this, "self: "); } this.print_type_ref(ty); - w!(this, ","); - if flags.contains(FnFlags::HAS_SELF_PARAM) && i == 0 { - wln!(this, " // self"); - } else { - wln!(this); - } + wln!(this, ","); } Param::Varargs => { wln!(this, "..."); @@ -293,7 +289,7 @@ impl<'a> Printer<'a> { ModItem::Struct(it) => { let Struct { visibility, name, fields, generic_params, ast_id: _ } = &self.tree[it]; self.print_visibility(*visibility); - w!(self, "struct {}", name); + w!(self, "struct {}", name.display(self.db)); self.print_generic_params(generic_params); self.print_fields_and_where_clause(fields, generic_params); if matches!(fields, Fields::Record(_)) { @@ -305,7 +301,7 @@ impl<'a> Printer<'a> { ModItem::Union(it) => { let Union { name, visibility, fields, generic_params, ast_id: _ } = &self.tree[it]; self.print_visibility(*visibility); - w!(self, "union {}", name); + w!(self, "union {}", name.display(self.db)); self.print_generic_params(generic_params); self.print_fields_and_where_clause(fields, generic_params); if matches!(fields, Fields::Record(_)) { @@ -317,14 +313,14 @@ impl<'a> Printer<'a> { ModItem::Enum(it) => { let Enum { name, visibility, variants, generic_params, ast_id: _ } = &self.tree[it]; self.print_visibility(*visibility); - w!(self, "enum {}", name); + w!(self, "enum {}", name.display(self.db)); self.print_generic_params(generic_params); self.print_where_clause_and_opening_brace(generic_params); self.indented(|this| { for variant in variants.clone() { let Variant { name, fields, ast_id: _ } = &this.tree[variant]; this.print_attrs_of(variant); - w!(this, "{}", name); + w!(this, "{}", name.display(self.db)); this.print_fields(fields); wln!(this, ","); } @@ -336,7 +332,7 @@ impl<'a> Printer<'a> { self.print_visibility(*visibility); w!(self, "const "); match name { - Some(name) => w!(self, "{}", name), + Some(name) => w!(self, "{}", name.display(self.db)), None => w!(self, "_"), } w!(self, ": "); @@ -350,7 +346,7 @@ impl<'a> Printer<'a> { if *mutable { w!(self, "mut "); } - w!(self, "{}: ", name); + w!(self, "{}: ", name.display(self.db)); self.print_type_ref(type_ref); w!(self, " = _;"); wln!(self); @@ -372,7 +368,7 @@ impl<'a> Printer<'a> { if *is_auto { w!(self, "auto "); } - w!(self, "trait {}", name); + w!(self, "trait {}", name.display(self.db)); self.print_generic_params(generic_params); self.print_where_clause_and_opening_brace(generic_params); self.indented(|this| { @@ -385,7 +381,7 @@ impl<'a> Printer<'a> { ModItem::TraitAlias(it) => { let TraitAlias { name, visibility, generic_params, ast_id: _ } = &self.tree[it]; self.print_visibility(*visibility); - w!(self, "trait {}", name); + w!(self, "trait {}", name.display(self.db)); self.print_generic_params(generic_params); w!(self, " = "); self.print_where_clause(generic_params); @@ -418,7 +414,7 @@ impl<'a> Printer<'a> { let TypeAlias { name, visibility, bounds, type_ref, generic_params, ast_id: _ } = &self.tree[it]; self.print_visibility(*visibility); - w!(self, "type {}", name); + w!(self, "type {}", name.display(self.db)); self.print_generic_params(generic_params); if !bounds.is_empty() { w!(self, ": "); @@ -435,7 +431,7 @@ impl<'a> Printer<'a> { ModItem::Mod(it) => { let Mod { name, visibility, kind, ast_id: _ } = &self.tree[it]; self.print_visibility(*visibility); - w!(self, "mod {}", name); + w!(self, "mod {}", name.display(self.db)); match kind { ModKind::Inline { items } => { w!(self, " {{"); @@ -453,16 +449,16 @@ impl<'a> Printer<'a> { } ModItem::MacroCall(it) => { let MacroCall { path, ast_id: _, expand_to: _ } = &self.tree[it]; - wln!(self, "{}!(...);", path); + wln!(self, "{}!(...);", path.display(self.db)); } ModItem::MacroRules(it) => { let MacroRules { name, ast_id: _ } = &self.tree[it]; - wln!(self, "macro_rules! {} {{ ... }}", name); + wln!(self, "macro_rules! {} {{ ... }}", name.display(self.db)); } ModItem::MacroDef(it) => { let MacroDef { name, visibility, ast_id: _ } = &self.tree[it]; self.print_visibility(*visibility); - wln!(self, "macro {} {{ ... }}", name); + wln!(self, "macro {} {{ ... }}", name.display(self.db)); } } @@ -470,15 +466,15 @@ impl<'a> Printer<'a> { } fn print_type_ref(&mut self, type_ref: &TypeRef) { - print_type_ref(type_ref, self).unwrap(); + print_type_ref(self.db, type_ref, self).unwrap(); } fn print_type_bounds(&mut self, bounds: &[Interned]) { - print_type_bounds(bounds, self).unwrap(); + print_type_bounds(self.db, bounds, self).unwrap(); } fn print_path(&mut self, path: &Path) { - print_path(path, self).unwrap(); + print_path(self.db, path, self).unwrap(); } fn print_generic_params(&mut self, params: &GenericParams) { @@ -493,7 +489,7 @@ impl<'a> Printer<'a> { w!(self, ", "); } first = false; - w!(self, "{}", lt.name); + w!(self, "{}", lt.name.display(self.db)); } for (idx, x) in params.type_or_consts.iter() { if !first { @@ -502,11 +498,11 @@ impl<'a> Printer<'a> { first = false; match x { TypeOrConstParamData::TypeParamData(ty) => match &ty.name { - Some(name) => w!(self, "{}", name), + Some(name) => w!(self, "{}", name.display(self.db)), None => w!(self, "_anon_{}", idx.into_raw()), }, TypeOrConstParamData::ConstParamData(konst) => { - w!(self, "const {}: ", konst.name); + w!(self, "const {}: ", konst.name.display(self.db)); self.print_type_ref(&konst.ty); } } @@ -538,7 +534,12 @@ impl<'a> Printer<'a> { let (target, bound) = match pred { WherePredicate::TypeBound { target, bound } => (target, bound), WherePredicate::Lifetime { target, bound } => { - wln!(this, "{}: {},", target.name, bound.name); + wln!( + this, + "{}: {},", + target.name.display(self.db), + bound.name.display(self.db) + ); continue; } WherePredicate::ForLifetime { lifetimes, target, bound } => { @@ -547,7 +548,7 @@ impl<'a> Printer<'a> { if i != 0 { w!(this, ", "); } - w!(this, "{}", lt); + w!(this, "{}", lt.display(self.db)); } w!(this, "> "); (target, bound) @@ -558,7 +559,7 @@ impl<'a> Printer<'a> { WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty), WherePredicateTypeTarget::TypeOrConstParam(id) => { match ¶ms.type_or_consts[*id].name() { - Some(name) => w!(this, "{}", name), + Some(name) => w!(this, "{}", name.display(self.db)), None => w!(this, "_anon_{}", id.into_raw()), } } diff --git a/crates/hir-def/src/item_tree/tests.rs b/crates/hir-def/src/item_tree/tests.rs index e30d9652bb5dd..5ded4b6b273ae 100644 --- a/crates/hir-def/src/item_tree/tests.rs +++ b/crates/hir-def/src/item_tree/tests.rs @@ -6,7 +6,7 @@ use crate::{db::DefDatabase, test_db::TestDB}; fn check(ra_fixture: &str, expect: Expect) { let (db, file_id) = TestDB::with_single_file(ra_fixture); let item_tree = db.file_item_tree(file_id.into()); - let pretty = item_tree.pretty_print(); + let pretty = item_tree.pretty_print(&db); expect.assert_eq(&pretty); } @@ -165,7 +165,7 @@ trait Tr: SuperTrait + 'lifetime { fn method(&self); } "#, - expect![[r##" + expect![[r#" pub static mut ST: () = _; pub(self) const _: Anon = _; @@ -174,8 +174,8 @@ trait Tr: SuperTrait + 'lifetime { #[inner_attr_in_fn] pub(self) fn f( #[attr] - arg: u8, - _: (), + u8, + (), ) -> () { ... } pub(self) trait Tr @@ -186,10 +186,10 @@ trait Tr: SuperTrait + 'lifetime { pub(self) type Assoc: AssocBound = Default; pub(self) fn method( - _: &Self, // self + self: &Self, ) -> (); } - "##]], + "#]], ); } @@ -336,7 +336,7 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {} T: 'b { pub(self) fn f( - arg: impl Copy, + impl Copy, ) -> impl Copy where G: 'a { ... } diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs index d338bb412054e..0e9ac58fbaaad 100644 --- a/crates/hir-def/src/lang_item.rs +++ b/crates/hir-def/src/lang_item.rs @@ -2,14 +2,13 @@ //! //! This attribute to tell the compiler about semi built-in std library //! features, such as Fn family of traits. -use std::sync::Arc; - use rustc_hash::FxHashMap; use syntax::SmolStr; +use triomphe::Arc; use crate::{ - db::DefDatabase, AdtId, AssocItemId, AttrDefId, CrateId, EnumId, EnumVariantId, FunctionId, - ImplId, ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, UnionId, + db::DefDatabase, path::Path, AdtId, AssocItemId, AttrDefId, CrateId, EnumId, EnumVariantId, + FunctionId, ImplId, ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, UnionId, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -200,7 +199,7 @@ pub enum GenericRequirement { macro_rules! language_item_table { ( - $( $(#[$attr:meta])* $variant:ident, $name:ident, $method:ident, $target:expr, $generics:expr; )* + $( $(#[$attr:meta])* $variant:ident, $module:ident :: $name:ident, $method:ident, $target:expr, $generics:expr; )* ) => { /// A representation of all the valid language items in Rust. @@ -220,11 +219,6 @@ macro_rules! language_item_table { } } - /// Opposite of [`LangItem::name`] - pub fn from_name(name: &hir_expand::name::Name) -> Option { - Self::from_str(name.as_str()?) - } - /// Opposite of [`LangItem::name`] pub fn from_str(name: &str) -> Option { match name { @@ -236,84 +230,100 @@ macro_rules! language_item_table { } } +impl LangItem { + /// Opposite of [`LangItem::name`] + pub fn from_name(name: &hir_expand::name::Name) -> Option { + Self::from_str(name.as_str()?) + } + + pub fn path(&self, db: &dyn DefDatabase, start_crate: CrateId) -> Option { + let t = db.lang_item(start_crate, *self)?; + Some(Path::LangItem(t)) + } +} + language_item_table! { // Variant name, Name, Getter method name, Target Generic requirements; - Sized, sized, sized_trait, Target::Trait, GenericRequirement::Exact(0); - Unsize, unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1); + Sized, sym::sized, sized_trait, Target::Trait, GenericRequirement::Exact(0); + Unsize, sym::unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1); /// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ"). - StructuralPeq, structural_peq, structural_peq_trait, Target::Trait, GenericRequirement::None; + StructuralPeq, sym::structural_peq, structural_peq_trait, Target::Trait, GenericRequirement::None; /// Trait injected by `#[derive(Eq)]`, (i.e. "Total EQ"; no, I will not apologize). - StructuralTeq, structural_teq, structural_teq_trait, Target::Trait, GenericRequirement::None; - Copy, copy, copy_trait, Target::Trait, GenericRequirement::Exact(0); - Clone, clone, clone_trait, Target::Trait, GenericRequirement::None; - Sync, sync, sync_trait, Target::Trait, GenericRequirement::Exact(0); - DiscriminantKind, discriminant_kind, discriminant_kind_trait, Target::Trait, GenericRequirement::None; + StructuralTeq, sym::structural_teq, structural_teq_trait, Target::Trait, GenericRequirement::None; + Copy, sym::copy, copy_trait, Target::Trait, GenericRequirement::Exact(0); + Clone, sym::clone, clone_trait, Target::Trait, GenericRequirement::None; + Sync, sym::sync, sync_trait, Target::Trait, GenericRequirement::Exact(0); + DiscriminantKind, sym::discriminant_kind, discriminant_kind_trait, Target::Trait, GenericRequirement::None; /// The associated item of the [`DiscriminantKind`] trait. - Discriminant, discriminant_type, discriminant_type, Target::AssocTy, GenericRequirement::None; + Discriminant, sym::discriminant_type, discriminant_type, Target::AssocTy, GenericRequirement::None; + + PointeeTrait, sym::pointee_trait, pointee_trait, Target::Trait, GenericRequirement::None; + Metadata, sym::metadata_type, metadata_type, Target::AssocTy, GenericRequirement::None; + DynMetadata, sym::dyn_metadata, dyn_metadata, Target::Struct, GenericRequirement::None; - PointeeTrait, pointee_trait, pointee_trait, Target::Trait, GenericRequirement::None; - Metadata, metadata_type, metadata_type, Target::AssocTy, GenericRequirement::None; - DynMetadata, dyn_metadata, dyn_metadata, Target::Struct, GenericRequirement::None; + Freeze, sym::freeze, freeze_trait, Target::Trait, GenericRequirement::Exact(0); - Freeze, freeze, freeze_trait, Target::Trait, GenericRequirement::Exact(0); + FnPtrTrait, sym::fn_ptr_trait, fn_ptr_trait, Target::Trait, GenericRequirement::Exact(0); + FnPtrAddr, sym::fn_ptr_addr, fn_ptr_addr, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; - Drop, drop, drop_trait, Target::Trait, GenericRequirement::None; - Destruct, destruct, destruct_trait, Target::Trait, GenericRequirement::None; + Drop, sym::drop, drop_trait, Target::Trait, GenericRequirement::None; + Destruct, sym::destruct, destruct_trait, Target::Trait, GenericRequirement::None; - CoerceUnsized, coerce_unsized, coerce_unsized_trait, Target::Trait, GenericRequirement::Minimum(1); - DispatchFromDyn, dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait, GenericRequirement::Minimum(1); + CoerceUnsized, sym::coerce_unsized, coerce_unsized_trait, Target::Trait, GenericRequirement::Minimum(1); + DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait, GenericRequirement::Minimum(1); // language items relating to transmutability - TransmuteOpts, transmute_opts, transmute_opts, Target::Struct, GenericRequirement::Exact(0); - TransmuteTrait, transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(3); - - Add, add, add_trait, Target::Trait, GenericRequirement::Exact(1); - Sub, sub, sub_trait, Target::Trait, GenericRequirement::Exact(1); - Mul, mul, mul_trait, Target::Trait, GenericRequirement::Exact(1); - Div, div, div_trait, Target::Trait, GenericRequirement::Exact(1); - Rem, rem, rem_trait, Target::Trait, GenericRequirement::Exact(1); - Neg, neg, neg_trait, Target::Trait, GenericRequirement::Exact(0); - Not, not, not_trait, Target::Trait, GenericRequirement::Exact(0); - BitXor, bitxor, bitxor_trait, Target::Trait, GenericRequirement::Exact(1); - BitAnd, bitand, bitand_trait, Target::Trait, GenericRequirement::Exact(1); - BitOr, bitor, bitor_trait, Target::Trait, GenericRequirement::Exact(1); - Shl, shl, shl_trait, Target::Trait, GenericRequirement::Exact(1); - Shr, shr, shr_trait, Target::Trait, GenericRequirement::Exact(1); - AddAssign, add_assign, add_assign_trait, Target::Trait, GenericRequirement::Exact(1); - SubAssign, sub_assign, sub_assign_trait, Target::Trait, GenericRequirement::Exact(1); - MulAssign, mul_assign, mul_assign_trait, Target::Trait, GenericRequirement::Exact(1); - DivAssign, div_assign, div_assign_trait, Target::Trait, GenericRequirement::Exact(1); - RemAssign, rem_assign, rem_assign_trait, Target::Trait, GenericRequirement::Exact(1); - BitXorAssign, bitxor_assign, bitxor_assign_trait, Target::Trait, GenericRequirement::Exact(1); - BitAndAssign, bitand_assign, bitand_assign_trait, Target::Trait, GenericRequirement::Exact(1); - BitOrAssign, bitor_assign, bitor_assign_trait, Target::Trait, GenericRequirement::Exact(1); - ShlAssign, shl_assign, shl_assign_trait, Target::Trait, GenericRequirement::Exact(1); - ShrAssign, shr_assign, shr_assign_trait, Target::Trait, GenericRequirement::Exact(1); - Index, index, index_trait, Target::Trait, GenericRequirement::Exact(1); - IndexMut, index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1); - - UnsafeCell, unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None; - VaList, va_list, va_list, Target::Struct, GenericRequirement::None; - - Deref, deref, deref_trait, Target::Trait, GenericRequirement::Exact(0); - DerefMut, deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0); - DerefTarget, deref_target, deref_target, Target::AssocTy, GenericRequirement::None; - Receiver, receiver, receiver_trait, Target::Trait, GenericRequirement::None; - - Fn, fn, fn_trait, Target::Trait, GenericRequirement::Exact(1); - FnMut, fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); - FnOnce, fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1); - - FnOnceOutput, fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None; - - Future, future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0); - GeneratorState, generator_state, gen_state, Target::Enum, GenericRequirement::None; - Generator, generator, gen_trait, Target::Trait, GenericRequirement::Minimum(1); - Unpin, unpin, unpin_trait, Target::Trait, GenericRequirement::None; - Pin, pin, pin_type, Target::Struct, GenericRequirement::None; - - PartialEq, eq, eq_trait, Target::Trait, GenericRequirement::Exact(1); - PartialOrd, partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1); + TransmuteOpts, sym::transmute_opts, transmute_opts, Target::Struct, GenericRequirement::Exact(0); + TransmuteTrait, sym::transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(3); + + Add, sym::add, add_trait, Target::Trait, GenericRequirement::Exact(1); + Sub, sym::sub, sub_trait, Target::Trait, GenericRequirement::Exact(1); + Mul, sym::mul, mul_trait, Target::Trait, GenericRequirement::Exact(1); + Div, sym::div, div_trait, Target::Trait, GenericRequirement::Exact(1); + Rem, sym::rem, rem_trait, Target::Trait, GenericRequirement::Exact(1); + Neg, sym::neg, neg_trait, Target::Trait, GenericRequirement::Exact(0); + Not, sym::not, not_trait, Target::Trait, GenericRequirement::Exact(0); + BitXor, sym::bitxor, bitxor_trait, Target::Trait, GenericRequirement::Exact(1); + BitAnd, sym::bitand, bitand_trait, Target::Trait, GenericRequirement::Exact(1); + BitOr, sym::bitor, bitor_trait, Target::Trait, GenericRequirement::Exact(1); + Shl, sym::shl, shl_trait, Target::Trait, GenericRequirement::Exact(1); + Shr, sym::shr, shr_trait, Target::Trait, GenericRequirement::Exact(1); + AddAssign, sym::add_assign, add_assign_trait, Target::Trait, GenericRequirement::Exact(1); + SubAssign, sym::sub_assign, sub_assign_trait, Target::Trait, GenericRequirement::Exact(1); + MulAssign, sym::mul_assign, mul_assign_trait, Target::Trait, GenericRequirement::Exact(1); + DivAssign, sym::div_assign, div_assign_trait, Target::Trait, GenericRequirement::Exact(1); + RemAssign, sym::rem_assign, rem_assign_trait, Target::Trait, GenericRequirement::Exact(1); + BitXorAssign, sym::bitxor_assign, bitxor_assign_trait, Target::Trait, GenericRequirement::Exact(1); + BitAndAssign, sym::bitand_assign, bitand_assign_trait, Target::Trait, GenericRequirement::Exact(1); + BitOrAssign, sym::bitor_assign, bitor_assign_trait, Target::Trait, GenericRequirement::Exact(1); + ShlAssign, sym::shl_assign, shl_assign_trait, Target::Trait, GenericRequirement::Exact(1); + ShrAssign, sym::shr_assign, shr_assign_trait, Target::Trait, GenericRequirement::Exact(1); + Index, sym::index, index_trait, Target::Trait, GenericRequirement::Exact(1); + IndexMut, sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1); + + UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None; + VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None; + + Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0); + DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0); + DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None; + Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None; + + Fn, kw::fn, fn_trait, Target::Trait, GenericRequirement::Exact(1); + FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); + FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1); + + FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None; + + Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0); + GeneratorState, sym::generator_state, gen_state, Target::Enum, GenericRequirement::None; + Generator, sym::generator, gen_trait, Target::Trait, GenericRequirement::Minimum(1); + Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None; + Pin, sym::pin, pin_type, Target::Struct, GenericRequirement::None; + + PartialEq, sym::eq, eq_trait, Target::Trait, GenericRequirement::Exact(1); + PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1); + CVoid, sym::c_void, c_void, Target::Enum, GenericRequirement::None; // A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and // various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays. @@ -322,92 +332,103 @@ language_item_table! { // in the sense that a crate is not required to have it defined to use it, but a final product // is required to define it somewhere. Additionally, there are restrictions on crates that use // a weak lang item, but do not have it defined. - Panic, panic, panic_fn, Target::Fn, GenericRequirement::Exact(0); - PanicNounwind, panic_nounwind, panic_nounwind, Target::Fn, GenericRequirement::Exact(0); - PanicFmt, panic_fmt, panic_fmt, Target::Fn, GenericRequirement::None; - PanicDisplay, panic_display, panic_display, Target::Fn, GenericRequirement::None; - ConstPanicFmt, const_panic_fmt, const_panic_fmt, Target::Fn, GenericRequirement::None; - PanicBoundsCheck, panic_bounds_check, panic_bounds_check_fn, Target::Fn, GenericRequirement::Exact(0); - PanicInfo, panic_info, panic_info, Target::Struct, GenericRequirement::None; - PanicLocation, panic_location, panic_location, Target::Struct, GenericRequirement::None; - PanicImpl, panic_impl, panic_impl, Target::Fn, GenericRequirement::None; - PanicCannotUnwind, panic_cannot_unwind, panic_cannot_unwind, Target::Fn, GenericRequirement::Exact(0); + Panic, sym::panic, panic_fn, Target::Fn, GenericRequirement::Exact(0); + PanicNounwind, sym::panic_nounwind, panic_nounwind, Target::Fn, GenericRequirement::Exact(0); + PanicFmt, sym::panic_fmt, panic_fmt, Target::Fn, GenericRequirement::None; + PanicDisplay, sym::panic_display, panic_display, Target::Fn, GenericRequirement::None; + ConstPanicFmt, sym::const_panic_fmt, const_panic_fmt, Target::Fn, GenericRequirement::None; + PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn, GenericRequirement::Exact(0); + PanicMisalignedPointerDereference, sym::panic_misaligned_pointer_dereference, panic_misaligned_pointer_dereference_fn, Target::Fn, GenericRequirement::Exact(0); + PanicInfo, sym::panic_info, panic_info, Target::Struct, GenericRequirement::None; + PanicLocation, sym::panic_location, panic_location, Target::Struct, GenericRequirement::None; + PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None; + PanicCannotUnwind, sym::panic_cannot_unwind, panic_cannot_unwind, Target::Fn, GenericRequirement::Exact(0); /// libstd panic entry point. Necessary for const eval to be able to catch it - BeginPanic, begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None; + BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None; - ExchangeMalloc, exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None; - BoxFree, box_free, box_free_fn, Target::Fn, GenericRequirement::Minimum(1); - DropInPlace, drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1); - AllocLayout, alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None; + // Lang items needed for `format_args!()`. + FormatAlignment, sym::format_alignment, format_alignment, Target::Enum, GenericRequirement::None; + FormatArgument, sym::format_argument, format_argument, Target::Struct, GenericRequirement::None; + FormatArguments, sym::format_arguments, format_arguments, Target::Struct, GenericRequirement::None; + FormatCount, sym::format_count, format_count, Target::Enum, GenericRequirement::None; + FormatPlaceholder, sym::format_placeholder, format_placeholder, Target::Struct, GenericRequirement::None; + FormatUnsafeArg, sym::format_unsafe_arg, format_unsafe_arg, Target::Struct, GenericRequirement::None; - Start, start, start_fn, Target::Fn, GenericRequirement::Exact(1); + ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None; + BoxFree, sym::box_free, box_free_fn, Target::Fn, GenericRequirement::Minimum(1); + DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1); + AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None; - EhPersonality, eh_personality, eh_personality, Target::Fn, GenericRequirement::None; - EhCatchTypeinfo, eh_catch_typeinfo, eh_catch_typeinfo, Target::Static, GenericRequirement::None; + Start, sym::start, start_fn, Target::Fn, GenericRequirement::Exact(1); - OwnedBox, owned_box, owned_box, Target::Struct, GenericRequirement::Minimum(1); + EhPersonality, sym::eh_personality, eh_personality, Target::Fn, GenericRequirement::None; + EhCatchTypeinfo, sym::eh_catch_typeinfo, eh_catch_typeinfo, Target::Static, GenericRequirement::None; - PhantomData, phantom_data, phantom_data, Target::Struct, GenericRequirement::Exact(1); + OwnedBox, sym::owned_box, owned_box, Target::Struct, GenericRequirement::Minimum(1); - ManuallyDrop, manually_drop, manually_drop, Target::Struct, GenericRequirement::None; + PhantomData, sym::phantom_data, phantom_data, Target::Struct, GenericRequirement::Exact(1); - MaybeUninit, maybe_uninit, maybe_uninit, Target::Union, GenericRequirement::None; + ManuallyDrop, sym::manually_drop, manually_drop, Target::Struct, GenericRequirement::None; + + MaybeUninit, sym::maybe_uninit, maybe_uninit, Target::Union, GenericRequirement::None; /// Align offset for stride != 1; must not panic. - AlignOffset, align_offset, align_offset_fn, Target::Fn, GenericRequirement::None; + AlignOffset, sym::align_offset, align_offset_fn, Target::Fn, GenericRequirement::None; - Termination, termination, termination, Target::Trait, GenericRequirement::None; + Termination, sym::termination, termination, Target::Trait, GenericRequirement::None; - Try, Try, try_trait, Target::Trait, GenericRequirement::None; + Try, sym::Try, try_trait, Target::Trait, GenericRequirement::None; - Tuple, tuple_trait, tuple_trait, Target::Trait, GenericRequirement::Exact(0); + Tuple, sym::tuple_trait, tuple_trait, Target::Trait, GenericRequirement::Exact(0); - SliceLen, slice_len_fn, slice_len_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None; + SliceLen, sym::slice_len_fn, slice_len_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None; // Language items from AST lowering - TryTraitFromResidual, from_residual, from_residual_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; - TryTraitFromOutput, from_output, from_output_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; - TryTraitBranch, branch, branch_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; - TryTraitFromYeet, from_yeet, from_yeet_fn, Target::Fn, GenericRequirement::None; + TryTraitFromResidual, sym::from_residual, from_residual_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; + TryTraitFromOutput, sym::from_output, from_output_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; + TryTraitBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; + TryTraitFromYeet, sym::from_yeet, from_yeet_fn, Target::Fn, GenericRequirement::None; + + PointerLike, sym::pointer_like, pointer_like, Target::Trait, GenericRequirement::Exact(0); - PointerSized, pointer_sized, pointer_sized, Target::Trait, GenericRequirement::Exact(0); + ConstParamTy, sym::const_param_ty, const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0); - Poll, Poll, poll, Target::Enum, GenericRequirement::None; - PollReady, Ready, poll_ready_variant, Target::Variant, GenericRequirement::None; - PollPending, Pending, poll_pending_variant, Target::Variant, GenericRequirement::None; + Poll, sym::Poll, poll, Target::Enum, GenericRequirement::None; + PollReady, sym::Ready, poll_ready_variant, Target::Variant, GenericRequirement::None; + PollPending, sym::Pending, poll_pending_variant, Target::Variant, GenericRequirement::None; // FIXME(swatinem): the following lang items are used for async lowering and // should become obsolete eventually. - ResumeTy, ResumeTy, resume_ty, Target::Struct, GenericRequirement::None; - GetContext, get_context, get_context_fn, Target::Fn, GenericRequirement::None; - - Context, Context, context, Target::Struct, GenericRequirement::None; - FuturePoll, poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; + ResumeTy, sym::ResumeTy, resume_ty, Target::Struct, GenericRequirement::None; + GetContext, sym::get_context, get_context_fn, Target::Fn, GenericRequirement::None; - FromFrom, from, from_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; + Context, sym::Context, context, Target::Struct, GenericRequirement::None; + FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; - OptionSome, Some, option_some_variant, Target::Variant, GenericRequirement::None; - OptionNone, None, option_none_variant, Target::Variant, GenericRequirement::None; + Option, sym::Option, option_type, Target::Enum, GenericRequirement::None; + OptionSome, sym::Some, option_some_variant, Target::Variant, GenericRequirement::None; + OptionNone, sym::None, option_none_variant, Target::Variant, GenericRequirement::None; - ResultOk, Ok, result_ok_variant, Target::Variant, GenericRequirement::None; - ResultErr, Err, result_err_variant, Target::Variant, GenericRequirement::None; + ResultOk, sym::Ok, result_ok_variant, Target::Variant, GenericRequirement::None; + ResultErr, sym::Err, result_err_variant, Target::Variant, GenericRequirement::None; - ControlFlowContinue, Continue, cf_continue_variant, Target::Variant, GenericRequirement::None; - ControlFlowBreak, Break, cf_break_variant, Target::Variant, GenericRequirement::None; + ControlFlowContinue, sym::Continue, cf_continue_variant, Target::Variant, GenericRequirement::None; + ControlFlowBreak, sym::Break, cf_break_variant, Target::Variant, GenericRequirement::None; - IntoFutureIntoFuture, into_future, into_future_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; - IntoIterIntoIter, into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; - IteratorNext, next, next_fn, Target::Method(MethodKind::Trait { body: false}), GenericRequirement::None; + IntoFutureIntoFuture, sym::into_future, into_future_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; + IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; + IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false}), GenericRequirement::None; - PinNewUnchecked, new_unchecked, new_unchecked_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None; + PinNewUnchecked, sym::new_unchecked, new_unchecked_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None; - RangeFrom, RangeFrom, range_from_struct, Target::Struct, GenericRequirement::None; - RangeFull, RangeFull, range_full_struct, Target::Struct, GenericRequirement::None; - RangeInclusiveStruct, RangeInclusive, range_inclusive_struct, Target::Struct, GenericRequirement::None; - RangeInclusiveNew, range_inclusive_new, range_inclusive_new_method, Target::Method(MethodKind::Inherent), GenericRequirement::None; - Range, Range, range_struct, Target::Struct, GenericRequirement::None; - RangeToInclusive, RangeToInclusive, range_to_inclusive_struct, Target::Struct, GenericRequirement::None; - RangeTo, RangeTo, range_to_struct, Target::Struct, GenericRequirement::None; + RangeFrom, sym::RangeFrom, range_from_struct, Target::Struct, GenericRequirement::None; + RangeFull, sym::RangeFull, range_full_struct, Target::Struct, GenericRequirement::None; + RangeInclusiveStruct, sym::RangeInclusive, range_inclusive_struct, Target::Struct, GenericRequirement::None; + RangeInclusiveNew, sym::range_inclusive_new, range_inclusive_new_method, Target::Method(MethodKind::Inherent), GenericRequirement::None; + Range, sym::Range, range_struct, Target::Struct, GenericRequirement::None; + RangeToInclusive, sym::RangeToInclusive, range_to_inclusive_struct, Target::Struct, GenericRequirement::None; + RangeTo, sym::RangeTo, range_to_struct, Target::Struct, GenericRequirement::None; - String, String, string, Target::Struct, GenericRequirement::None; + String, sym::String, string, Target::Struct, GenericRequirement::None; + CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None; } diff --git a/crates/hir-def/src/layout.rs b/crates/hir-def/src/layout.rs deleted file mode 100644 index 49b1190ad46a3..0000000000000 --- a/crates/hir-def/src/layout.rs +++ /dev/null @@ -1,97 +0,0 @@ -//! Definitions needed for computing data layout of types. - -use std::cmp; - -use la_arena::{Idx, RawIdx}; -pub use rustc_abi::{ - Abi, AbiAndPrefAlign, AddressSpace, Align, Endian, FieldsShape, Integer, IntegerType, - LayoutCalculator, Niche, Primitive, ReprFlags, ReprOptions, Scalar, Size, StructKind, - TargetDataLayout, TargetDataLayoutErrors, WrappingRange, -}; - -use crate::LocalEnumVariantId; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct RustcEnumVariantIdx(pub LocalEnumVariantId); - -impl rustc_index::vec::Idx for RustcEnumVariantIdx { - fn new(idx: usize) -> Self { - RustcEnumVariantIdx(Idx::from_raw(RawIdx::from(idx as u32))) - } - - fn index(self) -> usize { - u32::from(self.0.into_raw()) as usize - } -} - -pub type Layout = rustc_abi::LayoutS; -pub type TagEncoding = rustc_abi::TagEncoding; -pub type Variants = rustc_abi::Variants; - -pub trait IntegerExt { - fn repr_discr( - dl: &TargetDataLayout, - repr: &ReprOptions, - min: i128, - max: i128, - ) -> Result<(Integer, bool), LayoutError>; -} - -impl IntegerExt for Integer { - /// Finds the appropriate Integer type and signedness for the given - /// signed discriminant range and `#[repr]` attribute. - /// N.B.: `u128` values above `i128::MAX` will be treated as signed, but - /// that shouldn't affect anything, other than maybe debuginfo. - fn repr_discr( - dl: &TargetDataLayout, - repr: &ReprOptions, - min: i128, - max: i128, - ) -> Result<(Integer, bool), LayoutError> { - // Theoretically, negative values could be larger in unsigned representation - // than the unsigned representation of the signed minimum. However, if there - // are any negative values, the only valid unsigned representation is u128 - // which can fit all i128 values, so the result remains unaffected. - let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u128, max as u128)); - let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max)); - - if let Some(ity) = repr.int { - let discr = Integer::from_attr(dl, ity); - let fit = if ity.is_signed() { signed_fit } else { unsigned_fit }; - if discr < fit { - return Err(LayoutError::UserError( - "Integer::repr_discr: `#[repr]` hint too small for \ - discriminant range of enum " - .to_string(), - )); - } - return Ok((discr, ity.is_signed())); - } - - let at_least = if repr.c() { - // This is usually I32, however it can be different on some platforms, - // notably hexagon and arm-none/thumb-none - dl.c_enum_min_size - } else { - // repr(Rust) enums try to be as small as possible - Integer::I8 - }; - - // If there are no negative values, we can use the unsigned fit. - Ok(if min >= 0 { - (cmp::max(unsigned_fit, at_least), false) - } else { - (cmp::max(signed_fit, at_least), true) - }) - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum LayoutError { - UserError(String), - SizeOverflow, - TargetLayoutNotAvailable, - HasPlaceholder, - NotImplemented, - Unknown, -} diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 8c2e93f090597..9cd3dfd6f7c96 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -18,24 +18,23 @@ pub mod db; pub mod attr; pub mod path; -pub mod type_ref; pub mod builtin_type; -pub mod builtin_attr; pub mod per_ns; pub mod item_scope; +pub mod lower; +pub mod expander; + pub mod dyn_map; -pub mod keys; pub mod item_tree; -pub mod adt; pub mod data; pub mod generics; pub mod lang_item; -pub mod layout; -pub mod expr; +pub mod hir; +pub use self::hir::type_ref; pub mod body; pub mod resolver; @@ -49,29 +48,34 @@ pub mod visibility; pub mod find_path; pub mod import_map; +pub use rustc_abi as layout; +use triomphe::Arc; + #[cfg(test)] mod test_db; #[cfg(test)] mod macro_expansion_tests; mod pretty; -use std::{ - hash::{Hash, Hasher}, - sync::Arc, -}; +use std::hash::{Hash, Hasher}; -use base_db::{impl_intern_key, salsa, CrateId, ProcMacroKind}; +use base_db::{ + impl_intern_key, + salsa::{self, InternId}, + CrateId, ProcMacroKind, +}; use hir_expand::{ ast_id_map::FileAstId, attrs::{Attr, AttrId, AttrInput}, builtin_attr_macro::BuiltinAttrExpander, builtin_derive_macro::BuiltinDeriveExpander, builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander}, - eager::{expand_eager_macro, ErrorEmitted, ErrorSink}, + db::ExpandDatabase, + eager::expand_eager_macro, hygiene::Hygiene, proc_macro::ProcMacroExpander, - AstId, ExpandError, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, - MacroDefKind, UnresolvedMacro, + AstId, ExpandError, ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, + MacroDefId, MacroDefKind, UnresolvedMacro, }; use item_tree::ExternBlock; use la_arena::Idx; @@ -82,8 +86,8 @@ use syntax::ast; use ::tt::token_id as tt; use crate::{ - adt::VariantData, builtin_type::BuiltinType, + data::adt::VariantData, item_tree::{ Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, MacroDef, MacroRules, ModItem, Static, Struct, Trait, TraitAlias, TypeAlias, Union, @@ -104,13 +108,7 @@ pub struct ModuleId { impl ModuleId { pub fn def_map(&self, db: &dyn db::DefDatabase) -> Arc { match self.block { - Some(block) => { - db.block_def_map(block).unwrap_or_else(|| { - // NOTE: This should be unreachable - all `ModuleId`s come from their `DefMap`s, - // so the `DefMap` here must exist. - unreachable!("no `block_def_map` for `ModuleId` {:?}", self); - }) - } + Some(block) => db.block_def_map(block), None => db.crate_def_map(self.krate), } } @@ -236,7 +234,7 @@ pub struct EnumVariantId { pub local_id: LocalEnumVariantId, } -pub type LocalEnumVariantId = Idx; +pub type LocalEnumVariantId = Idx; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct FieldId { @@ -244,7 +242,7 @@ pub struct FieldId { pub local_id: LocalFieldId, } -pub type LocalFieldId = Idx; +pub type LocalFieldId = Idx; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ConstId(salsa::InternId); @@ -478,6 +476,46 @@ impl_from!( for ModuleDefId ); +// FIXME: make this a DefWithBodyId +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub struct AnonymousConstId(InternId); +impl_intern_key!(AnonymousConstId); + +/// A constant, which might appears as a const item, an annonymous const block in expressions +/// or patterns, or as a constant in types with const generics. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum GeneralConstId { + ConstId(ConstId), + AnonymousConstId(AnonymousConstId), +} + +impl_from!(ConstId, AnonymousConstId for GeneralConstId); + +impl GeneralConstId { + pub fn generic_def(self, db: &dyn db::DefDatabase) -> Option { + match self { + GeneralConstId::ConstId(x) => Some(x.into()), + GeneralConstId::AnonymousConstId(x) => { + let (parent, _) = db.lookup_intern_anonymous_const(x); + parent.as_generic_def_id() + } + } + } + + pub fn name(self, db: &dyn db::DefDatabase) -> String { + match self { + GeneralConstId::ConstId(const_id) => db + .const_data(const_id) + .name + .as_ref() + .and_then(|x| x.as_str()) + .unwrap_or("_") + .to_owned(), + GeneralConstId::AnonymousConstId(id) => format!("{{anonymous const {id:?}}}"), + } + } +} + /// The defs which have a body. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum DefWithBodyId { @@ -799,52 +837,43 @@ impl AttrDefId { pub trait AsMacroCall { fn as_call_id( &self, - db: &dyn db::DefDatabase, + db: &dyn ExpandDatabase, krate: CrateId, resolver: impl Fn(path::ModPath) -> Option, ) -> Option { - self.as_call_id_with_errors(db, krate, resolver, &mut |_| ()).ok()?.ok() + self.as_call_id_with_errors(db, krate, resolver).ok()?.value } fn as_call_id_with_errors( &self, - db: &dyn db::DefDatabase, + db: &dyn ExpandDatabase, krate: CrateId, resolver: impl Fn(path::ModPath) -> Option, - error_sink: &mut dyn FnMut(ExpandError), - ) -> Result, UnresolvedMacro>; + ) -> Result>, UnresolvedMacro>; } impl AsMacroCall for InFile<&ast::MacroCall> { fn as_call_id_with_errors( &self, - db: &dyn db::DefDatabase, + db: &dyn ExpandDatabase, krate: CrateId, resolver: impl Fn(path::ModPath) -> Option, - mut error_sink: &mut dyn FnMut(ExpandError), - ) -> Result, UnresolvedMacro> { + ) -> Result>, UnresolvedMacro> { let expands_to = hir_expand::ExpandTo::from_call_site(self.value); let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); - let h = Hygiene::new(db.upcast(), self.file_id); - let path = - self.value.path().and_then(|path| path::ModPath::from_src(db.upcast(), path, &h)); - - let path = match error_sink - .option(path, || ExpandError::Other("malformed macro invocation".into())) - { - Ok(path) => path, - Err(error) => { - return Ok(Err(error)); - } + let h = Hygiene::new(db, self.file_id); + let path = self.value.path().and_then(|path| path::ModPath::from_src(db, path, &h)); + + let Some(path) = path else { + return Ok(ExpandResult::only_err(ExpandError::Other("malformed macro invocation".into()))); }; - macro_call_as_call_id( + macro_call_as_call_id_( db, &AstIdWithPath::new(ast_id.file_id, ast_id.value, path), expands_to, krate, resolver, - error_sink, ) } } @@ -863,26 +892,37 @@ impl AstIdWithPath { } fn macro_call_as_call_id( - db: &dyn db::DefDatabase, + db: &dyn ExpandDatabase, + call: &AstIdWithPath, + expand_to: ExpandTo, + krate: CrateId, + resolver: impl Fn(path::ModPath) -> Option, +) -> Result, UnresolvedMacro> { + macro_call_as_call_id_(db, call, expand_to, krate, resolver).map(|res| res.value) +} + +fn macro_call_as_call_id_( + db: &dyn ExpandDatabase, call: &AstIdWithPath, expand_to: ExpandTo, krate: CrateId, resolver: impl Fn(path::ModPath) -> Option, - error_sink: &mut dyn FnMut(ExpandError), -) -> Result, UnresolvedMacro> { +) -> Result>, UnresolvedMacro> { let def = resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?; let res = if let MacroDefKind::BuiltInEager(..) = def.kind { - let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast())); - - expand_eager_macro(db.upcast(), krate, macro_call, def, &resolver, error_sink)? + let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db)); + expand_eager_macro(db, krate, macro_call, def, &resolver)? } else { - Ok(def.as_lazy_macro( - db.upcast(), - krate, - MacroCallKind::FnLike { ast_id: call.ast_id, expand_to }, - )) + ExpandResult { + value: Some(def.as_lazy_macro( + db, + krate, + MacroCallKind::FnLike { ast_id: call.ast_id, expand_to }, + )), + err: None, + } }; Ok(res) } @@ -986,7 +1026,6 @@ fn attr_macro_as_call_id( macro_attr: &Attr, krate: CrateId, def: MacroDefId, - is_derive: bool, ) -> MacroCallId { let arg = match macro_attr.input.as_deref() { Some(AttrInput::TokenTree(tt, map)) => ( @@ -1007,7 +1046,6 @@ fn attr_macro_as_call_id( ast_id: item_attr.ast_id, attr_args: Arc::new(arg), invoc_attr_index: macro_attr.id, - is_derive, }, ) } diff --git a/crates/hir-def/src/lower.rs b/crates/hir-def/src/lower.rs new file mode 100644 index 0000000000000..af623fd0e5d4d --- /dev/null +++ b/crates/hir-def/src/lower.rs @@ -0,0 +1,45 @@ +//! Context for lowering paths. +use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile}; +use once_cell::unsync::OnceCell; +use syntax::ast; +use triomphe::Arc; + +use crate::{db::DefDatabase, path::Path}; + +pub struct LowerCtx<'a> { + pub db: &'a dyn DefDatabase, + hygiene: Hygiene, + ast_id_map: Option<(HirFileId, OnceCell>)>, +} + +impl<'a> LowerCtx<'a> { + pub fn new(db: &'a dyn DefDatabase, hygiene: &Hygiene, file_id: HirFileId) -> Self { + LowerCtx { db, hygiene: hygiene.clone(), ast_id_map: Some((file_id, OnceCell::new())) } + } + + pub fn with_file_id(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self { + LowerCtx { + db, + hygiene: Hygiene::new(db.upcast(), file_id), + ast_id_map: Some((file_id, OnceCell::new())), + } + } + + pub fn with_hygiene(db: &'a dyn DefDatabase, hygiene: &Hygiene) -> Self { + LowerCtx { db, hygiene: hygiene.clone(), ast_id_map: None } + } + + pub(crate) fn hygiene(&self) -> &Hygiene { + &self.hygiene + } + + pub(crate) fn lower_path(&self, ast: ast::Path) -> Option { + Path::from_src(ast, self) + } + + pub(crate) fn ast_id(&self, item: &N) -> Option> { + let &(file_id, ref ast_id_map) = self.ast_id_map.as_ref()?; + let ast_id_map = ast_id_map.get_or_init(|| self.db.ast_id_map(file_id)); + Some(InFile::new(file_id, ast_id_map.ast_id(item))) + } +} diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs index fafcde25ae708..80474bc154d08 100644 --- a/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs +++ b/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs @@ -16,7 +16,7 @@ struct Foo; #[derive(Copy)] struct Foo; -impl < > core::marker::Copy for Foo< > {}"#]], +impl < > core::marker::Copy for Foo< > where {}"#]], ); } @@ -41,7 +41,7 @@ macro Copy {} #[derive(Copy)] struct Foo; -impl < > crate ::marker::Copy for Foo< > {}"#]], +impl < > crate ::marker::Copy for Foo< > where {}"#]], ); } @@ -57,7 +57,7 @@ struct Foo; #[derive(Copy)] struct Foo; -impl core::marker::Copy for Foo {}"#]], +impl core::marker::Copy for Foo where {}"#]], ); } @@ -74,7 +74,7 @@ struct Foo; #[derive(Copy)] struct Foo; -impl core::marker::Copy for Foo {}"#]], +impl core::marker::Copy for Foo where {}"#]], ); } @@ -84,13 +84,33 @@ fn test_clone_expand() { r#" //- minicore: derive, clone #[derive(Clone)] -struct Foo; +enum Command { + Move { x: A, y: B }, + Do(&'static str), + Jump, +} "#, expect![[r#" #[derive(Clone)] -struct Foo; +enum Command { + Move { x: A, y: B }, + Do(&'static str), + Jump, +} -impl core::clone::Clone for Foo {}"#]], +impl core::clone::Clone for Command where { + fn clone(&self ) -> Self { + match self { + Command::Move { + x: x, y: y, + } + =>Command::Move { + x: x.clone(), y: y.clone(), + } + , Command::Do(f0, )=>Command::Do(f0.clone(), ), Command::Jump=>Command::Jump, + } + } +}"#]], ); } @@ -106,6 +126,270 @@ struct Foo(u32); #[derive(Clone)] struct Foo(u32); -impl core::clone::Clone for Foo {}"#]], +impl core::clone::Clone for Foo where { + fn clone(&self ) -> Self { + match self { + Foo(f0, )=>Foo(f0.clone(), ), + } + } +}"#]], + ); +} + +#[test] +fn test_default_expand() { + check( + r#" +//- minicore: derive, default +#[derive(Default)] +struct Foo { + field1: i32, + field2: (), +} +#[derive(Default)] +enum Bar { + Foo(u8), + #[default] + Bar, +} +"#, + expect![[r#" +#[derive(Default)] +struct Foo { + field1: i32, + field2: (), +} +#[derive(Default)] +enum Bar { + Foo(u8), + #[default] + Bar, +} + +impl < > core::default::Default for Foo< > where { + fn default() -> Self { + Foo { + field1: core::default::Default::default(), field2: core::default::Default::default(), + } + } +} +impl < > core::default::Default for Bar< > where { + fn default() -> Self { + Bar::Bar + } +}"#]], + ); +} + +#[test] +fn test_partial_eq_expand() { + check( + r#" +//- minicore: derive, eq +#[derive(PartialEq, Eq)] +enum Command { + Move { x: i32, y: i32 }, + Do(&'static str), + Jump, +} +"#, + expect![[r#" +#[derive(PartialEq, Eq)] +enum Command { + Move { x: i32, y: i32 }, + Do(&'static str), + Jump, +} + +impl < > core::cmp::PartialEq for Command< > where { + fn eq(&self , other: &Self ) -> bool { + match (self , other) { + (Command::Move { + x: x_self, y: y_self, + } + , Command::Move { + x: x_other, y: y_other, + } + )=>x_self.eq(x_other) && y_self.eq(y_other), (Command::Do(f0_self, ), Command::Do(f0_other, ))=>f0_self.eq(f0_other), (Command::Jump, Command::Jump)=>true , _unused=>false + } + } +} +impl < > core::cmp::Eq for Command< > where {}"#]], + ); +} + +#[test] +fn test_partial_ord_expand() { + check( + r#" +//- minicore: derive, ord +#[derive(PartialOrd, Ord)] +enum Command { + Move { x: i32, y: i32 }, + Do(&'static str), + Jump, +} +"#, + expect![[r#" +#[derive(PartialOrd, Ord)] +enum Command { + Move { x: i32, y: i32 }, + Do(&'static str), + Jump, +} + +impl < > core::cmp::PartialOrd for Command< > where { + fn partial_cmp(&self , other: &Self ) -> core::option::Option::Option { + match core::intrinsics::discriminant_value(self ).partial_cmp(&core::intrinsics::discriminant_value(other)) { + core::option::Option::Some(core::cmp::Ordering::Equal)=> { + match (self , other) { + (Command::Move { + x: x_self, y: y_self, + } + , Command::Move { + x: x_other, y: y_other, + } + )=>match x_self.partial_cmp(&x_other) { + core::option::Option::Some(core::cmp::Ordering::Equal)=> { + match y_self.partial_cmp(&y_other) { + core::option::Option::Some(core::cmp::Ordering::Equal)=> { + core::option::Option::Some(core::cmp::Ordering::Equal) + } + c=>return c, + } + } + c=>return c, + } + , (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.partial_cmp(&f0_other) { + core::option::Option::Some(core::cmp::Ordering::Equal)=> { + core::option::Option::Some(core::cmp::Ordering::Equal) + } + c=>return c, + } + , (Command::Jump, Command::Jump)=>core::option::Option::Some(core::cmp::Ordering::Equal), _unused=>core::option::Option::Some(core::cmp::Ordering::Equal) + } + } + c=>return c, + } + } +} +impl < > core::cmp::Ord for Command< > where { + fn cmp(&self , other: &Self ) -> core::cmp::Ordering { + match core::intrinsics::discriminant_value(self ).cmp(&core::intrinsics::discriminant_value(other)) { + core::cmp::Ordering::Equal=> { + match (self , other) { + (Command::Move { + x: x_self, y: y_self, + } + , Command::Move { + x: x_other, y: y_other, + } + )=>match x_self.cmp(&x_other) { + core::cmp::Ordering::Equal=> { + match y_self.cmp(&y_other) { + core::cmp::Ordering::Equal=> { + core::cmp::Ordering::Equal + } + c=>return c, + } + } + c=>return c, + } + , (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.cmp(&f0_other) { + core::cmp::Ordering::Equal=> { + core::cmp::Ordering::Equal + } + c=>return c, + } + , (Command::Jump, Command::Jump)=>core::cmp::Ordering::Equal, _unused=>core::cmp::Ordering::Equal + } + } + c=>return c, + } + } +}"#]], + ); +} + +#[test] +fn test_hash_expand() { + check( + r#" +//- minicore: derive, hash +use core::hash::Hash; + +#[derive(Hash)] +enum Command { + Move { x: i32, y: i32 }, + Do(&'static str), + Jump, +} +"#, + expect![[r#" +use core::hash::Hash; + +#[derive(Hash)] +enum Command { + Move { x: i32, y: i32 }, + Do(&'static str), + Jump, +} + +impl < > core::hash::Hash for Command< > where { + fn hash(&self , state: &mut H) { + core::mem::discriminant(self ).hash(state); + match self { + Command::Move { + x: x, y: y, + } + => { + x.hash(state); + y.hash(state); + } + , Command::Do(f0, )=> { + f0.hash(state); + } + , Command::Jump=> {} + , + } + } +}"#]], + ); +} + +#[test] +fn test_debug_expand() { + check( + r#" +//- minicore: derive, fmt +use core::fmt::Debug; + +#[derive(Debug)] +enum Command { + Move { x: i32, y: i32 }, + Do(&'static str), + Jump, +} +"#, + expect![[r#" +use core::fmt::Debug; + +#[derive(Debug)] +enum Command { + Move { x: i32, y: i32 }, + Do(&'static str), + Jump, +} + +impl < > core::fmt::Debug for Command< > where { + fn fmt(&self , f: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Command::Move { + x: x, y: y, + } + =>f.debug_struct("Move").field("x", &x).field("y", &y).finish(), Command::Do(f0, )=>f.debug_tuple("Do").field(&f0).finish(), Command::Jump=>f.write_str("Jump"), + } + } +}"#]], ); } diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index 5fbd1789b3a9a..977f300636f5e 100644 --- a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -13,12 +13,12 @@ macro_rules! column {() => {}} fn main() { column!(); } "#, - expect![[r##" + expect![[r#" #[rustc_builtin_macro] macro_rules! column {() => {}} -fn main() { 0; } -"##]], +fn main() { 0 as u32; } +"#]], ); } @@ -31,12 +31,12 @@ macro_rules! line {() => {}} fn main() { line!() } "#, - expect![[r##" + expect![[r#" #[rustc_builtin_macro] macro_rules! line {() => {}} -fn main() { 0 } -"##]], +fn main() { 0 as u32 } +"#]], ); } @@ -97,7 +97,7 @@ fn main() { option_env!("TEST_ENV_VAR"); } #[rustc_builtin_macro] macro_rules! option_env {() => {}} -fn main() { $crate::option::Option::None:: < &str>; } +fn main() { ::core::option::Option::None:: < &str>; } "#]], ); } @@ -193,7 +193,7 @@ fn main() { format_args!("{} {:?}", arg1(a, b, c), arg2); } "#, - expect![[r#" + expect![[r##" #[rustc_builtin_macro] macro_rules! format_args { ($fmt:expr) => ({ /* compiler built-in */ }); @@ -201,9 +201,9 @@ macro_rules! format_args { } fn main() { - $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::Argument::new(&(arg1(a, b, c)), $crate::fmt::Display::fmt), $crate::fmt::Argument::new(&(arg2), $crate::fmt::Display::fmt), ]); + ::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::Argument::new(&(arg1(a, b, c)), ::core::fmt::Display::fmt), ::core::fmt::Argument::new(&(arg2), ::core::fmt::Debug::fmt), ]); } -"#]], +"##]], ); } @@ -221,7 +221,7 @@ fn main() { format_args!("{} {:?}", a::(), b); } "#, - expect![[r#" + expect![[r##" #[rustc_builtin_macro] macro_rules! format_args { ($fmt:expr) => ({ /* compiler built-in */ }); @@ -229,9 +229,76 @@ macro_rules! format_args { } fn main() { - $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::Argument::new(&(a::()), $crate::fmt::Display::fmt), $crate::fmt::Argument::new(&(b), $crate::fmt::Display::fmt), ]); + ::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::Argument::new(&(a::()), ::core::fmt::Display::fmt), ::core::fmt::Argument::new(&(b), ::core::fmt::Debug::fmt), ]); } -"#]], +"##]], + ); +} + +#[test] +fn test_format_args_expand_with_raw_strings() { + check( + r##" +#[rustc_builtin_macro] +macro_rules! format_args { + ($fmt:expr) => ({ /* compiler built-in */ }); + ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) +} + +fn main() { + format_args!( + r#"{},mismatch,"{}","{}""#, + location_csv_pat(db, &analysis, vfs, &sm, pat_id), + mismatch.expected.display(db), + mismatch.actual.display(db) + ); +} +"##, + expect![[r##" +#[rustc_builtin_macro] +macro_rules! format_args { + ($fmt:expr) => ({ /* compiler built-in */ }); + ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) +} + +fn main() { + ::core::fmt::Arguments::new_v1(&[r#""#, r#",mismatch,""#, r#"",""#, r#"""#, ], &[::core::fmt::Argument::new(&(location_csv_pat(db, &analysis, vfs, &sm, pat_id)), ::core::fmt::Display::fmt), ::core::fmt::Argument::new(&(mismatch.expected.display(db)), ::core::fmt::Display::fmt), ::core::fmt::Argument::new(&(mismatch.actual.display(db)), ::core::fmt::Display::fmt), ]); +} +"##]], + ); +} + +#[test] +fn test_format_args_expand_eager() { + check( + r#" +#[rustc_builtin_macro] +macro_rules! concat {} + +#[rustc_builtin_macro] +macro_rules! format_args { + ($fmt:expr) => ({ /* compiler built-in */ }); + ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) +} + +fn main() { + format_args!(concat!("xxx{}y", "{:?}zzz"), 2, b); +} +"#, + expect![[r##" +#[rustc_builtin_macro] +macro_rules! concat {} + +#[rustc_builtin_macro] +macro_rules! format_args { + ($fmt:expr) => ({ /* compiler built-in */ }); + ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) +} + +fn main() { + ::core::fmt::Arguments::new_v1(&["xxx", "y", "zzz", ], &[::core::fmt::Argument::new(&(2), ::core::fmt::Display::fmt), ::core::fmt::Argument::new(&(b), ::core::fmt::Debug::fmt), ]); +} +"##]], ); } @@ -250,7 +317,7 @@ fn main() { format_args!/*+errors*/("{} {:?}", a.); } "#, - expect![[r#" + expect![[r##" #[rustc_builtin_macro] macro_rules! format_args { ($fmt:expr) => ({ /* compiler built-in */ }); @@ -259,10 +326,10 @@ macro_rules! format_args { fn main() { let _ = - /* parse error: expected field name or number */ -$crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::Argument::new(&(a.), $crate::fmt::Display::fmt), ]); + /* error: no rule matches input tokens *//* parse error: expected field name or number */ +::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::Argument::new(&(a.), ::core::fmt::Display::fmt), ::core::fmt::Argument::new(&(), ::core::fmt::Debug::fmt), ]); } -"#]], +"##]], ); } diff --git a/crates/hir-def/src/macro_expansion_tests/mbe.rs b/crates/hir-def/src/macro_expansion_tests/mbe.rs index 7a3e8c3b05c91..553ffe3d0b88b 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -4,6 +4,7 @@ mod tt_conversion; mod matching; mod meta_syntax; +mod metavar_expr; mod regression; use expect_test::expect; @@ -98,7 +99,7 @@ fn#19 main#20(#21)#21 {#22 ); } #[test] -fn float_field_acces_macro_input() { +fn float_field_access_macro_input() { check( r#" macro_rules! foo { @@ -922,7 +923,7 @@ macro_rules! m { fn bar() -> &'a Baz {} -fn bar() -> extern "Rust"fn() -> Ret {} +fn bar() -> extern "Rust" fn() -> Ret {} "#]], ); } @@ -1293,19 +1294,53 @@ ok!(); } #[test] -fn test_vertical_bar_with_pat() { +fn test_vertical_bar_with_pat_param() { check( r#" -macro_rules! m { (|$pat:pat| ) => { ok!(); } } +macro_rules! m { (|$pat:pat_param| ) => { ok!(); } } m! { |x| } "#, expect![[r#" -macro_rules! m { (|$pat:pat| ) => { ok!(); } } +macro_rules! m { (|$pat:pat_param| ) => { ok!(); } } ok!(); "#]], ); } +#[test] +fn test_new_std_matches() { + check( + r#" +macro_rules! matches { + ($expression:expr, $pattern:pat $(if $guard:expr)? $(,)?) => { + match $expression { + $pattern $(if $guard)? => true, + _ => false + } + }; +} +fn main() { + matches!(0, 0 | 1 if true); +} + "#, + expect![[r#" +macro_rules! matches { + ($expression:expr, $pattern:pat $(if $guard:expr)? $(,)?) => { + match $expression { + $pattern $(if $guard)? => true, + _ => false + } + }; +} +fn main() { + match 0 { + 0|1 if true =>true , _=>false + }; +} + "#]], + ); +} + #[test] fn test_dollar_crate_lhs_is_not_meta() { check( @@ -1580,92 +1615,6 @@ struct Foo; ) } -#[test] -fn test_dollar_dollar() { - check( - r#" -macro_rules! register_struct { ($Struct:ident) => { - macro_rules! register_methods { ($$($method:ident),*) => { - macro_rules! implement_methods { ($$$$($$val:expr),*) => { - struct $Struct; - impl $Struct { $$(fn $method() -> &'static [u32] { &[$$$$($$$$val),*] })*} - }} - }} -}} - -register_struct!(Foo); -register_methods!(alpha, beta); -implement_methods!(1, 2, 3); -"#, - expect![[r#" -macro_rules! register_struct { ($Struct:ident) => { - macro_rules! register_methods { ($$($method:ident),*) => { - macro_rules! implement_methods { ($$$$($$val:expr),*) => { - struct $Struct; - impl $Struct { $$(fn $method() -> &'static [u32] { &[$$$$($$$$val),*] })*} - }} - }} -}} - -macro_rules !register_methods { - ($($method: ident), *) = > { - macro_rules!implement_methods { - ($$($val: expr), *) = > { - struct Foo; - impl Foo { - $(fn $method()-> &'static[u32] { - &[$$($$val), *] - } - )* - } - } - } - } -} -macro_rules !implement_methods { - ($($val: expr), *) = > { - struct Foo; - impl Foo { - fn alpha()-> &'static[u32] { - &[$($val), *] - } - fn beta()-> &'static[u32] { - &[$($val), *] - } - } - } -} -struct Foo; -impl Foo { - fn alpha() -> &'static[u32] { - &[1, 2, 3] - } - fn beta() -> &'static[u32] { - &[1, 2, 3] - } -} -"#]], - ) -} - -#[test] -fn test_metavar_exprs() { - check( - r#" -macro_rules! m { - ( $( $t:tt )* ) => ( $( ${ignore(t)} -${index()} )-* ); -} -const _: i32 = m!(a b c); - "#, - expect![[r#" -macro_rules! m { - ( $( $t:tt )* ) => ( $( ${ignore(t)} -${index()} )-* ); -} -const _: i32 = -0--1--2; - "#]], - ); -} - #[test] fn test_punct_without_space() { // Puncts are "glued" greedily. diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs b/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs index 26f16542cbb26..0909d8c835443 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs @@ -33,7 +33,7 @@ m!(&k"); "#, expect![[r#" macro_rules! m { ($i:literal) => {}; } -/* error: Failed to lower macro args to token tree */"#]], +/* error: invalid token tree */"#]], ); } @@ -73,7 +73,7 @@ fn main() { macro_rules! asi { ($($stmt:stmt)*) => ($($stmt)*); } fn main() { - let a = 2let b = 5drop(b-a)println!("{}", a+b) + let a = 2 let b = 5 drop(b-a)println!("{}", a+b) } "#]], ) @@ -106,7 +106,6 @@ stringify!(; #[test] fn range_patterns() { - // FIXME: rustc thinks there are three patterns here, not one. check( r#" macro_rules! m { @@ -118,7 +117,7 @@ m!(.. .. ..); macro_rules! m { ($($p:pat)*) => (stringify!($($p |)*);) } -stringify!(.. .. .. |); +stringify!(.. | .. | .. |); "#]], ); } diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs b/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs new file mode 100644 index 0000000000000..967b5ad36babf --- /dev/null +++ b/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs @@ -0,0 +1,311 @@ +//! Tests for RFC 3086 metavariable expressions. + +use expect_test::expect; + +use crate::macro_expansion_tests::check; + +#[test] +fn test_dollar_dollar() { + check( + r#" +macro_rules! register_struct { ($Struct:ident) => { + macro_rules! register_methods { ($$($method:ident),*) => { + macro_rules! implement_methods { ($$$$($$val:expr),*) => { + struct $Struct; + impl $Struct { $$(fn $method() -> &'static [u32] { &[$$$$($$$$val),*] })*} + }} + }} +}} + +register_struct!(Foo); +register_methods!(alpha, beta); +implement_methods!(1, 2, 3); +"#, + expect![[r#" +macro_rules! register_struct { ($Struct:ident) => { + macro_rules! register_methods { ($$($method:ident),*) => { + macro_rules! implement_methods { ($$$$($$val:expr),*) => { + struct $Struct; + impl $Struct { $$(fn $method() -> &'static [u32] { &[$$$$($$$$val),*] })*} + }} + }} +}} + +macro_rules !register_methods { + ($($method: ident), *) = > { + macro_rules!implement_methods { + ($$($val: expr), *) = > { + struct Foo; + impl Foo { + $(fn $method()-> &'static[u32] { + &[$$($$val), *] + } + )* + } + } + } + } +} +macro_rules !implement_methods { + ($($val: expr), *) = > { + struct Foo; + impl Foo { + fn alpha()-> &'static[u32] { + &[$($val), *] + } + fn beta()-> &'static[u32] { + &[$($val), *] + } + } + } +} +struct Foo; +impl Foo { + fn alpha() -> &'static[u32] { + &[1, 2, 3] + } + fn beta() -> &'static[u32] { + &[1, 2, 3] + } +} +"#]], + ) +} + +#[test] +fn test_metavar_exprs() { + check( + r#" +macro_rules! m { + ( $( $t:tt )* ) => ( $( ${ignore(t)} -${index()} )-* ); +} +const _: i32 = m!(a b c); + "#, + expect![[r#" +macro_rules! m { + ( $( $t:tt )* ) => ( $( ${ignore(t)} -${index()} )-* ); +} +const _: i32 = -0--1--2; + "#]], + ); +} + +#[test] +fn count_basic() { + check( + r#" +macro_rules! m { + ($($t:ident),*) => { + ${count(t)} + } +} + +fn test() { + m!(); + m!(a); + m!(a, a); +} +"#, + expect![[r#" +macro_rules! m { + ($($t:ident),*) => { + ${count(t)} + } +} + +fn test() { + 0; + 1; + 2; +} +"#]], + ); +} + +#[test] +fn count_with_depth() { + check( + r#" +macro_rules! foo { + ($( $( $($t:ident)* ),* );*) => { + $( + { + let depth_none = ${count(t)}; + let depth_zero = ${count(t, 0)}; + let depth_one = ${count(t, 1)}; + } + )* + } +} + +fn bar() { + foo!( + a a a, a, a a; + a a a + ) +} +"#, + expect![[r#" +macro_rules! foo { + ($( $( $($t:ident)* ),* );*) => { + $( + { + let depth_none = ${count(t)}; + let depth_zero = ${count(t, 0)}; + let depth_one = ${count(t, 1)}; + } + )* + } +} + +fn bar() { + { + let depth_none = 6; + let depth_zero = 3; + let depth_one = 6; + } { + let depth_none = 3; + let depth_zero = 1; + let depth_one = 3; + } +} +"#]], + ); +} + +#[test] +fn count_depth_out_of_bounds() { + check( + r#" +macro_rules! foo { + ($($t:ident)*) => { ${count(t, 1)} }; + ($( $( $l:literal )* );*) => { $(${count(l, 1)};)* } +} +macro_rules! bar { + ($($t:ident)*) => { ${count(t, 1024)} }; + ($( $( $l:literal )* );*) => { $(${count(l, 8192)};)* } +} + +fn test() { + foo!(a b); + foo!(1 2; 3); + bar!(a b); + bar!(1 2; 3); +} +"#, + expect![[r#" +macro_rules! foo { + ($($t:ident)*) => { ${count(t, 1)} }; + ($( $( $l:literal )* );*) => { $(${count(l, 1)};)* } +} +macro_rules! bar { + ($($t:ident)*) => { ${count(t, 1024)} }; + ($( $( $l:literal )* );*) => { $(${count(l, 8192)};)* } +} + +fn test() { + /* error: ${count} out of bounds */; + /* error: ${count} out of bounds */; + /* error: ${count} out of bounds */; + /* error: ${count} out of bounds */; +} +"#]], + ); +} + +#[test] +fn misplaced_count() { + check( + r#" +macro_rules! foo { + ($($t:ident)*) => { $(${count(t)})* }; + ($l:literal) => { ${count(l)} } +} + +fn test() { + foo!(a b c); + foo!(1); +} +"#, + expect![[r#" +macro_rules! foo { + ($($t:ident)*) => { $(${count(t)})* }; + ($l:literal) => { ${count(l)} } +} + +fn test() { + /* error: ${count} misplaced */; + /* error: ${count} misplaced */; +} +"#]], + ); +} + +#[test] +fn malformed_count() { + check( + r#" +macro_rules! too_many_args { + ($($t:ident)*) => { ${count(t, 1, leftover)} } +} +macro_rules! depth_suffixed { + ($($t:ident)*) => { ${count(t, 0usize)} } +} +macro_rules! depth_too_large { + ($($t:ident)*) => { ${count(t, 18446744073709551616)} } +} + +fn test() { + too_many_args!(); + depth_suffixed!(); + depth_too_large!(); +} +"#, + expect![[r#" +macro_rules! too_many_args { + ($($t:ident)*) => { ${count(t, 1, leftover)} } +} +macro_rules! depth_suffixed { + ($($t:ident)*) => { ${count(t, 0usize)} } +} +macro_rules! depth_too_large { + ($($t:ident)*) => { ${count(t, 18446744073709551616)} } +} + +fn test() { + /* error: invalid macro definition: invalid metavariable expression */; + /* error: invalid macro definition: invalid metavariable expression */; + /* error: invalid macro definition: invalid metavariable expression */; +} +"#]], + ); +} + +#[test] +fn count_interaction_with_empty_binding() { + // FIXME: Should this error? rustc currently accepts it. + check( + r#" +macro_rules! m { + ($($t:ident),*) => { + ${count(t, 100)} + } +} + +fn test() { + m!(); +} +"#, + expect![[r#" +macro_rules! m { + ($($t:ident),*) => { + ${count(t, 100)} + } +} + +fn test() { + 0; +} +"#]], + ); +} diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs index b663a2917897e..d8e4a4dcc7c2b 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs @@ -297,55 +297,55 @@ macro_rules! impl_fn_for_zst { #[derive(Clone)] struct CharEscapeDebugContinue; impl Fn<(char, )> for CharEscapeDebugContinue { - #[inline] extern "rust-call"fn call(&self , (c, ): (char, )) -> char::EscapeDebug { { + #[inline] extern "rust-call" fn call(&self , (c, ): (char, )) -> char::EscapeDebug { { c.escape_debug_ext(false ) } } } impl FnMut<(char, )> for CharEscapeDebugContinue { - #[inline] extern "rust-call"fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeDebug { + #[inline] extern "rust-call" fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeDebug { Fn::call(&*self , (c, )) } } impl FnOnce<(char, )> for CharEscapeDebugContinue { type Output = char::EscapeDebug; - #[inline] extern "rust-call"fn call_once(self , (c, ): (char, )) -> char::EscapeDebug { + #[inline] extern "rust-call" fn call_once(self , (c, ): (char, )) -> char::EscapeDebug { Fn::call(&self , (c, )) } } #[derive(Clone)] struct CharEscapeUnicode; impl Fn<(char, )> for CharEscapeUnicode { - #[inline] extern "rust-call"fn call(&self , (c, ): (char, )) -> char::EscapeUnicode { { + #[inline] extern "rust-call" fn call(&self , (c, ): (char, )) -> char::EscapeUnicode { { c.escape_unicode() } } } impl FnMut<(char, )> for CharEscapeUnicode { - #[inline] extern "rust-call"fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeUnicode { + #[inline] extern "rust-call" fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeUnicode { Fn::call(&*self , (c, )) } } impl FnOnce<(char, )> for CharEscapeUnicode { type Output = char::EscapeUnicode; - #[inline] extern "rust-call"fn call_once(self , (c, ): (char, )) -> char::EscapeUnicode { + #[inline] extern "rust-call" fn call_once(self , (c, ): (char, )) -> char::EscapeUnicode { Fn::call(&self , (c, )) } } #[derive(Clone)] struct CharEscapeDefault; impl Fn<(char, )> for CharEscapeDefault { - #[inline] extern "rust-call"fn call(&self , (c, ): (char, )) -> char::EscapeDefault { { + #[inline] extern "rust-call" fn call(&self , (c, ): (char, )) -> char::EscapeDefault { { c.escape_default() } } } impl FnMut<(char, )> for CharEscapeDefault { - #[inline] extern "rust-call"fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeDefault { + #[inline] extern "rust-call" fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeDefault { Fn::call(&*self , (c, )) } } impl FnOnce<(char, )> for CharEscapeDefault { type Output = char::EscapeDefault; - #[inline] extern "rust-call"fn call_once(self , (c, ): (char, )) -> char::EscapeDefault { + #[inline] extern "rust-call" fn call_once(self , (c, ): (char, )) -> char::EscapeDefault { Fn::call(&self , (c, )) } } @@ -833,7 +833,7 @@ macro_rules! rgb_color { /* parse error: expected SEMICOLON */ /* parse error: expected expression, item or let statement */ pub fn new() { - let _ = 0as u32<<(8+8); + let _ = 0 as u32<<(8+8); } // MACRO_ITEMS@0..31 // FN@0..31 diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs b/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs index b8d2ca687c9e0..ae56934f632f1 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs @@ -98,7 +98,7 @@ macro_rules! m1 { ($x:ident) => { ($x } } macro_rules! m2 { ($x:ident) => {} } /* error: invalid macro definition: expected subtree */ -/* error: Failed to lower macro args to token tree */ +/* error: invalid token tree */ "#]], ) } diff --git a/crates/hir-def/src/macro_expansion_tests.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs similarity index 86% rename from crates/hir-def/src/macro_expansion_tests.rs rename to crates/hir-def/src/macro_expansion_tests/mod.rs index 314bf22b95ee7..4a62696df0810 100644 --- a/crates/hir-def/src/macro_expansion_tests.rs +++ b/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -14,7 +14,7 @@ mod builtin_fn_macro; mod builtin_derive_macro; mod proc_macros; -use std::{iter, ops::Range, sync::Arc}; +use std::{iter, ops::Range, sync}; use ::mbe::TokenMap; use base_db::{fixture::WithFixture, ProcMacro, SourceDatabase}; @@ -33,8 +33,13 @@ use syntax::{ use tt::token_id::{Subtree, TokenId}; use crate::{ - db::DefDatabase, macro_id_to_def_id, nameres::ModuleSource, resolver::HasResolver, - src::HasSource, test_db::TestDB, AdtId, AsMacroCall, Lookup, ModuleDefId, + db::DefDatabase, + macro_id_to_def_id, + nameres::{DefMap, MacroSubNs, ModuleSource}, + resolver::HasResolver, + src::HasSource, + test_db::TestDB, + AdtId, AsMacroCall, Lookup, ModuleDefId, }; #[track_caller] @@ -50,13 +55,13 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream ProcMacro { name: "identity_when_valid".into(), kind: base_db::ProcMacroKind::Attr, - expander: Arc::new(IdentityWhenValidProcMacroExpander), + expander: sync::Arc::new(IdentityWhenValidProcMacroExpander), }, )]; let db = TestDB::with_files_extra_proc_macros(ra_fixture, extra_proc_macros); let krate = db.crate_graph().iter().next().unwrap(); let def_map = db.crate_def_map(krate); - let local_id = def_map.root(); + let local_id = DefMap::ROOT; let module = def_map.module_id(local_id); let resolver = module.resolver(&db); let source = def_map[local_id].definition_source(&db); @@ -125,21 +130,17 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream for macro_call in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) { let macro_call = InFile::new(source.file_id, ¯o_call); - let mut error = None; - let macro_call_id = macro_call - .as_call_id_with_errors( - &db, - krate, - |path| { - resolver.resolve_path_as_macro(&db, &path).map(|it| macro_id_to_def_id(&db, it)) - }, - &mut |err| error = Some(err), - ) - .unwrap() + let res = macro_call + .as_call_id_with_errors(&db, krate, |path| { + resolver + .resolve_path_as_macro(&db, &path, Some(MacroSubNs::Bang)) + .map(|it| macro_id_to_def_id(&db, it)) + }) .unwrap(); + let macro_call_id = res.value.unwrap(); let macro_file = MacroFile { macro_call_id }; let mut expansion_result = db.parse_macro_expansion(macro_file); - expansion_result.err = expansion_result.err.or(error); + expansion_result.err = expansion_result.err.or(res.err); expansions.push((macro_call.value.clone(), expansion_result, db.macro_arg(macro_call_id))); } @@ -157,34 +158,33 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream if let Some(err) = exp.err { format_to!(expn_text, "/* error: {} */", err); } - if let Some((parse, token_map)) = exp.value { - if expect_errors { - assert!(!parse.errors().is_empty(), "no parse errors in expansion"); - for e in parse.errors() { - format_to!(expn_text, "/* parse error: {} */\n", e); - } - } else { - assert!( - parse.errors().is_empty(), - "parse errors in expansion: \n{:#?}", - parse.errors() - ); + let (parse, token_map) = exp.value; + if expect_errors { + assert!(!parse.errors().is_empty(), "no parse errors in expansion"); + for e in parse.errors() { + format_to!(expn_text, "/* parse error: {} */\n", e); } - let pp = pretty_print_macro_expansion( - parse.syntax_node(), - show_token_ids.then_some(&*token_map), + } else { + assert!( + parse.errors().is_empty(), + "parse errors in expansion: \n{:#?}", + parse.errors() ); - let indent = IndentLevel::from_node(call.syntax()); - let pp = reindent(indent, pp); - format_to!(expn_text, "{}", pp); + } + let pp = pretty_print_macro_expansion( + parse.syntax_node(), + show_token_ids.then_some(&*token_map), + ); + let indent = IndentLevel::from_node(call.syntax()); + let pp = reindent(indent, pp); + format_to!(expn_text, "{}", pp); - if tree { - let tree = format!("{:#?}", parse.syntax_node()) - .split_inclusive('\n') - .map(|line| format!("// {line}")) - .collect::(); - format_to!(expn_text, "\n{}", tree) - } + if tree { + let tree = format!("{:#?}", parse.syntax_node()) + .split_inclusive('\n') + .map(|line| format!("// {line}")) + .collect::(); + format_to!(expn_text, "\n{}", tree) } let range = call.syntax().text_range(); let range: Range = range.into(); @@ -287,6 +287,7 @@ fn pretty_print_macro_expansion(expn: SyntaxNode, map: Option<&TokenMap>) -> Str let curr_kind = token.kind(); let space = match (prev_kind, curr_kind) { _ if prev_kind.is_trivia() || curr_kind.is_trivia() => "", + _ if prev_kind.is_literal() && !curr_kind.is_punct() => " ", (T!['{'], T!['}']) => "", (T![=], _) | (_, T![=]) => " ", (_, T!['{']) => " ", diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 4efe8c58a69e3..9b520bc3030f0 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -57,9 +57,9 @@ mod path_resolution; #[cfg(test)] mod tests; -use std::{cmp::Ord, ops::Deref, sync::Arc}; +use std::{cmp::Ord, ops::Deref}; -use base_db::{CrateId, Edition, FileId}; +use base_db::{CrateId, Edition, FileId, ProcMacroKind}; use hir_expand::{name::Name, InFile, MacroCallId, MacroDefId}; use itertools::Itertools; use la_arena::Arena; @@ -67,6 +67,7 @@ use profile::Count; use rustc_hash::{FxHashMap, FxHashSet}; use stdx::format_to; use syntax::{ast, SmolStr}; +use triomphe::Arc; use crate::{ db::DefDatabase, @@ -76,7 +77,8 @@ use crate::{ path::ModPath, per_ns::PerNs, visibility::Visibility, - AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, MacroId, ModuleId, ProcMacroId, + AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, + ProcMacroId, }; /// Contains the results of (early) name resolution. @@ -92,7 +94,6 @@ use crate::{ pub struct DefMap { _c: Count, block: Option, - root: LocalModuleId, modules: Arena, krate: CrateId, /// The prelude module for this crate. This either comes from an import @@ -102,7 +103,22 @@ pub struct DefMap { /// but that attribute is nightly and when used in a block, it affects resolution globally /// so we aren't handling this correctly anyways). prelude: Option, - /// The extern prelude is only populated for non-block DefMaps + /// `macro_use` prelude that contains macros from `#[macro_use]`'d external crates. Note that + /// this contains all kinds of macro, not just `macro_rules!` macro. + macro_use_prelude: FxHashMap, + + /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper + /// attributes. + derive_helpers_in_scope: FxHashMap, Vec<(Name, MacroId, MacroCallId)>>, + + diagnostics: Vec, + + data: Arc, +} + +/// Data that belongs to a crate which is shared between a crate's def map and all its block def maps. +#[derive(Clone, Debug, PartialEq, Eq)] +struct DefMapCrateData { extern_prelude: FxHashMap, /// Side table for resolving derive helpers. @@ -110,9 +126,6 @@ pub struct DefMap { fn_proc_macro_mapping: FxHashMap, /// The error that occurred when failing to load the proc-macro dll. proc_macro_loading_error: Option>, - /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper - /// attributes. - derive_helpers_in_scope: FxHashMap, Vec<(Name, MacroId, MacroCallId)>>, /// Custom attributes registered with `#![register_attr]`. registered_attrs: Vec, @@ -122,10 +135,36 @@ pub struct DefMap { unstable_features: FxHashSet, /// #[rustc_coherence_is_core] rustc_coherence_is_core: bool, + no_core: bool, + no_std: bool, edition: Edition, recursion_limit: Option, - diagnostics: Vec, +} + +impl DefMapCrateData { + fn shrink_to_fit(&mut self) { + let Self { + extern_prelude, + exported_derives, + fn_proc_macro_mapping, + registered_attrs, + registered_tools, + unstable_features, + proc_macro_loading_error: _, + rustc_coherence_is_core: _, + no_core: _, + no_std: _, + edition: _, + recursion_limit: _, + } = self; + extern_prelude.shrink_to_fit(); + exported_derives.shrink_to_fit(); + fn_proc_macro_mapping.shrink_to_fit(); + registered_attrs.shrink_to_fit(); + registered_tools.shrink_to_fit(); + unstable_features.shrink_to_fit(); + } } /// For `DefMap`s computed for a block expression, this stores its location in the parent map. @@ -134,7 +173,23 @@ struct BlockInfo { /// The `BlockId` this `DefMap` was created from. block: BlockId, /// The containing module. - parent: ModuleId, + parent: BlockRelativeModuleId, +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +struct BlockRelativeModuleId { + block: Option, + local_id: LocalModuleId, +} + +impl BlockRelativeModuleId { + fn def_map(self, db: &dyn DefDatabase, krate: CrateId) -> Arc { + self.into_module(krate).def_map(db) + } + + fn into_module(self, krate: CrateId) -> ModuleId { + ModuleId { krate, block: self.block, local_id: self.local_id } + } } impl std::ops::Index for DefMap { @@ -224,6 +279,8 @@ pub struct ModuleData { } impl DefMap { + pub const ROOT: LocalModuleId = LocalModuleId::from_raw(la_arena::RawIdx::from_u32(0)); + pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc { let _p = profile::span("crate_def_map_query").detail(|| { db.crate_graph()[krate].display_name.as_deref().unwrap_or_default().to_string() @@ -243,17 +300,10 @@ impl DefMap { Arc::new(def_map) } - pub(crate) fn block_def_map_query( - db: &dyn DefDatabase, - block_id: BlockId, - ) -> Option> { + pub(crate) fn block_def_map_query(db: &dyn DefDatabase, block_id: BlockId) -> Arc { let block: BlockLoc = db.lookup_intern_block(block_id); let tree_id = TreeId::new(block.ast_id.file_id, Some(block_id)); - let item_tree = tree_id.item_tree(db); - if item_tree.top_level_items().is_empty() { - return None; - } let parent_map = block.module.def_map(db); let krate = block.module.krate; @@ -265,36 +315,48 @@ impl DefMap { let module_data = ModuleData::new(ModuleOrigin::BlockExpr { block: block.ast_id }, visibility); - let mut def_map = DefMap::empty(krate, parent_map.edition, module_data); - def_map.block = Some(BlockInfo { block: block_id, parent: block.module }); + let mut def_map = DefMap::empty(krate, parent_map.data.edition, module_data); + def_map.data = parent_map.data.clone(); + def_map.block = Some(BlockInfo { + block: block_id, + parent: BlockRelativeModuleId { + block: block.module.block, + local_id: block.module.local_id, + }, + }); let def_map = collector::collect_defs(db, def_map, tree_id); - Some(Arc::new(def_map)) + Arc::new(def_map) } fn empty(krate: CrateId, edition: Edition, module_data: ModuleData) -> DefMap { let mut modules: Arena = Arena::default(); let root = modules.alloc(module_data); + assert_eq!(root, Self::ROOT); DefMap { _c: Count::new(), block: None, + modules, krate, - edition, - recursion_limit: None, - extern_prelude: FxHashMap::default(), - exported_derives: FxHashMap::default(), - fn_proc_macro_mapping: FxHashMap::default(), - proc_macro_loading_error: None, - derive_helpers_in_scope: FxHashMap::default(), prelude: None, - root, - modules, - registered_attrs: Vec::new(), - registered_tools: Vec::new(), - unstable_features: FxHashSet::default(), + macro_use_prelude: FxHashMap::default(), + derive_helpers_in_scope: FxHashMap::default(), diagnostics: Vec::new(), - rustc_coherence_is_core: false, + data: Arc::new(DefMapCrateData { + extern_prelude: FxHashMap::default(), + exported_derives: FxHashMap::default(), + fn_proc_macro_mapping: FxHashMap::default(), + proc_macro_loading_error: None, + registered_attrs: Vec::new(), + registered_tools: Vec::new(), + unstable_features: FxHashSet::default(), + rustc_coherence_is_core: false, + no_core: false, + no_std: false, + edition, + recursion_limit: None, + }), } } @@ -317,31 +379,31 @@ impl DefMap { } pub fn registered_tools(&self) -> &[SmolStr] { - &self.registered_tools + &self.data.registered_tools } pub fn registered_attrs(&self) -> &[SmolStr] { - &self.registered_attrs + &self.data.registered_attrs } pub fn is_unstable_feature_enabled(&self, feature: &str) -> bool { - self.unstable_features.contains(feature) + self.data.unstable_features.contains(feature) } pub fn is_rustc_coherence_is_core(&self) -> bool { - self.rustc_coherence_is_core + self.data.rustc_coherence_is_core } - pub fn root(&self) -> LocalModuleId { - self.root + pub fn is_no_std(&self) -> bool { + self.data.no_std || self.data.no_core } pub fn fn_as_proc_macro(&self, id: FunctionId) -> Option { - self.fn_proc_macro_mapping.get(&id).copied() + self.data.fn_proc_macro_mapping.get(&id).copied() } pub fn proc_macro_loading_error(&self) -> Option<&str> { - self.proc_macro_loading_error.as_deref() + self.data.proc_macro_loading_error.as_deref() } pub fn krate(&self) -> CrateId { @@ -356,8 +418,12 @@ impl DefMap { self.prelude } - pub(crate) fn extern_prelude(&self) -> impl Iterator + '_ { - self.extern_prelude.iter() + pub(crate) fn extern_prelude(&self) -> impl Iterator + '_ { + self.data.extern_prelude.iter().map(|(name, def)| (name, *def)) + } + + pub(crate) fn macro_use_prelude(&self) -> impl Iterator + '_ { + self.macro_use_prelude.iter().map(|(name, def)| (name, *def)) } pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId { @@ -365,11 +431,8 @@ impl DefMap { ModuleId { krate: self.krate, local_id, block } } - pub(crate) fn crate_root(&self, db: &dyn DefDatabase) -> ModuleId { - self.with_ancestor_maps(db, self.root, &mut |def_map, _module| { - if def_map.block.is_none() { Some(def_map.module_id(def_map.root)) } else { None } - }) - .expect("DefMap chain without root") + pub(crate) fn crate_root(&self) -> ModuleId { + ModuleId { krate: self.krate, block: None, local_id: DefMap::ROOT } } pub(crate) fn resolve_path( @@ -378,9 +441,16 @@ impl DefMap { original_module: LocalModuleId, path: &ModPath, shadow: BuiltinShadowMode, + expected_macro_subns: Option, ) -> (PerNs, Option) { - let res = - self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow); + let res = self.resolve_path_fp_with_macro( + db, + ResolveMode::Other, + original_module, + path, + shadow, + expected_macro_subns, + ); (res.resolved_def, res.segment_index) } @@ -397,6 +467,7 @@ impl DefMap { original_module, path, shadow, + None, // Currently this function isn't used for macro resolution. ); (res.resolved_def, res.segment_index) } @@ -416,7 +487,7 @@ impl DefMap { } let mut block = self.block; while let Some(block_info) = block { - let parent = block_info.parent.def_map(db); + let parent = block_info.parent.def_map(db, self.krate); if let Some(it) = f(&parent, block_info.parent.local_id) { return Some(it); } @@ -429,7 +500,8 @@ impl DefMap { /// If this `DefMap` is for a block expression, returns the module containing the block (which /// might again be a block, or a module inside a block). pub fn parent(&self) -> Option { - Some(self.block?.parent) + let BlockRelativeModuleId { block, local_id } = self.block?.parent; + Some(ModuleId { krate: self.krate, block, local_id }) } /// Returns the module containing `local_mod`, either the parent `mod`, or the module (or block) containing @@ -437,7 +509,13 @@ impl DefMap { pub fn containing_module(&self, local_mod: LocalModuleId) -> Option { match self[local_mod].parent { Some(parent) => Some(self.module_id(parent)), - None => self.block.map(|block| block.parent), + None => { + self.block.map( + |BlockInfo { parent: BlockRelativeModuleId { block, local_id }, .. }| { + ModuleId { krate: self.krate, block, local_id } + }, + ) + } } } @@ -448,25 +526,31 @@ impl DefMap { let mut arc; let mut current_map = self; while let Some(block) = current_map.block { - go(&mut buf, current_map, "block scope", current_map.root); + go(&mut buf, db, current_map, "block scope", Self::ROOT); buf.push('\n'); - arc = block.parent.def_map(db); + arc = block.parent.def_map(db, self.krate); current_map = &arc; } - go(&mut buf, current_map, "crate", current_map.root); + go(&mut buf, db, current_map, "crate", Self::ROOT); return buf; - fn go(buf: &mut String, map: &DefMap, path: &str, module: LocalModuleId) { + fn go( + buf: &mut String, + db: &dyn DefDatabase, + map: &DefMap, + path: &str, + module: LocalModuleId, + ) { format_to!(buf, "{}\n", path); - map.modules[module].scope.dump(buf); + map.modules[module].scope.dump(db.upcast(), buf); for (name, child) in map.modules[module].children.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0)) { - let path = format!("{path}::{name}"); + let path = format!("{path}::{}", name.display(db.upcast())); buf.push('\n'); - go(buf, map, &path, *child); + go(buf, db, map, &path, *child); } } } @@ -477,7 +561,7 @@ impl DefMap { let mut current_map = self; while let Some(block) = current_map.block { format_to!(buf, "{:?} in {:?}\n", block.block, block.parent); - arc = block.parent.def_map(db); + arc = block.parent.def_map(db, self.krate); current_map = &arc; } @@ -489,34 +573,20 @@ impl DefMap { // Exhaustive match to require handling new fields. let Self { _c: _, - exported_derives, - extern_prelude, + macro_use_prelude, diagnostics, modules, - registered_attrs, - registered_tools, - fn_proc_macro_mapping, derive_helpers_in_scope, - unstable_features, - proc_macro_loading_error: _, block: _, - edition: _, - recursion_limit: _, krate: _, prelude: _, - root: _, - rustc_coherence_is_core: _, + data: _, } = self; - extern_prelude.shrink_to_fit(); - exported_derives.shrink_to_fit(); + macro_use_prelude.shrink_to_fit(); diagnostics.shrink_to_fit(); modules.shrink_to_fit(); - registered_attrs.shrink_to_fit(); - registered_tools.shrink_to_fit(); - fn_proc_macro_mapping.shrink_to_fit(); derive_helpers_in_scope.shrink_to_fit(); - unstable_features.shrink_to_fit(); for (_, module) in modules.iter_mut() { module.children.shrink_to_fit(); module.scope.shrink_to_fit(); @@ -529,7 +599,7 @@ impl DefMap { } pub fn recursion_limit(&self) -> Option { - self.recursion_limit + self.data.recursion_limit } } @@ -564,3 +634,48 @@ pub enum ModuleSource { Module(ast::Module), BlockExpr(ast::BlockExpr), } + +/// See `sub_namespace_match()`. +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum MacroSubNs { + /// Function-like macros, suffixed with `!`. + Bang, + /// Macros inside attributes, i.e. attribute macros and derive macros. + Attr, +} + +impl MacroSubNs { + fn from_id(db: &dyn DefDatabase, macro_id: MacroId) -> Self { + let expander = match macro_id { + MacroId::Macro2Id(it) => it.lookup(db).expander, + MacroId::MacroRulesId(it) => it.lookup(db).expander, + MacroId::ProcMacroId(it) => { + return match it.lookup(db).kind { + ProcMacroKind::CustomDerive | ProcMacroKind::Attr => Self::Attr, + ProcMacroKind::FuncLike => Self::Bang, + }; + } + }; + + // Eager macros aren't *guaranteed* to be bang macros, but they *are* all bang macros currently. + match expander { + MacroExpander::Declarative + | MacroExpander::BuiltIn(_) + | MacroExpander::BuiltInEager(_) => Self::Bang, + MacroExpander::BuiltInAttr(_) | MacroExpander::BuiltInDerive(_) => Self::Attr, + } + } +} + +/// Quoted from [rustc]: +/// Macro namespace is separated into two sub-namespaces, one for bang macros and +/// one for attribute-like macros (attributes, derives). +/// We ignore resolutions from one sub-namespace when searching names in scope for another. +/// +/// [rustc]: https://github.com/rust-lang/rust/blob/1.69.0/compiler/rustc_resolve/src/macros.rs#L75 +fn sub_namespace_match(candidate: Option, expected: Option) -> bool { + match (candidate, expected) { + (Some(candidate), Some(expected)) => candidate == expected, + _ => true, + } +} diff --git a/crates/hir-def/src/nameres/attr_resolution.rs b/crates/hir-def/src/nameres/attr_resolution.rs index 79cabeb0fb7a4..a7abf445918aa 100644 --- a/crates/hir-def/src/nameres/attr_resolution.rs +++ b/crates/hir-def/src/nameres/attr_resolution.rs @@ -4,7 +4,8 @@ use hir_expand::{attrs::Attr, MacroCallId}; use syntax::{ast, SmolStr}; use crate::{ - attr_macro_as_call_id, builtin_attr, + attr::builtin::{find_builtin_attr_idx, TOOL_MODULES}, + attr_macro_as_call_id, db::DefDatabase, item_scope::BuiltinShadowMode, macro_id_to_def_id, @@ -13,7 +14,7 @@ use crate::{ AstIdWithPath, LocalModuleId, UnresolvedMacro, }; -use super::DefMap; +use super::{DefMap, MacroSubNs}; pub enum ResolvedAttr { /// Attribute resolved to an attribute macro. @@ -42,9 +43,12 @@ impl DefMap { original_module, &ast_id.path, BuiltinShadowMode::Module, + Some(MacroSubNs::Attr), ); let def = match resolved_res.resolved_def.take_macros() { Some(def) => { + // `MacroSubNs` is just a hint, so the path may still resolve to a custom derive + // macro, or even function-like macro when the path is qualified. if def.is_attribute(db) { def } else { @@ -60,7 +64,6 @@ impl DefMap { attr, self.krate, macro_id_to_def_id(db, def), - false, ))) } @@ -75,20 +78,16 @@ impl DefMap { let name = name.to_smol_str(); let pred = |n: &_| *n == name; - let registered = self.registered_tools.iter().map(SmolStr::as_str); - let is_tool = builtin_attr::TOOL_MODULES.iter().copied().chain(registered).any(pred); + let registered = self.data.registered_tools.iter().map(SmolStr::as_str); + let is_tool = TOOL_MODULES.iter().copied().chain(registered).any(pred); // FIXME: tool modules can be shadowed by actual modules if is_tool { return true; } if segments.len() == 1 { - let registered = self.registered_attrs.iter().map(SmolStr::as_str); - let is_inert = builtin_attr::INERT_ATTRIBUTES - .iter() - .map(|it| it.name) - .chain(registered) - .any(pred); + let mut registered = self.data.registered_attrs.iter().map(SmolStr::as_str); + let is_inert = find_builtin_attr_idx(&name).is_some() || registered.any(pred); return is_inert; } } diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index ddcee77ec4ccf..06542b4b1e999 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -5,7 +5,7 @@ use std::{iter, mem}; -use base_db::{CrateId, Edition, FileId}; +use base_db::{CrateId, Dependency, Edition, FileId}; use cfg::{CfgExpr, CfgOptions}; use either::Either; use hir_expand::{ @@ -14,10 +14,11 @@ use hir_expand::{ builtin_attr_macro::find_builtin_attr, builtin_derive_macro::find_builtin_derive, builtin_fn_macro::find_builtin_macro, + hygiene::Hygiene, name::{name, AsName, Name}, proc_macro::ProcMacroExpander, - ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, - MacroDefKind, + ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc, + MacroDefId, MacroDefKind, }; use itertools::{izip, Itertools}; use la_arena::Idx; @@ -25,6 +26,7 @@ use limit::Limit; use rustc_hash::{FxHashMap, FxHashSet}; use stdx::always; use syntax::{ast, SmolStr}; +use triomphe::Arc; use crate::{ attr::Attrs, @@ -33,8 +35,8 @@ use crate::{ derive_macro_as_call_id, item_scope::{ImportType, PerNsGlobImports}, item_tree::{ - self, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode, MacroCall, - MacroDef, MacroRules, Mod, ModItem, ModKind, TreeId, + self, ExternCrate, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode, + MacroCall, MacroDef, MacroRules, Mod, ModItem, ModKind, TreeId, }, macro_call_as_call_id, macro_id_to_def_id, nameres::{ @@ -42,7 +44,8 @@ use crate::{ mod_resolution::ModDir, path_resolution::ReachedFixedPoint, proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroDef, ProcMacroKind}, - BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode, + sub_namespace_match, BuiltinShadowMode, DefMap, MacroSubNs, ModuleData, ModuleOrigin, + ResolveMode, }, path::{ImportAlias, ModPath, PathKind}, per_ns::PerNs, @@ -59,7 +62,7 @@ static GLOB_RECURSION_LIMIT: Limit = Limit::new(100); static EXPANSION_DEPTH_LIMIT: Limit = Limit::new(128); static FIXED_POINT_LIMIT: Limit = Limit::new(8192); -pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: TreeId) -> DefMap { +pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeId) -> DefMap { let crate_graph = db.crate_graph(); let mut deps = FxHashMap::default(); @@ -67,36 +70,33 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T let krate = &crate_graph[def_map.krate]; for dep in &krate.dependencies { tracing::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id); - let dep_def_map = db.crate_def_map(dep.crate_id); - let dep_root = dep_def_map.module_id(dep_def_map.root); - deps.insert(dep.as_name(), dep_root); - - if dep.is_prelude() && !tree_id.is_block() { - def_map.extern_prelude.insert(dep.as_name(), dep_root); - } + deps.insert(dep.as_name(), dep.clone()); } let cfg_options = &krate.cfg_options; - let proc_macros = match &krate.proc_macro { - Ok(proc_macros) => { - proc_macros - .iter() - .enumerate() - .map(|(idx, it)| { - // FIXME: a hacky way to create a Name from string. - let name = - tt::Ident { text: it.name.clone(), span: tt::TokenId::unspecified() }; - (name.as_name(), ProcMacroExpander::new(base_db::ProcMacroId(idx as u32))) - }) - .collect() - } - Err(e) => { - def_map.proc_macro_loading_error = Some(e.clone().into_boxed_str()); - Vec::new() + + let is_proc_macro = krate.is_proc_macro; + let proc_macros = if is_proc_macro { + match db.proc_macros().get(&def_map.krate) { + Some(Ok(proc_macros)) => { + Ok(proc_macros + .iter() + .enumerate() + .map(|(idx, it)| { + // FIXME: a hacky way to create a Name from string. + let name = + tt::Ident { text: it.name.clone(), span: tt::TokenId::unspecified() }; + (name.as_name(), ProcMacroExpander::new(base_db::ProcMacroId(idx as u32))) + }) + .collect()) + } + Some(Err(e)) => Err(e.clone().into_boxed_str()), + None => Err("No proc-macros present for crate".to_owned().into_boxed_str()), } + } else { + Ok(vec![]) }; - let is_proc_macro = krate.is_proc_macro; let mut collector = DefCollector { db, @@ -112,6 +112,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T from_glob_import: Default::default(), skip_attrs: Default::default(), is_proc_macro, + hygienes: FxHashMap::default(), }; if tree_id.is_block() { collector.seed_with_inner(tree_id); @@ -238,7 +239,7 @@ enum MacroDirectiveKind { struct DefCollector<'a> { db: &'a dyn DefDatabase, def_map: DefMap, - deps: FxHashMap, + deps: FxHashMap, glob_imports: FxHashMap>, unresolved_imports: Vec, indeterminate_imports: Vec, @@ -249,7 +250,7 @@ struct DefCollector<'a> { /// built by the build system, and is the list of proc. macros we can actually expand. It is /// empty when proc. macro support is disabled (in which case we still do name resolution for /// them). - proc_macros: Vec<(Name, ProcMacroExpander)>, + proc_macros: Result, Box>, is_proc_macro: bool, from_glob_import: PerNsGlobImports, /// If we fail to resolve an attribute on a `ModItem`, we fall back to ignoring the attribute. @@ -259,6 +260,12 @@ struct DefCollector<'a> { /// This also stores the attributes to skip when we resolve derive helpers and non-macro /// non-builtin attributes in general. skip_attrs: FxHashMap, AttrId>, + /// `Hygiene` cache, because `Hygiene` construction is expensive. + /// + /// Almost all paths should have been lowered to `ModPath` during `ItemTree` construction. + /// However, `DefCollector` still needs to lower paths in attributes, in particular those in + /// derive meta item list. + hygienes: FxHashMap, } impl DefCollector<'_> { @@ -267,86 +274,117 @@ impl DefCollector<'_> { let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; let item_tree = self.db.file_item_tree(file_id.into()); - let module_id = self.def_map.root; + let module_id = DefMap::ROOT; let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate); - if attrs.cfg().map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) { - self.inject_prelude(&attrs); - - // Process other crate-level attributes. - for attr in &*attrs { - let attr_name = match attr.path.as_ident() { - Some(name) => name, - None => continue, - }; + let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap(); - if *attr_name == hir_expand::name![recursion_limit] { - if let Some(limit) = attr.string_value() { - if let Ok(limit) = limit.parse() { - self.def_map.recursion_limit = Some(limit); - } - } - continue; + if let Err(e) = &self.proc_macros { + crate_data.proc_macro_loading_error = Some(e.clone()); + } + + for (name, dep) in &self.deps { + if dep.is_prelude() { + crate_data.extern_prelude.insert( + name.clone(), + ModuleId { krate: dep.crate_id, block: None, local_id: DefMap::ROOT }, + ); + } + } + + // Process other crate-level attributes. + for attr in &*attrs { + if let Some(cfg) = attr.cfg() { + if self.cfg_options.check(&cfg) == Some(false) { + return; } + } + let attr_name = match attr.path.as_ident() { + Some(name) => name, + None => continue, + }; - if *attr_name == hir_expand::name![crate_type] { - if let Some("proc-macro") = attr.string_value().map(SmolStr::as_str) { - self.is_proc_macro = true; + if *attr_name == hir_expand::name![recursion_limit] { + if let Some(limit) = attr.string_value() { + if let Ok(limit) = limit.parse() { + crate_data.recursion_limit = Some(limit); } - continue; } + continue; + } - if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") { - self.def_map.rustc_coherence_is_core = true; - continue; + if *attr_name == hir_expand::name![crate_type] { + if let Some("proc-macro") = attr.string_value().map(SmolStr::as_str) { + self.is_proc_macro = true; } + continue; + } - if *attr_name == hir_expand::name![feature] { - let features = - attr.parse_path_comma_token_tree().into_iter().flatten().filter_map( - |feat| match feat.segments() { - [name] => Some(name.to_smol_str()), - _ => None, - }, - ); - self.def_map.unstable_features.extend(features); - } + if *attr_name == hir_expand::name![no_core] { + crate_data.no_core = true; + continue; + } - let attr_is_register_like = *attr_name == hir_expand::name![register_attr] - || *attr_name == hir_expand::name![register_tool]; - if !attr_is_register_like { - continue; - } + if *attr_name == hir_expand::name![no_std] { + crate_data.no_std = true; + continue; + } - let registered_name = match attr.single_ident_value() { - Some(ident) => ident.as_name(), - _ => continue, - }; + if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") { + crate_data.rustc_coherence_is_core = true; + continue; + } - if *attr_name == hir_expand::name![register_attr] { - self.def_map.registered_attrs.push(registered_name.to_smol_str()); - cov_mark::hit!(register_attr); - } else { - self.def_map.registered_tools.push(registered_name.to_smol_str()); - cov_mark::hit!(register_tool); - } + if *attr_name == hir_expand::name![feature] { + let hygiene = &Hygiene::new_unhygienic(); + let features = attr + .parse_path_comma_token_tree(self.db.upcast(), hygiene) + .into_iter() + .flatten() + .filter_map(|feat| match feat.segments() { + [name] => Some(name.to_smol_str()), + _ => None, + }); + crate_data.unstable_features.extend(features); } - ModCollector { - def_collector: self, - macro_depth: 0, - module_id, - tree_id: TreeId::new(file_id.into(), None), - item_tree: &item_tree, - mod_dir: ModDir::root(), + let attr_is_register_like = *attr_name == hir_expand::name![register_attr] + || *attr_name == hir_expand::name![register_tool]; + if !attr_is_register_like { + continue; + } + + let registered_name = match attr.single_ident_value() { + Some(ident) => ident.as_name(), + _ => continue, + }; + + if *attr_name == hir_expand::name![register_attr] { + crate_data.registered_attrs.push(registered_name.to_smol_str()); + cov_mark::hit!(register_attr); + } else { + crate_data.registered_tools.push(registered_name.to_smol_str()); + cov_mark::hit!(register_tool); } - .collect_in_top_module(item_tree.top_level_items()); } + + crate_data.shrink_to_fit(); + self.inject_prelude(); + + ModCollector { + def_collector: self, + macro_depth: 0, + module_id, + tree_id: TreeId::new(file_id.into(), None), + item_tree: &item_tree, + mod_dir: ModDir::root(), + } + .collect_in_top_module(item_tree.top_level_items()); } fn seed_with_inner(&mut self, tree_id: TreeId) { let item_tree = tree_id.item_tree(self.db); - let module_id = self.def_map.root; + let module_id = DefMap::ROOT; let is_cfg_enabled = item_tree .top_level_attrs(self.db, self.def_map.krate) @@ -428,7 +466,7 @@ impl DefCollector<'_> { // Additionally, while the proc macro entry points must be `pub`, they are not publicly // exported in type/value namespace. This function reduces the visibility of all items // in the crate root that aren't proc macros. - let root = self.def_map.root; + let root = DefMap::ROOT; let module_id = self.def_map.module_id(root); let root = &mut self.def_map.modules[root]; root.scope.censor_non_proc_macros(module_id); @@ -456,12 +494,8 @@ impl DefCollector<'_> { directive.module_id, MacroCallKind::Attr { ast_id: ast_id.ast_id, - attr_args: std::sync::Arc::new(( - tt::Subtree::empty(), - Default::default(), - )), + attr_args: Arc::new((tt::Subtree::empty(), Default::default())), invoc_attr_index: attr.id, - is_derive: false, }, attr.path().clone(), )); @@ -495,15 +529,15 @@ impl DefCollector<'_> { } } - fn inject_prelude(&mut self, crate_attrs: &Attrs) { + fn inject_prelude(&mut self) { // See compiler/rustc_builtin_macros/src/standard_library_imports.rs - if crate_attrs.by_key("no_core").exists() { + if self.def_map.data.no_core { // libcore does not get a prelude. return; } - let krate = if crate_attrs.by_key("no_std").exists() { + let krate = if self.def_map.data.no_std { name![core] } else { let std = name![std]; @@ -516,43 +550,31 @@ impl DefCollector<'_> { } }; - let edition = match self.def_map.edition { + let edition = match self.def_map.data.edition { Edition::Edition2015 => name![rust_2015], Edition::Edition2018 => name![rust_2018], Edition::Edition2021 => name![rust_2021], }; - let path_kind = match self.def_map.edition { + let path_kind = match self.def_map.data.edition { Edition::Edition2015 => PathKind::Plain, _ => PathKind::Abs, }; - let path = - ModPath::from_segments(path_kind, [krate.clone(), name![prelude], edition].into_iter()); - // Fall back to the older `std::prelude::v1` for compatibility with Rust <1.52.0 - // FIXME remove this fallback - let fallback_path = - ModPath::from_segments(path_kind, [krate, name![prelude], name![v1]].into_iter()); - - for path in &[path, fallback_path] { - let (per_ns, _) = self.def_map.resolve_path( - self.db, - self.def_map.root, - path, - BuiltinShadowMode::Other, - ); + let path = ModPath::from_segments(path_kind, [krate, name![prelude], edition]); - match per_ns.types { - Some((ModuleDefId::ModuleId(m), _)) => { - self.def_map.prelude = Some(m); - break; - } - types => { - tracing::debug!( - "could not resolve prelude path `{}` to module (resolved to {:?})", - path, - types - ); - } + let (per_ns, _) = + self.def_map.resolve_path(self.db, DefMap::ROOT, &path, BuiltinShadowMode::Other, None); + + match per_ns.types { + Some((ModuleDefId::ModuleId(m), _)) => { + self.def_map.prelude = Some(m); + } + types => { + tracing::debug!( + "could not resolve prelude path `{}` to module (resolved to {:?})", + path.display(self.db.upcast()), + types + ); } } } @@ -578,23 +600,29 @@ impl DefCollector<'_> { def: ProcMacroDef, id: ItemTreeId, fn_id: FunctionId, - module_id: ModuleId, ) { + if self.def_map.block.is_some() { + return; + } + let crate_root = self.def_map.module_id(DefMap::ROOT); + let kind = def.kind.to_basedb_kind(); - let (expander, kind) = match self.proc_macros.iter().find(|(n, _)| n == &def.name) { - Some(&(_, expander)) => (expander, kind), - None => (ProcMacroExpander::dummy(), kind), - }; + let (expander, kind) = + match self.proc_macros.as_ref().map(|it| it.iter().find(|(n, _)| n == &def.name)) { + Ok(Some(&(_, expander))) => (expander, kind), + _ => (ProcMacroExpander::dummy(), kind), + }; let proc_macro_id = - ProcMacroLoc { container: module_id, id, expander, kind }.intern(self.db); + ProcMacroLoc { container: crate_root, id, expander, kind }.intern(self.db); self.define_proc_macro(def.name.clone(), proc_macro_id); + let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap(); if let ProcMacroKind::CustomDerive { helpers } = def.kind { - self.def_map + crate_data .exported_derives .insert(macro_id_to_def_id(self.db, proc_macro_id.into()), helpers); } - self.def_map.fn_proc_macro_mapping.insert(fn_id, proc_macro_id); + crate_data.fn_proc_macro_mapping.insert(fn_id, proc_macro_id); } /// Define a macro with `macro_rules`. @@ -636,7 +664,7 @@ impl DefCollector<'_> { // In Rust, `#[macro_export]` macros are unconditionally visible at the // crate root, even if the parent modules is **not** visible. if export { - let module_id = self.def_map.root; + let module_id = DefMap::ROOT; self.def_map.modules[module_id].scope.declare(macro_.into()); self.update( module_id, @@ -687,7 +715,7 @@ impl DefCollector<'_> { /// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped. /// And unconditionally exported. fn define_proc_macro(&mut self, name: Name, macro_: ProcMacroId) { - let module_id = self.def_map.root; + let module_id = DefMap::ROOT; self.def_map.modules[module_id].scope.declare(macro_.into()); self.update( module_id, @@ -697,39 +725,28 @@ impl DefCollector<'_> { ); } - /// Import macros from `#[macro_use] extern crate`. - fn import_macros_from_extern_crate( - &mut self, - current_module_id: LocalModuleId, - extern_crate: &item_tree::ExternCrate, - ) { - tracing::debug!( - "importing macros from extern crate: {:?} ({:?})", - extern_crate, - self.def_map.edition, - ); - - if let Some(m) = self.resolve_extern_crate(&extern_crate.name) { - if m == self.def_map.module_id(current_module_id) { - cov_mark::hit!(ignore_macro_use_extern_crate_self); - return; - } - - cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use); - self.import_all_macros_exported(current_module_id, m.krate); - } - } - - /// Import all exported macros from another crate + /// Import exported macros from another crate. `names`, if `Some(_)`, specifies the name of + /// macros to be imported. Otherwise this method imports all exported macros. /// /// Exported macros are just all macros in the root module scope. /// Note that it contains not only all `#[macro_export]` macros, but also all aliases /// created by `use` in the root module, ignoring the visibility of `use`. - fn import_all_macros_exported(&mut self, current_module_id: LocalModuleId, krate: CrateId) { + fn import_macros_from_extern_crate(&mut self, krate: CrateId, names: Option>) { let def_map = self.db.crate_def_map(krate); - for (name, def) in def_map[def_map.root].scope.macros() { - // `#[macro_use]` brings macros into legacy scope. Yes, even non-`macro_rules!` macros. - self.define_legacy_macro(current_module_id, name.clone(), def); + // `#[macro_use]` brings macros into macro_use prelude. Yes, even non-`macro_rules!` + // macros. + let root_scope = &def_map[DefMap::ROOT].scope; + if let Some(names) = names { + for name in names { + // FIXME: Report diagnostic on 404. + if let Some(def) = root_scope.get(&name).take_macros() { + self.def_map.macro_use_prelude.insert(name, def); + } + } + } else { + for (name, def) in root_scope.macros() { + self.def_map.macro_use_prelude.insert(name.clone(), def); + } } } @@ -762,8 +779,9 @@ impl DefCollector<'_> { } fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport { - let _p = profile::span("resolve_import").detail(|| format!("{}", import.path)); - tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); + let _p = profile::span("resolve_import") + .detail(|| format!("{}", import.path.display(self.db.upcast()))); + tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition); if import.is_extern_crate { let name = import .path @@ -785,6 +803,7 @@ impl DefCollector<'_> { module_id, &import.path, BuiltinShadowMode::Module, + None, // An import may resolve to any kind of macro. ); let def = res.resolved_def; @@ -815,16 +834,13 @@ impl DefCollector<'_> { fn resolve_extern_crate(&self, name: &Name) -> Option { if *name == name!(self) { cov_mark::hit!(extern_crate_self_as); - let root = match self.def_map.block { - Some(_) => { - let def_map = self.def_map.crate_root(self.db).def_map(self.db); - def_map.module_id(def_map.root()) - } - None => self.def_map.module_id(self.def_map.root()), - }; - Some(root) + Some(self.def_map.crate_root()) } else { - self.deps.get(name).copied() + self.deps.get(name).map(|dep| ModuleId { + krate: dep.crate_id, + block: None, + local_id: DefMap::ROOT, + }) } } @@ -863,11 +879,14 @@ impl DefCollector<'_> { // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 if import.is_extern_crate && self.def_map.block.is_none() - && module_id == self.def_map.root + && module_id == DefMap::ROOT { if let (Some(ModuleDefId::ModuleId(def)), Some(name)) = (def.take_types(), name) { - self.def_map.extern_prelude.insert(name.clone(), def); + Arc::get_mut(&mut self.def_map.data) + .unwrap() + .extern_prelude + .insert(name.clone(), def); } } @@ -1082,7 +1101,14 @@ impl DefCollector<'_> { resolved.push((directive.module_id, directive.depth, directive.container, call_id)); }; let mut res = ReachedFixedPoint::Yes; + // Retain unresolved macros after this round of resolution. macros.retain(|directive| { + let subns = match &directive.kind { + MacroDirectiveKind::FnLike { .. } => MacroSubNs::Bang, + MacroDirectiveKind::Attr { .. } | MacroDirectiveKind::Derive { .. } => { + MacroSubNs::Attr + } + }; let resolver = |path| { let resolved_res = self.def_map.resolve_path_fp_with_macro( self.db, @@ -1090,6 +1116,7 @@ impl DefCollector<'_> { directive.module_id, &path, BuiltinShadowMode::Module, + Some(subns), ); resolved_res .resolved_def @@ -1101,15 +1128,15 @@ impl DefCollector<'_> { match &directive.kind { MacroDirectiveKind::FnLike { ast_id, expand_to } => { let call_id = macro_call_as_call_id( - self.db, + self.db.upcast(), ast_id, *expand_to, self.def_map.krate, resolver_def_id, - &mut |_err| (), ); - if let Ok(Ok(call_id)) = call_id { + if let Ok(Some(call_id)) = call_id { push_resolved(directive, call_id); + res = ReachedFixedPoint::No; return false; } @@ -1134,7 +1161,7 @@ impl DefCollector<'_> { // Record its helper attributes. if def_id.krate != self.def_map.krate { let def_map = self.db.crate_def_map(def_id.krate); - if let Some(helpers) = def_map.exported_derives.get(&def_id) { + if let Some(helpers) = def_map.data.exported_derives.get(&def_id) { self.def_map .derive_helpers_in_scope .entry(ast_id.ast_id.map(|it| it.upcast())) @@ -1214,7 +1241,19 @@ impl DefCollector<'_> { }; let ast_id = ast_id.with_value(ast_adt_id); - match attr.parse_path_comma_token_tree() { + let extend_unhygenic; + let hygiene = if file_id.is_macro() { + self.hygienes + .entry(file_id) + .or_insert_with(|| Hygiene::new(self.db.upcast(), file_id)) + } else { + // Avoid heap allocation (`Hygiene` embraces `Arc`) and hash map entry + // when we're in an oridinary (non-macro) file. + extend_unhygenic = Hygiene::new_unhygienic(); + &extend_unhygenic + }; + + match attr.parse_path_comma_token_tree(self.db.upcast(), hygiene) { Some(derive_macros) => { let mut len = 0; for (idx, path) in derive_macros.enumerate() { @@ -1241,7 +1280,6 @@ impl DefCollector<'_> { attr, self.def_map.krate, def, - true, ); self.def_map.modules[directive.module_id] .scope @@ -1261,18 +1299,12 @@ impl DefCollector<'_> { } // Not resolved to a derive helper or the derive attribute, so try to treat as a normal attribute. - let call_id = attr_macro_as_call_id( - self.db, - file_ast_id, - attr, - self.def_map.krate, - def, - false, - ); + let call_id = + attr_macro_as_call_id(self.db, file_ast_id, attr, self.def_map.krate, def); let loc: MacroCallLoc = self.db.lookup_intern_macro_call(call_id); // If proc attribute macro expansion is disabled, skip expanding it here - if !self.db.enable_proc_attr_macros() { + if !self.db.expand_proc_attr_macros() { self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro( directive.module_id, loc.kind, @@ -1345,25 +1377,31 @@ impl DefCollector<'_> { let file_id = macro_call_id.as_file(); // First, fetch the raw expansion result for purposes of error reporting. This goes through - // `macro_expand_error` to avoid depending on the full expansion result (to improve + // `parse_macro_expansion_error` to avoid depending on the full expansion result (to improve // incrementality). - let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id); - let err = self.db.macro_expand_error(macro_call_id); + let ExpandResult { value, err } = self.db.parse_macro_expansion_error(macro_call_id); if let Some(err) = err { + let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id); let diag = match err { + // why is this reported here? hir_expand::ExpandError::UnresolvedProcMacro(krate) => { always!(krate == loc.def.krate); - // Missing proc macros are non-fatal, so they are handled specially. DefDiagnostic::unresolved_proc_macro(module_id, loc.kind.clone(), loc.def.krate) } - _ => DefDiagnostic::macro_error(module_id, loc.kind, err.to_string()), + _ => DefDiagnostic::macro_error(module_id, loc.kind.clone(), err.to_string()), }; self.def_map.diagnostics.push(diag); } + if let errors @ [_, ..] = &*value { + let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id); + let diag = DefDiagnostic::macro_expansion_parse_error(module_id, loc.kind, &errors); + self.def_map.diagnostics.push(diag); + } // Then, fetch and process the item tree. This will reuse the expansion result from above. let item_tree = self.db.file_item_tree(file_id); + let mod_dir = self.mod_dirs[&module_id].clone(); ModCollector { def_collector: &mut *self, @@ -1384,8 +1422,9 @@ impl DefCollector<'_> { for directive in &self.unresolved_macros { match &directive.kind { MacroDirectiveKind::FnLike { ast_id, expand_to } => { + // FIXME: we shouldn't need to re-resolve the macro here just to get the unresolved error! let macro_call_as_call_id = macro_call_as_call_id( - self.db, + self.db.upcast(), ast_id, *expand_to, self.def_map.krate, @@ -1396,13 +1435,13 @@ impl DefCollector<'_> { directive.module_id, &path, BuiltinShadowMode::Module, + Some(MacroSubNs::Bang), ); resolved_res .resolved_def .take_macros() .map(|it| macro_id_to_def_id(self.db, it)) }, - &mut |_| (), ); if let Err(UnresolvedMacro { path }) = macro_call_as_call_id { self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call( @@ -1489,6 +1528,7 @@ impl ModCollector<'_, '_> { fn collect(&mut self, items: &[ModItem], container: ItemContainerId) { let krate = self.def_collector.def_map.krate; + let is_crate_root = self.module_id == DefMap::ROOT; // Note: don't assert that inserted value is fresh: it's simply not true // for macros. @@ -1496,28 +1536,22 @@ impl ModCollector<'_, '_> { // Prelude module is always considered to be `#[macro_use]`. if let Some(prelude_module) = self.def_collector.def_map.prelude { - if prelude_module.krate != krate { + if prelude_module.krate != krate && is_crate_root { cov_mark::hit!(prelude_is_macro_use); - self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate); + self.def_collector.import_macros_from_extern_crate(prelude_module.krate, None); } } // This should be processed eagerly instead of deferred to resolving. // `#[macro_use] extern crate` is hoisted to imports macros before collecting // any other items. - for &item in items { - let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into()); - if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) { + // + // If we're not at the crate root, `macro_use`d extern crates are an error so let's just + // ignore them. + if is_crate_root { + for &item in items { if let ModItem::ExternCrate(id) = item { - let import = &self.item_tree[id]; - let attrs = self.item_tree.attrs( - self.def_collector.db, - krate, - ModItem::from(id).into(), - ); - if attrs.by_key("macro_use").exists() { - self.def_collector.import_macros_from_extern_crate(self.module_id, import); - } + self.process_macro_use_extern_crate(id); } } } @@ -1610,14 +1644,12 @@ impl ModCollector<'_, '_> { FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db); let vis = resolve_vis(def_map, &self.item_tree[it.visibility]); - if self.def_collector.is_proc_macro && self.module_id == def_map.root { + if self.def_collector.is_proc_macro && self.module_id == DefMap::ROOT { if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) { - let crate_root = def_map.module_id(def_map.root); self.def_collector.export_proc_macro( proc_macro, ItemTreeId::new(self.tree_id, id), fn_id, - crate_root, ); } } @@ -1744,6 +1776,52 @@ impl ModCollector<'_, '_> { } } + fn process_macro_use_extern_crate(&mut self, extern_crate: FileItemTreeId) { + let db = self.def_collector.db; + let attrs = self.item_tree.attrs( + db, + self.def_collector.def_map.krate, + ModItem::from(extern_crate).into(), + ); + if let Some(cfg) = attrs.cfg() { + if !self.is_cfg_enabled(&cfg) { + return; + } + } + + let target_crate = + match self.def_collector.resolve_extern_crate(&self.item_tree[extern_crate].name) { + Some(m) => { + if m == self.def_collector.def_map.module_id(self.module_id) { + cov_mark::hit!(ignore_macro_use_extern_crate_self); + return; + } + m.krate + } + None => return, + }; + + cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use); + + let mut single_imports = Vec::new(); + let hygiene = Hygiene::new_unhygienic(); + for attr in attrs.by_key("macro_use").attrs() { + let Some(paths) = attr.parse_path_comma_token_tree(db.upcast(), &hygiene) else { + // `#[macro_use]` (without any paths) found, forget collected names and just import + // all visible macros. + self.def_collector.import_macros_from_extern_crate(target_crate, None); + return; + }; + for path in paths { + if let Some(name) = path.as_ident() { + single_imports.push(name.clone()); + } + } + } + + self.def_collector.import_macros_from_extern_crate(target_crate, Some(single_imports)); + } + fn collect_module(&mut self, module_id: FileItemTreeId, attrs: &Attrs) { let path_attr = attrs.by_key("path").string_value(); let is_macro_use = attrs.by_key("macro_use").exists(); @@ -1844,7 +1922,6 @@ impl ModCollector<'_, '_> { let vis = def_map .resolve_visibility(self.def_collector.db, self.module_id, visibility, false) .unwrap_or(Visibility::Public); - let modules = &mut def_map.modules; let origin = match definition { None => ModuleOrigin::Inline { definition: declaration, @@ -1858,6 +1935,7 @@ impl ModCollector<'_, '_> { }, }; + let modules = &mut def_map.modules; let res = modules.alloc(ModuleData::new(origin, vis)); modules[res].parent = Some(self.module_id); for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() { @@ -1919,7 +1997,10 @@ impl ModCollector<'_, '_> { if self.def_collector.def_map.is_builtin_or_registered_attr(&attr.path) { continue; } - tracing::debug!("non-builtin attribute {}", attr.path); + tracing::debug!( + "non-builtin attribute {}", + attr.path.display(self.def_collector.db.upcast()) + ); let ast_id = AstIdWithPath::new( self.file_id(), @@ -2053,8 +2134,8 @@ impl ModCollector<'_, '_> { stdx::always!( name == mac.name, "built-in macro {} has #[rustc_builtin_macro] which declares different name {}", - mac.name, - name + mac.name.display(self.def_collector.db.upcast()), + name.display(self.def_collector.db.upcast()) ); helpers_opt = Some(helpers); } @@ -2089,73 +2170,60 @@ impl ModCollector<'_, '_> { &self.item_tree[mac.visibility], ); if let Some(helpers) = helpers_opt { - self.def_collector - .def_map - .exported_derives - .insert(macro_id_to_def_id(self.def_collector.db, macro_id.into()), helpers); + if self.def_collector.def_map.block.is_none() { + Arc::get_mut(&mut self.def_collector.def_map.data) + .unwrap() + .exported_derives + .insert(macro_id_to_def_id(self.def_collector.db, macro_id.into()), helpers); + } } } fn collect_macro_call(&mut self, mac: &MacroCall, container: ItemContainerId) { let ast_id = AstIdWithPath::new(self.file_id(), mac.ast_id, ModPath::clone(&mac.path)); + let db = self.def_collector.db; + + // FIXME: Immediately expanding in "Case 1" is insufficient since "Case 2" may also define + // new legacy macros that create textual scopes. We need a way to resolve names in textual + // scopes without eager expansion. - // Case 1: try to resolve in legacy scope and expand macro_rules - let mut error = None; - match macro_call_as_call_id( - self.def_collector.db, + // Case 1: try to resolve macro calls with single-segment name and expand macro_rules + if let Ok(res) = macro_call_as_call_id( + db.upcast(), &ast_id, mac.expand_to, self.def_collector.def_map.krate, |path| { path.as_ident().and_then(|name| { - self.def_collector.def_map.with_ancestor_maps( - self.def_collector.db, - self.module_id, - &mut |map, module| { - map[module] - .scope - .get_legacy_macro(name) - .and_then(|it| it.last()) - .map(|&it| macro_id_to_def_id(self.def_collector.db, it)) - }, - ) + let def_map = &self.def_collector.def_map; + def_map + .with_ancestor_maps(db, self.module_id, &mut |map, module| { + map[module].scope.get_legacy_macro(name)?.last().copied() + }) + .or_else(|| def_map[self.module_id].scope.get(name).take_macros()) + .or_else(|| def_map.macro_use_prelude.get(name).copied()) + .filter(|&id| { + sub_namespace_match( + Some(MacroSubNs::from_id(db, id)), + Some(MacroSubNs::Bang), + ) + }) + .map(|it| macro_id_to_def_id(self.def_collector.db, it)) }) }, - &mut |err| { - error.get_or_insert(err); - }, ) { - Ok(Ok(macro_call_id)) => { - // Legacy macros need to be expanded immediately, so that any macros they produce - // are in scope. + // Legacy macros need to be expanded immediately, so that any macros they produce + // are in scope. + if let Some(val) = res { self.def_collector.collect_macro_expansion( self.module_id, - macro_call_id, + val, self.macro_depth + 1, container, ); - - if let Some(err) = error { - self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error( - self.module_id, - MacroCallKind::FnLike { ast_id: ast_id.ast_id, expand_to: mac.expand_to }, - err.to_string(), - )); - } - - return; } - Ok(Err(_)) => { - // Built-in macro failed eager expansion. - self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error( - self.module_id, - MacroCallKind::FnLike { ast_id: ast_id.ast_id, expand_to: mac.expand_to }, - error.unwrap().to_string(), - )); - return; - } - Err(UnresolvedMacro { .. }) => (), + return; } // Case 2: resolve in module scope, expand during name resolution. @@ -2215,10 +2283,11 @@ mod tests { unresolved_macros: Vec::new(), mod_dirs: FxHashMap::default(), cfg_options: &CfgOptions::default(), - proc_macros: Default::default(), + proc_macros: Ok(vec![]), from_glob_import: Default::default(), skip_attrs: Default::default(), is_proc_macro: false, + hygienes: FxHashMap::default(), }; collector.seed_with_top_level(); collector.collect(); diff --git a/crates/hir-def/src/nameres/diagnostics.rs b/crates/hir-def/src/nameres/diagnostics.rs index b024d7c6777c0..18b424255cd6b 100644 --- a/crates/hir-def/src/nameres/diagnostics.rs +++ b/crates/hir-def/src/nameres/diagnostics.rs @@ -4,7 +4,10 @@ use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; use hir_expand::{attrs::AttrId, MacroCallKind}; use la_arena::Idx; -use syntax::ast::{self, AnyHasAttrs}; +use syntax::{ + ast::{self, AnyHasAttrs}, + SyntaxError, +}; use crate::{ item_tree::{self, ItemTreeId}, @@ -29,11 +32,15 @@ pub enum DefDiagnosticKind { MacroError { ast: MacroCallKind, message: String }, + MacroExpansionParseError { ast: MacroCallKind, errors: Box<[SyntaxError]> }, + UnimplementedBuiltinMacro { ast: AstId }, InvalidDeriveTarget { ast: AstId, id: usize }, MalformedDerive { ast: AstId, id: usize }, + + MacroDefError { ast: AstId, message: String }, } #[derive(Debug, PartialEq, Eq)] @@ -81,7 +88,8 @@ impl DefDiagnostic { Self { in_module: container, kind: DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } } } - pub(super) fn unresolved_proc_macro( + // FIXME: Whats the difference between this and unresolved_macro_call + pub(crate) fn unresolved_proc_macro( container: LocalModuleId, ast: MacroCallKind, krate: CrateId, @@ -89,7 +97,7 @@ impl DefDiagnostic { Self { in_module: container, kind: DefDiagnosticKind::UnresolvedProcMacro { ast, krate } } } - pub(super) fn macro_error( + pub(crate) fn macro_error( container: LocalModuleId, ast: MacroCallKind, message: String, @@ -97,7 +105,22 @@ impl DefDiagnostic { Self { in_module: container, kind: DefDiagnosticKind::MacroError { ast, message } } } - pub(super) fn unresolved_macro_call( + pub(crate) fn macro_expansion_parse_error( + container: LocalModuleId, + ast: MacroCallKind, + errors: &[SyntaxError], + ) -> Self { + Self { + in_module: container, + kind: DefDiagnosticKind::MacroExpansionParseError { + ast, + errors: errors.to_vec().into_boxed_slice(), + }, + } + } + + // FIXME: Whats the difference between this and unresolved_proc_macro + pub(crate) fn unresolved_macro_call( container: LocalModuleId, ast: MacroCallKind, path: ModPath, diff --git a/crates/hir-def/src/nameres/mod_resolution.rs b/crates/hir-def/src/nameres/mod_resolution.rs index 51c565fe12339..2dcc2c30fe169 100644 --- a/crates/hir-def/src/nameres/mod_resolution.rs +++ b/crates/hir-def/src/nameres/mod_resolution.rs @@ -74,12 +74,20 @@ impl ModDir { candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner)) } None if file_id.is_include_macro(db.upcast()) => { - candidate_files.push(format!("{name}.rs")); - candidate_files.push(format!("{name}/mod.rs")); + candidate_files.push(format!("{}.rs", name.display(db.upcast()))); + candidate_files.push(format!("{}/mod.rs", name.display(db.upcast()))); } None => { - candidate_files.push(format!("{}{name}.rs", self.dir_path.0)); - candidate_files.push(format!("{}{name}/mod.rs", self.dir_path.0)); + candidate_files.push(format!( + "{}{}.rs", + self.dir_path.0, + name.display(db.upcast()) + )); + candidate_files.push(format!( + "{}{}/mod.rs", + self.dir_path.0, + name.display(db.upcast()) + )); } }; @@ -91,7 +99,7 @@ impl ModDir { let (dir_path, root_non_dir_owner) = if is_mod_rs || attr_path.is_some() { (DirPath::empty(), false) } else { - (DirPath::new(format!("{name}/")), true) + (DirPath::new(format!("{}/", name.display(db.upcast()))), true) }; if let Some(mod_dir) = self.child(dir_path, root_non_dir_owner) { return Ok((file_id, is_mod_rs, mod_dir)); diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs index 25478481dd0b3..5f6163175a726 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -16,11 +16,11 @@ use hir_expand::name::Name; use crate::{ db::DefDatabase, item_scope::BUILTIN_SCOPE, - nameres::{BuiltinShadowMode, DefMap}, + nameres::{sub_namespace_match, BuiltinShadowMode, DefMap, MacroSubNs}, path::{ModPath, PathKind}, per_ns::PerNs, visibility::{RawVisibility, Visibility}, - AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId, + AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, }; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -58,18 +58,22 @@ impl ResolvePathResult { } } -impl DefMap { - pub(super) fn resolve_name_in_extern_prelude( - &self, +impl PerNs { + pub(super) fn filter_macro( + mut self, db: &dyn DefDatabase, - name: &Name, - ) -> Option { - match self.block { - Some(_) => self.crate_root(db).def_map(db).extern_prelude.get(name).copied(), - None => self.extern_prelude.get(name).copied(), - } + expected: Option, + ) -> Self { + self.macros = self.macros.filter(|&(id, _)| { + let this = MacroSubNs::from_id(db, id); + sub_namespace_match(Some(this), expected) + }); + + self } +} +impl DefMap { pub(crate) fn resolve_visibility( &self, db: &dyn DefDatabase, @@ -83,7 +87,7 @@ impl DefMap { let mut vis = match visibility { RawVisibility::Module(path) => { let (result, remaining) = - self.resolve_path(db, original_module, path, BuiltinShadowMode::Module); + self.resolve_path(db, original_module, path, BuiltinShadowMode::Module, None); if remaining.is_some() { return None; } @@ -106,7 +110,7 @@ impl DefMap { // ...unless we're resolving visibility for an associated item in an impl. if self.block_id() != m.block && !within_impl { cov_mark::hit!(adjust_vis_in_block_def_map); - vis = Visibility::Module(self.module_id(self.root())); + vis = Visibility::Module(self.module_id(Self::ROOT)); tracing::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis); } } @@ -124,6 +128,9 @@ impl DefMap { mut original_module: LocalModuleId, path: &ModPath, shadow: BuiltinShadowMode, + // Pass `MacroSubNs` if we know we're resolving macro names and which kind of macro we're + // resolving them to. Pass `None` otherwise, e.g. when we're resolving import paths. + expected_macro_subns: Option, ) -> ResolvePathResult { let mut result = ResolvePathResult::empty(ReachedFixedPoint::No); @@ -136,6 +143,7 @@ impl DefMap { original_module, path, shadow, + expected_macro_subns, ); // Merge `new` into `result`. @@ -154,7 +162,7 @@ impl DefMap { match ¤t_map.block { Some(block) => { original_module = block.parent.local_id; - arc = block.parent.def_map(db); + arc = block.parent.def_map(db, current_map.krate); current_map = &*arc; } None => return result, @@ -169,11 +177,15 @@ impl DefMap { original_module: LocalModuleId, path: &ModPath, shadow: BuiltinShadowMode, + expected_macro_subns: Option, ) -> ResolvePathResult { let graph = db.crate_graph(); let _cx = stdx::panic_context::enter(format!( - "DefMap {:?} crate_name={:?} block={:?} path={path}", - self.krate, graph[self.krate].display_name, self.block + "DefMap {:?} crate_name={:?} block={:?} path={}", + self.krate, + graph[self.krate].display_name, + self.block, + path.display(db.upcast()) )); let mut segments = path.segments().iter().enumerate(); @@ -181,21 +193,21 @@ impl DefMap { PathKind::DollarCrate(krate) => { if krate == self.krate { cov_mark::hit!(macro_dollar_crate_self); - PerNs::types(self.crate_root(db).into(), Visibility::Public) + PerNs::types(self.crate_root().into(), Visibility::Public) } else { let def_map = db.crate_def_map(krate); - let module = def_map.module_id(def_map.root); + let module = def_map.module_id(Self::ROOT); cov_mark::hit!(macro_dollar_crate_other); PerNs::types(module.into(), Visibility::Public) } } - PathKind::Crate => PerNs::types(self.crate_root(db).into(), Visibility::Public), + PathKind::Crate => PerNs::types(self.crate_root().into(), Visibility::Public), // plain import or absolute path in 2015: crate-relative with // fallback to extern prelude (with the simplification in // rust-lang/rust#57745) // FIXME there must be a nicer way to write this condition PathKind::Plain | PathKind::Abs - if self.edition == Edition::Edition2015 + if self.data.edition == Edition::Edition2015 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => { let (_, segment) = match segments.next() { @@ -220,7 +232,13 @@ impl DefMap { if path.segments().len() == 1 { shadow } else { BuiltinShadowMode::Module }; tracing::debug!("resolving {:?} in module", segment); - self.resolve_name_in_module(db, original_module, segment, prefer_module) + self.resolve_name_in_module( + db, + original_module, + segment, + prefer_module, + expected_macro_subns, + ) } PathKind::Super(lvl) => { let mut module = original_module; @@ -236,16 +254,20 @@ impl DefMap { ); tracing::debug!( "`super` path: {} -> {} in parent map", - path, - new_path - ); - return block.parent.def_map(db).resolve_path_fp_with_macro( - db, - mode, - block.parent.local_id, - &new_path, - shadow, + path.display(db.upcast()), + new_path.display(db.upcast()) ); + return block + .parent + .def_map(db, self.krate) + .resolve_path_fp_with_macro( + db, + mode, + block.parent.local_id, + &new_path, + shadow, + expected_macro_subns, + ); } None => { tracing::debug!("super path in root module"); @@ -271,7 +293,7 @@ impl DefMap { Some((_, segment)) => segment, None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), }; - if let Some(&def) = self.extern_prelude.get(segment) { + if let Some(&def) = self.data.extern_prelude.get(segment) { tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def); PerNs::types(def.into(), Visibility::Public) } else { @@ -303,7 +325,12 @@ impl DefMap { ); tracing::debug!("resolving {:?} in other crate", path); let defp_map = module.def_map(db); - let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow); + // Macro sub-namespaces only matter when resolving single-segment paths + // because `macro_use` and other preludes should be taken into account. At + // this point, we know we're resolving a multi-segment path so macro kind + // expectation is discarded. + let (def, s) = + defp_map.resolve_path(db, module.local_id, &path, shadow, None); return ResolvePathResult::with( def, ReachedFixedPoint::Yes, @@ -331,11 +358,11 @@ impl DefMap { Some(local_id) => { let variant = EnumVariantId { parent: e, local_id }; match &*enum_data.variants[local_id].variant_data { - crate::adt::VariantData::Record(_) => { + crate::data::adt::VariantData::Record(_) => { PerNs::types(variant.into(), Visibility::Public) } - crate::adt::VariantData::Tuple(_) - | crate::adt::VariantData::Unit => { + crate::data::adt::VariantData::Tuple(_) + | crate::data::adt::VariantData::Unit => { PerNs::both(variant.into(), variant.into(), Visibility::Public) } } @@ -381,19 +408,24 @@ impl DefMap { module: LocalModuleId, name: &Name, shadow: BuiltinShadowMode, + expected_macro_subns: Option, ) -> PerNs { // Resolve in: // - legacy scope of macro // - current module / scope - // - extern prelude + // - extern prelude / macro_use prelude // - std prelude let from_legacy_macro = self[module] .scope .get_legacy_macro(name) // FIXME: shadowing .and_then(|it| it.last()) - .map_or_else(PerNs::none, |&m| PerNs::macros(m, Visibility::Public)); - let from_scope = self[module].scope.get(name); + .copied() + .filter(|&id| { + sub_namespace_match(Some(MacroSubNs::from_id(db, id)), expected_macro_subns) + }) + .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public)); + let from_scope = self[module].scope.get(name).filter_macro(db, expected_macro_subns); let from_builtin = match self.block { Some(_) => { // Only resolve to builtins in the root `DefMap`. @@ -410,13 +442,27 @@ impl DefMap { }; let extern_prelude = || { - self.extern_prelude + if self.block.is_some() { + // Don't resolve extern prelude in block `DefMap`s. + return PerNs::none(); + } + self.data + .extern_prelude .get(name) .map_or(PerNs::none(), |&it| PerNs::types(it.into(), Visibility::Public)) }; + let macro_use_prelude = || { + self.macro_use_prelude + .get(name) + .map_or(PerNs::none(), |&it| PerNs::macros(it.into(), Visibility::Public)) + }; let prelude = || self.resolve_in_prelude(db, name); - from_legacy_macro.or(from_scope_or_builtin).or_else(extern_prelude).or_else(prelude) + from_legacy_macro + .or(from_scope_or_builtin) + .or_else(extern_prelude) + .or_else(macro_use_prelude) + .or_else(prelude) } fn resolve_name_in_crate_root_or_extern_prelude( @@ -426,13 +472,20 @@ impl DefMap { ) -> PerNs { let from_crate_root = match self.block { Some(_) => { - let def_map = self.crate_root(db).def_map(db); - def_map[def_map.root].scope.get(name) + let def_map = self.crate_root().def_map(db); + def_map[Self::ROOT].scope.get(name) } - None => self[self.root].scope.get(name), + None => self[Self::ROOT].scope.get(name), }; let from_extern_prelude = || { - self.resolve_name_in_extern_prelude(db, name) + if self.block.is_some() { + // Don't resolve extern prelude in block `DefMap`s. + return PerNs::none(); + } + self.data + .extern_prelude + .get(name) + .copied() .map_or(PerNs::none(), |it| PerNs::types(it.into(), Visibility::Public)) }; diff --git a/crates/hir-def/src/nameres/proc_macro.rs b/crates/hir-def/src/nameres/proc_macro.rs index caad4a1f38172..751b7beaac153 100644 --- a/crates/hir-def/src/nameres/proc_macro.rs +++ b/crates/hir-def/src/nameres/proc_macro.rs @@ -52,7 +52,7 @@ impl Attrs { } // This fn is intended for `#[proc_macro_derive(..)]` and `#[rustc_builtin_macro(..)]`, which have -// the same strucuture. +// the same structure. #[rustfmt::skip] pub(crate) fn parse_macro_name_and_helper_attrs(tt: &[TokenTree]) -> Option<(Name, Box<[Name]>)> { match tt { diff --git a/crates/hir-def/src/nameres/tests.rs b/crates/hir-def/src/nameres/tests.rs index 8a27c60df5c27..dd7c3c3630623 100644 --- a/crates/hir-def/src/nameres/tests.rs +++ b/crates/hir-def/src/nameres/tests.rs @@ -4,10 +4,9 @@ mod macros; mod mod_resolution; mod primitives; -use std::sync::Arc; - use base_db::{fixture::WithFixture, SourceDatabase}; use expect_test::{expect, Expect}; +use triomphe::Arc; use crate::{db::DefDatabase, test_db::TestDB}; diff --git a/crates/hir-def/src/nameres/tests/incremental.rs b/crates/hir-def/src/nameres/tests/incremental.rs index 13e6825f8210e..4931c36bbca92 100644 --- a/crates/hir-def/src/nameres/tests/incremental.rs +++ b/crates/hir-def/src/nameres/tests/incremental.rs @@ -1,8 +1,7 @@ -use std::sync::Arc; - use base_db::SourceDatabaseExt; +use triomphe::Arc; -use crate::{AdtId, ModuleDefId}; +use crate::{db::DefDatabase, AdtId, ModuleDefId}; use super::*; @@ -15,7 +14,7 @@ fn check_def_map_is_not_recomputed(ra_fixture_initial: &str, ra_fixture_change: }); assert!(format!("{events:?}").contains("crate_def_map"), "{events:#?}") } - db.set_file_text(pos.file_id, Arc::new(ra_fixture_change.to_string())); + db.set_file_text(pos.file_id, Arc::from(ra_fixture_change)); { let events = db.log_executed(|| { @@ -96,7 +95,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() { }); assert!(format!("{events:?}").contains("crate_def_map"), "{events:#?}") } - db.set_file_text(pos.file_id, Arc::new("m!(Y);".to_string())); + db.set_file_text(pos.file_id, Arc::from("m!(Y);")); { let events = db.log_executed(|| { @@ -109,7 +108,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() { } #[test] -fn typing_inside_a_function_should_not_invalidate_expansions() { +fn typing_inside_a_function_should_not_invalidate_item_expansions() { let (mut db, pos) = TestDB::with_position( r#" //- /lib.rs @@ -140,7 +139,7 @@ m!(Z); let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); assert_eq!(n_recalculated_item_trees, 6); let n_reparsed_macros = - events.iter().filter(|it| it.contains("parse_macro_expansion")).count(); + events.iter().filter(|it| it.contains("parse_macro_expansion(")).count(); assert_eq!(n_reparsed_macros, 3); } @@ -150,7 +149,7 @@ fn quux() { 92 } m!(Y); m!(Z); "#; - db.set_file_text(pos.file_id, Arc::new(new_text.to_string())); + db.set_file_text(pos.file_id, Arc::from(new_text)); { let events = db.log_executed(|| { @@ -161,7 +160,7 @@ m!(Z); let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); assert_eq!(n_recalculated_item_trees, 1); let n_reparsed_macros = - events.iter().filter(|it| it.contains("parse_macro_expansion")).count(); + events.iter().filter(|it| it.contains("parse_macro_expansion(")).count(); assert_eq!(n_reparsed_macros, 0); } } diff --git a/crates/hir-def/src/nameres/tests/macros.rs b/crates/hir-def/src/nameres/tests/macros.rs index a4ccd14cbb463..f4cca8d68d0ac 100644 --- a/crates/hir-def/src/nameres/tests/macros.rs +++ b/crates/hir-def/src/nameres/tests/macros.rs @@ -259,6 +259,72 @@ mod priv_mod { ); } +#[test] +fn macro_use_filter() { + check( + r#" +//- /main.rs crate:main deps:empty,multiple,all +#[macro_use()] +extern crate empty; + +foo_not_imported!(); + +#[macro_use(bar1)] +#[macro_use()] +#[macro_use(bar2, bar3)] +extern crate multiple; + +bar1!(); +bar2!(); +bar3!(); +bar_not_imported!(); + +#[macro_use(baz1)] +#[macro_use] +#[macro_use(baz2)] +extern crate all; + +baz1!(); +baz2!(); +baz3!(); + +//- /empty.rs crate:empty +#[macro_export] +macro_rules! foo_not_imported { () => { struct NotOkFoo; } } + +//- /multiple.rs crate:multiple +#[macro_export] +macro_rules! bar1 { () => { struct OkBar1; } } +#[macro_export] +macro_rules! bar2 { () => { struct OkBar2; } } +#[macro_export] +macro_rules! bar3 { () => { struct OkBar3; } } +#[macro_export] +macro_rules! bar_not_imported { () => { struct NotOkBar; } } + +//- /all.rs crate:all +#[macro_export] +macro_rules! baz1 { () => { struct OkBaz1; } } +#[macro_export] +macro_rules! baz2 { () => { struct OkBaz2; } } +#[macro_export] +macro_rules! baz3 { () => { struct OkBaz3; } } +"#, + expect![[r#" + crate + OkBar1: t v + OkBar2: t v + OkBar3: t v + OkBaz1: t v + OkBaz2: t v + OkBaz3: t v + all: t + empty: t + multiple: t + "#]], + ); +} + #[test] fn prelude_is_macro_use() { cov_mark::check!(prelude_is_macro_use); @@ -664,6 +730,29 @@ pub struct bar; ); } +#[test] +fn macro_dollar_crate_is_correct_in_derive_meta() { + let map = compute_crate_def_map( + r#" +//- minicore: derive, clone +//- /main.rs crate:main deps:lib +lib::foo!(); + +//- /lib.rs crate:lib +#[macro_export] +macro_rules! foo { + () => { + #[derive($crate::Clone)] + struct S; + } +} + +pub use core::clone::Clone; +"#, + ); + assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1); +} + #[test] fn expand_derive() { let map = compute_crate_def_map( @@ -683,7 +772,7 @@ pub macro Copy {} pub macro Clone {} "#, ); - assert_eq!(map.modules[map.root].scope.impls().len(), 2); + assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 2); } #[test] @@ -726,7 +815,7 @@ pub macro derive($item:item) {} pub macro Clone {} "#, ); - assert_eq!(map.modules[map.root].scope.impls().len(), 1); + assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1); } #[test] @@ -991,7 +1080,7 @@ macro_rules! mbe { #[test] fn collects_derive_helpers() { - let def_map = compute_crate_def_map( + let db = TestDB::with_files( r#" #![crate_type="proc-macro"] struct TokenStream; @@ -1002,11 +1091,13 @@ pub fn derive_macro_2(_item: TokenStream) -> TokenStream { } "#, ); + let krate = db.crate_graph().iter().next().unwrap(); + let def_map = db.crate_def_map(krate); - assert_eq!(def_map.exported_derives.len(), 1); - match def_map.exported_derives.values().next() { + assert_eq!(def_map.data.exported_derives.len(), 1); + match def_map.data.exported_derives.values().next() { Some(helpers) => match &**helpers { - [attr] => assert_eq!(attr.to_string(), "helper_attr"), + [attr] => assert_eq!(attr.display(&db).to_string(), "helper_attr"), _ => unreachable!(), }, _ => unreachable!(), @@ -1169,7 +1260,7 @@ struct A; #[test] fn macro_use_imports_all_macro_types() { - let def_map = compute_crate_def_map( + let db = TestDB::with_files( r#" //- /main.rs crate:main deps:lib #[macro_use] @@ -1192,18 +1283,153 @@ struct TokenStream; fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a } "#, ); + let krate = db.crate_graph().iter().next().unwrap(); + let def_map = db.crate_def_map(krate); + + let root_module = &def_map[DefMap::ROOT].scope; + assert!( + root_module.legacy_macros().count() == 0, + "`#[macro_use]` shouldn't bring macros into textual macro scope", + ); - let root = &def_map[def_map.root()].scope; - let actual = root - .legacy_macros() - .sorted_by(|a, b| std::cmp::Ord::cmp(&a.0, &b.0)) - .map(|(name, _)| format!("{name}\n")) - .collect::(); + let actual = def_map + .macro_use_prelude + .iter() + .map(|(name, _)| name.display(&db).to_string()) + .sorted() + .join("\n"); expect![[r#" legacy macro20 - proc_attr - "#]] + proc_attr"#]] .assert_eq(&actual); } + +#[test] +fn non_prelude_macros_take_precedence_over_macro_use_prelude() { + check( + r#" +//- /lib.rs edition:2021 crate:lib deps:dep,core +#[macro_use] +extern crate dep; + +macro foo() { struct Ok; } +macro bar() { fn ok() {} } + +foo!(); +bar!(); + +//- /dep.rs crate:dep +#[macro_export] +macro_rules! foo { + () => { struct NotOk; } +} + +//- /core.rs crate:core +pub mod prelude { + pub mod rust_2021 { + #[macro_export] + macro_rules! bar { + () => { fn not_ok() {} } + } + } +} + "#, + expect![[r#" + crate + Ok: t v + bar: m + dep: t + foo: m + ok: v + "#]], + ); +} + +#[test] +fn macro_use_prelude_is_eagerly_expanded() { + // See FIXME in `ModCollector::collect_macro_call()`. + check( + r#" +//- /main.rs crate:main deps:lib +#[macro_use] +extern crate lib; +mk_foo!(); +mod a { + foo!(); +} +//- /lib.rs crate:lib +#[macro_export] +macro_rules! mk_foo { + () => { + macro_rules! foo { + () => { struct Ok; } + } + } +} + "#, + expect![[r#" + crate + a: t + lib: t + + crate::a + Ok: t v + "#]], + ); +} + +#[test] +fn macro_sub_namespace() { + let map = compute_crate_def_map( + r#" +//- minicore: derive, clone +macro_rules! Clone { () => {} } +macro_rules! derive { () => {} } + +#[derive(Clone)] +struct S; + "#, + ); + assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1); +} + +#[test] +fn macro_sub_namespace2() { + check( + r#" +//- /main.rs edition:2021 crate:main deps:proc,core +use proc::{foo, bar}; + +foo!(); +bar!(); + +//- /proc.rs crate:proc +#![crate_type="proc-macro"] +#[proc_macro_derive(foo)] +pub fn foo() {} +#[proc_macro_attribute] +pub fn bar() {} + +//- /core.rs crate:core +pub mod prelude { + pub mod rust_2021 { + pub macro foo() { + struct Ok; + } + pub macro bar() { + fn ok() {} + } + } +} + "#, + expect![[r#" + crate + Ok: t v + bar: m + foo: m + ok: v + "#]], + ); +} diff --git a/crates/hir-def/src/nameres/tests/mod_resolution.rs b/crates/hir-def/src/nameres/tests/mod_resolution.rs index a019312884787..81bc0ff91e3a7 100644 --- a/crates/hir-def/src/nameres/tests/mod_resolution.rs +++ b/crates/hir-def/src/nameres/tests/mod_resolution.rs @@ -887,7 +887,7 @@ mod module; //- /module.rs #![cfg(NEVER)] -struct AlsoShoulntAppear; +struct AlsoShouldNotAppear; "#, expect![[r#" crate diff --git a/crates/hir-def/src/path.rs b/crates/hir-def/src/path.rs index f3197d1800f22..b9b8082549718 100644 --- a/crates/hir-def/src/path.rs +++ b/crates/hir-def/src/path.rs @@ -7,15 +7,14 @@ use std::{ }; use crate::{ - body::LowerCtx, - type_ref::{ConstRefOrPath, LifetimeRef}, + lang_item::LangItemTarget, + lower::LowerCtx, + type_ref::{ConstRefOrPath, LifetimeRef, TypeBound, TypeRef}, }; use hir_expand::name::Name; use intern::Interned; use syntax::ast; -use crate::type_ref::{TypeBound, TypeRef}; - pub use hir_expand::mod_path::{path, ModPath, PathKind}; #[derive(Debug, Clone, PartialEq, Eq)] @@ -36,13 +35,19 @@ impl Display for ImportAlias { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Path { - /// Type based path like `::foo`. - /// Note that paths like `::foo` are desugared to `Trait::::foo`. - type_anchor: Option>, - mod_path: Interned, - /// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`. - generic_args: Option>]>>, +pub enum Path { + /// A normal path + Normal { + /// Type based path like `::foo`. + /// Note that paths like `::foo` are desugared to `Trait::::foo`. + type_anchor: Option>, + mod_path: Interned, + /// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`. + generic_args: Option>]>>, + }, + /// A link to a lang item. It is used in desugaring of things like `x?`. We can show these + /// links via a normal path since they might be private and not accessible in the usage place. + LangItem(LangItemTarget), } /// Generic arguments to a path segment (e.g. the `i32` in `Option`). This @@ -102,51 +107,77 @@ impl Path { ) -> Path { let generic_args = generic_args.into(); assert_eq!(path.len(), generic_args.len()); - Path { type_anchor: None, mod_path: Interned::new(path), generic_args: Some(generic_args) } + Path::Normal { + type_anchor: None, + mod_path: Interned::new(path), + generic_args: Some(generic_args), + } + } + + /// Converts a known mod path to `Path`. + pub fn from_known_path_with_no_generic(path: ModPath) -> Path { + Path::Normal { type_anchor: None, mod_path: Interned::new(path), generic_args: None } } pub fn kind(&self) -> &PathKind { - &self.mod_path.kind + match self { + Path::Normal { mod_path, .. } => &mod_path.kind, + Path::LangItem(_) => &PathKind::Abs, + } } pub fn type_anchor(&self) -> Option<&TypeRef> { - self.type_anchor.as_deref() + match self { + Path::Normal { type_anchor, .. } => type_anchor.as_deref(), + Path::LangItem(_) => None, + } } pub fn segments(&self) -> PathSegments<'_> { - let s = PathSegments { - segments: self.mod_path.segments(), - generic_args: self.generic_args.as_deref(), + let Path::Normal { mod_path, generic_args, .. } = self else { + return PathSegments { + segments: &[], + generic_args: None, + }; }; + let s = + PathSegments { segments: mod_path.segments(), generic_args: generic_args.as_deref() }; if let Some(generic_args) = s.generic_args { assert_eq!(s.segments.len(), generic_args.len()); } s } - pub fn mod_path(&self) -> &ModPath { - &self.mod_path + pub fn mod_path(&self) -> Option<&ModPath> { + match self { + Path::Normal { mod_path, .. } => Some(&mod_path), + Path::LangItem(_) => None, + } } pub fn qualifier(&self) -> Option { - if self.mod_path.is_ident() { + let Path::Normal { mod_path, generic_args, type_anchor } = self else { + return None; + }; + if mod_path.is_ident() { return None; } - let res = Path { - type_anchor: self.type_anchor.clone(), + let res = Path::Normal { + type_anchor: type_anchor.clone(), mod_path: Interned::new(ModPath::from_segments( - self.mod_path.kind, - self.mod_path.segments()[..self.mod_path.segments().len() - 1].iter().cloned(), + mod_path.kind, + mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(), )), - generic_args: self.generic_args.as_ref().map(|it| it[..it.len() - 1].to_vec().into()), + generic_args: generic_args.as_ref().map(|it| it[..it.len() - 1].to_vec().into()), }; Some(res) } pub fn is_self_type(&self) -> bool { - self.type_anchor.is_none() - && self.generic_args.as_deref().is_none() - && self.mod_path.is_Self() + let Path::Normal { mod_path, generic_args, type_anchor } = self else { + return false; + }; + type_anchor.is_none() && generic_args.as_deref().is_none() && mod_path.is_Self() } } @@ -222,7 +253,7 @@ impl GenericArgs { impl From for Path { fn from(name: Name) -> Path { - Path { + Path::Normal { type_anchor: None, mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))), generic_args: None, diff --git a/crates/hir-def/src/path/lower.rs b/crates/hir-def/src/path/lower.rs index b7542bd777d04..26d2706175ca9 100644 --- a/crates/hir-def/src/path/lower.rs +++ b/crates/hir-def/src/path/lower.rs @@ -2,17 +2,15 @@ use std::iter; -use crate::type_ref::ConstRefOrPath; +use crate::{lower::LowerCtx, type_ref::ConstRefOrPath}; use either::Either; use hir_expand::name::{name, AsName}; use intern::Interned; use syntax::ast::{self, AstNode, HasTypeBounds}; -use super::AssociatedTypeBinding; use crate::{ - body::LowerCtx, - path::{GenericArg, GenericArgs, ModPath, Path, PathKind}, + path::{AssociatedTypeBinding, GenericArg, GenericArgs, ModPath, Path, PathKind}, type_ref::{LifetimeRef, TypeBound, TypeRef}, }; @@ -75,8 +73,11 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option>::Foo desugars to Trait::Foo Some(trait_ref) => { - let Path { mod_path, generic_args: path_generic_args, .. } = - Path::from_src(trait_ref.path()?, ctx)?; + let Path::Normal { mod_path, generic_args: path_generic_args, .. } = + Path::from_src(trait_ref.path()?, ctx)? else + { + return None; + }; let num_segments = mod_path.segments().len(); kind = mod_path.kind; @@ -157,7 +158,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option { + if assoc_type_arg.param_list().is_some() { + // We currently ignore associated return type bounds. + continue; + } if let Some(name_ref) = assoc_type_arg.name_ref() { let name = name_ref.as_name(); let args = assoc_type_arg diff --git a/crates/hir-def/src/pretty.rs b/crates/hir-def/src/pretty.rs index 2d45c8c8da1a5..0aead6f37f73f 100644 --- a/crates/hir-def/src/pretty.rs +++ b/crates/hir-def/src/pretty.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Write}; -use hir_expand::mod_path::PathKind; +use hir_expand::{db::ExpandDatabase, mod_path::PathKind}; use intern::Interned; use itertools::Itertools; @@ -11,11 +11,14 @@ use crate::{ type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef}, }; -pub(crate) fn print_path(path: &Path, buf: &mut dyn Write) -> fmt::Result { +pub(crate) fn print_path(db: &dyn ExpandDatabase, path: &Path, buf: &mut dyn Write) -> fmt::Result { + if let Path::LangItem(x) = path { + return write!(buf, "$lang_item::{x:?}"); + } match path.type_anchor() { Some(anchor) => { write!(buf, "<")?; - print_type_ref(anchor, buf)?; + print_type_ref(db, anchor, buf)?; write!(buf, ">::")?; } None => match path.kind() { @@ -41,10 +44,10 @@ pub(crate) fn print_path(path: &Path, buf: &mut dyn Write) -> fmt::Result { write!(buf, "::")?; } - write!(buf, "{}", segment.name)?; + write!(buf, "{}", segment.name.display(db))?; if let Some(generics) = segment.args_and_bindings { write!(buf, "::<")?; - print_generic_args(generics, buf)?; + print_generic_args(db, generics, buf)?; write!(buf, ">")?; } @@ -53,12 +56,16 @@ pub(crate) fn print_path(path: &Path, buf: &mut dyn Write) -> fmt::Result { Ok(()) } -pub(crate) fn print_generic_args(generics: &GenericArgs, buf: &mut dyn Write) -> fmt::Result { +pub(crate) fn print_generic_args( + db: &dyn ExpandDatabase, + generics: &GenericArgs, + buf: &mut dyn Write, +) -> fmt::Result { let mut first = true; let args = if generics.has_self_type { let (self_ty, args) = generics.args.split_first().unwrap(); write!(buf, "Self=")?; - print_generic_arg(self_ty, buf)?; + print_generic_arg(db, self_ty, buf)?; first = false; args } else { @@ -69,35 +76,43 @@ pub(crate) fn print_generic_args(generics: &GenericArgs, buf: &mut dyn Write) -> write!(buf, ", ")?; } first = false; - print_generic_arg(arg, buf)?; + print_generic_arg(db, arg, buf)?; } for binding in generics.bindings.iter() { if !first { write!(buf, ", ")?; } first = false; - write!(buf, "{}", binding.name)?; + write!(buf, "{}", binding.name.display(db))?; if !binding.bounds.is_empty() { write!(buf, ": ")?; - print_type_bounds(&binding.bounds, buf)?; + print_type_bounds(db, &binding.bounds, buf)?; } if let Some(ty) = &binding.type_ref { write!(buf, " = ")?; - print_type_ref(ty, buf)?; + print_type_ref(db, ty, buf)?; } } Ok(()) } -pub(crate) fn print_generic_arg(arg: &GenericArg, buf: &mut dyn Write) -> fmt::Result { +pub(crate) fn print_generic_arg( + db: &dyn ExpandDatabase, + arg: &GenericArg, + buf: &mut dyn Write, +) -> fmt::Result { match arg { - GenericArg::Type(ty) => print_type_ref(ty, buf), - GenericArg::Const(c) => write!(buf, "{c}"), - GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name), + GenericArg::Type(ty) => print_type_ref(db, ty, buf), + GenericArg::Const(c) => write!(buf, "{}", c.display(db)), + GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db)), } } -pub(crate) fn print_type_ref(type_ref: &TypeRef, buf: &mut dyn Write) -> fmt::Result { +pub(crate) fn print_type_ref( + db: &dyn ExpandDatabase, + type_ref: &TypeRef, + buf: &mut dyn Write, +) -> fmt::Result { // FIXME: deduplicate with `HirDisplay` impl match type_ref { TypeRef::Never => write!(buf, "!")?, @@ -108,18 +123,18 @@ pub(crate) fn print_type_ref(type_ref: &TypeRef, buf: &mut dyn Write) -> fmt::Re if i != 0 { write!(buf, ", ")?; } - print_type_ref(field, buf)?; + print_type_ref(db, field, buf)?; } write!(buf, ")")?; } - TypeRef::Path(path) => print_path(path, buf)?, + TypeRef::Path(path) => print_path(db, path, buf)?, TypeRef::RawPtr(pointee, mtbl) => { let mtbl = match mtbl { Mutability::Shared => "*const", Mutability::Mut => "*mut", }; write!(buf, "{mtbl} ")?; - print_type_ref(pointee, buf)?; + print_type_ref(db, pointee, buf)?; } TypeRef::Reference(pointee, lt, mtbl) => { let mtbl = match mtbl { @@ -128,19 +143,19 @@ pub(crate) fn print_type_ref(type_ref: &TypeRef, buf: &mut dyn Write) -> fmt::Re }; write!(buf, "&")?; if let Some(lt) = lt { - write!(buf, "{} ", lt.name)?; + write!(buf, "{} ", lt.name.display(db))?; } write!(buf, "{mtbl}")?; - print_type_ref(pointee, buf)?; + print_type_ref(db, pointee, buf)?; } TypeRef::Array(elem, len) => { write!(buf, "[")?; - print_type_ref(elem, buf)?; - write!(buf, "; {len}]")?; + print_type_ref(db, elem, buf)?; + write!(buf, "; {}]", len.display(db))?; } TypeRef::Slice(elem) => { write!(buf, "[")?; - print_type_ref(elem, buf)?; + print_type_ref(db, elem, buf)?; write!(buf, "]")?; } TypeRef::Fn(args_and_ret, varargs, is_unsafe) => { @@ -154,7 +169,7 @@ pub(crate) fn print_type_ref(type_ref: &TypeRef, buf: &mut dyn Write) -> fmt::Re if i != 0 { write!(buf, ", ")?; } - print_type_ref(typeref, buf)?; + print_type_ref(db, typeref, buf)?; } if *varargs { if !args.is_empty() { @@ -163,7 +178,7 @@ pub(crate) fn print_type_ref(type_ref: &TypeRef, buf: &mut dyn Write) -> fmt::Re write!(buf, "...")?; } write!(buf, ") -> ")?; - print_type_ref(return_type, buf)?; + print_type_ref(db, return_type, buf)?; } TypeRef::Macro(_ast_id) => { write!(buf, "")?; @@ -171,11 +186,11 @@ pub(crate) fn print_type_ref(type_ref: &TypeRef, buf: &mut dyn Write) -> fmt::Re TypeRef::Error => write!(buf, "{{unknown}}")?, TypeRef::ImplTrait(bounds) => { write!(buf, "impl ")?; - print_type_bounds(bounds, buf)?; + print_type_bounds(db, bounds, buf)?; } TypeRef::DynTrait(bounds) => { write!(buf, "dyn ")?; - print_type_bounds(bounds, buf)?; + print_type_bounds(db, bounds, buf)?; } } @@ -183,6 +198,7 @@ pub(crate) fn print_type_ref(type_ref: &TypeRef, buf: &mut dyn Write) -> fmt::Re } pub(crate) fn print_type_bounds( + db: &dyn ExpandDatabase, bounds: &[Interned], buf: &mut dyn Write, ) -> fmt::Result { @@ -197,13 +213,13 @@ pub(crate) fn print_type_bounds( TraitBoundModifier::None => (), TraitBoundModifier::Maybe => write!(buf, "?")?, } - print_path(path, buf)?; + print_path(db, path, buf)?; } TypeBound::ForLifetime(lifetimes, path) => { - write!(buf, "for<{}> ", lifetimes.iter().format(", "))?; - print_path(path, buf)?; + write!(buf, "for<{}> ", lifetimes.iter().map(|it| it.display(db)).format(", "))?; + print_path(db, path, buf)?; } - TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name)?, + TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db))?, TypeBound::Error => write!(buf, "{{unknown}}")?, } } diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 61e64fc103631..06f5b2526a459 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -1,5 +1,5 @@ //! Name resolution façade. -use std::{fmt, hash::BuildHasherDefault, sync::Arc}; +use std::{fmt, hash::BuildHasherDefault}; use base_db::CrateId; use hir_expand::name::{name, Name}; @@ -7,16 +7,18 @@ use indexmap::IndexMap; use intern::Interned; use rustc_hash::FxHashSet; use smallvec::{smallvec, SmallVec}; +use triomphe::Arc; use crate::{ body::scope::{ExprScopes, ScopeId}, builtin_type::BuiltinType, db::DefDatabase, - expr::{BindingId, ExprId, LabelId}, generics::{GenericParams, TypeOrConstParamData}, + hir::{BindingId, ExprId, LabelId}, item_scope::{BuiltinShadowMode, BUILTIN_SCOPE}, - nameres::DefMap, - path::{ModPath, PathKind}, + lang_item::LangItemTarget, + nameres::{DefMap, MacroSubNs}, + path::{ModPath, Path, PathKind}, per_ns::PerNs, visibility::{RawVisibility, Visibility}, AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, @@ -78,7 +80,7 @@ enum Scope { ExprScope(ExprScope), } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum TypeNs { SelfType(ImplId), GenericParam(TypeParamId), @@ -153,7 +155,8 @@ impl Resolver { path: &ModPath, ) -> Option { let (item_map, module) = self.item_scope(); - let (module_res, idx) = item_map.resolve_path(db, module, path, BuiltinShadowMode::Module); + let (module_res, idx) = + item_map.resolve_path(db, module, path, BuiltinShadowMode::Module, None); match module_res.take_types()? { ModuleDefId::TraitId(it) => { let idx = idx?; @@ -176,8 +179,27 @@ impl Resolver { pub fn resolve_path_in_type_ns( &self, db: &dyn DefDatabase, - path: &ModPath, + path: &Path, ) -> Option<(TypeNs, Option)> { + let path = match path { + Path::Normal { mod_path, .. } => mod_path, + Path::LangItem(l) => { + return Some(( + match *l { + LangItemTarget::Union(x) => TypeNs::AdtId(x.into()), + LangItemTarget::TypeAlias(x) => TypeNs::TypeAliasId(x), + LangItemTarget::Struct(x) => TypeNs::AdtId(x.into()), + LangItemTarget::EnumVariant(x) => TypeNs::EnumVariantId(x), + LangItemTarget::EnumId(x) => TypeNs::AdtId(x.into()), + LangItemTarget::Trait(x) => TypeNs::TraitId(x), + LangItemTarget::Function(_) + | LangItemTarget::ImplDef(_) + | LangItemTarget::Static(_) => return None, + }, + None, + )) + } + }; let first_name = path.segments().first()?; let skip_to_mod = path.kind != PathKind::Plain; if skip_to_mod { @@ -217,7 +239,7 @@ impl Resolver { pub fn resolve_path_in_type_ns_fully( &self, db: &dyn DefDatabase, - path: &ModPath, + path: &Path, ) -> Option { let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?; if unresolved.is_some() { @@ -245,8 +267,24 @@ impl Resolver { pub fn resolve_path_in_value_ns( &self, db: &dyn DefDatabase, - path: &ModPath, + path: &Path, ) -> Option { + let path = match path { + Path::Normal { mod_path, .. } => mod_path, + Path::LangItem(l) => { + return Some(ResolveValueResult::ValueNs(match *l { + LangItemTarget::Function(x) => ValueNs::FunctionId(x), + LangItemTarget::Static(x) => ValueNs::StaticId(x), + LangItemTarget::Struct(x) => ValueNs::StructId(x), + LangItemTarget::EnumVariant(x) => ValueNs::EnumVariantId(x), + LangItemTarget::Union(_) + | LangItemTarget::ImplDef(_) + | LangItemTarget::TypeAlias(_) + | LangItemTarget::Trait(_) + | LangItemTarget::EnumId(_) => return None, + })) + } + }; let n_segments = path.segments().len(); let tmp = name![self]; let first_name = if path.is_self() { &tmp } else { path.segments().first()? }; @@ -340,7 +378,7 @@ impl Resolver { pub fn resolve_path_in_value_ns_fully( &self, db: &dyn DefDatabase, - path: &ModPath, + path: &Path, ) -> Option { match self.resolve_path_in_value_ns(db, path)? { ResolveValueResult::ValueNs(it) => Some(it), @@ -348,9 +386,17 @@ impl Resolver { } } - pub fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option { + pub fn resolve_path_as_macro( + &self, + db: &dyn DefDatabase, + path: &ModPath, + expected_macro_kind: Option, + ) -> Option { let (item_map, module) = self.item_scope(); - item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros() + item_map + .resolve_path(db, module, path, BuiltinShadowMode::Other, expected_macro_kind) + .0 + .take_macros() } /// Returns a set of names available in the current scope. @@ -415,7 +461,10 @@ impl Resolver { res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac))); }) }); - def_map.extern_prelude().for_each(|(name, &def)| { + def_map.macro_use_prelude().for_each(|(name, def)| { + res.add(name, ScopeDef::ModuleDef(def.into())); + }); + def_map.extern_prelude().for_each(|(name, def)| { res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def))); }); BUILTIN_SCOPE.iter().for_each(|(name, &def)| { @@ -441,7 +490,7 @@ impl Resolver { &Scope::ImplDefScope(impl_) => { if let Some(target_trait) = &db.impl_data(impl_).target_trait { if let Some(TypeNs::TraitId(trait_)) = - self.resolve_path_in_type_ns_fully(db, target_trait.path.mod_path()) + self.resolve_path_in_type_ns_fully(db, &target_trait.path) { traits.insert(trait_); } @@ -536,15 +585,13 @@ impl Resolver { scope_id, })); if let Some(block) = expr_scopes.block(scope_id) { - if let Some(def_map) = db.block_def_map(block) { - let root = def_map.root(); - resolver - .scopes - .push(Scope::BlockScope(ModuleItemMap { def_map, module_id: root })); - // FIXME: This adds as many module scopes as there are blocks, but resolving in each - // already traverses all parents, so this is O(n²). I think we could only store the - // innermost module scope instead? - } + let def_map = db.block_def_map(block); + resolver + .scopes + .push(Scope::BlockScope(ModuleItemMap { def_map, module_id: DefMap::ROOT })); + // FIXME: This adds as many module scopes as there are blocks, but resolving in each + // already traverses all parents, so this is O(n²). I think we could only store the + // innermost module scope instead? } } @@ -592,7 +639,8 @@ impl Resolver { shadow: BuiltinShadowMode, ) -> PerNs { let (item_map, module) = self.item_scope(); - let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow); + // This method resolves `path` just like import paths, so no expected macro subns is given. + let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow, None); if segment_index.is_some() { return PerNs::none(); } @@ -705,13 +753,11 @@ fn resolver_for_scope_( for scope in scope_chain.into_iter().rev() { if let Some(block) = scopes.block(scope) { - if let Some(def_map) = db.block_def_map(block) { - let root = def_map.root(); - r = r.push_block_scope(def_map, root); - // FIXME: This adds as many module scopes as there are blocks, but resolving in each - // already traverses all parents, so this is O(n²). I think we could only store the - // innermost module scope instead? - } + let def_map = db.block_def_map(block); + r = r.push_block_scope(def_map, DefMap::ROOT); + // FIXME: This adds as many module scopes as there are blocks, but resolving in each + // already traverses all parents, so this is O(n²). I think we could only store the + // innermost module scope instead? } r = r.push_expr_scope(owner, Arc::clone(&scopes), scope); @@ -1000,6 +1046,12 @@ impl HasResolver for GenericDefId { } } +impl HasResolver for EnumVariantId { + fn resolver(self, db: &dyn DefDatabase) -> Resolver { + self.parent.resolver(db) + } +} + impl HasResolver for VariantId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { match self { diff --git a/crates/hir-def/src/src.rs b/crates/hir-def/src/src.rs index f69356cac87d3..6047f770d4d30 100644 --- a/crates/hir-def/src/src.rs +++ b/crates/hir-def/src/src.rs @@ -20,7 +20,7 @@ impl HasSource for AssocItemLoc { fn source(&self, db: &dyn DefDatabase) -> InFile { let tree = self.id.item_tree(db); let ast_id_map = db.ast_id_map(self.id.file_id()); - let root = db.parse_or_expand(self.id.file_id()).unwrap(); + let root = db.parse_or_expand(self.id.file_id()); let node = &tree[self.id.value]; InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id()).to_node(&root)) @@ -33,7 +33,7 @@ impl HasSource for ItemLoc { fn source(&self, db: &dyn DefDatabase) -> InFile { let tree = self.id.item_tree(db); let ast_id_map = db.ast_id_map(self.id.file_id()); - let root = db.parse_or_expand(self.id.file_id()).unwrap(); + let root = db.parse_or_expand(self.id.file_id()); let node = &tree[self.id.value]; InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id()).to_node(&root)) @@ -46,7 +46,7 @@ impl HasSource for Macro2Loc { fn source(&self, db: &dyn DefDatabase) -> InFile { let tree = self.id.item_tree(db); let ast_id_map = db.ast_id_map(self.id.file_id()); - let root = db.parse_or_expand(self.id.file_id()).unwrap(); + let root = db.parse_or_expand(self.id.file_id()); let node = &tree[self.id.value]; InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id()).to_node(&root)) @@ -59,7 +59,7 @@ impl HasSource for MacroRulesLoc { fn source(&self, db: &dyn DefDatabase) -> InFile { let tree = self.id.item_tree(db); let ast_id_map = db.ast_id_map(self.id.file_id()); - let root = db.parse_or_expand(self.id.file_id()).unwrap(); + let root = db.parse_or_expand(self.id.file_id()); let node = &tree[self.id.value]; InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id()).to_node(&root)) @@ -72,7 +72,7 @@ impl HasSource for ProcMacroLoc { fn source(&self, db: &dyn DefDatabase) -> InFile { let tree = self.id.item_tree(db); let ast_id_map = db.ast_id_map(self.id.file_id()); - let root = db.parse_or_expand(self.id.file_id()).unwrap(); + let root = db.parse_or_expand(self.id.file_id()); let node = &tree[self.id.value]; InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id()).to_node(&root)) diff --git a/crates/hir-def/src/test_db.rs b/crates/hir-def/src/test_db.rs index ee143b19ae5b3..a6befc8a81a81 100644 --- a/crates/hir-def/src/test_db.rs +++ b/crates/hir-def/src/test_db.rs @@ -1,17 +1,16 @@ //! Database used for testing `hir_def`. -use std::{ - fmt, panic, - sync::{Arc, Mutex}, -}; +use std::{fmt, panic, sync::Mutex}; use base_db::{ - salsa, AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, FilePosition, - SourceDatabase, Upcast, + salsa::{self, Durability}, + AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, FilePosition, SourceDatabase, + Upcast, }; use hir_expand::{db::ExpandDatabase, InFile}; -use stdx::hash::NoHashHashSet; +use rustc_hash::FxHashSet; use syntax::{algo, ast, AstNode}; +use triomphe::Arc; use crate::{ db::DefDatabase, @@ -35,7 +34,7 @@ pub(crate) struct TestDB { impl Default for TestDB { fn default() -> Self { let mut this = Self { storage: Default::default(), events: Default::default() }; - this.set_enable_proc_attr_macros(true); + this.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH); this } } @@ -70,13 +69,13 @@ impl fmt::Debug for TestDB { impl panic::RefUnwindSafe for TestDB {} impl FileLoader for TestDB { - fn file_text(&self, file_id: FileId) -> Arc { + fn file_text(&self, file_id: FileId) -> Arc { FileLoaderDelegate(self).file_text(file_id) } fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { FileLoaderDelegate(self).resolve_path(path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } } @@ -111,7 +110,7 @@ impl TestDB { } _ => { // FIXME: handle `mod` inside block expression - return def_map.module_id(def_map.root()); + return def_map.module_id(DefMap::ROOT); } } } @@ -120,7 +119,7 @@ impl TestDB { /// Finds the smallest/innermost module in `def_map` containing `position`. fn mod_at_position(&self, def_map: &DefMap, position: FilePosition) -> LocalModuleId { let mut size = None; - let mut res = def_map.root(); + let mut res = DefMap::ROOT; for (module, data) in def_map.modules() { let src = data.definition_source(self); if src.file_id != position.file_id.into() { @@ -209,13 +208,11 @@ impl TestDB { }); for scope in scope_iter { - let containing_blocks = + let mut containing_blocks = scopes.scope_chain(Some(scope)).filter_map(|scope| scopes.block(scope)); - for block in containing_blocks { - if let Some(def_map) = self.block_def_map(block) { - return Some(def_map); - } + if let Some(block) = containing_blocks.next().map(|block| self.block_def_map(block)) { + return Some(block); } } diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs index ab76ed43d3a0e..30f48de61f2e8 100644 --- a/crates/hir-def/src/visibility.rs +++ b/crates/hir-def/src/visibility.rs @@ -1,10 +1,11 @@ //! Defines hir-level representation of visibility (e.g. `pub` and `pub(crate)`). -use std::{iter, sync::Arc}; +use std::iter; use hir_expand::{hygiene::Hygiene, InFile}; use la_arena::ArenaMap; use syntax::ast; +use triomphe::Arc; use crate::{ db::DefDatabase, diff --git a/crates/hir-expand/Cargo.toml b/crates/hir-expand/Cargo.toml index 5c684be03cf24..40d8659f25bad 100644 --- a/crates/hir-expand/Cargo.toml +++ b/crates/hir-expand/Cargo.toml @@ -22,6 +22,7 @@ hashbrown = { version = "0.12.1", features = [ "inline-more", ], default-features = false } smallvec.workspace = true +triomphe.workspace = true # local deps stdx.workspace = true diff --git a/crates/hir-expand/src/ast_id_map.rs b/crates/hir-expand/src/ast_id_map.rs index 2b27db0e95063..400442de94b98 100644 --- a/crates/hir-expand/src/ast_id_map.rs +++ b/crates/hir-expand/src/ast_id_map.rs @@ -115,6 +115,7 @@ impl AstIdMap { } } } + res.arena.shrink_to_fit(); res } @@ -123,6 +124,10 @@ impl AstIdMap { FileAstId { raw, _ty: PhantomData } } + pub fn get(&self, id: FileAstId) -> AstPtr { + AstPtr::try_from_raw(self.arena[id.raw].clone()).unwrap() + } + fn erased_ast_id(&self, item: &SyntaxNode) -> ErasedFileAstId { let ptr = SyntaxNodePtr::new(item); let hash = hash_ptr(&ptr); @@ -136,10 +141,6 @@ impl AstIdMap { } } - pub fn get(&self, id: FileAstId) -> AstPtr { - AstPtr::try_from_raw(self.arena[id.raw].clone()).unwrap() - } - fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId { self.arena.alloc(SyntaxNodePtr::new(item)) } diff --git a/crates/hir-expand/src/attrs.rs b/crates/hir-expand/src/attrs.rs index 8d1e88725ecbf..0c369a18bb9cc 100644 --- a/crates/hir-expand/src/attrs.rs +++ b/crates/hir-expand/src/attrs.rs @@ -1,5 +1,5 @@ //! A higher level attributes based on TokenTree, with also some shortcuts. -use std::{fmt, ops, sync::Arc}; +use std::{fmt, ops}; use base_db::CrateId; use cfg::CfgExpr; @@ -8,12 +8,12 @@ use intern::Interned; use mbe::{syntax_node_to_token_tree, DelimiterKind, Punct}; use smallvec::{smallvec, SmallVec}; use syntax::{ast, match_ast, AstNode, SmolStr, SyntaxNode}; +use triomphe::Arc; use crate::{ db::ExpandDatabase, hygiene::Hygiene, - mod_path::{ModPath, PathKind}, - name::AsName, + mod_path::ModPath, tt::{self, Subtree}, InFile, }; @@ -21,6 +21,7 @@ use crate::{ /// Syntactical attributes, without filtering of `cfg_attr`s. #[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct RawAttrs { + // FIXME: Make this a ThinArc entries: Option>, } @@ -50,7 +51,9 @@ impl RawAttrs { path: Interned::new(ModPath::from(crate::name!(doc))), }), }) - .collect::>(); + .collect::>(); + // FIXME: use `Arc::from_iter` when it becomes available + let entries: Arc<[Attr]> = Arc::from(entries); Self { entries: if entries.is_empty() { None } else { Some(entries) } } } @@ -68,7 +71,7 @@ impl RawAttrs { (Some(a), Some(b)) => { let last_ast_index = a.last().map_or(0, |it| it.id.ast_index() + 1) as u32; Self { - entries: Some( + entries: Some(Arc::from( a.iter() .cloned() .chain(b.iter().map(|it| { @@ -78,8 +81,9 @@ impl RawAttrs { << AttrId::AST_INDEX_BITS; it })) - .collect(), - ), + // FIXME: use `Arc::from_iter` when it becomes available + .collect::>(), + )), } } } @@ -96,48 +100,51 @@ impl RawAttrs { } let crate_graph = db.crate_graph(); - let new_attrs = self - .iter() - .flat_map(|attr| -> SmallVec<[_; 1]> { - let is_cfg_attr = - attr.path.as_ident().map_or(false, |name| *name == crate::name![cfg_attr]); - if !is_cfg_attr { - return smallvec![attr.clone()]; - } - - let subtree = match attr.token_tree_value() { - Some(it) => it, - _ => return smallvec![attr.clone()], - }; - - let (cfg, parts) = match parse_cfg_attr_input(subtree) { - Some(it) => it, - None => return smallvec![attr.clone()], - }; - let index = attr.id; - let attrs = - parts.enumerate().take(1 << AttrId::CFG_ATTR_BITS).filter_map(|(idx, attr)| { - let tree = Subtree { - delimiter: tt::Delimiter::unspecified(), - token_trees: attr.to_vec(), - }; - // FIXME hygiene - let hygiene = Hygiene::new_unhygienic(); - Attr::from_tt(db, &tree, &hygiene, index.with_cfg_attr(idx)) - }); - - let cfg_options = &crate_graph[krate].cfg_options; - let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() }; - let cfg = CfgExpr::parse(&cfg); - if cfg_options.check(&cfg) == Some(false) { - smallvec![] - } else { - cov_mark::hit!(cfg_attr_active); - - attrs.collect() - } - }) - .collect(); + let new_attrs = Arc::from( + self.iter() + .flat_map(|attr| -> SmallVec<[_; 1]> { + let is_cfg_attr = + attr.path.as_ident().map_or(false, |name| *name == crate::name![cfg_attr]); + if !is_cfg_attr { + return smallvec![attr.clone()]; + } + + let subtree = match attr.token_tree_value() { + Some(it) => it, + _ => return smallvec![attr.clone()], + }; + + let (cfg, parts) = match parse_cfg_attr_input(subtree) { + Some(it) => it, + None => return smallvec![attr.clone()], + }; + let index = attr.id; + let attrs = parts.enumerate().take(1 << AttrId::CFG_ATTR_BITS).filter_map( + |(idx, attr)| { + let tree = Subtree { + delimiter: tt::Delimiter::unspecified(), + token_trees: attr.to_vec(), + }; + // FIXME hygiene + let hygiene = Hygiene::new_unhygienic(); + Attr::from_tt(db, &tree, &hygiene, index.with_cfg_attr(idx)) + }, + ); + + let cfg_options = &crate_graph[krate].cfg_options; + let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() }; + let cfg = CfgExpr::parse(&cfg); + if cfg_options.check(&cfg) == Some(false) { + smallvec![] + } else { + cov_mark::hit!(cfg_attr_active); + + attrs.collect() + } + }) + // FIXME: use `Arc::from_iter` when it becomes available + .collect::>(), + ); RawAttrs { entries: Some(new_attrs) } } @@ -266,7 +273,11 @@ impl Attr { } /// Parses this attribute as a token tree consisting of comma separated paths. - pub fn parse_path_comma_token_tree(&self) -> Option + '_> { + pub fn parse_path_comma_token_tree<'a>( + &'a self, + db: &'a dyn ExpandDatabase, + hygiene: &'a Hygiene, + ) -> Option + 'a> { let args = self.token_tree_value()?; if args.delimiter.kind != DelimiterKind::Parenthesis { @@ -275,19 +286,37 @@ impl Attr { let paths = args .token_trees .split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. })))) - .filter_map(|tts| { + .filter_map(move |tts| { if tts.is_empty() { return None; } - let segments = tts.iter().filter_map(|tt| match tt { - tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => Some(id.as_name()), - _ => None, - }); - Some(ModPath::from_segments(PathKind::Plain, segments)) + // FIXME: This is necessarily a hack. It'd be nice if we could avoid allocation here. + let subtree = tt::Subtree { + delimiter: tt::Delimiter::unspecified(), + token_trees: tts.into_iter().cloned().collect(), + }; + let (parse, _) = + mbe::token_tree_to_syntax_node(&subtree, mbe::TopEntryPoint::MetaItem); + let meta = ast::Meta::cast(parse.syntax_node())?; + // Only simple paths are allowed. + if meta.eq_token().is_some() || meta.expr().is_some() || meta.token_tree().is_some() + { + return None; + } + let path = meta.path()?; + ModPath::from_src(db, path, hygiene) }); Some(paths) } + + pub fn cfg(&self) -> Option { + if *self.path.as_ident()? == crate::name![cfg] { + self.token_tree_value().map(CfgExpr::parse) + } else { + None + } + } } pub fn collect_attrs( diff --git a/crates/hir-expand/src/builtin_attr_macro.rs b/crates/hir-expand/src/builtin_attr_macro.rs index 277ecd9399422..80695bc065621 100644 --- a/crates/hir-expand/src/builtin_attr_macro.rs +++ b/crates/hir-expand/src/builtin_attr_macro.rs @@ -96,7 +96,7 @@ fn derive_attr_expand( ) -> ExpandResult { let loc = db.lookup_intern_macro_call(id); let derives = match &loc.kind { - MacroCallKind::Attr { attr_args, is_derive: true, .. } => &attr_args.0, + MacroCallKind::Attr { attr_args, .. } if loc.def.is_attribute_derive() => &attr_args.0, _ => return ExpandResult::ok(tt::Subtree::empty()), }; pseudo_derive_attr_expansion(tt, derives) diff --git a/crates/hir-expand/src/builtin_derive_macro.rs b/crates/hir-expand/src/builtin_derive_macro.rs index 5c1a75132ee94..54706943ac4fd 100644 --- a/crates/hir-expand/src/builtin_derive_macro.rs +++ b/crates/hir-expand/src/builtin_derive_macro.rs @@ -1,11 +1,19 @@ //! Builtin derives. +use ::tt::Ident; use base_db::{CrateOrigin, LangCrateOrigin}; +use itertools::izip; +use mbe::TokenMap; +use std::collections::HashSet; +use stdx::never; use tracing::debug; use crate::tt::{self, TokenId}; use syntax::{ - ast::{self, AstNode, HasGenericParams, HasModuleItem, HasName}, + ast::{ + self, AstNode, FieldList, HasAttrs, HasGenericParams, HasModuleItem, HasName, + HasTypeBounds, PathType, + }, match_ast, }; @@ -58,10 +66,129 @@ pub fn find_builtin_derive(ident: &name::Name) -> Option BuiltinDeriveExpander::find_by_name(ident) } +enum VariantShape { + Struct(Vec), + Tuple(usize), + Unit, +} + +fn tuple_field_iterator(n: usize) -> impl Iterator { + (0..n).map(|x| Ident::new(format!("f{x}"), tt::TokenId::unspecified())) +} + +impl VariantShape { + fn as_pattern(&self, path: tt::Subtree) -> tt::Subtree { + self.as_pattern_map(path, |x| quote!(#x)) + } + + fn field_names(&self) -> Vec { + match self { + VariantShape::Struct(s) => s.clone(), + VariantShape::Tuple(n) => tuple_field_iterator(*n).collect(), + VariantShape::Unit => vec![], + } + } + + fn as_pattern_map( + &self, + path: tt::Subtree, + field_map: impl Fn(&tt::Ident) -> tt::Subtree, + ) -> tt::Subtree { + match self { + VariantShape::Struct(fields) => { + let fields = fields.iter().map(|x| { + let mapped = field_map(x); + quote! { #x : #mapped , } + }); + quote! { + #path { ##fields } + } + } + &VariantShape::Tuple(n) => { + let fields = tuple_field_iterator(n).map(|x| { + let mapped = field_map(&x); + quote! { + #mapped , + } + }); + quote! { + #path ( ##fields ) + } + } + VariantShape::Unit => path, + } + } + + fn from(value: Option, token_map: &TokenMap) -> Result { + let r = match value { + None => VariantShape::Unit, + Some(FieldList::RecordFieldList(x)) => VariantShape::Struct( + x.fields() + .map(|x| x.name()) + .map(|x| name_to_token(token_map, x)) + .collect::>()?, + ), + Some(FieldList::TupleFieldList(x)) => VariantShape::Tuple(x.fields().count()), + }; + Ok(r) + } +} + +enum AdtShape { + Struct(VariantShape), + Enum { variants: Vec<(tt::Ident, VariantShape)>, default_variant: Option }, + Union, +} + +impl AdtShape { + fn as_pattern(&self, name: &tt::Ident) -> Vec { + self.as_pattern_map(name, |x| quote!(#x)) + } + + fn field_names(&self) -> Vec> { + match self { + AdtShape::Struct(s) => { + vec![s.field_names()] + } + AdtShape::Enum { variants, .. } => { + variants.iter().map(|(_, fields)| fields.field_names()).collect() + } + AdtShape::Union => { + never!("using fields of union in derive is always wrong"); + vec![] + } + } + } + + fn as_pattern_map( + &self, + name: &tt::Ident, + field_map: impl Fn(&tt::Ident) -> tt::Subtree, + ) -> Vec { + match self { + AdtShape::Struct(s) => { + vec![s.as_pattern_map(quote! { #name }, field_map)] + } + AdtShape::Enum { variants, .. } => variants + .iter() + .map(|(v, fields)| fields.as_pattern_map(quote! { #name :: #v }, &field_map)) + .collect(), + AdtShape::Union => { + never!("pattern matching on union is always wrong"); + vec![quote! { un }] + } + } + } +} + struct BasicAdtInfo { name: tt::Ident, - /// `Some(ty)` if it's a const param of type `ty`, `None` if it's a type param. - param_types: Vec>, + shape: AdtShape, + /// first field is the name, and + /// second field is `Some(ty)` if it's a const param of type `ty`, `None` if it's a type param. + /// third fields is where bounds, if any + param_types: Vec<(tt::Subtree, Option, Option)>, + associated_types: Vec, } fn parse_adt(tt: &tt::Subtree) -> Result { @@ -75,29 +202,52 @@ fn parse_adt(tt: &tt::Subtree) -> Result { ExpandError::Other("no item found".into()) })?; let node = item.syntax(); - let (name, params) = match_ast! { + let (name, params, shape) = match_ast! { match node { - ast::Struct(it) => (it.name(), it.generic_param_list()), - ast::Enum(it) => (it.name(), it.generic_param_list()), - ast::Union(it) => (it.name(), it.generic_param_list()), + ast::Struct(it) => (it.name(), it.generic_param_list(), AdtShape::Struct(VariantShape::from(it.field_list(), &token_map)?)), + ast::Enum(it) => { + let default_variant = it.variant_list().into_iter().flat_map(|x| x.variants()).position(|x| x.attrs().any(|x| x.simple_name() == Some("default".into()))); + ( + it.name(), + it.generic_param_list(), + AdtShape::Enum { + default_variant, + variants: it.variant_list() + .into_iter() + .flat_map(|x| x.variants()) + .map(|x| Ok((name_to_token(&token_map,x.name())?, VariantShape::from(x.field_list(), &token_map)?))).collect::>()? + } + ) + }, + ast::Union(it) => (it.name(), it.generic_param_list(), AdtShape::Union), _ => { debug!("unexpected node is {:?}", node); return Err(ExpandError::Other("expected struct, enum or union".into())) }, } }; - let name = name.ok_or_else(|| { - debug!("parsed item has no name"); - ExpandError::Other("missing name".into()) - })?; - let name_token_id = - token_map.token_by_range(name.syntax().text_range()).unwrap_or_else(TokenId::unspecified); - let name_token = tt::Ident { span: name_token_id, text: name.text().into() }; + let mut param_type_set: HashSet = HashSet::new(); let param_types = params .into_iter() .flat_map(|param_list| param_list.type_or_const_params()) .map(|param| { - if let ast::TypeOrConstParam::Const(param) = param { + let name = { + let this = param.name(); + match this { + Some(x) => { + param_type_set.insert(x.to_string()); + mbe::syntax_node_to_token_tree(x.syntax()).0 + } + None => tt::Subtree::empty(), + } + }; + let bounds = match ¶m { + ast::TypeOrConstParam::Type(x) => { + x.type_bound_list().map(|x| mbe::syntax_node_to_token_tree(x.syntax()).0) + } + ast::TypeOrConstParam::Const(_) => None, + }; + let ty = if let ast::TypeOrConstParam::Const(param) = param { let ty = param .ty() .map(|ty| mbe::syntax_node_to_token_tree(ty.syntax()).0) @@ -105,27 +255,107 @@ fn parse_adt(tt: &tt::Subtree) -> Result { Some(ty) } else { None - } + }; + (name, ty, bounds) }) .collect(); - Ok(BasicAdtInfo { name: name_token, param_types }) + let is_associated_type = |p: &PathType| { + if let Some(p) = p.path() { + if let Some(parent) = p.qualifier() { + if let Some(x) = parent.segment() { + if let Some(x) = x.path_type() { + if let Some(x) = x.path() { + if let Some(pname) = x.as_single_name_ref() { + if param_type_set.contains(&pname.to_string()) { + // ::Assoc + return true; + } + } + } + } + } + if let Some(pname) = parent.as_single_name_ref() { + if param_type_set.contains(&pname.to_string()) { + // T::Assoc + return true; + } + } + } + } + false + }; + let associated_types = node + .descendants() + .filter_map(PathType::cast) + .filter(is_associated_type) + .map(|x| mbe::syntax_node_to_token_tree(x.syntax()).0) + .collect::>(); + let name_token = name_to_token(&token_map, name)?; + Ok(BasicAdtInfo { name: name_token, shape, param_types, associated_types }) +} + +fn name_to_token(token_map: &TokenMap, name: Option) -> Result { + let name = name.ok_or_else(|| { + debug!("parsed item has no name"); + ExpandError::Other("missing name".into()) + })?; + let name_token_id = + token_map.token_by_range(name.syntax().text_range()).unwrap_or_else(TokenId::unspecified); + let name_token = tt::Ident { span: name_token_id, text: name.text().into() }; + Ok(name_token) } -fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResult { +/// Given that we are deriving a trait `DerivedTrait` for a type like: +/// +/// ```ignore (only-for-syntax-highlight) +/// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z> where C: WhereTrait { +/// a: A, +/// b: B::Item, +/// b1: ::Item, +/// c1: ::Item, +/// c2: Option<::Item>, +/// ... +/// } +/// ``` +/// +/// create an impl like: +/// +/// ```ignore (only-for-syntax-highlight) +/// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ... Z> where +/// C: WhereTrait, +/// A: DerivedTrait + B1 + ... + BN, +/// B: DerivedTrait + B1 + ... + BN, +/// C: DerivedTrait + B1 + ... + BN, +/// B::Item: DerivedTrait + B1 + ... + BN, +/// ::Item: DerivedTrait + B1 + ... + BN, +/// ... +/// { +/// ... +/// } +/// ``` +/// +/// where B1, ..., BN are the bounds given by `bounds_paths`.'. Z is a phantom type, and +/// therefore does not get bound by the derived trait. +fn expand_simple_derive( + tt: &tt::Subtree, + trait_path: tt::Subtree, + trait_body: impl FnOnce(&BasicAdtInfo) -> tt::Subtree, +) -> ExpandResult { let info = match parse_adt(tt) { Ok(info) => info, - Err(e) => return ExpandResult::with_err(tt::Subtree::empty(), e), + Err(e) => return ExpandResult::new(tt::Subtree::empty(), e), }; + let trait_body = trait_body(&info); + let mut where_block = vec![]; let (params, args): (Vec<_>, Vec<_>) = info .param_types .into_iter() - .enumerate() - .map(|(idx, param_ty)| { - let ident = tt::Leaf::Ident(tt::Ident { - span: tt::TokenId::unspecified(), - text: format!("T{idx}").into(), - }); + .map(|(ident, param_ty, bound)| { let ident_ = ident.clone(); + if let Some(b) = bound { + let ident = ident.clone(); + where_block.push(quote! { #ident : #b , }); + } if let Some(ty) = param_ty { (quote! { const #ident : #ty , }, quote! { #ident_ , }) } else { @@ -134,9 +364,16 @@ fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResu } }) .unzip(); + + where_block.extend(info.associated_types.iter().map(|x| { + let x = x.clone(); + let bound = trait_path.clone(); + quote! { #x : #bound , } + })); + let name = info.name; let expanded = quote! { - impl < ##params > #trait_path for #name < ##args > {} + impl < ##params > #trait_path for #name < ##args > where ##where_block { #trait_body } }; ExpandResult::ok(expanded) } @@ -163,7 +400,7 @@ fn copy_expand( tt: &tt::Subtree, ) -> ExpandResult { let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::marker::Copy }) + expand_simple_derive(tt, quote! { #krate::marker::Copy }, |_| quote! {}) } fn clone_expand( @@ -172,7 +409,63 @@ fn clone_expand( tt: &tt::Subtree, ) -> ExpandResult { let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::clone::Clone }) + expand_simple_derive(tt, quote! { #krate::clone::Clone }, |adt| { + if matches!(adt.shape, AdtShape::Union) { + let star = tt::Punct { + char: '*', + spacing: ::tt::Spacing::Alone, + span: tt::TokenId::unspecified(), + }; + return quote! { + fn clone(&self) -> Self { + #star self + } + }; + } + if matches!(&adt.shape, AdtShape::Enum { variants, .. } if variants.is_empty()) { + let star = tt::Punct { + char: '*', + spacing: ::tt::Spacing::Alone, + span: tt::TokenId::unspecified(), + }; + return quote! { + fn clone(&self) -> Self { + match #star self {} + } + }; + } + let name = &adt.name; + let patterns = adt.shape.as_pattern(name); + let exprs = adt.shape.as_pattern_map(name, |x| quote! { #x .clone() }); + let arms = patterns.into_iter().zip(exprs.into_iter()).map(|(pat, expr)| { + let fat_arrow = fat_arrow(); + quote! { + #pat #fat_arrow #expr, + } + }); + + quote! { + fn clone(&self) -> Self { + match self { + ##arms + } + } + } + }) +} + +/// This function exists since `quote! { => }` doesn't work. +fn fat_arrow() -> ::tt::Subtree { + let eq = + tt::Punct { char: '=', spacing: ::tt::Spacing::Joint, span: tt::TokenId::unspecified() }; + quote! { #eq> } +} + +/// This function exists since `quote! { && }` doesn't work. +fn and_and() -> ::tt::Subtree { + let and = + tt::Punct { char: '&', spacing: ::tt::Spacing::Joint, span: tt::TokenId::unspecified() }; + quote! { #and& } } fn default_expand( @@ -180,8 +473,38 @@ fn default_expand( id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult { - let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::default::Default }) + let krate = &find_builtin_crate(db, id); + expand_simple_derive(tt, quote! { #krate::default::Default }, |adt| { + let body = match &adt.shape { + AdtShape::Struct(fields) => { + let name = &adt.name; + fields + .as_pattern_map(quote!(#name), |_| quote!(#krate::default::Default::default())) + } + AdtShape::Enum { default_variant, variants } => { + if let Some(d) = default_variant { + let (name, fields) = &variants[*d]; + let adt_name = &adt.name; + fields.as_pattern_map( + quote!(#adt_name :: #name), + |_| quote!(#krate::default::Default::default()), + ) + } else { + // FIXME: Return expand error here + quote!() + } + } + AdtShape::Union => { + // FIXME: Return expand error here + quote!() + } + }; + quote! { + fn default() -> Self { + #body + } + } + }) } fn debug_expand( @@ -189,8 +512,79 @@ fn debug_expand( id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult { - let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::fmt::Debug }) + let krate = &find_builtin_crate(db, id); + expand_simple_derive(tt, quote! { #krate::fmt::Debug }, |adt| { + let for_variant = |name: String, v: &VariantShape| match v { + VariantShape::Struct(fields) => { + let for_fields = fields.iter().map(|x| { + let x_string = x.to_string(); + quote! { + .field(#x_string, & #x) + } + }); + quote! { + f.debug_struct(#name) ##for_fields .finish() + } + } + VariantShape::Tuple(n) => { + let for_fields = tuple_field_iterator(*n).map(|x| { + quote! { + .field( & #x) + } + }); + quote! { + f.debug_tuple(#name) ##for_fields .finish() + } + } + VariantShape::Unit => quote! { + f.write_str(#name) + }, + }; + if matches!(&adt.shape, AdtShape::Enum { variants, .. } if variants.is_empty()) { + let star = tt::Punct { + char: '*', + spacing: ::tt::Spacing::Alone, + span: tt::TokenId::unspecified(), + }; + return quote! { + fn fmt(&self, f: &mut #krate::fmt::Formatter) -> #krate::fmt::Result { + match #star self {} + } + }; + } + let arms = match &adt.shape { + AdtShape::Struct(fields) => { + let fat_arrow = fat_arrow(); + let name = &adt.name; + let pat = fields.as_pattern(quote!(#name)); + let expr = for_variant(name.to_string(), fields); + vec![quote! { #pat #fat_arrow #expr }] + } + AdtShape::Enum { variants, .. } => variants + .iter() + .map(|(name, v)| { + let fat_arrow = fat_arrow(); + let adt_name = &adt.name; + let pat = v.as_pattern(quote!(#adt_name :: #name)); + let expr = for_variant(name.to_string(), v); + quote! { + #pat #fat_arrow #expr , + } + }) + .collect(), + AdtShape::Union => { + // FIXME: Return expand error here + vec![] + } + }; + quote! { + fn fmt(&self, f: &mut #krate::fmt::Formatter) -> #krate::fmt::Result { + match self { + ##arms + } + } + } + }) } fn hash_expand( @@ -198,8 +592,47 @@ fn hash_expand( id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult { - let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::hash::Hash }) + let krate = &find_builtin_crate(db, id); + expand_simple_derive(tt, quote! { #krate::hash::Hash }, |adt| { + if matches!(adt.shape, AdtShape::Union) { + // FIXME: Return expand error here + return quote! {}; + } + if matches!(&adt.shape, AdtShape::Enum { variants, .. } if variants.is_empty()) { + let star = tt::Punct { + char: '*', + spacing: ::tt::Spacing::Alone, + span: tt::TokenId::unspecified(), + }; + return quote! { + fn hash(&self, state: &mut H) { + match #star self {} + } + }; + } + let arms = adt.shape.as_pattern(&adt.name).into_iter().zip(adt.shape.field_names()).map( + |(pat, names)| { + let expr = { + let it = names.iter().map(|x| quote! { #x . hash(state); }); + quote! { { + ##it + } } + }; + let fat_arrow = fat_arrow(); + quote! { + #pat #fat_arrow #expr , + } + }, + ); + quote! { + fn hash(&self, state: &mut H) { + #krate::mem::discriminant(self).hash(state); + match self { + ##arms + } + } + } + }) } fn eq_expand( @@ -208,7 +641,7 @@ fn eq_expand( tt: &tt::Subtree, ) -> ExpandResult { let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::cmp::Eq }) + expand_simple_derive(tt, quote! { #krate::cmp::Eq }, |_| quote! {}) } fn partial_eq_expand( @@ -217,7 +650,65 @@ fn partial_eq_expand( tt: &tt::Subtree, ) -> ExpandResult { let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::cmp::PartialEq }) + expand_simple_derive(tt, quote! { #krate::cmp::PartialEq }, |adt| { + if matches!(adt.shape, AdtShape::Union) { + // FIXME: Return expand error here + return quote! {}; + } + let name = &adt.name; + + let (self_patterns, other_patterns) = self_and_other_patterns(adt, name); + let arms = izip!(self_patterns, other_patterns, adt.shape.field_names()).map( + |(pat1, pat2, names)| { + let fat_arrow = fat_arrow(); + let body = match &*names { + [] => { + quote!(true) + } + [first, rest @ ..] => { + let rest = rest.iter().map(|x| { + let t1 = Ident::new(format!("{}_self", x.text), x.span); + let t2 = Ident::new(format!("{}_other", x.text), x.span); + let and_and = and_and(); + quote!(#and_and #t1 .eq( #t2 )) + }); + let first = { + let t1 = Ident::new(format!("{}_self", first.text), first.span); + let t2 = Ident::new(format!("{}_other", first.text), first.span); + quote!(#t1 .eq( #t2 )) + }; + quote!(#first ##rest) + } + }; + quote! { ( #pat1 , #pat2 ) #fat_arrow #body , } + }, + ); + + let fat_arrow = fat_arrow(); + quote! { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + ##arms + _unused #fat_arrow false + } + } + } + }) +} + +fn self_and_other_patterns( + adt: &BasicAdtInfo, + name: &tt::Ident, +) -> (Vec, Vec) { + let self_patterns = adt.shape.as_pattern_map(name, |x| { + let t = Ident::new(format!("{}_self", x.text), x.span); + quote!(#t) + }); + let other_patterns = adt.shape.as_pattern_map(name, |x| { + let t = Ident::new(format!("{}_other", x.text), x.span); + quote!(#t) + }); + (self_patterns, other_patterns) } fn ord_expand( @@ -225,8 +716,63 @@ fn ord_expand( id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult { - let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::cmp::Ord }) + let krate = &find_builtin_crate(db, id); + expand_simple_derive(tt, quote! { #krate::cmp::Ord }, |adt| { + fn compare( + krate: &tt::TokenTree, + left: tt::Subtree, + right: tt::Subtree, + rest: tt::Subtree, + ) -> tt::Subtree { + let fat_arrow1 = fat_arrow(); + let fat_arrow2 = fat_arrow(); + quote! { + match #left.cmp(&#right) { + #krate::cmp::Ordering::Equal #fat_arrow1 { + #rest + } + c #fat_arrow2 return c, + } + } + } + if matches!(adt.shape, AdtShape::Union) { + // FIXME: Return expand error here + return quote!(); + } + let left = quote!(#krate::intrinsics::discriminant_value(self)); + let right = quote!(#krate::intrinsics::discriminant_value(other)); + + let (self_patterns, other_patterns) = self_and_other_patterns(adt, &adt.name); + let arms = izip!(self_patterns, other_patterns, adt.shape.field_names()).map( + |(pat1, pat2, fields)| { + let mut body = quote!(#krate::cmp::Ordering::Equal); + for f in fields.into_iter().rev() { + let t1 = Ident::new(format!("{}_self", f.text), f.span); + let t2 = Ident::new(format!("{}_other", f.text), f.span); + body = compare(krate, quote!(#t1), quote!(#t2), body); + } + let fat_arrow = fat_arrow(); + quote! { ( #pat1 , #pat2 ) #fat_arrow #body , } + }, + ); + let fat_arrow = fat_arrow(); + let body = compare( + krate, + left, + right, + quote! { + match (self, other) { + ##arms + _unused #fat_arrow #krate::cmp::Ordering::Equal + } + }, + ); + quote! { + fn cmp(&self, other: &Self) -> #krate::cmp::Ordering { + #body + } + } + }) } fn partial_ord_expand( @@ -234,6 +780,61 @@ fn partial_ord_expand( id: MacroCallId, tt: &tt::Subtree, ) -> ExpandResult { - let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::cmp::PartialOrd }) + let krate = &find_builtin_crate(db, id); + expand_simple_derive(tt, quote! { #krate::cmp::PartialOrd }, |adt| { + fn compare( + krate: &tt::TokenTree, + left: tt::Subtree, + right: tt::Subtree, + rest: tt::Subtree, + ) -> tt::Subtree { + let fat_arrow1 = fat_arrow(); + let fat_arrow2 = fat_arrow(); + quote! { + match #left.partial_cmp(&#right) { + #krate::option::Option::Some(#krate::cmp::Ordering::Equal) #fat_arrow1 { + #rest + } + c #fat_arrow2 return c, + } + } + } + if matches!(adt.shape, AdtShape::Union) { + // FIXME: Return expand error here + return quote!(); + } + let left = quote!(#krate::intrinsics::discriminant_value(self)); + let right = quote!(#krate::intrinsics::discriminant_value(other)); + + let (self_patterns, other_patterns) = self_and_other_patterns(adt, &adt.name); + let arms = izip!(self_patterns, other_patterns, adt.shape.field_names()).map( + |(pat1, pat2, fields)| { + let mut body = quote!(#krate::option::Option::Some(#krate::cmp::Ordering::Equal)); + for f in fields.into_iter().rev() { + let t1 = Ident::new(format!("{}_self", f.text), f.span); + let t2 = Ident::new(format!("{}_other", f.text), f.span); + body = compare(krate, quote!(#t1), quote!(#t2), body); + } + let fat_arrow = fat_arrow(); + quote! { ( #pat1 , #pat2 ) #fat_arrow #body , } + }, + ); + let fat_arrow = fat_arrow(); + let body = compare( + krate, + left, + right, + quote! { + match (self, other) { + ##arms + _unused #fat_arrow #krate::option::Option::Some(#krate::cmp::Ordering::Equal) + } + }, + ); + quote! { + fn partial_cmp(&self, other: &Self) -> #krate::option::Option::Option<#krate::cmp::Ordering> { + #body + } + } + }) } diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs index a9c5e1488aac0..c7643bd0a18eb 100644 --- a/crates/hir-expand/src/builtin_fn_macro.rs +++ b/crates/hir-expand/src/builtin_fn_macro.rs @@ -1,9 +1,13 @@ //! Builtin macro +use std::mem; + +use ::tt::Ident; use base_db::{AnchoredPath, Edition, FileId}; use cfg::CfgExpr; use either::Either; -use mbe::{parse_exprs_with_sep, parse_to_token_tree}; +use mbe::{parse_exprs_with_sep, parse_to_token_tree, TokenMap}; +use rustc_hash::FxHashMap; use syntax::{ ast::{self, AstToken}, SmolStr, @@ -67,7 +71,7 @@ macro_rules! register_builtin { pub struct ExpandedEager { pub(crate) subtree: tt::Subtree, /// The included file ID of the include macro. - pub(crate) included_file: Option, + pub(crate) included_file: Option<(FileId, TokenMap)>, } impl ExpandedEager { @@ -90,11 +94,6 @@ register_builtin! { (module_path, ModulePath) => module_path_expand, (assert, Assert) => assert_expand, (stringify, Stringify) => stringify_expand, - (format_args, FormatArgs) => format_args_expand, - (const_format_args, ConstFormatArgs) => format_args_expand, - // format_args_nl only differs in that it adds a newline in the end, - // so we use the same stub expansion for now - (format_args_nl, FormatArgsNl) => format_args_expand, (llvm_asm, LlvmAsm) => asm_expand, (asm, Asm) => asm_expand, (global_asm, GlobalAsm) => global_asm_expand, @@ -106,6 +105,9 @@ register_builtin! { (trace_macros, TraceMacros) => trace_macros_expand, EAGER: + (format_args, FormatArgs) => format_args_expand, + (const_format_args, ConstFormatArgs) => format_args_expand, + (format_args_nl, FormatArgsNl) => format_args_nl_expand, (compile_error, CompileError) => compile_error_expand, (concat, Concat) => concat_expand, (concat_idents, ConcatIdents) => concat_idents_expand, @@ -135,9 +137,8 @@ fn line_expand( _tt: &tt::Subtree, ) -> ExpandResult { // dummy implementation for type-checking purposes - let line_num = 0; let expanded = quote! { - #line_num + 0 as u32 }; ExpandResult::ok(expanded) @@ -179,9 +180,8 @@ fn column_expand( _tt: &tt::Subtree, ) -> ExpandResult { // dummy implementation for type-checking purposes - let col_num = 0; let expanded = quote! { - #col_num + 0 as u32 }; ExpandResult::ok(expanded) @@ -234,45 +234,173 @@ fn file_expand( } fn format_args_expand( + db: &dyn ExpandDatabase, + id: MacroCallId, + tt: &tt::Subtree, +) -> ExpandResult { + format_args_expand_general(db, id, tt, "") + .map(|x| ExpandedEager { subtree: x, included_file: None }) +} + +fn format_args_nl_expand( + db: &dyn ExpandDatabase, + id: MacroCallId, + tt: &tt::Subtree, +) -> ExpandResult { + format_args_expand_general(db, id, tt, "\\n") + .map(|x| ExpandedEager { subtree: x, included_file: None }) +} + +fn format_args_expand_general( _db: &dyn ExpandDatabase, _id: MacroCallId, tt: &tt::Subtree, + end_string: &str, ) -> ExpandResult { - // We expand `format_args!("", a1, a2)` to - // ``` - // $crate::fmt::Arguments::new_v1(&[], &[ - // $crate::fmt::Argument::new(&arg1,$crate::fmt::Display::fmt), - // $crate::fmt::Argument::new(&arg2,$crate::fmt::Display::fmt), - // ]) - // ```, - // which is still not really correct, but close enough for now - let mut args = parse_exprs_with_sep(tt, ','); + let args = parse_exprs_with_sep(tt, ','); + + let expand_error = + ExpandResult::new(tt::Subtree::empty(), mbe::ExpandError::NoMatchingRule.into()); if args.is_empty() { - return ExpandResult::with_err( - tt::Subtree::empty(), - mbe::ExpandError::NoMatchingRule.into(), - ); + return expand_error; } - for arg in &mut args { + let mut key_args = FxHashMap::default(); + let mut args = args.into_iter().filter_map(|mut arg| { // Remove `key =`. if matches!(arg.token_trees.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=') { // but not with `==` - if !matches!(arg.token_trees.get(2), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=' ) + if !matches!(arg.token_trees.get(2), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=') { - arg.token_trees.drain(..2); + let key = arg.token_trees.drain(..2).next().unwrap(); + key_args.insert(key.to_string(), arg); + return None; } } + Some(arg) + }).collect::>().into_iter(); + // ^^^^^^^ we need this collect, to enforce the side effect of the filter_map closure (building the `key_args`) + let format_subtree = args.next().unwrap(); + let format_string = (|| { + let token_tree = format_subtree.token_trees.get(0)?; + match token_tree { + tt::TokenTree::Leaf(l) => match l { + tt::Leaf::Literal(l) => { + if let Some(mut text) = l.text.strip_prefix('r') { + let mut raw_sharps = String::new(); + while let Some(t) = text.strip_prefix('#') { + text = t; + raw_sharps.push('#'); + } + text = + text.strip_suffix(&raw_sharps)?.strip_prefix('"')?.strip_suffix('"')?; + Some((text, l.span, Some(raw_sharps))) + } else { + let text = l.text.strip_prefix('"')?.strip_suffix('"')?; + let span = l.span; + Some((text, span, None)) + } + } + _ => None, + }, + tt::TokenTree::Subtree(_) => None, + } + })(); + let Some((format_string, _format_string_span, raw_sharps)) = format_string else { + return expand_error; + }; + let mut format_iter = format_string.chars().peekable(); + let mut parts = vec![]; + let mut last_part = String::new(); + let mut arg_tts = vec![]; + let mut err = None; + while let Some(c) = format_iter.next() { + // Parsing the format string. See https://doc.rust-lang.org/std/fmt/index.html#syntax for the grammar and more info + match c { + '{' => { + if format_iter.peek() == Some(&'{') { + format_iter.next(); + last_part.push('{'); + continue; + } + let mut argument = String::new(); + while ![Some(&'}'), Some(&':')].contains(&format_iter.peek()) { + argument.push(match format_iter.next() { + Some(c) => c, + None => return expand_error, + }); + } + let format_spec = match format_iter.next().unwrap() { + '}' => "".to_owned(), + ':' => { + let mut s = String::new(); + while let Some(c) = format_iter.next() { + if c == '}' { + break; + } + s.push(c); + } + s + } + _ => unreachable!(), + }; + parts.push(mem::take(&mut last_part)); + let arg_tree = if argument.is_empty() { + match args.next() { + Some(x) => x, + None => { + err = Some(mbe::ExpandError::NoMatchingRule.into()); + tt::Subtree::empty() + } + } + } else if let Some(tree) = key_args.get(&argument) { + tree.clone() + } else { + // FIXME: we should pick the related substring of the `_format_string_span` as the span. You + // can use `.char_indices()` instead of `.char()` for `format_iter` to find the substring interval. + let ident = Ident::new(argument, tt::TokenId::unspecified()); + quote!(#ident) + }; + let formatter = match &*format_spec { + "?" => quote!(::core::fmt::Debug::fmt), + "" => quote!(::core::fmt::Display::fmt), + _ => { + // FIXME: implement the rest and return expand error here + quote!(::core::fmt::Display::fmt) + } + }; + arg_tts.push(quote! { ::core::fmt::Argument::new(&(#arg_tree), #formatter), }); + } + '}' => { + if format_iter.peek() == Some(&'}') { + format_iter.next(); + last_part.push('}'); + } else { + return expand_error; + } + } + _ => last_part.push(c), + } + } + last_part += end_string; + if !last_part.is_empty() { + parts.push(last_part); } - let _format_string = args.remove(0); - let arg_tts = args.into_iter().flat_map(|arg| { - quote! { #DOLLAR_CRATE::fmt::Argument::new(&(#arg), #DOLLAR_CRATE::fmt::Display::fmt), } - }.token_trees); + let part_tts = parts.into_iter().map(|x| { + let text = if let Some(raw) = &raw_sharps { + format!("r{raw}\"{}\"{raw}", x).into() + } else { + format!("\"{}\"", x).into() + }; + let l = tt::Literal { span: tt::TokenId::unspecified(), text }; + quote!(#l ,) + }); + let arg_tts = arg_tts.into_iter().flat_map(|arg| arg.token_trees); let expanded = quote! { - #DOLLAR_CRATE::fmt::Arguments::new_v1(&[], &[##arg_tts]) + ::core::fmt::Arguments::new_v1(&[##part_tts], &[##arg_tts]) }; - ExpandResult::ok(expanded) + ExpandResult { value: expanded, err } } fn asm_expand( @@ -566,16 +694,16 @@ fn include_expand( let path = parse_string(tt)?; let file_id = relative_file(db, arg_id, &path, false)?; - let subtree = - parse_to_token_tree(&db.file_text(file_id)).ok_or(mbe::ExpandError::ConversionError)?.0; - Ok((subtree, file_id)) + let (subtree, map) = + parse_to_token_tree(&db.file_text(file_id)).ok_or(mbe::ExpandError::ConversionError)?; + Ok((subtree, map, file_id)) })(); match res { - Ok((subtree, file_id)) => { - ExpandResult::ok(ExpandedEager { subtree, included_file: Some(file_id) }) + Ok((subtree, map, file_id)) => { + ExpandResult::ok(ExpandedEager { subtree, included_file: Some((file_id, map)) }) } - Err(e) => ExpandResult::with_err( + Err(e) => ExpandResult::new( ExpandedEager { subtree: tt::Subtree::empty(), included_file: None }, e, ), @@ -588,7 +716,7 @@ fn include_bytes_expand( tt: &tt::Subtree, ) -> ExpandResult { if let Err(e) = parse_string(tt) { - return ExpandResult::with_err( + return ExpandResult::new( ExpandedEager { subtree: tt::Subtree::empty(), included_file: None }, e, ); @@ -613,7 +741,7 @@ fn include_str_expand( let path = match parse_string(tt) { Ok(it) => it, Err(e) => { - return ExpandResult::with_err( + return ExpandResult::new( ExpandedEager { subtree: tt::Subtree::empty(), included_file: None }, e, ) @@ -650,7 +778,7 @@ fn env_expand( let key = match parse_string(tt) { Ok(it) => it, Err(e) => { - return ExpandResult::with_err( + return ExpandResult::new( ExpandedEager { subtree: tt::Subtree::empty(), included_file: None }, e, ) @@ -686,16 +814,16 @@ fn option_env_expand( let key = match parse_string(tt) { Ok(it) => it, Err(e) => { - return ExpandResult::with_err( + return ExpandResult::new( ExpandedEager { subtree: tt::Subtree::empty(), included_file: None }, e, ) } }; - + // FIXME: Use `DOLLAR_CRATE` when that works in eager macros. let expanded = match get_env_inner(db, arg_id, &key) { - None => quote! { #DOLLAR_CRATE::option::Option::None::<&str> }, - Some(s) => quote! { #DOLLAR_CRATE::option::Option::Some(#s) }, + None => quote! { ::core::option::Option::None::<&str> }, + Some(s) => quote! { ::core::option::Option::Some(#s) }, }; ExpandResult::ok(ExpandedEager::new(expanded)) diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index 45572499e8426..965dfa824d8f9 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -1,22 +1,22 @@ //! Defines database & queries for macro expansion. -use std::sync::Arc; - -use base_db::{salsa, SourceDatabase}; +use base_db::{salsa, Edition, SourceDatabase}; use either::Either; use limit::Limit; use mbe::syntax_node_to_token_tree; use rustc_hash::FxHashSet; use syntax::{ ast::{self, HasAttrs, HasDocComments}, - AstNode, GreenNode, Parse, SyntaxNode, SyntaxToken, T, + AstNode, GreenNode, Parse, SyntaxError, SyntaxNode, SyntaxToken, T, }; +use triomphe::Arc; use crate::{ - ast_id_map::AstIdMap, builtin_attr_macro::pseudo_derive_attr_expansion, fixup, - hygiene::HygieneFrame, tt, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, - ExpandError, ExpandResult, ExpandTo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, - MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander, + ast_id_map::AstIdMap, builtin_attr_macro::pseudo_derive_attr_expansion, + builtin_fn_macro::EagerExpander, fixup, hygiene::HygieneFrame, tt, BuiltinAttrExpander, + BuiltinDeriveExpander, BuiltinFnLikeExpander, ExpandError, ExpandResult, ExpandTo, HirFileId, + HirFileIdRepr, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, + ProcMacroExpander, }; /// Total limit on the number of tokens produced by any macro invocation. @@ -33,6 +33,8 @@ pub enum TokenExpander { DeclarativeMacro { mac: mbe::DeclarativeMacro, def_site_token_map: mbe::TokenMap }, /// Stuff like `line!` and `file!`. Builtin(BuiltinFnLikeExpander), + /// Built-in eagerly expanded fn-like macros (`include!`, `concat!`, etc.) + BuiltinEager(EagerExpander), /// `global_allocator` and such. BuiltinAttr(BuiltinAttrExpander), /// `derive(Copy)` and such. @@ -51,6 +53,9 @@ impl TokenExpander { match self { TokenExpander::DeclarativeMacro { mac, .. } => mac.expand(tt).map_err(Into::into), TokenExpander::Builtin(it) => it.expand(db, id, tt).map_err(Into::into), + TokenExpander::BuiltinEager(it) => { + it.expand(db, id, tt).map_err(Into::into).map(|res| res.subtree) + } TokenExpander::BuiltinAttr(it) => it.expand(db, id, tt), TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt), TokenExpander::ProcMacro(_) => { @@ -66,6 +71,7 @@ impl TokenExpander { match self { TokenExpander::DeclarativeMacro { mac, .. } => mac.map_id_down(id), TokenExpander::Builtin(..) + | TokenExpander::BuiltinEager(..) | TokenExpander::BuiltinAttr(..) | TokenExpander::BuiltinDerive(..) | TokenExpander::ProcMacro(..) => id, @@ -76,6 +82,7 @@ impl TokenExpander { match self { TokenExpander::DeclarativeMacro { mac, .. } => mac.map_id_up(id), TokenExpander::Builtin(..) + | TokenExpander::BuiltinEager(..) | TokenExpander::BuiltinAttr(..) | TokenExpander::BuiltinDerive(..) | TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call), @@ -90,12 +97,15 @@ pub trait ExpandDatabase: SourceDatabase { /// Main public API -- parses a hir file, not caring whether it's a real /// file or a macro expansion. #[salsa::transparent] - fn parse_or_expand(&self, file_id: HirFileId) -> Option; + fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode; + #[salsa::transparent] + fn parse_or_expand_with_err(&self, file_id: HirFileId) -> ExpandResult>; /// Implementation for the macro case. + // This query is LRU cached fn parse_macro_expansion( &self, macro_file: MacroFile, - ) -> ExpandResult, Arc)>>; + ) -> ExpandResult<(Parse, Arc)>; /// Macro ids. That's probably the tricksiest bit in rust-analyzer, and the /// reason why we use salsa at all. @@ -119,15 +129,19 @@ pub trait ExpandDatabase: SourceDatabase { /// just fetches procedural ones. fn macro_def(&self, id: MacroDefId) -> Result, mbe::ParseError>; - /// Expand macro call to a token tree. This query is LRUed (we keep 128 or so results in memory) - fn macro_expand(&self, macro_call: MacroCallId) -> ExpandResult>>; + /// Expand macro call to a token tree. + // This query is LRU cached + fn macro_expand(&self, macro_call: MacroCallId) -> ExpandResult>; /// Special case of the previous query for procedural macros. We can't LRU /// proc macros, since they are not deterministic in general, and - /// non-determinism breaks salsa in a very, very, very bad way. @edwin0cheng - /// heroically debugged this once! + /// non-determinism breaks salsa in a very, very, very bad way. + /// @edwin0cheng heroically debugged this once! fn expand_proc_macro(&self, call: MacroCallId) -> ExpandResult; - /// Firewall query that returns the error from the `macro_expand` query. - fn macro_expand_error(&self, macro_call: MacroCallId) -> Option; + /// Firewall query that returns the errors from the `parse_macro_expansion` query. + fn parse_macro_expansion_error( + &self, + macro_call: MacroCallId, + ) -> ExpandResult>; fn hygiene_frame(&self, file_id: HirFileId) -> Arc; } @@ -159,8 +173,8 @@ pub fn expand_speculative( ); let (attr_arg, token_id) = match loc.kind { - MacroCallKind::Attr { invoc_attr_index, is_derive, .. } => { - let attr = if is_derive { + MacroCallKind::Attr { invoc_attr_index, .. } => { + let attr = if loc.def.is_attribute_derive() { // for pseudo-derive expansion we actually pass the attribute itself only ast::Attr::cast(speculative_args.clone()) } else { @@ -236,17 +250,26 @@ pub fn expand_speculative( } fn ast_id_map(db: &dyn ExpandDatabase, file_id: HirFileId) -> Arc { - let map = db.parse_or_expand(file_id).map(|it| AstIdMap::from_source(&it)).unwrap_or_default(); - Arc::new(map) + Arc::new(AstIdMap::from_source(&db.parse_or_expand(file_id))) } -fn parse_or_expand(db: &dyn ExpandDatabase, file_id: HirFileId) -> Option { +fn parse_or_expand(db: &dyn ExpandDatabase, file_id: HirFileId) -> SyntaxNode { match file_id.repr() { - HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()), + HirFileIdRepr::FileId(file_id) => db.parse(file_id).tree().syntax().clone(), HirFileIdRepr::MacroFile(macro_file) => { - // FIXME: Note how we convert from `Parse` to `SyntaxNode` here, - // forgetting about parse errors. - db.parse_macro_expansion(macro_file).value.map(|(it, _)| it.syntax_node()) + db.parse_macro_expansion(macro_file).value.0.syntax_node() + } + } +} + +fn parse_or_expand_with_err( + db: &dyn ExpandDatabase, + file_id: HirFileId, +) -> ExpandResult> { + match file_id.repr() { + HirFileIdRepr::FileId(file_id) => ExpandResult::ok(db.parse(file_id).to_syntax()), + HirFileIdRepr::MacroFile(macro_file) => { + db.parse_macro_expansion(macro_file).map(|(it, _)| it) } } } @@ -254,35 +277,34 @@ fn parse_or_expand(db: &dyn ExpandDatabase, file_id: HirFileId) -> Option ExpandResult, Arc)>> { +) -> ExpandResult<(Parse, Arc)> { let _p = profile::span("parse_macro_expansion"); - let mbe::ValueResult { value, err } = db.macro_expand(macro_file.macro_call_id); + let mbe::ValueResult { value: tt, err } = db.macro_expand(macro_file.macro_call_id); if let Some(err) = &err { - // Note: - // The final goal we would like to make all parse_macro success, - // such that the following log will not call anyway. - let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - let node = loc.kind.to_node(db); - - // collect parent information for warning log - let parents = - std::iter::successors(loc.kind.file_id().call_node(db), |it| it.file_id.call_node(db)) - .map(|n| format!("{:#}", n.value)) - .collect::>() - .join("\n"); - - tracing::debug!( - "fail on macro_parse: (reason: {:?} macro_call: {:#}) parents: {}", - err, - node.value, - parents - ); + if tracing::enabled!(tracing::Level::DEBUG) { + // Note: + // The final goal we would like to make all parse_macro success, + // such that the following log will not call anyway. + let loc = db.lookup_intern_macro_call(macro_file.macro_call_id); + let node = loc.to_node(db); + + // collect parent information for warning log + let parents = std::iter::successors(loc.kind.file_id().call_node(db), |it| { + it.file_id.call_node(db) + }) + .map(|n| format!("{:#}", n.value)) + .collect::>() + .join("\n"); + + tracing::debug!( + "fail on macro_parse: (reason: {:?} macro_call: {:#}) parents: {}", + err, + node.value, + parents + ); + } } - let tt = match value { - Some(tt) => tt, - None => return ExpandResult { value: None, err }, - }; let expand_to = macro_expand_to(db, macro_file.macro_call_id); @@ -291,7 +313,7 @@ fn parse_macro_expansion( let (parse, rev_token_map) = token_tree_to_syntax_node(&tt, expand_to); - ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err } + ExpandResult { value: (parse, Arc::new(rev_token_map)), err } } fn macro_arg( @@ -339,7 +361,7 @@ fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet return None, + MacroCallKind::Attr { .. } if loc.def.is_attribute_derive() => return None, MacroCallKind::Attr { invoc_attr_index, .. } => { cov_mark::hit!(attribute_macro_attr_censoring); ast::Item::cast(node.clone())? @@ -385,13 +407,14 @@ fn macro_def( ) -> Result, mbe::ParseError> { match id.kind { MacroDefKind::Declarative(ast_id) => { + let is_2021 = db.crate_graph()[id.krate].edition >= Edition::Edition2021; let (mac, def_site_token_map) = match ast_id.to_node(db) { ast::Macro::MacroRules(macro_rules) => { let arg = macro_rules .token_tree() .ok_or_else(|| mbe::ParseError::Expected("expected a token tree".into()))?; let (tt, def_site_token_map) = mbe::syntax_node_to_token_tree(arg.syntax()); - let mac = mbe::DeclarativeMacro::parse_macro_rules(&tt)?; + let mac = mbe::DeclarativeMacro::parse_macro_rules(&tt, is_2021)?; (mac, def_site_token_map) } ast::Macro::MacroDef(macro_def) => { @@ -399,7 +422,7 @@ fn macro_def( .body() .ok_or_else(|| mbe::ParseError::Expected("expected a token tree".into()))?; let (tt, def_site_token_map) = mbe::syntax_node_to_token_tree(arg.syntax()); - let mac = mbe::DeclarativeMacro::parse_macro2(&tt)?; + let mac = mbe::DeclarativeMacro::parse_macro2(&tt, is_2021)?; (mac, def_site_token_map) } }; @@ -412,82 +435,96 @@ fn macro_def( MacroDefKind::BuiltInDerive(expander, _) => { Ok(Arc::new(TokenExpander::BuiltinDerive(expander))) } - MacroDefKind::BuiltInEager(..) => { - // FIXME: Return a random error here just to make the types align. - // This obviously should do something real instead. - Err(mbe::ParseError::UnexpectedToken("unexpected eager macro".into())) + MacroDefKind::BuiltInEager(expander, ..) => { + Ok(Arc::new(TokenExpander::BuiltinEager(expander))) } MacroDefKind::ProcMacro(expander, ..) => Ok(Arc::new(TokenExpander::ProcMacro(expander))), } } -fn macro_expand( - db: &dyn ExpandDatabase, - id: MacroCallId, -) -> ExpandResult>> { +fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult> { let _p = profile::span("macro_expand"); - let loc: MacroCallLoc = db.lookup_intern_macro_call(id); + let loc = db.lookup_intern_macro_call(id); if let Some(eager) = &loc.eager { - return ExpandResult { - value: Some(eager.arg_or_expansion.clone()), - // FIXME: There could be errors here! - err: None, - }; + return ExpandResult { value: eager.arg_or_expansion.clone(), err: eager.error.clone() }; } - let macro_arg = match db.macro_arg(id) { - Some(it) => it, - None => { - return ExpandResult::only_err(ExpandError::Other( - "Failed to lower macro args to token tree".into(), - )) - } - }; - let expander = match db.macro_def(loc.def) { Ok(it) => it, // FIXME: This is weird -- we effectively report macro *definition* // errors lazily, when we try to expand the macro. Instead, they should - // be reported at the definition site (when we construct a def map). + // be reported at the definition site when we construct a def map. + // (Note we do report them also at the definition site in the late diagnostic pass) Err(err) => { - return ExpandResult::only_err(ExpandError::Other( - format!("invalid macro definition: {err}").into(), - )) + return ExpandResult { + value: Arc::new(tt::Subtree { + delimiter: tt::Delimiter::UNSPECIFIED, + token_trees: vec![], + }), + err: Some(ExpandError::Other(format!("invalid macro definition: {err}").into())), + } } }; + let Some(macro_arg) = db.macro_arg(id) else { + return ExpandResult { + value: Arc::new( + tt::Subtree { + delimiter: tt::Delimiter::UNSPECIFIED, + token_trees: Vec::new(), + }, + ), + err: Some(ExpandError::Other( + "invalid token tree" + .into(), + )), + }; + }; let ExpandResult { value: mut tt, err } = expander.expand(db, id, ¯o_arg.0); // Set a hard limit for the expanded tt let count = tt.count(); if TOKEN_LIMIT.check(count).is_err() { - return ExpandResult::only_err(ExpandError::Other( - format!( - "macro invocation exceeds token limit: produced {} tokens, limit is {}", - count, - TOKEN_LIMIT.inner(), - ) - .into(), - )); + return ExpandResult { + value: Arc::new(tt::Subtree { + delimiter: tt::Delimiter::UNSPECIFIED, + token_trees: vec![], + }), + err: Some(ExpandError::Other( + format!( + "macro invocation exceeds token limit: produced {} tokens, limit is {}", + count, + TOKEN_LIMIT.inner(), + ) + .into(), + )), + }; } fixup::reverse_fixups(&mut tt, ¯o_arg.1, ¯o_arg.2); - ExpandResult { value: Some(Arc::new(tt)), err } + ExpandResult { value: Arc::new(tt), err } } -fn macro_expand_error(db: &dyn ExpandDatabase, macro_call: MacroCallId) -> Option { - db.macro_expand(macro_call).err +fn parse_macro_expansion_error( + db: &dyn ExpandDatabase, + macro_call_id: MacroCallId, +) -> ExpandResult> { + db.parse_macro_expansion(MacroFile { macro_call_id }) + .map(|it| it.0.errors().to_vec().into_boxed_slice()) } fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult { - let loc: MacroCallLoc = db.lookup_intern_macro_call(id); - let macro_arg = match db.macro_arg(id) { - Some(it) => it, - None => { - return ExpandResult::with_err( - tt::Subtree::empty(), - ExpandError::Other("No arguments for proc-macro".into()), - ) - } + let loc = db.lookup_intern_macro_call(id); + let Some(macro_arg) = db.macro_arg(id) else { + return ExpandResult { + value: tt::Subtree { + delimiter: tt::Delimiter::UNSPECIFIED, + token_trees: Vec::new(), + }, + err: Some(ExpandError::Other( + "invalid token tree" + .into(), + )), + }; }; let expander = match loc.def.kind { @@ -512,8 +549,7 @@ fn hygiene_frame(db: &dyn ExpandDatabase, file_id: HirFileId) -> Arc ExpandTo { - let loc: MacroCallLoc = db.lookup_intern_macro_call(id); - loc.kind.expand_to() + db.lookup_intern_macro_call(id).expand_to() } fn token_tree_to_syntax_node( diff --git a/crates/hir-expand/src/eager.rs b/crates/hir-expand/src/eager.rs index aca41b11f926e..59a92ff0ab612 100644 --- a/crates/hir-expand/src/eager.rs +++ b/crates/hir-expand/src/eager.rs @@ -18,10 +18,9 @@ //! //! //! See the full discussion : -use std::sync::Arc; - use base_db::CrateId; -use syntax::{ted, SyntaxNode}; +use syntax::{ted, Parse, SyntaxNode}; +use triomphe::Arc; use crate::{ ast::{self, AstNode}, @@ -32,77 +31,16 @@ use crate::{ MacroCallLoc, MacroDefId, MacroDefKind, UnresolvedMacro, }; -#[derive(Debug)] -pub struct ErrorEmitted { - _private: (), -} - -pub trait ErrorSink { - fn emit(&mut self, err: ExpandError); - - fn option( - &mut self, - opt: Option, - error: impl FnOnce() -> ExpandError, - ) -> Result { - match opt { - Some(it) => Ok(it), - None => { - self.emit(error()); - Err(ErrorEmitted { _private: () }) - } - } - } - - fn option_with( - &mut self, - opt: impl FnOnce() -> Option, - error: impl FnOnce() -> ExpandError, - ) -> Result { - self.option(opt(), error) - } - - fn result(&mut self, res: Result) -> Result { - match res { - Ok(it) => Ok(it), - Err(e) => { - self.emit(e); - Err(ErrorEmitted { _private: () }) - } - } - } - - fn expand_result_option(&mut self, res: ExpandResult>) -> Result { - match (res.value, res.err) { - (None, Some(err)) => { - self.emit(err); - Err(ErrorEmitted { _private: () }) - } - (Some(value), opt_err) => { - if let Some(err) = opt_err { - self.emit(err); - } - Ok(value) - } - (None, None) => unreachable!("`ExpandResult` without value or error"), - } - } -} - -impl ErrorSink for &'_ mut dyn FnMut(ExpandError) { - fn emit(&mut self, err: ExpandError) { - self(err); - } -} - pub fn expand_eager_macro( db: &dyn ExpandDatabase, krate: CrateId, macro_call: InFile, def: MacroDefId, resolver: &dyn Fn(ModPath) -> Option, - diagnostic_sink: &mut dyn FnMut(ExpandError), -) -> Result, UnresolvedMacro> { +) -> Result>, UnresolvedMacro> { + let MacroDefKind::BuiltInEager(eager, _) = def.kind else { + panic!("called `expand_eager_macro` on non-eager macro def {def:?}") + }; let hygiene = Hygiene::new(db, macro_call.file_id); let parsed_args = macro_call .value @@ -115,60 +53,54 @@ pub fn expand_eager_macro( let expand_to = ExpandTo::from_call_site(¯o_call.value); // Note: - // When `lazy_expand` is called, its *parent* file must be already exists. - // Here we store an eager macro id for the argument expanded subtree here + // When `lazy_expand` is called, its *parent* file must already exist. + // Here we store an eager macro id for the argument expanded subtree // for that purpose. let arg_id = db.intern_macro_call(MacroCallLoc { def, krate, - eager: Some(EagerCallInfo { + eager: Some(Box::new(EagerCallInfo { arg_or_expansion: Arc::new(parsed_args.clone()), included_file: None, - }), + error: None, + })), kind: MacroCallKind::FnLike { ast_id: call_id, expand_to: ExpandTo::Expr }, }); let parsed_args = mbe::token_tree_to_syntax_node(&parsed_args, mbe::TopEntryPoint::Expr).0; - let result = match eager_macro_recur( + let ExpandResult { value, mut err } = eager_macro_recur( db, &hygiene, InFile::new(arg_id.as_file(), parsed_args.syntax_node()), krate, resolver, - diagnostic_sink, - ) { - Ok(Ok(it)) => it, - Ok(Err(err)) => return Ok(Err(err)), - Err(err) => return Err(err), + )?; + let Some(value ) = value else { + return Ok(ExpandResult { value: None, err }) + }; + let subtree = { + let mut subtree = mbe::syntax_node_to_token_tree(&value).0; + subtree.delimiter = crate::tt::Delimiter::unspecified(); + subtree }; - let subtree = to_subtree(&result); - - if let MacroDefKind::BuiltInEager(eager, _) = def.kind { - let res = eager.expand(db, arg_id, &subtree); - if let Some(err) = res.err { - diagnostic_sink(err); - } - - let loc = MacroCallLoc { - def, - krate, - eager: Some(EagerCallInfo { - arg_or_expansion: Arc::new(res.value.subtree), - included_file: res.value.included_file, - }), - kind: MacroCallKind::FnLike { ast_id: call_id, expand_to }, - }; - Ok(Ok(db.intern_macro_call(loc))) - } else { - panic!("called `expand_eager_macro` on non-eager macro def {def:?}"); + let res = eager.expand(db, arg_id, &subtree); + if err.is_none() { + err = res.err; } -} -fn to_subtree(node: &SyntaxNode) -> crate::tt::Subtree { - let mut subtree = mbe::syntax_node_to_token_tree(node).0; - subtree.delimiter = crate::tt::Delimiter::unspecified(); - subtree + let loc = MacroCallLoc { + def, + krate, + eager: Some(Box::new(EagerCallInfo { + arg_or_expansion: Arc::new(res.value.subtree), + included_file: res.value.included_file, + error: err.clone(), + })), + kind: MacroCallKind::FnLike { ast_id: call_id, expand_to }, + }; + + Ok(ExpandResult { value: Some(db.intern_macro_call(loc)), err }) } fn lazy_expand( @@ -176,7 +108,7 @@ fn lazy_expand( def: &MacroDefId, macro_call: InFile, krate: CrateId, -) -> ExpandResult>> { +) -> ExpandResult>> { let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value); let expand_to = ExpandTo::from_call_site(¯o_call.value); @@ -186,10 +118,8 @@ fn lazy_expand( MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id), expand_to }, ); - let err = db.macro_expand_error(id); - let value = db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node)); - - ExpandResult { value, err } + let file_id = id.as_file(); + db.parse_or_expand_with_err(file_id).map(|parse| InFile::new(file_id, parse)) } fn eager_macro_recur( @@ -198,23 +128,25 @@ fn eager_macro_recur( curr: InFile, krate: CrateId, macro_resolver: &dyn Fn(ModPath) -> Option, - mut diagnostic_sink: &mut dyn FnMut(ExpandError), -) -> Result, UnresolvedMacro> { +) -> Result>, UnresolvedMacro> { let original = curr.value.clone_for_update(); let children = original.descendants().filter_map(ast::MacroCall::cast); let mut replacements = Vec::new(); + // Note: We only report a single error inside of eager expansions + let mut error = None; + // Collect replacement for child in children { let def = match child.path().and_then(|path| ModPath::from_src(db, path, hygiene)) { Some(path) => macro_resolver(path.clone()).ok_or(UnresolvedMacro { path })?, None => { - diagnostic_sink(ExpandError::Other("malformed macro invocation".into())); + error = Some(ExpandError::Other("malformed macro invocation".into())); continue; } }; - let insert = match def.kind { + let ExpandResult { value, err } = match def.kind { MacroDefKind::BuiltInEager(..) => { let id = match expand_eager_macro( db, @@ -222,45 +154,49 @@ fn eager_macro_recur( curr.with_value(child.clone()), def, macro_resolver, - diagnostic_sink, ) { - Ok(Ok(it)) => it, - Ok(Err(err)) => return Ok(Err(err)), + Ok(it) => it, Err(err) => return Err(err), }; - db.parse_or_expand(id.as_file()) - .expect("successful macro expansion should be parseable") - .clone_for_update() + id.map(|call| { + call.map(|call| db.parse_or_expand(call.as_file()).clone_for_update()) + }) } MacroDefKind::Declarative(_) | MacroDefKind::BuiltIn(..) | MacroDefKind::BuiltInAttr(..) | MacroDefKind::BuiltInDerive(..) | MacroDefKind::ProcMacro(..) => { - let res = lazy_expand(db, &def, curr.with_value(child.clone()), krate); - let val = match diagnostic_sink.expand_result_option(res) { - Ok(it) => it, - Err(err) => return Ok(Err(err)), - }; + let ExpandResult { value, err } = + lazy_expand(db, &def, curr.with_value(child.clone()), krate); // replace macro inside - let hygiene = Hygiene::new(db, val.file_id); - match eager_macro_recur(db, &hygiene, val, krate, macro_resolver, diagnostic_sink) { - Ok(Ok(it)) => it, - Ok(Err(err)) => return Ok(Err(err)), - Err(err) => return Err(err), - } + let hygiene = Hygiene::new(db, value.file_id); + let ExpandResult { value, err: error } = eager_macro_recur( + db, + &hygiene, + // FIXME: We discard parse errors here + value.map(|it| it.syntax_node()), + krate, + macro_resolver, + )?; + let err = if err.is_none() { error } else { err }; + ExpandResult { value, err } } }; - + if err.is_some() { + error = err; + } // check if the whole original syntax is replaced if child.syntax() == &original { - return Ok(Ok(insert)); + return Ok(ExpandResult { value, err: error }); } - replacements.push((child, insert)); + if let Some(insert) = value { + replacements.push((child, insert)); + } } replacements.into_iter().rev().for_each(|(old, new)| ted::replace(old.syntax(), new)); - Ok(Ok(original)) + Ok(ExpandResult { value: Some(original), err: error }) } diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs index b273f21768c68..00796e7c0dbb0 100644 --- a/crates/hir-expand/src/fixup.rs +++ b/crates/hir-expand/src/fixup.rs @@ -14,7 +14,7 @@ use tt::token_id::Subtree; /// The result of calculating fixes for a syntax node -- a bunch of changes /// (appending to and replacing nodes), the information that is needed to /// reverse those changes afterwards, and a token map. -#[derive(Debug)] +#[derive(Debug, Default)] pub(crate) struct SyntaxFixups { pub(crate) append: FxHashMap>, pub(crate) replace: FxHashMap>, @@ -24,7 +24,7 @@ pub(crate) struct SyntaxFixups { } /// This is the information needed to reverse the fixups. -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Default, PartialEq, Eq)] pub struct SyntaxFixupUndoInfo { original: Vec, } diff --git a/crates/hir-expand/src/hygiene.rs b/crates/hir-expand/src/hygiene.rs index 2eb56fc9e8b26..10f8fe9cec428 100644 --- a/crates/hir-expand/src/hygiene.rs +++ b/crates/hir-expand/src/hygiene.rs @@ -2,8 +2,6 @@ //! //! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at //! this moment, this is horribly incomplete and handles only `$crate`. -use std::sync::Arc; - use base_db::CrateId; use db::TokenExpander; use either::Either; @@ -12,6 +10,7 @@ use syntax::{ ast::{self, HasDocComments}, AstNode, SyntaxKind, SyntaxNode, TextRange, TextSize, }; +use triomphe::Arc; use crate::{ db::{self, ExpandDatabase}, @@ -200,8 +199,14 @@ fn make_hygiene_info( }); let macro_def = db.macro_def(loc.def).ok()?; - let (_, exp_map) = db.parse_macro_expansion(macro_file).value?; - let macro_arg = db.macro_arg(macro_file.macro_call_id)?; + let (_, exp_map) = db.parse_macro_expansion(macro_file).value; + let macro_arg = db.macro_arg(macro_file.macro_call_id).unwrap_or_else(|| { + Arc::new(( + tt::Subtree { delimiter: tt::Delimiter::UNSPECIFIED, token_trees: Vec::new() }, + Default::default(), + Default::default(), + )) + }); Some(HygieneInfo { file: macro_file, diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index 5e99eacc1b619..c8373778d32b0 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -20,11 +20,13 @@ pub mod mod_path; pub mod attrs; mod fixup; +use mbe::TokenMap; pub use mbe::{Origin, ValueResult}; use ::tt::token_id as tt; +use triomphe::Arc; -use std::{fmt, hash::Hash, iter, sync::Arc}; +use std::{fmt, hash::Hash, iter}; use base_db::{ impl_intern_key, @@ -51,11 +53,11 @@ use crate::{ pub type ExpandResult = ValueResult; -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Hash)] pub enum ExpandError { UnresolvedProcMacro(CrateId), Mbe(mbe::ExpandError), - RecursionOverflowPosioned, + RecursionOverflowPoisoned, Other(Box), } @@ -70,7 +72,7 @@ impl fmt::Display for ExpandError { match self { ExpandError::UnresolvedProcMacro(_) => f.write_str("unresolved proc-macro"), ExpandError::Mbe(it) => it.fmt(f), - ExpandError::RecursionOverflowPosioned => { + ExpandError::RecursionOverflowPoisoned => { f.write_str("overflow expanding the original macro") } ExpandError::Other(it) => f.write_str(it), @@ -113,7 +115,7 @@ impl_intern_key!(MacroCallId); pub struct MacroCallLoc { pub def: MacroDefId, pub(crate) krate: CrateId, - eager: Option, + eager: Option>, pub kind: MacroCallKind, } @@ -139,7 +141,8 @@ pub enum MacroDefKind { struct EagerCallInfo { /// NOTE: This can be *either* the expansion result, *or* the argument to the eager macro! arg_or_expansion: Arc, - included_file: Option, + included_file: Option<(FileId, TokenMap)>, + error: Option, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -166,8 +169,6 @@ pub enum MacroCallKind { /// Outer attributes are counted first, then inner attributes. This does not support /// out-of-line modules, which may have attributes spread across 2 files! invoc_attr_index: AttrId, - /// Whether this attribute is the `#[derive]` attribute. - is_derive: bool, }, } @@ -205,8 +206,8 @@ impl HirFileId { HirFileIdRepr::FileId(id) => break id, HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => { let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_call_id); - file_id = match loc.eager { - Some(EagerCallInfo { included_file: Some(file), .. }) => file.into(), + file_id = match loc.eager.as_deref() { + Some(&EagerCallInfo { included_file: Some((file, _)), .. }) => file.into(), _ => loc.kind.file_id(), }; } @@ -230,18 +231,17 @@ impl HirFileId { pub fn call_node(self, db: &dyn db::ExpandDatabase) -> Option> { let macro_file = self.macro_file()?; let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - Some(loc.kind.to_node(db)) + Some(loc.to_node(db)) } /// If this is a macro call, returns the syntax node of the very first macro call this file resides in. pub fn original_call_node(self, db: &dyn db::ExpandDatabase) -> Option<(FileId, SyntaxNode)> { - let mut call = - db.lookup_intern_macro_call(self.macro_file()?.macro_call_id).kind.to_node(db); + let mut call = db.lookup_intern_macro_call(self.macro_file()?.macro_call_id).to_node(db); loop { match call.file_id.repr() { HirFileIdRepr::FileId(file_id) => break Some((file_id, call.value)), HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => { - call = db.lookup_intern_macro_call(macro_call_id).kind.to_node(db); + call = db.lookup_intern_macro_call(macro_call_id).to_node(db); } } } @@ -255,8 +255,14 @@ impl HirFileId { let arg_tt = loc.kind.arg(db)?; let macro_def = db.macro_def(loc.def).ok()?; - let (parse, exp_map) = db.parse_macro_expansion(macro_file).value?; - let macro_arg = db.macro_arg(macro_file.macro_call_id)?; + let (parse, exp_map) = db.parse_macro_expansion(macro_file).value; + let macro_arg = db.macro_arg(macro_file.macro_call_id).unwrap_or_else(|| { + Arc::new(( + tt::Subtree { delimiter: tt::Delimiter::UNSPECIFIED, token_trees: Vec::new() }, + Default::default(), + Default::default(), + )) + }); let def = loc.def.ast_id().left().and_then(|id| { let def_tt = match id.to_node(db) { @@ -298,7 +304,7 @@ impl HirFileId { let macro_file = self.macro_file()?; let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); let attr = match loc.def.kind { - MacroDefKind::BuiltInDerive(..) => loc.kind.to_node(db), + MacroDefKind::BuiltInDerive(..) => loc.to_node(db), _ => return None, }; Some(attr.with_value(ast::Attr::cast(attr.value.clone())?)) @@ -319,7 +325,7 @@ impl HirFileId { match self.macro_file() { Some(macro_file) => { let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - matches!(loc.eager, Some(EagerCallInfo { included_file: Some(_), .. })) + matches!(loc.eager.as_deref(), Some(EagerCallInfo { included_file: Some(..), .. })) } _ => false, } @@ -342,7 +348,7 @@ impl HirFileId { match self.macro_file() { Some(macro_file) => { let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - matches!(loc.kind, MacroCallKind::Attr { is_derive: true, .. }) + loc.def.is_attribute_derive() } None => false, } @@ -413,22 +419,15 @@ impl MacroDefId { MacroDefKind::BuiltInAttr(..) | MacroDefKind::ProcMacro(_, ProcMacroKind::Attr, _) ) } -} - -// FIXME: attribute indices do not account for nested `cfg_attr` -impl MacroCallKind { - /// Returns the file containing the macro invocation. - fn file_id(&self) -> HirFileId { - match *self { - MacroCallKind::FnLike { ast_id: InFile { file_id, .. }, .. } - | MacroCallKind::Derive { ast_id: InFile { file_id, .. }, .. } - | MacroCallKind::Attr { ast_id: InFile { file_id, .. }, .. } => file_id, - } + pub fn is_attribute_derive(&self) -> bool { + matches!(self.kind, MacroDefKind::BuiltInAttr(expander, ..) if expander.is_derive()) } +} +impl MacroCallLoc { pub fn to_node(&self, db: &dyn db::ExpandDatabase) -> InFile { - match self { + match self.kind { MacroCallKind::FnLike { ast_id, .. } => { ast_id.with_value(ast_id.to_node(db).syntax().clone()) } @@ -444,23 +443,49 @@ impl MacroCallKind { .unwrap_or_else(|| it.syntax().clone()) }) } - MacroCallKind::Attr { ast_id, is_derive: true, invoc_attr_index, .. } => { - // FIXME: handle `cfg_attr` - ast_id.with_value(ast_id.to_node(db)).map(|it| { - it.doc_comments_and_attrs() - .nth(invoc_attr_index.ast_index()) - .and_then(|it| match it { - Either::Left(attr) => Some(attr.syntax().clone()), - Either::Right(_) => None, - }) - .unwrap_or_else(|| it.syntax().clone()) - }) + MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => { + if self.def.is_attribute_derive() { + // FIXME: handle `cfg_attr` + ast_id.with_value(ast_id.to_node(db)).map(|it| { + it.doc_comments_and_attrs() + .nth(invoc_attr_index.ast_index()) + .and_then(|it| match it { + Either::Left(attr) => Some(attr.syntax().clone()), + Either::Right(_) => None, + }) + .unwrap_or_else(|| it.syntax().clone()) + }) + } else { + ast_id.with_value(ast_id.to_node(db).syntax().clone()) + } } - MacroCallKind::Attr { ast_id, .. } => { - ast_id.with_value(ast_id.to_node(db).syntax().clone()) + } + } + + fn expand_to(&self) -> ExpandTo { + match self.kind { + MacroCallKind::FnLike { expand_to, .. } => expand_to, + MacroCallKind::Derive { .. } => ExpandTo::Items, + MacroCallKind::Attr { .. } if self.def.is_attribute_derive() => ExpandTo::Statements, + MacroCallKind::Attr { .. } => { + // is this always correct? + ExpandTo::Items } } } +} + +// FIXME: attribute indices do not account for nested `cfg_attr` + +impl MacroCallKind { + /// Returns the file containing the macro invocation. + fn file_id(&self) -> HirFileId { + match *self { + MacroCallKind::FnLike { ast_id: InFile { file_id, .. }, .. } + | MacroCallKind::Derive { ast_id: InFile { file_id, .. }, .. } + | MacroCallKind::Attr { ast_id: InFile { file_id, .. }, .. } => file_id, + } + } /// Returns the original file range that best describes the location of this macro call. /// @@ -538,15 +563,6 @@ impl MacroCallKind { MacroCallKind::Attr { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()), } } - - fn expand_to(&self) -> ExpandTo { - match self { - MacroCallKind::FnLike { expand_to, .. } => *expand_to, - MacroCallKind::Derive { .. } => ExpandTo::Items, - MacroCallKind::Attr { is_derive: true, .. } => ExpandTo::Statements, - MacroCallKind::Attr { .. } => ExpandTo::Items, // is this always correct? - } - } } impl MacroCallId { @@ -610,7 +626,7 @@ impl ExpansionInfo { let token_range = token.value.text_range(); match &loc.kind { - MacroCallKind::Attr { attr_args, invoc_attr_index, is_derive, .. } => { + MacroCallKind::Attr { attr_args, invoc_attr_index, .. } => { // FIXME: handle `cfg_attr` let attr = item .doc_comments_and_attrs() @@ -626,7 +642,8 @@ impl ExpansionInfo { token.value.text_range().checked_sub(attr_input_start)?; // shift by the item's tree's max id let token_id = attr_args.1.token_by_range(relative_range)?; - let token_id = if *is_derive { + + let token_id = if loc.def.is_attribute_derive() { // we do not shift for `#[derive]`, as we only need to downmap the derive attribute tokens token_id } else { @@ -677,20 +694,31 @@ impl ExpansionInfo { let call_id = self.expanded.file_id.macro_file()?.macro_call_id; let loc = db.lookup_intern_macro_call(call_id); + if let Some((file, map)) = loc.eager.and_then(|e| e.included_file) { + // Special case: map tokens from `include!` expansions to the included file + let range = map.first_range_by_token(token_id, token.value.kind())?; + let source = db.parse(file); + + let token = source.syntax_node().covering_element(range).into_token()?; + + return Some((InFile::new(file.into(), token), Origin::Call)); + } + // Attributes are a bit special for us, they have two inputs, the input tokentree and the annotated item. let (token_map, tt) = match &loc.kind { - MacroCallKind::Attr { attr_args, is_derive: true, .. } => { - (&attr_args.1, self.attr_input_or_mac_def.clone()?.syntax().cloned()) - } MacroCallKind::Attr { attr_args, .. } => { - // try unshifting the the token id, if unshifting fails, the token resides in the non-item attribute input - // note that the `TokenExpander::map_id_up` earlier only unshifts for declarative macros, so we don't double unshift with this - match self.macro_arg_shift.unshift(token_id) { - Some(unshifted) => { - token_id = unshifted; - (&attr_args.1, self.attr_input_or_mac_def.clone()?.syntax().cloned()) + if loc.def.is_attribute_derive() { + (&attr_args.1, self.attr_input_or_mac_def.clone()?.syntax().cloned()) + } else { + // try unshifting the token id, if unshifting fails, the token resides in the non-item attribute input + // note that the `TokenExpander::map_id_up` earlier only unshifts for declarative macros, so we don't double unshift with this + match self.macro_arg_shift.unshift(token_id) { + Some(unshifted) => { + token_id = unshifted; + (&attr_args.1, self.attr_input_or_mac_def.clone()?.syntax().cloned()) + } + None => (&self.macro_arg.1, self.arg.clone()), } - None => (&self.macro_arg.1, self.arg.clone()), } } _ => match origin { @@ -718,7 +746,7 @@ pub type AstId = InFile>; impl AstId { pub fn to_node(&self, db: &dyn db::ExpandDatabase) -> N { - let root = db.parse_or_expand(self.file_id).unwrap(); + let root = db.parse_or_expand(self.file_id); db.ast_id_map(self.file_id).get(self.value).to_node(&root) } } @@ -754,7 +782,7 @@ impl InFile { } pub fn file_syntax(&self, db: &dyn db::ExpandDatabase) -> SyntaxNode { - db.parse_or_expand(self.file_id).expect("source created from invalid file") + db.parse_or_expand(self.file_id) } } @@ -950,6 +978,7 @@ fn ascend_node_border_tokens( let first_token = |node: &SyntaxNode| skip_trivia_token(node.first_token()?, Direction::Next); let last_token = |node: &SyntaxNode| skip_trivia_token(node.last_token()?, Direction::Prev); + // FIXME: Once the token map rewrite is done, this shouldnt need to rely on syntax nodes and tokens anymore let first = first_token(node)?; let last = last_token(node)?; let first = ascend_call_token(db, &expansion, InFile::new(file_id, first))?; @@ -977,6 +1006,7 @@ impl InFile { self.value.syntax().descendants().filter_map(T::cast).map(move |n| self.with_value(n)) } + // FIXME: this should return `Option>` pub fn original_ast_node(self, db: &dyn db::ExpandDatabase) -> Option> { // This kind of upmapping can only be achieved in attribute expanded files, // as we don't have node inputs otherwise and therefore can't find an `N` node in the input diff --git a/crates/hir-expand/src/mod_path.rs b/crates/hir-expand/src/mod_path.rs index e9393cc89aedf..47a8ab7de77f9 100644 --- a/crates/hir-expand/src/mod_path.rs +++ b/crates/hir-expand/src/mod_path.rs @@ -1,7 +1,7 @@ //! A lowering for `use`-paths (more generally, paths without angle-bracketed segments). use std::{ - fmt::{self, Display}, + fmt::{self, Display as _}, iter, }; @@ -24,6 +24,12 @@ pub struct ModPath { #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct UnescapedModPath<'a>(&'a ModPath); +impl<'a> UnescapedModPath<'a> { + pub fn display(&'a self, db: &'a dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a { + UnescapedDisplay { db, path: self } + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum PathKind { Plain, @@ -110,52 +116,30 @@ impl ModPath { UnescapedModPath(self) } - fn _fmt(&self, f: &mut fmt::Formatter<'_>, escaped: bool) -> fmt::Result { - let mut first_segment = true; - let mut add_segment = |s| -> fmt::Result { - if !first_segment { - f.write_str("::")?; - } - first_segment = false; - f.write_str(s)?; - Ok(()) - }; - match self.kind { - PathKind::Plain => {} - PathKind::Super(0) => add_segment("self")?, - PathKind::Super(n) => { - for _ in 0..n { - add_segment("super")?; - } - } - PathKind::Crate => add_segment("crate")?, - PathKind::Abs => add_segment("")?, - PathKind::DollarCrate(_) => add_segment("$crate")?, - } - for segment in &self.segments { - if !first_segment { - f.write_str("::")?; - } - first_segment = false; - if escaped { - segment.fmt(f)? - } else { - segment.unescaped().fmt(f)? - }; - } - Ok(()) + pub fn display<'a>(&'a self, db: &'a dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a { + Display { db, path: self } } } -impl Display for ModPath { +struct Display<'a> { + db: &'a dyn ExpandDatabase, + path: &'a ModPath, +} + +impl<'a> fmt::Display for Display<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self._fmt(f, true) + display_fmt_path(self.db, self.path, f, true) } } -impl<'a> Display for UnescapedModPath<'a> { +struct UnescapedDisplay<'a> { + db: &'a dyn ExpandDatabase, + path: &'a UnescapedModPath<'a>, +} + +impl<'a> fmt::Display for UnescapedDisplay<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0._fmt(f, false) + display_fmt_path(self.db, self.path.0, f, false) } } @@ -164,6 +148,46 @@ impl From for ModPath { ModPath::from_segments(PathKind::Plain, iter::once(name)) } } +fn display_fmt_path( + db: &dyn ExpandDatabase, + path: &ModPath, + f: &mut fmt::Formatter<'_>, + escaped: bool, +) -> fmt::Result { + let mut first_segment = true; + let mut add_segment = |s| -> fmt::Result { + if !first_segment { + f.write_str("::")?; + } + first_segment = false; + f.write_str(s)?; + Ok(()) + }; + match path.kind { + PathKind::Plain => {} + PathKind::Super(0) => add_segment("self")?, + PathKind::Super(n) => { + for _ in 0..n { + add_segment("super")?; + } + } + PathKind::Crate => add_segment("crate")?, + PathKind::Abs => add_segment("")?, + PathKind::DollarCrate(_) => add_segment("$crate")?, + } + for segment in &path.segments { + if !first_segment { + f.write_str("::")?; + } + first_segment = false; + if escaped { + segment.display(db).fmt(f)?; + } else { + segment.unescaped().display(db).fmt(f)?; + } + } + Ok(()) +} fn convert_path( db: &dyn ExpandDatabase, diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index c3462beac73c5..f8dbb842775c3 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -24,27 +24,6 @@ enum Repr { TupleField(usize), } -impl fmt::Display for Name { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self.0 { - Repr::Text(text) => fmt::Display::fmt(&text, f), - Repr::TupleField(idx) => fmt::Display::fmt(&idx, f), - } - } -} - -impl<'a> fmt::Display for UnescapedName<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self.0 .0 { - Repr::Text(text) => { - let text = text.strip_prefix("r#").unwrap_or(text); - fmt::Display::fmt(&text, f) - } - Repr::TupleField(idx) => fmt::Display::fmt(&idx, f), - } - } -} - impl<'a> UnescapedName<'a> { /// Returns the textual representation of this name as a [`SmolStr`]. Prefer using this over /// [`ToString::to_string`] if possible as this conversion is cheaper in the general case. @@ -60,6 +39,11 @@ impl<'a> UnescapedName<'a> { Repr::TupleField(it) => SmolStr::new(it.to_string()), } } + + pub fn display(&'a self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a { + _ = db; + UnescapedDisplay { name: self } + } } impl Name { @@ -78,7 +62,7 @@ impl Name { Self::new_text(lt.text().into()) } - /// Shortcut to create inline plain text name + /// Shortcut to create inline plain text name. Panics if `text.len() > 22` const fn new_inline(text: &str) -> Name { Name::new_text(SmolStr::new_inline(text)) } @@ -112,6 +96,17 @@ impl Name { Name::new_inline("[missing name]") } + /// Generates a new name which is only equal to itself, by incrementing a counter. Due + /// its implementation, it should not be used in things that salsa considers, like + /// type names or field names, and it should be only used in names of local variables + /// and labels and similar things. + pub fn generate_new_name() -> Name { + use std::sync::atomic::{AtomicUsize, Ordering}; + static CNT: AtomicUsize = AtomicUsize::new(0); + let c = CNT.fetch_add(1, Ordering::Relaxed); + Name::new_text(format!("{c}").into()) + } + /// Returns the tuple index this name represents if it is a tuple field. pub fn as_tuple_index(&self) -> Option { match self.0 { @@ -156,6 +151,40 @@ impl Name { Repr::TupleField(_) => false, } } + + pub fn display<'a>(&'a self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a { + _ = db; + Display { name: self } + } +} + +struct Display<'a> { + name: &'a Name, +} + +impl<'a> fmt::Display for Display<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.name.0 { + Repr::Text(text) => fmt::Display::fmt(&text, f), + Repr::TupleField(idx) => fmt::Display::fmt(&idx, f), + } + } +} + +struct UnescapedDisplay<'a> { + name: &'a UnescapedName<'a>, +} + +impl<'a> fmt::Display for UnescapedDisplay<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.name.0 .0 { + Repr::Text(text) => { + let text = text.strip_prefix("r#").unwrap_or(text); + fmt::Display::fmt(&text, f) + } + Repr::TupleField(idx) => fmt::Display::fmt(&idx, f), + } + } } pub trait AsName { @@ -337,18 +366,24 @@ pub mod known { crate_type, derive, global_allocator, + no_core, + no_std, test, test_case, recursion_limit, feature, // known methods of lang items call_once, + call_mut, + call, eq, ne, ge, gt, le, lt, + // known fields of lang items + pieces, // lang items add_assign, add, @@ -363,6 +398,7 @@ pub mod known { deref, div_assign, div, + drop, fn_mut, fn_once, future_trait, diff --git a/crates/hir-expand/src/proc_macro.rs b/crates/hir-expand/src/proc_macro.rs index d758e9302cd87..c9539210abf65 100644 --- a/crates/hir-expand/src/proc_macro.rs +++ b/crates/hir-expand/src/proc_macro.rs @@ -7,20 +7,23 @@ use crate::{db::ExpandDatabase, tt, ExpandError, ExpandResult}; #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub struct ProcMacroExpander { - proc_macro_id: Option, + proc_macro_id: ProcMacroId, } +const DUMMY_ID: u32 = !0; + impl ProcMacroExpander { pub fn new(proc_macro_id: ProcMacroId) -> Self { - Self { proc_macro_id: Some(proc_macro_id) } + assert_ne!(proc_macro_id.0, DUMMY_ID); + Self { proc_macro_id } } pub fn dummy() -> Self { - Self { proc_macro_id: None } + Self { proc_macro_id: ProcMacroId(DUMMY_ID) } } pub fn is_dummy(&self) -> bool { - self.proc_macro_id.is_none() + self.proc_macro_id.0 == DUMMY_ID } pub fn expand( @@ -32,33 +35,37 @@ impl ProcMacroExpander { attr_arg: Option<&tt::Subtree>, ) -> ExpandResult { match self.proc_macro_id { - Some(id) => { - let krate_graph = db.crate_graph(); - let proc_macros = match &krate_graph[def_crate].proc_macro { - Ok(proc_macros) => proc_macros, - Err(_) => { + ProcMacroId(DUMMY_ID) => { + ExpandResult::new(tt::Subtree::empty(), ExpandError::UnresolvedProcMacro(def_crate)) + } + ProcMacroId(id) => { + let proc_macros = db.proc_macros(); + let proc_macros = match proc_macros.get(&def_crate) { + Some(Ok(proc_macros)) => proc_macros, + Some(Err(_)) | None => { never!("Non-dummy expander even though there are no proc macros"); - return ExpandResult::with_err( + return ExpandResult::new( tt::Subtree::empty(), ExpandError::Other("Internal error".into()), ); } }; - let proc_macro = match proc_macros.get(id.0 as usize) { + let proc_macro = match proc_macros.get(id as usize) { Some(proc_macro) => proc_macro, None => { never!( "Proc macro index out of bounds: the length is {} but the index is {}", proc_macros.len(), - id.0 + id ); - return ExpandResult::with_err( + return ExpandResult::new( tt::Subtree::empty(), ExpandError::Other("Internal error".into()), ); } }; + let krate_graph = db.crate_graph(); // Proc macros have access to the environment variables of the invoking crate. let env = &krate_graph[calling_crate].env; match proc_macro.expander.expand(tt, attr_arg, env) { @@ -74,17 +81,12 @@ impl ProcMacroExpander { } } ProcMacroExpansionError::System(text) - | ProcMacroExpansionError::Panic(text) => ExpandResult::with_err( - tt::Subtree::empty(), - ExpandError::Other(text.into()), - ), + | ProcMacroExpansionError::Panic(text) => { + ExpandResult::new(tt::Subtree::empty(), ExpandError::Other(text.into())) + } }, } } - None => ExpandResult::with_err( - tt::Subtree::empty(), - ExpandError::UnresolvedProcMacro(def_crate), - ), } } } diff --git a/crates/hir-expand/src/quote.rs b/crates/hir-expand/src/quote.rs index 63586f9daf069..ab3809abc7a26 100644 --- a/crates/hir-expand/src/quote.rs +++ b/crates/hir-expand/src/quote.rs @@ -162,6 +162,12 @@ impl ToTokenTree for crate::tt::TokenTree { } } +impl ToTokenTree for &crate::tt::TokenTree { + fn to_token(self) -> crate::tt::TokenTree { + self.clone() + } +} + impl ToTokenTree for crate::tt::Subtree { fn to_token(self) -> crate::tt::TokenTree { self.into() diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index 9b3296df2508a..6ca0dbb850399 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -15,7 +15,7 @@ doctest = false cov-mark = "2.0.0-pre.1" itertools = "0.10.5" arrayvec = "0.7.2" -bitflags = "1.3.2" +bitflags = "2.1.0" smallvec.workspace = true ena = "0.14.0" either = "1.7.0" @@ -28,6 +28,8 @@ chalk-recursive = { version = "0.89.0", default-features = false } chalk-derive = "0.89.0" la-arena = { version = "0.3.0", path = "../../lib/la-arena" } once_cell = "1.17.0" +triomphe.workspace = true +nohash-hasher.workspace = true typed-arena = "2.0.1" rustc_index = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_index", default-features = false } diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs index 58744dd0c0f98..f5b3f176b12e5 100644 --- a/crates/hir-ty/src/autoderef.rs +++ b/crates/hir-ty/src/autoderef.rs @@ -3,12 +3,11 @@ //! reference to a type with the field `bar`. This is an approximation of the //! logic in rustc (which lives in rustc_hir_analysis/check/autoderef.rs). -use std::sync::Arc; - use chalk_ir::cast::Cast; use hir_def::lang_item::LangItem; use hir_expand::name::name; use limit::Limit; +use triomphe::Arc; use crate::{ db::HirDatabase, infer::unify::InferenceTable, Canonical, Goal, Interner, ProjectionTyExt, @@ -23,6 +22,21 @@ pub(crate) enum AutoderefKind { Overloaded, } +pub fn autoderef( + db: &dyn HirDatabase, + env: Arc, + ty: Canonical, +) -> impl Iterator> + '_ { + let mut table = InferenceTable::new(db, env); + let ty = table.instantiate_canonical(ty); + let mut autoderef = Autoderef::new(&mut table, ty); + let mut v = Vec::new(); + while let Some((ty, _steps)) = autoderef.next() { + v.push(autoderef.table.canonicalize(ty).value); + } + v.into_iter() +} + #[derive(Debug)] pub(crate) struct Autoderef<'a, 'db> { pub(crate) table: &'a mut InferenceTable<'db>, @@ -76,49 +90,43 @@ pub(crate) fn autoderef_step( table: &mut InferenceTable<'_>, ty: Ty, ) -> Option<(AutoderefKind, Ty)> { - if let Some(derefed) = builtin_deref(&ty) { + if let Some(derefed) = builtin_deref(table, &ty, false) { Some((AutoderefKind::Builtin, table.resolve_ty_shallow(derefed))) } else { Some((AutoderefKind::Overloaded, deref_by_trait(table, ty)?)) } } -// FIXME: replace uses of this with Autoderef above -pub fn autoderef( - db: &dyn HirDatabase, - env: Arc, - ty: Canonical, -) -> impl Iterator> + '_ { - let mut table = InferenceTable::new(db, env); - let ty = table.instantiate_canonical(ty); - let mut autoderef = Autoderef::new(&mut table, ty); - let mut v = Vec::new(); - while let Some((ty, _steps)) = autoderef.next() { - v.push(autoderef.table.canonicalize(ty).value); - } - v.into_iter() -} - -pub(crate) fn deref(table: &mut InferenceTable<'_>, ty: Ty) -> Option { - let _p = profile::span("deref"); - autoderef_step(table, ty).map(|(_, ty)| ty) -} - -fn builtin_deref(ty: &Ty) -> Option<&Ty> { +pub(crate) fn builtin_deref<'ty>( + table: &mut InferenceTable<'_>, + ty: &'ty Ty, + explicit: bool, +) -> Option<&'ty Ty> { match ty.kind(Interner) { - TyKind::Ref(.., ty) | TyKind::Raw(.., ty) => Some(ty), + TyKind::Ref(.., ty) => Some(ty), + // FIXME: Maybe accept this but diagnose if its not explicit? + TyKind::Raw(.., ty) if explicit => Some(ty), + &TyKind::Adt(chalk_ir::AdtId(adt), ref substs) => { + if crate::lang_items::is_box(table.db, adt) { + substs.at(Interner, 0).ty(Interner) + } else { + None + } + } _ => None, } } -fn deref_by_trait(table: &mut InferenceTable<'_>, ty: Ty) -> Option { +pub(crate) fn deref_by_trait( + table @ &mut InferenceTable { db, .. }: &mut InferenceTable<'_>, + ty: Ty, +) -> Option { let _p = profile::span("deref_by_trait"); if table.resolve_ty_shallow(&ty).inference_var(Interner).is_some() { // don't try to deref unknown variables return None; } - let db = table.db; let deref_trait = db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait())?; let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?; diff --git a/crates/hir-ty/src/builder.rs b/crates/hir-ty/src/builder.rs index 03e9443599d8c..eec57ba3f80f1 100644 --- a/crates/hir-ty/src/builder.rs +++ b/crates/hir-ty/src/builder.rs @@ -18,7 +18,6 @@ use crate::{ consteval::unknown_const_as_generic, db::HirDatabase, infer::unify::InferenceTable, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, BoundVar, CallableSig, GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind, - ValueTyDefId, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -195,6 +194,19 @@ impl TyBuilder<()> { params.placeholder_subst(db) } + pub fn unknown_subst(db: &dyn HirDatabase, def: impl Into) -> Substitution { + let params = generics(db.upcast(), def.into()); + Substitution::from_iter( + Interner, + params.iter_id().map(|id| match id { + either::Either::Left(_) => TyKind::Error.intern(Interner).cast(Interner), + either::Either::Right(id) => { + unknown_const_as_generic(db.const_param_ty(id)).cast(Interner) + } + }), + ) + } + pub fn subst_for_def( db: &dyn HirDatabase, def: impl Into, @@ -233,6 +245,25 @@ impl TyBuilder<()> { TyBuilder::new((), params, parent_subst) } + pub fn subst_for_closure( + db: &dyn HirDatabase, + parent: DefWithBodyId, + sig_ty: Ty, + ) -> Substitution { + let sig_ty = sig_ty.cast(Interner); + let self_subst = iter::once(&sig_ty); + let Some(parent) = parent.as_generic_def_id() else { + return Substitution::from_iter(Interner, self_subst); + }; + Substitution::from_iter( + Interner, + self_subst + .chain(generics(db.upcast(), parent).placeholder_subst(db).iter(Interner)) + .cloned() + .collect::>(), + ) + } + pub fn build(self) -> Substitution { let ((), subst) = self.build_internal(); subst @@ -362,21 +393,4 @@ impl TyBuilder> { pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder> { TyBuilder::subst_for_def(db, def, None).with_data(db.impl_self_ty(def)) } - - pub fn value_ty( - db: &dyn HirDatabase, - def: ValueTyDefId, - parent_subst: Option, - ) -> TyBuilder> { - let poly_value_ty = db.value_ty(def); - let id = match def.to_generic_def_id() { - Some(id) => id, - None => { - // static items - assert!(parent_subst.is_none()); - return TyBuilder::new_empty(poly_value_ty); - } - }; - TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_value_ty) - } } diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs index 28ae4c349f83c..ac962c9e3e1f0 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -1,8 +1,8 @@ //! The implementation of `RustIrDatabase` for Chalk, which provides information //! about the code that Chalk needs. -use std::sync::Arc; +use core::ops; +use std::{iter, sync::Arc}; -use cov_mark::hit; use tracing::debug; use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds}; @@ -10,9 +10,9 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait}; use base_db::CrateId; use hir_def::{ - expr::Movability, + hir::Movability, lang_item::{lang_attr, LangItem, LangItemTarget}, - AssocItemId, GenericDefId, HasModule, ItemContainerId, Lookup, ModuleId, TypeAliasId, + AssocItemId, BlockId, GenericDefId, HasModule, ItemContainerId, Lookup, TypeAliasId, }; use hir_expand::name::name; @@ -25,7 +25,7 @@ use crate::{ method_resolution::{TraitImpls, TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS}, to_assoc_type_id, to_chalk_trait_id, traits::ChalkContext, - utils::generics, + utils::{generics, ClosureSubst}, wrap_empty_binders, AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, Interner, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause, @@ -108,17 +108,6 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { _ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]), }; - fn local_impls(db: &dyn HirDatabase, module: ModuleId) -> Option> { - let block = module.containing_block()?; - hit!(block_local_impls); - db.trait_impls_in_block(block) - } - - // Note: Since we're using impls_for_trait, only impls where the trait - // can be resolved should ever reach Chalk. impl_datum relies on that - // and will panic if the trait can't be resolved. - let in_deps = self.db.trait_impls_in_deps(self.krate); - let in_self = self.db.trait_impls_in_crate(self.krate); let trait_module = trait_.module(self.db.upcast()); let type_module = match self_ty_fp { Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(self.db.upcast())), @@ -128,33 +117,62 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(self.db.upcast())), _ => None, }; - let impl_maps = [ - Some(in_deps), - Some(in_self), - local_impls(self.db, trait_module), - type_module.and_then(|m| local_impls(self.db, m)), - ]; - let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db); + let mut def_blocks = + [trait_module.containing_block(), type_module.and_then(|it| it.containing_block())]; - let result: Vec<_> = if fps.is_empty() { - debug!("Unrestricted search for {:?} impls...", trait_); - impl_maps - .iter() - .filter_map(|o| o.as_ref()) - .flat_map(|impls| impls.for_trait(trait_).map(id_to_chalk)) - .collect() - } else { - impl_maps - .iter() - .filter_map(|o| o.as_ref()) - .flat_map(|impls| { - fps.iter().flat_map(move |fp| { - impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk) - }) - }) - .collect() - }; + // Note: Since we're using impls_for_trait, only impls where the trait + // can be resolved should ever reach Chalk. impl_datum relies on that + // and will panic if the trait can't be resolved. + let in_deps = self.db.trait_impls_in_deps(self.krate); + let in_self = self.db.trait_impls_in_crate(self.krate); + + let block_impls = iter::successors(self.block, |&block_id| { + cov_mark::hit!(block_local_impls); + self.db.block_def_map(block_id).parent().and_then(|module| module.containing_block()) + }) + .inspect(|&block_id| { + // make sure we don't search the same block twice + def_blocks.iter_mut().for_each(|block| { + if *block == Some(block_id) { + *block = None; + } + }); + }) + .map(|block_id| self.db.trait_impls_in_block(block_id)); + + let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db); + let mut result = vec![]; + match fps { + [] => { + debug!("Unrestricted search for {:?} impls...", trait_); + let mut f = |impls: &TraitImpls| { + result.extend(impls.for_trait(trait_).map(id_to_chalk)); + }; + f(&in_self); + in_deps.iter().map(ops::Deref::deref).for_each(&mut f); + block_impls.for_each(|it| f(&it)); + def_blocks + .into_iter() + .flatten() + .for_each(|it| f(&self.db.trait_impls_in_block(it))); + } + fps => { + let mut f = + |impls: &TraitImpls| { + result.extend(fps.iter().flat_map(|fp| { + impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk) + })); + }; + f(&in_self); + in_deps.iter().map(ops::Deref::deref).for_each(&mut f); + block_impls.for_each(|it| f(&it)); + def_blocks + .into_iter() + .flatten() + .for_each(|it| f(&self.db.trait_impls_in_block(it))); + } + } debug!("impls_for_trait returned {} impls", result.len()); result @@ -193,7 +211,7 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { &self, environment: &chalk_ir::Environment, ) -> chalk_ir::ProgramClauses { - self.db.program_clauses_for_chalk_env(self.krate, environment.clone()) + self.db.program_clauses_for_chalk_env(self.krate, self.block, environment.clone()) } fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId) -> Arc { @@ -321,7 +339,7 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { _closure_id: chalk_ir::ClosureId, substs: &chalk_ir::Substitution, ) -> chalk_ir::Binders> { - let sig_ty = substs.at(Interner, 0).assert_ty_ref(Interner).clone(); + let sig_ty = ClosureSubst(substs).sig_ty(); let sig = &sig_ty.callable_sig(self.db).expect("first closure param should be fn ptr"); let io = rust_ir::FnDefInputsAndOutputDatum { argument_types: sig.params().to_vec(), @@ -347,13 +365,19 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { fn trait_name(&self, trait_id: chalk_ir::TraitId) -> String { let id = from_chalk_trait_id(trait_id); - self.db.trait_data(id).name.to_string() + self.db.trait_data(id).name.display(self.db.upcast()).to_string() } fn adt_name(&self, chalk_ir::AdtId(adt_id): AdtId) -> String { match adt_id { - hir_def::AdtId::StructId(id) => self.db.struct_data(id).name.to_string(), - hir_def::AdtId::EnumId(id) => self.db.enum_data(id).name.to_string(), - hir_def::AdtId::UnionId(id) => self.db.union_data(id).name.to_string(), + hir_def::AdtId::StructId(id) => { + self.db.struct_data(id).name.display(self.db.upcast()).to_string() + } + hir_def::AdtId::EnumId(id) => { + self.db.enum_data(id).name.display(self.db.upcast()).to_string() + } + hir_def::AdtId::UnionId(id) => { + self.db.union_data(id).name.display(self.db.upcast()).to_string() + } } } fn adt_size_align(&self, _id: chalk_ir::AdtId) -> Arc { @@ -362,7 +386,7 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { } fn assoc_type_name(&self, assoc_ty_id: chalk_ir::AssocTypeId) -> String { let id = self.db.associated_ty_data(assoc_ty_id).name; - self.db.type_alias_data(id).name.to_string() + self.db.type_alias_data(id).name.display(self.db.upcast()).to_string() } fn opaque_type_name(&self, opaque_ty_id: chalk_ir::OpaqueTyId) -> String { format!("Opaque_{}", opaque_ty_id.0) @@ -373,7 +397,7 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { fn generator_datum( &self, id: chalk_ir::GeneratorId, - ) -> std::sync::Arc> { + ) -> Arc> { let (parent, expr) = self.db.lookup_intern_generator(id.into()); // We fill substitution with unknown type, because we only need to know whether the generic @@ -398,8 +422,8 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { let input_output = crate::make_type_and_const_binders(it, input_output); let movability = match self.db.body(parent)[expr] { - hir_def::expr::Expr::Closure { - closure_kind: hir_def::expr::ClosureKind::Generator(movability), + hir_def::hir::Expr::Closure { + closure_kind: hir_def::hir::ClosureKind::Generator(movability), .. } => movability, _ => unreachable!("non generator expression interned as generator"), @@ -414,7 +438,7 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { fn generator_witness_datum( &self, id: chalk_ir::GeneratorId, - ) -> std::sync::Arc> { + ) -> Arc> { // FIXME: calculate inner types let inner_types = rust_ir::GeneratorWitnessExistential { types: wrap_empty_binders(vec![]) }; @@ -435,7 +459,7 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { } } -impl<'a> chalk_ir::UnificationDatabase for &'a dyn HirDatabase { +impl chalk_ir::UnificationDatabase for &dyn HirDatabase { fn fn_def_variance( &self, fn_def_id: chalk_ir::FnDefId, @@ -451,9 +475,10 @@ impl<'a> chalk_ir::UnificationDatabase for &'a dyn HirDatabase { pub(crate) fn program_clauses_for_chalk_env_query( db: &dyn HirDatabase, krate: CrateId, + block: Option, environment: chalk_ir::Environment, ) -> chalk_ir::ProgramClauses { - chalk_solve::program_clauses_for_env(&ChalkContext { db, krate }, &environment) + chalk_solve::program_clauses_for_env(&ChalkContext { db, krate, block }, &environment) } pub(crate) fn associated_ty_data_query( @@ -786,17 +811,17 @@ pub(crate) fn adt_variance_query( ) } +/// Returns instantiated predicates. pub(super) fn convert_where_clauses( db: &dyn HirDatabase, def: GenericDefId, substs: &Substitution, ) -> Vec> { - let generic_predicates = db.generic_predicates(def); - let mut result = Vec::with_capacity(generic_predicates.len()); - for pred in generic_predicates.iter() { - result.push(pred.clone().substitute(Interner, substs)); - } - result + db.generic_predicates(def) + .iter() + .cloned() + .map(|pred| pred.substitute(Interner, substs)) + .collect() } pub(super) fn generic_predicate_to_inline_bound( diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs index 2141894922f7b..a8071591adac9 100644 --- a/crates/hir-ty/src/chalk_ext.rs +++ b/crates/hir-ty/src/chalk_ext.rs @@ -1,24 +1,28 @@ //! Various extensions traits for Chalk types. -use chalk_ir::{FloatTy, IntTy, Mutability, Scalar, TyVariableKind, UintTy}; +use chalk_ir::{cast::Cast, FloatTy, IntTy, Mutability, Scalar, TyVariableKind, UintTy}; use hir_def::{ builtin_type::{BuiltinFloat, BuiltinInt, BuiltinType, BuiltinUint}, generics::TypeOrConstParamData, lang_item::LangItem, type_ref::Rawness, - FunctionId, GenericDefId, HasModule, ItemContainerId, Lookup, TraitId, + DefWithBodyId, FunctionId, GenericDefId, HasModule, ItemContainerId, Lookup, TraitId, }; use crate::{ - db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, - from_placeholder_idx, to_chalk_trait_id, utils::generics, AdtId, AliasEq, AliasTy, Binders, - CallableDefId, CallableSig, DynTy, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy, + db::HirDatabase, + from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, + to_chalk_trait_id, + utils::{generics, ClosureSubst}, + AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, + ClosureId, DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, TypeFlags, WhereClause, }; pub trait TyExt { fn is_unit(&self) -> bool; fn is_integral(&self) -> bool; + fn is_scalar(&self) -> bool; fn is_floating_point(&self) -> bool; fn is_never(&self) -> bool; fn is_unknown(&self) -> bool; @@ -28,8 +32,10 @@ pub trait TyExt { fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>; fn as_builtin(&self) -> Option; fn as_tuple(&self) -> Option<&Substitution>; + fn as_closure(&self) -> Option; fn as_fn_def(&self, db: &dyn HirDatabase) -> Option; fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)>; + fn as_raw_ptr(&self) -> Option<(&Ty, Mutability)>; fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)>; fn as_generic_def(&self, db: &dyn HirDatabase) -> Option; @@ -44,6 +50,7 @@ pub trait TyExt { fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option>; fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option; + fn is_copy(self, db: &dyn HirDatabase, owner: DefWithBodyId) -> bool; /// FIXME: Get rid of this, it's not a good abstraction fn equals_ctor(&self, other: &Ty) -> bool; @@ -62,6 +69,10 @@ impl TyExt for Ty { ) } + fn is_scalar(&self) -> bool { + matches!(self.kind(Interner), TyKind::Scalar(_)) + } + fn is_floating_point(&self) -> bool { matches!( self.kind(Interner), @@ -128,12 +139,20 @@ impl TyExt for Ty { } } + fn as_closure(&self) -> Option { + match self.kind(Interner) { + TyKind::Closure(id, _) => Some(*id), + _ => None, + } + } + fn as_fn_def(&self, db: &dyn HirDatabase) -> Option { match self.callable_def(db) { Some(CallableDefId::FunctionId(func)) => Some(func), Some(CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_)) | None => None, } } + fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)> { match self.kind(Interner) { TyKind::Ref(mutability, lifetime, ty) => Some((ty, lifetime.clone(), *mutability)), @@ -141,6 +160,13 @@ impl TyExt for Ty { } } + fn as_raw_ptr(&self) -> Option<(&Ty, Mutability)> { + match self.kind(Interner) { + TyKind::Raw(mutability, ty) => Some((ty, *mutability)), + _ => None, + } + } + fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> { match self.kind(Interner) { TyKind::Ref(mutability, _, ty) => Some((ty, Rawness::Ref, *mutability)), @@ -176,10 +202,7 @@ impl TyExt for Ty { let sig = db.callable_item_signature(callable_def); Some(sig.substitute(Interner, parameters)) } - TyKind::Closure(.., substs) => { - let sig_param = substs.at(Interner, 0).assert_ty_ref(Interner); - sig_param.callable_sig(db) - } + TyKind::Closure(.., substs) => ClosureSubst(substs).sig_ty().callable_sig(db), _ => None, } } @@ -318,6 +341,20 @@ impl TyExt for Ty { } } + fn is_copy(self, db: &dyn HirDatabase, owner: DefWithBodyId) -> bool { + let crate_id = owner.module(db.upcast()).krate(); + let Some(copy_trait) = db.lang_item(crate_id, LangItem::Copy).and_then(|x| x.as_trait()) else { + return false; + }; + let trait_ref = TyBuilder::trait_ref(db, copy_trait).push(self).build(); + let env = db.trait_environment_for_body(owner); + let goal = Canonical { + value: InEnvironment::new(&env.env, trait_ref.cast(Interner)), + binders: CanonicalVarKinds::empty(Interner), + }; + db.trait_solve(crate_id, None, goal).is_some() + } + fn equals_ctor(&self, other: &Ty) -> bool { match (self.kind(Interner), other.kind(Interner)) { (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt == adt2, diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 5830c48988fe5..40b63b17b5aa4 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -3,19 +3,20 @@ use base_db::CrateId; use chalk_ir::{BoundVar, DebruijnIndex, GenericArgData}; use hir_def::{ - expr::Expr, - path::ModPath, + hir::Expr, + path::Path, resolver::{Resolver, ValueNs}, type_ref::ConstRef, - ConstId, EnumVariantId, + EnumVariantId, GeneralConstId, StaticId, }; use la_arena::{Idx, RawIdx}; use stdx::never; +use triomphe::Arc; use crate::{ - db::HirDatabase, infer::InferenceContext, layout::layout_of_ty, lower::ParamLoweringMode, - to_placeholder_idx, utils::Generics, Const, ConstData, ConstScalar, ConstValue, GenericArg, - Interner, MemoryMap, Ty, TyBuilder, + db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode, + mir::monomorphize_mir_body_bad, to_placeholder_idx, utils::Generics, Const, ConstData, + ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, Ty, TyBuilder, }; use super::mir::{interpret_mir, lower_to_mir, pad16, MirEvalError, MirLowerError}; @@ -57,7 +58,7 @@ pub enum ConstEvalError { impl From for ConstEvalError { fn from(value: MirLowerError) -> Self { match value { - MirLowerError::ConstEvalError(e) => *e, + MirLowerError::ConstEvalError(_, e) => *e, _ => ConstEvalError::MirLowerError(value), } } @@ -72,10 +73,11 @@ impl From for ConstEvalError { pub(crate) fn path_to_const( db: &dyn HirDatabase, resolver: &Resolver, - path: &ModPath, + path: &Path, mode: ParamLoweringMode, args_lazy: impl FnOnce() -> Generics, debruijn: DebruijnIndex, + expected_ty: Ty, ) -> Option { match resolver.resolve_path_in_value_ns_fully(db.upcast(), path) { Some(ValueNs::GenericParam(p)) => { @@ -89,7 +91,7 @@ pub(crate) fn path_to_const( Some(x) => ConstValue::BoundVar(BoundVar::new(debruijn, x)), None => { never!( - "Generic list doesn't contain this param: {:?}, {}, {:?}", + "Generic list doesn't contain this param: {:?}, {:?}, {:?}", args, path, p @@ -100,6 +102,10 @@ pub(crate) fn path_to_const( }; Some(ConstData { ty, value }.intern(Interner)) } + Some(ValueNs::ConstId(c)) => Some(intern_const_scalar( + ConstScalar::UnevaluatedConst(c.into(), Substitution::empty(Interner)), + expected_ty, + )), _ => None, } } @@ -124,14 +130,15 @@ pub fn intern_const_scalar(value: ConstScalar, ty: Ty) -> Const { /// Interns a constant scalar with the given type pub fn intern_const_ref(db: &dyn HirDatabase, value: &ConstRef, ty: Ty, krate: CrateId) -> Const { + let layout = db.layout_of_ty(ty.clone(), krate); let bytes = match value { ConstRef::Int(i) => { // FIXME: We should handle failure of layout better. - let size = layout_of_ty(db, &ty, krate).map(|x| x.size.bytes_usize()).unwrap_or(16); + let size = layout.map(|x| x.size.bytes_usize()).unwrap_or(16); ConstScalar::Bytes(i.to_le_bytes()[0..size].to_vec(), MemoryMap::default()) } ConstRef::UInt(i) => { - let size = layout_of_ty(db, &ty, krate).map(|x| x.size.bytes_usize()).unwrap_or(16); + let size = layout.map(|x| x.size.bytes_usize()).unwrap_or(16); ConstScalar::Bytes(i.to_le_bytes()[0..size].to_vec(), MemoryMap::default()) } ConstRef::Bool(b) => ConstScalar::Bytes(vec![*b as u8], MemoryMap::default()), @@ -153,13 +160,17 @@ pub fn usize_const(db: &dyn HirDatabase, value: Option, krate: CrateId) -> ) } -pub fn try_const_usize(c: &Const) -> Option { +pub fn try_const_usize(db: &dyn HirDatabase, c: &Const) -> Option { match &c.data(Interner).value { chalk_ir::ConstValue::BoundVar(_) => None, chalk_ir::ConstValue::InferenceVar(_) => None, chalk_ir::ConstValue::Placeholder(_) => None, chalk_ir::ConstValue::Concrete(c) => match &c.interned { ConstScalar::Bytes(x, _) => Some(u128::from_le_bytes(pad16(&x, false))), + ConstScalar::UnevaluatedConst(c, subst) => { + let ec = db.const_eval(*c, subst.clone()).ok()?; + try_const_usize(db, &ec) + } _ => None, }, } @@ -168,7 +179,16 @@ pub fn try_const_usize(c: &Const) -> Option { pub(crate) fn const_eval_recover( _: &dyn HirDatabase, _: &[String], - _: &ConstId, + _: &GeneralConstId, + _: &Substitution, +) -> Result { + Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) +} + +pub(crate) fn const_eval_static_recover( + _: &dyn HirDatabase, + _: &[String], + _: &StaticId, ) -> Result { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } @@ -183,11 +203,39 @@ pub(crate) fn const_eval_discriminant_recover( pub(crate) fn const_eval_query( db: &dyn HirDatabase, - const_id: ConstId, + def: GeneralConstId, + subst: Substitution, +) -> Result { + let body = match def { + GeneralConstId::ConstId(c) => { + db.monomorphized_mir_body(c.into(), subst, db.trait_environment(c.into()))? + } + GeneralConstId::AnonymousConstId(c) => { + let (def, root) = db.lookup_intern_anonymous_const(c); + let body = db.body(def); + let infer = db.infer(def); + Arc::new(monomorphize_mir_body_bad( + db, + lower_to_mir(db, def, &body, &infer, root)?, + subst, + db.trait_environment_for_body(def), + )?) + } + }; + let c = interpret_mir(db, &body, false).0?; + Ok(c) +} + +pub(crate) fn const_eval_static_query( + db: &dyn HirDatabase, + def: StaticId, ) -> Result { - let def = const_id.into(); - let body = db.mir_body(def)?; - let c = interpret_mir(db, &body, false)?; + let body = db.monomorphized_mir_body( + def.into(), + Substitution::empty(Interner), + db.trait_environment_for_body(def.into()), + )?; + let c = interpret_mir(db, &body, false).0?; Ok(c) } @@ -209,9 +257,13 @@ pub(crate) fn const_eval_discriminant_variant( }; return Ok(value); } - let mir_body = db.mir_body(def)?; - let c = interpret_mir(db, &mir_body, false)?; - let c = try_const_usize(&c).unwrap() as i128; + let mir_body = db.monomorphized_mir_body( + def, + Substitution::empty(Interner), + db.trait_environment_for_body(def), + )?; + let c = interpret_mir(db, &mir_body, false).0?; + let c = try_const_usize(db, &c).unwrap() as i128; Ok(c) } @@ -226,15 +278,16 @@ pub(crate) fn eval_to_const( debruijn: DebruijnIndex, ) -> Const { let db = ctx.db; + let infer = ctx.clone().resolve_all(); if let Expr::Path(p) = &ctx.body.exprs[expr] { let resolver = &ctx.resolver; - if let Some(c) = path_to_const(db, resolver, p.mod_path(), mode, args, debruijn) { + if let Some(c) = path_to_const(db, resolver, p, mode, args, debruijn, infer[expr].clone()) { return c; } } let infer = ctx.clone().resolve_all(); if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, &ctx.body, &infer, expr) { - if let Ok(result) = interpret_mir(db, &mir_body, true) { + if let Ok(result) = interpret_mir(db, &mir_body, true).0 { return result; } } diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 6a29e8ce52e62..06fff08b7d35b 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -1,8 +1,10 @@ -use base_db::fixture::WithFixture; +use base_db::{fixture::WithFixture, FileId}; +use chalk_ir::Substitution; use hir_def::db::DefDatabase; use crate::{ - consteval::try_const_usize, db::HirDatabase, test_db::TestDB, Const, ConstScalar, Interner, + consteval::try_const_usize, db::HirDatabase, mir::pad16, test_db::TestDB, Const, ConstScalar, + Interner, }; use super::{ @@ -10,9 +12,11 @@ use super::{ ConstEvalError, }; +mod intrinsics; + fn simplify(e: ConstEvalError) -> ConstEvalError { match e { - ConstEvalError::MirEvalError(MirEvalError::InFunction(_, e)) => { + ConstEvalError::MirEvalError(MirEvalError::InFunction(_, e, _, _)) => { simplify(ConstEvalError::MirEvalError(*e)) } _ => e, @@ -20,17 +24,35 @@ fn simplify(e: ConstEvalError) -> ConstEvalError { } #[track_caller] -fn check_fail(ra_fixture: &str, error: ConstEvalError) { - assert_eq!(eval_goal(ra_fixture).map_err(simplify), Err(error)); +fn check_fail(ra_fixture: &str, error: impl FnOnce(ConstEvalError) -> bool) { + let (db, file_id) = TestDB::with_single_file(ra_fixture); + match eval_goal(&db, file_id) { + Ok(_) => panic!("Expected fail, but it succeeded"), + Err(e) => { + assert!(error(simplify(e.clone())), "Actual error was: {}", pretty_print_err(e, db)) + } + } } #[track_caller] fn check_number(ra_fixture: &str, answer: i128) { - let r = eval_goal(ra_fixture).unwrap(); + let (db, file_id) = TestDB::with_single_file(ra_fixture); + let r = match eval_goal(&db, file_id) { + Ok(t) => t, + Err(e) => { + let err = pretty_print_err(e, db); + panic!("Error in evaluating goal: {}", err); + } + }; match &r.data(Interner).value { chalk_ir::ConstValue::Concrete(c) => match &c.interned { ConstScalar::Bytes(b, _) => { - assert_eq!(b, &answer.to_le_bytes()[0..b.len()]); + assert_eq!( + b, + &answer.to_le_bytes()[0..b.len()], + "Bytes differ. In decimal form: actual = {}, expected = {answer}", + i128::from_le_bytes(pad16(b, true)) + ); } x => panic!("Expected number but found {:?}", x), }, @@ -38,16 +60,26 @@ fn check_number(ra_fixture: &str, answer: i128) { } } -fn eval_goal(ra_fixture: &str) -> Result { - let (db, file_id) = TestDB::with_single_file(ra_fixture); +fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String { + let mut err = String::new(); + let span_formatter = |file, range| format!("{:?} {:?}", file, range); + match e { + ConstEvalError::MirLowerError(e) => e.pretty_print(&mut err, &db, span_formatter), + ConstEvalError::MirEvalError(e) => e.pretty_print(&mut err, &db, span_formatter), + } + .unwrap(); + err +} + +fn eval_goal(db: &TestDB, file_id: FileId) -> Result { let module_id = db.module_for_file(file_id); - let def_map = module_id.def_map(&db); + let def_map = module_id.def_map(db); let scope = &def_map[module_id.local_id].scope; let const_id = scope .declarations() .find_map(|x| match x { hir_def::ModuleDefId::ConstId(x) => { - if db.const_data(x).name.as_ref()?.to_string() == "GOAL" { + if db.const_data(x).name.as_ref()?.display(db).to_string() == "GOAL" { Some(x) } else { None @@ -56,7 +88,7 @@ fn eval_goal(ra_fixture: &str) -> Result { _ => None, }) .unwrap(); - db.const_eval(const_id) + db.const_eval(const_id.into(), Substitution::empty(Interner)) } #[test] @@ -72,8 +104,98 @@ fn bit_op() { check_number(r#"const GOAL: u8 = !0 & !(!0 >> 1)"#, 128); check_number(r#"const GOAL: i8 = !0 & !(!0 >> 1)"#, 0); check_number(r#"const GOAL: i8 = 1 << 7"#, (1i8 << 7) as i128); - // FIXME: report panic here - check_number(r#"const GOAL: i8 = 1 << 8"#, 0); + check_number(r#"const GOAL: i8 = -1 << 2"#, (-1i8 << 2) as i128); + check_fail(r#"const GOAL: i8 = 1 << 8"#, |e| { + e == ConstEvalError::MirEvalError(MirEvalError::Panic("Overflow in Shl".to_string())) + }); +} + +#[test] +fn floating_point() { + check_number( + r#"const GOAL: f64 = 2.0 + 3.0 * 5.5 - 8.;"#, + i128::from_le_bytes(pad16(&f64::to_le_bytes(10.5), true)), + ); + check_number( + r#"const GOAL: f32 = 2.0 + 3.0 * 5.5 - 8.;"#, + i128::from_le_bytes(pad16(&f32::to_le_bytes(10.5), true)), + ); + check_number( + r#"const GOAL: f32 = -90.0 + 36.0;"#, + i128::from_le_bytes(pad16(&f32::to_le_bytes(-54.0), true)), + ); +} + +#[test] +fn casts() { + check_number(r#"const GOAL: usize = 12 as *const i32 as usize"#, 12); + check_number( + r#" + //- minicore: coerce_unsized, index, slice + const GOAL: i32 = { + let a = [10, 20, 3, 15]; + let x: &[i32] = &a; + let y: *const [i32] = x; + let z = y as *const i32; + unsafe { *z } + }; + "#, + 10, + ); + check_number( + r#" + //- minicore: coerce_unsized, index, slice + const GOAL: i16 = { + let a = &mut 5; + let z = a as *mut _; + unsafe { *z } + }; + "#, + 5, + ); + check_number( + r#" + //- minicore: coerce_unsized, index, slice + const GOAL: usize = { + let a = &[10, 20, 30, 40] as &[i32]; + a.len() + }; + "#, + 4, + ); + check_number( + r#" + //- minicore: coerce_unsized, index, slice + const GOAL: usize = { + let a = [10, 20, 3, 15]; + let x: &[i32] = &a; + let y: *const [i32] = x; + let z = y as *const [u8]; // slice fat pointer cast don't touch metadata + let q = z as *const str; + let p = q as *const [u8]; + let w = unsafe { &*z }; + w.len() + }; + "#, + 4, + ); + check_number(r#"const GOAL: i32 = -12i8 as i32"#, -12); +} + +#[test] +fn raw_pointer_equality() { + check_number( + r#" + //- minicore: copy, eq + const GOAL: bool = { + let a = 2; + let p1 = a as *const i32; + let p2 = a as *const i32; + p1 == p2 + }; + "#, + 1, + ); } #[test] @@ -166,8 +288,7 @@ fn reference_autoderef() { #[test] fn overloaded_deref() { - // FIXME: We should support this. - check_fail( + check_number( r#" //- minicore: deref_mut struct Foo; @@ -185,9 +306,7 @@ fn overloaded_deref() { *y + *x }; "#, - ConstEvalError::MirLowerError(MirLowerError::NotSupported( - "explicit overloaded deref".into(), - )), + 10, ); } @@ -218,6 +337,117 @@ fn overloaded_deref_autoref() { ); } +#[test] +fn overloaded_index() { + check_number( + r#" + //- minicore: index + struct Foo; + + impl core::ops::Index for Foo { + type Output = i32; + fn index(&self, index: usize) -> &i32 { + if index == 7 { + &700 + } else { + &1000 + } + } + } + + impl core::ops::IndexMut for Foo { + fn index_mut(&mut self, index: usize) -> &mut i32 { + if index == 7 { + &mut 7 + } else { + &mut 10 + } + } + } + + const GOAL: i32 = { + (Foo[2]) + (Foo[7]) + (*&Foo[2]) + (*&Foo[7]) + (*&mut Foo[2]) + (*&mut Foo[7]) + }; + "#, + 3417, + ); +} + +#[test] +fn overloaded_binop() { + check_number( + r#" + //- minicore: add + enum Color { + Red, + Green, + Yellow, + } + + use Color::*; + + impl core::ops::Add for Color { + type Output = Color; + fn add(self, rhs: Color) -> Self::Output { + Yellow + } + } + + impl core::ops::AddAssign for Color { + fn add_assign(&mut self, rhs: Color) { + *self = Red; + } + } + + const GOAL: bool = { + let x = Red + Green; + let mut y = Green; + y += x; + x == Yellow && y == Red && Red + Green == Yellow && Red + Red == Yellow && Yellow + Green == Yellow + }; + "#, + 1, + ); + check_number( + r#" + //- minicore: add + impl core::ops::Add for usize { + type Output = usize; + fn add(self, rhs: usize) -> Self::Output { + self + rhs + } + } + + impl core::ops::AddAssign for usize { + fn add_assign(&mut self, rhs: usize) { + *self += rhs; + } + } + + #[lang = "shl"] + pub trait Shl { + type Output; + + fn shl(self, rhs: Rhs) -> Self::Output; + } + + impl Shl for usize { + type Output = usize; + + fn shl(self, rhs: u8) -> Self::Output { + self << rhs + } + } + + const GOAL: usize = { + let mut x = 10; + x += 20; + 2 + 2 + (x << 1u8) + };"#, + 64, + ); +} + #[test] fn function_call() { check_number( @@ -240,20 +470,6 @@ fn function_call() { ); } -#[test] -fn intrinsics() { - check_number( - r#" - extern "rust-intrinsic" { - pub fn size_of() -> usize; - } - - const GOAL: usize = size_of::(); - "#, - 4, - ); -} - #[test] fn trait_basic() { check_number( @@ -300,6 +516,35 @@ fn trait_method() { ); } +#[test] +fn trait_method_inside_block() { + check_number( + r#" +trait Twait { + fn a(&self) -> i32; +} + +fn outer() -> impl Twait { + struct Stwuct; + + impl Twait for Stwuct { + fn a(&self) -> i32 { + 5 + } + } + fn f() -> impl Twait { + let s = Stwuct; + s + } + f() +} + +const GOAL: i32 = outer().a(); + "#, + 5, + ); +} + #[test] fn generic_fn() { check_number( @@ -355,6 +600,16 @@ fn generic_fn() { "#, 12, ); + check_number( + r#" + const fn y(b: T) -> (T, ) { + let alloc = b; + (alloc, ) + } + const GOAL: u8 = y(2).0; + "#, + 2, + ); check_number( r#" //- minicore: coerce_unsized, index, slice @@ -483,6 +738,66 @@ fn loops() { "#, 4, ); + check_number( + r#" + const GOAL: u8 = { + let mut x = 0; + loop { + x = x + 1; + if x == 5 { + break x + 2; + } + } + }; + "#, + 7, + ); + check_number( + r#" + const GOAL: u8 = { + 'a: loop { + let x = 'b: loop { + let x = 'c: loop { + let x = 'd: loop { + let x = 'e: loop { + break 'd 1; + }; + break 2 + x; + }; + break 3 + x; + }; + break 'a 4 + x; + }; + break 5 + x; + } + }; + "#, + 8, + ); + check_number( + r#" + //- minicore: add + const GOAL: u8 = { + let mut x = 0; + 'a: loop { + 'b: loop { + 'c: while x < 20 { + 'd: while x < 5 { + 'e: loop { + x += 1; + continue 'c; + }; + }; + x += 1; + }; + break 'a; + }; + } + x + }; + "#, + 20, + ); } #[test] @@ -522,6 +837,18 @@ fn for_loops() { ); } +#[test] +fn ranges() { + check_number( + r#" + //- minicore: range + const GOAL: i32 = (1..2).start + (20..10).end + (100..=200).start + (2000..=1000).end + + (10000..).start + (..100000).end + (..=1000000).end; + "#, + 1111111, + ); +} + #[test] fn recursion() { check_number( @@ -555,6 +882,38 @@ fn structs() { "#, 17, ); + check_number( + r#" + struct Point { + x: i32, + y: i32, + } + + const GOAL: i32 = { + let p = Point { x: 5, y: 2 }; + let p2 = Point { x: 3, ..p }; + p.x * 1000 + p.y * 100 + p2.x * 10 + p2.y + }; + "#, + 5232, + ); + check_number( + r#" + struct Point { + x: i32, + y: i32, + } + + const GOAL: i32 = { + let p = Point { x: 5, y: 2 }; + let Point { x, y } = p; + let Point { x: x2, .. } = p; + let Point { y: y2, .. } = p; + x * 1000 + y * 100 + x2 * 10 + y2 + }; + "#, + 5252, + ); } #[test] @@ -599,13 +958,14 @@ fn tuples() { ); check_number( r#" - struct TupleLike(i32, u8, i64, u16); - const GOAL: u8 = { + struct TupleLike(i32, i64, u8, u16); + const GOAL: i64 = { let a = TupleLike(10, 20, 3, 15); - a.1 + let TupleLike(b, .., c) = a; + a.1 * 100 + b as i64 + c as i64 }; "#, - 20, + 2025, ); check_number( r#" @@ -638,11 +998,17 @@ fn path_pattern_matching() { use Season::*; + const MY_SEASON: Season = Summer; + + impl Season { + const FALL: Season = Fall; + } + const fn f(x: Season) -> i32 { match x { Spring => 1, - Summer => 2, - Fall => 3, + MY_SEASON => 2, + Season::FALL => 3, Winter => 4, } } @@ -653,42 +1019,137 @@ fn path_pattern_matching() { } #[test] -fn pattern_matching_ergonomics() { +fn pattern_matching_literal() { check_number( r#" - const fn f(x: &(u8, u8)) -> u8 { + const fn f(x: i32) -> i32 { match x { - (a, b) => *a + *b + -1 => 1, + 1 => 10, + _ => 100, } } - const GOAL: u8 = f(&(2, 3)); + const GOAL: i32 = f(-1) + f(1) + f(0) + f(-5); "#, - 5, + 211, ); -} - -#[test] -fn let_else() { check_number( r#" - const fn f(x: &(u8, u8)) -> u8 { - let (a, b) = x; - *a + *b + const fn f(x: &str) -> i32 { + match x { + "f" => 1, + "foo" => 10, + "" => 100, + "bar" => 1000, + _ => 10000, + } } - const GOAL: u8 = f(&(2, 3)); + const GOAL: i32 = f("f") + f("foo") * 2 + f("") * 3 + f("bar") * 4; "#, - 5, + 4321, ); +} + +#[test] +fn pattern_matching_range() { check_number( r#" - enum SingleVariant { - Var(u8, u8), + pub const L: i32 = 6; + mod x { + pub const R: i32 = 100; } - const fn f(x: &&&&&SingleVariant) -> u8 { - let SingleVariant::Var(a, b) = x; - *a + *b + const fn f(x: i32) -> i32 { + match x { + -1..=5 => x * 10, + L..=x::R => x * 100, + _ => x, + } } - const GOAL: u8 = f(&&&&&SingleVariant::Var(2, 3)); + const GOAL: i32 = f(-1) + f(2) + f(100) + f(-2) + f(1000); + "#, + 11008, + ); +} + +#[test] +fn pattern_matching_slice() { + check_number( + r#" + //- minicore: slice, index, coerce_unsized, copy + const fn f(x: &[usize]) -> usize { + match x { + [a, b @ .., c, d] => *a + b.len() + *c + *d, + } + } + const GOAL: usize = f(&[10, 20, 3, 15, 1000, 60, 16]); + "#, + 10 + 4 + 60 + 16, + ); + check_number( + r#" + //- minicore: slice, index, coerce_unsized, copy + const fn f(x: &[usize]) -> usize { + match x { + [] => 0, + [a] => *a, + &[a, b] => a + b, + [a, b @ .., c, d] => *a + b.len() + *c + *d, + } + } + const GOAL: usize = f(&[]) + f(&[10]) + f(&[100, 100]) + + f(&[1000, 1000, 1000]) + f(&[10000, 57, 34, 46, 10000, 10000]); + "#, + 33213, + ); +} + +#[test] +fn pattern_matching_ergonomics() { + check_number( + r#" + const fn f(x: &(u8, u8)) -> u8 { + match x { + (a, b) => *a + *b + } + } + const GOAL: u8 = f(&(2, 3)); + "#, + 5, + ); + check_number( + r#" + const GOAL: u8 = { + let a = &(2, 3); + let &(x, y) = a; + x + y + }; + "#, + 5, + ); +} + +#[test] +fn let_else() { + check_number( + r#" + const fn f(x: &(u8, u8)) -> u8 { + let (a, b) = x; + *a + *b + } + const GOAL: u8 = f(&(2, 3)); + "#, + 5, + ); + check_number( + r#" + enum SingleVariant { + Var(u8, u8), + } + const fn f(x: &&&&&SingleVariant) -> u8 { + let SingleVariant::Var(a, b) = x; + *a + *b + } + const GOAL: u8 = f(&&&&&SingleVariant::Var(2, 3)); "#, 5, ); @@ -748,6 +1209,77 @@ fn function_param_patterns() { ); } +#[test] +fn match_guards() { + check_number( + r#" + //- minicore: option + fn f(x: Option) -> i32 { + match x { + y if let Some(42) = y => 42000, + Some(y) => y, + None => 10 + } + } + const GOAL: i32 = f(Some(42)) + f(Some(2)) + f(None); + "#, + 42012, + ); +} + +#[test] +fn result_layout_niche_optimization() { + check_number( + r#" + //- minicore: option, result + const GOAL: i32 = match Some(2).ok_or(Some(2)) { + Ok(x) => x, + Err(_) => 1000, + }; + "#, + 2, + ); + check_number( + r#" + //- minicore: result + pub enum AlignmentEnum64 { + _Align1Shl0 = 1 << 0, + _Align1Shl1 = 1 << 1, + _Align1Shl2 = 1 << 2, + _Align1Shl3 = 1 << 3, + _Align1Shl4 = 1 << 4, + _Align1Shl5 = 1 << 5, + } + const GOAL: Result = { + let align = Err(()); + align + }; + "#, + 0, // It is 0 since result is niche encoded and 1 is valid for `AlignmentEnum64` + ); + check_number( + r#" + //- minicore: result + pub enum AlignmentEnum64 { + _Align1Shl0 = 1 << 0, + _Align1Shl1 = 1 << 1, + _Align1Shl2 = 1 << 2, + _Align1Shl3 = 1 << 3, + _Align1Shl4 = 1 << 4, + _Align1Shl5 = 1 << 5, + } + const GOAL: i32 = { + let align = Ok::<_, ()>(AlignmentEnum64::_Align1Shl0); + match align { + Ok(_) => 2, + Err(_) => 1, + } + }; + "#, + 2, + ); +} + #[test] fn options() { check_number( @@ -761,81 +1293,604 @@ fn options() { } }; "#, - 4, + 4, + ); + check_number( + r#" + //- minicore: option + fn f(x: Option>) -> i32 { + if let Some(y) = x && let Some(z) = y { + z + } else if let Some(y) = x { + 1 + } else { + 0 + } + } + const GOAL: i32 = f(Some(Some(10))) + f(Some(None)) + f(None); + "#, + 11, + ); + check_number( + r#" + //- minicore: option + const GOAL: u8 = { + let x = None; + match x { + Some(y) => 2 * y, + _ => 10, + } + }; + "#, + 10, + ); + check_number( + r#" + //- minicore: option + const GOAL: Option<&u8> = None; + "#, + 0, + ); +} + +#[test] +fn from_trait() { + check_number( + r#" + //- minicore: from + struct E1(i32); + struct E2(i32); + + impl From for E2 { + fn from(E1(x): E1) -> Self { + E2(1000 * x) + } + } + const GOAL: i32 = { + let x: E2 = E1(2).into(); + x.0 + }; + "#, + 2000, + ); +} + +#[test] +fn builtin_derive_macro() { + check_number( + r#" + //- minicore: clone, derive, builtin_impls + #[derive(Clone)] + enum Z { + Foo(Y), + Bar, + } + #[derive(Clone)] + struct X(i32, Z, i64) + #[derive(Clone)] + struct Y { + field1: i32, + field2: u8, + } + + const GOAL: u8 = { + let x = X(2, Z::Foo(Y { field1: 4, field2: 5 }), 8); + let x = x.clone(); + let Z::Foo(t) = x.1; + t.field2 + }; + "#, + 5, + ); + check_number( + r#" + //- minicore: default, derive, builtin_impls + #[derive(Default)] + struct X(i32, Y, i64) + #[derive(Default)] + struct Y { + field1: i32, + field2: u8, + } + + const GOAL: u8 = { + let x = X::default(); + x.1.field2 + }; + "#, + 0, + ); +} + +#[test] +fn try_operator() { + check_number( + r#" + //- minicore: option, try + const fn f(x: Option, y: Option) -> Option { + Some(x? * y?) + } + const fn g(x: Option, y: Option) -> i32 { + match f(x, y) { + Some(k) => k, + None => 5, + } + } + const GOAL: i32 = g(Some(10), Some(20)) + g(Some(30), None) + g(None, Some(40)) + g(None, None); + "#, + 215, + ); + check_number( + r#" + //- minicore: result, try, from + struct E1(i32); + struct E2(i32); + + impl From for E2 { + fn from(E1(x): E1) -> Self { + E2(1000 * x) + } + } + + const fn f(x: Result) -> Result { + Ok(x? * 10) + } + const fn g(x: Result) -> i32 { + match f(x) { + Ok(k) => 7 * k, + Err(E2(k)) => 5 * k, + } + } + const GOAL: i32 = g(Ok(2)) + g(Err(E1(3))); + "#, + 15140, + ); +} + +#[test] +fn try_block() { + check_number( + r#" + //- minicore: option, try + const fn g(x: Option, y: Option) -> i32 { + let r = try { x? * y? }; + match r { + Some(k) => k, + None => 5, + } + } + const GOAL: i32 = g(Some(10), Some(20)) + g(Some(30), None) + g(None, Some(40)) + g(None, None); + "#, + 215, + ); +} + +#[test] +fn closures() { + check_number( + r#" + //- minicore: fn, copy + const GOAL: i32 = { + let y = 5; + let c = |x| x + y; + c(2) + }; + "#, + 7, + ); + check_number( + r#" + //- minicore: fn, copy + const GOAL: i32 = { + let y = 5; + let c = |(a, b): &(i32, i32)| *a + *b + y; + c(&(2, 3)) + }; + "#, + 10, + ); + check_number( + r#" + //- minicore: fn, copy + const GOAL: i32 = { + let mut y = 5; + let c = |x| { + y = y + x; + }; + c(2); + c(3); + y + }; + "#, + 10, + ); + check_number( + r#" + //- minicore: fn, copy + const GOAL: i32 = { + let c: fn(i32) -> i32 = |x| 2 * x; + c(2) + c(10) + }; + "#, + 24, + ); + check_number( + r#" + //- minicore: fn, copy + struct X(i32); + impl X { + fn mult(&mut self, n: i32) { + self.0 = self.0 * n + } + } + const GOAL: i32 = { + let x = X(1); + let c = || { + x.mult(2); + || { + x.mult(3); + || { + || { + x.mult(4); + || { + x.mult(x.0); + || { + x.0 + } + } + } + } + } + }; + let r = c()()()()()(); + r + x.0 + }; + "#, + 24 * 24 * 2, + ); +} + +#[test] +fn closure_and_impl_fn() { + check_number( + r#" + //- minicore: fn, copy + fn closure_wrapper i32>(c: F) -> impl FnOnce() -> F { + || c + } + + const GOAL: i32 = { + let y = 5; + let c = closure_wrapper(|| y); + c()() + }; + "#, + 5, + ); + check_number( + r#" + //- minicore: fn, copy + fn f T>(t: F) -> impl Fn() -> T { + move || t() + } + + const GOAL: i32 = f(|| 2)(); + "#, + 2, + ); +} + +#[test] +fn or_pattern() { + check_number( + r#" + const GOAL: u8 = { + let (a | a) = 2; + a + }; + "#, + 2, + ); + check_number( + r#" + //- minicore: option + const fn f(x: Option) -> i32 { + let (Some(a) | Some(a)) = x else { return 2; }; + a + } + const GOAL: i32 = f(Some(10)) + f(None); + "#, + 12, + ); + check_number( + r#" + //- minicore: option + const fn f(x: Option, y: Option) -> i32 { + match (x, y) { + (Some(x), Some(y)) => x * y, + (Some(a), _) | (_, Some(a)) => a, + _ => 10, + } + } + const GOAL: i32 = f(Some(10), Some(20)) + f(Some(30), None) + f(None, Some(40)) + f(None, None); + "#, + 280, + ); +} + +#[test] +fn function_pointer_in_constants() { + check_number( + r#" + struct Foo { + f: fn(u8) -> u8, + } + const FOO: Foo = Foo { f: add2 }; + fn add2(x: u8) -> u8 { + x + 2 + } + const GOAL: u8 = (FOO.f)(3); + "#, + 5, + ); +} + +#[test] +fn function_pointer() { + check_number( + r#" + fn add2(x: u8) -> u8 { + x + 2 + } + const GOAL: u8 = { + let plus2 = add2; + plus2(3) + }; + "#, + 5, + ); + check_number( + r#" + fn add2(x: u8) -> u8 { + x + 2 + } + const GOAL: u8 = { + let plus2: fn(u8) -> u8 = add2; + plus2(3) + }; + "#, + 5, + ); + check_number( + r#" + //- minicore: coerce_unsized, index, slice + fn add2(x: u8) -> u8 { + x + 2 + } + fn mult3(x: u8) -> u8 { + x * 3 + } + const GOAL: u8 = { + let x = [add2, mult3]; + x[0](1) + x[1](5) + }; + "#, + 18, + ); +} + +#[test] +fn enum_variant_as_function() { + check_number( + r#" + //- minicore: option + const GOAL: u8 = { + let f = Some; + f(3).unwrap_or(2) + }; + "#, + 3, + ); + check_number( + r#" + //- minicore: option + const GOAL: u8 = { + let f: fn(u8) -> Option = Some; + f(3).unwrap_or(2) + }; + "#, + 3, + ); + check_number( + r#" + //- minicore: coerce_unsized, index, slice + enum Foo { + Add2(u8), + Mult3(u8), + } + use Foo::*; + const fn f(x: Foo) -> u8 { + match x { + Add2(x) => x + 2, + Mult3(x) => x * 3, + } + } + const GOAL: u8 = { + let x = [Add2, Mult3]; + f(x[0](1)) + f(x[1](5)) + }; + "#, + 18, ); +} + +#[test] +fn function_traits() { check_number( r#" - //- minicore: option - fn f(x: Option>) -> i32 { - if let Some(y) = x && let Some(z) = y { - z - } else if let Some(y) = x { - 1 - } else { - 0 - } + //- minicore: fn + fn add2(x: u8) -> u8 { + x + 2 } - const GOAL: i32 = f(Some(Some(10))) + f(Some(None)) + f(None); + fn call(f: impl Fn(u8) -> u8, x: u8) -> u8 { + f(x) + } + fn call_mut(mut f: impl FnMut(u8) -> u8, x: u8) -> u8 { + f(x) + } + fn call_once(f: impl FnOnce(u8) -> u8, x: u8) -> u8 { + f(x) + } + const GOAL: u8 = call(add2, 3) + call_mut(add2, 3) + call_once(add2, 3); "#, - 11, + 15, ); check_number( r#" - //- minicore: option + //- minicore: coerce_unsized, fn + fn add2(x: u8) -> u8 { + x + 2 + } + fn call(f: &dyn Fn(u8) -> u8, x: u8) -> u8 { + f(x) + } + fn call_mut(f: &mut dyn FnMut(u8) -> u8, x: u8) -> u8 { + f(x) + } + const GOAL: u8 = call(&add2, 3) + call_mut(&mut add2, 3); + "#, + 10, + ); + check_number( + r#" + //- minicore: fn + fn add2(x: u8) -> u8 { + x + 2 + } + fn call(f: impl Fn(u8) -> u8, x: u8) -> u8 { + f(x) + } + fn call_mut(mut f: impl FnMut(u8) -> u8, x: u8) -> u8 { + f(x) + } + fn call_once(f: impl FnOnce(u8) -> u8, x: u8) -> u8 { + f(x) + } const GOAL: u8 = { - let x = None; - match x { - Some(y) => 2 * y, - _ => 10, - } + let add2: fn(u8) -> u8 = add2; + call(add2, 3) + call_mut(add2, 3) + call_once(add2, 3) }; "#, - 10, + 15, ); check_number( r#" - //- minicore: option - const GOAL: Option<&u8> = None; + //- minicore: fn + fn add2(x: u8) -> u8 { + x + 2 + } + fn call(f: &&&&&impl Fn(u8) -> u8, x: u8) -> u8 { + f(x) + } + const GOAL: u8 = call(&&&&&add2, 3); "#, - 0, + 5, ); } #[test] -fn or_pattern() { +fn dyn_trait() { check_number( r#" + //- minicore: coerce_unsized, index, slice + trait Foo { + fn foo(&self) -> u8 { 10 } + } + struct S1; + struct S2; + struct S3; + impl Foo for S1 { + fn foo(&self) -> u8 { 1 } + } + impl Foo for S2 { + fn foo(&self) -> u8 { 2 } + } + impl Foo for S3 {} const GOAL: u8 = { - let (a | a) = 2; - a + let x: &[&dyn Foo] = &[&S1, &S2, &S3]; + x[0].foo() + x[1].foo() + x[2].foo() }; "#, - 2, + 13, ); check_number( r#" - //- minicore: option - const fn f(x: Option) -> i32 { - let (Some(a) | Some(a)) = x else { return 2; }; - a + //- minicore: coerce_unsized, index, slice + trait Foo { + fn foo(&self) -> i32 { 10 } } - const GOAL: i32 = f(Some(10)) + f(None); + trait Bar { + fn bar(&self) -> i32 { 20 } + } + + struct S; + impl Foo for S { + fn foo(&self) -> i32 { 200 } + } + impl Bar for dyn Foo { + fn bar(&self) -> i32 { 700 } + } + const GOAL: i32 = { + let x: &dyn Foo = &S; + x.bar() + x.foo() + }; "#, - 12, + 900, ); +} + +#[test] +fn boxes() { check_number( r#" - //- minicore: option - const fn f(x: Option, y: Option) -> i32 { - match (x, y) { - (Some(x), Some(y)) => x * y, - (Some(a), _) | (_, Some(a)) => a, - _ => 10, - } +//- minicore: coerce_unsized, deref_mut, slice +use core::ops::{Deref, DerefMut}; +use core::{marker::Unsize, ops::CoerceUnsized}; + +#[lang = "owned_box"] +pub struct Box { + inner: *mut T, +} +impl Box { + fn new(t: T) -> Self { + #[rustc_box] + Box::new(t) } - const GOAL: i32 = f(Some(10), Some(20)) + f(Some(30), None) + f(None, Some(40)) + f(None, None); - "#, - 280, +} + +impl Deref for Box { + type Target = T; + + fn deref(&self) -> &T { + &**self + } +} + +impl DerefMut for Box { + fn deref_mut(&mut self) -> &mut T { + &mut **self + } +} + +impl, U: ?Sized> CoerceUnsized> for Box {} + +const GOAL: usize = { + let x = Box::new(5); + let y: Box<[i32]> = Box::new([1, 2, 3]); + *x + y.len() +}; +"#, + 8, ); } @@ -867,9 +1922,42 @@ fn array_and_index() { check_number( r#" //- minicore: coerce_unsized, index, slice + const GOAL: usize = { + let a = [1, 2, 3]; + let x: &[i32] = &a; + let y = &*x; + y.len() + };"#, + 3, + ); + check_number( + r#" + //- minicore: coerce_unsized, index, slice const GOAL: usize = [1, 2, 3, 4, 5].len();"#, 5, ); + check_number( + r#" + //- minicore: coerce_unsized, index, slice + const GOAL: [u16; 5] = [1, 2, 3, 4, 5];"#, + 1 + (2 << 16) + (3 << 32) + (4 << 48) + (5 << 64), + ); + check_number( + r#" + //- minicore: coerce_unsized, index, slice + const GOAL: [u16; 5] = [12; 5];"#, + 12 + (12 << 16) + (12 << 32) + (12 << 48) + (12 << 64), + ); + check_number( + r#" + //- minicore: coerce_unsized, index, slice + const LEN: usize = 4; + const GOAL: u16 = { + let x = [7; LEN]; + x[2] + }"#, + 7, + ); } #[test] @@ -887,6 +1975,38 @@ fn byte_string() { ); } +#[test] +fn c_string() { + check_number( + r#" +//- minicore: index, slice +#[lang = "CStr"] +pub struct CStr { + inner: [u8] +} +const GOAL: u8 = { + let a = c"hello"; + a.inner[0] +}; + "#, + 104, + ); + check_number( + r#" +//- minicore: index, slice +#[lang = "CStr"] +pub struct CStr { + inner: [u8] +} +const GOAL: u8 = { + let a = c"hello"; + a.inner[6] +}; + "#, + 0, + ); +} + #[test] fn consts() { check_number( @@ -900,6 +2020,37 @@ fn consts() { ); } +#[test] +fn statics() { + check_number( + r#" + //- minicore: cell + use core::cell::Cell; + fn f() -> i32 { + static S: Cell = Cell::new(10); + S.set(S.get() + 1); + S.get() + } + const GOAL: i32 = f() + f() + f(); + "#, + 36, + ); +} + +#[test] +fn extern_weak_statics() { + check_number( + r#" + extern "C" { + #[linkage = "extern_weak"] + static __dso_handle: *mut u8; + } + const GOAL: usize = __dso_handle as usize; + "#, + 0, + ); +} + #[test] fn enums() { check_number( @@ -927,14 +2078,14 @@ fn enums() { "#, 0, ); - let r = eval_goal( + let (db, file_id) = TestDB::with_single_file( r#" enum E { A = 1, B } const GOAL: E = E::A; "#, - ) - .unwrap(); - assert_eq!(try_const_usize(&r), Some(1)); + ); + let r = eval_goal(&db, file_id).unwrap(); + assert_eq!(try_const_usize(&db, &r), Some(1)); } #[test] @@ -946,7 +2097,7 @@ fn const_loop() { const F2: i32 = 2 * F1; const GOAL: i32 = F3; "#, - ConstEvalError::MirLowerError(MirLowerError::Loop), + |e| e == ConstEvalError::MirLowerError(MirLowerError::Loop), ); } @@ -962,6 +2113,29 @@ fn const_transfer_memory() { ); } +#[test] +fn anonymous_const_block() { + check_number( + r#" + extern "rust-intrinsic" { + pub fn size_of() -> usize; + } + + const fn f() -> usize { + let r = const { size_of::() }; + r + } + + const GOAL: usize = { + let x = const { 2 + const { 3 } }; + let y = f::(); + x + y + }; + "#, + 9, + ); +} + #[test] fn const_impl_assoc() { check_number( @@ -970,9 +2144,9 @@ fn const_impl_assoc() { impl U5 { const VAL: usize = 5; } - const GOAL: usize = U5::VAL; + const GOAL: usize = U5::VAL + ::VAL; "#, - 5, + 10, ); } @@ -987,12 +2161,61 @@ fn const_generic_subst_fn() { "#, 11, ); + check_number( + r#" + fn f(x: [i32; N]) -> usize { + N + } + + trait ArrayExt { + fn f(self) -> usize; + } + + impl ArrayExt for [T; N] { + fn g(self) -> usize { + f(self) + } + } + + const GOAL: usize = f([1, 2, 5]); + "#, + 3, + ); +} + +#[test] +fn layout_of_type_with_associated_type_field_defined_inside_body() { + check_number( + r#" +trait Tr { + type Ty; +} + +struct St(T::Ty); + +const GOAL: i64 = { + // if we move `St2` out of body, the test will fail, as we don't see the impl anymore. That + // case will probably be rejected by rustc in some later edition, but we should support this + // case. + struct St2; + + impl Tr for St2 { + type Ty = i64; + } + + struct Goal(St); + + let x = Goal(St(5)); + x.0.0 +}; +"#, + 5, + ); } #[test] fn const_generic_subst_assoc_const_impl() { - // FIXME: this should evaluate to 5 - check_fail( + check_number( r#" struct Adder; impl Adder { @@ -1000,14 +2223,42 @@ fn const_generic_subst_assoc_const_impl() { } const GOAL: usize = Adder::<2, 3>::VAL; "#, - ConstEvalError::MirEvalError(MirEvalError::TypeError("missing generic arg")), + 5, + ); +} + +#[test] +fn associated_types() { + check_number( + r#" + trait Tr { + type Item; + fn get_item(&self) -> Self::Item; + } + + struct X(i32); + struct Y(i32); + + impl Tr for X { + type Item = Y; + fn get_item(&self) -> Self::Item { + Y(self.0 + 2) + } + } + + fn my_get_item(x: T) -> ::Item { + x.get_item() + } + + const GOAL: i32 = my_get_item(X(3)).0; + "#, + 5, ); } #[test] fn const_trait_assoc() { - // FIXME: this should evaluate to 0 - check_fail( + check_number( r#" struct U0; trait ToConst { @@ -1016,9 +2267,49 @@ fn const_trait_assoc() { impl ToConst for U0 { const VAL: usize = 0; } - const GOAL: usize = U0::VAL; + impl ToConst for i32 { + const VAL: usize = 32; + } + const GOAL: usize = U0::VAL + i32::VAL; + "#, + 32, + ); + check_number( + r#" + struct S(*mut T); + + trait MySized: Sized { + const SIZE: S = S(1 as *mut Self); + } + + impl MySized for i32 { + const SIZE: S = S(10 as *mut i32); + } + + impl MySized for i64 { + } + + const fn f() -> usize { + T::SIZE.0 as usize + } + + const GOAL: usize = f::() + f::() * 2; + "#, + 12, + ); +} + +#[test] +fn panic_messages() { + check_fail( + r#" + //- minicore: panic + const GOAL: u8 = { + let x: u16 = 2; + panic!("hello"); + }; "#, - ConstEvalError::MirLowerError(MirLowerError::IncompleteExpr), + |e| e == ConstEvalError::MirEvalError(MirEvalError::Panic("hello".to_string())), ); } @@ -1028,7 +2319,7 @@ fn exec_limits() { r#" const GOAL: usize = loop {}; "#, - ConstEvalError::MirEvalError(MirEvalError::ExecutionLimitExceeded), + |e| e == ConstEvalError::MirEvalError(MirEvalError::ExecutionLimitExceeded), ); check_fail( r#" @@ -1037,7 +2328,7 @@ fn exec_limits() { } const GOAL: i32 = f(0); "#, - ConstEvalError::MirEvalError(MirEvalError::StackOverflow), + |e| e == ConstEvalError::MirEvalError(MirEvalError::StackOverflow), ); // Reasonable code should still work check_number( @@ -1062,7 +2353,7 @@ fn exec_limits() { #[test] fn type_error() { - let e = eval_goal( + check_fail( r#" const GOAL: u8 = { let x: u16 = 2; @@ -1070,6 +2361,25 @@ fn type_error() { y.0 }; "#, + |e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::TypeMismatch(_))), + ); +} + +#[test] +fn unsized_local() { + check_fail( + r#" + //- minicore: coerce_unsized, index, slice + const fn x() -> SomeUnknownTypeThatDereferenceToSlice { + SomeUnknownTypeThatDereferenceToSlice + } + + const GOAL: u16 = { + let y = x(); + let z: &[u16] = &y; + z[1] + }; + "#, + |e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::UnsizedTemporary(_))), ); - assert!(matches!(e, Err(ConstEvalError::MirLowerError(MirLowerError::TypeMismatch(_))))); } diff --git a/crates/hir-ty/src/consteval/tests/intrinsics.rs b/crates/hir-ty/src/consteval/tests/intrinsics.rs new file mode 100644 index 0000000000000..e05d824dbacfc --- /dev/null +++ b/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -0,0 +1,377 @@ +use super::*; + +#[test] +fn size_of() { + check_number( + r#" + extern "rust-intrinsic" { + pub fn size_of() -> usize; + } + + const GOAL: usize = size_of::(); + "#, + 4, + ); +} + +#[test] +fn transmute() { + check_number( + r#" + extern "rust-intrinsic" { + pub fn transmute(e: T) -> U; + } + + const GOAL: i32 = transmute((1i16, 1i16)); + "#, + 0x00010001, + ); +} + +#[test] +fn const_eval_select() { + check_number( + r#" + extern "rust-intrinsic" { + pub fn const_eval_select(arg: ARG, called_in_const: F, called_at_rt: G) -> RET + where + G: FnOnce, + F: FnOnce; + } + + const fn in_const(x: i32, y: i32) -> i32 { + x + y + } + + fn in_rt(x: i32, y: i32) -> i32 { + x + y + } + + const GOAL: i32 = const_eval_select((2, 3), in_const, in_rt); + "#, + 5, + ); +} + +#[test] +fn wrapping_add() { + check_number( + r#" + extern "rust-intrinsic" { + pub fn wrapping_add(a: T, b: T) -> T; + } + + const GOAL: u8 = wrapping_add(10, 250); + "#, + 4, + ); +} + +#[test] +fn saturating_add() { + check_number( + r#" + extern "rust-intrinsic" { + pub fn saturating_add(a: T, b: T) -> T; + } + + const GOAL: u8 = saturating_add(10, 250); + "#, + 255, + ); + check_number( + r#" + extern "rust-intrinsic" { + pub fn saturating_add(a: T, b: T) -> T; + } + + const GOAL: i8 = saturating_add(5, 8); + "#, + 13, + ); +} + +#[test] +fn allocator() { + check_number( + r#" + extern "Rust" { + #[rustc_allocator] + fn __rust_alloc(size: usize, align: usize) -> *mut u8; + #[rustc_deallocator] + fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); + #[rustc_reallocator] + fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8; + #[rustc_allocator_zeroed] + fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; + } + + const GOAL: u8 = unsafe { + let ptr = __rust_alloc(4, 1); + let ptr2 = ((ptr as usize) + 1) as *mut u8; + *ptr = 23; + *ptr2 = 32; + let ptr = __rust_realloc(ptr, 4, 1, 8); + let ptr2 = ((ptr as usize) + 1) as *mut u8; + *ptr + *ptr2 + }; + "#, + 55, + ); +} + +#[test] +fn overflowing_add() { + check_number( + r#" + extern "rust-intrinsic" { + pub fn add_with_overflow(x: T, y: T) -> (T, bool); + } + + const GOAL: u8 = add_with_overflow(1, 2).0; + "#, + 3, + ); + check_number( + r#" + extern "rust-intrinsic" { + pub fn add_with_overflow(x: T, y: T) -> (T, bool); + } + + const GOAL: u8 = add_with_overflow(1, 2).1 as u8; + "#, + 0, + ); +} + +#[test] +fn needs_drop() { + check_number( + r#" + //- minicore: copy, sized + extern "rust-intrinsic" { + pub fn needs_drop() -> bool; + } + struct X; + const GOAL: bool = !needs_drop::() && needs_drop::(); + "#, + 1, + ); +} + +#[test] +fn likely() { + check_number( + r#" + extern "rust-intrinsic" { + pub fn likely(b: bool) -> bool; + pub fn unlikely(b: bool) -> bool; + } + + const GOAL: bool = likely(true) && unlikely(true) && !likely(false) && !unlikely(false); + "#, + 1, + ); +} + +#[test] +fn floating_point() { + check_number( + r#" + extern "rust-intrinsic" { + pub fn sqrtf32(x: f32) -> f32; + pub fn powf32(a: f32, x: f32) -> f32; + pub fn fmaf32(a: f32, b: f32, c: f32) -> f32; + } + + const GOAL: f32 = sqrtf32(1.2) + powf32(3.4, 5.6) + fmaf32(-7.8, 1.3, 2.4); + "#, + i128::from_le_bytes(pad16( + &f32::to_le_bytes(1.2f32.sqrt() + 3.4f32.powf(5.6) + (-7.8f32).mul_add(1.3, 2.4)), + true, + )), + ); + check_number( + r#" + extern "rust-intrinsic" { + pub fn powif64(a: f64, x: i32) -> f64; + pub fn sinf64(x: f64) -> f64; + pub fn minnumf64(x: f64, y: f64) -> f64; + } + + const GOAL: f64 = powif64(1.2, 5) + sinf64(3.4) + minnumf64(-7.8, 1.3); + "#, + i128::from_le_bytes(pad16( + &f64::to_le_bytes(1.2f64.powi(5) + 3.4f64.sin() + (-7.8f64).min(1.3)), + true, + )), + ); +} + +#[test] +fn atomic() { + check_number( + r#" + //- minicore: copy + extern "rust-intrinsic" { + pub fn atomic_load_seqcst(src: *const T) -> T; + pub fn atomic_xchg_acquire(dst: *mut T, src: T) -> T; + pub fn atomic_cxchg_release_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchgweak_acquire_acquire(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_store_release(dst: *mut T, val: T); + pub fn atomic_xadd_acqrel(dst: *mut T, src: T) -> T; + pub fn atomic_xsub_seqcst(dst: *mut T, src: T) -> T; + pub fn atomic_and_acquire(dst: *mut T, src: T) -> T; + pub fn atomic_nand_seqcst(dst: *mut T, src: T) -> T; + pub fn atomic_or_release(dst: *mut T, src: T) -> T; + pub fn atomic_xor_seqcst(dst: *mut T, src: T) -> T; + } + + fn should_not_reach() { + _ // fails the test if executed + } + + const GOAL: i32 = { + let mut x = 5; + atomic_store_release(&mut x, 10); + let mut y = atomic_xchg_acquire(&mut x, 100); + atomic_xadd_acqrel(&mut y, 20); + if (30, true) != atomic_cxchg_release_seqcst(&mut y, 30, 40) { + should_not_reach(); + } + if (40, false) != atomic_cxchg_release_seqcst(&mut y, 30, 50) { + should_not_reach(); + } + if (40, true) != atomic_cxchgweak_acquire_acquire(&mut y, 40, 30) { + should_not_reach(); + } + let mut z = atomic_xsub_seqcst(&mut x, -200); + atomic_xor_seqcst(&mut x, 1024); + atomic_load_seqcst(&x) + z * 3 + atomic_load_seqcst(&y) * 2 + }; + "#, + 660 + 1024, + ); +} + +#[test] +fn offset() { + check_number( + r#" + //- minicore: coerce_unsized, index, slice + extern "rust-intrinsic" { + pub fn offset(dst: *const T, offset: isize) -> *const T; + } + + const GOAL: u8 = unsafe { + let ar: &[(u8, u8, u8)] = &[ + (10, 11, 12), + (20, 21, 22), + (30, 31, 32), + (40, 41, 42), + (50, 51, 52), + ]; + let ar: *const [(u8, u8, u8)] = ar; + let ar = ar as *const (u8, u8, u8); + let element = *offset(ar, 2); + element.1 + }; + "#, + 31, + ); +} + +#[test] +fn arith_offset() { + check_number( + r#" + //- minicore: coerce_unsized, index, slice + extern "rust-intrinsic" { + pub fn arith_offset(dst: *const T, offset: isize) -> *const T; + } + + const GOAL: u8 = unsafe { + let ar: &[(u8, u8, u8)] = &[ + (10, 11, 12), + (20, 21, 22), + (30, 31, 32), + (40, 41, 42), + (50, 51, 52), + ]; + let ar: *const [(u8, u8, u8)] = ar; + let ar = ar as *const (u8, u8, u8); + let element = *arith_offset(arith_offset(ar, 102), -100); + element.1 + }; + "#, + 31, + ); +} + +#[test] +fn copy_nonoverlapping() { + check_number( + r#" + extern "rust-intrinsic" { + pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); + } + + const GOAL: u8 = unsafe { + let mut x = 2; + let y = 5; + copy_nonoverlapping(&y, &mut x, 1); + x + }; + "#, + 5, + ); +} + +#[test] +fn copy() { + check_number( + r#" + //- minicore: coerce_unsized, index, slice + extern "rust-intrinsic" { + pub fn copy(src: *const T, dst: *mut T, count: usize); + } + + const GOAL: i32 = unsafe { + let mut x = [1i32, 2, 3, 4, 5]; + let y = (&mut x as *mut _) as *mut i32; + let z = (y as usize + 4) as *const i32; + copy(z, y, 4); + x[0] + x[1] + x[2] + x[3] + x[4] + }; + "#, + 19, + ); +} + +#[test] +fn ctpop() { + check_number( + r#" + extern "rust-intrinsic" { + pub fn ctpop(x: T) -> T; + } + + const GOAL: i64 = ctpop(-29); + "#, + 61, + ); +} + +#[test] +fn cttz() { + check_number( + r#" + extern "rust-intrinsic" { + pub fn cttz(x: T) -> T; + } + + const GOAL: i64 = cttz(-24); + "#, + 3, + ); +} diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index 304c78767f129..ca8a394e360dc 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -1,27 +1,27 @@ //! The home of `HirDatabase`, which is the Salsa database containing all the //! type inference-related queries. -use std::sync::Arc; +use std::sync; use base_db::{impl_intern_key, salsa, CrateId, Upcast}; use hir_def::{ - db::DefDatabase, - expr::ExprId, - layout::{Layout, LayoutError, TargetDataLayout}, - AdtId, BlockId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, GenericDefId, - ImplId, LifetimeParamId, LocalFieldId, TypeOrConstParamId, VariantId, + db::DefDatabase, hir::ExprId, layout::TargetDataLayout, AdtId, BlockId, ConstParamId, + DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId, + LifetimeParamId, LocalFieldId, StaticId, TypeOrConstParamId, VariantId, }; use la_arena::ArenaMap; use smallvec::SmallVec; +use triomphe::Arc; use crate::{ chalk_db, consteval::ConstEvalError, + layout::{Layout, LayoutError}, method_resolution::{InherentImpls, TraitImpls, TyFingerprint}, mir::{BorrowckResult, MirBody, MirLowerError}, - Binders, CallableDefId, Const, FnDefId, GenericArg, ImplTraitId, InferenceResult, Interner, - PolyFnSig, QuantifiedWhereClause, ReturnTypeImplTraits, Substitution, TraitRef, Ty, TyDefId, - ValueTyDefId, + Binders, CallableDefId, ClosureId, Const, FnDefId, GenericArg, ImplTraitId, InferenceResult, + Interner, PolyFnSig, QuantifiedWhereClause, ReturnTypeImplTraits, Substitution, TraitRef, Ty, + TyDefId, ValueTyDefId, }; use hir_expand::name::Name; @@ -38,8 +38,28 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::cycle(crate::mir::mir_body_recover)] fn mir_body(&self, def: DefWithBodyId) -> Result, MirLowerError>; + #[salsa::invoke(crate::mir::mir_body_for_closure_query)] + fn mir_body_for_closure(&self, def: ClosureId) -> Result, MirLowerError>; + + #[salsa::invoke(crate::mir::monomorphized_mir_body_query)] + #[salsa::cycle(crate::mir::monomorphized_mir_body_recover)] + fn monomorphized_mir_body( + &self, + def: DefWithBodyId, + subst: Substitution, + env: Arc, + ) -> Result, MirLowerError>; + + #[salsa::invoke(crate::mir::monomorphized_mir_body_for_closure_query)] + fn monomorphized_mir_body_for_closure( + &self, + def: ClosureId, + subst: Substitution, + env: Arc, + ) -> Result, MirLowerError>; + #[salsa::invoke(crate::mir::borrowck_query)] - fn borrowck(&self, def: DefWithBodyId) -> Result, MirLowerError>; + fn borrowck(&self, def: DefWithBodyId) -> Result, MirLowerError>; #[salsa::invoke(crate::lower::ty_query)] #[salsa::cycle(crate::lower::ty_recover)] @@ -57,7 +77,12 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::invoke(crate::consteval::const_eval_query)] #[salsa::cycle(crate::consteval::const_eval_recover)] - fn const_eval(&self, def: ConstId) -> Result; + fn const_eval(&self, def: GeneralConstId, subst: Substitution) + -> Result; + + #[salsa::invoke(crate::consteval::const_eval_static_query)] + #[salsa::cycle(crate::consteval::const_eval_static_recover)] + fn const_eval_static(&self, def: StaticId) -> Result; #[salsa::invoke(crate::consteval::const_eval_discriminant_variant)] #[salsa::cycle(crate::consteval::const_eval_discriminant_recover)] @@ -71,7 +96,16 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::invoke(crate::layout::layout_of_adt_query)] #[salsa::cycle(crate::layout::layout_of_adt_recover)] - fn layout_of_adt(&self, def: AdtId, subst: Substitution) -> Result; + fn layout_of_adt( + &self, + def: AdtId, + subst: Substitution, + krate: CrateId, + ) -> Result, LayoutError>; + + #[salsa::invoke(crate::layout::layout_of_ty_query)] + #[salsa::cycle(crate::layout::layout_of_ty_recover)] + fn layout_of_ty(&self, ty: Ty, krate: CrateId) -> Result, LayoutError>; #[salsa::invoke(crate::layout::target_data_layout_query)] fn target_data_layout(&self, krate: CrateId) -> Option>; @@ -97,6 +131,10 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::invoke(crate::lower::generic_predicates_query)] fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders]>; + #[salsa::invoke(crate::lower::trait_environment_for_body_query)] + #[salsa::transparent] + fn trait_environment_for_body(&self, def: DefWithBodyId) -> Arc; + #[salsa::invoke(crate::lower::trait_environment_query)] fn trait_environment(&self, def: GenericDefId) -> Arc; @@ -108,7 +146,7 @@ pub trait HirDatabase: DefDatabase + Upcast { fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc; #[salsa::invoke(InherentImpls::inherent_impls_in_block_query)] - fn inherent_impls_in_block(&self, block: BlockId) -> Option>; + fn inherent_impls_in_block(&self, block: BlockId) -> Arc; /// Collects all crates in the dependency graph that have impls for the /// given fingerprint. This is only used for primitive types and types @@ -125,10 +163,10 @@ pub trait HirDatabase: DefDatabase + Upcast { fn trait_impls_in_crate(&self, krate: CrateId) -> Arc; #[salsa::invoke(TraitImpls::trait_impls_in_block_query)] - fn trait_impls_in_block(&self, krate: BlockId) -> Option>; + fn trait_impls_in_block(&self, block: BlockId) -> Arc; #[salsa::invoke(TraitImpls::trait_impls_in_deps_query)] - fn trait_impls_in_deps(&self, krate: CrateId) -> Arc; + fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<[Arc]>; // Interned IDs for Chalk integration #[salsa::interned] @@ -148,24 +186,34 @@ pub trait HirDatabase: DefDatabase + Upcast { fn intern_generator(&self, id: (DefWithBodyId, ExprId)) -> InternedGeneratorId; #[salsa::invoke(chalk_db::associated_ty_data_query)] - fn associated_ty_data(&self, id: chalk_db::AssocTypeId) -> Arc; + fn associated_ty_data( + &self, + id: chalk_db::AssocTypeId, + ) -> sync::Arc; #[salsa::invoke(chalk_db::trait_datum_query)] - fn trait_datum(&self, krate: CrateId, trait_id: chalk_db::TraitId) - -> Arc; + fn trait_datum( + &self, + krate: CrateId, + trait_id: chalk_db::TraitId, + ) -> sync::Arc; #[salsa::invoke(chalk_db::struct_datum_query)] fn struct_datum( &self, krate: CrateId, struct_id: chalk_db::AdtId, - ) -> Arc; + ) -> sync::Arc; #[salsa::invoke(chalk_db::impl_datum_query)] - fn impl_datum(&self, krate: CrateId, impl_id: chalk_db::ImplId) -> Arc; + fn impl_datum( + &self, + krate: CrateId, + impl_id: chalk_db::ImplId, + ) -> sync::Arc; #[salsa::invoke(chalk_db::fn_def_datum_query)] - fn fn_def_datum(&self, krate: CrateId, fn_def_id: FnDefId) -> Arc; + fn fn_def_datum(&self, krate: CrateId, fn_def_id: FnDefId) -> sync::Arc; #[salsa::invoke(chalk_db::fn_def_variance_query)] fn fn_def_variance(&self, fn_def_id: FnDefId) -> chalk_db::Variances; @@ -178,7 +226,7 @@ pub trait HirDatabase: DefDatabase + Upcast { &self, krate: CrateId, id: chalk_db::AssociatedTyValueId, - ) -> Arc; + ) -> sync::Arc; #[salsa::invoke(crate::traits::normalize_projection_query)] #[salsa::transparent] @@ -193,6 +241,7 @@ pub trait HirDatabase: DefDatabase + Upcast { fn trait_solve( &self, krate: CrateId, + block: Option, goal: crate::Canonical>, ) -> Option; @@ -200,6 +249,7 @@ pub trait HirDatabase: DefDatabase + Upcast { fn trait_solve_query( &self, krate: CrateId, + block: Option, goal: crate::Canonical>, ) -> Option; @@ -207,19 +257,26 @@ pub trait HirDatabase: DefDatabase + Upcast { fn program_clauses_for_chalk_env( &self, krate: CrateId, + block: Option, env: chalk_ir::Environment, ) -> chalk_ir::ProgramClauses; } fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc { let _p = profile::span("infer:wait").detail(|| match def { - DefWithBodyId::FunctionId(it) => db.function_data(it).name.to_string(), - DefWithBodyId::StaticId(it) => db.static_data(it).name.clone().to_string(), - DefWithBodyId::ConstId(it) => { - db.const_data(it).name.clone().unwrap_or_else(Name::missing).to_string() + DefWithBodyId::FunctionId(it) => db.function_data(it).name.display(db.upcast()).to_string(), + DefWithBodyId::StaticId(it) => { + db.static_data(it).name.clone().display(db.upcast()).to_string() } + DefWithBodyId::ConstId(it) => db + .const_data(it) + .name + .clone() + .unwrap_or_else(Name::missing) + .display(db.upcast()) + .to_string(), DefWithBodyId::VariantId(it) => { - db.enum_data(it.parent).variants[it.local_id].name.to_string() + db.enum_data(it.parent).variants[it.local_id].name.display(db.upcast()).to_string() } }); db.infer_query(def) @@ -228,10 +285,11 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc fn trait_solve_wait( db: &dyn HirDatabase, krate: CrateId, + block: Option, goal: crate::Canonical>, ) -> Option { let _p = profile::span("trait_solve::wait"); - db.trait_solve_query(krate, goal) + db.trait_solve_query(krate, block, goal) } #[test] diff --git a/crates/hir-ty/src/diagnostics/decl_check.rs b/crates/hir-ty/src/diagnostics/decl_check.rs index d36b93e3bdde1..1233469b947b4 100644 --- a/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/crates/hir-ty/src/diagnostics/decl_check.rs @@ -16,8 +16,8 @@ use std::fmt; use base_db::CrateId; use hir_def::{ - adt::VariantData, - expr::{Pat, PatId}, + data::adt::VariantData, + hir::{Pat, PatId}, src::HasSource, AdtId, AttrDefId, ConstId, EnumId, FunctionId, ItemContainerId, Lookup, ModuleDefId, StaticId, StructId, @@ -223,7 +223,7 @@ impl<'a> DeclValidator<'a> { } // Check the function name. - let function_name = data.name.to_string(); + let function_name = data.name.display(self.db.upcast()).to_string(); let fn_name_replacement = to_lower_snake_case(&function_name).map(|new_name| Replacement { current_name: data.name.clone(), suggested_text: new_name, @@ -244,7 +244,9 @@ impl<'a> DeclValidator<'a> { id, Replacement { current_name: bind_name.clone(), - suggested_text: to_lower_snake_case(&bind_name.to_string())?, + suggested_text: to_lower_snake_case( + &bind_name.display(self.db.upcast()).to_string(), + )?, expected_case: CaseType::LowerSnakeCase, }, )) @@ -287,7 +289,7 @@ impl<'a> DeclValidator<'a> { ident_type: IdentType::Function, ident: AstPtr::new(&ast_ptr), expected_case: fn_name_replacement.expected_case, - ident_text: fn_name_replacement.current_name.to_string(), + ident_text: fn_name_replacement.current_name.display(self.db.upcast()).to_string(), suggested_text: fn_name_replacement.suggested_text, }; @@ -343,7 +345,10 @@ impl<'a> DeclValidator<'a> { ident_type, ident: AstPtr::new(&name_ast), expected_case: replacement.expected_case, - ident_text: replacement.current_name.to_string(), + ident_text: replacement + .current_name + .display(self.db.upcast()) + .to_string(), suggested_text: replacement.suggested_text, }; @@ -362,7 +367,7 @@ impl<'a> DeclValidator<'a> { let non_snake_case_allowed = self.allowed(struct_id.into(), allow::NON_SNAKE_CASE, false); // Check the structure name. - let struct_name = data.name.to_string(); + let struct_name = data.name.display(self.db.upcast()).to_string(); let struct_name_replacement = if !non_camel_case_allowed { to_camel_case(&struct_name).map(|new_name| Replacement { current_name: data.name.clone(), @@ -379,7 +384,7 @@ impl<'a> DeclValidator<'a> { if !non_snake_case_allowed { if let VariantData::Record(fields) = data.variant_data.as_ref() { for (_, field) in fields.iter() { - let field_name = field.name.to_string(); + let field_name = field.name.display(self.db.upcast()).to_string(); if let Some(new_name) = to_lower_snake_case(&field_name) { let replacement = Replacement { current_name: field.name.clone(), @@ -434,7 +439,7 @@ impl<'a> DeclValidator<'a> { ident_type: IdentType::Structure, ident: AstPtr::new(&ast_ptr), expected_case: replacement.expected_case, - ident_text: replacement.current_name.to_string(), + ident_text: replacement.current_name.display(self.db.upcast()).to_string(), suggested_text: replacement.suggested_text, }; @@ -479,7 +484,7 @@ impl<'a> DeclValidator<'a> { ident_type: IdentType::Field, ident: AstPtr::new(&ast_ptr), expected_case: field_to_rename.expected_case, - ident_text: field_to_rename.current_name.to_string(), + ident_text: field_to_rename.current_name.display(self.db.upcast()).to_string(), suggested_text: field_to_rename.suggested_text, }; @@ -496,7 +501,7 @@ impl<'a> DeclValidator<'a> { } // Check the enum name. - let enum_name = data.name.to_string(); + let enum_name = data.name.display(self.db.upcast()).to_string(); let enum_name_replacement = to_camel_case(&enum_name).map(|new_name| Replacement { current_name: data.name.clone(), suggested_text: new_name, @@ -510,7 +515,9 @@ impl<'a> DeclValidator<'a> { .filter_map(|(_, variant)| { Some(Replacement { current_name: variant.name.clone(), - suggested_text: to_camel_case(&variant.name.to_string())?, + suggested_text: to_camel_case( + &variant.name.display(self.db.upcast()).to_string(), + )?, expected_case: CaseType::UpperCamelCase, }) }) @@ -558,7 +565,7 @@ impl<'a> DeclValidator<'a> { ident_type: IdentType::Enum, ident: AstPtr::new(&ast_ptr), expected_case: replacement.expected_case, - ident_text: replacement.current_name.to_string(), + ident_text: replacement.current_name.display(self.db.upcast()).to_string(), suggested_text: replacement.suggested_text, }; @@ -603,7 +610,7 @@ impl<'a> DeclValidator<'a> { ident_type: IdentType::Variant, ident: AstPtr::new(&ast_ptr), expected_case: variant_to_rename.expected_case, - ident_text: variant_to_rename.current_name.to_string(), + ident_text: variant_to_rename.current_name.display(self.db.upcast()).to_string(), suggested_text: variant_to_rename.suggested_text, }; @@ -623,7 +630,7 @@ impl<'a> DeclValidator<'a> { None => return, }; - let const_name = name.to_string(); + let const_name = name.display(self.db.upcast()).to_string(); let replacement = if let Some(new_name) = to_upper_snake_case(&const_name) { Replacement { current_name: name.clone(), @@ -648,7 +655,7 @@ impl<'a> DeclValidator<'a> { ident_type: IdentType::Constant, ident: AstPtr::new(&ast_ptr), expected_case: replacement.expected_case, - ident_text: replacement.current_name.to_string(), + ident_text: replacement.current_name.display(self.db.upcast()).to_string(), suggested_text: replacement.suggested_text, }; @@ -668,7 +675,7 @@ impl<'a> DeclValidator<'a> { let name = &data.name; - let static_name = name.to_string(); + let static_name = name.display(self.db.upcast()).to_string(); let replacement = if let Some(new_name) = to_upper_snake_case(&static_name) { Replacement { current_name: name.clone(), @@ -693,7 +700,7 @@ impl<'a> DeclValidator<'a> { ident_type: IdentType::StaticVariable, ident: AstPtr::new(&ast_ptr), expected_case: replacement.expected_case, - ident_text: replacement.current_name.to_string(), + ident_text: replacement.current_name.display(self.db.upcast()).to_string(), suggested_text: replacement.suggested_text, }; diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs index 2e9066788cf62..ab34dc88d87bc 100644 --- a/crates/hir-ty/src/diagnostics/expr.rs +++ b/crates/hir-ty/src/diagnostics/expr.rs @@ -3,7 +3,6 @@ //! fields, etc. use std::fmt; -use std::sync::Arc; use either::Either; use hir_def::lang_item::LangItem; @@ -12,6 +11,7 @@ use hir_def::{ItemContainerId, Lookup}; use hir_expand::name; use itertools::Itertools; use rustc_hash::FxHashSet; +use triomphe::Arc; use typed_arena::Arena; use crate::{ @@ -27,7 +27,7 @@ use crate::{ pub(crate) use hir_def::{ body::Body, - expr::{Expr, ExprId, MatchArm, Pat, PatId}, + hir::{Expr, ExprId, MatchArm, Pat, PatId}, LocalFieldId, VariantId, }; @@ -207,7 +207,7 @@ impl ExprValidator { let report = compute_match_usefulness(&cx, &m_arms, scrut_ty); - // FIXME Report unreacheble arms + // FIXME Report unreachable arms // https://github.com/rust-lang/rust/blob/f31622a50/compiler/rustc_mir_build/src/thir/pattern/check_match.rs#L200 let witnesses = report.non_exhaustiveness_witnesses; diff --git a/crates/hir-ty/src/diagnostics/match_check.rs b/crates/hir-ty/src/diagnostics/match_check.rs index 859a37804ae7f..f8cdeaa5e3549 100644 --- a/crates/hir-ty/src/diagnostics/match_check.rs +++ b/crates/hir-ty/src/diagnostics/match_check.rs @@ -1,6 +1,6 @@ //! Validation of matches. //! -//! This module provides lowering from [hir_def::expr::Pat] to [self::Pat] and match +//! This module provides lowering from [hir_def::hir::Pat] to [self::Pat] and match //! checking algorithm. //! //! It is modeled on the rustc module `rustc_mir_build::thir::pattern`. @@ -12,7 +12,7 @@ pub(crate) mod usefulness; use chalk_ir::Mutability; use hir_def::{ - adt::VariantData, body::Body, expr::PatId, AdtId, EnumVariantId, LocalFieldId, VariantId, + body::Body, data::adt::VariantData, hir::PatId, AdtId, EnumVariantId, LocalFieldId, VariantId, }; use hir_expand::name::Name; use stdx::{always, never}; @@ -125,15 +125,15 @@ impl<'a> PatCtxt<'a> { let variant = self.infer.variant_resolution_for_pat(pat); let kind = match self.body[pat] { - hir_def::expr::Pat::Wild => PatKind::Wild, + hir_def::hir::Pat::Wild => PatKind::Wild, - hir_def::expr::Pat::Lit(expr) => self.lower_lit(expr), + hir_def::hir::Pat::Lit(expr) => self.lower_lit(expr), - hir_def::expr::Pat::Path(ref path) => { + hir_def::hir::Pat::Path(ref path) => { return self.lower_path(pat, path); } - hir_def::expr::Pat::Tuple { ref args, ellipsis } => { + hir_def::hir::Pat::Tuple { ref args, ellipsis } => { let arity = match *ty.kind(Interner) { TyKind::Tuple(arity, _) => arity, _ => { @@ -146,13 +146,14 @@ impl<'a> PatCtxt<'a> { PatKind::Leaf { subpatterns } } - hir_def::expr::Pat::Bind { id, subpat, .. } => { - let bm = self.infer.pat_binding_modes[&pat]; + hir_def::hir::Pat::Bind { id, subpat, .. } => { + let bm = self.infer.binding_modes[id]; + ty = &self.infer[id]; let name = &self.body.bindings[id].name; match (bm, ty.kind(Interner)) { (BindingMode::Ref(_), TyKind::Ref(.., rty)) => ty = rty, (BindingMode::Ref(_), _) => { - never!("`ref {}` has wrong type {:?}", name, ty); + never!("`ref {}` has wrong type {:?}", name.display(self.db.upcast()), ty); self.errors.push(PatternError::UnexpectedType); return Pat { ty: ty.clone(), kind: PatKind::Wild.into() }; } @@ -161,13 +162,13 @@ impl<'a> PatCtxt<'a> { PatKind::Binding { name: name.clone(), subpattern: self.lower_opt_pattern(subpat) } } - hir_def::expr::Pat::TupleStruct { ref args, ellipsis, .. } if variant.is_some() => { + hir_def::hir::Pat::TupleStruct { ref args, ellipsis, .. } if variant.is_some() => { let expected_len = variant.unwrap().variant_data(self.db.upcast()).fields().len(); let subpatterns = self.lower_tuple_subpats(args, expected_len, ellipsis); self.lower_variant_or_leaf(pat, ty, subpatterns) } - hir_def::expr::Pat::Record { ref args, .. } if variant.is_some() => { + hir_def::hir::Pat::Record { ref args, .. } if variant.is_some() => { let variant_data = variant.unwrap().variant_data(self.db.upcast()); let subpatterns = args .iter() @@ -187,12 +188,12 @@ impl<'a> PatCtxt<'a> { } } } - hir_def::expr::Pat::TupleStruct { .. } | hir_def::expr::Pat::Record { .. } => { + hir_def::hir::Pat::TupleStruct { .. } | hir_def::hir::Pat::Record { .. } => { self.errors.push(PatternError::UnresolvedVariant); PatKind::Wild } - hir_def::expr::Pat::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) }, + hir_def::hir::Pat::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) }, _ => { self.errors.push(PatternError::Unimplemented); @@ -279,8 +280,8 @@ impl<'a> PatCtxt<'a> { } } - fn lower_lit(&mut self, expr: hir_def::expr::ExprId) -> PatKind { - use hir_def::expr::{Expr, Literal::Bool}; + fn lower_lit(&mut self, expr: hir_def::hir::ExprId) -> PatKind { + use hir_def::hir::{Expr, Literal::Bool}; match self.body[expr] { Expr::Literal(Bool(value)) => PatKind::LiteralBool { value }, @@ -297,7 +298,7 @@ impl HirDisplay for Pat { match &*self.kind { PatKind::Wild => write!(f, "_"), PatKind::Binding { name, subpattern } => { - write!(f, "{name}")?; + write!(f, "{}", name.display(f.db.upcast()))?; if let Some(subpattern) = subpattern { write!(f, " @ ")?; subpattern.hir_fmt(f)?; @@ -318,10 +319,14 @@ impl HirDisplay for Pat { match variant { VariantId::EnumVariantId(v) => { let data = f.db.enum_data(v.parent); - write!(f, "{}", data.variants[v.local_id].name)?; + write!(f, "{}", data.variants[v.local_id].name.display(f.db.upcast()))?; + } + VariantId::StructId(s) => { + write!(f, "{}", f.db.struct_data(s).name.display(f.db.upcast()))? + } + VariantId::UnionId(u) => { + write!(f, "{}", f.db.union_data(u).name.display(f.db.upcast()))? } - VariantId::StructId(s) => write!(f, "{}", f.db.struct_data(s).name)?, - VariantId::UnionId(u) => write!(f, "{}", f.db.union_data(u).name)?, }; let variant_data = variant.variant_data(f.db.upcast()); @@ -335,7 +340,11 @@ impl HirDisplay for Pat { .map(|p| { printed += 1; WriteWith(move |f| { - write!(f, "{}: ", rec_fields[p.field].name)?; + write!( + f, + "{}: ", + rec_fields[p.field].name.display(f.db.upcast()) + )?; p.pattern.hir_fmt(f) }) }); @@ -379,7 +388,7 @@ impl HirDisplay for Pat { } PatKind::Deref { subpattern } => { match self.ty.kind(Interner) { - TyKind::Adt(adt, _) if is_box(adt.0, f.db) => write!(f, "box ")?, + TyKind::Adt(adt, _) if is_box(f.db, adt.0) => write!(f, "box ")?, &TyKind::Ref(mutbl, ..) => { write!(f, "&{}", if mutbl == Mutability::Mut { "mut " } else { "" })? } diff --git a/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs b/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs index d130827a77e84..a0f6b9368ee01 100644 --- a/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs +++ b/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs @@ -82,7 +82,7 @@ fn expand_or_pat(pat: &Pat) -> Vec<&Pat> { pats } -/// [Constructor] uses this in umimplemented variants. +/// [Constructor] uses this in unimplemented variants. /// It allows porting match expressions from upstream algorithm without losing semantics. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(super) enum Void {} @@ -384,7 +384,7 @@ impl Constructor { TyKind::Tuple(arity, ..) => arity, TyKind::Ref(..) => 1, TyKind::Adt(adt, ..) => { - if is_box(adt.0, pcx.cx.db) { + if is_box(pcx.cx.db, adt.0) { // The only legal patterns of type `Box` (outside `std`) are `_` and box // patterns. If we're here we can assume this is a box pattern. 1 @@ -772,7 +772,7 @@ impl<'p> Fields<'p> { (0..fields_len).map(|idx| LocalFieldId::from_raw(idx.into())).filter_map(move |fid| { let ty = field_ty[fid].clone().substitute(Interner, substs); - let ty = normalize(cx.db, cx.body, ty); + let ty = normalize(cx.db, cx.db.trait_environment_for_body(cx.body), ty); let is_visible = matches!(adt, hir_def::AdtId::EnumId(..)) || visibility[fid].is_visible_from(cx.db.upcast(), cx.module); let is_uninhabited = cx.is_uninhabited(&ty); @@ -800,7 +800,7 @@ impl<'p> Fields<'p> { } TyKind::Ref(.., rty) => Fields::wildcards_from_tys(cx, once(rty.clone())), &TyKind::Adt(AdtId(adt), ref substs) => { - if is_box(adt, cx.db) { + if is_box(cx.db, adt) { // The only legal patterns of type `Box` (outside `std`) are `_` and box // patterns. If we're here we can assume this is a box pattern. let subst_ty = substs.at(Interner, 0).assert_ty_ref(Interner).clone(); @@ -905,7 +905,7 @@ impl<'p> DeconstructedPat<'p> { } fields = Fields::from_iter(cx, wilds) } - TyKind::Adt(adt, substs) if is_box(adt.0, cx.db) => { + TyKind::Adt(adt, substs) if is_box(cx.db, adt.0) => { // The only legal patterns of type `Box` (outside `std`) are `_` and box // patterns. If we're here we can assume this is a box pattern. // FIXME(Nadrieril): A `Box` can in theory be matched either with `Box(_, @@ -992,7 +992,7 @@ impl<'p> DeconstructedPat<'p> { }) .collect(), }, - TyKind::Adt(adt, _) if is_box(adt.0, cx.db) => { + TyKind::Adt(adt, _) if is_box(cx.db, adt.0) => { // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside // of `std`). So this branch is only reachable when the feature is enabled and // the pattern is a box pattern. diff --git a/crates/hir-ty/src/diagnostics/match_check/pat_util.rs b/crates/hir-ty/src/diagnostics/match_check/pat_util.rs index b89b4f2bfb7d9..217454499ef6d 100644 --- a/crates/hir-ty/src/diagnostics/match_check/pat_util.rs +++ b/crates/hir-ty/src/diagnostics/match_check/pat_util.rs @@ -1,4 +1,4 @@ -//! Pattern untilities. +//! Pattern utilities. //! //! Originates from `rustc_hir::pat_util` diff --git a/crates/hir-ty/src/diagnostics/match_check/usefulness.rs b/crates/hir-ty/src/diagnostics/match_check/usefulness.rs index c4d709a975b02..d737b24ad32bb 100644 --- a/crates/hir-ty/src/diagnostics/match_check/usefulness.rs +++ b/crates/hir-ty/src/diagnostics/match_check/usefulness.rs @@ -755,7 +755,7 @@ pub(crate) enum Reachability { /// The arm is reachable. This additionally carries a set of or-pattern branches that have been /// found to be unreachable despite the overall arm being reachable. Used only in the presence /// of or-patterns, otherwise it stays empty. - // FIXME: store ureachable subpattern IDs + // FIXME: store unreachable subpattern IDs Reachable, /// The arm is unreachable. Unreachable, diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs index d25c0ccf00dcd..7c38e6583a75f 100644 --- a/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -3,7 +3,7 @@ use hir_def::{ body::Body, - expr::{Expr, ExprId, UnaryOp}, + hir::{Expr, ExprId, UnaryOp}, resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, DefWithBodyId, }; @@ -73,7 +73,7 @@ fn walk_unsafe( } Expr::Path(path) => { let resolver = resolver_for_expr(db.upcast(), def, current); - let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path.mod_path()); + let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path); if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id))) = value_or_partial { if db.static_data(id).mutable { unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block }); diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index bd3eccfe43dab..f90e025c7cc62 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -7,32 +7,36 @@ use std::fmt::{self, Debug}; use base_db::CrateId; use chalk_ir::{BoundVar, TyKind}; use hir_def::{ - adt::VariantData, - body, + data::adt::VariantData, db::DefDatabase, find_path, generics::{TypeOrConstParamData, TypeParamProvenance}, item_scope::ItemInNs, lang_item::{LangItem, LangItemTarget}, + nameres::DefMap, path::{Path, PathKind}, type_ref::{TraitBoundModifier, TypeBound, TypeRef}, visibility::Visibility, - HasModule, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId, TraitId, + EnumVariantId, HasModule, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId, + TraitId, }; use hir_expand::{hygiene::Hygiene, name::Name}; use intern::{Internable, Interned}; use itertools::Itertools; +use la_arena::ArenaMap; use smallvec::SmallVec; +use stdx::never; use crate::{ + consteval::try_const_usize, db::HirDatabase, from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, - layout::layout_of_ty, + layout::Layout, lt_from_placeholder_idx, mapping::from_chalk, mir::pad16, primitive, to_assoc_type_id, - utils::{self, generics}, + utils::{self, detect_variant_from_bytes, generics, ClosureSubst}, AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstScalar, ConstValue, DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, MemoryMap, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Scalar, @@ -64,6 +68,7 @@ pub struct HirFormatter<'a> { curr_size: usize, pub(crate) max_size: Option, omit_verbose_types: bool, + closure_style: ClosureStyle, display_target: DisplayTarget, } @@ -87,6 +92,7 @@ pub trait HirDisplay { max_size: Option, omit_verbose_types: bool, display_target: DisplayTarget, + closure_style: ClosureStyle, ) -> HirDisplayWrapper<'a, Self> where Self: Sized, @@ -95,7 +101,14 @@ pub trait HirDisplay { !matches!(display_target, DisplayTarget::SourceCode { .. }), "HirDisplayWrapper cannot fail with DisplaySourceCodeError, use HirDisplay::hir_fmt directly instead" ); - HirDisplayWrapper { db, t: self, max_size, omit_verbose_types, display_target } + HirDisplayWrapper { + db, + t: self, + max_size, + omit_verbose_types, + display_target, + closure_style, + } } /// Returns a `Display`able type that is human-readable. @@ -109,6 +122,7 @@ pub trait HirDisplay { t: self, max_size: None, omit_verbose_types: false, + closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::Diagnostics, } } @@ -128,6 +142,7 @@ pub trait HirDisplay { t: self, max_size, omit_verbose_types: true, + closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::Diagnostics, } } @@ -138,6 +153,7 @@ pub trait HirDisplay { &'a self, db: &'a dyn HirDatabase, module_id: ModuleId, + allow_opaque: bool, ) -> Result { let mut result = String::new(); match self.hir_fmt(&mut HirFormatter { @@ -147,7 +163,8 @@ pub trait HirDisplay { curr_size: 0, max_size: None, omit_verbose_types: false, - display_target: DisplayTarget::SourceCode { module_id }, + closure_style: ClosureStyle::ImplFn, + display_target: DisplayTarget::SourceCode { module_id, allow_opaque }, }) { Ok(()) => {} Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"), @@ -166,6 +183,7 @@ pub trait HirDisplay { t: self, max_size: None, omit_verbose_types: false, + closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::Test, } } @@ -235,26 +253,34 @@ pub enum DisplayTarget { Diagnostics, /// Display types for inserting them in source files. /// The generated code should compile, so paths need to be qualified. - SourceCode { module_id: ModuleId }, + SourceCode { module_id: ModuleId, allow_opaque: bool }, /// Only for test purpose to keep real types Test, } impl DisplayTarget { - fn is_source_code(&self) -> bool { + fn is_source_code(self) -> bool { matches!(self, Self::SourceCode { .. }) } - fn is_test(&self) -> bool { + + fn is_test(self) -> bool { matches!(self, Self::Test) } + + fn allows_opaque(self) -> bool { + match self { + Self::SourceCode { allow_opaque, .. } => allow_opaque, + _ => true, + } + } } #[derive(Debug)] pub enum DisplaySourceCodeError { PathNotFound, UnknownType, - Closure, Generator, + OpaqueType, } pub enum HirDisplayError { @@ -274,9 +300,25 @@ pub struct HirDisplayWrapper<'a, T> { t: &'a T, max_size: Option, omit_verbose_types: bool, + closure_style: ClosureStyle, display_target: DisplayTarget, } +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum ClosureStyle { + /// `impl FnX(i32, i32) -> i32`, where `FnX` is the most special trait between `Fn`, `FnMut`, `FnOnce` that the + /// closure implements. This is the default. + ImplFn, + /// `|i32, i32| -> i32` + RANotation, + /// `{closure#14825}`, useful for some diagnostics (like type mismatch) and internal usage. + ClosureWithId, + /// `{closure#14825}`, useful for internal usage. + ClosureWithSubst, + /// `…`, which is the `TYPE_HINT_TRUNCATION` + Hide, +} + impl HirDisplayWrapper<'_, T> { pub fn write_to(&self, f: &mut F) -> Result<(), HirDisplayError> { self.t.hir_fmt(&mut HirFormatter { @@ -287,8 +329,14 @@ impl HirDisplayWrapper<'_, T> { max_size: self.max_size, omit_verbose_types: self.omit_verbose_types, display_target: self.display_target, + closure_style: self.closure_style, }) } + + pub fn with_closure_style(mut self, c: ClosureStyle) -> Self { + self.closure_style = c; + self + } } impl<'a, T> fmt::Display for HirDisplayWrapper<'a, T> @@ -330,7 +378,13 @@ impl HirDisplay for ProjectionTy { let trait_ref = self.trait_ref(f.db); write!(f, "<")?; fmt_trait_ref(f, &trait_ref, true)?; - write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?; + write!( + f, + ">::{}", + f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)) + .name + .display(f.db.upcast()) + )?; let proj_params_count = self.substitution.len(Interner) - trait_ref.substitution.len(Interner); let proj_params = &self.substitution.as_slice(Interner)[..proj_params_count]; @@ -373,10 +427,16 @@ impl HirDisplay for Const { let id = from_placeholder_idx(f.db, *idx); let generics = generics(f.db.upcast(), id.parent); let param_data = &generics.params.type_or_consts[id.local_id]; - write!(f, "{}", param_data.name().unwrap()) + write!(f, "{}", param_data.name().unwrap().display(f.db.upcast()))?; + Ok(()) } ConstValue::Concrete(c) => match &c.interned { ConstScalar::Bytes(b, m) => render_const_scalar(f, &b, m, &data.ty), + ConstScalar::UnevaluatedConst(c, parameters) => { + write!(f, "{}", c.name(f.db.upcast()))?; + hir_fmt_generics(f, parameters, c.generic_def(f.db.upcast()))?; + Ok(()) + } ConstScalar::Unknown => f.write_char('_'), }, } @@ -411,8 +471,11 @@ fn render_const_scalar( memory_map: &MemoryMap, ty: &Ty, ) -> Result<(), HirDisplayError> { + // FIXME: We need to get krate from the final callers of the hir display + // infrastructure and have it here as a field on `f`. + let krate = *f.db.crate_graph().crates_in_topological_order().last().unwrap(); match ty.kind(Interner) { - chalk_ir::TyKind::Scalar(s) => match s { + TyKind::Scalar(s) => match s { Scalar::Bool => write!(f, "{}", if b[0] == 0 { false } else { true }), Scalar::Char => { let x = u128::from_le_bytes(pad16(b, false)) as u32; @@ -440,22 +503,54 @@ fn render_const_scalar( } }, }, - chalk_ir::TyKind::Ref(_, _, t) => match t.kind(Interner) { - chalk_ir::TyKind::Str => { + TyKind::Ref(_, _, t) => match t.kind(Interner) { + TyKind::Str => { let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap()); - let bytes = memory_map.0.get(&addr).map(|x| &**x).unwrap_or(&[]); - let s = std::str::from_utf8(bytes).unwrap_or(""); + let size = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap()); + let Some(bytes) = memory_map.get(addr, size) else { + return f.write_str(""); + }; + let s = std::str::from_utf8(&bytes).unwrap_or(""); write!(f, "{s:?}") } - _ => f.write_str(""), + TyKind::Slice(ty) => { + let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap()); + let count = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap()); + let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else { + return f.write_str(""); + }; + let size_one = layout.size.bytes_usize(); + let Some(bytes) = memory_map.get(addr, size_one * count) else { + return f.write_str(""); + }; + f.write_str("&[")?; + let mut first = true; + for i in 0..count { + if first { + first = false; + } else { + f.write_str(", ")?; + } + let offset = size_one * i; + render_const_scalar(f, &bytes[offset..offset + size_one], memory_map, &ty)?; + } + f.write_str("]") + } + _ => { + let addr = usize::from_le_bytes(b.try_into().unwrap()); + let Ok(layout) = f.db.layout_of_ty(t.clone(), krate) else { + return f.write_str(""); + }; + let size = layout.size.bytes_usize(); + let Some(bytes) = memory_map.get(addr, size) else { + return f.write_str(""); + }; + f.write_str("&")?; + render_const_scalar(f, bytes, memory_map, t) + } }, - chalk_ir::TyKind::Tuple(_, subst) => { - // FIXME: Remove this line. If the target data layout is independent - // of the krate, the `db.target_data_layout` and its callers like `layout_of_ty` don't need - // to get krate. Otherwise, we need to get krate from the final callers of the hir display - // infrastructure and have it here as a field on `f`. - let krate = *f.db.crate_graph().crates_in_topological_order().last().unwrap(); - let Ok(layout) = layout_of_ty(f.db, ty, krate) else { + TyKind::Tuple(_, subst) => { + let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else { return f.write_str(""); }; f.write_str("(")?; @@ -468,7 +563,7 @@ fn render_const_scalar( } let ty = ty.assert_ty_ref(Interner); // Tuple only has type argument let offset = layout.fields.offset(id).bytes_usize(); - let Ok(layout) = layout_of_ty(f.db, &ty, krate) else { + let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else { f.write_str("")?; continue; }; @@ -477,62 +572,144 @@ fn render_const_scalar( } f.write_str(")") } - chalk_ir::TyKind::Adt(adt, subst) => match adt.0 { - hir_def::AdtId::StructId(s) => { - let data = f.db.struct_data(s); - let Ok(layout) = f.db.layout_of_adt(adt.0, subst.clone()) else { + TyKind::Adt(adt, subst) => { + let Ok(layout) = f.db.layout_of_adt(adt.0, subst.clone(), krate) else { + return f.write_str(""); + }; + match adt.0 { + hir_def::AdtId::StructId(s) => { + let data = f.db.struct_data(s); + write!(f, "{}", data.name.display(f.db.upcast()))?; + let field_types = f.db.field_types(s.into()); + render_variant_after_name( + &data.variant_data, + f, + &field_types, + adt.0.module(f.db.upcast()).krate(), + &layout, + subst, + b, + memory_map, + ) + } + hir_def::AdtId::UnionId(u) => { + write!(f, "{}", f.db.union_data(u).name.display(f.db.upcast())) + } + hir_def::AdtId::EnumId(e) => { + let Some((var_id, var_layout)) = + detect_variant_from_bytes(&layout, f.db, krate, b, e) else { + return f.write_str(""); + }; + let data = &f.db.enum_data(e).variants[var_id]; + write!(f, "{}", data.name.display(f.db.upcast()))?; + let field_types = + f.db.field_types(EnumVariantId { parent: e, local_id: var_id }.into()); + render_variant_after_name( + &data.variant_data, + f, + &field_types, + adt.0.module(f.db.upcast()).krate(), + &var_layout, + subst, + b, + memory_map, + ) + } + } + } + TyKind::FnDef(..) => ty.hir_fmt(f), + TyKind::Function(_) | TyKind::Raw(_, _) => { + let x = u128::from_le_bytes(pad16(b, false)); + write!(f, "{:#X} as ", x)?; + ty.hir_fmt(f) + } + TyKind::Array(ty, len) => { + let Some(len) = try_const_usize(f.db, len) else { + return f.write_str(""); + }; + let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else { + return f.write_str(""); + }; + let size_one = layout.size.bytes_usize(); + f.write_str("[")?; + let mut first = true; + for i in 0..len as usize { + if first { + first = false; + } else { + f.write_str(", ")?; + } + let offset = size_one * i; + render_const_scalar(f, &b[offset..offset + size_one], memory_map, &ty)?; + } + f.write_str("]") + } + TyKind::Never => f.write_str("!"), + TyKind::Closure(_, _) => f.write_str(""), + TyKind::Generator(_, _) => f.write_str(""), + TyKind::GeneratorWitness(_, _) => f.write_str(""), + // The below arms are unreachable, since const eval will bail out before here. + TyKind::Foreign(_) => f.write_str(""), + TyKind::Error + | TyKind::Placeholder(_) + | TyKind::Alias(_) + | TyKind::AssociatedType(_, _) + | TyKind::OpaqueType(_, _) + | TyKind::BoundVar(_) + | TyKind::InferenceVar(_, _) => f.write_str(""), + // The below arms are unreachable, since we handled them in ref case. + TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => f.write_str(""), + } +} + +fn render_variant_after_name( + data: &VariantData, + f: &mut HirFormatter<'_>, + field_types: &ArenaMap>, + krate: CrateId, + layout: &Layout, + subst: &Substitution, + b: &[u8], + memory_map: &MemoryMap, +) -> Result<(), HirDisplayError> { + match data { + VariantData::Record(fields) | VariantData::Tuple(fields) => { + let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| { + let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize(); + let ty = field_types[id].clone().substitute(Interner, subst); + let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else { return f.write_str(""); }; - match data.variant_data.as_ref() { - VariantData::Record(fields) | VariantData::Tuple(fields) => { - let field_types = f.db.field_types(s.into()); - let krate = adt.0.module(f.db.upcast()).krate(); - let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| { - let offset = layout - .fields - .offset(u32::from(id.into_raw()) as usize) - .bytes_usize(); - let ty = field_types[id].clone().substitute(Interner, subst); - let Ok(layout) = layout_of_ty(f.db, &ty, krate) else { - return f.write_str(""); - }; - let size = layout.size.bytes_usize(); - render_const_scalar(f, &b[offset..offset + size], memory_map, &ty) - }; - let mut it = fields.iter(); - if matches!(data.variant_data.as_ref(), VariantData::Record(_)) { - write!(f, "{} {{", data.name)?; - if let Some((id, data)) = it.next() { - write!(f, " {}: ", data.name)?; - render_field(f, id)?; - } - for (id, data) in it { - write!(f, ", {}: ", data.name)?; - render_field(f, id)?; - } - write!(f, " }}")?; - } else { - let mut it = it.map(|x| x.0); - write!(f, "{}(", data.name)?; - if let Some(id) = it.next() { - render_field(f, id)?; - } - for id in it { - write!(f, ", ")?; - render_field(f, id)?; - } - write!(f, ")")?; - } - return Ok(()); - } - VariantData::Unit => write!(f, "{}", data.name), + let size = layout.size.bytes_usize(); + render_const_scalar(f, &b[offset..offset + size], memory_map, &ty) + }; + let mut it = fields.iter(); + if matches!(data, VariantData::Record(_)) { + write!(f, " {{")?; + if let Some((id, data)) = it.next() { + write!(f, " {}: ", data.name.display(f.db.upcast()))?; + render_field(f, id)?; + } + for (id, data) in it { + write!(f, ", {}: ", data.name.display(f.db.upcast()))?; + render_field(f, id)?; + } + write!(f, " }}")?; + } else { + let mut it = it.map(|x| x.0); + write!(f, "(")?; + if let Some(id) = it.next() { + render_field(f, id)?; } + for id in it { + write!(f, ", ")?; + render_field(f, id)?; + } + write!(f, ")")?; } - hir_def::AdtId::UnionId(u) => write!(f, "{}", f.db.union_data(u).name), - hir_def::AdtId::EnumId(_) => f.write_str(""), - }, - chalk_ir::TyKind::FnDef(..) => ty.hir_fmt(f), - _ => f.write_str(""), + return Ok(()); + } + VariantData::Unit => Ok(()), } } @@ -689,11 +866,17 @@ impl HirDisplay for Ty { let sig = db.callable_item_signature(def).substitute(Interner, parameters); f.start_location_link(def.into()); match def { - CallableDefId::FunctionId(ff) => write!(f, "fn {}", db.function_data(ff).name)?, - CallableDefId::StructId(s) => write!(f, "{}", db.struct_data(s).name)?, - CallableDefId::EnumVariantId(e) => { - write!(f, "{}", db.enum_data(e.parent).variants[e.local_id].name)? + CallableDefId::FunctionId(ff) => { + write!(f, "fn {}", db.function_data(ff).name.display(f.db.upcast()))? + } + CallableDefId::StructId(s) => { + write!(f, "{}", db.struct_data(s).name.display(f.db.upcast()))? } + CallableDefId::EnumVariantId(e) => write!( + f, + "{}", + db.enum_data(e.parent).variants[e.local_id].name.display(f.db.upcast()) + )?, }; f.end_location_link(); if parameters.len(Interner) > 0 { @@ -733,16 +916,16 @@ impl HirDisplay for Ty { hir_def::AdtId::UnionId(it) => db.union_data(it).name.clone(), hir_def::AdtId::EnumId(it) => db.enum_data(it).name.clone(), }; - write!(f, "{name}")?; + write!(f, "{}", name.display(f.db.upcast()))?; } - DisplayTarget::SourceCode { module_id } => { + DisplayTarget::SourceCode { module_id, allow_opaque: _ } => { if let Some(path) = find_path::find_path( db.upcast(), ItemInNs::Types((*def_id).into()), module_id, false, ) { - write!(f, "{path}")?; + write!(f, "{}", path.display(f.db.upcast()))?; } else { return Err(HirDisplayError::DisplaySourceCodeError( DisplaySourceCodeError::PathNotFound, @@ -752,82 +935,9 @@ impl HirDisplay for Ty { } f.end_location_link(); - if parameters.len(Interner) > 0 { - let parameters_to_write = if f.display_target.is_source_code() - || f.omit_verbose_types() - { - match self - .as_generic_def(db) - .map(|generic_def_id| db.generic_defaults(generic_def_id)) - .filter(|defaults| !defaults.is_empty()) - { - None => parameters.as_slice(Interner), - Some(default_parameters) => { - fn should_show( - parameter: &GenericArg, - default_parameters: &[Binders], - i: usize, - parameters: &Substitution, - ) -> bool { - if parameter.ty(Interner).map(|x| x.kind(Interner)) - == Some(&TyKind::Error) - { - return true; - } - if let Some(ConstValue::Concrete(c)) = parameter - .constant(Interner) - .map(|x| &x.data(Interner).value) - { - if c.interned == ConstScalar::Unknown { - return true; - } - } - let default_parameter = match default_parameters.get(i) { - Some(x) => x, - None => return true, - }; - let actual_default = - default_parameter.clone().substitute(Interner, ¶meters); - parameter != &actual_default - } - let mut default_from = 0; - for (i, parameter) in parameters.iter(Interner).enumerate() { - if should_show(parameter, &default_parameters, i, parameters) { - default_from = i + 1; - } - } - ¶meters.as_slice(Interner)[0..default_from] - } - } - } else { - parameters.as_slice(Interner) - }; - if !parameters_to_write.is_empty() { - write!(f, "<")?; + let generic_def = self.as_generic_def(db); - if f.display_target.is_source_code() { - let mut first = true; - for generic_arg in parameters_to_write { - if !first { - write!(f, ", ")?; - } - first = false; - - if generic_arg.ty(Interner).map(|ty| ty.kind(Interner)) - == Some(&TyKind::Error) - { - write!(f, "_")?; - } else { - generic_arg.hir_fmt(f)?; - } - } - } else { - f.write_joined(parameters_to_write, ", ")?; - } - - write!(f, ">")?; - } - } + hir_fmt_generics(f, parameters, generic_def)?; } TyKind::AssociatedType(assoc_type_id, parameters) => { let type_alias = from_assoc_type_id(*assoc_type_id); @@ -841,12 +951,12 @@ impl HirDisplay for Ty { // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types) if f.display_target.is_test() { f.start_location_link(trait_.into()); - write!(f, "{}", trait_data.name)?; + write!(f, "{}", trait_data.name.display(f.db.upcast()))?; f.end_location_link(); write!(f, "::")?; f.start_location_link(type_alias.into()); - write!(f, "{}", type_alias_data.name)?; + write!(f, "{}", type_alias_data.name.display(f.db.upcast()))?; f.end_location_link(); // Note that the generic args for the associated type come before those for the // trait (including the self type). @@ -869,10 +979,15 @@ impl HirDisplay for Ty { let alias = from_foreign_def_id(*type_alias); let type_alias = db.type_alias_data(alias); f.start_location_link(alias.into()); - write!(f, "{}", type_alias.name)?; + write!(f, "{}", type_alias.name.display(f.db.upcast()))?; f.end_location_link(); } TyKind::OpaqueType(opaque_ty_id, parameters) => { + if !f.display_target.allows_opaque() { + return Err(HirDisplayError::DisplaySourceCodeError( + DisplaySourceCodeError::OpaqueType, + )); + } let impl_trait_id = db.lookup_intern_impl_trait_id((*opaque_ty_id).into()); match impl_trait_id { ImplTraitId::ReturnTypeImplTrait(func, idx) => { @@ -919,26 +1034,52 @@ impl HirDisplay for Ty { } } } - TyKind::Closure(.., substs) => { + TyKind::Closure(id, substs) => { if f.display_target.is_source_code() { - return Err(HirDisplayError::DisplaySourceCodeError( - DisplaySourceCodeError::Closure, - )); + if !f.display_target.allows_opaque() { + return Err(HirDisplayError::DisplaySourceCodeError( + DisplaySourceCodeError::OpaqueType, + )); + } else if f.closure_style != ClosureStyle::ImplFn { + never!("Only `impl Fn` is valid for displaying closures in source code"); + } } - let sig = substs.at(Interner, 0).assert_ty_ref(Interner).callable_sig(db); + match f.closure_style { + ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"), + ClosureStyle::ClosureWithId => { + return write!(f, "{{closure#{:?}}}", id.0.as_u32()) + } + ClosureStyle::ClosureWithSubst => { + write!(f, "{{closure#{:?}}}", id.0.as_u32())?; + return hir_fmt_generics(f, substs, None); + } + _ => (), + } + let sig = ClosureSubst(substs).sig_ty().callable_sig(db); if let Some(sig) = sig { + let (def, _) = db.lookup_intern_closure((*id).into()); + let infer = db.infer(def); + let (_, kind) = infer.closure_info(id); + match f.closure_style { + ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?, + ClosureStyle::RANotation => write!(f, "|")?, + _ => unreachable!(), + } if sig.params().is_empty() { - write!(f, "||")?; } else if f.should_truncate() { - write!(f, "|{TYPE_HINT_TRUNCATION}|")?; + write!(f, "{TYPE_HINT_TRUNCATION}")?; } else { - write!(f, "|")?; f.write_joined(sig.params(), ", ")?; - write!(f, "|")?; }; - - write!(f, " -> ")?; - sig.ret().hir_fmt(f)?; + match f.closure_style { + ClosureStyle::ImplFn => write!(f, ")")?, + ClosureStyle::RANotation => write!(f, "|")?, + _ => unreachable!(), + } + if f.closure_style == ClosureStyle::RANotation || !sig.ret().is_unit() { + write!(f, " -> ")?; + sig.ret().hir_fmt(f)?; + } } else { write!(f, "{{closure}}")?; } @@ -950,7 +1091,11 @@ impl HirDisplay for Ty { match param_data { TypeOrConstParamData::TypeParamData(p) => match p.provenance { TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { - write!(f, "{}", p.name.clone().unwrap_or_else(Name::missing))? + write!( + f, + "{}", + p.name.clone().unwrap_or_else(Name::missing).display(f.db.upcast()) + )? } TypeParamProvenance::ArgumentImplTrait => { let substs = generics.placeholder_subst(db); @@ -979,7 +1124,7 @@ impl HirDisplay for Ty { } }, TypeOrConstParamData::ConstParamData(p) => { - write!(f, "{}", p.name)?; + write!(f, "{}", p.name.display(f.db.upcast()))?; } } } @@ -1004,6 +1149,11 @@ impl HirDisplay for Ty { } TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?, TyKind::Alias(AliasTy::Opaque(opaque_ty)) => { + if !f.display_target.allows_opaque() { + return Err(HirDisplayError::DisplaySourceCodeError( + DisplaySourceCodeError::OpaqueType, + )); + } let impl_trait_id = db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into()); match impl_trait_id { ImplTraitId::ReturnTypeImplTrait(func, idx) => { @@ -1067,6 +1217,88 @@ impl HirDisplay for Ty { } } +fn hir_fmt_generics( + f: &mut HirFormatter<'_>, + parameters: &Substitution, + generic_def: Option, +) -> Result<(), HirDisplayError> { + let db = f.db; + let lifetime_args_count = generic_def.map_or(0, |g| db.generic_params(g).lifetimes.len()); + if parameters.len(Interner) + lifetime_args_count > 0 { + let parameters_to_write = if f.display_target.is_source_code() || f.omit_verbose_types() { + match generic_def + .map(|generic_def_id| db.generic_defaults(generic_def_id)) + .filter(|defaults| !defaults.is_empty()) + { + None => parameters.as_slice(Interner), + Some(default_parameters) => { + fn should_show( + parameter: &GenericArg, + default_parameters: &[Binders], + i: usize, + parameters: &Substitution, + ) -> bool { + if parameter.ty(Interner).map(|x| x.kind(Interner)) == Some(&TyKind::Error) + { + return true; + } + if let Some(ConstValue::Concrete(c)) = + parameter.constant(Interner).map(|x| &x.data(Interner).value) + { + if c.interned == ConstScalar::Unknown { + return true; + } + } + let default_parameter = match default_parameters.get(i) { + Some(x) => x, + None => return true, + }; + let actual_default = + default_parameter.clone().substitute(Interner, ¶meters); + parameter != &actual_default + } + let mut default_from = 0; + for (i, parameter) in parameters.iter(Interner).enumerate() { + if should_show(parameter, &default_parameters, i, parameters) { + default_from = i + 1; + } + } + ¶meters.as_slice(Interner)[0..default_from] + } + } + } else { + parameters.as_slice(Interner) + }; + if !parameters_to_write.is_empty() || lifetime_args_count != 0 { + write!(f, "<")?; + let mut first = true; + for _ in 0..lifetime_args_count { + if !first { + write!(f, ", ")?; + } + first = false; + write!(f, "'_")?; + } + for generic_arg in parameters_to_write { + if !first { + write!(f, ", ")?; + } + first = false; + if f.display_target.is_source_code() + && generic_arg.ty(Interner).map(|ty| ty.kind(Interner)) == Some(&TyKind::Error) + { + write!(f, "_")?; + } else { + generic_arg.hir_fmt(f)?; + } + } + + write!(f, ">")?; + } + } + Ok(()) +} + impl HirDisplay for CallableSig { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write!(f, "fn(")?; @@ -1170,7 +1402,7 @@ fn write_bounds_like_dyn_trait( // existential) here, which is the only thing that's // possible in actual Rust, and hence don't print it f.start_location_link(trait_.into()); - write!(f, "{}", f.db.trait_data(trait_).name)?; + write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?; f.end_location_link(); if let [_, params @ ..] = &*trait_ref.substitution.as_slice(Interner) { if is_fn_trait { @@ -1209,7 +1441,7 @@ fn write_bounds_like_dyn_trait( let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id); let type_alias = f.db.type_alias_data(assoc_ty_id); f.start_location_link(assoc_ty_id.into()); - write!(f, "{}", type_alias.name)?; + write!(f, "{}", type_alias.name.display(f.db.upcast()))?; f.end_location_link(); let proj_arg_count = generics(f.db.upcast(), assoc_ty_id.into()).len_self(); @@ -1276,7 +1508,7 @@ fn fmt_trait_ref( } let trait_ = tr.hir_trait_id(); f.start_location_link(trait_.into()); - write!(f, "{}", f.db.trait_data(trait_).name)?; + write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?; f.end_location_link(); if tr.substitution.len(Interner) > 1 { write!(f, "<")?; @@ -1306,7 +1538,7 @@ impl HirDisplay for WhereClause { write!(f, ">::",)?; let type_alias = from_assoc_type_id(projection_ty.associated_ty_id); f.start_location_link(type_alias.into()); - write!(f, "{}", f.db.type_alias_data(type_alias).name,)?; + write!(f, "{}", f.db.type_alias_data(type_alias).name.display(f.db.upcast()),)?; f.end_location_link(); write!(f, " = ")?; ty.hir_fmt(f)?; @@ -1344,7 +1576,8 @@ impl HirDisplay for LifetimeData { let id = lt_from_placeholder_idx(f.db, *idx); let generics = generics(f.db.upcast(), id.parent); let param_data = &generics.params.lifetimes[id.local_id]; - write!(f, "{}", param_data.name) + write!(f, "{}", param_data.name.display(f.db.upcast()))?; + Ok(()) } LifetimeData::Static => write!(f, "'static"), LifetimeData::Erased => Ok(()), @@ -1376,7 +1609,7 @@ pub fn write_visibility( Visibility::Public => write!(f, "pub "), Visibility::Module(vis_id) => { let def_map = module_id.def_map(f.db.upcast()); - let root_module_id = def_map.module_id(def_map.root()); + let root_module_id = def_map.module_id(DefMap::ROOT); if vis_id == module_id { // pub(self) or omitted Ok(()) @@ -1420,7 +1653,7 @@ impl HirDisplay for TypeRef { }; write!(f, "&")?; if let Some(lifetime) = lifetime { - write!(f, "{} ", lifetime.name)?; + write!(f, "{} ", lifetime.name.display(f.db.upcast()))?; } write!(f, "{mutability}")?; inner.hir_fmt(f)?; @@ -1428,7 +1661,7 @@ impl HirDisplay for TypeRef { TypeRef::Array(inner, len) => { write!(f, "[")?; inner.hir_fmt(f)?; - write!(f, "; {len}]")?; + write!(f, "; {}]", len.display(f.db.upcast()))?; } TypeRef::Slice(inner) => { write!(f, "[")?; @@ -1445,7 +1678,7 @@ impl HirDisplay for TypeRef { for index in 0..function_parameters.len() { let (param_name, param_type) = &function_parameters[index]; if let Some(name) = param_name { - write!(f, "{name}: ")?; + write!(f, "{}: ", name.display(f.db.upcast()))?; } param_type.hir_fmt(f)?; @@ -1477,7 +1710,10 @@ impl HirDisplay for TypeRef { } TypeRef::Macro(macro_call) => { let macro_call = macro_call.to_node(f.db.upcast()); - let ctx = body::LowerCtx::with_hygiene(f.db.upcast(), &Hygiene::new_unhygienic()); + let ctx = hir_def::lower::LowerCtx::with_hygiene( + f.db.upcast(), + &Hygiene::new_unhygienic(), + ); match macro_call.path() { Some(path) => match Path::from_src(path, &ctx) { Some(path) => path.hir_fmt(f)?, @@ -1503,9 +1739,13 @@ impl HirDisplay for TypeBound { } path.hir_fmt(f) } - TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name), + TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name.display(f.db.upcast())), TypeBound::ForLifetime(lifetimes, path) => { - write!(f, "for<{}> ", lifetimes.iter().format(", "))?; + write!( + f, + "for<{}> ", + lifetimes.iter().map(|it| it.display(f.db.upcast())).format(", ") + )?; path.hir_fmt(f) } TypeBound::Error => write!(f, "{{error}}"), @@ -1551,7 +1791,7 @@ impl HirDisplay for Path { if !matches!(self.kind(), PathKind::Plain) || seg_idx > 0 { write!(f, "::")?; } - write!(f, "{}", segment.name)?; + write!(f, "{}", segment.name.display(f.db.upcast()))?; if let Some(generic_args) = segment.args_and_bindings { // We should be in type context, so format as `Foo` instead of `Foo::`. // Do we actually format expressions? @@ -1598,7 +1838,7 @@ impl HirDisplay for Path { } else { write!(f, ", ")?; } - write!(f, "{}", binding.name)?; + write!(f, "{}", binding.name.display(f.db.upcast()))?; match &binding.type_ref { Some(ty) => { write!(f, " = ")?; @@ -1621,8 +1861,10 @@ impl HirDisplay for hir_def::path::GenericArg { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { match self { hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f), - hir_def::path::GenericArg::Const(c) => write!(f, "{c}"), - hir_def::path::GenericArg::Lifetime(lifetime) => write!(f, "{}", lifetime.name), + hir_def::path::GenericArg::Const(c) => write!(f, "{}", c.display(f.db.upcast())), + hir_def::path::GenericArg::Lifetime(lifetime) => { + write!(f, "{}", lifetime.name.display(f.db.upcast())) + } } } } diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 7de5b4295fcc4..80f32e96ee63f 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -13,34 +13,38 @@ //! to certain types. To record this, we use the union-find implementation from //! the `ena` crate, which is extracted from rustc. -use std::ops::Index; -use std::sync::Arc; +use std::{convert::identity, ops::Index}; -use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags}; +use chalk_ir::{ + cast::Cast, fold::TypeFoldable, interner::HasInterner, DebruijnIndex, Mutability, Safety, + Scalar, TyKind, TypeFlags, +}; use either::Either; use hir_def::{ body::Body, builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, data::{ConstData, StaticData}, - expr::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, PatId}, + hir::LabelId, + hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, PatId}, lang_item::{LangItem, LangItemTarget}, layout::Integer, - path::Path, + path::{ModPath, Path}, resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, type_ref::TypeRef, - AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, - ItemContainerId, Lookup, TraitId, TypeAliasId, VariantId, + AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, ItemContainerId, Lookup, + TraitId, TypeAliasId, VariantId, }; use hir_expand::name::{name, Name}; -use la_arena::ArenaMap; +use la_arena::{ArenaMap, Entry}; use rustc_hash::{FxHashMap, FxHashSet}; -use stdx::always; +use stdx::{always, never}; +use triomphe::Arc; use crate::{ - db::HirDatabase, fold_tys, fold_tys_and_consts, infer::coerce::CoerceMany, - lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Const, DomainGoal, + db::HirDatabase, fold_tys, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode, + static_lifetime, to_assoc_type_id, traits::FnTrait, AliasEq, AliasTy, ClosureId, DomainGoal, GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, RpitId, Substitution, - TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, + TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, }; // This lint has a false positive here. See the link below for details. @@ -51,12 +55,15 @@ pub use coerce::could_coerce; #[allow(unreachable_pub)] pub use unify::could_unify; +pub(crate) use self::closure::{CaptureKind, CapturedItem, CapturedItemWithoutTy}; + pub(crate) mod unify; mod path; mod expr; mod pat; mod coerce; -mod closure; +pub(crate) mod closure; +mod mutability; /// The entry point of type inference. pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc { @@ -99,6 +106,10 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc Arc Ty { - if !ty.data(Interner).flags.intersects(TypeFlags::HAS_PROJECTION) { +pub(crate) fn normalize(db: &dyn HirDatabase, trait_env: Arc, ty: Ty) -> Ty { + // FIXME: TypeFlags::HAS_CT_PROJECTION is not implemented in chalk, so TypeFlags::HAS_PROJECTION only + // works for the type case, so we check array unconditionally. Remove the array part + // when the bug in chalk becomes fixed. + if !ty.data(Interner).flags.intersects(TypeFlags::HAS_PROJECTION) + && !matches!(ty.kind(Interner), TyKind::Array(..)) + { return ty; } - let krate = owner.module(db.upcast()).krate(); - let trait_env = owner - .as_generic_def_id() - .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d)); let mut table = unify::InferenceTable::new(db, trait_env); let ty_with_vars = table.normalize_associated_types_in(ty); @@ -188,7 +200,7 @@ pub enum InferenceDiagnostic { /// Contains the type the field resolves to field_with_same_name: Option, }, - // FIXME: Make this proper + // FIXME: This should be emitted in body lowering BreakOutsideOfLoop { expr: ExprId, is_break: bool, @@ -203,6 +215,10 @@ pub enum InferenceDiagnostic { call_expr: ExprId, found: Ty, }, + TypedHole { + expr: ExprId, + expected: Ty, + }, } /// A mismatch between an expected and an inferred type. @@ -276,6 +292,13 @@ pub struct Adjustment { pub target: Ty, } +impl Adjustment { + pub fn borrow(m: Mutability, ty: Ty) -> Self { + let ty = TyKind::Ref(m, static_lifetime(), ty).intern(Interner); + Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(m)), target: ty } + } +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum Adjust { /// Go from ! to any type. @@ -304,6 +327,13 @@ pub enum AutoBorrow { RawPtr(Mutability), } +impl AutoBorrow { + fn mutability(self) -> Mutability { + let (AutoBorrow::Ref(m) | AutoBorrow::RawPtr(m)) = self; + m + } +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum PointerCast { /// Go from a fn-item type to a fn-pointer type. @@ -337,6 +367,10 @@ pub enum PointerCast { } /// The result of type inference: A mapping from expressions and patterns to types. +/// +/// When you add a field that stores types (including `Substitution` and the like), don't forget +/// `resolve_completely()`'ing them in `InferenceContext::resolve_all()`. Inference variables must +/// not appear in the final inference result. #[derive(Clone, PartialEq, Eq, Debug, Default)] pub struct InferenceResult { /// For each method call expr, records the function it resolves to. @@ -363,8 +397,11 @@ pub struct InferenceResult { standard_types: InternedStandardTypes, /// Stores the types which were implicitly dereferenced in pattern binding modes. pub pat_adjustments: FxHashMap>, - pub pat_binding_modes: FxHashMap, + pub binding_modes: ArenaMap, pub expr_adjustments: FxHashMap>, + pub(crate) closure_info: FxHashMap, FnTrait)>, + // FIXME: remove this field + pub mutated_bindings_in_closure: FxHashSet, } impl InferenceResult { @@ -401,6 +438,9 @@ impl InferenceResult { _ => None, }) } + pub fn closure_info(&self, closure: &ClosureId) -> &(Vec, FnTrait) { + self.closure_info.get(closure).unwrap() + } } impl Index for InferenceResult { @@ -435,7 +475,6 @@ pub(crate) struct InferenceContext<'a> { pub(crate) body: &'a Body, pub(crate) resolver: Resolver, table: unify::InferenceTable<'a>, - trait_env: Arc, /// The traits in scope, disregarding block modules. This is used for caching purposes. traits_in_scope: FxHashSet, pub(crate) result: InferenceResult, @@ -453,6 +492,14 @@ pub(crate) struct InferenceContext<'a> { resume_yield_tys: Option<(Ty, Ty)>, diverges: Diverges, breakables: Vec, + + // fields related to closure capture + current_captures: Vec, + current_closure: Option, + /// Stores the list of closure ids that need to be analyzed before this closure. See the + /// comment on `InferenceContext::sort_closures` + closure_dependencies: FxHashMap>, + deferred_closures: FxHashMap, ExprId)>>, } #[derive(Clone, Debug)] @@ -462,7 +509,7 @@ struct BreakableContext { /// The coercion target of the context. coerce: Option, /// The optional label of the context. - label: Option, + label: Option, kind: BreakableKind, } @@ -477,21 +524,21 @@ enum BreakableKind { fn find_breakable<'c>( ctxs: &'c mut [BreakableContext], - label: Option<&name::Name>, + label: Option, ) -> Option<&'c mut BreakableContext> { let mut ctxs = ctxs .iter_mut() .rev() .take_while(|it| matches!(it.kind, BreakableKind::Block | BreakableKind::Loop)); match label { - Some(_) => ctxs.find(|ctx| ctx.label.as_ref() == label), + Some(_) => ctxs.find(|ctx| ctx.label == label), None => ctxs.find(|ctx| matches!(ctx.kind, BreakableKind::Loop)), } } fn find_continuable<'c>( ctxs: &'c mut [BreakableContext], - label: Option<&name::Name>, + label: Option, ) -> Option<&'c mut BreakableContext> { match label { Some(_) => find_breakable(ctxs, label).filter(|it| matches!(it.kind, BreakableKind::Loop)), @@ -506,14 +553,10 @@ impl<'a> InferenceContext<'a> { body: &'a Body, resolver: Resolver, ) -> Self { - let krate = owner.module(db.upcast()).krate(); - let trait_env = owner - .as_generic_def_id() - .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d)); + let trait_env = db.trait_environment_for_body(owner); InferenceContext { result: InferenceResult::default(), - table: unify::InferenceTable::new(db, trait_env.clone()), - trait_env, + table: unify::InferenceTable::new(db, trait_env), return_ty: TyKind::Error.intern(Interner), // set in collect_* calls resume_yield_tys: None, return_coercion: None, @@ -524,6 +567,10 @@ impl<'a> InferenceContext<'a> { resolver, diverges: Diverges::Maybe, breakables: Vec::new(), + current_captures: vec![], + current_closure: None, + deferred_closures: FxHashMap::default(), + closure_dependencies: FxHashMap::default(), } } @@ -533,6 +580,30 @@ impl<'a> InferenceContext<'a> { // there is no problem in it being `pub(crate)`, remove this comment. pub(crate) fn resolve_all(self) -> InferenceResult { let InferenceContext { mut table, mut result, .. } = self; + // Destructure every single field so whenever new fields are added to `InferenceResult` we + // don't forget to handle them here. + let InferenceResult { + method_resolutions, + field_resolutions: _, + variant_resolutions: _, + assoc_resolutions, + diagnostics, + type_of_expr, + type_of_pat, + type_of_binding, + type_of_rpit, + type_of_for_iterator, + type_mismatches, + standard_types: _, + pat_adjustments, + binding_modes: _, + expr_adjustments, + // Types in `closure_info` have already been `resolve_completely()`'d during + // `InferenceContext::infer_closures()` (in `HirPlace::ty()` specifically), so no need + // to resolve them here. + closure_info: _, + mutated_bindings_in_closure: _, + } = &mut result; table.fallback_if_possible(); @@ -541,62 +612,63 @@ impl<'a> InferenceContext<'a> { // make sure diverging type variables are marked as such table.propagate_diverging_flag(); - for ty in result.type_of_expr.values_mut() { + for ty in type_of_expr.values_mut() { *ty = table.resolve_completely(ty.clone()); } - for ty in result.type_of_pat.values_mut() { + for ty in type_of_pat.values_mut() { *ty = table.resolve_completely(ty.clone()); } - for ty in result.type_of_binding.values_mut() { + for ty in type_of_binding.values_mut() { *ty = table.resolve_completely(ty.clone()); } - for ty in result.type_of_rpit.values_mut() { + for ty in type_of_rpit.values_mut() { *ty = table.resolve_completely(ty.clone()); } - for ty in result.type_of_for_iterator.values_mut() { + for ty in type_of_for_iterator.values_mut() { *ty = table.resolve_completely(ty.clone()); } - for mismatch in result.type_mismatches.values_mut() { + for mismatch in type_mismatches.values_mut() { mismatch.expected = table.resolve_completely(mismatch.expected.clone()); mismatch.actual = table.resolve_completely(mismatch.actual.clone()); } - result.diagnostics.retain_mut(|diagnostic| { - if let InferenceDiagnostic::ExpectedFunction { found: ty, .. } - | InferenceDiagnostic::UnresolvedField { receiver: ty, .. } - | InferenceDiagnostic::UnresolvedMethodCall { receiver: ty, .. } = diagnostic - { - *ty = table.resolve_completely(ty.clone()); - // FIXME: Remove this when we are on par with rustc in terms of inference - if ty.contains_unknown() { - return false; - } + diagnostics.retain_mut(|diagnostic| { + use InferenceDiagnostic::*; + match diagnostic { + ExpectedFunction { found: ty, .. } + | UnresolvedField { receiver: ty, .. } + | UnresolvedMethodCall { receiver: ty, .. } => { + *ty = table.resolve_completely(ty.clone()); + // FIXME: Remove this when we are on par with rustc in terms of inference + if ty.contains_unknown() { + return false; + } - if let InferenceDiagnostic::UnresolvedMethodCall { field_with_same_name, .. } = - diagnostic - { - let clear = if let Some(ty) = field_with_same_name { - *ty = table.resolve_completely(ty.clone()); - ty.contains_unknown() - } else { - false - }; - if clear { - *field_with_same_name = None; + if let UnresolvedMethodCall { field_with_same_name, .. } = diagnostic { + if let Some(ty) = field_with_same_name { + *ty = table.resolve_completely(ty.clone()); + if ty.contains_unknown() { + *field_with_same_name = None; + } + } } } + TypedHole { expected: ty, .. } => { + *ty = table.resolve_completely(ty.clone()); + } + _ => (), } true }); - for (_, subst) in result.method_resolutions.values_mut() { + for (_, subst) in method_resolutions.values_mut() { *subst = table.resolve_completely(subst.clone()); } - for (_, subst) in result.assoc_resolutions.values_mut() { + for (_, subst) in assoc_resolutions.values_mut() { *subst = table.resolve_completely(subst.clone()); } - for adjustment in result.expr_adjustments.values_mut().flatten() { + for adjustment in expr_adjustments.values_mut().flatten() { adjustment.target = table.resolve_completely(adjustment.target.clone()); } - for adjustment in result.pat_adjustments.values_mut().flatten() { + for adjustment in pat_adjustments.values_mut().flatten() { *adjustment = table.resolve_completely(adjustment.clone()); } result @@ -615,7 +687,7 @@ impl<'a> InferenceContext<'a> { let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) .with_impl_trait_mode(ImplTraitLoweringMode::Param); let mut param_tys = - data.params.iter().map(|(_, type_ref)| ctx.lower_ty(type_ref)).collect::>(); + data.params.iter().map(|type_ref| ctx.lower_ty(type_ref)).collect::>(); // Check if function contains a va_list, if it does then we append it to the parameter types // that are collected from the function data if data.is_varargs() { @@ -634,12 +706,7 @@ impl<'a> InferenceContext<'a> { self.infer_top_pat(*pat, &ty); } - let error_ty = &TypeRef::Error; - let return_ty = if data.has_async_kw() { - data.async_ret_type.as_deref().unwrap_or(error_ty) - } else { - &*data.ret_type - }; + let return_ty = &*data.ret_type; let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); @@ -649,36 +716,16 @@ impl<'a> InferenceContext<'a> { let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) { // RPIT opaque types use substitution of their parent function. let fn_placeholders = TyBuilder::placeholder_subst(self.db, func); - fold_tys( - return_ty, - |ty, _| { - let opaque_ty_id = match ty.kind(Interner) { - TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id, - _ => return ty, - }; - let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) { - ImplTraitId::ReturnTypeImplTrait(_, idx) => idx, - _ => unreachable!(), - }; - let bounds = (*rpits).map_ref(|rpits| { - rpits.impl_traits[idx].bounds.map_ref(|it| it.into_iter()) - }); - let var = self.table.new_type_var(); - let var_subst = Substitution::from1(Interner, var.clone()); - for bound in bounds { - let predicate = - bound.map(|it| it.cloned()).substitute(Interner, &fn_placeholders); - let (var_predicate, binders) = predicate - .substitute(Interner, &var_subst) - .into_value_and_skipped_binders(); - always!(binders.is_empty(Interner)); // quantified where clauses not yet handled - self.push_obligation(var_predicate.cast(Interner)); - } - self.result.type_of_rpit.insert(idx, var.clone()); - var - }, - DebruijnIndex::INNERMOST, - ) + let result = + self.insert_inference_vars_for_rpit(return_ty, rpits.clone(), fn_placeholders); + let rpits = rpits.skip_binders(); + for (id, _) in rpits.impl_traits.iter() { + if let Entry::Vacant(e) = self.result.type_of_rpit.entry(id) { + never!("Missed RPIT in `insert_inference_vars_for_rpit`"); + e.insert(TyKind::Error.intern(Interner)); + } + } + result } else { return_ty }; @@ -687,6 +734,50 @@ impl<'a> InferenceContext<'a> { self.return_coercion = Some(CoerceMany::new(self.return_ty.clone())); } + fn insert_inference_vars_for_rpit( + &mut self, + t: T, + rpits: Arc>, + fn_placeholders: Substitution, + ) -> T + where + T: crate::HasInterner + crate::TypeFoldable, + { + fold_tys( + t, + |ty, _| { + let opaque_ty_id = match ty.kind(Interner) { + TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id, + _ => return ty, + }; + let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) { + ImplTraitId::ReturnTypeImplTrait(_, idx) => idx, + _ => unreachable!(), + }; + let bounds = (*rpits) + .map_ref(|rpits| rpits.impl_traits[idx].bounds.map_ref(|it| it.into_iter())); + let var = self.table.new_type_var(); + let var_subst = Substitution::from1(Interner, var.clone()); + for bound in bounds { + let predicate = + bound.map(|it| it.cloned()).substitute(Interner, &fn_placeholders); + let (var_predicate, binders) = + predicate.substitute(Interner, &var_subst).into_value_and_skipped_binders(); + always!(binders.is_empty(Interner)); // quantified where clauses not yet handled + let var_predicate = self.insert_inference_vars_for_rpit( + var_predicate, + rpits.clone(), + fn_placeholders.clone(), + ); + self.push_obligation(var_predicate.cast(Interner)); + } + self.result.type_of_rpit.insert(idx, var.clone()); + var + }, + DebruijnIndex::INNERMOST, + ) + } + fn infer_body(&mut self) { match self.return_coercion { Some(_) => self.infer_return(self.body.body_expr), @@ -742,43 +833,16 @@ impl<'a> InferenceContext<'a> { self.result.standard_types.unknown.clone() } - /// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it. - fn insert_const_vars_shallow(&mut self, c: Const) -> Const { - let data = c.data(Interner); - match &data.value { - ConstValue::Concrete(cc) => match cc.interned { - crate::ConstScalar::Unknown => self.table.new_const_var(data.ty.clone()), - _ => c, - }, - _ => c, - } - } - /// Replaces `Ty::Error` by a new type var, so we can maybe still infer it. fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { - match ty.kind(Interner) { - TyKind::Error => self.table.new_type_var(), - TyKind::InferenceVar(..) => { - let ty_resolved = self.resolve_ty_shallow(&ty); - if ty_resolved.is_unknown() { - self.table.new_type_var() - } else { - ty - } - } - _ => ty, - } + self.table.insert_type_vars_shallow(ty) } - fn insert_type_vars(&mut self, ty: Ty) -> Ty { - fold_tys_and_consts( - ty, - |x, _| match x { - Either::Left(ty) => Either::Left(self.insert_type_vars_shallow(ty)), - Either::Right(c) => Either::Right(self.insert_const_vars_shallow(c)), - }, - DebruijnIndex::INNERMOST, - ) + fn insert_type_vars(&mut self, ty: T) -> T + where + T: HasInterner + TypeFoldable, + { + self.table.insert_type_vars(ty) } fn push_obligation(&mut self, o: DomainGoal) { @@ -789,13 +853,75 @@ impl<'a> InferenceContext<'a> { self.table.unify(ty1, ty2) } + /// Attempts to returns the deeply last field of nested structures, but + /// does not apply any normalization in its search. Returns the same type + /// if input `ty` is not a structure at all. + fn struct_tail_without_normalization(&mut self, ty: Ty) -> Ty { + self.struct_tail_with_normalize(ty, identity) + } + + /// Returns the deeply last field of nested structures, or the same type if + /// not a structure at all. Corresponds to the only possible unsized field, + /// and its type can be used to determine unsizing strategy. + /// + /// This is parameterized over the normalization strategy (i.e. how to + /// handle `::Assoc` and `impl Trait`); pass the identity + /// function to indicate no normalization should take place. + fn struct_tail_with_normalize( + &mut self, + mut ty: Ty, + mut normalize: impl FnMut(Ty) -> Ty, + ) -> Ty { + // FIXME: fetch the limit properly + let recursion_limit = 10; + for iteration in 0.. { + if iteration > recursion_limit { + return self.err_ty(); + } + match ty.kind(Interner) { + TyKind::Adt(chalk_ir::AdtId(hir_def::AdtId::StructId(struct_id)), substs) => { + match self.db.field_types((*struct_id).into()).values().next_back().cloned() { + Some(field) => { + ty = field.substitute(Interner, substs); + } + None => break, + } + } + TyKind::Adt(..) => break, + TyKind::Tuple(_, substs) => { + match substs + .as_slice(Interner) + .split_last() + .and_then(|(last_ty, _)| last_ty.ty(Interner)) + { + Some(last_ty) => ty = last_ty.clone(), + None => break, + } + } + TyKind::Alias(..) => { + let normalized = normalize(ty.clone()); + if ty == normalized { + return ty; + } else { + ty = normalized; + } + } + _ => break, + } + } + ty + } + /// Recurses through the given type, normalizing associated types mentioned /// in it by replacing them by type variables and registering obligations to /// resolve later. This should be done once for every type we get from some /// type annotation (e.g. from a let type annotation, field type or function /// call). `make_ty` handles this already, but e.g. for field types we need /// to do it as well. - fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { + fn normalize_associated_types_in(&mut self, ty: T) -> T + where + T: HasInterner + TypeFoldable, + { self.table.normalize_associated_types_in(ty) } @@ -848,10 +974,8 @@ impl<'a> InferenceContext<'a> { None => return (self.err_ty(), None), }; let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); - // FIXME: this should resolve assoc items as well, see this example: - // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 let (resolution, unresolved) = if value_ns { - match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path.mod_path()) { + match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path) { Some(ResolveValueResult::ValueNs(value)) => match value { ValueNs::EnumVariantId(var) => { let substs = ctx.substs_from_path(path, var.into(), true); @@ -872,11 +996,15 @@ impl<'a> InferenceContext<'a> { None => return (self.err_ty(), None), } } else { - match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) { + match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path) { Some(it) => it, None => return (self.err_ty(), None), } }; + let Some(mod_path) = path.mod_path() else { + never!("resolver should always resolve lang item paths"); + return (self.err_ty(), None); + }; return match resolution { TypeNs::AdtId(AdtId::StructId(strukt)) => { let substs = ctx.substs_from_path(path, strukt.into(), true); @@ -899,8 +1027,68 @@ impl<'a> InferenceContext<'a> { TypeNs::SelfType(impl_id) => { let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); let substs = generics.placeholder_subst(self.db); - let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs); - self.resolve_variant_on_alias(ty, unresolved, path) + let mut ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs); + + let Some(mut remaining_idx) = unresolved else { + return self.resolve_variant_on_alias(ty, None, mod_path); + }; + + let mut remaining_segments = path.segments().skip(remaining_idx); + + // We need to try resolving unresolved segments one by one because each may resolve + // to a projection, which `TyLoweringContext` cannot handle on its own. + while !remaining_segments.is_empty() { + let resolved_segment = path.segments().get(remaining_idx - 1).unwrap(); + let current_segment = remaining_segments.take(1); + + // If we can resolve to an enum variant, it takes priority over associated type + // of the same name. + if let Some((AdtId::EnumId(id), _)) = ty.as_adt() { + let enum_data = self.db.enum_data(id); + let name = current_segment.first().unwrap().name; + if let Some(local_id) = enum_data.variant(name) { + let variant = EnumVariantId { parent: id, local_id }; + return if remaining_segments.len() == 1 { + (ty, Some(variant.into())) + } else { + // We still have unresolved paths, but enum variants never have + // associated types! + (self.err_ty(), None) + }; + } + } + + // `lower_partly_resolved_path()` returns `None` as type namespace unless + // `remaining_segments` is empty, which is never the case here. We don't know + // which namespace the new `ty` is in until normalized anyway. + (ty, _) = ctx.lower_partly_resolved_path( + resolution, + resolved_segment, + current_segment, + false, + ); + + ty = self.table.insert_type_vars(ty); + ty = self.table.normalize_associated_types_in(ty); + ty = self.table.resolve_ty_shallow(&ty); + if ty.is_unknown() { + return (self.err_ty(), None); + } + + // FIXME(inherent_associated_types): update `resolution` based on `ty` here. + remaining_idx += 1; + remaining_segments = remaining_segments.skip(1); + } + + let variant = ty.as_adt().and_then(|(id, _)| match id { + AdtId::StructId(s) => Some(VariantId::StructId(s)), + AdtId::UnionId(u) => Some(VariantId::UnionId(u)), + AdtId::EnumId(_) => { + // FIXME Error E0071, expected struct, variant or union type, found enum `Foo` + None + } + }); + (ty, variant) } TypeNs::TypeAliasId(it) => { let container = it.lookup(self.db.upcast()).container; @@ -917,7 +1105,7 @@ impl<'a> InferenceContext<'a> { let ty = TyBuilder::def_ty(self.db, it.into(), parent_subst) .fill_with_inference_vars(&mut self.table) .build(); - self.resolve_variant_on_alias(ty, unresolved, path) + self.resolve_variant_on_alias(ty, unresolved, mod_path) } TypeNs::AdtSelfType(_) => { // FIXME this could happen in array size expressions, once we're checking them @@ -953,9 +1141,9 @@ impl<'a> InferenceContext<'a> { &mut self, ty: Ty, unresolved: Option, - path: &Path, + path: &ModPath, ) -> (Ty, Option) { - let remaining = unresolved.map(|x| path.segments().skip(x).len()).filter(|x| x > &0); + let remaining = unresolved.map(|x| path.segments()[x..].len()).filter(|x| x > &0); match remaining { None => { let variant = ty.as_adt().and_then(|(adt_id, _)| match adt_id { @@ -969,7 +1157,7 @@ impl<'a> InferenceContext<'a> { (ty, variant) } Some(1) => { - let segment = path.mod_path().segments().last().unwrap(); + let segment = path.segments().last().unwrap(); // this could be an enum variant or associated type if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() { let enum_data = self.db.enum_data(enum_id); @@ -993,22 +1181,6 @@ impl<'a> InferenceContext<'a> { self.db.lang_item(krate, item) } - fn resolve_into_iter_item(&self) -> Option { - let ItemContainerId::TraitId(trait_) = self.resolve_lang_item(LangItem::IntoIterIntoIter)? - .as_function()? - .lookup(self.db.upcast()).container - else { return None }; - self.db.trait_data(trait_).associated_type_by_name(&name![IntoIter]) - } - - fn resolve_iterator_item(&self) -> Option { - let ItemContainerId::TraitId(trait_) = self.resolve_lang_item(LangItem::IteratorNext)? - .as_function()? - .lookup(self.db.upcast()).container - else { return None }; - self.db.trait_data(trait_).associated_type_by_name(&name![Item]) - } - fn resolve_output_on(&self, trait_: TraitId) -> Option { self.db.trait_data(trait_).associated_type_by_name(&name![Output]) } @@ -1017,10 +1189,6 @@ impl<'a> InferenceContext<'a> { self.resolve_lang_item(lang)?.as_trait() } - fn resolve_ops_try_output(&self) -> Option { - self.resolve_output_on(self.resolve_lang_trait(LangItem::Try)?) - } - fn resolve_ops_neg_output(&self) -> Option { self.resolve_output_on(self.resolve_lang_trait(LangItem::Neg)?) } @@ -1136,9 +1304,8 @@ impl Expectation { /// which still is useful, because it informs integer literals and the like. /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169 /// for examples of where this comes up,. - fn rvalue_hint(table: &mut unify::InferenceTable<'_>, ty: Ty) -> Self { - // FIXME: do struct_tail_without_normalization - match table.resolve_ty_shallow(&ty).kind(Interner) { + fn rvalue_hint(ctx: &mut InferenceContext<'_>, ty: Ty) -> Self { + match ctx.struct_tail_without_normalization(ty.clone()).kind(Interner) { TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => Expectation::RValueLikeUnsized(ty), _ => Expectation::has_type(ty), } diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index a6449d019ff6a..23189f383e0e6 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -1,12 +1,33 @@ //! Inference of closure parameter types based on the closure's expected type. -use chalk_ir::{cast::Cast, AliasEq, AliasTy, FnSubst, WhereClause}; -use hir_def::{expr::ExprId, HasModule}; +use std::{cmp, collections::HashMap, convert::Infallible, mem}; + +use chalk_ir::{ + cast::Cast, + fold::{FallibleTypeFolder, TypeFoldable}, + AliasEq, AliasTy, BoundVar, DebruijnIndex, FnSubst, Mutability, TyKind, WhereClause, +}; +use hir_def::{ + data::adt::VariantData, + hir::{Array, BinaryOp, BindingId, CaptureBy, Expr, ExprId, Pat, PatId, Statement, UnaryOp}, + lang_item::LangItem, + resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, + DefWithBodyId, FieldId, HasModule, VariantId, +}; +use hir_expand::name; +use rustc_hash::FxHashMap; use smallvec::SmallVec; +use stdx::never; use crate::{ - to_chalk_trait_id, utils, ChalkTraitId, DynTy, FnPointer, FnSig, Interner, Substitution, Ty, - TyExt, TyKind, + db::HirDatabase, + from_placeholder_idx, make_binders, + mir::{BorrowKind, MirSpan, ProjectionElem}, + static_lifetime, to_chalk_trait_id, + traits::FnTrait, + utils::{self, generics, Generics}, + Adjust, Adjustment, Binders, BindingMode, ChalkTraitId, ClosureId, DynTy, FnPointer, FnSig, + Interner, Substitution, Ty, TyExt, }; use super::{Expectation, InferenceContext}; @@ -86,3 +107,906 @@ impl InferenceContext<'_> { None } } + +// The below functions handle capture and closure kind (Fn, FnMut, ..) + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub(crate) struct HirPlace { + pub(crate) local: BindingId, + pub(crate) projections: Vec>, +} + +impl HirPlace { + fn ty(&self, ctx: &mut InferenceContext<'_>) -> Ty { + let mut ty = ctx.table.resolve_completely(ctx.result[self.local].clone()); + for p in &self.projections { + ty = p.projected_ty( + ty, + ctx.db, + |_, _, _| { + unreachable!("Closure field only happens in MIR"); + }, + ctx.owner.module(ctx.db.upcast()).krate(), + ); + } + ty.clone() + } + + fn capture_kind_of_truncated_place( + &self, + mut current_capture: CaptureKind, + len: usize, + ) -> CaptureKind { + match current_capture { + CaptureKind::ByRef(BorrowKind::Mut { .. }) => { + if self.projections[len..].iter().any(|x| *x == ProjectionElem::Deref) { + current_capture = CaptureKind::ByRef(BorrowKind::Unique); + } + } + _ => (), + } + current_capture + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum CaptureKind { + ByRef(BorrowKind), + ByValue, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct CapturedItem { + pub(crate) place: HirPlace, + pub(crate) kind: CaptureKind, + pub(crate) span: MirSpan, + pub(crate) ty: Binders, +} + +impl CapturedItem { + pub fn local(&self) -> BindingId { + self.place.local + } + + pub fn ty(&self, subst: &Substitution) -> Ty { + self.ty.clone().substitute(Interner, utils::ClosureSubst(subst).parent_subst()) + } + + pub fn kind(&self) -> CaptureKind { + self.kind + } + + pub fn display_place(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String { + let body = db.body(owner); + let mut result = body[self.place.local].name.display(db.upcast()).to_string(); + let mut field_need_paren = false; + for proj in &self.place.projections { + match proj { + ProjectionElem::Deref => { + result = format!("*{result}"); + field_need_paren = true; + } + ProjectionElem::Field(f) => { + if field_need_paren { + result = format!("({result})"); + } + let variant_data = f.parent.variant_data(db.upcast()); + let field = match &*variant_data { + VariantData::Record(fields) => fields[f.local_id] + .name + .as_str() + .unwrap_or("[missing field]") + .to_string(), + VariantData::Tuple(fields) => fields + .iter() + .position(|x| x.0 == f.local_id) + .unwrap_or_default() + .to_string(), + VariantData::Unit => "[missing field]".to_string(), + }; + result = format!("{result}.{field}"); + field_need_paren = false; + } + &ProjectionElem::TupleOrClosureField(field) => { + if field_need_paren { + result = format!("({result})"); + } + result = format!("{result}.{field}"); + field_need_paren = false; + } + ProjectionElem::Index(_) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::OpaqueCast(_) => { + never!("Not happen in closure capture"); + continue; + } + } + } + result + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) struct CapturedItemWithoutTy { + pub(crate) place: HirPlace, + pub(crate) kind: CaptureKind, + pub(crate) span: MirSpan, +} + +impl CapturedItemWithoutTy { + fn with_ty(self, ctx: &mut InferenceContext<'_>) -> CapturedItem { + let ty = self.place.ty(ctx).clone(); + let ty = match &self.kind { + CaptureKind::ByValue => ty, + CaptureKind::ByRef(bk) => { + let m = match bk { + BorrowKind::Mut { .. } => Mutability::Mut, + _ => Mutability::Not, + }; + TyKind::Ref(m, static_lifetime(), ty).intern(Interner) + } + }; + return CapturedItem { + place: self.place, + kind: self.kind, + span: self.span, + ty: replace_placeholder_with_binder(ctx.db, ctx.owner, ty), + }; + + fn replace_placeholder_with_binder( + db: &dyn HirDatabase, + owner: DefWithBodyId, + ty: Ty, + ) -> Binders { + struct Filler<'a> { + db: &'a dyn HirDatabase, + generics: Generics, + } + impl FallibleTypeFolder for Filler<'_> { + type Error = (); + + fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder { + self + } + + fn interner(&self) -> Interner { + Interner + } + + fn try_fold_free_placeholder_const( + &mut self, + ty: chalk_ir::Ty, + idx: chalk_ir::PlaceholderIndex, + outer_binder: DebruijnIndex, + ) -> Result, Self::Error> { + let x = from_placeholder_idx(self.db, idx); + let Some(idx) = self.generics.param_idx(x) else { + return Err(()); + }; + Ok(BoundVar::new(outer_binder, idx).to_const(Interner, ty)) + } + + fn try_fold_free_placeholder_ty( + &mut self, + idx: chalk_ir::PlaceholderIndex, + outer_binder: DebruijnIndex, + ) -> std::result::Result { + let x = from_placeholder_idx(self.db, idx); + let Some(idx) = self.generics.param_idx(x) else { + return Err(()); + }; + Ok(BoundVar::new(outer_binder, idx).to_ty(Interner)) + } + } + let Some(generic_def) = owner.as_generic_def_id() else { + return Binders::empty(Interner, ty); + }; + let filler = &mut Filler { db, generics: generics(db.upcast(), generic_def) }; + let result = ty.clone().try_fold_with(filler, DebruijnIndex::INNERMOST).unwrap_or(ty); + make_binders(db, &filler.generics, result) + } + } +} + +impl InferenceContext<'_> { + fn place_of_expr(&mut self, tgt_expr: ExprId) -> Option { + let r = self.place_of_expr_without_adjust(tgt_expr)?; + let default = vec![]; + let adjustments = self.result.expr_adjustments.get(&tgt_expr).unwrap_or(&default); + apply_adjusts_to_place(r, adjustments) + } + + fn place_of_expr_without_adjust(&mut self, tgt_expr: ExprId) -> Option { + match &self.body[tgt_expr] { + Expr::Path(p) => { + let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr); + if let Some(r) = resolver.resolve_path_in_value_ns(self.db.upcast(), p) { + if let ResolveValueResult::ValueNs(v) = r { + if let ValueNs::LocalBinding(b) = v { + return Some(HirPlace { local: b, projections: vec![] }); + } + } + } + } + Expr::Field { expr, name } => { + let mut place = self.place_of_expr(*expr)?; + if let TyKind::Tuple(..) = self.expr_ty(*expr).kind(Interner) { + let index = name.as_tuple_index()?; + place.projections.push(ProjectionElem::TupleOrClosureField(index)) + } else { + let field = self.result.field_resolution(tgt_expr)?; + place.projections.push(ProjectionElem::Field(field)); + } + return Some(place); + } + Expr::UnaryOp { expr, op: UnaryOp::Deref } => { + if matches!( + self.expr_ty_after_adjustments(*expr).kind(Interner), + TyKind::Ref(..) | TyKind::Raw(..) + ) { + let mut place = self.place_of_expr(*expr)?; + place.projections.push(ProjectionElem::Deref); + return Some(place); + } + } + _ => (), + } + None + } + + fn push_capture(&mut self, capture: CapturedItemWithoutTy) { + self.current_captures.push(capture); + } + + fn ref_expr(&mut self, expr: ExprId) { + if let Some(place) = self.place_of_expr(expr) { + self.add_capture(place, CaptureKind::ByRef(BorrowKind::Shared), expr.into()); + } + self.walk_expr(expr); + } + + fn add_capture(&mut self, place: HirPlace, kind: CaptureKind, span: MirSpan) { + if self.is_upvar(&place) { + self.push_capture(CapturedItemWithoutTy { place, kind, span }); + } + } + + fn mutate_expr(&mut self, expr: ExprId) { + if let Some(place) = self.place_of_expr(expr) { + self.add_capture( + place, + CaptureKind::ByRef(BorrowKind::Mut { allow_two_phase_borrow: false }), + expr.into(), + ); + } + self.walk_expr(expr); + } + + fn consume_expr(&mut self, expr: ExprId) { + if let Some(place) = self.place_of_expr(expr) { + self.consume_place(place, expr.into()); + } + self.walk_expr(expr); + } + + fn consume_place(&mut self, place: HirPlace, span: MirSpan) { + if self.is_upvar(&place) { + let ty = place.ty(self).clone(); + let kind = if self.is_ty_copy(ty) { + CaptureKind::ByRef(BorrowKind::Shared) + } else { + CaptureKind::ByValue + }; + self.push_capture(CapturedItemWithoutTy { place, kind, span }); + } + } + + fn walk_expr_with_adjust(&mut self, tgt_expr: ExprId, adjustment: &[Adjustment]) { + if let Some((last, rest)) = adjustment.split_last() { + match last.kind { + Adjust::NeverToAny | Adjust::Deref(None) | Adjust::Pointer(_) => { + self.walk_expr_with_adjust(tgt_expr, rest) + } + Adjust::Deref(Some(m)) => match m.0 { + Some(m) => { + self.ref_capture_with_adjusts(m, tgt_expr, rest); + } + None => unreachable!(), + }, + Adjust::Borrow(b) => { + self.ref_capture_with_adjusts(b.mutability(), tgt_expr, rest); + } + } + } else { + self.walk_expr_without_adjust(tgt_expr); + } + } + + fn ref_capture_with_adjusts(&mut self, m: Mutability, tgt_expr: ExprId, rest: &[Adjustment]) { + let capture_kind = match m { + Mutability::Mut => { + CaptureKind::ByRef(BorrowKind::Mut { allow_two_phase_borrow: false }) + } + Mutability::Not => CaptureKind::ByRef(BorrowKind::Shared), + }; + if let Some(place) = self.place_of_expr_without_adjust(tgt_expr) { + if let Some(place) = apply_adjusts_to_place(place, rest) { + self.add_capture(place, capture_kind, tgt_expr.into()); + } + } + self.walk_expr_with_adjust(tgt_expr, rest); + } + + fn walk_expr(&mut self, tgt_expr: ExprId) { + if let Some(x) = self.result.expr_adjustments.get_mut(&tgt_expr) { + // FIXME: this take is completely unneeded, and just is here to make borrow checker + // happy. Remove it if you can. + let x_taken = mem::take(x); + self.walk_expr_with_adjust(tgt_expr, &x_taken); + *self.result.expr_adjustments.get_mut(&tgt_expr).unwrap() = x_taken; + } else { + self.walk_expr_without_adjust(tgt_expr); + } + } + + fn walk_expr_without_adjust(&mut self, tgt_expr: ExprId) { + match &self.body[tgt_expr] { + Expr::If { condition, then_branch, else_branch } => { + self.consume_expr(*condition); + self.consume_expr(*then_branch); + if let &Some(expr) = else_branch { + self.consume_expr(expr); + } + } + Expr::Async { statements, tail, .. } + | Expr::Unsafe { statements, tail, .. } + | Expr::Block { statements, tail, .. } => { + for s in statements.iter() { + match s { + Statement::Let { pat, type_ref: _, initializer, else_branch } => { + if let Some(else_branch) = else_branch { + self.consume_expr(*else_branch); + if let Some(initializer) = initializer { + self.consume_expr(*initializer); + } + return; + } + if let Some(initializer) = initializer { + self.walk_expr(*initializer); + if let Some(place) = self.place_of_expr(*initializer) { + self.consume_with_pat(place, *pat); + } + } + } + Statement::Expr { expr, has_semi: _ } => { + self.consume_expr(*expr); + } + } + } + if let Some(tail) = tail { + self.consume_expr(*tail); + } + } + Expr::While { condition, body, label: _ } => { + self.consume_expr(*condition); + self.consume_expr(*body); + } + Expr::Call { callee, args, is_assignee_expr: _ } => { + self.consume_expr(*callee); + self.consume_exprs(args.iter().copied()); + } + Expr::MethodCall { receiver, args, .. } => { + self.consume_expr(*receiver); + self.consume_exprs(args.iter().copied()); + } + Expr::Match { expr, arms } => { + for arm in arms.iter() { + self.consume_expr(arm.expr); + if let Some(guard) = arm.guard { + self.consume_expr(guard); + } + } + self.walk_expr(*expr); + if let Some(discr_place) = self.place_of_expr(*expr) { + if self.is_upvar(&discr_place) { + let mut capture_mode = None; + for arm in arms.iter() { + self.walk_pat(&mut capture_mode, arm.pat); + } + if let Some(c) = capture_mode { + self.push_capture(CapturedItemWithoutTy { + place: discr_place, + kind: c, + span: (*expr).into(), + }) + } + } + } + } + Expr::Break { expr, label: _ } + | Expr::Return { expr } + | Expr::Yield { expr } + | Expr::Yeet { expr } => { + if let &Some(expr) = expr { + self.consume_expr(expr); + } + } + Expr::RecordLit { fields, spread, .. } => { + if let &Some(expr) = spread { + self.consume_expr(expr); + } + self.consume_exprs(fields.iter().map(|x| x.expr)); + } + Expr::Field { expr, name: _ } => self.select_from_expr(*expr), + Expr::UnaryOp { expr, op: UnaryOp::Deref } => { + if matches!( + self.expr_ty_after_adjustments(*expr).kind(Interner), + TyKind::Ref(..) | TyKind::Raw(..) + ) { + self.select_from_expr(*expr); + } else if let Some((f, _)) = self.result.method_resolution(tgt_expr) { + let mutability = 'b: { + if let Some(deref_trait) = + self.resolve_lang_item(LangItem::DerefMut).and_then(|x| x.as_trait()) + { + if let Some(deref_fn) = + self.db.trait_data(deref_trait).method_by_name(&name![deref_mut]) + { + break 'b deref_fn == f; + } + } + false + }; + if mutability { + self.mutate_expr(*expr); + } else { + self.ref_expr(*expr); + } + } else { + self.select_from_expr(*expr); + } + } + Expr::UnaryOp { expr, op: _ } + | Expr::Array(Array::Repeat { initializer: expr, repeat: _ }) + | Expr::Await { expr } + | Expr::Loop { body: expr, label: _ } + | Expr::Let { pat: _, expr } + | Expr::Box { expr } + | Expr::Cast { expr, type_ref: _ } => { + self.consume_expr(*expr); + } + Expr::Ref { expr, rawness: _, mutability } => match mutability { + hir_def::type_ref::Mutability::Shared => self.ref_expr(*expr), + hir_def::type_ref::Mutability::Mut => self.mutate_expr(*expr), + }, + Expr::BinaryOp { lhs, rhs, op } => { + let Some(op) = op else { + return; + }; + if matches!(op, BinaryOp::Assignment { .. }) { + self.mutate_expr(*lhs); + self.consume_expr(*rhs); + return; + } + self.consume_expr(*lhs); + self.consume_expr(*rhs); + } + Expr::Range { lhs, rhs, range_type: _ } => { + if let &Some(expr) = lhs { + self.consume_expr(expr); + } + if let &Some(expr) = rhs { + self.consume_expr(expr); + } + } + Expr::Index { base, index } => { + self.select_from_expr(*base); + self.consume_expr(*index); + } + Expr::Closure { .. } => { + let ty = self.expr_ty(tgt_expr); + let TyKind::Closure(id, _) = ty.kind(Interner) else { + never!("closure type is always closure"); + return; + }; + let (captures, _) = + self.result.closure_info.get(id).expect( + "We sort closures, so we should always have data for inner closures", + ); + let mut cc = mem::take(&mut self.current_captures); + cc.extend(captures.iter().filter(|x| self.is_upvar(&x.place)).map(|x| { + CapturedItemWithoutTy { place: x.place.clone(), kind: x.kind, span: x.span } + })); + self.current_captures = cc; + } + Expr::Array(Array::ElementList { elements: exprs, is_assignee_expr: _ }) + | Expr::Tuple { exprs, is_assignee_expr: _ } => { + self.consume_exprs(exprs.iter().copied()) + } + Expr::Missing + | Expr::Continue { .. } + | Expr::Path(_) + | Expr::Literal(_) + | Expr::Const(_) + | Expr::Underscore => (), + } + } + + fn walk_pat(&mut self, result: &mut Option, pat: PatId) { + let mut update_result = |ck: CaptureKind| match result { + Some(r) => { + *r = cmp::max(*r, ck); + } + None => *result = Some(ck), + }; + + self.walk_pat_inner( + pat, + &mut update_result, + BorrowKind::Mut { allow_two_phase_borrow: false }, + ); + } + + fn walk_pat_inner( + &mut self, + p: PatId, + update_result: &mut impl FnMut(CaptureKind), + mut for_mut: BorrowKind, + ) { + match &self.body[p] { + Pat::Ref { .. } + | Pat::Box { .. } + | Pat::Missing + | Pat::Wild + | Pat::Tuple { .. } + | Pat::Or(_) => (), + Pat::TupleStruct { .. } | Pat::Record { .. } => { + if let Some(variant) = self.result.variant_resolution_for_pat(p) { + let adt = variant.adt_id(); + let is_multivariant = match adt { + hir_def::AdtId::EnumId(e) => self.db.enum_data(e).variants.len() != 1, + _ => false, + }; + if is_multivariant { + update_result(CaptureKind::ByRef(BorrowKind::Shared)); + } + } + } + Pat::Slice { .. } + | Pat::ConstBlock(_) + | Pat::Path(_) + | Pat::Lit(_) + | Pat::Range { .. } => { + update_result(CaptureKind::ByRef(BorrowKind::Shared)); + } + Pat::Bind { id, .. } => match self.result.binding_modes[*id] { + crate::BindingMode::Move => { + if self.is_ty_copy(self.result.type_of_binding[*id].clone()) { + update_result(CaptureKind::ByRef(BorrowKind::Shared)); + } else { + update_result(CaptureKind::ByValue); + } + } + crate::BindingMode::Ref(r) => match r { + Mutability::Mut => update_result(CaptureKind::ByRef(for_mut)), + Mutability::Not => update_result(CaptureKind::ByRef(BorrowKind::Shared)), + }, + }, + } + if self.result.pat_adjustments.get(&p).map_or(false, |x| !x.is_empty()) { + for_mut = BorrowKind::Unique; + } + self.body.walk_pats_shallow(p, |p| self.walk_pat_inner(p, update_result, for_mut)); + } + + fn expr_ty(&self, expr: ExprId) -> Ty { + self.result[expr].clone() + } + + fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty { + let mut ty = None; + if let Some(x) = self.result.expr_adjustments.get(&e) { + if let Some(x) = x.last() { + ty = Some(x.target.clone()); + } + } + ty.unwrap_or_else(|| self.expr_ty(e)) + } + + fn is_upvar(&self, place: &HirPlace) -> bool { + let b = &self.body[place.local]; + if let Some(c) = self.current_closure { + let (_, root) = self.db.lookup_intern_closure(c.into()); + return b.is_upvar(root); + } + false + } + + fn is_ty_copy(&mut self, ty: Ty) -> bool { + if let TyKind::Closure(id, _) = ty.kind(Interner) { + // FIXME: We handle closure as a special case, since chalk consider every closure as copy. We + // should probably let chalk know which closures are copy, but I don't know how doing it + // without creating query cycles. + return self.result.closure_info.get(id).map(|x| x.1 == FnTrait::Fn).unwrap_or(true); + } + self.table.resolve_completely(ty).is_copy(self.db, self.owner) + } + + fn select_from_expr(&mut self, expr: ExprId) { + self.walk_expr(expr); + } + + fn adjust_for_move_closure(&mut self) { + for capture in &mut self.current_captures { + if let Some(first_deref) = + capture.place.projections.iter().position(|proj| *proj == ProjectionElem::Deref) + { + capture.place.projections.truncate(first_deref); + } + capture.kind = CaptureKind::ByValue; + } + } + + fn minimize_captures(&mut self) { + self.current_captures.sort_by_key(|x| x.place.projections.len()); + let mut hash_map = HashMap::::new(); + let result = mem::take(&mut self.current_captures); + for item in result { + let mut lookup_place = HirPlace { local: item.place.local, projections: vec![] }; + let mut it = item.place.projections.iter(); + let prev_index = loop { + if let Some(k) = hash_map.get(&lookup_place) { + break Some(*k); + } + match it.next() { + Some(x) => lookup_place.projections.push(x.clone()), + None => break None, + } + }; + match prev_index { + Some(p) => { + let len = self.current_captures[p].place.projections.len(); + let kind_after_truncate = + item.place.capture_kind_of_truncated_place(item.kind, len); + self.current_captures[p].kind = + cmp::max(kind_after_truncate, self.current_captures[p].kind); + } + None => { + hash_map.insert(item.place.clone(), self.current_captures.len()); + self.current_captures.push(item); + } + } + } + } + + fn consume_with_pat(&mut self, mut place: HirPlace, pat: PatId) { + let cnt = self.result.pat_adjustments.get(&pat).map(|x| x.len()).unwrap_or_default(); + place.projections = place + .projections + .iter() + .cloned() + .chain((0..cnt).map(|_| ProjectionElem::Deref)) + .collect::>() + .into(); + match &self.body[pat] { + Pat::Missing | Pat::Wild => (), + Pat::Tuple { args, ellipsis } => { + let (al, ar) = args.split_at(ellipsis.unwrap_or(args.len())); + let field_count = match self.result[pat].kind(Interner) { + TyKind::Tuple(_, s) => s.len(Interner), + _ => return, + }; + let fields = 0..field_count; + let it = al.iter().zip(fields.clone()).chain(ar.iter().rev().zip(fields.rev())); + for (arg, i) in it { + let mut p = place.clone(); + p.projections.push(ProjectionElem::TupleOrClosureField(i)); + self.consume_with_pat(p, *arg); + } + } + Pat::Or(pats) => { + for pat in pats.iter() { + self.consume_with_pat(place.clone(), *pat); + } + } + Pat::Record { args, .. } => { + let Some(variant) = self.result.variant_resolution_for_pat(pat) else { + return; + }; + match variant { + VariantId::EnumVariantId(_) | VariantId::UnionId(_) => { + self.consume_place(place, pat.into()) + } + VariantId::StructId(s) => { + let vd = &*self.db.struct_data(s).variant_data; + for field_pat in args.iter() { + let arg = field_pat.pat; + let Some(local_id) = vd.field(&field_pat.name) else { + continue; + }; + let mut p = place.clone(); + p.projections.push(ProjectionElem::Field(FieldId { + parent: variant.into(), + local_id, + })); + self.consume_with_pat(p, arg); + } + } + } + } + Pat::Range { .. } + | Pat::Slice { .. } + | Pat::ConstBlock(_) + | Pat::Path(_) + | Pat::Lit(_) => self.consume_place(place, pat.into()), + Pat::Bind { id, subpat: _ } => { + let mode = self.result.binding_modes[*id]; + let capture_kind = match mode { + BindingMode::Move => { + self.consume_place(place, pat.into()); + return; + } + BindingMode::Ref(Mutability::Not) => BorrowKind::Shared, + BindingMode::Ref(Mutability::Mut) => { + BorrowKind::Mut { allow_two_phase_borrow: false } + } + }; + self.add_capture(place, CaptureKind::ByRef(capture_kind), pat.into()); + } + Pat::TupleStruct { path: _, args, ellipsis } => { + let Some(variant) = self.result.variant_resolution_for_pat(pat) else { + return; + }; + match variant { + VariantId::EnumVariantId(_) | VariantId::UnionId(_) => { + self.consume_place(place, pat.into()) + } + VariantId::StructId(s) => { + let vd = &*self.db.struct_data(s).variant_data; + let (al, ar) = args.split_at(ellipsis.unwrap_or(args.len())); + let fields = vd.fields().iter(); + let it = + al.iter().zip(fields.clone()).chain(ar.iter().rev().zip(fields.rev())); + for (arg, (i, _)) in it { + let mut p = place.clone(); + p.projections.push(ProjectionElem::Field(FieldId { + parent: variant.into(), + local_id: i, + })); + self.consume_with_pat(p, *arg); + } + } + } + } + Pat::Ref { pat, mutability: _ } => { + place.projections.push(ProjectionElem::Deref); + self.consume_with_pat(place, *pat) + } + Pat::Box { .. } => (), // not supported + } + } + + fn consume_exprs(&mut self, exprs: impl Iterator) { + for expr in exprs { + self.consume_expr(expr); + } + } + + fn closure_kind(&self) -> FnTrait { + let mut r = FnTrait::Fn; + for x in &self.current_captures { + r = cmp::min( + r, + match &x.kind { + CaptureKind::ByRef(BorrowKind::Unique | BorrowKind::Mut { .. }) => { + FnTrait::FnMut + } + CaptureKind::ByRef(BorrowKind::Shallow | BorrowKind::Shared) => FnTrait::Fn, + CaptureKind::ByValue => FnTrait::FnOnce, + }, + ) + } + r + } + + fn analyze_closure(&mut self, closure: ClosureId) -> FnTrait { + let (_, root) = self.db.lookup_intern_closure(closure.into()); + self.current_closure = Some(closure); + let Expr::Closure { body, capture_by, .. } = &self.body[root] else { + unreachable!("Closure expression id is always closure"); + }; + self.consume_expr(*body); + for item in &self.current_captures { + if matches!(item.kind, CaptureKind::ByRef(BorrowKind::Mut { .. })) + && !item.place.projections.contains(&ProjectionElem::Deref) + { + // FIXME: remove the `mutated_bindings_in_closure` completely and add proper fake reads in + // MIR. I didn't do that due duplicate diagnostics. + self.result.mutated_bindings_in_closure.insert(item.place.local); + } + } + // closure_kind should be done before adjust_for_move_closure + let closure_kind = self.closure_kind(); + match capture_by { + CaptureBy::Value => self.adjust_for_move_closure(), + CaptureBy::Ref => (), + } + self.minimize_captures(); + let result = mem::take(&mut self.current_captures); + let captures = result.into_iter().map(|x| x.with_ty(self)).collect::>(); + self.result.closure_info.insert(closure, (captures, closure_kind)); + closure_kind + } + + pub(crate) fn infer_closures(&mut self) { + let deferred_closures = self.sort_closures(); + for (closure, exprs) in deferred_closures.into_iter().rev() { + self.current_captures = vec![]; + let kind = self.analyze_closure(closure); + + for (derefed_callee, callee_ty, params, expr) in exprs { + if let &Expr::Call { callee, .. } = &self.body[expr] { + let mut adjustments = + self.result.expr_adjustments.remove(&callee).unwrap_or_default(); + self.write_fn_trait_method_resolution( + kind, + &derefed_callee, + &mut adjustments, + &callee_ty, + ¶ms, + expr, + ); + self.result.expr_adjustments.insert(callee, adjustments); + } + } + } + } + + /// We want to analyze some closures before others, to have a correct analysis: + /// * We should analyze nested closures before the parent, since the parent should capture some of + /// the things that its children captures. + /// * If a closure calls another closure, we need to analyze the callee, to find out how we should + /// capture it (e.g. by move for FnOnce) + /// + /// These dependencies are collected in the main inference. We do a topological sort in this function. It + /// will consume the `deferred_closures` field and return its content in a sorted vector. + fn sort_closures(&mut self) -> Vec<(ClosureId, Vec<(Ty, Ty, Vec, ExprId)>)> { + let mut deferred_closures = mem::take(&mut self.deferred_closures); + let mut dependents_count: FxHashMap = + deferred_closures.keys().map(|x| (*x, 0)).collect(); + for (_, deps) in &self.closure_dependencies { + for dep in deps { + *dependents_count.entry(*dep).or_default() += 1; + } + } + let mut queue: Vec<_> = + deferred_closures.keys().copied().filter(|x| dependents_count[x] == 0).collect(); + let mut result = vec![]; + while let Some(x) = queue.pop() { + if let Some(d) = deferred_closures.remove(&x) { + result.push((x, d)); + } + for dep in self.closure_dependencies.get(&x).into_iter().flat_map(|x| x.iter()) { + let cnt = dependents_count.get_mut(dep).unwrap(); + *cnt -= 1; + if *cnt == 0 { + queue.push(*dep); + } + } + } + result + } +} + +fn apply_adjusts_to_place(mut r: HirPlace, adjustments: &[Adjustment]) -> Option { + for adj in adjustments { + match &adj.kind { + Adjust::Deref(None) => { + r.projections.push(ProjectionElem::Deref); + } + _ => return None, + } + } + Some(r) +} diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs index 48c91530266df..05a476f632dc2 100644 --- a/crates/hir-ty/src/infer/coerce.rs +++ b/crates/hir-ty/src/infer/coerce.rs @@ -5,14 +5,15 @@ //! See and //! `rustc_hir_analysis/check/coercion.rs`. -use std::{iter, sync::Arc}; +use std::iter; -use chalk_ir::{cast::Cast, BoundVar, Goal, Mutability, TyVariableKind}; +use chalk_ir::{cast::Cast, BoundVar, Goal, Mutability, TyKind, TyVariableKind}; use hir_def::{ - expr::ExprId, + hir::ExprId, lang_item::{LangItem, LangItemTarget}, }; use stdx::always; +use triomphe::Arc; use crate::{ autoderef::{Autoderef, AutoderefKind}, @@ -21,8 +22,10 @@ use crate::{ Adjust, Adjustment, AutoBorrow, InferOk, InferenceContext, OverloadedDeref, PointerCast, TypeError, TypeMismatch, }, - static_lifetime, Canonical, DomainGoal, FnPointer, FnSig, Guidance, InEnvironment, Interner, - Solution, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, + static_lifetime, + utils::ClosureSubst, + Canonical, DomainGoal, FnPointer, FnSig, Guidance, InEnvironment, Interner, Solution, + Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, }; use super::unify::InferenceTable; @@ -47,15 +50,23 @@ fn success( Ok(InferOk { goals, value: (adj, target) }) } +pub(super) enum CoercionCause { + // FIXME: Make better use of this. Right now things like return and break without a value + // use it to point to themselves, causing us to report a mismatch on those expressions even + // though technically they themselves are `!` + Expr(ExprId), +} + #[derive(Clone, Debug)] pub(super) struct CoerceMany { expected_ty: Ty, final_ty: Option, + expressions: Vec, } impl CoerceMany { pub(super) fn new(expected: Ty) -> Self { - CoerceMany { expected_ty: expected, final_ty: None } + CoerceMany { expected_ty: expected, final_ty: None, expressions: vec![] } } /// Returns the "expected type" with which this coercion was @@ -86,8 +97,12 @@ impl CoerceMany { } } - pub(super) fn coerce_forced_unit(&mut self, ctx: &mut InferenceContext<'_>) { - self.coerce(ctx, None, &ctx.result.standard_types.unit.clone()) + pub(super) fn coerce_forced_unit( + &mut self, + ctx: &mut InferenceContext<'_>, + cause: CoercionCause, + ) { + self.coerce(ctx, None, &ctx.result.standard_types.unit.clone(), cause) } /// Merge two types from different branches, with possible coercion. @@ -102,6 +117,7 @@ impl CoerceMany { ctx: &mut InferenceContext<'_>, expr: Option, expr_ty: &Ty, + cause: CoercionCause, ) { let expr_ty = ctx.resolve_ty_shallow(expr_ty); self.expected_ty = ctx.resolve_ty_shallow(&self.expected_ty); @@ -110,6 +126,8 @@ impl CoerceMany { // pointers to have a chance at getting a match. See // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 let sig = match (self.merged_ty().kind(Interner), expr_ty.kind(Interner)) { + (TyKind::FnDef(x, _), TyKind::FnDef(y, _)) if x == y => None, + (TyKind::Closure(x, _), TyKind::Closure(y, _)) if x == y => None, (TyKind::FnDef(..) | TyKind::Closure(..), TyKind::FnDef(..) | TyKind::Closure(..)) => { // FIXME: we're ignoring safety here. To be more correct, if we have one FnDef and one Closure, // we should be coercing the closure to a fn pointer of the safety of the FnDef @@ -125,8 +143,15 @@ impl CoerceMany { let result1 = ctx.table.coerce_inner(self.merged_ty(), &target_ty); let result2 = ctx.table.coerce_inner(expr_ty.clone(), &target_ty); if let (Ok(result1), Ok(result2)) = (result1, result2) { - ctx.table.register_infer_ok(result1); - ctx.table.register_infer_ok(result2); + ctx.table.register_infer_ok(InferOk { value: (), goals: result1.goals }); + for &e in &self.expressions { + ctx.write_expr_adj(e, result1.value.0.clone()); + } + ctx.table.register_infer_ok(InferOk { value: (), goals: result2.goals }); + if let Some(expr) = expr { + ctx.write_expr_adj(expr, result2.value.0); + self.expressions.push(expr); + } return self.final_ty = Some(target_ty); } } @@ -140,14 +165,19 @@ impl CoerceMany { } else if let Ok(res) = ctx.coerce(expr, &self.merged_ty(), &expr_ty) { self.final_ty = Some(res); } else { - if let Some(id) = expr { - ctx.result.type_mismatches.insert( - id.into(), - TypeMismatch { expected: self.merged_ty().clone(), actual: expr_ty.clone() }, - ); + match cause { + CoercionCause::Expr(id) => { + ctx.result.type_mismatches.insert( + id.into(), + TypeMismatch { expected: self.merged_ty(), actual: expr_ty.clone() }, + ); + } } cov_mark::hit!(coerce_merge_fail_fallback); } + if let Some(expr) = expr { + self.expressions.push(expr); + } } } @@ -625,7 +655,7 @@ impl<'a> InferenceTable<'a> { // Need to find out in what cases this is necessary let solution = self .db - .trait_solve(krate, canonicalized.value.clone().cast(Interner)) + .trait_solve(krate, self.trait_env.block, canonicalized.value.clone().cast(Interner)) .ok_or(TypeError)?; match solution { @@ -657,7 +687,7 @@ impl<'a> InferenceTable<'a> { } fn coerce_closure_fn_ty(closure_substs: &Substitution, safety: chalk_ir::Safety) -> Ty { - let closure_sig = closure_substs.at(Interner, 0).assert_ty_ref(Interner).clone(); + let closure_sig = ClosureSubst(closure_substs).sig_ty().clone(); match closure_sig.kind(Interner) { TyKind::Function(fn_ty) => TyKind::Function(FnPointer { num_binders: fn_ty.num_binders, diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index ee186673ee130..33e98ac86cf6b 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -6,37 +6,43 @@ use std::{ }; use chalk_ir::{ - cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyKind, TyVariableKind, + cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind, }; use hir_def::{ - expr::{ + generics::TypeOrConstParamData, + hir::{ ArithOp, Array, BinaryOp, ClosureKind, Expr, ExprId, LabelId, Literal, Statement, UnaryOp, }, - generics::TypeOrConstParamData, - lang_item::LangItem, + lang_item::{LangItem, LangItemTarget}, path::{GenericArg, GenericArgs}, - ConstParamId, FieldId, ItemContainerId, Lookup, + BlockId, ConstParamId, FieldId, ItemContainerId, Lookup, }; use hir_expand::name::{name, Name}; use stdx::always; use syntax::ast::RangeOp; +use triomphe::Arc; use crate::{ - autoderef::{self, Autoderef}, + autoderef::{builtin_deref, deref_by_trait, Autoderef}, consteval, infer::{ - coerce::CoerceMany, find_continuable, pat::contains_explicit_ref_binding, BreakableKind, + coerce::{CoerceMany, CoercionCause}, + find_continuable, + pat::contains_explicit_ref_binding, + BreakableKind, }, + lang_items::lang_items_for_bin_op, lower::{ const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode, }, mapping::{from_chalk, ToChalk}, - method_resolution::{self, lang_items_for_bin_op, VisibleFromModule}, + method_resolution::{self, VisibleFromModule}, primitive::{self, UintTy}, static_lifetime, to_chalk_trait_id, + traits::FnTrait, utils::{generics, Generics}, Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, FnPointer, FnSig, FnSubst, - Interner, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, + Interner, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind, }; use super::{ @@ -83,10 +89,10 @@ impl<'a> InferenceContext<'a> { } } - pub(super) fn infer_expr_coerce_never(&mut self, expr: ExprId, expected: &Expectation) -> Ty { + fn infer_expr_coerce_never(&mut self, expr: ExprId, expected: &Expectation) -> Ty { let ty = self.infer_expr_inner(expr, expected); // While we don't allow *arbitrary* coercions here, we *do* allow - // coercions from ! to `expected`. + // coercions from `!` to `expected`. if ty.is_never() { if let Some(adjustments) = self.result.expr_adjustments.get(&expr) { return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &**adjustments { @@ -96,13 +102,22 @@ impl<'a> InferenceContext<'a> { }; } - let adj_ty = self.table.new_type_var(); - self.write_expr_adj( - expr, - vec![Adjustment { kind: Adjust::NeverToAny, target: adj_ty.clone() }], - ); - adj_ty + if let Some(target) = expected.only_has_type(&mut self.table) { + self.coerce(Some(expr), &ty, &target) + .expect("never-to-any coercion should always succeed") + } else { + ty + } } else { + if let Some(expected_ty) = expected.only_has_type(&mut self.table) { + let could_unify = self.unify(&ty, &expected_ty); + if !could_unify { + self.result.type_mismatches.insert( + expr.into(), + TypeMismatch { expected: expected_ty, actual: ty.clone() }, + ); + } + } ty } } @@ -120,24 +135,28 @@ impl<'a> InferenceContext<'a> { ); let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); - let mut both_arms_diverge = Diverges::Always; let then_ty = self.infer_expr_inner(then_branch, expected); - both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe); + let then_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); let mut coerce = CoerceMany::new(expected.coercion_target_type(&mut self.table)); - coerce.coerce(self, Some(then_branch), &then_ty); + coerce.coerce(self, Some(then_branch), &then_ty, CoercionCause::Expr(then_branch)); match else_branch { Some(else_branch) => { let else_ty = self.infer_expr_inner(else_branch, expected); - coerce.coerce(self, Some(else_branch), &else_ty); + let else_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); + coerce.coerce( + self, + Some(else_branch), + &else_ty, + CoercionCause::Expr(else_branch), + ); + self.diverges = condition_diverges | then_diverges & else_diverges; } None => { - coerce.coerce_forced_unit(self); + coerce.coerce_forced_unit(self, CoercionCause::Expr(tgt_expr)); + self.diverges = condition_diverges; } } - both_arms_diverge &= self.diverges; - - self.diverges = condition_diverges | both_arms_diverge; coerce.complete(self) } @@ -146,67 +165,21 @@ impl<'a> InferenceContext<'a> { self.infer_top_pat(pat, &input_ty); self.result.standard_types.bool_.clone() } - Expr::Block { statements, tail, label, id: _ } => { - self.infer_block(tgt_expr, statements, *tail, *label, expected) + Expr::Block { statements, tail, label, id } => { + self.infer_block(tgt_expr, *id, statements, *tail, *label, expected) } - Expr::Unsafe { id: _, statements, tail } => { - self.infer_block(tgt_expr, statements, *tail, None, expected) + Expr::Unsafe { id, statements, tail } => { + self.infer_block(tgt_expr, *id, statements, *tail, None, expected) } - Expr::Const { id: _, statements, tail } => { + Expr::Const(id) => { self.with_breakable_ctx(BreakableKind::Border, None, None, |this| { - this.infer_block(tgt_expr, statements, *tail, None, expected) + let (_, expr) = this.db.lookup_intern_anonymous_const(*id); + this.infer_expr(expr, expected) }) .1 } - Expr::TryBlock { id: _, statements, tail } => { - // The type that is returned from the try block - let try_ty = self.table.new_type_var(); - if let Some(ty) = expected.only_has_type(&mut self.table) { - self.unify(&try_ty, &ty); - } - - // The ok-ish type that is expected from the last expression - let ok_ty = - self.resolve_associated_type(try_ty.clone(), self.resolve_ops_try_output()); - - self.infer_block( - tgt_expr, - statements, - *tail, - None, - &Expectation::has_type(ok_ty.clone()), - ); - try_ty - } - Expr::Async { id: _, statements, tail } => { - let ret_ty = self.table.new_type_var(); - let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); - let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); - let prev_ret_coercion = - mem::replace(&mut self.return_coercion, Some(CoerceMany::new(ret_ty.clone()))); - - let (_, inner_ty) = - self.with_breakable_ctx(BreakableKind::Border, None, None, |this| { - this.infer_block( - tgt_expr, - statements, - *tail, - None, - &Expectation::has_type(ret_ty), - ) - }); - - self.diverges = prev_diverges; - self.return_ty = prev_ret_ty; - self.return_coercion = prev_ret_coercion; - - // Use the first type parameter as the output type of future. - // existential type AsyncBlockImplTrait: Future - let impl_trait_id = - crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, tgt_expr); - let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into(); - TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty)) - .intern(Interner) + Expr::Async { id, statements, tail } => { + self.infer_async_block(tgt_expr, id, statements, tail) } &Expr::Loop { body, label } => { // FIXME: should be: @@ -238,25 +211,7 @@ impl<'a> InferenceContext<'a> { self.diverges = Diverges::Maybe; TyBuilder::unit() } - &Expr::For { iterable, body, pat, label } => { - let iterable_ty = self.infer_expr(iterable, &Expectation::none()); - let into_iter_ty = - self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); - let pat_ty = self - .resolve_associated_type(into_iter_ty.clone(), self.resolve_iterator_item()); - - self.result.type_of_for_iterator.insert(tgt_expr, into_iter_ty); - - self.infer_top_pat(pat, &pat_ty); - self.with_breakable_ctx(BreakableKind::Loop, None, label, |this| { - this.infer_expr(body, &Expectation::HasType(TyBuilder::unit())); - }); - - // the body may not run, so it diverging doesn't mean we diverge - self.diverges = Diverges::Maybe; - TyBuilder::unit() - } - Expr::Closure { body, args, ret_type, arg_types, closure_kind } => { + Expr::Closure { body, args, ret_type, arg_types, closure_kind, capture_by: _ } => { assert_eq!(args.len(), arg_types.len()); let mut sig_tys = Vec::with_capacity(arg_types.len() + 1); @@ -276,18 +231,7 @@ impl<'a> InferenceContext<'a> { None => self.table.new_type_var(), }; if let ClosureKind::Async = closure_kind { - // Use the first type parameter as the output type of future. - // existential type AsyncBlockImplTrait: Future - let impl_trait_id = - crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body); - let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into(); - sig_tys.push( - TyKind::OpaqueType( - opaque_ty_id, - Substitution::from1(Interner, ret_ty.clone()), - ) - .intern(Interner), - ); + sig_tys.push(self.lower_async_block_type_impl_trait(ret_ty.clone(), *body)); } else { sig_tys.push(ret_ty.clone()); } @@ -302,7 +246,7 @@ impl<'a> InferenceContext<'a> { }) .intern(Interner); - let (ty, resume_yield_tys) = match closure_kind { + let (id, ty, resume_yield_tys) = match closure_kind { ClosureKind::Generator(_) => { // FIXME: report error when there are more than 1 parameter. let resume_ty = match sig_tys.first() { @@ -322,17 +266,20 @@ impl<'a> InferenceContext<'a> { let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into(); let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner); - (generator_ty, Some((resume_ty, yield_ty))) + (None, generator_ty, Some((resume_ty, yield_ty))) } ClosureKind::Closure | ClosureKind::Async => { let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into(); let closure_ty = TyKind::Closure( closure_id, - Substitution::from1(Interner, sig_ty.clone()), + TyBuilder::subst_for_closure(self.db, self.owner, sig_ty.clone()), ) .intern(Interner); - - (closure_ty, None) + self.deferred_closures.entry(closure_id).or_default(); + if let Some(c) = self.current_closure { + self.closure_dependencies.entry(c).or_default().push(closure_id); + } + (Some(closure_id), closure_ty, None) } }; @@ -348,9 +295,10 @@ impl<'a> InferenceContext<'a> { // FIXME: lift these out into a struct let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); + let prev_closure = mem::replace(&mut self.current_closure, id); let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); let prev_ret_coercion = - mem::replace(&mut self.return_coercion, Some(CoerceMany::new(ret_ty.clone()))); + mem::replace(&mut self.return_coercion, Some(CoerceMany::new(ret_ty))); let prev_resume_yield_tys = mem::replace(&mut self.resume_yield_tys, resume_yield_tys); @@ -361,6 +309,7 @@ impl<'a> InferenceContext<'a> { self.diverges = prev_diverges; self.return_ty = prev_ret_ty; self.return_coercion = prev_ret_coercion; + self.current_closure = prev_closure; self.resume_yield_tys = prev_resume_yield_tys; ty @@ -385,16 +334,31 @@ impl<'a> InferenceContext<'a> { || res.is_none(); let (param_tys, ret_ty) = match res { Some((func, params, ret_ty)) => { - let adjustments = auto_deref_adjust_steps(&derefs); - // FIXME: Handle call adjustments for Fn/FnMut - self.write_expr_adj(*callee, adjustments); - if let Some((trait_, func)) = func { - let subst = TyBuilder::subst_for_def(self.db, trait_, None) - .push(callee_ty.clone()) - .push(TyBuilder::tuple_with(params.iter().cloned())) - .build(); - self.write_method_resolution(tgt_expr, func, subst.clone()); + let mut adjustments = auto_deref_adjust_steps(&derefs); + if let TyKind::Closure(c, _) = + self.table.resolve_completely(callee_ty.clone()).kind(Interner) + { + if let Some(par) = self.current_closure { + self.closure_dependencies.entry(par).or_default().push(*c); + } + self.deferred_closures.entry(*c).or_default().push(( + derefed_callee.clone(), + callee_ty.clone(), + params.clone(), + tgt_expr, + )); } + if let Some(fn_x) = func { + self.write_fn_trait_method_resolution( + fn_x, + &derefed_callee, + &mut adjustments, + &callee_ty, + ¶ms, + tgt_expr, + ); + } + self.write_expr_adj(*callee, adjustments); (params, ret_ty) } None => { @@ -470,7 +434,7 @@ impl<'a> InferenceContext<'a> { let arm_ty = self.infer_expr_inner(arm.expr, &expected); all_arms_diverge &= self.diverges; - coerce.coerce(self, Some(arm.expr), &arm_ty); + coerce.coerce(self, Some(arm.expr), &arm_ty, CoercionCause::Expr(arm.expr)); } self.diverges = matchee_diverges | all_arms_diverge; @@ -484,8 +448,8 @@ impl<'a> InferenceContext<'a> { self.resolver.reset_to_guard(g); ty } - Expr::Continue { label } => { - if let None = find_continuable(&mut self.breakables, label.as_ref()) { + &Expr::Continue { label } => { + if let None = find_continuable(&mut self.breakables, label) { self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { expr: tgt_expr, is_break: false, @@ -494,9 +458,9 @@ impl<'a> InferenceContext<'a> { }; self.result.standard_types.never.clone() } - Expr::Break { expr, label } => { - let val_ty = if let Some(expr) = *expr { - let opt_coerce_to = match find_breakable(&mut self.breakables, label.as_ref()) { + &Expr::Break { expr, label } => { + let val_ty = if let Some(expr) = expr { + let opt_coerce_to = match find_breakable(&mut self.breakables, label) { Some(ctxt) => match &ctxt.coerce { Some(coerce) => coerce.expected_ty(), None => { @@ -515,13 +479,17 @@ impl<'a> InferenceContext<'a> { TyBuilder::unit() }; - match find_breakable(&mut self.breakables, label.as_ref()) { + match find_breakable(&mut self.breakables, label) { Some(ctxt) => match ctxt.coerce.take() { Some(mut coerce) => { - coerce.coerce(self, *expr, &val_ty); + let cause = match expr { + Some(expr) => CoercionCause::Expr(expr), + None => CoercionCause::Expr(tgt_expr), + }; + coerce.coerce(self, expr, &val_ty, cause); // Avoiding borrowck - let ctxt = find_breakable(&mut self.breakables, label.as_ref()) + let ctxt = find_breakable(&mut self.breakables, label) .expect("breakable stack changed during coercion"); ctxt.may_break = true; ctxt.coerce = Some(coerce); @@ -538,7 +506,7 @@ impl<'a> InferenceContext<'a> { } self.result.standard_types.never.clone() } - &Expr::Return { expr } => self.infer_expr_return(expr), + &Expr::Return { expr } => self.infer_expr_return(tgt_expr, expr), Expr::Yield { expr } => { if let Some((resume_ty, yield_ty)) = self.resume_yield_tys.clone() { if let Some(expr) = expr { @@ -589,6 +557,9 @@ impl<'a> InferenceContext<'a> { let field_ty = field_def.map_or(self.err_ty(), |it| { field_types[it.local_id].clone().substitute(Interner, &substs) }); + // Field type might have some unknown types + // FIXME: we may want to emit a single type variable for all instance of type fields? + let field_ty = self.insert_type_vars(field_ty); self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty)); } if let Some(expr) = spread { @@ -601,26 +572,18 @@ impl<'a> InferenceContext<'a> { let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); self.resolve_associated_type(inner_ty, self.resolve_future_future_output()) } - Expr::Try { expr } => { - let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); - if let Some(trait_) = self.resolve_lang_trait(LangItem::Try) { - if let Some(func) = self.db.trait_data(trait_).method_by_name(&name!(branch)) { - let subst = TyBuilder::subst_for_def(self.db, trait_, None) - .push(inner_ty.clone()) - .build(); - self.write_method_resolution(tgt_expr, func, subst.clone()); - } - let try_output = self.resolve_output_on(trait_); - self.resolve_associated_type(inner_ty, try_output) - } else { - self.err_ty() - } - } Expr::Cast { expr, type_ref } => { let cast_ty = self.make_ty(type_ref); // FIXME: propagate the "castable to" expectation - let _inner_ty = self.infer_expr_no_expect(*expr); - // FIXME check the cast... + let inner_ty = self.infer_expr_no_expect(*expr); + match (inner_ty.kind(Interner), cast_ty.kind(Interner)) { + (TyKind::Ref(_, _, inner), TyKind::Raw(_, cast)) => { + // FIXME: record invalid cast diagnostic in case of mismatch + self.unify(inner, cast); + } + // FIXME check the other kinds of cast... + _ => (), + } cast_ty } Expr::Ref { expr, rawness, mutability } => { @@ -638,7 +601,7 @@ impl<'a> InferenceContext<'a> { // FIXME: record type error - expected reference but found ptr, // which cannot be coerced } - Expectation::rvalue_hint(&mut self.table, Ty::clone(exp_inner)) + Expectation::rvalue_hint(self, Ty::clone(exp_inner)) } else { Expectation::none() }; @@ -656,7 +619,25 @@ impl<'a> InferenceContext<'a> { // FIXME: Note down method resolution her match op { UnaryOp::Deref => { - autoderef::deref(&mut self.table, inner_ty).unwrap_or_else(|| self.err_ty()) + if let Some(deref_trait) = self.resolve_lang_trait(LangItem::Deref) { + if let Some(deref_fn) = + self.db.trait_data(deref_trait).method_by_name(&name![deref]) + { + // FIXME: this is wrong in multiple ways, subst is empty, and we emit it even for builtin deref (note that + // the mutability is not wrong, and will be fixed in `self.infer_mut`). + self.write_method_resolution( + tgt_expr, + deref_fn, + Substitution::empty(Interner), + ); + } + } + if let Some(derefed) = builtin_deref(&mut self.table, &inner_ty, true) { + self.resolve_ty_shallow(derefed) + } else { + deref_by_trait(&mut self.table, inner_ty) + .unwrap_or_else(|| self.err_ty()) + } } UnaryOp::Neg => { match inner_ty.kind(Interner) { @@ -767,14 +748,16 @@ impl<'a> InferenceContext<'a> { let canonicalized = self.canonicalize(base_ty.clone()); let receiver_adjustments = method_resolution::resolve_indexing_op( self.db, - self.trait_env.clone(), + self.table.trait_env.clone(), canonicalized.value, index_trait, ); - let (self_ty, adj) = receiver_adjustments + let (self_ty, mut adj) = receiver_adjustments .map_or((self.err_ty(), Vec::new()), |adj| { adj.apply(&mut self.table, base_ty) }); + // mutability will be fixed up in `InferenceContext::infer_mut`; + adj.push(Adjustment::borrow(Mutability::Not, self_ty.clone())); self.write_expr_adj(*base, adj); if let Some(func) = self.db.trait_data(index_trait).method_by_name(&name!(index)) @@ -783,7 +766,7 @@ impl<'a> InferenceContext<'a> { .push(self_ty.clone()) .push(index_ty.clone()) .build(); - self.write_method_resolution(tgt_expr, func, substs.clone()); + self.write_method_resolution(tgt_expr, func, substs); } self.resolve_associated_type_with_params( self_ty, @@ -834,6 +817,20 @@ impl<'a> InferenceContext<'a> { let array_type = TyKind::Array(byte_type, len).intern(Interner); TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(Interner) } + Literal::CString(..) => TyKind::Ref( + Mutability::Not, + static_lifetime(), + self.resolve_lang_item(LangItem::CStr) + .and_then(LangItemTarget::as_struct) + .map_or_else( + || self.err_ty(), + |strukt| { + TyKind::Adt(AdtId(strukt.into()), Substitution::empty(Interner)) + .intern(Interner) + }, + ), + ) + .intern(Interner), Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(Interner), Literal::Int(_v, ty) => match ty { Some(int_ty) => { @@ -859,9 +856,15 @@ impl<'a> InferenceContext<'a> { }, Expr::Underscore => { // Underscore expressions may only appear in assignee expressions, - // which are handled by `infer_assignee_expr()`, so any underscore - // expression reaching this branch is an error. - self.err_ty() + // which are handled by `infer_assignee_expr()`. + // Any other underscore expression is an error, we render a specialized diagnostic + // to let the user know what type is expected though. + let expected = expected.to_option(&mut self.table).unwrap_or_else(|| self.err_ty()); + self.push_diagnostic(InferenceDiagnostic::TypedHole { + expr: tgt_expr, + expected: expected.clone(), + }); + expected } }; // use a new type variable if we got unknown here @@ -874,6 +877,88 @@ impl<'a> InferenceContext<'a> { ty } + fn infer_async_block( + &mut self, + tgt_expr: ExprId, + id: &Option, + statements: &[Statement], + tail: &Option, + ) -> Ty { + let ret_ty = self.table.new_type_var(); + let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); + let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); + let prev_ret_coercion = + mem::replace(&mut self.return_coercion, Some(CoerceMany::new(ret_ty.clone()))); + + let (_, inner_ty) = self.with_breakable_ctx(BreakableKind::Border, None, None, |this| { + this.infer_block(tgt_expr, *id, statements, *tail, None, &Expectation::has_type(ret_ty)) + }); + + self.diverges = prev_diverges; + self.return_ty = prev_ret_ty; + self.return_coercion = prev_ret_coercion; + + self.lower_async_block_type_impl_trait(inner_ty, tgt_expr) + } + + pub(crate) fn lower_async_block_type_impl_trait( + &mut self, + inner_ty: Ty, + tgt_expr: ExprId, + ) -> Ty { + // Use the first type parameter as the output type of future. + // existential type AsyncBlockImplTrait: Future + let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, tgt_expr); + let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into(); + TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty)).intern(Interner) + } + + pub(crate) fn write_fn_trait_method_resolution( + &mut self, + fn_x: FnTrait, + derefed_callee: &Ty, + adjustments: &mut Vec, + callee_ty: &Ty, + params: &Vec, + tgt_expr: ExprId, + ) { + match fn_x { + FnTrait::FnOnce => (), + FnTrait::FnMut => { + if let TyKind::Ref(Mutability::Mut, _, inner) = derefed_callee.kind(Interner) { + if adjustments + .last() + .map(|x| matches!(x.kind, Adjust::Borrow(_))) + .unwrap_or(true) + { + // prefer reborrow to move + adjustments + .push(Adjustment { kind: Adjust::Deref(None), target: inner.clone() }); + adjustments.push(Adjustment::borrow(Mutability::Mut, inner.clone())) + } + } else { + adjustments.push(Adjustment::borrow(Mutability::Mut, derefed_callee.clone())); + } + } + FnTrait::Fn => { + if !matches!(derefed_callee.kind(Interner), TyKind::Ref(Mutability::Not, _, _)) { + adjustments.push(Adjustment::borrow(Mutability::Not, derefed_callee.clone())); + } + } + } + let Some(trait_) = fn_x.get_id(self.db, self.table.trait_env.krate) else { + return; + }; + let trait_data = self.db.trait_data(trait_); + if let Some(func) = trait_data.method_by_name(&fn_x.method_name()) { + let subst = TyBuilder::subst_for_def(self.db, trait_, None) + .push(callee_ty.clone()) + .push(TyBuilder::tuple_with(params.iter().cloned())) + .build(); + self.write_method_resolution(tgt_expr, func, subst.clone()); + } + } + fn infer_expr_array( &mut self, array: &Array, @@ -892,10 +977,10 @@ impl<'a> InferenceContext<'a> { (elem_ty, consteval::usize_const(self.db, Some(0), krate)) } Array::ElementList { elements, .. } => { - let mut coerce = CoerceMany::new(elem_ty.clone()); + let mut coerce = CoerceMany::new(elem_ty); for &expr in elements.iter() { let cur_elem_ty = self.infer_expr_inner(expr, &expected); - coerce.coerce(self, Some(expr), &cur_elem_ty); + coerce.coerce(self, Some(expr), &cur_elem_ty, CoercionCause::Expr(expr)); } ( coerce.complete(self), @@ -904,12 +989,13 @@ impl<'a> InferenceContext<'a> { } &Array::Repeat { initializer, repeat } => { self.infer_expr_coerce(initializer, &Expectation::has_type(elem_ty.clone())); - self.infer_expr( - repeat, - &Expectation::HasType( - TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner), - ), - ); + let usize = TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner); + match self.body[repeat] { + Expr::Underscore => { + self.write_expr_ty(repeat, usize); + } + _ => _ = self.infer_expr(repeat, &Expectation::HasType(usize)), + } ( elem_ty, @@ -928,7 +1014,8 @@ impl<'a> InferenceContext<'a> { ) } }; - + // Try to evaluate unevaluated constant, and insert variable if is not possible. + let len = self.table.insert_const_vars_shallow(len); TyKind::Array(elem_ty, len).intern(Interner) } @@ -940,18 +1027,18 @@ impl<'a> InferenceContext<'a> { .expected_ty(); let return_expr_ty = self.infer_expr_inner(expr, &Expectation::HasType(ret_ty)); let mut coerce_many = self.return_coercion.take().unwrap(); - coerce_many.coerce(self, Some(expr), &return_expr_ty); + coerce_many.coerce(self, Some(expr), &return_expr_ty, CoercionCause::Expr(expr)); self.return_coercion = Some(coerce_many); } - fn infer_expr_return(&mut self, expr: Option) -> Ty { + fn infer_expr_return(&mut self, ret: ExprId, expr: Option) -> Ty { match self.return_coercion { Some(_) => { if let Some(expr) = expr { self.infer_return(expr); } else { let mut coerce = self.return_coercion.take().unwrap(); - coerce.coerce_forced_unit(self); + coerce.coerce_forced_unit(self, CoercionCause::Expr(ret)); self.return_coercion = Some(coerce); } } @@ -976,7 +1063,7 @@ impl<'a> InferenceContext<'a> { .filter(|(e_adt, _)| e_adt == &box_id) .map(|(_, subts)| { let g = subts.at(Interner, 0); - Expectation::rvalue_hint(table, Ty::clone(g.assert_ty_ref(Interner))) + Expectation::rvalue_hint(self, Ty::clone(g.assert_ty_ref(Interner))) }) .unwrap_or_else(Expectation::none); @@ -1185,6 +1272,7 @@ impl<'a> InferenceContext<'a> { fn infer_block( &mut self, expr: ExprId, + block_id: Option, statements: &[Statement], tail: Option, label: Option, @@ -1192,9 +1280,14 @@ impl<'a> InferenceContext<'a> { ) -> Ty { let coerce_ty = expected.coercion_target_type(&mut self.table); let g = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr); + let prev_env = block_id.map(|block_id| { + let prev_env = self.table.trait_env.clone(); + Arc::make_mut(&mut self.table.trait_env).block = Some(block_id); + prev_env + }); let (break_ty, ty) = - self.with_breakable_ctx(BreakableKind::Block, Some(coerce_ty.clone()), label, |this| { + self.with_breakable_ctx(BreakableKind::Block, Some(coerce_ty), label, |this| { for stmt in statements { match stmt { Statement::Let { pat, type_ref, initializer, else_branch } => { @@ -1280,6 +1373,9 @@ impl<'a> InferenceContext<'a> { } }); self.resolver.reset_to_guard(g); + if let Some(prev_env) = prev_env { + self.table.trait_env = prev_env; + } break_ty.unwrap_or(ty) } @@ -1378,7 +1474,7 @@ impl<'a> InferenceContext<'a> { method_resolution::lookup_method( self.db, &canonicalized_receiver.value, - self.trait_env.clone(), + self.table.trait_env.clone(), self.get_traits_in_scope().as_ref().left_or_else(|&it| it), VisibleFromModule::Filter(self.resolver.module()), name, @@ -1411,7 +1507,7 @@ impl<'a> InferenceContext<'a> { let resolved = method_resolution::lookup_method( self.db, &canonicalized_receiver.value, - self.trait_env.clone(), + self.table.trait_env.clone(), self.get_traits_in_scope().as_ref().left_or_else(|&it| it), VisibleFromModule::Filter(self.resolver.module()), method_name, @@ -1562,7 +1658,7 @@ impl<'a> InferenceContext<'a> { // the parameter to coerce to the expected type (for example in // `coerce_unsize_expected_type_4`). let param_ty = self.normalize_associated_types_in(param_ty); - let expected = Expectation::rvalue_hint(&mut self.table, expected_ty); + let expected = Expectation::rvalue_hint(self, expected_ty); // infer with the expected type we have... let ty = self.infer_expr_inner(arg, &expected); @@ -1575,9 +1671,10 @@ impl<'a> InferenceContext<'a> { } else { param_ty }; - if !coercion_target.is_unknown() - && self.coerce(Some(arg), &ty, &coercion_target).is_err() - { + // The function signature may contain some unknown types, so we need to insert + // type vars here to avoid type mismatch false positive. + let coercion_target = self.insert_type_vars(coercion_target); + if self.coerce(Some(arg), &ty, &coercion_target).is_err() { self.result.type_mismatches.insert( arg.into(), TypeMismatch { expected: coercion_target, actual: ty.clone() }, @@ -1868,7 +1965,6 @@ impl<'a> InferenceContext<'a> { cb: impl FnOnce(&mut Self) -> T, ) -> (Option, T) { self.breakables.push({ - let label = label.map(|label| self.body[label].name.clone()); BreakableContext { kind, may_break: false, coerce: ty.map(CoerceMany::new), label } }); let res = cb(self); diff --git a/crates/hir-ty/src/infer/mutability.rs b/crates/hir-ty/src/infer/mutability.rs new file mode 100644 index 0000000000000..447834243908a --- /dev/null +++ b/crates/hir-ty/src/infer/mutability.rs @@ -0,0 +1,218 @@ +//! Finds if an expression is an immutable context or a mutable context, which is used in selecting +//! between `Deref` and `DerefMut` or `Index` and `IndexMut` or similar. + +use chalk_ir::Mutability; +use hir_def::{ + hir::{Array, BinaryOp, BindingAnnotation, Expr, ExprId, PatId, Statement, UnaryOp}, + lang_item::LangItem, +}; +use hir_expand::name; + +use crate::{lower::lower_to_chalk_mutability, Adjust, Adjustment, AutoBorrow, OverloadedDeref}; + +use super::InferenceContext; + +impl<'a> InferenceContext<'a> { + pub(crate) fn infer_mut_body(&mut self) { + self.infer_mut_expr(self.body.body_expr, Mutability::Not); + } + + fn infer_mut_expr(&mut self, tgt_expr: ExprId, mut mutability: Mutability) { + if let Some(adjustments) = self.result.expr_adjustments.get_mut(&tgt_expr) { + for adj in adjustments.iter_mut().rev() { + match &mut adj.kind { + Adjust::NeverToAny | Adjust::Deref(None) | Adjust::Pointer(_) => (), + Adjust::Deref(Some(d)) => *d = OverloadedDeref(Some(mutability)), + Adjust::Borrow(b) => match b { + AutoBorrow::Ref(m) | AutoBorrow::RawPtr(m) => mutability = *m, + }, + } + } + } + self.infer_mut_expr_without_adjust(tgt_expr, mutability); + } + + fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutability) { + match &self.body[tgt_expr] { + Expr::Missing => (), + &Expr::If { condition, then_branch, else_branch } => { + self.infer_mut_expr(condition, Mutability::Not); + self.infer_mut_expr(then_branch, Mutability::Not); + if let Some(else_branch) = else_branch { + self.infer_mut_expr(else_branch, Mutability::Not); + } + } + Expr::Const(id) => { + let (_, expr) = self.db.lookup_intern_anonymous_const(*id); + self.infer_mut_expr(expr, Mutability::Not); + } + Expr::Let { pat, expr } => self.infer_mut_expr(*expr, self.pat_bound_mutability(*pat)), + Expr::Block { id: _, statements, tail, label: _ } + | Expr::Async { id: _, statements, tail } + | Expr::Unsafe { id: _, statements, tail } => { + for st in statements.iter() { + match st { + Statement::Let { pat, type_ref: _, initializer, else_branch } => { + if let Some(i) = initializer { + self.infer_mut_expr(*i, self.pat_bound_mutability(*pat)); + } + if let Some(e) = else_branch { + self.infer_mut_expr(*e, Mutability::Not); + } + } + Statement::Expr { expr, has_semi: _ } => { + self.infer_mut_expr(*expr, Mutability::Not); + } + } + } + if let Some(tail) = tail { + self.infer_mut_expr(*tail, Mutability::Not); + } + } + &Expr::While { condition: c, body, label: _ } => { + self.infer_mut_expr(c, Mutability::Not); + self.infer_mut_expr(body, Mutability::Not); + } + Expr::MethodCall { receiver: x, method_name: _, args, generic_args: _ } + | Expr::Call { callee: x, args, is_assignee_expr: _ } => { + self.infer_mut_not_expr_iter(args.iter().copied().chain(Some(*x))); + } + Expr::Match { expr, arms } => { + let m = self.pat_iter_bound_mutability(arms.iter().map(|x| x.pat)); + self.infer_mut_expr(*expr, m); + for arm in arms.iter() { + self.infer_mut_expr(arm.expr, Mutability::Not); + if let Some(g) = arm.guard { + self.infer_mut_expr(g, Mutability::Not); + } + } + } + Expr::Yield { expr } + | Expr::Yeet { expr } + | Expr::Return { expr } + | Expr::Break { expr, label: _ } => { + if let &Some(expr) = expr { + self.infer_mut_expr(expr, Mutability::Not); + } + } + Expr::RecordLit { path: _, fields, spread, ellipsis: _, is_assignee_expr: _ } => { + self.infer_mut_not_expr_iter(fields.iter().map(|x| x.expr).chain(*spread)) + } + &Expr::Index { base, index } => { + if mutability == Mutability::Mut { + if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) { + if let Some(index_trait) = self + .db + .lang_item(self.table.trait_env.krate, LangItem::IndexMut) + .and_then(|l| l.as_trait()) + { + if let Some(index_fn) = + self.db.trait_data(index_trait).method_by_name(&name![index_mut]) + { + *f = index_fn; + let base_adjustments = self + .result + .expr_adjustments + .get_mut(&base) + .and_then(|it| it.last_mut()); + if let Some(Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(mutability)), + .. + }) = base_adjustments + { + *mutability = Mutability::Mut; + } + } + } + } + } + self.infer_mut_expr(base, mutability); + self.infer_mut_expr(index, Mutability::Not); + } + Expr::UnaryOp { expr, op: UnaryOp::Deref } => { + if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) { + if mutability == Mutability::Mut { + if let Some(deref_trait) = self + .db + .lang_item(self.table.trait_env.krate, LangItem::DerefMut) + .and_then(|l| l.as_trait()) + { + if let Some(deref_fn) = + self.db.trait_data(deref_trait).method_by_name(&name![deref_mut]) + { + *f = deref_fn; + } + } + } + } + self.infer_mut_expr(*expr, mutability); + } + Expr::Field { expr, name: _ } => { + self.infer_mut_expr(*expr, mutability); + } + Expr::UnaryOp { expr, op: _ } + | Expr::Range { lhs: Some(expr), rhs: None, range_type: _ } + | Expr::Range { rhs: Some(expr), lhs: None, range_type: _ } + | Expr::Await { expr } + | Expr::Box { expr } + | Expr::Loop { body: expr, label: _ } + | Expr::Cast { expr, type_ref: _ } => { + self.infer_mut_expr(*expr, Mutability::Not); + } + Expr::Ref { expr, rawness: _, mutability } => { + let mutability = lower_to_chalk_mutability(*mutability); + self.infer_mut_expr(*expr, mutability); + } + Expr::BinaryOp { lhs, rhs, op: Some(BinaryOp::Assignment { .. }) } => { + self.infer_mut_expr(*lhs, Mutability::Mut); + self.infer_mut_expr(*rhs, Mutability::Not); + } + Expr::Array(Array::Repeat { initializer: lhs, repeat: rhs }) + | Expr::BinaryOp { lhs, rhs, op: _ } + | Expr::Range { lhs: Some(lhs), rhs: Some(rhs), range_type: _ } => { + self.infer_mut_expr(*lhs, Mutability::Not); + self.infer_mut_expr(*rhs, Mutability::Not); + } + Expr::Closure { body, .. } => { + self.infer_mut_expr(*body, Mutability::Not); + } + Expr::Tuple { exprs, is_assignee_expr: _ } + | Expr::Array(Array::ElementList { elements: exprs, is_assignee_expr: _ }) => { + self.infer_mut_not_expr_iter(exprs.iter().copied()); + } + // These don't need any action, as they don't have sub expressions + Expr::Range { lhs: None, rhs: None, range_type: _ } + | Expr::Literal(_) + | Expr::Path(_) + | Expr::Continue { .. } + | Expr::Underscore => (), + } + } + + fn infer_mut_not_expr_iter(&mut self, exprs: impl Iterator) { + for expr in exprs { + self.infer_mut_expr(expr, Mutability::Not); + } + } + + fn pat_iter_bound_mutability(&self, mut pat: impl Iterator) -> Mutability { + if pat.any(|p| self.pat_bound_mutability(p) == Mutability::Mut) { + Mutability::Mut + } else { + Mutability::Not + } + } + + /// Checks if the pat contains a `ref mut` binding. Such paths makes the context of bounded expressions + /// mutable. For example in `let (ref mut x0, ref x1) = *x;` we need to use `DerefMut` for `*x` but in + /// `let (ref x0, ref x1) = *x;` we should use `Deref`. + fn pat_bound_mutability(&self, pat: PatId) -> Mutability { + let mut r = Mutability::Not; + self.body.walk_bindings_in_pat(pat, |b| { + if self.body.bindings[b].mode == BindingAnnotation::RefMut { + r = Mutability::Mut; + } + }); + r + } +} diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs index 5f839fc307aab..2480f8babac4f 100644 --- a/crates/hir-ty/src/infer/pat.rs +++ b/crates/hir-ty/src/infer/pat.rs @@ -5,7 +5,7 @@ use std::iter::repeat_with; use chalk_ir::Mutability; use hir_def::{ body::Body, - expr::{Binding, BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, Literal, Pat, PatId}, + hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, Literal, Pat, PatId}, path::Path, }; use hir_expand::name::Name; @@ -255,15 +255,15 @@ impl<'a> InferenceContext<'a> { self.infer_slice_pat(&expected, prefix, slice, suffix, default_bm) } Pat::Wild => expected.clone(), - Pat::Range { start, end } => { - let start_ty = self.infer_expr(*start, &Expectation::has_type(expected.clone())); - self.infer_expr(*end, &Expectation::has_type(start_ty)) + Pat::Range { .. } => { + // FIXME: do some checks here. + expected.clone() } &Pat::Lit(expr) => { // Don't emit type mismatches again, the expression lowering already did that. let ty = self.infer_lit_pat(expr, &expected); self.write_pat_ty(pat, ty.clone()); - return ty; + return self.pat_ty_after_adjustment(pat); } Pat::Box { inner } => match self.resolve_boxed_box() { Some(box_adt) => { @@ -298,22 +298,38 @@ impl<'a> InferenceContext<'a> { .type_mismatches .insert(pat.into(), TypeMismatch { expected, actual: ty.clone() }); } - self.write_pat_ty(pat, ty.clone()); - ty + self.write_pat_ty(pat, ty); + self.pat_ty_after_adjustment(pat) + } + + fn pat_ty_after_adjustment(&self, pat: PatId) -> Ty { + self.result + .pat_adjustments + .get(&pat) + .and_then(|x| x.first()) + .unwrap_or(&self.result.type_of_pat[pat]) + .clone() } fn infer_ref_pat( &mut self, - pat: PatId, + inner_pat: PatId, mutability: Mutability, expected: &Ty, default_bm: BindingMode, ) -> Ty { let expectation = match expected.as_reference() { Some((inner_ty, _lifetime, _exp_mut)) => inner_ty.clone(), - _ => self.result.standard_types.unknown.clone(), + None => { + let inner_ty = self.table.new_type_var(); + let ref_ty = + TyKind::Ref(mutability, static_lifetime(), inner_ty.clone()).intern(Interner); + // Unification failure will be reported by the caller. + self.unify(&ref_ty, expected); + inner_ty + } }; - let subty = self.infer_pat(pat, &expectation, default_bm); + let subty = self.infer_pat(inner_pat, &expectation, default_bm); TyKind::Ref(mutability, static_lifetime(), subty).intern(Interner) } @@ -331,7 +347,7 @@ impl<'a> InferenceContext<'a> { } else { BindingMode::convert(mode) }; - self.result.pat_binding_modes.insert(pat, mode); + self.result.binding_modes.insert(binding, mode); let inner_ty = match subpat { Some(subpat) => self.infer_pat(subpat, &expected, default_bm), @@ -345,7 +361,7 @@ impl<'a> InferenceContext<'a> { } BindingMode::Move => inner_ty.clone(), }; - self.write_pat_ty(pat, bound_ty.clone()); + self.write_pat_ty(pat, inner_ty.clone()); self.write_binding_ty(binding, bound_ty); return inner_ty; } @@ -370,7 +386,7 @@ impl<'a> InferenceContext<'a> { if let &Some(slice_pat_id) = slice { let rest_pat_ty = match expected.kind(Interner) { TyKind::Array(_, length) => { - let len = try_const_usize(length); + let len = try_const_usize(self.db, length); let len = len.and_then(|len| len.checked_sub((prefix.len() + suffix.len()) as u128)); TyKind::Array(elem_ty.clone(), usize_const(self.db, len, self.resolver.krate())) @@ -419,17 +435,10 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool { // FIXME: ConstBlock/Path/Lit might actually evaluate to ref, but inference is unimplemented. Pat::Path(..) => true, Pat::ConstBlock(..) => true, - Pat::Lit(expr) => { - !matches!(body[*expr], Expr::Literal(Literal::String(..) | Literal::ByteString(..))) - } - Pat::Bind { id, subpat: Some(subpat), .. } - if matches!( - body.bindings[*id].mode, - BindingAnnotation::Mutable | BindingAnnotation::Unannotated - ) => - { - is_non_ref_pat(body, *subpat) - } + Pat::Lit(expr) => !matches!( + body[*expr], + Expr::Literal(Literal::String(..) | Literal::CString(..) | Literal::ByteString(..)) + ), Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false, } } @@ -437,7 +446,7 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool { pub(super) fn contains_explicit_ref_binding(body: &Body, pat_id: PatId) -> bool { let mut res = false; body.walk_pats(pat_id, &mut |pat| { - res |= matches!(pat, Pat::Bind { id, .. } if body.bindings[*id].mode == BindingAnnotation::Ref); + res |= matches!(body[pat], Pat::Bind { id, .. } if body.bindings[id].mode == BindingAnnotation::Ref); }); res } diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs index 2267fedaa8e92..95a20f983f1b4 100644 --- a/crates/hir-ty/src/infer/path.rs +++ b/crates/hir-ty/src/infer/path.rs @@ -4,7 +4,7 @@ use chalk_ir::cast::Cast; use hir_def::{ path::{Path, PathSegment}, resolver::{ResolveValueResult, TypeNs, ValueNs}, - AdtId, AssocItemId, EnumVariantId, ItemContainerId, Lookup, + AdtId, AssocItemId, EnumVariantId, GenericDefId, ItemContainerId, Lookup, }; use hir_expand::name::Name; use stdx::never; @@ -13,6 +13,7 @@ use crate::{ builder::ParamKind, consteval, method_resolution::{self, VisibleFromModule}, + to_chalk_trait_id, utils::generics, InferenceDiagnostic, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId, @@ -20,26 +21,43 @@ use crate::{ use super::{ExprOrPatId, InferenceContext, TraitRef}; -impl<'a> InferenceContext<'a> { +impl InferenceContext<'_> { pub(super) fn infer_path(&mut self, path: &Path, id: ExprOrPatId) -> Option { - let ty = self.resolve_value_path(path, id)?; - let ty = self.insert_type_vars(ty); + let (value_def, generic_def, substs) = match self.resolve_value_path(path, id)? { + ValuePathResolution::GenericDef(value_def, generic_def, substs) => { + (value_def, generic_def, substs) + } + ValuePathResolution::NonGeneric(ty) => return Some(ty), + }; + let substs = self.insert_type_vars(substs); + let substs = self.normalize_associated_types_in(substs); + + self.add_required_obligations_for_value_path(generic_def, &substs); + + let ty = self.db.value_ty(value_def).substitute(Interner, &substs); let ty = self.normalize_associated_types_in(ty); Some(ty) } - fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option { + fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option { let (value, self_subst) = if let Some(type_ref) = path.type_anchor() { - let Some(last) = path.segments().last() else { return None }; - let ty = self.make_ty(type_ref); - let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1); + let last = path.segments().last()?; + + // Don't use `self.make_ty()` here as we need `orig_ns`. let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); - let (ty, _) = ctx.lower_ty_relative_path(ty, None, remaining_segments_for_ty); + let (ty, orig_ns) = ctx.lower_ty_ext(type_ref); + let ty = self.table.insert_type_vars(ty); + let ty = self.table.normalize_associated_types_in(ty); + + let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1); + let (ty, _) = ctx.lower_ty_relative_path(ty, orig_ns, remaining_segments_for_ty); + let ty = self.table.insert_type_vars(ty); + let ty = self.table.normalize_associated_types_in(ty); self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))? } else { // FIXME: report error, unresolved first path segment let value_or_partial = - self.resolver.resolve_path_in_value_ns(self.db.upcast(), path.mod_path())?; + self.resolver.resolve_path_in_value_ns(self.db.upcast(), path)?; match value_or_partial { ResolveValueResult::ValueNs(it) => (it, None), @@ -49,9 +67,9 @@ impl<'a> InferenceContext<'a> { } }; - let typable: ValueTyDefId = match value { + let value_def = match value { ValueNs::LocalBinding(pat) => match self.result.type_of_binding.get(pat) { - Some(ty) => return Some(ty.clone()), + Some(ty) => return Some(ValuePathResolution::NonGeneric(ty.clone())), None => { never!("uninferred pattern?"); return None; @@ -75,28 +93,45 @@ impl<'a> InferenceContext<'a> { let substs = generics.placeholder_subst(self.db); let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs); if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() { - let ty = self.db.value_ty(struct_id.into()).substitute(Interner, &substs); - return Some(ty); + return Some(ValuePathResolution::GenericDef( + struct_id.into(), + struct_id.into(), + substs.clone(), + )); } else { // FIXME: report error, invalid Self reference return None; } } - ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)), + ValueNs::GenericParam(it) => { + return Some(ValuePathResolution::NonGeneric(self.db.const_param_ty(it))) + } }; let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); - let substs = ctx.substs_from_path(path, typable, true); + let substs = ctx.substs_from_path(path, value_def, true); let substs = substs.as_slice(Interner); let parent_substs = self_subst.or_else(|| { - let generics = generics(self.db.upcast(), typable.to_generic_def_id()?); + let generics = generics(self.db.upcast(), value_def.to_generic_def_id()?); let parent_params_len = generics.parent_generics()?.len(); let parent_args = &substs[substs.len() - parent_params_len..]; Some(Substitution::from_iter(Interner, parent_args)) }); let parent_substs_len = parent_substs.as_ref().map_or(0, |s| s.len(Interner)); let mut it = substs.iter().take(substs.len() - parent_substs_len).cloned(); - let ty = TyBuilder::value_ty(self.db, typable, parent_substs) + + let Some(generic_def) = value_def.to_generic_def_id() else { + // `value_def` is the kind of item that can never be generic (i.e. statics, at least + // currently). We can just skip the binders to get its type. + let (ty, binders) = self.db.value_ty(value_def).into_value_and_skipped_binders(); + stdx::always!( + parent_substs.is_none() && binders.is_empty(Interner), + "non-empty binders for non-generic def", + ); + return Some(ValuePathResolution::NonGeneric(ty)); + }; + let builder = TyBuilder::subst_for_def(self.db, generic_def, parent_substs); + let substs = builder .fill(|x| { it.next().unwrap_or_else(|| match x { ParamKind::Type => self.result.standard_types.unknown.clone().cast(Interner), @@ -104,7 +139,35 @@ impl<'a> InferenceContext<'a> { }) }) .build(); - Some(ty) + + Some(ValuePathResolution::GenericDef(value_def, generic_def, substs)) + } + + fn add_required_obligations_for_value_path(&mut self, def: GenericDefId, subst: &Substitution) { + let predicates = self.db.generic_predicates(def); + for predicate in predicates.iter() { + let (predicate, binders) = + predicate.clone().substitute(Interner, &subst).into_value_and_skipped_binders(); + // Quantified where clauses are not yet handled. + stdx::always!(binders.is_empty(Interner)); + self.push_obligation(predicate.cast(Interner)); + } + + // We need to add `Self: Trait` obligation when `def` is a trait assoc item. + let container = match def { + GenericDefId::FunctionId(id) => id.lookup(self.db.upcast()).container, + GenericDefId::ConstId(id) => id.lookup(self.db.upcast()).container, + _ => return, + }; + + if let ItemContainerId::TraitId(trait_) = container { + let param_len = generics(self.db.upcast(), def).len_self(); + let parent_subst = + Substitution::from_iter(Interner, subst.iter(Interner).skip(param_len)); + let trait_ref = + TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: parent_subst }; + self.push_obligation(trait_ref.cast(Interner)); + } } fn resolve_assoc_item( @@ -169,7 +232,7 @@ impl<'a> InferenceContext<'a> { ) -> Option<(ValueNs, Substitution)> { let trait_ = trait_ref.hir_trait_id(); let item = - self.db.trait_data(trait_).items.iter().map(|(_name, id)| (*id)).find_map(|item| { + self.db.trait_data(trait_).items.iter().map(|(_name, id)| *id).find_map(|item| { match item { AssocItemId::FunctionId(func) => { if segment.name == &self.db.function_data(func).name { @@ -288,7 +351,7 @@ impl<'a> InferenceContext<'a> { name: &Name, id: ExprOrPatId, ) -> Option<(ValueNs, Substitution)> { - let ty = self.resolve_ty_shallow(ty); + let ty = self.resolve_ty_shallow(&ty); let (enum_id, subst) = match ty.as_adt() { Some((AdtId::EnumId(e), subst)) => (e, subst), _ => return None, @@ -300,3 +363,10 @@ impl<'a> InferenceContext<'a> { Some((ValueNs::EnumVariantId(variant), subst.clone())) } } + +enum ValuePathResolution { + // It's awkward to wrap a single ID in two enums, but we need both and this saves fallible + // conversion between them + `unwrap()`. + GenericDef(ValueTyDefId, GenericDefId, Substitution), + NonGeneric(Ty), +} diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index 504f0743aa947..e33d8f1795e2e 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -1,23 +1,25 @@ //! Unification and canonicalization logic. -use std::{fmt, iter, mem, sync::Arc}; +use std::{fmt, iter, mem}; use chalk_ir::{ cast::Cast, fold::TypeFoldable, interner::HasInterner, zip::Zip, CanonicalVarKind, FloatTy, IntTy, TyVariableKind, UniverseIndex, }; use chalk_solve::infer::ParameterEnaVariableExt; +use either::Either; use ena::unify::UnifyKey; -use hir_def::{FunctionId, TraitId}; use hir_expand::name; use stdx::never; +use triomphe::Arc; use super::{InferOk, InferResult, InferenceContext, TypeError}; use crate::{ - db::HirDatabase, fold_tys, static_lifetime, traits::FnTrait, AliasEq, AliasTy, BoundVar, - Canonical, Const, DebruijnIndex, GenericArg, GenericArgData, Goal, Guidance, InEnvironment, - InferenceVar, Interner, Lifetime, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Solution, - Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind, + consteval::unknown_const, db::HirDatabase, fold_tys_and_consts, static_lifetime, + to_chalk_trait_id, traits::FnTrait, AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue, + DebruijnIndex, GenericArg, GenericArgData, Goal, Guidance, InEnvironment, InferenceVar, + Interner, Lifetime, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Solution, Substitution, + TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind, }; impl<'a> InferenceContext<'a> { @@ -130,7 +132,7 @@ pub(crate) fn unify( } bitflags::bitflags! { - #[derive(Default)] + #[derive(Default, Clone, Copy)] pub(crate) struct TypeVariableFlags: u8 { const DIVERGING = 1 << 0; const INTEGER = 1 << 1; @@ -230,14 +232,40 @@ impl<'a> InferenceTable<'a> { /// type annotation (e.g. from a let type annotation, field type or function /// call). `make_ty` handles this already, but e.g. for field types we need /// to do it as well. - pub(crate) fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { - fold_tys( + pub(crate) fn normalize_associated_types_in(&mut self, ty: T) -> T + where + T: HasInterner + TypeFoldable, + { + fold_tys_and_consts( ty, - |ty, _| match ty.kind(Interner) { - TyKind::Alias(AliasTy::Projection(proj_ty)) => { - self.normalize_projection_ty(proj_ty.clone()) - } - _ => ty, + |e, _| match e { + Either::Left(ty) => Either::Left(match ty.kind(Interner) { + TyKind::Alias(AliasTy::Projection(proj_ty)) => { + self.normalize_projection_ty(proj_ty.clone()) + } + _ => ty, + }), + Either::Right(c) => Either::Right(match &c.data(Interner).value { + chalk_ir::ConstValue::Concrete(cc) => match &cc.interned { + crate::ConstScalar::UnevaluatedConst(c_id, subst) => { + // FIXME: Ideally here we should do everything that we do with type alias, i.e. adding a variable + // and registering an obligation. But it needs chalk support, so we handle the most basic + // case (a non associated const without generic parameters) manually. + if subst.len(Interner) == 0 { + if let Ok(eval) = self.db.const_eval((*c_id).into(), subst.clone()) + { + eval + } else { + unknown_const(c.data(Interner).ty.clone()) + } + } else { + unknown_const(c.data(Interner).ty.clone()) + } + } + _ => c, + }, + _ => c, + }), }, DebruijnIndex::INNERMOST, ) @@ -463,7 +491,8 @@ impl<'a> InferenceTable<'a> { pub(crate) fn try_obligation(&mut self, goal: Goal) -> Option { let in_env = InEnvironment::new(&self.trait_env.env, goal); let canonicalized = self.canonicalize(in_env); - let solution = self.db.trait_solve(self.trait_env.krate, canonicalized.value); + let solution = + self.db.trait_solve(self.trait_env.krate, self.trait_env.block, canonicalized.value); solution } @@ -598,7 +627,11 @@ impl<'a> InferenceTable<'a> { &mut self, canonicalized: &Canonicalized>, ) -> bool { - let solution = self.db.trait_solve(self.trait_env.krate, canonicalized.value.clone()); + let solution = self.db.trait_solve( + self.trait_env.krate, + self.trait_env.block, + canonicalized.value.clone(), + ); match solution { Some(Solution::Unique(canonical_subst)) => { @@ -631,10 +664,13 @@ impl<'a> InferenceTable<'a> { &mut self, ty: &Ty, num_args: usize, - ) -> Option<(Option<(TraitId, FunctionId)>, Vec, Ty)> { + ) -> Option<(Option, Vec, Ty)> { match ty.callable_sig(self.db) { Some(sig) => Some((None, sig.params().to_vec(), sig.ret().clone())), - None => self.callable_sig_from_fn_trait(ty, num_args), + None => { + let (f, args_ty, return_ty) = self.callable_sig_from_fn_trait(ty, num_args)?; + Some((Some(f), args_ty, return_ty)) + } } } @@ -642,7 +678,7 @@ impl<'a> InferenceTable<'a> { &mut self, ty: &Ty, num_args: usize, - ) -> Option<(Option<(TraitId, FunctionId)>, Vec, Ty)> { + ) -> Option<(FnTrait, Vec, Ty)> { let krate = self.trait_env.krate; let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?; let trait_data = self.db.trait_data(fn_once_trait); @@ -676,23 +712,90 @@ impl<'a> InferenceTable<'a> { }; let trait_env = self.trait_env.env.clone(); + let mut trait_ref = projection.trait_ref(self.db); let obligation = InEnvironment { - goal: projection.trait_ref(self.db).cast(Interner), - environment: trait_env, + goal: trait_ref.clone().cast(Interner), + environment: trait_env.clone(), }; let canonical = self.canonicalize(obligation.clone()); - if self.db.trait_solve(krate, canonical.value.cast(Interner)).is_some() { + if self + .db + .trait_solve(krate, self.trait_env.block, canonical.value.cast(Interner)) + .is_some() + { self.register_obligation(obligation.goal); let return_ty = self.normalize_projection_ty(projection); - Some(( - Some(fn_once_trait).zip(trait_data.method_by_name(&name!(call_once))), - arg_tys, - return_ty, - )) + for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] { + let fn_x_trait = fn_x.get_id(self.db, krate)?; + trait_ref.trait_id = to_chalk_trait_id(fn_x_trait); + let obligation: chalk_ir::InEnvironment> = InEnvironment { + goal: trait_ref.clone().cast(Interner), + environment: trait_env.clone(), + }; + let canonical = self.canonicalize(obligation.clone()); + if self + .db + .trait_solve(krate, self.trait_env.block, canonical.value.cast(Interner)) + .is_some() + { + return Some((fn_x, arg_tys, return_ty)); + } + } + unreachable!("It should at least implement FnOnce at this point"); } else { None } } + + pub(super) fn insert_type_vars(&mut self, ty: T) -> T + where + T: HasInterner + TypeFoldable, + { + fold_tys_and_consts( + ty, + |x, _| match x { + Either::Left(ty) => Either::Left(self.insert_type_vars_shallow(ty)), + Either::Right(c) => Either::Right(self.insert_const_vars_shallow(c)), + }, + DebruijnIndex::INNERMOST, + ) + } + + /// Replaces `Ty::Error` by a new type var, so we can maybe still infer it. + pub(super) fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { + match ty.kind(Interner) { + TyKind::Error => self.new_type_var(), + TyKind::InferenceVar(..) => { + let ty_resolved = self.resolve_ty_shallow(&ty); + if ty_resolved.is_unknown() { + self.new_type_var() + } else { + ty + } + } + _ => ty, + } + } + + /// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it. + pub(super) fn insert_const_vars_shallow(&mut self, c: Const) -> Const { + let data = c.data(Interner); + match &data.value { + ConstValue::Concrete(cc) => match &cc.interned { + crate::ConstScalar::Unknown => self.new_const_var(data.ty.clone()), + // try to evaluate unevaluated const. Replace with new var if const eval failed. + crate::ConstScalar::UnevaluatedConst(id, subst) => { + if let Ok(eval) = self.db.const_eval(*id, subst.clone()) { + eval + } else { + self.new_const_var(data.ty.clone()) + } + } + _ => c, + }, + _ => c, + } + } } impl<'a> fmt::Debug for InferenceTable<'a> { diff --git a/crates/hir-ty/src/inhabitedness.rs b/crates/hir-ty/src/inhabitedness.rs index 36af78153d43a..e5038543b68e6 100644 --- a/crates/hir-ty/src/inhabitedness.rs +++ b/crates/hir-ty/src/inhabitedness.rs @@ -6,9 +6,10 @@ use chalk_ir::{ DebruijnIndex, }; use hir_def::{ - adt::VariantData, attr::Attrs, visibility::Visibility, AdtId, EnumVariantId, HasModule, Lookup, - ModuleId, VariantId, + attr::Attrs, data::adt::VariantData, visibility::Visibility, AdtId, EnumVariantId, HasModule, + Lookup, ModuleId, VariantId, }; +use rustc_hash::FxHashSet; use crate::{ consteval::try_const_usize, db::HirDatabase, Binders, Interner, Substitution, Ty, TyKind, @@ -16,7 +17,8 @@ use crate::{ /// Checks whether a type is visibly uninhabited from a particular module. pub(crate) fn is_ty_uninhabited_from(ty: &Ty, target_mod: ModuleId, db: &dyn HirDatabase) -> bool { - let mut uninhabited_from = UninhabitedFrom { target_mod, db }; + let mut uninhabited_from = + UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() }; let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST); inhabitedness == BREAK_VISIBLY_UNINHABITED } @@ -32,7 +34,8 @@ pub(crate) fn is_enum_variant_uninhabited_from( let vars_attrs = db.variants_attrs(variant.parent); let is_local = variant.parent.lookup(db.upcast()).container.krate() == target_mod.krate(); - let mut uninhabited_from = UninhabitedFrom { target_mod, db }; + let mut uninhabited_from = + UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() }; let inhabitedness = uninhabited_from.visit_variant( variant.into(), &enum_data.variants[variant.local_id].variant_data, @@ -45,6 +48,9 @@ pub(crate) fn is_enum_variant_uninhabited_from( struct UninhabitedFrom<'a> { target_mod: ModuleId, + recursive_ty: FxHashSet, + // guard for preventing stack overflow in non trivial non terminating types + max_depth: usize, db: &'a dyn HirDatabase, } @@ -65,17 +71,27 @@ impl TypeVisitor for UninhabitedFrom<'_> { ty: &Ty, outer_binder: DebruijnIndex, ) -> ControlFlow { - match ty.kind(Interner) { + if self.recursive_ty.contains(ty) || self.max_depth == 0 { + // rustc considers recursive types always inhabited. I think it is valid to consider + // recursive types as always uninhabited, but we should do what rustc is doing. + return CONTINUE_OPAQUELY_INHABITED; + } + self.recursive_ty.insert(ty.clone()); + self.max_depth -= 1; + let r = match ty.kind(Interner) { TyKind::Adt(adt, subst) => self.visit_adt(adt.0, subst), TyKind::Never => BREAK_VISIBLY_UNINHABITED, TyKind::Tuple(..) => ty.super_visit_with(self, outer_binder), - TyKind::Array(item_ty, len) => match try_const_usize(len) { + TyKind::Array(item_ty, len) => match try_const_usize(self.db, len) { Some(0) | None => CONTINUE_OPAQUELY_INHABITED, Some(1..) => item_ty.super_visit_with(self, outer_binder), }, TyKind::Ref(..) | _ => CONTINUE_OPAQUELY_INHABITED, - } + }; + self.recursive_ty.remove(ty); + self.max_depth += 1; + r } fn interner(&self) -> Interner { diff --git a/crates/hir-ty/src/interner.rs b/crates/hir-ty/src/interner.rs index aea7e9762fdf4..89f7d9c4f4abc 100644 --- a/crates/hir-ty/src/interner.rs +++ b/crates/hir-ty/src/interner.rs @@ -7,7 +7,8 @@ use chalk_ir::{Goal, GoalData}; use hir_def::TypeAliasId; use intern::{impl_internable, Interned}; use smallvec::SmallVec; -use std::{fmt, sync::Arc}; +use std::fmt; +use triomphe::Arc; #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] pub struct Interner; @@ -43,7 +44,7 @@ impl_internable!( ); impl chalk_ir::interner::Interner for Interner { - type InternedType = Interned>>; + type InternedType = Interned>>; type InternedLifetime = Interned>>; type InternedConst = Interned>>; type InternedConcreteConst = ConstScalar; @@ -51,8 +52,8 @@ impl chalk_ir::interner::Interner for Interner { type InternedGoal = Arc>; type InternedGoals = Vec>; type InternedSubstitution = Interned>>; - type InternedProgramClause = chalk_ir::ProgramClauseData; type InternedProgramClauses = Interned>>>; + type InternedProgramClause = chalk_ir::ProgramClauseData; type InternedQuantifiedWhereClauses = Interned>>>; type InternedVariableKinds = Interned>>>; @@ -86,6 +87,27 @@ impl chalk_ir::interner::Interner for Interner { tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt))) } + fn debug_opaque_ty_id( + opaque_ty_id: chalk_ir::OpaqueTyId, + fmt: &mut fmt::Formatter<'_>, + ) -> Option { + Some(write!(fmt, "OpaqueTy#{}", opaque_ty_id.0)) + } + + fn debug_fn_def_id( + fn_def_id: chalk_ir::FnDefId, + fmt: &mut fmt::Formatter<'_>, + ) -> Option { + tls::with_current_program(|prog| Some(prog?.debug_fn_def_id(fn_def_id, fmt))) + } + + fn debug_closure_id( + _fn_def_id: chalk_ir::ClosureId, + _fmt: &mut fmt::Formatter<'_>, + ) -> Option { + None + } + fn debug_alias( alias: &chalk_ir::AliasTy, fmt: &mut fmt::Formatter<'_>, @@ -113,13 +135,6 @@ impl chalk_ir::interner::Interner for Interner { Some(write!(fmt, "{:?}", opaque_ty.opaque_ty_id)) } - fn debug_opaque_ty_id( - opaque_ty_id: chalk_ir::OpaqueTyId, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "OpaqueTy#{}", opaque_ty_id.0)) - } - fn debug_ty(ty: &chalk_ir::Ty, fmt: &mut fmt::Formatter<'_>) -> Option { Some(write!(fmt, "{:?}", ty.data(Interner))) } @@ -131,76 +146,56 @@ impl chalk_ir::interner::Interner for Interner { Some(write!(fmt, "{:?}", lifetime.data(Interner))) } - fn debug_generic_arg( - parameter: &GenericArg, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", parameter.data(Interner).inner_debug())) - } - - fn debug_goal(goal: &Goal, fmt: &mut fmt::Formatter<'_>) -> Option { - let goal_data = goal.data(Interner); - Some(write!(fmt, "{goal_data:?}")) - } - - fn debug_goals( - goals: &chalk_ir::Goals, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", goals.debug(Interner))) - } - - fn debug_program_clause_implication( - pci: &chalk_ir::ProgramClauseImplication, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", pci.debug(Interner))) - } - - fn debug_substitution( - substitution: &chalk_ir::Substitution, + fn debug_const( + constant: &chalk_ir::Const, fmt: &mut fmt::Formatter<'_>, ) -> Option { - Some(write!(fmt, "{:?}", substitution.debug(Interner))) + Some(write!(fmt, "{:?}", constant.data(Interner))) } - fn debug_separator_trait_ref( - separator_trait_ref: &chalk_ir::SeparatorTraitRef<'_, Interner>, + fn debug_generic_arg( + parameter: &GenericArg, fmt: &mut fmt::Formatter<'_>, ) -> Option { - Some(write!(fmt, "{:?}", separator_trait_ref.debug(Interner))) + Some(write!(fmt, "{:?}", parameter.data(Interner).inner_debug())) } - fn debug_fn_def_id( - fn_def_id: chalk_ir::FnDefId, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_fn_def_id(fn_def_id, fmt))) - } - fn debug_const( - constant: &chalk_ir::Const, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", constant.data(Interner))) - } fn debug_variable_kinds( variable_kinds: &chalk_ir::VariableKinds, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", variable_kinds.as_slice(Interner))) } + fn debug_variable_kinds_with_angles( variable_kinds: &chalk_ir::VariableKinds, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", variable_kinds.inner_debug(Interner))) } + fn debug_canonical_var_kinds( canonical_var_kinds: &chalk_ir::CanonicalVarKinds, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", canonical_var_kinds.as_slice(Interner))) } + fn debug_goal(goal: &Goal, fmt: &mut fmt::Formatter<'_>) -> Option { + let goal_data = goal.data(Interner); + Some(write!(fmt, "{goal_data:?}")) + } + fn debug_goals( + goals: &chalk_ir::Goals, + fmt: &mut fmt::Formatter<'_>, + ) -> Option { + Some(write!(fmt, "{:?}", goals.debug(Interner))) + } + fn debug_program_clause_implication( + pci: &chalk_ir::ProgramClauseImplication, + fmt: &mut fmt::Formatter<'_>, + ) -> Option { + Some(write!(fmt, "{:?}", pci.debug(Interner))) + } fn debug_program_clause( clause: &chalk_ir::ProgramClause, fmt: &mut fmt::Formatter<'_>, @@ -213,6 +208,19 @@ impl chalk_ir::interner::Interner for Interner { ) -> Option { Some(write!(fmt, "{:?}", clauses.as_slice(Interner))) } + fn debug_substitution( + substitution: &chalk_ir::Substitution, + fmt: &mut fmt::Formatter<'_>, + ) -> Option { + Some(write!(fmt, "{:?}", substitution.debug(Interner))) + } + fn debug_separator_trait_ref( + separator_trait_ref: &chalk_ir::SeparatorTraitRef<'_, Interner>, + fmt: &mut fmt::Formatter<'_>, + ) -> Option { + Some(write!(fmt, "{:?}", separator_trait_ref.debug(Interner))) + } + fn debug_quantified_where_clauses( clauses: &chalk_ir::QuantifiedWhereClauses, fmt: &mut fmt::Formatter<'_>, @@ -220,6 +228,13 @@ impl chalk_ir::interner::Interner for Interner { Some(write!(fmt, "{:?}", clauses.as_slice(Interner))) } + fn debug_constraints( + _clauses: &chalk_ir::Constraints, + _fmt: &mut fmt::Formatter<'_>, + ) -> Option { + None + } + fn intern_ty(self, kind: chalk_ir::TyKind) -> Self::InternedType { let flags = kind.compute_flags(self); Interned::new(InternedWrapper(chalk_ir::TyData { kind, flags })) @@ -272,6 +287,10 @@ impl chalk_ir::interner::Interner for Interner { Arc::new(goal) } + fn goal_data(self, goal: &Self::InternedGoal) -> &GoalData { + goal + } + fn intern_goals( self, data: impl IntoIterator, E>>, @@ -279,10 +298,6 @@ impl chalk_ir::interner::Interner for Interner { data.into_iter().collect() } - fn goal_data(self, goal: &Self::InternedGoal) -> &GoalData { - goal - } - fn goals_data(self, goals: &Self::InternedGoals) -> &[Goal] { goals } @@ -367,32 +382,18 @@ impl chalk_ir::interner::Interner for Interner { ) -> &[chalk_ir::CanonicalVarKind] { canonical_var_kinds } - fn intern_constraints( self, data: impl IntoIterator>, E>>, ) -> Result { data.into_iter().collect() } - fn constraints_data( self, constraints: &Self::InternedConstraints, ) -> &[chalk_ir::InEnvironment>] { constraints } - fn debug_closure_id( - _fn_def_id: chalk_ir::ClosureId, - _fmt: &mut fmt::Formatter<'_>, - ) -> Option { - None - } - fn debug_constraints( - _clauses: &chalk_ir::Constraints, - _fmt: &mut fmt::Formatter<'_>, - ) -> Option { - None - } fn intern_variances( self, diff --git a/crates/hir-ty/src/lang_items.rs b/crates/hir-ty/src/lang_items.rs index 5308c72161b26..85ed46b96321a 100644 --- a/crates/hir-ty/src/lang_items.rs +++ b/crates/hir-ty/src/lang_items.rs @@ -1,19 +1,65 @@ //! Functions to detect special lang items -use hir_def::{lang_item::LangItem, AdtId, HasModule}; +use hir_def::{data::adt::StructFlags, lang_item::LangItem, AdtId}; +use hir_expand::name::Name; use crate::db::HirDatabase; -pub fn is_box(adt: AdtId, db: &dyn HirDatabase) -> bool { - let krate = adt.module(db.upcast()).krate(); - let box_adt = - db.lang_item(krate, LangItem::OwnedBox).and_then(|it| it.as_struct()).map(AdtId::from); - Some(adt) == box_adt +pub fn is_box(db: &dyn HirDatabase, adt: AdtId) -> bool { + let AdtId::StructId(id) = adt else { return false }; + db.struct_data(id).flags.contains(StructFlags::IS_BOX) } -pub fn is_unsafe_cell(adt: AdtId, db: &dyn HirDatabase) -> bool { - let krate = adt.module(db.upcast()).krate(); - let box_adt = - db.lang_item(krate, LangItem::UnsafeCell).and_then(|it| it.as_struct()).map(AdtId::from); - Some(adt) == box_adt +pub fn is_unsafe_cell(db: &dyn HirDatabase, adt: AdtId) -> bool { + let AdtId::StructId(id) = adt else { return false }; + db.struct_data(id).flags.contains(StructFlags::IS_UNSAFE_CELL) +} + +pub fn lang_items_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, LangItem)> { + use hir_expand::name; + use syntax::ast::{ArithOp, BinaryOp, CmpOp, Ordering}; + Some(match op { + BinaryOp::LogicOp(_) => return None, + BinaryOp::ArithOp(aop) => match aop { + ArithOp::Add => (name![add], LangItem::Add), + ArithOp::Mul => (name![mul], LangItem::Mul), + ArithOp::Sub => (name![sub], LangItem::Sub), + ArithOp::Div => (name![div], LangItem::Div), + ArithOp::Rem => (name![rem], LangItem::Rem), + ArithOp::Shl => (name![shl], LangItem::Shl), + ArithOp::Shr => (name![shr], LangItem::Shr), + ArithOp::BitXor => (name![bitxor], LangItem::BitXor), + ArithOp::BitOr => (name![bitor], LangItem::BitOr), + ArithOp::BitAnd => (name![bitand], LangItem::BitAnd), + }, + BinaryOp::Assignment { op: Some(aop) } => match aop { + ArithOp::Add => (name![add_assign], LangItem::AddAssign), + ArithOp::Mul => (name![mul_assign], LangItem::MulAssign), + ArithOp::Sub => (name![sub_assign], LangItem::SubAssign), + ArithOp::Div => (name![div_assign], LangItem::DivAssign), + ArithOp::Rem => (name![rem_assign], LangItem::RemAssign), + ArithOp::Shl => (name![shl_assign], LangItem::ShlAssign), + ArithOp::Shr => (name![shr_assign], LangItem::ShrAssign), + ArithOp::BitXor => (name![bitxor_assign], LangItem::BitXorAssign), + ArithOp::BitOr => (name![bitor_assign], LangItem::BitOrAssign), + ArithOp::BitAnd => (name![bitand_assign], LangItem::BitAndAssign), + }, + BinaryOp::CmpOp(cop) => match cop { + CmpOp::Eq { negated: false } => (name![eq], LangItem::PartialEq), + CmpOp::Eq { negated: true } => (name![ne], LangItem::PartialEq), + CmpOp::Ord { ordering: Ordering::Less, strict: false } => { + (name![le], LangItem::PartialOrd) + } + CmpOp::Ord { ordering: Ordering::Less, strict: true } => { + (name![lt], LangItem::PartialOrd) + } + CmpOp::Ord { ordering: Ordering::Greater, strict: false } => { + (name![ge], LangItem::PartialOrd) + } + CmpOp::Ord { ordering: Ordering::Greater, strict: true } => { + (name![gt], LangItem::PartialOrd) + } + }, + BinaryOp::Assignment { op: None } => return None, + }) } diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs index b95bb01fcefeb..35d3407c16c13 100644 --- a/crates/hir-ty/src/layout.rs +++ b/crates/hir-ty/src/layout.rs @@ -1,19 +1,23 @@ //! Compute the binary representation of a type use base_db::CrateId; -use chalk_ir::{AdtId, TyKind}; +use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy}; use hir_def::{ layout::{ - Abi, FieldsShape, Integer, Layout, LayoutCalculator, LayoutError, Primitive, ReprOptions, - RustcEnumVariantIdx, Scalar, Size, StructKind, TargetDataLayout, Variants, WrappingRange, + Abi, FieldsShape, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions, Scalar, Size, + StructKind, TargetDataLayout, WrappingRange, }, - LocalFieldId, + LocalEnumVariantId, LocalFieldId, }; +use la_arena::{Idx, RawIdx}; use stdx::never; +use triomphe::Arc; -use crate::{consteval::try_const_usize, db::HirDatabase, Interner, Substitution, Ty}; +use crate::{ + consteval::try_const_usize, db::HirDatabase, infer::normalize, layout::adt::struct_variant_idx, + utils::ClosureSubst, Interner, Substitution, TraitEnvironment, Ty, +}; -use self::adt::struct_variant_idx; pub use self::{ adt::{layout_of_adt_query, layout_of_adt_recover}, target::target_data_layout_query, @@ -28,6 +32,34 @@ macro_rules! user_error { mod adt; mod target; +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct RustcEnumVariantIdx(pub LocalEnumVariantId); + +impl rustc_index::vec::Idx for RustcEnumVariantIdx { + fn new(idx: usize) -> Self { + RustcEnumVariantIdx(Idx::from_raw(RawIdx::from(idx as u32))) + } + + fn index(self) -> usize { + u32::from(self.0.into_raw()) as usize + } +} + +pub type Layout = LayoutS; +pub type TagEncoding = hir_def::layout::TagEncoding; +pub type Variants = hir_def::layout::Variants; + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum LayoutError { + UserError(String), + SizeOverflow, + TargetLayoutNotAvailable, + HasPlaceholder, + HasErrorType, + NotImplemented, + Unknown, +} + struct LayoutCx<'a> { krate: CrateId, target: &'a TargetDataLayout, @@ -45,20 +77,18 @@ impl<'a> LayoutCalculator for LayoutCx<'a> { } } -fn scalar_unit(dl: &TargetDataLayout, value: Primitive) -> Scalar { - Scalar::Initialized { value, valid_range: WrappingRange::full(value.size(dl)) } -} - -fn scalar(dl: &TargetDataLayout, value: Primitive) -> Layout { - Layout::scalar(dl, scalar_unit(dl, value)) -} - -pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result { +pub fn layout_of_ty_query( + db: &dyn HirDatabase, + ty: Ty, + krate: CrateId, +) -> Result, LayoutError> { let Some(target) = db.target_data_layout(krate) else { return Err(LayoutError::TargetLayoutNotAvailable) }; let cx = LayoutCx { krate, target: &target }; let dl = &*cx.current_data_layout(); - Ok(match ty.kind(Interner) { - TyKind::Adt(AdtId(def), subst) => db.layout_of_adt(*def, subst.clone())?, + let trait_env = Arc::new(TraitEnvironment::empty(krate)); + let ty = normalize(db, trait_env, ty.clone()); + let result = match ty.kind(Interner) { + TyKind::Adt(AdtId(def), subst) => return db.layout_of_adt(*def, subst.clone(), krate), TyKind::Scalar(s) => match s { chalk_ir::Scalar::Bool => Layout::scalar( dl, @@ -78,12 +108,12 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result dl.ptr_sized_integer(), - chalk_ir::IntTy::I8 => Integer::I8, - chalk_ir::IntTy::I16 => Integer::I16, - chalk_ir::IntTy::I32 => Integer::I32, - chalk_ir::IntTy::I64 => Integer::I64, - chalk_ir::IntTy::I128 => Integer::I128, + IntTy::Isize => dl.ptr_sized_integer(), + IntTy::I8 => Integer::I8, + IntTy::I16 => Integer::I16, + IntTy::I32 => Integer::I32, + IntTy::I64 => Integer::I64, + IntTy::I128 => Integer::I128, }, true, ), @@ -92,12 +122,12 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result dl.ptr_sized_integer(), - chalk_ir::UintTy::U8 => Integer::I8, - chalk_ir::UintTy::U16 => Integer::I16, - chalk_ir::UintTy::U32 => Integer::I32, - chalk_ir::UintTy::U64 => Integer::I64, - chalk_ir::UintTy::U128 => Integer::I128, + UintTy::Usize => dl.ptr_sized_integer(), + UintTy::U8 => Integer::I8, + UintTy::U16 => Integer::I16, + UintTy::U32 => Integer::I32, + UintTy::U64 => Integer::I64, + UintTy::U128 => Integer::I128, }, false, ), @@ -105,8 +135,8 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result scalar( dl, match f { - chalk_ir::FloatTy::F32 => Primitive::F32, - chalk_ir::FloatTy::F64 => Primitive::F64, + FloatTy::F32 => Primitive::F32, + FloatTy::F64 => Primitive::F64, }, ), }, @@ -115,17 +145,17 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result, _>>()?; - let fields = fields.iter().collect::>(); + let fields = fields.iter().map(|x| &**x).collect::>(); let fields = fields.iter().collect::>(); cx.univariant(dl, &fields, &ReprOptions::default(), kind).ok_or(LayoutError::Unknown)? } TyKind::Array(element, count) => { - let count = try_const_usize(&count).ok_or(LayoutError::UserError( - "mismatched type of const generic parameter".to_string(), + let count = try_const_usize(db, &count).ok_or(LayoutError::UserError( + "unevaluated or mistyped const generic parameter".to_string(), ))? as u64; - let element = layout_of_ty(db, element, krate)?; + let element = db.layout_of_ty(element.clone(), krate)?; let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow)?; let abi = if count != 0 && matches!(element.abi, Abi::Uninhabited) { @@ -146,7 +176,7 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result { - let element = layout_of_ty(db, element, krate)?; + let element = db.layout_of_ty(element.clone(), krate)?; Layout { variants: Variants::Single { index: struct_variant_idx() }, fields: FieldsShape::Array { stride: element.size, count: 0 }, @@ -180,7 +210,7 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result { // pointee is sized - return Ok(Layout::scalar(dl, data_ptr)); + return Ok(Arc::new(Layout::scalar(dl, data_ptr))); } }; @@ -222,23 +252,51 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result { let infer = db.infer(func.into()); - layout_of_ty(db, &infer.type_of_rpit[idx], krate)? + return db.layout_of_ty(infer.type_of_rpit[idx].clone(), krate); } crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { return Err(LayoutError::NotImplemented) } } } - TyKind::Closure(_, _) | TyKind::Generator(_, _) | TyKind::GeneratorWitness(_, _) => { + TyKind::Closure(c, subst) => { + let (def, _) = db.lookup_intern_closure((*c).into()); + let infer = db.infer(def); + let (captures, _) = infer.closure_info(c); + let fields = captures + .iter() + .map(|x| { + db.layout_of_ty( + x.ty.clone().substitute(Interner, ClosureSubst(subst).parent_subst()), + krate, + ) + }) + .collect::, _>>()?; + let fields = fields.iter().map(|x| &**x).collect::>(); + let fields = fields.iter().collect::>(); + cx.univariant(dl, &fields, &ReprOptions::default(), StructKind::AlwaysSized) + .ok_or(LayoutError::Unknown)? + } + TyKind::Generator(_, _) | TyKind::GeneratorWitness(_, _) => { return Err(LayoutError::NotImplemented) } + TyKind::Error => return Err(LayoutError::HasErrorType), TyKind::AssociatedType(_, _) - | TyKind::Error | TyKind::Alias(_) | TyKind::Placeholder(_) | TyKind::BoundVar(_) | TyKind::InferenceVar(_, _) => return Err(LayoutError::HasPlaceholder), - }) + }; + Ok(Arc::new(result)) +} + +pub fn layout_of_ty_recover( + _: &dyn HirDatabase, + _: &[String], + _: &Ty, + _: &CrateId, +) -> Result, LayoutError> { + user_error!("infinite sized recursive type"); } fn layout_of_unit(cx: &LayoutCx<'_>, dl: &TargetDataLayout) -> Result { @@ -274,5 +332,13 @@ fn field_ty( db.field_types(def)[fd].clone().substitute(Interner, subst) } +fn scalar_unit(dl: &TargetDataLayout, value: Primitive) -> Scalar { + Scalar::Initialized { value, valid_range: WrappingRange::full(value.size(dl)) } +} + +fn scalar(dl: &TargetDataLayout, value: Primitive) -> Layout { + Layout::scalar(dl, scalar_unit(dl, value)) +} + #[cfg(test)] mod tests; diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs index b22d0fe8ded11..bd2752a7119ab 100644 --- a/crates/hir-ty/src/layout/adt.rs +++ b/crates/hir-ty/src/layout/adt.rs @@ -1,18 +1,25 @@ //! Compute the binary representation of structs, unions and enums -use std::ops::Bound; +use std::{cmp, ops::Bound}; +use base_db::CrateId; use hir_def::{ - adt::VariantData, - layout::{Integer, IntegerExt, Layout, LayoutCalculator, LayoutError, RustcEnumVariantIdx}, - AdtId, EnumVariantId, HasModule, LocalEnumVariantId, VariantId, + data::adt::VariantData, + layout::{Integer, LayoutCalculator, ReprOptions, TargetDataLayout}, + AdtId, EnumVariantId, LocalEnumVariantId, VariantId, }; use la_arena::RawIdx; use smallvec::SmallVec; +use triomphe::Arc; -use crate::{db::HirDatabase, lang_items::is_unsafe_cell, layout::field_ty, Substitution}; +use crate::{ + db::HirDatabase, + lang_items::is_unsafe_cell, + layout::{field_ty, Layout, LayoutError, RustcEnumVariantIdx}, + Substitution, +}; -use super::{layout_of_ty, LayoutCx}; +use super::LayoutCx; pub(crate) fn struct_variant_idx() -> RustcEnumVariantIdx { RustcEnumVariantIdx(LocalEnumVariantId::from_raw(RawIdx::from(0))) @@ -22,29 +29,29 @@ pub fn layout_of_adt_query( db: &dyn HirDatabase, def: AdtId, subst: Substitution, -) -> Result { - let krate = def.module(db.upcast()).krate(); + krate: CrateId, +) -> Result, LayoutError> { let Some(target) = db.target_data_layout(krate) else { return Err(LayoutError::TargetLayoutNotAvailable) }; let cx = LayoutCx { krate, target: &target }; let dl = cx.current_data_layout(); let handle_variant = |def: VariantId, var: &VariantData| { var.fields() .iter() - .map(|(fd, _)| layout_of_ty(db, &field_ty(db, def, fd, &subst), cx.krate)) + .map(|(fd, _)| db.layout_of_ty(field_ty(db, def, fd, &subst), cx.krate)) .collect::, _>>() }; - let (variants, is_enum, is_union, repr) = match def { + let (variants, repr) = match def { AdtId::StructId(s) => { let data = db.struct_data(s); let mut r = SmallVec::<[_; 1]>::new(); r.push(handle_variant(s.into(), &data.variant_data)?); - (r, false, false, data.repr.unwrap_or_default()) + (r, data.repr.unwrap_or_default()) } AdtId::UnionId(id) => { let data = db.union_data(id); let mut r = SmallVec::new(); r.push(handle_variant(id.into(), &data.variant_data)?); - (r, false, true, data.repr.unwrap_or_default()) + (r, data.repr.unwrap_or_default()) } AdtId::EnumId(e) => { let data = db.enum_data(e); @@ -58,22 +65,24 @@ pub fn layout_of_adt_query( ) }) .collect::, _>>()?; - (r, true, false, data.repr.unwrap_or_default()) + (r, data.repr.unwrap_or_default()) } }; - let variants = - variants.iter().map(|x| x.iter().collect::>()).collect::>(); + let variants = variants + .iter() + .map(|x| x.iter().map(|x| &**x).collect::>()) + .collect::>(); let variants = variants.iter().map(|x| x.iter().collect()).collect(); - if is_union { - cx.layout_of_union(&repr, &variants).ok_or(LayoutError::Unknown) + let result = if matches!(def, AdtId::UnionId(..)) { + cx.layout_of_union(&repr, &variants).ok_or(LayoutError::Unknown)? } else { cx.layout_of_struct_or_enum( &repr, &variants, - is_enum, - is_unsafe_cell(def, db), + matches!(def, AdtId::EnumId(..)), + is_unsafe_cell(db, def), layout_scalar_valid_range(db, def), - |min, max| Integer::repr_discr(&dl, &repr, min, max).unwrap_or((Integer::I8, false)), + |min, max| repr_discr(&dl, &repr, min, max).unwrap_or((Integer::I8, false)), variants.iter_enumerated().filter_map(|(id, _)| { let AdtId::EnumId(e) = def else { return None }; let d = @@ -90,15 +99,16 @@ pub fn layout_of_adt_query( // .iter_enumerated() // .any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32())) repr.inhibit_enum_layout_opt(), - !is_enum + !matches!(def, AdtId::EnumId(..)) && variants .iter() .next() .and_then(|x| x.last().map(|x| x.is_unsized())) .unwrap_or(true), ) - .ok_or(LayoutError::SizeOverflow) - } + .ok_or(LayoutError::SizeOverflow)? + }; + Ok(Arc::new(result)) } fn layout_scalar_valid_range(db: &dyn HirDatabase, def: AdtId) -> (Bound, Bound) { @@ -122,6 +132,54 @@ pub fn layout_of_adt_recover( _: &[String], _: &AdtId, _: &Substitution, -) -> Result { + _: &CrateId, +) -> Result, LayoutError> { user_error!("infinite sized recursive type"); } + +/// Finds the appropriate Integer type and signedness for the given +/// signed discriminant range and `#[repr]` attribute. +/// N.B.: `u128` values above `i128::MAX` will be treated as signed, but +/// that shouldn't affect anything, other than maybe debuginfo. +fn repr_discr( + dl: &TargetDataLayout, + repr: &ReprOptions, + min: i128, + max: i128, +) -> Result<(Integer, bool), LayoutError> { + // Theoretically, negative values could be larger in unsigned representation + // than the unsigned representation of the signed minimum. However, if there + // are any negative values, the only valid unsigned representation is u128 + // which can fit all i128 values, so the result remains unaffected. + let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u128, max as u128)); + let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max)); + + if let Some(ity) = repr.int { + let discr = Integer::from_attr(dl, ity); + let fit = if ity.is_signed() { signed_fit } else { unsigned_fit }; + if discr < fit { + return Err(LayoutError::UserError( + "Integer::repr_discr: `#[repr]` hint too small for \ + discriminant range of enum " + .to_string(), + )); + } + return Ok((discr, ity.is_signed())); + } + + let at_least = if repr.c() { + // This is usually I32, however it can be different on some platforms, + // notably hexagon and arm-none/thumb-none + dl.c_enum_min_size + } else { + // repr(Rust) enums try to be as small as possible + Integer::I8 + }; + + // If there are no negative values, we can use the unsigned fit. + Ok(if min >= 0 { + (cmp::max(unsigned_fit, at_least), false) + } else { + (cmp::max(signed_fit, at_least), true) + }) +} diff --git a/crates/hir-ty/src/layout/target.rs b/crates/hir-ty/src/layout/target.rs index adfae0a1abb38..04b940afbe8f8 100644 --- a/crates/hir-ty/src/layout/target.rs +++ b/crates/hir-ty/src/layout/target.rs @@ -1,9 +1,8 @@ //! Target dependent parameters needed for layouts -use std::sync::Arc; - use base_db::CrateId; use hir_def::layout::TargetDataLayout; +use triomphe::Arc; use crate::db::HirDatabase; diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs index a8971fde3c21e..fca2e09ff0a99 100644 --- a/crates/hir-ty/src/layout/tests.rs +++ b/crates/hir-ty/src/layout/tests.rs @@ -2,49 +2,55 @@ use std::collections::HashMap; use base_db::fixture::WithFixture; use chalk_ir::{AdtId, TyKind}; -use hir_def::{ - db::DefDatabase, +use hir_def::db::DefDatabase; +use triomphe::Arc; + +use crate::{ + db::HirDatabase, layout::{Layout, LayoutError}, + test_db::TestDB, + Interner, Substitution, }; -use crate::{db::HirDatabase, test_db::TestDB, Interner, Substitution}; - -use super::layout_of_ty; +mod closure; fn current_machine_data_layout() -> String { project_model::target_data_layout::get(None, None, &HashMap::default()).unwrap() } -fn eval_goal(ra_fixture: &str, minicore: &str) -> Result { +fn eval_goal(ra_fixture: &str, minicore: &str) -> Result, LayoutError> { let target_data_layout = current_machine_data_layout(); let ra_fixture = format!( "{minicore}//- /main.rs crate:test target_data_layout:{target_data_layout}\n{ra_fixture}", ); - let (db, file_id) = TestDB::with_single_file(&ra_fixture); - let module_id = db.module_for_file(file_id); - let def_map = module_id.def_map(&db); - let scope = &def_map[module_id.local_id].scope; - let adt_id = scope - .declarations() - .find_map(|x| match x { - hir_def::ModuleDefId::AdtId(x) => { - let name = match x { - hir_def::AdtId::StructId(x) => db.struct_data(x).name.to_smol_str(), - hir_def::AdtId::UnionId(x) => db.union_data(x).name.to_smol_str(), - hir_def::AdtId::EnumId(x) => db.enum_data(x).name.to_smol_str(), - }; - (name == "Goal").then_some(x) - } - _ => None, + let (db, file_ids) = TestDB::with_many_files(&ra_fixture); + let (adt_id, module_id) = file_ids + .into_iter() + .find_map(|file_id| { + let module_id = db.module_for_file(file_id); + let def_map = module_id.def_map(&db); + let scope = &def_map[module_id.local_id].scope; + let adt_id = scope.declarations().find_map(|x| match x { + hir_def::ModuleDefId::AdtId(x) => { + let name = match x { + hir_def::AdtId::StructId(x) => db.struct_data(x).name.to_smol_str(), + hir_def::AdtId::UnionId(x) => db.union_data(x).name.to_smol_str(), + hir_def::AdtId::EnumId(x) => db.enum_data(x).name.to_smol_str(), + }; + (name == "Goal").then_some(x) + } + _ => None, + })?; + Some((adt_id, module_id)) }) .unwrap(); let goal_ty = TyKind::Adt(AdtId(adt_id), Substitution::empty(Interner)).intern(Interner); - layout_of_ty(&db, &goal_ty, module_id.krate()) + db.layout_of_ty(goal_ty, module_id.krate()) } /// A version of `eval_goal` for types that can not be expressed in ADTs, like closures and `impl Trait` -fn eval_expr(ra_fixture: &str, minicore: &str) -> Result { +fn eval_expr(ra_fixture: &str, minicore: &str) -> Result, LayoutError> { let target_data_layout = current_machine_data_layout(); let ra_fixture = format!( "{minicore}//- /main.rs crate:test target_data_layout:{target_data_layout}\nfn main(){{let goal = {{{ra_fixture}}};}}", @@ -68,7 +74,7 @@ fn eval_expr(ra_fixture: &str, minicore: &str) -> Result { let b = hir_body.bindings.iter().find(|x| x.1.name.to_smol_str() == "goal").unwrap().0; let infer = db.infer(adt_id.into()); let goal_ty = infer.type_of_binding[b].clone(); - layout_of_ty(&db, &goal_ty, module_id.krate()) + db.layout_of_ty(goal_ty, module_id.krate()) } #[track_caller] @@ -81,8 +87,8 @@ fn check_size_and_align(ra_fixture: &str, minicore: &str, size: u64, align: u64) #[track_caller] fn check_size_and_align_expr(ra_fixture: &str, minicore: &str, size: u64, align: u64) { let l = eval_expr(ra_fixture, minicore).unwrap(); - assert_eq!(l.size.bytes(), size); - assert_eq!(l.align.abi.bytes(), align); + assert_eq!(l.size.bytes(), size, "size mismatch"); + assert_eq!(l.align.abi.bytes(), align, "align mismatch"); } #[track_caller] @@ -118,13 +124,31 @@ macro_rules! size_and_align { }; } +#[macro_export] macro_rules! size_and_align_expr { + (minicore: $($x:tt),*; stmts: [$($s:tt)*] $($t:tt)*) => { + { + #[allow(dead_code)] + #[allow(unused_must_use)] + #[allow(path_statements)] + { + $($s)* + let val = { $($t)* }; + $crate::layout::tests::check_size_and_align_expr( + &format!("{{ {} let val = {{ {} }}; val }}", stringify!($($s)*), stringify!($($t)*)), + &format!("//- minicore: {}\n", stringify!($($x),*)), + ::std::mem::size_of_val(&val) as u64, + ::std::mem::align_of_val(&val) as u64, + ); + } + } + }; ($($t:tt)*) => { { #[allow(dead_code)] { let val = { $($t)* }; - check_size_and_align_expr( + $crate::layout::tests::check_size_and_align_expr( stringify!($($t)*), "", ::std::mem::size_of_val(&val) as u64, @@ -196,6 +220,44 @@ fn generic() { } } +#[test] +fn associated_types() { + size_and_align! { + trait Tr { + type Ty; + } + + impl Tr for i32 { + type Ty = i64; + } + + struct Foo(::Ty); + struct Bar(A::Ty); + struct Goal(Foo, Bar, ::Ty); + } + check_size_and_align( + r#" +//- /b/mod.rs crate:b +pub trait Tr { + type Ty; +} +pub struct Foo(::Ty); + +//- /a/mod.rs crate:a deps:b +use b::{Tr, Foo}; + +struct S; +impl Tr for S { + type Ty = i64; +} +struct Goal(Foo); + "#, + "", + 8, + 8, + ); +} + #[test] fn return_position_impl_trait() { size_and_align_expr! { @@ -212,6 +274,45 @@ fn return_position_impl_trait() { fn foo() -> (impl T, impl T, impl T) { (2i64, 5i32, 7i32) } foo() } + size_and_align_expr! { + minicore: iterators; + stmts: [] + trait Tr {} + impl Tr for i32 {} + fn foo() -> impl Iterator { + [1, 2, 3].into_iter() + } + let mut iter = foo(); + let item = iter.next(); + (iter, item) + } + size_and_align_expr! { + minicore: future; + stmts: [] + use core::{future::Future, task::{Poll, Context}, pin::pin}; + use std::{task::Wake, sync::Arc}; + trait Tr {} + impl Tr for i32 {} + async fn f() -> impl Tr { + 2 + } + fn unwrap_fut(inp: impl Future) -> Poll { + // In a normal test we could use `loop {}` or `panic!()` here, + // but rustc actually runs this code. + let pinned = pin!(inp); + struct EmptyWaker; + impl Wake for EmptyWaker { + fn wake(self: Arc) { + } + } + let waker = Arc::new(EmptyWaker).into(); + let mut context = Context::from_waker(&waker); + let x = pinned.poll(&mut context); + x + } + let x = unwrap_fut(f()); + x + } size_and_align_expr! { struct Foo(T, T, (T, T)); trait T {} @@ -276,6 +377,14 @@ fn niche_optimization() { } } +#[test] +fn const_eval() { + size_and_align! { + const X: usize = 5; + struct Goal([i32; X]); + } +} + #[test] fn enums_with_discriminants() { size_and_align! { diff --git a/crates/hir-ty/src/layout/tests/closure.rs b/crates/hir-ty/src/layout/tests/closure.rs new file mode 100644 index 0000000000000..576e7f3fc619c --- /dev/null +++ b/crates/hir-ty/src/layout/tests/closure.rs @@ -0,0 +1,257 @@ +use crate::size_and_align_expr; + +#[test] +fn zero_capture_simple() { + size_and_align_expr! { + |x: i32| x + 2 + } +} + +#[test] +fn move_simple() { + size_and_align_expr! { + minicore: copy; + stmts: [] + let y: i32 = 5; + move |x: i32| { + x + y + } + } +} + +#[test] +fn ref_simple() { + size_and_align_expr! { + minicore: copy; + stmts: [ + let y: i32 = 5; + ] + |x: i32| { + x + y + } + } + size_and_align_expr! { + minicore: copy; + stmts: [ + let mut y: i32 = 5; + ] + |x: i32| { + y = y + x; + y + } + } + size_and_align_expr! { + minicore: copy, deref_mut; + stmts: [ + let y: &mut i32 = &mut 5; + ] + |x: i32| { + *y += x; + } + } + size_and_align_expr! { + minicore: copy; + stmts: [ + struct X(i32, i64); + let x: X = X(2, 6); + ] + || { + x + } + } + size_and_align_expr! { + minicore: copy, deref_mut; + stmts: [ + struct X(i32, i64); + let x: &mut X = &mut X(2, 6); + ] + || { + (*x).0 as i64 + x.1 + } + } +} + +#[test] +fn ref_then_mut_then_move() { + size_and_align_expr! { + minicore: copy; + stmts: [ + struct X(i32, i64); + let mut x: X = X(2, 6); + ] + || { + &x; + &mut x; + x; + } + } +} + +#[test] +fn nested_closures() { + size_and_align_expr! { + || { + || { + || { + let x = 2; + move || { + move || { + x + } + } + } + } + } + } +} + +#[test] +fn capture_specific_fields2() { + size_and_align_expr! { + minicore: copy; + stmts: [ + let x = &mut 2; + ] + || { + *x = 5; + &x; + } + } +} + +#[test] +fn capture_specific_fields() { + size_and_align_expr! { + struct X(i64, i32, (u8, i128)); + let y: X = X(2, 5, (7, 3)); + move |x: i64| { + y.0 + x + (y.2 .0 as i64) + } + } + size_and_align_expr! { + struct X(i64, i32, (u8, i128)); + let y: X = X(2, 5, (7, 3)); + move |x: i64| { + let _ = &y; + y.0 + x + (y.2 .0 as i64) + } + } + size_and_align_expr! { + minicore: copy; + stmts: [ + struct X(i64, i32, (u8, i128)); + let y: X = X(2, 5, (7, 3)); + ] + let y = &y; + move |x: i64| { + y.0 + x + (y.2 .0 as i64) + } + } + size_and_align_expr! { + struct X(i64, i32, (u8, i128)); + let y: X = X(2, 5, (7, 3)); + move |x: i64| { + let X(a, _, (b, _)) = y; + a + x + (b as i64) + } + } + size_and_align_expr! { + struct X(i64, i32, (u8, i128)); + let y = &&X(2, 5, (7, 3)); + move |x: i64| { + let X(a, _, (b, _)) = y; + *a + x + (*b as i64) + } + } + size_and_align_expr! { + struct X(i64, i32, (u8, i128)); + let y: X = X(2, 5, (7, 3)); + move |x: i64| { + match y { + X(a, _, (b, _)) => a + x + (b as i64), + } + } + } + size_and_align_expr! { + struct X(i64, i32, (u8, i128)); + let y: X = X(2, 5, (7, 3)); + move |x: i64| { + let X(a @ 2, _, (b, _)) = y else { return 5 }; + a + x + (b as i64) + } + } +} + +#[test] +fn match_pattern() { + size_and_align_expr! { + struct X(i64, i32, (u8, i128)); + let y: X = X(2, 5, (7, 3)); + move |x: i64| { + match y { + _ => x, + } + } + } + size_and_align_expr! { + minicore: copy; + stmts: [ + struct X(i64, i32, (u8, i128)); + let y: X = X(2, 5, (7, 3)); + ] + |x: i64| { + match y { + X(_a, _, _c) => x, + } + } + } + size_and_align_expr! { + minicore: copy; + stmts: [ + struct X(i64, i32, (u8, i128)); + let y: X = X(2, 5, (7, 3)); + ] + |x: i64| { + match y { + _y => x, + } + } + } + size_and_align_expr! { + minicore: copy; + stmts: [ + struct X(i64, i32, (u8, i128)); + let y: X = X(2, 5, (7, 3)); + ] + |x: i64| { + match y { + ref _y => x, + } + } + } +} + +#[test] +fn ellipsis_pattern() { + size_and_align_expr! { + struct X(i8, u16, i32, u64, i128, u8); + let y: X = X(1, 2, 3, 4, 5, 6); + move |_: i64| { + let X(_a, .., _b, _c) = y; + } + } + size_and_align_expr! { + struct X { a: i32, b: u8, c: i128} + let y: X = X { a: 1, b: 2, c: 3 }; + move |_: i64| { + let X { a, b, .. } = y; + _ = (a, b); + } + } + size_and_align_expr! { + let y: (&&&(i8, u16, i32, u64, i128, u8), u16, i32, u64, i128, u8) = (&&&(1, 2, 3, 4, 5, 6), 2, 3, 4, 5, 6); + move |_: i64| { + let ((_a, .., _b, _c), .., _e, _f) = y; + } + } +} diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 9c63d67ab19a4..1a4d003bf5e99 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -1,6 +1,5 @@ //! The type system. We currently use this to infer types for completion, hover //! information and various assists. - #![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] #[allow(unused)] @@ -8,12 +7,9 @@ macro_rules! eprintln { ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; } -mod autoderef; mod builder; mod chalk_db; mod chalk_ext; -pub mod consteval; -pub mod mir; mod infer; mod inhabitedness; mod interner; @@ -21,21 +17,28 @@ mod lower; mod mapping; mod tls; mod utils; + +pub mod autoderef; +pub mod consteval; pub mod db; pub mod diagnostics; pub mod display; +pub mod lang_items; +pub mod layout; pub mod method_resolution; +pub mod mir; pub mod primitive; pub mod traits; -pub mod layout; -pub mod lang_items; #[cfg(test)] mod tests; #[cfg(test)] mod test_db; -use std::{collections::HashMap, hash::Hash, sync::Arc}; +use std::{ + collections::{hash_map::Entry, HashMap}, + hash::Hash, +}; use chalk_ir::{ fold::{Shift, TypeFoldable}, @@ -44,12 +47,13 @@ use chalk_ir::{ NoSolution, TyData, }; use either::Either; -use hir_def::{expr::ExprId, type_ref::Rawness, TypeOrConstParamId}; +use hir_def::{hir::ExprId, type_ref::Rawness, GeneralConstId, TypeOrConstParamId}; use hir_expand::name; use la_arena::{Arena, Idx}; -use mir::MirEvalError; +use mir::{MirEvalError, VTableMap}; use rustc_hash::FxHashSet; use traits::FnTrait; +use triomphe::Arc; use utils::Generics; use crate::{ @@ -60,6 +64,7 @@ pub use autoderef::autoderef; pub use builder::{ParamKind, TyBuilder}; pub use chalk_ext::*; pub use infer::{ + closure::{CaptureKind, CapturedItem}, could_coerce, could_unify, Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic, InferenceResult, OverloadedDeref, PointerCast, }; @@ -148,14 +153,26 @@ pub type Guidance = chalk_solve::Guidance; pub type WhereClause = chalk_ir::WhereClause; /// A constant can have reference to other things. Memory map job is holding -/// the neccessary bits of memory of the const eval session to keep the constant +/// the necessary bits of memory of the const eval session to keep the constant /// meaningful. #[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct MemoryMap(pub HashMap>); +pub struct MemoryMap { + pub memory: HashMap>, + pub vtable: VTableMap, +} impl MemoryMap { fn insert(&mut self, addr: usize, x: Vec) { - self.0.insert(addr, x); + match self.memory.entry(addr) { + Entry::Occupied(mut e) => { + if e.get().len() < x.len() { + e.insert(x); + } + } + Entry::Vacant(e) => { + e.insert(x); + } + } } /// This functions convert each address by a function `f` which gets the byte intervals and assign an address @@ -165,7 +182,15 @@ impl MemoryMap { &self, mut f: impl FnMut(&[u8]) -> Result, ) -> Result, MirEvalError> { - self.0.iter().map(|x| Ok((*x.0, f(x.1)?))).collect() + self.memory.iter().map(|x| Ok((*x.0, f(x.1)?))).collect() + } + + fn get<'a>(&'a self, addr: usize, size: usize) -> Option<&'a [u8]> { + if size == 0 { + Some(&[]) + } else { + self.memory.get(&addr)?.get(0..size) + } } } @@ -173,6 +198,9 @@ impl MemoryMap { #[derive(Debug, Clone, PartialEq, Eq)] pub enum ConstScalar { Bytes(Vec, MemoryMap), + // FIXME: this is a hack to get around chalk not being able to represent unevaluatable + // constants + UnevaluatedConst(GeneralConstId, Substitution), /// Case of an unknown value that rustc might know but we don't // FIXME: this is a hack to get around chalk not being able to represent unevaluatable // constants @@ -283,16 +311,19 @@ impl CallableSig { pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig { CallableSig { // FIXME: what to do about lifetime params? -> return PolyFnSig - params_and_return: fn_ptr - .substitution - .clone() - .shifted_out_to(Interner, DebruijnIndex::ONE) - .expect("unexpected lifetime vars in fn ptr") - .0 - .as_slice(Interner) - .iter() - .map(|arg| arg.assert_ty_ref(Interner).clone()) - .collect(), + // FIXME: use `Arc::from_iter` when it becomes available + params_and_return: Arc::from( + fn_ptr + .substitution + .clone() + .shifted_out_to(Interner, DebruijnIndex::ONE) + .expect("unexpected lifetime vars in fn ptr") + .0 + .as_slice(Interner) + .iter() + .map(|arg| arg.assert_ty_ref(Interner).clone()) + .collect::>(), + ), is_varargs: fn_ptr.sig.variadic, safety: fn_ptr.sig.safety, } @@ -576,15 +607,19 @@ where } pub fn callable_sig_from_fnonce( - self_ty: &Ty, + mut self_ty: &Ty, env: Arc, db: &dyn HirDatabase, ) -> Option { + if let Some((ty, _, _)) = self_ty.as_reference() { + // This will happen when it implements fn or fn mut, since we add a autoborrow adjustment + self_ty = ty; + } let krate = env.krate; let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?; let output_assoc_type = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?; - let mut table = InferenceTable::new(db, env.clone()); + let mut table = InferenceTable::new(db, env); let b = TyBuilder::trait_ref(db, fn_once_trait); if b.remaining() != 2 { return None; diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 23b15087e3165..0c68891fe4932 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -8,7 +8,6 @@ use std::{ cell::{Cell, RefCell, RefMut}, iter, - sync::Arc, }; use base_db::CrateId; @@ -18,19 +17,20 @@ use chalk_ir::{ use either::Either; use hir_def::{ - adt::StructKind, - body::{Expander, LowerCtx}, builtin_type::BuiltinType, + data::adt::StructKind, + expander::Expander, generics::{ TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, }, lang_item::{lang_attr, LangItem}, - path::{GenericArg, ModPath, Path, PathKind, PathSegment, PathSegments}, + nameres::MacroSubNs, + path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{ConstRefOrPath, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef}, - AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, - HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, StaticId, StructId, - TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId, + AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, + GenericDefId, HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, StaticId, + StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId, }; use hir_expand::{name::Name, ExpandResult}; use intern::Interned; @@ -39,6 +39,7 @@ use rustc_hash::FxHashSet; use smallvec::SmallVec; use stdx::{impl_from, never}; use syntax::ast; +use triomphe::Arc; use crate::{ all_super_traits, @@ -103,7 +104,7 @@ impl ImplTraitLoweringState { #[derive(Debug)] pub struct TyLoweringContext<'a> { pub db: &'a dyn HirDatabase, - pub resolver: &'a Resolver, + resolver: &'a Resolver, in_binders: DebruijnIndex, /// Note: Conceptually, it's thinkable that we could be in a location where /// some type params should be represented as placeholders, and others @@ -378,10 +379,19 @@ impl<'a> TyLoweringContext<'a> { }; let ty = { let macro_call = macro_call.to_node(self.db.upcast()); - match expander.enter_expand::(self.db.upcast(), macro_call) { + let resolver = |path| { + self.resolver.resolve_path_as_macro( + self.db.upcast(), + &path, + Some(MacroSubNs::Bang), + ) + }; + match expander.enter_expand::(self.db.upcast(), macro_call, resolver) + { Ok(ExpandResult { value: Some((mark, expanded)), .. }) => { - let ctx = LowerCtx::new(self.db.upcast(), expander.current_file_id()); - let type_ref = TypeRef::from_ast(&ctx, expanded); + let ctx = expander.ctx(self.db.upcast()); + // FIXME: Report syntax errors in expansion here + let type_ref = TypeRef::from_ast(&ctx, expanded.tree()); drop(expander); let ty = self.lower_ty(&type_ref); @@ -425,11 +435,10 @@ impl<'a> TyLoweringContext<'a> { if path.segments().len() > 1 { return None; } - let resolution = - match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) { - Some((it, None)) => it, - _ => return None, - }; + let resolution = match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path) { + Some((it, None)) => it, + _ => return None, + }; match resolution { TypeNs::GenericParam(param_id) => Some(param_id.into()), _ => None, @@ -608,7 +617,7 @@ impl<'a> TyLoweringContext<'a> { } let (resolution, remaining_index) = - match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) { + match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path) { Some(it) => it, None => return (TyKind::Error.intern(Interner), None), }; @@ -716,7 +725,7 @@ impl<'a> TyLoweringContext<'a> { resolved: ValueTyDefId, infer_args: bool, ) -> Substitution { - let last = path.segments().last().expect("path should have at least one segment"); + let last = path.segments().last(); let (segment, generic_def) = match resolved { ValueTyDefId::FunctionId(it) => (last, Some(it.into())), ValueTyDefId::StructId(it) => (last, Some(it.into())), @@ -732,13 +741,20 @@ impl<'a> TyLoweringContext<'a> { let len = path.segments().len(); let penultimate = len.checked_sub(2).and_then(|idx| path.segments().get(idx)); let segment = match penultimate { - Some(segment) if segment.args_and_bindings.is_some() => segment, + Some(segment) if segment.args_and_bindings.is_some() => Some(segment), _ => last, }; (segment, Some(var.parent.into())) } }; - self.substs_from_path_segment(segment, generic_def, infer_args, None) + if let Some(segment) = segment { + self.substs_from_path_segment(segment, generic_def, infer_args, None) + } else if let Some(generic_def) = generic_def { + // lang item + self.substs_from_args_and_bindings(None, Some(generic_def), infer_args, None) + } else { + Substitution::empty(Interner) + } } fn substs_from_path_segment( @@ -747,6 +763,21 @@ impl<'a> TyLoweringContext<'a> { def: Option, infer_args: bool, explicit_self_ty: Option, + ) -> Substitution { + self.substs_from_args_and_bindings( + segment.args_and_bindings, + def, + infer_args, + explicit_self_ty, + ) + } + + fn substs_from_args_and_bindings( + &self, + args_and_bindings: Option<&GenericArgs>, + def: Option, + infer_args: bool, + explicit_self_ty: Option, ) -> Substitution { // Remember that the item's own generic args come before its parent's. let mut substs = Vec::new(); @@ -780,7 +811,7 @@ impl<'a> TyLoweringContext<'a> { }; let mut had_explicit_args = false; - if let Some(generic_args) = &segment.args_and_bindings { + if let Some(generic_args) = &args_and_bindings { if !generic_args.has_self_type { fill_self_params(); } @@ -879,12 +910,11 @@ impl<'a> TyLoweringContext<'a> { path: &Path, explicit_self_ty: Option, ) -> Option { - let resolved = - match self.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path.mod_path())? { - // FIXME(trait_alias): We need to handle trait alias here. - TypeNs::TraitId(tr) => tr, - _ => return None, - }; + let resolved = match self.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path)? { + // FIXME(trait_alias): We need to handle trait alias here. + TypeNs::TraitId(tr) => tr, + _ => return None, + }; let segment = path.segments().last().expect("path should have at least one segment"); Some(self.lower_trait_ref_from_resolved_path(resolved, segment, explicit_self_ty)) } @@ -968,7 +998,7 @@ impl<'a> TyLoweringContext<'a> { // ignore `T: Drop` or `T: Destruct` bounds. // - `T: ~const Drop` has a special meaning in Rust 1.61 that we don't implement. // (So ideally, we'd only ignore `~const Drop` here) - // - `Destruct` impls are built-in in 1.62 (current nightlies as of 08-04-2022), so until + // - `Destruct` impls are built-in in 1.62 (current nightly as of 08-04-2022), so until // the builtin impls are supported by Chalk, we ignore them here. if let Some(lang) = lang_attr(self.db.upcast(), tr.hir_trait_id()) { if matches!(lang, LangItem::Drop | LangItem::Destruct) { @@ -1062,23 +1092,23 @@ impl<'a> TyLoweringContext<'a> { associated_ty_id: to_assoc_type_id(associated_ty), substitution, }; - let mut preds: SmallVec<[_; 1]> = SmallVec::with_capacity( + let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity( binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), ); if let Some(type_ref) = &binding.type_ref { let ty = self.lower_ty(type_ref); let alias_eq = AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty }; - preds.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq))); + predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq))); } for bound in binding.bounds.iter() { - preds.extend(self.lower_type_bound( + predicates.extend(self.lower_type_bound( bound, TyKind::Alias(AliasTy::Projection(projection_ty.clone())).intern(Interner), false, )); } - preds + predicates }) } @@ -1145,7 +1175,7 @@ impl<'a> TyLoweringContext<'a> { return None; } - // As multiple occurrences of the same auto traits *are* permitted, we dedulicate the + // As multiple occurrences of the same auto traits *are* permitted, we deduplicate the // bounds. We shouldn't have repeated elements besides auto traits at this point. bounds.dedup(); @@ -1381,9 +1411,7 @@ pub(crate) fn generic_predicates_for_param_query( Some(it) => it, None => return true, }; - let tr = match resolver - .resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()) - { + let tr = match resolver.resolve_path_in_type_ns_fully(db.upcast(), path) { Some(TypeNs::TraitId(tr)) => tr, _ => return false, }; @@ -1420,7 +1448,19 @@ pub(crate) fn generic_predicates_for_param_recover( _param_id: &TypeOrConstParamId, _assoc_name: &Option, ) -> Arc<[Binders]> { - Arc::new([]) + // FIXME: use `Arc::from_iter` when it becomes available + Arc::from(vec![]) +} + +pub(crate) fn trait_environment_for_body_query( + db: &dyn HirDatabase, + def: DefWithBodyId, +) -> Arc { + let Some(def) = def.as_generic_def_id() else { + let krate = def.module(db.upcast()).krate(); + return Arc::new(TraitEnvironment::empty(krate)); + }; + db.trait_environment(def) } pub(crate) fn trait_environment_query( @@ -1478,7 +1518,7 @@ pub(crate) fn trait_environment_query( let env = chalk_ir::Environment::new(Interner).add_clauses(Interner, clauses); - Arc::new(TraitEnvironment { krate, traits_from_clauses: traits_in_scope, env }) + Arc::new(TraitEnvironment { krate, block: None, traits_from_clauses: traits_in_scope, env }) } /// Resolve the where clause(s) of an item with generics. @@ -1547,30 +1587,33 @@ pub(crate) fn generic_defaults_query( let generic_params = generics(db.upcast(), def); let parent_start_idx = generic_params.len_self(); - let defaults = generic_params - .iter() - .enumerate() - .map(|(idx, (id, p))| { - let p = match p { - TypeOrConstParamData::TypeParamData(p) => p, - TypeOrConstParamData::ConstParamData(_) => { - // FIXME: implement const generic defaults - let val = unknown_const_as_generic( - db.const_param_ty(ConstParamId::from_unchecked(id)), - ); - return make_binders(db, &generic_params, val); - } - }; - let mut ty = - p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t)); - - // Each default can only refer to previous parameters. - // Type variable default referring to parameter coming - // after it is forbidden (FIXME: report diagnostic) - ty = fallback_bound_vars(ty, idx, parent_start_idx); - crate::make_binders(db, &generic_params, ty.cast(Interner)) - }) - .collect(); + let defaults = Arc::from( + generic_params + .iter() + .enumerate() + .map(|(idx, (id, p))| { + let p = match p { + TypeOrConstParamData::TypeParamData(p) => p, + TypeOrConstParamData::ConstParamData(_) => { + // FIXME: implement const generic defaults + let val = unknown_const_as_generic( + db.const_param_ty(ConstParamId::from_unchecked(id)), + ); + return make_binders(db, &generic_params, val); + } + }; + let mut ty = + p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t)); + + // Each default can only refer to previous parameters. + // Type variable default referring to parameter coming + // after it is forbidden (FIXME: report diagnostic) + ty = fallback_bound_vars(ty, idx, parent_start_idx); + crate::make_binders(db, &generic_params, ty.cast(Interner)) + }) + // FIXME: use `Arc::from_iter` when it becomes available + .collect::>(), + ); defaults } @@ -1583,18 +1626,21 @@ pub(crate) fn generic_defaults_recover( let generic_params = generics(db.upcast(), *def); // FIXME: this code is not covered in tests. // we still need one default per parameter - let defaults = generic_params - .iter_id() - .map(|id| { - let val = match id { - Either::Left(_) => { - GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner) - } - Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)), - }; - crate::make_binders(db, &generic_params, val) - }) - .collect(); + let defaults = Arc::from( + generic_params + .iter_id() + .map(|id| { + let val = match id { + Either::Left(_) => { + GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner) + } + Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)), + }; + crate::make_binders(db, &generic_params, val) + }) + // FIXME: use `Arc::from_iter` when it becomes available + .collect::>(), + ); defaults } @@ -1605,7 +1651,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { let ctx_params = TyLoweringContext::new(db, &resolver) .with_impl_trait_mode(ImplTraitLoweringMode::Variable) .with_type_param_mode(ParamLoweringMode::Variable); - let params = data.params.iter().map(|(_, tr)| ctx_params.lower_ty(tr)).collect::>(); + let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr)).collect::>(); let ctx_ret = TyLoweringContext::new(db, &resolver) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) .with_type_param_mode(ParamLoweringMode::Variable); @@ -1948,7 +1994,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( // as types. Maybe here is not the best place to do it, but // it works. if let TypeRef::Path(p) = t { - let p = p.mod_path(); + let p = p.mod_path()?; if p.kind == PathKind::Plain { if let [n] = p.segments() { let c = ConstRefOrPath::Path(n.clone()); @@ -1977,8 +2023,16 @@ pub(crate) fn const_or_path_to_chalk( ConstRefOrPath::Scalar(s) => intern_const_ref(db, s, expected_ty, resolver.krate()), ConstRefOrPath::Path(n) => { let path = ModPath::from_segments(PathKind::Plain, Some(n.clone())); - path_to_const(db, resolver, &path, mode, args, debruijn) - .unwrap_or_else(|| unknown_const(expected_ty)) + path_to_const( + db, + resolver, + &Path::from_known_path_with_no_generic(path), + mode, + args, + debruijn, + expected_ty.clone(), + ) + .unwrap_or_else(|| unknown_const(expected_ty)) } } } diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index f3a27632bf545..6fa3d1351a916 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -2,25 +2,28 @@ //! For details about how this works in rustc, see the method lookup page in the //! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html) //! and the corresponding code mostly in rustc_hir_analysis/check/method/probe.rs. -use std::{ops::ControlFlow, sync::Arc}; +use std::ops::ControlFlow; use base_db::{CrateId, Edition}; -use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex}; +use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex, WhereClause}; use hir_def::{ - data::ImplData, item_scope::ItemScope, lang_item::LangItem, nameres::DefMap, AssocItemId, - BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, - ModuleId, TraitId, + data::{adt::StructFlags, ImplData}, + item_scope::ItemScope, + nameres::DefMap, + AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup, + ModuleDefId, ModuleId, TraitId, }; use hir_expand::name::Name; use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::{smallvec, SmallVec}; use stdx::never; +use triomphe::Arc; use crate::{ autoderef::{self, AutoderefKind}, db::HirDatabase, from_chalk_trait_id, from_foreign_def_id, - infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast}, + infer::{unify::InferenceTable, Adjust, Adjustment, OverloadedDeref, PointerCast}, primitive::{FloatTy, IntTy, UintTy}, static_lifetime, to_chalk_trait_id, utils::all_super_traits, @@ -147,31 +150,30 @@ impl TraitImpls { Arc::new(impls) } - pub(crate) fn trait_impls_in_block_query( - db: &dyn HirDatabase, - block: BlockId, - ) -> Option> { + pub(crate) fn trait_impls_in_block_query(db: &dyn HirDatabase, block: BlockId) -> Arc { let _p = profile::span("trait_impls_in_block_query"); let mut impls = Self { map: FxHashMap::default() }; - let block_def_map = db.block_def_map(block)?; + let block_def_map = db.block_def_map(block); impls.collect_def_map(db, &block_def_map); impls.shrink_to_fit(); - Some(Arc::new(impls)) + Arc::new(impls) } - pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc { + pub(crate) fn trait_impls_in_deps_query( + db: &dyn HirDatabase, + krate: CrateId, + ) -> Arc<[Arc]> { let _p = profile::span("trait_impls_in_deps_query").detail(|| format!("{krate:?}")); let crate_graph = db.crate_graph(); - let mut res = Self { map: FxHashMap::default() }; - - for krate in crate_graph.transitive_deps(krate) { - res.merge(&db.trait_impls_in_crate(krate)); - } - res.shrink_to_fit(); - - Arc::new(res) + // FIXME: use `Arc::from_iter` when it becomes available + Arc::from( + crate_graph + .transitive_deps(krate) + .map(|krate| db.trait_impls_in_crate(krate)) + .collect::>(), + ) } fn shrink_to_fit(&mut self) { @@ -185,6 +187,15 @@ impl TraitImpls { fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) { for (_module_id, module_data) in def_map.modules() { for impl_id in module_data.scope.impls() { + // Reservation impls should be ignored during trait resolution, so we never need + // them during type analysis. See rust-lang/rust#64631 for details. + // + // FIXME: Reservation impls should be considered during coherence checks. If we are + // (ever) to implement coherence checks, this filtering should be done by the trait + // solver. + if db.attrs(impl_id.into()).by_key("rustc_reservation_impl").exists() { + continue; + } let target_trait = match db.impl_trait(impl_id) { Some(tr) => tr.skip_binders().hir_trait_id(), None => continue, @@ -210,15 +221,6 @@ impl TraitImpls { } } - fn merge(&mut self, other: &Self) { - for (trait_, other_map) in &other.map { - let map = self.map.entry(*trait_).or_default(); - for (fp, impls) in other_map { - map.entry(*fp).or_default().extend(impls); - } - } - } - /// Queries all trait impls for the given type. pub fn for_self_ty_without_blanket_impls( &self, @@ -271,6 +273,7 @@ pub struct InherentImpls { impl InherentImpls { pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc { + let _p = profile::span("inherent_impls_in_crate_query").detail(|| format!("{krate:?}")); let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() }; let crate_def_map = db.crate_def_map(krate); @@ -280,17 +283,15 @@ impl InherentImpls { Arc::new(impls) } - pub(crate) fn inherent_impls_in_block_query( - db: &dyn HirDatabase, - block: BlockId, - ) -> Option> { + pub(crate) fn inherent_impls_in_block_query(db: &dyn HirDatabase, block: BlockId) -> Arc { + let _p = profile::span("inherent_impls_in_block_query"); let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() }; - if let Some(block_def_map) = db.block_def_map(block) { - impls.collect_def_map(db, &block_def_map); - impls.shrink_to_fit(); - return Some(Arc::new(impls)); - } - None + + let block_def_map = db.block_def_map(block); + impls.collect_def_map(db, &block_def_map); + impls.shrink_to_fit(); + + Arc::new(impls) } fn shrink_to_fit(&mut self) { @@ -404,12 +405,14 @@ pub fn def_crates( match ty.kind(Interner) { &TyKind::Adt(AdtId(def_id), _) => { let rustc_has_incoherent_inherent_impls = match def_id { - hir_def::AdtId::StructId(id) => { - db.struct_data(id).rustc_has_incoherent_inherent_impls - } - hir_def::AdtId::UnionId(id) => { - db.union_data(id).rustc_has_incoherent_inherent_impls - } + hir_def::AdtId::StructId(id) => db + .struct_data(id) + .flags + .contains(StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL), + hir_def::AdtId::UnionId(id) => db + .union_data(id) + .flags + .contains(StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL), hir_def::AdtId::EnumId(id) => db.enum_data(id).rustc_has_incoherent_inherent_impls, }; Some(if rustc_has_incoherent_inherent_impls { @@ -449,55 +452,6 @@ pub fn def_crates( } } -pub fn lang_items_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, LangItem)> { - use hir_expand::name; - use syntax::ast::{ArithOp, BinaryOp, CmpOp, Ordering}; - Some(match op { - BinaryOp::LogicOp(_) => return None, - BinaryOp::ArithOp(aop) => match aop { - ArithOp::Add => (name![add], LangItem::Add), - ArithOp::Mul => (name![mul], LangItem::Mul), - ArithOp::Sub => (name![sub], LangItem::Sub), - ArithOp::Div => (name![div], LangItem::Div), - ArithOp::Rem => (name![rem], LangItem::Rem), - ArithOp::Shl => (name![shl], LangItem::Shl), - ArithOp::Shr => (name![shr], LangItem::Shr), - ArithOp::BitXor => (name![bitxor], LangItem::BitXor), - ArithOp::BitOr => (name![bitor], LangItem::BitOr), - ArithOp::BitAnd => (name![bitand], LangItem::BitAnd), - }, - BinaryOp::Assignment { op: Some(aop) } => match aop { - ArithOp::Add => (name![add_assign], LangItem::AddAssign), - ArithOp::Mul => (name![mul_assign], LangItem::MulAssign), - ArithOp::Sub => (name![sub_assign], LangItem::SubAssign), - ArithOp::Div => (name![div_assign], LangItem::DivAssign), - ArithOp::Rem => (name![rem_assign], LangItem::RemAssign), - ArithOp::Shl => (name![shl_assign], LangItem::ShlAssign), - ArithOp::Shr => (name![shr_assign], LangItem::ShrAssign), - ArithOp::BitXor => (name![bitxor_assign], LangItem::BitXorAssign), - ArithOp::BitOr => (name![bitor_assign], LangItem::BitOrAssign), - ArithOp::BitAnd => (name![bitand_assign], LangItem::BitAndAssign), - }, - BinaryOp::CmpOp(cop) => match cop { - CmpOp::Eq { negated: false } => (name![eq], LangItem::PartialEq), - CmpOp::Eq { negated: true } => (name![ne], LangItem::PartialEq), - CmpOp::Ord { ordering: Ordering::Less, strict: false } => { - (name![le], LangItem::PartialOrd) - } - CmpOp::Ord { ordering: Ordering::Less, strict: true } => { - (name![lt], LangItem::PartialOrd) - } - CmpOp::Ord { ordering: Ordering::Greater, strict: false } => { - (name![ge], LangItem::PartialOrd) - } - CmpOp::Ord { ordering: Ordering::Greater, strict: true } => { - (name![gt], LangItem::PartialOrd) - } - }, - BinaryOp::Assignment { op: None } => return None, - }) -} - /// Look up the method with the given name. pub(crate) fn lookup_method( db: &dyn HirDatabase, @@ -600,9 +554,9 @@ impl ReceiverAdjustments { } } if let Some(m) = self.autoref { - ty = TyKind::Ref(m, static_lifetime(), ty).intern(Interner); - adjust - .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(m)), target: ty.clone() }); + let a = Adjustment::borrow(m, ty); + ty = a.target.clone(); + adjust.push(a); } if self.unsize_array { ty = 'x: { @@ -692,6 +646,39 @@ pub fn lookup_impl_const( .unwrap_or((const_id, subs)) } +/// Checks if the self parameter of `Trait` method is the `dyn Trait` and we should +/// call the method using the vtable. +pub fn is_dyn_method( + db: &dyn HirDatabase, + _env: Arc, + func: FunctionId, + fn_subst: Substitution, +) -> Option { + let ItemContainerId::TraitId(trait_id) = func.lookup(db.upcast()).container else { + return None; + }; + let trait_params = db.generic_params(trait_id.into()).type_or_consts.len(); + let fn_params = fn_subst.len(Interner) - trait_params; + let trait_ref = TraitRef { + trait_id: to_chalk_trait_id(trait_id), + substitution: Substitution::from_iter(Interner, fn_subst.iter(Interner).skip(fn_params)), + }; + let self_ty = trait_ref.self_type_parameter(Interner); + if let TyKind::Dyn(d) = self_ty.kind(Interner) { + let is_my_trait_in_bounds = + d.bounds.skip_binders().as_slice(Interner).iter().any(|x| match x.skip_binders() { + // rustc doesn't accept `impl Foo<2> for dyn Foo<5>`, so if the trait id is equal, no matter + // what the generics are, we are sure that the method is come from the vtable. + WhereClause::Implemented(tr) => tr.trait_id == trait_ref.trait_id, + _ => false, + }); + if is_my_trait_in_bounds { + return Some(fn_params); + } + } + None +} + /// Looks up the impl method that actually runs for the trait method `func`. /// /// Returns `func` if it's not a method defined in a trait or the lookup failed. @@ -701,9 +688,8 @@ pub fn lookup_impl_method( func: FunctionId, fn_subst: Substitution, ) -> (FunctionId, Substitution) { - let trait_id = match func.lookup(db.upcast()).container { - ItemContainerId::TraitId(id) => id, - _ => return (func, fn_subst), + let ItemContainerId::TraitId(trait_id) = func.lookup(db.upcast()).container else { + return (func, fn_subst) }; let trait_params = db.generic_params(trait_id.into()).type_or_consts.len(); let fn_params = fn_subst.len(Interner) - trait_params; @@ -713,7 +699,7 @@ pub fn lookup_impl_method( }; let name = &db.function_data(func).name; - lookup_impl_assoc_item_for_trait_ref(trait_ref, db, env, name) + let Some((impl_fn, impl_subst)) = lookup_impl_assoc_item_for_trait_ref(trait_ref, db, env, name) .and_then(|assoc| { if let (AssocItemId::FunctionId(id), subst) = assoc { Some((id, subst)) @@ -721,7 +707,16 @@ pub fn lookup_impl_method( None } }) - .unwrap_or((func, fn_subst)) + else { + return (func, fn_subst); + }; + ( + impl_fn, + Substitution::from_iter( + Interner, + fn_subst.iter(Interner).take(fn_params).chain(impl_subst.iter(Interner)), + ), + ) } fn lookup_impl_assoc_item_for_trait_ref( @@ -730,10 +725,20 @@ fn lookup_impl_assoc_item_for_trait_ref( env: Arc, name: &Name, ) -> Option<(AssocItemId, Substitution)> { + let hir_trait_id = trait_ref.hir_trait_id(); let self_ty = trait_ref.self_type_parameter(Interner); let self_ty_fp = TyFingerprint::for_trait_impl(&self_ty)?; let impls = db.trait_impls_in_deps(env.krate); - let impls = impls.for_trait_and_self_ty(trait_ref.hir_trait_id(), self_ty_fp); + let self_impls = match self_ty.kind(Interner) { + TyKind::Adt(id, _) => { + id.0.module(db.upcast()).containing_block().map(|x| db.trait_impls_in_block(x)) + } + _ => None, + }; + let impls = impls + .iter() + .chain(self_impls.as_ref()) + .flat_map(|impls| impls.for_trait_and_self_ty(hir_trait_id, self_ty_fp)); let table = InferenceTable::new(db, env); @@ -759,9 +764,8 @@ fn find_matching_impl( actual_trait_ref: TraitRef, ) -> Option<(Arc, Substitution)> { let db = table.db; - loop { - let impl_ = impls.next()?; - let r = table.run_in_snapshot(|table| { + impls.find_map(|impl_| { + table.run_in_snapshot(|table| { let impl_data = db.impl_data(impl_); let impl_substs = TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build(); @@ -778,12 +782,11 @@ fn find_matching_impl( .into_iter() .map(|b| b.cast(Interner)); let goal = crate::Goal::all(Interner, wcs); - table.try_obligation(goal).map(|_| (impl_data, table.resolve_completely(impl_substs))) - }); - if r.is_some() { - break r; - } - } + table.try_obligation(goal.clone())?; + table.register_obligation(goal); + Some((impl_data, table.resolve_completely(impl_substs))) + }) + }) } fn is_inherent_impl_coherent( @@ -824,12 +827,14 @@ fn is_inherent_impl_coherent( | TyKind::Scalar(_) => true, &TyKind::Adt(AdtId(adt), _) => match adt { - hir_def::AdtId::StructId(it) => { - db.struct_data(it).rustc_has_incoherent_inherent_impls - } - hir_def::AdtId::UnionId(it) => { - db.union_data(it).rustc_has_incoherent_inherent_impls - } + hir_def::AdtId::StructId(id) => db + .struct_data(id) + .flags + .contains(StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL), + hir_def::AdtId::UnionId(id) => db + .union_data(id) + .flags + .contains(StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL), hir_def::AdtId::EnumId(it) => db.enum_data(it).rustc_has_incoherent_inherent_impls, }, TyKind::Dyn(it) => it.principal().map_or(false, |trait_ref| { @@ -963,7 +968,14 @@ fn iterate_method_candidates_with_autoref( ) }; - iterate_method_candidates_by_receiver(receiver_ty, first_adjustment.clone())?; + let mut maybe_reborrowed = first_adjustment.clone(); + if let Some((_, _, m)) = receiver_ty.value.as_reference() { + // Prefer reborrow of references to move + maybe_reborrowed.autoref = Some(m); + maybe_reborrowed.autoderefs += 1; + } + + iterate_method_candidates_by_receiver(receiver_ty, maybe_reborrowed)?; let refed = Canonical { value: TyKind::Ref(Mutability::Not, static_lifetime(), receiver_ty.value.clone()) @@ -1108,7 +1120,7 @@ fn iterate_trait_method_candidates( }; if !known_implemented { let goal = generic_implements_goal(db, env.clone(), t, &canonical_self_ty); - if db.trait_solve(env.krate, goal.cast(Interner)).is_none() { + if db.trait_solve(env.krate, env.block, goal.cast(Interner)).is_none() { continue 'traits; } } @@ -1180,23 +1192,19 @@ fn iterate_inherent_methods( }; while let Some(block_id) = block { - if let Some(impls) = db.inherent_impls_in_block(block_id) { - impls_for_self_ty( - &impls, - self_ty, - table, - name, - receiver_ty, - receiver_adjustments.clone(), - module, - callback, - )?; - } + let impls = db.inherent_impls_in_block(block_id); + impls_for_self_ty( + &impls, + self_ty, + table, + name, + receiver_ty, + receiver_adjustments.clone(), + module, + callback, + )?; - block = db - .block_def_map(block_id) - .and_then(|map| map.parent()) - .and_then(|module| module.containing_block()); + block = db.block_def_map(block_id).parent().and_then(|module| module.containing_block()); } for krate in def_crates { @@ -1274,7 +1282,7 @@ fn iterate_inherent_methods( } /// Returns the receiver type for the index trait call. -pub fn resolve_indexing_op( +pub(crate) fn resolve_indexing_op( db: &dyn HirDatabase, env: Arc, ty: Canonical, @@ -1284,8 +1292,11 @@ pub fn resolve_indexing_op( let ty = table.instantiate_canonical(ty); let deref_chain = autoderef_method_receiver(&mut table, ty); for (ty, adj) in deref_chain { - let goal = generic_implements_goal(db, env.clone(), index_trait, &ty); - if db.trait_solve(env.krate, goal.cast(Interner)).is_some() { + let goal = generic_implements_goal(db, table.trait_env.clone(), index_trait, &ty); + if db + .trait_solve(table.trait_env.krate, table.trait_env.block, goal.cast(Interner)) + .is_some() + { return Some(adj); } } @@ -1310,14 +1321,12 @@ fn is_valid_candidate( ) -> IsValidCandidate { let db = table.db; match item { - AssocItemId::FunctionId(m) => { - is_valid_fn_candidate(table, m, name, receiver_ty, self_ty, visible_from_module) + AssocItemId::FunctionId(f) => { + is_valid_fn_candidate(table, f, name, receiver_ty, self_ty, visible_from_module) } AssocItemId::ConstId(c) => { - let data = db.const_data(c); check_that!(receiver_ty.is_none()); - - check_that!(name.map_or(true, |n| data.name.as_ref() == Some(n))); + check_that!(name.map_or(true, |n| db.const_data(c).name.as_ref() == Some(n))); if let Some(from_module) = visible_from_module { if !db.const_visibility(c).is_visible_from(db.upcast(), from_module) { @@ -1441,7 +1450,7 @@ pub fn implements_trait( trait_: TraitId, ) -> bool { let goal = generic_implements_goal(db, env.clone(), trait_, ty); - let solution = db.trait_solve(env.krate, goal.cast(Interner)); + let solution = db.trait_solve(env.krate, env.block, goal.cast(Interner)); solution.is_some() } @@ -1453,7 +1462,7 @@ pub fn implements_trait_unique( trait_: TraitId, ) -> bool { let goal = generic_implements_goal(db, env.clone(), trait_, ty); - let solution = db.trait_solve(env.krate, goal.cast(Interner)); + let solution = db.trait_solve(env.krate, env.block, goal.cast(Interner)); matches!(solution, Some(crate::Solution::Unique(_))) } diff --git a/crates/hir-ty/src/mir.rs b/crates/hir-ty/src/mir.rs index 7c1cbbdf53d27..2345bab0bb4df 100644 --- a/crates/hir-ty/src/mir.rs +++ b/crates/hir-ty/src/mir.rs @@ -3,12 +3,15 @@ use std::{fmt::Display, iter}; use crate::{ - infer::PointerCast, Const, ConstScalar, InferenceResult, Interner, MemoryMap, Substitution, Ty, + consteval::usize_const, db::HirDatabase, display::HirDisplay, infer::PointerCast, + lang_items::is_box, mapping::ToChalk, CallableDefId, ClosureId, Const, ConstScalar, + InferenceResult, Interner, MemoryMap, Substitution, Ty, TyKind, }; +use base_db::CrateId; use chalk_ir::Mutability; use hir_def::{ - expr::{BindingId, Expr, ExprId, Ordering, PatId}, - DefWithBodyId, FieldId, UnionId, VariantId, + hir::{BindingId, Expr, ExprId, Ordering, PatId}, + DefWithBodyId, FieldId, StaticId, UnionId, VariantId, }; use la_arena::{Arena, ArenaMap, Idx, RawIdx}; @@ -16,12 +19,19 @@ mod eval; mod lower; mod borrowck; mod pretty; +mod monomorphization; pub use borrowck::{borrowck_query, BorrowckResult, MutabilityReason}; -pub use eval::{interpret_mir, pad16, Evaluator, MirEvalError}; -pub use lower::{lower_to_mir, mir_body_query, mir_body_recover, MirLowerError}; +pub use eval::{interpret_mir, pad16, Evaluator, MirEvalError, VTableMap}; +pub use lower::{ + lower_to_mir, mir_body_for_closure_query, mir_body_query, mir_body_recover, MirLowerError, +}; +pub use monomorphization::{ + monomorphize_mir_body_bad, monomorphized_mir_body_for_closure_query, + monomorphized_mir_body_query, monomorphized_mir_body_recover, +}; use smallvec::{smallvec, SmallVec}; -use stdx::impl_from; +use stdx::{impl_from, never}; use super::consteval::{intern_const_scalar, try_const_usize}; @@ -32,7 +42,7 @@ fn return_slot() -> LocalId { LocalId::from_raw(RawIdx::from(0)) } -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Local { pub ty: Ty, } @@ -52,7 +62,7 @@ pub struct Local { /// This is what is implemented in miri today. Are these the semantics we want for MIR? Is this /// something we can even decide without knowing more about Rust's memory model? /// -/// **Needs clarifiation:** Is loading a place that has its variant index set well-formed? Miri +/// **Needs clarification:** Is loading a place that has its variant index set well-formed? Miri /// currently implements it, but it seems like this may be something to check against in the /// validator. #[derive(Debug, PartialEq, Eq, Clone)] @@ -73,6 +83,9 @@ pub enum Operand { Move(Place), /// Constants are already semantically values, and remain unchanged. Constant(Const), + /// NON STANDARD: This kind of operand returns an immutable reference to that static memory. Rustc + /// handles it with the `Constant` variant somehow. + Static(StaticId), } impl Operand { @@ -87,31 +100,141 @@ impl Operand { fn const_zst(ty: Ty) -> Operand { Self::from_bytes(vec![], ty) } + + fn from_fn( + db: &dyn HirDatabase, + func_id: hir_def::FunctionId, + generic_args: Substitution, + ) -> Operand { + let ty = + chalk_ir::TyKind::FnDef(CallableDefId::FunctionId(func_id).to_chalk(db), generic_args) + .intern(Interner); + Operand::from_bytes(vec![], ty) + } } -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ProjectionElem { Deref, Field(FieldId), - TupleField(usize), + // FIXME: get rid of this, and use FieldId for tuples and closures + TupleOrClosureField(usize), Index(V), - ConstantIndex { offset: u64, min_length: u64, from_end: bool }, - Subslice { from: u64, to: u64, from_end: bool }, + ConstantIndex { offset: u64, from_end: bool }, + Subslice { from: u64, to: u64 }, //Downcast(Option, VariantIdx), OpaqueCast(T), } +impl ProjectionElem { + pub fn projected_ty( + &self, + base: Ty, + db: &dyn HirDatabase, + closure_field: impl FnOnce(ClosureId, &Substitution, usize) -> Ty, + krate: CrateId, + ) -> Ty { + match self { + ProjectionElem::Deref => match &base.data(Interner).kind { + TyKind::Raw(_, inner) | TyKind::Ref(_, _, inner) => inner.clone(), + TyKind::Adt(adt, subst) if is_box(db, adt.0) => { + subst.at(Interner, 0).assert_ty_ref(Interner).clone() + } + _ => { + never!("Overloaded deref on type {} is not a projection", base.display(db)); + return TyKind::Error.intern(Interner); + } + }, + ProjectionElem::Field(f) => match &base.data(Interner).kind { + TyKind::Adt(_, subst) => { + db.field_types(f.parent)[f.local_id].clone().substitute(Interner, subst) + } + _ => { + never!("Only adt has field"); + return TyKind::Error.intern(Interner); + } + }, + ProjectionElem::TupleOrClosureField(f) => match &base.data(Interner).kind { + TyKind::Tuple(_, subst) => subst + .as_slice(Interner) + .get(*f) + .map(|x| x.assert_ty_ref(Interner)) + .cloned() + .unwrap_or_else(|| { + never!("Out of bound tuple field"); + TyKind::Error.intern(Interner) + }), + TyKind::Closure(id, subst) => closure_field(*id, subst, *f), + _ => { + never!("Only tuple or closure has tuple or closure field"); + return TyKind::Error.intern(Interner); + } + }, + ProjectionElem::ConstantIndex { .. } | ProjectionElem::Index(_) => { + match &base.data(Interner).kind { + TyKind::Array(inner, _) | TyKind::Slice(inner) => inner.clone(), + _ => { + never!("Overloaded index is not a projection"); + return TyKind::Error.intern(Interner); + } + } + } + &ProjectionElem::Subslice { from, to } => match &base.data(Interner).kind { + TyKind::Array(inner, c) => { + let next_c = usize_const( + db, + match try_const_usize(db, c) { + None => None, + Some(x) => x.checked_sub(u128::from(from + to)), + }, + krate, + ); + TyKind::Array(inner.clone(), next_c).intern(Interner) + } + TyKind::Slice(_) => base.clone(), + _ => { + never!("Subslice projection should only happen on slice and array"); + return TyKind::Error.intern(Interner); + } + }, + ProjectionElem::OpaqueCast(_) => { + never!("We don't emit these yet"); + return TyKind::Error.intern(Interner); + } + } + } +} + type PlaceElem = ProjectionElem; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Place { pub local: LocalId, - pub projection: Vec, + pub projection: Box<[PlaceElem]>, +} + +impl Place { + fn is_parent(&self, child: &Place) -> bool { + self.local == child.local && child.projection.starts_with(&self.projection) + } + + fn iterate_over_parents(&self) -> impl Iterator + '_ { + (0..self.projection.len()) + .map(|x| &self.projection[0..x]) + .map(|x| Place { local: self.local, projection: x.to_vec().into() }) + } + + fn project(&self, projection: PlaceElem) -> Place { + Place { + local: self.local, + projection: self.projection.iter().cloned().chain([projection]).collect(), + } + } } impl From for Place { fn from(local: LocalId) -> Self { - Self { local, projection: vec![] } + Self { local, projection: vec![].into() } } } @@ -123,7 +246,7 @@ pub enum AggregateKind { Tuple(Ty), Adt(VariantId, Substitution), Union(UnionId, FieldId), - //Closure(LocalDefId, SubstsRef), + Closure(Ty), //Generator(LocalDefId, SubstsRef, Movability), } @@ -197,7 +320,13 @@ impl SwitchTargets { } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum Terminator { +pub struct Terminator { + span: MirSpan, + kind: TerminatorKind, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum TerminatorKind { /// Block has one successor; we continue execution there. Goto { target: BasicBlockId }, @@ -320,7 +449,7 @@ pub enum Terminator { /// These are owned by the callee, which is free to modify them. /// This allows the memory occupied by "by-value" arguments to be /// reused across function calls without duplicating the contents. - args: Vec, + args: Box<[Operand]>, /// Where the returned value will be written destination: Place, /// Where to go after this call returns. If none, the call necessarily diverges. @@ -418,7 +547,7 @@ pub enum Terminator { }, } -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)] pub enum BorrowKind { /// Data must be immutable and is aliasable. Shared, @@ -564,6 +693,20 @@ pub enum BinOp { Offset, } +impl BinOp { + fn run_compare(&self, l: T, r: T) -> bool { + match self { + BinOp::Ge => l >= r, + BinOp::Gt => l > r, + BinOp::Le => l <= r, + BinOp::Lt => l < r, + BinOp::Eq => l == r, + BinOp::Ne => l != r, + x => panic!("`run_compare` called on operator {x:?}"), + } + } +} + impl Display for BinOp { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str(match self { @@ -588,32 +731,32 @@ impl Display for BinOp { } } -impl From for BinOp { - fn from(value: hir_def::expr::ArithOp) -> Self { +impl From for BinOp { + fn from(value: hir_def::hir::ArithOp) -> Self { match value { - hir_def::expr::ArithOp::Add => BinOp::Add, - hir_def::expr::ArithOp::Mul => BinOp::Mul, - hir_def::expr::ArithOp::Sub => BinOp::Sub, - hir_def::expr::ArithOp::Div => BinOp::Div, - hir_def::expr::ArithOp::Rem => BinOp::Rem, - hir_def::expr::ArithOp::Shl => BinOp::Shl, - hir_def::expr::ArithOp::Shr => BinOp::Shr, - hir_def::expr::ArithOp::BitXor => BinOp::BitXor, - hir_def::expr::ArithOp::BitOr => BinOp::BitOr, - hir_def::expr::ArithOp::BitAnd => BinOp::BitAnd, + hir_def::hir::ArithOp::Add => BinOp::Add, + hir_def::hir::ArithOp::Mul => BinOp::Mul, + hir_def::hir::ArithOp::Sub => BinOp::Sub, + hir_def::hir::ArithOp::Div => BinOp::Div, + hir_def::hir::ArithOp::Rem => BinOp::Rem, + hir_def::hir::ArithOp::Shl => BinOp::Shl, + hir_def::hir::ArithOp::Shr => BinOp::Shr, + hir_def::hir::ArithOp::BitXor => BinOp::BitXor, + hir_def::hir::ArithOp::BitOr => BinOp::BitOr, + hir_def::hir::ArithOp::BitAnd => BinOp::BitAnd, } } } -impl From for BinOp { - fn from(value: hir_def::expr::CmpOp) -> Self { +impl From for BinOp { + fn from(value: hir_def::hir::CmpOp) -> Self { match value { - hir_def::expr::CmpOp::Eq { negated: false } => BinOp::Eq, - hir_def::expr::CmpOp::Eq { negated: true } => BinOp::Ne, - hir_def::expr::CmpOp::Ord { ordering: Ordering::Greater, strict: false } => BinOp::Ge, - hir_def::expr::CmpOp::Ord { ordering: Ordering::Greater, strict: true } => BinOp::Gt, - hir_def::expr::CmpOp::Ord { ordering: Ordering::Less, strict: false } => BinOp::Le, - hir_def::expr::CmpOp::Ord { ordering: Ordering::Less, strict: true } => BinOp::Lt, + hir_def::hir::CmpOp::Eq { negated: false } => BinOp::Eq, + hir_def::hir::CmpOp::Eq { negated: true } => BinOp::Ne, + hir_def::hir::CmpOp::Ord { ordering: Ordering::Greater, strict: false } => BinOp::Ge, + hir_def::hir::CmpOp::Ord { ordering: Ordering::Greater, strict: true } => BinOp::Gt, + hir_def::hir::CmpOp::Ord { ordering: Ordering::Less, strict: false } => BinOp::Le, + hir_def::hir::CmpOp::Ord { ordering: Ordering::Less, strict: true } => BinOp::Lt, } } } @@ -642,7 +785,6 @@ pub enum CastKind { FloatToInt, FloatToFloat, IntToFloat, - PtrToPtr, FnPtrToPtr, } @@ -653,13 +795,8 @@ pub enum Rvalue { /// Creates an array where each element is the value of the operand. /// - /// This is the cause of a bug in the case where the repetition count is zero because the value - /// is not dropped, see [#74836]. - /// /// Corresponds to source code like `[x; 32]`. - /// - /// [#74836]: https://github.com/rust-lang/rust/issues/74836 - //Repeat(Operand, ty::Const), + Repeat(Operand, Const), /// Creates a reference of the indicated kind to the place. /// @@ -768,7 +905,7 @@ pub enum Rvalue { /// /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Generator`. After /// generator lowering, `Generator` aggregate kinds are disallowed too. - Aggregate(AggregateKind, Vec), + Aggregate(AggregateKind, Box<[Operand]>), /// Transmutes a `*mut u8` into shallow-initialized `Box`. /// @@ -777,6 +914,9 @@ pub enum Rvalue { /// affects alias analysis. ShallowInitBox(Operand, Ty), + /// NON STANDARD: allocates memory with the type's layout, and shallow init the box with the resulting pointer. + ShallowInitBoxWithAlloc(Ty), + /// A CopyForDeref is equivalent to a read from a place at the /// codegen level, but is treated specially by drop elaboration. When such a read happens, it /// is guaranteed (via nature of the mir_opt `Derefer` in rustc_mir_transform/src/deref_separator) @@ -816,7 +956,7 @@ pub struct Statement { pub span: MirSpan, } -#[derive(Debug, Default, PartialEq, Eq)] +#[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct BasicBlock { /// List of statements in this block. pub statements: Vec, @@ -838,19 +978,118 @@ pub struct BasicBlock { pub is_cleanup: bool, } -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct MirBody { pub basic_blocks: Arena, pub locals: Arena, pub start_block: BasicBlockId, pub owner: DefWithBodyId, - pub arg_count: usize, pub binding_locals: ArenaMap, pub param_locals: Vec, + /// This field stores the closures directly owned by this body. It is used + /// in traversing every mir body. + pub closures: Vec, } -fn const_as_usize(c: &Const) -> usize { - try_const_usize(c).unwrap() as usize +impl MirBody { + fn walk_places(&mut self, mut f: impl FnMut(&mut Place)) { + fn for_operand(op: &mut Operand, f: &mut impl FnMut(&mut Place)) { + match op { + Operand::Copy(p) | Operand::Move(p) => { + f(p); + } + Operand::Constant(_) | Operand::Static(_) => (), + } + } + for (_, block) in self.basic_blocks.iter_mut() { + for statement in &mut block.statements { + match &mut statement.kind { + StatementKind::Assign(p, r) => { + f(p); + match r { + Rvalue::ShallowInitBoxWithAlloc(_) => (), + Rvalue::ShallowInitBox(o, _) + | Rvalue::UnaryOp(_, o) + | Rvalue::Cast(_, o, _) + | Rvalue::Repeat(o, _) + | Rvalue::Use(o) => for_operand(o, &mut f), + Rvalue::CopyForDeref(p) + | Rvalue::Discriminant(p) + | Rvalue::Len(p) + | Rvalue::Ref(_, p) => f(p), + Rvalue::CheckedBinaryOp(_, o1, o2) => { + for_operand(o1, &mut f); + for_operand(o2, &mut f); + } + Rvalue::Aggregate(_, ops) => { + for op in ops.iter_mut() { + for_operand(op, &mut f); + } + } + } + } + StatementKind::Deinit(p) => f(p), + StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + | StatementKind::Nop => (), + } + } + match &mut block.terminator { + Some(x) => match &mut x.kind { + TerminatorKind::SwitchInt { discr, .. } => for_operand(discr, &mut f), + TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::GeneratorDrop + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable => (), + TerminatorKind::Drop { place, .. } => { + f(place); + } + TerminatorKind::DropAndReplace { place, value, .. } => { + f(place); + for_operand(value, &mut f); + } + TerminatorKind::Call { func, args, destination, .. } => { + for_operand(func, &mut f); + args.iter_mut().for_each(|x| for_operand(x, &mut f)); + f(destination); + } + TerminatorKind::Assert { cond, .. } => { + for_operand(cond, &mut f); + } + TerminatorKind::Yield { value, resume_arg, .. } => { + for_operand(value, &mut f); + f(resume_arg); + } + }, + None => (), + } + } + } + + fn shrink_to_fit(&mut self) { + let MirBody { + basic_blocks, + locals, + start_block: _, + owner: _, + binding_locals, + param_locals, + closures, + } = self; + basic_blocks.shrink_to_fit(); + locals.shrink_to_fit(); + binding_locals.shrink_to_fit(); + param_locals.shrink_to_fit(); + closures.shrink_to_fit(); + for (_, b) in basic_blocks.iter_mut() { + let BasicBlock { statements, terminator: _, is_cleanup: _ } = b; + statements.shrink_to_fit(); + } + } } #[derive(Debug, PartialEq, Eq, Clone, Copy)] diff --git a/crates/hir-ty/src/mir/borrowck.rs b/crates/hir-ty/src/mir/borrowck.rs index c8729af86a9ea..a0ea1cc5ef7d9 100644 --- a/crates/hir-ty/src/mir/borrowck.rs +++ b/crates/hir-ty/src/mir/borrowck.rs @@ -3,17 +3,20 @@ // Currently it is an ad-hoc implementation, only useful for mutability analysis. Feel free to remove all of these // if needed for implementing a proper borrow checker. -use std::sync::Arc; +use std::iter; -use hir_def::DefWithBodyId; +use hir_def::{DefWithBodyId, HasModule}; use la_arena::ArenaMap; use stdx::never; +use triomphe::Arc; -use crate::db::HirDatabase; +use crate::{ + db::HirDatabase, mir::Operand, utils::ClosureSubst, ClosureId, Interner, Ty, TyExt, TypeFlags, +}; use super::{ BasicBlockId, BorrowKind, LocalId, MirBody, MirLowerError, MirSpan, Place, ProjectionElem, - Rvalue, StatementKind, Terminator, + Rvalue, StatementKind, TerminatorKind, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -23,26 +26,167 @@ pub enum MutabilityReason { Not, } +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct MovedOutOfRef { + pub ty: Ty, + pub span: MirSpan, +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct BorrowckResult { pub mir_body: Arc, pub mutability_of_locals: ArenaMap, + pub moved_out_of_ref: Vec, +} + +fn all_mir_bodies( + db: &dyn HirDatabase, + def: DefWithBodyId, +) -> Box, MirLowerError>> + '_> { + fn for_closure( + db: &dyn HirDatabase, + c: ClosureId, + ) -> Box, MirLowerError>> + '_> { + match db.mir_body_for_closure(c) { + Ok(body) => { + let closures = body.closures.clone(); + Box::new( + iter::once(Ok(body)) + .chain(closures.into_iter().flat_map(|x| for_closure(db, x))), + ) + } + Err(e) => Box::new(iter::once(Err(e))), + } + } + match db.mir_body(def) { + Ok(body) => { + let closures = body.closures.clone(); + Box::new( + iter::once(Ok(body)).chain(closures.into_iter().flat_map(|x| for_closure(db, x))), + ) + } + Err(e) => Box::new(iter::once(Err(e))), + } } pub fn borrowck_query( db: &dyn HirDatabase, def: DefWithBodyId, -) -> Result, MirLowerError> { +) -> Result, MirLowerError> { let _p = profile::span("borrowck_query"); - let body = db.mir_body(def)?; - let r = BorrowckResult { mutability_of_locals: mutability_of_locals(&body), mir_body: body }; - Ok(Arc::new(r)) + let r = all_mir_bodies(db, def) + .map(|body| { + let body = body?; + Ok(BorrowckResult { + mutability_of_locals: mutability_of_locals(db, &body), + moved_out_of_ref: moved_out_of_ref(db, &body), + mir_body: body, + }) + }) + .collect::, MirLowerError>>()?; + Ok(r.into()) } -fn is_place_direct(lvalue: &Place) -> bool { - !lvalue.projection.iter().any(|x| *x == ProjectionElem::Deref) +fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec { + let mut result = vec![]; + let mut for_operand = |op: &Operand, span: MirSpan| match op { + Operand::Copy(p) | Operand::Move(p) => { + let mut ty: Ty = body.locals[p.local].ty.clone(); + let mut is_dereference_of_ref = false; + for proj in &*p.projection { + if *proj == ProjectionElem::Deref && ty.as_reference().is_some() { + is_dereference_of_ref = true; + } + ty = proj.projected_ty( + ty, + db, + |c, subst, f| { + let (def, _) = db.lookup_intern_closure(c.into()); + let infer = db.infer(def); + let (captures, _) = infer.closure_info(&c); + let parent_subst = ClosureSubst(subst).parent_subst(); + captures + .get(f) + .expect("broken closure field") + .ty + .clone() + .substitute(Interner, parent_subst) + }, + body.owner.module(db.upcast()).krate(), + ); + } + if is_dereference_of_ref + && !ty.clone().is_copy(db, body.owner) + && !ty.data(Interner).flags.intersects(TypeFlags::HAS_ERROR) + { + result.push(MovedOutOfRef { span, ty }); + } + } + Operand::Constant(_) | Operand::Static(_) => (), + }; + for (_, block) in body.basic_blocks.iter() { + for statement in &block.statements { + match &statement.kind { + StatementKind::Assign(_, r) => match r { + Rvalue::ShallowInitBoxWithAlloc(_) => (), + Rvalue::ShallowInitBox(o, _) + | Rvalue::UnaryOp(_, o) + | Rvalue::Cast(_, o, _) + | Rvalue::Repeat(o, _) + | Rvalue::Use(o) => for_operand(o, statement.span), + Rvalue::CopyForDeref(_) + | Rvalue::Discriminant(_) + | Rvalue::Len(_) + | Rvalue::Ref(_, _) => (), + Rvalue::CheckedBinaryOp(_, o1, o2) => { + for_operand(o1, statement.span); + for_operand(o2, statement.span); + } + Rvalue::Aggregate(_, ops) => { + for op in ops.iter() { + for_operand(op, statement.span); + } + } + }, + StatementKind::Deinit(_) + | StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + | StatementKind::Nop => (), + } + } + match &block.terminator { + Some(terminator) => match &terminator.kind { + TerminatorKind::SwitchInt { discr, .. } => for_operand(discr, terminator.span), + TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::GeneratorDrop + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::Drop { .. } => (), + TerminatorKind::DropAndReplace { value, .. } => { + for_operand(value, terminator.span); + } + TerminatorKind::Call { func, args, .. } => { + for_operand(func, terminator.span); + args.iter().for_each(|x| for_operand(x, terminator.span)); + } + TerminatorKind::Assert { cond, .. } => { + for_operand(cond, terminator.span); + } + TerminatorKind::Yield { value, .. } => { + for_operand(value, terminator.span); + } + }, + None => (), + } + } + result } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] enum ProjectionCase { /// Projection is a local Direct, @@ -52,20 +196,39 @@ enum ProjectionCase { Indirect, } -fn place_case(lvalue: &Place) -> ProjectionCase { +fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> ProjectionCase { let mut is_part_of = false; - for proj in lvalue.projection.iter().rev() { + let mut ty = body.locals[lvalue.local].ty.clone(); + for proj in lvalue.projection.iter() { match proj { - ProjectionElem::Deref => return ProjectionCase::Indirect, // It's indirect - ProjectionElem::ConstantIndex { .. } + ProjectionElem::Deref if ty.as_adt().is_none() => return ProjectionCase::Indirect, // It's indirect in case of reference and raw + ProjectionElem::Deref // It's direct in case of `Box` + | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Field(_) - | ProjectionElem::TupleField(_) + | ProjectionElem::TupleOrClosureField(_) | ProjectionElem::Index(_) => { is_part_of = true; } ProjectionElem::OpaqueCast(_) => (), } + ty = proj.projected_ty( + ty, + db, + |c, subst, f| { + let (def, _) = db.lookup_intern_closure(c.into()); + let infer = db.infer(def); + let (captures, _) = infer.closure_info(&c); + let parent_subst = ClosureSubst(subst).parent_subst(); + captures + .get(f) + .expect("broken closure field") + .ty + .clone() + .substitute(Interner, parent_subst) + }, + body.owner.module(db.upcast()).krate(), + ); } if is_part_of { ProjectionCase::DirectPart @@ -76,7 +239,7 @@ fn place_case(lvalue: &Place) -> ProjectionCase { /// Returns a map from basic blocks to the set of locals that might be ever initialized before /// the start of the block. Only `StorageDead` can remove something from this map, and we ignore -/// `Uninit` and `drop` and similars after initialization. +/// `Uninit` and `drop` and similar after initialization. fn ever_initialized_map(body: &MirBody) -> ArenaMap> { let mut result: ArenaMap> = body.basic_blocks.iter().map(|x| (x.0, ArenaMap::default())).collect(); @@ -107,26 +270,28 @@ fn ever_initialized_map(body: &MirBody) -> ArenaMap vec![*target], - Terminator::SwitchInt { targets, .. } => targets.all_targets().to_vec(), - Terminator::Resume - | Terminator::Abort - | Terminator::Return - | Terminator::Unreachable => vec![], - Terminator::Call { target, cleanup, destination, .. } => { + let targets = match &terminator.kind { + TerminatorKind::Goto { target } => vec![*target], + TerminatorKind::SwitchInt { targets, .. } => targets.all_targets().to_vec(), + TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable => vec![], + TerminatorKind::Call { target, cleanup, destination, .. } => { if destination.projection.len() == 0 && destination.local == l { is_ever_initialized = true; } target.into_iter().chain(cleanup.into_iter()).copied().collect() } - Terminator::Drop { .. } - | Terminator::DropAndReplace { .. } - | Terminator::Assert { .. } - | Terminator::Yield { .. } - | Terminator::GeneratorDrop - | Terminator::FalseEdge { .. } - | Terminator::FalseUnwind { .. } => { + TerminatorKind::Drop { target, unwind, place: _ } => { + Some(target).into_iter().chain(unwind.into_iter()).copied().collect() + } + TerminatorKind::DropAndReplace { .. } + | TerminatorKind::Assert { .. } + | TerminatorKind::Yield { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } => { never!("We don't emit these MIR terminators yet"); vec![] } @@ -151,7 +316,10 @@ fn ever_initialized_map(body: &MirBody) -> ArenaMap ArenaMap { +fn mutability_of_locals( + db: &dyn HirDatabase, + body: &MirBody, +) -> ArenaMap { let mut result: ArenaMap = body.locals.iter().map(|x| (x.0, MutabilityReason::Not)).collect(); let mut push_mut_span = |local, span| match &mut result[local] { @@ -164,7 +332,7 @@ fn mutability_of_locals(body: &MirBody) -> ArenaMap { for statement in &block.statements { match &statement.kind { StatementKind::Assign(place, value) => { - match place_case(place) { + match place_case(db, body, place) { ProjectionCase::Direct => { if ever_init_map.get(place.local).copied().unwrap_or_default() { push_mut_span(place.local, statement.span); @@ -179,7 +347,7 @@ fn mutability_of_locals(body: &MirBody) -> ArenaMap { ProjectionCase::Indirect => (), } if let Rvalue::Ref(BorrowKind::Mut { .. }, p) = value { - if is_place_direct(p) { + if place_case(db, body, p) != ProjectionCase::Indirect { push_mut_span(p.local, statement.span); } } @@ -194,21 +362,21 @@ fn mutability_of_locals(body: &MirBody) -> ArenaMap { never!("Terminator should be none only in construction"); continue; }; - match terminator { - Terminator::Goto { .. } - | Terminator::Resume - | Terminator::Abort - | Terminator::Return - | Terminator::Unreachable - | Terminator::FalseEdge { .. } - | Terminator::FalseUnwind { .. } - | Terminator::GeneratorDrop - | Terminator::SwitchInt { .. } - | Terminator::Drop { .. } - | Terminator::DropAndReplace { .. } - | Terminator::Assert { .. } - | Terminator::Yield { .. } => (), - Terminator::Call { destination, .. } => { + match &terminator.kind { + TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Drop { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::Assert { .. } + | TerminatorKind::Yield { .. } => (), + TerminatorKind::Call { destination, .. } => { if destination.projection.len() == 0 { if ever_init_map.get(destination.local).copied().unwrap_or_default() { push_mut_span(destination.local, MirSpan::Unknown); diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index c5d843d9ebd89..ce14f6dbad536 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -1,41 +1,134 @@ //! This module provides a MIR interpreter, which is used in const eval. -use std::{borrow::Cow, collections::HashMap, iter}; +use std::{borrow::Cow, collections::HashMap, fmt::Write, iter, ops::Range}; -use base_db::CrateId; -use chalk_ir::{ - fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}, - DebruijnIndex, TyKind, -}; +use base_db::{CrateId, FileId}; +use chalk_ir::Mutability; +use either::Either; use hir_def::{ builtin_type::BuiltinType, + data::adt::{StructFlags, VariantData}, lang_item::{lang_attr, LangItem}, - layout::{Layout, LayoutError, RustcEnumVariantIdx, TagEncoding, Variants}, - AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, Lookup, VariantId, + layout::{TagEncoding, Variants}, + AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, StaticId, + VariantId, }; +use hir_expand::InFile; use intern::Interned; use la_arena::ArenaMap; +use rustc_hash::{FxHashMap, FxHashSet}; +use stdx::never; +use syntax::{SyntaxNodePtr, TextRange}; +use triomphe::Arc; use crate::{ - consteval::{intern_const_scalar, ConstEvalError}, + consteval::{intern_const_scalar, try_const_usize, ConstEvalError}, db::HirDatabase, - from_placeholder_idx, - infer::{normalize, PointerCast}, - layout::layout_of_ty, + display::{ClosureStyle, HirDisplay}, + infer::PointerCast, + layout::{Layout, LayoutError, RustcEnumVariantIdx}, mapping::from_chalk, - method_resolution::lookup_impl_method, - CallableDefId, Const, ConstScalar, Interner, MemoryMap, Substitution, Ty, TyBuilder, TyExt, + method_resolution::{is_dyn_method, lookup_impl_method}, + name, static_lifetime, + traits::FnTrait, + utils::{detect_variant_from_bytes, ClosureSubst}, + CallableDefId, ClosureId, Const, ConstScalar, FnDefId, GenericArgData, Interner, MemoryMap, + Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, }; use super::{ - const_as_usize, return_slot, AggregateKind, BinOp, CastKind, LocalId, MirBody, MirLowerError, - Operand, Place, ProjectionElem, Rvalue, StatementKind, Terminator, UnOp, + return_slot, AggregateKind, BinOp, CastKind, LocalId, MirBody, MirLowerError, MirSpan, Operand, + Place, ProjectionElem, Rvalue, StatementKind, TerminatorKind, UnOp, }; +mod shim; +#[cfg(test)] +mod tests; + +macro_rules! from_bytes { + ($ty:tt, $value:expr) => { + ($ty::from_le_bytes(match ($value).try_into() { + Ok(x) => x, + Err(_) => return Err(MirEvalError::TypeError(stringify!(mismatched size in constructing $ty))), + })) + }; +} + +macro_rules! not_supported { + ($x: expr) => { + return Err(MirEvalError::NotSupported(format!($x))) + }; +} + +#[derive(Debug, Default, Clone, PartialEq, Eq)] +pub struct VTableMap { + ty_to_id: FxHashMap, + id_to_ty: Vec, +} + +impl VTableMap { + fn id(&mut self, ty: Ty) -> usize { + if let Some(x) = self.ty_to_id.get(&ty) { + return *x; + } + let id = self.id_to_ty.len(); + self.id_to_ty.push(ty.clone()); + self.ty_to_id.insert(ty, id); + id + } + + fn ty(&self, id: usize) -> Result<&Ty> { + self.id_to_ty.get(id).ok_or(MirEvalError::InvalidVTableId(id)) + } + + fn ty_of_bytes(&self, bytes: &[u8]) -> Result<&Ty> { + let id = from_bytes!(usize, bytes); + self.ty(id) + } +} + +#[derive(Debug, Default, Clone, PartialEq, Eq)] +struct TlsData { + keys: Vec, +} + +impl TlsData { + fn create_key(&mut self) -> usize { + self.keys.push(0); + self.keys.len() - 1 + } + + fn get_key(&mut self, key: usize) -> Result { + let r = self.keys.get(key).ok_or_else(|| { + MirEvalError::UndefinedBehavior(format!("Getting invalid tls key {key}")) + })?; + Ok(*r) + } + + fn set_key(&mut self, key: usize, value: u128) -> Result<()> { + let r = self.keys.get_mut(key).ok_or_else(|| { + MirEvalError::UndefinedBehavior(format!("Setting invalid tls key {key}")) + })?; + *r = value; + Ok(()) + } +} + pub struct Evaluator<'a> { db: &'a dyn HirDatabase, + trait_env: Arc, stack: Vec, heap: Vec, + /// Stores the global location of the statics. We const evaluate every static first time we need it + /// and see it's missing, then we add it to this to reuse. + static_locations: FxHashMap, + /// We don't really have function pointers, i.e. pointers to some assembly instructions that we can run. Instead, we + /// store the type as an interned id in place of function and vtable pointers, and we recover back the type at the + /// time of use. + vtable_map: VTableMap, + thread_local_storage: TlsData, + stdout: Vec, + stderr: Vec, crate_id: CrateId, // FIXME: This is a workaround, see the comment on `interpret_mir` assert_placeholder_ty_is_unused: bool, @@ -45,19 +138,27 @@ pub struct Evaluator<'a> { stack_depth_limit: usize, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] enum Address { Stack(usize), Heap(usize), + Invalid(usize), } use Address::*; +#[derive(Debug, Clone, Copy)] struct Interval { addr: Address, size: usize, } +#[derive(Debug, Clone)] +struct IntervalAndTy { + interval: Interval, + ty: Ty, +} + impl Interval { fn new(addr: Address, size: usize) -> Self { Self { addr, size } @@ -66,12 +167,49 @@ impl Interval { fn get<'a>(&self, memory: &'a Evaluator<'a>) -> Result<&'a [u8]> { memory.read_memory(self.addr, self.size) } + + fn write_from_bytes(&self, memory: &mut Evaluator<'_>, bytes: &[u8]) -> Result<()> { + memory.write_memory(self.addr, bytes) + } + + fn write_from_interval(&self, memory: &mut Evaluator<'_>, interval: Interval) -> Result<()> { + // FIXME: this could be more efficient + let bytes = &interval.get(memory)?.to_vec(); + memory.write_memory(self.addr, bytes) + } + + fn slice(self, range: Range) -> Interval { + Interval { addr: self.addr.offset(range.start), size: range.len() } + } +} + +impl IntervalAndTy { + fn get<'a>(&self, memory: &'a Evaluator<'a>) -> Result<&'a [u8]> { + memory.read_memory(self.interval.addr, self.interval.size) + } + + fn new( + addr: Address, + ty: Ty, + evaluator: &Evaluator<'_>, + locals: &Locals<'_>, + ) -> Result { + let size = evaluator.size_of_sized(&ty, locals, "type of interval")?; + Ok(IntervalAndTy { interval: Interval { addr, size }, ty }) + } } enum IntervalOrOwned { Owned(Vec), Borrowed(Interval), } + +impl From for IntervalOrOwned { + fn from(it: Interval) -> IntervalOrOwned { + IntervalOrOwned::Borrowed(it) + } +} + impl IntervalOrOwned { pub(crate) fn to_vec(self, memory: &Evaluator<'_>) -> Result> { Ok(match self { @@ -79,15 +217,13 @@ impl IntervalOrOwned { IntervalOrOwned::Borrowed(b) => b.get(memory)?.to_vec(), }) } -} -macro_rules! from_bytes { - ($ty:tt, $value:expr) => { - ($ty::from_le_bytes(match ($value).try_into() { - Ok(x) => x, - Err(_) => return Err(MirEvalError::TypeError("mismatched size")), - })) - }; + fn get<'a>(&'a self, memory: &'a Evaluator<'a>) -> Result<&'a [u8]> { + Ok(match self { + IntervalOrOwned::Owned(o) => o, + IntervalOrOwned::Borrowed(b) => b.get(memory)?, + }) + } } impl Address { @@ -97,9 +233,11 @@ impl Address { fn from_usize(x: usize) -> Self { if x > usize::MAX / 2 { - Stack(usize::MAX - x) + Stack(x - usize::MAX / 2) + } else if x > usize::MAX / 4 { + Heap(x - usize::MAX / 4) } else { - Heap(x) + Invalid(x) } } @@ -109,8 +247,9 @@ impl Address { fn to_usize(&self) -> usize { let as_num = match self { - Stack(x) => usize::MAX - *x, - Heap(x) => *x, + Stack(x) => *x + usize::MAX / 2, + Heap(x) => *x + usize::MAX / 4, + Invalid(x) => *x, }; as_num } @@ -119,6 +258,7 @@ impl Address { match self { Stack(x) => Stack(f(*x)), Heap(x) => Heap(f(*x)), + Invalid(x) => Invalid(f(*x)), } } @@ -129,28 +269,123 @@ impl Address { #[derive(Clone, PartialEq, Eq)] pub enum MirEvalError { - ConstEvalError(Box), + ConstEvalError(String, Box), LayoutError(LayoutError, Ty), /// Means that code had type errors (or mismatched args) and we shouldn't generate mir in first place. TypeError(&'static str), /// Means that code had undefined behavior. We don't try to actively detect UB, but if it was detected /// then use this type of error. - UndefinedBehavior(&'static str), - Panic, + UndefinedBehavior(String), + Panic(String), MirLowerError(FunctionId, MirLowerError), + MirLowerErrorForClosure(ClosureId, MirLowerError), TypeIsUnsized(Ty, &'static str), NotSupported(String), InvalidConst(Const), - InFunction(FunctionId, Box), + InFunction(Either, Box, MirSpan, DefWithBodyId), ExecutionLimitExceeded, StackOverflow, TargetDataLayoutNotAvailable, + InvalidVTableId(usize), + CoerceUnsizedError(Ty), + LangItemNotFound(LangItem), +} + +impl MirEvalError { + pub fn pretty_print( + &self, + f: &mut String, + db: &dyn HirDatabase, + span_formatter: impl Fn(FileId, TextRange) -> String, + ) -> std::result::Result<(), std::fmt::Error> { + writeln!(f, "Mir eval error:")?; + let mut err = self; + while let MirEvalError::InFunction(func, e, span, def) = err { + err = e; + match func { + Either::Left(func) => { + let function_name = db.function_data(*func); + writeln!( + f, + "In function {} ({:?})", + function_name.name.display(db.upcast()), + func + )?; + } + Either::Right(clos) => { + writeln!(f, "In {:?}", clos)?; + } + } + let source_map = db.body_with_source_map(*def).1; + let span: InFile = match span { + MirSpan::ExprId(e) => match source_map.expr_syntax(*e) { + Ok(s) => s.map(|x| x.into()), + Err(_) => continue, + }, + MirSpan::PatId(p) => match source_map.pat_syntax(*p) { + Ok(s) => s.map(|x| match x { + Either::Left(e) => e.into(), + Either::Right(e) => e.into(), + }), + Err(_) => continue, + }, + MirSpan::Unknown => continue, + }; + let file_id = span.file_id.original_file(db.upcast()); + let text_range = span.value.text_range(); + writeln!(f, "{}", span_formatter(file_id, text_range))?; + } + match err { + MirEvalError::InFunction(..) => unreachable!(), + MirEvalError::LayoutError(err, ty) => { + write!( + f, + "Layout for type `{}` is not available due {err:?}", + ty.display(db).with_closure_style(ClosureStyle::ClosureWithId).to_string() + )?; + } + MirEvalError::MirLowerError(func, err) => { + let function_name = db.function_data(*func); + writeln!( + f, + "MIR lowering for function `{}` ({:?}) failed due:", + function_name.name.display(db.upcast()), + func + )?; + err.pretty_print(f, db, span_formatter)?; + } + MirEvalError::ConstEvalError(name, err) => { + MirLowerError::ConstEvalError(name.clone(), err.clone()).pretty_print( + f, + db, + span_formatter, + )?; + } + MirEvalError::TypeError(_) + | MirEvalError::UndefinedBehavior(_) + | MirEvalError::Panic(_) + | MirEvalError::MirLowerErrorForClosure(_, _) + | MirEvalError::TypeIsUnsized(_, _) + | MirEvalError::NotSupported(_) + | MirEvalError::InvalidConst(_) + | MirEvalError::ExecutionLimitExceeded + | MirEvalError::StackOverflow + | MirEvalError::TargetDataLayoutNotAvailable + | MirEvalError::CoerceUnsizedError(_) + | MirEvalError::LangItemNotFound(_) + | MirEvalError::InvalidVTableId(_) => writeln!(f, "{:?}", err)?, + } + Ok(()) + } } impl std::fmt::Debug for MirEvalError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::ConstEvalError(arg0) => f.debug_tuple("ConstEvalError").field(arg0).finish(), + Self::ConstEvalError(arg0, arg1) => { + f.debug_tuple("ConstEvalError").field(arg0).field(arg1).finish() + } + Self::LangItemNotFound(arg0) => f.debug_tuple("LangItemNotFound").field(arg0).finish(), Self::LayoutError(arg0, arg1) => { f.debug_tuple("LayoutError").field(arg0).field(arg1).finish() } @@ -158,7 +393,7 @@ impl std::fmt::Debug for MirEvalError { Self::UndefinedBehavior(arg0) => { f.debug_tuple("UndefinedBehavior").field(arg0).finish() } - Self::Panic => write!(f, "Panic"), + Self::Panic(msg) => write!(f, "Panic with message:\n{msg:?}"), Self::TargetDataLayoutNotAvailable => write!(f, "TargetDataLayoutNotAvailable"), Self::TypeIsUnsized(ty, it) => write!(f, "{ty:?} is unsized. {it} should be sized."), Self::ExecutionLimitExceeded => write!(f, "execution limit exceeded"), @@ -166,17 +401,24 @@ impl std::fmt::Debug for MirEvalError { Self::MirLowerError(arg0, arg1) => { f.debug_tuple("MirLowerError").field(arg0).field(arg1).finish() } + Self::MirLowerErrorForClosure(arg0, arg1) => { + f.debug_tuple("MirLowerError").field(arg0).field(arg1).finish() + } + Self::CoerceUnsizedError(arg0) => { + f.debug_tuple("CoerceUnsizedError").field(arg0).finish() + } + Self::InvalidVTableId(arg0) => f.debug_tuple("InvalidVTableId").field(arg0).finish(), Self::NotSupported(arg0) => f.debug_tuple("NotSupported").field(arg0).finish(), Self::InvalidConst(arg0) => { let data = &arg0.data(Interner); f.debug_struct("InvalidConst").field("ty", &data.ty).field("value", &arg0).finish() } - Self::InFunction(func, e) => { + Self::InFunction(func, e, span, _) => { let mut e = &**e; - let mut stack = vec![*func]; - while let Self::InFunction(f, next_e) = e { + let mut stack = vec![(*func, *span)]; + while let Self::InFunction(f, next_e, span, _) = e { e = &next_e; - stack.push(*f); + stack.push((*f, *span)); } f.debug_struct("WithStack").field("error", e).field("stack", &stack).finish() } @@ -184,26 +426,33 @@ impl std::fmt::Debug for MirEvalError { } } -macro_rules! not_supported { - ($x: expr) => { - return Err(MirEvalError::NotSupported(format!($x))) - }; +type Result = std::result::Result; + +#[derive(Debug, Default)] +struct DropFlags { + need_drop: FxHashSet, } -impl From for MirEvalError { - fn from(value: ConstEvalError) -> Self { - match value { - _ => MirEvalError::ConstEvalError(Box::new(value)), +impl DropFlags { + fn add_place(&mut self, p: Place) { + if p.iterate_over_parents().any(|x| self.need_drop.contains(&x)) { + return; } + self.need_drop.retain(|x| !p.is_parent(x)); + self.need_drop.insert(p); } -} -type Result = std::result::Result; + fn remove_place(&mut self, p: &Place) -> bool { + // FIXME: replace parents with parts + self.need_drop.remove(p) + } +} +#[derive(Debug)] struct Locals<'a> { - ptr: &'a ArenaMap, + ptr: &'a ArenaMap, body: &'a MirBody, - subst: &'a Substitution, + drop_flags: DropFlags, } pub fn interpret_mir( @@ -215,38 +464,65 @@ pub fn interpret_mir( // a zero size, hoping that they are all outside of our current body. Even without a fix for #7434, we can // (and probably should) do better here, for example by excluding bindings outside of the target expression. assert_placeholder_ty_is_unused: bool, -) -> Result { +) -> (Result, String, String) { let ty = body.locals[return_slot()].ty.clone(); - let mut evaluator = - Evaluator::new(db, body.owner.module(db.upcast()).krate(), assert_placeholder_ty_is_unused); - let bytes = evaluator.interpret_mir_with_no_arg(&body)?; - let memory_map = evaluator.create_memory_map( - &bytes, - &ty, - &Locals { ptr: &ArenaMap::new(), body: &body, subst: &Substitution::empty(Interner) }, - )?; - return Ok(intern_const_scalar(ConstScalar::Bytes(bytes, memory_map), ty)); + let mut evaluator = Evaluator::new(db, body, assert_placeholder_ty_is_unused); + let x: Result = (|| { + let bytes = evaluator.interpret_mir(&body, None.into_iter())?; + let mut memory_map = evaluator.create_memory_map( + &bytes, + &ty, + &Locals { ptr: &ArenaMap::new(), body: &body, drop_flags: DropFlags::default() }, + )?; + memory_map.vtable = evaluator.vtable_map.clone(); + return Ok(intern_const_scalar(ConstScalar::Bytes(bytes, memory_map), ty)); + })(); + ( + x, + String::from_utf8_lossy(&evaluator.stdout).into_owned(), + String::from_utf8_lossy(&evaluator.stderr).into_owned(), + ) } impl Evaluator<'_> { pub fn new<'a>( db: &'a dyn HirDatabase, - crate_id: CrateId, + body: &MirBody, assert_placeholder_ty_is_unused: bool, ) -> Evaluator<'a> { + let crate_id = body.owner.module(db.upcast()).krate(); + let trait_env = db.trait_environment_for_body(body.owner); Evaluator { stack: vec![0], heap: vec![0], + vtable_map: VTableMap::default(), + thread_local_storage: TlsData::default(), + static_locations: HashMap::default(), db, + trait_env, crate_id, + stdout: vec![], + stderr: vec![], assert_placeholder_ty_is_unused, stack_depth_limit: 100, - execution_limit: 100_000, + execution_limit: 1000_000, } } fn place_addr(&self, p: &Place, locals: &Locals<'_>) -> Result
{ - Ok(self.place_addr_and_ty(p, locals)?.0) + Ok(self.place_addr_and_ty_and_metadata(p, locals)?.0) + } + + fn place_interval(&self, p: &Place, locals: &Locals<'_>) -> Result { + let place_addr_and_ty = self.place_addr_and_ty_and_metadata(p, locals)?; + Ok(Interval { + addr: place_addr_and_ty.0, + size: self.size_of_sized( + &place_addr_and_ty.1, + locals, + "Type of place that we need its interval", + )?, + }) } fn ptr_size(&self) -> usize { @@ -256,125 +532,170 @@ impl Evaluator<'_> { } } - fn place_addr_and_ty<'a>(&'a self, p: &Place, locals: &'a Locals<'a>) -> Result<(Address, Ty)> { - let mut addr = locals.ptr[p.local]; - let mut ty: Ty = - self.ty_filler(&locals.body.locals[p.local].ty, locals.subst, locals.body.owner)?; - for proj in &p.projection { + fn place_addr_and_ty_and_metadata<'a>( + &'a self, + p: &Place, + locals: &'a Locals<'a>, + ) -> Result<(Address, Ty, Option)> { + let mut addr = locals.ptr[p.local].addr; + let mut ty: Ty = locals.body.locals[p.local].ty.clone(); + let mut metadata: Option = None; // locals are always sized + for proj in &*p.projection { + let prev_ty = ty.clone(); + ty = proj.projected_ty( + ty, + self.db, + |c, subst, f| { + let (def, _) = self.db.lookup_intern_closure(c.into()); + let infer = self.db.infer(def); + let (captures, _) = infer.closure_info(&c); + let parent_subst = ClosureSubst(subst).parent_subst(); + captures + .get(f) + .expect("broken closure field") + .ty + .clone() + .substitute(Interner, parent_subst) + }, + self.crate_id, + ); match proj { ProjectionElem::Deref => { - ty = match &ty.data(Interner).kind { - TyKind::Raw(_, inner) | TyKind::Ref(_, _, inner) => inner.clone(), - _ => { - return Err(MirEvalError::TypeError( - "Overloaded deref in MIR is disallowed", - )) - } + metadata = if self.size_align_of(&ty, locals)?.is_none() { + Some( + Interval { addr: addr.offset(self.ptr_size()), size: self.ptr_size() } + .into(), + ) + } else { + None }; let x = from_bytes!(usize, self.read_memory(addr, self.ptr_size())?); addr = Address::from_usize(x); } ProjectionElem::Index(op) => { - let offset = - from_bytes!(usize, self.read_memory(locals.ptr[*op], self.ptr_size())?); - match &ty.data(Interner).kind { - TyKind::Ref(_, _, inner) => match &inner.data(Interner).kind { - TyKind::Slice(inner) => { - ty = inner.clone(); - let ty_size = self.size_of_sized( - &ty, - locals, - "slice inner type should be sized", - )?; - let value = self.read_memory(addr, self.ptr_size() * 2)?; - addr = Address::from_bytes(&value[0..8])?.offset(ty_size * offset); - } - x => not_supported!("MIR index for ref type {x:?}"), - }, - TyKind::Array(inner, _) | TyKind::Slice(inner) => { - ty = inner.clone(); - let ty_size = self.size_of_sized( - &ty, - locals, - "array inner type should be sized", - )?; - addr = addr.offset(ty_size * offset); - } - x => not_supported!("MIR index for type {x:?}"), - } + let offset = from_bytes!( + usize, + self.read_memory(locals.ptr[*op].addr, self.ptr_size())? + ); + metadata = None; // Result of index is always sized + let ty_size = + self.size_of_sized(&ty, locals, "array inner type should be sized")?; + addr = addr.offset(ty_size * offset); } - &ProjectionElem::TupleField(f) => match &ty.data(Interner).kind { - TyKind::Tuple(_, subst) => { - let layout = self.layout(&ty)?; - ty = subst - .as_slice(Interner) - .get(f) - .ok_or(MirEvalError::TypeError("not enough tuple fields"))? - .assert_ty_ref(Interner) - .clone(); - let offset = layout.fields.offset(f).bytes_usize(); - addr = addr.offset(offset); - } - _ => return Err(MirEvalError::TypeError("Only tuple has tuple fields")), - }, - ProjectionElem::Field(f) => match &ty.data(Interner).kind { - TyKind::Adt(adt, subst) => { - let layout = self.layout_adt(adt.0, subst.clone())?; - let variant_layout = match &layout.variants { - Variants::Single { .. } => &layout, - Variants::Multiple { variants, .. } => { - &variants[match f.parent { - hir_def::VariantId::EnumVariantId(x) => { - RustcEnumVariantIdx(x.local_id) - } - _ => { - return Err(MirEvalError::TypeError( - "Multivariant layout only happens for enums", - )) - } - }] - } + &ProjectionElem::ConstantIndex { from_end, offset } => { + let offset = if from_end { + let len = match prev_ty.kind(Interner) { + TyKind::Array(_, c) => match try_const_usize(self.db, c) { + Some(x) => x as u64, + None => { + not_supported!("indexing array with unknown const from end") + } + }, + TyKind::Slice(_) => match metadata { + Some(x) => from_bytes!(u64, x.get(self)?), + None => not_supported!("slice place without metadata"), + }, + _ => not_supported!("bad type for const index"), }; - ty = self.db.field_types(f.parent)[f.local_id] - .clone() - .substitute(Interner, subst); - let offset = variant_layout - .fields - .offset(u32::from(f.local_id.into_raw()) as usize) - .bytes_usize(); - addr = addr.offset(offset); - } - _ => return Err(MirEvalError::TypeError("Only adt has fields")), - }, - ProjectionElem::ConstantIndex { .. } => { - not_supported!("constant index") + (len - offset - 1) as usize + } else { + offset as usize + }; + metadata = None; // Result of index is always sized + let ty_size = + self.size_of_sized(&ty, locals, "array inner type should be sized")?; + addr = addr.offset(ty_size * offset); + } + &ProjectionElem::Subslice { from, to } => { + let inner_ty = match &ty.data(Interner).kind { + TyKind::Array(inner, _) | TyKind::Slice(inner) => inner.clone(), + _ => TyKind::Error.intern(Interner), + }; + metadata = match metadata { + Some(x) => { + let prev_len = from_bytes!(u64, x.get(self)?); + Some(IntervalOrOwned::Owned( + (prev_len - from - to).to_le_bytes().to_vec(), + )) + } + None => None, + }; + let ty_size = + self.size_of_sized(&inner_ty, locals, "array inner type should be sized")?; + addr = addr.offset(ty_size * (from as usize)); + } + &ProjectionElem::TupleOrClosureField(f) => { + let layout = self.layout(&prev_ty)?; + let offset = layout.fields.offset(f).bytes_usize(); + addr = addr.offset(offset); + metadata = None; // tuple field is always sized + } + ProjectionElem::Field(f) => { + let layout = self.layout(&prev_ty)?; + let variant_layout = match &layout.variants { + Variants::Single { .. } => &layout, + Variants::Multiple { variants, .. } => { + &variants[match f.parent { + hir_def::VariantId::EnumVariantId(x) => { + RustcEnumVariantIdx(x.local_id) + } + _ => { + return Err(MirEvalError::TypeError( + "Multivariant layout only happens for enums", + )) + } + }] + } + }; + let offset = variant_layout + .fields + .offset(u32::from(f.local_id.into_raw()) as usize) + .bytes_usize(); + addr = addr.offset(offset); + // FIXME: support structs with unsized fields + metadata = None; } - ProjectionElem::Subslice { .. } => not_supported!("subslice"), ProjectionElem::OpaqueCast(_) => not_supported!("opaque cast"), } } - Ok((addr, ty)) + Ok((addr, ty, metadata)) } - fn layout(&self, ty: &Ty) -> Result { - layout_of_ty(self.db, ty, self.crate_id) + fn layout(&self, ty: &Ty) -> Result> { + self.db + .layout_of_ty(ty.clone(), self.crate_id) .map_err(|e| MirEvalError::LayoutError(e, ty.clone())) } - fn layout_adt(&self, adt: AdtId, subst: Substitution) -> Result { - self.db.layout_of_adt(adt, subst.clone()).map_err(|e| { + fn layout_adt(&self, adt: AdtId, subst: Substitution) -> Result> { + self.db.layout_of_adt(adt, subst.clone(), self.crate_id).map_err(|e| { MirEvalError::LayoutError(e, TyKind::Adt(chalk_ir::AdtId(adt), subst).intern(Interner)) }) } fn place_ty<'a>(&'a self, p: &Place, locals: &'a Locals<'a>) -> Result { - Ok(self.place_addr_and_ty(p, locals)?.1) + Ok(self.place_addr_and_ty_and_metadata(p, locals)?.1) } - fn operand_ty<'a>(&'a self, o: &'a Operand, locals: &'a Locals<'a>) -> Result { + fn operand_ty(&self, o: &Operand, locals: &Locals<'_>) -> Result { Ok(match o { Operand::Copy(p) | Operand::Move(p) => self.place_ty(p, locals)?, Operand::Constant(c) => c.data(Interner).ty.clone(), + &Operand::Static(s) => { + let ty = self.db.infer(s.into())[self.db.body(s.into()).body_expr].clone(); + TyKind::Ref(Mutability::Not, static_lifetime(), ty).intern(Interner) + } + }) + } + + fn operand_ty_and_eval( + &mut self, + o: &Operand, + locals: &mut Locals<'_>, + ) -> Result { + Ok(IntervalAndTy { + interval: self.eval_operand(o, locals)?, + ty: self.operand_ty(o, locals)?, }) } @@ -382,7 +703,6 @@ impl Evaluator<'_> { &mut self, body: &MirBody, args: impl Iterator>, - subst: Substitution, ) -> Result> { if let Some(x) = self.stack_depth_limit.checked_sub(1) { self.stack_depth_limit = x; @@ -390,7 +710,8 @@ impl Evaluator<'_> { return Err(MirEvalError::StackOverflow); } let mut current_block_idx = body.start_block; - let mut locals = Locals { ptr: &ArenaMap::new(), body: &body, subst: &subst }; + let mut locals = + Locals { ptr: &ArenaMap::new(), body: &body, drop_flags: DropFlags::default() }; let (locals_ptr, stack_size) = { let mut stack_ptr = self.stack.len(); let addr = body @@ -401,7 +722,7 @@ impl Evaluator<'_> { self.size_of_sized(&x.ty, &locals, "no unsized local in extending stack")?; let my_ptr = stack_ptr; stack_ptr += size; - Ok((id, Stack(my_ptr))) + Ok((id, Interval { addr: Stack(my_ptr), size })) }) .collect::>>()?; let stack_size = stack_ptr - self.stack.len(); @@ -409,9 +730,10 @@ impl Evaluator<'_> { }; locals.ptr = &locals_ptr; self.stack.extend(iter::repeat(0).take(stack_size)); - let mut remain_args = body.arg_count; - for ((_, addr), value) in locals_ptr.iter().skip(1).zip(args) { - self.write_memory(*addr, &value)?; + let mut remain_args = body.param_locals.len(); + for ((l, interval), value) in locals_ptr.iter().skip(1).zip(args) { + locals.drop_flags.add_place(l.into()); + interval.write_from_bytes(self, &value)?; if remain_args == 0 { return Err(MirEvalError::TypeError("more arguments provided")); } @@ -431,8 +753,9 @@ impl Evaluator<'_> { match &statement.kind { StatementKind::Assign(l, r) => { let addr = self.place_addr(l, &locals)?; - let result = self.eval_rvalue(r, &locals)?.to_vec(&self)?; + let result = self.eval_rvalue(r, &mut locals)?.to_vec(&self)?; self.write_memory(addr, &result)?; + locals.drop_flags.add_place(l.clone()); } StatementKind::Deinit(_) => not_supported!("de-init statement"), StatementKind::StorageLive(_) @@ -443,11 +766,11 @@ impl Evaluator<'_> { let Some(terminator) = current_block.terminator.as_ref() else { not_supported!("block without terminator"); }; - match terminator { - Terminator::Goto { target } => { + match &terminator.kind { + TerminatorKind::Goto { target } => { current_block_idx = *target; } - Terminator::Call { + TerminatorKind::Call { func, args, destination, @@ -455,155 +778,84 @@ impl Evaluator<'_> { cleanup: _, from_hir_call: _, } => { + let destination_interval = self.place_interval(destination, &locals)?; let fn_ty = self.operand_ty(func, &locals)?; + let args = args + .iter() + .map(|x| self.operand_ty_and_eval(x, &mut locals)) + .collect::>>()?; match &fn_ty.data(Interner).kind { + TyKind::Function(_) => { + let bytes = self.eval_operand(func, &mut locals)?; + self.exec_fn_pointer( + bytes, + destination_interval, + &args, + &locals, + terminator.span, + )?; + } TyKind::FnDef(def, generic_args) => { - let def: CallableDefId = from_chalk(self.db, *def); - let generic_args = self.subst_filler(generic_args, &locals); - match def { - CallableDefId::FunctionId(def) => { - let arg_bytes = args - .iter() - .map(|x| { - Ok(self - .eval_operand(x, &locals)? - .get(&self)? - .to_owned()) - }) - .collect::>>()? - .into_iter(); - let function_data = self.db.function_data(def); - let is_intrinsic = match &function_data.abi { - Some(abi) => *abi == Interned::new_str("rust-intrinsic"), - None => match def.lookup(self.db.upcast()).container { - hir_def::ItemContainerId::ExternBlockId(block) => { - let id = block.lookup(self.db.upcast()).id; - id.item_tree(self.db.upcast())[id.value] - .abi - .as_deref() - == Some("rust-intrinsic") - } - _ => false, - }, - }; - let result = if is_intrinsic { - self.exec_intrinsic( - function_data - .name - .as_text() - .unwrap_or_default() - .as_str(), - arg_bytes, - generic_args, - &locals, - )? - } else if let Some(x) = self.detect_lang_function(def) { - self.exec_lang_item(x, arg_bytes)? - } else { - let trait_env = { - let Some(d) = body.owner.as_generic_def_id() else { - not_supported!("trait resolving in non generic def id"); - }; - self.db.trait_environment(d) - }; - let (imp, generic_args) = lookup_impl_method( - self.db, - trait_env, - def, - generic_args.clone(), - ); - let generic_args = - self.subst_filler(&generic_args, &locals); - let def = imp.into(); - let mir_body = self - .db - .mir_body(def) - .map_err(|e| MirEvalError::MirLowerError(imp, e))?; - self.interpret_mir(&mir_body, arg_bytes, generic_args) - .map_err(|e| { - MirEvalError::InFunction(imp, Box::new(e)) - })? - }; - let dest_addr = self.place_addr(destination, &locals)?; - self.write_memory(dest_addr, &result)?; - } - CallableDefId::StructId(id) => { - let (size, variant_layout, tag) = self.layout_of_variant( - id.into(), - generic_args.clone(), - &locals, - )?; - let result = self.make_by_layout( - size, - &variant_layout, - tag, - args, - &locals, - )?; - let dest_addr = self.place_addr(destination, &locals)?; - self.write_memory(dest_addr, &result)?; - } - CallableDefId::EnumVariantId(id) => { - let (size, variant_layout, tag) = self.layout_of_variant( - id.into(), - generic_args.clone(), - &locals, - )?; - let result = self.make_by_layout( - size, - &variant_layout, - tag, - args, - &locals, - )?; - let dest_addr = self.place_addr(destination, &locals)?; - self.write_memory(dest_addr, &result)?; - } - } - current_block_idx = - target.expect("broken mir, function without target"); + self.exec_fn_def( + *def, + generic_args, + destination_interval, + &args, + &locals, + terminator.span, + )?; } - _ => not_supported!("unknown function type"), + x => not_supported!("unknown function type {x:?}"), } + locals.drop_flags.add_place(destination.clone()); + current_block_idx = target.expect("broken mir, function without target"); } - Terminator::SwitchInt { discr, targets } => { + TerminatorKind::SwitchInt { discr, targets } => { let val = u128::from_le_bytes(pad16( - self.eval_operand(discr, &locals)?.get(&self)?, + self.eval_operand(discr, &mut locals)?.get(&self)?, false, )); current_block_idx = targets.target_for_value(val); } - Terminator::Return => { - let ty = body.locals[return_slot()].ty.clone(); + TerminatorKind::Return => { self.stack_depth_limit += 1; - return Ok(self - .read_memory( - locals.ptr[return_slot()], - self.size_of_sized(&ty, &locals, "return type")?, - )? - .to_owned()); + return Ok(locals.ptr[return_slot()].get(self)?.to_vec()); + } + TerminatorKind::Unreachable => { + return Err(MirEvalError::UndefinedBehavior("unreachable executed".to_owned())); } - Terminator::Unreachable => { - return Err(MirEvalError::UndefinedBehavior("unreachable executed")) + TerminatorKind::Drop { place, target, unwind: _ } => { + self.drop_place(place, &mut locals, terminator.span)?; + current_block_idx = *target; } _ => not_supported!("unknown terminator"), } } } - fn eval_rvalue<'a>( - &'a mut self, - r: &'a Rvalue, - locals: &'a Locals<'a>, - ) -> Result { + fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals<'_>) -> Result { use IntervalOrOwned::*; Ok(match r { Rvalue::Use(x) => Borrowed(self.eval_operand(x, locals)?), Rvalue::Ref(_, p) => { - let addr = self.place_addr(p, locals)?; - Owned(addr.to_bytes()) + let (addr, _, metadata) = self.place_addr_and_ty_and_metadata(p, locals)?; + let mut r = addr.to_bytes(); + if let Some(metadata) = metadata { + r.extend(metadata.get(self)?); + } + Owned(r) + } + Rvalue::Len(p) => { + let (_, _, metadata) = self.place_addr_and_ty_and_metadata(p, locals)?; + match metadata { + Some(m) => m, + None => { + return Err(MirEvalError::TypeError( + "type without metadata is used for Rvalue::Len", + )); + } + } } - Rvalue::Len(_) => not_supported!("rvalue len"), Rvalue::UnaryOp(op, val) => { let mut c = self.eval_operand(val, locals)?.get(&self)?; let mut ty = self.operand_ty(val, locals)?; @@ -612,27 +864,40 @@ impl Evaluator<'_> { let size = self.size_of_sized(&ty, locals, "operand of unary op")?; c = self.read_memory(Address::from_bytes(c)?, size)?; } - let mut c = c.to_vec(); - if ty.as_builtin() == Some(BuiltinType::Bool) { - c[0] = 1 - c[0]; + if let TyKind::Scalar(chalk_ir::Scalar::Float(f)) = ty.kind(Interner) { + match f { + chalk_ir::FloatTy::F32 => { + let c = -from_bytes!(f32, c); + Owned(c.to_le_bytes().into()) + } + chalk_ir::FloatTy::F64 => { + let c = -from_bytes!(f64, c); + Owned(c.to_le_bytes().into()) + } + } } else { - match op { - UnOp::Not => c.iter_mut().for_each(|x| *x = !*x), - UnOp::Neg => { - c.iter_mut().for_each(|x| *x = !*x); - for k in c.iter_mut() { - let o; - (*k, o) = k.overflowing_add(1); - if !o { - break; + let mut c = c.to_vec(); + if ty.as_builtin() == Some(BuiltinType::Bool) { + c[0] = 1 - c[0]; + } else { + match op { + UnOp::Not => c.iter_mut().for_each(|x| *x = !*x), + UnOp::Neg => { + c.iter_mut().for_each(|x| *x = !*x); + for k in c.iter_mut() { + let o; + (*k, o) = k.overflowing_add(1); + if !o { + break; + } } } } } + Owned(c) } - Owned(c) } - Rvalue::CheckedBinaryOp(op, lhs, rhs) => { + Rvalue::CheckedBinaryOp(op, lhs, rhs) => 'binary_op: { let lc = self.eval_operand(lhs, locals)?; let rc = self.eval_operand(rhs, locals)?; let mut lc = lc.get(&self)?; @@ -640,79 +905,170 @@ impl Evaluator<'_> { let mut ty = self.operand_ty(lhs, locals)?; while let TyKind::Ref(_, _, z) = ty.kind(Interner) { ty = z.clone(); - let size = self.size_of_sized(&ty, locals, "operand of binary op")?; + let size = if ty.kind(Interner) == &TyKind::Str { + if *op != BinOp::Eq { + never!("Only eq is builtin for `str`"); + } + let ls = from_bytes!(usize, &lc[self.ptr_size()..self.ptr_size() * 2]); + let rs = from_bytes!(usize, &rc[self.ptr_size()..self.ptr_size() * 2]); + if ls != rs { + break 'binary_op Owned(vec![0]); + } + lc = &lc[..self.ptr_size()]; + rc = &rc[..self.ptr_size()]; + ls + } else { + self.size_of_sized(&ty, locals, "operand of binary op")? + }; lc = self.read_memory(Address::from_bytes(lc)?, size)?; rc = self.read_memory(Address::from_bytes(rc)?, size)?; } - let is_signed = matches!(ty.as_builtin(), Some(BuiltinType::Int(_))); - let l128 = i128::from_le_bytes(pad16(lc, is_signed)); - let r128 = i128::from_le_bytes(pad16(rc, is_signed)); - match op { - BinOp::Ge | BinOp::Gt | BinOp::Le | BinOp::Lt | BinOp::Eq | BinOp::Ne => { - let r = match op { - BinOp::Ge => l128 >= r128, - BinOp::Gt => l128 > r128, - BinOp::Le => l128 <= r128, - BinOp::Lt => l128 < r128, - BinOp::Eq => l128 == r128, - BinOp::Ne => l128 != r128, - _ => unreachable!(), - }; - let r = r as u8; - Owned(vec![r]) + if let TyKind::Scalar(chalk_ir::Scalar::Float(f)) = ty.kind(Interner) { + match f { + chalk_ir::FloatTy::F32 => { + let l = from_bytes!(f32, lc); + let r = from_bytes!(f32, rc); + match op { + BinOp::Ge + | BinOp::Gt + | BinOp::Le + | BinOp::Lt + | BinOp::Eq + | BinOp::Ne => { + let r = op.run_compare(l, r) as u8; + Owned(vec![r]) + } + BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => { + let r = match op { + BinOp::Add => l + r, + BinOp::Sub => l - r, + BinOp::Mul => l * r, + BinOp::Div => l / r, + _ => unreachable!(), + }; + Owned(r.to_le_bytes().into()) + } + x => not_supported!( + "invalid binop {x:?} on floating point operators" + ), + } + } + chalk_ir::FloatTy::F64 => { + let l = from_bytes!(f64, lc); + let r = from_bytes!(f64, rc); + match op { + BinOp::Ge + | BinOp::Gt + | BinOp::Le + | BinOp::Lt + | BinOp::Eq + | BinOp::Ne => { + let r = op.run_compare(l, r) as u8; + Owned(vec![r]) + } + BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => { + let r = match op { + BinOp::Add => l + r, + BinOp::Sub => l - r, + BinOp::Mul => l * r, + BinOp::Div => l / r, + _ => unreachable!(), + }; + Owned(r.to_le_bytes().into()) + } + x => not_supported!( + "invalid binop {x:?} on floating point operators" + ), + } + } } - BinOp::BitAnd - | BinOp::BitOr - | BinOp::BitXor - | BinOp::Add - | BinOp::Mul - | BinOp::Div - | BinOp::Rem - | BinOp::Sub => { - let r = match op { - BinOp::Add => l128.overflowing_add(r128).0, - BinOp::Mul => l128.overflowing_mul(r128).0, - BinOp::Div => l128.checked_div(r128).ok_or(MirEvalError::Panic)?, - BinOp::Rem => l128.checked_rem(r128).ok_or(MirEvalError::Panic)?, - BinOp::Sub => l128.overflowing_sub(r128).0, - BinOp::BitAnd => l128 & r128, - BinOp::BitOr => l128 | r128, - BinOp::BitXor => l128 ^ r128, - _ => unreachable!(), - }; + } else { + let is_signed = matches!(ty.as_builtin(), Some(BuiltinType::Int(_))); + let l128 = i128::from_le_bytes(pad16(lc, is_signed)); + let r128 = i128::from_le_bytes(pad16(rc, is_signed)); + let check_overflow = |r: i128| { + // FIXME: this is not very correct, and only catches the basic cases. let r = r.to_le_bytes(); for &k in &r[lc.len()..] { if k != 0 && (k != 255 || !is_signed) { - return Err(MirEvalError::Panic); + return Err(MirEvalError::Panic(format!("Overflow in {op:?}"))); } } - Owned(r[0..lc.len()].into()) - } - BinOp::Shl | BinOp::Shr => { - let shift_amout = if r128 < 0 { - return Err(MirEvalError::Panic); - } else if r128 > 128 { - return Err(MirEvalError::Panic); - } else { - r128 as u8 - }; - let r = match op { - BinOp::Shl => l128 << shift_amout, - BinOp::Shr => l128 >> shift_amout, - _ => unreachable!(), - }; - Owned(r.to_le_bytes()[0..lc.len()].into()) + Ok(Owned(r[0..lc.len()].into())) + }; + match op { + BinOp::Ge | BinOp::Gt | BinOp::Le | BinOp::Lt | BinOp::Eq | BinOp::Ne => { + let r = op.run_compare(l128, r128) as u8; + Owned(vec![r]) + } + BinOp::BitAnd + | BinOp::BitOr + | BinOp::BitXor + | BinOp::Add + | BinOp::Mul + | BinOp::Div + | BinOp::Rem + | BinOp::Sub => { + let r = match op { + BinOp::Add => l128.overflowing_add(r128).0, + BinOp::Mul => l128.overflowing_mul(r128).0, + BinOp::Div => l128.checked_div(r128).ok_or_else(|| { + MirEvalError::Panic(format!("Overflow in {op:?}")) + })?, + BinOp::Rem => l128.checked_rem(r128).ok_or_else(|| { + MirEvalError::Panic(format!("Overflow in {op:?}")) + })?, + BinOp::Sub => l128.overflowing_sub(r128).0, + BinOp::BitAnd => l128 & r128, + BinOp::BitOr => l128 | r128, + BinOp::BitXor => l128 ^ r128, + _ => unreachable!(), + }; + check_overflow(r)? + } + BinOp::Shl | BinOp::Shr => { + let r = 'b: { + if let Ok(shift_amount) = u32::try_from(r128) { + let r = match op { + BinOp::Shl => l128.checked_shl(shift_amount), + BinOp::Shr => l128.checked_shr(shift_amount), + _ => unreachable!(), + }; + if let Some(r) = r { + break 'b r; + } + }; + return Err(MirEvalError::Panic(format!("Overflow in {op:?}"))); + }; + check_overflow(r)? + } + BinOp::Offset => not_supported!("offset binop"), } - BinOp::Offset => not_supported!("offset binop"), } } Rvalue::Discriminant(p) => { let ty = self.place_ty(p, locals)?; let bytes = self.eval_place(p, locals)?.get(&self)?; let layout = self.layout(&ty)?; - match layout.variants { - Variants::Single { .. } => Owned(0u128.to_le_bytes().to_vec()), - Variants::Multiple { tag, tag_encoding, .. } => { + let enum_id = 'b: { + match ty.kind(Interner) { + TyKind::Adt(e, _) => match e.0 { + AdtId::EnumId(e) => break 'b e, + _ => (), + }, + _ => (), + } + return Ok(Owned(0u128.to_le_bytes().to_vec())); + }; + match &layout.variants { + Variants::Single { index } => { + let r = self.const_eval_discriminant(EnumVariantId { + parent: enum_id, + local_id: index.0, + })?; + Owned(r.to_le_bytes().to_vec()) + } + Variants::Multiple { tag, tag_encoding, variants, .. } => { let Some(target_data_layout) = self.db.target_data_layout(self.crate_id) else { not_supported!("missing target data layout"); }; @@ -725,120 +1081,142 @@ impl Evaluator<'_> { } TagEncoding::Niche { untagged_variant, niche_start, .. } => { let tag = &bytes[offset..offset + size]; - let candidate_discriminant = i128::from_le_bytes(pad16(tag, false)) - .wrapping_sub(niche_start as i128); - let enum_id = match ty.kind(Interner) { - TyKind::Adt(e, _) => match e.0 { - AdtId::EnumId(e) => e, - _ => not_supported!("Non enum with multi variant layout"), - }, - _ => not_supported!("Non adt with multi variant layout"), - }; - let enum_data = self.db.enum_data(enum_id); - let result = 'b: { - for (local_id, _) in enum_data.variants.iter() { - if candidate_discriminant - == self.db.const_eval_discriminant(EnumVariantId { - parent: enum_id, - local_id, - })? - { - break 'b candidate_discriminant; - } - } - self.db.const_eval_discriminant(EnumVariantId { - parent: enum_id, - local_id: untagged_variant.0, - })? - }; + let candidate_tag = i128::from_le_bytes(pad16(tag, false)) + .wrapping_sub(*niche_start as i128) + as usize; + let variant = variants + .iter_enumerated() + .map(|(x, _)| x) + .filter(|x| x != untagged_variant) + .nth(candidate_tag) + .unwrap_or(*untagged_variant) + .0; + let result = self.const_eval_discriminant(EnumVariantId { + parent: enum_id, + local_id: variant, + })?; Owned(result.to_le_bytes().to_vec()) } } } } } + Rvalue::Repeat(x, len) => { + let len = match try_const_usize(self.db, &len) { + Some(x) => x as usize, + None => not_supported!("non evaluatable array len in repeat Rvalue"), + }; + let val = self.eval_operand(x, locals)?.get(self)?; + let size = len * val.len(); + Owned(val.iter().copied().cycle().take(size).collect()) + } Rvalue::ShallowInitBox(_, _) => not_supported!("shallow init box"), + Rvalue::ShallowInitBoxWithAlloc(ty) => { + let Some((size, align)) = self.size_align_of(ty, locals)? else { + not_supported!("unsized box initialization"); + }; + let addr = self.heap_allocate(size, align); + Owned(addr.to_bytes()) + } Rvalue::CopyForDeref(_) => not_supported!("copy for deref"), - Rvalue::Aggregate(kind, values) => match kind { - AggregateKind::Array(_) => { - let mut r = vec![]; - for x in values { - let value = self.eval_operand(x, locals)?.get(&self)?; - r.extend(value); + Rvalue::Aggregate(kind, values) => { + let values = values + .iter() + .map(|x| self.eval_operand(x, locals)) + .collect::>>()?; + match kind { + AggregateKind::Array(_) => { + let mut r = vec![]; + for x in values { + let value = x.get(&self)?; + r.extend(value); + } + Owned(r) + } + AggregateKind::Tuple(ty) => { + let layout = self.layout(&ty)?; + Owned(self.make_by_layout( + layout.size.bytes_usize(), + &layout, + None, + values.iter().map(|&x| x.into()), + )?) + } + AggregateKind::Union(x, f) => { + let layout = self.layout_adt((*x).into(), Substitution::empty(Interner))?; + let offset = layout + .fields + .offset(u32::from(f.local_id.into_raw()) as usize) + .bytes_usize(); + let op = values[0].get(&self)?; + let mut result = vec![0; layout.size.bytes_usize()]; + result[offset..offset + op.len()].copy_from_slice(op); + Owned(result) + } + AggregateKind::Adt(x, subst) => { + let (size, variant_layout, tag) = + self.layout_of_variant(*x, subst.clone(), locals)?; + Owned(self.make_by_layout( + size, + &variant_layout, + tag, + values.iter().map(|&x| x.into()), + )?) + } + AggregateKind::Closure(ty) => { + let layout = self.layout(&ty)?; + Owned(self.make_by_layout( + layout.size.bytes_usize(), + &layout, + None, + values.iter().map(|&x| x.into()), + )?) } - Owned(r) - } - AggregateKind::Tuple(ty) => { - let layout = self.layout(&ty)?; - Owned(self.make_by_layout( - layout.size.bytes_usize(), - &layout, - None, - values, - locals, - )?) - } - AggregateKind::Union(x, f) => { - let layout = self.layout_adt((*x).into(), Substitution::empty(Interner))?; - let offset = layout - .fields - .offset(u32::from(f.local_id.into_raw()) as usize) - .bytes_usize(); - let op = self.eval_operand(&values[0], locals)?.get(&self)?; - let mut result = vec![0; layout.size.bytes_usize()]; - result[offset..offset + op.len()].copy_from_slice(op); - Owned(result) - } - AggregateKind::Adt(x, subst) => { - let (size, variant_layout, tag) = - self.layout_of_variant(*x, subst.clone(), locals)?; - Owned(self.make_by_layout(size, &variant_layout, tag, values, locals)?) } - }, + } Rvalue::Cast(kind, operand, target_ty) => match kind { - CastKind::PointerExposeAddress => not_supported!("exposing pointer address"), - CastKind::PointerFromExposedAddress => { - not_supported!("creating pointer from exposed address") - } CastKind::Pointer(cast) => match cast { - PointerCast::Unsize => { + PointerCast::ReifyFnPointer | PointerCast::ClosureFnPointer(_) => { let current_ty = self.operand_ty(operand, locals)?; - match &target_ty.data(Interner).kind { - TyKind::Raw(_, ty) | TyKind::Ref(_, _, ty) => { - match &ty.data(Interner).kind { - TyKind::Slice(_) => match ¤t_ty.data(Interner).kind { - TyKind::Raw(_, ty) | TyKind::Ref(_, _, ty) => { - match &ty.data(Interner).kind { - TyKind::Array(_, size) => { - let addr = self - .eval_operand(operand, locals)? - .get(&self)?; - let len = const_as_usize(size); - let mut r = Vec::with_capacity(16); - r.extend(addr.iter().copied()); - r.extend(len.to_le_bytes().into_iter()); - Owned(r) - } - _ => { - not_supported!("slice unsizing from non arrays") - } - } - } - _ => not_supported!("slice unsizing from non pointers"), - }, - TyKind::Dyn(_) => not_supported!("dyn pointer unsize cast"), - _ => not_supported!("unknown unsized cast"), - } - } - _ => not_supported!("unsized cast on unknown pointer type"), + if let TyKind::FnDef(_, _) | TyKind::Closure(_, _) = + ¤t_ty.data(Interner).kind + { + let id = self.vtable_map.id(current_ty); + let ptr_size = self.ptr_size(); + Owned(id.to_le_bytes()[0..ptr_size].to_vec()) + } else { + not_supported!( + "creating a fn pointer from a non FnDef or Closure type" + ); } } - x => not_supported!("pointer cast {x:?}"), + PointerCast::Unsize => { + let current_ty = self.operand_ty(operand, locals)?; + let addr = self.eval_operand(operand, locals)?; + self.coerce_unsized(addr, ¤t_ty, target_ty)? + } + PointerCast::MutToConstPointer | PointerCast::UnsafeFnPointer => { + // This is no-op + Borrowed(self.eval_operand(operand, locals)?) + } + PointerCast::ArrayToPointer => { + // We should remove the metadata part if the current type is slice + Borrowed(self.eval_operand(operand, locals)?.slice(0..self.ptr_size())) + } }, CastKind::DynStar => not_supported!("dyn star cast"), - CastKind::IntToInt => { - // FIXME: handle signed cast - let current = pad16(self.eval_operand(operand, locals)?.get(&self)?, false); + CastKind::IntToInt + | CastKind::PointerExposeAddress + | CastKind::PointerFromExposedAddress => { + let current_ty = self.operand_ty(operand, locals)?; + let is_signed = match current_ty.kind(Interner) { + TyKind::Scalar(s) => match s { + chalk_ir::Scalar::Int(_) => true, + _ => false, + }, + _ => false, + }; + let current = pad16(self.eval_operand(operand, locals)?.get(&self)?, is_signed); let dest_size = self.size_of_sized(target_ty, locals, "destination of int to int cast")?; Owned(current[0..dest_size].to_vec()) @@ -846,31 +1224,106 @@ impl Evaluator<'_> { CastKind::FloatToInt => not_supported!("float to int cast"), CastKind::FloatToFloat => not_supported!("float to float cast"), CastKind::IntToFloat => not_supported!("float to int cast"), - CastKind::PtrToPtr => not_supported!("ptr to ptr cast"), CastKind::FnPtrToPtr => not_supported!("fn ptr to ptr cast"), }, }) } + fn coerce_unsized_look_through_fields( + &self, + ty: &Ty, + goal: impl Fn(&TyKind) -> Option, + ) -> Result { + let kind = ty.kind(Interner); + if let Some(x) = goal(kind) { + return Ok(x); + } + if let TyKind::Adt(id, subst) = kind { + if let AdtId::StructId(struct_id) = id.0 { + let field_types = self.db.field_types(struct_id.into()); + let mut field_types = field_types.iter(); + if let Some(ty) = + field_types.next().map(|x| x.1.clone().substitute(Interner, subst)) + { + return self.coerce_unsized_look_through_fields(&ty, goal); + } + } + } + Err(MirEvalError::CoerceUnsizedError(ty.clone())) + } + + fn coerce_unsized( + &mut self, + addr: Interval, + current_ty: &Ty, + target_ty: &Ty, + ) -> Result { + use IntervalOrOwned::*; + fn for_ptr(x: &TyKind) -> Option { + match x { + TyKind::Raw(_, ty) | TyKind::Ref(_, _, ty) => Some(ty.clone()), + _ => None, + } + } + Ok(match self.coerce_unsized_look_through_fields(target_ty, for_ptr)? { + ty => match &ty.data(Interner).kind { + TyKind::Slice(_) => { + match self.coerce_unsized_look_through_fields(current_ty, for_ptr)? { + ty => match &ty.data(Interner).kind { + TyKind::Array(_, size) => { + let len = match try_const_usize(self.db, size) { + None => not_supported!( + "unevaluatble len of array in coerce unsized" + ), + Some(x) => x as usize, + }; + let mut r = Vec::with_capacity(16); + let addr = addr.get(self)?; + r.extend(addr.iter().copied()); + r.extend(len.to_le_bytes().into_iter()); + Owned(r) + } + t => { + not_supported!("slice unsizing from non array type {t:?}") + } + }, + } + } + TyKind::Dyn(_) => match ¤t_ty.data(Interner).kind { + TyKind::Raw(_, ty) | TyKind::Ref(_, _, ty) => { + let vtable = self.vtable_map.id(ty.clone()); + let mut r = Vec::with_capacity(16); + let addr = addr.get(self)?; + r.extend(addr.iter().copied()); + r.extend(vtable.to_le_bytes().into_iter()); + Owned(r) + } + _ => not_supported!("dyn unsizing from non pointers"), + }, + _ => not_supported!("unknown unsized cast"), + }, + }) + } + fn layout_of_variant( &mut self, x: VariantId, subst: Substitution, locals: &Locals<'_>, - ) -> Result<(usize, Layout, Option<(usize, usize, i128)>)> { + ) -> Result<(usize, Arc, Option<(usize, usize, i128)>)> { let adt = x.adt_id(); if let DefWithBodyId::VariantId(f) = locals.body.owner { if let VariantId::EnumVariantId(x) = x { if AdtId::from(f.parent) == adt { // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and // infinite sized type errors) we use a dummy layout - let i = self.db.const_eval_discriminant(x)?; + let i = self.const_eval_discriminant(x)?; return Ok((16, self.layout(&TyBuilder::unit())?, Some((0, 16, i)))); } } } let layout = self.layout_adt(adt, subst)?; - Ok(match layout.variants { + Ok(match &layout.variants { Variants::Single { .. } => (layout.size.bytes_usize(), layout, None), Variants::Multiple { variants, tag, tag_encoding, .. } => { let cx = self @@ -882,18 +1335,27 @@ impl Evaluator<'_> { _ => not_supported!("multi variant layout for non-enums"), }; let rustc_enum_variant_idx = RustcEnumVariantIdx(enum_variant_id.local_id); - let mut discriminant = self.db.const_eval_discriminant(enum_variant_id)?; + let mut discriminant = self.const_eval_discriminant(enum_variant_id)?; let variant_layout = variants[rustc_enum_variant_idx].clone(); let have_tag = match tag_encoding { TagEncoding::Direct => true, TagEncoding::Niche { untagged_variant, niche_variants: _, niche_start } => { - discriminant = discriminant.wrapping_add(niche_start as i128); - untagged_variant != rustc_enum_variant_idx + if *untagged_variant == rustc_enum_variant_idx { + false + } else { + discriminant = (variants + .iter_enumerated() + .filter(|(x, _)| x != untagged_variant) + .position(|(x, _)| x == rustc_enum_variant_idx) + .unwrap() as i128) + .wrapping_add(*niche_start as i128); + true + } } }; ( layout.size.bytes_usize(), - variant_layout, + Arc::new(variant_layout), if have_tag { Some(( layout.fields.offset(0).bytes_usize(), @@ -910,71 +1372,84 @@ impl Evaluator<'_> { fn make_by_layout( &mut self, - size: usize, // Not neccessarily equal to variant_layout.size + size: usize, // Not necessarily equal to variant_layout.size variant_layout: &Layout, tag: Option<(usize, usize, i128)>, - values: &Vec, - locals: &Locals<'_>, + values: impl Iterator, ) -> Result> { let mut result = vec![0; size]; if let Some((offset, size, value)) = tag { result[offset..offset + size].copy_from_slice(&value.to_le_bytes()[0..size]); } - for (i, op) in values.iter().enumerate() { + for (i, op) in values.enumerate() { let offset = variant_layout.fields.offset(i).bytes_usize(); - let op = self.eval_operand(op, locals)?.get(&self)?; + let op = op.get(&self)?; result[offset..offset + op.len()].copy_from_slice(op); } Ok(result) } - fn eval_operand(&mut self, x: &Operand, locals: &Locals<'_>) -> Result { + fn eval_operand(&mut self, x: &Operand, locals: &mut Locals<'_>) -> Result { Ok(match x { - Operand::Copy(p) | Operand::Move(p) => self.eval_place(p, locals)?, + Operand::Copy(p) | Operand::Move(p) => { + locals.drop_flags.remove_place(p); + self.eval_place(p, locals)? + } + Operand::Static(st) => { + let addr = self.eval_static(*st, locals)?; + Interval::new(addr, self.ptr_size()) + } Operand::Constant(konst) => { let data = &konst.data(Interner); match &data.value { - chalk_ir::ConstValue::BoundVar(b) => { - let c = locals - .subst - .as_slice(Interner) - .get(b.index) - .ok_or(MirEvalError::TypeError("missing generic arg"))? - .assert_const_ref(Interner); - self.eval_operand(&Operand::Constant(c.clone()), locals)? - } + chalk_ir::ConstValue::BoundVar(_) => not_supported!("bound var constant"), chalk_ir::ConstValue::InferenceVar(_) => { not_supported!("inference var constant") } chalk_ir::ConstValue::Placeholder(_) => not_supported!("placeholder constant"), - chalk_ir::ConstValue::Concrete(c) => match &c.interned { - ConstScalar::Bytes(v, memory_map) => { - let mut v: Cow<'_, [u8]> = Cow::Borrowed(v); - let patch_map = memory_map.transform_addresses(|b| { - let addr = self.heap_allocate(b.len()); - self.write_memory(addr, b)?; - Ok(addr.to_usize()) - })?; - let size = self.size_of(&data.ty, locals)?.unwrap_or(v.len()); - if size != v.len() { - // Handle self enum - if size == 16 && v.len() < 16 { - v = Cow::Owned(pad16(&v, false).to_vec()); - } else if size < 16 && v.len() == 16 { - v = Cow::Owned(v[0..size].to_vec()); - } else { - return Err(MirEvalError::InvalidConst(konst.clone())); - } - } - let addr = self.heap_allocate(size); - self.write_memory(addr, &v)?; - self.patch_addresses(&patch_map, addr, &data.ty, locals)?; - Interval::new(addr, size) - } - ConstScalar::Unknown => not_supported!("evaluating unknown const"), - }, + chalk_ir::ConstValue::Concrete(c) => { + self.allocate_const_in_heap(c, &data.ty, locals, konst)? + } + } + } + }) + } + + fn allocate_const_in_heap( + &mut self, + c: &chalk_ir::ConcreteConst, + ty: &Ty, + locals: &Locals<'_>, + konst: &chalk_ir::Const, + ) -> Result { + Ok(match &c.interned { + ConstScalar::Bytes(v, memory_map) => { + let mut v: Cow<'_, [u8]> = Cow::Borrowed(v); + let patch_map = memory_map.transform_addresses(|b| { + let addr = self.heap_allocate(b.len(), 1); // FIXME: align is wrong + self.write_memory(addr, b)?; + Ok(addr.to_usize()) + })?; + let (size, align) = self.size_align_of(ty, locals)?.unwrap_or((v.len(), 1)); + if size != v.len() { + // Handle self enum + if size == 16 && v.len() < 16 { + v = Cow::Owned(pad16(&v, false).to_vec()); + } else if size < 16 && v.len() == 16 { + v = Cow::Owned(v[0..size].to_vec()); + } else { + return Err(MirEvalError::InvalidConst(konst.clone())); + } } + let addr = self.heap_allocate(size, align); + self.write_memory(addr, &v)?; + self.patch_addresses(&patch_map, &memory_map.vtable, addr, ty, locals)?; + Interval::new(addr, size) + } + ConstScalar::UnevaluatedConst(..) => { + not_supported!("unevaluated const present in monomorphized mir"); } + ConstScalar::Unknown => not_supported!("evaluating unknown const"), }) } @@ -987,197 +1462,205 @@ impl Evaluator<'_> { } fn read_memory(&self, addr: Address, size: usize) -> Result<&[u8]> { + if size == 0 { + return Ok(&[]); + } let (mem, pos) = match addr { Stack(x) => (&self.stack, x), Heap(x) => (&self.heap, x), + Invalid(x) => { + return Err(MirEvalError::UndefinedBehavior(format!( + "read invalid memory address {x} with size {size}" + ))); + } }; - mem.get(pos..pos + size).ok_or(MirEvalError::UndefinedBehavior("out of bound memory read")) + mem.get(pos..pos + size) + .ok_or_else(|| MirEvalError::UndefinedBehavior("out of bound memory read".to_string())) } fn write_memory(&mut self, addr: Address, r: &[u8]) -> Result<()> { + if r.is_empty() { + return Ok(()); + } let (mem, pos) = match addr { Stack(x) => (&mut self.stack, x), Heap(x) => (&mut self.heap, x), + Invalid(x) => { + return Err(MirEvalError::UndefinedBehavior(format!( + "write invalid memory address {x} with content {r:?}" + ))); + } }; mem.get_mut(pos..pos + r.len()) - .ok_or(MirEvalError::UndefinedBehavior("out of bound memory write"))? + .ok_or_else(|| { + MirEvalError::UndefinedBehavior("out of bound memory write".to_string()) + })? .copy_from_slice(r); Ok(()) } - fn size_of(&self, ty: &Ty, locals: &Locals<'_>) -> Result> { + fn size_align_of(&self, ty: &Ty, locals: &Locals<'_>) -> Result> { if let DefWithBodyId::VariantId(f) = locals.body.owner { if let Some((adt, _)) = ty.as_adt() { if AdtId::from(f.parent) == adt { // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and // infinite sized type errors) we use a dummy size - return Ok(Some(16)); + return Ok(Some((16, 16))); } } } - let ty = &self.ty_filler(ty, locals.subst, locals.body.owner)?; let layout = self.layout(ty); if self.assert_placeholder_ty_is_unused { if matches!(layout, Err(MirEvalError::LayoutError(LayoutError::HasPlaceholder, _))) { - return Ok(Some(0)); + return Ok(Some((0, 1))); } } let layout = layout?; - Ok(layout.is_sized().then(|| layout.size.bytes_usize())) + Ok(layout + .is_sized() + .then(|| (layout.size.bytes_usize(), layout.align.abi.bytes() as usize))) } /// A version of `self.size_of` which returns error if the type is unsized. `what` argument should /// be something that complete this: `error: type {ty} was unsized. {what} should be sized` fn size_of_sized(&self, ty: &Ty, locals: &Locals<'_>, what: &'static str) -> Result { - match self.size_of(ty, locals)? { - Some(x) => Ok(x), + match self.size_align_of(ty, locals)? { + Some(x) => Ok(x.0), None => Err(MirEvalError::TypeIsUnsized(ty.clone(), what)), } } - /// Uses `ty_filler` to fill an entire subst - fn subst_filler(&self, subst: &Substitution, locals: &Locals<'_>) -> Substitution { - Substitution::from_iter( - Interner, - subst.iter(Interner).map(|x| match x.data(Interner) { - chalk_ir::GenericArgData::Ty(ty) => { - let Ok(ty) = self.ty_filler(ty, locals.subst, locals.body.owner) else { - return x.clone(); - }; - chalk_ir::GenericArgData::Ty(ty).intern(Interner) - } - _ => x.clone(), - }), - ) - } - - /// This function substitutes placeholders of the body with the provided subst, effectively plays - /// the rule of monomorphization. In addition to placeholders, it substitutes opaque types (return - /// position impl traits) with their underlying type. - fn ty_filler(&self, ty: &Ty, subst: &Substitution, owner: DefWithBodyId) -> Result { - struct Filler<'a> { - db: &'a dyn HirDatabase, - subst: &'a Substitution, - skip_params: usize, - } - impl FallibleTypeFolder for Filler<'_> { - type Error = MirEvalError; - - fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder { - self - } - - fn interner(&self) -> Interner { - Interner - } - - fn try_fold_ty( - &mut self, - ty: Ty, - outer_binder: DebruijnIndex, - ) -> std::result::Result { - match ty.kind(Interner) { - TyKind::OpaqueType(id, subst) => { - let impl_trait_id = self.db.lookup_intern_impl_trait_id((*id).into()); - match impl_trait_id { - crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => { - let infer = self.db.infer(func.into()); - let filler = &mut Filler { db: self.db, subst, skip_params: 0 }; - filler.try_fold_ty(infer.type_of_rpit[idx].clone(), outer_binder) - } - crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { - not_supported!("async block impl trait"); - } - } - } - _ => ty.try_super_fold_with(self.as_dyn(), outer_binder), - } - } - - fn try_fold_free_placeholder_ty( - &mut self, - idx: chalk_ir::PlaceholderIndex, - _outer_binder: DebruijnIndex, - ) -> std::result::Result { - let x = from_placeholder_idx(self.db, idx); - Ok(self - .subst - .as_slice(Interner) - .get((u32::from(x.local_id.into_raw()) as usize) + self.skip_params) - .and_then(|x| x.ty(Interner)) - .ok_or(MirEvalError::TypeError("Generic arg not provided"))? - .clone()) - } - } - let filler = &mut Filler { db: self.db, subst, skip_params: 0 }; - Ok(normalize(self.db, owner, ty.clone().try_fold_with(filler, DebruijnIndex::INNERMOST)?)) - } - - fn heap_allocate(&mut self, s: usize) -> Address { + fn heap_allocate(&mut self, size: usize, _align: usize) -> Address { let pos = self.heap.len(); - self.heap.extend(iter::repeat(0).take(s)); + self.heap.extend(iter::repeat(0).take(size)); Address::Heap(pos) } - pub fn interpret_mir_with_no_arg(&mut self, body: &MirBody) -> Result> { - self.interpret_mir(&body, vec![].into_iter(), Substitution::empty(Interner)) - } - - fn detect_lang_function(&self, def: FunctionId) -> Option { - let candidate = lang_attr(self.db.upcast(), def)?; - // filter normal lang functions out - if [LangItem::IntoIterIntoIter, LangItem::IteratorNext].contains(&candidate) { + fn detect_fn_trait(&self, def: FunctionId) -> Option { + use LangItem::*; + let ItemContainerId::TraitId(parent) = self.db.lookup_intern_function(def).container else { return None; + }; + let l = lang_attr(self.db.upcast(), parent)?; + match l { + FnOnce => Some(FnTrait::FnOnce), + FnMut => Some(FnTrait::FnMut), + Fn => Some(FnTrait::Fn), + _ => None, } - Some(candidate) } fn create_memory_map(&self, bytes: &[u8], ty: &Ty, locals: &Locals<'_>) -> Result { - // FIXME: support indirect references - let mut mm = MemoryMap::default(); - match ty.kind(Interner) { - TyKind::Ref(_, _, t) => { - let size = self.size_of(t, locals)?; - match size { - Some(size) => { - let addr_usize = from_bytes!(usize, bytes); - mm.insert( - addr_usize, - self.read_memory(Address::from_usize(addr_usize), size)?.to_vec(), - ) - } - None => { - let element_size = match t.kind(Interner) { - TyKind::Str => 1, - TyKind::Slice(t) => { - self.size_of_sized(t, locals, "slice inner type")? + fn rec( + this: &Evaluator<'_>, + bytes: &[u8], + ty: &Ty, + locals: &Locals<'_>, + mm: &mut MemoryMap, + ) -> Result<()> { + match ty.kind(Interner) { + TyKind::Ref(_, _, t) => { + let size = this.size_align_of(t, locals)?; + match size { + Some((size, _)) => { + let addr_usize = from_bytes!(usize, bytes); + mm.insert( + addr_usize, + this.read_memory(Address::from_usize(addr_usize), size)?.to_vec(), + ) + } + None => { + let mut check_inner = None; + let element_size = match t.kind(Interner) { + TyKind::Str => 1, + TyKind::Slice(t) => { + check_inner = Some(t); + this.size_of_sized(t, locals, "slice inner type")? + } + _ => return Ok(()), // FIXME: support other kind of unsized types + }; + let (addr, meta) = bytes.split_at(bytes.len() / 2); + let count = from_bytes!(usize, meta); + let size = element_size * count; + let addr = Address::from_bytes(addr)?; + let b = this.read_memory(addr, size)?; + mm.insert(addr.to_usize(), b.to_vec()); + if let Some(ty) = check_inner { + for i in 0..count { + let offset = element_size * i; + rec(this, &b[offset..offset + element_size], ty, locals, mm)?; + } } - _ => return Ok(mm), // FIXME: support other kind of unsized types - }; - let (addr, meta) = bytes.split_at(bytes.len() / 2); - let size = element_size * from_bytes!(usize, meta); - let addr = Address::from_bytes(addr)?; - mm.insert(addr.to_usize(), self.read_memory(addr, size)?.to_vec()); + } } } + chalk_ir::TyKind::Tuple(_, subst) => { + let layout = this.layout(ty)?; + for (id, ty) in subst.iter(Interner).enumerate() { + let ty = ty.assert_ty_ref(Interner); // Tuple only has type argument + let offset = layout.fields.offset(id).bytes_usize(); + let size = this.layout(ty)?.size.bytes_usize(); + rec(this, &bytes[offset..offset + size], ty, locals, mm)?; + } + } + chalk_ir::TyKind::Adt(adt, subst) => match adt.0 { + AdtId::StructId(s) => { + let data = this.db.struct_data(s); + let layout = this.layout(ty)?; + let field_types = this.db.field_types(s.into()); + for (f, _) in data.variant_data.fields().iter() { + let offset = layout + .fields + .offset(u32::from(f.into_raw()) as usize) + .bytes_usize(); + let ty = &field_types[f].clone().substitute(Interner, subst); + let size = this.layout(ty)?.size.bytes_usize(); + rec(this, &bytes[offset..offset + size], ty, locals, mm)?; + } + } + AdtId::EnumId(e) => { + let layout = this.layout(ty)?; + if let Some((v, l)) = + detect_variant_from_bytes(&layout, this.db, this.crate_id, bytes, e) + { + let data = &this.db.enum_data(e).variants[v].variant_data; + let field_types = this + .db + .field_types(EnumVariantId { parent: e, local_id: v }.into()); + for (f, _) in data.fields().iter() { + let offset = + l.fields.offset(u32::from(f.into_raw()) as usize).bytes_usize(); + let ty = &field_types[f].clone().substitute(Interner, subst); + let size = this.layout(ty)?.size.bytes_usize(); + rec(this, &bytes[offset..offset + size], ty, locals, mm)?; + } + } + } + AdtId::UnionId(_) => (), + }, + _ => (), } - _ => (), + Ok(()) } + let mut mm = MemoryMap::default(); + rec(self, bytes, ty, locals, &mut mm)?; Ok(mm) } fn patch_addresses( &mut self, patch_map: &HashMap, + old_vtable: &VTableMap, addr: Address, ty: &Ty, locals: &Locals<'_>, ) -> Result<()> { // FIXME: support indirect references + let layout = self.layout(ty)?; let my_size = self.size_of_sized(ty, locals, "value to patch address")?; match ty.kind(Interner) { TyKind::Ref(_, _, t) => { - let size = self.size_of(t, locals)?; + let size = self.size_align_of(t, locals)?; match size { Some(_) => { let current = from_bytes!(usize, self.read_memory(addr, my_size)?); @@ -1193,51 +1676,441 @@ impl Evaluator<'_> { } } } - _ => (), + TyKind::Function(_) => { + let ty = old_vtable.ty_of_bytes(self.read_memory(addr, my_size)?)?.clone(); + let new_id = self.vtable_map.id(ty); + self.write_memory(addr, &new_id.to_le_bytes())?; + } + TyKind::Adt(id, subst) => match id.0 { + AdtId::StructId(s) => { + for (i, (_, ty)) in self.db.field_types(s.into()).iter().enumerate() { + let offset = layout.fields.offset(i).bytes_usize(); + let ty = ty.clone().substitute(Interner, subst); + self.patch_addresses( + patch_map, + old_vtable, + addr.offset(offset), + &ty, + locals, + )?; + } + } + AdtId::UnionId(_) => (), + AdtId::EnumId(_) => (), + }, + TyKind::AssociatedType(_, _) + | TyKind::Scalar(_) + | TyKind::Tuple(_, _) + | TyKind::Array(_, _) + | TyKind::Slice(_) + | TyKind::Raw(_, _) + | TyKind::OpaqueType(_, _) + | TyKind::FnDef(_, _) + | TyKind::Str + | TyKind::Never + | TyKind::Closure(_, _) + | TyKind::Generator(_, _) + | TyKind::GeneratorWitness(_, _) + | TyKind::Foreign(_) + | TyKind::Error + | TyKind::Placeholder(_) + | TyKind::Dyn(_) + | TyKind::Alias(_) + | TyKind::BoundVar(_) + | TyKind::InferenceVar(_, _) => (), } Ok(()) } - fn exec_intrinsic( - &self, - as_str: &str, - _arg_bytes: impl Iterator>, - generic_args: Substitution, + fn exec_fn_pointer( + &mut self, + bytes: Interval, + destination: Interval, + args: &[IntervalAndTy], locals: &Locals<'_>, - ) -> Result> { - match as_str { - "size_of" => { - let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { - return Err(MirEvalError::TypeError("size_of generic arg is not provided")); - }; - let size = self.size_of(ty, locals)?; - match size { - Some(x) => Ok(x.to_le_bytes().to_vec()), - None => return Err(MirEvalError::TypeError("size_of arg is unsized")), + span: MirSpan, + ) -> Result<()> { + let id = from_bytes!(usize, bytes.get(self)?); + let next_ty = self.vtable_map.ty(id)?.clone(); + match &next_ty.data(Interner).kind { + TyKind::FnDef(def, generic_args) => { + self.exec_fn_def(*def, generic_args, destination, args, &locals, span)?; + } + TyKind::Closure(id, subst) => { + self.exec_closure(*id, bytes.slice(0..0), subst, destination, args, locals, span)?; + } + _ => return Err(MirEvalError::TypeError("function pointer to non function")), + } + Ok(()) + } + + fn exec_closure( + &mut self, + closure: ClosureId, + closure_data: Interval, + generic_args: &Substitution, + destination: Interval, + args: &[IntervalAndTy], + locals: &Locals<'_>, + span: MirSpan, + ) -> Result<()> { + let mir_body = self + .db + .monomorphized_mir_body_for_closure( + closure, + generic_args.clone(), + self.trait_env.clone(), + ) + .map_err(|x| MirEvalError::MirLowerErrorForClosure(closure, x))?; + let closure_data = if mir_body.locals[mir_body.param_locals[0]].ty.as_reference().is_some() + { + closure_data.addr.to_bytes() + } else { + closure_data.get(self)?.to_owned() + }; + let arg_bytes = iter::once(Ok(closure_data)) + .chain(args.iter().map(|x| Ok(x.get(&self)?.to_owned()))) + .collect::>>()?; + let bytes = self.interpret_mir(&mir_body, arg_bytes.into_iter()).map_err(|e| { + MirEvalError::InFunction(Either::Right(closure), Box::new(e), span, locals.body.owner) + })?; + destination.write_from_bytes(self, &bytes) + } + + fn exec_fn_def( + &mut self, + def: FnDefId, + generic_args: &Substitution, + destination: Interval, + args: &[IntervalAndTy], + locals: &Locals<'_>, + span: MirSpan, + ) -> Result<()> { + let def: CallableDefId = from_chalk(self.db, def); + let generic_args = generic_args.clone(); + match def { + CallableDefId::FunctionId(def) => { + if let Some(_) = self.detect_fn_trait(def) { + self.exec_fn_trait(&args, destination, locals, span)?; + return Ok(()); } + self.exec_fn_with_args(def, args, generic_args, locals, destination, span)?; + } + CallableDefId::StructId(id) => { + let (size, variant_layout, tag) = + self.layout_of_variant(id.into(), generic_args, &locals)?; + let result = self.make_by_layout( + size, + &variant_layout, + tag, + args.iter().map(|x| x.interval.into()), + )?; + destination.write_from_bytes(self, &result)?; + } + CallableDefId::EnumVariantId(id) => { + let (size, variant_layout, tag) = + self.layout_of_variant(id.into(), generic_args, &locals)?; + let result = self.make_by_layout( + size, + &variant_layout, + tag, + args.iter().map(|x| x.interval.into()), + )?; + destination.write_from_bytes(self, &result)?; } - _ => not_supported!("unknown intrinsic {as_str}"), } + Ok(()) } - pub(crate) fn exec_lang_item( - &self, - x: LangItem, - mut args: std::vec::IntoIter>, - ) -> Result> { - use LangItem::*; - match x { - PanicFmt | BeginPanic => Err(MirEvalError::Panic), - SliceLen => { - let arg = args - .next() - .ok_or(MirEvalError::TypeError("argument of <[T]>::len() is not provided"))?; - let ptr_size = arg.len() / 2; - Ok(arg[ptr_size..].into()) + fn exec_fn_with_args( + &mut self, + def: FunctionId, + args: &[IntervalAndTy], + generic_args: Substitution, + locals: &Locals<'_>, + destination: Interval, + span: MirSpan, + ) -> Result<()> { + if self.detect_and_exec_special_function( + def, + args, + &generic_args, + locals, + destination, + span, + )? { + return Ok(()); + } + let arg_bytes = + args.iter().map(|x| Ok(x.get(&self)?.to_owned())).collect::>>()?; + if let Some(self_ty_idx) = + is_dyn_method(self.db, self.trait_env.clone(), def, generic_args.clone()) + { + // In the layout of current possible receiver, which at the moment of writing this code is one of + // `&T`, `&mut T`, `Box`, `Rc`, `Arc`, and `Pin

` where `P` is one of possible recievers, + // the vtable is exactly in the `[ptr_size..2*ptr_size]` bytes. So we can use it without branching on + // the type. + let ty = + self.vtable_map.ty_of_bytes(&arg_bytes[0][self.ptr_size()..self.ptr_size() * 2])?; + let mut args_for_target = args.to_vec(); + args_for_target[0] = IntervalAndTy { + interval: args_for_target[0].interval.slice(0..self.ptr_size()), + ty: ty.clone(), + }; + let ty = GenericArgData::Ty(ty.clone()).intern(Interner); + let generics_for_target = + Substitution::from_iter( + Interner, + generic_args.iter(Interner).enumerate().map(|(i, x)| { + if i == self_ty_idx { + &ty + } else { + x + } + }), + ); + return self.exec_fn_with_args( + def, + &args_for_target, + generics_for_target, + locals, + destination, + span, + ); + } + let (imp, generic_args) = + lookup_impl_method(self.db, self.trait_env.clone(), def, generic_args); + self.exec_looked_up_function(generic_args, locals, imp, arg_bytes, span, destination) + } + + fn exec_looked_up_function( + &mut self, + generic_args: Substitution, + locals: &Locals<'_>, + imp: FunctionId, + arg_bytes: Vec>, + span: MirSpan, + destination: Interval, + ) -> Result<()> { + let def = imp.into(); + let mir_body = self + .db + .monomorphized_mir_body(def, generic_args, self.trait_env.clone()) + .map_err(|e| { + MirEvalError::InFunction( + Either::Left(imp), + Box::new(MirEvalError::MirLowerError(imp, e)), + span, + locals.body.owner, + ) + })?; + let result = self.interpret_mir(&mir_body, arg_bytes.iter().cloned()).map_err(|e| { + MirEvalError::InFunction(Either::Left(imp), Box::new(e), span, locals.body.owner) + })?; + destination.write_from_bytes(self, &result)?; + Ok(()) + } + + fn exec_fn_trait( + &mut self, + args: &[IntervalAndTy], + destination: Interval, + locals: &Locals<'_>, + span: MirSpan, + ) -> Result<()> { + let func = args.get(0).ok_or(MirEvalError::TypeError("fn trait with no arg"))?; + let mut func_ty = func.ty.clone(); + let mut func_data = func.interval; + while let TyKind::Ref(_, _, z) = func_ty.kind(Interner) { + func_ty = z.clone(); + if matches!(func_ty.kind(Interner), TyKind::Dyn(_)) { + let id = + from_bytes!(usize, &func_data.get(self)?[self.ptr_size()..self.ptr_size() * 2]); + func_data = func_data.slice(0..self.ptr_size()); + func_ty = self.vtable_map.ty(id)?.clone(); + } + let size = self.size_of_sized(&func_ty, locals, "self type of fn trait")?; + func_data = Interval { addr: Address::from_bytes(func_data.get(self)?)?, size }; + } + match &func_ty.data(Interner).kind { + TyKind::FnDef(def, subst) => { + self.exec_fn_def(*def, subst, destination, &args[1..], locals, span)?; + } + TyKind::Function(_) => { + self.exec_fn_pointer(func_data, destination, &args[1..], locals, span)?; + } + TyKind::Closure(closure, subst) => { + self.exec_closure( + *closure, + func_data, + &Substitution::from_iter(Interner, ClosureSubst(subst).parent_subst()), + destination, + &args[1..], + locals, + span, + )?; + } + x => not_supported!("Call FnTrait methods with type {x:?}"), + } + Ok(()) + } + + fn eval_static(&mut self, st: StaticId, locals: &Locals<'_>) -> Result

{ + if let Some(o) = self.static_locations.get(&st) { + return Ok(*o); + }; + let static_data = self.db.static_data(st); + let result = if !static_data.is_extern { + let konst = self.db.const_eval_static(st).map_err(|e| { + MirEvalError::ConstEvalError( + static_data.name.as_str().unwrap_or("_").to_owned(), + Box::new(e), + ) + })?; + let data = &konst.data(Interner); + if let chalk_ir::ConstValue::Concrete(c) = &data.value { + self.allocate_const_in_heap(&c, &data.ty, locals, &konst)? + } else { + not_supported!("unevaluatable static"); + } + } else { + let ty = &self.db.infer(st.into())[self.db.body(st.into()).body_expr]; + let Some((size, align)) = self.size_align_of(&ty, locals)? else { + not_supported!("unsized extern static"); + }; + let addr = self.heap_allocate(size, align); + Interval::new(addr, size) + }; + let addr = self.heap_allocate(self.ptr_size(), self.ptr_size()); + self.write_memory(addr, &result.addr.to_bytes())?; + self.static_locations.insert(st, addr); + Ok(addr) + } + + fn const_eval_discriminant(&self, variant: EnumVariantId) -> Result { + let r = self.db.const_eval_discriminant(variant); + match r { + Ok(r) => Ok(r), + Err(e) => { + let data = self.db.enum_data(variant.parent); + let name = format!( + "{}::{}", + data.name.display(self.db.upcast()), + data.variants[variant.local_id].name.display(self.db.upcast()) + ); + Err(MirEvalError::ConstEvalError(name, Box::new(e))) } - x => not_supported!("Executing lang item {x:?}"), } } + + fn drop_place(&mut self, place: &Place, locals: &mut Locals<'_>, span: MirSpan) -> Result<()> { + let (addr, ty, metadata) = self.place_addr_and_ty_and_metadata(place, locals)?; + if !locals.drop_flags.remove_place(place) { + return Ok(()); + } + let metadata = match metadata { + Some(x) => x.get(self)?.to_vec(), + None => vec![], + }; + self.run_drop_glue_deep(ty, locals, addr, &metadata, span) + } + + fn run_drop_glue_deep( + &mut self, + ty: Ty, + locals: &Locals<'_>, + addr: Address, + _metadata: &[u8], + span: MirSpan, + ) -> Result<()> { + let Some(drop_fn) = (|| { + let drop_trait = self.db.lang_item(self.crate_id, LangItem::Drop)?.as_trait()?; + self.db.trait_data(drop_trait).method_by_name(&name![drop]) + })() else { + // in some tests we don't have drop trait in minicore, and + // we can ignore drop in them. + return Ok(()); + }; + let (impl_drop_candidate, subst) = lookup_impl_method( + self.db, + self.trait_env.clone(), + drop_fn, + Substitution::from1(Interner, ty.clone()), + ); + if impl_drop_candidate != drop_fn { + self.exec_looked_up_function( + subst, + locals, + impl_drop_candidate, + vec![addr.to_bytes()], + span, + Interval { addr: Address::Invalid(0), size: 0 }, + )?; + } + match ty.kind(Interner) { + TyKind::Adt(id, subst) => { + match id.0 { + AdtId::StructId(s) => { + let data = self.db.struct_data(s); + if data.flags.contains(StructFlags::IS_MANUALLY_DROP) { + return Ok(()); + } + let layout = self.layout_adt(id.0, subst.clone())?; + match data.variant_data.as_ref() { + VariantData::Record(fields) | VariantData::Tuple(fields) => { + let field_types = self.db.field_types(s.into()); + for (field, _) in fields.iter() { + let offset = layout + .fields + .offset(u32::from(field.into_raw()) as usize) + .bytes_usize(); + let addr = addr.offset(offset); + let ty = field_types[field].clone().substitute(Interner, subst); + self.run_drop_glue_deep(ty, locals, addr, &[], span)?; + } + } + VariantData::Unit => (), + } + } + AdtId::UnionId(_) => (), // union fields don't need drop + AdtId::EnumId(_) => (), + } + } + TyKind::AssociatedType(_, _) + | TyKind::Scalar(_) + | TyKind::Tuple(_, _) + | TyKind::Array(_, _) + | TyKind::Slice(_) + | TyKind::Raw(_, _) + | TyKind::Ref(_, _, _) + | TyKind::OpaqueType(_, _) + | TyKind::FnDef(_, _) + | TyKind::Str + | TyKind::Never + | TyKind::Closure(_, _) + | TyKind::Generator(_, _) + | TyKind::GeneratorWitness(_, _) + | TyKind::Foreign(_) + | TyKind::Error + | TyKind::Placeholder(_) + | TyKind::Dyn(_) + | TyKind::Alias(_) + | TyKind::Function(_) + | TyKind::BoundVar(_) + | TyKind::InferenceVar(_, _) => (), + }; + Ok(()) + } + + fn write_to_stdout(&mut self, interval: Interval) -> Result<()> { + self.stdout.extend(interval.get(self)?.to_vec()); + Ok(()) + } + + fn write_to_stderr(&mut self, interval: Interval) -> Result<()> { + self.stderr.extend(interval.get(self)?.to_vec()); + Ok(()) + } } pub fn pad16(x: &[u8], is_signed: bool) -> [u8; 16] { diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs new file mode 100644 index 0000000000000..3b9ef03c369f4 --- /dev/null +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -0,0 +1,792 @@ +//! Interpret intrinsics, lang items and `extern "C"` wellknown functions which their implementation +//! is not available. + +use std::cmp; + +use super::*; + +macro_rules! from_bytes { + ($ty:tt, $value:expr) => { + ($ty::from_le_bytes(match ($value).try_into() { + Ok(x) => x, + Err(_) => return Err(MirEvalError::TypeError("mismatched size")), + })) + }; +} + +macro_rules! not_supported { + ($x: expr) => { + return Err(MirEvalError::NotSupported(format!($x))) + }; +} + +impl Evaluator<'_> { + pub(super) fn detect_and_exec_special_function( + &mut self, + def: FunctionId, + args: &[IntervalAndTy], + generic_args: &Substitution, + locals: &Locals<'_>, + destination: Interval, + span: MirSpan, + ) -> Result { + let function_data = self.db.function_data(def); + let is_intrinsic = match &function_data.abi { + Some(abi) => *abi == Interned::new_str("rust-intrinsic"), + None => match def.lookup(self.db.upcast()).container { + hir_def::ItemContainerId::ExternBlockId(block) => { + let id = block.lookup(self.db.upcast()).id; + id.item_tree(self.db.upcast())[id.value].abi.as_deref() + == Some("rust-intrinsic") + } + _ => false, + }, + }; + if is_intrinsic { + self.exec_intrinsic( + function_data.name.as_text().unwrap_or_default().as_str(), + args, + generic_args, + destination, + &locals, + span, + )?; + return Ok(true); + } + let is_extern_c = match def.lookup(self.db.upcast()).container { + hir_def::ItemContainerId::ExternBlockId(block) => { + let id = block.lookup(self.db.upcast()).id; + id.item_tree(self.db.upcast())[id.value].abi.as_deref() == Some("C") + } + _ => false, + }; + if is_extern_c { + self.exec_extern_c( + function_data.name.as_text().unwrap_or_default().as_str(), + args, + generic_args, + destination, + &locals, + span, + )?; + return Ok(true); + } + let alloc_fn = function_data + .attrs + .iter() + .filter_map(|x| x.path().as_ident()) + .filter_map(|x| x.as_str()) + .find(|x| { + [ + "rustc_allocator", + "rustc_deallocator", + "rustc_reallocator", + "rustc_allocator_zeroed", + ] + .contains(x) + }); + if let Some(alloc_fn) = alloc_fn { + self.exec_alloc_fn(alloc_fn, args, destination)?; + return Ok(true); + } + if let Some(x) = self.detect_lang_function(def) { + let arg_bytes = + args.iter().map(|x| Ok(x.get(&self)?.to_owned())).collect::>>()?; + let result = self.exec_lang_item(x, generic_args, &arg_bytes, locals, span)?; + destination.write_from_bytes(self, &result)?; + return Ok(true); + } + Ok(false) + } + + fn exec_alloc_fn( + &mut self, + alloc_fn: &str, + args: &[IntervalAndTy], + destination: Interval, + ) -> Result<()> { + match alloc_fn { + "rustc_allocator_zeroed" | "rustc_allocator" => { + let [size, align] = args else { + return Err(MirEvalError::TypeError("rustc_allocator args are not provided")); + }; + let size = from_bytes!(usize, size.get(self)?); + let align = from_bytes!(usize, align.get(self)?); + let result = self.heap_allocate(size, align); + destination.write_from_bytes(self, &result.to_bytes())?; + } + "rustc_deallocator" => { /* no-op for now */ } + "rustc_reallocator" => { + let [ptr, old_size, align, new_size] = args else { + return Err(MirEvalError::TypeError("rustc_allocator args are not provided")); + }; + let ptr = Address::from_bytes(ptr.get(self)?)?; + let old_size = from_bytes!(usize, old_size.get(self)?); + let new_size = from_bytes!(usize, new_size.get(self)?); + let align = from_bytes!(usize, align.get(self)?); + let result = self.heap_allocate(new_size, align); + Interval { addr: result, size: old_size } + .write_from_interval(self, Interval { addr: ptr, size: old_size })?; + destination.write_from_bytes(self, &result.to_bytes())?; + } + _ => not_supported!("unknown alloc function"), + } + Ok(()) + } + + fn detect_lang_function(&self, def: FunctionId) -> Option { + use LangItem::*; + let candidate = lang_attr(self.db.upcast(), def)?; + // We want to execute these functions with special logic + if [PanicFmt, BeginPanic, SliceLen, DropInPlace].contains(&candidate) { + return Some(candidate); + } + None + } + + fn exec_lang_item( + &mut self, + x: LangItem, + generic_args: &Substitution, + args: &[Vec], + locals: &Locals<'_>, + span: MirSpan, + ) -> Result> { + use LangItem::*; + let mut args = args.iter(); + match x { + BeginPanic => Err(MirEvalError::Panic("".to_string())), + PanicFmt => { + let message = (|| { + let arguments_struct = + self.db.lang_item(self.crate_id, LangItem::FormatArguments)?.as_struct()?; + let arguments_layout = self + .layout_adt(arguments_struct.into(), Substitution::empty(Interner)) + .ok()?; + let arguments_field_pieces = + self.db.struct_data(arguments_struct).variant_data.field(&name![pieces])?; + let pieces_offset = arguments_layout + .fields + .offset(u32::from(arguments_field_pieces.into_raw()) as usize) + .bytes_usize(); + let ptr_size = self.ptr_size(); + let arg = args.next()?; + let pieces_array_addr = + Address::from_bytes(&arg[pieces_offset..pieces_offset + ptr_size]).ok()?; + let pieces_array_len = usize::from_le_bytes( + (&arg[pieces_offset + ptr_size..pieces_offset + 2 * ptr_size]) + .try_into() + .ok()?, + ); + let mut message = "".to_string(); + for i in 0..pieces_array_len { + let piece_ptr_addr = pieces_array_addr.offset(2 * i * ptr_size); + let piece_addr = + Address::from_bytes(self.read_memory(piece_ptr_addr, ptr_size).ok()?) + .ok()?; + let piece_len = usize::from_le_bytes( + self.read_memory(piece_ptr_addr.offset(ptr_size), ptr_size) + .ok()? + .try_into() + .ok()?, + ); + let piece_data = self.read_memory(piece_addr, piece_len).ok()?; + message += &std::string::String::from_utf8_lossy(piece_data); + } + Some(message) + })() + .unwrap_or_else(|| "".to_string()); + Err(MirEvalError::Panic(message)) + } + SliceLen => { + let arg = args + .next() + .ok_or(MirEvalError::TypeError("argument of <[T]>::len() is not provided"))?; + let ptr_size = arg.len() / 2; + Ok(arg[ptr_size..].into()) + } + DropInPlace => { + let ty = + generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)).ok_or( + MirEvalError::TypeError( + "generic argument of drop_in_place is not provided", + ), + )?; + let arg = args + .next() + .ok_or(MirEvalError::TypeError("argument of drop_in_place is not provided"))?; + self.run_drop_glue_deep( + ty.clone(), + locals, + Address::from_bytes(&arg[0..self.ptr_size()])?, + &arg[self.ptr_size()..], + span, + )?; + Ok(vec![]) + } + x => not_supported!("Executing lang item {x:?}"), + } + } + + fn exec_extern_c( + &mut self, + as_str: &str, + args: &[IntervalAndTy], + _generic_args: &Substitution, + destination: Interval, + locals: &Locals<'_>, + _span: MirSpan, + ) -> Result<()> { + match as_str { + "memcmp" => { + let [ptr1, ptr2, size] = args else { + return Err(MirEvalError::TypeError("memcmp args are not provided")); + }; + let addr1 = Address::from_bytes(ptr1.get(self)?)?; + let addr2 = Address::from_bytes(ptr2.get(self)?)?; + let size = from_bytes!(usize, size.get(self)?); + let slice1 = self.read_memory(addr1, size)?; + let slice2 = self.read_memory(addr2, size)?; + let r: i128 = match slice1.cmp(slice2) { + cmp::Ordering::Less => -1, + cmp::Ordering::Equal => 0, + cmp::Ordering::Greater => 1, + }; + destination.write_from_bytes(self, &r.to_le_bytes()[..destination.size]) + } + "write" => { + let [fd, ptr, len] = args else { + return Err(MirEvalError::TypeError("libc::write args are not provided")); + }; + let fd = u128::from_le_bytes(pad16(fd.get(self)?, false)); + let interval = Interval { + addr: Address::from_bytes(ptr.get(self)?)?, + size: from_bytes!(usize, len.get(self)?), + }; + match fd { + 1 => { + self.write_to_stdout(interval)?; + } + 2 => { + self.write_to_stderr(interval)?; + } + _ => not_supported!("write to arbitrary file descriptor"), + } + destination.write_from_interval(self, len.interval)?; + Ok(()) + } + "pthread_key_create" => { + let key = self.thread_local_storage.create_key(); + let Some(arg0) = args.get(0) else { + return Err(MirEvalError::TypeError("pthread_key_create arg0 is not provided")); + }; + let arg0_addr = Address::from_bytes(arg0.get(self)?)?; + let key_ty = if let Some((ty, ..)) = arg0.ty.as_reference_or_ptr() { + ty + } else { + return Err(MirEvalError::TypeError( + "pthread_key_create arg0 is not a pointer", + )); + }; + let arg0_interval = Interval::new( + arg0_addr, + self.size_of_sized(key_ty, locals, "pthread_key_create key arg")?, + ); + arg0_interval.write_from_bytes(self, &key.to_le_bytes()[0..arg0_interval.size])?; + // return 0 as success + destination.write_from_bytes(self, &0u64.to_le_bytes()[0..destination.size])?; + Ok(()) + } + "pthread_getspecific" => { + let Some(arg0) = args.get(0) else { + return Err(MirEvalError::TypeError("pthread_getspecific arg0 is not provided")); + }; + let key = from_bytes!(usize, &pad16(arg0.get(self)?, false)[0..8]); + let value = self.thread_local_storage.get_key(key)?; + destination.write_from_bytes(self, &value.to_le_bytes()[0..destination.size])?; + Ok(()) + } + "pthread_setspecific" => { + let Some(arg0) = args.get(0) else { + return Err(MirEvalError::TypeError("pthread_setspecific arg0 is not provided")); + }; + let key = from_bytes!(usize, &pad16(arg0.get(self)?, false)[0..8]); + let Some(arg1) = args.get(1) else { + return Err(MirEvalError::TypeError("pthread_setspecific arg1 is not provided")); + }; + let value = from_bytes!(u128, pad16(arg1.get(self)?, false)); + self.thread_local_storage.set_key(key, value)?; + // return 0 as success + destination.write_from_bytes(self, &0u64.to_le_bytes()[0..destination.size])?; + Ok(()) + } + "pthread_key_delete" => { + // we ignore this currently + // return 0 as success + destination.write_from_bytes(self, &0u64.to_le_bytes()[0..destination.size])?; + Ok(()) + } + _ => not_supported!("unknown external function {as_str}"), + } + } + + fn exec_intrinsic( + &mut self, + name: &str, + args: &[IntervalAndTy], + generic_args: &Substitution, + destination: Interval, + locals: &Locals<'_>, + span: MirSpan, + ) -> Result<()> { + if let Some(name) = name.strip_prefix("atomic_") { + return self.exec_atomic_intrinsic(name, args, generic_args, destination, locals, span); + } + if let Some(name) = name.strip_suffix("f64") { + let result = match name { + "sqrt" | "sin" | "cos" | "exp" | "exp2" | "log" | "log10" | "log2" | "fabs" + | "floor" | "ceil" | "trunc" | "rint" | "nearbyint" | "round" | "roundeven" => { + let [arg] = args else { + return Err(MirEvalError::TypeError("f64 intrinsic signature doesn't match fn (f64) -> f64")); + }; + let arg = from_bytes!(f64, arg.get(self)?); + match name { + "sqrt" => arg.sqrt(), + "sin" => arg.sin(), + "cos" => arg.cos(), + "exp" => arg.exp(), + "exp2" => arg.exp2(), + "log" => arg.ln(), + "log10" => arg.log10(), + "log2" => arg.log2(), + "fabs" => arg.abs(), + "floor" => arg.floor(), + "ceil" => arg.ceil(), + "trunc" => arg.trunc(), + // FIXME: these rounds should be different, but only `.round()` is stable now. + "rint" => arg.round(), + "nearbyint" => arg.round(), + "round" => arg.round(), + "roundeven" => arg.round(), + _ => unreachable!(), + } + } + "pow" | "minnum" | "maxnum" | "copysign" => { + let [arg1, arg2] = args else { + return Err(MirEvalError::TypeError("f64 intrinsic signature doesn't match fn (f64, f64) -> f64")); + }; + let arg1 = from_bytes!(f64, arg1.get(self)?); + let arg2 = from_bytes!(f64, arg2.get(self)?); + match name { + "pow" => arg1.powf(arg2), + "minnum" => arg1.min(arg2), + "maxnum" => arg1.max(arg2), + "copysign" => arg1.copysign(arg2), + _ => unreachable!(), + } + } + "powi" => { + let [arg1, arg2] = args else { + return Err(MirEvalError::TypeError("powif64 signature doesn't match fn (f64, i32) -> f64")); + }; + let arg1 = from_bytes!(f64, arg1.get(self)?); + let arg2 = from_bytes!(i32, arg2.get(self)?); + arg1.powi(arg2) + } + "fma" => { + let [arg1, arg2, arg3] = args else { + return Err(MirEvalError::TypeError("fmaf64 signature doesn't match fn (f64, f64, f64) -> f64")); + }; + let arg1 = from_bytes!(f64, arg1.get(self)?); + let arg2 = from_bytes!(f64, arg2.get(self)?); + let arg3 = from_bytes!(f64, arg3.get(self)?); + arg1.mul_add(arg2, arg3) + } + _ => not_supported!("unknown f64 intrinsic {name}"), + }; + return destination.write_from_bytes(self, &result.to_le_bytes()); + } + if let Some(name) = name.strip_suffix("f32") { + let result = match name { + "sqrt" | "sin" | "cos" | "exp" | "exp2" | "log" | "log10" | "log2" | "fabs" + | "floor" | "ceil" | "trunc" | "rint" | "nearbyint" | "round" | "roundeven" => { + let [arg] = args else { + return Err(MirEvalError::TypeError("f32 intrinsic signature doesn't match fn (f32) -> f32")); + }; + let arg = from_bytes!(f32, arg.get(self)?); + match name { + "sqrt" => arg.sqrt(), + "sin" => arg.sin(), + "cos" => arg.cos(), + "exp" => arg.exp(), + "exp2" => arg.exp2(), + "log" => arg.ln(), + "log10" => arg.log10(), + "log2" => arg.log2(), + "fabs" => arg.abs(), + "floor" => arg.floor(), + "ceil" => arg.ceil(), + "trunc" => arg.trunc(), + // FIXME: these rounds should be different, but only `.round()` is stable now. + "rint" => arg.round(), + "nearbyint" => arg.round(), + "round" => arg.round(), + "roundeven" => arg.round(), + _ => unreachable!(), + } + } + "pow" | "minnum" | "maxnum" | "copysign" => { + let [arg1, arg2] = args else { + return Err(MirEvalError::TypeError("f32 intrinsic signature doesn't match fn (f32, f32) -> f32")); + }; + let arg1 = from_bytes!(f32, arg1.get(self)?); + let arg2 = from_bytes!(f32, arg2.get(self)?); + match name { + "pow" => arg1.powf(arg2), + "minnum" => arg1.min(arg2), + "maxnum" => arg1.max(arg2), + "copysign" => arg1.copysign(arg2), + _ => unreachable!(), + } + } + "powi" => { + let [arg1, arg2] = args else { + return Err(MirEvalError::TypeError("powif32 signature doesn't match fn (f32, i32) -> f32")); + }; + let arg1 = from_bytes!(f32, arg1.get(self)?); + let arg2 = from_bytes!(i32, arg2.get(self)?); + arg1.powi(arg2) + } + "fma" => { + let [arg1, arg2, arg3] = args else { + return Err(MirEvalError::TypeError("fmaf32 signature doesn't match fn (f32, f32, f32) -> f32")); + }; + let arg1 = from_bytes!(f32, arg1.get(self)?); + let arg2 = from_bytes!(f32, arg2.get(self)?); + let arg3 = from_bytes!(f32, arg3.get(self)?); + arg1.mul_add(arg2, arg3) + } + _ => not_supported!("unknown f32 intrinsic {name}"), + }; + return destination.write_from_bytes(self, &result.to_le_bytes()); + } + match name { + "size_of" => { + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { + return Err(MirEvalError::TypeError("size_of generic arg is not provided")); + }; + let size = self.size_of_sized(ty, locals, "size_of arg")?; + destination.write_from_bytes(self, &size.to_le_bytes()[0..destination.size]) + } + "min_align_of" | "pref_align_of" => { + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { + return Err(MirEvalError::TypeError("align_of generic arg is not provided")); + }; + let align = self.layout(ty)?.align.abi.bytes(); + destination.write_from_bytes(self, &align.to_le_bytes()[0..destination.size]) + } + "needs_drop" => { + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { + return Err(MirEvalError::TypeError("size_of generic arg is not provided")); + }; + let result = !ty.clone().is_copy(self.db, locals.body.owner); + destination.write_from_bytes(self, &[u8::from(result)]) + } + "ptr_guaranteed_cmp" => { + // FIXME: this is wrong for const eval, it should return 2 in some + // cases. + let [lhs, rhs] = args else { + return Err(MirEvalError::TypeError("wrapping_add args are not provided")); + }; + let ans = lhs.get(self)? == rhs.get(self)?; + destination.write_from_bytes(self, &[u8::from(ans)]) + } + "saturating_add" => { + let [lhs, rhs] = args else { + return Err(MirEvalError::TypeError("saturating_add args are not provided")); + }; + let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, false)); + let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, false)); + let ans = lhs.saturating_add(rhs); + let bits = destination.size * 8; + // FIXME: signed + let is_signed = false; + let mx: u128 = if is_signed { (1 << (bits - 1)) - 1 } else { (1 << bits) - 1 }; + // FIXME: signed + let mn: u128 = 0; + let ans = cmp::min(mx, cmp::max(mn, ans)); + destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]) + } + "wrapping_add" | "unchecked_add" => { + let [lhs, rhs] = args else { + return Err(MirEvalError::TypeError("wrapping_add args are not provided")); + }; + let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, false)); + let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, false)); + let ans = lhs.wrapping_add(rhs); + destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]) + } + "wrapping_sub" | "unchecked_sub" | "ptr_offset_from_unsigned" | "ptr_offset_from" => { + let [lhs, rhs] = args else { + return Err(MirEvalError::TypeError("wrapping_sub args are not provided")); + }; + let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, false)); + let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, false)); + let ans = lhs.wrapping_sub(rhs); + destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]) + } + "wrapping_mul" | "unchecked_mul" => { + let [lhs, rhs] = args else { + return Err(MirEvalError::TypeError("wrapping_mul args are not provided")); + }; + let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, false)); + let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, false)); + let ans = lhs.wrapping_mul(rhs); + destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]) + } + "unchecked_rem" => { + // FIXME: signed + let [lhs, rhs] = args else { + return Err(MirEvalError::TypeError("unchecked_rem args are not provided")); + }; + let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, false)); + let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, false)); + let ans = lhs.checked_rem(rhs).ok_or_else(|| { + MirEvalError::UndefinedBehavior("unchecked_rem with bad inputs".to_owned()) + })?; + destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]) + } + "unchecked_div" | "exact_div" => { + // FIXME: signed + let [lhs, rhs] = args else { + return Err(MirEvalError::TypeError("unchecked_div args are not provided")); + }; + let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, false)); + let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, false)); + let ans = lhs.checked_div(rhs).ok_or_else(|| { + MirEvalError::UndefinedBehavior("unchecked_rem with bad inputs".to_owned()) + })?; + destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]) + } + "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => { + let [lhs, rhs] = args else { + return Err(MirEvalError::TypeError("const_eval_select args are not provided")); + }; + let result_ty = TyKind::Tuple( + 2, + Substitution::from_iter(Interner, [lhs.ty.clone(), TyBuilder::bool()]), + ) + .intern(Interner); + let op_size = + self.size_of_sized(&lhs.ty, locals, "operand of add_with_overflow")?; + let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, false)); + let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, false)); + let (ans, u128overflow) = match name { + "add_with_overflow" => lhs.overflowing_add(rhs), + "sub_with_overflow" => lhs.overflowing_sub(rhs), + "mul_with_overflow" => lhs.overflowing_mul(rhs), + _ => unreachable!(), + }; + let is_overflow = u128overflow + || ans.to_le_bytes()[op_size..].iter().any(|&x| x != 0 && x != 255); + let is_overflow = vec![u8::from(is_overflow)]; + let layout = self.layout(&result_ty)?; + let result = self.make_by_layout( + layout.size.bytes_usize(), + &layout, + None, + [ans.to_le_bytes()[0..op_size].to_vec(), is_overflow] + .into_iter() + .map(IntervalOrOwned::Owned), + )?; + destination.write_from_bytes(self, &result) + } + "copy" | "copy_nonoverlapping" => { + let [src, dst, offset] = args else { + return Err(MirEvalError::TypeError("copy_nonoverlapping args are not provided")); + }; + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { + return Err(MirEvalError::TypeError("copy_nonoverlapping generic arg is not provided")); + }; + let src = Address::from_bytes(src.get(self)?)?; + let dst = Address::from_bytes(dst.get(self)?)?; + let offset = from_bytes!(usize, offset.get(self)?); + let size = self.size_of_sized(ty, locals, "copy_nonoverlapping ptr type")?; + let size = offset * size; + let src = Interval { addr: src, size }; + let dst = Interval { addr: dst, size }; + dst.write_from_interval(self, src) + } + "offset" | "arith_offset" => { + let [ptr, offset] = args else { + return Err(MirEvalError::TypeError("offset args are not provided")); + }; + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { + return Err(MirEvalError::TypeError("offset generic arg is not provided")); + }; + let ptr = u128::from_le_bytes(pad16(ptr.get(self)?, false)); + let offset = u128::from_le_bytes(pad16(offset.get(self)?, false)); + let size = self.size_of_sized(ty, locals, "offset ptr type")? as u128; + let ans = ptr + offset * size; + destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]) + } + "assert_inhabited" | "assert_zero_valid" | "assert_uninit_valid" | "assume" => { + // FIXME: We should actually implement these checks + Ok(()) + } + "forget" => { + // We don't call any drop glue yet, so there is nothing here + Ok(()) + } + "transmute" => { + let [arg] = args else { + return Err(MirEvalError::TypeError("trasmute arg is not provided")); + }; + destination.write_from_interval(self, arg.interval) + } + "likely" | "unlikely" => { + let [arg] = args else { + return Err(MirEvalError::TypeError("likely arg is not provided")); + }; + destination.write_from_interval(self, arg.interval) + } + "ctpop" => { + let [arg] = args else { + return Err(MirEvalError::TypeError("likely arg is not provided")); + }; + let result = u128::from_le_bytes(pad16(arg.get(self)?, false)).count_ones(); + destination + .write_from_bytes(self, &(result as u128).to_le_bytes()[0..destination.size]) + } + "cttz" | "cttz_nonzero" => { + let [arg] = args else { + return Err(MirEvalError::TypeError("likely arg is not provided")); + }; + let result = u128::from_le_bytes(pad16(arg.get(self)?, false)).trailing_zeros(); + destination + .write_from_bytes(self, &(result as u128).to_le_bytes()[0..destination.size]) + } + "const_eval_select" => { + let [tuple, const_fn, _] = args else { + return Err(MirEvalError::TypeError("const_eval_select args are not provided")); + }; + let mut args = vec![const_fn.clone()]; + let TyKind::Tuple(_, fields) = tuple.ty.kind(Interner) else { + return Err(MirEvalError::TypeError("const_eval_select arg[0] is not a tuple")); + }; + let layout = self.layout(&tuple.ty)?; + for (i, field) in fields.iter(Interner).enumerate() { + let field = field.assert_ty_ref(Interner).clone(); + let offset = layout.fields.offset(i).bytes_usize(); + let addr = tuple.interval.addr.offset(offset); + args.push(IntervalAndTy::new(addr, field, self, locals)?); + } + self.exec_fn_trait(&args, destination, locals, span) + } + _ => not_supported!("unknown intrinsic {name}"), + } + } + + fn exec_atomic_intrinsic( + &mut self, + name: &str, + args: &[IntervalAndTy], + generic_args: &Substitution, + destination: Interval, + locals: &Locals<'_>, + _span: MirSpan, + ) -> Result<()> { + // We are a single threaded runtime with no UB checking and no optimization, so + // we can implement these as normal functions. + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { + return Err(MirEvalError::TypeError("atomic intrinsic generic arg is not provided")); + }; + let Some(arg0) = args.get(0) else { + return Err(MirEvalError::TypeError("atomic intrinsic arg0 is not provided")); + }; + let arg0_addr = Address::from_bytes(arg0.get(self)?)?; + let arg0_interval = + Interval::new(arg0_addr, self.size_of_sized(ty, locals, "atomic intrinsic type arg")?); + if name.starts_with("load_") { + return destination.write_from_interval(self, arg0_interval); + } + let Some(arg1) = args.get(1) else { + return Err(MirEvalError::TypeError("atomic intrinsic arg1 is not provided")); + }; + if name.starts_with("store_") { + return arg0_interval.write_from_interval(self, arg1.interval); + } + if name.starts_with("xchg_") { + destination.write_from_interval(self, arg0_interval)?; + return arg0_interval.write_from_interval(self, arg1.interval); + } + if name.starts_with("xadd_") { + destination.write_from_interval(self, arg0_interval)?; + let lhs = u128::from_le_bytes(pad16(arg0_interval.get(self)?, false)); + let rhs = u128::from_le_bytes(pad16(arg1.get(self)?, false)); + let ans = lhs.wrapping_add(rhs); + return arg0_interval.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]); + } + if name.starts_with("xsub_") { + destination.write_from_interval(self, arg0_interval)?; + let lhs = u128::from_le_bytes(pad16(arg0_interval.get(self)?, false)); + let rhs = u128::from_le_bytes(pad16(arg1.get(self)?, false)); + let ans = lhs.wrapping_sub(rhs); + return arg0_interval.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]); + } + if name.starts_with("and_") { + destination.write_from_interval(self, arg0_interval)?; + let lhs = u128::from_le_bytes(pad16(arg0_interval.get(self)?, false)); + let rhs = u128::from_le_bytes(pad16(arg1.get(self)?, false)); + let ans = lhs & rhs; + return arg0_interval.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]); + } + if name.starts_with("or_") { + destination.write_from_interval(self, arg0_interval)?; + let lhs = u128::from_le_bytes(pad16(arg0_interval.get(self)?, false)); + let rhs = u128::from_le_bytes(pad16(arg1.get(self)?, false)); + let ans = lhs | rhs; + return arg0_interval.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]); + } + if name.starts_with("xor_") { + destination.write_from_interval(self, arg0_interval)?; + let lhs = u128::from_le_bytes(pad16(arg0_interval.get(self)?, false)); + let rhs = u128::from_le_bytes(pad16(arg1.get(self)?, false)); + let ans = lhs ^ rhs; + return arg0_interval.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]); + } + if name.starts_with("nand_") { + destination.write_from_interval(self, arg0_interval)?; + let lhs = u128::from_le_bytes(pad16(arg0_interval.get(self)?, false)); + let rhs = u128::from_le_bytes(pad16(arg1.get(self)?, false)); + let ans = !(lhs & rhs); + return arg0_interval.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]); + } + let Some(arg2) = args.get(2) else { + return Err(MirEvalError::TypeError("atomic intrinsic arg2 is not provided")); + }; + if name.starts_with("cxchg_") || name.starts_with("cxchgweak_") { + let dest = if arg1.get(self)? == arg0_interval.get(self)? { + arg0_interval.write_from_interval(self, arg2.interval)?; + (arg1.interval, true) + } else { + (arg0_interval, false) + }; + let result_ty = TyKind::Tuple( + 2, + Substitution::from_iter(Interner, [ty.clone(), TyBuilder::bool()]), + ) + .intern(Interner); + let layout = self.layout(&result_ty)?; + let result = self.make_by_layout( + layout.size.bytes_usize(), + &layout, + None, + [IntervalOrOwned::Borrowed(dest.0), IntervalOrOwned::Owned(vec![u8::from(dest.1)])] + .into_iter(), + )?; + return destination.write_from_bytes(self, &result); + } + not_supported!("unknown atomic intrinsic {name}"); + } +} diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ty/src/mir/eval/tests.rs new file mode 100644 index 0000000000000..ca4268b8fb00c --- /dev/null +++ b/crates/hir-ty/src/mir/eval/tests.rs @@ -0,0 +1,676 @@ +use base_db::{fixture::WithFixture, FileId}; +use hir_def::db::DefDatabase; +use syntax::{TextRange, TextSize}; + +use crate::{db::HirDatabase, test_db::TestDB, Interner, Substitution}; + +use super::{interpret_mir, MirEvalError}; + +fn eval_main(db: &TestDB, file_id: FileId) -> Result<(String, String), MirEvalError> { + let module_id = db.module_for_file(file_id); + let def_map = module_id.def_map(db); + let scope = &def_map[module_id.local_id].scope; + let func_id = scope + .declarations() + .find_map(|x| match x { + hir_def::ModuleDefId::FunctionId(x) => { + if db.function_data(x).name.display(db).to_string() == "main" { + Some(x) + } else { + None + } + } + _ => None, + }) + .expect("no main function found"); + let body = db + .monomorphized_mir_body( + func_id.into(), + Substitution::empty(Interner), + db.trait_environment(func_id.into()), + ) + .map_err(|e| MirEvalError::MirLowerError(func_id.into(), e))?; + let (result, stdout, stderr) = interpret_mir(db, &body, false); + result?; + Ok((stdout, stderr)) +} + +fn check_pass(ra_fixture: &str) { + check_pass_and_stdio(ra_fixture, "", ""); +} + +fn check_pass_and_stdio(ra_fixture: &str, expected_stdout: &str, expected_stderr: &str) { + let (db, file_ids) = TestDB::with_many_files(ra_fixture); + let file_id = *file_ids.last().unwrap(); + let x = eval_main(&db, file_id); + match x { + Err(e) => { + let mut err = String::new(); + let line_index = |size: TextSize| { + let mut size = u32::from(size) as usize; + let mut lines = ra_fixture.lines().enumerate(); + while let Some((i, l)) = lines.next() { + if let Some(x) = size.checked_sub(l.len()) { + size = x; + } else { + return (i, size); + } + } + (usize::MAX, size) + }; + let span_formatter = |file, range: TextRange| { + format!("{:?} {:?}..{:?}", file, line_index(range.start()), line_index(range.end())) + }; + e.pretty_print(&mut err, &db, span_formatter).unwrap(); + panic!("Error in interpreting: {err}"); + } + Ok((stdout, stderr)) => { + assert_eq!(stdout, expected_stdout); + assert_eq!(stderr, expected_stderr); + } + } +} + +#[test] +fn function_with_extern_c_abi() { + check_pass( + r#" +extern "C" fn foo(a: i32, b: i32) -> i32 { + a + b +} + +fn main() { + let x = foo(2, 3); +} + "#, + ); +} + +#[test] +fn drop_basic() { + check_pass( + r#" +//- minicore: drop, add + +struct X<'a>(&'a mut i32); +impl<'a> Drop for X<'a> { + fn drop(&mut self) { + *self.0 += 1; + } +} + +struct NestedX<'a> { f1: X<'a>, f2: X<'a> } + +fn should_not_reach() { + _ // FIXME: replace this function with panic when that works +} + +fn my_drop2(x: X<'_>) { + return; +} + +fn my_drop(x: X<'_>) { + drop(x); +} + +fn main() { + let mut s = 10; + let mut x = X(&mut s); + my_drop(x); + x = X(&mut s); + my_drop2(x); + X(&mut s); // dropped immediately + let x = X(&mut s); + NestedX { f1: x, f2: X(&mut s) }; + if s != 15 { + should_not_reach(); + } +} + "#, + ); +} + +#[test] +fn drop_if_let() { + check_pass( + r#" +//- minicore: drop, add, option, cell, builtin_impls + +use core::cell::Cell; + +struct X<'a>(&'a Cell); +impl<'a> Drop for X<'a> { + fn drop(&mut self) { + self.0.set(self.0.get() + 1) + } +} + +fn should_not_reach() { + _ // FIXME: replace this function with panic when that works +} + +#[test] +fn main() { + let s = Cell::new(0); + let x = Some(X(&s)); + if let Some(y) = x { + if s.get() != 0 { + should_not_reach(); + } + if s.get() != 0 { + should_not_reach(); + } + } else { + should_not_reach(); + } + if s.get() != 1 { + should_not_reach(); + } + let x = Some(X(&s)); + if let None = x { + should_not_reach(); + } else { + if s.get() != 1 { + should_not_reach(); + } + } + if s.get() != 1 { + should_not_reach(); + } +} + "#, + ); +} + +#[test] +fn drop_in_place() { + check_pass( + r#" +//- minicore: drop, add, coerce_unsized +use core::ptr::drop_in_place; + +struct X<'a>(&'a mut i32); +impl<'a> Drop for X<'a> { + fn drop(&mut self) { + *self.0 += 1; + } +} + +fn should_not_reach() { + _ // FIXME: replace this function with panic when that works +} + +fn main() { + let mut s = 2; + let x = X(&mut s); + drop_in_place(&mut x); + drop(x); + if s != 4 { + should_not_reach(); + } + let p: &mut [X] = &mut [X(&mut 2)]; + drop_in_place(p); +} + "#, + ); +} + +#[test] +fn manually_drop() { + check_pass( + r#" +//- minicore: manually_drop +use core::mem::ManuallyDrop; + +struct X; +impl Drop for X { + fn drop(&mut self) { + should_not_reach(); + } +} + +fn should_not_reach() { + _ // FIXME: replace this function with panic when that works +} + +fn main() { + let x = ManuallyDrop::new(X); +} + "#, + ); +} + +#[test] +fn generic_impl_for_trait_with_generic_method() { + check_pass( + r#" +//- minicore: drop +struct S(T); + +trait Tr { + fn f(&self, x: F); +} + +impl Tr for S { + fn f(&self, x: F) { + } +} + +fn main() { + let s = S(1u8); + s.f(5i64); +} + "#, + ); +} + +#[test] +fn index_of_slice_should_preserve_len() { + check_pass( + r#" +//- minicore: index, slice, coerce_unsized + +struct X; + +impl core::ops::Index for [i32] { + type Output = i32; + + fn index(&self, _: X) -> &i32 { + if self.len() != 3 { + should_not_reach(); + } + &self[0] + } +} + +fn should_not_reach() { + _ // FIXME: replace this function with panic when that works +} + +fn main() { + let x: &[i32] = &[1, 2, 3]; + &x[X]; +} + "#, + ); +} + +#[test] +fn memcmp() { + check_pass( + r#" +//- minicore: slice, coerce_unsized, index + +fn should_not_reach() -> bool { + _ // FIXME: replace this function with panic when that works +} + +extern "C" { + fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; +} + +fn my_cmp(x: &[u8], y: &[u8]) -> i32 { + memcmp(x as *const u8, y as *const u8, x.len()) +} + +fn main() { + if my_cmp(&[1, 2, 3], &[1, 2, 3]) != 0 { + should_not_reach(); + } + if my_cmp(&[1, 20, 3], &[1, 2, 3]) <= 0 { + should_not_reach(); + } + if my_cmp(&[1, 2, 3], &[1, 20, 3]) >= 0 { + should_not_reach(); + } +} + "#, + ); +} + +#[test] +fn unix_write_stdout() { + check_pass_and_stdio( + r#" +//- minicore: slice, index, coerce_unsized + +type pthread_key_t = u32; +type c_void = u8; +type c_int = i32; + +extern "C" { + pub fn write(fd: i32, buf: *const u8, count: usize) -> usize; +} + +fn main() { + let stdout = b"stdout"; + let stderr = b"stderr"; + write(1, &stdout[0], 6); + write(2, &stderr[0], 6); +} + "#, + "stdout", + "stderr", + ); +} + +#[test] +fn closure_layout_in_rpit() { + check_pass( + r#" +//- minicore: fn + +fn f(x: F) { + fn g(x: impl Fn()) -> impl FnOnce() { + move || { + x(); + } + } + g(x)(); +} + +fn main() { + f(|| {}); +} + "#, + ); +} + +#[test] +fn from_fn() { + check_pass( + r#" +//- minicore: fn, iterator +struct FromFn(F); + +impl Option> Iterator for FromFn { + type Item = T; + + fn next(&mut self) -> Option { + (self.0)() + } +} + +fn main() { + let mut tokenize = { + FromFn(move || Some(2)) + }; + let s = tokenize.next(); +} + "#, + ); +} + +#[test] +fn for_loop() { + check_pass( + r#" +//- minicore: iterator, add +fn should_not_reach() { + _ // FIXME: replace this function with panic when that works +} + +struct X; +struct XIter(i32); + +impl IntoIterator for X { + type Item = i32; + + type IntoIter = XIter; + + fn into_iter(self) -> Self::IntoIter { + XIter(0) + } +} + +impl Iterator for XIter { + type Item = i32; + + fn next(&mut self) -> Option { + if self.0 == 5 { + None + } else { + self.0 += 1; + Some(self.0) + } + } +} + +fn main() { + let mut s = 0; + for x in X { + s += x; + } + if s != 15 { + should_not_reach(); + } +} + "#, + ); +} + +#[test] +fn field_with_associated_type() { + check_pass( + r#" +//- /b/mod.rs crate:b +pub trait Tr { + fn f(self); +} + +pub trait Tr2 { + type Ty: Tr; +} + +pub struct S { + pub t: T::Ty, +} + +impl S { + pub fn g(&self) { + let k = (self.t, self.t); + self.t.f(); + } +} + +//- /a/mod.rs crate:a deps:b +use b::{Tr, Tr2, S}; + +struct A(i32); +struct B(u8); + +impl Tr for A { + fn f(&self) { + } +} + +impl Tr2 for B { + type Ty = A; +} + +#[test] +fn main() { + let s: S = S { t: A(2) }; + s.g(); +} + "#, + ); +} + +#[test] +fn specialization_array_clone() { + check_pass( + r#" +//- minicore: copy, derive, slice, index, coerce_unsized +impl Clone for [T; N] { + #[inline] + fn clone(&self) -> Self { + SpecArrayClone::clone(self) + } +} + +trait SpecArrayClone: Clone { + fn clone(array: &[Self; N]) -> [Self; N]; +} + +impl SpecArrayClone for T { + #[inline] + default fn clone(array: &[T; N]) -> [T; N] { + // FIXME: panic here when we actually implement specialization. + from_slice(array) + } +} + +fn from_slice(s: &[T]) -> [T; N] { + [s[0]; N] +} + +impl SpecArrayClone for T { + #[inline] + fn clone(array: &[T; N]) -> [T; N] { + *array + } +} + +#[derive(Clone, Copy)] +struct X(i32); + +fn main() { + let ar = [X(1), X(2)]; + ar.clone(); +} + "#, + ); +} + +#[test] +fn short_circuit_operator() { + check_pass( + r#" +fn should_not_reach() -> bool { + _ // FIXME: replace this function with panic when that works +} + +fn main() { + if false && should_not_reach() { + should_not_reach(); + } + true || should_not_reach(); + +} + "#, + ); +} + +#[test] +fn closure_state() { + check_pass( + r#" +//- minicore: fn, add, copy +fn should_not_reach() { + _ // FIXME: replace this function with panic when that works +} + +fn main() { + let mut x = 2; + let mut c = move || { + x += 1; + x + }; + c(); + c(); + c(); + if x != 2 { + should_not_reach(); + } + if c() != 6 { + should_not_reach(); + } +} + "#, + ); +} + +#[test] +fn closure_capture_array_const_generic() { + check_pass( + r#" +//- minicore: fn, add, copy +struct X(i32); + +fn f(mut x: [X; N]) { // -> impl FnOnce() { + let c = || { + x; + }; + c(); +} + +fn main() { + let s = f([X(1)]); + //s(); +} + "#, + ); +} + +#[test] +fn posix_tls() { + check_pass( + r#" +//- minicore: option + +type pthread_key_t = u32; +type c_void = u8; +type c_int = i32; + +extern "C" { + pub fn pthread_key_create( + key: *mut pthread_key_t, + dtor: Option, + ) -> c_int; + pub fn pthread_key_delete(key: pthread_key_t) -> c_int; + pub fn pthread_getspecific(key: pthread_key_t) -> *mut c_void; + pub fn pthread_setspecific(key: pthread_key_t, value: *const c_void) -> c_int; +} + +fn main() { + let mut key = 2; + pthread_key_create(&mut key, None); +} + "#, + ); +} + +#[test] +fn regression_14966() { + check_pass( + r#" +//- minicore: fn, copy, coerce_unsized +trait A { + fn a(&self) {} +} +impl A<()> for () {} + +struct B; +impl B { + pub fn b(s: &dyn A) -> Self { + B + } +} +struct C; +impl C { + fn c(a: &dyn A) -> Self { + let mut c = C; + let b = B::b(a); + c.d(|| a.a()); + c + } + fn d(&mut self, f: impl FnOnce()) {} +} + +fn main() { + C::c(&()); +} +"#, + ); +} diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index c4dd7c0ace46c..aad1a82f2981c 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -1,60 +1,88 @@ //! This module generates a polymorphic MIR from a hir body -use std::{iter, mem, sync::Arc}; +use std::{fmt::Write, iter, mem}; +use base_db::FileId; use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind}; use hir_def::{ body::Body, - expr::{ - Array, BindingAnnotation, BindingId, ExprId, LabelId, Literal, MatchArm, Pat, PatId, - RecordLitField, + data::adt::{StructKind, VariantData}, + hir::{ + ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal, + LiteralOrConst, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField, }, lang_item::{LangItem, LangItemTarget}, - layout::LayoutError, path::Path, - resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, - DefWithBodyId, EnumVariantId, HasModule, + resolver::{resolver_for_expr, HasResolver, ResolveValueResult, ValueNs}, + AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId, + TraitId, TypeOrConstParamId, }; use hir_expand::name::Name; use la_arena::ArenaMap; +use rustc_hash::FxHashMap; +use syntax::TextRange; +use triomphe::Arc; use crate::{ - consteval::ConstEvalError, db::HirDatabase, display::HirDisplay, infer::TypeMismatch, - inhabitedness::is_ty_uninhabited_from, layout::layout_of_ty, mapping::ToChalk, static_lifetime, - utils::generics, Adjust, Adjustment, AutoBorrow, CallableDefId, TyBuilder, TyExt, + consteval::ConstEvalError, + db::HirDatabase, + display::HirDisplay, + infer::{CaptureKind, CapturedItem, TypeMismatch}, + inhabitedness::is_ty_uninhabited_from, + layout::LayoutError, + mapping::ToChalk, + static_lifetime, + traits::FnTrait, + utils::{generics, ClosureSubst}, + Adjust, Adjustment, AutoBorrow, CallableDefId, TyBuilder, TyExt, }; use super::*; mod as_place; +mod pattern_matching; -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone)] struct LoopBlocks { begin: BasicBlockId, /// `None` for loops that are not terminating end: Option, + place: Place, + drop_scope_index: usize, +} + +#[derive(Debug, Clone, Default)] +struct DropScope { + /// locals, in order of definition (so we should run drop glues in reverse order) + locals: Vec, } struct MirLowerCtx<'a> { result: MirBody, owner: DefWithBodyId, current_loop_blocks: Option, + labeled_loop_blocks: FxHashMap, discr_temp: Option, db: &'a dyn HirDatabase, body: &'a Body, infer: &'a InferenceResult, + drop_scopes: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] pub enum MirLowerError { - ConstEvalError(Box), + ConstEvalError(String, Box), LayoutError(LayoutError), IncompleteExpr, + IncompletePattern, + /// Trying to lower a trait function, instead of an implementation + TraitFunctionDefinition(TraitId, Name), UnresolvedName(String), RecordLiteralWithoutPath, - UnresolvedMethod, + UnresolvedMethod(String), UnresolvedField, - MissingFunctionDefinition, + UnsizedTemporary(Ty), + MissingFunctionDefinition(DefWithBodyId, ExprId), TypeMismatch(TypeMismatch), /// This should be never happen. Type mismatch should catch everything. TypeError(&'static str), @@ -63,9 +91,114 @@ pub enum MirLowerError { BreakWithoutLoop, Loop, /// Something that should never happen and is definitely a bug, but we don't want to panic if it happened - ImplementationError(&'static str), + ImplementationError(String), LangItemNotFound(LangItem), MutatingRvalue, + UnresolvedLabel, + UnresolvedUpvar(Place), + UnaccessableLocal, + + // monomorphization errors: + GenericArgNotProvided(TypeOrConstParamId, Substitution), +} + +/// A token to ensuring that each drop scope is popped at most once, thanks to the compiler that checks moves. +struct DropScopeToken; +impl DropScopeToken { + fn pop_and_drop(self, ctx: &mut MirLowerCtx<'_>, current: BasicBlockId) -> BasicBlockId { + std::mem::forget(self); + ctx.pop_drop_scope_internal(current) + } + + /// It is useful when we want a drop scope is syntaxically closed, but we don't want to execute any drop + /// code. Either when the control flow is diverging (so drop code doesn't reached) or when drop is handled + /// for us (for example a block that ended with a return statement. Return will drop everything, so the block shouldn't + /// do anything) + fn pop_assume_dropped(self, ctx: &mut MirLowerCtx<'_>) { + std::mem::forget(self); + ctx.pop_drop_scope_assume_dropped_internal(); + } +} + +// Uncomment this to make `DropScopeToken` a drop bomb. Unfortunately we can't do this in release, since +// in cases that mir lowering fails, we don't handle (and don't need to handle) drop scopes so it will be +// actually reached. `pop_drop_scope_assert_finished` will also detect this case, but doesn't show useful +// stack trace. +// +// impl Drop for DropScopeToken { +// fn drop(&mut self) { +// never!("Drop scope doesn't popped"); +// } +// } + +impl MirLowerError { + pub fn pretty_print( + &self, + f: &mut String, + db: &dyn HirDatabase, + span_formatter: impl Fn(FileId, TextRange) -> String, + ) -> std::result::Result<(), std::fmt::Error> { + match self { + MirLowerError::ConstEvalError(name, e) => { + writeln!(f, "In evaluating constant {name}")?; + match &**e { + ConstEvalError::MirLowerError(e) => e.pretty_print(f, db, span_formatter)?, + ConstEvalError::MirEvalError(e) => e.pretty_print(f, db, span_formatter)?, + } + } + MirLowerError::MissingFunctionDefinition(owner, x) => { + let body = db.body(*owner); + writeln!( + f, + "Missing function definition for {}", + body.pretty_print_expr(db.upcast(), *owner, *x) + )?; + } + MirLowerError::TypeMismatch(e) => { + writeln!( + f, + "Type mismatch: Expected {}, found {}", + e.expected.display(db), + e.actual.display(db), + )?; + } + MirLowerError::GenericArgNotProvided(id, subst) => { + let parent = id.parent; + let param = &db.generic_params(parent).type_or_consts[id.local_id]; + writeln!( + f, + "Generic arg not provided for {}", + param.name().unwrap_or(&Name::missing()).display(db.upcast()) + )?; + writeln!(f, "Provided args: [")?; + for g in subst.iter(Interner) { + write!(f, " {},", g.display(db).to_string())?; + } + writeln!(f, "]")?; + } + MirLowerError::LayoutError(_) + | MirLowerError::UnsizedTemporary(_) + | MirLowerError::IncompleteExpr + | MirLowerError::IncompletePattern + | MirLowerError::UnaccessableLocal + | MirLowerError::TraitFunctionDefinition(_, _) + | MirLowerError::UnresolvedName(_) + | MirLowerError::RecordLiteralWithoutPath + | MirLowerError::UnresolvedMethod(_) + | MirLowerError::UnresolvedField + | MirLowerError::TypeError(_) + | MirLowerError::NotSupported(_) + | MirLowerError::ContinueWithoutLoop + | MirLowerError::BreakWithoutLoop + | MirLowerError::Loop + | MirLowerError::ImplementationError(_) + | MirLowerError::LangItemNotFound(_) + | MirLowerError::MutatingRvalue + | MirLowerError::UnresolvedLabel + | MirLowerError::UnresolvedUpvar(_) => writeln!(f, "{:?}", self)?, + } + Ok(()) + } } macro_rules! not_supported { @@ -76,20 +209,11 @@ macro_rules! not_supported { macro_rules! implementation_error { ($x: expr) => {{ - ::stdx::never!("MIR lower implementation bug: {}", $x); - return Err(MirLowerError::ImplementationError($x)); + ::stdx::never!("MIR lower implementation bug: {}", format!($x)); + return Err(MirLowerError::ImplementationError(format!($x))); }}; } -impl From for MirLowerError { - fn from(value: ConstEvalError) -> Self { - match value { - ConstEvalError::MirLowerError(e) => e, - _ => MirLowerError::ConstEvalError(Box::new(value)), - } - } -} - impl From for MirLowerError { fn from(value: LayoutError) -> Self { MirLowerError::LayoutError(value) @@ -104,12 +228,51 @@ impl MirLowerError { type Result = std::result::Result; -impl MirLowerCtx<'_> { - fn temp(&mut self, ty: Ty) -> Result { +impl<'ctx> MirLowerCtx<'ctx> { + fn new( + db: &'ctx dyn HirDatabase, + owner: DefWithBodyId, + body: &'ctx Body, + infer: &'ctx InferenceResult, + ) -> Self { + let mut basic_blocks = Arena::new(); + let start_block = basic_blocks.alloc(BasicBlock { + statements: vec![], + terminator: None, + is_cleanup: false, + }); + let locals = Arena::new(); + let binding_locals: ArenaMap = ArenaMap::new(); + let mir = MirBody { + basic_blocks, + locals, + start_block, + binding_locals, + param_locals: vec![], + owner, + closures: vec![], + }; + let ctx = MirLowerCtx { + result: mir, + db, + infer, + body, + owner, + current_loop_blocks: None, + labeled_loop_blocks: Default::default(), + discr_temp: None, + drop_scopes: vec![DropScope::default()], + }; + ctx + } + + fn temp(&mut self, ty: Ty, current: BasicBlockId, span: MirSpan) -> Result { if matches!(ty.kind(Interner), TyKind::Slice(_) | TyKind::Dyn(_)) { - implementation_error!("unsized temporaries"); + return Err(MirLowerError::UnsizedTemporary(ty)); } - Ok(self.result.locals.alloc(Local { ty })) + let l = self.result.locals.alloc(Local { ty }); + self.push_storage_live_for_local(l, current, span)?; + Ok(l) } fn lower_expr_to_some_operand( @@ -120,7 +283,7 @@ impl MirLowerCtx<'_> { if !self.has_adjustments(expr_id) { match &self.body.exprs[expr_id] { Expr::Literal(l) => { - let ty = self.expr_ty(expr_id); + let ty = self.expr_ty_without_adjust(expr_id); return Ok(Some((self.lower_literal_to_operand(ty, l)?, current))); } _ => (), @@ -142,7 +305,8 @@ impl MirLowerCtx<'_> { match adjustments.split_last() { Some((last, rest)) => match &last.kind { Adjust::NeverToAny => { - let temp = self.temp(TyKind::Never.intern(Interner))?; + let temp = + self.temp(TyKind::Never.intern(Interner), current, MirSpan::Unknown)?; self.lower_expr_to_place_with_adjust(expr_id, temp.into(), current, rest) } Adjust::Deref(_) => { @@ -200,65 +364,82 @@ impl MirLowerCtx<'_> { mut current: BasicBlockId, ) -> Result> { match &self.body.exprs[expr_id] { - Expr::Missing => Err(MirLowerError::IncompleteExpr), + Expr::Missing => { + if let DefWithBodyId::FunctionId(f) = self.owner { + let assoc = self.db.lookup_intern_function(f); + if let ItemContainerId::TraitId(t) = assoc.container { + let name = &self.db.function_data(f).name; + return Err(MirLowerError::TraitFunctionDefinition(t, name.clone())); + } + } + Err(MirLowerError::IncompleteExpr) + }, Expr::Path(p) => { - let unresolved_name = || MirLowerError::unresolved_path(self.db, p); - let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id); - let pr = resolver - .resolve_path_in_value_ns(self.db.upcast(), p.mod_path()) - .ok_or_else(unresolved_name)?; - let pr = match pr { - ResolveValueResult::ValueNs(v) => v, - ResolveValueResult::Partial(..) => { - if let Some(assoc) = self - .infer - .assoc_resolutions_for_expr(expr_id) - { - match assoc.0 { - hir_def::AssocItemId::ConstId(c) => { - self.lower_const(c, current, place, expr_id.into())?; - return Ok(Some(current)) - }, - _ => not_supported!("associated functions and types"), - } - } else if let Some(variant) = self - .infer - .variant_resolution_for_expr(expr_id) - { - match variant { - VariantId::EnumVariantId(e) => ValueNs::EnumVariantId(e), - VariantId::StructId(s) => ValueNs::StructId(s), - VariantId::UnionId(_) => implementation_error!("Union variant as path"), - } - } else { - return Err(unresolved_name()); + let pr = if let Some((assoc, subst)) = self + .infer + .assoc_resolutions_for_expr(expr_id) + { + match assoc { + hir_def::AssocItemId::ConstId(c) => { + self.lower_const(c.into(), current, place, subst, expr_id.into(), self.expr_ty_without_adjust(expr_id))?; + return Ok(Some(current)) + }, + hir_def::AssocItemId::FunctionId(_) => { + // FnDefs are zero sized, no action is needed. + return Ok(Some(current)) } + hir_def::AssocItemId::TypeAliasId(_) => { + // FIXME: If it is unreachable, use proper error instead of `not_supported`. + not_supported!("associated functions and types") + }, } + } else if let Some(variant) = self + .infer + .variant_resolution_for_expr(expr_id) + { + match variant { + VariantId::EnumVariantId(e) => ValueNs::EnumVariantId(e), + VariantId::StructId(s) => ValueNs::StructId(s), + VariantId::UnionId(_) => implementation_error!("Union variant as path"), + } + } else { + let unresolved_name = || MirLowerError::unresolved_path(self.db, p); + let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id); + resolver + .resolve_path_in_value_ns_fully(self.db.upcast(), p) + .ok_or_else(unresolved_name)? }; match pr { - ValueNs::LocalBinding(pat_id) => { + ValueNs::LocalBinding(_) | ValueNs::StaticId(_) => { + let Some((temp, current)) = self.lower_expr_as_place_without_adjust(current, expr_id, false)? else { + return Ok(None); + }; self.push_assignment( current, place, - Operand::Copy(self.result.binding_locals[pat_id].into()).into(), + Operand::Copy(temp).into(), expr_id.into(), ); Ok(Some(current)) } ValueNs::ConstId(const_id) => { - self.lower_const(const_id, current, place, expr_id.into())?; + self.lower_const(const_id.into(), current, place, Substitution::empty(Interner), expr_id.into(), self.expr_ty_without_adjust(expr_id))?; Ok(Some(current)) } ValueNs::EnumVariantId(variant_id) => { - let ty = self.infer.type_of_expr[expr_id].clone(); - let current = self.lower_enum_variant( - variant_id, - current, - place, - ty, - vec![], - expr_id.into(), - )?; + let variant_data = &self.db.enum_data(variant_id.parent).variants[variant_id.local_id]; + if variant_data.variant_data.kind() == StructKind::Unit { + let ty = self.infer.type_of_expr[expr_id].clone(); + current = self.lower_enum_variant( + variant_id, + current, + place, + ty, + Box::new([]), + expr_id.into(), + )?; + } + // Otherwise its a tuple like enum, treated like a zero sized function, so no action is needed Ok(Some(current)) } ValueNs::GenericParam(p) => { @@ -266,7 +447,7 @@ impl MirLowerCtx<'_> { not_supported!("owner without generic def id"); }; let gen = generics(self.db.upcast(), def); - let ty = self.expr_ty(expr_id); + let ty = self.expr_ty_without_adjust(expr_id); self.push_assignment( current, place, @@ -287,7 +468,7 @@ impl MirLowerCtx<'_> { ); Ok(Some(current)) } - ValueNs::StructId(_) => { + ValueNs::FunctionId(_) | ValueNs::StructId(_) => { // It's probably a unit struct or a zero sized function, so no action is needed. Ok(Some(current)) } @@ -311,12 +492,13 @@ impl MirLowerCtx<'_> { }; self.set_terminator( current, - Terminator::SwitchInt { + TerminatorKind::SwitchInt { discr, targets: SwitchTargets::static_if(1, start_of_then, start_of_else), }, + expr_id.into(), ); - Ok(self.merge_blocks(end_of_then, end_of_else)) + Ok(self.merge_blocks(end_of_then, end_of_else, expr_id.into())) } Expr::Let { pat, expr } => { let Some((cond_place, current)) = self.lower_expr_as_place(current, *expr, true)? else { @@ -326,9 +508,7 @@ impl MirLowerCtx<'_> { current, None, cond_place, - self.expr_ty_after_adjustments(*expr), *pat, - BindingAnnotation::Unannotated, )?; self.write_bytes_to_place( then_target, @@ -346,141 +526,107 @@ impl MirLowerCtx<'_> { MirSpan::Unknown, )?; } - Ok(self.merge_blocks(Some(then_target), else_target)) + Ok(self.merge_blocks(Some(then_target), else_target, expr_id.into())) } Expr::Unsafe { id: _, statements, tail } => { - self.lower_block_to_place(None, statements, current, *tail, place) + self.lower_block_to_place(statements, current, *tail, place, expr_id.into()) } Expr::Block { id: _, statements, tail, label } => { - self.lower_block_to_place(*label, statements, current, *tail, place) + if let Some(label) = label { + self.lower_loop(current, place.clone(), Some(*label), expr_id.into(), |this, begin| { + if let Some(current) = this.lower_block_to_place(statements, begin, *tail, place, expr_id.into())? { + let end = this.current_loop_end()?; + this.set_goto(current, end, expr_id.into()); + } + Ok(()) + }) + } else { + self.lower_block_to_place(statements, current, *tail, place, expr_id.into()) + } } - Expr::Loop { body, label } => self.lower_loop(current, *label, |this, begin| { - if let Some((_, block)) = this.lower_expr_as_place(begin, *body, true)? { - this.set_goto(block, begin); + Expr::Loop { body, label } => self.lower_loop(current, place, *label, expr_id.into(), |this, begin| { + let scope = this.push_drop_scope(); + if let Some((_, mut current)) = this.lower_expr_as_place(begin, *body, true)? { + current = scope.pop_and_drop(this, current); + this.set_goto(current, begin, expr_id.into()); + } else { + scope.pop_assume_dropped(this); } Ok(()) }), Expr::While { condition, body, label } => { - self.lower_loop(current, *label, |this, begin| { + self.lower_loop(current, place, *label, expr_id.into(),|this, begin| { + let scope = this.push_drop_scope(); let Some((discr, to_switch)) = this.lower_expr_to_some_operand(*condition, begin)? else { return Ok(()); }; - let end = this.current_loop_end()?; + let fail_cond = this.new_basic_block(); let after_cond = this.new_basic_block(); this.set_terminator( to_switch, - Terminator::SwitchInt { + TerminatorKind::SwitchInt { discr, - targets: SwitchTargets::static_if(1, after_cond, end), + targets: SwitchTargets::static_if(1, after_cond, fail_cond), }, + expr_id.into(), ); + let fail_cond = this.drop_until_scope(this.drop_scopes.len() - 1, fail_cond); + let end = this.current_loop_end()?; + this.set_goto(fail_cond, end, expr_id.into()); if let Some((_, block)) = this.lower_expr_as_place(after_cond, *body, true)? { - this.set_goto(block, begin); + let block = scope.pop_and_drop(this, block); + this.set_goto(block, begin, expr_id.into()); + } else { + scope.pop_assume_dropped(this); } Ok(()) }) } - &Expr::For { iterable, pat, body, label } => { - let into_iter_fn = self.resolve_lang_item(LangItem::IntoIterIntoIter)? - .as_function().ok_or(MirLowerError::LangItemNotFound(LangItem::IntoIterIntoIter))?; - let iter_next_fn = self.resolve_lang_item(LangItem::IteratorNext)? - .as_function().ok_or(MirLowerError::LangItemNotFound(LangItem::IteratorNext))?; - let option_some = self.resolve_lang_item(LangItem::OptionSome)? - .as_enum_variant().ok_or(MirLowerError::LangItemNotFound(LangItem::OptionSome))?; - let option = option_some.parent; - let into_iter_fn_op = Operand::const_zst( - TyKind::FnDef( - self.db.intern_callable_def(CallableDefId::FunctionId(into_iter_fn)).into(), - Substitution::from1(Interner, self.expr_ty(iterable)) - ).intern(Interner)); - let iter_next_fn_op = Operand::const_zst( - TyKind::FnDef( - self.db.intern_callable_def(CallableDefId::FunctionId(iter_next_fn)).into(), - Substitution::from1(Interner, self.expr_ty(iterable)) - ).intern(Interner)); - let &Some(iterator_ty) = &self.infer.type_of_for_iterator.get(&expr_id) else { - return Err(MirLowerError::TypeError("unknown for loop iterator type")); - }; - let ref_mut_iterator_ty = TyKind::Ref(Mutability::Mut, static_lifetime(), iterator_ty.clone()).intern(Interner); - let item_ty = &self.infer.type_of_pat[pat]; - let option_item_ty = TyKind::Adt(chalk_ir::AdtId(option.into()), Substitution::from1(Interner, item_ty.clone())).intern(Interner); - let iterator_place: Place = self.temp(iterator_ty.clone())?.into(); - let option_item_place: Place = self.temp(option_item_ty.clone())?.into(); - let ref_mut_iterator_place: Place = self.temp(ref_mut_iterator_ty)?.into(); - let Some(current) = self.lower_call_and_args(into_iter_fn_op, Some(iterable).into_iter(), iterator_place.clone(), current, false)? - else { - return Ok(None); - }; - self.push_assignment(current, ref_mut_iterator_place.clone(), Rvalue::Ref(BorrowKind::Mut { allow_two_phase_borrow: false }, iterator_place), expr_id.into()); - self.lower_loop(current, label, |this, begin| { - let Some(current) = this.lower_call(iter_next_fn_op, vec![Operand::Copy(ref_mut_iterator_place)], option_item_place.clone(), begin, false)? - else { - return Ok(()); - }; - let end = this.current_loop_end()?; - let (current, _) = this.pattern_matching_variant( - option_item_ty.clone(), - BindingAnnotation::Unannotated, - option_item_place.into(), - option_some.into(), - current, - pat.into(), - Some(end), - &[pat], &None)?; - if let Some((_, block)) = this.lower_expr_as_place(current, body, true)? { - this.set_goto(block, begin); - } - Ok(()) - }) - }, Expr::Call { callee, args, .. } => { + if let Some((func_id, generic_args)) = + self.infer.method_resolution(expr_id) { + let ty = chalk_ir::TyKind::FnDef( + CallableDefId::FunctionId(func_id).to_chalk(self.db), + generic_args, + ) + .intern(Interner); + let func = Operand::from_bytes(vec![], ty); + return self.lower_call_and_args( + func, + iter::once(*callee).chain(args.iter().copied()), + place, + current, + self.is_uninhabited(expr_id), + expr_id.into(), + ); + } let callee_ty = self.expr_ty_after_adjustments(*callee); match &callee_ty.data(Interner).kind { chalk_ir::TyKind::FnDef(..) => { let func = Operand::from_bytes(vec![], callee_ty.clone()); - self.lower_call_and_args(func, args.iter().copied(), place, current, self.is_uninhabited(expr_id)) + self.lower_call_and_args(func, args.iter().copied(), place, current, self.is_uninhabited(expr_id), expr_id.into()) } - TyKind::Scalar(_) - | TyKind::Tuple(_, _) - | TyKind::Array(_, _) - | TyKind::Adt(_, _) - | TyKind::Str - | TyKind::Foreign(_) - | TyKind::Slice(_) => { - return Err(MirLowerError::TypeError("function call on data type")) + chalk_ir::TyKind::Function(_) => { + let Some((func, current)) = self.lower_expr_to_some_operand(*callee, current)? else { + return Ok(None); + }; + self.lower_call_and_args(func, args.iter().copied(), place, current, self.is_uninhabited(expr_id), expr_id.into()) } - TyKind::Error => return Err(MirLowerError::MissingFunctionDefinition), - TyKind::AssociatedType(_, _) - | TyKind::Raw(_, _) - | TyKind::Ref(_, _, _) - | TyKind::OpaqueType(_, _) - | TyKind::Never - | TyKind::Closure(_, _) - | TyKind::Generator(_, _) - | TyKind::GeneratorWitness(_, _) - | TyKind::Placeholder(_) - | TyKind::Dyn(_) - | TyKind::Alias(_) - | TyKind::Function(_) - | TyKind::BoundVar(_) - | TyKind::InferenceVar(_, _) => not_supported!("dynamic function call"), + TyKind::Error => return Err(MirLowerError::MissingFunctionDefinition(self.owner, expr_id)), + _ => return Err(MirLowerError::TypeError("function call on bad type")), } } - Expr::MethodCall { receiver, args, .. } => { + Expr::MethodCall { receiver, args, method_name, .. } => { let (func_id, generic_args) = - self.infer.method_resolution(expr_id).ok_or(MirLowerError::UnresolvedMethod)?; - let ty = chalk_ir::TyKind::FnDef( - CallableDefId::FunctionId(func_id).to_chalk(self.db), - generic_args, - ) - .intern(Interner); - let func = Operand::from_bytes(vec![], ty); + self.infer.method_resolution(expr_id).ok_or_else(|| MirLowerError::UnresolvedMethod(method_name.display(self.db.upcast()).to_string()))?; + let func = Operand::from_fn(self.db, func_id, generic_args); self.lower_call_and_args( func, iter::once(*receiver).chain(args.iter().copied()), place, current, self.is_uninhabited(expr_id), + expr_id.into(), ) } Expr::Match { expr, arms } => { @@ -488,23 +634,27 @@ impl MirLowerCtx<'_> { else { return Ok(None); }; - let cond_ty = self.expr_ty_after_adjustments(*expr); let mut end = None; for MatchArm { pat, guard, expr } in arms.iter() { - if guard.is_some() { - not_supported!("pattern matching with guard"); - } - let (then, otherwise) = self.pattern_match( + let (then, mut otherwise) = self.pattern_match( current, None, cond_place.clone(), - cond_ty.clone(), *pat, - BindingAnnotation::Unannotated, )?; + let then = if let &Some(guard) = guard { + let next = self.new_basic_block(); + let o = otherwise.get_or_insert_with(|| self.new_basic_block()); + if let Some((discr, c)) = self.lower_expr_to_some_operand(guard, then)? { + self.set_terminator(c, TerminatorKind::SwitchInt { discr, targets: SwitchTargets::static_if(1, next, *o) }, expr_id.into()); + } + next + } else { + then + }; if let Some(block) = self.lower_expr_to_place(*expr, place.clone(), then)? { let r = end.get_or_insert_with(|| self.new_basic_block()); - self.set_goto(block, *r); + self.set_goto(block, *r, expr_id.into()); } match otherwise { Some(o) => current = o, @@ -516,32 +666,43 @@ impl MirLowerCtx<'_> { } } if self.is_unterminated(current) { - self.set_terminator(current, Terminator::Unreachable); + self.set_terminator(current, TerminatorKind::Unreachable, expr_id.into()); } Ok(end) } - Expr::Continue { label } => match label { - Some(_) => not_supported!("continue with label"), - None => { - let loop_data = - self.current_loop_blocks.ok_or(MirLowerError::ContinueWithoutLoop)?; - self.set_goto(current, loop_data.begin); - Ok(None) - } + Expr::Continue { label } => { + let loop_data = match label { + Some(l) => self.labeled_loop_blocks.get(l).ok_or(MirLowerError::UnresolvedLabel)?, + None => self.current_loop_blocks.as_ref().ok_or(MirLowerError::ContinueWithoutLoop)?, + }; + let begin = loop_data.begin; + current = self.drop_until_scope(loop_data.drop_scope_index, current); + self.set_goto(current, begin, expr_id.into()); + Ok(None) }, - Expr::Break { expr, label } => { - if expr.is_some() { - not_supported!("break with value"); + &Expr::Break { expr, label } => { + if let Some(expr) = expr { + let loop_data = match label { + Some(l) => self.labeled_loop_blocks.get(&l).ok_or(MirLowerError::UnresolvedLabel)?, + None => self.current_loop_blocks.as_ref().ok_or(MirLowerError::BreakWithoutLoop)?, + }; + let Some(c) = self.lower_expr_to_place(expr, loop_data.place.clone(), current)? else { + return Ok(None); + }; + current = c; } - match label { - Some(_) => not_supported!("break with label"), + let (end, drop_scope) = match label { + Some(l) => { + let loop_blocks = self.labeled_loop_blocks.get(&l).ok_or(MirLowerError::UnresolvedLabel)?; + (loop_blocks.end.expect("We always generate end for labeled loops"), loop_blocks.drop_scope_index) + }, None => { - let end = - self.current_loop_end()?; - self.set_goto(current, end); - Ok(None) - } - } + (self.current_loop_end()?, self.current_loop_blocks.as_ref().unwrap().drop_scope_index) + }, + }; + current = self.drop_until_scope(drop_scope, current); + self.set_goto(current, end, expr_id.into()); + Ok(None) } Expr::Return { expr } => { if let Some(expr) = expr { @@ -551,11 +712,22 @@ impl MirLowerCtx<'_> { return Ok(None); } } - self.set_terminator(current, Terminator::Return); + current = self.drop_until_scope(0, current); + self.set_terminator(current, TerminatorKind::Return, expr_id.into()); Ok(None) } Expr::Yield { .. } => not_supported!("yield"), - Expr::RecordLit { fields, path, .. } => { + Expr::RecordLit { fields, path, spread, ellipsis: _, is_assignee_expr: _ } => { + let spread_place = match spread { + &Some(x) => { + let Some((p, c)) = self.lower_expr_as_place(current, x, true)? else { + return Ok(None); + }; + current = c; + Some(p) + }, + None => None, + }; let variant_id = self .infer .variant_resolution_for_expr(expr_id) @@ -563,7 +735,7 @@ impl MirLowerCtx<'_> { Some(p) => MirLowerError::UnresolvedName(p.display(self.db).to_string()), None => MirLowerError::RecordLiteralWithoutPath, })?; - let subst = match self.expr_ty(expr_id).kind(Interner) { + let subst = match self.expr_ty_without_adjust(expr_id).kind(Interner) { TyKind::Adt(_, s) => s.clone(), _ => not_supported!("Non ADT record literal"), }; @@ -585,9 +757,23 @@ impl MirLowerCtx<'_> { place, Rvalue::Aggregate( AggregateKind::Adt(variant_id, subst), - operands.into_iter().map(|x| x).collect::>().ok_or( - MirLowerError::TypeError("missing field in record literal"), - )?, + match spread_place { + Some(sp) => operands.into_iter().enumerate().map(|(i, x)| { + match x { + Some(x) => x, + None => { + let p = sp.project(ProjectionElem::Field(FieldId { + parent: variant_id, + local_id: LocalFieldId::from_raw(RawIdx::from(i as u32)), + })); + Operand::Copy(p) + }, + } + }).collect(), + None => operands.into_iter().collect::>().ok_or( + MirLowerError::TypeError("missing field in record literal"), + )?, + }, ), expr_id.into(), ); @@ -599,20 +785,19 @@ impl MirLowerCtx<'_> { }; let local_id = variant_data.field(name).ok_or(MirLowerError::UnresolvedField)?; - let mut place = place; - place - .projection - .push(PlaceElem::Field(FieldId { parent: union_id.into(), local_id })); + let place = place.project(PlaceElem::Field(FieldId { parent: union_id.into(), local_id })); self.lower_expr_to_place(*expr, place, current) } } } Expr::Await { .. } => not_supported!("await"), - Expr::Try { .. } => not_supported!("? operator"), Expr::Yeet { .. } => not_supported!("yeet"), - Expr::TryBlock { .. } => not_supported!("try block"), Expr::Async { .. } => not_supported!("async block"), - Expr::Const { .. } => not_supported!("anonymous const block"), + &Expr::Const(id) => { + let subst = self.placeholder_subst(); + self.lower_const(id.into(), current, place, subst, expr_id.into(), self.expr_ty_without_adjust(expr_id))?; + Ok(Some(current)) + }, Expr::Cast { expr, type_ref: _ } => { let Some((x, current)) = self.lower_expr_to_some_operand(*expr, current)? else { return Ok(None); @@ -635,21 +820,30 @@ impl MirLowerCtx<'_> { self.push_assignment(current, place, Rvalue::Ref(bk, p), expr_id.into()); Ok(Some(current)) } - Expr::Box { .. } => not_supported!("box expression"), - Expr::Field { .. } | Expr::Index { .. } | Expr::UnaryOp { op: hir_def::expr::UnaryOp::Deref, .. } => { + Expr::Box { expr } => { + let ty = self.expr_ty_after_adjustments(*expr); + self.push_assignment(current, place.clone(), Rvalue::ShallowInitBoxWithAlloc(ty), expr_id.into()); + let Some((operand, current)) = self.lower_expr_to_some_operand(*expr, current)? else { + return Ok(None); + }; + let p = place.project(ProjectionElem::Deref); + self.push_assignment(current, p, operand.into(), expr_id.into()); + Ok(Some(current)) + }, + Expr::Field { .. } | Expr::Index { .. } | Expr::UnaryOp { op: hir_def::hir::UnaryOp::Deref, .. } => { let Some((p, current)) = self.lower_expr_as_place_without_adjust(current, expr_id, true)? else { return Ok(None); }; self.push_assignment(current, place, Operand::Copy(p).into(), expr_id.into()); Ok(Some(current)) } - Expr::UnaryOp { expr, op: op @ (hir_def::expr::UnaryOp::Not | hir_def::expr::UnaryOp::Neg) } => { + Expr::UnaryOp { expr, op: op @ (hir_def::hir::UnaryOp::Not | hir_def::hir::UnaryOp::Neg) } => { let Some((operand, current)) = self.lower_expr_to_some_operand(*expr, current)? else { return Ok(None); }; let operation = match op { - hir_def::expr::UnaryOp::Not => UnOp::Not, - hir_def::expr::UnaryOp::Neg => UnOp::Neg, + hir_def::hir::UnaryOp::Not => UnOp::Not, + hir_def::hir::UnaryOp::Neg => UnOp::Neg, _ => unreachable!(), }; self.push_assignment( @@ -662,24 +856,93 @@ impl MirLowerCtx<'_> { }, Expr::BinaryOp { lhs, rhs, op } => { let op = op.ok_or(MirLowerError::IncompleteExpr)?; - if let hir_def::expr::BinaryOp::Assignment { op } = op { - if op.is_some() { - not_supported!("assignment with arith op (like +=)"); + let is_builtin = 'b: { + // Without adjust here is a hack. We assume that we know every possible adjustment + // for binary operator, and use without adjust to simplify our conditions. + let lhs_ty = self.expr_ty_without_adjust(*lhs); + let rhs_ty = self.expr_ty_without_adjust(*rhs); + if matches!(op ,BinaryOp::CmpOp(syntax::ast::CmpOp::Eq { .. })) { + if lhs_ty.as_raw_ptr().is_some() && rhs_ty.as_raw_ptr().is_some() { + break 'b true; + } } - let Some((lhs_place, current)) = + let builtin_inequal_impls = matches!( + op, + BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) | BinaryOp::Assignment { op: Some(ArithOp::Shl | ArithOp::Shr) } + ); + lhs_ty.is_scalar() && rhs_ty.is_scalar() && (lhs_ty == rhs_ty || builtin_inequal_impls) + }; + if !is_builtin { + if let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id) { + let func = Operand::from_fn(self.db, func_id, generic_args); + return self.lower_call_and_args( + func, + [*lhs, *rhs].into_iter(), + place, + current, + self.is_uninhabited(expr_id), + expr_id.into(), + ); + } + } + if let hir_def::hir::BinaryOp::Assignment { op } = op { + if let Some(op) = op { + // last adjustment is `&mut` which we don't want it. + let adjusts = self + .infer + .expr_adjustments + .get(lhs) + .and_then(|x| x.split_last()) + .map(|x| x.1) + .ok_or(MirLowerError::TypeError("adjustment of binary op was missing"))?; + let Some((lhs_place, current)) = + self.lower_expr_as_place_with_adjust(current, *lhs, false, adjusts)? + else { + return Ok(None); + }; + let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)? else { + return Ok(None); + }; + let r_value = Rvalue::CheckedBinaryOp(op.into(), Operand::Copy(lhs_place.clone()), rhs_op); + self.push_assignment(current, lhs_place, r_value, expr_id.into()); + return Ok(Some(current)); + } else { + let Some((lhs_place, current)) = self.lower_expr_as_place(current, *lhs, false)? - else { - return Ok(None); - }; - let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)? else { - return Ok(None); - }; - self.push_assignment(current, lhs_place, rhs_op.into(), expr_id.into()); - return Ok(Some(current)); + else { + return Ok(None); + }; + let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)? else { + return Ok(None); + }; + self.push_assignment(current, lhs_place, rhs_op.into(), expr_id.into()); + return Ok(Some(current)); + } } let Some((lhs_op, current)) = self.lower_expr_to_some_operand(*lhs, current)? else { return Ok(None); }; + if let hir_def::hir::BinaryOp::LogicOp(op) = op { + let value_to_short = match op { + syntax::ast::LogicOp::And => 0, + syntax::ast::LogicOp::Or => 1, + }; + let start_of_then = self.new_basic_block(); + self.push_assignment(start_of_then, place.clone(), lhs_op.clone().into(), expr_id.into()); + let end_of_then = Some(start_of_then); + let start_of_else = self.new_basic_block(); + let end_of_else = + self.lower_expr_to_place(*rhs, place, start_of_else)?; + self.set_terminator( + current, + TerminatorKind::SwitchInt { + discr: lhs_op, + targets: SwitchTargets::static_if(value_to_short, start_of_then, start_of_else), + }, + expr_id.into(), + ); + return Ok(self.merge_blocks(end_of_then, end_of_else, expr_id.into())); + } let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)? else { return Ok(None); }; @@ -688,13 +951,13 @@ impl MirLowerCtx<'_> { place, Rvalue::CheckedBinaryOp( match op { - hir_def::expr::BinaryOp::LogicOp(op) => match op { - hir_def::expr::LogicOp::And => BinOp::BitAnd, // FIXME: make these short circuit - hir_def::expr::LogicOp::Or => BinOp::BitOr, + hir_def::hir::BinaryOp::LogicOp(op) => match op { + hir_def::hir::LogicOp::And => BinOp::BitAnd, // FIXME: make these short circuit + hir_def::hir::LogicOp::Or => BinOp::BitOr, }, - hir_def::expr::BinaryOp::ArithOp(op) => BinOp::from(op), - hir_def::expr::BinaryOp::CmpOp(op) => BinOp::from(op), - hir_def::expr::BinaryOp::Assignment { .. } => unreachable!(), // handled above + hir_def::hir::BinaryOp::ArithOp(op) => BinOp::from(op), + hir_def::hir::BinaryOp::CmpOp(op) => BinOp::from(op), + hir_def::hir::BinaryOp::Assignment { .. } => unreachable!(), // handled above }, lhs_op, rhs_op, @@ -703,8 +966,96 @@ impl MirLowerCtx<'_> { ); Ok(Some(current)) } - Expr::Range { .. } => not_supported!("range"), - Expr::Closure { .. } => not_supported!("closure"), + &Expr::Range { lhs, rhs, range_type: _ } => { + let ty = self.expr_ty_without_adjust(expr_id); + let Some((adt, subst)) = ty.as_adt() else { + return Err(MirLowerError::TypeError("Range type is not adt")); + }; + let AdtId::StructId(st) = adt else { + return Err(MirLowerError::TypeError("Range type is not struct")); + }; + let mut lp = None; + let mut rp = None; + if let Some(x) = lhs { + let Some((o, c)) = self.lower_expr_to_some_operand(x, current)? else { + return Ok(None); + }; + lp = Some(o); + current = c; + } + if let Some(x) = rhs { + let Some((o, c)) = self.lower_expr_to_some_operand(x, current)? else { + return Ok(None); + }; + rp = Some(o); + current = c; + } + self.push_assignment( + current, + place, + Rvalue::Aggregate( + AggregateKind::Adt(st.into(), subst.clone()), + self.db.struct_data(st).variant_data.fields().iter().map(|x| { + let o = match x.1.name.as_str() { + Some("start") => lp.take(), + Some("end") => rp.take(), + Some("exhausted") => Some(Operand::from_bytes(vec![0], TyBuilder::bool())), + _ => None, + }; + o.ok_or(MirLowerError::UnresolvedField) + }).collect::>()?, + ), + expr_id.into(), + ); + Ok(Some(current)) + }, + Expr::Closure { .. } => { + let ty = self.expr_ty_without_adjust(expr_id); + let TyKind::Closure(id, _) = ty.kind(Interner) else { + not_supported!("closure with non closure type"); + }; + self.result.closures.push(*id); + let (captures, _) = self.infer.closure_info(id); + let mut operands = vec![]; + for capture in captures.iter() { + let p = Place { + local: self.binding_local(capture.place.local)?, + projection: capture.place.projections.clone().into_iter().map(|x| { + match x { + ProjectionElem::Deref => ProjectionElem::Deref, + ProjectionElem::Field(x) => ProjectionElem::Field(x), + ProjectionElem::TupleOrClosureField(x) => ProjectionElem::TupleOrClosureField(x), + ProjectionElem::ConstantIndex { offset, from_end } => ProjectionElem::ConstantIndex { offset, from_end }, + ProjectionElem::Subslice { from, to } => ProjectionElem::Subslice { from, to }, + ProjectionElem::OpaqueCast(x) => ProjectionElem::OpaqueCast(x), + ProjectionElem::Index(x) => match x { }, + } + }).collect(), + }; + match &capture.kind { + CaptureKind::ByRef(bk) => { + let placeholder_subst = self.placeholder_subst(); + let tmp_ty = capture.ty.clone().substitute(Interner, &placeholder_subst); + let tmp: Place = self.temp(tmp_ty, current, capture.span)?.into(); + self.push_assignment( + current, + tmp.clone(), + Rvalue::Ref(bk.clone(), p), + capture.span, + ); + operands.push(Operand::Move(tmp)); + }, + CaptureKind::ByValue => operands.push(Operand::Move(p)), + } + } + self.push_assignment( + current, + place, + Rvalue::Aggregate(AggregateKind::Closure(ty), operands.into()), + expr_id.into(), + ); + Ok(Some(current)) + }, Expr::Tuple { exprs, is_assignee_expr: _ } => { let Some(values) = exprs .iter() @@ -720,7 +1071,7 @@ impl MirLowerCtx<'_> { return Ok(None); }; let r = Rvalue::Aggregate( - AggregateKind::Tuple(self.expr_ty(expr_id)), + AggregateKind::Tuple(self.expr_ty_without_adjust(expr_id)), values, ); self.push_assignment(current, place, r, expr_id.into()); @@ -728,7 +1079,7 @@ impl MirLowerCtx<'_> { } Expr::Array(l) => match l { Array::ElementList { elements, .. } => { - let elem_ty = match &self.expr_ty(expr_id).data(Interner).kind { + let elem_ty = match &self.expr_ty_without_adjust(expr_id).data(Interner).kind { TyKind::Array(ty, _) => ty.clone(), _ => { return Err(MirLowerError::TypeError( @@ -756,10 +1107,25 @@ impl MirLowerCtx<'_> { self.push_assignment(current, place, r, expr_id.into()); Ok(Some(current)) } - Array::Repeat { .. } => not_supported!("array repeat"), + Array::Repeat { initializer, .. } => { + let Some((init, current)) = self.lower_expr_to_some_operand(*initializer, current)? else { + return Ok(None); + }; + let len = match &self.expr_ty_without_adjust(expr_id).data(Interner).kind { + TyKind::Array(_, len) => len.clone(), + _ => { + return Err(MirLowerError::TypeError( + "Array repeat expression with non array type", + )) + } + }; + let r = Rvalue::Repeat(init, len); + self.push_assignment(current, place, r, expr_id.into()); + Ok(Some(current)) + }, }, Expr::Literal(l) => { - let ty = self.expr_ty(expr_id); + let ty = self.expr_ty_without_adjust(expr_id); let op = self.lower_literal_to_operand(ty, l)?; self.push_assignment(current, place, op.into(), expr_id.into()); Ok(Some(current)) @@ -768,17 +1134,25 @@ impl MirLowerCtx<'_> { } } + fn placeholder_subst(&mut self) -> Substitution { + let placeholder_subst = match self.owner.as_generic_def_id() { + Some(x) => TyBuilder::placeholder_subst(self.db, x), + None => Substitution::empty(Interner), + }; + placeholder_subst + } + fn push_field_projection(&self, place: &mut Place, expr_id: ExprId) -> Result<()> { if let Expr::Field { expr, name } = &self.body[expr_id] { if let TyKind::Tuple(..) = self.expr_ty_after_adjustments(*expr).kind(Interner) { let index = name .as_tuple_index() .ok_or(MirLowerError::TypeError("named field on tuple"))?; - place.projection.push(ProjectionElem::TupleField(index)) + *place = place.project(ProjectionElem::TupleOrClosureField(index)) } else { let field = self.infer.field_resolution(expr_id).ok_or(MirLowerError::UnresolvedField)?; - place.projection.push(ProjectionElem::Field(field)); + *place = place.project(ProjectionElem::Field(field)); } } else { not_supported!("") @@ -786,33 +1160,75 @@ impl MirLowerCtx<'_> { Ok(()) } + fn lower_literal_or_const_to_operand( + &mut self, + ty: Ty, + loc: &LiteralOrConst, + ) -> Result { + match loc { + LiteralOrConst::Literal(l) => self.lower_literal_to_operand(ty, l), + LiteralOrConst::Const(c) => { + let unresolved_name = || MirLowerError::unresolved_path(self.db, c); + let resolver = self.owner.resolver(self.db.upcast()); + let pr = resolver + .resolve_path_in_value_ns(self.db.upcast(), c) + .ok_or_else(unresolved_name)?; + match pr { + ResolveValueResult::ValueNs(v) => { + if let ValueNs::ConstId(c) = v { + self.lower_const_to_operand(Substitution::empty(Interner), c.into(), ty) + } else { + not_supported!("bad path in range pattern"); + } + } + ResolveValueResult::Partial(_, _) => { + not_supported!("associated constants in range pattern") + } + } + } + } + } + fn lower_literal_to_operand(&mut self, ty: Ty, l: &Literal) -> Result { - let size = layout_of_ty(self.db, &ty, self.owner.module(self.db.upcast()).krate())? + let size = self + .db + .layout_of_ty(ty.clone(), self.owner.module(self.db.upcast()).krate())? .size .bytes_usize(); let bytes = match l { - hir_def::expr::Literal::String(b) => { + hir_def::hir::Literal::String(b) => { let b = b.as_bytes(); - let mut data = vec![]; + let mut data = Vec::with_capacity(mem::size_of::() * 2); data.extend(0usize.to_le_bytes()); data.extend(b.len().to_le_bytes()); let mut mm = MemoryMap::default(); mm.insert(0, b.to_vec()); return Ok(Operand::from_concrete_const(data, mm, ty)); } - hir_def::expr::Literal::ByteString(b) => { - let mut data = vec![]; + hir_def::hir::Literal::CString(b) => { + let b = b.as_bytes(); + let bytes = b.iter().copied().chain(iter::once(0)).collect::>(); + + let mut data = Vec::with_capacity(mem::size_of::() * 2); + data.extend(0usize.to_le_bytes()); + data.extend(bytes.len().to_le_bytes()); + let mut mm = MemoryMap::default(); + mm.insert(0, bytes); + return Ok(Operand::from_concrete_const(data, mm, ty)); + } + hir_def::hir::Literal::ByteString(b) => { + let mut data = Vec::with_capacity(mem::size_of::() * 2); data.extend(0usize.to_le_bytes()); data.extend(b.len().to_le_bytes()); let mut mm = MemoryMap::default(); mm.insert(0, b.to_vec()); return Ok(Operand::from_concrete_const(data, mm, ty)); } - hir_def::expr::Literal::Char(c) => u32::from(*c).to_le_bytes().into(), - hir_def::expr::Literal::Bool(b) => vec![*b as u8], - hir_def::expr::Literal::Int(x, _) => x.to_le_bytes()[0..size].into(), - hir_def::expr::Literal::Uint(x, _) => x.to_le_bytes()[0..size].into(), - hir_def::expr::Literal::Float(f, _) => match size { + hir_def::hir::Literal::Char(c) => u32::from(*c).to_le_bytes().into(), + hir_def::hir::Literal::Bool(b) => vec![*b as u8], + hir_def::hir::Literal::Int(x, _) => x.to_le_bytes()[0..size].into(), + hir_def::hir::Literal::Uint(x, _) => x.to_le_bytes()[0..size].into(), + hir_def::hir::Literal::Float(f, _) => match size { 8 => f.into_f64().to_le_bytes().into(), 4 => f.into_f32().to_le_bytes().into(), _ => { @@ -829,24 +1245,34 @@ impl MirLowerCtx<'_> { fn lower_const( &mut self, - const_id: hir_def::ConstId, + const_id: GeneralConstId, prev_block: BasicBlockId, place: Place, + subst: Substitution, span: MirSpan, + ty: Ty, ) -> Result<()> { - let c = self.db.const_eval(const_id)?; - self.write_const_to_place(c, prev_block, place, span) + let c = self.lower_const_to_operand(subst, const_id, ty)?; + self.push_assignment(prev_block, place, c.into(), span); + Ok(()) } - fn write_const_to_place( + fn lower_const_to_operand( &mut self, - c: Const, - prev_block: BasicBlockId, - place: Place, - span: MirSpan, - ) -> Result<()> { - self.push_assignment(prev_block, place, Operand::Constant(c).into(), span); - Ok(()) + subst: Substitution, + const_id: GeneralConstId, + ty: Ty, + ) -> Result { + let c = if subst.len(Interner) != 0 { + // We can't evaluate constant with substitution now, as generics are not monomorphized in lowering. + intern_const_scalar(ConstScalar::UnevaluatedConst(const_id, subst), ty) + } else { + let name = const_id.name(self.db.upcast()); + self.db + .const_eval(const_id.into(), subst) + .map_err(|e| MirLowerError::ConstEvalError(name, Box::new(e)))? + }; + Ok(Operand::Constant(c)) } fn write_bytes_to_place( @@ -867,12 +1293,12 @@ impl MirLowerCtx<'_> { prev_block: BasicBlockId, place: Place, ty: Ty, - fields: Vec, + fields: Box<[Operand]>, span: MirSpan, ) -> Result { let subst = match ty.kind(Interner) { TyKind::Adt(_, subst) => subst.clone(), - _ => not_supported!("Non ADT enum"), + _ => implementation_error!("Non ADT enum"), }; self.push_assignment( prev_block, @@ -890,6 +1316,7 @@ impl MirLowerCtx<'_> { place: Place, mut current: BasicBlockId, is_uninhabited: bool, + span: MirSpan, ) -> Result> { let Some(args) = args .map(|arg| { @@ -904,21 +1331,22 @@ impl MirLowerCtx<'_> { else { return Ok(None); }; - self.lower_call(func, args, place, current, is_uninhabited) + self.lower_call(func, args.into(), place, current, is_uninhabited, span) } fn lower_call( &mut self, func: Operand, - args: Vec, + args: Box<[Operand]>, place: Place, current: BasicBlockId, is_uninhabited: bool, + span: MirSpan, ) -> Result> { let b = if is_uninhabited { None } else { Some(self.new_basic_block()) }; self.set_terminator( current, - Terminator::Call { + TerminatorKind::Call { func, args, destination: place, @@ -926,6 +1354,7 @@ impl MirLowerCtx<'_> { cleanup: None, from_hir_call: true, }, + span, ); Ok(b) } @@ -934,15 +1363,15 @@ impl MirLowerCtx<'_> { self.result.basic_blocks[source].terminator.is_none() } - fn set_terminator(&mut self, source: BasicBlockId, terminator: Terminator) { - self.result.basic_blocks[source].terminator = Some(terminator); + fn set_terminator(&mut self, source: BasicBlockId, terminator: TerminatorKind, span: MirSpan) { + self.result.basic_blocks[source].terminator = Some(Terminator { span, kind: terminator }); } - fn set_goto(&mut self, source: BasicBlockId, target: BasicBlockId) { - self.set_terminator(source, Terminator::Goto { target }); + fn set_goto(&mut self, source: BasicBlockId, target: BasicBlockId, span: MirSpan) { + self.set_terminator(source, TerminatorKind::Goto { target }, span); } - fn expr_ty(&self, e: ExprId) -> Ty { + fn expr_ty_without_adjust(&self, e: ExprId) -> Ty { self.infer[e].clone() } @@ -953,7 +1382,7 @@ impl MirLowerCtx<'_> { ty = Some(x.target.clone()); } } - ty.unwrap_or_else(|| self.expr_ty(e)) + ty.unwrap_or_else(|| self.expr_ty_without_adjust(e)) } fn push_statement(&mut self, block: BasicBlockId, statement: Statement) { @@ -970,293 +1399,14 @@ impl MirLowerCtx<'_> { self.push_statement(block, StatementKind::Assign(place, rvalue).with_span(span)); } - /// It gets a `current` unterminated block, appends some statements and possibly a terminator to it to check if - /// the pattern matches and write bindings, and returns two unterminated blocks, one for the matched path (which - /// can be the `current` block) and one for the mismatched path. If the input pattern is irrefutable, the - /// mismatched path block is `None`. - /// - /// By default, it will create a new block for mismatched path. If you already have one, you can provide it with - /// `current_else` argument to save an unneccessary jump. If `current_else` isn't `None`, the result mismatched path - /// wouldn't be `None` as well. Note that this function will add jumps to the beginning of the `current_else` block, - /// so it should be an empty block. - fn pattern_match( - &mut self, - mut current: BasicBlockId, - mut current_else: Option, - mut cond_place: Place, - mut cond_ty: Ty, - pattern: PatId, - mut binding_mode: BindingAnnotation, - ) -> Result<(BasicBlockId, Option)> { - Ok(match &self.body.pats[pattern] { - Pat::Missing => return Err(MirLowerError::IncompleteExpr), - Pat::Wild => (current, current_else), - Pat::Tuple { args, ellipsis } => { - pattern_matching_dereference(&mut cond_ty, &mut binding_mode, &mut cond_place); - let subst = match cond_ty.kind(Interner) { - TyKind::Tuple(_, s) => s, - _ => { - return Err(MirLowerError::TypeError( - "non tuple type matched with tuple pattern", - )) - } - }; - self.pattern_match_tuple_like( - current, - current_else, - args.iter().enumerate().map(|(i, x)| { - ( - PlaceElem::TupleField(i), - *x, - subst.at(Interner, i).assert_ty_ref(Interner).clone(), - ) - }), - *ellipsis, - &cond_place, - binding_mode, - )? - } - Pat::Or(pats) => { - let then_target = self.new_basic_block(); - let mut finished = false; - for pat in &**pats { - let (next, next_else) = self.pattern_match( - current, - None, - cond_place.clone(), - cond_ty.clone(), - *pat, - binding_mode, - )?; - self.set_goto(next, then_target); - match next_else { - Some(t) => { - current = t; - } - None => { - finished = true; - break; - } - } - } - if !finished { - let ce = *current_else.get_or_insert_with(|| self.new_basic_block()); - self.set_goto(current, ce); - } - (then_target, current_else) - } - Pat::Record { .. } => not_supported!("record pattern"), - Pat::Range { .. } => not_supported!("range pattern"), - Pat::Slice { .. } => not_supported!("slice pattern"), - Pat::Path(_) => { - let Some(variant) = self.infer.variant_resolution_for_pat(pattern) else { - not_supported!("unresolved variant"); - }; - self.pattern_matching_variant( - cond_ty, - binding_mode, - cond_place, - variant, - current, - pattern.into(), - current_else, - &[], - &None, - )? - } - Pat::Lit(l) => { - let then_target = self.new_basic_block(); - let else_target = current_else.unwrap_or_else(|| self.new_basic_block()); - match &self.body.exprs[*l] { - Expr::Literal(l) => match l { - hir_def::expr::Literal::Int(x, _) => { - self.set_terminator( - current, - Terminator::SwitchInt { - discr: Operand::Copy(cond_place), - targets: SwitchTargets::static_if( - *x as u128, - then_target, - else_target, - ), - }, - ); - } - hir_def::expr::Literal::Uint(x, _) => { - self.set_terminator( - current, - Terminator::SwitchInt { - discr: Operand::Copy(cond_place), - targets: SwitchTargets::static_if(*x, then_target, else_target), - }, - ); - } - _ => not_supported!("non int path literal"), - }, - _ => not_supported!("expression path literal"), - } - (then_target, Some(else_target)) - } - Pat::Bind { id, subpat } => { - let target_place = self.result.binding_locals[*id]; - let mode = self.body.bindings[*id].mode; - if let Some(subpat) = subpat { - (current, current_else) = self.pattern_match( - current, - current_else, - cond_place.clone(), - cond_ty, - *subpat, - binding_mode, - )? - } - if matches!(mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) { - binding_mode = mode; - } - self.push_storage_live(*id, current); - self.push_assignment( - current, - target_place.into(), - match binding_mode { - BindingAnnotation::Unannotated | BindingAnnotation::Mutable => { - Operand::Copy(cond_place).into() - } - BindingAnnotation::Ref => Rvalue::Ref(BorrowKind::Shared, cond_place), - BindingAnnotation::RefMut => Rvalue::Ref( - BorrowKind::Mut { allow_two_phase_borrow: false }, - cond_place, - ), - }, - pattern.into(), - ); - (current, current_else) - } - Pat::TupleStruct { path: _, args, ellipsis } => { - let Some(variant) = self.infer.variant_resolution_for_pat(pattern) else { - not_supported!("unresolved variant"); - }; - self.pattern_matching_variant( - cond_ty, - binding_mode, - cond_place, - variant, - current, - pattern.into(), - current_else, - args, - ellipsis, - )? - } - Pat::Ref { .. } => not_supported!("& pattern"), - Pat::Box { .. } => not_supported!("box pattern"), - Pat::ConstBlock(_) => not_supported!("const block pattern"), - }) - } - - fn pattern_matching_variant( - &mut self, - mut cond_ty: Ty, - mut binding_mode: BindingAnnotation, - mut cond_place: Place, - variant: VariantId, - current: BasicBlockId, - span: MirSpan, - current_else: Option, - args: &[PatId], - ellipsis: &Option, - ) -> Result<(BasicBlockId, Option)> { - pattern_matching_dereference(&mut cond_ty, &mut binding_mode, &mut cond_place); - let subst = match cond_ty.kind(Interner) { - TyKind::Adt(_, s) => s, - _ => return Err(MirLowerError::TypeError("non adt type matched with tuple struct")), - }; - let fields_type = self.db.field_types(variant); - Ok(match variant { - VariantId::EnumVariantId(v) => { - let e = self.db.const_eval_discriminant(v)? as u128; - let next = self.new_basic_block(); - let tmp = self.discr_temp_place(); - self.push_assignment( - current, - tmp.clone(), - Rvalue::Discriminant(cond_place.clone()), - span, - ); - let else_target = current_else.unwrap_or_else(|| self.new_basic_block()); - self.set_terminator( - current, - Terminator::SwitchInt { - discr: Operand::Copy(tmp), - targets: SwitchTargets::static_if(e, next, else_target), - }, - ); - let enum_data = self.db.enum_data(v.parent); - let fields = - enum_data.variants[v.local_id].variant_data.fields().iter().map(|(x, _)| { - ( - PlaceElem::Field(FieldId { parent: v.into(), local_id: x }), - fields_type[x].clone().substitute(Interner, subst), - ) - }); - self.pattern_match_tuple_like( - next, - Some(else_target), - args.iter().zip(fields).map(|(x, y)| (y.0, *x, y.1)), - *ellipsis, - &cond_place, - binding_mode, - )? - } - VariantId::StructId(s) => { - let struct_data = self.db.struct_data(s); - let fields = struct_data.variant_data.fields().iter().map(|(x, _)| { - ( - PlaceElem::Field(FieldId { parent: s.into(), local_id: x }), - fields_type[x].clone().substitute(Interner, subst), - ) - }); - self.pattern_match_tuple_like( - current, - current_else, - args.iter().zip(fields).map(|(x, y)| (y.0, *x, y.1)), - *ellipsis, - &cond_place, - binding_mode, - )? - } - VariantId::UnionId(_) => { - return Err(MirLowerError::TypeError("pattern matching on union")) - } - }) - } - - fn pattern_match_tuple_like( - &mut self, - mut current: BasicBlockId, - mut current_else: Option, - args: impl Iterator, - ellipsis: Option, - cond_place: &Place, - binding_mode: BindingAnnotation, - ) -> Result<(BasicBlockId, Option)> { - if ellipsis.is_some() { - not_supported!("tuple like pattern with ellipsis"); - } - for (proj, arg, ty) in args { - let mut cond_place = cond_place.clone(); - cond_place.projection.push(proj); - (current, current_else) = - self.pattern_match(current, current_else, cond_place, ty, arg, binding_mode)?; - } - Ok((current, current_else)) - } - - fn discr_temp_place(&mut self) -> Place { + fn discr_temp_place(&mut self, current: BasicBlockId) -> Place { match &self.discr_temp { Some(x) => x.clone(), None => { - let tmp: Place = - self.temp(TyBuilder::discr_ty()).expect("discr_ty is never unsized").into(); + let tmp: Place = self + .temp(TyBuilder::discr_ty(), current, MirSpan::Unknown) + .expect("discr_ty is never unsized") + .into(); self.discr_temp = Some(tmp.clone()); tmp } @@ -1266,19 +1416,34 @@ impl MirLowerCtx<'_> { fn lower_loop( &mut self, prev_block: BasicBlockId, + place: Place, label: Option, + span: MirSpan, f: impl FnOnce(&mut MirLowerCtx<'_>, BasicBlockId) -> Result<()>, ) -> Result> { - if label.is_some() { - not_supported!("loop with label"); - } let begin = self.new_basic_block(); - let prev = - mem::replace(&mut self.current_loop_blocks, Some(LoopBlocks { begin, end: None })); - self.set_goto(prev_block, begin); + let prev = mem::replace( + &mut self.current_loop_blocks, + Some(LoopBlocks { begin, end: None, place, drop_scope_index: self.drop_scopes.len() }), + ); + let prev_label = if let Some(label) = label { + // We should generate the end now, to make sure that it wouldn't change later. It is + // bad as we may emit end (unnecessary unreachable block) for unterminating loop, but + // it should not affect correctness. + self.current_loop_end()?; + self.labeled_loop_blocks + .insert(label, self.current_loop_blocks.as_ref().unwrap().clone()) + } else { + None + }; + self.set_goto(prev_block, begin, span); f(self, begin)?; - let my = mem::replace(&mut self.current_loop_blocks, prev) - .ok_or(MirLowerError::ImplementationError("current_loop_blocks is corrupt"))?; + let my = mem::replace(&mut self.current_loop_blocks, prev).ok_or( + MirLowerError::ImplementationError("current_loop_blocks is corrupt".to_string()), + )?; + if let Some(prev) = prev_label { + self.labeled_loop_blocks.insert(label.unwrap(), prev); + } Ok(my.end) } @@ -1290,14 +1455,15 @@ impl MirLowerCtx<'_> { &mut self, b1: Option, b2: Option, + span: MirSpan, ) -> Option { match (b1, b2) { (None, None) => None, (None, Some(b)) | (Some(b), None) => Some(b), (Some(b1), Some(b2)) => { let bm = self.new_basic_block(); - self.set_goto(b1, bm); - self.set_goto(b2, bm); + self.set_goto(b1, bm, span); + self.set_goto(b2, bm, span); Some(bm) } } @@ -1307,7 +1473,9 @@ impl MirLowerCtx<'_> { let r = match self .current_loop_blocks .as_mut() - .ok_or(MirLowerError::ImplementationError("Current loop access out of loop"))? + .ok_or(MirLowerError::ImplementationError( + "Current loop access out of loop".to_string(), + ))? .end { Some(x) => x, @@ -1315,7 +1483,9 @@ impl MirLowerCtx<'_> { let s = self.new_basic_block(); self.current_loop_blocks .as_mut() - .ok_or(MirLowerError::ImplementationError("Current loop access out of loop"))? + .ok_or(MirLowerError::ImplementationError( + "Current loop access out of loop".to_string(), + ))? .end = Some(s); s } @@ -1327,36 +1497,28 @@ impl MirLowerCtx<'_> { is_ty_uninhabited_from(&self.infer[expr_id], self.owner.module(self.db.upcast()), self.db) } - /// This function push `StorageLive` statement for the binding, and applies changes to add `StorageDead` in - /// the appropriated places. - fn push_storage_live(&mut self, b: BindingId, current: BasicBlockId) { - // Current implementation is wrong. It adds no `StorageDead` at the end of scope, and before each break - // and continue. It just add a `StorageDead` before the `StorageLive`, which is not wrong, but unneeeded in - // the proper implementation. Due this limitation, implementing a borrow checker on top of this mir will falsely - // allow this: - // - // ``` - // let x; - // loop { - // let y = 2; - // x = &y; - // if some_condition { - // break; // we need to add a StorageDead(y) above this to kill the x borrow - // } - // } - // use(x) - // ``` - // But I think this approach work for mutability analysis, as user can't write code which mutates a binding - // after StorageDead, except loops, which are handled by this hack. + /// This function push `StorageLive` statement for the binding, and applies changes to add `StorageDead` and + /// `Drop` in the appropriated places. + fn push_storage_live(&mut self, b: BindingId, current: BasicBlockId) -> Result<()> { let span = self.body.bindings[b] .definitions .first() .copied() .map(MirSpan::PatId) .unwrap_or(MirSpan::Unknown); - let l = self.result.binding_locals[b]; - self.push_statement(current, StatementKind::StorageDead(l).with_span(span)); + let l = self.binding_local(b)?; + self.push_storage_live_for_local(l, current, span) + } + + fn push_storage_live_for_local( + &mut self, + l: LocalId, + current: BasicBlockId, + span: MirSpan, + ) -> Result<()> { + self.drop_scopes.last_mut().unwrap().locals.push(l); self.push_statement(current, StatementKind::StorageLive(l).with_span(span)); + Ok(()) } fn resolve_lang_item(&self, item: LangItem) -> Result { @@ -1366,81 +1528,204 @@ impl MirLowerCtx<'_> { fn lower_block_to_place( &mut self, - label: Option, - statements: &[hir_def::expr::Statement], + statements: &[hir_def::hir::Statement], mut current: BasicBlockId, tail: Option, place: Place, + span: MirSpan, ) -> Result>> { - if label.is_some() { - not_supported!("block with label"); - } + let scope = self.push_drop_scope(); for statement in statements.iter() { match statement { - hir_def::expr::Statement::Let { pat, initializer, else_branch, type_ref: _ } => { + hir_def::hir::Statement::Let { pat, initializer, else_branch, type_ref: _ } => { if let Some(expr_id) = initializer { let else_block; let Some((init_place, c)) = self.lower_expr_as_place(current, *expr_id, true)? else { + scope.pop_assume_dropped(self); return Ok(None); }; current = c; - (current, else_block) = self.pattern_match( - current, - None, - init_place, - self.expr_ty_after_adjustments(*expr_id), - *pat, - BindingAnnotation::Unannotated, - )?; + (current, else_block) = + self.pattern_match(current, None, init_place, *pat)?; match (else_block, else_branch) { (None, _) => (), (Some(else_block), None) => { - self.set_terminator(else_block, Terminator::Unreachable); + self.set_terminator(else_block, TerminatorKind::Unreachable, span); } (Some(else_block), Some(else_branch)) => { if let Some((_, b)) = self.lower_expr_as_place(else_block, *else_branch, true)? { - self.set_terminator(b, Terminator::Unreachable); + self.set_terminator(b, TerminatorKind::Unreachable, span); } } } } else { + let mut err = None; self.body.walk_bindings_in_pat(*pat, |b| { - self.push_storage_live(b, current); + if let Err(e) = self.push_storage_live(b, current) { + err = Some(e); + } }); + if let Some(e) = err { + return Err(e); + } } } - hir_def::expr::Statement::Expr { expr, has_semi: _ } => { + hir_def::hir::Statement::Expr { expr, has_semi: _ } => { + let scope2 = self.push_drop_scope(); let Some((_, c)) = self.lower_expr_as_place(current, *expr, true)? else { + scope2.pop_assume_dropped(self); + scope.pop_assume_dropped(self); return Ok(None); }; - current = c; + current = scope2.pop_and_drop(self, c); } } } - match tail { - Some(tail) => self.lower_expr_to_place(tail, place, current), - None => Ok(Some(current)), + if let Some(tail) = tail { + let Some(c) = self.lower_expr_to_place(tail, place, current)? else { + scope.pop_assume_dropped(self); + return Ok(None); + }; + current = c; } + current = scope.pop_and_drop(self, current); + Ok(Some(current)) } -} -fn pattern_matching_dereference( - cond_ty: &mut Ty, - binding_mode: &mut BindingAnnotation, - cond_place: &mut Place, -) { - while let Some((ty, _, mu)) = cond_ty.as_reference() { - if mu == Mutability::Mut && *binding_mode != BindingAnnotation::Ref { - *binding_mode = BindingAnnotation::RefMut; - } else { - *binding_mode = BindingAnnotation::Ref; + fn lower_params_and_bindings( + &mut self, + params: impl Iterator + Clone, + pick_binding: impl Fn(BindingId) -> bool, + ) -> Result { + let base_param_count = self.result.param_locals.len(); + self.result.param_locals.extend(params.clone().map(|(x, ty)| { + let local_id = self.result.locals.alloc(Local { ty }); + self.drop_scopes.last_mut().unwrap().locals.push(local_id); + if let Pat::Bind { id, subpat: None } = self.body[x] { + if matches!( + self.body.bindings[id].mode, + BindingAnnotation::Unannotated | BindingAnnotation::Mutable + ) { + self.result.binding_locals.insert(id, local_id); + } + } + local_id + })); + // and then rest of bindings + for (id, _) in self.body.bindings.iter() { + if !pick_binding(id) { + continue; + } + if !self.result.binding_locals.contains_idx(id) { + self.result + .binding_locals + .insert(id, self.result.locals.alloc(Local { ty: self.infer[id].clone() })); + } + } + let mut current = self.result.start_block; + for ((param, _), local) in + params.zip(self.result.param_locals.clone().into_iter().skip(base_param_count)) + { + if let Pat::Bind { id, .. } = self.body[param] { + if local == self.binding_local(id)? { + continue; + } + } + let r = self.pattern_match(current, None, local.into(), param)?; + if let Some(b) = r.1 { + self.set_terminator(b, TerminatorKind::Unreachable, param.into()); + } + current = r.0; + } + Ok(current) + } + + fn binding_local(&self, b: BindingId) -> Result { + match self.result.binding_locals.get(b) { + Some(x) => Ok(*x), + None => { + // FIXME: It should never happens, but currently it will happen in `const_dependent_on_local` test, which + // is a hir lowering problem IMO. + // never!("Using unaccessable local for binding is always a bug"); + Err(MirLowerError::UnaccessableLocal) + } + } + } + + fn const_eval_discriminant(&self, variant: EnumVariantId) -> Result { + let r = self.db.const_eval_discriminant(variant); + match r { + Ok(r) => Ok(r), + Err(e) => { + let data = self.db.enum_data(variant.parent); + let name = format!( + "{}::{}", + data.name.display(self.db.upcast()), + data.variants[variant.local_id].name.display(self.db.upcast()) + ); + Err(MirLowerError::ConstEvalError(name, Box::new(e))) + } + } + } + + fn drop_until_scope(&mut self, scope_index: usize, mut current: BasicBlockId) -> BasicBlockId { + for scope in self.drop_scopes[scope_index..].to_vec().iter().rev() { + self.emit_drop_and_storage_dead_for_scope(scope, &mut current); + } + current + } + + fn push_drop_scope(&mut self) -> DropScopeToken { + self.drop_scopes.push(DropScope::default()); + DropScopeToken + } + + /// Don't call directly + fn pop_drop_scope_assume_dropped_internal(&mut self) { + self.drop_scopes.pop(); + } + + /// Don't call directly + fn pop_drop_scope_internal(&mut self, mut current: BasicBlockId) -> BasicBlockId { + let scope = self.drop_scopes.pop().unwrap(); + self.emit_drop_and_storage_dead_for_scope(&scope, &mut current); + current + } + + fn pop_drop_scope_assert_finished( + &mut self, + mut current: BasicBlockId, + ) -> Result { + current = self.pop_drop_scope_internal(current); + if !self.drop_scopes.is_empty() { + implementation_error!("Mismatched count between drop scope push and pops"); + } + Ok(current) + } + + fn emit_drop_and_storage_dead_for_scope( + &mut self, + scope: &DropScope, + current: &mut Idx, + ) { + for &l in scope.locals.iter().rev() { + if !self.result.locals[l].ty.clone().is_copy(self.db, self.owner) { + let prev = std::mem::replace(current, self.new_basic_block()); + self.set_terminator( + prev, + TerminatorKind::Drop { place: l.into(), target: *current, unwind: None }, + MirSpan::Unknown, + ); + } + self.push_statement( + *current, + StatementKind::StorageDead(l).with_span(MirSpan::Unknown), + ); } - *cond_ty = ty.clone(); - cond_place.projection.push(ProjectionElem::Deref); } } @@ -1452,6 +1737,26 @@ fn cast_kind(source_ty: &Ty, target_ty: &Ty) -> Result { (_, chalk_ir::Scalar::Float(_)) => CastKind::IntToFloat, (_, _) => CastKind::IntToInt, }, + (TyKind::Scalar(_), TyKind::Raw(..)) => CastKind::PointerFromExposedAddress, + (TyKind::Raw(..), TyKind::Scalar(_)) => CastKind::PointerExposeAddress, + (TyKind::Raw(_, a) | TyKind::Ref(_, _, a), TyKind::Raw(_, b) | TyKind::Ref(_, _, b)) => { + CastKind::Pointer(if a == b { + PointerCast::MutToConstPointer + } else if matches!(a.kind(Interner), TyKind::Slice(_) | TyKind::Str) + && matches!(b.kind(Interner), TyKind::Slice(_) | TyKind::Str) + { + // slice to slice cast is no-op (metadata is not touched), so we use this + PointerCast::MutToConstPointer + } else if matches!(b.kind(Interner), TyKind::Slice(_) | TyKind::Dyn(_)) { + PointerCast::Unsize + } else if matches!(a.kind(Interner), TyKind::Slice(s) if s == b) { + PointerCast::ArrayToPointer + } else { + // cast between two sized pointer, like *const i32 to *const i8. There is no specific variant + // for it in `PointerCast` so we use `MutToConstPointer` + PointerCast::MutToConstPointer + }) + } // Enum to int casts (TyKind::Scalar(_), TyKind::Adt(..)) | (TyKind::Adt(..), TyKind::Scalar(_)) => { CastKind::IntToInt @@ -1460,20 +1765,122 @@ fn cast_kind(source_ty: &Ty, target_ty: &Ty) -> Result { }) } +pub fn mir_body_for_closure_query( + db: &dyn HirDatabase, + closure: ClosureId, +) -> Result> { + let (owner, expr) = db.lookup_intern_closure(closure.into()); + let body = db.body(owner); + let infer = db.infer(owner); + let Expr::Closure { args, body: root, .. } = &body[expr] else { + implementation_error!("closure expression is not closure"); + }; + let TyKind::Closure(_, substs) = &infer[expr].kind(Interner) else { + implementation_error!("closure expression is not closure"); + }; + let (captures, kind) = infer.closure_info(&closure); + let mut ctx = MirLowerCtx::new(db, owner, &body, &infer); + // 0 is return local + ctx.result.locals.alloc(Local { ty: infer[*root].clone() }); + let closure_local = ctx.result.locals.alloc(Local { + ty: match kind { + FnTrait::FnOnce => infer[expr].clone(), + FnTrait::FnMut => TyKind::Ref(Mutability::Mut, static_lifetime(), infer[expr].clone()) + .intern(Interner), + FnTrait::Fn => TyKind::Ref(Mutability::Not, static_lifetime(), infer[expr].clone()) + .intern(Interner), + }, + }); + ctx.result.param_locals.push(closure_local); + let Some(sig) = ClosureSubst(substs).sig_ty().callable_sig(db) else { + implementation_error!("closure has not callable sig"); + }; + let current = ctx.lower_params_and_bindings( + args.iter().zip(sig.params().iter()).map(|(x, y)| (*x, y.clone())), + |_| true, + )?; + if let Some(current) = ctx.lower_expr_to_place(*root, return_slot().into(), current)? { + let current = ctx.pop_drop_scope_assert_finished(current)?; + ctx.set_terminator(current, TerminatorKind::Return, (*root).into()); + } + let mut upvar_map: FxHashMap> = FxHashMap::default(); + for (i, capture) in captures.iter().enumerate() { + let local = ctx.binding_local(capture.place.local)?; + upvar_map.entry(local).or_default().push((capture, i)); + } + let mut err = None; + let closure_local = ctx.result.locals.iter().nth(1).unwrap().0; + let closure_projection = match kind { + FnTrait::FnOnce => vec![], + FnTrait::FnMut | FnTrait::Fn => vec![ProjectionElem::Deref], + }; + ctx.result.walk_places(|p| { + if let Some(x) = upvar_map.get(&p.local) { + let r = x.iter().find(|x| { + if p.projection.len() < x.0.place.projections.len() { + return false; + } + for (x, y) in p.projection.iter().zip(x.0.place.projections.iter()) { + match (x, y) { + (ProjectionElem::Deref, ProjectionElem::Deref) => (), + (ProjectionElem::Field(x), ProjectionElem::Field(y)) if x == y => (), + ( + ProjectionElem::TupleOrClosureField(x), + ProjectionElem::TupleOrClosureField(y), + ) if x == y => (), + _ => return false, + } + } + true + }); + match r { + Some(x) => { + p.local = closure_local; + let mut next_projs = closure_projection.clone(); + next_projs.push(PlaceElem::TupleOrClosureField(x.1)); + let prev_projs = mem::take(&mut p.projection); + if x.0.kind != CaptureKind::ByValue { + next_projs.push(ProjectionElem::Deref); + } + next_projs.extend(prev_projs.iter().cloned().skip(x.0.place.projections.len())); + p.projection = next_projs.into(); + } + None => err = Some(p.clone()), + } + } + }); + ctx.result.binding_locals = ctx + .result + .binding_locals + .into_iter() + .filter(|x| ctx.body[x.0].owner == Some(expr)) + .collect(); + if let Some(err) = err { + return Err(MirLowerError::UnresolvedUpvar(err)); + } + ctx.result.shrink_to_fit(); + Ok(Arc::new(ctx.result)) +} + pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result> { let _p = profile::span("mir_body_query").detail(|| match def { - DefWithBodyId::FunctionId(it) => db.function_data(it).name.to_string(), - DefWithBodyId::StaticId(it) => db.static_data(it).name.clone().to_string(), - DefWithBodyId::ConstId(it) => { - db.const_data(it).name.clone().unwrap_or_else(Name::missing).to_string() - } + DefWithBodyId::FunctionId(it) => db.function_data(it).name.display(db.upcast()).to_string(), + DefWithBodyId::StaticId(it) => db.static_data(it).name.display(db.upcast()).to_string(), + DefWithBodyId::ConstId(it) => db + .const_data(it) + .name + .clone() + .unwrap_or_else(Name::missing) + .display(db.upcast()) + .to_string(), DefWithBodyId::VariantId(it) => { - db.enum_data(it.parent).variants[it.local_id].name.to_string() + db.enum_data(it.parent).variants[it.local_id].name.display(db.upcast()).to_string() } }); let body = db.body(def); let infer = db.infer(def); - let result = lower_to_mir(db, def, &body, &infer, body.body_expr)?; + let mut result = lower_to_mir(db, def, &body, &infer, body.body_expr)?; + result.shrink_to_fit(); Ok(Arc::new(result)) } @@ -1497,85 +1904,39 @@ pub fn lower_to_mir( if let Some((_, x)) = infer.type_mismatches().next() { return Err(MirLowerError::TypeMismatch(x.clone())); } - let mut basic_blocks = Arena::new(); - let start_block = - basic_blocks.alloc(BasicBlock { statements: vec![], terminator: None, is_cleanup: false }); - let mut locals = Arena::new(); + let mut ctx = MirLowerCtx::new(db, owner, body, infer); // 0 is return local - locals.alloc(Local { ty: infer[root_expr].clone() }); - let mut binding_locals: ArenaMap = ArenaMap::new(); - // 1 to param_len is for params - let param_locals: Vec = if let DefWithBodyId::FunctionId(fid) = owner { - let substs = TyBuilder::placeholder_subst(db, fid); - let callable_sig = db.callable_item_signature(fid.into()).substitute(Interner, &substs); - body.params - .iter() - .zip(callable_sig.params().iter()) - .map(|(&x, ty)| { - let local_id = locals.alloc(Local { ty: ty.clone() }); - if let Pat::Bind { id, subpat: None } = body[x] { - if matches!( - body.bindings[id].mode, - BindingAnnotation::Unannotated | BindingAnnotation::Mutable - ) { - binding_locals.insert(id, local_id); - } - } - local_id - }) - .collect() - } else { - if !body.params.is_empty() { - return Err(MirLowerError::TypeError("Unexpected parameter for non function body")); - } - vec![] - }; - // and then rest of bindings - for (id, _) in body.bindings.iter() { - if !binding_locals.contains_idx(id) { - binding_locals.insert(id, locals.alloc(Local { ty: infer[id].clone() })); + ctx.result.locals.alloc(Local { ty: ctx.expr_ty_after_adjustments(root_expr) }); + let binding_picker = |b: BindingId| { + if root_expr == body.body_expr { + body[b].owner.is_none() + } else { + body[b].owner == Some(root_expr) } - } - let mir = MirBody { - basic_blocks, - locals, - start_block, - binding_locals, - param_locals, - owner, - arg_count: body.params.len(), - }; - let mut ctx = MirLowerCtx { - result: mir, - db, - infer, - body, - owner, - current_loop_blocks: None, - discr_temp: None, }; - let mut current = start_block; - for (¶m, local) in body.params.iter().zip(ctx.result.param_locals.clone().into_iter()) { - if let Pat::Bind { id, .. } = body[param] { - if local == ctx.result.binding_locals[id] { - continue; + // 1 to param_len is for params + // FIXME: replace with let chain once it becomes stable + let current = 'b: { + if body.body_expr == root_expr { + // otherwise it's an inline const, and has no parameter + if let DefWithBodyId::FunctionId(fid) = owner { + let substs = TyBuilder::placeholder_subst(db, fid); + let callable_sig = + db.callable_item_signature(fid.into()).substitute(Interner, &substs); + break 'b ctx.lower_params_and_bindings( + body.params + .iter() + .zip(callable_sig.params().iter()) + .map(|(x, y)| (*x, y.clone())), + binding_picker, + )?; } } - let r = ctx.pattern_match( - current, - None, - local.into(), - ctx.result.locals[local].ty.clone(), - param, - BindingAnnotation::Unannotated, - )?; - if let Some(b) = r.1 { - ctx.set_terminator(b, Terminator::Unreachable); - } - current = r.0; - } - if let Some(b) = ctx.lower_expr_to_place(root_expr, return_slot().into(), current)? { - ctx.result.basic_blocks[b].terminator = Some(Terminator::Return); + ctx.lower_params_and_bindings([].into_iter(), binding_picker)? + }; + if let Some(current) = ctx.lower_expr_to_place(root_expr, return_slot().into(), current)? { + let current = ctx.pop_drop_scope_assert_finished(current)?; + ctx.set_terminator(current, TerminatorKind::Return, root_expr.into()); } Ok(ctx.result) } diff --git a/crates/hir-ty/src/mir/lower/as_place.rs b/crates/hir-ty/src/mir/lower/as_place.rs index fe8147dcd3e7a..d2c8d9a089e00 100644 --- a/crates/hir-ty/src/mir/lower/as_place.rs +++ b/crates/hir-ty/src/mir/lower/as_place.rs @@ -1,6 +1,7 @@ //! MIR lowering for places use super::*; +use hir_def::{lang_item::lang_attr, FunctionId}; use hir_expand::name; macro_rules! not_supported { @@ -15,8 +16,8 @@ impl MirLowerCtx<'_> { expr_id: ExprId, prev_block: BasicBlockId, ) -> Result> { - let ty = self.expr_ty(expr_id); - let place = self.temp(ty)?; + let ty = self.expr_ty_without_adjust(expr_id); + let place = self.temp(ty, prev_block, expr_id.into())?; let Some(current) = self.lower_expr_to_place_without_adjust(expr_id, place.into(), prev_block)? else { return Ok(None); }; @@ -29,9 +30,11 @@ impl MirLowerCtx<'_> { prev_block: BasicBlockId, adjustments: &[Adjustment], ) -> Result> { - let ty = - adjustments.last().map(|x| x.target.clone()).unwrap_or_else(|| self.expr_ty(expr_id)); - let place = self.temp(ty)?; + let ty = adjustments + .last() + .map(|x| x.target.clone()) + .unwrap_or_else(|| self.expr_ty_without_adjust(expr_id)); + let place = self.temp(ty, prev_block, expr_id.into())?; let Some(current) = self.lower_expr_to_place_with_adjust(expr_id, place.into(), prev_block, adjustments)? else { return Ok(None); }; @@ -62,7 +65,7 @@ impl MirLowerCtx<'_> { )? else { return Ok(None); }; - x.0.projection.push(ProjectionElem::Deref); + x.0 = x.0.project(ProjectionElem::Deref); Ok(Some(x)) } Adjust::Deref(Some(od)) => { @@ -79,7 +82,7 @@ impl MirLowerCtx<'_> { r, rest.last() .map(|x| x.target.clone()) - .unwrap_or_else(|| self.expr_ty(expr_id)), + .unwrap_or_else(|| self.expr_ty_without_adjust(expr_id)), last.target.clone(), expr_id.into(), match od.0 { @@ -125,35 +128,74 @@ impl MirLowerCtx<'_> { match &self.body.exprs[expr_id] { Expr::Path(p) => { let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id); - let Some(pr) = resolver.resolve_path_in_value_ns(self.db.upcast(), p.mod_path()) else { - return Err(MirLowerError::unresolved_path(self.db, p)); - }; - let pr = match pr { - ResolveValueResult::ValueNs(v) => v, - ResolveValueResult::Partial(..) => return try_rvalue(self), + let Some(pr) = resolver.resolve_path_in_value_ns_fully(self.db.upcast(), p) else { + return try_rvalue(self); }; match pr { ValueNs::LocalBinding(pat_id) => { - Ok(Some((self.result.binding_locals[pat_id].into(), current))) + Ok(Some((self.binding_local(pat_id)?.into(), current))) + } + ValueNs::StaticId(s) => { + let ty = self.expr_ty_without_adjust(expr_id); + let ref_ty = + TyKind::Ref(Mutability::Not, static_lifetime(), ty).intern(Interner); + let temp: Place = self.temp(ref_ty, current, expr_id.into())?.into(); + self.push_assignment( + current, + temp.clone(), + Operand::Static(s).into(), + expr_id.into(), + ); + Ok(Some((temp.project(ProjectionElem::Deref), current))) } _ => try_rvalue(self), } } Expr::UnaryOp { expr, op } => match op { - hir_def::expr::UnaryOp::Deref => { - if !matches!( - self.expr_ty(*expr).kind(Interner), - TyKind::Ref(..) | TyKind::Raw(..) - ) { - let Some(_) = self.lower_expr_as_place(current, *expr, true)? else { + hir_def::hir::UnaryOp::Deref => { + let is_builtin = match self.expr_ty_without_adjust(*expr).kind(Interner) { + TyKind::Ref(..) | TyKind::Raw(..) => true, + TyKind::Adt(id, _) => { + if let Some(lang_item) = lang_attr(self.db.upcast(), id.0) { + lang_item == LangItem::OwnedBox + } else { + false + } + } + _ => false, + }; + if !is_builtin { + let Some((p, current)) = self.lower_expr_as_place(current, *expr, true)? else { return Ok(None); }; - not_supported!("explicit overloaded deref"); + return self.lower_overloaded_deref( + current, + p, + self.expr_ty_after_adjustments(*expr), + self.expr_ty_without_adjust(expr_id), + expr_id.into(), + 'b: { + if let Some((f, _)) = self.infer.method_resolution(expr_id) { + if let Some(deref_trait) = + self.resolve_lang_item(LangItem::DerefMut)?.as_trait() + { + if let Some(deref_fn) = self + .db + .trait_data(deref_trait) + .method_by_name(&name![deref_mut]) + { + break 'b deref_fn == f; + } + } + } + false + }, + ); } let Some((mut r, current)) = self.lower_expr_as_place(current, *expr, true)? else { return Ok(None); }; - r.projection.push(ProjectionElem::Deref); + r = r.project(ProjectionElem::Deref); Ok(Some((r, current))) } _ => try_rvalue(self), @@ -169,25 +211,84 @@ impl MirLowerCtx<'_> { let base_ty = self.expr_ty_after_adjustments(*base); let index_ty = self.expr_ty_after_adjustments(*index); if index_ty != TyBuilder::usize() - || !matches!(base_ty.kind(Interner), TyKind::Array(..) | TyKind::Slice(..)) + || !matches!( + base_ty.strip_reference().kind(Interner), + TyKind::Array(..) | TyKind::Slice(..) + ) { - not_supported!("overloaded index"); + let Some(index_fn) = self.infer.method_resolution(expr_id) else { + return Err(MirLowerError::UnresolvedMethod("[overloaded index]".to_string())); + }; + let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true)? else { + return Ok(None); + }; + let Some((index_operand, current)) = self.lower_expr_to_some_operand(*index, current)? else { + return Ok(None); + }; + return self.lower_overloaded_index( + current, + base_place, + base_ty, + self.expr_ty_without_adjust(expr_id), + index_operand, + expr_id.into(), + index_fn, + ); } + let adjusts = self + .infer + .expr_adjustments + .get(base) + .and_then(|x| x.split_last()) + .map(|x| x.1) + .unwrap_or(&[]); let Some((mut p_base, current)) = - self.lower_expr_as_place(current, *base, true)? else { + self.lower_expr_as_place_with_adjust(current, *base, true, adjusts)? + else { return Ok(None); }; - let l_index = self.temp(self.expr_ty_after_adjustments(*index))?; + let l_index = + self.temp(self.expr_ty_after_adjustments(*index), current, expr_id.into())?; let Some(current) = self.lower_expr_to_place(*index, l_index.into(), current)? else { return Ok(None); }; - p_base.projection.push(ProjectionElem::Index(l_index)); + p_base = p_base.project(ProjectionElem::Index(l_index)); Ok(Some((p_base, current))) } _ => try_rvalue(self), } } + fn lower_overloaded_index( + &mut self, + current: BasicBlockId, + place: Place, + base_ty: Ty, + result_ty: Ty, + index_operand: Operand, + span: MirSpan, + index_fn: (FunctionId, Substitution), + ) -> Result> { + let mutability = match base_ty.as_reference() { + Some((_, _, mutability)) => mutability, + None => Mutability::Not, + }; + let result_ref = TyKind::Ref(mutability, static_lifetime(), result_ty).intern(Interner); + let mut result: Place = self.temp(result_ref, current, span)?.into(); + let index_fn_op = Operand::const_zst( + TyKind::FnDef( + self.db.intern_callable_def(CallableDefId::FunctionId(index_fn.0)).into(), + index_fn.1, + ) + .intern(Interner), + ); + let Some(current) = self.lower_call(index_fn_op, Box::new([Operand::Copy(place), index_operand]), result.clone(), current, false, span)? else { + return Ok(None); + }; + result = result.project(ProjectionElem::Deref); + Ok(Some((result, current))) + } + fn lower_overloaded_deref( &mut self, current: BasicBlockId, @@ -209,7 +310,7 @@ impl MirLowerCtx<'_> { }; let ty_ref = TyKind::Ref(chalk_mut, static_lifetime(), source_ty.clone()).intern(Interner); let target_ty_ref = TyKind::Ref(chalk_mut, static_lifetime(), target_ty).intern(Interner); - let ref_place: Place = self.temp(ty_ref)?.into(); + let ref_place: Place = self.temp(ty_ref, current, span)?.into(); self.push_assignment(current, ref_place.clone(), Rvalue::Ref(borrow_kind, place), span); let deref_trait = self .resolve_lang_item(trait_lang_item)? @@ -227,11 +328,11 @@ impl MirLowerCtx<'_> { ) .intern(Interner), ); - let mut result: Place = self.temp(target_ty_ref)?.into(); - let Some(current) = self.lower_call(deref_fn_op, vec![Operand::Copy(ref_place)], result.clone(), current, false)? else { + let mut result: Place = self.temp(target_ty_ref, current, span)?.into(); + let Some(current) = self.lower_call(deref_fn_op, Box::new([Operand::Copy(ref_place)]), result.clone(), current, false, span)? else { return Ok(None); }; - result.projection.push(ProjectionElem::Deref); + result = result.project(ProjectionElem::Deref); Ok(Some((result, current))) } } diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs new file mode 100644 index 0000000000000..ff43c64a9e60f --- /dev/null +++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -0,0 +1,617 @@ +//! MIR lowering for patterns + +use hir_def::{hir::LiteralOrConst, resolver::HasResolver, AssocItemId}; + +use crate::BindingMode; + +use super::*; + +macro_rules! not_supported { + ($x: expr) => { + return Err(MirLowerError::NotSupported(format!($x))) + }; +} + +pub(super) enum AdtPatternShape<'a> { + Tuple { args: &'a [PatId], ellipsis: Option }, + Record { args: &'a [RecordFieldPat] }, + Unit, +} + +/// We need to do pattern matching in two phases: One to check if the pattern matches, and one to fill the bindings +/// of patterns. This is necessary to prevent double moves and similar problems. For example: +/// ```ignore +/// struct X; +/// match (X, 3) { +/// (b, 2) | (b, 3) => {}, +/// _ => {} +/// } +/// ``` +/// If we do everything in one pass, we will move `X` to the first `b`, then we see that the second field of tuple +/// doesn't match and we should move the `X` to the second `b` (which here is the same thing, but doesn't need to be) and +/// it might even doesn't match the second pattern and we may want to not move `X` at all. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum MatchingMode { + /// Check that if this pattern matches + Check, + /// Assume that this pattern matches, fill bindings + Bind, +} + +impl MirLowerCtx<'_> { + /// It gets a `current` unterminated block, appends some statements and possibly a terminator to it to check if + /// the pattern matches and write bindings, and returns two unterminated blocks, one for the matched path (which + /// can be the `current` block) and one for the mismatched path. If the input pattern is irrefutable, the + /// mismatched path block is `None`. + /// + /// By default, it will create a new block for mismatched path. If you already have one, you can provide it with + /// `current_else` argument to save an unnecessary jump. If `current_else` isn't `None`, the result mismatched path + /// wouldn't be `None` as well. Note that this function will add jumps to the beginning of the `current_else` block, + /// so it should be an empty block. + pub(super) fn pattern_match( + &mut self, + current: BasicBlockId, + current_else: Option, + cond_place: Place, + pattern: PatId, + ) -> Result<(BasicBlockId, Option)> { + let (current, current_else) = self.pattern_match_inner( + current, + current_else, + cond_place.clone(), + pattern, + MatchingMode::Check, + )?; + let (current, current_else) = self.pattern_match_inner( + current, + current_else, + cond_place, + pattern, + MatchingMode::Bind, + )?; + Ok((current, current_else)) + } + + fn pattern_match_inner( + &mut self, + mut current: BasicBlockId, + mut current_else: Option, + mut cond_place: Place, + pattern: PatId, + mode: MatchingMode, + ) -> Result<(BasicBlockId, Option)> { + let cnt = self.infer.pat_adjustments.get(&pattern).map(|x| x.len()).unwrap_or_default(); + cond_place.projection = cond_place + .projection + .iter() + .cloned() + .chain((0..cnt).map(|_| ProjectionElem::Deref)) + .collect::>() + .into(); + Ok(match &self.body.pats[pattern] { + Pat::Missing => return Err(MirLowerError::IncompletePattern), + Pat::Wild => (current, current_else), + Pat::Tuple { args, ellipsis } => { + let subst = match self.infer[pattern].kind(Interner) { + TyKind::Tuple(_, s) => s, + _ => { + return Err(MirLowerError::TypeError( + "non tuple type matched with tuple pattern", + )) + } + }; + self.pattern_match_tuple_like( + current, + current_else, + args, + *ellipsis, + (0..subst.len(Interner)).map(|i| PlaceElem::TupleOrClosureField(i)), + &(&mut cond_place), + mode, + )? + } + Pat::Or(pats) => { + let then_target = self.new_basic_block(); + let mut finished = false; + for pat in &**pats { + let (mut next, next_else) = self.pattern_match_inner( + current, + None, + (&mut cond_place).clone(), + *pat, + MatchingMode::Check, + )?; + if mode == MatchingMode::Bind { + (next, _) = self.pattern_match_inner( + next, + None, + (&mut cond_place).clone(), + *pat, + MatchingMode::Bind, + )?; + } + self.set_goto(next, then_target, pattern.into()); + match next_else { + Some(t) => { + current = t; + } + None => { + finished = true; + break; + } + } + } + if !finished { + if mode == MatchingMode::Bind { + self.set_terminator(current, TerminatorKind::Unreachable, pattern.into()); + } else { + let ce = *current_else.get_or_insert_with(|| self.new_basic_block()); + self.set_goto(current, ce, pattern.into()); + } + } + (then_target, current_else) + } + Pat::Record { args, .. } => { + let Some(variant) = self.infer.variant_resolution_for_pat(pattern) else { + not_supported!("unresolved variant for record"); + }; + self.pattern_matching_variant( + cond_place, + variant, + current, + pattern.into(), + current_else, + AdtPatternShape::Record { args: &*args }, + mode, + )? + } + Pat::Range { start, end } => { + let mut add_check = |l: &LiteralOrConst, binop| -> Result<()> { + let lv = + self.lower_literal_or_const_to_operand(self.infer[pattern].clone(), l)?; + let else_target = *current_else.get_or_insert_with(|| self.new_basic_block()); + let next = self.new_basic_block(); + let discr: Place = + self.temp(TyBuilder::bool(), current, pattern.into())?.into(); + self.push_assignment( + current, + discr.clone(), + Rvalue::CheckedBinaryOp( + binop, + lv, + Operand::Copy((&mut cond_place).clone()), + ), + pattern.into(), + ); + let discr = Operand::Copy(discr); + self.set_terminator( + current, + TerminatorKind::SwitchInt { + discr, + targets: SwitchTargets::static_if(1, next, else_target), + }, + pattern.into(), + ); + current = next; + Ok(()) + }; + if mode == MatchingMode::Check { + if let Some(start) = start { + add_check(start, BinOp::Le)?; + } + if let Some(end) = end { + add_check(end, BinOp::Ge)?; + } + } + (current, current_else) + } + Pat::Slice { prefix, slice, suffix } => { + if mode == MatchingMode::Check { + // emit runtime length check for slice + if let TyKind::Slice(_) = self.infer[pattern].kind(Interner) { + let pattern_len = prefix.len() + suffix.len(); + let place_len: Place = + self.temp(TyBuilder::usize(), current, pattern.into())?.into(); + self.push_assignment( + current, + place_len.clone(), + Rvalue::Len((&mut cond_place).clone()), + pattern.into(), + ); + let else_target = + *current_else.get_or_insert_with(|| self.new_basic_block()); + let next = self.new_basic_block(); + if slice.is_none() { + self.set_terminator( + current, + TerminatorKind::SwitchInt { + discr: Operand::Copy(place_len), + targets: SwitchTargets::static_if( + pattern_len as u128, + next, + else_target, + ), + }, + pattern.into(), + ); + } else { + let c = Operand::from_concrete_const( + pattern_len.to_le_bytes().to_vec(), + MemoryMap::default(), + TyBuilder::usize(), + ); + let discr: Place = + self.temp(TyBuilder::bool(), current, pattern.into())?.into(); + self.push_assignment( + current, + discr.clone(), + Rvalue::CheckedBinaryOp(BinOp::Le, c, Operand::Copy(place_len)), + pattern.into(), + ); + let discr = Operand::Copy(discr); + self.set_terminator( + current, + TerminatorKind::SwitchInt { + discr, + targets: SwitchTargets::static_if(1, next, else_target), + }, + pattern.into(), + ); + } + current = next; + } + } + for (i, &pat) in prefix.iter().enumerate() { + let next_place = (&mut cond_place).project(ProjectionElem::ConstantIndex { + offset: i as u64, + from_end: false, + }); + (current, current_else) = + self.pattern_match_inner(current, current_else, next_place, pat, mode)?; + } + if let Some(slice) = slice { + if mode == MatchingMode::Bind { + if let Pat::Bind { id, subpat: _ } = self.body[*slice] { + let next_place = (&mut cond_place).project(ProjectionElem::Subslice { + from: prefix.len() as u64, + to: suffix.len() as u64, + }); + (current, current_else) = self.pattern_match_binding( + id, + next_place, + (*slice).into(), + current, + current_else, + )?; + } + } + } + for (i, &pat) in suffix.iter().enumerate() { + let next_place = (&mut cond_place).project(ProjectionElem::ConstantIndex { + offset: i as u64, + from_end: true, + }); + (current, current_else) = + self.pattern_match_inner(current, current_else, next_place, pat, mode)?; + } + (current, current_else) + } + Pat::Path(p) => match self.infer.variant_resolution_for_pat(pattern) { + Some(variant) => self.pattern_matching_variant( + cond_place, + variant, + current, + pattern.into(), + current_else, + AdtPatternShape::Unit, + mode, + )?, + None => { + let unresolved_name = || MirLowerError::unresolved_path(self.db, p); + let resolver = self.owner.resolver(self.db.upcast()); + let pr = resolver + .resolve_path_in_value_ns(self.db.upcast(), p) + .ok_or_else(unresolved_name)?; + let (c, subst) = 'b: { + if let Some(x) = self.infer.assoc_resolutions_for_pat(pattern) { + if let AssocItemId::ConstId(c) = x.0 { + break 'b (c, x.1); + } + } + if let ResolveValueResult::ValueNs(v) = pr { + if let ValueNs::ConstId(c) = v { + break 'b (c, Substitution::empty(Interner)); + } + } + not_supported!("path in pattern position that is not const or variant") + }; + let tmp: Place = + self.temp(self.infer[pattern].clone(), current, pattern.into())?.into(); + let span = pattern.into(); + self.lower_const( + c.into(), + current, + tmp.clone(), + subst, + span, + self.infer[pattern].clone(), + )?; + let tmp2: Place = self.temp(TyBuilder::bool(), current, pattern.into())?.into(); + self.push_assignment( + current, + tmp2.clone(), + Rvalue::CheckedBinaryOp( + BinOp::Eq, + Operand::Copy(tmp), + Operand::Copy(cond_place), + ), + span, + ); + let next = self.new_basic_block(); + let else_target = current_else.unwrap_or_else(|| self.new_basic_block()); + self.set_terminator( + current, + TerminatorKind::SwitchInt { + discr: Operand::Copy(tmp2), + targets: SwitchTargets::static_if(1, next, else_target), + }, + span, + ); + (next, Some(else_target)) + } + }, + Pat::Lit(l) => match &self.body.exprs[*l] { + Expr::Literal(l) => { + let c = self.lower_literal_to_operand(self.infer[pattern].clone(), l)?; + if mode == MatchingMode::Check { + self.pattern_match_const(current_else, current, c, cond_place, pattern)? + } else { + (current, current_else) + } + } + _ => not_supported!("expression path literal"), + }, + Pat::Bind { id, subpat } => { + if let Some(subpat) = subpat { + (current, current_else) = self.pattern_match_inner( + current, + current_else, + (&mut cond_place).clone(), + *subpat, + mode, + )? + } + if mode == MatchingMode::Bind { + self.pattern_match_binding( + *id, + cond_place, + pattern.into(), + current, + current_else, + )? + } else { + (current, current_else) + } + } + Pat::TupleStruct { path: _, args, ellipsis } => { + let Some(variant) = self.infer.variant_resolution_for_pat(pattern) else { + not_supported!("unresolved variant"); + }; + self.pattern_matching_variant( + cond_place, + variant, + current, + pattern.into(), + current_else, + AdtPatternShape::Tuple { args, ellipsis: *ellipsis }, + mode, + )? + } + Pat::Ref { pat, mutability: _ } => self.pattern_match_inner( + current, + current_else, + cond_place.project(ProjectionElem::Deref), + *pat, + mode, + )?, + Pat::Box { .. } => not_supported!("box pattern"), + Pat::ConstBlock(_) => not_supported!("const block pattern"), + }) + } + + fn pattern_match_binding( + &mut self, + id: BindingId, + cond_place: Place, + span: MirSpan, + current: BasicBlockId, + current_else: Option, + ) -> Result<(BasicBlockId, Option)> { + let target_place = self.binding_local(id)?; + let mode = self.infer.binding_modes[id]; + self.push_storage_live(id, current)?; + self.push_assignment( + current, + target_place.into(), + match mode { + BindingMode::Move => Operand::Copy(cond_place).into(), + BindingMode::Ref(Mutability::Not) => Rvalue::Ref(BorrowKind::Shared, cond_place), + BindingMode::Ref(Mutability::Mut) => { + Rvalue::Ref(BorrowKind::Mut { allow_two_phase_borrow: false }, cond_place) + } + }, + span, + ); + Ok((current, current_else)) + } + + fn pattern_match_const( + &mut self, + current_else: Option, + current: BasicBlockId, + c: Operand, + cond_place: Place, + pattern: Idx, + ) -> Result<(BasicBlockId, Option)> { + let then_target = self.new_basic_block(); + let else_target = current_else.unwrap_or_else(|| self.new_basic_block()); + let discr: Place = self.temp(TyBuilder::bool(), current, pattern.into())?.into(); + self.push_assignment( + current, + discr.clone(), + Rvalue::CheckedBinaryOp(BinOp::Eq, c, Operand::Copy(cond_place)), + pattern.into(), + ); + let discr = Operand::Copy(discr); + self.set_terminator( + current, + TerminatorKind::SwitchInt { + discr, + targets: SwitchTargets::static_if(1, then_target, else_target), + }, + pattern.into(), + ); + Ok((then_target, Some(else_target))) + } + + fn pattern_matching_variant( + &mut self, + cond_place: Place, + variant: VariantId, + mut current: BasicBlockId, + span: MirSpan, + mut current_else: Option, + shape: AdtPatternShape<'_>, + mode: MatchingMode, + ) -> Result<(BasicBlockId, Option)> { + Ok(match variant { + VariantId::EnumVariantId(v) => { + if mode == MatchingMode::Check { + let e = self.const_eval_discriminant(v)? as u128; + let tmp = self.discr_temp_place(current); + self.push_assignment( + current, + tmp.clone(), + Rvalue::Discriminant(cond_place.clone()), + span, + ); + let next = self.new_basic_block(); + let else_target = current_else.get_or_insert_with(|| self.new_basic_block()); + self.set_terminator( + current, + TerminatorKind::SwitchInt { + discr: Operand::Copy(tmp), + targets: SwitchTargets::static_if(e, next, *else_target), + }, + span, + ); + current = next; + } + let enum_data = self.db.enum_data(v.parent); + self.pattern_matching_variant_fields( + shape, + &enum_data.variants[v.local_id].variant_data, + variant, + current, + current_else, + &cond_place, + mode, + )? + } + VariantId::StructId(s) => { + let struct_data = self.db.struct_data(s); + self.pattern_matching_variant_fields( + shape, + &struct_data.variant_data, + variant, + current, + current_else, + &cond_place, + mode, + )? + } + VariantId::UnionId(_) => { + return Err(MirLowerError::TypeError("pattern matching on union")) + } + }) + } + + fn pattern_matching_variant_fields( + &mut self, + shape: AdtPatternShape<'_>, + variant_data: &VariantData, + v: VariantId, + current: BasicBlockId, + current_else: Option, + cond_place: &Place, + mode: MatchingMode, + ) -> Result<(BasicBlockId, Option)> { + Ok(match shape { + AdtPatternShape::Record { args } => { + let it = args + .iter() + .map(|x| { + let field_id = + variant_data.field(&x.name).ok_or(MirLowerError::UnresolvedField)?; + Ok(( + PlaceElem::Field(FieldId { parent: v.into(), local_id: field_id }), + x.pat, + )) + }) + .collect::>>()?; + self.pattern_match_adt(current, current_else, it.into_iter(), cond_place, mode)? + } + AdtPatternShape::Tuple { args, ellipsis } => { + let fields = variant_data + .fields() + .iter() + .map(|(x, _)| PlaceElem::Field(FieldId { parent: v.into(), local_id: x })); + self.pattern_match_tuple_like( + current, + current_else, + args, + ellipsis, + fields, + cond_place, + mode, + )? + } + AdtPatternShape::Unit => (current, current_else), + }) + } + + fn pattern_match_adt( + &mut self, + mut current: BasicBlockId, + mut current_else: Option, + args: impl Iterator, + cond_place: &Place, + mode: MatchingMode, + ) -> Result<(BasicBlockId, Option)> { + for (proj, arg) in args { + let cond_place = cond_place.project(proj); + (current, current_else) = + self.pattern_match_inner(current, current_else, cond_place, arg, mode)?; + } + Ok((current, current_else)) + } + + fn pattern_match_tuple_like( + &mut self, + current: BasicBlockId, + current_else: Option, + args: &[PatId], + ellipsis: Option, + fields: impl DoubleEndedIterator + Clone, + cond_place: &Place, + mode: MatchingMode, + ) -> Result<(BasicBlockId, Option)> { + let (al, ar) = args.split_at(ellipsis.unwrap_or(args.len())); + let it = al + .iter() + .zip(fields.clone()) + .chain(ar.iter().rev().zip(fields.rev())) + .map(|(x, y)| (y, *x)); + self.pattern_match_adt(current, current_else, it, cond_place, mode) + } +} diff --git a/crates/hir-ty/src/mir/monomorphization.rs b/crates/hir-ty/src/mir/monomorphization.rs new file mode 100644 index 0000000000000..ce3f7a8e51026 --- /dev/null +++ b/crates/hir-ty/src/mir/monomorphization.rs @@ -0,0 +1,351 @@ +//! Monomorphization of mir, which is used in mir interpreter and const eval. +//! +//! The job of monomorphization is: +//! * Monomorphization. That is, replacing `Option` with `Option` where `T:=i32` substitution +//! is provided +//! * Normalizing types, for example replacing RPIT of other functions called in this body. +//! +//! So the monomorphization should be called even if the substitution is empty. + +use std::mem; + +use chalk_ir::{ + fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}, + ConstData, DebruijnIndex, +}; +use hir_def::{DefWithBodyId, GeneralConstId}; +use triomphe::Arc; + +use crate::{ + consteval::unknown_const, + db::HirDatabase, + from_placeholder_idx, + infer::normalize, + method_resolution::lookup_impl_const, + utils::{generics, Generics}, + ClosureId, Const, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, TyKind, +}; + +use super::{MirBody, MirLowerError, Operand, Rvalue, StatementKind, TerminatorKind}; + +macro_rules! not_supported { + ($x: expr) => { + return Err(MirLowerError::NotSupported(format!($x))) + }; +} + +struct Filler<'a> { + db: &'a dyn HirDatabase, + trait_env: Arc, + subst: &'a Substitution, + generics: Option, + owner: DefWithBodyId, +} +impl FallibleTypeFolder for Filler<'_> { + type Error = MirLowerError; + + fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder { + self + } + + fn interner(&self) -> Interner { + Interner + } + + fn try_fold_ty( + &mut self, + ty: Ty, + outer_binder: DebruijnIndex, + ) -> std::result::Result { + match ty.kind(Interner) { + TyKind::AssociatedType(id, subst) => { + // I don't know exactly if and why this is needed, but it looks like `normalize_ty` likes + // this kind of associated types. + Ok(TyKind::Alias(chalk_ir::AliasTy::Projection(ProjectionTy { + associated_ty_id: *id, + substitution: subst.clone().try_fold_with(self, outer_binder)?, + })) + .intern(Interner)) + } + TyKind::OpaqueType(id, subst) => { + let impl_trait_id = self.db.lookup_intern_impl_trait_id((*id).into()); + let subst = subst.clone().try_fold_with(self.as_dyn(), outer_binder)?; + match impl_trait_id { + crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => { + let infer = self.db.infer(func.into()); + let filler = &mut Filler { + db: self.db, + owner: self.owner, + trait_env: self.trait_env.clone(), + subst: &subst, + generics: Some(generics(self.db.upcast(), func.into())), + }; + filler.try_fold_ty(infer.type_of_rpit[idx].clone(), outer_binder) + } + crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { + not_supported!("async block impl trait"); + } + } + } + _ => ty.try_super_fold_with(self.as_dyn(), outer_binder), + } + } + + fn try_fold_free_placeholder_const( + &mut self, + _ty: chalk_ir::Ty, + idx: chalk_ir::PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> std::result::Result, Self::Error> { + let x = from_placeholder_idx(self.db, idx); + let Some(idx) = self.generics.as_ref().and_then(|g| g.param_idx(x)) else { + not_supported!("missing idx in generics"); + }; + Ok(self + .subst + .as_slice(Interner) + .get(idx) + .and_then(|x| x.constant(Interner)) + .ok_or_else(|| MirLowerError::GenericArgNotProvided(x, self.subst.clone()))? + .clone()) + } + + fn try_fold_free_placeholder_ty( + &mut self, + idx: chalk_ir::PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> std::result::Result { + let x = from_placeholder_idx(self.db, idx); + let Some(idx) = self.generics.as_ref().and_then(|g| g.param_idx(x)) else { + not_supported!("missing idx in generics"); + }; + Ok(self + .subst + .as_slice(Interner) + .get(idx) + .and_then(|x| x.ty(Interner)) + .ok_or_else(|| MirLowerError::GenericArgNotProvided(x, self.subst.clone()))? + .clone()) + } + + fn try_fold_const( + &mut self, + constant: chalk_ir::Const, + outer_binder: DebruijnIndex, + ) -> Result, Self::Error> { + let next_ty = normalize( + self.db, + self.trait_env.clone(), + constant.data(Interner).ty.clone().try_fold_with(self, outer_binder)?, + ); + ConstData { ty: next_ty, value: constant.data(Interner).value.clone() } + .intern(Interner) + .try_super_fold_with(self, outer_binder) + } +} + +impl Filler<'_> { + fn fill_ty(&mut self, ty: &mut Ty) -> Result<(), MirLowerError> { + let tmp = mem::replace(ty, TyKind::Error.intern(Interner)); + *ty = normalize( + self.db, + self.trait_env.clone(), + tmp.try_fold_with(self, DebruijnIndex::INNERMOST)?, + ); + Ok(()) + } + + fn fill_const(&mut self, c: &mut Const) -> Result<(), MirLowerError> { + let tmp = mem::replace(c, unknown_const(c.data(Interner).ty.clone())); + *c = tmp.try_fold_with(self, DebruijnIndex::INNERMOST)?; + Ok(()) + } + + fn fill_subst(&mut self, ty: &mut Substitution) -> Result<(), MirLowerError> { + let tmp = mem::replace(ty, Substitution::empty(Interner)); + *ty = tmp.try_fold_with(self, DebruijnIndex::INNERMOST)?; + Ok(()) + } + + fn fill_operand(&mut self, op: &mut Operand) -> Result<(), MirLowerError> { + match op { + Operand::Constant(c) => { + match &c.data(Interner).value { + chalk_ir::ConstValue::BoundVar(b) => { + let resolved = self + .subst + .as_slice(Interner) + .get(b.index) + .ok_or_else(|| { + MirLowerError::GenericArgNotProvided( + self.generics + .as_ref() + .and_then(|x| x.iter().nth(b.index)) + .unwrap() + .0, + self.subst.clone(), + ) + })? + .assert_const_ref(Interner); + *c = resolved.clone(); + } + chalk_ir::ConstValue::InferenceVar(_) + | chalk_ir::ConstValue::Placeholder(_) => {} + chalk_ir::ConstValue::Concrete(cc) => match &cc.interned { + crate::ConstScalar::UnevaluatedConst(const_id, subst) => { + let mut const_id = *const_id; + let mut subst = subst.clone(); + self.fill_subst(&mut subst)?; + if let GeneralConstId::ConstId(c) = const_id { + let (c, s) = lookup_impl_const( + self.db, + self.db.trait_environment_for_body(self.owner), + c, + subst, + ); + const_id = GeneralConstId::ConstId(c); + subst = s; + } + let result = + self.db.const_eval(const_id.into(), subst).map_err(|e| { + let name = const_id.name(self.db.upcast()); + MirLowerError::ConstEvalError(name, Box::new(e)) + })?; + *c = result; + } + crate::ConstScalar::Bytes(_, _) | crate::ConstScalar::Unknown => (), + }, + } + self.fill_const(c)?; + } + Operand::Copy(_) | Operand::Move(_) | Operand::Static(_) => (), + } + Ok(()) + } + + fn fill_body(&mut self, body: &mut MirBody) -> Result<(), MirLowerError> { + for (_, l) in body.locals.iter_mut() { + self.fill_ty(&mut l.ty)?; + } + for (_, bb) in body.basic_blocks.iter_mut() { + for statement in &mut bb.statements { + match &mut statement.kind { + StatementKind::Assign(_, r) => match r { + Rvalue::Aggregate(ak, ops) => { + for op in &mut **ops { + self.fill_operand(op)?; + } + match ak { + super::AggregateKind::Array(ty) + | super::AggregateKind::Tuple(ty) + | super::AggregateKind::Closure(ty) => self.fill_ty(ty)?, + super::AggregateKind::Adt(_, subst) => self.fill_subst(subst)?, + super::AggregateKind::Union(_, _) => (), + } + } + Rvalue::ShallowInitBox(_, ty) | Rvalue::ShallowInitBoxWithAlloc(ty) => { + self.fill_ty(ty)?; + } + Rvalue::Use(op) => { + self.fill_operand(op)?; + } + Rvalue::Repeat(op, len) => { + self.fill_operand(op)?; + self.fill_const(len)?; + } + Rvalue::Ref(_, _) + | Rvalue::Len(_) + | Rvalue::Cast(_, _, _) + | Rvalue::CheckedBinaryOp(_, _, _) + | Rvalue::UnaryOp(_, _) + | Rvalue::Discriminant(_) + | Rvalue::CopyForDeref(_) => (), + }, + StatementKind::Deinit(_) + | StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + | StatementKind::Nop => (), + } + } + if let Some(terminator) = &mut bb.terminator { + match &mut terminator.kind { + TerminatorKind::Call { func, args, .. } => { + self.fill_operand(func)?; + for op in &mut **args { + self.fill_operand(op)?; + } + } + TerminatorKind::SwitchInt { discr, .. } => { + self.fill_operand(discr)?; + } + TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::Drop { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::Assert { .. } + | TerminatorKind::Yield { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } => (), + } + } + } + Ok(()) + } +} + +pub fn monomorphized_mir_body_query( + db: &dyn HirDatabase, + owner: DefWithBodyId, + subst: Substitution, + trait_env: Arc, +) -> Result, MirLowerError> { + let generics = owner.as_generic_def_id().map(|g_def| generics(db.upcast(), g_def)); + let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner }; + let body = db.mir_body(owner)?; + let mut body = (*body).clone(); + filler.fill_body(&mut body)?; + Ok(Arc::new(body)) +} + +pub fn monomorphized_mir_body_recover( + _: &dyn HirDatabase, + _: &[String], + _: &DefWithBodyId, + _: &Substitution, + _: &Arc, +) -> Result, MirLowerError> { + return Err(MirLowerError::Loop); +} + +pub fn monomorphized_mir_body_for_closure_query( + db: &dyn HirDatabase, + closure: ClosureId, + subst: Substitution, + trait_env: Arc, +) -> Result, MirLowerError> { + let (owner, _) = db.lookup_intern_closure(closure.into()); + let generics = owner.as_generic_def_id().map(|g_def| generics(db.upcast(), g_def)); + let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner }; + let body = db.mir_body_for_closure(closure)?; + let mut body = (*body).clone(); + filler.fill_body(&mut body)?; + Ok(Arc::new(body)) +} + +// FIXME: remove this function. Monomorphization is a time consuming job and should always be a query. +pub fn monomorphize_mir_body_bad( + db: &dyn HirDatabase, + mut body: MirBody, + subst: Substitution, + trait_env: Arc, +) -> Result { + let owner = body.owner; + let generics = owner.as_generic_def_id().map(|g_def| generics(db.upcast(), g_def)); + let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner }; + filler.fill_body(&mut body)?; + Ok(body) +} diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs index ffc08b7e346c7..58662b01b99b1 100644 --- a/crates/hir-ty/src/mir/pretty.rs +++ b/crates/hir-ty/src/mir/pretty.rs @@ -1,28 +1,80 @@ //! A pretty-printer for MIR. -use std::fmt::{Display, Write}; +use std::{ + fmt::{Debug, Display, Write}, + mem, +}; -use hir_def::{body::Body, expr::BindingId}; +use hir_def::{body::Body, hir::BindingId}; use hir_expand::name::Name; use la_arena::ArenaMap; use crate::{ db::HirDatabase, - display::HirDisplay, - mir::{PlaceElem, ProjectionElem, StatementKind, Terminator}, + display::{ClosureStyle, HirDisplay}, + mir::{PlaceElem, ProjectionElem, StatementKind, TerminatorKind}, + ClosureId, }; use super::{ AggregateKind, BasicBlockId, BorrowKind, LocalId, MirBody, Operand, Place, Rvalue, UnOp, }; +macro_rules! w { + ($dst:expr, $($arg:tt)*) => { + { let _ = write!($dst, $($arg)*); } + }; +} + +macro_rules! wln { + ($dst:expr) => { + { let _ = writeln!($dst); } + }; + ($dst:expr, $($arg:tt)*) => { + { let _ = writeln!($dst, $($arg)*); } + }; +} + impl MirBody { pub fn pretty_print(&self, db: &dyn HirDatabase) -> String { let hir_body = db.body(self.owner); let mut ctx = MirPrettyCtx::new(self, &hir_body, db); - ctx.for_body(); + ctx.for_body(|this| match ctx.body.owner { + hir_def::DefWithBodyId::FunctionId(id) => { + let data = db.function_data(id); + w!(this, "fn {}() ", data.name.display(db.upcast())); + } + hir_def::DefWithBodyId::StaticId(id) => { + let data = db.static_data(id); + w!(this, "static {}: _ = ", data.name.display(db.upcast())); + } + hir_def::DefWithBodyId::ConstId(id) => { + let data = db.const_data(id); + w!( + this, + "const {}: _ = ", + data.name.as_ref().unwrap_or(&Name::missing()).display(db.upcast()) + ); + } + hir_def::DefWithBodyId::VariantId(id) => { + let data = db.enum_data(id.parent); + w!(this, "enum {} = ", data.name.display(db.upcast())); + } + }); ctx.result } + + // String with lines is rendered poorly in `dbg` macros, which I use very much, so this + // function exists to solve that. + pub fn dbg(&self, db: &dyn HirDatabase) -> impl Debug { + struct StringDbg(String); + impl Debug for StringDbg { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&self.0) + } + } + StringDbg(self.pretty_print(db)) + } } struct MirPrettyCtx<'a> { @@ -30,25 +82,10 @@ struct MirPrettyCtx<'a> { hir_body: &'a Body, db: &'a dyn HirDatabase, result: String, - ident: String, + indent: String, local_to_binding: ArenaMap, } -macro_rules! w { - ($dst:expr, $($arg:tt)*) => { - { let _ = write!($dst, $($arg)*); } - }; -} - -macro_rules! wln { - ($dst:expr) => { - { let _ = writeln!($dst); } - }; - ($dst:expr, $($arg:tt)*) => { - { let _ = writeln!($dst, $($arg)*); } - }; -} - impl Write for MirPrettyCtx<'_> { fn write_str(&mut self, s: &str) -> std::fmt::Result { let mut it = s.split('\n'); // note: `.lines()` is wrong here @@ -66,31 +103,62 @@ enum LocalName { Binding(Name, LocalId), } -impl Display for LocalName { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl HirDisplay for LocalName { + fn hir_fmt( + &self, + f: &mut crate::display::HirFormatter<'_>, + ) -> Result<(), crate::display::HirDisplayError> { match self { LocalName::Unknown(l) => write!(f, "_{}", u32::from(l.into_raw())), - LocalName::Binding(n, l) => write!(f, "{n}_{}", u32::from(l.into_raw())), + LocalName::Binding(n, l) => { + write!(f, "{}_{}", n.display(f.db.upcast()), u32::from(l.into_raw())) + } } } } impl<'a> MirPrettyCtx<'a> { - fn for_body(&mut self) { + fn for_body(&mut self, name: impl FnOnce(&mut MirPrettyCtx<'_>)) { + name(self); self.with_block(|this| { this.locals(); wln!(this); this.blocks(); }); + for &closure in &self.body.closures { + self.for_closure(closure); + } + } + + fn for_closure(&mut self, closure: ClosureId) { + let body = match self.db.mir_body_for_closure(closure) { + Ok(x) => x, + Err(e) => { + wln!(self, "// error in {closure:?}: {e:?}"); + return; + } + }; + let result = mem::take(&mut self.result); + let indent = mem::take(&mut self.indent); + let mut ctx = MirPrettyCtx { + body: &body, + local_to_binding: body.binding_locals.iter().map(|(x, y)| (*y, x)).collect(), + result, + indent, + ..*self + }; + ctx.for_body(|this| wln!(this, "// Closure: {:?}", closure)); + self.result = ctx.result; + self.indent = ctx.indent; } fn with_block(&mut self, f: impl FnOnce(&mut MirPrettyCtx<'_>)) { - self.ident += " "; + self.indent += " "; wln!(self, "{{"); f(self); for _ in 0..4 { self.result.pop(); - self.ident.pop(); + self.indent.pop(); } wln!(self, "}}"); } @@ -101,7 +169,7 @@ impl<'a> MirPrettyCtx<'a> { body, db, result: String::new(), - ident: String::new(), + indent: String::new(), local_to_binding, hir_body, } @@ -109,7 +177,7 @@ impl<'a> MirPrettyCtx<'a> { fn write_line(&mut self) { self.result.push('\n'); - self.result += &self.ident; + self.result += &self.indent; } fn write(&mut self, line: &str) { @@ -118,7 +186,12 @@ impl<'a> MirPrettyCtx<'a> { fn locals(&mut self) { for (id, local) in self.body.locals.iter() { - wln!(self, "let {}: {};", self.local_name(id), local.ty.display(self.db)); + wln!( + self, + "let {}: {};", + self.local_name(id).display(self.db), + self.hir_display(&local.ty) + ); } } @@ -147,10 +220,10 @@ impl<'a> MirPrettyCtx<'a> { wln!(this, ";"); } StatementKind::StorageDead(p) => { - wln!(this, "StorageDead({})", this.local_name(*p)); + wln!(this, "StorageDead({})", this.local_name(*p).display(self.db)); } StatementKind::StorageLive(p) => { - wln!(this, "StorageLive({})", this.local_name(*p)); + wln!(this, "StorageLive({})", this.local_name(*p).display(self.db)); } StatementKind::Deinit(p) => { w!(this, "Deinit("); @@ -161,11 +234,11 @@ impl<'a> MirPrettyCtx<'a> { } } match &block.terminator { - Some(terminator) => match terminator { - Terminator::Goto { target } => { + Some(terminator) => match &terminator.kind { + TerminatorKind::Goto { target } => { wln!(this, "goto 'bb{};", u32::from(target.into_raw())) } - Terminator::SwitchInt { discr, targets } => { + TerminatorKind::SwitchInt { discr, targets } => { w!(this, "switch "); this.operand(discr); w!(this, " "); @@ -176,7 +249,7 @@ impl<'a> MirPrettyCtx<'a> { wln!(this, "_ => {},", this.basic_block_id(targets.otherwise())); }); } - Terminator::Call { func, args, destination, target, .. } => { + TerminatorKind::Call { func, args, destination, target, .. } => { w!(this, "Call "); this.with_block(|this| { w!(this, "func: "); @@ -208,7 +281,7 @@ impl<'a> MirPrettyCtx<'a> { fn f(this: &mut MirPrettyCtx<'_>, local: LocalId, projections: &[PlaceElem]) { let Some((last, head)) = projections.split_last() else { // no projection - w!(this, "{}", this.local_name(local)); + w!(this, "{}", this.local_name(local).display(this.db)); return; }; match last { @@ -226,21 +299,26 @@ impl<'a> MirPrettyCtx<'a> { f(this, local, head); let variant_name = &this.db.enum_data(e.parent).variants[e.local_id].name; - w!(this, " as {}).{}", variant_name, name); + w!( + this, + " as {}).{}", + variant_name.display(this.db.upcast()), + name.display(this.db.upcast()) + ); } hir_def::VariantId::StructId(_) | hir_def::VariantId::UnionId(_) => { f(this, local, head); - w!(this, ".{name}"); + w!(this, ".{}", name.display(this.db.upcast())); } } } - ProjectionElem::TupleField(x) => { + ProjectionElem::TupleOrClosureField(x) => { f(this, local, head); w!(this, ".{}", x); } ProjectionElem::Index(l) => { f(this, local, head); - w!(this, "[{}]", this.local_name(*l)); + w!(this, "[{}]", this.local_name(*l).display(this.db)); } x => { f(this, local, head); @@ -258,7 +336,8 @@ impl<'a> MirPrettyCtx<'a> { // equally. Feel free to change it. self.place(p); } - Operand::Constant(c) => w!(self, "Const({})", c.display(self.db)), + Operand::Constant(c) => w!(self, "Const({})", self.hir_display(c)), + Operand::Static(s) => w!(self, "Static({:?})", s), } } @@ -284,11 +363,21 @@ impl<'a> MirPrettyCtx<'a> { self.operand_list(x); w!(self, "]"); } + Rvalue::Repeat(op, len) => { + w!(self, "["); + self.operand(op); + w!(self, "; {}]", len.display(self.db)); + } Rvalue::Aggregate(AggregateKind::Adt(_, _), x) => { w!(self, "Adt("); self.operand_list(x); w!(self, ")"); } + Rvalue::Aggregate(AggregateKind::Closure(_), x) => { + w!(self, "Closure("); + self.operand_list(x); + w!(self, ")"); + } Rvalue::Aggregate(AggregateKind::Union(_, _), x) => { w!(self, "Union("); self.operand_list(x); @@ -300,9 +389,9 @@ impl<'a> MirPrettyCtx<'a> { w!(self, ")"); } Rvalue::Cast(ck, op, ty) => { - w!(self, "Discriminant({ck:?}"); + w!(self, "Cast({ck:?}, "); self.operand(op); - w!(self, "{})", ty.display(self.db)); + w!(self, ", {})", self.hir_display(ty)); } Rvalue::CheckedBinaryOp(b, o1, o2) => { self.operand(o1); @@ -322,6 +411,7 @@ impl<'a> MirPrettyCtx<'a> { self.place(p); w!(self, ")"); } + Rvalue::ShallowInitBoxWithAlloc(_) => w!(self, "ShallowInitBoxWithAlloc"), Rvalue::ShallowInitBox(op, _) => { w!(self, "ShallowInitBox("); self.operand(op); @@ -345,4 +435,8 @@ impl<'a> MirPrettyCtx<'a> { } } } + + fn hir_display(&self, ty: &'a T) -> impl Display + 'a { + ty.display(self.db).with_closure_style(ClosureStyle::ClosureWithSubst) + } } diff --git a/crates/hir-ty/src/test_db.rs b/crates/hir-ty/src/test_db.rs index 8c48331b94b53..7d19e0a19169a 100644 --- a/crates/hir-ty/src/test_db.rs +++ b/crates/hir-ty/src/test_db.rs @@ -1,18 +1,18 @@ //! Database used for testing `hir`. -use std::{ - fmt, panic, - sync::{Arc, Mutex}, -}; +use std::{fmt, panic, sync::Mutex}; use base_db::{ - salsa, AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast, + salsa::{self, Durability}, + AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast, }; use hir_def::{db::DefDatabase, ModuleId}; use hir_expand::db::ExpandDatabase; -use stdx::hash::{NoHashHashMap, NoHashHashSet}; +use nohash_hasher::IntMap; +use rustc_hash::FxHashSet; use syntax::TextRange; use test_utils::extract_annotations; +use triomphe::Arc; #[salsa::database( base_db::SourceDatabaseExtStorage, @@ -30,7 +30,7 @@ pub(crate) struct TestDB { impl Default for TestDB { fn default() -> Self { let mut this = Self { storage: Default::default(), events: Default::default() }; - this.set_enable_proc_attr_macros(true); + this.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH); this } } @@ -74,13 +74,13 @@ impl salsa::ParallelDatabase for TestDB { impl panic::RefUnwindSafe for TestDB {} impl FileLoader for TestDB { - fn file_text(&self, file_id: FileId) -> Arc { + fn file_text(&self, file_id: FileId) -> Arc { FileLoaderDelegate(self).file_text(file_id) } fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { FileLoaderDelegate(self).resolve_path(path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } } @@ -102,7 +102,7 @@ impl TestDB { self.module_for_file_opt(file_id).unwrap() } - pub(crate) fn extract_annotations(&self) -> NoHashHashMap> { + pub(crate) fn extract_annotations(&self) -> IntMap> { let mut files = Vec::new(); let crate_graph = self.crate_graph(); for krate in crate_graph.iter() { diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index 83d31f002a1dc..2db04024b7b64 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -10,14 +10,14 @@ mod display_source_code; mod incremental; mod diagnostics; -use std::{collections::HashMap, env, sync::Arc}; +use std::{collections::HashMap, env}; use base_db::{fixture::WithFixture, FileRange, SourceDatabaseExt}; use expect_test::Expect; use hir_def::{ body::{Body, BodySourceMap, SyntheticSyntax}, db::{DefDatabase, InternDatabase}, - expr::{ExprId, PatId}, + hir::{ExprId, Pat, PatId}, item_scope::ItemScope, nameres::DefMap, src::HasSource, @@ -32,6 +32,7 @@ use syntax::{ }; use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry}; use tracing_tree::HierarchicalLayer; +use triomphe::Arc; use crate::{ db::HirDatabase, @@ -148,10 +149,13 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour }); let mut unexpected_type_mismatches = String::new(); for def in defs { - let (_body, body_source_map) = db.body_with_source_map(def); + let (body, body_source_map) = db.body_with_source_map(def); let inference_result = db.infer(def); - for (pat, ty) in inference_result.type_of_pat.iter() { + for (pat, mut ty) in inference_result.type_of_pat.iter() { + if let Pat::Bind { id, .. } = body.pats[pat] { + ty = &inference_result.type_of_binding[id]; + } let node = match pat_node(&body_source_map, pat, &db) { Some(value) => value, None => continue, @@ -159,7 +163,7 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour let range = node.as_ref().original_file_range(&db); if let Some(expected) = types.remove(&range) { let actual = if display_source { - ty.display_source_code(&db, def.module(&db)).unwrap() + ty.display_source_code(&db, def.module(&db), true).unwrap() } else { ty.display_test(&db).to_string() }; @@ -175,7 +179,7 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour let range = node.as_ref().original_file_range(&db); if let Some(expected) = types.remove(&range) { let actual = if display_source { - ty.display_source_code(&db, def.module(&db)).unwrap() + ty.display_source_code(&db, def.module(&db), true).unwrap() } else { ty.display_test(&db).to_string() }; @@ -198,8 +202,8 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour for (expr_or_pat, mismatch) in inference_result.type_mismatches() { let Some(node) = (match expr_or_pat { - hir_def::expr::ExprOrPatId::ExprId(expr) => expr_node(&body_source_map, expr, &db), - hir_def::expr::ExprOrPatId::PatId(pat) => pat_node(&body_source_map, pat, &db), + hir_def::hir::ExprOrPatId::ExprId(expr) => expr_node(&body_source_map, expr, &db), + hir_def::hir::ExprOrPatId::PatId(pat) => pat_node(&body_source_map, pat, &db), }) else { continue; }; let range = node.as_ref().original_file_range(&db); let actual = format!( @@ -246,7 +250,7 @@ fn expr_node( ) -> Option> { Some(match body_source_map.expr_syntax(expr) { Ok(sp) => { - let root = db.parse_or_expand(sp.file_id).unwrap(); + let root = db.parse_or_expand(sp.file_id); sp.map(|ptr| ptr.to_node(&root).syntax().clone()) } Err(SyntheticSyntax) => return None, @@ -260,7 +264,7 @@ fn pat_node( ) -> Option> { Some(match body_source_map.pat_syntax(pat) { Ok(sp) => { - let root = db.parse_or_expand(sp.file_id).unwrap(); + let root = db.parse_or_expand(sp.file_id); sp.map(|ptr| { ptr.either( |it| it.to_node(&root).syntax().clone(), @@ -283,14 +287,18 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { let mut buf = String::new(); let mut infer_def = |inference_result: Arc, + body: Arc, body_source_map: Arc| { let mut types: Vec<(InFile, &Ty)> = Vec::new(); let mut mismatches: Vec<(InFile, &TypeMismatch)> = Vec::new(); - for (pat, ty) in inference_result.type_of_pat.iter() { + for (pat, mut ty) in inference_result.type_of_pat.iter() { + if let Pat::Bind { id, .. } = body.pats[pat] { + ty = &inference_result.type_of_binding[id]; + } let syntax_ptr = match body_source_map.pat_syntax(pat) { Ok(sp) => { - let root = db.parse_or_expand(sp.file_id).unwrap(); + let root = db.parse_or_expand(sp.file_id); sp.map(|ptr| { ptr.either( |it| it.to_node(&root).syntax().clone(), @@ -309,7 +317,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { for (expr, ty) in inference_result.type_of_expr.iter() { let node = match body_source_map.expr_syntax(expr) { Ok(sp) => { - let root = db.parse_or_expand(sp.file_id).unwrap(); + let root = db.parse_or_expand(sp.file_id); sp.map(|ptr| ptr.to_node(&root).syntax().clone()) } Err(SyntheticSyntax) => continue, @@ -385,9 +393,9 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { } }); for def in defs { - let (_body, source_map) = db.body_with_source_map(def); + let (body, source_map) = db.body_with_source_map(def); let infer = db.infer(def); - infer_def(infer, source_map); + infer_def(infer, body, source_map); } buf.truncate(buf.trim_end().len()); @@ -572,10 +580,9 @@ fn salsa_bug() { let x = 1; x.push(1); } - " - .to_string(); + "; - db.set_file_text(pos.file_id, Arc::new(new_text)); + db.set_file_text(pos.file_id, Arc::from(new_text)); let module = db.module_for_file(pos.file_id); let crate_def_map = module.def_map(&db); diff --git a/crates/hir-ty/src/tests/coercion.rs b/crates/hir-ty/src/tests/coercion.rs index b524922b6cf40..16e5ef85d09d5 100644 --- a/crates/hir-ty/src/tests/coercion.rs +++ b/crates/hir-ty/src/tests/coercion.rs @@ -258,7 +258,6 @@ fn test() { #[test] fn coerce_autoderef_block() { - // FIXME: We should know mutability in overloaded deref check_no_mismatches( r#" //- minicore: deref @@ -268,7 +267,7 @@ fn takes_ref_str(x: &str) {} fn returns_string() -> String { loop {} } fn test() { takes_ref_str(&{ returns_string() }); - // ^^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(None), Deref(Some(OverloadedDeref(None))), Borrow(Ref(Not)) + // ^^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(None), Deref(Some(OverloadedDeref(Some(Not)))), Borrow(Ref(Not)) } "#, ); @@ -396,10 +395,40 @@ fn test() { ); } +#[test] +fn coerce_fn_item_to_fn_ptr_in_array() { + check_no_mismatches( + r" +fn foo(x: u32) -> isize { 1 } +fn bar(x: u32) -> isize { 1 } +fn test() { + let f = [foo, bar]; + // ^^^ adjustments: Pointer(ReifyFnPointer) +}", + ); +} + #[test] fn coerce_fn_items_in_match_arms() { cov_mark::check!(coerce_fn_reification); + check_no_mismatches( + r" +fn foo1(x: u32) -> isize { 1 } +fn foo2(x: u32) -> isize { 2 } +fn foo3(x: u32) -> isize { 3 } +fn test() { + let x = match 1 { + 1 => foo1, + // ^^^^ adjustments: Pointer(ReifyFnPointer) + 2 => foo2, + // ^^^^ adjustments: Pointer(ReifyFnPointer) + _ => foo3, + // ^^^^ adjustments: Pointer(ReifyFnPointer) + }; + x; +}", + ); check_types( r" fn foo1(x: u32) -> isize { 1 } @@ -507,7 +536,6 @@ fn test() { #[test] fn coerce_unsize_generic() { - // FIXME: fix the type mismatches here check( r#" //- minicore: coerce_unsized @@ -516,9 +544,9 @@ struct Bar(Foo); fn test() { let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; - //^^^^^^^^^ expected [usize], got [usize; 3] + //^^^^^^^^^^^^^^^^^^^^^ expected &Foo<[usize]>, got &Foo<[i32; 3]> let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); - //^^^^^^^^^ expected [usize], got [usize; 3] + //^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &Bar<[usize]>, got &Bar<[i32; 3]> } "#, ); @@ -547,7 +575,7 @@ fn two_closures_lub() { fn foo(c: i32) { let add = |a: i32, b: i32| a + b; let sub = |a, b| a - b; - //^^^^^^^^^^^^ |i32, i32| -> i32 + //^^^^^^^^^^^^ impl Fn(i32, i32) -> i32 if c > 42 { add } else { sub }; //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fn(i32, i32) -> i32 } @@ -842,3 +870,74 @@ fn test() { }", ); } + +#[test] +fn adjust_index() { + check_no_mismatches( + r" +//- minicore: index, slice, coerce_unsized +fn test() { + let x = [1, 2, 3]; + x[2] = 6; + // ^ adjustments: Borrow(Ref(Mut)) +} + ", + ); + check_no_mismatches( + r" +//- minicore: index +struct Struct; +impl core::ops::Index for Struct { + type Output = (); + + fn index(&self, index: usize) -> &Self::Output { &() } +} +struct StructMut; + +impl core::ops::Index for StructMut { + type Output = (); + + fn index(&self, index: usize) -> &Self::Output { &() } +} +impl core::ops::IndexMut for StructMut { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { &mut () } +} +fn test() { + Struct[0]; + // ^^^^^^ adjustments: Borrow(Ref(Not)) + StructMut[0]; + // ^^^^^^^^^ adjustments: Borrow(Ref(Not)) + &mut StructMut[0]; + // ^^^^^^^^^ adjustments: Borrow(Ref(Mut)) +}", + ); +} + +#[test] +fn regression_14443_dyn_coercion_block_impls() { + check_no_mismatches( + r#" +//- minicore: coerce_unsized +trait T {} + +fn dyn_t(d: &dyn T) {} + +fn main() { + struct A; + impl T for A {} + + let a = A; + + let b = { + struct B; + impl T for B {} + + B + }; + + dyn_t(&a); + dyn_t(&b); +} +"#, + ) +} diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs index 073d6d9be2b9f..bb15ca8c436a2 100644 --- a/crates/hir-ty/src/tests/incremental.rs +++ b/crates/hir-ty/src/tests/incremental.rs @@ -1,6 +1,5 @@ -use std::sync::Arc; - use base_db::{fixture::WithFixture, SourceDatabaseExt}; +use triomphe::Arc; use crate::{db::HirDatabase, test_db::TestDB}; @@ -33,10 +32,9 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() { + 1 } - " - .to_string(); + "; - db.set_file_text(pos.file_id, Arc::new(new_text)); + db.set_file_text(pos.file_id, Arc::from(new_text)); { let events = db.log_executed(|| { diff --git a/crates/hir-ty/src/tests/macros.rs b/crates/hir-ty/src/tests/macros.rs index 8b75ec842a4f6..111ac0b618eb2 100644 --- a/crates/hir-ty/src/tests/macros.rs +++ b/crates/hir-ty/src/tests/macros.rs @@ -140,6 +140,7 @@ fn infer_path_qualified_macros_expanded() { fn expr_macro_def_expanded_in_various_places() { check_infer( r#" + //- minicore: iterator macro spam() { 1isize } @@ -195,10 +196,19 @@ fn expr_macro_def_expanded_in_various_places() { !0..6 '1isize': isize 39..442 '{ ...!(); }': () 73..94 'spam!(...am!())': {unknown} + 100..119 'for _ ...!() {}': fn into_iter(isize) -> ::IntoIter + 100..119 'for _ ...!() {}': IntoIterator::IntoIter + 100..119 'for _ ...!() {}': ! + 100..119 'for _ ...!() {}': IntoIterator::IntoIter + 100..119 'for _ ...!() {}': &mut IntoIterator::IntoIter + 100..119 'for _ ...!() {}': fn next>(&mut IntoIterator::IntoIter) -> Option< as Iterator>::Item> + 100..119 'for _ ...!() {}': Option>> 100..119 'for _ ...!() {}': () - 104..105 '_': {unknown} + 100..119 'for _ ...!() {}': () + 100..119 'for _ ...!() {}': () + 104..105 '_': Iterator::Item> 117..119 '{}': () - 124..134 '|| spam!()': || -> isize + 124..134 '|| spam!()': impl Fn() -> isize 140..156 'while ...!() {}': () 154..156 '{}': () 161..174 'break spam!()': ! @@ -221,6 +231,7 @@ fn expr_macro_def_expanded_in_various_places() { fn expr_macro_rules_expanded_in_various_places() { check_infer( r#" + //- minicore: iterator macro_rules! spam { () => (1isize); } @@ -276,10 +287,19 @@ fn expr_macro_rules_expanded_in_various_places() { !0..6 '1isize': isize 53..456 '{ ...!(); }': () 87..108 'spam!(...am!())': {unknown} + 114..133 'for _ ...!() {}': fn into_iter(isize) -> ::IntoIter + 114..133 'for _ ...!() {}': IntoIterator::IntoIter + 114..133 'for _ ...!() {}': ! + 114..133 'for _ ...!() {}': IntoIterator::IntoIter + 114..133 'for _ ...!() {}': &mut IntoIterator::IntoIter + 114..133 'for _ ...!() {}': fn next>(&mut IntoIterator::IntoIter) -> Option< as Iterator>::Item> + 114..133 'for _ ...!() {}': Option>> + 114..133 'for _ ...!() {}': () 114..133 'for _ ...!() {}': () - 118..119 '_': {unknown} + 114..133 'for _ ...!() {}': () + 118..119 '_': Iterator::Item> 131..133 '{}': () - 138..148 '|| spam!()': || -> isize + 138..148 '|| spam!()': impl Fn() -> isize 154..170 'while ...!() {}': () 168..170 '{}': () 175..188 'break spam!()': ! @@ -661,8 +681,9 @@ fn infer_builtin_macros_line() { "#, expect![[r#" !0..1 '0': i32 + !0..6 '0asu32': u32 63..87 '{ ...!(); }': () - 73..74 'x': i32 + 73..74 'x': u32 "#]], ); } @@ -699,8 +720,9 @@ fn infer_builtin_macros_column() { "#, expect![[r#" !0..1 '0': i32 + !0..6 '0asu32': u32 65..91 '{ ...!(); }': () - 75..76 'x': i32 + 75..76 'x': u32 "#]], ); } @@ -945,7 +967,7 @@ fn infer_builtin_macros_concat_with_lazy() { #[test] fn infer_builtin_macros_env() { - check_infer( + check_types( r#" //- /main.rs env:foo=bar #[rustc_builtin_macro] @@ -953,13 +975,26 @@ fn infer_builtin_macros_env() { fn main() { let x = env!("foo"); + //^ &str + } + "#, + ); +} + +#[test] +fn infer_builtin_macros_option_env() { + check_types( + r#" + //- minicore: option + //- /main.rs env:foo=bar + #[rustc_builtin_macro] + macro_rules! option_env {() => {}} + + fn main() { + let x = option_env!("foo"); + //^ Option<&str> } "#, - expect![[r#" - !0..22 '"__RA_...TED__"': &str - 62..90 '{ ...o"); }': () - 72..73 'x': &str - "#]], ); } diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs index 378d478336102..1e57a4ae2968a 100644 --- a/crates/hir-ty/src/tests/method_resolution.rs +++ b/crates/hir-ty/src/tests/method_resolution.rs @@ -388,6 +388,24 @@ mod bar_test { ); } +#[test] +fn infer_trait_method_multiple_mutable_reference() { + check_types( + r#" +trait Trait { + fn method(&mut self) -> i32 { 5 } +} +struct S; +impl Trait for &mut &mut S {} +fn test() { + let s = &mut &mut &mut S; + s.method(); + //^^^^^^^^^^ i32 +} + "#, + ); +} + #[test] fn infer_trait_method_generic_1() { // the trait implementation is intentionally incomplete -- it shouldn't matter @@ -1255,7 +1273,6 @@ fn foo(a: &T) { #[test] fn autoderef_visibility_field() { - // FIXME: We should know mutability in overloaded deref check( r#" //- minicore: deref @@ -1277,7 +1294,7 @@ mod a { mod b { fn foo() { let x = super::a::Bar::new().0; - // ^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(Some(OverloadedDeref(None))) + // ^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(Some(OverloadedDeref(Some(Not)))) // ^^^^^^^^^^^^^^^^^^^^^^ type: char } } @@ -1723,7 +1740,7 @@ fn test() { Foo.foo(); //^^^ adjustments: Borrow(Ref(Not)) (&Foo).foo(); - // ^^^^ adjustments: , + // ^^^^ adjustments: Deref(None), Borrow(Ref(Not)) } "#, ); @@ -1922,3 +1939,54 @@ fn foo() { "#, ); } + +#[test] +fn box_deref_is_builtin() { + check( + r#" +//- minicore: deref +use core::ops::Deref; + +#[lang = "owned_box"] +struct Box(*mut T); + +impl Box { + fn new(t: T) -> Self { + loop {} + } +} + +impl Deref for Box { + type Target = T; + fn deref(&self) -> &Self::Target; +} + +struct Foo; +impl Foo { + fn foo(&self) {} +} +fn test() { + Box::new(Foo).foo(); + //^^^^^^^^^^^^^ adjustments: Deref(None), Borrow(Ref(Not)) +} +"#, + ); +} + +#[test] +fn manually_drop_deref_is_not_builtin() { + check( + r#" +//- minicore: manually_drop, deref +struct Foo; +impl Foo { + fn foo(&self) {} +} +use core::mem::ManuallyDrop; +fn test() { + ManuallyDrop::new(Foo).foo(); + //^^^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(Some(OverloadedDeref(Some(Not)))), Borrow(Ref(Not)) +} +"#, + ); +} diff --git a/crates/hir-ty/src/tests/never_type.rs b/crates/hir-ty/src/tests/never_type.rs index fbdc8209f8f4b..59046c0435a3a 100644 --- a/crates/hir-ty/src/tests/never_type.rs +++ b/crates/hir-ty/src/tests/never_type.rs @@ -327,6 +327,7 @@ fn diverging_expression_2() { fn diverging_expression_3_break() { check_infer_with_mismatches( r" + //- minicore: iterator //- /main.rs fn test1() { // should give type mismatch @@ -360,6 +361,15 @@ fn diverging_expression_3_break() { 97..343 '{ ...; }; }': () 140..141 'x': u32 149..175 '{ for ...; }; }': u32 + 151..172 'for a ...eak; }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter + 151..172 'for a ...eak; }': {unknown} + 151..172 'for a ...eak; }': ! + 151..172 'for a ...eak; }': {unknown} + 151..172 'for a ...eak; }': &mut {unknown} + 151..172 'for a ...eak; }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item> + 151..172 'for a ...eak; }': Option<{unknown}> + 151..172 'for a ...eak; }': () + 151..172 'for a ...eak; }': () 151..172 'for a ...eak; }': () 155..156 'a': {unknown} 160..161 'b': {unknown} @@ -367,12 +377,30 @@ fn diverging_expression_3_break() { 164..169 'break': ! 226..227 'x': u32 235..253 '{ for ... {}; }': u32 + 237..250 'for a in b {}': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter + 237..250 'for a in b {}': {unknown} + 237..250 'for a in b {}': ! + 237..250 'for a in b {}': {unknown} + 237..250 'for a in b {}': &mut {unknown} + 237..250 'for a in b {}': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item> + 237..250 'for a in b {}': Option<{unknown}> + 237..250 'for a in b {}': () + 237..250 'for a in b {}': () 237..250 'for a in b {}': () 241..242 'a': {unknown} 246..247 'b': {unknown} 248..250 '{}': () 304..305 'x': u32 313..340 '{ for ...; }; }': u32 + 315..337 'for a ...urn; }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter + 315..337 'for a ...urn; }': {unknown} + 315..337 'for a ...urn; }': ! + 315..337 'for a ...urn; }': {unknown} + 315..337 'for a ...urn; }': &mut {unknown} + 315..337 'for a ...urn; }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item> + 315..337 'for a ...urn; }': Option<{unknown}> + 315..337 'for a ...urn; }': () + 315..337 'for a ...urn; }': () 315..337 'for a ...urn; }': () 319..320 'a': {unknown} 324..325 'b': {unknown} @@ -483,3 +511,22 @@ fn example() -> bool { "#, ); } + +#[test] +fn reservation_impl_should_be_ignored() { + // See rust-lang/rust#64631. + check_types( + r#" +//- minicore: from +struct S; +#[rustc_reservation_impl] +impl From for T {} +fn foo>(_: U) -> T { loop {} } + +fn test() { + let s = foo(S); + //^ S +} +"#, + ); +} diff --git a/crates/hir-ty/src/tests/patterns.rs b/crates/hir-ty/src/tests/patterns.rs index 74bcab6caa94a..0f5a3e1752cf5 100644 --- a/crates/hir-ty/src/tests/patterns.rs +++ b/crates/hir-ty/src/tests/patterns.rs @@ -1,11 +1,12 @@ use expect_test::expect; -use super::{check, check_infer, check_infer_with_mismatches, check_types}; +use super::{check, check_infer, check_infer_with_mismatches, check_no_mismatches, check_types}; #[test] fn infer_pattern() { check_infer( r#" + //- minicore: iterator fn test(x: &i32) { let y = x; let &z = x; @@ -46,6 +47,15 @@ fn infer_pattern() { 82..94 '(1, "hello")': (i32, &str) 83..84 '1': i32 86..93 '"hello"': &str + 101..151 'for (e... }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter + 101..151 'for (e... }': {unknown} + 101..151 'for (e... }': ! + 101..151 'for (e... }': {unknown} + 101..151 'for (e... }': &mut {unknown} + 101..151 'for (e... }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item> + 101..151 'for (e... }': Option<({unknown}, {unknown})> + 101..151 'for (e... }': () + 101..151 'for (e... }': () 101..151 'for (e... }': () 105..111 '(e, f)': ({unknown}, {unknown}) 106..107 'e': {unknown} @@ -70,8 +80,8 @@ fn infer_pattern() { 228..233 '&true': &bool 229..233 'true': bool 234..236 '{}': () - 246..252 'lambda': |u64, u64, i32| -> i32 - 255..287 '|a: u6...b; c }': |u64, u64, i32| -> i32 + 246..252 'lambda': impl Fn(u64, u64, i32) -> i32 + 255..287 '|a: u6...b; c }': impl Fn(u64, u64, i32) -> i32 256..257 'a': u64 264..265 'b': u64 267..268 'c': i32 @@ -240,6 +250,21 @@ fn infer_pattern_match_ergonomics_ref() { ); } +#[test] +fn ref_pat_with_inference_variable() { + check_no_mismatches( + r#" +enum E { A } +fn test() { + let f = |e| match e { + &E::A => {} + }; + f(&E::A); +} +"#, + ); +} + #[test] fn infer_pattern_match_slice() { check_infer( @@ -476,7 +501,7 @@ fn infer_adt_pattern() { 183..184 'x': usize 190..191 'x': usize 201..205 'E::B': E - 209..212 'foo': {unknown} + 209..212 'foo': bool 216..217 '1': usize 227..231 'E::B': E 235..237 '10': usize @@ -677,25 +702,25 @@ fn test() { 51..58 'loop {}': ! 56..58 '{}': () 72..171 '{ ... x); }': () - 78..81 'foo': fn foo<&(i32, &str), i32, |&(i32, &str)| -> i32>(&(i32, &str), |&(i32, &str)| -> i32) -> i32 + 78..81 'foo': fn foo<&(i32, &str), i32, impl Fn(&(i32, &str)) -> i32>(&(i32, &str), impl Fn(&(i32, &str)) -> i32) -> i32 78..105 'foo(&(...y)| x)': i32 82..91 '&(1, "a")': &(i32, &str) 83..91 '(1, "a")': (i32, &str) 84..85 '1': i32 87..90 '"a"': &str - 93..104 '|&(x, y)| x': |&(i32, &str)| -> i32 + 93..104 '|&(x, y)| x': impl Fn(&(i32, &str)) -> i32 94..101 '&(x, y)': &(i32, &str) 95..101 '(x, y)': (i32, &str) 96..97 'x': i32 99..100 'y': &str 103..104 'x': i32 - 142..145 'foo': fn foo<&(i32, &str), &i32, |&(i32, &str)| -> &i32>(&(i32, &str), |&(i32, &str)| -> &i32) -> &i32 + 142..145 'foo': fn foo<&(i32, &str), &i32, impl Fn(&(i32, &str)) -> &i32>(&(i32, &str), impl Fn(&(i32, &str)) -> &i32) -> &i32 142..168 'foo(&(...y)| x)': &i32 146..155 '&(1, "a")': &(i32, &str) 147..155 '(1, "a")': (i32, &str) 148..149 '1': i32 151..154 '"a"': &str - 157..167 '|(x, y)| x': |&(i32, &str)| -> &i32 + 157..167 '|(x, y)| x': impl Fn(&(i32, &str)) -> &i32 158..164 '(x, y)': (i32, &str) 159..160 'x': &i32 162..163 'y': &&str @@ -1084,7 +1109,7 @@ fn var_args() { #[lang = "va_list"] pub struct VaListImpl<'f>; fn my_fn(foo: ...) {} - //^^^ VaListImpl + //^^^ VaListImpl<'_> "#, ); } diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index 689f0da44f680..f18c953a7afd2 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -246,6 +246,7 @@ fn infer_std_crash_5() { // taken from rustc check_infer( r#" + //- minicore: iterator fn extra_compiler_flags() { for content in doesnt_matter { let name = if doesnt_matter { @@ -264,13 +265,22 @@ fn infer_std_crash_5() { "#, expect![[r#" 26..322 '{ ... } }': () + 32..320 'for co... }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter + 32..320 'for co... }': {unknown} + 32..320 'for co... }': ! + 32..320 'for co... }': {unknown} + 32..320 'for co... }': &mut {unknown} + 32..320 'for co... }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item> + 32..320 'for co... }': Option<{unknown}> + 32..320 'for co... }': () + 32..320 'for co... }': () 32..320 'for co... }': () 36..43 'content': {unknown} 47..60 'doesnt_matter': {unknown} 61..320 '{ ... }': () 75..79 'name': &{unknown} 82..166 'if doe... }': &{unknown} - 85..98 'doesnt_matter': {unknown} + 85..98 'doesnt_matter': bool 99..128 '{ ... }': &{unknown} 113..118 'first': &{unknown} 134..166 '{ ... }': &{unknown} @@ -279,7 +289,7 @@ fn infer_std_crash_5() { 181..188 'content': &{unknown} 191..313 'if ICE... }': &{unknown} 194..231 'ICE_RE..._VALUE': {unknown} - 194..247 'ICE_RE...&name)': {unknown} + 194..247 'ICE_RE...&name)': bool 241..246 '&name': &&{unknown} 242..246 'name': &{unknown} 248..276 '{ ... }': &{unknown} @@ -805,19 +815,19 @@ fn issue_4966() { 225..229 'iter': T 244..246 '{}': Vec 258..402 '{ ...r(); }': () - 268..273 'inner': Map<|&f64| -> f64> - 276..300 'Map { ... 0.0 }': Map<|&f64| -> f64> - 285..298 '|_: &f64| 0.0': |&f64| -> f64 + 268..273 'inner': Map f64> + 276..300 'Map { ... 0.0 }': Map f64> + 285..298 '|_: &f64| 0.0': impl Fn(&f64) -> f64 286..287 '_': &f64 295..298 '0.0': f64 - 311..317 'repeat': Repeat f64>> - 320..345 'Repeat...nner }': Repeat f64>> - 338..343 'inner': Map<|&f64| -> f64> - 356..359 'vec': Vec f64>>>> - 362..371 'from_iter': fn from_iter f64>>>, Repeat f64>>>(Repeat f64>>) -> Vec f64>>>> - 362..379 'from_i...epeat)': Vec f64>>>> - 372..378 'repeat': Repeat f64>> - 386..389 'vec': Vec f64>>>> + 311..317 'repeat': Repeat f64>> + 320..345 'Repeat...nner }': Repeat f64>> + 338..343 'inner': Map f64> + 356..359 'vec': Vec f64>>>> + 362..371 'from_iter': fn from_iter f64>>>, Repeat f64>>>(Repeat f64>>) -> Vec f64>>>> + 362..379 'from_i...epeat)': Vec f64>>>> + 372..378 'repeat': Repeat f64>> + 386..389 'vec': Vec f64>>>> 386..399 'vec.foo_bar()': {unknown} "#]], ); @@ -852,7 +862,7 @@ fn main() { 123..126 'S()': S 132..133 's': S 132..144 's.g(|_x| {})': () - 136..143 '|_x| {}': |&i32| -> () + 136..143 '|_x| {}': impl Fn(&i32) 137..139 '_x': &i32 141..143 '{}': () 150..151 's': S @@ -886,13 +896,13 @@ fn flush(&self) { "#, expect![[r#" 123..127 'self': &Mutex - 150..152 '{}': MutexGuard + 150..152 '{}': MutexGuard<'_, T> 234..238 'self': &{unknown} 240..290 '{ ...()); }': () 250..251 'w': &Mutex 276..287 '*(w.lock())': BufWriter 278..279 'w': &Mutex - 278..286 'w.lock()': MutexGuard + 278..286 'w.lock()': MutexGuard<'_, BufWriter> "#]], ); } @@ -1060,13 +1070,30 @@ fn infix_parse(_state: S, _level_code: &Fn(S)) -> T { loop {} } -fn parse_arule() { +fn parse_a_rule() { infix_parse((), &(|_recurse| ())) } "#, ) } +#[test] +fn nested_closure() { + check_types( + r#" +//- minicore: fn, option + +fn map(o: Option, f: impl FnOnce(T) -> U) -> Option { loop {} } + +fn test() { + let o = Some(Some(2)); + map(o, |s| map(s, |x| x)); + // ^ i32 +} + "#, + ); +} + #[test] fn call_expected_type_closure() { check_types( @@ -1198,6 +1225,7 @@ fn mamba(a: U32!(), p: u32) -> u32 { fn for_loop_block_expr_iterable() { check_infer( r#" +//- minicore: iterator fn test() { for _ in { let x = 0; } { let y = 0; @@ -1206,8 +1234,17 @@ fn test() { "#, expect![[r#" 10..68 '{ ... } }': () + 16..66 'for _ ... }': fn into_iter<()>(()) -> <() as IntoIterator>::IntoIter + 16..66 'for _ ... }': IntoIterator::IntoIter<()> + 16..66 'for _ ... }': ! + 16..66 'for _ ... }': IntoIterator::IntoIter<()> + 16..66 'for _ ... }': &mut IntoIterator::IntoIter<()> + 16..66 'for _ ... }': fn next>(&mut IntoIterator::IntoIter<()>) -> Option< as Iterator>::Item> + 16..66 'for _ ... }': Option>> + 16..66 'for _ ... }': () 16..66 'for _ ... }': () - 20..21 '_': {unknown} + 16..66 'for _ ... }': () + 20..21 '_': Iterator::Item> 25..39 '{ let x = 0; }': () 31..32 'x': i32 35..36 '0': i32 @@ -1458,13 +1495,12 @@ fn regression_11688_3() { struct Ar(T); fn f( num_zeros: usize, - ) -> dyn Iterator; LEN]> { + ) -> &dyn Iterator; LEN]> { loop {} } fn dynamic_programming() { - for board in f::<9, u8, 7>(1) { - //^^^^^ [Ar; 9] - } + let board = f::<9, u8, 7>(1).next(); + //^^^^^ Option<[Ar; 9]> } "#, ); @@ -1757,6 +1793,21 @@ const C: usize = 2 + 2; ); } +#[test] +fn regression_14456() { + check_types( + r#" +//- minicore: future +async fn x() {} +fn f() { + let fut = x(); + let t = [0u8; { let a = 2 + 2; a }]; + //^ [u8; 4] +} +"#, + ); +} + #[test] fn regression_14164() { check_types( @@ -1788,3 +1839,119 @@ where "#, ); } + +#[test] +fn match_ergonomics_with_binding_modes_interaction() { + check_types( + r" +enum E { A } +fn foo() { + match &E::A { + b @ (x @ E::A | x) => { + b; + //^ &E + x; + //^ &E + } + } +}", + ); +} + +#[test] +fn regression_14844() { + check_no_mismatches( + r#" +pub type Ty = Unknown; + +pub struct Inner(); + +pub struct Outer { + pub inner: Inner, +} + +fn main() { + _ = Outer { + inner: Inner::(), + }; +} + "#, + ); + check_no_mismatches( + r#" +pub const ONE: usize = 1; + +pub struct Inner(); + +pub struct Outer { + pub inner: Inner, +} + +fn main() { + _ = Outer { + inner: Inner::<1>(), + }; +} + "#, + ); + check_no_mismatches( + r#" +pub const ONE: usize = unknown(); + +pub struct Inner(); + +pub struct Outer { + pub inner: Inner, +} + +fn main() { + _ = Outer { + inner: Inner::<1>(), + }; +} + "#, + ); + check_no_mismatches( + r#" +pub const N: usize = 2 + 2; + +fn f(t: [u8; N]) {} + +fn main() { + let a = [1, 2, 3, 4]; + f(a); + let b = [1; 4]; + let c: [u8; N] = b; + let d = [1; N]; + let e: [u8; N] = d; + let f = [1; N]; + let g = match f { + [a, b, c, d] => a + b + c + d, + }; +} + "#, + ); +} + +#[test] +fn regression_14844_2() { + check_no_mismatches( + r#" +//- minicore: fn +pub const ONE: usize = 1; + +pub type MyInner = Inner; + +pub struct Inner(); + +impl Inner<1> { + fn map(&self, func: F) -> bool + where + F: Fn(&MyInner) -> bool, + { + func(self) + } +} + "#, + ); +} diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs index 13cc3fea52d16..3ece40486dde8 100644 --- a/crates/hir-ty/src/tests/simple.rs +++ b/crates/hir-ty/src/tests/simple.rs @@ -854,9 +854,9 @@ fn test2(a1: *const A, a2: *mut A) { 237..239 'a2': *mut A 249..272 '{ ...2.b; }': () 255..257 'a1': *const A - 255..259 'a1.b': B + 255..259 'a1.b': {unknown} 265..267 'a2': *mut A - 265..269 'a2.b': B + 265..269 'a2.b': {unknown} "#]], ); } @@ -1812,6 +1812,20 @@ fn main() { //^ [(); 7] }"#, ); + check_types( + r#" +trait Foo { + fn x(self); +} + +impl Foo for u8 { + fn x(self) { + let t = [0; 4 + 2]; + //^ [i32; 6] + } +} + "#, + ); } #[test] @@ -1906,8 +1920,8 @@ fn closure_return() { "#, expect![[r#" 16..58 '{ ...; }; }': u32 - 26..27 'x': || -> usize - 30..55 '|| -> ...n 1; }': || -> usize + 26..27 'x': impl Fn() -> usize + 30..55 '|| -> ...n 1; }': impl Fn() -> usize 42..55 '{ return 1; }': usize 44..52 'return 1': ! 51..52 '1': usize @@ -1925,8 +1939,8 @@ fn closure_return_unit() { "#, expect![[r#" 16..47 '{ ...; }; }': u32 - 26..27 'x': || -> () - 30..44 '|| { return; }': || -> () + 26..27 'x': impl Fn() + 30..44 '|| { return; }': impl Fn() 33..44 '{ return; }': () 35..41 'return': ! "#]], @@ -1943,8 +1957,8 @@ fn closure_return_inferred() { "#, expect![[r#" 16..46 '{ ..." }; }': u32 - 26..27 'x': || -> &str - 30..43 '|| { "test" }': || -> &str + 26..27 'x': impl Fn() -> &str + 30..43 '|| { "test" }': impl Fn() -> &str 33..43 '{ "test" }': &str 35..41 '"test"': &str "#]], @@ -2033,6 +2047,56 @@ fn test() { ); } +#[test] +fn tuple_pattern_nested_match_ergonomics() { + check_no_mismatches( + r#" +fn f(x: (&i32, &i32)) -> i32 { + match x { + (3, 4) => 5, + _ => 12, + } +} + "#, + ); + check_types( + r#" +fn f(x: (&&&&i32, &&&i32)) { + let f = match x { + t @ (3, 4) => t, + _ => loop {}, + }; + f; + //^ (&&&&i32, &&&i32) +} + "#, + ); + check_types( + r#" +fn f() { + let x = &&&(&&&2, &&&&&3); + let (y, z) = x; + //^ &&&&i32 + let t @ (y, z) = x; + t; + //^ &&&(&&&i32, &&&&&i32) +} + "#, + ); + check_types( + r#" +fn f() { + let x = &&&(&&&2, &&&&&3); + let (y, z) = x; + //^ &&&&i32 + let t @ (y, z) = x; + t; + //^ &&&(&&&i32, &&&&&i32) +} + "#, + ); +} + #[test] fn fn_pointer_return() { check_infer( @@ -2050,7 +2114,7 @@ fn fn_pointer_return() { 47..120 '{ ...hod; }': () 57..63 'vtable': Vtable 66..90 'Vtable...| {} }': Vtable - 83..88 '|| {}': || -> () + 83..88 '|| {}': impl Fn() 86..88 '{}': () 100..101 'm': fn() 104..110 'vtable': Vtable @@ -2087,6 +2151,7 @@ async fn main() { 136..138 '()': () 150..151 'w': i32 154..166 'const { 92 }': i32 + 154..166 'const { 92 }': i32 162..164 '92': i32 176..177 't': i32 180..190 ''a: { 92 }': i32 @@ -2094,6 +2159,24 @@ async fn main() { "#]], ) } + +#[test] +fn async_fn_and_try_operator() { + check_no_mismatches( + r#" +//- minicore: future, result, fn, try, from +async fn foo() -> Result<(), ()> { + Ok(()) +} + +async fn bar() -> Result<(), ()> { + let x = foo().await?; + Ok(x) +} + "#, + ) +} + #[test] fn async_block_early_return() { check_infer( @@ -2124,9 +2207,9 @@ fn main() { 149..151 'Ok': Ok<(), ()>(()) -> Result<(), ()> 149..155 'Ok(())': Result<(), ()> 152..154 '()': () - 167..171 'test': fn test<(), (), || -> impl Future>, impl Future>>(|| -> impl Future>) + 167..171 'test': fn test<(), (), impl Fn() -> impl Future>, impl Future>>(impl Fn() -> impl Future>) 167..228 'test(|... })': () - 172..227 '|| asy... }': || -> impl Future> + 172..227 '|| asy... }': impl Fn() -> impl Future> 175..227 'async ... }': impl Future> 191..205 'return Err(())': ! 198..201 'Err': Err<(), ()>(()) -> Result<(), ()> @@ -2252,8 +2335,8 @@ fn infer_labelled_break_with_val() { "#, expect![[r#" 9..335 '{ ... }; }': () - 19..21 '_x': || -> bool - 24..332 '|| 'ou... }': || -> bool + 19..21 '_x': impl Fn() -> bool + 24..332 '|| 'ou... }': impl Fn() -> bool 27..332 ''outer... }': bool 40..332 '{ ... }': () 54..59 'inner': i8 @@ -2677,6 +2760,179 @@ impl B for Astruct {} ) } +#[test] +fn capture_kinds_simple() { + check_types( + r#" +struct S; + +impl S { + fn read(&self) -> &S { self } + fn write(&mut self) -> &mut S { self } + fn consume(self) -> S { self } +} + +fn f() { + let x = S; + let c1 = || x.read(); + //^^ impl Fn() -> &S + let c2 = || x.write(); + //^^ impl FnMut() -> &mut S + let c3 = || x.consume(); + //^^ impl FnOnce() -> S + let c3 = || x.consume().consume().consume(); + //^^ impl FnOnce() -> S + let c3 = || x.consume().write().read(); + //^^ impl FnOnce() -> &S + let x = &mut x; + let c1 = || x.write(); + //^^ impl FnMut() -> &mut S + let x = S; + let c1 = || { let ref t = x; t }; + //^^ impl Fn() -> &S + let c2 = || { let ref mut t = x; t }; + //^^ impl FnMut() -> &mut S + let c3 = || { let t = x; t }; + //^^ impl FnOnce() -> S +} + "#, + ) +} + +#[test] +fn capture_kinds_closure() { + check_types( + r#" +//- minicore: copy, fn +fn f() { + let mut x = 2; + x = 5; + let mut c1 = || { x = 3; x }; + //^^^^^^ impl FnMut() -> i32 + let mut c2 = || { c1() }; + //^^^^^^ impl FnMut() -> i32 + let mut c1 = || { x }; + //^^^^^^ impl Fn() -> i32 + let mut c2 = || { c1() }; + //^^^^^^ impl Fn() -> i32 + struct X; + let x = X; + let mut c1 = || { x }; + //^^^^^^ impl FnOnce() -> X + let mut c2 = || { c1() }; + //^^^^^^ impl FnOnce() -> X +} + "#, + ); +} + +#[test] +fn capture_kinds_overloaded_deref() { + check_types( + r#" +//- minicore: fn, deref_mut +use core::ops::{Deref, DerefMut}; + +struct Foo; +impl Deref for Foo { + type Target = (i32, u8); + fn deref(&self) -> &(i32, u8) { + &(5, 2) + } +} +impl DerefMut for Foo { + fn deref_mut(&mut self) -> &mut (i32, u8) { + &mut (5, 2) + } +} +fn test() { + let mut x = Foo; + let c1 = || *x; + //^^ impl Fn() -> (i32, u8) + let c2 = || { *x = (2, 5); }; + //^^ impl FnMut() + let c3 = || { x.1 }; + //^^ impl Fn() -> u8 + let c4 = || { x.1 = 6; }; + //^^ impl FnMut() +} + "#, + ); +} + +#[test] +fn capture_kinds_with_copy_types() { + check_types( + r#" +//- minicore: copy, clone, derive +#[derive(Clone, Copy)] +struct Copy; +struct NotCopy; +#[derive(Clone, Copy)] +struct Generic(T); + +trait Tr { + type Assoc; +} + +impl Tr for Copy { + type Assoc = NotCopy; +} + +#[derive(Clone, Copy)] +struct AssocGeneric(T::Assoc); + +fn f() { + let a = Copy; + let b = NotCopy; + let c = Generic(Copy); + let d = Generic(NotCopy); + let e: AssocGeneric = AssocGeneric(NotCopy); + let c1 = || a; + //^^ impl Fn() -> Copy + let c2 = || b; + //^^ impl FnOnce() -> NotCopy + let c3 = || c; + //^^ impl Fn() -> Generic + let c3 = || d; + //^^ impl FnOnce() -> Generic + let c3 = || e; + //^^ impl FnOnce() -> AssocGeneric +} + "#, + ) +} + +#[test] +fn derive_macro_should_work_for_associated_type() { + check_types( + r#" +//- minicore: copy, clone, derive +#[derive(Clone)] +struct X; +#[derive(Clone)] +struct Y; + +trait Tr { + type Assoc; +} + +impl Tr for X { + type Assoc = Y; +} + +#[derive(Clone)] +struct AssocGeneric(T::Assoc); + +fn f() { + let e: AssocGeneric = AssocGeneric(Y); + let e_clone = e.clone(); + //^^^^^^^ AssocGeneric +} + "#, + ) +} + #[test] fn cfgd_out_assoc_items() { check_types( @@ -2696,6 +2952,21 @@ fn f() { ) } +#[test] +fn infer_ref_to_raw_cast() { + check_types( + r#" +struct S; + +fn f() { + let s = &mut S; + let s = s as *mut _; + //^ *mut S +} + "#, + ); +} + #[test] fn infer_missing_type() { check_types( @@ -3258,35 +3529,60 @@ fn f(t: Ark) { ); } -// FIXME #[test] -fn castable_to2() { - check_infer( +fn const_dependent_on_local() { + check_types( r#" -fn func() { - let x = &0u32 as *const _; +fn main() { + let s = 5; + let t = [2; s]; + //^ [i32; _] } "#, - expect![[r#" - 10..44 '{ ...t _; }': () - 20..21 'x': *const {unknown} - 24..29 '&0u32': &u32 - 24..41 '&0u32 ...onst _': *const {unknown} - 25..29 '0u32': u32 - "#]], ); } #[test] fn issue_14275() { - // FIXME: evaluate const generic check_types( r#" struct Foo; fn main() { const B: bool = false; let foo = Foo::; - //^^^ Foo<_> + //^^^ Foo +} +"#, + ); + check_types( + r#" +struct Foo; +impl Foo { + fn foo(self) -> u8 { 2 } +} +impl Foo { + fn foo(self) -> u16 { 5 } +} +fn main() { + const B: bool = false; + let foo: Foo = Foo; + let x = foo.foo(); + //^ u16 +} +"#, + ); +} + +#[test] +fn cstring_literals() { + check_types( + r#" +#[lang = "CStr"] +pub struct CStr; + +fn main() { + c"ello"; + //^^^^^^^ &CStr } "#, ); diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index da76d7fd83f76..829a6ab189ecc 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -90,7 +90,7 @@ fn infer_async_closure() { async fn test() { let f = async move |x: i32| x + 42; f; -// ^ |i32| -> impl Future +// ^ impl Fn(i32) -> impl Future let a = f(4); a; // ^ impl Future @@ -99,7 +99,7 @@ async fn test() { // ^ i32 let f = async move || 42; f; -// ^ || -> impl Future +// ^ impl Fn() -> impl Future let a = f(); a; // ^ impl Future @@ -116,7 +116,7 @@ async fn test() { }; let _: Option = c().await; c; -// ^ || -> impl Future> +// ^ impl Fn() -> impl Future> } "#, ); @@ -206,19 +206,27 @@ fn test() { fn infer_try_trait() { check_types( r#" -//- minicore: try, result +//- minicore: try, result, from fn test() { let r: Result = Result::Ok(1); let v = r?; v; } //^ i32 - -impl core::ops::Try for Result { - type Output = O; - type Error = Result; +"#, + ); } -impl> core::ops::FromResidual> for Result {} +#[test] +fn infer_try_block() { + // FIXME: We should test more cases, but it currently doesn't work, since + // our labeled block type inference is broken. + check_types( + r#" +//- minicore: try, option +fn test() { + let x: Option<_> = try { Some(2)?; }; + //^ Option<()> +} "#, ); } @@ -542,7 +550,7 @@ fn test() -> u64 { 53..54 'a': S 57..58 'S': S(fn(u32) -> u64) -> S 57..74 'S(|i| ...s u64)': S - 59..73 '|i| 2*i as u64': |u32| -> u64 + 59..73 '|i| 2*i as u64': impl Fn(u32) -> u64 60..61 'i': u32 63..64 '2': u64 63..73 '2*i as u64': u64 @@ -1325,9 +1333,9 @@ fn foo() -> (impl FnOnce(&str, T), impl Trait) { } "#, expect![[r#" - 134..165 '{ ...(C)) }': (|&str, T| -> (), Bar) - 140..163 '(|inpu...ar(C))': (|&str, T| -> (), Bar) - 141..154 '|input, t| {}': |&str, T| -> () + 134..165 '{ ...(C)) }': (impl Fn(&str, T), Bar) + 140..163 '(|inpu...ar(C))': (impl Fn(&str, T), Bar) + 141..154 '|input, t| {}': impl Fn(&str, T) 142..147 'input': &str 149..150 't': T 152..154 '{}': () @@ -1498,8 +1506,8 @@ fn main() { 71..105 '{ ...()); }': () 77..78 'f': fn f(&dyn Fn(S)) 77..102 'f(&|nu...foo())': () - 79..101 '&|numb....foo()': &|S| -> () - 80..101 '|numbe....foo()': |S| -> () + 79..101 '&|numb....foo()': &impl Fn(S) + 80..101 '|numbe....foo()': impl Fn(S) 81..87 'number': S 89..95 'number': S 89..101 'number.foo()': () @@ -1904,13 +1912,13 @@ fn test() { 131..132 'f': F 151..153 '{}': Lazy 251..497 '{ ...o(); }': () - 261..266 'lazy1': Lazy Foo> - 283..292 'Lazy::new': fn new Foo>(|| -> Foo) -> Lazy Foo> - 283..300 'Lazy::...| Foo)': Lazy Foo> - 293..299 '|| Foo': || -> Foo + 261..266 'lazy1': Lazy Foo> + 283..292 'Lazy::new': fn new Foo>(impl Fn() -> Foo) -> Lazy Foo> + 283..300 'Lazy::...| Foo)': Lazy Foo> + 293..299 '|| Foo': impl Fn() -> Foo 296..299 'Foo': Foo 310..312 'r1': usize - 315..320 'lazy1': Lazy Foo> + 315..320 'lazy1': Lazy Foo> 315..326 'lazy1.foo()': usize 368..383 'make_foo_fn_ptr': fn() -> Foo 399..410 'make_foo_fn': fn make_foo_fn() -> Foo @@ -1955,20 +1963,20 @@ fn test() { 163..167 '1u32': u32 174..175 'x': Option 174..190 'x.map(...v + 1)': Option - 180..189 '|v| v + 1': |u32| -> u32 + 180..189 '|v| v + 1': impl Fn(u32) -> u32 181..182 'v': u32 184..185 'v': u32 184..189 'v + 1': u32 188..189 '1': u32 196..197 'x': Option 196..212 'x.map(... 1u64)': Option - 202..211 '|_v| 1u64': |u32| -> u64 + 202..211 '|_v| 1u64': impl Fn(u32) -> u64 203..205 '_v': u32 207..211 '1u64': u64 222..223 'y': Option 239..240 'x': Option 239..252 'x.map(|_v| 1)': Option - 245..251 '|_v| 1': |u32| -> i64 + 245..251 '|_v| 1': impl Fn(u32) -> i64 246..248 '_v': u32 250..251 '1': i64 "#]], @@ -1997,11 +2005,11 @@ fn test u64>(f: F) { //^^^^ u64 let g = |v| v + 1; //^^^^^ u64 - //^^^^^^^^^ |u64| -> u64 + //^^^^^^^^^ impl Fn(u64) -> u64 g(1u64); //^^^^^^^ u64 let h = |v| 1u128 + v; - //^^^^^^^^^^^^^ |u128| -> u128 + //^^^^^^^^^^^^^ impl Fn(u128) -> u128 }"#, ); } @@ -2054,17 +2062,17 @@ fn test() { 312..314 '{}': () 330..489 '{ ... S); }': () 340..342 'x1': u64 - 345..349 'foo1': fn foo1 u64>(S, |S| -> u64) -> u64 + 345..349 'foo1': fn foo1 u64>(S, impl Fn(S) -> u64) -> u64 345..368 'foo1(S...hod())': u64 350..351 'S': S - 353..367 '|s| s.method()': |S| -> u64 + 353..367 '|s| s.method()': impl Fn(S) -> u64 354..355 's': S 357..358 's': S 357..367 's.method()': u64 378..380 'x2': u64 - 383..387 'foo2': fn foo2 u64>(|S| -> u64, S) -> u64 + 383..387 'foo2': fn foo2 u64>(impl Fn(S) -> u64, S) -> u64 383..406 'foo2(|...(), S)': u64 - 388..402 '|s| s.method()': |S| -> u64 + 388..402 '|s| s.method()': impl Fn(S) -> u64 389..390 's': S 392..393 's': S 392..402 's.method()': u64 @@ -2073,14 +2081,14 @@ fn test() { 421..422 'S': S 421..446 'S.foo1...hod())': u64 428..429 'S': S - 431..445 '|s| s.method()': |S| -> u64 + 431..445 '|s| s.method()': impl Fn(S) -> u64 432..433 's': S 435..436 's': S 435..445 's.method()': u64 456..458 'x4': u64 461..462 'S': S 461..486 'S.foo2...(), S)': u64 - 468..482 '|s| s.method()': |S| -> u64 + 468..482 '|s| s.method()': impl Fn(S) -> u64 469..470 's': S 472..473 's': S 472..482 's.method()': u64 @@ -2554,9 +2562,9 @@ fn main() { 72..74 '_v': F 117..120 '{ }': () 132..163 '{ ... }); }': () - 138..148 'f::<(), _>': fn f<(), |&()| -> ()>(|&()| -> ()) + 138..148 'f::<(), _>': fn f<(), impl Fn(&())>(impl Fn(&())) 138..160 'f::<()... z; })': () - 149..159 '|z| { z; }': |&()| -> () + 149..159 '|z| { z; }': impl Fn(&()) 150..151 'z': &() 153..159 '{ z; }': () 155..156 'z': &() @@ -2713,9 +2721,9 @@ fn main() { 983..998 'Vec::::new': fn new() -> Vec 983..1000 'Vec::<...:new()': Vec 983..1012 'Vec::<...iter()': IntoIter - 983..1075 'Vec::<...one })': FilterMap, |i32| -> Option> + 983..1075 'Vec::<...one })': FilterMap, impl Fn(i32) -> Option> 983..1101 'Vec::<... y; })': () - 1029..1074 '|x| if...None }': |i32| -> Option + 1029..1074 '|x| if...None }': impl Fn(i32) -> Option 1030..1031 'x': i32 1033..1074 'if x >...None }': Option 1036..1037 'x': i32 @@ -2728,7 +2736,7 @@ fn main() { 1049..1057 'x as u32': u32 1066..1074 '{ None }': Option 1068..1072 'None': Option - 1090..1100 '|y| { y; }': |u32| -> () + 1090..1100 '|y| { y; }': impl Fn(u32) 1091..1092 'y': u32 1094..1100 '{ y; }': () 1096..1097 'y': u32 @@ -2971,13 +2979,13 @@ fn foo() { 52..126 '{ ...)(s) }': () 62..63 's': Option 66..78 'Option::None': Option - 88..89 'f': |Option| -> () - 92..111 '|x: Op...2>| {}': |Option| -> () + 88..89 'f': impl Fn(Option) + 92..111 '|x: Op...2>| {}': impl Fn(Option) 93..94 'x': Option 109..111 '{}': () 117..124 '(&f)(s)': () - 118..120 '&f': &|Option| -> () - 119..120 'f': |Option| -> () + 118..120 '&f': &impl Fn(Option) + 119..120 'f': impl Fn(Option) 122..123 's': Option "#]], ); @@ -3043,7 +3051,7 @@ impl core::ops::Deref for Box { type Target = T; fn deref(&self) -> &T { - &self.inner + unsafe { &*self.inner } } } @@ -3054,23 +3062,25 @@ fn foo() { }"#, expect![[r#" 154..158 'self': &Box - 166..193 '{ ... }': &T - 176..187 '&self.inner': &*mut T - 177..181 'self': &Box - 177..187 'self.inner': *mut T - 206..296 '{ ...&s); }': () - 216..217 's': Option - 220..224 'None': Option - 234..235 'f': Box)> - 269..282 'box (|ps| {})': Box<|&Option| -> ()> - 274..281 '|ps| {}': |&Option| -> () - 275..277 'ps': &Option - 279..281 '{}': () - 288..289 'f': Box)> - 288..293 'f(&s)': () - 290..292 '&s': &Option - 291..292 's': Option - 269..282: expected Box)>, got Box<|&Option| -> ()> + 166..205 '{ ... }': &T + 176..199 'unsafe...nner }': &T + 185..197 '&*self.inner': &T + 186..197 '*self.inner': T + 187..191 'self': &Box + 187..197 'self.inner': *mut T + 218..308 '{ ...&s); }': () + 228..229 's': Option + 232..236 'None': Option + 246..247 'f': Box)> + 281..294 'box (|ps| {})': Box)> + 286..293 '|ps| {}': impl Fn(&Option) + 287..289 'ps': &Option + 291..293 '{}': () + 300..301 'f': Box)> + 300..305 'f(&s)': () + 302..304 '&s': &Option + 303..304 's': Option + 281..294: expected Box)>, got Box)> "#]], ); } @@ -3709,7 +3719,6 @@ async fn get_accounts() -> Result { #[test] fn local_impl_1() { - check!(block_local_impls); check_types( r#" trait Trait { @@ -3731,7 +3740,6 @@ fn test() { #[test] fn local_impl_2() { - check!(block_local_impls); check_types( r#" struct S; @@ -3753,7 +3761,6 @@ fn test() { #[test] fn local_impl_3() { - check!(block_local_impls); check_types( r#" trait Trait { @@ -3777,6 +3784,62 @@ fn test() { ); } +#[test] +fn foreign_trait_with_local_trait_impl() { + check!(block_local_impls); + check( + r#" +mod module { + pub trait T { + const C: usize; + fn f(&self); + } +} + +fn f() { + use module::T; + impl T for usize { + const C: usize = 0; + fn f(&self) {} + } + 0usize.f(); + //^^^^^^^^^^ type: () + usize::C; + //^^^^^^^^type: usize +} +"#, + ); +} + +#[test] +fn regression_14443_trait_solve() { + check_no_mismatches( + r#" +trait T { + fn f(&self) {} +} + + +fn main() { + struct A; + impl T for A {} + + let a = A; + + let b = { + struct B; + impl T for B {} + + B + }; + + a.f(); + b.f(); +} +"#, + ) +} + #[test] fn associated_type_sized_bounds() { check_infer( @@ -4149,3 +4212,201 @@ fn test() { "#, ); } + +#[test] +fn associated_type_in_struct_expr_path() { + // FIXME: All annotation should be resolvable. + // For lines marked as unstable, see rust-lang/rust#86935. + // FIXME: Remove the comments once stablized. + check_types( + r#" +trait Trait { + type Assoc; + fn f(); +} + +struct S { x: u32 } + +impl Trait for () { + type Assoc = S; + + fn f() { + let x = 42; + let a = Self::Assoc { x }; + // ^ S + let a = ::Assoc { x }; // unstable + // ^ {unknown} + + // should be `Copy` but we don't track ownership anyway. + let value = S { x }; + if let Self::Assoc { x } = value {} + // ^ u32 + if let ::Assoc { x } = value {} // unstable + // ^ {unknown} + } +} + "#, + ); +} + +#[test] +fn associated_type_in_struct_expr_path_enum() { + // FIXME: All annotation should be resolvable. + // For lines marked as unstable, see rust-lang/rust#86935. + // FIXME: Remove the comments once stablized. + check_types( + r#" +trait Trait { + type Assoc; + fn f(); +} + +enum E { + Unit, + Struct { x: u32 }, +} + +impl Trait for () { + type Assoc = E; + + fn f() { + let a = Self::Assoc::Unit; + // ^ E + let a = ::Assoc::Unit; + // ^ E + let a = ::Unit; + // ^ E + let a = <::Assoc>::Unit; + // ^ E + + // should be `Copy` but we don't track ownership anyway. + let value = E::Unit; + if let Self::Assoc::Unit = value {} + // ^^^^^^^^^^^^^^^^^ E + if let ::Assoc::Unit = value {} + // ^^^^^^^^^^^^^^^^^^^ E + if let ::Unit = value {} + // ^^^^^^^^^^^^^^^^^^^ E + if let <::Assoc>::Unit = value {} + // ^^^^^^^^^^^^^^^^^^^^^ E + + let x = 42; + let a = Self::Assoc::Struct { x }; + // ^ E + let a = ::Assoc::Struct { x }; // unstable + // ^ {unknown} + let a = ::Struct { x }; // unstable + // ^ {unknown} + let a = <::Assoc>::Struct { x }; // unstable + // ^ {unknown} + + // should be `Copy` but we don't track ownership anyway. + let value = E::Struct { x: 42 }; + if let Self::Assoc::Struct { x } = value {} + // ^ u32 + if let ::Assoc::Struct { x } = value {} // unstable + // ^ {unknown} + if let ::Struct { x } = value {} // unstable + // ^ {unknown} + if let <::Assoc>::Struct { x } = value {} // unstable + // ^ {unknown} + } +} + "#, + ); +} + +#[test] +fn derive_macro_bounds() { + check_types( + r#" + //- minicore: clone, derive + #[derive(Clone)] + struct Copy; + struct NotCopy; + #[derive(Clone)] + struct Generic(T); + trait Tr { + type Assoc; + } + impl Tr for Copy { + type Assoc = NotCopy; + } + #[derive(Clone)] + struct AssocGeneric(T::Assoc); + + #[derive(Clone)] + struct AssocGeneric2(::Assoc); + + #[derive(Clone)] + struct AssocGeneric3(Generic); + + #[derive(Clone)] + struct Vec(); + + #[derive(Clone)] + struct R1(Vec); + #[derive(Clone)] + struct R2(R1); + + fn f() { + let x = (&Copy).clone(); + //^ Copy + let x = (&NotCopy).clone(); + //^ &NotCopy + let x = (&Generic(Copy)).clone(); + //^ Generic + let x = (&Generic(NotCopy)).clone(); + //^ &Generic + let x: &AssocGeneric = &AssocGeneric(NotCopy); + let x = x.clone(); + //^ &AssocGeneric + let x: &AssocGeneric2 = &AssocGeneric2(NotCopy); + let x = x.clone(); + //^ &AssocGeneric2 + let x: &AssocGeneric3 = &AssocGeneric3(Generic(NotCopy)); + let x = x.clone(); + //^ &AssocGeneric3 + let x = (&R1(Vec())).clone(); + //^ R1 + let x = (&R2(R1(Vec()))).clone(); + //^ R2 + } + "#, + ); +} + +#[test] +fn trait_obligations_should_be_registered_during_path_inference() { + check_types( + r#" +//- minicore: fn, from +struct S(T); +fn map S>(_: T, _: F) -> U { loop {} } + +fn test(v: S) { + let res = map(v, Into::into); + //^^^ i32 +} +"#, + ); +} + +#[test] +fn fn_obligation_should_be_registered_during_path_inference() { + check_types( + r#" +//- minicore: fn, from +struct S(T); +impl S { + fn foo>>(_: U) -> Self { loop {} } +} +fn map U>(_: T, _: F) -> U { loop {} } + +fn test(v: S) { + let res = map(v, S::foo); + //^^^ S +} +"#, + ); +} diff --git a/crates/hir-ty/src/tls.rs b/crates/hir-ty/src/tls.rs index b7e6ee6740be7..83814ed0ec1f1 100644 --- a/crates/hir-ty/src/tls.rs +++ b/crates/hir-ty/src/tls.rs @@ -24,7 +24,8 @@ impl DebugContext<'_> { AdtId::UnionId(it) => self.0.union_data(it).name.clone(), AdtId::EnumId(it) => self.0.enum_data(it).name.clone(), }; - name.fmt(f) + name.display(self.0.upcast()).fmt(f)?; + Ok(()) } pub(crate) fn debug_trait_id( @@ -34,7 +35,8 @@ impl DebugContext<'_> { ) -> Result<(), fmt::Error> { let trait_: hir_def::TraitId = from_chalk_trait_id(id); let trait_data = self.0.trait_data(trait_); - trait_data.name.fmt(f) + trait_data.name.display(self.0.upcast()).fmt(f)?; + Ok(()) } pub(crate) fn debug_assoc_type_id( @@ -49,7 +51,13 @@ impl DebugContext<'_> { _ => panic!("associated type not in trait"), }; let trait_data = self.0.trait_data(trait_); - write!(fmt, "{}::{}", trait_data.name, type_alias_data.name) + write!( + fmt, + "{}::{}", + trait_data.name.display(self.0.upcast()), + type_alias_data.name.display(self.0.upcast()) + )?; + Ok(()) } pub(crate) fn debug_projection_ty( @@ -67,7 +75,7 @@ impl DebugContext<'_> { let trait_ref = projection_ty.trait_ref(self.0); let trait_params = trait_ref.substitution.as_slice(Interner); let self_ty = trait_ref.self_type_parameter(Interner); - write!(fmt, "<{self_ty:?} as {trait_name}")?; + write!(fmt, "<{self_ty:?} as {}", trait_name.display(self.0.upcast()))?; if trait_params.len() > 1 { write!( fmt, @@ -75,7 +83,7 @@ impl DebugContext<'_> { trait_params[1..].iter().format_with(", ", |x, f| f(&format_args!("{x:?}"))), )?; } - write!(fmt, ">::{}", type_alias_data.name)?; + write!(fmt, ">::{}", type_alias_data.name.display(self.0.upcast()))?; let proj_params_count = projection_ty.substitution.len(Interner) - trait_params.len(); let proj_params = &projection_ty.substitution.as_slice(Interner)[..proj_params_count]; @@ -105,9 +113,9 @@ impl DebugContext<'_> { } }; match def { - CallableDefId::FunctionId(_) => write!(fmt, "{{fn {name}}}"), + CallableDefId::FunctionId(_) => write!(fmt, "{{fn {}}}", name.display(self.0.upcast())), CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => { - write!(fmt, "{{ctor {name}}}") + write!(fmt, "{{ctor {}}}", name.display(self.0.upcast())) } } } diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs index 3ab85c68f5b9d..f40b7db3a5512 100644 --- a/crates/hir-ty/src/traits.rs +++ b/crates/hir-ty/src/traits.rs @@ -1,22 +1,24 @@ //! Trait solving using Chalk. -use std::{env::var, sync::Arc}; +use std::env::var; -use chalk_ir::GoalData; +use chalk_ir::{fold::TypeFoldable, DebruijnIndex, GoalData}; use chalk_recursive::Cache; -use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver}; +use chalk_solve::{logging_db::LoggingRustIrDatabase, rust_ir, Solver}; use base_db::CrateId; use hir_def::{ lang_item::{LangItem, LangItemTarget}, - TraitId, + BlockId, TraitId, }; +use hir_expand::name::{name, Name}; use stdx::panic_context; +use triomphe::Arc; use crate::{ - db::HirDatabase, infer::unify::InferenceTable, AliasEq, AliasTy, Canonical, DomainGoal, Goal, - Guidance, InEnvironment, Interner, ProjectionTy, ProjectionTyExt, Solution, TraitRefExt, Ty, - TyKind, WhereClause, + db::HirDatabase, infer::unify::InferenceTable, utils::UnevaluatedConstEvaluatorFolder, AliasEq, + AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment, Interner, ProjectionTy, + ProjectionTyExt, Solution, TraitRefExt, Ty, TyKind, WhereClause, }; /// This controls how much 'time' we give the Chalk solver before giving up. @@ -26,6 +28,7 @@ const CHALK_SOLVER_FUEL: i32 = 1000; pub(crate) struct ChalkContext<'a> { pub(crate) db: &'a dyn HirDatabase, pub(crate) krate: CrateId, + pub(crate) block: Option, } fn create_chalk_solver() -> chalk_recursive::RecursiveSolver { @@ -43,6 +46,7 @@ fn create_chalk_solver() -> chalk_recursive::RecursiveSolver { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct TraitEnvironment { pub krate: CrateId, + pub block: Option, // FIXME make this a BTreeMap pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>, pub env: chalk_ir::Environment, @@ -52,6 +56,7 @@ impl TraitEnvironment { pub fn empty(krate: CrateId) -> Self { TraitEnvironment { krate, + block: None, traits_from_clauses: Vec::new(), env: chalk_ir::Environment::new(Interner), } @@ -78,11 +83,12 @@ pub(crate) fn normalize_projection_query( pub(crate) fn trait_solve_query( db: &dyn HirDatabase, krate: CrateId, + block: Option, goal: Canonical>, ) -> Option { let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal.data(Interner) { GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => { - db.trait_data(it.hir_trait_id()).name.to_string() + db.trait_data(it.hir_trait_id()).name.display(db.upcast()).to_string() } GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_string(), _ => "??".to_string(), @@ -100,18 +106,25 @@ pub(crate) fn trait_solve_query( } } + // Chalk see `UnevaluatedConst` as a unique concrete value, but we see it as an alias for another const. So + // we should get rid of it when talking to chalk. + let goal = goal + .try_fold_with(&mut UnevaluatedConstEvaluatorFolder { db }, DebruijnIndex::INNERMOST) + .unwrap(); + // We currently don't deal with universes (I think / hope they're not yet // relevant for our use cases?) let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 }; - solve(db, krate, &u_canonical) + solve(db, krate, block, &u_canonical) } fn solve( db: &dyn HirDatabase, krate: CrateId, + block: Option, goal: &chalk_ir::UCanonical>>, ) -> Option> { - let context = ChalkContext { db, krate }; + let context = ChalkContext { db, krate, block }; tracing::debug!("solve goal: {:?}", goal); let mut solver = create_chalk_solver(); @@ -171,8 +184,10 @@ fn is_chalk_print() -> bool { std::env::var("CHALK_PRINT").is_ok() } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum FnTrait { + // Warning: Order is important. If something implements `x` it should also implement + // `y` if `y <= x`. FnOnce, FnMut, Fn, @@ -187,7 +202,23 @@ impl FnTrait { } } - pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option { + pub const fn to_chalk_ir(self) -> rust_ir::ClosureKind { + match self { + FnTrait::FnOnce => rust_ir::ClosureKind::FnOnce, + FnTrait::FnMut => rust_ir::ClosureKind::FnMut, + FnTrait::Fn => rust_ir::ClosureKind::Fn, + } + } + + pub fn method_name(self) -> Name { + match self { + FnTrait::FnOnce => name!(call_once), + FnTrait::FnMut => name!(call_mut), + FnTrait::Fn => name!(call), + } + } + + pub fn get_id(self, db: &dyn HirDatabase, krate: CrateId) -> Option { let target = db.lang_item(krate, self.lang_item())?; match target { LangItemTarget::Trait(t) => Some(t), diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs index 34d957e26ef5b..681d087ede6ea 100644 --- a/crates/hir-ty/src/utils.rs +++ b/crates/hir-ty/src/utils.rs @@ -4,7 +4,11 @@ use std::iter; use base_db::CrateId; -use chalk_ir::{cast::Cast, fold::Shift, BoundVar, DebruijnIndex}; +use chalk_ir::{ + cast::Cast, + fold::{FallibleTypeFolder, Shift}, + BoundVar, DebruijnIndex, +}; use either::Either; use hir_def::{ db::DefDatabase, @@ -15,16 +19,22 @@ use hir_def::{ lang_item::LangItem, resolver::{HasResolver, TypeNs}, type_ref::{TraitBoundModifier, TypeRef}, - ConstParamId, FunctionId, GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId, - TypeOrConstParamId, TypeParamId, + ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, ItemContainerId, + LocalEnumVariantId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, }; use hir_expand::name::Name; use intern::Interned; use rustc_hash::FxHashSet; use smallvec::{smallvec, SmallVec}; +use stdx::never; use crate::{ - db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, WhereClause, + consteval::unknown_const, + db::HirDatabase, + layout::{Layout, TagEncoding}, + mir::pad16, + ChalkTraitId, Const, ConstScalar, GenericArg, Interner, Substitution, TraitRef, TraitRefExt, + Ty, WhereClause, }; pub(crate) fn fn_traits( @@ -69,9 +79,7 @@ pub(super) fn all_super_trait_refs( cb: impl FnMut(TraitRef) -> Option, ) -> Option { let seen = iter::once(trait_ref.trait_id).collect(); - let mut stack = Vec::new(); - stack.push(trait_ref); - SuperTraits { db, seen, stack }.find_map(cb) + SuperTraits { db, seen, stack: vec![trait_ref] }.find_map(cb) } struct SuperTraits<'a> { @@ -130,7 +138,7 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(Tra WherePredicate::Lifetime { .. } => None, }) .filter(|(_, bound_modifier)| matches!(bound_modifier, TraitBoundModifier::None)) - .filter_map(|(path, _)| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) { + .filter_map(|(path, _)| match resolver.resolve_path_in_type_ns_fully(db, path) { Some(TypeNs::TraitId(t)) => Some(t), _ => None, }) @@ -176,6 +184,37 @@ pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { Generics { def, params: db.generic_params(def), parent_generics } } +/// It is a bit different from the rustc equivalent. Currently it stores: +/// - 0: the function signature, encoded as a function pointer type +/// - 1..n: generics of the parent +/// +/// and it doesn't store the closure types and fields. +/// +/// Codes should not assume this ordering, and should always use methods available +/// on this struct for retriving, and `TyBuilder::substs_for_closure` for creating. +pub(crate) struct ClosureSubst<'a>(pub(crate) &'a Substitution); + +impl<'a> ClosureSubst<'a> { + pub(crate) fn parent_subst(&self) -> &'a [GenericArg] { + match self.0.as_slice(Interner) { + [_, x @ ..] => x, + _ => { + never!("Closure missing parameter"); + &[] + } + } + } + + pub(crate) fn sig_ty(&self) -> &'a Ty { + match self.0.as_slice(Interner) { + [x, ..] => x.assert_ty_ref(Interner), + _ => { + unreachable!("Closure missing sig_ty parameter"); + } + } + } +} + #[derive(Debug)] pub(crate) struct Generics { def: GenericDefId, @@ -354,3 +393,74 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool { _ => false, } } + +pub(crate) struct UnevaluatedConstEvaluatorFolder<'a> { + pub(crate) db: &'a dyn HirDatabase, +} + +impl FallibleTypeFolder for UnevaluatedConstEvaluatorFolder<'_> { + type Error = (); + + fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder { + self + } + + fn interner(&self) -> Interner { + Interner + } + + fn try_fold_const( + &mut self, + constant: Const, + _outer_binder: DebruijnIndex, + ) -> Result { + if let chalk_ir::ConstValue::Concrete(c) = &constant.data(Interner).value { + if let ConstScalar::UnevaluatedConst(id, subst) = &c.interned { + if let Ok(eval) = self.db.const_eval(*id, subst.clone()) { + return Ok(eval); + } else { + return Ok(unknown_const(constant.data(Interner).ty.clone())); + } + } + } + Ok(constant) + } +} + +pub(crate) fn detect_variant_from_bytes<'a>( + layout: &'a Layout, + db: &dyn HirDatabase, + krate: CrateId, + b: &[u8], + e: EnumId, +) -> Option<(LocalEnumVariantId, &'a Layout)> { + let (var_id, var_layout) = match &layout.variants { + hir_def::layout::Variants::Single { index } => (index.0, &*layout), + hir_def::layout::Variants::Multiple { tag, tag_encoding, variants, .. } => { + let target_data_layout = db.target_data_layout(krate)?; + let size = tag.size(&*target_data_layout).bytes_usize(); + let offset = layout.fields.offset(0).bytes_usize(); // The only field on enum variants is the tag field + let tag = i128::from_le_bytes(pad16(&b[offset..offset + size], false)); + match tag_encoding { + TagEncoding::Direct => { + let x = variants.iter_enumerated().find(|x| { + db.const_eval_discriminant(EnumVariantId { parent: e, local_id: x.0 .0 }) + == Ok(tag) + })?; + (x.0 .0, x.1) + } + TagEncoding::Niche { untagged_variant, niche_start, .. } => { + let candidate_tag = tag.wrapping_sub(*niche_start as i128) as usize; + let variant = variants + .iter_enumerated() + .map(|(x, _)| x) + .filter(|x| x != untagged_variant) + .nth(candidate_tag) + .unwrap_or(*untagged_variant); + (variant.0, &variants[variant]) + } + } + } + }; + Some((var_id, var_layout)) +} diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml index ef40a8902d73f..a20aff93f19b7 100644 --- a/crates/hir/Cargo.toml +++ b/crates/hir/Cargo.toml @@ -17,6 +17,7 @@ either = "1.7.0" arrayvec = "0.7.2" itertools = "0.10.5" smallvec.workspace = true +triomphe.workspace = true once_cell = "1.17.0" # local deps diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index db0b84ef0887b..b817937296d20 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs @@ -4,7 +4,6 @@ use hir_def::{ attr::{AttrsWithOwner, Documentation}, item_scope::ItemInNs, path::ModPath, - per_ns::PerNs, resolver::HasResolver, AttrDefId, GenericParamId, ModuleDefId, }; @@ -41,7 +40,7 @@ macro_rules! impl_has_attrs { impl HasAttrs for $def { fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner { let def = AttrDefId::$def_id(self.into()); - db.attrs(def) + db.attrs_with_owner(def) } fn docs(self, db: &dyn HirDatabase) -> Option { let def = AttrDefId::$def_id(self.into()); @@ -121,6 +120,7 @@ impl HasAttrs for AssocItem { } } +/// Resolves the item `link` points to in the scope of `def`. fn resolve_doc_path( db: &dyn HirDatabase, def: AttrDefId, @@ -155,14 +155,14 @@ fn resolve_doc_path( .syntax_node() .descendants() .find_map(ast::Path::cast)?; - if ast_path.to_string() != link { + if ast_path.syntax().text() != link { return None; } ModPath::from_src(db.upcast(), ast_path, &Hygiene::new_unhygienic())? }; let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath); - let resolved = if resolved == PerNs::none() { + let resolved = if resolved.is_none() { resolver.resolve_module_path_in_trait_assoc_items(db.upcast(), &modpath)? } else { resolved diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs index 0935b5ea51945..e0cde689fed88 100644 --- a/crates/hir/src/db.rs +++ b/crates/hir/src/db.rs @@ -6,8 +6,8 @@ pub use hir_def::db::*; pub use hir_expand::db::{ AstIdMapQuery, ExpandDatabase, ExpandDatabaseStorage, ExpandProcMacroQuery, HygieneFrameQuery, - InternMacroCallQuery, MacroArgTextQuery, MacroDefQuery, MacroExpandErrorQuery, - MacroExpandQuery, ParseMacroExpansionQuery, + InternMacroCallQuery, MacroArgTextQuery, MacroDefQuery, MacroExpandQuery, + ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery, }; pub use hir_ty::db::*; diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 253d62dafc60b..b64d81490bb11 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -10,7 +10,7 @@ use cfg::{CfgExpr, CfgOptions}; use either::Either; use hir_def::path::ModPath; use hir_expand::{name::Name, HirFileId, InFile}; -use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; +use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange}; use crate::{AssocItem, Field, Local, MacroKind, Type}; @@ -38,19 +38,25 @@ diagnostics![ IncorrectCase, InvalidDeriveTarget, IncoherentImpl, + MacroDefError, MacroError, + MacroExpansionParseError, MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms, MissingUnsafe, + MovedOutOfRef, NeedMut, NoSuchField, PrivateAssocItem, PrivateField, ReplaceFilterMapNextWithFindMap, + TypedHole, TypeMismatch, + UndeclaredLabel, UnimplementedBuiltinMacro, + UnreachableLabel, UnresolvedExternCrate, UnresolvedField, UnresolvedImport, @@ -61,6 +67,19 @@ diagnostics![ UnusedMut, ]; +#[derive(Debug)] +pub struct BreakOutsideOfLoop { + pub expr: InFile>, + pub is_break: bool, + pub bad_value_break: bool, +} + +#[derive(Debug)] +pub struct TypedHole { + pub expr: InFile>, + pub expected: Type, +} + #[derive(Debug)] pub struct UnresolvedModule { pub decl: InFile>, @@ -84,6 +103,17 @@ pub struct UnresolvedMacroCall { pub path: ModPath, pub is_bang: bool, } +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct UnreachableLabel { + pub node: InFile>, + pub name: Name, +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct UndeclaredLabel { + pub node: InFile>, + pub name: Name, +} #[derive(Debug, Clone, Eq, PartialEq)] pub struct InactiveCode { @@ -111,6 +141,20 @@ pub struct MacroError { pub message: String, } +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct MacroExpansionParseError { + pub node: InFile, + pub precise_location: Option, + pub errors: Box<[SyntaxError]>, +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct MacroDefError { + pub node: InFile>, + pub message: String, + pub name: Option, +} + #[derive(Debug)] pub struct UnimplementedBuiltinMacro { pub node: InFile, @@ -166,13 +210,6 @@ pub struct PrivateField { pub field: Field, } -#[derive(Debug)] -pub struct BreakOutsideOfLoop { - pub expr: InFile>, - pub is_break: bool, - pub bad_value_break: bool, -} - #[derive(Debug)] pub struct MissingUnsafe { pub expr: InFile>, @@ -223,3 +260,9 @@ pub struct NeedMut { pub struct UnusedMut { pub local: Local, } + +#[derive(Debug)] +pub struct MovedOutOfRef { + pub ty: Type, + pub span: InFile, +} diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index 5aae92efd19ed..9a2090ab79a2c 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs @@ -1,6 +1,6 @@ //! HirDisplay implementations for various hir types. use hir_def::{ - adt::VariantData, + data::adt::VariantData, generics::{ TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, }, @@ -8,6 +8,7 @@ use hir_def::{ type_ref::{TypeBound, TypeRef}, AdtId, GenericDefId, }; +use hir_expand::name; use hir_ty::{ display::{ write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError, @@ -50,7 +51,7 @@ impl HirDisplay for Function { // FIXME: String escape? write!(f, "extern \"{}\" ", &**abi)?; } - write!(f, "fn {}", data.name)?; + write!(f, "fn {}", data.name.display(f.db.upcast()))?; write_generic_params(GenericDefId::FunctionId(self.id), f)?; @@ -62,7 +63,7 @@ impl HirDisplay for Function { { f.write_char('&')?; if let Some(lifetime) = lifetime { - write!(f, "{} ", lifetime.name)?; + write!(f, "{} ", lifetime.name.display(f.db.upcast()))?; } if let hir_def::type_ref::Mutability::Mut = mut_ { f.write_str("mut ")?; @@ -76,22 +77,22 @@ impl HirDisplay for Function { }; let mut first = true; - for (name, type_ref) in &data.params { + // FIXME: Use resolved `param.ty` once we no longer discard lifetimes + for (type_ref, param) in data.params.iter().zip(self.assoc_fn_params(db)) { + let local = param.as_local(db).map(|it| it.name(db)); if !first { f.write_str(", ")?; } else { first = false; - if data.has_self_param() { + if local == Some(name!(self)) { write_self_param(type_ref, f)?; continue; } } - match name { - Some(name) => write!(f, "{name}: ")?, + match local { + Some(name) => write!(f, "{}: ", name.display(f.db.upcast()))?, None => f.write_str("_: ")?, } - // FIXME: Use resolved `param.ty` or raw `type_ref`? - // The former will ignore lifetime arguments currently. type_ref.hir_fmt(f)?; } @@ -150,7 +151,7 @@ impl HirDisplay for Struct { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; f.write_str("struct ")?; - write!(f, "{}", self.name(f.db))?; + write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; let def_id = GenericDefId::AdtId(AdtId::StructId(self.id)); write_generic_params(def_id, f)?; write_where_clause(def_id, f)?; @@ -162,7 +163,7 @@ impl HirDisplay for Enum { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; f.write_str("enum ")?; - write!(f, "{}", self.name(f.db))?; + write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id)); write_generic_params(def_id, f)?; write_where_clause(def_id, f)?; @@ -174,7 +175,7 @@ impl HirDisplay for Union { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; f.write_str("union ")?; - write!(f, "{}", self.name(f.db))?; + write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id)); write_generic_params(def_id, f)?; write_where_clause(def_id, f)?; @@ -185,14 +186,14 @@ impl HirDisplay for Union { impl HirDisplay for Field { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?; - write!(f, "{}: ", self.name(f.db))?; + write!(f, "{}: ", self.name(f.db).display(f.db.upcast()))?; self.ty(f.db).hir_fmt(f) } } impl HirDisplay for Variant { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write!(f, "{}", self.name(f.db))?; + write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; let data = self.variant_data(f.db); match &*data { VariantData::Unit => {} @@ -221,7 +222,7 @@ impl HirDisplay for Variant { f.write_str(", ")?; } // Enum variant fields must be pub. - write!(f, "{}: ", field.name)?; + write!(f, "{}: ", field.name.display(f.db.upcast()))?; field.type_ref.hir_fmt(f)?; } f.write_str(" }")?; @@ -258,7 +259,7 @@ impl HirDisplay for TypeOrConstParam { impl HirDisplay for TypeParam { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write!(f, "{}", self.name(f.db))?; + write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; if f.omit_verbose_types() { return Ok(()); } @@ -285,13 +286,13 @@ impl HirDisplay for TypeParam { impl HirDisplay for LifetimeParam { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write!(f, "{}", self.name(f.db)) + write!(f, "{}", self.name(f.db).display(f.db.upcast())) } } impl HirDisplay for ConstParam { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write!(f, "const {}: ", self.name(f.db))?; + write!(f, "const {}: ", self.name(f.db).display(f.db.upcast()))?; self.ty(f.db).hir_fmt(f) } } @@ -324,7 +325,7 @@ fn write_generic_params( }; for (_, lifetime) in params.lifetimes.iter() { delim(f)?; - write!(f, "{}", lifetime.name)?; + write!(f, "{}", lifetime.name.display(f.db.upcast()))?; } for (_, ty) in params.type_or_consts.iter() { if let Some(name) = &ty.name() { @@ -334,7 +335,7 @@ fn write_generic_params( continue; } delim(f)?; - write!(f, "{name}")?; + write!(f, "{}", name.display(f.db.upcast()))?; if let Some(default) = &ty.default { f.write_str(" = ")?; default.hir_fmt(f)?; @@ -342,7 +343,7 @@ fn write_generic_params( } TypeOrConstParamData::ConstParamData(c) => { delim(f)?; - write!(f, "const {name}: ")?; + write!(f, "const {}: ", name.display(f.db.upcast()))?; c.ty.hir_fmt(f)?; } } @@ -379,7 +380,7 @@ fn write_where_clause(def: GenericDefId, f: &mut HirFormatter<'_>) -> Result<(), WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f), WherePredicateTypeTarget::TypeOrConstParam(id) => { match ¶ms.type_or_consts[*id].name() { - Some(name) => write!(f, "{name}"), + Some(name) => write!(f, "{}", name.display(f.db.upcast())), None => f.write_str("{unnamed}"), } } @@ -411,10 +412,15 @@ fn write_where_clause(def: GenericDefId, f: &mut HirFormatter<'_>) -> Result<(), WherePredicate::Lifetime { target, bound } => { if matches!(prev_pred, Some(WherePredicate::Lifetime { target: target_, .. }) if target_ == target) { - write!(f, " + {}", bound.name)?; + write!(f, " + {}", bound.name.display(f.db.upcast()))?; } else { new_predicate(f)?; - write!(f, "{}: {}", target.name, bound.name)?; + write!( + f, + "{}: {}", + target.name.display(f.db.upcast()), + bound.name.display(f.db.upcast()) + )?; } } WherePredicate::ForLifetime { lifetimes, target, bound } => { @@ -431,7 +437,7 @@ fn write_where_clause(def: GenericDefId, f: &mut HirFormatter<'_>) -> Result<(), if idx != 0 { f.write_str(", ")?; } - write!(f, "{lifetime}")?; + write!(f, "{}", lifetime.display(f.db.upcast()))?; } f.write_str("> ")?; write_target(target, f)?; @@ -461,7 +467,7 @@ impl HirDisplay for Const { let data = db.const_data(self.id); f.write_str("const ")?; match &data.name { - Some(name) => write!(f, "{name}: ")?, + Some(name) => write!(f, "{}: ", name.display(f.db.upcast()))?, None => f.write_str("_: ")?, } data.type_ref.hir_fmt(f)?; @@ -477,7 +483,7 @@ impl HirDisplay for Static { if data.mutable { f.write_str("mut ")?; } - write!(f, "{}: ", &data.name)?; + write!(f, "{}: ", data.name.display(f.db.upcast()))?; data.type_ref.hir_fmt(f)?; Ok(()) } @@ -493,7 +499,7 @@ impl HirDisplay for Trait { if data.is_auto { f.write_str("auto ")?; } - write!(f, "trait {}", data.name)?; + write!(f, "trait {}", data.name.display(f.db.upcast()))?; let def_id = GenericDefId::TraitId(self.id); write_generic_params(def_id, f)?; write_where_clause(def_id, f)?; @@ -505,7 +511,7 @@ impl HirDisplay for TraitAlias { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; let data = f.db.trait_alias_data(self.id); - write!(f, "trait {}", data.name)?; + write!(f, "trait {}", data.name.display(f.db.upcast()))?; let def_id = GenericDefId::TraitAliasId(self.id); write_generic_params(def_id, f)?; f.write_str(" = ")?; @@ -521,7 +527,7 @@ impl HirDisplay for TypeAlias { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; let data = f.db.type_alias_data(self.id); - write!(f, "type {}", data.name)?; + write!(f, "type {}", data.name.display(f.db.upcast()))?; let def_id = GenericDefId::TypeAliasId(self.id); write_generic_params(def_id, f)?; write_where_clause(def_id, f)?; @@ -541,8 +547,8 @@ impl HirDisplay for Module { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { // FIXME: Module doesn't have visibility saved in data. match self.name(f.db) { - Some(name) => write!(f, "mod {name}"), - None if self.is_crate_root(f.db) => match self.krate(f.db).display_name(f.db) { + Some(name) => write!(f, "mod {}", name.display(f.db.upcast())), + None if self.is_crate_root() => match self.krate(f.db).display_name(f.db) { Some(name) => write!(f, "extern crate {name}"), None => f.write_str("extern crate {unknown}"), }, @@ -558,6 +564,6 @@ impl HirDisplay for Macro { hir_def::MacroId::MacroRulesId(_) => f.write_str("macro_rules!"), hir_def::MacroId::ProcMacroId(_) => f.write_str("proc_macro"), }?; - write!(f, " {}", self.name(f.db)) + write!(f, " {}", self.name(f.db).display(f.db.upcast())) } } diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs index aaaa7abf3863c..883e6a29b06a6 100644 --- a/crates/hir/src/from_id.rs +++ b/crates/hir/src/from_id.rs @@ -4,7 +4,7 @@ //! are splitting the hir. use hir_def::{ - expr::{BindingId, LabelId}, + hir::{BindingId, LabelId}, AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, GenericParamId, ModuleDefId, VariantId, }; diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 35424feec8b29..5926d8654210d 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -6,7 +6,7 @@ //! applied. So, the relation between syntax and HIR is many-to-one. //! //! HIR is the public API of the all of the compiler logic above syntax trees. -//! It is written in "OO" style. Each type is self contained (as in, it knows it's +//! It is written in "OO" style. Each type is self contained (as in, it knows its //! parents and full context). It should be "clean code". //! //! `hir_*` crates are the implementation of the compiler logic. @@ -33,24 +33,25 @@ pub mod symbols; mod display; -use std::{iter, ops::ControlFlow, sync::Arc}; +use std::{iter, ops::ControlFlow}; use arrayvec::ArrayVec; use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId, ProcMacroKind}; use either::Either; use hir_def::{ - adt::VariantData, body::{BodyDiagnostic, SyntheticSyntax}, - expr::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat}, + data::adt::VariantData, generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, + hir::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat}, item_tree::ItemTreeNode, - lang_item::{LangItem, LangItemTarget}, - layout::{Layout, LayoutError, ReprOptions}, + lang_item::LangItemTarget, + layout::{self, ReprOptions, TargetDataLayout}, + macro_id_to_def_id, nameres::{self, diagnostics::DefDiagnostic, ModuleOrigin}, per_ns::PerNs, resolver::{HasResolver, Resolver}, src::HasSource as _, - AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, + AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, @@ -61,14 +62,15 @@ use hir_ty::{ consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt}, diagnostics::BodyValidationDiagnostic, display::HexifiedConst, - layout::layout_of_ty, + layout::{Layout as TyLayout, RustcEnumVariantIdx, TagEncoding}, method_resolution::{self, TyFingerprint}, mir::{self, interpret_mir}, primitive::UintTy, traits::FnTrait, AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution, - TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, WhereClause, + TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, ValueTyDefId, + WhereClause, }; use itertools::Itertools; use nameres::diagnostics::DefDiagnosticKind; @@ -79,6 +81,7 @@ use syntax::{ ast::{self, HasAttrs as _, HasDocComments, HasName}, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, T, }; +use triomphe::Arc; use crate::db::{DefDatabase, HirDatabase}; @@ -86,11 +89,13 @@ pub use crate::{ attrs::{HasAttrs, Namespace}, diagnostics::{ AnyDiagnostic, BreakOutsideOfLoop, ExpectedFunction, InactiveCode, IncoherentImpl, - IncorrectCase, InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount, - MissingFields, MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField, PrivateAssocItem, - PrivateField, ReplaceFilterMapNextWithFindMap, TypeMismatch, UnimplementedBuiltinMacro, - UnresolvedExternCrate, UnresolvedField, UnresolvedImport, UnresolvedMacroCall, - UnresolvedMethodCall, UnresolvedModule, UnresolvedProcMacro, UnusedMut, + IncorrectCase, InvalidDeriveTarget, MacroDefError, MacroError, MacroExpansionParseError, + MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms, MissingUnsafe, + MovedOutOfRef, NeedMut, NoSuchField, PrivateAssocItem, PrivateField, + ReplaceFilterMapNextWithFindMap, TypeMismatch, TypedHole, UndeclaredLabel, + UnimplementedBuiltinMacro, UnreachableLabel, UnresolvedExternCrate, UnresolvedField, + UnresolvedImport, UnresolvedMacroCall, UnresolvedMethodCall, UnresolvedModule, + UnresolvedProcMacro, UnusedMut, }, has_source::HasSource, semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits}, @@ -108,20 +113,18 @@ pub use crate::{ pub use { cfg::{CfgAtom, CfgExpr, CfgOptions}, hir_def::{ - adt::StructKind, - attr::{Attrs, AttrsWithOwner, Documentation}, - builtin_attr::AttributeTemplate, + attr::{builtin::AttributeTemplate, Attrs, AttrsWithOwner, Documentation}, + data::adt::StructKind, find_path::PrefixKind, import_map, - nameres::ModuleSource, + lang_item::LangItem, + nameres::{DefMap, ModuleSource}, path::{ModPath, PathKind}, type_ref::{Mutability, TypeRef}, visibility::Visibility, - // FIXME: This is here since it is input of a method in `HirWrite` - // and things outside of hir need to implement that trait. We probably - // should move whole `hir_ty::display` to this crate so we will become - // able to use `ModuleDef` or `Definition` instead of `ModuleDefId`. - ModuleDefId, + // FIXME: This is here since some queries take it as input that are used + // outside of hir. + {AdtId, ModuleDefId}, }, hir_expand::{ attrs::Attr, @@ -129,7 +132,8 @@ pub use { ExpandResult, HirFileId, InFile, MacroFile, Origin, }, hir_ty::{ - display::{HirDisplay, HirDisplayError, HirWrite}, + display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite}, + layout::LayoutError, mir::MirEvalError, PointerCast, Safety, }, @@ -198,7 +202,7 @@ impl Crate { pub fn root_module(self, db: &dyn HirDatabase) -> Module { let def_map = db.crate_def_map(self.id); - Module { id: def_map.module_id(def_map.root()) } + Module { id: def_map.module_id(DefMap::ROOT) } } pub fn modules(self, db: &dyn HirDatabase) -> Vec { @@ -253,7 +257,8 @@ impl Crate { } pub fn potential_cfg(&self, db: &dyn HirDatabase) -> CfgOptions { - db.crate_graph()[self.id].potential_cfg_options.clone() + let data = &db.crate_graph()[self.id]; + data.potential_cfg_options.clone().unwrap_or_else(|| data.cfg_options.clone()) } } @@ -326,7 +331,7 @@ impl ModuleDef { segments.extend(m.name(db)) } segments.reverse(); - Some(segments.into_iter().join("::")) + Some(segments.iter().map(|it| it.display(db.upcast())).join("::")) } pub fn canonical_module_path( @@ -470,12 +475,11 @@ impl Module { /// in the module tree of any target in `Cargo.toml`. pub fn crate_root(self, db: &dyn HirDatabase) -> Module { let def_map = db.crate_def_map(self.id.krate()); - Module { id: def_map.module_id(def_map.root()) } + Module { id: def_map.module_id(DefMap::ROOT) } } - pub fn is_crate_root(self, db: &dyn HirDatabase) -> bool { - let def_map = db.crate_def_map(self.id.krate()); - def_map.root() == self.id.local_id + pub fn is_crate_root(self) -> bool { + DefMap::ROOT == self.id.local_id } /// Iterates over all child modules. @@ -552,7 +556,11 @@ impl Module { /// Fills `acc` with the module's diagnostics. pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec) { let _p = profile::span("Module::diagnostics").detail(|| { - format!("{:?}", self.name(db).map_or("".into(), |name| name.to_string())) + format!( + "{:?}", + self.name(db) + .map_or("".into(), |name| name.display(db.upcast()).to_string()) + ) }); let def_map = self.id.def_map(db.upcast()); for diag in def_map.diagnostics() { @@ -562,6 +570,7 @@ impl Module { } emit_def_diagnostic(db, acc, diag); } + for decl in self.declarations(db) { match decl { ModuleDef::Module(m) => { @@ -600,9 +609,11 @@ impl Module { } acc.extend(decl.diagnostics(db)) } + ModuleDef::Macro(m) => emit_macro_def_diagnostics(db, acc, m), _ => acc.extend(decl.diagnostics(db)), } } + self.legacy_macros(db).into_iter().for_each(|m| emit_macro_def_diagnostics(db, acc, m)); let inherent_impls = db.inherent_impls_in_crate(self.id.krate()); @@ -684,8 +695,31 @@ impl Module { } } +fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec, m: Macro) { + let id = macro_id_to_def_id(db.upcast(), m.id); + if let Err(e) = db.macro_def(id) { + let Some(ast) = id.ast_id().left() else { + never!("MacroDefError for proc-macro: {:?}", e); + return; + }; + emit_def_diagnostic_( + db, + acc, + &DefDiagnosticKind::MacroDefError { ast, message: e.to_string() }, + ); + } +} + fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec, diag: &DefDiagnostic) { - match &diag.kind { + emit_def_diagnostic_(db, acc, &diag.kind) +} + +fn emit_def_diagnostic_( + db: &dyn HirDatabase, + acc: &mut Vec, + diag: &DefDiagnosticKind, +) { + match diag { DefDiagnosticKind::UnresolvedModule { ast: declaration, candidates } => { let decl = declaration.to_node(db.upcast()); acc.push( @@ -725,7 +759,6 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec, diag: .into(), ); } - DefDiagnosticKind::UnresolvedProcMacro { ast, krate } => { let (node, precise_location, macro_name, kind) = precise_macro_call_location(ast, db); acc.push( @@ -733,7 +766,6 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec, diag: .into(), ); } - DefDiagnosticKind::UnresolvedMacroCall { ast, path } => { let (node, precise_location, _, _) = precise_macro_call_location(ast, db); acc.push( @@ -746,12 +778,16 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec, diag: .into(), ); } - DefDiagnosticKind::MacroError { ast, message } => { let (node, precise_location, _, _) = precise_macro_call_location(ast, db); acc.push(MacroError { node, precise_location, message: message.clone() }.into()); } - + DefDiagnosticKind::MacroExpansionParseError { ast, errors } => { + let (node, precise_location, _, _) = precise_macro_call_location(ast, db); + acc.push( + MacroExpansionParseError { node, precise_location, errors: errors.clone() }.into(), + ); + } DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => { let node = ast.to_node(db.upcast()); // Must have a name, otherwise we wouldn't emit it. @@ -793,6 +829,17 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec, diag: None => stdx::never!("derive diagnostic on item without derive attribute"), } } + DefDiagnosticKind::MacroDefError { ast, message } => { + let node = ast.to_node(db.upcast()); + acc.push( + MacroDefError { + node: InFile::new(ast.file_id, AstPtr::new(&node)), + name: node.name().map(|it| it.syntax().text_range()), + message: message.clone(), + } + .into(), + ); + } } } @@ -800,7 +847,7 @@ fn precise_macro_call_location( ast: &MacroCallKind, db: &dyn HirDatabase, ) -> (InFile, Option, Option, MacroKind) { - // FIXME: maaybe we actually want slightly different ranges for the different macro diagnostics + // FIXME: maybe we actually want slightly different ranges for the different macro diagnostics // - e.g. the full attribute for macro errors, but only the name for name resolution match ast { MacroCallKind::FnLike { ast_id, .. } => { @@ -915,7 +962,8 @@ impl Field { } pub fn layout(&self, db: &dyn HirDatabase) -> Result { - layout_of_ty(db, &self.ty(db).ty, self.parent.module(db).krate().into()) + db.layout_of_ty(self.ty(db).ty.clone(), self.parent.module(db).krate().into()) + .map(|layout| Layout(layout, db.target_data_layout(self.krate(db).into()).unwrap())) } pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef { @@ -959,6 +1007,10 @@ impl Struct { Type::from_def(db, self.id) } + pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type { + Type::from_value_def(db, self.id) + } + pub fn repr(self, db: &dyn HirDatabase) -> Option { db.struct_data(self.id).repr } @@ -996,6 +1048,10 @@ impl Union { Type::from_def(db, self.id) } + pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type { + Type::from_value_def(db, self.id) + } + pub fn fields(self, db: &dyn HirDatabase) -> Vec { db.union_data(self.id) .variant_data @@ -1034,6 +1090,10 @@ impl Enum { db.enum_data(self.id).variants.iter().map(|(id, _)| Variant { parent: self, id }).collect() } + pub fn repr(self, db: &dyn HirDatabase) -> Option { + db.enum_data(self.id).repr + } + pub fn ty(self, db: &dyn HirDatabase) -> Type { Type::from_def(db, self.id) } @@ -1043,7 +1103,7 @@ impl Enum { Type::new_for_crate( self.id.lookup(db.upcast()).container.krate(), TyBuilder::builtin(match db.enum_data(self.id).variant_body_type() { - hir_def::layout::IntegerType::Pointer(sign) => match sign { + layout::IntegerType::Pointer(sign) => match sign { true => hir_def::builtin_type::BuiltinType::Int( hir_def::builtin_type::BuiltinInt::Isize, ), @@ -1051,29 +1111,34 @@ impl Enum { hir_def::builtin_type::BuiltinUint::Usize, ), }, - hir_def::layout::IntegerType::Fixed(i, sign) => match sign { + layout::IntegerType::Fixed(i, sign) => match sign { true => hir_def::builtin_type::BuiltinType::Int(match i { - hir_def::layout::Integer::I8 => hir_def::builtin_type::BuiltinInt::I8, - hir_def::layout::Integer::I16 => hir_def::builtin_type::BuiltinInt::I16, - hir_def::layout::Integer::I32 => hir_def::builtin_type::BuiltinInt::I32, - hir_def::layout::Integer::I64 => hir_def::builtin_type::BuiltinInt::I64, - hir_def::layout::Integer::I128 => hir_def::builtin_type::BuiltinInt::I128, + layout::Integer::I8 => hir_def::builtin_type::BuiltinInt::I8, + layout::Integer::I16 => hir_def::builtin_type::BuiltinInt::I16, + layout::Integer::I32 => hir_def::builtin_type::BuiltinInt::I32, + layout::Integer::I64 => hir_def::builtin_type::BuiltinInt::I64, + layout::Integer::I128 => hir_def::builtin_type::BuiltinInt::I128, }), false => hir_def::builtin_type::BuiltinType::Uint(match i { - hir_def::layout::Integer::I8 => hir_def::builtin_type::BuiltinUint::U8, - hir_def::layout::Integer::I16 => hir_def::builtin_type::BuiltinUint::U16, - hir_def::layout::Integer::I32 => hir_def::builtin_type::BuiltinUint::U32, - hir_def::layout::Integer::I64 => hir_def::builtin_type::BuiltinUint::U64, - hir_def::layout::Integer::I128 => hir_def::builtin_type::BuiltinUint::U128, + layout::Integer::I8 => hir_def::builtin_type::BuiltinUint::U8, + layout::Integer::I16 => hir_def::builtin_type::BuiltinUint::U16, + layout::Integer::I32 => hir_def::builtin_type::BuiltinUint::U32, + layout::Integer::I64 => hir_def::builtin_type::BuiltinUint::U64, + layout::Integer::I128 => hir_def::builtin_type::BuiltinUint::U128, }), }, }), ) } + /// Returns true if at least one variant of this enum is a non-unit variant. pub fn is_data_carrying(self, db: &dyn HirDatabase) -> bool { self.variants(db).iter().any(|v| !matches!(v.kind(db), StructKind::Unit)) } + + pub fn layout(self, db: &dyn HirDatabase) -> Result { + Adt::from(self).layout(db) + } } impl HasVisibility for Enum { @@ -1103,6 +1168,10 @@ impl Variant { self.parent } + pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type { + Type::from_value_def(db, EnumVariantId { parent: self.parent.id, local_id: self.id }) + } + pub fn name(self, db: &dyn HirDatabase) -> Name { db.enum_data(self.parent.id).variants[self.id].name.clone() } @@ -1130,6 +1199,18 @@ impl Variant { pub fn eval(self, db: &dyn HirDatabase) -> Result { db.const_eval_discriminant(self.into()) } + + pub fn layout(&self, db: &dyn HirDatabase) -> Result { + let parent_enum = self.parent_enum(db); + let parent_layout = parent_enum.layout(db)?; + Ok(match &parent_layout.0.variants { + layout::Variants::Multiple { variants, .. } => Layout( + Arc::new(variants[RustcEnumVariantIdx(self.id)].clone()), + db.target_data_layout(parent_enum.krate(db).into()).unwrap(), + ), + _ => parent_layout, + }) + } } /// Variants inherit visibility from the parent enum. @@ -1161,7 +1242,9 @@ impl Adt { if db.generic_params(self.into()).iter().count() != 0 { return Err(LayoutError::HasPlaceholder); } - db.layout_of_adt(self.into(), Substitution::empty(Interner)) + let krate = self.krate(db).id; + db.layout_of_adt(self.into(), Substitution::empty(Interner), krate) + .map(|layout| Layout(layout, db.target_data_layout(krate).unwrap())) } /// Turns this ADT into a type. Any type parameters of the ADT will be @@ -1392,6 +1475,12 @@ impl DefWithBody { } .into(), ), + BodyDiagnostic::UnreachableLabel { node, name } => { + acc.push(UnreachableLabel { node: node.clone(), name: name.clone() }.into()) + } + BodyDiagnostic::UndeclaredLabel { node, name } => { + acc.push(UndeclaredLabel { node: node.clone(), name: name.clone() }.into()) + } } } @@ -1404,14 +1493,6 @@ impl DefWithBody { let field = source_map.field_syntax(expr); acc.push(NoSuchField { field }.into()) } - &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { - expr, - is_break, - bad_value_break, - } => { - let expr = expr_syntax(expr); - acc.push(BreakOutsideOfLoop { expr, is_break, bad_value_break }.into()) - } &hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => { acc.push( MismatchedArgCount { call_expr: expr_syntax(call_expr), expected, found } @@ -1483,14 +1564,29 @@ impl DefWithBody { .into(), ) } + &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { + expr, + is_break, + bad_value_break, + } => { + let expr = expr_syntax(expr); + acc.push(BreakOutsideOfLoop { expr, is_break, bad_value_break }.into()) + } + hir_ty::InferenceDiagnostic::TypedHole { expr, expected } => { + let expr = expr_syntax(*expr); + acc.push( + TypedHole { + expr, + expected: Type::new(db, DefWithBodyId::from(self), expected.clone()), + } + .into(), + ) + } } } for (pat_or_expr, mismatch) in infer.type_mismatches() { let expr_or_pat = match pat_or_expr { ExprOrPatId::ExprId(expr) => source_map.expr_syntax(expr).map(Either::Left), - // FIXME: Re-enable these once we have less false positives - ExprOrPatId::PatId(_pat) => continue, - #[allow(unreachable_patterns)] ExprOrPatId::PatId(pat) => source_map.pat_syntax(pat).map(Either::Right), }; let expr_or_pat = match expr_or_pat { @@ -1515,7 +1611,7 @@ impl DefWithBody { match source_map.expr_syntax(expr) { Ok(expr) => acc.push(MissingUnsafe { expr }.into()), Err(SyntheticSyntax) => { - // FIXME: Here and eslwhere in this file, the `expr` was + // FIXME: Here and elsewhere in this file, the `expr` was // desugared, report or assert that this doesn't happen. } } @@ -1523,35 +1619,71 @@ impl DefWithBody { let hir_body = db.body(self.into()); - if let Ok(borrowck_result) = db.borrowck(self.into()) { - let mir_body = &borrowck_result.mir_body; - let mol = &borrowck_result.mutability_of_locals; - for (binding_id, _) in hir_body.bindings.iter() { - let need_mut = &mol[mir_body.binding_locals[binding_id]]; - let local = Local { parent: self.into(), binding_id }; - match (need_mut, local.is_mut(db)) { - (mir::MutabilityReason::Mut { .. }, true) - | (mir::MutabilityReason::Not, false) => (), - (mir::MutabilityReason::Mut { spans }, false) => { - for span in spans { - let span: InFile = match span { - mir::MirSpan::ExprId(e) => match source_map.expr_syntax(*e) { - Ok(s) => s.map(|x| x.into()), - Err(_) => continue, - }, - mir::MirSpan::PatId(p) => match source_map.pat_syntax(*p) { - Ok(s) => s.map(|x| match x { - Either::Left(e) => e.into(), - Either::Right(e) => e.into(), - }), - Err(_) => continue, - }, - mir::MirSpan::Unknown => continue, - }; - acc.push(NeedMut { local, span }.into()); + if let Ok(borrowck_results) = db.borrowck(self.into()) { + for borrowck_result in borrowck_results.iter() { + let mir_body = &borrowck_result.mir_body; + for moof in &borrowck_result.moved_out_of_ref { + let span: InFile = match moof.span { + mir::MirSpan::ExprId(e) => match source_map.expr_syntax(e) { + Ok(s) => s.map(|x| x.into()), + Err(_) => continue, + }, + mir::MirSpan::PatId(p) => match source_map.pat_syntax(p) { + Ok(s) => s.map(|x| match x { + Either::Left(e) => e.into(), + Either::Right(e) => e.into(), + }), + Err(_) => continue, + }, + mir::MirSpan::Unknown => continue, + }; + acc.push( + MovedOutOfRef { ty: Type::new_for_crate(krate, moof.ty.clone()), span } + .into(), + ) + } + let mol = &borrowck_result.mutability_of_locals; + for (binding_id, binding_data) in hir_body.bindings.iter() { + if binding_data.problems.is_some() { + // We should report specific diagnostics for these problems, not `need-mut` and `unused-mut`. + continue; + } + let Some(&local) = mir_body.binding_locals.get(binding_id) else { + continue; + }; + let need_mut = &mol[local]; + let local = Local { parent: self.into(), binding_id }; + match (need_mut, local.is_mut(db)) { + (mir::MutabilityReason::Mut { .. }, true) + | (mir::MutabilityReason::Not, false) => (), + (mir::MutabilityReason::Mut { spans }, false) => { + for span in spans { + let span: InFile = match span { + mir::MirSpan::ExprId(e) => match source_map.expr_syntax(*e) { + Ok(s) => s.map(|x| x.into()), + Err(_) => continue, + }, + mir::MirSpan::PatId(p) => match source_map.pat_syntax(*p) { + Ok(s) => s.map(|x| match x { + Either::Left(e) => e.into(), + Either::Right(e) => e.into(), + }), + Err(_) => continue, + }, + mir::MirSpan::Unknown => continue, + }; + acc.push(NeedMut { local, span }.into()); + } + } + (mir::MutabilityReason::Not, true) => { + if !infer.mutated_bindings_in_closure.contains(&binding_id) { + let should_ignore = matches!(body[binding_id].name.as_str(), Some(x) if x.starts_with("_")); + if !should_ignore { + acc.push(UnusedMut { local }.into()) + } + } } } - (mir::MutabilityReason::Not, true) => acc.push(UnusedMut { local }.into()), } } } @@ -1686,6 +1818,10 @@ impl Function { db.function_data(self.id).name.clone() } + pub fn ty(self, db: &dyn HirDatabase) -> Type { + Type::from_value_def(db, self.id) + } + /// Get this function's return type pub fn ret_type(self, db: &dyn HirDatabase) -> Type { let resolver = self.id.resolver(db.upcast()); @@ -1797,12 +1933,41 @@ impl Function { def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() }) } - pub fn eval(self, db: &dyn HirDatabase) -> Result<(), MirEvalError> { - let body = db - .mir_body(self.id.into()) - .map_err(|e| MirEvalError::MirLowerError(self.id.into(), e))?; - interpret_mir(db, &body, false)?; - Ok(()) + pub fn eval( + self, + db: &dyn HirDatabase, + span_formatter: impl Fn(FileId, TextRange) -> String, + ) -> String { + let body = match db.monomorphized_mir_body( + self.id.into(), + Substitution::empty(Interner), + db.trait_environment(self.id.into()), + ) { + Ok(body) => body, + Err(e) => { + let mut r = String::new(); + _ = e.pretty_print(&mut r, db, &span_formatter); + return r; + } + }; + let (result, stdout, stderr) = interpret_mir(db, &body, false); + let mut text = match result { + Ok(_) => "pass".to_string(), + Err(e) => { + let mut r = String::new(); + _ = e.pretty_print(&mut r, db, &span_formatter); + r + } + }; + if !stdout.is_empty() { + text += "\n--------- stdout ---------\n"; + text += &stdout; + } + if !stderr.is_empty() { + text += "\n--------- stderr ---------\n"; + text += &stderr; + } + text } } @@ -1837,7 +2002,7 @@ impl Param { } pub fn name(&self, db: &dyn HirDatabase) -> Option { - db.function_data(self.func.id).params[self.idx].0.clone() + Some(self.as_local(db)?.name(db)) } pub fn as_local(&self, db: &dyn HirDatabase) -> Option { @@ -1878,7 +2043,7 @@ impl SelfParam { func_data .params .first() - .map(|(_, param)| match &**param { + .map(|param| match &**param { TypeRef::Reference(.., mutability) => match mutability { hir_def::type_ref::Mutability::Shared => Access::Shared, hir_def::type_ref::Mutability::Mut => Access::Exclusive, @@ -1939,24 +2104,12 @@ impl Const { } pub fn ty(self, db: &dyn HirDatabase) -> Type { - let data = db.const_data(self.id); - let resolver = self.id.resolver(db.upcast()); - let ctx = hir_ty::TyLoweringContext::new(db, &resolver); - let ty = ctx.lower_ty(&data.type_ref); - Type::new_with_resolver_inner(db, &resolver, ty) + Type::from_value_def(db, self.id) } pub fn render_eval(self, db: &dyn HirDatabase) -> Result { - let c = db.const_eval(self.id)?; + let c = db.const_eval(self.id.into(), Substitution::empty(Interner))?; let r = format!("{}", HexifiedConst(c).display(db)); - // We want to see things like `` and `` as they are probably bug in our - // implementation, but there is no need to show things like `` or `` to - // the user. - if r.contains("not-supported>") { - return Err(ConstEvalError::MirEvalError(MirEvalError::NotSupported( - "rendering complex constants".to_string(), - ))); - } return Ok(r); } } @@ -1990,11 +2143,7 @@ impl Static { } pub fn ty(self, db: &dyn HirDatabase) -> Type { - let data = db.static_data(self.id); - let resolver = self.id.resolver(db.upcast()); - let ctx = hir_ty::TyLoweringContext::new(db, &resolver); - let ty = ctx.lower_ty(&data.type_ref); - Type::new_with_resolver_inner(db, &resolver, ty) + Type::from_value_def(db, self.id) } } @@ -2545,8 +2694,12 @@ impl LocalSource { self.source.file_id.original_file(db.upcast()) } - pub fn name(&self) -> Option { - self.source.value.name() + pub fn file(&self) -> HirFileId { + self.source.file_id + } + + pub fn name(&self) -> Option> { + self.source.as_ref().map(|it| it.name()).transpose() } pub fn syntax(&self) -> &SyntaxNode { @@ -2689,9 +2842,7 @@ impl BuiltinAttr { } fn builtin(name: &str) -> Option { - hir_def::builtin_attr::INERT_ATTRIBUTES - .iter() - .position(|tool| tool.name == name) + hir_def::attr::builtin::find_builtin_attr_idx(name) .map(|idx| BuiltinAttr { krate: None, idx: idx as u32 }) } @@ -2699,14 +2850,14 @@ impl BuiltinAttr { // FIXME: Return a `Name` here match self.krate { Some(krate) => db.crate_def_map(krate).registered_attrs()[self.idx as usize].clone(), - None => SmolStr::new(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx as usize].name), + None => SmolStr::new(hir_def::attr::builtin::INERT_ATTRIBUTES[self.idx as usize].name), } } pub fn template(&self, _: &dyn HirDatabase) -> Option { match self.krate { Some(_) => None, - None => Some(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx as usize].template), + None => Some(hir_def::attr::builtin::INERT_ATTRIBUTES[self.idx as usize].template), } } } @@ -2729,7 +2880,7 @@ impl ToolModule { } fn builtin(name: &str) -> Option { - hir_def::builtin_attr::TOOL_MODULES + hir_def::attr::builtin::TOOL_MODULES .iter() .position(|&tool| tool == name) .map(|idx| ToolModule { krate: None, idx: idx as u32 }) @@ -2739,7 +2890,7 @@ impl ToolModule { // FIXME: Return a `Name` here match self.krate { Some(krate) => db.crate_def_map(krate).registered_tools()[self.idx as usize].clone(), - None => SmolStr::new(hir_def::builtin_attr::TOOL_MODULES[self.idx as usize]), + None => SmolStr::new(hir_def::attr::builtin::TOOL_MODULES[self.idx as usize]), } } } @@ -3117,6 +3268,103 @@ impl TraitRef { } } +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Closure { + id: ClosureId, + subst: Substitution, +} + +impl From for ClosureId { + fn from(value: Closure) -> Self { + value.id + } +} + +impl Closure { + fn as_ty(self) -> Ty { + TyKind::Closure(self.id, self.subst).intern(Interner) + } + + pub fn display_with_id(&self, db: &dyn HirDatabase) -> String { + self.clone().as_ty().display(db).with_closure_style(ClosureStyle::ClosureWithId).to_string() + } + + pub fn display_with_impl(&self, db: &dyn HirDatabase) -> String { + self.clone().as_ty().display(db).with_closure_style(ClosureStyle::ImplFn).to_string() + } + + pub fn captured_items(&self, db: &dyn HirDatabase) -> Vec { + let owner = db.lookup_intern_closure((self.id).into()).0; + let infer = &db.infer(owner); + let info = infer.closure_info(&self.id); + info.0 + .iter() + .cloned() + .map(|capture| ClosureCapture { owner, closure: self.id, capture }) + .collect() + } + + pub fn capture_types(&self, db: &dyn HirDatabase) -> Vec { + let owner = db.lookup_intern_closure((self.id).into()).0; + let infer = &db.infer(owner); + let (captures, _) = infer.closure_info(&self.id); + captures + .iter() + .cloned() + .map(|capture| Type { + env: db.trait_environment_for_body(owner), + ty: capture.ty(&self.subst), + }) + .collect() + } + + pub fn fn_trait(&self, db: &dyn HirDatabase) -> FnTrait { + let owner = db.lookup_intern_closure((self.id).into()).0; + let infer = &db.infer(owner); + let info = infer.closure_info(&self.id); + info.1 + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ClosureCapture { + owner: DefWithBodyId, + closure: ClosureId, + capture: hir_ty::CapturedItem, +} + +impl ClosureCapture { + pub fn local(&self) -> Local { + Local { parent: self.owner, binding_id: self.capture.local() } + } + + pub fn kind(&self) -> CaptureKind { + match self.capture.kind() { + hir_ty::CaptureKind::ByRef( + hir_ty::mir::BorrowKind::Shallow | hir_ty::mir::BorrowKind::Shared, + ) => CaptureKind::SharedRef, + hir_ty::CaptureKind::ByRef(hir_ty::mir::BorrowKind::Unique) => { + CaptureKind::UniqueSharedRef + } + hir_ty::CaptureKind::ByRef(hir_ty::mir::BorrowKind::Mut { .. }) => { + CaptureKind::MutableRef + } + hir_ty::CaptureKind::ByValue => CaptureKind::Move, + } + } + + pub fn display_place(&self, db: &dyn HirDatabase) -> String { + self.capture.display_place(self.owner, db) + } +} + +pub enum CaptureKind { + SharedRef, + UniqueSharedRef, + MutableRef, + Move, +} + #[derive(Clone, PartialEq, Eq, Debug)] pub struct Type { env: Arc, @@ -3164,24 +3412,33 @@ impl Type { Type { env: environment, ty } } - fn from_def(db: &dyn HirDatabase, def: impl HasResolver + Into) -> Type { - let ty_def = def.into(); - let parent_subst = match ty_def { - TyDefId::TypeAliasId(id) => match id.lookup(db.upcast()).container { - ItemContainerId::TraitId(id) => { - let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build(); - Some(subst) - } - ItemContainerId::ImplId(id) => { - let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build(); - Some(subst) - } - _ => None, + fn from_def(db: &dyn HirDatabase, def: impl Into + HasResolver) -> Type { + let ty = db.ty(def.into()); + let substs = TyBuilder::unknown_subst( + db, + match def.into() { + TyDefId::AdtId(it) => GenericDefId::AdtId(it), + TyDefId::TypeAliasId(it) => GenericDefId::TypeAliasId(it), + TyDefId::BuiltinType(_) => return Type::new(db, def, ty.skip_binders().clone()), }, - _ => None, - }; - let ty = TyBuilder::def_ty(db, ty_def, parent_subst).fill_with_unknown().build(); - Type::new(db, def, ty) + ); + Type::new(db, def, ty.substitute(Interner, &substs)) + } + + fn from_value_def(db: &dyn HirDatabase, def: impl Into + HasResolver) -> Type { + let ty = db.value_ty(def.into()); + let substs = TyBuilder::unknown_subst( + db, + match def.into() { + ValueTyDefId::ConstId(it) => GenericDefId::ConstId(it), + ValueTyDefId::FunctionId(it) => GenericDefId::FunctionId(it), + ValueTyDefId::StructId(it) => GenericDefId::AdtId(AdtId::StructId(it)), + ValueTyDefId::UnionId(it) => GenericDefId::AdtId(AdtId::UnionId(it)), + ValueTyDefId::EnumVariantId(it) => GenericDefId::EnumVariantId(it), + ValueTyDefId::StaticId(_) => return Type::new(db, def, ty.skip_binders().clone()), + }, + ); + Type::new(db, def, ty.substitute(Interner, &substs)) } pub fn new_slice(ty: Type) -> Type { @@ -3331,7 +3588,7 @@ impl Type { binders: CanonicalVarKinds::empty(Interner), }; - db.trait_solve(self.env.krate, goal).is_some() + db.trait_solve(self.env.krate, self.env.block, goal).is_some() } pub fn normalize_trait_assoc_type( @@ -3378,7 +3635,12 @@ impl Type { } pub fn as_callable(&self, db: &dyn HirDatabase) -> Option { + let mut the_ty = &self.ty; let callee = match self.ty.kind(Interner) { + TyKind::Ref(_, _, ty) if ty.as_closure().is_some() => { + the_ty = ty; + Callee::Closure(ty.as_closure().unwrap()) + } TyKind::Closure(id, _) => Callee::Closure(*id), TyKind::Function(_) => Callee::FnPtr, TyKind::FnDef(..) => Callee::Def(self.ty.callable_def(db)?), @@ -3393,7 +3655,7 @@ impl Type { } }; - let sig = self.ty.callable_sig(db)?; + let sig = the_ty.callable_sig(db)?; Some(Callable { ty: self.clone(), sig, callee, is_bound_method: false }) } @@ -3401,6 +3663,13 @@ impl Type { matches!(self.ty.kind(Interner), TyKind::Closure { .. }) } + pub fn as_closure(&self) -> Option { + match self.ty.kind(Interner) { + TyKind::Closure(id, subst) => Some(Closure { id: *id, subst: subst.clone() }), + _ => None, + } + } + pub fn is_fn(&self) -> bool { matches!(self.ty.kind(Interner), TyKind::FnDef(..) | TyKind::Function { .. }) } @@ -3502,9 +3771,9 @@ impl Type { } } - pub fn as_array(&self, _db: &dyn HirDatabase) -> Option<(Type, usize)> { + pub fn as_array(&self, db: &dyn HirDatabase) -> Option<(Type, usize)> { if let TyKind::Array(ty, len) = &self.ty.kind(Interner) { - try_const_usize(len).map(|x| (self.derived(ty.clone()), x as usize)) + try_const_usize(db, len).map(|x| (self.derived(ty.clone()), x as usize)) } else { None } @@ -3517,8 +3786,7 @@ impl Type { fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator + 'a { // There should be no inference vars in types passed here let canonical = hir_ty::replace_errors_with_variables(&self.ty); - let environment = self.env.clone(); - autoderef(db, environment, canonical).map(|canonical| canonical.value) + autoderef(db, self.env.clone(), canonical).map(|canonical| canonical.value) } // This would be nicer if it just returned an iterator, but that runs into @@ -3636,7 +3904,7 @@ impl Type { self.as_adt() .and_then(|a| a.lifetime(db).and_then(|lt| Some((<.name).to_smol_str()))) .into_iter() - // add the type and const paramaters + // add the type and const parameters .chain(self.type_and_const_arguments(db)) } @@ -3955,6 +4223,11 @@ impl Type { .map(|id| TypeOrConstParam { id }.split(db).either_into()) .collect() } + + pub fn layout(&self, db: &dyn HirDatabase) -> Result { + db.layout_of_ty(self.ty.clone(), self.env.krate) + .map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap())) + } } // FIXME: Document this @@ -4064,6 +4337,48 @@ fn closure_source(db: &dyn HirDatabase, closure: ClosureId) -> Option, Arc); + +impl Layout { + pub fn size(&self) -> u64 { + self.0.size.bytes() + } + + pub fn align(&self) -> u64 { + self.0.align.abi.bytes() + } + + pub fn niches(&self) -> Option { + Some(self.0.largest_niche?.available(&*self.1)) + } + + pub fn field_offset(&self, idx: usize) -> Option { + match self.0.fields { + layout::FieldsShape::Primitive => None, + layout::FieldsShape::Union(_) => Some(0), + layout::FieldsShape::Array { stride, count } => { + let i = u64::try_from(idx).ok()?; + (i < count).then_some((stride * i).bytes()) + } + layout::FieldsShape::Arbitrary { ref offsets, .. } => Some(offsets.get(idx)?.bytes()), + } + } + + pub fn enum_tag_size(&self) -> Option { + let tag_size = + if let layout::Variants::Multiple { tag, tag_encoding, .. } = &self.0.variants { + match tag_encoding { + TagEncoding::Direct => tag.size(&*self.1).bytes_usize(), + TagEncoding::Niche { .. } => 0, + } + } else { + return None; + }; + Some(tag_size) + } +} + #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum BindingMode { Move, @@ -4215,6 +4530,12 @@ impl HasCrate for Union { } } +impl HasCrate for Enum { + fn krate(&self, db: &dyn HirDatabase) -> Crate { + self.module(db).krate() + } +} + impl HasCrate for Field { fn krate(&self, db: &dyn HirDatabase) -> Crate { self.parent_def(db).module(db).krate() @@ -4286,3 +4607,90 @@ impl HasCrate for Module { Module::krate(*self) } } + +pub trait HasContainer { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer; +} + +impl HasContainer for Module { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + // FIXME: handle block expressions as modules (their parent is in a different DefMap) + let def_map = self.id.def_map(db.upcast()); + match def_map[self.id.local_id].parent { + Some(parent_id) => ItemContainer::Module(Module { id: def_map.module_id(parent_id) }), + None => ItemContainer::Crate(def_map.krate()), + } + } +} + +impl HasContainer for Function { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + container_id_to_hir(self.id.lookup(db.upcast()).container) + } +} + +impl HasContainer for Struct { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + ItemContainer::Module(Module { id: self.id.lookup(db.upcast()).container }) + } +} + +impl HasContainer for Union { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + ItemContainer::Module(Module { id: self.id.lookup(db.upcast()).container }) + } +} + +impl HasContainer for Enum { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + ItemContainer::Module(Module { id: self.id.lookup(db.upcast()).container }) + } +} + +impl HasContainer for TypeAlias { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + container_id_to_hir(self.id.lookup(db.upcast()).container) + } +} + +impl HasContainer for Const { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + container_id_to_hir(self.id.lookup(db.upcast()).container) + } +} + +impl HasContainer for Static { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + container_id_to_hir(self.id.lookup(db.upcast()).container) + } +} + +impl HasContainer for Trait { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + ItemContainer::Module(Module { id: self.id.lookup(db.upcast()).container }) + } +} + +impl HasContainer for TraitAlias { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + ItemContainer::Module(Module { id: self.id.lookup(db.upcast()).container }) + } +} + +fn container_id_to_hir(c: ItemContainerId) -> ItemContainer { + match c { + ItemContainerId::ExternBlockId(_id) => ItemContainer::ExternBlock(), + ItemContainerId::ModuleId(id) => ItemContainer::Module(Module { id }), + ItemContainerId::ImplId(id) => ItemContainer::Impl(Impl { id }), + ItemContainerId::TraitId(id) => ItemContainer::Trait(Trait { id }), + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ItemContainer { + Trait(Trait), + Impl(Impl), + Module(Module), + ExternBlock(), + Crate(CrateId), +} diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 407ba6f65844e..2d2b00b147e55 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -7,9 +7,10 @@ use std::{cell::RefCell, fmt, iter, mem, ops}; use base_db::{FileId, FileRange}; use either::Either; use hir_def::{ - body, - expr::Expr, + hir::Expr, + lower::LowerCtx, macro_id_to_def_id, + nameres::MacroSubNs, resolver::{self, HasResolver, Resolver, TypeNs}, type_ref::Mutability, AsMacroCall, DefWithBodyId, FieldId, FunctionId, MacroId, TraitId, VariantId, @@ -140,7 +141,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.parse(file_id) } - pub fn parse_or_expand(&self, file_id: HirFileId) -> Option { + pub fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode { self.imp.parse_or_expand(file_id) } @@ -350,6 +351,13 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.type_of_pat(pat) } + /// It also includes the changes that binding mode makes in the type. For example in + /// `let ref x @ Some(_) = None` the result of `type_of_pat` is `Option` but the result + /// of this function is `&mut Option` + pub fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option { + self.imp.type_of_binding_in_pat(pat) + } + pub fn type_of_self(&self, param: &ast::SelfParam) -> Option { self.imp.type_of_self(param) } @@ -518,23 +526,23 @@ impl<'db> SemanticsImpl<'db> { tree } - fn parse_or_expand(&self, file_id: HirFileId) -> Option { - let node = self.db.parse_or_expand(file_id)?; + fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode { + let node = self.db.parse_or_expand(file_id); self.cache(node.clone(), file_id); - Some(node) + node } fn expand(&self, macro_call: &ast::MacroCall) -> Option { let sa = self.analyze_no_infer(macro_call.syntax())?; let file_id = sa.expand(self.db, InFile::new(sa.file_id, macro_call))?; - let node = self.parse_or_expand(file_id)?; + let node = self.parse_or_expand(file_id); Some(node) } fn expand_attr_macro(&self, item: &ast::Item) -> Option { let src = self.wrap_node_infile(item.clone()); let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src))?; - self.parse_or_expand(macro_call_id.as_file()) + Some(self.parse_or_expand(macro_call_id.as_file())) } fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Attr) -> Option { @@ -543,7 +551,7 @@ impl<'db> SemanticsImpl<'db> { let call_id = self.with_ctx(|ctx| { ctx.attr_to_derive_macro_call(src.with_value(&adt), src).map(|(_, it, _)| it) })?; - self.parse_or_expand(call_id.as_file()) + Some(self.parse_or_expand(call_id.as_file())) } fn resolve_derive_macro(&self, attr: &ast::Attr) -> Option>> { @@ -566,7 +574,7 @@ impl<'db> SemanticsImpl<'db> { .into_iter() .flat_map(|call| { let file_id = call?.as_file(); - let node = self.db.parse_or_expand(file_id)?; + let node = self.db.parse_or_expand(file_id); self.cache(node.clone(), file_id); Some(node) }) @@ -609,7 +617,7 @@ impl<'db> SemanticsImpl<'db> { let krate = resolver.krate(); let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| { resolver - .resolve_path_as_macro(self.db.upcast(), &path) + .resolve_path_as_macro(self.db.upcast(), &path, Some(MacroSubNs::Bang)) .map(|it| macro_id_to_def_id(self.db.upcast(), it)) })?; hir_expand::db::expand_speculative( @@ -990,7 +998,7 @@ impl<'db> SemanticsImpl<'db> { } fn diagnostics_display_range(&self, src: InFile) -> FileRange { - let root = self.parse_or_expand(src.file_id).unwrap(); + let root = self.parse_or_expand(src.file_id); let node = src.map(|it| it.to_node(&root)); node.as_ref().original_file_range(self.db.upcast()) } @@ -1065,7 +1073,7 @@ impl<'db> SemanticsImpl<'db> { fn resolve_type(&self, ty: &ast::Type) -> Option { let analyze = self.analyze(ty.syntax())?; - let ctx = body::LowerCtx::new(self.db.upcast(), analyze.file_id); + let ctx = LowerCtx::with_file_id(self.db.upcast(), analyze.file_id); let ty = hir_ty::TyLoweringContext::new(self.db, &analyze.resolver) .lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone())); Some(Type::new_with_resolver(self.db, &analyze.resolver, ty)) @@ -1074,12 +1082,9 @@ impl<'db> SemanticsImpl<'db> { fn resolve_trait(&self, path: &ast::Path) -> Option { let analyze = self.analyze(path.syntax())?; let hygiene = hir_expand::hygiene::Hygiene::new(self.db.upcast(), analyze.file_id); - let ctx = body::LowerCtx::with_hygiene(self.db.upcast(), &hygiene); + let ctx = LowerCtx::with_hygiene(self.db.upcast(), &hygiene); let hir_path = Path::from_src(path.clone(), &ctx)?; - match analyze - .resolver - .resolve_path_in_type_ns_fully(self.db.upcast(), hir_path.mod_path())? - { + match analyze.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), &hir_path)? { TypeNs::TraitId(id) => Some(Trait { id }), _ => None, } @@ -1141,6 +1146,10 @@ impl<'db> SemanticsImpl<'db> { .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced }) } + fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option { + self.analyze(pat.syntax())?.type_of_binding_in_pat(self.db, pat) + } + fn type_of_self(&self, param: &ast::SelfParam) -> Option { self.analyze(param.syntax())?.type_of_self(self.db, param) } @@ -1647,6 +1656,7 @@ impl<'a> SemanticsScope<'a> { VisibleTraits(resolver.traits_in_scope(self.db.upcast())) } + /// Calls the passed closure `f` on all names in scope. pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) { let scope = self.resolver.names_in_scope(self.db.upcast()); for (name, entries) in scope { @@ -1674,7 +1684,7 @@ impl<'a> SemanticsScope<'a> { /// Resolve a path as-if it was written at the given scope. This is /// necessary a heuristic, as it doesn't take hygiene into account. pub fn speculative_resolve(&self, path: &ast::Path) -> Option { - let ctx = body::LowerCtx::new(self.db.upcast(), self.file_id); + let ctx = LowerCtx::with_file_id(self.db.upcast(), self.file_id); let path = Path::from_src(path.clone(), &ctx)?; resolve_hir_path(self.db, &self.resolver, &path) } diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index f6f8c9a250f06..c50ffa4f8b703 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -14,7 +14,7 @@ //! expression, an item definition. //! //! Knowing only the syntax gives us relatively little info. For example, -//! looking at the syntax of the function we can realise that it is a part of an +//! looking at the syntax of the function we can realize that it is a part of an //! `impl` block, but we won't be able to tell what trait function the current //! function overrides, and whether it does that correctly. For that, we need to //! go from [`ast::Fn`] to [`crate::Function`], and that's exactly what this @@ -88,9 +88,11 @@ use base_db::FileId; use hir_def::{ child_by_source::ChildBySource, - dyn_map::DynMap, - expr::{BindingId, LabelId}, - keys::{self, Key}, + dyn_map::{ + keys::{self, Key}, + DynMap, + }, + hir::{BindingId, LabelId}, AdtId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, GenericDefId, GenericParamId, ImplId, LifetimeParamId, MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeParamId, UnionId, VariantId, diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index c24d196e1b624..1374fa332c648 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -5,21 +5,19 @@ //! //! So, this modules should not be used during hir construction, it exists //! purely for "IDE needs". -use std::{ - iter::{self, once}, - sync::Arc, -}; +use std::iter::{self, once}; use either::Either; use hir_def::{ body::{ - self, scope::{ExprScopes, ScopeId}, Body, BodySourceMap, }, - expr::{ExprId, Pat, PatId}, + hir::{BindingId, ExprId, Pat, PatId}, lang_item::LangItem, + lower::LowerCtx, macro_id_to_def_id, + nameres::MacroSubNs, path::{ModPath, Path, PathKind}, resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs}, type_ref::Mutability, @@ -39,7 +37,8 @@ use hir_ty::{ record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions, UnsafeExpr, }, - method_resolution::{self, lang_items_for_bin_op}, + lang_items::lang_items_for_bin_op, + method_resolution::{self}, Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext, }; use itertools::Itertools; @@ -48,6 +47,7 @@ use syntax::{ ast::{self, AstNode}, SyntaxKind, SyntaxNode, TextRange, TextSize, }; +use triomphe::Arc; use crate::{ db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr, @@ -134,13 +134,22 @@ impl SourceAnalyzer { self.body_source_map()?.node_pat(src) } + fn binding_id_of_pat(&self, pat: &ast::IdentPat) -> Option { + let pat_id = self.pat_id(&pat.clone().into())?; + if let Pat::Bind { id, .. } = self.body()?.pats[pat_id] { + Some(id) + } else { + None + } + } + fn expand_expr( &self, db: &dyn HirDatabase, expr: InFile, ) -> Option> { let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?; - let expanded = db.parse_or_expand(macro_file)?; + let expanded = db.parse_or_expand(macro_file); let res = if let Some(stmts) = ast::MacroStmts::cast(expanded.clone()) { match stmts.expr()? { ast::Expr::MacroExpr(mac) => { @@ -199,6 +208,18 @@ impl SourceAnalyzer { Some((mk_ty(ty), coerced.map(mk_ty))) } + pub(crate) fn type_of_binding_in_pat( + &self, + db: &dyn HirDatabase, + pat: &ast::IdentPat, + ) -> Option { + let binding_id = self.binding_id_of_pat(pat)?; + let infer = self.infer.as_ref()?; + let ty = infer[binding_id].clone(); + let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty); + Some(mk_ty(ty)) + } + pub(crate) fn type_of_self( &self, db: &dyn HirDatabase, @@ -215,9 +236,9 @@ impl SourceAnalyzer { _db: &dyn HirDatabase, pat: &ast::IdentPat, ) -> Option { - let pat_id = self.pat_id(&pat.clone().into())?; + let binding_id = self.binding_id_of_pat(pat)?; let infer = self.infer.as_ref()?; - infer.pat_binding_modes.get(&pat_id).map(|bm| match bm { + infer.binding_modes.get(binding_id).map(|bm| match bm { hir_ty::BindingMode::Move => BindingMode::Move, hir_ty::BindingMode::Ref(hir_ty::Mutability::Mut) => BindingMode::Ref(Mutability::Mut), hir_ty::BindingMode::Ref(hir_ty::Mutability::Not) => { @@ -420,7 +441,10 @@ impl SourceAnalyzer { None } else { // Shorthand syntax, resolve to the local - let path = ModPath::from_segments(PathKind::Plain, once(local_name.clone())); + let path = Path::from_known_path_with_no_generic(ModPath::from_segments( + PathKind::Plain, + once(local_name.clone()), + )); match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) { Some(ValueNs::LocalBinding(binding_id)) => { Some(Local { binding_id, parent: self.resolver.body_owner()? }) @@ -459,9 +483,11 @@ impl SourceAnalyzer { db: &dyn HirDatabase, macro_call: InFile<&ast::MacroCall>, ) -> Option { - let ctx = body::LowerCtx::new(db.upcast(), macro_call.file_id); + let ctx = LowerCtx::with_file_id(db.upcast(), macro_call.file_id); let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?; - self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into()) + self.resolver + .resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Bang)) + .map(|it| it.into()) } pub(crate) fn resolve_bind_pat_to_const( @@ -571,7 +597,7 @@ impl SourceAnalyzer { // This must be a normal source file rather than macro file. let hygiene = Hygiene::new(db.upcast(), self.file_id); - let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene); + let ctx = LowerCtx::with_hygiene(db.upcast(), &hygiene); let hir_path = Path::from_src(path.clone(), &ctx)?; // Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are @@ -655,7 +681,7 @@ impl SourceAnalyzer { } } } - return match resolve_hir_path_as_macro(db, &self.resolver, &hir_path) { + return match resolve_hir_path_as_attr_macro(db, &self.resolver, &hir_path) { Some(m) => Some(PathResolution::Def(ModuleDef::Macro(m))), // this labels any path that starts with a tool module as the tool itself, this is technically wrong // but there is no benefit in differentiating these two cases for the time being @@ -733,7 +759,7 @@ impl SourceAnalyzer { let krate = self.resolver.krate(); let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| { self.resolver - .resolve_path_as_macro(db.upcast(), &path) + .resolve_path_as_macro(db.upcast(), &path, Some(MacroSubNs::Bang)) .map(|it| macro_id_to_def_id(db.upcast(), it)) })?; Some(macro_call_id.as_file()).filter(|it| it.expansion_level(db.upcast()) < 64) @@ -801,15 +827,11 @@ impl SourceAnalyzer { func: FunctionId, substs: Substitution, ) -> FunctionId { - let krate = self.resolver.krate(); let owner = match self.resolver.body_owner() { Some(it) => it, None => return func, }; - let env = owner.as_generic_def_id().map_or_else( - || Arc::new(hir_ty::TraitEnvironment::empty(krate)), - |d| db.trait_environment(d), - ); + let env = db.trait_environment_for_body(owner); method_resolution::lookup_impl_method(db, env, func, substs).0 } @@ -819,15 +841,11 @@ impl SourceAnalyzer { const_id: ConstId, subs: Substitution, ) -> ConstId { - let krate = self.resolver.krate(); let owner = match self.resolver.body_owner() { Some(it) => it, None => return const_id, }; - let env = owner.as_generic_def_id().map_or_else( - || Arc::new(hir_ty::TraitEnvironment::empty(krate)), - |d| db.trait_environment(d), - ); + let env = db.trait_environment_for_body(owner); method_resolution::lookup_impl_const(db, env, const_id, subs).0 } @@ -941,12 +959,14 @@ pub(crate) fn resolve_hir_path( } #[inline] -pub(crate) fn resolve_hir_path_as_macro( +pub(crate) fn resolve_hir_path_as_attr_macro( db: &dyn HirDatabase, resolver: &Resolver, path: &Path, ) -> Option { - resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(Into::into) + resolver + .resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Attr)) + .map(Into::into) } fn resolve_hir_path_( @@ -962,8 +982,7 @@ fn resolve_hir_path_( res.map(|ty_ns| (ty_ns, path.segments().first())) } None => { - let (ty, remaining_idx) = - resolver.resolve_path_in_type_ns(db.upcast(), path.mod_path())?; + let (ty, remaining_idx) = resolver.resolve_path_in_type_ns(db.upcast(), path)?; match remaining_idx { Some(remaining_idx) => { if remaining_idx + 1 == path.segments().len() { @@ -1019,7 +1038,7 @@ fn resolve_hir_path_( let body_owner = resolver.body_owner(); let values = || { - resolver.resolve_path_in_value_ns_fully(db.upcast(), path.mod_path()).and_then(|val| { + resolver.resolve_path_in_value_ns_fully(db.upcast(), path).and_then(|val| { let res = match val { ValueNs::LocalBinding(binding_id) => { let var = Local { parent: body_owner?, binding_id }; @@ -1039,14 +1058,14 @@ fn resolve_hir_path_( let items = || { resolver - .resolve_module_path_in_items(db.upcast(), path.mod_path()) + .resolve_module_path_in_items(db.upcast(), path.mod_path()?) .take_types() .map(|it| PathResolution::Def(it.into())) }; let macros = || { resolver - .resolve_path_as_macro(db.upcast(), path.mod_path()) + .resolve_path_as_macro(db.upcast(), path.mod_path()?, None) .map(|def| PathResolution::Def(ModuleDef::Macro(def.into()))) }; @@ -1074,7 +1093,7 @@ fn resolve_hir_path_qualifier( path: &Path, ) -> Option { resolver - .resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()) + .resolve_path_in_type_ns_fully(db.upcast(), &path) .map(|ty| match ty { TypeNs::SelfType(it) => PathResolution::SelfType(it.into()), TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()), @@ -1089,7 +1108,7 @@ fn resolve_hir_path_qualifier( }) .or_else(|| { resolver - .resolve_module_path_in_items(db.upcast(), path.mod_path()) + .resolve_module_path_in_items(db.upcast(), path.mod_path()?) .take_types() .map(|it| PathResolution::Def(it.into())) }) diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs index a9afa1c6f4519..207e8206c92d5 100644 --- a/crates/hir/src/symbols.rs +++ b/crates/hir/src/symbols.rs @@ -2,23 +2,25 @@ use base_db::FileRange; use hir_def::{ - item_tree::ItemTreeNode, src::HasSource, AdtId, AssocItemId, AssocItemLoc, DefWithBodyId, - HasModule, ImplId, ItemContainerId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, + src::HasSource, AdtId, AssocItemId, DefWithBodyId, HasModule, ImplId, Lookup, MacroId, + ModuleDefId, ModuleId, TraitId, }; use hir_expand::{HirFileId, InFile}; use hir_ty::db::HirDatabase; use syntax::{ast::HasName, AstNode, SmolStr, SyntaxNode, SyntaxNodePtr}; -use crate::{Module, Semantics}; +use crate::{Module, ModuleDef, Semantics}; /// The actual data that is stored in the index. It should be as compact as /// possible. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct FileSymbol { + // even though name can be derived from the def, we store it for efficiency pub name: SmolStr, + pub def: ModuleDef, pub loc: DeclarationLocation, - pub kind: FileSymbolKind, pub container_name: Option, + pub is_alias: bool, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -32,18 +34,26 @@ pub struct DeclarationLocation { } impl DeclarationLocation { - pub fn syntax(&self, sema: &Semantics<'_, DB>) -> Option { - let root = sema.parse_or_expand(self.hir_file_id)?; - Some(self.ptr.to_node(&root)) + pub fn syntax(&self, sema: &Semantics<'_, DB>) -> SyntaxNode { + let root = sema.parse_or_expand(self.hir_file_id); + self.ptr.to_node(&root) } - pub fn original_range(&self, db: &dyn HirDatabase) -> Option { - let node = resolve_node(db, self.hir_file_id, &self.ptr)?; - Some(node.as_ref().original_file_range(db.upcast())) + pub fn original_range(&self, db: &dyn HirDatabase) -> FileRange { + if let Some(file_id) = self.hir_file_id.file_id() { + // fast path to prevent parsing + return FileRange { file_id, range: self.ptr.text_range() }; + } + let node = resolve_node(db, self.hir_file_id, &self.ptr); + node.as_ref().original_file_range(db.upcast()) } pub fn original_name_range(&self, db: &dyn HirDatabase) -> Option { - let node = resolve_node(db, self.hir_file_id, &self.name_ptr)?; + if let Some(file_id) = self.hir_file_id.file_id() { + // fast path to prevent parsing + return Some(FileRange { file_id, range: self.name_ptr.text_range() }); + } + let node = resolve_node(db, self.hir_file_id, &self.name_ptr); node.as_ref().original_file_range_opt(db.upcast()) } } @@ -52,38 +62,10 @@ fn resolve_node( db: &dyn HirDatabase, file_id: HirFileId, ptr: &SyntaxNodePtr, -) -> Option> { - let root = db.parse_or_expand(file_id)?; +) -> InFile { + let root = db.parse_or_expand(file_id); let node = ptr.to_node(&root); - Some(InFile::new(file_id, node)) -} - -#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] -pub enum FileSymbolKind { - Const, - Enum, - Function, - Macro, - Module, - Static, - Struct, - Trait, - TraitAlias, - TypeAlias, - Union, -} - -impl FileSymbolKind { - pub fn is_type(self: FileSymbolKind) -> bool { - matches!( - self, - FileSymbolKind::Struct - | FileSymbolKind::Enum - | FileSymbolKind::Trait - | FileSymbolKind::TypeAlias - | FileSymbolKind::Union - ) - } + InFile::new(file_id, node) } /// Represents an outstanding module that the symbol collector must collect symbols from. @@ -102,21 +84,33 @@ pub struct SymbolCollector<'a> { /// Given a [`ModuleId`] and a [`HirDatabase`], use the DefMap for the module's crate to collect /// all symbols that should be indexed for the given module. impl<'a> SymbolCollector<'a> { - pub fn collect(db: &dyn HirDatabase, module: Module) -> Vec { - let mut symbol_collector = SymbolCollector { + pub fn new(db: &'a dyn HirDatabase) -> Self { + SymbolCollector { db, symbols: Default::default(), + work: Default::default(), current_container_name: None, - // The initial work is the root module we're collecting, additional work will - // be populated as we traverse the module's definitions. - work: vec![SymbolCollectorWork { module_id: module.into(), parent: None }], - }; + } + } + + pub fn collect(&mut self, module: Module) { + // The initial work is the root module we're collecting, additional work will + // be populated as we traverse the module's definitions. + self.work.push(SymbolCollectorWork { module_id: module.into(), parent: None }); - while let Some(work) = symbol_collector.work.pop() { - symbol_collector.do_work(work); + while let Some(work) = self.work.pop() { + self.do_work(work); } + } + + pub fn finish(self) -> Vec { + self.symbols + } - symbol_collector.symbols + pub fn collect_module(db: &dyn HirDatabase, module: Module) -> Vec { + let mut symbol_collector = SymbolCollector::new(db); + symbol_collector.collect(module); + symbol_collector.finish() } fn do_work(&mut self, work: SymbolCollectorWork) { @@ -134,36 +128,34 @@ impl<'a> SymbolCollector<'a> { match module_def_id { ModuleDefId::ModuleId(id) => self.push_module(id), ModuleDefId::FunctionId(id) => { - self.push_decl_assoc(id, FileSymbolKind::Function); + self.push_decl(id); self.collect_from_body(id); } - ModuleDefId::AdtId(AdtId::StructId(id)) => { - self.push_decl(id, FileSymbolKind::Struct) - } - ModuleDefId::AdtId(AdtId::EnumId(id)) => self.push_decl(id, FileSymbolKind::Enum), - ModuleDefId::AdtId(AdtId::UnionId(id)) => self.push_decl(id, FileSymbolKind::Union), + ModuleDefId::AdtId(AdtId::StructId(id)) => self.push_decl(id), + ModuleDefId::AdtId(AdtId::EnumId(id)) => self.push_decl(id), + ModuleDefId::AdtId(AdtId::UnionId(id)) => self.push_decl(id), ModuleDefId::ConstId(id) => { - self.push_decl_assoc(id, FileSymbolKind::Const); + self.push_decl(id); self.collect_from_body(id); } ModuleDefId::StaticId(id) => { - self.push_decl_assoc(id, FileSymbolKind::Static); + self.push_decl(id); self.collect_from_body(id); } ModuleDefId::TraitId(id) => { - self.push_decl(id, FileSymbolKind::Trait); + self.push_decl(id); self.collect_from_trait(id); } ModuleDefId::TraitAliasId(id) => { - self.push_decl(id, FileSymbolKind::TraitAlias); + self.push_decl(id); } ModuleDefId::TypeAliasId(id) => { - self.push_decl_assoc(id, FileSymbolKind::TypeAlias); + self.push_decl(id); } ModuleDefId::MacroId(id) => match id { - MacroId::Macro2Id(id) => self.push_decl(id, FileSymbolKind::Macro), - MacroId::MacroRulesId(id) => self.push_decl(id, FileSymbolKind::Macro), - MacroId::ProcMacroId(id) => self.push_decl(id, FileSymbolKind::Macro), + MacroId::Macro2Id(id) => self.push_decl(id), + MacroId::MacroRulesId(id) => self.push_decl(id), + MacroId::ProcMacroId(id) => self.push_decl(id), }, // Don't index these. ModuleDefId::BuiltinType(_) => {} @@ -183,9 +175,9 @@ impl<'a> SymbolCollector<'a> { for &id in id { if id.module(self.db.upcast()) == module_id { match id { - MacroId::Macro2Id(id) => self.push_decl(id, FileSymbolKind::Macro), - MacroId::MacroRulesId(id) => self.push_decl(id, FileSymbolKind::Macro), - MacroId::ProcMacroId(id) => self.push_decl(id, FileSymbolKind::Macro), + MacroId::Macro2Id(id) => self.push_decl(id), + MacroId::MacroRulesId(id) => self.push_decl(id), + MacroId::ProcMacroId(id) => self.push_decl(id), } } } @@ -233,124 +225,94 @@ impl<'a> SymbolCollector<'a> { } } - fn current_container_name(&self) -> Option { - self.current_container_name.clone() - } - fn def_with_body_id_name(&self, body_id: DefWithBodyId) -> Option { match body_id { - DefWithBodyId::FunctionId(id) => Some( - id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(), - ), - DefWithBodyId::StaticId(id) => Some( - id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(), - ), - DefWithBodyId::ConstId(id) => Some( - id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(), - ), - DefWithBodyId::VariantId(id) => Some({ - let db = self.db.upcast(); - id.parent.lookup(db).source(db).value.name()?.text().into() - }), + DefWithBodyId::FunctionId(id) => Some(self.db.function_data(id).name.to_smol_str()), + DefWithBodyId::StaticId(id) => Some(self.db.static_data(id).name.to_smol_str()), + DefWithBodyId::ConstId(id) => Some(self.db.const_data(id).name.as_ref()?.to_smol_str()), + DefWithBodyId::VariantId(id) => { + Some(self.db.enum_data(id.parent).variants[id.local_id].name.to_smol_str()) + } } } fn push_assoc_item(&mut self, assoc_item_id: AssocItemId) { match assoc_item_id { - AssocItemId::FunctionId(id) => self.push_decl_assoc(id, FileSymbolKind::Function), - AssocItemId::ConstId(id) => self.push_decl_assoc(id, FileSymbolKind::Const), - AssocItemId::TypeAliasId(id) => self.push_decl_assoc(id, FileSymbolKind::TypeAlias), + AssocItemId::FunctionId(id) => self.push_decl(id), + AssocItemId::ConstId(id) => self.push_decl(id), + AssocItemId::TypeAliasId(id) => self.push_decl(id), } } - fn push_decl_assoc(&mut self, id: L, kind: FileSymbolKind) + fn push_decl(&mut self, id: L) where - L: Lookup>, - T: ItemTreeNode, - ::Source: HasName, + L: Lookup + Into, + ::Data: HasSource, + <::Data as HasSource>::Value: HasName, { - fn container_name(db: &dyn HirDatabase, container: ItemContainerId) -> Option { - match container { - ItemContainerId::ModuleId(module_id) => { - let module = Module::from(module_id); - module.name(db).and_then(|name| name.as_text()) - } - ItemContainerId::TraitId(trait_id) => { - let trait_data = db.trait_data(trait_id); - trait_data.name.as_text() - } - ItemContainerId::ImplId(_) | ItemContainerId::ExternBlockId(_) => None, + let loc = id.lookup(self.db.upcast()); + let source = loc.source(self.db.upcast()); + let Some(name_node) = source.value.name() else { return }; + let def = ModuleDef::from(id.into()); + let dec_loc = DeclarationLocation { + hir_file_id: source.file_id, + ptr: SyntaxNodePtr::new(source.value.syntax()), + name_ptr: SyntaxNodePtr::new(name_node.syntax()), + }; + + if let Some(attrs) = def.attrs(self.db) { + for alias in attrs.doc_aliases() { + self.symbols.push(FileSymbol { + name: alias, + def, + loc: dec_loc.clone(), + container_name: self.current_container_name.clone(), + is_alias: true, + }); } } - self.push_file_symbol(|s| { - let loc = id.lookup(s.db.upcast()); - let source = loc.source(s.db.upcast()); - let name_node = source.value.name()?; - let container_name = - container_name(s.db, loc.container).or_else(|| s.current_container_name()); - - Some(FileSymbol { - name: name_node.text().into(), - kind, - container_name, - loc: DeclarationLocation { - hir_file_id: source.file_id, - ptr: SyntaxNodePtr::new(source.value.syntax()), - name_ptr: SyntaxNodePtr::new(name_node.syntax()), - }, - }) - }) - } - - fn push_decl(&mut self, id: L, kind: FileSymbolKind) - where - L: Lookup, - ::Data: HasSource, - <::Data as HasSource>::Value: HasName, - { - self.push_file_symbol(|s| { - let loc = id.lookup(s.db.upcast()); - let source = loc.source(s.db.upcast()); - let name_node = source.value.name()?; - - Some(FileSymbol { - name: name_node.text().into(), - kind, - container_name: s.current_container_name(), - loc: DeclarationLocation { - hir_file_id: source.file_id, - ptr: SyntaxNodePtr::new(source.value.syntax()), - name_ptr: SyntaxNodePtr::new(name_node.syntax()), - }, - }) - }) + self.symbols.push(FileSymbol { + name: name_node.text().into(), + def, + container_name: self.current_container_name.clone(), + loc: dec_loc, + is_alias: false, + }); } fn push_module(&mut self, module_id: ModuleId) { - self.push_file_symbol(|s| { - let def_map = module_id.def_map(s.db.upcast()); - let module_data = &def_map[module_id.local_id]; - let declaration = module_data.origin.declaration()?; - let module = declaration.to_node(s.db.upcast()); - let name_node = module.name()?; - - Some(FileSymbol { - name: name_node.text().into(), - kind: FileSymbolKind::Module, - container_name: s.current_container_name(), - loc: DeclarationLocation { - hir_file_id: declaration.file_id, - ptr: SyntaxNodePtr::new(module.syntax()), - name_ptr: SyntaxNodePtr::new(name_node.syntax()), - }, - }) - }) - } + let def_map = module_id.def_map(self.db.upcast()); + let module_data = &def_map[module_id.local_id]; + let Some(declaration) = module_data.origin.declaration() else { return }; + let module = declaration.to_node(self.db.upcast()); + let Some(name_node) = module.name() else { return }; + let dec_loc = DeclarationLocation { + hir_file_id: declaration.file_id, + ptr: SyntaxNodePtr::new(module.syntax()), + name_ptr: SyntaxNodePtr::new(name_node.syntax()), + }; - fn push_file_symbol(&mut self, f: impl FnOnce(&Self) -> Option) { - if let Some(file_symbol) = f(self) { - self.symbols.push(file_symbol); + let def = ModuleDef::Module(module_id.into()); + + if let Some(attrs) = def.attrs(self.db) { + for alias in attrs.doc_aliases() { + self.symbols.push(FileSymbol { + name: alias, + def, + loc: dec_loc.clone(), + container_name: self.current_container_name.clone(), + is_alias: true, + }); + } } + + self.symbols.push(FileSymbol { + name: name_node.text().into(), + def: ModuleDef::Module(module_id.into()), + container_name: self.current_container_name.clone(), + loc: dec_loc, + is_alias: false, + }); } } diff --git a/crates/ide-assists/src/handlers/add_explicit_type.rs b/crates/ide-assists/src/handlers/add_explicit_type.rs index 785ae3d09c6e3..8bc285614e039 100644 --- a/crates/ide-assists/src/handlers/add_explicit_type.rs +++ b/crates/ide-assists/src/handlers/add_explicit_type.rs @@ -69,7 +69,7 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> O return None; } - let inferred_type = ty.display_source_code(ctx.db(), module.into()).ok()?; + let inferred_type = ty.display_source_code(ctx.db(), module.into(), false).ok()?; acc.add( AssistId("add_explicit_type", AssistKind::RefactorRewrite), format!("Insert explicit type `{inferred_type}`"), diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 4e11b31deb02b..6340feda452e1 100644 --- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -184,7 +184,8 @@ fn try_gen_trait_body( trait_ref: hir::TraitRef, impl_def: &ast::Impl, ) -> Option<()> { - let trait_path = make::ext::ident_path(&trait_ref.trait_().name(ctx.db()).to_string()); + let trait_path = + make::ext::ident_path(&trait_ref.trait_().name(ctx.db()).display(ctx.db()).to_string()); let hir_ty = ctx.sema.resolve_type(&impl_def.self_ty()?)?; let adt = hir_ty.as_adt()?.source(ctx.db())?; gen_trait_fn_body(func, &trait_path, &adt.value, Some(trait_ref)) @@ -252,7 +253,7 @@ impl Foo for S { } #[test] - fn test_copied_overriden_members() { + fn test_copied_overridden_members() { check_assist( add_missing_impl_members, r#" @@ -1346,8 +1347,8 @@ struct SomeStruct { } impl PartialEq for SomeStruct { $0fn ne(&self, other: &Self) -> bool { - !self.eq(other) - } + !self.eq(other) + } } "#, ); @@ -1511,11 +1512,175 @@ fn main() { struct S; impl Tr for S { fn method() { - ${0:todo!()} - } + ${0:todo!()} + } } } "#, ); } + + #[test] + fn test_add_missing_preserves_indentation() { + // in different modules + check_assist( + add_missing_impl_members, + r#" +mod m { + pub trait Foo { + const CONST_MULTILINE: ( + i32, + i32 + ); + + fn foo(&self); + } +} +struct S; +impl m::Foo for S { $0 }"#, + r#" +mod m { + pub trait Foo { + const CONST_MULTILINE: ( + i32, + i32 + ); + + fn foo(&self); + } +} +struct S; +impl m::Foo for S { + $0const CONST_MULTILINE: ( + i32, + i32 + ); + + fn foo(&self) { + todo!() + } +}"#, + ); + // in the same module + check_assist( + add_missing_impl_members, + r#" +mod m { + trait Foo { + type Output; + + const CONST: usize = 42; + const CONST_2: i32; + const CONST_MULTILINE: ( + i32, + i32 + ); + + fn foo(&self); + fn bar(&self); + fn baz(&self); + } + + struct S; + + impl Foo for S { + fn bar(&self) {} +$0 + } +}"#, + r#" +mod m { + trait Foo { + type Output; + + const CONST: usize = 42; + const CONST_2: i32; + const CONST_MULTILINE: ( + i32, + i32 + ); + + fn foo(&self); + fn bar(&self); + fn baz(&self); + } + + struct S; + + impl Foo for S { + fn bar(&self) {} + + $0type Output; + + const CONST_2: i32; + + const CONST_MULTILINE: ( + i32, + i32 + ); + + fn foo(&self) { + todo!() + } + + fn baz(&self) { + todo!() + } + + } +}"#, + ); + } + + #[test] + fn test_add_default_preserves_indentation() { + check_assist( + add_missing_default_members, + r#" +mod m { + pub trait Foo { + type Output; + + const CONST: usize = 42; + const CONST_2: i32; + const CONST_MULTILINE: = ( + i32, + i32, + ) = (3, 14); + + fn valid(some: u32) -> bool { false } + fn foo(some: u32) -> bool; + } +} +struct S; +impl m::Foo for S { $0 }"#, + r#" +mod m { + pub trait Foo { + type Output; + + const CONST: usize = 42; + const CONST_2: i32; + const CONST_MULTILINE: = ( + i32, + i32, + ) = (3, 14); + + fn valid(some: u32) -> bool { false } + fn foo(some: u32) -> bool; + } +} +struct S; +impl m::Foo for S { + $0const CONST: usize = 42; + + const CONST_MULTILINE: = ( + i32, + i32, + ) = (3, 14); + + fn valid(some: u32) -> bool { false } +}"#, + ) + } } diff --git a/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 5d81e8cfeacbc..7384390f28b57 100644 --- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -148,7 +148,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) return None; } - let variants_of_enums = vec![variants.clone(); len]; + let variants_of_enums = vec![variants; len]; let missing_pats = variants_of_enums .into_iter() diff --git a/crates/ide-assists/src/handlers/add_return_type.rs b/crates/ide-assists/src/handlers/add_return_type.rs index 879c478acf882..e5f0201bd527e 100644 --- a/crates/ide-assists/src/handlers/add_return_type.rs +++ b/crates/ide-assists/src/handlers/add_return_type.rs @@ -22,7 +22,7 @@ pub(crate) fn add_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt if ty.is_unit() { return None; } - let ty = ty.display_source_code(ctx.db(), module.into()).ok()?; + let ty = ty.display_source_code(ctx.db(), module.into(), true).ok()?; acc.add( AssistId("add_return_type", AssistKind::RefactorRewrite), @@ -34,8 +34,8 @@ pub(crate) fn add_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt |builder| { match builder_edit_pos { InsertOrReplace::Insert(insert_pos, needs_whitespace) => { - let preceeding_whitespace = if needs_whitespace { " " } else { "" }; - builder.insert(insert_pos, format!("{preceeding_whitespace}-> {ty} ")) + let preceding_whitespace = if needs_whitespace { " " } else { "" }; + builder.insert(insert_pos, format!("{preceding_whitespace}-> {ty} ")) } InsertOrReplace::Replace(text_range) => { builder.replace(text_range, format!("-> {ty}")) diff --git a/crates/ide-assists/src/handlers/auto_import.rs b/crates/ide-assists/src/handlers/auto_import.rs index 698ad78cce6ff..7acf2ea0a0de6 100644 --- a/crates/ide-assists/src/handlers/auto_import.rs +++ b/crates/ide-assists/src/handlers/auto_import.rs @@ -132,7 +132,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< acc.add_group( &group_label, AssistId("auto_import", AssistKind::QuickFix), - format!("Import `{import_path}`"), + format!("Import `{}`", import_path.display(ctx.db())), range, |builder| { let scope = match scope.clone() { @@ -203,7 +203,7 @@ fn relevance_score( // get the distance between the imported path and the current module // (prefer items that are more local) Some((item_module, current_module)) => { - score -= module_distance_hueristic(db, current_module, &item_module) as i32; + score -= module_distance_heuristic(db, current_module, &item_module) as i32; } // could not find relevant modules, so just use the length of the path as an estimate @@ -214,7 +214,7 @@ fn relevance_score( } /// A heuristic that gives a higher score to modules that are more separated. -fn module_distance_hueristic(db: &dyn HirDatabase, current: &Module, item: &Module) -> usize { +fn module_distance_heuristic(db: &dyn HirDatabase, current: &Module, item: &Module) -> usize { // get the path starting from the item to the respective crate roots let mut current_path = current.path_to_root(db); let mut item_path = item.path_to_root(db); diff --git a/crates/ide-assists/src/handlers/convert_bool_then.rs b/crates/ide-assists/src/handlers/convert_bool_then.rs index db96ad33047fb..1af52c592183d 100644 --- a/crates/ide-assists/src/handlers/convert_bool_then.rs +++ b/crates/ide-assists/src/handlers/convert_bool_then.rs @@ -160,7 +160,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_> }; // Verify this is `bool::then` that is being called. let func = ctx.sema.resolve_method_call(&mcall)?; - if func.name(ctx.sema.db).to_string() != "then" { + if func.name(ctx.sema.db).display(ctx.db()).to_string() != "then" { return None; } let assoc = func.as_assoc_item(ctx.sema.db)?; diff --git a/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs b/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs index 9e1d9a702a15f..db96c8fe40aa5 100644 --- a/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs +++ b/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs @@ -119,7 +119,7 @@ pub(crate) fn convert_for_loop_with_for_each( { // We have either "for x in &col" and col implements a method called iter // or "for x in &mut col" and col implements a method called iter_mut - format_to!(buf, "{expr_behind_ref}.{method}()"); + format_to!(buf, "{expr_behind_ref}.{}()", method.display(ctx.db())); } else if let ast::Expr::RangeExpr(..) = iterable { // range expressions need to be parenthesized for the syntax to be correct format_to!(buf, "({iterable})"); diff --git a/crates/ide-assists/src/handlers/convert_let_else_to_match.rs b/crates/ide-assists/src/handlers/convert_let_else_to_match.rs index c82a3b5303259..5f7056b9c1c43 100644 --- a/crates/ide-assists/src/handlers/convert_let_else_to_match.rs +++ b/crates/ide-assists/src/handlers/convert_let_else_to_match.rs @@ -5,6 +5,88 @@ use syntax::T; use crate::{AssistContext, AssistId, AssistKind, Assists}; +// Assist: convert_let_else_to_match +// +// Converts let-else statement to let statement and match expression. +// +// ``` +// fn main() { +// let Ok(mut x) = f() else$0 { return }; +// } +// ``` +// -> +// ``` +// fn main() { +// let mut x = match f() { +// Ok(x) => x, +// _ => return, +// }; +// } +// ``` +pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + // should focus on else token to trigger + let let_stmt = ctx + .find_token_syntax_at_offset(T![else]) + .and_then(|it| it.parent()?.parent()) + .or_else(|| ctx.find_token_syntax_at_offset(T![let])?.parent())?; + let let_stmt = LetStmt::cast(let_stmt)?; + let let_else_block = let_stmt.let_else()?.block_expr()?; + let let_init = let_stmt.initializer()?; + if let_stmt.ty().is_some() { + // don't support let with type annotation + return None; + } + let pat = let_stmt.pat()?; + let mut binders = Vec::new(); + binders_in_pat(&mut binders, &pat, &ctx.sema)?; + + let target = let_stmt.syntax().text_range(); + acc.add( + AssistId("convert_let_else_to_match", AssistKind::RefactorRewrite), + "Convert let-else to let and match", + target, + |edit| { + let indent_level = let_stmt.indent_level().0 as usize; + let indent = " ".repeat(indent_level); + let indent1 = " ".repeat(indent_level + 1); + + let binders_str = binders_to_str(&binders, false); + let binders_str_mut = binders_to_str(&binders, true); + + let init_expr = let_init.syntax().text(); + let mut pat_no_mut = pat.syntax().text().to_string(); + // remove the mut from the pattern + for (b, ismut) in binders.iter() { + if *ismut { + pat_no_mut = pat_no_mut.replace(&format!("mut {b}"), &b.to_string()); + } + } + + let only_expr = let_else_block.statements().next().is_none(); + let branch2 = match &let_else_block.tail_expr() { + Some(tail) if only_expr => format!("{tail},"), + _ => let_else_block.syntax().text().to_string(), + }; + let replace = if binders.is_empty() { + format!( + "match {init_expr} {{ +{indent1}{pat_no_mut} => {binders_str} +{indent1}_ => {branch2} +{indent}}}" + ) + } else { + format!( + "let {binders_str_mut} = match {init_expr} {{ +{indent1}{pat_no_mut} => {binders_str}, +{indent1}_ => {branch2} +{indent}}};" + ) + }; + edit.replace(target, replace); + }, + ) +} + /// Gets a list of binders in a pattern, and whether they are mut. fn binders_in_pat( acc: &mut Vec<(Name, bool)>, @@ -97,85 +179,6 @@ fn binders_to_str(binders: &[(Name, bool)], addmut: bool) -> String { } } -// Assist: convert_let_else_to_match -// -// Converts let-else statement to let statement and match expression. -// -// ``` -// fn main() { -// let Ok(mut x) = f() else$0 { return }; -// } -// ``` -// -> -// ``` -// fn main() { -// let mut x = match f() { -// Ok(x) => x, -// _ => return, -// }; -// } -// ``` -pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - // should focus on else token to trigger - let else_token = ctx.find_token_syntax_at_offset(T![else])?; - let let_stmt = LetStmt::cast(else_token.parent()?.parent()?)?; - let let_else_block = let_stmt.let_else()?.block_expr()?; - let let_init = let_stmt.initializer()?; - if let_stmt.ty().is_some() { - // don't support let with type annotation - return None; - } - let pat = let_stmt.pat()?; - let mut binders = Vec::new(); - binders_in_pat(&mut binders, &pat, &ctx.sema)?; - - let target = let_stmt.syntax().text_range(); - acc.add( - AssistId("convert_let_else_to_match", AssistKind::RefactorRewrite), - "Convert let-else to let and match", - target, - |edit| { - let indent_level = let_stmt.indent_level().0 as usize; - let indent = " ".repeat(indent_level); - let indent1 = " ".repeat(indent_level + 1); - - let binders_str = binders_to_str(&binders, false); - let binders_str_mut = binders_to_str(&binders, true); - - let init_expr = let_init.syntax().text(); - let mut pat_no_mut = pat.syntax().text().to_string(); - // remove the mut from the pattern - for (b, ismut) in binders.iter() { - if *ismut { - pat_no_mut = pat_no_mut.replace(&format!("mut {b}"), &b.to_string()); - } - } - - let only_expr = let_else_block.statements().next().is_none(); - let branch2 = match &let_else_block.tail_expr() { - Some(tail) if only_expr => format!("{tail},"), - _ => let_else_block.syntax().text().to_string(), - }; - let replace = if binders.is_empty() { - format!( - "match {init_expr} {{ -{indent1}{pat_no_mut} => {binders_str} -{indent1}_ => {branch2} -{indent}}}" - ) - } else { - format!( - "let {binders_str_mut} = match {init_expr} {{ -{indent1}{pat_no_mut} => {binders_str}, -{indent1}_ => {branch2} -{indent}}};" - ) - }; - edit.replace(target, replace); - }, - ) -} - #[cfg(test)] mod tests { use super::*; diff --git a/crates/ide-assists/src/handlers/convert_match_to_let_else.rs b/crates/ide-assists/src/handlers/convert_match_to_let_else.rs index 7f2c01772baef..fc6236a17558c 100644 --- a/crates/ide-assists/src/handlers/convert_match_to_let_else.rs +++ b/crates/ide-assists/src/handlers/convert_match_to_let_else.rs @@ -16,7 +16,7 @@ use crate::{ // ``` // # //- minicore: option // fn foo(opt: Option<()>) { -// let val = $0match opt { +// let val$0 = match opt { // Some(it) => it, // None => return, // }; @@ -30,7 +30,10 @@ use crate::{ // ``` pub(crate) fn convert_match_to_let_else(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let let_stmt: ast::LetStmt = ctx.find_node_at_offset()?; - let binding = let_stmt.pat()?; + let pat = let_stmt.pat()?; + if ctx.offset() > pat.syntax().text_range().end() { + return None; + } let Some(ast::Expr::MatchExpr(initializer)) = let_stmt.initializer() else { return None }; let initializer_expr = initializer.expr()?; @@ -56,7 +59,7 @@ pub(crate) fn convert_match_to_let_else(acc: &mut Assists, ctx: &AssistContext<' let_stmt.syntax().text_range(), |builder| { let extracting_arm_pat = - rename_variable(&extracting_arm_pat, &extracted_variable_positions, binding); + rename_variable(&extracting_arm_pat, &extracted_variable_positions, pat); builder.replace( let_stmt.syntax().text_range(), format!("let {extracting_arm_pat} = {initializer_expr} else {diverging_arm_expr};"), @@ -161,7 +164,7 @@ mod tests { r#" //- minicore: option fn foo(opt: Option<()>) { - let val = $0match opt { + let val$0 = match opt { Some(it) => it, None => (), }; @@ -211,7 +214,7 @@ fn foo(opt: Option) -> Result { r#" //- minicore: option fn foo(opt: Option) { - let val = $0match opt { + let val$0 = match opt { Some(it) => it + 1, None => return, }; @@ -224,7 +227,7 @@ fn foo(opt: Option) { r#" //- minicore: option fn foo(opt: Option<()>) { - let val = $0match opt { + let val$0 = match opt { Some(it) => { let _ = 1 + 1; it @@ -244,7 +247,7 @@ fn foo(opt: Option<()>) { r#" //- minicore: option fn foo(opt: Option<()>) { - let val = $0match opt { + let val$0 = match opt { Some(it) if 2 > 1 => it, None => return, }; @@ -260,7 +263,7 @@ fn foo(opt: Option<()>) { r#" //- minicore: option fn foo(opt: Option<()>) { - let val = $0match opt { + let val$0 = match opt { Some(it) => it, None => return, }; @@ -281,7 +284,7 @@ fn foo(opt: Option<()>) { r#" //- minicore: option fn foo(opt: Option<()>) { - let ref mut val = $0match opt { + let ref mut val$0 = match opt { Some(it) => it, None => return, }; @@ -302,7 +305,7 @@ fn foo(opt: Option<()>) { r#" //- minicore: option, result fn foo(opt: Option>) { - let val = $0match opt { + let val$0 = match opt { Some(Ok(it)) => it, _ => return, }; @@ -324,7 +327,7 @@ fn foo(opt: Option>) { //- minicore: option fn foo(opt: Option<()>) { loop { - let val = $0match opt { + let val$0 = match opt { Some(it) => it, None => break, }; @@ -346,7 +349,7 @@ fn foo(opt: Option<()>) { //- minicore: option fn foo(opt: Option<()>) { loop { - let val = $0match opt { + let val$0 = match opt { Some(it) => it, None => continue, }; @@ -370,7 +373,7 @@ fn panic() -> ! {} fn foo(opt: Option<()>) { loop { - let val = $0match opt { + let val$0 = match opt { Some(it) => it, None => panic(), }; @@ -401,7 +404,7 @@ struct Point { } fn foo(opt: Option) { - let val = $0match opt { + let val$0 = match opt { Some(Point { x: 0, y }) => y, _ => return, }; @@ -427,7 +430,7 @@ fn foo(opt: Option) { r#" //- minicore: option fn foo(opt: Option) -> Option { - let val = $0match opt { + let val$0 = match opt { it @ Some(42) => it, _ => return None, }; @@ -450,7 +453,7 @@ fn foo(opt: Option) -> Option { r#" //- minicore: option fn f() { - let (x, y) = $0match Some((0, 1)) { + let (x, y)$0 = match Some((0, 1)) { Some(it) => it, None => return, }; @@ -471,7 +474,7 @@ fn f() { r#" //- minicore: option fn f() { - let x = $0match Some(()) { + let x$0 = match Some(()) { Some(it) => it, None => {//comment println!("nope"); diff --git a/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs index 9dc1da2461a34..fe1cb6fce3630 100644 --- a/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs +++ b/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs @@ -1,9 +1,9 @@ use either::Either; -use ide_db::defs::Definition; +use ide_db::{defs::Definition, search::FileReference}; use itertools::Itertools; use syntax::{ ast::{self, AstNode, HasGenericParams, HasVisibility}, - match_ast, SyntaxKind, SyntaxNode, + match_ast, SyntaxKind, }; use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists}; @@ -52,7 +52,11 @@ pub(crate) fn convert_named_struct_to_tuple_struct( acc: &mut Assists, ctx: &AssistContext<'_>, ) -> Option<()> { - let strukt = ctx.find_node_at_offset::>()?; + // XXX: We don't currently provide this assist for struct definitions inside macros, but if we + // are to lift this limitation, don't forget to make `edit_struct_def()` consider macro files + // too. + let name = ctx.find_node_at_offset::()?; + let strukt = name.syntax().parent().and_then(>::cast)?; let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?; let record_fields = match field_list { ast::FieldList::RecordFieldList(it) => it, @@ -62,12 +66,11 @@ pub(crate) fn convert_named_struct_to_tuple_struct( Either::Left(s) => Either::Left(ctx.sema.to_def(s)?), Either::Right(v) => Either::Right(ctx.sema.to_def(v)?), }; - let target = strukt.as_ref().either(|s| s.syntax(), |v| v.syntax()).text_range(); acc.add( AssistId("convert_named_struct_to_tuple_struct", AssistKind::RefactorRewrite), "Convert to tuple struct", - target, + strukt.syntax().text_range(), |edit| { edit_field_references(ctx, edit, record_fields.fields()); edit_struct_references(ctx, edit, strukt_def); @@ -82,6 +85,8 @@ fn edit_struct_def( strukt: &Either, record_fields: ast::RecordFieldList, ) { + // Note that we don't need to consider macro files in this function because this this is + // currently not triggered for struct definitions inside macro calls. let tuple_fields = record_fields .fields() .filter_map(|f| Some(ast::make::tuple_field(f.visibility(), f.ty()?))); @@ -137,50 +142,72 @@ fn edit_struct_references( }; let usages = strukt_def.usages(&ctx.sema).include_self_refs().all(); - let edit_node = |edit: &mut SourceChangeBuilder, node: SyntaxNode| -> Option<()> { - match_ast! { - match node { - ast::RecordPat(record_struct_pat) => { - edit.replace( - record_struct_pat.syntax().text_range(), - ast::make::tuple_struct_pat( - record_struct_pat.path()?, - record_struct_pat - .record_pat_field_list()? - .fields() - .filter_map(|pat| pat.pat()) - ) - .to_string() - ); - }, - ast::RecordExpr(record_expr) => { - let path = record_expr.path()?; - let args = record_expr - .record_expr_field_list()? - .fields() - .filter_map(|f| f.expr()) - .join(", "); - - edit.replace(record_expr.syntax().text_range(), format!("{path}({args})")); - }, - _ => return None, - } - } - Some(()) - }; - for (file_id, refs) in usages { edit.edit_file(file_id); for r in refs { - for node in r.name.syntax().ancestors() { - if edit_node(edit, node).is_some() { - break; - } - } + process_struct_name_reference(ctx, r, edit); } } } +fn process_struct_name_reference( + ctx: &AssistContext<'_>, + r: FileReference, + edit: &mut SourceChangeBuilder, +) -> Option<()> { + // First check if it's the last semgnet of a path that directly belongs to a record + // expression/pattern. + let name_ref = r.name.as_name_ref()?; + let path_segment = name_ref.syntax().parent().and_then(ast::PathSegment::cast)?; + // A `PathSegment` always belongs to a `Path`, so there's at least one `Path` at this point. + let full_path = + path_segment.syntax().parent()?.ancestors().map_while(ast::Path::cast).last().unwrap(); + + if full_path.segment().unwrap().name_ref()? != *name_ref { + // `name_ref` isn't the last segment of the path, so `full_path` doesn't point to the + // struct we want to edit. + return None; + } + + let parent = full_path.syntax().parent()?; + match_ast! { + match parent { + ast::RecordPat(record_struct_pat) => { + // When we failed to get the original range for the whole struct expression node, + // we can't provide any reasonable edit. Leave it untouched. + let file_range = ctx.sema.original_range_opt(record_struct_pat.syntax())?; + edit.replace( + file_range.range, + ast::make::tuple_struct_pat( + record_struct_pat.path()?, + record_struct_pat + .record_pat_field_list()? + .fields() + .filter_map(|pat| pat.pat()) + ) + .to_string() + ); + }, + ast::RecordExpr(record_expr) => { + // When we failed to get the original range for the whole struct pattern node, + // we can't provide any reasonable edit. Leave it untouched. + let file_range = ctx.sema.original_range_opt(record_expr.syntax())?; + let path = record_expr.path()?; + let args = record_expr + .record_expr_field_list()? + .fields() + .filter_map(|f| f.expr()) + .join(", "); + + edit.replace(file_range.range, format!("{path}({args})")); + }, + _ => {} + } + } + + Some(()) +} + fn edit_field_references( ctx: &AssistContext<'_>, edit: &mut SourceChangeBuilder, @@ -199,7 +226,7 @@ fn edit_field_references( if let Some(name_ref) = r.name.as_name_ref() { // Only edit the field reference if it's part of a `.field` access if name_ref.syntax().parent().and_then(ast::FieldExpr::cast).is_some() { - edit.replace(name_ref.syntax().text_range(), index.to_string()); + edit.replace(r.range, index.to_string()); } } } @@ -813,6 +840,141 @@ use crate::{A::Variant, Inner}; fn f() { let a = Variant(Inner); } +"#, + ); + } + + #[test] + fn field_access_inside_macro_call() { + check_assist( + convert_named_struct_to_tuple_struct, + r#" +struct $0Struct { + inner: i32, +} + +macro_rules! id { + ($e:expr) => { $e } +} + +fn test(c: Struct) { + id!(c.inner); +} +"#, + r#" +struct Struct(i32); + +macro_rules! id { + ($e:expr) => { $e } +} + +fn test(c: Struct) { + id!(c.0); +} +"#, + ) + } + + #[test] + fn struct_usage_inside_macro_call() { + check_assist( + convert_named_struct_to_tuple_struct, + r#" +macro_rules! id { + ($($t:tt)*) => { $($t)* } +} + +struct $0Struct { + inner: i32, +} + +fn test() { + id! { + let s = Struct { + inner: 42, + }; + let Struct { inner: value } = s; + let Struct { inner } = s; + } +} +"#, + r#" +macro_rules! id { + ($($t:tt)*) => { $($t)* } +} + +struct Struct(i32); + +fn test() { + id! { + let s = Struct(42); + let Struct(value) = s; + let Struct(inner) = s; + } +} +"#, + ); + } + + #[test] + fn struct_name_ref_may_not_be_part_of_struct_expr_or_struct_pat() { + check_assist( + convert_named_struct_to_tuple_struct, + r#" +struct $0Struct { + inner: i32, +} +struct Outer { + value: T, +} +fn foo() -> T { loop {} } + +fn test() { + Outer { + value: foo::(); + } +} + +trait HasAssoc { + type Assoc; + fn test(); +} +impl HasAssoc for Struct { + type Assoc = Outer; + fn test() { + let a = Self::Assoc { + value: 42, + }; + let Self::Assoc { value } = a; + } +} +"#, + r#" +struct Struct(i32); +struct Outer { + value: T, +} +fn foo() -> T { loop {} } + +fn test() { + Outer { + value: foo::(); + } +} + +trait HasAssoc { + type Assoc; + fn test(); +} +impl HasAssoc for Struct { + type Assoc = Outer; + fn test() { + let a = Self::Assoc { + value: 42, + }; + let Self::Assoc { value } = a; + } +} "#, ); } diff --git a/crates/ide-assists/src/handlers/convert_nested_function_to_closure.rs b/crates/ide-assists/src/handlers/convert_nested_function_to_closure.rs new file mode 100644 index 0000000000000..399f87c8f509d --- /dev/null +++ b/crates/ide-assists/src/handlers/convert_nested_function_to_closure.rs @@ -0,0 +1,209 @@ +use ide_db::assists::{AssistId, AssistKind}; +use syntax::ast::{self, HasGenericParams, HasName}; +use syntax::{AstNode, SyntaxKind}; + +use crate::assist_context::{AssistContext, Assists}; + +// Assist: convert_nested_function_to_closure +// +// Converts a function that is defined within the body of another function into a closure. +// +// ``` +// fn main() { +// fn fo$0o(label: &str, number: u64) { +// println!("{}: {}", label, number); +// } +// +// foo("Bar", 100); +// } +// ``` +// -> +// ``` +// fn main() { +// let foo = |label: &str, number: u64| { +// println!("{}: {}", label, number); +// }; +// +// foo("Bar", 100); +// } +// ``` +pub(crate) fn convert_nested_function_to_closure( + acc: &mut Assists, + ctx: &AssistContext<'_>, +) -> Option<()> { + let name = ctx.find_node_at_offset::()?; + let function = name.syntax().parent().and_then(ast::Fn::cast)?; + + if !is_nested_function(&function) || is_generic(&function) || has_modifiers(&function) { + return None; + } + + let target = function.syntax().text_range(); + let body = function.body()?; + let name = function.name()?; + let param_list = function.param_list()?; + + acc.add( + AssistId("convert_nested_function_to_closure", AssistKind::RefactorRewrite), + "Convert nested function to closure", + target, + |edit| { + let params = ¶m_list.syntax().text().to_string(); + let params = params.strip_prefix("(").unwrap_or(params); + let params = params.strip_suffix(")").unwrap_or(params); + + let mut body = body.to_string(); + if !has_semicolon(&function) { + body.push(';'); + } + edit.replace(target, format!("let {name} = |{params}| {body}")); + }, + ) +} + +/// Returns whether the given function is nested within the body of another function. +fn is_nested_function(function: &ast::Fn) -> bool { + function.syntax().ancestors().skip(1).find_map(ast::Item::cast).map_or(false, |it| { + matches!(it, ast::Item::Fn(_) | ast::Item::Static(_) | ast::Item::Const(_)) + }) +} + +/// Returns whether the given nested function has generic parameters. +fn is_generic(function: &ast::Fn) -> bool { + function.generic_param_list().is_some() +} + +/// Returns whether the given nested function has any modifiers: +/// +/// - `async`, +/// - `const` or +/// - `unsafe` +fn has_modifiers(function: &ast::Fn) -> bool { + function.async_token().is_some() + || function.const_token().is_some() + || function.unsafe_token().is_some() +} + +/// Returns whether the given nested function has a trailing semicolon. +fn has_semicolon(function: &ast::Fn) -> bool { + function + .syntax() + .next_sibling_or_token() + .map(|t| t.kind() == SyntaxKind::SEMICOLON) + .unwrap_or(false) +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::convert_nested_function_to_closure; + + #[test] + fn convert_nested_function_to_closure_works() { + check_assist( + convert_nested_function_to_closure, + r#" +fn main() { + fn $0foo(a: u64, b: u64) -> u64 { + 2 * (a + b) + } + + _ = foo(3, 4); +} + "#, + r#" +fn main() { + let foo = |a: u64, b: u64| { + 2 * (a + b) + }; + + _ = foo(3, 4); +} + "#, + ); + } + + #[test] + fn convert_nested_function_to_closure_works_with_existing_semicolon() { + check_assist( + convert_nested_function_to_closure, + r#" +fn main() { + fn foo$0(a: u64, b: u64) -> u64 { + 2 * (a + b) + }; + + _ = foo(3, 4); +} + "#, + r#" +fn main() { + let foo = |a: u64, b: u64| { + 2 * (a + b) + }; + + _ = foo(3, 4); +} + "#, + ); + } + + #[test] + fn convert_nested_function_to_closure_is_not_suggested_on_top_level_function() { + check_assist_not_applicable( + convert_nested_function_to_closure, + r#" +fn ma$0in() {} + "#, + ); + } + + #[test] + fn convert_nested_function_to_closure_is_not_suggested_when_cursor_off_name() { + check_assist_not_applicable( + convert_nested_function_to_closure, + r#" +fn main() { + fn foo(a: u64, $0b: u64) -> u64 { + 2 * (a + b) + } + + _ = foo(3, 4); +} + "#, + ); + } + + #[test] + fn convert_nested_function_to_closure_is_not_suggested_if_function_has_generic_params() { + check_assist_not_applicable( + convert_nested_function_to_closure, + r#" +fn main() { + fn fo$0o>(s: S) -> String { + s.into() + } + + _ = foo("hello"); +} + "#, + ); + } + + #[test] + fn convert_nested_function_to_closure_is_not_suggested_if_function_has_modifier() { + check_assist_not_applicable( + convert_nested_function_to_closure, + r#" +fn main() { + const fn fo$0o(s: String) -> String { + s + } + + _ = foo("hello"); +} + "#, + ); + } +} diff --git a/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/crates/ide-assists/src/handlers/convert_to_guarded_return.rs index b97be34c5f7e4..dcb96ab8af44f 100644 --- a/crates/ide-assists/src/handlers/convert_to_guarded_return.rs +++ b/crates/ide-assists/src/handlers/convert_to_guarded_return.rs @@ -504,7 +504,7 @@ fn main() { } #[test] - fn ignore_statements_aftert_if() { + fn ignore_statements_after_if() { check_assist_not_applicable( convert_to_guarded_return, r#" diff --git a/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs index 772e032fb2934..017853a4a2023 100644 --- a/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs +++ b/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs @@ -50,7 +50,8 @@ pub(crate) fn convert_tuple_struct_to_named_struct( acc: &mut Assists, ctx: &AssistContext<'_>, ) -> Option<()> { - let strukt = ctx.find_node_at_offset::>()?; + let name = ctx.find_node_at_offset::()?; + let strukt = name.syntax().parent().and_then(>::cast)?; let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?; let tuple_fields = match field_list { ast::FieldList::TupleFieldList(it) => it, diff --git a/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index 31c2ce7c1b54a..ea71d165e6aa6 100644 --- a/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -91,7 +91,7 @@ fn collect_data(ident_pat: IdentPat, ctx: &AssistContext<'_>) -> Option) -> let names_to_import = find_names_to_import(ctx, refs_in_target, imported_defs); let expanded = make::use_tree_list(names_to_import.iter().map(|n| { - let path = make::ext::ident_path(&n.to_string()); + let path = make::ext::ident_path(&n.display(ctx.db()).to_string()); make::use_tree(path, None, None, false) })) .clone_for_update(); diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs index 0b90c9ba34f5f..2a67909e63719 100644 --- a/crates/ide-assists/src/handlers/extract_function.rs +++ b/crates/ide-assists/src/handlers/extract_function.rs @@ -70,6 +70,11 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op } let node = ctx.covering_element(); + if matches!(node.kind(), T!['{'] | T!['}'] | T!['('] | T![')'] | T!['['] | T![']']) { + cov_mark::hit!(extract_function_in_braces_is_not_applicable); + return None; + } + if node.kind() == COMMENT { cov_mark::hit!(extract_function_in_comment_is_not_applicable); return None; @@ -178,7 +183,9 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op fn make_function_name(semantics_scope: &hir::SemanticsScope<'_>) -> ast::NameRef { let mut names_in_scope = vec![]; - semantics_scope.process_all_names(&mut |name, _| names_in_scope.push(name.to_string())); + semantics_scope.process_all_names(&mut |name, _| { + names_in_scope.push(name.display(semantics_scope.db.upcast()).to_string()) + }); let default_name = "fun_name"; @@ -369,7 +376,7 @@ struct OutlivedLocal { /// Container of local variable usages /// -/// Semanticall same as `UsageSearchResult`, but provides more convenient interface +/// Semantically same as `UsageSearchResult`, but provides more convenient interface struct LocalUsages(ide_db::search::UsageSearchResult); impl LocalUsages { @@ -438,7 +445,7 @@ impl Param { } fn to_param(&self, ctx: &AssistContext<'_>, module: hir::Module) -> ast::Param { - let var = self.var.name(ctx.db()).to_string(); + let var = self.var.name(ctx.db()).display(ctx.db()).to_string(); let var_name = make::name(&var); let pat = match self.kind() { ParamKind::MutValue => make::ident_pat(false, true, var_name), @@ -468,7 +475,8 @@ impl TryKind { let name = adt.name(ctx.db()); // FIXME: use lang items to determine if it is std type or user defined // E.g. if user happens to define type named `Option`, we would have false positive - match name.to_string().as_str() { + let name = &name.display(ctx.db()).to_string(); + match name.as_str() { "Option" => Some(TryKind::Option), "Result" => Some(TryKind::Result { ty }), _ => None, @@ -702,7 +710,7 @@ impl FunctionBody { ) -> (FxIndexSet, Option) { let mut self_param = None; let mut res = FxIndexSet::default(); - let mut cb = |name_ref: Option<_>| { + let mut add_name_if_local = |name_ref: Option<_>| { let local_ref = match name_ref.and_then(|name_ref| NameRefClass::classify(sema, &name_ref)) { Some( @@ -726,21 +734,24 @@ impl FunctionBody { }; self.walk_expr(&mut |expr| match expr { ast::Expr::PathExpr(path_expr) => { - cb(path_expr.path().and_then(|it| it.as_single_name_ref())) + add_name_if_local(path_expr.path().and_then(|it| it.as_single_name_ref())) } ast::Expr::ClosureExpr(closure_expr) => { if let Some(body) = closure_expr.body() { - body.syntax().descendants().map(ast::NameRef::cast).for_each(|it| cb(it)); + body.syntax() + .descendants() + .map(ast::NameRef::cast) + .for_each(&mut add_name_if_local); } } ast::Expr::MacroExpr(expr) => { if let Some(tt) = expr.macro_call().and_then(|call| call.token_tree()) { tt.syntax() - .children_with_tokens() - .flat_map(SyntaxElement::into_token) - .filter(|it| it.kind() == SyntaxKind::IDENT) + .descendants_with_tokens() + .filter_map(SyntaxElement::into_token) + .filter(|it| matches!(it.kind(), SyntaxKind::IDENT | T![self])) .flat_map(|t| sema.descend_into_macros(t)) - .for_each(|t| cb(t.parent().and_then(ast::NameRef::cast))); + .for_each(|t| add_name_if_local(t.parent().and_then(ast::NameRef::cast))); } } _ => (), @@ -1286,8 +1297,8 @@ fn find_non_trait_impl(trait_impl: &SyntaxNode) -> Option { let as_impl = ast::Impl::cast(trait_impl.clone())?; let impl_type = Some(impl_type_name(&as_impl)?); - let sibblings = trait_impl.parent()?.children(); - sibblings + let siblings = trait_impl.parent()?.children(); + siblings .filter_map(ast::Impl::cast) .find(|s| impl_type_name(s) == impl_type && !is_trait_impl(s)) } @@ -1333,14 +1344,15 @@ fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> St [var] => { let modifier = mut_modifier(var); let name = var.local.name(ctx.db()); - format_to!(buf, "let {modifier}{name} = ") + format_to!(buf, "let {modifier}{} = ", name.display(ctx.db())) } vars => { buf.push_str("let ("); let bindings = vars.iter().format_with(", ", |local, f| { let modifier = mut_modifier(local); let name = local.local.name(ctx.db()); - f(&format_args!("{modifier}{name}")) + f(&format_args!("{modifier}{}", name.display(ctx.db())))?; + Ok(()) }); format_to!(buf, "{bindings}"); buf.push_str(") = "); @@ -1479,7 +1491,7 @@ impl FlowHandler { } fn path_expr_from_local(ctx: &AssistContext<'_>, var: Local) -> ast::Expr { - let name = var.name(ctx.db()).to_string(); + let name = var.name(ctx.db()).display(ctx.db()).to_string(); make::expr_path(make::ext::ident_path(&name)) } @@ -1879,7 +1891,7 @@ fn with_tail_expr(block: ast::BlockExpr, tail_expr: ast::Expr) -> ast::BlockExpr } fn format_type(ty: &hir::Type, ctx: &AssistContext<'_>, module: hir::Module) -> String { - ty.display_source_code(ctx.db(), module.into()).ok().unwrap_or_else(|| "_".to_string()) + ty.display_source_code(ctx.db(), module.into(), true).ok().unwrap_or_else(|| "_".to_string()) } fn make_ty(ty: &hir::Type, ctx: &AssistContext<'_>, module: hir::Module) -> ast::Type { @@ -4339,6 +4351,82 @@ fn $0fun_name(n: i32) -> i32 { ); } + #[test] + fn param_usage_in_macro_with_nested_tt() { + check_assist( + extract_function, + r#" +macro_rules! m { + ($val:expr) => { $val }; +} + +fn foo() { + let n = 1; + let t = 1; + $0let k = n * m!((n) + { t });$0 + let m = k + 1; +} +"#, + r#" +macro_rules! m { + ($val:expr) => { $val }; +} + +fn foo() { + let n = 1; + let t = 1; + let k = fun_name(n, t); + let m = k + 1; +} + +fn $0fun_name(n: i32, t: i32) -> i32 { + let k = n * m!((n) + { t }); + k +} +"#, + ) + } + + #[test] + fn param_usage_in_macro_with_nested_tt_2() { + check_assist( + extract_function, + r#" +macro_rules! m { + ($val:expr) => { $val }; +} + +struct S(i32); +impl S { + fn foo(&self) { + let n = 1; + $0let k = n * m!((n) + { self.0 });$0 + let m = k + 1; + } +} +"#, + r#" +macro_rules! m { + ($val:expr) => { $val }; +} + +struct S(i32); +impl S { + fn foo(&self) { + let n = 1; + let k = self.fun_name(n); + let m = k + 1; + } + + fn $0fun_name(&self, n: i32) -> i32 { + let k = n * m!((n) + { self.0 }); + k + } +} +"#, + ) + } + #[test] fn extract_with_await() { check_assist( @@ -4640,6 +4728,7 @@ const fn $0fun_name() { check_assist( extract_function, r#" +//- minicore: iterator fn foo() { let mut x = 5; for _ in 0..10 { @@ -4663,6 +4752,7 @@ fn $0fun_name(x: &mut i32) { check_assist( extract_function, r#" +//- minicore: iterator fn foo() { for _ in 0..10 { let mut x = 5; @@ -4686,6 +4776,7 @@ fn $0fun_name(mut x: i32) { check_assist( extract_function, r#" +//- minicore: iterator fn foo() { loop { let mut x = 5; @@ -5387,6 +5478,30 @@ fn $0fun_name(i: T) { ); } + #[test] + fn dont_emit_type_with_hidden_lifetime_parameter() { + // FIXME: We should emit a `` generic argument for the generated function + check_assist( + extract_function, + r#" +struct Struct<'a, T>(&'a T); +fn func(i: Struct<'_, T>) { + $0foo(i);$0 +} +"#, + r#" +struct Struct<'a, T>(&'a T); +fn func(i: Struct<'_, T>) { + fun_name(i); +} + +fn $0fun_name(i: Struct<'_, T>) { + foo(i); +} +"#, + ); + } + #[test] fn preserve_generics_from_body() { check_assist( @@ -5800,4 +5915,40 @@ fn $0fun_name() -> ControlFlow<()> { "#, ); } + + #[test] + fn in_left_curly_is_not_applicable() { + cov_mark::check!(extract_function_in_braces_is_not_applicable); + check_assist_not_applicable(extract_function, r"fn foo() { $0}$0"); + } + + #[test] + fn in_right_curly_is_not_applicable() { + cov_mark::check!(extract_function_in_braces_is_not_applicable); + check_assist_not_applicable(extract_function, r"fn foo() $0{$0 }"); + } + + #[test] + fn in_left_paren_is_not_applicable() { + cov_mark::check!(extract_function_in_braces_is_not_applicable); + check_assist_not_applicable(extract_function, r"fn foo( $0)$0 { }"); + } + + #[test] + fn in_right_paren_is_not_applicable() { + cov_mark::check!(extract_function_in_braces_is_not_applicable); + check_assist_not_applicable(extract_function, r"fn foo $0($0 ) { }"); + } + + #[test] + fn in_left_brack_is_not_applicable() { + cov_mark::check!(extract_function_in_braces_is_not_applicable); + check_assist_not_applicable(extract_function, r"fn foo(arr: &mut [i32$0]$0) {}"); + } + + #[test] + fn in_right_brack_is_not_applicable() { + cov_mark::check!(extract_function_in_braces_is_not_applicable); + check_assist_not_applicable(extract_function, r"fn foo(arr: &mut $0[$0i32]) {}"); + } } diff --git a/crates/ide-assists/src/handlers/extract_module.rs b/crates/ide-assists/src/handlers/extract_module.rs index 0fa7bd558bbfa..de37f5f130fca 100644 --- a/crates/ide-assists/src/handlers/extract_module.rs +++ b/crates/ide-assists/src/handlers/extract_module.rs @@ -357,7 +357,7 @@ impl Module { fn change_visibility(&mut self, record_fields: Vec) { let (mut replacements, record_field_parents, impls) = - get_replacements_for_visibilty_change(&mut self.body_items, false); + get_replacements_for_visibility_change(&mut self.body_items, false); let mut impl_items: Vec = impls .into_iter() @@ -366,7 +366,7 @@ impl Module { .collect(); let (mut impl_item_replacements, _, _) = - get_replacements_for_visibilty_change(&mut impl_items, true); + get_replacements_for_visibility_change(&mut impl_items, true); replacements.append(&mut impl_item_replacements); @@ -824,7 +824,7 @@ fn does_source_exists_outside_sel_in_same_mod( source_exists_outside_sel_in_same_mod } -fn get_replacements_for_visibilty_change( +fn get_replacements_for_visibility_change( items: &mut [ast::Item], is_clone_for_updated: bool, ) -> ( @@ -904,7 +904,7 @@ fn compare_hir_and_ast_module( ) -> Option<()> { let hir_mod_name = hir_module.name(ctx.db())?; let ast_mod_name = ast_module.name()?; - if hir_mod_name.to_string() != ast_mod_name.to_string() { + if hir_mod_name.display(ctx.db()).to_string() != ast_mod_name.to_string() { return None; } @@ -1236,7 +1236,8 @@ mod modname { } #[test] - fn test_extract_module_for_correspoding_adt_of_impl_present_in_same_mod_but_not_in_selection() { + fn test_extract_module_for_corresponding_adt_of_impl_present_in_same_mod_but_not_in_selection() + { check_assist( extract_module, r" diff --git a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index 49debafe1a0ad..e4f64ccc754e0 100644 --- a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -158,7 +158,7 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va ), _ => false, }) - .any(|(name, _)| name.to_string() == variant_name.to_string()) + .any(|(name, _)| name.display(db).to_string() == variant_name.to_string()) } fn extract_generic_params( @@ -1006,7 +1006,7 @@ enum X<'a, 'b, 'x> { } #[test] - fn test_extract_struct_with_liftime_type_const() { + fn test_extract_struct_with_lifetime_type_const() { check_assist( extract_struct_from_enum_variant, r#" diff --git a/crates/ide-assists/src/handlers/extract_variable.rs b/crates/ide-assists/src/handlers/extract_variable.rs index 16356141288d5..014c23197face 100644 --- a/crates/ide-assists/src/handlers/extract_variable.rs +++ b/crates/ide-assists/src/handlers/extract_variable.rs @@ -1,3 +1,4 @@ +use hir::TypeInfo; use stdx::format_to; use syntax::{ ast::{self, AstNode}, @@ -46,21 +47,24 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op .take_while(|it| ctx.selection_trimmed().contains_range(it.text_range())) .find_map(valid_target_expr)?; - if let Some(ty_info) = ctx.sema.type_of_expr(&to_extract) { - if ty_info.adjusted().is_unit() { - return None; - } + let ty = ctx.sema.type_of_expr(&to_extract).map(TypeInfo::adjusted); + if matches!(&ty, Some(ty_info) if ty_info.is_unit()) { + return None; } - let reference_modifier = match get_receiver_type(ctx, &to_extract) { + let parent = to_extract.syntax().parent().and_then(ast::Expr::cast); + let needs_adjust = parent + .as_ref() + .map_or(false, |it| matches!(it, ast::Expr::FieldExpr(_) | ast::Expr::MethodCallExpr(_))); + + let reference_modifier = match ty.filter(|_| needs_adjust) { Some(receiver_type) if receiver_type.is_mutable_reference() => "&mut ", Some(receiver_type) if receiver_type.is_reference() => "&", _ => "", }; - let parent_ref_expr = to_extract.syntax().parent().and_then(ast::RefExpr::cast); - let var_modifier = match parent_ref_expr { - Some(expr) if expr.mut_token().is_some() => "mut ", + let var_modifier = match parent { + Some(ast::Expr::RefExpr(expr)) if expr.mut_token().is_some() => "mut ", _ => "", }; @@ -164,22 +168,6 @@ fn valid_target_expr(node: SyntaxNode) -> Option { } } -fn get_receiver_type(ctx: &AssistContext<'_>, expression: &ast::Expr) -> Option { - let receiver = get_receiver(expression.clone())?; - Some(ctx.sema.type_of_expr(&receiver)?.original()) -} - -/// In the expression `a.b.c.x()`, find `a` -fn get_receiver(expression: ast::Expr) -> Option { - match expression { - ast::Expr::FieldExpr(field) if field.expr().is_some() => { - let nested_expression = &field.expr()?; - get_receiver(nested_expression.to_owned()) - } - _ => Some(expression), - } -} - #[derive(Debug)] enum Anchor { Before(SyntaxNode), @@ -944,6 +932,11 @@ struct S { vec: Vec } +struct Vec; +impl Vec { + fn push(&mut self, _:usize) {} +} + fn foo(s: &mut S) { $0s.vec$0.push(0); }"#, @@ -952,6 +945,11 @@ struct S { vec: Vec } +struct Vec; +impl Vec { + fn push(&mut self, _:usize) {} +} + fn foo(s: &mut S) { let $0vec = &mut s.vec; vec.push(0); @@ -973,6 +971,10 @@ struct X { struct S { vec: Vec } +struct Vec; +impl Vec { + fn push(&mut self, _:usize) {} +} fn foo(f: &mut Y) { $0f.field.field.vec$0.push(0); @@ -987,6 +989,10 @@ struct X { struct S { vec: Vec } +struct Vec; +impl Vec { + fn push(&mut self, _:usize) {} +} fn foo(f: &mut Y) { let $0vec = &mut f.field.field.vec; @@ -1123,7 +1129,7 @@ struct S { } fn foo(s: S) { - let $0x = s.sub; + let $0x = &s.sub; x.do_thing(); }"#, ); @@ -1189,7 +1195,7 @@ impl X { fn foo() { let local = &mut S::new(); - let $0x = &mut local.sub; + let $0x = &local.sub; x.do_thing(); }"#, ); diff --git a/crates/ide-assists/src/handlers/fix_visibility.rs b/crates/ide-assists/src/handlers/fix_visibility.rs index 4c61678eab4f2..d6c59a9c82950 100644 --- a/crates/ide-assists/src/handlers/fix_visibility.rs +++ b/crates/ide-assists/src/handlers/fix_visibility.rs @@ -62,7 +62,9 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>) let assist_label = match target_name { None => format!("Change visibility to {missing_visibility}"), - Some(name) => format!("Change visibility of {name} to {missing_visibility}"), + Some(name) => { + format!("Change visibility of {} to {missing_visibility}", name.display(ctx.db())) + } }; acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |builder| { @@ -117,8 +119,11 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext<'_> let target_file = in_file_source.file_id.original_file(ctx.db()); let target_name = record_field_def.name(ctx.db()); - let assist_label = - format!("Change visibility of {parent_name}.{target_name} to {missing_visibility}"); + let assist_label = format!( + "Change visibility of {}.{} to {missing_visibility}", + parent_name.display(ctx.db()), + target_name.display(ctx.db()) + ); acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |builder| { builder.edit_file(target_file); diff --git a/crates/ide-assists/src/handlers/generate_constant.rs b/crates/ide-assists/src/handlers/generate_constant.rs index ccdfcb0d9e4fd..eccd7675fbaae 100644 --- a/crates/ide-assists/src/handlers/generate_constant.rs +++ b/crates/ide-assists/src/handlers/generate_constant.rs @@ -46,7 +46,8 @@ pub(crate) fn generate_constant(acc: &mut Assists, ctx: &AssistContext<'_>) -> O let ty = ctx.sema.type_of_expr(&expr)?; let scope = ctx.sema.scope(statement.syntax())?; let constant_module = scope.module(); - let type_name = ty.original().display_source_code(ctx.db(), constant_module.into()).ok()?; + let type_name = + ty.original().display_source_code(ctx.db(), constant_module.into(), false).ok()?; let target = statement.syntax().parent()?.text_range(); let path = constant_token.syntax().ancestors().find_map(ast::Path::cast)?; @@ -106,10 +107,10 @@ fn get_text_for_generate_constant( let mut text = format!("{vis}const {constant_token}: {type_name} = $0;"); while let Some(name_ref) = not_exist_name_ref.pop() { let vis = if not_exist_name_ref.len() == 0 && !outer_exists { "" } else { "\npub " }; - text = text.replace("\n", "\n "); + text = text.replace('\n', "\n "); text = format!("{vis}mod {name_ref} {{{text}\n}}"); } - Some(text.replace("\n", &format!("\n{indent}"))) + Some(text.replace('\n', &format!("\n{indent}"))) } fn target_data_for_generate_constant( @@ -131,7 +132,7 @@ fn target_data_for_generate_constant( let siblings_has_newline = l_curly_token .siblings_with_tokens(Direction::Next) - .find(|it| it.kind() == SyntaxKind::WHITESPACE && it.to_string().contains("\n")) + .find(|it| it.kind() == SyntaxKind::WHITESPACE && it.to_string().contains('\n')) .is_some(); let post_string = if siblings_has_newline { format!("{indent}") } else { format!("\n{indent}") }; diff --git a/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/crates/ide-assists/src/handlers/generate_delegate_methods.rs index ed1b8f4e28d30..3667fc375b439 100644 --- a/crates/ide-assists/src/handlers/generate_delegate_methods.rs +++ b/crates/ide-assists/src/handlers/generate_delegate_methods.rs @@ -1,3 +1,5 @@ +use std::collections::HashSet; + use hir::{self, HasCrate, HasSource, HasVisibility}; use syntax::ast::{self, make, AstNode, HasGenericParams, HasName, HasVisibility as _}; @@ -63,25 +65,36 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' }; let sema_field_ty = ctx.sema.resolve_type(&field_ty)?; - let krate = sema_field_ty.krate(ctx.db()); let mut methods = vec![]; - sema_field_ty.iterate_assoc_items(ctx.db(), krate, |item| { - if let hir::AssocItem::Function(f) = item { - if f.self_param(ctx.db()).is_some() && f.is_visible_from(ctx.db(), current_module) { - methods.push(f) + let mut seen_names = HashSet::new(); + + for ty in sema_field_ty.autoderef(ctx.db()) { + let krate = ty.krate(ctx.db()); + ty.iterate_assoc_items(ctx.db(), krate, |item| { + if let hir::AssocItem::Function(f) = item { + if f.self_param(ctx.db()).is_some() + && f.is_visible_from(ctx.db(), current_module) + && seen_names.insert(f.name(ctx.db())) + { + methods.push(f) + } } - } - Option::<()>::None - }); + Option::<()>::None + }); + } for method in methods { let adt = ast::Adt::Struct(strukt.clone()); - let name = method.name(ctx.db()).to_string(); - let impl_def = find_struct_impl(ctx, &adt, &[name]).flatten(); + let name = method.name(ctx.db()).display(ctx.db()).to_string(); + // if `find_struct_impl` returns None, that means that a function named `name` already exists. + let Some(impl_def) = find_struct_impl(ctx, &adt, &[name]) else { continue; }; acc.add_group( &GroupLabel("Generate delegate methods…".to_owned()), AssistId("generate_delegate_methods", AssistKind::Generate), - format!("Generate delegate for `{field_name}.{}()`", method.name(ctx.db())), + format!( + "Generate delegate for `{field_name}.{}()`", + method.name(ctx.db()).display(ctx.db()) + ), target, |builder| { // Create the function @@ -91,7 +104,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' }; let method_name = method.name(ctx.db()); let vis = method_source.visibility(); - let name = make::name(&method.name(ctx.db()).to_string()); + let name = make::name(&method.name(ctx.db()).display(ctx.db()).to_string()); let params = method_source.param_list().unwrap_or_else(|| make::param_list(None, [])); let type_params = method_source.generic_param_list(); @@ -101,17 +114,30 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' }; let tail_expr = make::expr_method_call( make::ext::field_from_idents(["self", &field_name]).unwrap(), // This unwrap is ok because we have at least 1 arg in the list - make::name_ref(&method_name.to_string()), + make::name_ref(&method_name.display(ctx.db()).to_string()), arg_list, ); let ret_type = method_source.ret_type(); let is_async = method_source.async_token().is_some(); + let is_const = method_source.const_token().is_some(); + let is_unsafe = method_source.unsafe_token().is_some(); let tail_expr_finished = if is_async { make::expr_await(tail_expr) } else { tail_expr }; let body = make::block_expr([], Some(tail_expr_finished)); - let f = make::fn_(vis, name, type_params, None, params, body, ret_type, is_async) - .indent(ast::edit::IndentLevel(1)) - .clone_for_update(); + let f = make::fn_( + vis, + name, + type_params, + None, + params, + body, + ret_type, + is_async, + is_const, + is_unsafe, + ) + .indent(ast::edit::IndentLevel(1)) + .clone_for_update(); let cursor = Cursor::Before(f.syntax()); @@ -143,8 +169,16 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' let name = &strukt_name.to_string(); let params = strukt.generic_param_list(); let ty_params = params.clone(); - let impl_def = make::impl_(make::ext::ident_path(name), params, ty_params) - .clone_for_update(); + let where_clause = strukt.where_clause(); + + let impl_def = make::impl_( + ty_params, + None, + make::ty_path(make::ext::ident_path(name)), + where_clause, + None, + ) + .clone_for_update(); let assoc_items = impl_def.get_or_create_assoc_item_list(); assoc_items.add_item(f.clone().into()); @@ -314,6 +348,44 @@ impl Person { ); } + #[test] + fn test_generates_delegate_autoderef() { + check_assist( + generate_delegate_methods, + r#" +//- minicore: deref +struct Age(u8); +impl Age { + fn age(&self) -> u8 { + self.0 + } +} +struct AgeDeref(Age); +impl core::ops::Deref for AgeDeref { type Target = Age; } +struct Person { + ag$0e: AgeDeref, +} +impl Person {}"#, + r#" +struct Age(u8); +impl Age { + fn age(&self) -> u8 { + self.0 + } +} +struct AgeDeref(Age); +impl core::ops::Deref for AgeDeref { type Target = Age; } +struct Person { + age: AgeDeref, +} +impl Person { + $0fn age(&self) -> u8 { + self.age.age() + } +}"#, + ); + } + #[test] fn test_generate_delegate_visibility() { check_assist_not_applicable( @@ -333,4 +405,26 @@ struct Person { }"#, ) } + + #[test] + fn test_generate_not_eligible_if_fn_exists() { + check_assist_not_applicable( + generate_delegate_methods, + r#" +struct Age(u8); +impl Age { + fn age(&self) -> u8 { + self.0 + } +} + +struct Person { + ag$0e: Age, +} +impl Person { + fn age(&self) -> u8 { 0 } +} +"#, + ); + } } diff --git a/crates/ide-assists/src/handlers/generate_deref.rs b/crates/ide-assists/src/handlers/generate_deref.rs index b6958e29193ca..81545396175ba 100644 --- a/crates/ide-assists/src/handlers/generate_deref.rs +++ b/crates/ide-assists/src/handlers/generate_deref.rs @@ -70,6 +70,7 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( target, |edit| { generate_edit( + ctx.db(), edit, strukt, field_type.syntax(), @@ -109,6 +110,7 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<() target, |edit| { generate_edit( + ctx.db(), edit, strukt, field_type.syntax(), @@ -121,6 +123,7 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<() } fn generate_edit( + db: &RootDatabase, edit: &mut SourceChangeBuilder, strukt: ast::Struct, field_type_syntax: &SyntaxNode, @@ -144,7 +147,8 @@ fn generate_edit( ), }; let strukt_adt = ast::Adt::Struct(strukt); - let deref_impl = generate_trait_impl_text(&strukt_adt, &trait_path.to_string(), &impl_code); + let deref_impl = + generate_trait_impl_text(&strukt_adt, &trait_path.display(db).to_string(), &impl_code); edit.insert(start_offset, deref_impl); } diff --git a/crates/ide-assists/src/handlers/generate_derive.rs b/crates/ide-assists/src/handlers/generate_derive.rs index 339245b94eca4..78ac2eb30e591 100644 --- a/crates/ide-assists/src/handlers/generate_derive.rs +++ b/crates/ide-assists/src/handlers/generate_derive.rs @@ -1,5 +1,5 @@ use syntax::{ - ast::{self, AstNode, HasAttrs}, + ast::{self, edit::IndentLevel, AstNode, HasAttrs}, SyntaxKind::{COMMENT, WHITESPACE}, TextSize, }; @@ -42,7 +42,12 @@ pub(crate) fn generate_derive(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt .next(); match derive_attr { None => { - builder.insert_snippet(cap, node_start, "#[derive($0)]\n"); + let indent_level = IndentLevel::from_node(nominal.syntax()); + builder.insert_snippet( + cap, + node_start, + format!("#[derive($0)]\n{indent_level}"), + ); } Some(tt) => { // Just move the cursor. @@ -84,6 +89,20 @@ mod tests { "struct Foo { $0 a: i32, }", "#[derive($0)]\nstruct Foo { a: i32, }", ); + check_assist( + generate_derive, + " +mod m { + struct Foo { a: i32,$0 } +} + ", + " +mod m { + #[derive($0)] + struct Foo { a: i32, } +} + ", + ); } #[test] @@ -111,6 +130,24 @@ struct Foo { a: i32$0, } struct Foo { a: i32, } ", ); + check_assist( + generate_derive, + " +mod m { + /// `Foo` is a pretty important struct. + /// It does stuff. + struct Foo { a: i32,$0 } +} + ", + " +mod m { + /// `Foo` is a pretty important struct. + /// It does stuff. + #[derive($0)] + struct Foo { a: i32, } +} + ", + ); } #[test] diff --git a/crates/ide-assists/src/handlers/generate_documentation_template.rs b/crates/ide-assists/src/handlers/generate_documentation_template.rs index b8415c72a2a32..e87132218ea90 100644 --- a/crates/ide-assists/src/handlers/generate_documentation_template.rs +++ b/crates/ide-assists/src/handlers/generate_documentation_template.rs @@ -324,7 +324,7 @@ fn self_name(ast_func: &ast::Fn) -> Option { self_partial_type(ast_func).map(|name| to_lower_snake_case(&name)) } -/// Heper function to get the name of the type of `self` +/// Helper function to get the name of the type of `self` fn self_type(ast_func: &ast::Fn) -> Option { ast_func.syntax().ancestors().find_map(ast::Impl::cast).and_then(|i| i.self_ty()) } @@ -350,7 +350,7 @@ fn self_type_without_lifetimes(ast_func: &ast::Fn) -> Option { Some(name) } -/// Heper function to get the name of the type of `self` without generic arguments +/// Helper function to get the name of the type of `self` without generic arguments fn self_partial_type(ast_func: &ast::Fn) -> Option { let mut self_type = self_type(ast_func)?.to_string(); if let Some(idx) = self_type.find(|c| ['<', ' '].contains(&c)) { diff --git a/crates/ide-assists/src/handlers/generate_enum_variant.rs b/crates/ide-assists/src/handlers/generate_enum_variant.rs index cd037f7492c66..184f523e01bd9 100644 --- a/crates/ide-assists/src/handlers/generate_enum_variant.rs +++ b/crates/ide-assists/src/handlers/generate_enum_variant.rs @@ -192,7 +192,7 @@ fn expr_ty( scope: &hir::SemanticsScope<'_>, ) -> Option { let ty = ctx.sema.type_of_expr(&arg).map(|it| it.adjusted())?; - let text = ty.display_source_code(ctx.db(), scope.module().into()).ok()?; + let text = ty.display_source_code(ctx.db(), scope.module().into(), false).ok()?; Some(make::ty(&text)) } diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs index 0768389281ca3..850be21c300ca 100644 --- a/crates/ide-assists/src/handlers/generate_function.rs +++ b/crates/ide-assists/src/handlers/generate_function.rs @@ -196,7 +196,7 @@ fn add_func_to_accumulator( let mut func = function_template.to_string(ctx.config.snippet_cap); if let Some(name) = adt_name { // FIXME: adt may have generic params. - func = format!("\n{indent}impl {name} {{\n{func}\n{indent}}}"); + func = format!("\n{indent}impl {} {{\n{func}\n{indent}}}", name.display(ctx.db())); } builder.edit_file(file); match ctx.config.snippet_cap { @@ -378,6 +378,8 @@ impl FunctionBuilder { fn_body, self.ret_type, self.is_async, + false, // FIXME : const and unsafe are not handled yet. + false, ); let leading_ws; let trailing_ws; @@ -438,7 +440,7 @@ fn make_return_type( Some(ty) if ty.is_unit() => (None, false), Some(ty) => { necessary_generic_params.extend(ty.generic_params(ctx.db())); - let rendered = ty.display_source_code(ctx.db(), target_module.into()); + let rendered = ty.display_source_code(ctx.db(), target_module.into(), true); match rendered { Ok(rendered) => (Some(make::ty(&rendered)), false), Err(_) => (Some(make::ty_placeholder()), true), @@ -893,14 +895,14 @@ fn filter_bounds_in_scope( let target_impl = target.parent().ancestors().find_map(ast::Impl::cast)?; let target_impl = ctx.sema.to_def(&target_impl)?; // It's sufficient to test only the first element of `generic_params` because of the order of - // insertion (see `relevant_parmas_and_where_clauses()`). + // insertion (see `params_and_where_preds_in_scope()`). let def = generic_params.first()?.self_ty_param.parent(); if def != hir::GenericDef::Impl(target_impl) { return None; } // Now we know every element that belongs to an impl would be in scope at `target`, we can - // filter them out just by lookint at their parent. + // filter them out just by looking at their parent. generic_params.retain(|it| !matches!(it.self_ty_param.parent(), hir::GenericDef::Impl(_))); where_preds.retain(|it| { it.node.syntax().parent().and_then(|it| it.parent()).and_then(ast::Impl::cast).is_none() @@ -992,9 +994,9 @@ fn fn_arg_type( let famous_defs = &FamousDefs(&ctx.sema, ctx.sema.scope(fn_arg.syntax())?.krate()); convert_reference_type(ty.strip_references(), ctx.db(), famous_defs) .map(|conversion| conversion.convert_type(ctx.db())) - .or_else(|| ty.display_source_code(ctx.db(), target_module.into()).ok()) + .or_else(|| ty.display_source_code(ctx.db(), target_module.into(), true).ok()) } else { - ty.display_source_code(ctx.db(), target_module.into()).ok() + ty.display_source_code(ctx.db(), target_module.into(), true).ok() } } @@ -1087,7 +1089,7 @@ fn calculate_necessary_visibility( } } -// This is never intended to be used as a generic graph strucuture. If there's ever another need of +// This is never intended to be used as a generic graph structure. If there's ever another need of // graph algorithm, consider adding a library for that (and replace the following). /// Minimally implemented directed graph structure represented by adjacency list. struct Graph { @@ -1910,7 +1912,6 @@ fn bar(new: fn) ${0:-> _} { #[test] fn add_function_with_closure_arg() { - // FIXME: The argument in `bar` is wrong. check_assist( generate_function, r" @@ -1925,7 +1926,7 @@ fn foo() { bar(closure) } -fn bar(closure: _) { +fn bar(closure: impl Fn(i64) -> i64) { ${0:todo!()} } ", @@ -2381,7 +2382,7 @@ mod s { } #[test] - fn create_method_with_cursor_anywhere_on_call_expresion() { + fn create_method_with_cursor_anywhere_on_call_expression() { check_assist( generate_function, r" @@ -2488,7 +2489,7 @@ fn foo() {s::S::bar();} } #[test] - fn create_static_method_with_cursor_anywhere_on_call_expresion() { + fn create_static_method_with_cursor_anywhere_on_call_expression() { check_assist( generate_function, r" diff --git a/crates/ide-assists/src/handlers/generate_getter.rs b/crates/ide-assists/src/handlers/generate_getter.rs index 4595cfe29c85d..dd6bbd84afccf 100644 --- a/crates/ide-assists/src/handlers/generate_getter.rs +++ b/crates/ide-assists/src/handlers/generate_getter.rs @@ -174,7 +174,7 @@ pub(crate) fn generate_getter_impl( // this buf inserts a newline at the end of a getter // automatically, if one wants to add one more newline // for separating it from other assoc items, that needs - // to be handled spearately + // to be handled separately let mut getter_buf = generate_getter_from_info(ctx, &getter_info, record_field_info); diff --git a/crates/ide-assists/src/handlers/generate_new.rs b/crates/ide-assists/src/handlers/generate_new.rs index e30a3e942c4cc..824255e4f8e32 100644 --- a/crates/ide-assists/src/handlers/generate_new.rs +++ b/crates/ide-assists/src/handlers/generate_new.rs @@ -98,9 +98,9 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option .fields() .enumerate() .filter_map(|(i, f)| { - let contructor = trivial_constructors[i].clone(); - if contructor.is_some() { - contructor + let constructor = trivial_constructors[i].clone(); + if constructor.is_some() { + constructor } else { Some(f.name()?.to_string()) } diff --git a/crates/ide-assists/src/handlers/inline_macro.rs b/crates/ide-assists/src/handlers/inline_macro.rs index 3fc552306a6ff..5aa8e56f5626c 100644 --- a/crates/ide-assists/src/handlers/inline_macro.rs +++ b/crates/ide-assists/src/handlers/inline_macro.rs @@ -148,7 +148,7 @@ macro_rules! num { #[test] fn inline_macro_simple_not_applicable_broken_macro() { // FIXME: This is a bug. The macro should not expand, but it's - // the same behaviour as the "Expand Macro Recursively" commmand + // the same behaviour as the "Expand Macro Recursively" command // so it's presumably OK for the time being. check_assist( inline_macro, @@ -254,4 +254,49 @@ fn f() { if true{}; } "#, ) } + + #[test] + fn whitespace_between_text_and_pound() { + check_assist( + inline_macro, + r#" +macro_rules! foo { + () => { + cfg_if! { + if #[cfg(test)] { + 1; + } else { + 1; + } + } + } +} +fn main() { + $0foo!(); +} +"#, + r#" +macro_rules! foo { + () => { + cfg_if! { + if #[cfg(test)] { + 1; + } else { + 1; + } + } + } +} +fn main() { + cfg_if!{ + if #[cfg(test)]{ + 1; + }else { + 1; + } +}; +} +"#, + ); + } } diff --git a/crates/ide-assists/src/handlers/introduce_named_generic.rs b/crates/ide-assists/src/handlers/introduce_named_generic.rs index 062c816aef0da..b0d35c02d67ba 100644 --- a/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -1,5 +1,5 @@ use syntax::{ - ast::{self, edit_in_place::GenericParamsOwnerEdit, make, AstNode}, + ast::{self, edit_in_place::GenericParamsOwnerEdit, make, AstNode, HasGenericParams}, ted, }; @@ -14,7 +14,7 @@ use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists}; // ``` // -> // ``` -// fn foo(bar: B) {} +// fn foo<$0B: Bar>(bar: B) {} // ``` pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let impl_trait_type = ctx.find_node_at_offset::()?; @@ -39,7 +39,15 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> let new_ty = make::ty(&type_param_name).clone_for_update(); ted::replace(impl_trait_type.syntax(), new_ty.syntax()); - fn_.get_or_create_generic_param_list().add_generic_param(type_param.into()) + fn_.get_or_create_generic_param_list().add_generic_param(type_param.into()); + + if let Some(cap) = ctx.config.snippet_cap { + if let Some(generic_param) = + fn_.generic_param_list().and_then(|it| it.generic_params().last()) + { + edit.add_tabstop_before(cap, generic_param); + } + } }, ) } @@ -55,7 +63,7 @@ mod tests { check_assist( introduce_named_generic, r#"fn foo(bar: $0impl Bar) {}"#, - r#"fn foo(bar: B) {}"#, + r#"fn foo(bar: B) {}"#, ); } @@ -64,7 +72,7 @@ mod tests { check_assist( introduce_named_generic, r#"fn foo(bar: $0impl Bar) {}"#, - r#"fn foo(bar: B) {}"#, + r#"fn foo<$0B: Bar>(bar: B) {}"#, ); } @@ -73,7 +81,7 @@ mod tests { check_assist( introduce_named_generic, r#"fn foo(foo: impl Foo, bar: $0impl Bar) {}"#, - r#"fn foo(foo: impl Foo, bar: B) {}"#, + r#"fn foo(foo: impl Foo, bar: B) {}"#, ); } @@ -82,7 +90,7 @@ mod tests { check_assist( introduce_named_generic, r#"fn foo<>(bar: $0impl Bar) {}"#, - r#"fn foo(bar: B) {}"#, + r#"fn foo<$0B: Bar>(bar: B) {}"#, ); } @@ -95,7 +103,7 @@ fn foo< >(bar: $0impl Bar) {} "#, r#" -fn foo(bar: B) {} "#, ); @@ -108,7 +116,7 @@ fn foo(bar: $0impl Bar) {}"#, - r#"fn foo(bar: B) {}"#, + r#"fn foo(bar: B) {}"#, ); } @@ -127,7 +135,7 @@ fn foo< fn foo< G: Foo, F, - H, B: Bar, + H, $0B: Bar, >(bar: B) {} "#, ); @@ -138,7 +146,7 @@ fn foo< check_assist( introduce_named_generic, r#"fn foo(bar: $0impl Foo + Bar) {}"#, - r#"fn foo(bar: F) {}"#, + r#"fn foo<$0F: Foo + Bar>(bar: F) {}"#, ); } } diff --git a/crates/ide-assists/src/handlers/introduce_named_lifetime.rs b/crates/ide-assists/src/handlers/introduce_named_lifetime.rs index a54dc4f96de00..c5aa9755bc0b2 100644 --- a/crates/ide-assists/src/handlers/introduce_named_lifetime.rs +++ b/crates/ide-assists/src/handlers/introduce_named_lifetime.rs @@ -66,7 +66,7 @@ fn generate_fn_def_assist( // if we have a self reference, use that Some(NeedsLifetime::SelfParam(self_param)) } else { - // otherwise, if there's a single reference parameter without a named liftime, use that + // otherwise, if there's a single reference parameter without a named lifetime, use that let fn_params_without_lifetime: Vec<_> = param_list .params() .filter_map(|param| match param.ty() { @@ -79,7 +79,7 @@ fn generate_fn_def_assist( match fn_params_without_lifetime.len() { 1 => Some(fn_params_without_lifetime.into_iter().next()?), 0 => None, - // multiple unnnamed is invalid. assist is not applicable + // multiple unnamed is invalid. assist is not applicable _ => return None, } }; diff --git a/crates/ide-assists/src/handlers/merge_match_arms.rs b/crates/ide-assists/src/handlers/merge_match_arms.rs index 641c90885bf53..aae9f20d4ea5c 100644 --- a/crates/ide-assists/src/handlers/merge_match_arms.rs +++ b/crates/ide-assists/src/handlers/merge_match_arms.rs @@ -1,4 +1,4 @@ -use hir::TypeInfo; +use hir::Type; use std::{collections::HashMap, iter::successors}; use syntax::{ algo::neighbor, @@ -95,7 +95,7 @@ fn contains_placeholder(a: &ast::MatchArm) -> bool { } fn are_same_types( - current_arm_types: &HashMap>, + current_arm_types: &HashMap>, arm: &ast::MatchArm, ctx: &AssistContext<'_>, ) -> bool { @@ -103,7 +103,7 @@ fn are_same_types( for (other_arm_type_name, other_arm_type) in arm_types { match (current_arm_types.get(&other_arm_type_name), other_arm_type) { (Some(Some(current_arm_type)), Some(other_arm_type)) - if other_arm_type.original == current_arm_type.original => {} + if other_arm_type == *current_arm_type => {} _ => return false, } } @@ -114,44 +114,44 @@ fn are_same_types( fn get_arm_types( context: &AssistContext<'_>, arm: &ast::MatchArm, -) -> HashMap> { - let mut mapping: HashMap> = HashMap::new(); +) -> HashMap> { + let mut mapping: HashMap> = HashMap::new(); fn recurse( - map: &mut HashMap>, + map: &mut HashMap>, ctx: &AssistContext<'_>, pat: &Option, ) { if let Some(local_pat) = pat { - match pat { - Some(ast::Pat::TupleStructPat(tuple)) => { + match local_pat { + ast::Pat::TupleStructPat(tuple) => { for field in tuple.fields() { recurse(map, ctx, &Some(field)); } } - Some(ast::Pat::TuplePat(tuple)) => { + ast::Pat::TuplePat(tuple) => { for field in tuple.fields() { recurse(map, ctx, &Some(field)); } } - Some(ast::Pat::RecordPat(record)) => { + ast::Pat::RecordPat(record) => { if let Some(field_list) = record.record_pat_field_list() { for field in field_list.fields() { recurse(map, ctx, &field.pat()); } } } - Some(ast::Pat::ParenPat(parentheses)) => { + ast::Pat::ParenPat(parentheses) => { recurse(map, ctx, &parentheses.pat()); } - Some(ast::Pat::SlicePat(slice)) => { + ast::Pat::SlicePat(slice) => { for slice_pat in slice.pats() { recurse(map, ctx, &Some(slice_pat)); } } - Some(ast::Pat::IdentPat(ident_pat)) => { + ast::Pat::IdentPat(ident_pat) => { if let Some(name) = ident_pat.name() { - let pat_type = ctx.sema.type_of_pat(local_pat); + let pat_type = ctx.sema.type_of_binding_in_pat(ident_pat); map.insert(name.text().to_string(), pat_type); } } diff --git a/crates/ide-assists/src/handlers/move_const_to_impl.rs b/crates/ide-assists/src/handlers/move_const_to_impl.rs index d848fce4be821..b6027eac55dee 100644 --- a/crates/ide-assists/src/handlers/move_const_to_impl.rs +++ b/crates/ide-assists/src/handlers/move_const_to_impl.rs @@ -98,7 +98,7 @@ pub(crate) fn move_const_to_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> }; builder.delete(range_to_delete); - let const_ref = format!("Self::{name}"); + let const_ref = format!("Self::{}", name.display(ctx.db())); for range in usages.all().file_ranges().map(|it| it.range) { builder.replace(range, const_ref.clone()); } diff --git a/crates/ide-assists/src/handlers/move_from_mod_rs.rs b/crates/ide-assists/src/handlers/move_from_mod_rs.rs index 1728c03cd03e2..917d0b3671e8e 100644 --- a/crates/ide-assists/src/handlers/move_from_mod_rs.rs +++ b/crates/ide-assists/src/handlers/move_from_mod_rs.rs @@ -39,7 +39,7 @@ pub(crate) fn move_from_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op } let target = source_file.syntax().text_range(); - let module_name = module.name(ctx.db())?.to_string(); + let module_name = module.name(ctx.db())?.display(ctx.db()).to_string(); let path = format!("../{module_name}.rs"); let dst = AnchoredPathBuf { anchor: ctx.file_id(), path }; acc.add( diff --git a/crates/ide-assists/src/handlers/move_module_to_file.rs b/crates/ide-assists/src/handlers/move_module_to_file.rs index a7c605325ea69..166b25c69e188 100644 --- a/crates/ide-assists/src/handlers/move_module_to_file.rs +++ b/crates/ide-assists/src/handlers/move_module_to_file.rs @@ -52,7 +52,7 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext<'_>) -> let mut buf = String::from("./"); match parent_module.name(ctx.db()) { Some(name) if !parent_module.is_mod_rs(ctx.db()) => { - format_to!(buf, "{name}/") + format_to!(buf, "{}/", name.display(ctx.db())) } _ => (), } diff --git a/crates/ide-assists/src/handlers/move_to_mod_rs.rs b/crates/ide-assists/src/handlers/move_to_mod_rs.rs index 076d25411a818..b73270cd05fb5 100644 --- a/crates/ide-assists/src/handlers/move_to_mod_rs.rs +++ b/crates/ide-assists/src/handlers/move_to_mod_rs.rs @@ -39,7 +39,7 @@ pub(crate) fn move_to_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti } let target = source_file.syntax().text_range(); - let module_name = module.name(ctx.db())?.to_string(); + let module_name = module.name(ctx.db())?.display(ctx.db()).to_string(); let path = format!("./{module_name}/mod.rs"); let dst = AnchoredPathBuf { anchor: ctx.file_id(), path }; acc.add( diff --git a/crates/ide-assists/src/handlers/promote_local_to_const.rs b/crates/ide-assists/src/handlers/promote_local_to_const.rs index cbbea6c1e6373..23153b4c566c8 100644 --- a/crates/ide-assists/src/handlers/promote_local_to_const.rs +++ b/crates/ide-assists/src/handlers/promote_local_to_const.rs @@ -57,11 +57,13 @@ pub(crate) fn promote_local_to_const(acc: &mut Assists, ctx: &AssistContext<'_>) let local = ctx.sema.to_def(&pat)?; let ty = ctx.sema.type_of_pat(&pat.into())?.original; - if ty.contains_unknown() || ty.is_closure() { - cov_mark::hit!(promote_lcoal_not_applicable_if_ty_not_inferred); - return None; - } - let ty = ty.display_source_code(ctx.db(), module.into()).ok()?; + let ty = match ty.display_source_code(ctx.db(), module.into(), false) { + Ok(ty) => ty, + Err(_) => { + cov_mark::hit!(promote_local_not_applicable_if_ty_not_inferred); + return None; + } + }; let initializer = let_stmt.initializer()?; if !is_body_const(&ctx.sema, &initializer) { @@ -187,7 +189,7 @@ fn foo() { #[test] fn not_applicable_unknown_ty() { - cov_mark::check!(promote_lcoal_not_applicable_if_ty_not_inferred); + cov_mark::check!(promote_local_not_applicable_if_ty_not_inferred); check_assist_not_applicable( promote_local_to_const, r" diff --git a/crates/ide-assists/src/handlers/pull_assignment_up.rs b/crates/ide-assists/src/handlers/pull_assignment_up.rs index 4cfe6c99b23c2..a5c7fea403d31 100644 --- a/crates/ide-assists/src/handlers/pull_assignment_up.rs +++ b/crates/ide-assists/src/handlers/pull_assignment_up.rs @@ -386,7 +386,7 @@ fn foo() { } #[test] - fn pull_assignment_up_if_missing_assigment_not_applicable() { + fn pull_assignment_up_if_missing_assignment_not_applicable() { check_assist_not_applicable( pull_assignment_up, r#" @@ -401,7 +401,7 @@ fn foo() { } #[test] - fn pull_assignment_up_match_missing_assigment_not_applicable() { + fn pull_assignment_up_match_missing_assignment_not_applicable() { check_assist_not_applicable( pull_assignment_up, r#" diff --git a/crates/ide-assists/src/handlers/qualify_method_call.rs b/crates/ide-assists/src/handlers/qualify_method_call.rs index e7014597a1d8b..4bf974a5655af 100644 --- a/crates/ide-assists/src/handlers/qualify_method_call.rs +++ b/crates/ide-assists/src/handlers/qualify_method_call.rs @@ -507,7 +507,7 @@ fn main() { } #[test] - fn struct_method_over_stuct_instance() { + fn struct_method_over_struct_instance() { check_assist_not_applicable( qualify_method_call, r#" @@ -525,7 +525,7 @@ fn main() { } #[test] - fn trait_method_over_stuct_instance() { + fn trait_method_over_struct_instance() { check_assist_not_applicable( qualify_method_call, r#" diff --git a/crates/ide-assists/src/handlers/qualify_path.rs b/crates/ide-assists/src/handlers/qualify_path.rs index e759e1561cbd0..239149dc411d6 100644 --- a/crates/ide-assists/src/handlers/qualify_path.rs +++ b/crates/ide-assists/src/handlers/qualify_path.rs @@ -86,7 +86,7 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option acc.add_group( &group_label, AssistId("qualify_path", AssistKind::QuickFix), - label(candidate, &import), + label(ctx.db(), candidate, &import), range, |builder| { qualify_candidate.qualify( @@ -186,7 +186,7 @@ fn find_trait_method( if let Some(hir::AssocItem::Function(method)) = trait_.items(db).into_iter().find(|item: &hir::AssocItem| { item.name(db) - .map(|name| name.to_string() == trait_method_name.to_string()) + .map(|name| name.display(db).to_string() == trait_method_name.to_string()) .unwrap_or(false) }) { @@ -216,14 +216,14 @@ fn group_label(candidate: &ImportCandidate) -> GroupLabel { GroupLabel(format!("Qualify {name}")) } -fn label(candidate: &ImportCandidate, import: &LocatedImport) -> String { +fn label(db: &RootDatabase, candidate: &ImportCandidate, import: &LocatedImport) -> String { let import_path = &import.import_path; match candidate { ImportCandidate::Path(candidate) if candidate.qualifier.is_none() => { - format!("Qualify as `{import_path}`") + format!("Qualify as `{}`", import_path.display(db)) } - _ => format!("Qualify with `{import_path}`"), + _ => format!("Qualify with `{}`", import_path.display(db)), } } diff --git a/crates/ide-assists/src/handlers/raw_string.rs b/crates/ide-assists/src/handlers/raw_string.rs index 01420430bb419..40ee4771d1707 100644 --- a/crates/ide-assists/src/handlers/raw_string.rs +++ b/crates/ide-assists/src/handlers/raw_string.rs @@ -20,6 +20,7 @@ use crate::{utils::required_hashes, AssistContext, AssistId, AssistKind, Assists // } // ``` pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + // FIXME: This should support byte and c strings as well. let token = ctx.find_token_at_offset::()?; if token.is_raw() { return None; diff --git a/crates/ide-assists/src/handlers/remove_parentheses.rs b/crates/ide-assists/src/handlers/remove_parentheses.rs index e9c7c6bae9cee..ffc32f8049968 100644 --- a/crates/ide-assists/src/handlers/remove_parentheses.rs +++ b/crates/ide-assists/src/handlers/remove_parentheses.rs @@ -124,7 +124,7 @@ mod tests { } #[test] - fn remove_parens_doesnt_apply_weird_syntax_and_adge_cases() { + fn remove_parens_doesnt_apply_weird_syntax_and_edge_cases() { // removing `()` would break code because {} would be counted as the loop/if body check_assist_not_applicable(remove_parentheses, r#"fn f() { for _ in $0(0..{3}) {} }"#); check_assist_not_applicable(remove_parentheses, r#"fn f() { for _ in $0(S {}) {} }"#); diff --git a/crates/ide-assists/src/handlers/remove_unused_param.rs b/crates/ide-assists/src/handlers/remove_unused_param.rs index bd2e8fbe38966..0772b168d49c8 100644 --- a/crates/ide-assists/src/handlers/remove_unused_param.rs +++ b/crates/ide-assists/src/handlers/remove_unused_param.rs @@ -232,7 +232,7 @@ fn b() { foo( ) } } #[test] - fn remove_unused_surrounded_by_parms() { + fn remove_unused_surrounded_by_params() { check_assist( remove_unused_param, r#" diff --git a/crates/ide-assists/src/handlers/reorder_fields.rs b/crates/ide-assists/src/handlers/reorder_fields.rs index 58dcaf9a221d8..0256256697740 100644 --- a/crates/ide-assists/src/handlers/reorder_fields.rs +++ b/crates/ide-assists/src/handlers/reorder_fields.rs @@ -20,9 +20,10 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // const test: Foo = Foo {foo: 1, bar: 0} // ``` pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let record = ctx.find_node_at_offset::>()?; + let path = ctx.find_node_at_offset::()?; + let record = + path.syntax().parent().and_then(>::cast)?; - let path = record.as_ref().either(|it| it.path(), |it| it.path())?; let ranks = compute_fields_ranks(&path, ctx)?; let get_rank_of_field = |of: Option<_>| *ranks.get(&of.unwrap_or_default()).unwrap_or(&usize::MAX); @@ -96,7 +97,7 @@ fn compute_fields_ranks( .fields(ctx.db()) .into_iter() .enumerate() - .map(|(idx, field)| (field.name(ctx.db()).to_string(), idx)) + .map(|(idx, field)| (field.name(ctx.db()).display(ctx.db()).to_string(), idx)) .collect(); Some(res) diff --git a/crates/ide-assists/src/handlers/reorder_impl_items.rs b/crates/ide-assists/src/handlers/reorder_impl_items.rs index 208c3e109ddec..66669662316fe 100644 --- a/crates/ide-assists/src/handlers/reorder_impl_items.rs +++ b/crates/ide-assists/src/handlers/reorder_impl_items.rs @@ -21,7 +21,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // } // // struct Bar; -// $0impl Foo for Bar { +// $0impl Foo for Bar$0 { // const B: u8 = 17; // fn c() {} // type A = String; @@ -45,6 +45,16 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; pub(crate) fn reorder_impl_items(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let impl_ast = ctx.find_node_at_offset::()?; let items = impl_ast.assoc_item_list()?; + + // restrict the range + // if cursor is in assoc_items, abort + let assoc_range = items.syntax().text_range(); + let cursor_position = ctx.offset(); + if assoc_range.contains_inclusive(cursor_position) { + cov_mark::hit!(not_applicable_editing_assoc_items); + return None; + } + let assoc_items = items.assoc_items().collect::>(); let path = impl_ast @@ -104,7 +114,7 @@ fn compute_item_ranks( .iter() .flat_map(|i| i.name(ctx.db())) .enumerate() - .map(|(idx, name)| (name.to_string(), idx)) + .map(|(idx, name)| (name.display(ctx.db()).to_string(), idx)) .collect(), ) } @@ -264,9 +274,9 @@ trait Bar { } struct Foo; -impl Bar for Foo { +$0impl Bar for Foo { type Fooo = (); - type Foo = ();$0 + type Foo = (); }"#, r#" trait Bar { @@ -281,4 +291,29 @@ impl Bar for Foo { }"#, ) } + + #[test] + fn not_applicable_editing_assoc_items() { + cov_mark::check!(not_applicable_editing_assoc_items); + check_assist_not_applicable( + reorder_impl_items, + r#" +trait Bar { + type T; + const C: (); + fn a() {} + fn z() {} + fn b() {} +} +struct Foo; +impl Bar for Foo { + type T = ();$0 + const C: () = (); + fn z() {} + fn a() {} + fn b() {} +} + "#, + ) + } } diff --git a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index 4cfae0c7212c2..36ac8c71d8154 100644 --- a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -59,7 +59,7 @@ pub(crate) fn replace_derive_with_manual_impl( // collect the derive paths from the #[derive] expansion let current_derives = ctx .sema - .parse_or_expand(hir_file)? + .parse_or_expand(hir_file) .descendants() .filter_map(ast::Attr::cast) .filter_map(|attr| attr.path()) diff --git a/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs b/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs new file mode 100644 index 0000000000000..e7b62d49bb814 --- /dev/null +++ b/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs @@ -0,0 +1,351 @@ +use hir::Semantics; +use ide_db::{ + base_db::{FileId, FileRange}, + defs::Definition, + search::{SearchScope, UsageSearchResult}, + RootDatabase, +}; +use syntax::{ + ast::{ + self, make::impl_trait_type, HasGenericParams, HasName, HasTypeBounds, Name, NameLike, + PathType, + }, + match_ast, ted, AstNode, +}; +use text_edit::TextRange; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +// Assist: replace_named_generic_with_impl +// +// Replaces named generic with an `impl Trait` in function argument. +// +// ``` +// fn new>(location: P) -> Self {} +// ``` +// -> +// ``` +// fn new(location: impl AsRef) -> Self {} +// ``` +pub(crate) fn replace_named_generic_with_impl( + acc: &mut Assists, + ctx: &AssistContext<'_>, +) -> Option<()> { + // finds `>` + let type_param = ctx.find_node_at_offset::()?; + // returns `P` + let type_param_name = type_param.name()?; + + // The list of type bounds / traits: `AsRef` + let type_bound_list = type_param.type_bound_list()?; + + let fn_ = type_param.syntax().ancestors().find_map(ast::Fn::cast)?; + let param_list_text_range = fn_.param_list()?.syntax().text_range(); + + let type_param_hir_def = ctx.sema.to_def(&type_param)?; + let type_param_def = Definition::GenericParam(hir::GenericParam::TypeParam(type_param_hir_def)); + + // get all usage references for the type param + let usage_refs = find_usages(&ctx.sema, &fn_, type_param_def, ctx.file_id()); + if usage_refs.is_empty() { + return None; + } + + // All usage references need to be valid (inside the function param list) + if !check_valid_usages(&usage_refs, param_list_text_range) { + return None; + } + + let mut path_types_to_replace = Vec::new(); + for (_a, refs) in usage_refs.iter() { + for usage_ref in refs { + let param_node = find_path_type(&ctx.sema, &type_param_name, &usage_ref.name)?; + path_types_to_replace.push(param_node); + } + } + + let target = type_param.syntax().text_range(); + + acc.add( + AssistId("replace_named_generic_with_impl", AssistKind::RefactorRewrite), + "Replace named generic with impl trait", + target, + |edit| { + let type_param = edit.make_mut(type_param); + let fn_ = edit.make_mut(fn_); + + let path_types_to_replace = path_types_to_replace + .into_iter() + .map(|param| edit.make_mut(param)) + .collect::>(); + + // remove trait from generic param list + if let Some(generic_params) = fn_.generic_param_list() { + generic_params.remove_generic_param(ast::GenericParam::TypeParam(type_param)); + if generic_params.generic_params().count() == 0 { + ted::remove(generic_params.syntax()); + } + } + + let new_bounds = impl_trait_type(type_bound_list); + for path_type in path_types_to_replace.iter().rev() { + ted::replace(path_type.syntax(), new_bounds.clone_for_update().syntax()); + } + }, + ) +} + +fn find_path_type( + sema: &Semantics<'_, RootDatabase>, + type_param_name: &Name, + param: &NameLike, +) -> Option { + let path_type = + sema.ancestors_with_macros(param.syntax().clone()).find_map(ast::PathType::cast)?; + + // Ignore any path types that look like `P::Assoc` + if path_type.path()?.as_single_name_ref()?.text() != type_param_name.text() { + return None; + } + + let ancestors = sema.ancestors_with_macros(path_type.syntax().clone()); + + let mut in_generic_arg_list = false; + let mut is_associated_type = false; + + // walking the ancestors checks them in a heuristic way until the `Fn` node is reached. + for ancestor in ancestors { + match_ast! { + match ancestor { + ast::PathSegment(ps) => { + match ps.kind()? { + ast::PathSegmentKind::Name(_name_ref) => (), + ast::PathSegmentKind::Type { .. } => return None, + _ => return None, + } + }, + ast::GenericArgList(_) => { + in_generic_arg_list = true; + }, + ast::AssocTypeArg(_) => { + is_associated_type = true; + }, + ast::ImplTraitType(_) => { + if in_generic_arg_list && !is_associated_type { + return None; + } + }, + ast::DynTraitType(_) => { + if !is_associated_type { + return None; + } + }, + ast::Fn(_) => return Some(path_type), + _ => (), + } + } + } + + None +} + +/// Returns all usage references for the given type parameter definition. +fn find_usages( + sema: &Semantics<'_, RootDatabase>, + fn_: &ast::Fn, + type_param_def: Definition, + file_id: FileId, +) -> UsageSearchResult { + let file_range = FileRange { file_id, range: fn_.syntax().text_range() }; + type_param_def.usages(sema).in_scope(SearchScope::file_range(file_range)).all() +} + +fn check_valid_usages(usages: &UsageSearchResult, param_list_range: TextRange) -> bool { + usages + .iter() + .flat_map(|(_, usage_refs)| usage_refs) + .all(|usage_ref| param_list_range.contains_range(usage_ref.range)) +} + +#[cfg(test)] +mod tests { + use super::*; + + use crate::tests::{check_assist, check_assist_not_applicable}; + + #[test] + fn replace_generic_moves_into_function() { + check_assist( + replace_named_generic_with_impl, + r#"fn new(input: T) -> Self {}"#, + r#"fn new(input: impl ToString) -> Self {}"#, + ); + } + + #[test] + fn replace_generic_with_inner_associated_type() { + check_assist( + replace_named_generic_with_impl, + r#"fn new>(input: P) -> Self {}"#, + r#"fn new(input: impl AsRef) -> Self {}"#, + ); + } + + #[test] + fn replace_generic_trait_applies_to_all_matching_params() { + check_assist( + replace_named_generic_with_impl, + r#"fn new(a: T, b: T) -> Self {}"#, + r#"fn new(a: impl ToString, b: impl ToString) -> Self {}"#, + ); + } + + #[test] + fn replace_generic_trait_applies_to_generic_arguments_in_params() { + check_assist( + replace_named_generic_with_impl, + r#" + fn foo( + _: P, + _: Option

, + _: Option>, + _: impl Iterator, + _: &dyn Iterator, + ) {} + "#, + r#" + fn foo( + _: impl Trait, + _: Option, + _: Option>, + _: impl Iterator, + _: &dyn Iterator, + ) {} + "#, + ); + } + + #[test] + fn replace_generic_not_applicable_when_one_param_type_is_invalid() { + check_assist_not_applicable( + replace_named_generic_with_impl, + r#" + fn foo( + _: i32, + _: Option

, + _: Option>, + _: impl Iterator, + _: &dyn Iterator, + _:

::Assoc, + ) {} + "#, + ); + } + + #[test] + fn replace_generic_not_applicable_when_referenced_in_where_clause() { + check_assist_not_applicable( + replace_named_generic_with_impl, + r#"fn foo() where I: FromRef

{}"#, + ); + } + + #[test] + fn replace_generic_not_applicable_when_used_with_type_alias() { + check_assist_not_applicable( + replace_named_generic_with_impl, + r#"fn foo(p:

::Assoc) {}"#, + ); + } + + #[test] + fn replace_generic_not_applicable_when_used_as_argument_in_outer_trait_alias() { + check_assist_not_applicable( + replace_named_generic_with_impl, + r#"fn foo(_: <() as OtherTrait

>::Assoc) {}"#, + ); + } + + #[test] + fn replace_generic_not_applicable_with_inner_associated_type() { + check_assist_not_applicable( + replace_named_generic_with_impl, + r#"fn foo(_: P::Assoc) {}"#, + ); + } + + #[test] + fn replace_generic_not_applicable_when_passed_into_outer_impl_trait() { + check_assist_not_applicable( + replace_named_generic_with_impl, + r#"fn foo(_: impl OtherTrait

) {}"#, + ); + } + + #[test] + fn replace_generic_not_applicable_when_used_in_passed_function_parameter() { + check_assist_not_applicable( + replace_named_generic_with_impl, + r#"fn foo(_: &dyn Fn(P)) {}"#, + ); + } + + #[test] + fn replace_generic_with_multiple_generic_params() { + check_assist( + replace_named_generic_with_impl, + r#"fn new, T$0: ToString>(t: T, p: P) -> Self {}"#, + r#"fn new>(t: impl ToString, p: P) -> Self {}"#, + ); + check_assist( + replace_named_generic_with_impl, + r#"fn new>(t: T, p: P) -> Self {}"#, + r#"fn new>(t: impl ToString, p: P) -> Self {}"#, + ); + check_assist( + replace_named_generic_with_impl, + r#"fn new(a: A, b: B, c: C) -> Self {}"#, + r#"fn new(a: A, b: impl ToString, c: C) -> Self {}"#, + ); + } + + #[test] + fn replace_generic_with_multiple_trait_bounds() { + check_assist( + replace_named_generic_with_impl, + r#"fn new(p: P) -> Self {}"#, + r#"fn new(p: impl Send + Sync) -> Self {}"#, + ); + } + + #[test] + fn replace_generic_not_applicable_if_param_used_as_return_type() { + check_assist_not_applicable( + replace_named_generic_with_impl, + r#"fn new(p: P) -> P {}"#, + ); + } + + #[test] + fn replace_generic_not_applicable_if_param_used_in_fn_body() { + check_assist_not_applicable( + replace_named_generic_with_impl, + r#"fn new(p: P) { let x: &dyn P = &O; }"#, + ); + } + + #[test] + fn replace_generic_ignores_another_function_with_same_param_type() { + check_assist( + replace_named_generic_with_impl, + r#" + fn new(p: P) {} + fn hello(p: P) { println!("{:?}", p); } + "#, + r#" + fn new(p: impl Send + Sync) {} + fn hello(p: P) { println!("{:?}", p); } + "#, + ); + } +} diff --git a/crates/ide-assists/src/handlers/replace_string_with_char.rs b/crates/ide-assists/src/handlers/replace_string_with_char.rs index decb5fb62a772..6310981ccce7a 100644 --- a/crates/ide-assists/src/handlers/replace_string_with_char.rs +++ b/crates/ide-assists/src/handlers/replace_string_with_char.rs @@ -31,14 +31,14 @@ pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext<'_ if value.chars().take(2).count() != 1 { return None; } - let quote_offets = token.quote_offsets()?; + let quote_offsets = token.quote_offsets()?; acc.add( AssistId("replace_string_with_char", AssistKind::RefactorRewrite), "Replace string with char", target, |edit| { - let (left, right) = quote_offets.quotes; + let (left, right) = quote_offsets.quotes; edit.replace(left, '\''); edit.replace(right, '\''); if value == "'" { diff --git a/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs b/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs index 38fccb33829a3..2e26f59d030ff 100644 --- a/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs +++ b/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs @@ -20,7 +20,7 @@ use crate::assist_context::{AssistContext, Assists}; // Replaces a `try` expression with a `match` expression. // // ``` -// # //- minicore:option +// # //- minicore: try, option // fn handle() { // let pat = Some(true)$0?; // } @@ -111,7 +111,7 @@ mod tests { check_assist( replace_try_expr_with_match, r#" -//- minicore:option +//- minicore: try, option fn test() { let pat = Some(true)$0?; } @@ -132,7 +132,7 @@ fn test() { check_assist( replace_try_expr_with_match, r#" -//- minicore:result +//- minicore: try, from, result fn test() { let pat = Ok(true)$0?; } diff --git a/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs b/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs index 6626ce0795997..43a97d7d3a551 100644 --- a/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs +++ b/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs @@ -55,7 +55,7 @@ pub(crate) fn replace_turbofish_with_explicit_type( let returned_type = match ctx.sema.type_of_expr(&initializer) { Some(returned_type) if !returned_type.original.contains_unknown() => { let module = ctx.sema.scope(let_stmt.syntax())?.module(); - returned_type.original.display_source_code(ctx.db(), module.into()).ok()? + returned_type.original.display_source_code(ctx.db(), module.into(), false).ok()? } _ => { cov_mark::hit!(fallback_to_turbofish_type_if_type_info_not_available); diff --git a/crates/ide-assists/src/handlers/sort_items.rs b/crates/ide-assists/src/handlers/sort_items.rs index a93704b39474b..3a0121f55fa02 100644 --- a/crates/ide-assists/src/handlers/sort_items.rs +++ b/crates/ide-assists/src/handlers/sort_items.rs @@ -87,11 +87,7 @@ pub(crate) fn sort_items(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( return None; } - if let Some(trait_ast) = ctx.find_node_at_offset::() { - add_sort_methods_assist(acc, trait_ast.assoc_item_list()?) - } else if let Some(impl_ast) = ctx.find_node_at_offset::() { - add_sort_methods_assist(acc, impl_ast.assoc_item_list()?) - } else if let Some(struct_ast) = ctx.find_node_at_offset::() { + if let Some(struct_ast) = ctx.find_node_at_offset::() { add_sort_field_list_assist(acc, struct_ast.field_list()) } else if let Some(union_ast) = ctx.find_node_at_offset::() { add_sort_fields_assist(acc, union_ast.record_field_list()?) @@ -103,6 +99,10 @@ pub(crate) fn sort_items(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( add_sort_fields_assist(acc, enum_struct_variant_ast) } else if let Some(enum_ast) = ctx.find_node_at_offset::() { add_sort_variants_assist(acc, enum_ast.variant_list()?) + } else if let Some(trait_ast) = ctx.find_node_at_offset::() { + add_sort_methods_assist(acc, ctx, trait_ast.assoc_item_list()?) + } else if let Some(impl_ast) = ctx.find_node_at_offset::() { + add_sort_methods_assist(acc, ctx, impl_ast.assoc_item_list()?) } else { None } @@ -116,9 +116,11 @@ trait AddRewrite { new: Vec, target: TextRange, ) -> Option<()>; + fn yeet() {} } impl AddRewrite for Assists { + fn yeet() {} fn add_rewrite( &mut self, label: &str, @@ -146,7 +148,19 @@ fn add_sort_field_list_assist(acc: &mut Assists, field_list: Option Option<()> { +fn add_sort_methods_assist( + acc: &mut Assists, + ctx: &AssistContext<'_>, + item_list: ast::AssocItemList, +) -> Option<()> { + let selection = ctx.selection_trimmed(); + + // ignore assist if the selection intersects with an associated item. + if item_list.assoc_items().any(|item| item.syntax().text_range().intersect(selection).is_some()) + { + return None; + } + let methods = get_methods(&item_list); let sorted = sort_by_name(&methods); @@ -216,6 +230,51 @@ mod tests { use super::*; + #[test] + fn not_applicable_if_selection_in_fn_body() { + check_assist_not_applicable( + sort_items, + r#" +struct S; +impl S { + fn func2() { + $0 bar $0 + } + fn func() {} +} + "#, + ) + } + + #[test] + fn not_applicable_if_selection_at_associated_const() { + check_assist_not_applicable( + sort_items, + r#" +struct S; +impl S { + fn func2() {} + fn func() {} + const C: () = $0()$0; +} + "#, + ) + } + + #[test] + fn not_applicable_if_selection_overlaps_nodes() { + check_assist_not_applicable( + sort_items, + r#" +struct S; +impl $0S { + fn$0 func2() {} + fn func() {} +} + "#, + ) + } + #[test] fn not_applicable_if_no_selection() { cov_mark::check!(not_applicable_if_no_selection); @@ -231,6 +290,21 @@ t$0rait Bar { ) } + #[test] + fn not_applicable_if_selection_in_trait_fn_body() { + check_assist_not_applicable( + sort_items, + r#" +trait Bar { + fn b() { + $0 hello $0 + } + fn a(); +} + "#, + ) + } + #[test] fn not_applicable_if_trait_empty() { cov_mark::check!(not_applicable_if_sorted_or_empty_or_single); @@ -458,6 +532,31 @@ struct Bar { ) } + #[test] + fn sort_struct_inside_a_function() { + check_assist( + sort_items, + r#" +fn hello() { + $0struct Bar$0 { + b: u8, + a: u32, + c: u64, + } +} + "#, + r#" +fn hello() { + struct Bar { + a: u32, + b: u8, + c: u64, + } +} + "#, + ) + } + #[test] fn sort_generic_struct_with_lifetime() { check_assist( diff --git a/crates/ide-assists/src/handlers/unwrap_block.rs b/crates/ide-assists/src/handlers/unwrap_block.rs index 33b19a354b9aa..939055f148c45 100644 --- a/crates/ide-assists/src/handlers/unwrap_block.rs +++ b/crates/ide-assists/src/handlers/unwrap_block.rs @@ -51,15 +51,11 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option let replaced = match list.syntax().last_child() { Some(last) => { let stmts: Vec = list.statements().collect(); - let initializer = ast::Expr::cast(last.clone())?; + let initializer = ast::Expr::cast(last)?; let let_stmt = make::let_stmt(pattern, ty, Some(initializer)); if stmts.len() > 0 { let block = make::block_expr(stmts, None); - format!( - "{}\n {}", - update_expr_string(block.to_string()), - let_stmt.to_string() - ) + format!("{}\n {}", update_expr_string(block.to_string()), let_stmt) } else { let_stmt.to_string() } diff --git a/crates/ide-assists/src/handlers/unwrap_result_return_type.rs b/crates/ide-assists/src/handlers/unwrap_result_return_type.rs index 9ef4ae047ef0e..26f3c192617e1 100644 --- a/crates/ide-assists/src/handlers/unwrap_result_return_type.rs +++ b/crates/ide-assists/src/handlers/unwrap_result_return_type.rs @@ -5,7 +5,7 @@ use ide_db::{ use itertools::Itertools; use syntax::{ ast::{self, Expr}, - match_ast, AstNode, TextRange, TextSize, + match_ast, AstNode, NodeOrToken, SyntaxKind, TextRange, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -38,14 +38,15 @@ pub(crate) fn unwrap_result_return_type(acc: &mut Assists, ctx: &AssistContext<' }; let type_ref = &ret_type.ty()?; - let ty = ctx.sema.resolve_type(type_ref)?.as_adt(); + let Some(hir::Adt::Enum(ret_enum)) = ctx.sema.resolve_type(type_ref)?.as_adt() else { return None; }; let result_enum = FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate()).core_result_Result()?; - - if !matches!(ty, Some(hir::Adt::Enum(ret_type)) if ret_type == result_enum) { + if ret_enum != result_enum { return None; } + let Some(ok_type) = unwrap_result_type(type_ref) else { return None; }; + acc.add( AssistId("unwrap_result_return_type", AssistKind::RefactorRewrite), "Unwrap Result return type", @@ -64,26 +65,19 @@ pub(crate) fn unwrap_result_return_type(acc: &mut Assists, ctx: &AssistContext<' }); for_each_tail_expr(&body, tail_cb); - let mut is_unit_type = false; - if let Some((_, inner_type)) = type_ref.to_string().split_once('<') { - let inner_type = match inner_type.split_once(',') { - Some((success_inner_type, _)) => success_inner_type, - None => inner_type, - }; - let new_ret_type = inner_type.strip_suffix('>').unwrap_or(inner_type); - if new_ret_type == "()" { - is_unit_type = true; - let text_range = TextRange::new( - ret_type.syntax().text_range().start(), - ret_type.syntax().text_range().end() + TextSize::from(1u32), - ); - builder.delete(text_range) - } else { - builder.replace( - type_ref.syntax().text_range(), - inner_type.strip_suffix('>').unwrap_or(inner_type), - ) + let is_unit_type = is_unit_type(&ok_type); + if is_unit_type { + let mut text_range = ret_type.syntax().text_range(); + + if let Some(NodeOrToken::Token(token)) = ret_type.syntax().next_sibling_or_token() { + if token.kind() == SyntaxKind::WHITESPACE { + text_range = TextRange::new(text_range.start(), token.text_range().end()); + } } + + builder.delete(text_range); + } else { + builder.replace(type_ref.syntax().text_range(), ok_type.syntax().text()); } for ret_expr_arg in exprs_to_unwrap { @@ -134,6 +128,22 @@ fn tail_cb_impl(acc: &mut Vec, e: &ast::Expr) { } } +// Tries to extract `T` from `Result`. +fn unwrap_result_type(ty: &ast::Type) -> Option { + let ast::Type::PathType(path_ty) = ty else { return None; }; + let path = path_ty.path()?; + let segment = path.first_segment()?; + let generic_arg_list = segment.generic_arg_list()?; + let generic_args: Vec<_> = generic_arg_list.generic_args().collect(); + let ast::GenericArg::TypeArg(ok_type) = generic_args.first()? else { return None; }; + ok_type.ty() +} + +fn is_unit_type(ty: &ast::Type) -> bool { + let ast::Type::TupleType(tuple) = ty else { return false }; + tuple.fields().next().is_none() +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -173,6 +183,21 @@ fn foo() -> Result<(), Box> { r#" fn foo() { } +"#, + ); + + // Unformatted return type + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> Result<(), Box>{ + Ok(()) +} +"#, + r#" +fn foo() { +} "#, ); } @@ -1014,6 +1039,54 @@ fn foo(the_field: u32) -> u32 { } the_field } +"#, + ); + } + + #[test] + fn unwrap_result_return_type_nested_type() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result, option +fn foo() -> Result, ()> { + Ok(Some(42)) +} +"#, + r#" +fn foo() -> Option { + Some(42) +} +"#, + ); + + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result, option +fn foo() -> Result>, ()> { + Ok(None) +} +"#, + r#" +fn foo() -> Option> { + None +} +"#, + ); + + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result, option, iterators +fn foo() -> Result$0, ()> { + Ok(Some(42).into_iter()) +} +"#, + r#" +fn foo() -> impl Iterator { + Some(42).into_iter() +} "#, ); } diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index 8b07e29a5879f..bd282e5343409 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -122,6 +122,7 @@ mod handlers { mod convert_iter_for_each_to_for; mod convert_let_else_to_match; mod convert_match_to_let_else; + mod convert_nested_function_to_closure; mod convert_tuple_struct_to_named_struct; mod convert_named_struct_to_tuple_struct; mod convert_to_guarded_return; @@ -192,6 +193,7 @@ mod handlers { mod replace_arith_op; mod introduce_named_generic; mod replace_let_with_if_let; + mod replace_named_generic_with_impl; mod replace_qualified_name_with_use; mod replace_string_with_char; mod replace_turbofish_with_explicit_type; @@ -228,8 +230,9 @@ mod handlers { convert_iter_for_each_to_for::convert_iter_for_each_to_for, convert_iter_for_each_to_for::convert_for_loop_with_for_each, convert_let_else_to_match::convert_let_else_to_match, - convert_named_struct_to_tuple_struct::convert_named_struct_to_tuple_struct, convert_match_to_let_else::convert_match_to_let_else, + convert_named_struct_to_tuple_struct::convert_named_struct_to_tuple_struct, + convert_nested_function_to_closure::convert_nested_function_to_closure, convert_to_guarded_return::convert_to_guarded_return, convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct, convert_two_arm_bool_match_to_matches_macro::convert_two_arm_bool_match_to_matches_macro, @@ -297,6 +300,7 @@ mod handlers { replace_let_with_if_let::replace_let_with_if_let, replace_method_eager_lazy::replace_with_eager_method, replace_method_eager_lazy::replace_with_lazy_method, + replace_named_generic_with_impl::replace_named_generic_with_impl, replace_turbofish_with_explicit_type::replace_turbofish_with_explicit_type, replace_qualified_name_with_use::replace_qualified_name_with_use, replace_arith_op::replace_arith_with_wrapping, diff --git a/crates/ide-assists/src/tests.rs b/crates/ide-assists/src/tests.rs index 94be99fd7abf8..344f2bfcce14a 100644 --- a/crates/ide-assists/src/tests.rs +++ b/crates/ide-assists/src/tests.rs @@ -3,7 +3,7 @@ mod generated; mod sourcegen; use expect_test::expect; -use hir::{db::DefDatabase, Semantics}; +use hir::Semantics; use ide_db::{ base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}, imports::insert_use::{ImportGranularity, InsertUseConfig}, @@ -161,7 +161,7 @@ fn check_with_config( assist_label: Option<&str>, ) { let (mut db, file_with_caret_id, range_or_offset) = RootDatabase::with_range_or_offset(before); - db.set_enable_proc_attr_macros(true); + db.enable_proc_attr_macros(); let text_without_caret = db.file_text(file_with_caret_id).to_string(); let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() }; @@ -273,8 +273,9 @@ fn assist_order_field_struct() { assert_eq!(assists.next().expect("expected assist").label, "Generate a getter method"); assert_eq!(assists.next().expect("expected assist").label, "Generate a mut getter method"); assert_eq!(assists.next().expect("expected assist").label, "Generate a setter method"); - assert_eq!(assists.next().expect("expected assist").label, "Convert to tuple struct"); assert_eq!(assists.next().expect("expected assist").label, "Add `#[derive]`"); + assert_eq!(assists.next().expect("expected assist").label, "Generate `new`"); + assert_eq!(assists.next().map(|it| it.label.to_string()), None); } #[test] diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index e5a8d675a9ead..8a35fd290e686 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -439,7 +439,7 @@ fn doctest_convert_match_to_let_else() { r#####" //- minicore: option fn foo(opt: Option<()>) { - let val = $0match opt { + let val$0 = match opt { Some(it) => it, None => return, }; @@ -494,6 +494,31 @@ impl Point { ) } +#[test] +fn doctest_convert_nested_function_to_closure() { + check_doc_test( + "convert_nested_function_to_closure", + r#####" +fn main() { + fn fo$0o(label: &str, number: u64) { + println!("{}: {}", label, number); + } + + foo("Bar", 100); +} +"#####, + r#####" +fn main() { + let foo = |label: &str, number: u64| { + println!("{}: {}", label, number); + }; + + foo("Bar", 100); +} +"#####, + ) +} + #[test] fn doctest_convert_to_guarded_return() { check_doc_test( @@ -1596,7 +1621,7 @@ fn doctest_introduce_named_generic() { fn foo(bar: $0impl Bar) {} "#####, r#####" -fn foo(bar: B) {} +fn foo<$0B: Bar>(bar: B) {} "#####, ) } @@ -2116,7 +2141,7 @@ trait Foo { } struct Bar; -$0impl Foo for Bar { +$0impl Foo for Bar$0 { const B: u8 = 17; fn c() {} type A = String; @@ -2313,6 +2338,19 @@ fn handle(action: Action) { ) } +#[test] +fn doctest_replace_named_generic_with_impl() { + check_doc_test( + "replace_named_generic_with_impl", + r#####" +fn new>(location: P) -> Self {} +"#####, + r#####" +fn new(location: impl AsRef) -> Self {} +"#####, + ) +} + #[test] fn doctest_replace_qualified_name_with_use() { check_doc_test( @@ -2352,7 +2390,7 @@ fn doctest_replace_try_expr_with_match() { check_doc_test( "replace_try_expr_with_match", r#####" -//- minicore:option +//- minicore: try, option fn handle() { let pat = Some(true)$0?; } diff --git a/crates/ide-assists/src/tests/sourcegen.rs b/crates/ide-assists/src/tests/sourcegen.rs index b4f50c7fb26a4..3da90e9052f2f 100644 --- a/crates/ide-assists/src/tests/sourcegen.rs +++ b/crates/ide-assists/src/tests/sourcegen.rs @@ -90,8 +90,6 @@ impl Assist { let comment_blocks = sourcegen::CommentBlock::extract("Assist", &text); for block in comment_blocks { - // FIXME: doesn't support blank lines yet, need to tweak - // `extract_comment_blocks` for that. let id = block.id; assert!( id.chars().all(|it| it.is_ascii_lowercase() || it == '_'), diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs index f323ebcf7a3bd..8f7ea26306c42 100644 --- a/crates/ide-assists/src/utils.rs +++ b/crates/ide-assists/src/utils.rs @@ -9,8 +9,8 @@ use stdx::format_to; use syntax::{ ast::{ self, - edit::{self, AstNodeEdit}, - edit_in_place::{AttrsOwnerEdit, Removable}, + edit::{AstNodeEdit, IndentLevel}, + edit_in_place::{AttrsOwnerEdit, Indent, Removable}, make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace, }, ted, AstNode, AstToken, Direction, SourceFile, @@ -139,9 +139,11 @@ pub fn add_trait_assoc_items_to_impl( let transform = PathTransform::trait_impl(&target_scope, &source_scope, trait_, impl_.clone()); + let new_indent_level = IndentLevel::from_node(impl_.syntax()) + 1; let items = items.into_iter().map(|assoc_item| { transform.apply(assoc_item.syntax()); assoc_item.remove_attrs_and_docs(); + assoc_item.reindent_to(new_indent_level); assoc_item }); @@ -153,8 +155,10 @@ pub fn add_trait_assoc_items_to_impl( first_item.get_or_insert_with(|| item.clone()); match &item { ast::AssocItem::Fn(fn_) if fn_.body().is_none() => { - let body = make::block_expr(None, Some(make::ext::expr_todo())) - .indent(edit::IndentLevel(1)); + let body = AstNodeEdit::indent( + &make::block_expr(None, Some(make::ext::expr_todo())), + new_indent_level, + ); ted::replace(fn_.get_or_create_body().syntax(), body.clone_for_update().syntax()) } ast::AssocItem::TypeAlias(type_alias) => { @@ -338,7 +342,12 @@ fn calc_depth(pat: &ast::Pat, depth: usize) -> usize { /// `find_struct_impl` looks for impl of a struct, but this also has additional feature /// where it takes a list of function names and check if they exist inside impl_, if -/// even one match is found, it returns None +/// even one match is found, it returns None. +/// +/// That means this function can have 3 potential return values: +/// - `None`: an impl exists, but one of the function names within the impl matches one of the provided names. +/// - `Some(None)`: no impl exists. +/// - `Some(Some(_))`: an impl exists, with no matching function names. pub(crate) fn find_struct_impl( ctx: &AssistContext<'_>, adt: &ast::Adt, diff --git a/crates/ide-assists/src/utils/suggest_name.rs b/crates/ide-assists/src/utils/suggest_name.rs index c521a10fccfc3..f74ebfae02c77 100644 --- a/crates/ide-assists/src/utils/suggest_name.rs +++ b/crates/ide-assists/src/utils/suggest_name.rs @@ -234,7 +234,7 @@ fn from_type(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option Option { let name = if let Some(adt) = ty.as_adt() { - let name = adt.name(db).to_string(); + let name = adt.name(db).display(db).to_string(); if WRAPPER_TYPES.contains(&name.as_str()) { let inner_ty = ty.type_arguments().next()?; @@ -258,7 +258,7 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase) -> Option { } fn trait_name(trait_: &hir::Trait, db: &RootDatabase) -> Option { - let name = trait_.name(db).to_string(); + let name = trait_.name(db).display(db).to_string(); if USELESS_TRAITS.contains(&name.as_str()) { return None; } diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs index c3136f6df4b39..480cb77b4fd6a 100644 --- a/crates/ide-completion/src/completions.rs +++ b/crates/ide-completion/src/completions.rs @@ -23,8 +23,8 @@ pub(crate) mod env_vars; use std::iter; -use hir::{known, ScopeDef, Variant}; -use ide_db::{imports::import_assets::LocatedImport, SymbolKind}; +use hir::{known, HasAttrs, ScopeDef, Variant}; +use ide_db::{imports::import_assets::LocatedImport, RootDatabase, SymbolKind}; use syntax::ast; use crate::{ @@ -62,8 +62,8 @@ impl From for Vec { impl Builder { /// Convenience method, which allows to add a freshly created completion into accumulator /// without binding it to the variable. - pub(crate) fn add_to(self, acc: &mut Completions) { - acc.add(self.build()) + pub(crate) fn add_to(self, acc: &mut Completions, db: &RootDatabase) { + acc.add(self.build(db)) } } @@ -78,17 +78,9 @@ impl Completions { } } - pub(crate) fn add_all(&mut self, items: I) - where - I: IntoIterator, - I::Item: Into, - { - items.into_iter().for_each(|item| self.add(item.into())) - } - pub(crate) fn add_keyword(&mut self, ctx: &CompletionContext<'_>, keyword: &'static str) { let item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), keyword); - item.add_to(self); + item.add_to(self, ctx.db); } pub(crate) fn add_nameref_keywords_with_colon(&mut self, ctx: &CompletionContext<'_>) { @@ -142,7 +134,7 @@ impl Completions { item.insert_text(if snippet.contains('$') { kw } else { snippet }); } }; - item.add_to(self); + item.add_to(self, ctx.db); } pub(crate) fn add_keyword_snippet( @@ -157,7 +149,7 @@ impl Completions { Some(cap) => item.insert_snippet(cap, snippet), None => item.insert_text(if snippet.contains('$') { kw } else { snippet }), }; - item.add_to(self); + item.add_to(self, ctx.db); } pub(crate) fn add_crate_roots( @@ -165,9 +157,9 @@ impl Completions { ctx: &CompletionContext<'_>, path_ctx: &PathCompletionCtx, ) { - ctx.process_all_names(&mut |name, res| match res { - ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => { - self.add_module(ctx, path_ctx, m, name); + ctx.process_all_names(&mut |name, res, doc_aliases| match res { + ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root() => { + self.add_module(ctx, path_ctx, m, name, doc_aliases); } _ => (), }); @@ -179,7 +171,11 @@ impl Completions { path_ctx: &PathCompletionCtx, local_name: hir::Name, resolution: hir::ScopeDef, + doc_aliases: Vec, ) { + if !ctx.check_stability(resolution.attrs(ctx.db).as_deref()) { + return; + } let is_private_editable = match ctx.def_is_visible(&resolution) { Visible::Yes => false, Visible::Editable => true, @@ -187,12 +183,14 @@ impl Completions { }; self.add( render_path_resolution( - RenderContext::new(ctx).private_editable(is_private_editable), + RenderContext::new(ctx) + .private_editable(is_private_editable) + .doc_aliases(doc_aliases), path_ctx, local_name, resolution, ) - .build(), + .build(ctx.db), ); } @@ -203,6 +201,9 @@ impl Completions { local_name: hir::Name, resolution: hir::ScopeDef, ) { + if !ctx.check_stability(resolution.attrs(ctx.db).as_deref()) { + return; + } let is_private_editable = match ctx.def_is_visible(&resolution) { Visible::Yes => false, Visible::Editable => true, @@ -215,7 +216,7 @@ impl Completions { local_name, resolution, ) - .build(), + .build(ctx.db), ); } @@ -225,6 +226,9 @@ impl Completions { path_ctx: &PathCompletionCtx, e: hir::Enum, ) { + if !ctx.check_stability(Some(&e.attrs(ctx.db))) { + return; + } e.variants(ctx.db) .into_iter() .for_each(|variant| self.add_enum_variant(ctx, path_ctx, variant, None)); @@ -236,12 +240,17 @@ impl Completions { path_ctx: &PathCompletionCtx, module: hir::Module, local_name: hir::Name, + doc_aliases: Vec, ) { + if !ctx.check_stability(Some(&module.attrs(ctx.db))) { + return; + } self.add_path_resolution( ctx, path_ctx, local_name, hir::ScopeDef::ModuleDef(module.into()), + doc_aliases, ); } @@ -252,6 +261,9 @@ impl Completions { mac: hir::Macro, local_name: hir::Name, ) { + if !ctx.check_stability(Some(&mac.attrs(ctx.db))) { + return; + } let is_private_editable = match ctx.is_visible(&mac) { Visible::Yes => false, Visible::Editable => true, @@ -264,7 +276,7 @@ impl Completions { local_name, mac, ) - .build(), + .build(ctx.db), ); } @@ -275,19 +287,25 @@ impl Completions { func: hir::Function, local_name: Option, ) { + if !ctx.check_stability(Some(&func.attrs(ctx.db))) { + return; + } let is_private_editable = match ctx.is_visible(&func) { Visible::Yes => false, Visible::Editable => true, Visible::No => return, }; + let doc_aliases = ctx.doc_aliases(&func); self.add( render_fn( - RenderContext::new(ctx).private_editable(is_private_editable), + RenderContext::new(ctx) + .private_editable(is_private_editable) + .doc_aliases(doc_aliases), path_ctx, local_name, func, ) - .build(), + .build(ctx.db), ); } @@ -299,20 +317,26 @@ impl Completions { receiver: Option, local_name: Option, ) { + if !ctx.check_stability(Some(&func.attrs(ctx.db))) { + return; + } let is_private_editable = match ctx.is_visible(&func) { Visible::Yes => false, Visible::Editable => true, Visible::No => return, }; + let doc_aliases = ctx.doc_aliases(&func); self.add( render_method( - RenderContext::new(ctx).private_editable(is_private_editable), + RenderContext::new(ctx) + .private_editable(is_private_editable) + .doc_aliases(doc_aliases), dot_access, receiver, local_name, func, ) - .build(), + .build(ctx.db), ); } @@ -323,26 +347,34 @@ impl Completions { func: hir::Function, import: LocatedImport, ) { + if !ctx.check_stability(Some(&func.attrs(ctx.db))) { + return; + } let is_private_editable = match ctx.is_visible(&func) { Visible::Yes => false, Visible::Editable => true, Visible::No => return, }; + let doc_aliases = ctx.doc_aliases(&func); self.add( render_method( RenderContext::new(ctx) .private_editable(is_private_editable) + .doc_aliases(doc_aliases) .import_to_add(Some(import)), dot_access, None, None, func, ) - .build(), + .build(ctx.db), ); } pub(crate) fn add_const(&mut self, ctx: &CompletionContext<'_>, konst: hir::Const) { + if !ctx.check_stability(Some(&konst.attrs(ctx.db))) { + return; + } let is_private_editable = match ctx.is_visible(&konst) { Visible::Yes => false, Visible::Editable => true, @@ -359,6 +391,9 @@ impl Completions { ctx: &CompletionContext<'_>, type_alias: hir::TypeAlias, ) { + if !ctx.check_stability(Some(&type_alias.attrs(ctx.db))) { + return; + } let is_private_editable = match ctx.is_visible(&type_alias) { Visible::Yes => false, Visible::Editable => true, @@ -375,6 +410,9 @@ impl Completions { ctx: &CompletionContext<'_>, type_alias: hir::TypeAlias, ) { + if !ctx.check_stability(Some(&type_alias.attrs(ctx.db))) { + return; + } self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias)); } @@ -385,10 +423,13 @@ impl Completions { variant: hir::Variant, path: hir::ModPath, ) { + if !ctx.check_stability(Some(&variant.attrs(ctx.db))) { + return; + } if let Some(builder) = render_variant_lit(RenderContext::new(ctx), path_ctx, None, variant, Some(path)) { - self.add(builder.build()); + self.add(builder.build(ctx.db)); } } @@ -399,6 +440,9 @@ impl Completions { variant: hir::Variant, local_name: Option, ) { + if !ctx.check_stability(Some(&variant.attrs(ctx.db))) { + return; + } if let PathCompletionCtx { kind: PathKind::Pat { pat_ctx }, .. } = path_ctx { cov_mark::hit!(enum_variant_pattern_path); self.add_variant_pat(ctx, pat_ctx, Some(path_ctx), variant, local_name); @@ -408,7 +452,7 @@ impl Completions { if let Some(builder) = render_variant_lit(RenderContext::new(ctx), path_ctx, local_name, variant, None) { - self.add(builder.build()); + self.add(builder.build(ctx.db)); } } @@ -420,13 +464,17 @@ impl Completions { field: hir::Field, ty: &hir::Type, ) { + if !ctx.check_stability(Some(&field.attrs(ctx.db))) { + return; + } let is_private_editable = match ctx.is_visible(&field) { Visible::Yes => false, Visible::Editable => true, Visible::No => return, }; + let doc_aliases = ctx.doc_aliases(&field); let item = render_field( - RenderContext::new(ctx).private_editable(is_private_editable), + RenderContext::new(ctx).private_editable(is_private_editable).doc_aliases(doc_aliases), dot_access, receiver, field, @@ -443,10 +491,13 @@ impl Completions { path: Option, local_name: Option, ) { + if !ctx.check_stability(Some(&strukt.attrs(ctx.db))) { + return; + } if let Some(builder) = render_struct_literal(RenderContext::new(ctx), path_ctx, strukt, path, local_name) { - self.add(builder.build()); + self.add(builder.build(ctx.db)); } } @@ -457,6 +508,9 @@ impl Completions { path: Option, local_name: Option, ) { + if !ctx.check_stability(Some(&un.attrs(ctx.db))) { + return; + } let item = render_union_literal(RenderContext::new(ctx), un, path, local_name); self.add_opt(item); } @@ -468,17 +522,20 @@ impl Completions { field: usize, ty: &hir::Type, ) { + // Only used for (unnamed) tuples, whose all fields *are* stable. No need to check + // stability here. let item = render_tuple_field(RenderContext::new(ctx), receiver, field, ty); self.add(item); } pub(crate) fn add_lifetime(&mut self, ctx: &CompletionContext<'_>, name: hir::Name) { CompletionItem::new(SymbolKind::LifetimeParam, ctx.source_range(), name.to_smol_str()) - .add_to(self) + .add_to(self, ctx.db) } pub(crate) fn add_label(&mut self, ctx: &CompletionContext<'_>, name: hir::Name) { - CompletionItem::new(SymbolKind::Label, ctx.source_range(), name.to_smol_str()).add_to(self) + CompletionItem::new(SymbolKind::Label, ctx.source_range(), name.to_smol_str()) + .add_to(self, ctx.db) } pub(crate) fn add_variant_pat( @@ -489,6 +546,9 @@ impl Completions { variant: hir::Variant, local_name: Option, ) { + if !ctx.check_stability(Some(&variant.attrs(ctx.db))) { + return; + } self.add_opt(render_variant_pat( RenderContext::new(ctx), pattern_ctx, @@ -506,6 +566,9 @@ impl Completions { variant: hir::Variant, path: hir::ModPath, ) { + if !ctx.check_stability(Some(&variant.attrs(ctx.db))) { + return; + } let path = Some(&path); self.add_opt(render_variant_pat( RenderContext::new(ctx), @@ -524,6 +587,9 @@ impl Completions { strukt: hir::Struct, local_name: Option, ) { + if !ctx.check_stability(Some(&strukt.attrs(ctx.db))) { + return; + } self.add_opt(render_struct_pat(RenderContext::new(ctx), pattern_ctx, strukt, local_name)); } } diff --git a/crates/ide-completion/src/completions/attribute.rs b/crates/ide-completion/src/completions/attribute.rs index bb950c76f8831..466f0b1fb7f9b 100644 --- a/crates/ide-completion/src/completions/attribute.rs +++ b/crates/ide-completion/src/completions/attribute.rs @@ -93,7 +93,7 @@ pub(crate) fn complete_attribute_path( acc.add_macro(ctx, path_ctx, m, name) } hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => { - acc.add_module(ctx, path_ctx, m, name) + acc.add_module(ctx, path_ctx, m, name, vec![]) } _ => (), } @@ -104,12 +104,12 @@ pub(crate) fn complete_attribute_path( Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx), // only show modules in a fresh UseTree Qualified::No => { - ctx.process_all_names(&mut |name, def| match def { + ctx.process_all_names(&mut |name, def, doc_aliases| match def { hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_attr(ctx.db) => { acc.add_macro(ctx, path_ctx, m, name) } hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => { - acc.add_module(ctx, path_ctx, m, name) + acc.add_module(ctx, path_ctx, m, name, doc_aliases) } _ => (), }); @@ -139,7 +139,7 @@ pub(crate) fn complete_attribute_path( } if is_inner || !attr_completion.prefer_inner { - item.add_to(acc); + item.add_to(acc, ctx.db); } }; diff --git a/crates/ide-completion/src/completions/attribute/cfg.rs b/crates/ide-completion/src/completions/attribute/cfg.rs index 7ef4ff30b56c7..19bfd294b25cc 100644 --- a/crates/ide-completion/src/completions/attribute/cfg.rs +++ b/crates/ide-completion/src/completions/attribute/cfg.rs @@ -12,7 +12,7 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) { let add_completion = |item: &str| { let mut completion = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), item); completion.insert_text(format!(r#""{item}""#)); - acc.add(completion.build()); + acc.add(completion.build(ctx.db)); }; let previous = iter::successors(ctx.original_token.prev_token(), |t| { @@ -33,11 +33,11 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) { let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s); item.insert_text(insert_text); - acc.add(item.build()); + acc.add(item.build(ctx.db)); }), None => ctx.krate.potential_cfg(ctx.db).get_cfg_keys().cloned().unique().for_each(|s| { let item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s); - acc.add(item.build()); + acc.add(item.build(ctx.db)); }), }; } diff --git a/crates/ide-completion/src/completions/attribute/derive.rs b/crates/ide-completion/src/completions/attribute/derive.rs index 793c22630bf89..9447bc7db0a79 100644 --- a/crates/ide-completion/src/completions/attribute/derive.rs +++ b/crates/ide-completion/src/completions/attribute/derive.rs @@ -34,7 +34,7 @@ pub(crate) fn complete_derive_path( acc.add_macro(ctx, path_ctx, mac, name) } ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => { - acc.add_module(ctx, path_ctx, m, name) + acc.add_module(ctx, path_ctx, m, name, vec![]) } _ => (), } @@ -43,7 +43,7 @@ pub(crate) fn complete_derive_path( Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx), // only show modules in a fresh UseTree Qualified::No => { - ctx.process_all_names(&mut |name, def| { + ctx.process_all_names(&mut |name, def, doc_aliases| { let mac = match def { ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) if !existing_derives.contains(&mac) && mac.is_derive(ctx.db) => @@ -51,7 +51,7 @@ pub(crate) fn complete_derive_path( mac } ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => { - return acc.add_module(ctx, path_ctx, m, name); + return acc.add_module(ctx, path_ctx, m, name, doc_aliases); } _ => return, }; @@ -90,7 +90,7 @@ pub(crate) fn complete_derive_path( item.documentation(docs); } item.lookup_by(lookup); - item.add_to(acc); + item.add_to(acc, ctx.db); } None => acc.add_macro(ctx, path_ctx, mac, name), } diff --git a/crates/ide-completion/src/completions/attribute/lint.rs b/crates/ide-completion/src/completions/attribute/lint.rs index 818c3cfd5fe7f..6bc6f34ed41b3 100644 --- a/crates/ide-completion/src/completions/attribute/lint.rs +++ b/crates/ide-completion/src/completions/attribute/lint.rs @@ -56,6 +56,6 @@ pub(super) fn complete_lint( }; let mut item = CompletionItem::new(SymbolKind::Attribute, ctx.source_range(), label); item.documentation(hir::Documentation::new(description.to_owned())); - item.add_to(acc) + item.add_to(acc, ctx.db) } } diff --git a/crates/ide-completion/src/completions/attribute/repr.rs b/crates/ide-completion/src/completions/attribute/repr.rs index a29417133e68b..14f464b7753d7 100644 --- a/crates/ide-completion/src/completions/attribute/repr.rs +++ b/crates/ide-completion/src/completions/attribute/repr.rs @@ -37,7 +37,7 @@ pub(super) fn complete_repr( if let Some((snippet, cap)) = snippet.zip(ctx.config.snippet_cap) { item.insert_snippet(cap, snippet); } - item.add_to(acc); + item.add_to(acc, ctx.db); } } } diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs index 77246379e7bd9..57a784c45b614 100644 --- a/crates/ide-completion/src/completions/dot.rs +++ b/crates/ide-completion/src/completions/dot.rs @@ -23,7 +23,7 @@ pub(crate) fn complete_dot( let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), "await"); item.detail("expr.await"); - item.add_to(acc); + item.add_to(acc, ctx.db); } if let DotAccessKind::Method { .. } = dot_access.kind { @@ -172,6 +172,43 @@ fn foo(s: S) { s.$0 } ); } + #[test] + fn no_unstable_method_on_stable() { + check( + r#" +//- /main.rs crate:main deps:std +fn foo(s: std::S) { s.$0 } +//- /std.rs crate:std +pub struct S; +impl S { + #[unstable] + pub fn bar(&self) {} +} +"#, + expect![""], + ); + } + + #[test] + fn unstable_method_on_nightly() { + check( + r#" +//- toolchain:nightly +//- /main.rs crate:main deps:std +fn foo(s: std::S) { s.$0 } +//- /std.rs crate:std +pub struct S; +impl S { + #[unstable] + pub fn bar(&self) {} +} +"#, + expect![[r#" + me bar() fn(&self) + "#]], + ); + } + #[test] fn test_struct_field_completion_self() { check( diff --git a/crates/ide-completion/src/completions/env_vars.rs b/crates/ide-completion/src/completions/env_vars.rs index 1002be21131d9..419b864565559 100644 --- a/crates/ide-completion/src/completions/env_vars.rs +++ b/crates/ide-completion/src/completions/env_vars.rs @@ -37,10 +37,10 @@ pub(crate) fn complete_cargo_env_vars( guard_env_macro(expanded, &ctx.sema)?; let range = expanded.text_range_between_quotes()?; - CARGO_DEFINED_VARS.iter().for_each(|(var, detail)| { + CARGO_DEFINED_VARS.into_iter().for_each(|&(var, detail)| { let mut item = CompletionItem::new(CompletionItemKind::Keyword, range, var); - item.detail(*detail); - item.add_to(acc); + item.detail(detail); + item.add_to(acc, ctx.db); }); Some(()) diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index cfe4787f734d7..9daa6984c3e38 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -88,7 +88,13 @@ pub(crate) fn complete_expr_path( let module_scope = module.scope(ctx.db, Some(ctx.module)); for (name, def) in module_scope { if scope_def_applicable(def) { - acc.add_path_resolution(ctx, path_ctx, name, def); + acc.add_path_resolution( + ctx, + path_ctx, + name, + def, + ctx.doc_aliases_in_scope(def), + ); } } } @@ -212,7 +218,7 @@ pub(crate) fn complete_expr_path( } } } - ctx.process_all_names(&mut |name, def| match def { + ctx.process_all_names(&mut |name, def, doc_aliases| match def { ScopeDef::ModuleDef(hir::ModuleDef::Trait(t)) => { let assocs = t.items_with_supertraits(ctx.db); match &*assocs { @@ -220,12 +226,14 @@ pub(crate) fn complete_expr_path( // there is no associated item path that can be constructed with them [] => (), // FIXME: Render the assoc item with the trait qualified - &[_item] => acc.add_path_resolution(ctx, path_ctx, name, def), + &[_item] => acc.add_path_resolution(ctx, path_ctx, name, def, doc_aliases), // FIXME: Append `::` to the thing here, since a trait on its own won't work - [..] => acc.add_path_resolution(ctx, path_ctx, name, def), + [..] => acc.add_path_resolution(ctx, path_ctx, name, def, doc_aliases), } } - _ if scope_def_applicable(def) => acc.add_path_resolution(ctx, path_ctx, name, def), + _ if scope_def_applicable(def) => { + acc.add_path_resolution(ctx, path_ctx, name, def, doc_aliases) + } _ => (), }); diff --git a/crates/ide-completion/src/completions/extern_abi.rs b/crates/ide-completion/src/completions/extern_abi.rs index 4e89ef6960821..c717a9cb55b8e 100644 --- a/crates/ide-completion/src/completions/extern_abi.rs +++ b/crates/ide-completion/src/completions/extern_abi.rs @@ -42,7 +42,7 @@ const SUPPORTED_CALLING_CONVENTIONS: &[&str] = &[ pub(crate) fn complete_extern_abi( acc: &mut Completions, - _ctx: &CompletionContext<'_>, + ctx: &CompletionContext<'_>, expanded: &ast::String, ) -> Option<()> { if !expanded.syntax().parent().map_or(false, |it| ast::Abi::can_cast(it.kind())) { @@ -51,7 +51,7 @@ pub(crate) fn complete_extern_abi( let abi_str = expanded; let source_range = abi_str.text_range_between_quotes()?; for &abi in SUPPORTED_CALLING_CONVENTIONS { - CompletionItem::new(CompletionItemKind::Keyword, source_range, abi).add_to(acc); + CompletionItem::new(CompletionItemKind::Keyword, source_range, abi).add_to(acc, ctx.db); } Some(()) } diff --git a/crates/ide-completion/src/completions/flyimport.rs b/crates/ide-completion/src/completions/flyimport.rs index 0979f6a6dfc7d..39c1b7f7b3fb4 100644 --- a/crates/ide-completion/src/completions/flyimport.rs +++ b/crates/ide-completion/src/completions/flyimport.rs @@ -257,30 +257,24 @@ fn import_on_the_fly( }; let user_input_lowercased = potential_import_name.to_lowercase(); - acc.add_all( - import_assets - .search_for_imports( - &ctx.sema, - ctx.config.insert_use.prefix_kind, - ctx.config.prefer_no_std, - ) - .into_iter() - .filter(ns_filter) - .filter(|import| { - !ctx.is_item_hidden(&import.item_to_import) - && !ctx.is_item_hidden(&import.original_item) - }) - .sorted_by_key(|located_import| { - compute_fuzzy_completion_order_key( - &located_import.import_path, - &user_input_lowercased, - ) - }) - .filter_map(|import| { - render_resolution_with_import(RenderContext::new(ctx), path_ctx, import) - }) - .map(|builder| builder.build()), - ); + import_assets + .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind, ctx.config.prefer_no_std) + .into_iter() + .filter(ns_filter) + .filter(|import| { + let original_item = &import.original_item; + !ctx.is_item_hidden(&import.item_to_import) + && !ctx.is_item_hidden(original_item) + && ctx.check_stability(original_item.attrs(ctx.db).as_deref()) + }) + .sorted_by_key(|located_import| { + compute_fuzzy_completion_order_key(&located_import.import_path, &user_input_lowercased) + }) + .filter_map(|import| { + render_resolution_with_import(RenderContext::new(ctx), path_ctx, import) + }) + .map(|builder| builder.build(ctx.db)) + .for_each(|item| acc.add(item)); Some(()) } @@ -305,30 +299,24 @@ fn import_on_the_fly_pat_( }; let user_input_lowercased = potential_import_name.to_lowercase(); - acc.add_all( - import_assets - .search_for_imports( - &ctx.sema, - ctx.config.insert_use.prefix_kind, - ctx.config.prefer_no_std, - ) - .into_iter() - .filter(ns_filter) - .filter(|import| { - !ctx.is_item_hidden(&import.item_to_import) - && !ctx.is_item_hidden(&import.original_item) - }) - .sorted_by_key(|located_import| { - compute_fuzzy_completion_order_key( - &located_import.import_path, - &user_input_lowercased, - ) - }) - .filter_map(|import| { - render_resolution_with_import_pat(RenderContext::new(ctx), pattern_ctx, import) - }) - .map(|builder| builder.build()), - ); + import_assets + .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind, ctx.config.prefer_no_std) + .into_iter() + .filter(ns_filter) + .filter(|import| { + let original_item = &import.original_item; + !ctx.is_item_hidden(&import.item_to_import) + && !ctx.is_item_hidden(original_item) + && ctx.check_stability(original_item.attrs(ctx.db).as_deref()) + }) + .sorted_by_key(|located_import| { + compute_fuzzy_completion_order_key(&located_import.import_path, &user_input_lowercased) + }) + .filter_map(|import| { + render_resolution_with_import_pat(RenderContext::new(ctx), pattern_ctx, import) + }) + .map(|builder| builder.build(ctx.db)) + .for_each(|item| acc.add(item)); Some(()) } diff --git a/crates/ide-completion/src/completions/fn_param.rs b/crates/ide-completion/src/completions/fn_param.rs index d8b8a190eb840..8b38d4f01f673 100644 --- a/crates/ide-completion/src/completions/fn_param.rs +++ b/crates/ide-completion/src/completions/fn_param.rs @@ -40,7 +40,7 @@ pub(crate) fn complete_fn_param( }; // Completion lookup is omitted intentionally here. // See the full discussion: https://github.com/rust-lang/rust-analyzer/issues/12073 - item.add_to(acc) + item.add_to(acc, ctx.db) }; match kind { @@ -50,7 +50,7 @@ pub(crate) fn complete_fn_param( ParamKind::Closure(closure) => { let stmt_list = closure.syntax().ancestors().find_map(ast::StmtList::cast)?; params_from_stmt_list_scope(ctx, stmt_list, |name, ty| { - add_new_item_to_acc(&format!("{name}: {ty}")); + add_new_item_to_acc(&format!("{}: {ty}", name.display(ctx.db))); }); } } @@ -100,7 +100,9 @@ fn fill_fn_params( if let Some(stmt_list) = function.syntax().parent().and_then(ast::StmtList::cast) { params_from_stmt_list_scope(ctx, stmt_list, |name, ty| { - file_params.entry(format!("{name}: {ty}")).or_insert(name.to_string()); + file_params + .entry(format!("{}: {ty}", name.display(ctx.db))) + .or_insert(name.display(ctx.db).to_string()); }); } remove_duplicated(&mut file_params, param_list.params()); @@ -127,7 +129,7 @@ fn params_from_stmt_list_scope( let module = scope.module().into(); scope.process_all_names(&mut |name, def| { if let hir::ScopeDef::Local(local) = def { - if let Ok(ty) = local.ty(ctx.db).display_source_code(ctx.db, module) { + if let Ok(ty) = local.ty(ctx.db).display_source_code(ctx.db, module, true) { cb(name, ty); } } diff --git a/crates/ide-completion/src/completions/format_string.rs b/crates/ide-completion/src/completions/format_string.rs index 5c46c5806e65e..8e904fd605a8d 100644 --- a/crates/ide-completion/src/completions/format_string.rs +++ b/crates/ide-completion/src/completions/format_string.rs @@ -32,7 +32,7 @@ pub(crate) fn format_string( let source_range = TextRange::new(brace_offset, cursor); ctx.locals.iter().for_each(|(name, _)| { CompletionItem::new(CompletionItemKind::Binding, source_range, name.to_smol_str()) - .add_to(acc); + .add_to(acc, ctx.db); }) } diff --git a/crates/ide-completion/src/completions/item_list.rs b/crates/ide-completion/src/completions/item_list.rs index 60d05ae46b916..5ea6a49b1ae15 100644 --- a/crates/ide-completion/src/completions/item_list.rs +++ b/crates/ide-completion/src/completions/item_list.rs @@ -45,7 +45,7 @@ pub(crate) fn complete_item_list( acc.add_macro(ctx, path_ctx, m, name) } hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => { - acc.add_module(ctx, path_ctx, m, name) + acc.add_module(ctx, path_ctx, m, name, vec![]) } _ => (), } @@ -55,12 +55,12 @@ pub(crate) fn complete_item_list( } Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx), Qualified::No if ctx.qualifier_ctx.none() => { - ctx.process_all_names(&mut |name, def| match def { + ctx.process_all_names(&mut |name, def, doc_aliases| match def { hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_fn_like(ctx.db) => { acc.add_macro(ctx, path_ctx, m, name) } hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => { - acc.add_module(ctx, path_ctx, m, name) + acc.add_module(ctx, path_ctx, m, name, doc_aliases) } _ => (), }); diff --git a/crates/ide-completion/src/completions/item_list/trait_impl.rs b/crates/ide-completion/src/completions/item_list/trait_impl.rs index 889d90095fab1..7de1bf2dc131f 100644 --- a/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -150,21 +150,24 @@ fn complete_trait_impl( impl_def: &ast::Impl, ) { if let Some(hir_impl) = ctx.sema.to_def(impl_def) { - get_missing_assoc_items(&ctx.sema, impl_def).into_iter().for_each(|item| { - use self::ImplCompletionKind::*; - match (item, kind) { - (hir::AssocItem::Function(func), All | Fn) => { - add_function_impl(acc, ctx, replacement_range, func, hir_impl) + get_missing_assoc_items(&ctx.sema, impl_def) + .into_iter() + .filter(|item| ctx.check_stability(Some(&item.attrs(ctx.db)))) + .for_each(|item| { + use self::ImplCompletionKind::*; + match (item, kind) { + (hir::AssocItem::Function(func), All | Fn) => { + add_function_impl(acc, ctx, replacement_range, func, hir_impl) + } + (hir::AssocItem::TypeAlias(type_alias), All | TypeAlias) => { + add_type_alias_impl(acc, ctx, replacement_range, type_alias, hir_impl) + } + (hir::AssocItem::Const(const_), All | Const) => { + add_const_impl(acc, ctx, replacement_range, const_, hir_impl) + } + _ => {} } - (hir::AssocItem::TypeAlias(type_alias), All | TypeAlias) => { - add_type_alias_impl(acc, ctx, replacement_range, type_alias, hir_impl) - } - (hir::AssocItem::Const(const_), All | Const) => { - add_const_impl(acc, ctx, replacement_range, const_, hir_impl) - } - _ => {} - } - }); + }); } } @@ -179,7 +182,7 @@ fn add_function_impl( let label = format!( "fn {}({})", - fn_name, + fn_name.display(ctx.db), if func.assoc_fn_params(ctx.db).is_empty() { "" } else { ".." } ); @@ -190,7 +193,7 @@ fn add_function_impl( }; let mut item = CompletionItem::new(completion_kind, replacement_range, label); - item.lookup_by(format!("fn {fn_name}")) + item.lookup_by(format!("fn {}", fn_name.display(ctx.db))) .set_documentation(func.docs(ctx.db)) .set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() }); @@ -213,7 +216,7 @@ fn add_function_impl( item.text_edit(TextEdit::replace(replacement_range, header)); } }; - item.add_to(acc); + item.add_to(acc, ctx.db); } } } @@ -297,7 +300,7 @@ fn add_type_alias_impl( item.text_edit(TextEdit::replace(replacement_range, decl)); } }; - item.add_to(acc); + item.add_to(acc, ctx.db); } } } @@ -337,7 +340,7 @@ fn add_const_impl( ), None => item.text_edit(TextEdit::replace(replacement_range, replacement)), }; - item.add_to(acc); + item.add_to(acc, ctx.db); } } } diff --git a/crates/ide-completion/src/completions/lifetime.rs b/crates/ide-completion/src/completions/lifetime.rs index 3b79def639df4..2c6cbf6146a95 100644 --- a/crates/ide-completion/src/completions/lifetime.rs +++ b/crates/ide-completion/src/completions/lifetime.rs @@ -329,6 +329,7 @@ fn foo() { fn complete_label_in_for_iterable() { check( r#" +//- minicore: iterator fn foo() { 'outer: for _ in [{ 'inner: loop { break '$0 } }] {} } diff --git a/crates/ide-completion/src/completions/mod_.rs b/crates/ide-completion/src/completions/mod_.rs index 950731eb4ca8c..d3e75c6da4761 100644 --- a/crates/ide-completion/src/completions/mod_.rs +++ b/crates/ide-completion/src/completions/mod_.rs @@ -52,7 +52,7 @@ pub(crate) fn complete_mod( let existing_mod_declarations = current_module .children(ctx.db) - .filter_map(|module| Some(module.name(ctx.db)?.to_string())) + .filter_map(|module| Some(module.name(ctx.db)?.display(ctx.db).to_string())) .filter(|module| module != ctx.original_token.text()) .collect::>(); @@ -99,7 +99,7 @@ pub(crate) fn complete_mod( label.push(';'); } let item = CompletionItem::new(SymbolKind::Module, ctx.source_range(), &label); - item.add_to(acc) + item.add_to(acc, ctx.db) }); Some(()) diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs index 58d5bf114cca4..40b2c831a5d01 100644 --- a/crates/ide-completion/src/completions/pattern.rs +++ b/crates/ide-completion/src/completions/pattern.rs @@ -64,7 +64,7 @@ pub(crate) fn complete_pattern( // FIXME: ideally, we should look at the type we are matching against and // suggest variants + auto-imports - ctx.process_all_names(&mut |name, res| { + ctx.process_all_names(&mut |name, res, _| { let add_simple_path = match res { hir::ScopeDef::ModuleDef(def) => match def { hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => { @@ -127,7 +127,7 @@ pub(crate) fn complete_pattern_path( }; if add_resolution { - acc.add_path_resolution(ctx, path_ctx, name, def); + acc.add_path_resolution(ctx, path_ctx, name, def, vec![]); } } } @@ -164,7 +164,7 @@ pub(crate) fn complete_pattern_path( Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx), Qualified::No => { // this will only be hit if there are brackets or braces, otherwise this will be parsed as an ident pattern - ctx.process_all_names(&mut |name, res| { + ctx.process_all_names(&mut |name, res, doc_aliases| { // FIXME: we should check what kind of pattern we are in and filter accordingly let add_completion = match res { ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db), @@ -175,7 +175,7 @@ pub(crate) fn complete_pattern_path( _ => false, }; if add_completion { - acc.add_path_resolution(ctx, path_ctx, name, res); + acc.add_path_resolution(ctx, path_ctx, name, res, doc_aliases); } }); diff --git a/crates/ide-completion/src/completions/postfix.rs b/crates/ide-completion/src/completions/postfix.rs index c55bd9aaae521..2ffe123374471 100644 --- a/crates/ide-completion/src/completions/postfix.rs +++ b/crates/ide-completion/src/completions/postfix.rs @@ -64,7 +64,7 @@ pub(crate) fn complete_postfix( &format!("drop($0{receiver_text})"), ); item.set_documentation(drop_fn.docs(ctx.db)); - item.add_to(acc); + item.add_to(acc, ctx.db); } } } @@ -78,14 +78,14 @@ pub(crate) fn complete_postfix( "if let Ok {}", &format!("if let Ok($1) = {receiver_text} {{\n $0\n}}"), ) - .add_to(acc); + .add_to(acc, ctx.db); postfix_snippet( "while", "while let Ok {}", &format!("while let Ok($1) = {receiver_text} {{\n $0\n}}"), ) - .add_to(acc); + .add_to(acc, ctx.db); } TryEnum::Option => { postfix_snippet( @@ -93,22 +93,22 @@ pub(crate) fn complete_postfix( "if let Some {}", &format!("if let Some($1) = {receiver_text} {{\n $0\n}}"), ) - .add_to(acc); + .add_to(acc, ctx.db); postfix_snippet( "while", "while let Some {}", &format!("while let Some($1) = {receiver_text} {{\n $0\n}}"), ) - .add_to(acc); + .add_to(acc, ctx.db); } } } else if receiver_ty.is_bool() || receiver_ty.is_unknown() { postfix_snippet("if", "if expr {}", &format!("if {receiver_text} {{\n $0\n}}")) - .add_to(acc); + .add_to(acc, ctx.db); postfix_snippet("while", "while expr {}", &format!("while {receiver_text} {{\n $0\n}}")) - .add_to(acc); - postfix_snippet("not", "!expr", &format!("!{receiver_text}")).add_to(acc); + .add_to(acc, ctx.db); + postfix_snippet("not", "!expr", &format!("!{receiver_text}")).add_to(acc, ctx.db); } else if let Some(trait_) = ctx.famous_defs().core_iter_IntoIterator() { if receiver_ty.impls_trait(ctx.db, trait_, &[]) { postfix_snippet( @@ -116,12 +116,12 @@ pub(crate) fn complete_postfix( "for ele in expr {}", &format!("for ele in {receiver_text} {{\n $0\n}}"), ) - .add_to(acc); + .add_to(acc, ctx.db); } } - postfix_snippet("ref", "&expr", &format!("&{receiver_text}")).add_to(acc); - postfix_snippet("refm", "&mut expr", &format!("&mut {receiver_text}")).add_to(acc); + postfix_snippet("ref", "&expr", &format!("&{receiver_text}")).add_to(acc, ctx.db); + postfix_snippet("refm", "&mut expr", &format!("&mut {receiver_text}")).add_to(acc, ctx.db); let mut unsafe_should_be_wrapped = true; if dot_receiver.syntax().kind() == BLOCK_EXPR { @@ -137,7 +137,7 @@ pub(crate) fn complete_postfix( } else { format!("unsafe {receiver_text}") }; - postfix_snippet("unsafe", "unsafe {}", &unsafe_completion_string).add_to(acc); + postfix_snippet("unsafe", "unsafe {}", &unsafe_completion_string).add_to(acc, ctx.db); // The rest of the postfix completions create an expression that moves an argument, // so it's better to consider references now to avoid breaking the compilation @@ -162,7 +162,7 @@ pub(crate) fn complete_postfix( "match expr {}", &format!("match {receiver_text} {{\n Ok(${{1:_}}) => {{$2}},\n Err(${{3:_}}) => {{$0}},\n}}"), ) - .add_to(acc); + .add_to(acc, ctx.db); } TryEnum::Option => { postfix_snippet( @@ -172,7 +172,7 @@ pub(crate) fn complete_postfix( "match {receiver_text} {{\n Some(${{1:_}}) => {{$2}},\n None => {{$0}},\n}}" ), ) - .add_to(acc); + .add_to(acc, ctx.db); } }, None => { @@ -181,20 +181,23 @@ pub(crate) fn complete_postfix( "match expr {}", &format!("match {receiver_text} {{\n ${{1:_}} => {{$0}},\n}}"), ) - .add_to(acc); + .add_to(acc, ctx.db); } } - postfix_snippet("box", "Box::new(expr)", &format!("Box::new({receiver_text})")).add_to(acc); - postfix_snippet("dbg", "dbg!(expr)", &format!("dbg!({receiver_text})")).add_to(acc); // fixme - postfix_snippet("dbgr", "dbg!(&expr)", &format!("dbg!(&{receiver_text})")).add_to(acc); - postfix_snippet("call", "function(expr)", &format!("${{1}}({receiver_text})")).add_to(acc); + postfix_snippet("box", "Box::new(expr)", &format!("Box::new({receiver_text})")) + .add_to(acc, ctx.db); + postfix_snippet("dbg", "dbg!(expr)", &format!("dbg!({receiver_text})")).add_to(acc, ctx.db); // fixme + postfix_snippet("dbgr", "dbg!(&expr)", &format!("dbg!(&{receiver_text})")).add_to(acc, ctx.db); + postfix_snippet("call", "function(expr)", &format!("${{1}}({receiver_text})")) + .add_to(acc, ctx.db); if let Some(parent) = dot_receiver.syntax().parent().and_then(|p| p.parent()) { if matches!(parent.kind(), STMT_LIST | EXPR_STMT) { - postfix_snippet("let", "let", &format!("let $0 = {receiver_text};")).add_to(acc); + postfix_snippet("let", "let", &format!("let $0 = {receiver_text};")) + .add_to(acc, ctx.db); postfix_snippet("letm", "let mut", &format!("let mut $0 = {receiver_text};")) - .add_to(acc); + .add_to(acc, ctx.db); } } @@ -315,7 +318,7 @@ fn add_custom_postfix_completions( for import in imports.into_iter() { builder.add_import(import); } - builder.add_to(acc); + builder.add_to(acc, ctx.db); }, ); None diff --git a/crates/ide-completion/src/completions/postfix/format_like.rs b/crates/ide-completion/src/completions/postfix/format_like.rs index dfcc78e92308d..cb242e4aa6869 100644 --- a/crates/ide-completion/src/completions/postfix/format_like.rs +++ b/crates/ide-completion/src/completions/postfix/format_like.rs @@ -60,7 +60,7 @@ pub(crate) fn add_format_like_completions( format!(r#"{}({}, {})"#, macro_name, out, exprs.join(", ")) }; - postfix_snippet(label, macro_name, &snippet).add_to(acc); + postfix_snippet(label, macro_name, &snippet).add_to(acc, ctx.db); } } } diff --git a/crates/ide-completion/src/completions/record.rs b/crates/ide-completion/src/completions/record.rs index 0521e735dedf1..945c3945bfa39 100644 --- a/crates/ide-completion/src/completions/record.rs +++ b/crates/ide-completion/src/completions/record.rs @@ -69,7 +69,7 @@ pub(crate) fn complete_record_expr_fields( let mut item = CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), ".."); item.insert_text("."); - item.add_to(acc); + item.add_to(acc, ctx.db); return; } missing_fields @@ -98,7 +98,7 @@ pub(crate) fn add_default_update( postfix_match: Some(CompletionRelevancePostfixMatch::Exact), ..Default::default() }); - item.add_to(acc); + item.add_to(acc, ctx.db); } } diff --git a/crates/ide-completion/src/completions/snippet.rs b/crates/ide-completion/src/completions/snippet.rs index da1f0542d286f..e9831a5b2a121 100644 --- a/crates/ide-completion/src/completions/snippet.rs +++ b/crates/ide-completion/src/completions/snippet.rs @@ -32,8 +32,8 @@ pub(crate) fn complete_expr_snippet( } if in_block_expr { - snippet(ctx, cap, "pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc); - snippet(ctx, cap, "ppd", "eprintln!(\"$0 = {:#?}\", $0);").add_to(acc); + snippet(ctx, cap, "pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc, ctx.db); + snippet(ctx, cap, "ppd", "eprintln!(\"$0 = {:#?}\", $0);").add_to(acc, ctx.db); let item = snippet( ctx, cap, @@ -45,7 +45,7 @@ macro_rules! $1 { }; }", ); - item.add_to(acc); + item.add_to(acc, ctx.db); } } @@ -88,7 +88,7 @@ mod tests { }", ); item.lookup_by("tmod"); - item.add_to(acc); + item.add_to(acc, ctx.db); let mut item = snippet( ctx, @@ -101,7 +101,7 @@ fn ${1:feature}() { }", ); item.lookup_by("tfn"); - item.add_to(acc); + item.add_to(acc, ctx.db); let item = snippet( ctx, @@ -114,7 +114,7 @@ macro_rules! $1 { }; }", ); - item.add_to(acc); + item.add_to(acc, ctx.db); } } @@ -146,7 +146,7 @@ fn add_custom_completions( builder.add_import(import); } builder.set_detail(snip.description.clone()); - builder.add_to(acc); + builder.add_to(acc, ctx.db); }, ); None diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs index 69c05a76df4ce..e47054756389b 100644 --- a/crates/ide-completion/src/completions/type.rs +++ b/crates/ide-completion/src/completions/type.rs @@ -85,7 +85,7 @@ pub(crate) fn complete_type_path( let module_scope = module.scope(ctx.db, Some(ctx.module)); for (name, def) in module_scope { if scope_def_applicable(def) { - acc.add_path_resolution(ctx, path_ctx, name, def); + acc.add_path_resolution(ctx, path_ctx, name, def, vec![]); } } } @@ -141,7 +141,7 @@ pub(crate) fn complete_type_path( match location { TypeLocation::TypeBound => { acc.add_nameref_keywords_with_colon(ctx); - ctx.process_all_names(&mut |name, res| { + ctx.process_all_names(&mut |name, res, doc_aliases| { let add_resolution = match res { ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => { mac.is_fn_like(ctx.db) @@ -152,7 +152,7 @@ pub(crate) fn complete_type_path( _ => false, }; if add_resolution { - acc.add_path_resolution(ctx, path_ctx, name, res); + acc.add_path_resolution(ctx, path_ctx, name, res, doc_aliases); } }); return; @@ -215,9 +215,9 @@ pub(crate) fn complete_type_path( }; acc.add_nameref_keywords_with_colon(ctx); - ctx.process_all_names(&mut |name, def| { + ctx.process_all_names(&mut |name, def, doc_aliases| { if scope_def_applicable(def) { - acc.add_path_resolution(ctx, path_ctx, name, def); + acc.add_path_resolution(ctx, path_ctx, name, def, doc_aliases); } }); } @@ -242,7 +242,7 @@ pub(crate) fn complete_ascribed_type( } }? .adjusted(); - let ty_string = x.display_source_code(ctx.db, ctx.module.into()).ok()?; + let ty_string = x.display_source_code(ctx.db, ctx.module.into(), true).ok()?; acc.add(render_type_inference(ty_string, ctx)); None } diff --git a/crates/ide-completion/src/completions/use_.rs b/crates/ide-completion/src/completions/use_.rs index 2555c34aa7477..7a60030e9ef72 100644 --- a/crates/ide-completion/src/completions/use_.rs +++ b/crates/ide-completion/src/completions/use_.rs @@ -52,6 +52,9 @@ pub(crate) fn complete_use_path( ) }; for (name, def) in module_scope { + if !ctx.check_stability(def.attrs(ctx.db).as_deref()) { + continue; + } let is_name_already_imported = name .as_text() .map_or(false, |text| already_imported_names.contains(text.as_str())); @@ -72,7 +75,7 @@ pub(crate) fn complete_use_path( is_name_already_imported, ..Default::default() }); - acc.add(builder.build()); + acc.add(builder.build(ctx.db)); } } } @@ -91,10 +94,10 @@ pub(crate) fn complete_use_path( // only show modules and non-std enum in a fresh UseTree Qualified::No => { cov_mark::hit!(unqualified_path_selected_only); - ctx.process_all_names(&mut |name, res| { + ctx.process_all_names(&mut |name, res, doc_aliases| { match res { ScopeDef::ModuleDef(hir::ModuleDef::Module(module)) => { - acc.add_module(ctx, path_ctx, module, name); + acc.add_module(ctx, path_ctx, module, name, doc_aliases); } ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => { // exclude prelude enum @@ -105,9 +108,9 @@ pub(crate) fn complete_use_path( let item = CompletionItem::new( CompletionItemKind::SymbolKind(SymbolKind::Enum), ctx.source_range(), - format!("{}::", e.name(ctx.db)), + format!("{}::", e.name(ctx.db).display(ctx.db)), ); - acc.add(item.build()); + acc.add(item.build(ctx.db)); } } _ => {} diff --git a/crates/ide-completion/src/completions/vis.rs b/crates/ide-completion/src/completions/vis.rs index 5e6cf4bf9a521..e0a959ad0b340 100644 --- a/crates/ide-completion/src/completions/vis.rs +++ b/crates/ide-completion/src/completions/vis.rs @@ -23,7 +23,7 @@ pub(crate) fn complete_vis_path( if let Some(next) = next_towards_current { if let Some(name) = next.name(ctx.db) { cov_mark::hit!(visibility_qualified); - acc.add_module(ctx, path_ctx, next, name); + acc.add_module(ctx, path_ctx, next, name, vec![]); } } diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index 8cbf89e9c3019..7b145f3c14e32 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -17,7 +17,7 @@ use ide_db::{ }; use syntax::{ ast::{self, AttrKind, NameOrNameRef}, - AstNode, + AstNode, SmolStr, SyntaxKind::{self, *}, SyntaxToken, TextRange, TextSize, T, }; @@ -367,6 +367,8 @@ pub(crate) struct CompletionContext<'a> { pub(super) krate: hir::Crate, /// The module of the `scope`. pub(super) module: hir::Module, + /// Whether nightly toolchain is used. Cached since this is looked up a lot. + is_nightly: bool, /// The expected name of what we are completing. /// This is usually the parameter name of the function argument we are completing. @@ -386,7 +388,7 @@ pub(crate) struct CompletionContext<'a> { pub(super) depth_from_crate_root: usize, } -impl<'a> CompletionContext<'a> { +impl CompletionContext<'_> { /// The range of the identifier that is being completed. pub(crate) fn source_range(&self) -> TextRange { let kind = self.original_token.kind(); @@ -441,6 +443,14 @@ impl<'a> CompletionContext<'a> { self.is_visible_impl(&vis, &attrs, item.krate(self.db)) } + pub(crate) fn doc_aliases(&self, item: &I) -> Vec + where + I: hir::HasAttrs + Copy, + { + let attrs = item.attrs(self.db); + attrs.doc_aliases().collect() + } + /// Check if an item is `#[doc(hidden)]`. pub(crate) fn is_item_hidden(&self, item: &hir::ItemInNs) -> bool { let attrs = item.attrs(self.db); @@ -451,6 +461,12 @@ impl<'a> CompletionContext<'a> { } } + /// Checks whether this item should be listed in regards to stability. Returns `true` if we should. + pub(crate) fn check_stability(&self, attrs: Option<&hir::Attrs>) -> bool { + let Some(attrs) = attrs else { return true; }; + !attrs.is_unstable() || self.is_nightly + } + /// Whether the given trait is an operator trait or not. pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool { match trait_.attrs(self.db).lang() { @@ -491,21 +507,22 @@ impl<'a> CompletionContext<'a> { ); } - /// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items. - pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) { + /// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items and + /// passes all doc-aliases along, to funnel it into [`Completions::add_path_resolution`]. + pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef, Vec)) { let _p = profile::span("CompletionContext::process_all_names"); self.scope.process_all_names(&mut |name, def| { if self.is_scope_def_hidden(def) { return; } - - f(name, def); + let doc_aliases = self.doc_aliases_in_scope(def); + f(name, def, doc_aliases); }); } pub(crate) fn process_all_names_raw(&self, f: &mut dyn FnMut(Name, ScopeDef)) { let _p = profile::span("CompletionContext::process_all_names_raw"); - self.scope.process_all_names(&mut |name, def| f(name, def)); + self.scope.process_all_names(f); } fn is_scope_def_hidden(&self, scope_def: ScopeDef) -> bool { @@ -545,6 +562,14 @@ impl<'a> CompletionContext<'a> { // `doc(hidden)` items are only completed within the defining crate. self.krate != defining_crate && attrs.has_doc_hidden() } + + pub(crate) fn doc_aliases_in_scope(&self, scope_def: ScopeDef) -> Vec { + if let Some(attrs) = scope_def.attrs(self.db) { + attrs.doc_aliases().collect() + } else { + vec![] + } + } } // CompletionContext construction @@ -615,6 +640,11 @@ impl<'a> CompletionContext<'a> { let krate = scope.krate(); let module = scope.module(); + let toolchain = db.crate_graph()[krate.into()].channel; + // `toolchain == None` means we're in some detached files. Since we have no information on + // the toolchain being used, let's just allow unstable items to be listed. + let is_nightly = matches!(toolchain, Some(base_db::ReleaseChannel::Nightly) | None); + let mut locals = FxHashMap::default(); scope.process_all_names(&mut |name, scope| { if let ScopeDef::Local(local) = scope { @@ -634,6 +664,7 @@ impl<'a> CompletionContext<'a> { token, krate, module, + is_nightly, expected_name, expected_type, qualifier_ctx, diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index a94c404586b11..cc5221cfccbdc 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -609,14 +609,14 @@ fn classify_name_ref( _ => false, }; - let reciever_is_part_of_indivisible_expression = match &receiver { + let receiver_is_part_of_indivisible_expression = match &receiver { Some(ast::Expr::IfExpr(_)) => { let next_token_kind = next_non_trivia_token(name_ref.syntax().clone()).map(|t| t.kind()); next_token_kind == Some(SyntaxKind::ELSE_KW) }, _ => false }; - if reciever_is_part_of_indivisible_expression { + if receiver_is_part_of_indivisible_expression { return None; } @@ -1190,7 +1190,7 @@ fn pattern_context_for( }) }).and_then(|variants| { Some(variants.iter().filter_map(|variant| { - let variant_name = variant.name(sema.db).to_string(); + let variant_name = variant.name(sema.db).display(sema.db).to_string(); let variant_already_present = match_arm_list.arms().any(|arm| { arm.pat().and_then(|pat| { diff --git a/crates/ide-completion/src/item.rs b/crates/ide-completion/src/item.rs index bb9fa7ccaccc6..e850f7bfdf3f9 100644 --- a/crates/ide-completion/src/item.rs +++ b/crates/ide-completion/src/item.rs @@ -3,7 +3,8 @@ use std::fmt; use hir::{Documentation, Mutability}; -use ide_db::{imports::import_assets::LocatedImport, SnippetCap, SymbolKind}; +use ide_db::{imports::import_assets::LocatedImport, RootDatabase, SnippetCap, SymbolKind}; +use itertools::Itertools; use smallvec::SmallVec; use stdx::{impl_from, never}; use syntax::{SmolStr, TextRange, TextSize}; @@ -45,7 +46,7 @@ pub struct CompletionItem { /// /// That is, in `foo.bar$0` lookup of `abracadabra` will be accepted (it /// contains `bar` sub sequence), and `quux` will rejected. - pub lookup: Option, + pub lookup: SmolStr, /// Additional info to show in the UI pop up. pub detail: Option, @@ -75,7 +76,8 @@ pub struct CompletionItem { pub ref_match: Option<(Mutability, TextSize)>, /// The import data to add to completion's edits. - pub import_to_add: SmallVec<[LocatedImport; 1]>, + /// (ImportPath, LastSegment) + pub import_to_add: SmallVec<[(String, String); 1]>, } // We use custom debug for CompletionItem to make snapshot tests more readable. @@ -353,12 +355,13 @@ impl CompletionItem { relevance: CompletionRelevance::default(), ref_match: None, imports_to_add: Default::default(), + doc_aliases: vec![], } } /// What string is used for filtering. pub fn lookup(&self) -> &str { - self.lookup.as_deref().unwrap_or(&self.label) + self.lookup.as_str() } pub fn ref_match(&self) -> Option<(String, text_edit::Indel, CompletionRelevance)> { @@ -385,6 +388,7 @@ pub(crate) struct Builder { source_range: TextRange, imports_to_add: SmallVec<[LocatedImport; 1]>, trait_name: Option, + doc_aliases: Vec, label: SmolStr, insert_text: Option, is_snippet: bool, @@ -406,21 +410,31 @@ impl Builder { local_name: hir::Name, resolution: hir::ScopeDef, ) -> Self { - render_path_resolution(RenderContext::new(ctx), path_ctx, local_name, resolution) + let doc_aliases = ctx.doc_aliases_in_scope(resolution); + render_path_resolution( + RenderContext::new(ctx).doc_aliases(doc_aliases), + path_ctx, + local_name, + resolution, + ) } - pub(crate) fn build(self) -> CompletionItem { + pub(crate) fn build(self, db: &RootDatabase) -> CompletionItem { let _p = profile::span("item::Builder::build"); let mut label = self.label; - let mut lookup = self.lookup; + let mut lookup = self.lookup.unwrap_or_else(|| label.clone()); let insert_text = self.insert_text.unwrap_or_else(|| label.to_string()); + if !self.doc_aliases.is_empty() { + let doc_aliases = self.doc_aliases.into_iter().join(", "); + label = SmolStr::from(format!("{label} (alias {doc_aliases})")); + lookup = SmolStr::from(format!("{lookup} {doc_aliases}")); + } if let [import_edit] = &*self.imports_to_add { // snippets can have multiple imports, but normal completions only have up to one if let Some(original_path) = import_edit.original_path.as_ref() { - lookup = lookup.or_else(|| Some(label.clone())); - label = SmolStr::from(format!("{label} (use {original_path})")); + label = SmolStr::from(format!("{label} (use {})", original_path.display(db))); } } else if let Some(trait_name) = self.trait_name { label = SmolStr::from(format!("{label} (as {trait_name})")); @@ -431,6 +445,17 @@ impl Builder { None => TextEdit::replace(self.source_range, insert_text), }; + let import_to_add = self + .imports_to_add + .into_iter() + .filter_map(|import| { + Some(( + import.import_path.display(db).to_string(), + import.import_path.segments().last()?.display(db).to_string(), + )) + }) + .collect(); + CompletionItem { source_range: self.source_range, label, @@ -444,7 +469,7 @@ impl Builder { trigger_call_info: self.trigger_call_info, relevance: self.relevance, ref_match: self.ref_match, - import_to_add: self.imports_to_add, + import_to_add, } } pub(crate) fn lookup_by(&mut self, lookup: impl Into) -> &mut Builder { @@ -459,6 +484,10 @@ impl Builder { self.trait_name = Some(trait_name); self } + pub(crate) fn doc_aliases(&mut self, doc_aliases: Vec) -> &mut Builder { + self.doc_aliases = doc_aliases; + self + } pub(crate) fn insert_text(&mut self, insert_text: impl Into) -> &mut Builder { self.insert_text = Some(insert_text.into()); self diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs index 6fe7811140399..106d4e1e52f9a 100644 --- a/crates/ide-completion/src/lib.rs +++ b/crates/ide-completion/src/lib.rs @@ -97,7 +97,7 @@ pub use crate::{ /// Main entry point for completion. We run completion as a two-phase process. /// -/// First, we look at the position and collect a so-called `CompletionContext. +/// First, we look at the position and collect a so-called `CompletionContext`. /// This is a somewhat messy process, because, during completion, syntax tree is /// incomplete and can look really weird. /// @@ -133,7 +133,7 @@ pub use crate::{ /// /// Another case where this would be instrumental is macro expansion. We want to /// insert a fake ident and re-expand code. There's `expand_speculative` as a -/// work-around for this. +/// workaround for this. /// /// A different use-case is completion of injection (examples and links in doc /// comments). When computing completion for a path in a doc-comment, you want @@ -243,7 +243,7 @@ pub fn resolve_completion_edits( config.prefer_no_std, ) }) - .find(|mod_path| mod_path.to_string() == full_import_path); + .find(|mod_path| mod_path.display(db).to_string() == full_import_path); if let Some(import_path) = import { insert_use::insert_use(&new_ast, mod_path_to_ast(&import_path), &config.insert_use); } diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index c1f51aabb9676..1953eb4795772 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -32,11 +32,17 @@ pub(crate) struct RenderContext<'a> { completion: &'a CompletionContext<'a>, is_private_editable: bool, import_to_add: Option, + doc_aliases: Vec, } impl<'a> RenderContext<'a> { pub(crate) fn new(completion: &'a CompletionContext<'a>) -> RenderContext<'a> { - RenderContext { completion, is_private_editable: false, import_to_add: None } + RenderContext { + completion, + is_private_editable: false, + import_to_add: None, + doc_aliases: vec![], + } } pub(crate) fn private_editable(mut self, private_editable: bool) -> Self { @@ -49,6 +55,11 @@ impl<'a> RenderContext<'a> { self } + pub(crate) fn doc_aliases(mut self, doc_aliases: Vec) -> Self { + self.doc_aliases = doc_aliases; + self + } + fn snippet_cap(&self) -> Option { self.completion.config.snippet_cap } @@ -115,24 +126,25 @@ pub(crate) fn render_field( field: hir::Field, ty: &hir::Type, ) -> CompletionItem { + let db = ctx.db(); let is_deprecated = ctx.is_deprecated(field); - let name = field.name(ctx.db()); + let name = field.name(db); let (name, escaped_name) = (name.unescaped().to_smol_str(), name.to_smol_str()); let mut item = CompletionItem::new( SymbolKind::Field, ctx.source_range(), - field_with_receiver(receiver.as_ref(), &name), + field_with_receiver(db, receiver.as_ref(), &name), ); item.set_relevance(CompletionRelevance { type_match: compute_type_match(ctx.completion, ty), exact_name_match: compute_exact_name_match(ctx.completion, name.as_str()), ..CompletionRelevance::default() }); - item.detail(ty.display(ctx.db()).to_string()) - .set_documentation(field.docs(ctx.db())) + item.detail(ty.display(db).to_string()) + .set_documentation(field.docs(db)) .set_deprecated(is_deprecated) .lookup_by(name); - item.insert_text(field_with_receiver(receiver.as_ref(), &escaped_name)); + item.insert_text(field_with_receiver(db, receiver.as_ref(), &escaped_name)); if let Some(receiver) = &dot_access.receiver { if let Some(original) = ctx.completion.sema.original_ast_node(receiver.clone()) { if let Some(ref_match) = compute_ref_match(ctx.completion, ty) { @@ -140,11 +152,19 @@ pub(crate) fn render_field( } } } - item.build() + item.doc_aliases(ctx.doc_aliases); + item.build(db) } -fn field_with_receiver(receiver: Option<&hir::Name>, field_name: &str) -> SmolStr { - receiver.map_or_else(|| field_name.into(), |receiver| format!("{receiver}.{field_name}").into()) +fn field_with_receiver( + db: &RootDatabase, + receiver: Option<&hir::Name>, + field_name: &str, +) -> SmolStr { + receiver.map_or_else( + || field_name.into(), + |receiver| format!("{}.{field_name}", receiver.display(db)).into(), + ) } pub(crate) fn render_tuple_field( @@ -156,10 +176,10 @@ pub(crate) fn render_tuple_field( let mut item = CompletionItem::new( SymbolKind::Field, ctx.source_range(), - field_with_receiver(receiver.as_ref(), &field.to_string()), + field_with_receiver(ctx.db(), receiver.as_ref(), &field.to_string()), ); item.detail(ty.display(ctx.db()).to_string()).lookup_by(field.to_string()); - item.build() + item.build(ctx.db()) } pub(crate) fn render_type_inference( @@ -169,7 +189,7 @@ pub(crate) fn render_type_inference( let mut builder = CompletionItem::new(CompletionItemKind::InferredType, ctx.source_range(), ty_string); builder.set_relevance(CompletionRelevance { is_definite: true, ..Default::default() }); - builder.build() + builder.build(ctx.db) } pub(crate) fn render_path_resolution( @@ -197,7 +217,9 @@ pub(crate) fn render_resolution_with_import( ) -> Option { let resolution = ScopeDef::from(import_edit.original_item); let local_name = scope_def_to_name(resolution, &ctx, &import_edit)?; - + //this now just renders the alias text, but we need to find the aliases earlier and call this with the alias instead + let doc_aliases = ctx.completion.doc_aliases_in_scope(resolution); + let ctx = ctx.doc_aliases(doc_aliases); Some(render_resolution_path(ctx, path_ctx, local_name, Some(import_edit), resolution)) } @@ -305,7 +327,7 @@ fn render_resolution_path( item.lookup_by(name.clone()) .label(SmolStr::from_iter([&name, "<…>"])) .trigger_call_info() - .insert_snippet(cap, format!("{local_name}<$0>")); + .insert_snippet(cap, format!("{}<$0>", local_name.display(db))); } } } @@ -348,6 +370,8 @@ fn render_resolution_simple_( if let Some(import_to_add) = ctx.import_to_add { item.add_import(import_to_add); } + + item.doc_aliases(ctx.doc_aliases); item } diff --git a/crates/ide-completion/src/render/const_.rs b/crates/ide-completion/src/render/const_.rs index 70b19988ca733..3c73983c39a2b 100644 --- a/crates/ide-completion/src/render/const_.rs +++ b/crates/ide-completion/src/render/const_.rs @@ -29,5 +29,5 @@ fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option } item.insert_text(escaped_name); - Some(item.build()) + Some(item.build(ctx.db())) } diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs index 197592e78ce26..8afce8db5ea86 100644 --- a/crates/ide-completion/src/render/function.rs +++ b/crates/ide-completion/src/render/function.rs @@ -52,8 +52,13 @@ fn render( let (call, escaped_call) = match &func_kind { FuncKind::Method(_, Some(receiver)) => ( - format!("{}.{}", receiver.unescaped(), name.unescaped()).into(), - format!("{receiver}.{name}").into(), + format!( + "{}.{}", + receiver.unescaped().display(ctx.db()), + name.unescaped().display(ctx.db()) + ) + .into(), + format!("{}.{}", receiver.display(ctx.db()), name.display(ctx.db())).into(), ), _ => (name.unescaped().to_smol_str(), name.to_smol_str()), }; @@ -147,6 +152,8 @@ fn render( } } } + + item.doc_aliases(ctx.doc_aliases); item } diff --git a/crates/ide-completion/src/render/literal.rs b/crates/ide-completion/src/render/literal.rs index ed78fcd8e6529..728d236dff476 100644 --- a/crates/ide-completion/src/render/literal.rs +++ b/crates/ide-completion/src/render/literal.rs @@ -71,8 +71,10 @@ fn render( } None => (name.clone().into(), name.into(), false), }; - let (qualified_name, escaped_qualified_name) = - (qualified_name.unescaped().to_string(), qualified_name.to_string()); + let (qualified_name, escaped_qualified_name) = ( + qualified_name.unescaped().display(ctx.db()).to_string(), + qualified_name.display(ctx.db()).to_string(), + ); let snippet_cap = ctx.snippet_cap(); let mut rendered = match kind { @@ -98,7 +100,7 @@ fn render( } let label = format_literal_label(&qualified_name, kind, snippet_cap); let lookup = if qualified { - format_literal_lookup(&short_qualified_name.to_string(), kind) + format_literal_lookup(&short_qualified_name.display(ctx.db()).to_string(), kind) } else { format_literal_lookup(&qualified_name, kind) }; diff --git a/crates/ide-completion/src/render/macro_.rs b/crates/ide-completion/src/render/macro_.rs index 44e8860763329..ce7af1d3400e7 100644 --- a/crates/ide-completion/src/render/macro_.rs +++ b/crates/ide-completion/src/render/macro_.rs @@ -74,7 +74,7 @@ fn render( item.insert_text(banged_name(&escaped_name)).lookup_by(banged_name(&name)); } _ => { - cov_mark::hit!(dont_insert_macro_call_parens_unncessary); + cov_mark::hit!(dont_insert_macro_call_parens_unnecessary); item.insert_text(escaped_name); } }; @@ -140,8 +140,8 @@ mod tests { use crate::tests::check_edit; #[test] - fn dont_insert_macro_call_parens_unncessary() { - cov_mark::check!(dont_insert_macro_call_parens_unncessary); + fn dont_insert_macro_call_parens_unnecessary() { + cov_mark::check!(dont_insert_macro_call_parens_unnecessary); check_edit( "frobnicate", r#" diff --git a/crates/ide-completion/src/render/pattern.rs b/crates/ide-completion/src/render/pattern.rs index 9225c91bebf51..d06abc5e91e0b 100644 --- a/crates/ide-completion/src/render/pattern.rs +++ b/crates/ide-completion/src/render/pattern.rs @@ -57,7 +57,10 @@ pub(crate) fn render_variant_pat( let enum_ty = variant.parent_enum(ctx.db()).ty(ctx.db()); let (name, escaped_name) = match path { - Some(path) => (path.unescaped().to_string().into(), path.to_string().into()), + Some(path) => ( + path.unescaped().display(ctx.db()).to_string().into(), + path.display(ctx.db()).to_string().into(), + ), None => { let name = local_name.unwrap_or_else(|| variant.name(ctx.db())); (name.unescaped().to_smol_str(), name.to_smol_str()) @@ -121,7 +124,7 @@ fn build_completion( Some(snippet_cap) => item.insert_snippet(snippet_cap, pat), None => item.insert_text(pat), }; - item.build() + item.build(ctx.db()) } fn render_pat( @@ -172,7 +175,7 @@ fn render_record_as_pat( format!( "{name} {{ {}{} }}", fields.enumerate().format_with(", ", |(idx, field), f| { - f(&format_args!("{}${}", field.name(db), idx + 1)) + f(&format_args!("{}${}", field.name(db).display(db.upcast()), idx + 1)) }), if fields_omitted { ", .." } else { "" }, name = name diff --git a/crates/ide-completion/src/render/type_alias.rs b/crates/ide-completion/src/render/type_alias.rs index fbe120d2ac949..343ba7e28d8e0 100644 --- a/crates/ide-completion/src/render/type_alias.rs +++ b/crates/ide-completion/src/render/type_alias.rs @@ -53,5 +53,5 @@ fn render( } item.insert_text(escaped_name); - Some(item.build()) + Some(item.build(ctx.db())) } diff --git a/crates/ide-completion/src/render/union_literal.rs b/crates/ide-completion/src/render/union_literal.rs index 6e0c53ec94c43..93e943dbed98e 100644 --- a/crates/ide-completion/src/render/union_literal.rs +++ b/crates/ide-completion/src/render/union_literal.rs @@ -21,8 +21,10 @@ pub(crate) fn render_union_literal( let name = local_name.unwrap_or_else(|| un.name(ctx.db())); let (qualified_name, escaped_qualified_name) = match path { - Some(p) => (p.unescaped().to_string(), p.to_string()), - None => (name.unescaped().to_string(), name.to_string()), + Some(p) => (p.unescaped().display(ctx.db()).to_string(), p.display(ctx.db()).to_string()), + None => { + (name.unescaped().display(ctx.db()).to_string(), name.display(ctx.db()).to_string()) + } }; let label = format_literal_label(&name.to_smol_str(), StructKind::Record, ctx.snippet_cap()); let lookup = format_literal_lookup(&name.to_smol_str(), StructKind::Record); @@ -51,9 +53,9 @@ pub(crate) fn render_union_literal( format!( "{} {{ {} }}", escaped_qualified_name, - fields - .iter() - .format_with(", ", |field, f| { f(&format_args!("{}: ()", field.name(ctx.db()))) }) + fields.iter().format_with(", ", |field, f| { + f(&format_args!("{}: ()", field.name(ctx.db()).display(ctx.db()))) + }) ) }; @@ -61,7 +63,11 @@ pub(crate) fn render_union_literal( "{} {{ {}{} }}", qualified_name, fields.iter().format_with(", ", |field, f| { - f(&format_args!("{}: {}", field.name(ctx.db()), field.ty(ctx.db()).display(ctx.db()))) + f(&format_args!( + "{}: {}", + field.name(ctx.db()).display(ctx.db()), + field.ty(ctx.db()).display(ctx.db()) + )) }), if fields_omitted { ", .." } else { "" } ); @@ -76,5 +82,5 @@ pub(crate) fn render_union_literal( None => item.insert_text(literal), }; - Some(item.build()) + Some(item.build(ctx.db())) } diff --git a/crates/ide-completion/src/render/variant.rs b/crates/ide-completion/src/render/variant.rs index 55c55725be4f9..a9a01a3a30f5b 100644 --- a/crates/ide-completion/src/render/variant.rs +++ b/crates/ide-completion/src/render/variant.rs @@ -27,14 +27,14 @@ pub(crate) fn render_record_lit( } let completions = fields.iter().enumerate().format_with(", ", |(idx, field), f| { if snippet_cap.is_some() { - f(&format_args!("{}: ${{{}:()}}", field.name(db), idx + 1)) + f(&format_args!("{}: ${{{}:()}}", field.name(db).display(db.upcast()), idx + 1)) } else { - f(&format_args!("{}: ()", field.name(db))) + f(&format_args!("{}: ()", field.name(db).display(db.upcast()))) } }); let types = fields.iter().format_with(", ", |field, f| { - f(&format_args!("{}: {}", field.name(db), field.ty(db).display(db))) + f(&format_args!("{}: {}", field.name(db).display(db.upcast()), field.ty(db).display(db))) }); RenderedLiteral { diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs index 1fe48b9e96f9d..2464e8d5f8175 100644 --- a/crates/ide-completion/src/tests.rs +++ b/crates/ide-completion/src/tests.rs @@ -23,7 +23,8 @@ mod type_pos; mod use_tree; mod visibility; -use hir::{db::DefDatabase, PrefixKind}; +use expect_test::Expect; +use hir::PrefixKind; use ide_db::{ base_db::{fixture::ChangeFixture, FileLoader, FilePosition}, imports::insert_use::{ImportGranularity, InsertUseConfig}, @@ -104,7 +105,7 @@ fn completion_list_with_config( include_keywords: bool, trigger_character: Option, ) -> String { - // filter out all but one builtintype completion for smaller test outputs + // filter out all but one built-in type completion for smaller test outputs let items = get_all_items(config, ra_fixture, trigger_character); let items = items .into_iter() @@ -120,7 +121,7 @@ fn completion_list_with_config( pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { let change_fixture = ChangeFixture::parse(ra_fixture); let mut database = RootDatabase::default(); - database.set_enable_proc_attr_macros(true); + database.enable_proc_attr_macros(); database.apply_change(change_fixture.change); let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); let offset = range_or_offset.expect_offset(); @@ -197,11 +198,11 @@ pub(crate) fn check_edit_with_config( &db, &config, position, - completion.import_to_add.iter().filter_map(|import_edit| { - let import_path = &import_edit.import_path; - let import_name = import_path.segments().last()?; - Some((import_path.to_string(), import_name.to_string())) - }), + completion + .import_to_add + .iter() + .cloned() + .filter_map(|(import_path, import_name)| Some((import_path, import_name))), ) .into_iter() .flatten() @@ -215,6 +216,11 @@ pub(crate) fn check_edit_with_config( assert_eq_text!(&ra_fixture_after, &actual) } +fn check_empty(ra_fixture: &str, expect: Expect) { + let actual = completion_list(ra_fixture); + expect.assert_eq(&actual); +} + pub(crate) fn get_all_items( config: CompletionConfig, code: &str, diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs index c1c6a689eb18a..be5b7f8a3404e 100644 --- a/crates/ide-completion/src/tests/expression.rs +++ b/crates/ide-completion/src/tests/expression.rs @@ -1,18 +1,13 @@ //! Completion tests for expressions. use expect_test::{expect, Expect}; -use crate::tests::{check_edit, completion_list, BASE_ITEMS_FIXTURE}; +use crate::tests::{check_edit, check_empty, completion_list, BASE_ITEMS_FIXTURE}; fn check(ra_fixture: &str, expect: Expect) { let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}{ra_fixture}")); expect.assert_eq(&actual) } -fn check_empty(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); -} - #[test] fn complete_literal_struct_with_a_private_field() { // `FooDesc.bar` is private, the completion should not be triggered. @@ -672,7 +667,7 @@ fn main() { } #[test] -fn varaiant_with_struct() { +fn variant_with_struct() { check_empty( r#" pub struct YoloVariant { @@ -997,3 +992,105 @@ fn foo() { if foo {} el$0 { let x = 92; } } "#]], ); } + +#[test] +fn expr_no_unstable_item_on_stable() { + check_empty( + r#" +//- /main.rs crate:main deps:std +use std::*; +fn main() { + $0 +} +//- /std.rs crate:std +#[unstable] +pub struct UnstableThisShouldNotBeListed; +"#, + expect![[r#" + fn main() fn() + md std + bt u32 + kw const + kw crate:: + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw let + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); +} + +#[test] +fn expr_unstable_item_on_nightly() { + check_empty( + r#" +//- toolchain:nightly +//- /main.rs crate:main deps:std +use std::*; +fn main() { + $0 +} +//- /std.rs crate:std +#[unstable] +pub struct UnstableButWeAreOnNightlyAnyway; +"#, + expect![[r#" + fn main() fn() + md std + st UnstableButWeAreOnNightlyAnyway + bt u32 + kw const + kw crate:: + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw let + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); +} diff --git a/crates/ide-completion/src/tests/flyimport.rs b/crates/ide-completion/src/tests/flyimport.rs index 0b485eb776d8a..8c038c0fbaa1c 100644 --- a/crates/ide-completion/src/tests/flyimport.rs +++ b/crates/ide-completion/src/tests/flyimport.rs @@ -1107,6 +1107,41 @@ fn function() { ); } +#[test] +fn flyimport_pattern_no_unstable_item_on_stable() { + check( + r#" +//- /main.rs crate:main deps:std +fn function() { + let foo$0 +} +//- /std.rs crate:std +#[unstable] +pub struct FooStruct {} +"#, + expect![""], + ); +} + +#[test] +fn flyimport_pattern_unstable_item_on_nightly() { + check( + r#" +//- toolchain:nightly +//- /main.rs crate:main deps:std +fn function() { + let foo$0 +} +//- /std.rs crate:std +#[unstable] +pub struct FooStruct {} +"#, + expect![[r#" + st FooStruct (use std::FooStruct) + "#]], + ); +} + #[test] fn flyimport_item_name() { check( @@ -1230,3 +1265,24 @@ macro_rules! define_struct { "#]], ); } + +#[test] +fn macro_use_prelude_is_in_scope() { + check( + r#" +//- /main.rs crate:main deps:dep +#[macro_use] +extern crate dep; + +fn main() { + print$0 +} +//- /lib.rs crate:dep +#[macro_export] +macro_rules! println { + () => {} +} +"#, + expect![""], + ) +} diff --git a/crates/ide-completion/src/tests/item_list.rs b/crates/ide-completion/src/tests/item_list.rs index 9fc731bb11d57..2b5b4dd773c87 100644 --- a/crates/ide-completion/src/tests/item_list.rs +++ b/crates/ide-completion/src/tests/item_list.rs @@ -1,7 +1,7 @@ //! Completion tests for item list position. use expect_test::{expect, Expect}; -use crate::tests::{check_edit, completion_list, BASE_ITEMS_FIXTURE}; +use crate::tests::{check_edit, check_empty, completion_list, BASE_ITEMS_FIXTURE}; fn check(ra_fixture: &str, expect: Expect) { let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}{ra_fixture}")); @@ -297,6 +297,58 @@ impl Test for () { ); } +#[test] +fn in_trait_impl_no_unstable_item_on_stable() { + check_empty( + r#" +trait Test { + #[unstable] + type Type; + #[unstable] + const CONST: (); + #[unstable] + fn function(); +} + +impl Test for () { + $0 +} +"#, + expect![[r#" + kw crate:: + kw self:: + "#]], + ); +} + +#[test] +fn in_trait_impl_unstable_item_on_nightly() { + check_empty( + r#" +//- toolchain:nightly +trait Test { + #[unstable] + type Type; + #[unstable] + const CONST: (); + #[unstable] + fn function(); +} + +impl Test for () { + $0 +} +"#, + expect![[r#" + ct const CONST: () = + fn fn function() + ta type Type = + kw crate:: + kw self:: + "#]], + ); +} + #[test] fn after_unit_struct() { check( diff --git a/crates/ide-completion/src/tests/pattern.rs b/crates/ide-completion/src/tests/pattern.rs index c0e485c36fdd1..8af6cce98f635 100644 --- a/crates/ide-completion/src/tests/pattern.rs +++ b/crates/ide-completion/src/tests/pattern.rs @@ -1,12 +1,7 @@ //! Completion tests for pattern position. use expect_test::{expect, Expect}; -use crate::tests::{check_edit, completion_list, BASE_ITEMS_FIXTURE}; - -fn check_empty(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual) -} +use crate::tests::{check_edit, check_empty, completion_list, BASE_ITEMS_FIXTURE}; fn check(ra_fixture: &str, expect: Expect) { let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}\n{ra_fixture}")); @@ -742,3 +737,56 @@ fn f(x: EnumAlias) { "#]], ); } + +#[test] +fn pat_no_unstable_item_on_stable() { + check_empty( + r#" +//- /main.rs crate:main deps:std +use std::*; +fn foo() { + let a$0 +} +//- /std.rs crate:std +#[unstable] +pub struct S; +#[unstable] +pub enum Enum { + Variant +} +"#, + expect![[r#" + md std + kw mut + kw ref + "#]], + ); +} + +#[test] +fn pat_unstable_item_on_nightly() { + check_empty( + r#" +//- toolchain:nightly +//- /main.rs crate:main deps:std +use std::*; +fn foo() { + let a$0 +} +//- /std.rs crate:std +#[unstable] +pub struct S; +#[unstable] +pub enum Enum { + Variant +} +"#, + expect![[r#" + en Enum + md std + st S + kw mut + kw ref + "#]], + ); +} diff --git a/crates/ide-completion/src/tests/predicate.rs b/crates/ide-completion/src/tests/predicate.rs index 2656a4d545e66..789ad66345b12 100644 --- a/crates/ide-completion/src/tests/predicate.rs +++ b/crates/ide-completion/src/tests/predicate.rs @@ -1,7 +1,7 @@ //! Completion tests for predicates and bounds. use expect_test::{expect, Expect}; -use crate::tests::{completion_list, BASE_ITEMS_FIXTURE}; +use crate::tests::{check_empty, completion_list, BASE_ITEMS_FIXTURE}; fn check(ra_fixture: &str, expect: Expect) { let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}\n{ra_fixture}")); @@ -129,3 +129,43 @@ impl Record { "#]], ); } + +#[test] +fn pred_no_unstable_item_on_stable() { + check_empty( + r#" +//- /main.rs crate:main deps:std +use std::*; +struct Foo where T: $0 {} +//- /std.rs crate:std +#[unstable] +pub trait Trait {} +"#, + expect![[r#" + md std + kw crate:: + kw self:: + "#]], + ); +} + +#[test] +fn pred_unstable_item_on_nightly() { + check_empty( + r#" +//- toolchain:nightly +//- /main.rs crate:main deps:std +use std::*; +struct Foo where T: $0 {} +//- /std.rs crate:std +#[unstable] +pub trait Trait {} +"#, + expect![[r#" + md std + tt Trait + kw crate:: + kw self:: + "#]], + ); +} diff --git a/crates/ide-completion/src/tests/proc_macros.rs b/crates/ide-completion/src/tests/proc_macros.rs index 92ea4d15b8512..2d6234e310c60 100644 --- a/crates/ide-completion/src/tests/proc_macros.rs +++ b/crates/ide-completion/src/tests/proc_macros.rs @@ -81,7 +81,7 @@ impl Foo { } #[proc_macros::input_replace( - fn suprise() { + fn surprise() { Foo.$0 } )] @@ -114,7 +114,7 @@ impl Foo { } #[proc_macros::input_replace( - fn suprise() { + fn surprise() { Foo.f$0 } )] diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs index f8a6f6cd3ed06..3824720839eb9 100644 --- a/crates/ide-completion/src/tests/special.rs +++ b/crates/ide-completion/src/tests/special.rs @@ -989,3 +989,294 @@ fn foo { crate::::$0 } expect![""], ) } + +#[test] +fn completes_struct_via_doc_alias_in_fn_body() { + check( + r#" +#[doc(alias = "Bar")] +struct Foo; + +fn here_we_go() { + $0 +} +"#, + expect![[r#" + fn here_we_go() fn() + st Foo (alias Bar) + bt u32 + kw const + kw crate:: + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw let + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); +} + +#[test] +fn completes_struct_via_multiple_doc_aliases_in_fn_body() { + check( + r#" +#[doc(alias("Bar", "Qux"))] +#[doc(alias = "Baz")] +struct Foo; + +fn here_we_go() { + B$0 +} +"#, + expect![[r#" + fn here_we_go() fn() + st Foo (alias Bar, Qux, Baz) + bt u32 + kw const + kw crate:: + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw let + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); +} + +#[test] +fn completes_field_name_via_doc_alias_in_fn_body() { + check( + r#" +struct Foo { + #[doc(alias = "qux")] + bar: u8 +}; + +fn here_we_go() { + let foo = Foo { q$0 } +} +"#, + expect![[r#" + fd bar (alias qux) u8 + "#]], + ); +} + +#[test] +fn completes_struct_fn_name_via_doc_alias_in_fn_body() { + check( + r#" +struct Foo; +impl Foo { + #[doc(alias = "qux")] + fn bar() -> u8 { 1 } +} + +fn here_we_go() { + Foo::q$0 +} +"#, + expect![[r#" + fn bar() (alias qux) fn() -> u8 + "#]], + ); +} + +#[test] +fn completes_method_name_via_doc_alias_in_fn_body() { + check( + r#" +struct Foo { + bar: u8 +} +impl Foo { + #[doc(alias = "qux")] + fn baz(&self) -> u8 { + self.bar + } +} + +fn here_we_go() { + let foo = Foo { field: 42 }; + foo.q$0 +} +"#, + expect![[r#" + fd bar u8 + me baz() (alias qux) fn(&self) -> u8 + sn box Box::new(expr) + sn call function(expr) + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr + sn unsafe unsafe {} + "#]], + ); +} + +#[test] +fn completes_fn_name_via_doc_alias_in_fn_body() { + check( + r#" +#[doc(alias = "qux")] +fn foo() {} +fn bar() { qu$0 } +"#, + expect![[r#" + fn bar() fn() + fn foo() (alias qux) fn() + bt u32 + kw const + kw crate:: + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw let + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); +} + +#[test] +fn completes_struct_name_via_doc_alias_in_another_mod() { + check( + r#" +mod foo { + #[doc(alias = "Qux")] + pub struct Bar(u8); +} + +fn here_we_go() { + use foo; + let foo = foo::Q$0 +} +"#, + expect![[r#" + st Bar (alias Qux) + "#]], + ); +} + +#[test] +fn completes_use_via_doc_alias_in_another_mod() { + check( + r#" +mod foo { + #[doc(alias = "Qux")] + pub struct Bar(u8); +} + +fn here_we_go() { + use foo::Q$0; +} +"#, + expect![[r#" + st Bar (alias Qux) + "#]], + ); +} + +#[test] +fn completes_flyimport_with_doc_alias_in_another_mod() { + check( + r#" +mod foo { + #[doc(alias = "Qux")] + pub struct Bar(); +} + +fn here_we_go() { + let foo = Bar$0 +} +"#, + expect![[r#" + fn here_we_go() fn() + md foo + st Bar (alias Qux) (use foo::Bar) + bt u32 + kw crate:: + kw false + kw for + kw if + kw if let + kw loop + kw match + kw return + kw self:: + kw true + kw unsafe + kw while + kw while let + "#]], + ); +} diff --git a/crates/ide-completion/src/tests/type_pos.rs b/crates/ide-completion/src/tests/type_pos.rs index c3f4fb4d1817f..8cb1ff4a125f7 100644 --- a/crates/ide-completion/src/tests/type_pos.rs +++ b/crates/ide-completion/src/tests/type_pos.rs @@ -1,7 +1,7 @@ //! Completion tests for type position. use expect_test::{expect, Expect}; -use crate::tests::{completion_list, BASE_ITEMS_FIXTURE}; +use crate::tests::{check_empty, completion_list, BASE_ITEMS_FIXTURE}; fn check(ra_fixture: &str, expect: Expect) { let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}\n{ra_fixture}")); @@ -669,3 +669,53 @@ fn f(t: impl MyTrait {} } +"#, + expect![""], + ); +} + +#[test] +fn use_tree_unstable_items_on_nightly() { + check( + r#" +//- toolchain:nightly +//- /lib.rs crate:main deps:std +use std::$0 +//- /std.rs crate:std +#[unstable] +pub mod simd {} +#[unstable] +pub struct S; +#[unstable] +pub fn foo() {} +#[unstable] +#[macro_export] +marco_rules! m { () => {} } +"#, + expect![[r#" + fn foo fn() + md simd + st S + "#]], + ); +} diff --git a/crates/ide-db/Cargo.toml b/crates/ide-db/Cargo.toml index 57daaf623df29..4e75dc4dba541 100644 --- a/crates/ide-db/Cargo.toml +++ b/crates/ide-db/Cargo.toml @@ -23,6 +23,8 @@ itertools = "0.10.5" arrayvec = "0.7.2" indexmap = "1.9.1" memchr = "2.5.0" +triomphe.workspace = true +nohash-hasher.workspace = true # local deps base-db.workspace = true @@ -36,6 +38,8 @@ text-edit.workspace = true # something from some `hir-xxx` subpackage, reexport the API via `hir`. hir.workspace = true +line-index.workspace = true + [dev-dependencies] expect-test = "1.4.0" oorandom = "11.1.3" diff --git a/crates/ide-db/src/apply_change.rs b/crates/ide-db/src/apply_change.rs index ea1d9cc4919d3..8edda432ce398 100644 --- a/crates/ide-db/src/apply_change.rs +++ b/crates/ide-db/src/apply_change.rs @@ -1,13 +1,12 @@ //! Applies changes to the IDE state transactionally. -use std::sync::Arc; - use base_db::{ salsa::{Database, Durability}, Change, SourceRootId, }; use profile::{memory_usage, Bytes}; use rustc_hash::FxHashSet; +use triomphe::Arc; use crate::{symbol_index::SymbolsDatabase, RootDatabase}; @@ -64,6 +63,7 @@ impl RootDatabase { // SourceDatabase base_db::ParseQuery base_db::CrateGraphQuery + base_db::ProcMacrosQuery // SourceDatabaseExt base_db::FileTextQuery @@ -79,7 +79,6 @@ impl RootDatabase { hir::db::MacroDefQuery hir::db::MacroExpandQuery hir::db::ExpandProcMacroQuery - hir::db::MacroExpandErrorQuery hir::db::HygieneFrameQuery // DefDatabase diff --git a/crates/ide-db/src/assists.rs b/crates/ide-db/src/assists.rs index 8c6c1c44aa706..7a7328f312d20 100644 --- a/crates/ide-db/src/assists.rs +++ b/crates/ide-db/src/assists.rs @@ -98,7 +98,7 @@ impl FromStr for AssistKind { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct AssistId(pub &'static str, pub AssistKind); -/// A way to control how many asssist to resolve during the assist resolution. +/// A way to control how many assist to resolve during the assist resolution. /// When an assist is resolved, its edits are calculated that might be costly to always do by default. #[derive(Debug)] pub enum AssistResolveStrategy { diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs index 4071c490b7fc3..760834bfafc7b 100644 --- a/crates/ide-db/src/defs.rs +++ b/crates/ide-db/src/defs.rs @@ -8,8 +8,8 @@ use arrayvec::ArrayVec; use hir::{ Adt, AsAssocItem, AssocItem, BuiltinAttr, BuiltinType, Const, Crate, DeriveHelper, Field, - Function, GenericParam, HasVisibility, Impl, ItemInNs, Label, Local, Macro, Module, ModuleDef, - Name, PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias, TypeAlias, Variant, + Function, GenericParam, HasVisibility, Impl, Label, Local, Macro, Module, ModuleDef, Name, + PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias, TypeAlias, Variant, Visibility, }; use stdx::impl_from; @@ -622,22 +622,3 @@ impl From for Definition { } } } - -impl From for Option { - fn from(def: Definition) -> Self { - let item = match def { - Definition::Module(it) => ModuleDef::Module(it), - Definition::Function(it) => ModuleDef::Function(it), - Definition::Adt(it) => ModuleDef::Adt(it), - Definition::Variant(it) => ModuleDef::Variant(it), - Definition::Const(it) => ModuleDef::Const(it), - Definition::Static(it) => ModuleDef::Static(it), - Definition::Trait(it) => ModuleDef::Trait(it), - Definition::TraitAlias(it) => ModuleDef::TraitAlias(it), - Definition::TypeAlias(it) => ModuleDef::TypeAlias(it), - Definition::BuiltinType(it) => ModuleDef::BuiltinType(it), - _ => return None, - }; - Some(ItemInNs::from(item)) - } -} diff --git a/crates/ide-db/src/generated/lints.rs b/crates/ide-db/src/generated/lints.rs index f0c3690962aff..e488300b41caa 100644 --- a/crates/ide-db/src/generated/lints.rs +++ b/crates/ide-db/src/generated/lints.rs @@ -4230,7 +4230,7 @@ pub union GenericUnion { // Unions with non-`Copy` fields are unstable. pub const THIS_IS_OKAY: GenericUnion<()> = GenericUnion { field: () }; ``` -Like transarent `struct`s, a transparent `union` of type `U` has the same +Like transparent `struct`s, a transparent `union` of type `U` has the same layout, size, and ABI as its single non-ZST field. If it is generic over a type `T`, and all its fields are ZSTs except for exactly one field of type `T`, then it has the same layout and ABI as `T` (even if `T` is a ZST when monomorphized). @@ -6548,7 +6548,7 @@ subtracting elements in an Add impl."##, }, Lint { label: "clippy::suspicious_assignment_formatting", - description: r##"Checks for use of the non-existent `=*`, `=!` and `=-` + description: r##"Checks for use of the nonexistent `=*`, `=!` and `=-` operators."##, }, Lint { diff --git a/crates/ide-db/src/helpers.rs b/crates/ide-db/src/helpers.rs index 8e3b1eef15b2d..eba9d8afc40ab 100644 --- a/crates/ide-db/src/helpers.rs +++ b/crates/ide-db/src/helpers.rs @@ -77,7 +77,7 @@ pub fn visit_file_defs( } module.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.into())); - let is_root = module.is_crate_root(db); + let is_root = module.is_crate_root(); module .legacy_macros(db) .into_iter() diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs index b26b0a9087ea2..901d592c69104 100644 --- a/crates/ide-db/src/imports/import_assets.rs +++ b/crates/ide-db/src/imports/import_assets.rs @@ -362,12 +362,12 @@ fn import_for_item( let original_item_candidate = item_for_path_search(db, original_item)?; let import_path_candidate = mod_path(original_item_candidate)?; - let import_path_string = import_path_candidate.to_string(); + let import_path_string = import_path_candidate.display(db).to_string(); let expected_import_end = if item_as_assoc(db, original_item).is_some() { unresolved_qualifier.to_string() } else { - format!("{unresolved_qualifier}::{}", item_name(db, original_item)?) + format!("{unresolved_qualifier}::{}", item_name(db, original_item)?.display(db)) }; if !import_path_string.contains(unresolved_first_segment) || !import_path_string.ends_with(&expected_import_end) diff --git a/crates/ide-db/src/items_locator.rs b/crates/ide-db/src/items_locator.rs index 07a57c883b2d9..46f1353e2e1b0 100644 --- a/crates/ide-db/src/items_locator.rs +++ b/crates/ide-db/src/items_locator.rs @@ -5,17 +5,11 @@ use either::Either; use hir::{ import_map::{self, ImportKind}, - symbols::FileSymbol, AsAssocItem, Crate, ItemInNs, Semantics, }; use limit::Limit; -use syntax::{ast, AstNode, SyntaxKind::NAME}; -use crate::{ - defs::{Definition, NameClass}, - imports::import_assets::NameToImport, - symbol_index, RootDatabase, -}; +use crate::{imports::import_assets::NameToImport, symbol_index, RootDatabase}; /// A value to use, when uncertain which limit to pick. pub static DEFAULT_QUERY_SEARCH_LIMIT: Limit = Limit::new(40); @@ -115,12 +109,12 @@ fn find_items<'a>( }); // Query the local crate using the symbol index. - let local_results = symbol_index::crate_symbols(db, krate, local_query) + let local_results = local_query + .search(&symbol_index::crate_symbols(db, krate)) .into_iter() - .filter_map(move |local_candidate| get_name_definition(sema, &local_candidate)) - .filter_map(|name_definition_to_import| match name_definition_to_import { - Definition::Macro(macro_def) => Some(ItemInNs::from(macro_def)), - def => >::from(def), + .filter_map(|local_candidate| match local_candidate.def { + hir::ModuleDef::Macro(macro_def) => Some(ItemInNs::Macros(macro_def)), + def => Some(ItemInNs::from(def)), }); external_importables.chain(local_results).filter(move |&item| match assoc_item_search { @@ -130,22 +124,6 @@ fn find_items<'a>( }) } -fn get_name_definition( - sema: &Semantics<'_, RootDatabase>, - import_candidate: &FileSymbol, -) -> Option { - let _p = profile::span("get_name_definition"); - - let candidate_node = import_candidate.loc.syntax(sema)?; - let candidate_name_node = if candidate_node.kind() != NAME { - candidate_node.children().find(|it| it.kind() == NAME)? - } else { - candidate_node - }; - let name = ast::Name::cast(candidate_name_node)?; - NameClass::classify(sema, &name)?.defined() -} - fn is_assoc_item(item: ItemInNs, db: &RootDatabase) -> bool { item.as_module_def().and_then(|module_def| module_def.as_assoc_item(db)).is_some() } diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs index b1df11bf91172..ff1a20f03f44c 100644 --- a/crates/ide-db/src/lib.rs +++ b/crates/ide-db/src/lib.rs @@ -13,7 +13,6 @@ pub mod famous_defs; pub mod helpers; pub mod items_locator; pub mod label; -pub mod line_index; pub mod path_transform; pub mod rename; pub mod rust_doc; @@ -43,21 +42,20 @@ pub mod syntax_helpers { pub use parser::LexedStr; } -use std::{fmt, mem::ManuallyDrop, sync::Arc}; +use std::{fmt, mem::ManuallyDrop}; use base_db::{ salsa::{self, Durability}, AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast, }; -use hir::{ - db::{DefDatabase, ExpandDatabase, HirDatabase}, - symbols::FileSymbolKind, -}; -use stdx::hash::NoHashHashSet; +use hir::db::{DefDatabase, ExpandDatabase, HirDatabase}; +use triomphe::Arc; use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase}; pub use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; +pub use ::line_index; + /// `base_db` is normally also needed in places where `ide_db` is used, so this re-export is for convenience. pub use base_db; @@ -114,13 +112,13 @@ impl Upcast for RootDatabase { } impl FileLoader for RootDatabase { - fn file_text(&self, file_id: FileId) -> Arc { + fn file_text(&self, file_id: FileId) -> Arc { FileLoaderDelegate(self).file_text(file_id) } fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { FileLoaderDelegate(self).resolve_path(path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } } @@ -137,18 +135,186 @@ impl RootDatabase { pub fn new(lru_capacity: Option) -> RootDatabase { let mut db = RootDatabase { storage: ManuallyDrop::new(salsa::Storage::default()) }; db.set_crate_graph_with_durability(Default::default(), Durability::HIGH); + db.set_proc_macros_with_durability(Default::default(), Durability::HIGH); db.set_local_roots_with_durability(Default::default(), Durability::HIGH); db.set_library_roots_with_durability(Default::default(), Durability::HIGH); - db.set_enable_proc_attr_macros(false); - db.update_lru_capacity(lru_capacity); + db.set_expand_proc_attr_macros_with_durability(false, Durability::HIGH); + db.update_parse_query_lru_capacity(lru_capacity); db } - pub fn update_lru_capacity(&mut self, lru_capacity: Option) { - let lru_capacity = lru_capacity.unwrap_or(base_db::DEFAULT_LRU_CAP); + pub fn enable_proc_attr_macros(&mut self) { + self.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH); + } + + pub fn update_parse_query_lru_capacity(&mut self, lru_capacity: Option) { + let lru_capacity = lru_capacity.unwrap_or(base_db::DEFAULT_PARSE_LRU_CAP); base_db::ParseQuery.in_db_mut(self).set_lru_capacity(lru_capacity); - hir::db::ParseMacroExpansionQuery.in_db_mut(self).set_lru_capacity(lru_capacity); - hir::db::MacroExpandQuery.in_db_mut(self).set_lru_capacity(lru_capacity); + // macro expansions are usually rather small, so we can afford to keep more of them alive + hir::db::ParseMacroExpansionQuery.in_db_mut(self).set_lru_capacity(4 * lru_capacity); + hir::db::MacroExpandQuery.in_db_mut(self).set_lru_capacity(4 * lru_capacity); + } + + pub fn update_lru_capacities(&mut self, lru_capacities: &FxHashMap, usize>) { + use hir::db as hir_db; + + base_db::ParseQuery.in_db_mut(self).set_lru_capacity( + lru_capacities + .get(stringify!(ParseQuery)) + .copied() + .unwrap_or(base_db::DEFAULT_PARSE_LRU_CAP), + ); + hir_db::ParseMacroExpansionQuery.in_db_mut(self).set_lru_capacity( + lru_capacities + .get(stringify!(ParseMacroExpansionQuery)) + .copied() + .unwrap_or(4 * base_db::DEFAULT_PARSE_LRU_CAP), + ); + hir_db::MacroExpandQuery.in_db_mut(self).set_lru_capacity( + lru_capacities + .get(stringify!(MacroExpandQuery)) + .copied() + .unwrap_or(4 * base_db::DEFAULT_PARSE_LRU_CAP), + ); + + macro_rules! update_lru_capacity_per_query { + ($( $module:ident :: $query:ident )*) => {$( + if let Some(&cap) = lru_capacities.get(stringify!($query)) { + $module::$query.in_db_mut(self).set_lru_capacity(cap); + } + )*} + } + update_lru_capacity_per_query![ + // SourceDatabase + // base_db::ParseQuery + // base_db::CrateGraphQuery + // base_db::ProcMacrosQuery + + // SourceDatabaseExt + // base_db::FileTextQuery + // base_db::FileSourceRootQuery + // base_db::SourceRootQuery + base_db::SourceRootCratesQuery + + // ExpandDatabase + hir_db::AstIdMapQuery + // hir_db::ParseMacroExpansionQuery + // hir_db::InternMacroCallQuery + hir_db::MacroArgTextQuery + hir_db::MacroDefQuery + // hir_db::MacroExpandQuery + hir_db::ExpandProcMacroQuery + hir_db::HygieneFrameQuery + hir_db::ParseMacroExpansionErrorQuery + + // DefDatabase + hir_db::FileItemTreeQuery + hir_db::CrateDefMapQueryQuery + hir_db::BlockDefMapQuery + hir_db::StructDataQuery + hir_db::StructDataWithDiagnosticsQuery + hir_db::UnionDataQuery + hir_db::UnionDataWithDiagnosticsQuery + hir_db::EnumDataQuery + hir_db::EnumDataWithDiagnosticsQuery + hir_db::ImplDataQuery + hir_db::ImplDataWithDiagnosticsQuery + hir_db::TraitDataQuery + hir_db::TraitDataWithDiagnosticsQuery + hir_db::TraitAliasDataQuery + hir_db::TypeAliasDataQuery + hir_db::FunctionDataQuery + hir_db::ConstDataQuery + hir_db::StaticDataQuery + hir_db::Macro2DataQuery + hir_db::MacroRulesDataQuery + hir_db::ProcMacroDataQuery + hir_db::BodyWithSourceMapQuery + hir_db::BodyQuery + hir_db::ExprScopesQuery + hir_db::GenericParamsQuery + hir_db::VariantsAttrsQuery + hir_db::FieldsAttrsQuery + hir_db::VariantsAttrsSourceMapQuery + hir_db::FieldsAttrsSourceMapQuery + hir_db::AttrsQuery + hir_db::CrateLangItemsQuery + hir_db::LangItemQuery + hir_db::ImportMapQuery + hir_db::FieldVisibilitiesQuery + hir_db::FunctionVisibilityQuery + hir_db::ConstVisibilityQuery + hir_db::CrateSupportsNoStdQuery + + // HirDatabase + hir_db::InferQueryQuery + hir_db::MirBodyQuery + hir_db::BorrowckQuery + hir_db::TyQuery + hir_db::ValueTyQuery + hir_db::ImplSelfTyQuery + hir_db::ConstParamTyQuery + hir_db::ConstEvalQuery + hir_db::ConstEvalDiscriminantQuery + hir_db::ImplTraitQuery + hir_db::FieldTypesQuery + hir_db::LayoutOfAdtQuery + hir_db::TargetDataLayoutQuery + hir_db::CallableItemSignatureQuery + hir_db::ReturnTypeImplTraitsQuery + hir_db::GenericPredicatesForParamQuery + hir_db::GenericPredicatesQuery + hir_db::TraitEnvironmentQuery + hir_db::GenericDefaultsQuery + hir_db::InherentImplsInCrateQuery + hir_db::InherentImplsInBlockQuery + hir_db::IncoherentInherentImplCratesQuery + hir_db::TraitImplsInCrateQuery + hir_db::TraitImplsInBlockQuery + hir_db::TraitImplsInDepsQuery + // hir_db::InternCallableDefQuery + // hir_db::InternLifetimeParamIdQuery + // hir_db::InternImplTraitIdQuery + // hir_db::InternTypeOrConstParamIdQuery + // hir_db::InternClosureQuery + // hir_db::InternGeneratorQuery + hir_db::AssociatedTyDataQuery + hir_db::TraitDatumQuery + hir_db::StructDatumQuery + hir_db::ImplDatumQuery + hir_db::FnDefDatumQuery + hir_db::FnDefVarianceQuery + hir_db::AdtVarianceQuery + hir_db::AssociatedTyValueQuery + hir_db::TraitSolveQueryQuery + hir_db::ProgramClausesForChalkEnvQuery + + // SymbolsDatabase + symbol_index::ModuleSymbolsQuery + symbol_index::LibrarySymbolsQuery + // symbol_index::LocalRootsQuery + // symbol_index::LibraryRootsQuery + + // LineIndexDatabase + crate::LineIndexQuery + + // InternDatabase + // hir_db::InternFunctionQuery + // hir_db::InternStructQuery + // hir_db::InternUnionQuery + // hir_db::InternEnumQuery + // hir_db::InternConstQuery + // hir_db::InternStaticQuery + // hir_db::InternTraitQuery + // hir_db::InternTraitAliasQuery + // hir_db::InternTypeAliasQuery + // hir_db::InternImplQuery + // hir_db::InternExternBlockQuery + // hir_db::InternBlockQuery + // hir_db::InternMacro2Query + // hir_db::InternProcMacroQuery + // hir_db::InternMacroRulesQuery + ]; } } @@ -211,20 +377,22 @@ impl From for SymbolKind { } } -impl From for SymbolKind { - fn from(it: FileSymbolKind) -> Self { +impl From for SymbolKind { + fn from(it: hir::ModuleDefId) -> Self { match it { - FileSymbolKind::Const => SymbolKind::Const, - FileSymbolKind::Enum => SymbolKind::Enum, - FileSymbolKind::Function => SymbolKind::Function, - FileSymbolKind::Macro => SymbolKind::Macro, - FileSymbolKind::Module => SymbolKind::Module, - FileSymbolKind::Static => SymbolKind::Static, - FileSymbolKind::Struct => SymbolKind::Struct, - FileSymbolKind::Trait => SymbolKind::Trait, - FileSymbolKind::TraitAlias => SymbolKind::TraitAlias, - FileSymbolKind::TypeAlias => SymbolKind::TypeAlias, - FileSymbolKind::Union => SymbolKind::Union, + hir::ModuleDefId::ConstId(..) => SymbolKind::Const, + hir::ModuleDefId::EnumVariantId(..) => SymbolKind::Variant, + hir::ModuleDefId::FunctionId(..) => SymbolKind::Function, + hir::ModuleDefId::MacroId(..) => SymbolKind::Macro, + hir::ModuleDefId::ModuleId(..) => SymbolKind::Module, + hir::ModuleDefId::StaticId(..) => SymbolKind::Static, + hir::ModuleDefId::AdtId(hir::AdtId::StructId(..)) => SymbolKind::Struct, + hir::ModuleDefId::AdtId(hir::AdtId::EnumId(..)) => SymbolKind::Enum, + hir::ModuleDefId::AdtId(hir::AdtId::UnionId(..)) => SymbolKind::Union, + hir::ModuleDefId::TraitId(..) => SymbolKind::Trait, + hir::ModuleDefId::TraitAliasId(..) => SymbolKind::TraitAlias, + hir::ModuleDefId::TypeAliasId(..) => SymbolKind::TypeAlias, + hir::ModuleDefId::BuiltinType(..) => SymbolKind::TypeAlias, } } } @@ -247,4 +415,5 @@ impl SnippetCap { #[cfg(test)] mod tests { mod sourcegen_lints; + mod line_index; } diff --git a/crates/ide-db/src/line_index.rs b/crates/ide-db/src/line_index.rs deleted file mode 100644 index 16814a1e636fa..0000000000000 --- a/crates/ide-db/src/line_index.rs +++ /dev/null @@ -1,314 +0,0 @@ -//! `LineIndex` maps flat `TextSize` offsets into `(Line, Column)` -//! representation. -use std::{iter, mem}; - -use stdx::hash::NoHashHashMap; -use syntax::{TextRange, TextSize}; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct LineIndex { - /// Offset the beginning of each line, zero-based. - pub(crate) newlines: Vec, - /// List of non-ASCII characters on each line. - pub(crate) line_wide_chars: NoHashHashMap>, -} - -/// Line/Column information in native, utf8 format. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LineCol { - /// Zero-based - pub line: u32, - /// Zero-based utf8 offset - pub col: u32, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum WideEncoding { - Utf16, - Utf32, -} - -/// Line/Column information in legacy encodings. -/// -/// Deliberately not a generic type and different from `LineCol`. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct WideLineCol { - /// Zero-based - pub line: u32, - /// Zero-based - pub col: u32, -} - -#[derive(Clone, Debug, Hash, PartialEq, Eq)] -pub(crate) struct WideChar { - /// Start offset of a character inside a line, zero-based - pub(crate) start: TextSize, - /// End offset of a character inside a line, zero-based - pub(crate) end: TextSize, -} - -impl WideChar { - /// Returns the length in 8-bit UTF-8 code units. - fn len(&self) -> TextSize { - self.end - self.start - } - - /// Returns the length in UTF-16 or UTF-32 code units. - fn wide_len(&self, enc: WideEncoding) -> usize { - match enc { - WideEncoding::Utf16 => { - if self.len() == TextSize::from(4) { - 2 - } else { - 1 - } - } - - WideEncoding::Utf32 => 1, - } - } -} - -impl LineIndex { - pub fn new(text: &str) -> LineIndex { - let mut line_wide_chars = NoHashHashMap::default(); - let mut wide_chars = Vec::new(); - - let mut newlines = Vec::with_capacity(16); - newlines.push(TextSize::from(0)); - - let mut curr_row = 0.into(); - let mut curr_col = 0.into(); - let mut line = 0; - for c in text.chars() { - let c_len = TextSize::of(c); - curr_row += c_len; - if c == '\n' { - newlines.push(curr_row); - - // Save any utf-16 characters seen in the previous line - if !wide_chars.is_empty() { - line_wide_chars.insert(line, mem::take(&mut wide_chars)); - } - - // Prepare for processing the next line - curr_col = 0.into(); - line += 1; - continue; - } - - if !c.is_ascii() { - wide_chars.push(WideChar { start: curr_col, end: curr_col + c_len }); - } - - curr_col += c_len; - } - - // Save any utf-16 characters seen in the last line - if !wide_chars.is_empty() { - line_wide_chars.insert(line, wide_chars); - } - - LineIndex { newlines, line_wide_chars } - } - - pub fn line_col(&self, offset: TextSize) -> LineCol { - let line = self.newlines.partition_point(|&it| it <= offset) - 1; - let line_start_offset = self.newlines[line]; - let col = offset - line_start_offset; - LineCol { line: line as u32, col: col.into() } - } - - pub fn offset(&self, line_col: LineCol) -> Option { - self.newlines - .get(line_col.line as usize) - .map(|offset| offset + TextSize::from(line_col.col)) - } - - pub fn to_wide(&self, enc: WideEncoding, line_col: LineCol) -> WideLineCol { - let col = self.utf8_to_wide_col(enc, line_col.line, line_col.col.into()); - WideLineCol { line: line_col.line, col: col as u32 } - } - - pub fn to_utf8(&self, enc: WideEncoding, line_col: WideLineCol) -> LineCol { - let col = self.wide_to_utf8_col(enc, line_col.line, line_col.col); - LineCol { line: line_col.line, col: col.into() } - } - - pub fn lines(&self, range: TextRange) -> impl Iterator + '_ { - let lo = self.newlines.partition_point(|&it| it < range.start()); - let hi = self.newlines.partition_point(|&it| it <= range.end()); - let all = iter::once(range.start()) - .chain(self.newlines[lo..hi].iter().copied()) - .chain(iter::once(range.end())); - - all.clone() - .zip(all.skip(1)) - .map(|(lo, hi)| TextRange::new(lo, hi)) - .filter(|it| !it.is_empty()) - } - - fn utf8_to_wide_col(&self, enc: WideEncoding, line: u32, col: TextSize) -> usize { - let mut res: usize = col.into(); - if let Some(wide_chars) = self.line_wide_chars.get(&line) { - for c in wide_chars { - if c.end <= col { - res -= usize::from(c.len()) - c.wide_len(enc); - } else { - // From here on, all utf16 characters come *after* the character we are mapping, - // so we don't need to take them into account - break; - } - } - } - res - } - - fn wide_to_utf8_col(&self, enc: WideEncoding, line: u32, mut col: u32) -> TextSize { - if let Some(wide_chars) = self.line_wide_chars.get(&line) { - for c in wide_chars { - if col > u32::from(c.start) { - col += u32::from(c.len()) - c.wide_len(enc) as u32; - } else { - // From here on, all utf16 characters come *after* the character we are mapping, - // so we don't need to take them into account - break; - } - } - } - - col.into() - } -} - -#[cfg(test)] -mod tests { - use test_utils::skip_slow_tests; - - use super::WideEncoding::{Utf16, Utf32}; - use super::*; - - #[test] - fn test_line_index() { - let text = "hello\nworld"; - let table = [ - (00, 0, 0), - (01, 0, 1), - (05, 0, 5), - (06, 1, 0), - (07, 1, 1), - (08, 1, 2), - (10, 1, 4), - (11, 1, 5), - (12, 1, 6), - ]; - - let index = LineIndex::new(text); - for (offset, line, col) in table { - assert_eq!(index.line_col(offset.into()), LineCol { line, col }); - } - - let text = "\nhello\nworld"; - let table = [(0, 0, 0), (1, 1, 0), (2, 1, 1), (6, 1, 5), (7, 2, 0)]; - let index = LineIndex::new(text); - for (offset, line, col) in table { - assert_eq!(index.line_col(offset.into()), LineCol { line, col }); - } - } - - #[test] - fn test_char_len() { - assert_eq!('メ'.len_utf8(), 3); - assert_eq!('メ'.len_utf16(), 1); - } - - #[test] - fn test_empty_index() { - let col_index = LineIndex::new( - " -const C: char = 'x'; -", - ); - assert_eq!(col_index.line_wide_chars.len(), 0); - } - - #[test] - fn test_every_chars() { - if skip_slow_tests() { - return; - } - - let text: String = { - let mut chars: Vec = ((0 as char)..char::MAX).collect(); // Neat! - chars.extend("\n".repeat(chars.len() / 16).chars()); - let mut rng = oorandom::Rand32::new(stdx::rand::seed()); - stdx::rand::shuffle(&mut chars, |i| rng.rand_range(0..i as u32) as usize); - chars.into_iter().collect() - }; - assert!(text.contains('💩')); // Sanity check. - - let line_index = LineIndex::new(&text); - - let mut lin_col = LineCol { line: 0, col: 0 }; - let mut col_utf16 = 0; - let mut col_utf32 = 0; - for (offset, c) in text.char_indices() { - let got_offset = line_index.offset(lin_col).unwrap(); - assert_eq!(usize::from(got_offset), offset); - - let got_lin_col = line_index.line_col(got_offset); - assert_eq!(got_lin_col, lin_col); - - for enc in [Utf16, Utf32] { - let wide_lin_col = line_index.to_wide(enc, lin_col); - let got_lin_col = line_index.to_utf8(enc, wide_lin_col); - assert_eq!(got_lin_col, lin_col); - - let want_col = match enc { - Utf16 => col_utf16, - Utf32 => col_utf32, - }; - assert_eq!(wide_lin_col.col, want_col) - } - - if c == '\n' { - lin_col.line += 1; - lin_col.col = 0; - col_utf16 = 0; - col_utf32 = 0; - } else { - lin_col.col += c.len_utf8() as u32; - col_utf16 += c.len_utf16() as u32; - col_utf32 += 1; - } - } - } - - #[test] - fn test_splitlines() { - fn r(lo: u32, hi: u32) -> TextRange { - TextRange::new(lo.into(), hi.into()) - } - - let text = "a\nbb\nccc\n"; - let line_index = LineIndex::new(text); - - let actual = line_index.lines(r(0, 9)).collect::>(); - let expected = vec![r(0, 2), r(2, 5), r(5, 9)]; - assert_eq!(actual, expected); - - let text = ""; - let line_index = LineIndex::new(text); - - let actual = line_index.lines(r(0, 0)).collect::>(); - let expected = vec![]; - assert_eq!(actual, expected); - - let text = "\n"; - let line_index = LineIndex::new(text); - - let actual = line_index.lines(r(0, 1)).collect::>(); - let expected = vec![r(0, 1)]; - assert_eq!(actual, expected) - } -} diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs index 6402a84a68bb3..0ee627a44c68e 100644 --- a/crates/ide-db/src/path_transform.rs +++ b/crates/ide-db/src/path_transform.rs @@ -116,7 +116,9 @@ impl<'a> PathTransform<'a> { Some(( k, ast::make::ty( - &default.display_source_code(db, source_module.into()).ok()?, + &default + .display_source_code(db, source_module.into(), false) + .ok()?, ), )) } diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs index f710211c8cb0f..52a23b4b8f3d2 100644 --- a/crates/ide-db/src/rename.rs +++ b/crates/ide-db/src/rename.rs @@ -178,7 +178,7 @@ fn rename_mod( let mut source_change = SourceChange::default(); - if module.is_crate_root(sema.db) { + if module.is_crate_root() { return Ok(source_change); } @@ -202,12 +202,13 @@ fn rename_mod( // - Module has submodules defined in separate files let dir_paths = match (is_mod_rs, has_detached_child, module.name(sema.db)) { // Go up one level since the anchor is inside the dir we're trying to rename - (true, _, Some(mod_name)) => { - Some((format!("../{}", mod_name.unescaped()), format!("../{new_name}"))) - } + (true, _, Some(mod_name)) => Some(( + format!("../{}", mod_name.unescaped().display(sema.db)), + format!("../{new_name}"), + )), // The anchor is on the same level as target dir (false, true, Some(mod_name)) => { - Some((mod_name.unescaped().to_string(), new_name.to_string())) + Some((mod_name.unescaped().display(sema.db).to_string(), new_name.to_owned())) } _ => None, }; @@ -232,7 +233,7 @@ fn rename_mod( { source_change.insert_source_edit( file_id, - TextEdit::replace(file_range.range, new_name.to_string()), + TextEdit::replace(file_range.range, new_name.to_owned()), ) }; } @@ -442,7 +443,7 @@ fn source_edit_from_name_ref( let s = field_name.syntax().text_range().start(); let e = pat.syntax().text_range().start(); edit.delete(TextRange::new(s, e)); - edit.replace(name.syntax().text_range(), new_name.to_string()); + edit.replace(name.syntax().text_range(), new_name.to_owned()); return true; } } @@ -462,7 +463,19 @@ fn source_edit_from_def( if let Definition::Local(local) = def { let mut file_id = None; for source in local.sources(sema.db) { - let source = source.source; + let source = match source.source.clone().original_ast_node(sema.db) { + Some(source) => source, + None => match source.source.syntax().original_file_range_opt(sema.db) { + Some(FileRange { file_id: file_id2, range }) => { + file_id = Some(file_id2); + edit.replace(range, new_name.to_owned()); + continue; + } + None => { + bail!("Can't rename local that is defined in a macro declaration") + } + }, + }; file_id = source.file_id.file_id(); if let Either::Left(pat) = source.value { let name_range = pat.name().unwrap().syntax().text_range(); @@ -485,7 +498,7 @@ fn source_edit_from_def( // Foo { field: ref mut local @ local 2} -> Foo { field: ref mut new_name @ local2 } // Foo { field: ref mut local } -> Foo { field: ref mut new_name } // ^^^^^ replace this with `new_name` - edit.replace(name_range, new_name.to_string()); + edit.replace(name_range, new_name.to_owned()); } } else { // Foo { ref mut field } -> Foo { field: ref mut new_name } @@ -495,10 +508,10 @@ fn source_edit_from_def( pat.syntax().text_range().start(), format!("{}: ", pat_field.field_name().unwrap()), ); - edit.replace(name_range, new_name.to_string()); + edit.replace(name_range, new_name.to_owned()); } } else { - edit.replace(name_range, new_name.to_string()); + edit.replace(name_range, new_name.to_owned()); } } } diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index 12f5e4e2a23a8..73cd5dcaf23fc 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -4,17 +4,18 @@ //! get a super-set of matches. Then, we we confirm each match using precise //! name resolution. -use std::{mem, sync::Arc}; +use std::mem; use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt}; use hir::{ AsAssocItem, DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility, }; use memchr::memmem::Finder; +use nohash_hasher::IntMap; use once_cell::unsync::Lazy; use parser::SyntaxKind; -use stdx::hash::NoHashHashMap; use syntax::{ast, match_ast, AstNode, TextRange, TextSize}; +use triomphe::Arc; use crate::{ defs::{Definition, NameClass, NameRefClass}, @@ -24,7 +25,7 @@ use crate::{ #[derive(Debug, Default, Clone)] pub struct UsageSearchResult { - pub references: NoHashHashMap>, + pub references: IntMap>, } impl UsageSearchResult { @@ -49,7 +50,7 @@ impl UsageSearchResult { impl IntoIterator for UsageSearchResult { type Item = (FileId, Vec); - type IntoIter = > as IntoIterator>::IntoIter; + type IntoIter = > as IntoIterator>::IntoIter; fn into_iter(self) -> Self::IntoIter { self.references.into_iter() @@ -83,17 +84,17 @@ pub enum ReferenceCategory { /// e.g. for things like local variables. #[derive(Clone, Debug)] pub struct SearchScope { - entries: NoHashHashMap>, + entries: IntMap>, } impl SearchScope { - fn new(entries: NoHashHashMap>) -> SearchScope { + fn new(entries: IntMap>) -> SearchScope { SearchScope { entries } } /// Build a search scope spanning the entire crate graph of files. fn crate_graph(db: &RootDatabase) -> SearchScope { - let mut entries = NoHashHashMap::default(); + let mut entries = IntMap::default(); let graph = db.crate_graph(); for krate in graph.iter() { @@ -107,7 +108,7 @@ impl SearchScope { /// Build a search scope spanning all the reverse dependencies of the given crate. fn reverse_dependencies(db: &RootDatabase, of: hir::Crate) -> SearchScope { - let mut entries = NoHashHashMap::default(); + let mut entries = IntMap::default(); for rev_dep in of.transitive_reverse_dependencies(db) { let root_file = rev_dep.root_file(db); let source_root_id = db.file_source_root(root_file); @@ -127,7 +128,7 @@ impl SearchScope { /// Build a search scope spanning the given module and all its submodules. fn module_and_children(db: &RootDatabase, module: hir::Module) -> SearchScope { - let mut entries = NoHashHashMap::default(); + let mut entries = IntMap::default(); let (file_id, range) = { let InFile { file_id, value } = module.definition_source(db); @@ -160,7 +161,7 @@ impl SearchScope { /// Build an empty search scope. pub fn empty() -> SearchScope { - SearchScope::new(NoHashHashMap::default()) + SearchScope::new(IntMap::default()) } /// Build a empty search scope spanning the given file. @@ -224,7 +225,7 @@ impl Definition { // def is crate root // FIXME: We don't do searches for crates currently, as a crate does not actually have a single name if let &Definition::Module(module) = self { - if module.is_crate_root(db) { + if module.is_crate_root() { return SearchScope::reverse_dependencies(db, module.krate()); } } @@ -391,7 +392,7 @@ impl<'a> FindUsages<'a> { let name = match self.def { // special case crate modules as these do not have a proper name - Definition::Module(module) if module.is_crate_root(self.sema.db) => { + Definition::Module(module) if module.is_crate_root() => { // FIXME: This assumes the crate name is always equal to its display name when it really isn't module .krate() @@ -438,11 +439,11 @@ impl<'a> FindUsages<'a> { fn scope_files<'a>( sema: &'a Semantics<'_, RootDatabase>, scope: &'a SearchScope, - ) -> impl Iterator, FileId, TextRange)> + 'a { + ) -> impl Iterator, FileId, TextRange)> + 'a { scope.entries.iter().map(|(&file_id, &search_range)| { let text = sema.db.file_text(file_id); let search_range = - search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str()))); + search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(&*text))); (text, file_id, search_range) }) @@ -499,7 +500,7 @@ impl<'a> FindUsages<'a> { let scope = search_scope.intersection(&SearchScope::module_and_children(self.sema.db, module)); - let is_crate_root = module.is_crate_root(self.sema.db).then(|| Finder::new("crate")); + let is_crate_root = module.is_crate_root().then(|| Finder::new("crate")); let finder = &Finder::new("super"); for (text, file_id, search_range) in scope_files(sema, &scope) { @@ -553,7 +554,7 @@ impl<'a> FindUsages<'a> { let text = sema.db.file_text(file_id); let search_range = - search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str()))); + search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(&*text))); let tree = Lazy::new(|| sema.parse(file_id).syntax().clone()); let finder = &Finder::new("self"); diff --git a/crates/ide-db/src/source_change.rs b/crates/ide-db/src/source_change.rs index 936354f296134..061fb0f05cfb9 100644 --- a/crates/ide-db/src/source_change.rs +++ b/crates/ide-db/src/source_change.rs @@ -5,16 +5,16 @@ use std::{collections::hash_map::Entry, iter, mem}; +use crate::SnippetCap; use base_db::{AnchoredPathBuf, FileId}; -use stdx::{hash::NoHashHashMap, never}; -use syntax::{algo, AstNode, SyntaxNode, SyntaxNodePtr, TextRange, TextSize}; +use nohash_hasher::IntMap; +use stdx::never; +use syntax::{algo, ast, ted, AstNode, SyntaxNode, SyntaxNodePtr, TextRange, TextSize}; use text_edit::{TextEdit, TextEditBuilder}; -use crate::SnippetCap; - #[derive(Default, Debug, Clone)] pub struct SourceChange { - pub source_file_edits: NoHashHashMap, + pub source_file_edits: IntMap, pub file_system_edits: Vec, pub is_snippet: bool, } @@ -23,7 +23,7 @@ impl SourceChange { /// Creates a new SourceChange with the given label /// from the edits. pub fn from_edits( - source_file_edits: NoHashHashMap, + source_file_edits: IntMap, file_system_edits: Vec, ) -> Self { SourceChange { source_file_edits, file_system_edits, is_snippet: false } @@ -77,8 +77,8 @@ impl Extend for SourceChange { } } -impl From> for SourceChange { - fn from(source_file_edits: NoHashHashMap) -> SourceChange { +impl From> for SourceChange { + fn from(source_file_edits: IntMap) -> SourceChange { SourceChange { source_file_edits, file_system_edits: Vec::new(), is_snippet: false } } } @@ -99,6 +99,8 @@ pub struct SourceChangeBuilder { /// Maps the original, immutable `SyntaxNode` to a `clone_for_update` twin. pub mutated_tree: Option, + /// Keeps track of where to place snippets + pub snippet_builder: Option, } pub struct TreeMutator { @@ -106,6 +108,12 @@ pub struct TreeMutator { mutable_clone: SyntaxNode, } +#[derive(Default)] +pub struct SnippetBuilder { + /// Where to place snippets at + places: Vec, +} + impl TreeMutator { pub fn new(immutable: &SyntaxNode) -> TreeMutator { let immutable = immutable.ancestors().last().unwrap(); @@ -131,6 +139,7 @@ impl SourceChangeBuilder { source_change: SourceChange::default(), trigger_signature_help: false, mutated_tree: None, + snippet_builder: None, } } @@ -140,6 +149,17 @@ impl SourceChangeBuilder { } fn commit(&mut self) { + // Render snippets first so that they get bundled into the tree diff + if let Some(mut snippets) = self.snippet_builder.take() { + // Last snippet always has stop index 0 + let last_stop = snippets.places.pop().unwrap(); + last_stop.place(0); + + for (index, stop) in snippets.places.into_iter().enumerate() { + stop.place(index + 1) + } + } + if let Some(tm) = self.mutated_tree.take() { algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit) } @@ -161,7 +181,7 @@ impl SourceChangeBuilder { /// mutability, and different nodes in the same tree see the same mutations. /// /// The typical pattern for an assist is to find specific nodes in the read - /// phase, and then get their mutable couterparts using `make_mut` in the + /// phase, and then get their mutable counterparts using `make_mut` in the /// mutable state. pub fn make_syntax_mut(&mut self, node: SyntaxNode) -> SyntaxNode { self.mutated_tree.get_or_insert_with(|| TreeMutator::new(&node)).make_syntax_mut(&node) @@ -214,6 +234,30 @@ impl SourceChangeBuilder { self.trigger_signature_help = true; } + /// Adds a tabstop snippet to place the cursor before `node` + pub fn add_tabstop_before(&mut self, _cap: SnippetCap, node: impl AstNode) { + assert!(node.syntax().parent().is_some()); + self.add_snippet(PlaceSnippet::Before(node.syntax().clone())); + } + + /// Adds a tabstop snippet to place the cursor after `node` + pub fn add_tabstop_after(&mut self, _cap: SnippetCap, node: impl AstNode) { + assert!(node.syntax().parent().is_some()); + self.add_snippet(PlaceSnippet::After(node.syntax().clone())); + } + + /// Adds a snippet to move the cursor selected over `node` + pub fn add_placeholder_snippet(&mut self, _cap: SnippetCap, node: impl AstNode) { + assert!(node.syntax().parent().is_some()); + self.add_snippet(PlaceSnippet::Over(node.syntax().clone())) + } + + fn add_snippet(&mut self, snippet: PlaceSnippet) { + let snippet_builder = self.snippet_builder.get_or_insert(SnippetBuilder { places: vec![] }); + snippet_builder.places.push(snippet); + self.source_change.is_snippet = true; + } + pub fn finish(mut self) -> SourceChange { self.commit(); mem::take(&mut self.source_change) @@ -236,3 +280,66 @@ impl From for SourceChange { } } } + +enum PlaceSnippet { + /// Place a tabstop before a node + Before(SyntaxNode), + /// Place a tabstop before a node + After(SyntaxNode), + /// Place a placeholder snippet in place of the node + Over(SyntaxNode), +} + +impl PlaceSnippet { + /// Places the snippet before or over a node with the given tab stop index + fn place(self, order: usize) { + // ensure the target node is still attached + match &self { + PlaceSnippet::Before(node) | PlaceSnippet::After(node) | PlaceSnippet::Over(node) => { + // node should still be in the tree, but if it isn't + // then it's okay to just ignore this place + if stdx::never!(node.parent().is_none()) { + return; + } + } + } + + match self { + PlaceSnippet::Before(node) => { + ted::insert_raw(ted::Position::before(&node), Self::make_tab_stop(order)); + } + PlaceSnippet::After(node) => { + ted::insert_raw(ted::Position::after(&node), Self::make_tab_stop(order)); + } + PlaceSnippet::Over(node) => { + let position = ted::Position::before(&node); + node.detach(); + + let snippet = ast::SourceFile::parse(&format!("${{{order}:_}}")) + .syntax_node() + .clone_for_update(); + + let placeholder = + snippet.descendants().find_map(ast::UnderscoreExpr::cast).unwrap(); + ted::replace(placeholder.syntax(), node); + + ted::insert_raw(position, snippet); + } + } + } + + fn make_tab_stop(order: usize) -> SyntaxNode { + let stop = ast::SourceFile::parse(&format!("stop!(${order})")) + .syntax_node() + .descendants() + .find_map(ast::TokenTree::cast) + .unwrap() + .syntax() + .clone_for_update(); + + stop.first_token().unwrap().detach(); + stop.last_token().unwrap().detach(); + + stop + } +} diff --git a/crates/ide-db/src/symbol_index.rs b/crates/ide-db/src/symbol_index.rs index a91ffd1ec4fd1..b54c43b296b2a 100644 --- a/crates/ide-db/src/symbol_index.rs +++ b/crates/ide-db/src/symbol_index.rs @@ -25,7 +25,6 @@ use std::{ fmt, hash::{Hash, Hasher}, mem, - sync::Arc, }; use base_db::{ @@ -40,6 +39,7 @@ use hir::{ }; use rayon::prelude::*; use rustc_hash::FxHashSet; +use triomphe::Arc; use crate::RootDatabase; @@ -98,6 +98,10 @@ pub trait SymbolsDatabase: HirDatabase + SourceDatabaseExt + Upcast Arc; + #[salsa::transparent] + /// The symbol indices of modules that make up a given crate. + fn crate_symbols(&self, krate: Crate) -> Box<[Arc]>; + /// The set of "local" (that is, from the current workspace) roots. /// Files in local roots are assumed to change frequently. #[salsa::input] @@ -112,26 +116,33 @@ pub trait SymbolsDatabase: HirDatabase + SourceDatabaseExt + Upcast Arc { let _p = profile::span("library_symbols"); - // todo: this could be parallelized, once I figure out how to do that... - let symbols = db - .source_root_crates(source_root_id) + let mut symbol_collector = SymbolCollector::new(db.upcast()); + + db.source_root_crates(source_root_id) .iter() .flat_map(|&krate| Crate::from(krate).modules(db.upcast())) - // we specifically avoid calling SymbolsDatabase::module_symbols here, even they do the same thing, + // we specifically avoid calling other SymbolsDatabase queries here, even though they do the same thing, // as the index for a library is not going to really ever change, and we do not want to store each - // module's index in salsa. - .flat_map(|module| SymbolCollector::collect(db.upcast(), module)) - .collect(); + // the module or crate indices for those in salsa unless we need to. + .for_each(|module| symbol_collector.collect(module)); + let mut symbols = symbol_collector.finish(); + symbols.shrink_to_fit(); Arc::new(SymbolIndex::new(symbols)) } fn module_symbols(db: &dyn SymbolsDatabase, module: Module) -> Arc { let _p = profile::span("module_symbols"); - let symbols = SymbolCollector::collect(db.upcast(), module); + + let symbols = SymbolCollector::collect_module(db.upcast(), module); Arc::new(SymbolIndex::new(symbols)) } +pub fn crate_symbols(db: &dyn SymbolsDatabase, krate: Crate) -> Box<[Arc]> { + let _p = profile::span("crate_symbols"); + krate.modules(db.upcast()).into_iter().map(|module| db.module_symbols(module)).collect() +} + /// Need to wrap Snapshot to provide `Clone` impl for `map_with` struct Snap(DB); impl Snap> { @@ -187,36 +198,21 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec { .map_with(Snap::new(db), |snap, &root| snap.library_symbols(root)) .collect() } else { - let mut modules = Vec::new(); + let mut crates = Vec::new(); for &root in db.local_roots().iter() { - let crates = db.source_root_crates(root); - for &krate in crates.iter() { - modules.extend(Crate::from(krate).modules(db)); - } + crates.extend(db.source_root_crates(root).iter().copied()) } - - modules - .par_iter() - .map_with(Snap::new(db), |snap, &module| snap.module_symbols(module)) - .collect() + let indices: Vec<_> = crates + .into_par_iter() + .map_with(Snap::new(db), |snap, krate| snap.crate_symbols(krate.into())) + .collect(); + indices.iter().flat_map(|indices| indices.iter().cloned()).collect() }; query.search(&indices) } -pub fn crate_symbols(db: &RootDatabase, krate: Crate, query: Query) -> Vec { - let _p = profile::span("crate_symbols").detail(|| format!("{query:?}")); - - let modules = krate.modules(db); - let indices: Vec<_> = modules - .par_iter() - .map_with(Snap::new(db), |snap, &module| snap.module_symbols(module)) - .collect(); - - query.search(&indices) -} - #[derive(Default)] pub struct SymbolIndex { symbols: Vec, @@ -274,7 +270,12 @@ impl SymbolIndex { builder.insert(key, value).unwrap(); } - let map = fst::Map::new(builder.into_inner().unwrap()).unwrap(); + let map = fst::Map::new({ + let mut buf = builder.into_inner().unwrap(); + buf.shrink_to_fit(); + buf + }) + .unwrap(); SymbolIndex { symbols, map } } @@ -316,7 +317,14 @@ impl Query { let (start, end) = SymbolIndex::map_value_to_range(indexed_value.value); for symbol in &symbol_index.symbols[start..end] { - if self.only_types && !symbol.kind.is_type() { + if self.only_types + && !matches!( + symbol.def, + hir::ModuleDef::Adt(..) + | hir::ModuleDef::TypeAlias(..) + | hir::ModuleDef::BuiltinType(..) + ) + { continue; } if self.exact { @@ -418,7 +426,7 @@ struct StructInModB; .modules(&db) .into_iter() .map(|module_id| { - let mut symbols = SymbolCollector::collect(&db, module_id); + let mut symbols = SymbolCollector::collect_module(&db, module_id); symbols.sort_by_key(|it| it.name.clone()); (module_id, symbols) }) @@ -426,4 +434,31 @@ struct StructInModB; expect_file!["./test_data/test_symbol_index_collection.txt"].assert_debug_eq(&symbols); } + + #[test] + fn test_doc_alias() { + let (db, _) = RootDatabase::with_single_file( + r#" +#[doc(alias="s1")] +#[doc(alias="s2")] +#[doc(alias("mul1","mul2"))] +struct Struct; + +#[doc(alias="s1")] +struct Duplicate; + "#, + ); + + let symbols: Vec<_> = Crate::from(db.test_crate()) + .modules(&db) + .into_iter() + .map(|module_id| { + let mut symbols = SymbolCollector::collect_module(&db, module_id); + symbols.sort_by_key(|it| it.name.clone()); + (module_id, symbols) + }) + .collect(); + + expect_file!["./test_data/test_doc_alias.txt"].assert_debug_eq(&symbols); + } } diff --git a/crates/ide-db/src/syntax_helpers/format_string.rs b/crates/ide-db/src/syntax_helpers/format_string.rs index 2d6927cee9953..acf0a67de4a12 100644 --- a/crates/ide-db/src/syntax_helpers/format_string.rs +++ b/crates/ide-db/src/syntax_helpers/format_string.rs @@ -92,7 +92,7 @@ pub fn lex_format_specifiers( let (_, second) = cloned.next().unwrap_or_default(); match second { '<' | '^' | '>' => { - // alignment specifier, first char specifies fillment + // alignment specifier, first char specifies fill skip_char_and_emit(&mut chars, FormatSpecifier::Fill, &mut callback); skip_char_and_emit(&mut chars, FormatSpecifier::Align, &mut callback); } diff --git a/crates/ide-db/src/syntax_helpers/format_string_exprs.rs b/crates/ide-db/src/syntax_helpers/format_string_exprs.rs index fcef71fb74e7b..fc230818193dc 100644 --- a/crates/ide-db/src/syntax_helpers/format_string_exprs.rs +++ b/crates/ide-db/src/syntax_helpers/format_string_exprs.rs @@ -1,7 +1,7 @@ //! Tools to work with expressions present in format string literals for the `format_args!` family of macros. //! Primarily meant for assists and completions. -/// Enum for represenging extraced format string args. +/// Enum for representing extracted format string args. /// Can either be extracted expressions (which includes identifiers), /// or placeholders `{}`. #[derive(Debug, PartialEq, Eq)] diff --git a/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs b/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs index 8bc093a85a21b..0b0fc6693526f 100644 --- a/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs +++ b/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs @@ -60,7 +60,9 @@ pub fn insert_ws_into(syn: SyntaxNode) -> SyntaxNode { |f: fn(SyntaxKind) -> bool, default| -> bool { last.map(f).unwrap_or(default) }; match tok.kind() { - k if is_text(k) && is_next(|it| !it.is_punct() || it == UNDERSCORE, false) => { + k if is_text(k) + && is_next(|it| !it.is_punct() || matches!(it, T![_] | T![#]), false) => + { mods.push(do_ws(after, tok)); } L_CURLY if is_next(|it| it != R_CURLY, true) => { diff --git a/crates/ide-db/src/syntax_helpers/node_ext.rs b/crates/ide-db/src/syntax_helpers/node_ext.rs index a34dc1b69507e..22ced69d81e4a 100644 --- a/crates/ide-db/src/syntax_helpers/node_ext.rs +++ b/crates/ide-db/src/syntax_helpers/node_ext.rs @@ -52,7 +52,9 @@ pub fn preorder_expr(start: &ast::Expr, cb: &mut dyn FnMut(WalkEvent) } }; if let Some(let_stmt) = node.parent().and_then(ast::LetStmt::cast) { - if Some(node.clone()) != let_stmt.initializer().map(|it| it.syntax().clone()) { + if let_stmt.initializer().map(|it| it.syntax() != &node).unwrap_or(true) + && let_stmt.let_else().map(|it| it.syntax() != &node).unwrap_or(true) + { // skipping potential const pat expressions in let statements preorder.skip_subtree(); continue; diff --git a/crates/ide-db/src/test_data/test_doc_alias.txt b/crates/ide-db/src/test_data/test_doc_alias.txt new file mode 100644 index 0000000000000..77714efa35040 --- /dev/null +++ b/crates/ide-db/src/test_data/test_doc_alias.txt @@ -0,0 +1,202 @@ +[ + ( + Module { + id: ModuleId { + krate: Idx::(0), + block: None, + local_id: Idx::(0), + }, + }, + [ + FileSymbol { + name: "Duplicate", + def: Adt( + Struct( + Struct { + id: StructId( + 1, + ), + }, + ), + ), + loc: DeclarationLocation { + hir_file_id: HirFileId( + 0, + ), + ptr: SyntaxNodePtr { + kind: STRUCT, + range: 83..119, + }, + name_ptr: SyntaxNodePtr { + kind: NAME, + range: 109..118, + }, + }, + container_name: None, + is_alias: false, + }, + FileSymbol { + name: "Struct", + def: Adt( + Struct( + Struct { + id: StructId( + 0, + ), + }, + ), + ), + loc: DeclarationLocation { + hir_file_id: HirFileId( + 0, + ), + ptr: SyntaxNodePtr { + kind: STRUCT, + range: 0..81, + }, + name_ptr: SyntaxNodePtr { + kind: NAME, + range: 74..80, + }, + }, + container_name: None, + is_alias: false, + }, + FileSymbol { + name: "mul1", + def: Adt( + Struct( + Struct { + id: StructId( + 0, + ), + }, + ), + ), + loc: DeclarationLocation { + hir_file_id: HirFileId( + 0, + ), + ptr: SyntaxNodePtr { + kind: STRUCT, + range: 0..81, + }, + name_ptr: SyntaxNodePtr { + kind: NAME, + range: 74..80, + }, + }, + container_name: None, + is_alias: true, + }, + FileSymbol { + name: "mul2", + def: Adt( + Struct( + Struct { + id: StructId( + 0, + ), + }, + ), + ), + loc: DeclarationLocation { + hir_file_id: HirFileId( + 0, + ), + ptr: SyntaxNodePtr { + kind: STRUCT, + range: 0..81, + }, + name_ptr: SyntaxNodePtr { + kind: NAME, + range: 74..80, + }, + }, + container_name: None, + is_alias: true, + }, + FileSymbol { + name: "s1", + def: Adt( + Struct( + Struct { + id: StructId( + 0, + ), + }, + ), + ), + loc: DeclarationLocation { + hir_file_id: HirFileId( + 0, + ), + ptr: SyntaxNodePtr { + kind: STRUCT, + range: 0..81, + }, + name_ptr: SyntaxNodePtr { + kind: NAME, + range: 74..80, + }, + }, + container_name: None, + is_alias: true, + }, + FileSymbol { + name: "s1", + def: Adt( + Struct( + Struct { + id: StructId( + 1, + ), + }, + ), + ), + loc: DeclarationLocation { + hir_file_id: HirFileId( + 0, + ), + ptr: SyntaxNodePtr { + kind: STRUCT, + range: 83..119, + }, + name_ptr: SyntaxNodePtr { + kind: NAME, + range: 109..118, + }, + }, + container_name: None, + is_alias: true, + }, + FileSymbol { + name: "s2", + def: Adt( + Struct( + Struct { + id: StructId( + 0, + ), + }, + ), + ), + loc: DeclarationLocation { + hir_file_id: HirFileId( + 0, + ), + ptr: SyntaxNodePtr { + kind: STRUCT, + range: 0..81, + }, + name_ptr: SyntaxNodePtr { + kind: NAME, + range: 74..80, + }, + }, + container_name: None, + is_alias: true, + }, + ], + ), +] diff --git a/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/crates/ide-db/src/test_data/test_symbol_index_collection.txt index 8c11408dec5d7..b5adfc13d9644 100644 --- a/crates/ide-db/src/test_data/test_symbol_index_collection.txt +++ b/crates/ide-db/src/test_data/test_symbol_index_collection.txt @@ -2,9 +2,7 @@ ( Module { id: ModuleId { - krate: CrateId( - 0, - ), + krate: Idx::(0), block: None, local_id: Idx::(0), }, @@ -12,6 +10,13 @@ [ FileSymbol { name: "Alias", + def: TypeAlias( + TypeAlias { + id: TypeAliasId( + 0, + ), + }, + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -25,11 +30,18 @@ range: 402..407, }, }, - kind: TypeAlias, container_name: None, + is_alias: false, }, FileSymbol { name: "CONST", + def: Const( + Const { + id: ConstId( + 0, + ), + }, + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -43,11 +55,18 @@ range: 346..351, }, }, - kind: Const, container_name: None, + is_alias: false, }, FileSymbol { name: "CONST_WITH_INNER", + def: Const( + Const { + id: ConstId( + 2, + ), + }, + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -61,11 +80,20 @@ range: 526..542, }, }, - kind: Const, container_name: None, + is_alias: false, }, FileSymbol { name: "Enum", + def: Adt( + Enum( + Enum { + id: EnumId( + 0, + ), + }, + ), + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -79,11 +107,20 @@ range: 190..194, }, }, - kind: Enum, container_name: None, + is_alias: false, }, FileSymbol { name: "Macro", + def: Macro( + Macro { + id: Macro2Id( + Macro2Id( + 0, + ), + ), + }, + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -97,11 +134,18 @@ range: 159..164, }, }, - kind: Macro, container_name: None, + is_alias: false, }, FileSymbol { name: "STATIC", + def: Static( + Static { + id: StaticId( + 0, + ), + }, + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -115,11 +159,20 @@ range: 369..375, }, }, - kind: Static, container_name: None, + is_alias: false, }, FileSymbol { name: "Struct", + def: Adt( + Struct( + Struct { + id: StructId( + 1, + ), + }, + ), + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -133,11 +186,20 @@ range: 177..183, }, }, - kind: Struct, container_name: None, + is_alias: false, }, FileSymbol { name: "StructFromMacro", + def: Adt( + Struct( + Struct { + id: StructId( + 0, + ), + }, + ), + ), loc: DeclarationLocation { hir_file_id: HirFileId( 2147483648, @@ -151,11 +213,20 @@ range: 6..21, }, }, - kind: Struct, container_name: None, + is_alias: false, }, FileSymbol { name: "StructInFn", + def: Adt( + Struct( + Struct { + id: StructId( + 4, + ), + }, + ), + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -169,13 +240,22 @@ range: 325..335, }, }, - kind: Struct, container_name: Some( "main", ), + is_alias: false, }, FileSymbol { name: "StructInNamedConst", + def: Adt( + Struct( + Struct { + id: StructId( + 5, + ), + }, + ), + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -189,13 +269,22 @@ range: 562..580, }, }, - kind: Struct, container_name: Some( "CONST_WITH_INNER", ), + is_alias: false, }, FileSymbol { name: "StructInUnnamedConst", + def: Adt( + Struct( + Struct { + id: StructId( + 6, + ), + }, + ), + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -209,11 +298,18 @@ range: 486..506, }, }, - kind: Struct, container_name: None, + is_alias: false, }, FileSymbol { name: "Trait", + def: Trait( + Trait { + id: TraitId( + 0, + ), + }, + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -227,11 +323,20 @@ range: 267..272, }, }, - kind: Trait, container_name: None, + is_alias: false, }, FileSymbol { name: "Union", + def: Adt( + Union( + Union { + id: UnionId( + 0, + ), + }, + ), + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -245,11 +350,20 @@ range: 214..219, }, }, - kind: Union, container_name: None, + is_alias: false, }, FileSymbol { name: "a_mod", + def: Module( + Module { + id: ModuleId { + krate: Idx::(0), + block: None, + local_id: Idx::(1), + }, + }, + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -263,11 +377,20 @@ range: 423..428, }, }, - kind: Module, container_name: None, + is_alias: false, }, FileSymbol { name: "b_mod", + def: Module( + Module { + id: ModuleId { + krate: Idx::(0), + block: None, + local_id: Idx::(2), + }, + }, + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -281,11 +404,20 @@ range: 598..603, }, }, - kind: Module, container_name: None, + is_alias: false, }, FileSymbol { name: "define_struct", + def: Macro( + Macro { + id: MacroRulesId( + MacroRulesId( + 1, + ), + ), + }, + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -299,11 +431,18 @@ range: 64..77, }, }, - kind: Macro, container_name: None, + is_alias: false, }, FileSymbol { name: "impl_fn", + def: Function( + Function { + id: FunctionId( + 2, + ), + }, + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -317,11 +456,20 @@ range: 245..252, }, }, - kind: Function, container_name: None, + is_alias: false, }, FileSymbol { name: "macro_rules_macro", + def: Macro( + Macro { + id: MacroRulesId( + MacroRulesId( + 0, + ), + ), + }, + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -335,11 +483,18 @@ range: 14..31, }, }, - kind: Macro, container_name: None, + is_alias: false, }, FileSymbol { name: "main", + def: Function( + Function { + id: FunctionId( + 0, + ), + }, + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -353,11 +508,18 @@ range: 305..309, }, }, - kind: Function, container_name: None, + is_alias: false, }, FileSymbol { name: "trait_fn", + def: Function( + Function { + id: FunctionId( + 1, + ), + }, + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -371,19 +533,17 @@ range: 282..290, }, }, - kind: Function, container_name: Some( "Trait", ), + is_alias: false, }, ], ), ( Module { id: ModuleId { - krate: CrateId( - 0, - ), + krate: Idx::(0), block: None, local_id: Idx::(1), }, @@ -391,6 +551,15 @@ [ FileSymbol { name: "StructInModA", + def: Adt( + Struct( + Struct { + id: StructId( + 2, + ), + }, + ), + ), loc: DeclarationLocation { hir_file_id: HirFileId( 0, @@ -404,17 +573,15 @@ range: 442..454, }, }, - kind: Struct, container_name: None, + is_alias: false, }, ], ), ( Module { id: ModuleId { - krate: CrateId( - 0, - ), + krate: Idx::(0), block: None, local_id: Idx::(2), }, @@ -422,6 +589,15 @@ [ FileSymbol { name: "StructInModB", + def: Adt( + Struct( + Struct { + id: StructId( + 3, + ), + }, + ), + ), loc: DeclarationLocation { hir_file_id: HirFileId( 1, @@ -435,8 +611,8 @@ range: 7..19, }, }, - kind: Struct, container_name: None, + is_alias: false, }, ], ), diff --git a/crates/ide-db/src/tests/line_index.rs b/crates/ide-db/src/tests/line_index.rs new file mode 100644 index 0000000000000..6b49bb2631c19 --- /dev/null +++ b/crates/ide-db/src/tests/line_index.rs @@ -0,0 +1,49 @@ +use line_index::{LineCol, LineIndex, WideEncoding}; +use test_utils::skip_slow_tests; + +#[test] +fn test_every_chars() { + if skip_slow_tests() { + return; + } + + let text: String = { + let mut chars: Vec = ((0 as char)..char::MAX).collect(); // Neat! + chars.extend("\n".repeat(chars.len() / 16).chars()); + let mut rng = oorandom::Rand32::new(stdx::rand::seed()); + stdx::rand::shuffle(&mut chars, |i| rng.rand_range(0..i as u32) as usize); + chars.into_iter().collect() + }; + assert!(text.contains('💩')); // Sanity check. + + let line_index = LineIndex::new(&text); + + let mut lin_col = LineCol { line: 0, col: 0 }; + let mut col_utf16 = 0; + let mut col_utf32 = 0; + for (offset, c) in text.char_indices() { + let got_offset = line_index.offset(lin_col).unwrap(); + assert_eq!(usize::from(got_offset), offset); + + let got_lin_col = line_index.line_col(got_offset); + assert_eq!(got_lin_col, lin_col); + + for (enc, col) in [(WideEncoding::Utf16, col_utf16), (WideEncoding::Utf32, col_utf32)] { + let wide_lin_col = line_index.to_wide(enc, lin_col).unwrap(); + let got_lin_col = line_index.to_utf8(enc, wide_lin_col).unwrap(); + assert_eq!(got_lin_col, lin_col); + assert_eq!(wide_lin_col.col, col) + } + + if c == '\n' { + lin_col.line += 1; + lin_col.col = 0; + col_utf16 = 0; + col_utf32 = 0; + } else { + lin_col.col += c.len_utf8() as u32; + col_utf16 += c.len_utf16() as u32; + col_utf32 += 1; + } + } +} diff --git a/crates/ide-db/src/traits.rs b/crates/ide-db/src/traits.rs index 6a7ea7c19f228..9abbc34414291 100644 --- a/crates/ide-db/src/traits.rs +++ b/crates/ide-db/src/traits.rs @@ -38,15 +38,15 @@ pub fn get_missing_assoc_items( for item in imp.items(sema.db) { match item { hir::AssocItem::Function(it) => { - impl_fns_consts.insert(it.name(sema.db).to_string()); + impl_fns_consts.insert(it.name(sema.db).display(sema.db).to_string()); } hir::AssocItem::Const(it) => { if let Some(name) = it.name(sema.db) { - impl_fns_consts.insert(name.to_string()); + impl_fns_consts.insert(name.display(sema.db).to_string()); } } hir::AssocItem::TypeAlias(it) => { - impl_type.insert(it.name(sema.db).to_string()); + impl_type.insert(it.name(sema.db).display(sema.db).to_string()); } } } @@ -57,12 +57,14 @@ pub fn get_missing_assoc_items( .into_iter() .filter(|i| match i { hir::AssocItem::Function(f) => { - !impl_fns_consts.contains(&f.name(sema.db).to_string()) + !impl_fns_consts.contains(&f.name(sema.db).display(sema.db).to_string()) + } + hir::AssocItem::TypeAlias(t) => { + !impl_type.contains(&t.name(sema.db).display(sema.db).to_string()) } - hir::AssocItem::TypeAlias(t) => !impl_type.contains(&t.name(sema.db).to_string()), hir::AssocItem::Const(c) => c .name(sema.db) - .map(|n| !impl_fns_consts.contains(&n.to_string())) + .map(|n| !impl_fns_consts.contains(&n.display(sema.db).to_string())) .unwrap_or_default(), }) .collect() @@ -137,7 +139,7 @@ mod tests { sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap(); let trait_ = crate::traits::resolve_target_trait(&sema, &impl_block); let actual = match trait_ { - Some(trait_) => trait_.name(&db).to_string(), + Some(trait_) => trait_.name(&db).display(&db).to_string(), None => String::new(), }; expect.assert_eq(&actual); @@ -152,7 +154,7 @@ mod tests { let items = crate::traits::get_missing_assoc_items(&sema, &impl_block); let actual = items .into_iter() - .map(|item| item.name(&db).unwrap().to_string()) + .map(|item| item.name(&db).unwrap().display(&db).to_string()) .collect::>() .join("\n"); expect.assert_eq(&actual); diff --git a/crates/ide-db/src/use_trivial_constructor.rs b/crates/ide-db/src/use_trivial_constructor.rs index 39431bed3821c..f96ea29ae2f9d 100644 --- a/crates/ide-db/src/use_trivial_constructor.rs +++ b/crates/ide-db/src/use_trivial_constructor.rs @@ -1,9 +1,9 @@ -//! Functionality for generating trivial contructors +//! Functionality for generating trivial constructors use hir::StructKind; use syntax::ast; -/// given a type return the trivial contructor (if one exists) +/// given a type return the trivial constructor (if one exists) pub fn use_trivial_constructor( db: &crate::RootDatabase, path: ast::Path, diff --git a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs index 114face2dca85..30576c71fb7c2 100644 --- a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs +++ b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs @@ -31,12 +31,8 @@ mod tests { fn foo() { break; //^^^^^ error: break outside of loop - break 'a; - //^^^^^^^^ error: break outside of loop continue; //^^^^^^^^ error: continue outside of loop - continue 'a; - //^^^^^^^^^^^ error: continue outside of loop } "#, ); @@ -51,12 +47,8 @@ fn foo() { async { break; //^^^^^ error: break outside of loop - break 'a; - //^^^^^^^^ error: break outside of loop continue; //^^^^^^^^ error: continue outside of loop - continue 'a; - //^^^^^^^^^^^ error: continue outside of loop }; } } @@ -73,12 +65,8 @@ fn foo() { || { break; //^^^^^ error: break outside of loop - break 'a; - //^^^^^^^^ error: break outside of loop continue; //^^^^^^^^ error: continue outside of loop - continue 'a; - //^^^^^^^^^^^ error: continue outside of loop }; } } @@ -94,9 +82,7 @@ fn foo() { 'a: loop { { break; - break 'a; continue; - continue 'a; } } } @@ -112,9 +98,7 @@ fn foo() { 'a: loop { try { break; - break 'a; continue; - continue 'a; }; } } @@ -130,11 +114,8 @@ fn foo() { 'a: { break; //^^^^^ error: break outside of loop - break 'a; continue; //^^^^^^^^ error: continue outside of loop - continue 'a; - //^^^^^^^^^^^ error: continue outside of loop } } "#, @@ -143,14 +124,34 @@ fn foo() { #[test] fn value_break_in_for_loop() { + // FIXME: the error is correct, but the message is terrible check_diagnostics( r#" +//- minicore: iterator fn test() { for _ in [()] { break 3; - // ^^^^^^^ error: can't break with a value in this position + // ^ error: expected (), found i32 } } +"#, + ); + } + + #[test] + fn try_block_desugaring_inside_closure() { + // regression test for #14701 + check_diagnostics( + r#" +//- minicore: option, try +fn test() { + try { + || { + let x = Some(2); + Some(x?) + }; + }; +} "#, ); } diff --git a/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/crates/ide-diagnostics/src/handlers/incorrect_case.rs index db88bf7b9313d..90279e14536be 100644 --- a/crates/ide-diagnostics/src/handlers/incorrect_case.rs +++ b/crates/ide-diagnostics/src/handlers/incorrect_case.rs @@ -27,7 +27,7 @@ pub(crate) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCas } fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option> { - let root = ctx.sema.db.parse_or_expand(d.file)?; + let root = ctx.sema.db.parse_or_expand(d.file); let name_node = d.ident.to_node(&root); let def = NameClass::classify(&ctx.sema, &name_node)?.defined()?; @@ -295,7 +295,7 @@ impl someStruct { } #[test] - fn no_diagnostic_for_enum_varinats() { + fn no_diagnostic_for_enum_variants() { check_diagnostics( r#" enum Option { Some, None } diff --git a/crates/ide-diagnostics/src/handlers/macro_error.rs b/crates/ide-diagnostics/src/handlers/macro_error.rs index 870c78d1f1eb7..7547779a95c72 100644 --- a/crates/ide-diagnostics/src/handlers/macro_error.rs +++ b/crates/ide-diagnostics/src/handlers/macro_error.rs @@ -9,6 +9,16 @@ pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic::new("macro-error", d.message.clone(), display_range).experimental() } +// Diagnostic: macro-error +// +// This diagnostic is shown for macro expansion errors. +pub(crate) fn macro_def_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroDefError) -> Diagnostic { + // Use more accurate position if available. + let display_range = + ctx.resolve_precise_location(&d.node.clone().map(|it| it.syntax_node_ptr()), d.name); + Diagnostic::new("macro-def-error", d.message.clone(), display_range).experimental() +} + #[cfg(test)] mod tests { use crate::{ @@ -188,6 +198,7 @@ fn f() { "#, ); } + #[test] fn dollar_crate_in_builtin_macro() { check_diagnostics( @@ -209,6 +220,40 @@ macro_rules! outer { fn f() { outer!(); } //^^^^^^^^ error: leftover tokens +"#, + ) + } + + #[test] + fn def_diagnostic() { + check_diagnostics( + r#" +macro_rules! foo { + //^^^ error: expected subtree + f => {}; +} + +fn f() { + foo!(); + //^^^ error: invalid macro definition: expected subtree + +} +"#, + ) + } + + #[test] + fn expansion_syntax_diagnostic() { + check_diagnostics( + r#" +macro_rules! foo { + () => { struct; }; +} + +fn f() { + foo!(); + //^^^ error: Syntax Error in Expansion: expected a name +} "#, ) } diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs index 5c4327ff93413..60ccc41df01cc 100644 --- a/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -31,7 +31,7 @@ use crate::{fix, Diagnostic, DiagnosticsContext}; pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic { let mut message = String::from("missing structure fields:\n"); for field in &d.missed_fields { - format_to!(message, "- {}\n", field); + format_to!(message, "- {}\n", field.display(ctx.sema.db)); } let ptr = InFile::new( @@ -56,7 +56,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option ctx.sema.scope(ptr.to_node(&root).syntax()).map(|it| it.module()), @@ -175,8 +175,10 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option ast::Type { let ty_str = match ty.as_adt() { - Some(adt) => adt.name(db).to_string(), - None => ty.display_source_code(db, module.into()).ok().unwrap_or_else(|| "_".to_string()), + Some(adt) => adt.name(db).display(db.upcast()).to_string(), + None => { + ty.display_source_code(db, module.into(), false).ok().unwrap_or_else(|| "_".to_string()) + } }; make::ty(&ty_str) diff --git a/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/crates/ide-diagnostics/src/handlers/missing_match_arms.rs index ac4463331f2d2..3f13b97a44734 100644 --- a/crates/ide-diagnostics/src/handlers/missing_match_arms.rs +++ b/crates/ide-diagnostics/src/handlers/missing_match_arms.rs @@ -271,15 +271,20 @@ enum Either2 { C, D } fn main() { match Either::A { Either2::C => (), + //^^^^^^^^^^ error: expected Either, found Either2 Either2::D => (), + //^^^^^^^^^^ error: expected Either, found Either2 } match (true, false) { (true, false, true) => (), + //^^^^^^^^^^^^^^^^^^^ error: expected (bool, bool), found (bool, bool, bool) (true) => (), // ^^^^ error: expected (bool, bool), found bool } match (true, false) { (true,) => {} } + //^^^^^^^ error: expected (bool, bool), found (bool,) match (0) { () => () } + //^^ error: expected i32, found () match Unresolved::Bar { Unresolved::Baz => () } } "#, @@ -293,7 +298,9 @@ fn main() { r#" fn main() { match false { true | () => {} } + //^^ error: expected bool, found () match (false,) { (true | (),) => {} } + //^^ error: expected bool, found () } "#, ); @@ -738,17 +745,13 @@ fn main() { #[test] fn binding_ref_has_correct_type() { - cov_mark::check_count!(validate_match_bailed_out, 1); - // Asserts `PatKind::Binding(ref _x): bool`, not &bool. // If that's not true match checking will panic with "incompatible constructors" // FIXME: make facilities to test this directly like `tests::check_infer(..)` - check_diagnostics( + check_diagnostics_no_bails( r#" enum Foo { A } fn main() { - // FIXME: this should not bail out but current behavior is such as the old algorithm. - // ExprValidator::validate_match(..) checks types of top level patterns incorrectly. match Foo::A { ref _x => {} Foo::A => {} @@ -1024,6 +1027,7 @@ fn main() { check_diagnostics( r#" +//- minicore: copy fn main() { match &false { &true => {} @@ -1035,11 +1039,13 @@ fn main() { #[test] fn reference_patterns_in_fields() { - cov_mark::check_count!(validate_match_bailed_out, 2); + cov_mark::check_count!(validate_match_bailed_out, 1); check_diagnostics( r#" +//- minicore: copy fn main() { match (&false,) { + //^^^^^^^^^ error: missing match arm: `(&false,)` not covered (true,) => {} } match (&false,) { diff --git a/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index eb32db250656c..2026b6fcef537 100644 --- a/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -24,7 +24,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Option, d: &hir::MovedOutOfRef) -> Diagnostic { + Diagnostic::new( + "moved-out-of-ref", + format!("cannot move `{}` out of reference", d.ty.display(ctx.sema.db)), + ctx.sema.diagnostics_display_range(d.span.clone()).range, + ) + .experimental() // spans are broken, and I'm not sure how precise we can detect copy types +} + +#[cfg(test)] +mod tests { + use crate::tests::check_diagnostics; + + // FIXME: spans are broken + + #[test] + fn move_by_explicit_deref() { + check_diagnostics( + r#" +struct X; +fn main() { + let a = &X; + let b = *a; + //^ error: cannot move `X` out of reference +} +"#, + ); + } + + #[test] + fn move_out_of_field() { + check_diagnostics( + r#" +//- minicore: copy +struct X; +struct Y(X, i32); +fn main() { + let a = &Y(X, 5); + let b = a.0; + //^ error: cannot move `X` out of reference + let y = a.1; +} +"#, + ); + } + + #[test] + fn move_out_of_static() { + check_diagnostics( + r#" +//- minicore: copy +struct X; +fn main() { + static S: X = X; + let s = S; + //^ error: cannot move `X` out of reference +} +"#, + ); + } + + #[test] + fn generic_types() { + check_diagnostics( + r#" +//- minicore: derive, copy + +#[derive(Copy)] +struct X(T); +struct Y; + +fn consume(_: X) { + +} + +fn main() { + let a = &X(Y); + consume(*a); + //^^^^^^^^^^^ error: cannot move `X` out of reference + let a = &X(5); + consume(*a); +} +"#, + ); + } + + #[test] + fn no_false_positive_simple() { + check_diagnostics( + r#" +//- minicore: copy +fn f(_: i32) {} +fn main() { + let x = &2; + f(*x); +} +"#, + ); + } + + #[test] + fn no_false_positive_unknown_type() { + check_diagnostics( + r#" +//- minicore: derive, copy +fn f(x: &Unknown) -> Unknown { + *x +} + +#[derive(Copy)] +struct X(T); + +struct Y(T); + +fn g(x: &X) -> X { + *x +} + +fn h(x: &Y) -> Y { + // FIXME: we should show error for this, as `Y` is not copy + // regardless of its generic parameter. + *x +} + +"#, + ); + } + + #[test] + fn no_false_positive_dyn_fn() { + check_diagnostics( + r#" +//- minicore: copy, fn +fn f(x: &mut &mut dyn Fn()) { + x(); +} + +struct X<'a> { + field: &'a mut dyn Fn(), +} + +fn f(x: &mut X<'_>) { + (x.field)(); +} +"#, + ); + } + + #[test] + fn no_false_positive_match_and_closure_capture() { + check_diagnostics( + r#" +//- minicore: copy, fn +enum X { + Foo(u16), + Bar, +} + +fn main() { + let x = &X::Bar; + let c = || match *x { + X::Foo(t) => t, + _ => 5, + }; +} + "#, + ); + } +} diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs index 96470265d11d1..f61460e317f78 100644 --- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -18,7 +18,8 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Diagno let use_range = d.span.value.text_range(); for source in d.local.sources(ctx.sema.db) { let Some(ast) = source.name() else { continue }; - edit_builder.insert(ast.syntax().text_range().start(), "mut ".to_string()); + // FIXME: macros + edit_builder.insert(ast.value.syntax().text_range().start(), "mut ".to_string()); } let edit = edit_builder.finish(); Some(vec![fix( @@ -30,7 +31,10 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Diagno })(); Diagnostic::new( "need-mut", - format!("cannot mutate immutable variable `{}`", d.local.name(ctx.sema.db)), + format!( + "cannot mutate immutable variable `{}`", + d.local.name(ctx.sema.db).display(ctx.sema.db) + ), ctx.sema.diagnostics_display_range(d.span.clone()).range, ) .with_fixes(fixes) @@ -340,6 +344,7 @@ fn main() { fn regression_14310() { check_diagnostics( r#" + //- minicore: copy, builtin_impls fn clone(mut i: &!) -> ! { //^^^^^ 💡 weak: variable does not need to be mutable *i @@ -348,6 +353,32 @@ fn main() { ); } + #[test] + fn match_closure_capture() { + check_diagnostics( + r#" +//- minicore: option +fn main() { + let mut v = &mut Some(2); + //^^^^^ 💡 weak: variable does not need to be mutable + let _ = || match v { + Some(k) => { + *k = 5; + } + None => {} + }; + let v = &mut Some(2); + let _ = || match v { + //^ 💡 error: cannot mutate immutable variable `v` + ref mut k => { + *k = &mut Some(5); + } + }; +} +"#, + ); + } + #[test] fn match_bindings() { check_diagnostics( @@ -368,7 +399,7 @@ fn main() { #[test] fn mutation_in_dead_code() { // This one is interesting. Dead code is not represented at all in the MIR, so - // there would be no mutablility error for locals in dead code. Rustc tries to + // there would be no mutability error for locals in dead code. Rustc tries to // not emit `unused_mut` in this case, but since it works without `mut`, and // special casing it is not trivial, we emit it. check_diagnostics( @@ -481,6 +512,38 @@ fn main() { f(x); } } +"#, + ); + check_diagnostics( + r#" +fn check(_: i32) -> bool { + false +} +fn main() { + loop { + let x = 1; + if check(x) { + break; + } + let y = (1, 2); + if check(y.1) { + return; + } + let z = (1, 2); + match z { + (k @ 5, ref mut t) if { continue; } => { + //^^^^^^^^^ 💡 error: cannot mutate immutable variable `z` + *t = 5; + } + _ => { + let y = (1, 2); + if check(y.1) { + return; + } + } + } + } +} "#, ); check_diagnostics( @@ -544,6 +607,28 @@ fn f(x: i32) { x = 5; //^^^^^ 💡 error: cannot mutate immutable variable `x` } +"#, + ); + check_diagnostics( + r#" +fn f((x, y): (i32, i32)) { + let t = [0; 2]; + x = 5; + //^^^^^ 💡 error: cannot mutate immutable variable `x` +} +"#, + ); + } + + #[test] + fn no_diagnostics_in_case_of_multiple_bounds() { + check_diagnostics( + r#" +fn f() { + let (b, a, b) = (2, 3, 5); + a = 8; + //^^^^^ 💡 error: cannot mutate immutable variable `a` +} "#, ); } @@ -552,7 +637,7 @@ fn f(x: i32) { fn for_loop() { check_diagnostics( r#" -//- minicore: iterators +//- minicore: iterators, copy fn f(x: [(i32, u8); 10]) { for (a, mut b) in x { //^^^^^ 💡 weak: variable does not need to be mutable @@ -564,9 +649,97 @@ fn f(x: [(i32, u8); 10]) { ); } + #[test] + fn while_let() { + check_diagnostics( + r#" +//- minicore: iterators, copy +fn f(x: [(i32, u8); 10]) { + let mut it = x.into_iter(); + while let Some((a, mut b)) = it.next() { + //^^^^^ 💡 weak: variable does not need to be mutable + while let Some((c, mut d)) = it.next() { + //^^^^^ 💡 weak: variable does not need to be mutable + a = 2; + //^^^^^ 💡 error: cannot mutate immutable variable `a` + c = 2; + //^^^^^ 💡 error: cannot mutate immutable variable `c` + } + } +} +"#, + ); + } + + #[test] + fn index() { + check_diagnostics( + r#" +//- minicore: coerce_unsized, index, slice +fn f() { + let x = [1, 2, 3]; + x[2] = 5; + //^^^^^^^^ 💡 error: cannot mutate immutable variable `x` + let x = &mut x; + //^^^^^^ 💡 error: cannot mutate immutable variable `x` + let mut x = x; + //^^^^^ 💡 weak: variable does not need to be mutable + x[2] = 5; +} +"#, + ); + } + + #[test] + fn overloaded_index() { + check_diagnostics( + r#" +//- minicore: index +use core::ops::{Index, IndexMut}; + +struct Foo; +impl Index for Foo { + type Output = (i32, u8); + fn index(&self, index: usize) -> &(i32, u8) { + &(5, 2) + } +} +impl IndexMut for Foo { + fn index_mut(&mut self, index: usize) -> &mut (i32, u8) { + &mut (5, 2) + } +} +fn f() { + let mut x = Foo; + //^^^^^ 💡 weak: variable does not need to be mutable + let y = &x[2]; + let x = Foo; + let y = &mut x[2]; + //^💡 error: cannot mutate immutable variable `x` + let mut x = &mut Foo; + //^^^^^ 💡 weak: variable does not need to be mutable + let y: &mut (i32, u8) = &mut x[2]; + let x = Foo; + let ref mut y = x[7]; + //^ 💡 error: cannot mutate immutable variable `x` + let (ref mut y, _) = x[3]; + //^ 💡 error: cannot mutate immutable variable `x` + match x[10] { + //^ 💡 error: cannot mutate immutable variable `x` + (ref y, _) => (), + (_, ref mut y) => (), + } + let mut x = Foo; + let mut i = 5; + //^^^^^ 💡 weak: variable does not need to be mutable + let y = &mut x[i]; +} +"#, + ); + } + #[test] fn overloaded_deref() { - // FIXME: check for false negative check_diagnostics( r#" //- minicore: deref_mut @@ -574,22 +747,36 @@ use core::ops::{Deref, DerefMut}; struct Foo; impl Deref for Foo { - type Target = i32; - fn deref(&self) -> &i32 { - &5 + type Target = (i32, u8); + fn deref(&self) -> &(i32, u8) { + &(5, 2) } } impl DerefMut for Foo { - fn deref_mut(&mut self) -> &mut i32 { - &mut 5 + fn deref_mut(&mut self) -> &mut (i32, u8) { + &mut (5, 2) } } fn f() { - let x = Foo; + let mut x = Foo; + //^^^^^ 💡 weak: variable does not need to be mutable let y = &*x; let x = Foo; - let mut x = Foo; - let y: &mut i32 = &mut x; + let y = &mut *x; + //^^ 💡 error: cannot mutate immutable variable `x` + let x = Foo; + let x = Foo; + let y: &mut (i32, u8) = &mut x; + //^^^^^^ 💡 error: cannot mutate immutable variable `x` + let ref mut y = *x; + //^^ 💡 error: cannot mutate immutable variable `x` + let (ref mut y, _) = *x; + //^^ 💡 error: cannot mutate immutable variable `x` + match *x { + //^^ 💡 error: cannot mutate immutable variable `x` + (ref y, _) => (), + (_, ref mut y) => (), + } } "#, ); @@ -631,6 +818,267 @@ fn f(inp: (Foo, Foo, Foo, Foo)) { ); } + #[test] + // FIXME: We should have tests for `is_ty_uninhabited_from` + fn regression_14421() { + check_diagnostics( + r#" +pub enum Tree { + Node(TreeNode), + Leaf(TreeLeaf), +} + +struct Box(&T); + +pub struct TreeNode { + pub depth: usize, + pub children: [Box; 8] +} + +pub struct TreeLeaf { + pub depth: usize, + pub data: u8 +} + +pub fn test() { + let mut tree = Tree::Leaf( + //^^^^^^^^ 💡 weak: variable does not need to be mutable + TreeLeaf { + depth: 0, + data: 0 + } + ); +} +"#, + ); + } + + #[test] + fn fn_traits() { + check_diagnostics( + r#" +//- minicore: fn +fn fn_ref(mut x: impl Fn(u8) -> u8) -> u8 { + //^^^^^ 💡 weak: variable does not need to be mutable + x(2) +} +fn fn_mut(x: impl FnMut(u8) -> u8) -> u8 { + x(2) + //^ 💡 error: cannot mutate immutable variable `x` +} +fn fn_borrow_mut(mut x: &mut impl FnMut(u8) -> u8) -> u8 { + //^^^^^ 💡 weak: variable does not need to be mutable + x(2) +} +fn fn_once(mut x: impl FnOnce(u8) -> u8) -> u8 { + //^^^^^ 💡 weak: variable does not need to be mutable + x(2) +} +"#, + ); + } + + #[test] + fn closure() { + // FIXME: Diagnostic spans are inconsistent inside and outside closure + check_diagnostics( + r#" + //- minicore: copy, fn + struct X; + + impl X { + fn mutate(&mut self) {} + } + + fn f() { + let x = 5; + let closure1 = || { x = 2; }; + //^ 💡 error: cannot mutate immutable variable `x` + let _ = closure1(); + //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1` + let closure2 = || { x = x; }; + //^ 💡 error: cannot mutate immutable variable `x` + let closure3 = || { + let x = 2; + x = 5; + //^^^^^ 💡 error: cannot mutate immutable variable `x` + x + }; + let x = X; + let closure4 = || { x.mutate(); }; + //^ 💡 error: cannot mutate immutable variable `x` + } + "#, + ); + check_diagnostics( + r#" + //- minicore: copy, fn + fn f() { + let mut x = 5; + //^^^^^ 💡 weak: variable does not need to be mutable + let mut y = 2; + y = 7; + let closure = || { + let mut z = 8; + z = 3; + let mut k = z; + //^^^^^ 💡 weak: variable does not need to be mutable + }; + } + "#, + ); + check_diagnostics( + r#" +//- minicore: copy, fn +fn f() { + let closure = || { + || { + || { + let x = 2; + || { || { x = 5; } } + //^ 💡 error: cannot mutate immutable variable `x` + } + } + }; +} + "#, + ); + check_diagnostics( + r#" +//- minicore: copy, fn +fn f() { + struct X; + let mut x = X; + //^^^^^ 💡 weak: variable does not need to be mutable + let c1 = || x; + let mut x = X; + let c2 = || { x = X; x }; + let mut x = X; + let c2 = move || { x = X; }; +} + "#, + ); + check_diagnostics( + r#" + //- minicore: copy, fn, deref_mut + struct X(i32, i64); + + fn f() { + let mut x = &mut 5; + //^^^^^ 💡 weak: variable does not need to be mutable + let closure1 = || { *x = 2; }; + let _ = closure1(); + //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1` + let mut x = &mut 5; + //^^^^^ 💡 weak: variable does not need to be mutable + let closure1 = || { *x = 2; &x; }; + let _ = closure1(); + //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1` + let mut x = &mut 5; + let closure1 = || { *x = 2; &x; x = &mut 3; }; + let _ = closure1(); + //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1` + let mut x = &mut 5; + //^^^^^ 💡 weak: variable does not need to be mutable + let closure1 = move || { *x = 2; }; + let _ = closure1(); + //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1` + let mut x = &mut X(1, 2); + //^^^^^ 💡 weak: variable does not need to be mutable + let closure1 = || { x.0 = 2; }; + let _ = closure1(); + //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1` + } + "#, + ); + } + + #[test] + fn slice_pattern() { + check_diagnostics( + r#" +//- minicore: coerce_unsized, deref_mut, slice, copy +fn x(t: &[u8]) { + match t { + &[a, mut b] | &[a, _, mut b] => { + //^^^^^ 💡 weak: variable does not need to be mutable + + a = 2; + //^^^^^ 💡 error: cannot mutate immutable variable `a` + + } + _ => {} + } +} + "#, + ); + } + + #[test] + fn boxes() { + check_diagnostics( + r#" +//- minicore: coerce_unsized, deref_mut, slice +use core::ops::{Deref, DerefMut}; +use core::{marker::Unsize, ops::CoerceUnsized}; + +#[lang = "owned_box"] +pub struct Box { + inner: *mut T, +} +impl Box { + fn new(t: T) -> Self { + #[rustc_box] + Box::new(t) + } +} + +impl Deref for Box { + type Target = T; + + fn deref(&self) -> &T { + &**self + } +} + +impl DerefMut for Box { + fn deref_mut(&mut self) -> &mut T { + &mut **self + } +} + +fn f() { + let x = Box::new(5); + x = Box::new(7); + //^^^^^^^^^^^^^^^ 💡 error: cannot mutate immutable variable `x` + let x = Box::new(5); + *x = 7; + //^^^^^^ 💡 error: cannot mutate immutable variable `x` + let mut y = Box::new(5); + //^^^^^ 💡 weak: variable does not need to be mutable + *x = *y; + //^^^^^^^ 💡 error: cannot mutate immutable variable `x` + let x = Box::new(5); + let closure = || *x = 2; + //^ 💡 error: cannot mutate immutable variable `x` +} +"#, + ); + } + + #[test] + fn allow_unused_mut_for_identifiers_starting_with_underline() { + check_diagnostics( + r#" +fn f(_: i32) {} +fn main() { + let mut _x = 2; + f(_x); +} +"#, + ); + } + #[test] fn respect_allow_unused_mut() { // FIXME: respect diff --git a/crates/ide-diagnostics/src/handlers/no_such_field.rs b/crates/ide-diagnostics/src/handlers/no_such_field.rs index 24c521ed1a8a4..a39eceab24379 100644 --- a/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -21,7 +21,7 @@ pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) } fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Option> { - let root = ctx.sema.db.parse_or_expand(d.field.file_id)?; + let root = ctx.sema.db.parse_or_expand(d.field.file_id); missing_record_expr_field_fixes( &ctx.sema, d.field.file_id.original_file(ctx.sema.db), @@ -69,7 +69,7 @@ fn missing_record_expr_field_fixes( let new_field = make::record_field( None, make::name(record_expr_field.field_name()?.ident_token()?.text()), - make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?), + make::ty(&new_field_type.display_source_code(sema.db, module.into(), true).ok()?), ); let last_field = record_fields.fields().last()?; diff --git a/crates/ide-diagnostics/src/handlers/private_assoc_item.rs b/crates/ide-diagnostics/src/handlers/private_assoc_item.rs index 67da5c7f27d14..4cd85a479a061 100644 --- a/crates/ide-diagnostics/src/handlers/private_assoc_item.rs +++ b/crates/ide-diagnostics/src/handlers/private_assoc_item.rs @@ -11,7 +11,11 @@ pub(crate) fn private_assoc_item( d: &hir::PrivateAssocItem, ) -> Diagnostic { // FIXME: add quickfix - let name = d.item.name(ctx.sema.db).map(|name| format!("`{name}` ")).unwrap_or_default(); + let name = d + .item + .name(ctx.sema.db) + .map(|name| format!("`{}` ", name.display(ctx.sema.db))) + .unwrap_or_default(); Diagnostic::new( "private-assoc-item", format!( diff --git a/crates/ide-diagnostics/src/handlers/private_field.rs b/crates/ide-diagnostics/src/handlers/private_field.rs index be83ad6aaadaa..de7f51f693c42 100644 --- a/crates/ide-diagnostics/src/handlers/private_field.rs +++ b/crates/ide-diagnostics/src/handlers/private_field.rs @@ -9,8 +9,8 @@ pub(crate) fn private_field(ctx: &DiagnosticsContext<'_>, d: &hir::PrivateField) "private-field", format!( "field `{}` of `{}` is private", - d.field.name(ctx.sema.db), - d.field.parent_def(ctx.sema.db).name(ctx.sema.db) + d.field.name(ctx.sema.db).display(ctx.sema.db), + d.field.parent_def(ctx.sema.db).name(ctx.sema.db).display(ctx.sema.db) ), ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range, ) diff --git a/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs index 9b1c65983e615..d3eda3c5ebce3 100644 --- a/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs +++ b/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs @@ -28,7 +28,7 @@ fn fixes( ctx: &DiagnosticsContext<'_>, d: &hir::ReplaceFilterMapNextWithFindMap, ) -> Option> { - let root = ctx.sema.db.parse_or_expand(d.file)?; + let root = ctx.sema.db.parse_or_expand(d.file); let next_expr = d.next_expr.to_node(&root); let next_call = ast::MethodCallExpr::cast(next_expr.syntax().clone())?; @@ -115,7 +115,7 @@ fn foo() { r#" //- minicore: iterators fn foo() { - let m = core::iter::repeat(()) + let mut m = core::iter::repeat(()) .filter_map(|()| Some(92)); let n = m.next(); } diff --git a/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/crates/ide-diagnostics/src/handlers/type_mismatch.rs index 4abc25a28fbc0..c28f98d8333e2 100644 --- a/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -1,5 +1,5 @@ use either::Either; -use hir::{db::ExpandDatabase, HirDisplay, InFile, Type}; +use hir::{db::ExpandDatabase, ClosureStyle, HirDisplay, InFile, Type}; use ide_db::{famous_defs::FamousDefs, source_change::SourceChange}; use syntax::{ ast::{self, BlockExpr, ExprStmt}, @@ -15,15 +15,25 @@ use crate::{adjusted_display_range, fix, Assist, Diagnostic, DiagnosticsContext} // the expected type. pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Diagnostic { let display_range = match &d.expr_or_pat { - Either::Left(expr) => adjusted_display_range::( - ctx, - expr.clone().map(|it| it.into()), - &|block| { - let r_curly_range = block.stmt_list()?.r_curly_token()?.text_range(); - cov_mark::hit!(type_mismatch_on_block); - Some(r_curly_range) - }, - ), + Either::Left(expr) => { + adjusted_display_range::(ctx, expr.clone().map(|it| it.into()), &|expr| { + let salient_token_range = match expr { + ast::Expr::IfExpr(it) => it.if_token()?.text_range(), + ast::Expr::LoopExpr(it) => it.loop_token()?.text_range(), + ast::Expr::ForExpr(it) => it.for_token()?.text_range(), + ast::Expr::WhileExpr(it) => it.while_token()?.text_range(), + ast::Expr::BlockExpr(it) => it.stmt_list()?.r_curly_token()?.text_range(), + ast::Expr::MatchExpr(it) => it.match_token()?.text_range(), + ast::Expr::MethodCallExpr(it) => it.name_ref()?.ident_token()?.text_range(), + ast::Expr::FieldExpr(it) => it.name_ref()?.ident_token()?.text_range(), + ast::Expr::AwaitExpr(it) => it.await_token()?.text_range(), + _ => return None, + }; + + cov_mark::hit!(type_mismatch_range_adjustment); + Some(salient_token_range) + }) + } Either::Right(pat) => { ctx.sema.diagnostics_display_range(pat.clone().map(|it| it.into())).range } @@ -32,8 +42,8 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) "type-mismatch", format!( "expected {}, found {}", - d.expected.display(ctx.sema.db), - d.actual.display(ctx.sema.db) + d.expected.display(ctx.sema.db).with_closure_style(ClosureStyle::ClosureWithId), + d.actual.display(ctx.sema.db).with_closure_style(ClosureStyle::ClosureWithId), ), display_range, ) @@ -93,7 +103,7 @@ fn add_missing_ok_or_some( expr_ptr: &InFile>, acc: &mut Vec, ) -> Option<()> { - let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id)?; + let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id); let expr = expr_ptr.value.to_node(&root); let expr_range = expr.syntax().text_range(); let scope = ctx.sema.scope(expr.syntax())?; @@ -133,7 +143,7 @@ fn remove_semicolon( expr_ptr: &InFile>, acc: &mut Vec, ) -> Option<()> { - let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id)?; + let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id); let expr = expr_ptr.value.to_node(&root); if !d.actual.is_unit() { return None; @@ -169,7 +179,7 @@ fn str_ref_to_owned( return None; } - let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id)?; + let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id); let expr = expr_ptr.value.to_node(&root); let expr_range = expr.syntax().text_range(); @@ -597,8 +607,21 @@ fn test() -> String { } #[test] - fn type_mismatch_on_block() { - cov_mark::check!(type_mismatch_on_block); + fn closure_mismatch_show_different_type() { + check_diagnostics( + r#" +fn f() { + let mut x = (|| 1, 2); + x = (|| 3, 4); + //^^^^ error: expected {closure#0}, found {closure#1} +} + "#, + ); + } + + #[test] + fn type_mismatch_range_adjustment() { + cov_mark::check!(type_mismatch_range_adjustment); check_diagnostics( r#" fn f() -> i32 { @@ -607,6 +630,57 @@ fn f() -> i32 { let _ = x + y; } //^ error: expected i32, found () + +fn g() -> i32 { + while true {} +} //^^^^^ error: expected i32, found () + +struct S; +impl S { fn foo(&self) -> &S { self } } +fn h() { + let _: i32 = S.foo().foo().foo(); +} //^^^ error: expected i32, found &S +"#, + ); + } + + #[test] + fn unknown_type_in_function_signature() { + check_diagnostics( + r#" +struct X(T); + +fn foo(x: X) {} +fn test1() { + // Unknown might be `i32`, so we should not emit type mismatch here. + foo(X(42)); +} +fn test2() { + foo(42); + //^^ error: expected X<{unknown}>, found i32 +} +"#, + ); + } + + #[test] + fn evaluate_const_generics_in_types() { + check_diagnostics( + r#" +pub const ONE: usize = 1; + +pub struct Inner(); + +pub struct Outer { + pub inner: Inner, +} + +fn main() { + _ = Outer { + inner: Inner::<2>(), + //^^^^^^^^^^^^ error: expected Inner<1>, found Inner<2> + }; +} "#, ); } @@ -617,11 +691,48 @@ fn f() -> i32 { r#" fn f() { let &() = &mut (); + //^^^ error: expected &mut (), found &() match &() { + // FIXME: we should only show the deep one. &9 => () + //^^ error: expected &(), found &i32 //^ error: expected (), found i32 } } +"#, + ); + } + + #[test] + fn regression_14768() { + check_diagnostics( + r#" +//- minicore: derive, fmt, slice, coerce_unsized, builtin_impls +use core::fmt::Debug; + +#[derive(Debug)] +struct Foo(u8, u16, [u8]); + +#[derive(Debug)] +struct Bar { + f1: u8, + f2: &[u16], + f3: dyn Debug, +} +"#, + ); + } + + #[test] + fn return_no_value() { + check_diagnostics( + r#" +fn f() -> i32 { + return; + // ^^^^^^ error: expected i32, found () + 0 +} +fn g() { return; } "#, ); } diff --git a/crates/ide-diagnostics/src/handlers/typed_hole.rs b/crates/ide-diagnostics/src/handlers/typed_hole.rs new file mode 100644 index 0000000000000..e12bbcf682068 --- /dev/null +++ b/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -0,0 +1,232 @@ +use hir::{db::ExpandDatabase, ClosureStyle, HirDisplay, StructKind}; +use ide_db::{ + assists::{Assist, AssistId, AssistKind, GroupLabel}, + label::Label, + source_change::SourceChange, +}; +use syntax::AstNode; +use text_edit::TextEdit; + +use crate::{Diagnostic, DiagnosticsContext}; + +// Diagnostic: typed-hole +// +// This diagnostic is triggered when an underscore expression is used in an invalid position. +pub(crate) fn typed_hole(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Diagnostic { + let display_range = ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())); + let (message, fixes) = if d.expected.is_unknown() { + ("`_` expressions may only appear on the left-hand side of an assignment".to_owned(), None) + } else { + ( + format!( + "invalid `_` expression, expected type `{}`", + d.expected.display(ctx.sema.db).with_closure_style(ClosureStyle::ClosureWithId), + ), + fixes(ctx, d), + ) + }; + + Diagnostic::new("typed-hole", message, display_range.range).with_fixes(fixes) +} + +fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option> { + let db = ctx.sema.db; + let root = db.parse_or_expand(d.expr.file_id); + let original_range = + d.expr.as_ref().map(|it| it.to_node(&root)).syntax().original_file_range_opt(db)?; + let scope = ctx.sema.scope(d.expr.value.to_node(&root).syntax())?; + let mut assists = vec![]; + scope.process_all_names(&mut |name, def| { + let ty = match def { + hir::ScopeDef::ModuleDef(it) => match it { + hir::ModuleDef::Function(it) => it.ty(db), + hir::ModuleDef::Adt(hir::Adt::Struct(it)) if it.kind(db) != StructKind::Record => { + it.constructor_ty(db) + } + hir::ModuleDef::Variant(it) if it.kind(db) != StructKind::Record => { + it.constructor_ty(db) + } + hir::ModuleDef::Const(it) => it.ty(db), + hir::ModuleDef::Static(it) => it.ty(db), + _ => return, + }, + hir::ScopeDef::GenericParam(hir::GenericParam::ConstParam(it)) => it.ty(db), + hir::ScopeDef::Local(it) => it.ty(db), + _ => return, + }; + // FIXME: should also check coercions if it is at a coercion site + if !ty.contains_unknown() && ty.could_unify_with(db, &d.expected) { + assists.push(Assist { + id: AssistId("typed-hole", AssistKind::QuickFix), + label: Label::new(format!("Replace `_` with `{}`", name.display(db))), + group: Some(GroupLabel("Replace `_` with a matching entity in scope".to_owned())), + target: original_range.range, + source_change: Some(SourceChange::from_text_edit( + original_range.file_id, + TextEdit::replace(original_range.range, name.display(db).to_string()), + )), + trigger_signature_help: false, + }); + } + }); + if assists.is_empty() { + None + } else { + Some(assists) + } +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_diagnostics, check_fixes}; + + #[test] + fn unknown() { + check_diagnostics( + r#" +fn main() { + _; + //^ error: `_` expressions may only appear on the left-hand side of an assignment +} +"#, + ); + } + + #[test] + fn concrete_expectation() { + check_diagnostics( + r#" +fn main() { + if _ {} + //^ error: invalid `_` expression, expected type `bool` + let _: fn() -> i32 = _; + //^ error: invalid `_` expression, expected type `fn() -> i32` + let _: fn() -> () = _; // FIXME: This should trigger an assist because `main` matches via *coercion* + //^ error: invalid `_` expression, expected type `fn()` +} +"#, + ); + } + + #[test] + fn integer_ty_var() { + check_diagnostics( + r#" +fn main() { + let mut x = 3; + x = _; + //^ 💡 error: invalid `_` expression, expected type `i32` +} +"#, + ); + } + + #[test] + fn ty_var_resolved() { + check_diagnostics( + r#" +fn main() { + let mut x = t(); + x = _; + //^ 💡 error: invalid `_` expression, expected type `&str` + x = ""; +} +fn t() -> T { loop {} } +"#, + ); + } + + #[test] + fn valid_positions() { + check_diagnostics( + r#" +fn main() { + let x = [(); _]; + let y: [(); 10] = [(); _]; + _ = 0; + (_,) = (1,); +} +"#, + ); + } + + #[test] + fn check_quick_fix() { + check_fixes( + r#" +enum Foo { + Bar +} +use Foo::Bar; +const C: Foo = Foo::Bar; +fn main(param: Foo) { + let local = Foo::Bar; + let _: Foo = _$0; + //^ error: invalid `_` expression, expected type `fn()` +} +"#, + vec![ + r#" +enum Foo { + Bar +} +use Foo::Bar; +const C: Foo = Foo::Bar; +fn main(param: Foo) { + let local = Foo::Bar; + let _: Foo = local; + //^ error: invalid `_` expression, expected type `fn()` +} +"#, + r#" +enum Foo { + Bar +} +use Foo::Bar; +const C: Foo = Foo::Bar; +fn main(param: Foo) { + let local = Foo::Bar; + let _: Foo = param; + //^ error: invalid `_` expression, expected type `fn()` +} +"#, + r#" +enum Foo { + Bar +} +use Foo::Bar; +const C: Foo = Foo::Bar; +fn main(param: Foo) { + let local = Foo::Bar; + let _: Foo = CP; + //^ error: invalid `_` expression, expected type `fn()` +} +"#, + r#" +enum Foo { + Bar +} +use Foo::Bar; +const C: Foo = Foo::Bar; +fn main(param: Foo) { + let local = Foo::Bar; + let _: Foo = Bar; + //^ error: invalid `_` expression, expected type `fn()` +} +"#, + r#" +enum Foo { + Bar +} +use Foo::Bar; +const C: Foo = Foo::Bar; +fn main(param: Foo) { + let local = Foo::Bar; + let _: Foo = C; + //^ error: invalid `_` expression, expected type `fn()` +} +"#, + ], + ); + } +} diff --git a/crates/ide-diagnostics/src/handlers/undeclared_label.rs b/crates/ide-diagnostics/src/handlers/undeclared_label.rs new file mode 100644 index 0000000000000..034e4fcfb85b2 --- /dev/null +++ b/crates/ide-diagnostics/src/handlers/undeclared_label.rs @@ -0,0 +1,88 @@ +use crate::{Diagnostic, DiagnosticsContext}; + +// Diagnostic: undeclared-label +pub(crate) fn undeclared_label( + ctx: &DiagnosticsContext<'_>, + d: &hir::UndeclaredLabel, +) -> Diagnostic { + let name = &d.name; + Diagnostic::new( + "undeclared-label", + format!("use of undeclared label `{}`", name.display(ctx.sema.db)), + ctx.sema.diagnostics_display_range(d.node.clone().map(|it| it.into())).range, + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::check_diagnostics; + + #[test] + fn smoke_test() { + check_diagnostics( + r#" +fn foo() { + break 'a; + //^^^^^^^^ error: break outside of loop + //^^ error: use of undeclared label `'a` + continue 'a; + //^^^^^^^^^^^ error: continue outside of loop + //^^ error: use of undeclared label `'a` +} +"#, + ); + } + + #[test] + fn for_loop() { + check_diagnostics( + r#" +//- minicore: iterator +fn foo() { + 'xxx: for _ in unknown { + 'yyy: for _ in unknown { + break 'xxx; + continue 'yyy; + break 'zzz; + //^^^^ error: use of undeclared label `'zzz` + } + continue 'xxx; + continue 'yyy; + //^^^^ error: use of undeclared label `'yyy` + break 'xxx; + break 'yyy; + //^^^^ error: use of undeclared label `'yyy` + } +} +"#, + ); + } + + #[test] + fn try_operator_desugar_works() { + check_diagnostics( + r#" +//- minicore: option, try +fn foo() { + None?; +} +"#, + ); + check_diagnostics( + r#" +//- minicore: option, try, future +async fn foo() { + None?; +} +"#, + ); + check_diagnostics( + r#" +//- minicore: option, try, future, fn +async fn foo() { + || None?; +} +"#, + ); + } +} diff --git a/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/crates/ide-diagnostics/src/handlers/unlinked_file.rs index 3d45a75913ad8..271e7ce73bcdd 100644 --- a/crates/ide-diagnostics/src/handlers/unlinked_file.rs +++ b/crates/ide-diagnostics/src/handlers/unlinked_file.rs @@ -2,7 +2,7 @@ use std::iter; -use hir::{db::DefDatabase, InFile, ModuleSource}; +use hir::{db::DefDatabase, DefMap, InFile, ModuleSource}; use ide_db::{ base_db::{FileId, FileLoader, SourceDatabase, SourceDatabaseExt}, source_change::SourceChange, @@ -10,7 +10,7 @@ use ide_db::{ }; use syntax::{ ast::{self, edit::IndentLevel, HasModuleItem, HasName}, - AstNode, TextRange, TextSize, + AstNode, TextRange, }; use text_edit::TextEdit; @@ -27,14 +27,28 @@ pub(crate) fn unlinked_file( ) { // Limit diagnostic to the first few characters in the file. This matches how VS Code // renders it with the full span, but on other editors, and is less invasive. + let fixes = fixes(ctx, file_id); + // FIXME: This is a hack for the vscode extension to notice whether there is an autofix or not before having to resolve diagnostics. + // This is to prevent project linking popups from appearing when there is an autofix. https://github.com/rust-lang/rust-analyzer/issues/14523 + let message = if fixes.is_none() { + "file not included in crate hierarchy" + } else { + "file not included in module tree" + }; + let range = ctx.sema.db.parse(file_id).syntax_node().text_range(); - // FIXME: This is wrong if one of the first three characters is not ascii: `//Ы`. - let range = range.intersect(TextRange::up_to(TextSize::of("..."))).unwrap_or(range); + let range = FileLoader::file_text(ctx.sema.db, file_id) + .char_indices() + .take(3) + .last() + .map(|(i, _)| i) + .map(|i| TextRange::up_to(i.try_into().unwrap())) + .unwrap_or(range); acc.push( - Diagnostic::new("unlinked-file", "file not included in module tree", range) + Diagnostic::new("unlinked-file", message, range) .severity(Severity::WeakWarning) - .with_fixes(fixes(ctx, file_id)), + .with_fixes(fixes), ); } @@ -60,7 +74,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, file_id: FileId) -> Option> { 'crates: for &krate in &*ctx.sema.db.relevant_crates(file_id) { let crate_def_map = ctx.sema.db.crate_def_map(krate); - let root_module = &crate_def_map[crate_def_map.root()]; + let root_module = &crate_def_map[DefMap::ROOT]; let Some(root_file_id) = root_module.origin.file_id() else { continue }; let Some(crate_root_path) = source_root.path_for_file(&root_file_id) else { continue }; let Some(rel) = parent.strip_prefix(&crate_root_path.parent()?) else { continue }; @@ -92,7 +106,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, file_id: FileId) -> Option> { // if we aren't adding to a crate root, walk backwards such that we support `#[path = ...]` overrides if possible // build all parent paths of the form `../module_name/mod.rs` and `../module_name.rs` - let paths = iter::successors(Some(parent.clone()), |prev| prev.parent()).filter_map(|path| { + let paths = iter::successors(Some(parent), |prev| prev.parent()).filter_map(|path| { let parent = path.parent()?; let (name, _) = path.name_and_extension()?; Some(([parent.join(&format!("{name}.rs"))?, path.join("mod.rs")?], name.to_owned())) diff --git a/crates/ide-diagnostics/src/handlers/unreachable_label.rs b/crates/ide-diagnostics/src/handlers/unreachable_label.rs new file mode 100644 index 0000000000000..9fedadeae0359 --- /dev/null +++ b/crates/ide-diagnostics/src/handlers/unreachable_label.rs @@ -0,0 +1,91 @@ +use crate::{Diagnostic, DiagnosticsContext}; + +// Diagnostic: unreachable-label +pub(crate) fn unreachable_label( + ctx: &DiagnosticsContext<'_>, + d: &hir::UnreachableLabel, +) -> Diagnostic { + let name = &d.name; + Diagnostic::new( + "unreachable-label", + format!("use of unreachable label `{}`", name.display(ctx.sema.db)), + ctx.sema.diagnostics_display_range(d.node.clone().map(|it| it.into())).range, + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::check_diagnostics; + + #[test] + fn async_blocks_are_borders() { + check_diagnostics( + r#" +fn foo() { + 'a: loop { + async { + break 'a; + //^^^^^^^^ error: break outside of loop + // ^^ error: use of unreachable label `'a` + continue 'a; + //^^^^^^^^^^^ error: continue outside of loop + // ^^ error: use of unreachable label `'a` + }; + } +} +"#, + ); + } + + #[test] + fn closures_are_borders() { + check_diagnostics( + r#" +fn foo() { + 'a: loop { + || { + break 'a; + //^^^^^^^^ error: break outside of loop + // ^^ error: use of unreachable label `'a` + continue 'a; + //^^^^^^^^^^^ error: continue outside of loop + // ^^ error: use of unreachable label `'a` + }; + } +} +"#, + ); + } + + #[test] + fn blocks_pass_through() { + check_diagnostics( + r#" +fn foo() { + 'a: loop { + { + break 'a; + continue 'a; + } + } +} +"#, + ); + } + + #[test] + fn try_blocks_pass_through() { + check_diagnostics( + r#" +fn foo() { + 'a: loop { + try { + break 'a; + continue 'a; + }; + } +} +"#, + ); + } +} diff --git a/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/crates/ide-diagnostics/src/handlers/unresolved_field.rs index cefa74e523e8f..5e4efa41fd9c3 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_field.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_field.rs @@ -26,7 +26,7 @@ pub(crate) fn unresolved_field( "unresolved-field", format!( "no field `{}` on type `{}`{method_suffix}", - d.name, + d.name.display(ctx.sema.db), d.receiver.display(ctx.sema.db) ), ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range, @@ -45,12 +45,12 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option, expr_ptr: &InFile>, ) -> Option> { - let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id)?; + let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id); let expr = expr_ptr.value.to_node(&root); let FileRange { range, file_id } = ctx.sema.original_range_opt(expr.syntax())?; Some(vec![Assist { diff --git a/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs b/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs index 1a5efff2c0c60..3943b51ab422d 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs @@ -13,7 +13,7 @@ pub(crate) fn unresolved_macro_call( let bang = if d.is_bang { "!" } else { "" }; Diagnostic::new( "unresolved-macro-call", - format!("unresolved macro `{}{bang}`", d.path), + format!("unresolved macro `{}{bang}`", d.path.display(ctx.sema.db)), display_range, ) .experimental() diff --git a/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/crates/ide-diagnostics/src/handlers/unresolved_method.rs index f3ec6efa75215..8bbb837e6709e 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_method.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_method.rs @@ -26,7 +26,7 @@ pub(crate) fn unresolved_method( "unresolved-method", format!( "no method `{}` on type `{}`{field_suffix}", - d.name, + d.name.display(ctx.sema.db), d.receiver.display(ctx.sema.db) ), ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range, @@ -53,7 +53,7 @@ fn field_fix( return None; } let expr_ptr = &d.expr; - let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id)?; + let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id); let expr = expr_ptr.value.to_node(&root); let (file_id, range) = match expr { ast::Expr::MethodCallExpr(mcall) => { diff --git a/crates/ide-diagnostics/src/handlers/unresolved_module.rs b/crates/ide-diagnostics/src/handlers/unresolved_module.rs index 94614f11c3349..6e3fd3b42b0c3 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_module.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_module.rs @@ -31,7 +31,7 @@ pub(crate) fn unresolved_module( } fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedModule) -> Option> { - let root = ctx.sema.db.parse_or_expand(d.decl.file_id)?; + let root = ctx.sema.db.parse_or_expand(d.decl.file_id); let unresolved_module = d.decl.value.to_node(&root); Some( d.candidates diff --git a/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs b/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs index 9a984ba6bf07a..ae5cf135839f1 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs @@ -25,25 +25,21 @@ pub(crate) fn unresolved_proc_macro( _ => proc_macros_enabled, }; - let message = match &d.macro_name { + let not_expanded_message = match &d.macro_name { Some(name) => format!("proc macro `{name}` not expanded"), None => "proc macro not expanded".to_string(), }; let severity = if config_enabled { Severity::Error } else { Severity::WeakWarning }; let def_map = ctx.sema.db.crate_def_map(d.krate); - let message = format!( - "{message}: {}", - if config_enabled { - def_map.proc_macro_loading_error().unwrap_or("proc macro not found in the built dylib") - } else { - match d.kind { - hir::MacroKind::Attr if proc_macros_enabled => { - "attribute macro expansion is disabled" - } - _ => "proc-macro expansion is disabled", - } - }, - ); + let message = if config_enabled { + def_map.proc_macro_loading_error().unwrap_or("proc macro not found in the built dylib") + } else { + match d.kind { + hir::MacroKind::Attr if proc_macros_enabled => "attribute macro expansion is disabled", + _ => "proc-macro expansion is disabled", + } + }; + let message = format!("{not_expanded_message}: {message}"); Diagnostic::new("unresolved-proc-macro", message, display_range).severity(severity) } diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index 71f136b8c9030..55a4a482d3b28 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -38,11 +38,13 @@ mod handlers { pub(crate) mod missing_fields; pub(crate) mod missing_match_arms; pub(crate) mod missing_unsafe; + pub(crate) mod moved_out_of_ref; pub(crate) mod mutability_errors; pub(crate) mod no_such_field; pub(crate) mod private_assoc_item; pub(crate) mod private_field; pub(crate) mod replace_filter_map_next_with_find_map; + pub(crate) mod typed_hole; pub(crate) mod type_mismatch; pub(crate) mod unimplemented_builtin_macro; pub(crate) mod unresolved_extern_crate; @@ -52,6 +54,8 @@ mod handlers { pub(crate) mod unresolved_macro_call; pub(crate) mod unresolved_module; pub(crate) mod unresolved_proc_macro; + pub(crate) mod undeclared_label; + pub(crate) mod unreachable_label; // The handlers below are unusual, the implement the diagnostics as well. pub(crate) mod field_shorthand; @@ -74,6 +78,7 @@ use ide_db::{ }; use syntax::{algo::find_node_at_range, ast::AstNode, SyntaxNodePtr, TextRange}; +// FIXME: Make this an enum #[derive(Copy, Clone, Debug, PartialEq)] pub struct DiagnosticCode(pub &'static str); @@ -198,7 +203,7 @@ impl<'a> DiagnosticsContext<'a> { let sema = &self.sema; (|| { let precise_location = precise_location?; - let root = sema.parse_or_expand(node.file_id)?; + let root = sema.parse_or_expand(node.file_id); match root.covering_element(precise_location) { syntax::NodeOrToken::Node(it) => Some(sema.original_range(&it)), syntax::NodeOrToken::Token(it) => { @@ -246,42 +251,60 @@ pub fn diagnostics( let mut diags = Vec::new(); if let Some(m) = module { - m.diagnostics(db, &mut diags) + m.diagnostics(db, &mut diags); } for diag in diags { #[rustfmt::skip] let d = match diag { - AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d), AnyDiagnostic::ExpectedFunction(d) => handlers::expected_function::expected_function(&ctx, &d), - AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d), + AnyDiagnostic::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) { + Some(it) => it, + None => continue, + } AnyDiagnostic::IncoherentImpl(d) => handlers::incoherent_impl::incoherent_impl(&ctx, &d), + AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d), + AnyDiagnostic::InvalidDeriveTarget(d) => handlers::invalid_derive_target::invalid_derive_target(&ctx, &d), + AnyDiagnostic::MacroDefError(d) => handlers::macro_error::macro_def_error(&ctx, &d), AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d), + AnyDiagnostic::MacroExpansionParseError(d) => { + res.extend(d.errors.iter().take(32).map(|err| { + { + Diagnostic::new( + "syntax-error", + format!("Syntax Error in Expansion: {err}"), + ctx.resolve_precise_location(&d.node.clone(), d.precise_location), + ) + } + .experimental() + })); + continue; + }, AnyDiagnostic::MalformedDerive(d) => handlers::malformed_derive::malformed_derive(&ctx, &d), AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d), AnyDiagnostic::MissingFields(d) => handlers::missing_fields::missing_fields(&ctx, &d), AnyDiagnostic::MissingMatchArms(d) => handlers::missing_match_arms::missing_match_arms(&ctx, &d), AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d), + AnyDiagnostic::MovedOutOfRef(d) => handlers::moved_out_of_ref::moved_out_of_ref(&ctx, &d), + AnyDiagnostic::NeedMut(d) => handlers::mutability_errors::need_mut(&ctx, &d), AnyDiagnostic::NoSuchField(d) => handlers::no_such_field::no_such_field(&ctx, &d), AnyDiagnostic::PrivateAssocItem(d) => handlers::private_assoc_item::private_assoc_item(&ctx, &d), AnyDiagnostic::PrivateField(d) => handlers::private_field::private_field(&ctx, &d), AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d), + AnyDiagnostic::TypedHole(d) => handlers::typed_hole::typed_hole(&ctx, &d), AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d), + AnyDiagnostic::UndeclaredLabel(d) => handlers::undeclared_label::undeclared_label(&ctx, &d), AnyDiagnostic::UnimplementedBuiltinMacro(d) => handlers::unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d), + AnyDiagnostic::UnreachableLabel(d) => handlers::unreachable_label:: unreachable_label(&ctx, &d), AnyDiagnostic::UnresolvedExternCrate(d) => handlers::unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), + AnyDiagnostic::UnresolvedField(d) => handlers::unresolved_field::unresolved_field(&ctx, &d), AnyDiagnostic::UnresolvedImport(d) => handlers::unresolved_import::unresolved_import(&ctx, &d), AnyDiagnostic::UnresolvedMacroCall(d) => handlers::unresolved_macro_call::unresolved_macro_call(&ctx, &d), + AnyDiagnostic::UnresolvedMethodCall(d) => handlers::unresolved_method::unresolved_method(&ctx, &d), AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d), AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d, config.proc_macros_enabled, config.proc_attr_macros_enabled), - AnyDiagnostic::InvalidDeriveTarget(d) => handlers::invalid_derive_target::invalid_derive_target(&ctx, &d), - AnyDiagnostic::UnresolvedField(d) => handlers::unresolved_field::unresolved_field(&ctx, &d), - AnyDiagnostic::UnresolvedMethodCall(d) => handlers::unresolved_method::unresolved_method(&ctx, &d), - AnyDiagnostic::NeedMut(d) => handlers::mutability_errors::need_mut(&ctx, &d), AnyDiagnostic::UnusedMut(d) => handlers::mutability_errors::unused_mut(&ctx, &d), - AnyDiagnostic::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) { - Some(it) => it, - None => continue, - } + AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d), }; res.push(d) } diff --git a/crates/ide-diagnostics/src/tests.rs b/crates/ide-diagnostics/src/tests.rs index afa641c733ebb..b5cd4e0d68911 100644 --- a/crates/ide-diagnostics/src/tests.rs +++ b/crates/ide-diagnostics/src/tests.rs @@ -8,7 +8,7 @@ use ide_db::{ RootDatabase, }; use stdx::trim_indent; -use test_utils::{assert_eq_text, extract_annotations}; +use test_utils::{assert_eq_text, extract_annotations, MiniCore}; use crate::{DiagnosticsConfig, ExprFillDefaultMode, Severity}; @@ -121,6 +121,15 @@ pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixtur }) .collect::>(); actual.sort_by_key(|(range, _)| range.start()); + if expected.is_empty() { + // makes minicore smoke test debugable + for (e, _) in &actual { + eprintln!( + "Code in range {e:?} = {}", + &db.file_text(file_id)[usize::from(e.start())..usize::from(e.end())] + ) + } + } assert_eq!(expected, actual); } } @@ -143,3 +152,28 @@ fn test_disabled_diagnostics() { ); assert!(!diagnostics.is_empty()); } + +#[test] +fn minicore_smoke_test() { + fn check(minicore: MiniCore) { + let source = minicore.source_code(); + let mut config = DiagnosticsConfig::test_sample(); + // This should be ignored since we conditionaly remove code which creates single item use with braces + config.disabled.insert("unnecessary-braces".to_string()); + check_diagnostics_with_config(config, &source); + } + + // Checks that there is no diagnostic in minicore for each flag. + for flag in MiniCore::available_flags() { + if flag == "clone" { + // Clone without copy has `moved-out-of-ref`, so ignoring. + // FIXME: Maybe we should merge copy and clone in a single flag? + continue; + } + eprintln!("Checking minicore flag {flag}"); + check(MiniCore::from_flags([flag])); + } + // And one time for all flags, to check codes which are behind multiple flags + prevent name collisions + eprintln!("Checking all minicore flags"); + check(MiniCore::from_flags(MiniCore::available_flags())) +} diff --git a/crates/ide-ssr/Cargo.toml b/crates/ide-ssr/Cargo.toml index 04efa7b91d824..70ed6dea5bf28 100644 --- a/crates/ide-ssr/Cargo.toml +++ b/crates/ide-ssr/Cargo.toml @@ -15,6 +15,8 @@ doctest = false [dependencies] cov-mark = "2.0.0-pre.1" itertools = "0.10.5" +triomphe.workspace = true +nohash-hasher.workspace = true # local deps hir.workspace = true diff --git a/crates/ide-ssr/src/lib.rs b/crates/ide-ssr/src/lib.rs index d9834ee63adcc..66832a0bee496 100644 --- a/crates/ide-ssr/src/lib.rs +++ b/crates/ide-ssr/src/lib.rs @@ -87,8 +87,8 @@ pub use crate::{errors::SsrError, from_comment::ssr_from_comment, matching::Matc use crate::{errors::bail, matching::MatchFailureReason}; use hir::Semantics; use ide_db::base_db::{FileId, FilePosition, FileRange}; +use nohash_hasher::IntMap; use resolving::ResolvedRule; -use stdx::hash::NoHashHashMap; use syntax::{ast, AstNode, SyntaxNode, TextRange}; use text_edit::TextEdit; @@ -168,9 +168,9 @@ impl<'db> MatchFinder<'db> { } /// Finds matches for all added rules and returns edits for all found matches. - pub fn edits(&self) -> NoHashHashMap { + pub fn edits(&self) -> IntMap { use ide_db::base_db::SourceDatabaseExt; - let mut matches_by_file = NoHashHashMap::default(); + let mut matches_by_file = IntMap::default(); for m in self.matches().matches { matches_by_file .entry(m.range.file_id) @@ -184,6 +184,7 @@ impl<'db> MatchFinder<'db> { ( file_id, replacing::matches_to_edit( + self.sema.db, &matches, &self.sema.db.file_text(file_id), &self.rules, @@ -224,7 +225,7 @@ impl<'db> MatchFinder<'db> { let file = self.sema.parse(file_id); let mut res = Vec::new(); let file_text = self.sema.db.file_text(file_id); - let mut remaining_text = file_text.as_str(); + let mut remaining_text = &*file_text; let mut base = 0; let len = snippet.len() as u32; while let Some(offset) = remaining_text.find(snippet) { diff --git a/crates/ide-ssr/src/replacing.rs b/crates/ide-ssr/src/replacing.rs index e27ef6e35ef42..b4b83f62da240 100644 --- a/crates/ide-ssr/src/replacing.rs +++ b/crates/ide-ssr/src/replacing.rs @@ -14,14 +14,16 @@ use crate::{fragments, resolving::ResolvedRule, Match, SsrMatches}; /// template. Placeholders in the template will have been substituted with whatever they matched to /// in the original code. pub(crate) fn matches_to_edit( + db: &dyn hir::db::ExpandDatabase, matches: &SsrMatches, file_src: &str, rules: &[ResolvedRule], ) -> TextEdit { - matches_to_edit_at_offset(matches, file_src, 0.into(), rules) + matches_to_edit_at_offset(db, matches, file_src, 0.into(), rules) } fn matches_to_edit_at_offset( + db: &dyn hir::db::ExpandDatabase, matches: &SsrMatches, file_src: &str, relative_start: TextSize, @@ -31,13 +33,14 @@ fn matches_to_edit_at_offset( for m in &matches.matches { edit_builder.replace( m.range.range.checked_sub(relative_start).unwrap(), - render_replace(m, file_src, rules), + render_replace(db, m, file_src, rules), ); } edit_builder.finish() } struct ReplacementRenderer<'a> { + db: &'a dyn hir::db::ExpandDatabase, match_info: &'a Match, file_src: &'a str, rules: &'a [ResolvedRule], @@ -53,13 +56,19 @@ struct ReplacementRenderer<'a> { placeholder_tokens_requiring_parenthesis: FxHashSet, } -fn render_replace(match_info: &Match, file_src: &str, rules: &[ResolvedRule]) -> String { +fn render_replace( + db: &dyn hir::db::ExpandDatabase, + match_info: &Match, + file_src: &str, + rules: &[ResolvedRule], +) -> String { let rule = &rules[match_info.rule_index]; let template = rule .template .as_ref() .expect("You called MatchFinder::edits after calling MatchFinder::add_search_pattern"); let mut renderer = ReplacementRenderer { + db, match_info, file_src, rules, @@ -96,7 +105,7 @@ impl ReplacementRenderer<'_> { fn render_node(&mut self, node: &SyntaxNode) { if let Some(mod_path) = self.match_info.rendered_template_paths.get(node) { - self.out.push_str(&mod_path.to_string()); + self.out.push_str(&mod_path.display(self.db).to_string()); // Emit everything except for the segment's name-ref, since we already effectively // emitted that as part of `mod_path`. if let Some(path) = ast::Path::cast(node.clone()) { @@ -144,6 +153,7 @@ impl ReplacementRenderer<'_> { ); } let edit = matches_to_edit_at_offset( + self.db, &placeholder_value.inner_matches, self.file_src, range.start(), diff --git a/crates/ide-ssr/src/tests.rs b/crates/ide-ssr/src/tests.rs index 61698fca80fee..424ba3d7fd506 100644 --- a/crates/ide-ssr/src/tests.rs +++ b/crates/ide-ssr/src/tests.rs @@ -3,8 +3,8 @@ use ide_db::{ base_db::{salsa::Durability, FileId, FilePosition, FileRange, SourceDatabaseExt}, FxHashSet, }; -use std::sync::Arc; use test_utils::RangeOrOffset; +use triomphe::Arc; use crate::{MatchFinder, SsrRule}; diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index 30e514e4136a4..2aee203c4ea54 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml @@ -23,6 +23,8 @@ pulldown-cmark = { version = "0.9.1", default-features = false } url = "2.3.1" dot = "0.1.4" smallvec.workspace = true +triomphe.workspace = true +nohash-hasher.workspace = true # local deps cfg.workspace = true diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs index 48bcd37b62c61..dd1d0d75c63ee 100644 --- a/crates/ide/src/call_hierarchy.rs +++ b/crates/ide/src/call_hierarchy.rs @@ -263,7 +263,7 @@ mod tests { expect![["callee Function FileId(0) 0..14 3..9"]], expect![[r#" caller1 Function FileId(0) 15..45 18..25 : [34..40] - test_caller Function FileId(0) 95..149 110..121 : [134..140]"#]], + test_caller Function FileId(0) 95..149 110..121 tests : [134..140]"#]], expect![[]], ); } @@ -283,7 +283,7 @@ fn caller() { //- /foo/mod.rs pub fn callee() {} "#, - expect![["callee Function FileId(1) 0..18 7..13"]], + expect!["callee Function FileId(1) 0..18 7..13 foo"], expect![["caller Function FileId(0) 27..56 30..36 : [45..51]"]], expect![[]], ); @@ -323,7 +323,7 @@ pub fn callee() {} "#, expect![["caller Function FileId(0) 27..56 30..36"]], expect![[]], - expect![["callee Function FileId(1) 0..18 7..13 : [45..51]"]], + expect!["callee Function FileId(1) 0..18 7..13 foo : [45..51]"], ); } @@ -477,7 +477,7 @@ fn caller() { S1::callee(); } "#, - expect![["callee Function FileId(0) 15..27 18..24"]], + expect!["callee Function FileId(0) 15..27 18..24 T1"], expect![["caller Function FileId(0) 82..115 85..91 : [104..110]"]], expect![[]], ); diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index fae25f3102333..8112c4f7259cf 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs @@ -5,6 +5,8 @@ mod tests; mod intra_doc_links; +use std::ffi::OsStr; + use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag}; use pulldown_cmark_to_cmark::{cmark_resume_with_options, Options as CMarkOptions}; use stdx::format_to; @@ -12,7 +14,7 @@ use url::Url; use hir::{db::HirDatabase, Adt, AsAssocItem, AssocItem, AssocItemContainer, HasAttrs}; use ide_db::{ - base_db::{CrateOrigin, LangCrateOrigin, SourceDatabase}, + base_db::{CrateOrigin, LangCrateOrigin, ReleaseChannel, SourceDatabase}, defs::{Definition, NameClass, NameRefClass}, helpers::pick_best_token, RootDatabase, @@ -29,8 +31,16 @@ use crate::{ FilePosition, Semantics, }; -/// Weblink to an item's documentation. -pub(crate) type DocumentationLink = String; +/// Web and local links to an item's documentation. +#[derive(Default, Debug, Clone, PartialEq, Eq)] +pub struct DocumentationLinks { + /// The URL to the documentation on docs.rs. + /// May not lead anywhere. + pub web_url: Option, + /// The URL to the documentation in the local file system. + /// May not lead anywhere. + pub local_url: Option, +} const MARKDOWN_OPTIONS: Options = Options::ENABLE_FOOTNOTES.union(Options::ENABLE_TABLES).union(Options::ENABLE_TASKLISTS); @@ -109,7 +119,7 @@ pub(crate) fn remove_links(markdown: &str) -> String { // Feature: Open Docs // -// Retrieve a link to documentation for the given symbol. +// Retrieve a links to documentation for the given symbol. // // The simplest way to use this feature is via the context menu. Right-click on // the selected item. The context menu opens. Select **Open Docs**. @@ -122,7 +132,9 @@ pub(crate) fn remove_links(markdown: &str) -> String { pub(crate) fn external_docs( db: &RootDatabase, position: &FilePosition, -) -> Option { + target_dir: Option<&OsStr>, + sysroot: Option<&OsStr>, +) -> Option { let sema = &Semantics::new(db); let file = sema.parse(position.file_id).syntax().clone(); let token = pick_best_token(file.token_at_offset(position.offset), |kind| match kind { @@ -146,11 +158,11 @@ pub(crate) fn external_docs( NameClass::Definition(it) | NameClass::ConstReference(it) => it, NameClass::PatFieldShorthand { local_def: _, field_ref } => Definition::Field(field_ref), }, - _ => return None, + _ => return None } }; - get_doc_link(db, definition) + Some(get_doc_links(db, definition, target_dir, sysroot)) } /// Extracts all links from a given markdown text returning the definition text range, link-text @@ -308,19 +320,35 @@ fn broken_link_clone_cb(link: BrokenLink<'_>) -> Option<(CowStr<'_>, CowStr<'_>) // // This should cease to be a problem if RFC2988 (Stable Rustdoc URLs) is implemented // https://github.com/rust-lang/rfcs/pull/2988 -fn get_doc_link(db: &RootDatabase, def: Definition) -> Option { - let (target, file, frag) = filename_and_frag_for_def(db, def)?; +fn get_doc_links( + db: &RootDatabase, + def: Definition, + target_dir: Option<&OsStr>, + sysroot: Option<&OsStr>, +) -> DocumentationLinks { + let join_url = |base_url: Option, path: &str| -> Option { + base_url.and_then(|url| url.join(path).ok()) + }; + + let Some((target, file, frag)) = filename_and_frag_for_def(db, def) else { return Default::default(); }; - let mut url = get_doc_base_url(db, target)?; + let (mut web_url, mut local_url) = get_doc_base_urls(db, target, target_dir, sysroot); if let Some(path) = mod_path_of_def(db, target) { - url = url.join(&path).ok()?; + web_url = join_url(web_url, &path); + local_url = join_url(local_url, &path); } - url = url.join(&file).ok()?; - url.set_fragment(frag.as_deref()); + web_url = join_url(web_url, &file); + local_url = join_url(local_url, &file); - Some(url.into()) + web_url.as_mut().map(|url| url.set_fragment(frag.as_deref())); + local_url.as_mut().map(|url| url.set_fragment(frag.as_deref())); + + DocumentationLinks { + web_url: web_url.map(|it| it.into()), + local_url: local_url.map(|it| it.into()), + } } fn rewrite_intra_doc_link( @@ -332,7 +360,7 @@ fn rewrite_intra_doc_link( let (link, ns) = parse_intra_doc_link(target); let resolved = resolve_doc_path_for_def(db, def, link, ns)?; - let mut url = get_doc_base_url(db, resolved)?; + let mut url = get_doc_base_urls(db, resolved, None, None).0?; let (_, file, frag) = filename_and_frag_for_def(db, resolved)?; if let Some(path) = mod_path_of_def(db, resolved) { @@ -351,7 +379,7 @@ fn rewrite_url_link(db: &RootDatabase, def: Definition, target: &str) -> Option< return None; } - let mut url = get_doc_base_url(db, def)?; + let mut url = get_doc_base_urls(db, def, None, None).0?; let (def, file, frag) = filename_and_frag_for_def(db, def)?; if let Some(path) = mod_path_of_def(db, def) { @@ -366,7 +394,7 @@ fn rewrite_url_link(db: &RootDatabase, def: Definition, target: &str) -> Option< fn mod_path_of_def(db: &RootDatabase, def: Definition) -> Option { def.canonical_module_path(db).map(|it| { let mut path = String::new(); - it.flat_map(|it| it.name(db)).for_each(|name| format_to!(path, "{}/", name)); + it.flat_map(|it| it.name(db)).for_each(|name| format_to!(path, "{}/", name.display(db))); path }) } @@ -426,18 +454,38 @@ fn map_links<'e>( /// ```ignore /// https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next /// ^^^^^^^^^^^^^^^^^^^^^^^^^^ +/// file:///project/root/target/doc/std/iter/trait.Iterator.html#tymethod.next +/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /// ``` -fn get_doc_base_url(db: &RootDatabase, def: Definition) -> Option { +fn get_doc_base_urls( + db: &RootDatabase, + def: Definition, + target_dir: Option<&OsStr>, + sysroot: Option<&OsStr>, +) -> (Option, Option) { + let local_doc = target_dir + .and_then(|path| path.to_str()) + .and_then(|path| Url::parse(&format!("file:///{path}/")).ok()) + .and_then(|it| it.join("doc/").ok()); + let system_doc = sysroot + .and_then(|it| it.to_str()) + .map(|sysroot| format!("file:///{sysroot}/share/doc/rust/html/")) + .and_then(|it| Url::parse(&it).ok()); + // special case base url of `BuiltinType` to core // https://github.com/rust-lang/rust-analyzer/issues/12250 if let Definition::BuiltinType(..) = def { - return Url::parse("https://doc.rust-lang.org/nightly/core/").ok(); + let web_link = Url::parse("https://doc.rust-lang.org/nightly/core/").ok(); + let system_link = system_doc.and_then(|it| it.join("core/").ok()); + return (web_link, system_link); }; - let krate = def.krate(db)?; - let display_name = krate.display_name(db)?; + let Some(krate) = def.krate(db) else { return Default::default() }; + let Some(display_name) = krate.display_name(db) else { return Default::default() }; + let crate_data = &db.crate_graph()[krate.into()]; + let channel = crate_data.channel.map_or("nightly", ReleaseChannel::as_str); - let base = match db.crate_graph()[krate.into()].origin { + let (web_base, local_base) = match &crate_data.origin { // std and co do not specify `html_root_url` any longer so we gotta handwrite this ourself. // FIXME: Use the toolchains channel instead of nightly CrateOrigin::Lang( @@ -447,10 +495,17 @@ fn get_doc_base_url(db: &RootDatabase, def: Definition) -> Option { | LangCrateOrigin::Std | LangCrateOrigin::Test), ) => { - format!("https://doc.rust-lang.org/nightly/{origin}") + let system_url = system_doc.and_then(|it| it.join(&format!("{origin}")).ok()); + let web_url = format!("https://doc.rust-lang.org/{channel}/{origin}"); + (Some(web_url), system_url) } - _ => { - krate.get_html_root_url(db).or_else(|| { + CrateOrigin::Lang(_) => return (None, None), + CrateOrigin::Rustc { name: _ } => { + (Some(format!("https://doc.rust-lang.org/{channel}/nightly-rustc/")), None) + } + CrateOrigin::Local { repo: _, name: _ } => { + // FIXME: These should not attempt to link to docs.rs! + let weblink = krate.get_html_root_url(db).or_else(|| { let version = krate.version(db); // Fallback to docs.rs. This uses `display_name` and can never be // correct, but that's what fallbacks are about. @@ -462,10 +517,32 @@ fn get_doc_base_url(db: &RootDatabase, def: Definition) -> Option { krate = display_name, version = version.as_deref().unwrap_or("*") )) - })? + }); + (weblink, local_doc) + } + CrateOrigin::Library { repo: _, name } => { + let weblink = krate.get_html_root_url(db).or_else(|| { + let version = krate.version(db); + // Fallback to docs.rs. This uses `display_name` and can never be + // correct, but that's what fallbacks are about. + // + // FIXME: clicking on the link should just open the file in the editor, + // instead of falling back to external urls. + Some(format!( + "https://docs.rs/{krate}/{version}/", + krate = name, + version = version.as_deref().unwrap_or("*") + )) + }); + (weblink, local_doc) } }; - Url::parse(&base).ok()?.join(&format!("{display_name}/")).ok() + let web_base = web_base + .and_then(|it| Url::parse(&it).ok()) + .and_then(|it| it.join(&format!("{display_name}/")).ok()); + let local_base = local_base.and_then(|it| it.join(&format!("{display_name}/")).ok()); + + (web_base, local_base) } /// Get the filename and extension generated for a symbol by rustdoc. @@ -490,9 +567,9 @@ fn filename_and_frag_for_def( let res = match def { Definition::Adt(adt) => match adt { - Adt::Struct(s) => format!("struct.{}.html", s.name(db)), - Adt::Enum(e) => format!("enum.{}.html", e.name(db)), - Adt::Union(u) => format!("union.{}.html", u.name(db)), + Adt::Struct(s) => format!("struct.{}.html", s.name(db).display(db.upcast())), + Adt::Enum(e) => format!("enum.{}.html", e.name(db).display(db.upcast())), + Adt::Union(u) => format!("union.{}.html", u.name(db).display(db.upcast())), }, Definition::Module(m) => match m.name(db) { // `#[doc(keyword = "...")]` is internal used only by rust compiler @@ -500,21 +577,25 @@ fn filename_and_frag_for_def( Some(kw) => { format!("keyword.{}.html", kw.trim_matches('"')) } - None => format!("{name}/index.html"), + None => format!("{}/index.html", name.display(db.upcast())), }, None => String::from("index.html"), }, - Definition::Trait(t) => format!("trait.{}.html", t.name(db)), - Definition::TraitAlias(t) => format!("traitalias.{}.html", t.name(db)), - Definition::TypeAlias(t) => format!("type.{}.html", t.name(db)), - Definition::BuiltinType(t) => format!("primitive.{}.html", t.name()), - Definition::Function(f) => format!("fn.{}.html", f.name(db)), + Definition::Trait(t) => format!("trait.{}.html", t.name(db).display(db.upcast())), + Definition::TraitAlias(t) => format!("traitalias.{}.html", t.name(db).display(db.upcast())), + Definition::TypeAlias(t) => format!("type.{}.html", t.name(db).display(db.upcast())), + Definition::BuiltinType(t) => format!("primitive.{}.html", t.name().display(db.upcast())), + Definition::Function(f) => format!("fn.{}.html", f.name(db).display(db.upcast())), Definition::Variant(ev) => { - format!("enum.{}.html#variant.{}", ev.parent_enum(db).name(db), ev.name(db)) + format!( + "enum.{}.html#variant.{}", + ev.parent_enum(db).name(db).display(db.upcast()), + ev.name(db).display(db.upcast()) + ) } - Definition::Const(c) => format!("const.{}.html", c.name(db)?), - Definition::Static(s) => format!("static.{}.html", s.name(db)), - Definition::Macro(mac) => format!("macro.{}.html", mac.name(db)), + Definition::Const(c) => format!("const.{}.html", c.name(db)?.display(db.upcast())), + Definition::Static(s) => format!("static.{}.html", s.name(db).display(db.upcast())), + Definition::Macro(mac) => format!("macro.{}.html", mac.name(db).display(db.upcast())), Definition::Field(field) => { let def = match field.parent_def(db) { hir::VariantDef::Struct(it) => Definition::Adt(it.into()), @@ -522,7 +603,11 @@ fn filename_and_frag_for_def( hir::VariantDef::Variant(it) => Definition::Variant(it), }; let (_, file, _) = filename_and_frag_for_def(db, def)?; - return Some((def, file, Some(format!("structfield.{}", field.name(db))))); + return Some(( + def, + file, + Some(format!("structfield.{}", field.name(db).display(db.upcast()))), + )); } Definition::SelfType(impl_) => { let adt = impl_.self_ty(db).as_adt()?.into(); @@ -556,12 +641,14 @@ fn get_assoc_item_fragment(db: &dyn HirDatabase, assoc_item: hir::AssocItem) -> // Rustdoc makes this decision based on whether a method 'has defaultness'. // Currently this is only the case for provided trait methods. if is_trait_method && !function.has_body(db) { - format!("tymethod.{}", function.name(db)) + format!("tymethod.{}", function.name(db).display(db.upcast())) } else { - format!("method.{}", function.name(db)) + format!("method.{}", function.name(db).display(db.upcast())) } } - AssocItem::Const(constant) => format!("associatedconstant.{}", constant.name(db)?), - AssocItem::TypeAlias(ty) => format!("associatedtype.{}", ty.name(db)), + AssocItem::Const(constant) => { + format!("associatedconstant.{}", constant.name(db)?.display(db.upcast())) + } + AssocItem::TypeAlias(ty) => format!("associatedtype.{}", ty.name(db).display(db.upcast())), }) } diff --git a/crates/ide/src/doc_links/tests.rs b/crates/ide/src/doc_links/tests.rs index 104181a33e68d..05a64b33bfdc9 100644 --- a/crates/ide/src/doc_links/tests.rs +++ b/crates/ide/src/doc_links/tests.rs @@ -1,3 +1,5 @@ +use std::ffi::OsStr; + use expect_test::{expect, Expect}; use hir::{HasAttrs, Semantics}; use ide_db::{ @@ -13,11 +15,33 @@ use crate::{ fixture, TryToNav, }; -fn check_external_docs(ra_fixture: &str, expect: Expect) { +fn check_external_docs( + ra_fixture: &str, + target_dir: Option<&OsStr>, + expect_web_url: Option, + expect_local_url: Option, + sysroot: Option<&OsStr>, +) { let (analysis, position) = fixture::position(ra_fixture); - let url = analysis.external_docs(position).unwrap().expect("could not find url for symbol"); + let links = analysis.external_docs(position, target_dir, sysroot).unwrap(); + + let web_url = links.web_url; + let local_url = links.local_url; + + println!("web_url: {:?}", web_url); + println!("local_url: {:?}", local_url); + + match (expect_web_url, web_url) { + (Some(expect), Some(url)) => expect.assert_eq(&url), + (None, None) => (), + _ => panic!("Unexpected web url"), + } - expect.assert_eq(&url) + match (expect_local_url, local_url) { + (Some(expect), Some(url)) => expect.assert_eq(&url), + (None, None) => (), + _ => panic!("Unexpected local url"), + } } fn check_rewrite(ra_fixture: &str, expect: Expect) { @@ -96,6 +120,20 @@ fn node_to_def( }) } +#[test] +fn external_docs_doc_builtin_type() { + check_external_docs( + r#" +//- /main.rs crate:foo +let x: u3$02 = 0; +"#, + Some(&OsStr::new("/home/user/project")), + Some(expect![[r#"https://doc.rust-lang.org/nightly/core/primitive.u32.html"#]]), + Some(expect![[r#"file:///sysroot/share/doc/rust/html/core/primitive.u32.html"#]]), + Some(&OsStr::new("/sysroot")), + ); +} + #[test] fn external_docs_doc_url_crate() { check_external_docs( @@ -105,7 +143,10 @@ use foo$0::Foo; //- /lib.rs crate:foo pub struct Foo; "#, - expect![[r#"https://docs.rs/foo/*/foo/index.html"#]], + Some(&OsStr::new("/home/user/project")), + Some(expect![[r#"https://docs.rs/foo/*/foo/index.html"#]]), + Some(expect![[r#"file:///home/user/project/doc/foo/index.html"#]]), + Some(&OsStr::new("/sysroot")), ); } @@ -116,7 +157,10 @@ fn external_docs_doc_url_std_crate() { //- /main.rs crate:std use self$0; "#, - expect![[r#"https://doc.rust-lang.org/nightly/std/index.html"#]], + Some(&OsStr::new("/home/user/project")), + Some(expect!["https://doc.rust-lang.org/stable/std/index.html"]), + Some(expect!["file:///sysroot/share/doc/rust/html/std/index.html"]), + Some(&OsStr::new("/sysroot")), ); } @@ -127,7 +171,38 @@ fn external_docs_doc_url_struct() { //- /main.rs crate:foo pub struct Fo$0o; "#, - expect![[r#"https://docs.rs/foo/*/foo/struct.Foo.html"#]], + Some(&OsStr::new("/home/user/project")), + Some(expect![[r#"https://docs.rs/foo/*/foo/struct.Foo.html"#]]), + Some(expect![[r#"file:///home/user/project/doc/foo/struct.Foo.html"#]]), + Some(&OsStr::new("/sysroot")), + ); +} + +#[test] +fn external_docs_doc_url_windows_backslash_path() { + check_external_docs( + r#" +//- /main.rs crate:foo +pub struct Fo$0o; +"#, + Some(&OsStr::new(r"C:\Users\user\project")), + Some(expect![[r#"https://docs.rs/foo/*/foo/struct.Foo.html"#]]), + Some(expect![[r#"file:///C:/Users/user/project/doc/foo/struct.Foo.html"#]]), + Some(&OsStr::new("/sysroot")), + ); +} + +#[test] +fn external_docs_doc_url_windows_slash_path() { + check_external_docs( + r#" +//- /main.rs crate:foo +pub struct Fo$0o; +"#, + Some(&OsStr::new(r"C:/Users/user/project")), + Some(expect![[r#"https://docs.rs/foo/*/foo/struct.Foo.html"#]]), + Some(expect![[r#"file:///C:/Users/user/project/doc/foo/struct.Foo.html"#]]), + Some(&OsStr::new("/sysroot")), ); } @@ -140,7 +215,10 @@ pub struct Foo { field$0: () } "#, - expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#structfield.field"##]], + None, + Some(expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#structfield.field"##]]), + None, + None, ); } @@ -151,7 +229,10 @@ fn external_docs_doc_url_fn() { //- /main.rs crate:foo pub fn fo$0o() {} "#, - expect![[r#"https://docs.rs/foo/*/foo/fn.foo.html"#]], + None, + Some(expect![[r#"https://docs.rs/foo/*/foo/fn.foo.html"#]]), + None, + None, ); } @@ -165,7 +246,10 @@ impl Foo { pub fn method$0() {} } "#, - expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#method.method"##]], + None, + Some(expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#method.method"##]]), + None, + None, ); check_external_docs( r#" @@ -175,7 +259,10 @@ impl Foo { const CONST$0: () = (); } "#, - expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#associatedconstant.CONST"##]], + None, + Some(expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#associatedconstant.CONST"##]]), + None, + None, ); } @@ -192,7 +279,10 @@ impl Trait for Foo { pub fn method$0() {} } "#, - expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#method.method"##]], + None, + Some(expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#method.method"##]]), + None, + None, ); check_external_docs( r#" @@ -205,7 +295,10 @@ impl Trait for Foo { const CONST$0: () = (); } "#, - expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#associatedconstant.CONST"##]], + None, + Some(expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#associatedconstant.CONST"##]]), + None, + None, ); check_external_docs( r#" @@ -218,7 +311,10 @@ impl Trait for Foo { type Type$0 = (); } "#, - expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#associatedtype.Type"##]], + None, + Some(expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#associatedtype.Type"##]]), + None, + None, ); } @@ -231,7 +327,10 @@ pub trait Foo { fn method$0(); } "#, - expect![[r##"https://docs.rs/foo/*/foo/trait.Foo.html#tymethod.method"##]], + None, + Some(expect![[r##"https://docs.rs/foo/*/foo/trait.Foo.html#tymethod.method"##]]), + None, + None, ); check_external_docs( r#" @@ -240,7 +339,10 @@ pub trait Foo { const CONST$0: (); } "#, - expect![[r##"https://docs.rs/foo/*/foo/trait.Foo.html#associatedconstant.CONST"##]], + None, + Some(expect![[r##"https://docs.rs/foo/*/foo/trait.Foo.html#associatedconstant.CONST"##]]), + None, + None, ); check_external_docs( r#" @@ -249,7 +351,10 @@ pub trait Foo { type Type$0; } "#, - expect![[r##"https://docs.rs/foo/*/foo/trait.Foo.html#associatedtype.Type"##]], + None, + Some(expect![[r##"https://docs.rs/foo/*/foo/trait.Foo.html#associatedtype.Type"##]]), + None, + None, ); } @@ -260,7 +365,10 @@ fn external_docs_trait() { //- /main.rs crate:foo trait Trait$0 {} "#, - expect![[r#"https://docs.rs/foo/*/foo/trait.Trait.html"#]], + None, + Some(expect![[r#"https://docs.rs/foo/*/foo/trait.Trait.html"#]]), + None, + None, ) } @@ -273,7 +381,10 @@ pub mod foo { pub mod ba$0r {} } "#, - expect![[r#"https://docs.rs/foo/*/foo/foo/bar/index.html"#]], + None, + Some(expect![[r#"https://docs.rs/foo/*/foo/foo/bar/index.html"#]]), + None, + None, ) } @@ -294,7 +405,10 @@ fn foo() { let bar: wrapper::It$0em; } "#, - expect![[r#"https://docs.rs/foo/*/foo/wrapper/module/struct.Item.html"#]], + None, + Some(expect![[r#"https://docs.rs/foo/*/foo/wrapper/module/struct.Item.html"#]]), + None, + None, ) } diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs index 418043d679811..d6bbf2bf794dc 100644 --- a/crates/ide/src/expand_macro.rs +++ b/crates/ide/src/expand_macro.rs @@ -76,15 +76,17 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< if let Some(item) = ast::Item::cast(node.clone()) { if let Some(def) = sema.resolve_attr_macro_call(&item) { break ( - def.name(db).to_string(), + def.name(db).display(db).to_string(), expand_attr_macro_recur(&sema, &item)?, SyntaxKind::MACRO_ITEMS, ); } } if let Some(mac) = ast::MacroCall::cast(node) { + let mut name = mac.path()?.segment()?.name_ref()?.to_string(); + name.push('!'); break ( - mac.path()?.segment()?.name_ref()?.to_string(), + name, expand_macro_recur(&sema, &mac)?, mac.syntax().parent().map(|it| it.kind()).unwrap_or(SyntaxKind::MACRO_ITEMS), ); @@ -149,9 +151,11 @@ fn _format( _db: &RootDatabase, _kind: SyntaxKind, _file_id: FileId, - _expansion: &str, + expansion: &str, ) -> Option { - None + // remove trailing spaces for test + use itertools::Itertools; + Some(expansion.lines().map(|x| x.trim_end()).join("\n")) } #[cfg(not(any(test, target_arch = "wasm32", target_os = "emscripten")))] @@ -235,7 +239,7 @@ fn main() { } "#, expect![[r#" - bar + bar! 5i64 as _"#]], ); } @@ -252,7 +256,7 @@ fn main() { } "#, expect![[r#" - bar + bar! for _ in 0..42{}"#]], ); } @@ -273,9 +277,8 @@ macro_rules! baz { f$0oo!(); "#, expect![[r#" - foo - fn b(){} - "#]], + foo! + fn b(){}"#]], ); } @@ -294,7 +297,7 @@ macro_rules! foo { f$0oo!(); "#, expect![[r#" - foo + foo! fn some_thing() -> u32 { let a = 0; a+10 @@ -328,16 +331,16 @@ fn main() { } "#, expect![[r#" - match_ast - { - if let Some(it) = ast::TraitDef::cast(container.clone()){} - else if let Some(it) = ast::ImplDef::cast(container.clone()){} - else { - { - continue - } - } - }"#]], + match_ast! + { + if let Some(it) = ast::TraitDef::cast(container.clone()){} + else if let Some(it) = ast::ImplDef::cast(container.clone()){} + else { + { + continue + } + } + }"#]], ); } @@ -358,7 +361,7 @@ fn main() { } "#, expect![[r#" - match_ast + match_ast! {}"#]], ); } @@ -383,7 +386,7 @@ fn main() { } "#, expect![[r#" - foo + foo! { macro_rules! bar { () => { @@ -411,7 +414,7 @@ fn main() { } "#, expect![[r#" - foo + foo! "#]], ); } @@ -433,7 +436,7 @@ fn main() { } "#, expect![[r#" - foo + foo! 0"#]], ); } @@ -451,7 +454,7 @@ fn main() { } "#, expect![[r#" - foo + foo! fn f(_: &dyn ::std::marker::Copy){}"#]], ); } @@ -469,8 +472,17 @@ struct Foo {} "#, expect![[r#" Clone - impl < >core::clone::Clone for Foo< >{} - "#]], + impl < >core::clone::Clone for Foo< >where { + fn clone(&self) -> Self { + match self { + Foo{} + => Foo{} + , + + } + } + + }"#]], ); } @@ -486,8 +498,7 @@ struct Foo {} "#, expect![[r#" Copy - impl < >core::marker::Copy for Foo< >{} - "#]], + impl < >core::marker::Copy for Foo< >where{}"#]], ); } @@ -502,8 +513,7 @@ struct Foo {} "#, expect![[r#" Copy - impl < >core::marker::Copy for Foo< >{} - "#]], + impl < >core::marker::Copy for Foo< >where{}"#]], ); check( r#" @@ -514,8 +524,17 @@ struct Foo {} "#, expect![[r#" Clone - impl < >core::clone::Clone for Foo< >{} - "#]], + impl < >core::clone::Clone for Foo< >where { + fn clone(&self) -> Self { + match self { + Foo{} + => Foo{} + , + + } + } + + }"#]], ); } } diff --git a/crates/ide/src/extend_selection.rs b/crates/ide/src/extend_selection.rs index 9f78c75e90aa2..f906182224468 100644 --- a/crates/ide/src/extend_selection.rs +++ b/crates/ide/src/extend_selection.rs @@ -39,7 +39,7 @@ fn try_extend_selection( ) -> Option { let range = frange.range; - let string_kinds = [COMMENT, STRING, BYTE_STRING]; + let string_kinds = [COMMENT, STRING, BYTE_STRING, C_STRING]; let list_kinds = [ RECORD_PAT_FIELD_LIST, MATCH_ARM_LIST, diff --git a/crates/ide/src/fetch_crates.rs b/crates/ide/src/fetch_crates.rs new file mode 100644 index 0000000000000..46ee671defbc0 --- /dev/null +++ b/crates/ide/src/fetch_crates.rs @@ -0,0 +1,42 @@ +use ide_db::{ + base_db::{CrateOrigin, FileId, SourceDatabase}, + FxIndexSet, RootDatabase, +}; + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct CrateInfo { + pub name: Option, + pub version: Option, + pub root_file_id: FileId, +} + +// Feature: Show Dependency Tree +// +// Shows a view tree with all the dependencies of this project +// +// |=== +// | Editor | Panel Name +// +// | VS Code | **Rust Dependencies** +// |=== +// +// image::https://user-images.githubusercontent.com/5748995/229394139-2625beab-f4c9-484b-84ed-ad5dee0b1e1a.png[] +pub(crate) fn fetch_crates(db: &RootDatabase) -> FxIndexSet { + let crate_graph = db.crate_graph(); + crate_graph + .iter() + .map(|crate_id| &crate_graph[crate_id]) + .filter(|&data| !matches!(data.origin, CrateOrigin::Local { .. })) + .map(|data| crate_info(data)) + .collect() +} + +fn crate_info(data: &ide_db::base_db::CrateData) -> CrateInfo { + let crate_name = crate_name(data); + let version = data.version.clone(); + CrateInfo { name: crate_name, version, root_file_id: data.root_file_id } +} + +fn crate_name(data: &ide_db::base_db::CrateData) -> Option { + data.display_name.as_ref().map(|it| it.canonical_name().to_owned()) +} diff --git a/crates/ide/src/file_structure.rs b/crates/ide/src/file_structure.rs index a32ac35496aa4..b278924721c0f 100644 --- a/crates/ide/src/file_structure.rs +++ b/crates/ide/src/file_structure.rs @@ -219,7 +219,7 @@ mod tests { } #[test] - fn test_nagative_trait_bound() { + fn test_negative_trait_bound() { let txt = r#"impl !Unpin for Test {}"#; check( txt, diff --git a/crates/ide/src/fixture.rs b/crates/ide/src/fixture.rs index 2ea6f6a9ab1b6..2e5903c0602e3 100644 --- a/crates/ide/src/fixture.rs +++ b/crates/ide/src/fixture.rs @@ -1,5 +1,4 @@ //! Utilities for creating `Analysis` instances for tests. -use hir::db::DefDatabase; use ide_db::base_db::fixture::ChangeFixture; use test_utils::{extract_annotations, RangeOrOffset}; @@ -9,7 +8,7 @@ use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange}; pub(crate) fn file(ra_fixture: &str) -> (Analysis, FileId) { let mut host = AnalysisHost::default(); let change_fixture = ChangeFixture::parse(ra_fixture); - host.db.set_enable_proc_attr_macros(true); + host.db.enable_proc_attr_macros(); host.db.apply_change(change_fixture.change); (host.analysis(), change_fixture.files[0]) } @@ -18,7 +17,7 @@ pub(crate) fn file(ra_fixture: &str) -> (Analysis, FileId) { pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) { let mut host = AnalysisHost::default(); let change_fixture = ChangeFixture::parse(ra_fixture); - host.db.set_enable_proc_attr_macros(true); + host.db.enable_proc_attr_macros(); host.db.apply_change(change_fixture.change); let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); let offset = range_or_offset.expect_offset(); @@ -29,7 +28,7 @@ pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) { pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) { let mut host = AnalysisHost::default(); let change_fixture = ChangeFixture::parse(ra_fixture); - host.db.set_enable_proc_attr_macros(true); + host.db.enable_proc_attr_macros(); host.db.apply_change(change_fixture.change); let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); let range = range_or_offset.expect_range(); @@ -40,7 +39,7 @@ pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) { pub(crate) fn range_or_position(ra_fixture: &str) -> (Analysis, FileId, RangeOrOffset) { let mut host = AnalysisHost::default(); let change_fixture = ChangeFixture::parse(ra_fixture); - host.db.set_enable_proc_attr_macros(true); + host.db.enable_proc_attr_macros(); host.db.apply_change(change_fixture.change); let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); (host.analysis(), file_id, range_or_offset) @@ -50,7 +49,7 @@ pub(crate) fn range_or_position(ra_fixture: &str) -> (Analysis, FileId, RangeOrO pub(crate) fn annotations(ra_fixture: &str) -> (Analysis, FilePosition, Vec<(FileRange, String)>) { let mut host = AnalysisHost::default(); let change_fixture = ChangeFixture::parse(ra_fixture); - host.db.set_enable_proc_attr_macros(true); + host.db.enable_proc_attr_macros(); host.db.apply_change(change_fixture.change); let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); let offset = range_or_offset.expect_offset(); @@ -67,11 +66,11 @@ pub(crate) fn annotations(ra_fixture: &str) -> (Analysis, FilePosition, Vec<(Fil (host.analysis(), FilePosition { file_id, offset }, annotations) } -/// Creates analysis from a multi-file fixture with annonations without $0 +/// Creates analysis from a multi-file fixture with annotations without $0 pub(crate) fn annotations_without_marker(ra_fixture: &str) -> (Analysis, Vec<(FileRange, String)>) { let mut host = AnalysisHost::default(); let change_fixture = ChangeFixture::parse(ra_fixture); - host.db.set_enable_proc_attr_macros(true); + host.db.enable_proc_attr_macros(); host.db.apply_change(change_fixture.change); let annotations = change_fixture diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index cf0819a2524b9..4e641357e3728 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -113,6 +113,7 @@ fn try_lookup_include_path( file_id, full_range: TextRange::new(0.into(), size), name: path.into(), + alias: None, focus_range: None, kind: None, container_name: None, @@ -833,8 +834,7 @@ fn test() { #[rustc_builtin_macro] macro_rules! include {} - include!("foo.rs"); -//^^^^^^^^^^^^^^^^^^^ +include!("foo.rs"); fn f() { foo$0(); @@ -846,6 +846,33 @@ mod confuse_index { //- /foo.rs fn foo() {} + //^^^ + "#, + ); + } + + #[test] + fn goto_through_included_file_struct_with_doc_comment() { + check( + r#" +//- /main.rs +#[rustc_builtin_macro] +macro_rules! include {} + +include!("foo.rs"); + +fn f() { + let x = Foo$0; +} + +mod confuse_index { + pub struct Foo; +} + +//- /foo.rs +/// This is a doc comment +pub struct Foo; + //^^^ "#, ); } @@ -1466,6 +1493,29 @@ impl Twait for Stwuct { fn f() { let s = Stwuct; s.a$0(); +} + "#, + ); + } + #[test] + fn method_call_inside_block() { + check( + r#" +trait Twait { + fn a(&self); +} + +fn outer() { + struct Stwuct; + + impl Twait for Stwuct { + fn a(&self){} + //^ + } + fn f() { + let s = Stwuct; + s.a$0(); + } } "#, ); diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs index 6d2d0bd635165..6048990f7492c 100644 --- a/crates/ide/src/goto_type_definition.rs +++ b/crates/ide/src/goto_type_definition.rs @@ -10,7 +10,7 @@ use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav}; // |=== // | Editor | Action Name // -// | VS Code | **Go to Type Definition* +// | VS Code | **Go to Type Definition** // |=== // // image::https://user-images.githubusercontent.com/48062697/113020657-b560f500-917a-11eb-9007-0f809733a338.gif[] @@ -38,32 +38,41 @@ pub(crate) fn goto_type_definition( }; let range = token.text_range(); sema.descend_into_macros(token) - .iter() + .into_iter() .filter_map(|token| { - let ty = sema.token_ancestors_with_macros(token.clone()).find_map(|node| { - let ty = match_ast! { - match node { - ast::Expr(it) => sema.type_of_expr(&it)?.original, - ast::Pat(it) => sema.type_of_pat(&it)?.original, - ast::SelfParam(it) => sema.type_of_self(&it)?, - ast::Type(it) => sema.resolve_type(&it)?, - ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?, - // can't match on RecordExprField directly as `ast::Expr` will match an iteration too early otherwise - ast::NameRef(it) => { - if let Some(record_field) = ast::RecordExprField::for_name_ref(&it) { - let (_, _, ty) = sema.resolve_record_field(&record_field)?; - ty - } else { - let record_field = ast::RecordPatField::for_field_name_ref(&it)?; - sema.resolve_record_pat_field(&record_field)?.1 - } - }, - _ => return None, - } - }; + let ty = sema + .token_ancestors_with_macros(token) + // When `token` is within a macro call, we can't determine its type. Don't continue + // this traversal because otherwise we'll end up returning the type of *that* macro + // call, which is not what we want in general. + // + // Macro calls always wrap `TokenTree`s, so it's sufficient and efficient to test + // if the current node is a `TokenTree`. + .take_while(|node| !ast::TokenTree::can_cast(node.kind())) + .find_map(|node| { + let ty = match_ast! { + match node { + ast::Expr(it) => sema.type_of_expr(&it)?.original, + ast::Pat(it) => sema.type_of_pat(&it)?.original, + ast::SelfParam(it) => sema.type_of_self(&it)?, + ast::Type(it) => sema.resolve_type(&it)?, + ast::RecordField(it) => sema.to_def(&it)?.ty(db.upcast()), + // can't match on RecordExprField directly as `ast::Expr` will match an iteration too early otherwise + ast::NameRef(it) => { + if let Some(record_field) = ast::RecordExprField::for_name_ref(&it) { + let (_, _, ty) = sema.resolve_record_field(&record_field)?; + ty + } else { + let record_field = ast::RecordPatField::for_field_name_ref(&it)?; + sema.resolve_record_pat_field(&record_field)?.1 + } + }, + _ => return None, + } + }; - Some(ty) - }); + Some(ty) + }); ty }) .for_each(|ty| { @@ -94,7 +103,7 @@ mod tests { fn check(ra_fixture: &str) { let (analysis, position, expected) = fixture::annotations(ra_fixture); let navs = analysis.goto_type_definition(position).unwrap().unwrap().info; - assert_ne!(navs.len(), 0); + assert!(!navs.is_empty(), "navigation is empty"); let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start()); let navs = navs @@ -104,7 +113,7 @@ mod tests { .collect::>(); let expected = expected .into_iter() - .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range }) + .map(|(file_range, _)| file_range) .sorted_by_key(cmp) .collect::>(); assert_eq!(expected, navs); @@ -198,6 +207,32 @@ id! { ); } + #[test] + fn dont_collect_type_from_token_in_macro_call() { + check( + r#" +struct DontCollectMe; +struct S; + //^ + +macro_rules! inner { + ($t:tt) => { DontCollectMe } +} +macro_rules! m { + ($t:ident) => { + match $t { + _ => inner!($t); + } + } +} + +fn test() { + m!($0S); +} +"#, + ); + } + #[test] fn goto_type_definition_for_param() { check( diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs index d88ffd25c40fe..7e545491f8e7e 100644 --- a/crates/ide/src/highlight_related.rs +++ b/crates/ide/src/highlight_related.rs @@ -1,10 +1,12 @@ use hir::Semantics; use ide_db::{ - base_db::{FileId, FilePosition}, + base_db::{FileId, FilePosition, FileRange}, defs::{Definition, IdentClass}, helpers::pick_best_token, search::{FileReference, ReferenceCategory, SearchScope}, - syntax_helpers::node_ext::{for_each_break_and_continue_expr, for_each_tail_expr, walk_expr}, + syntax_helpers::node_ext::{ + for_each_break_and_continue_expr, for_each_tail_expr, full_path_of_name_ref, walk_expr, + }, FxHashSet, RootDatabase, }; use syntax::{ @@ -30,6 +32,7 @@ pub struct HighlightRelatedConfig { pub references: bool, pub exit_points: bool, pub break_points: bool, + pub closure_captures: bool, pub yield_points: bool, } @@ -38,11 +41,13 @@ pub struct HighlightRelatedConfig { // Highlights constructs related to the thing under the cursor: // // . if on an identifier, highlights all references to that identifier in the current file +// .. additionally, if the identifier is a trait in a where clause, type parameter trait bound or use item, highlights all references to that trait's assoc items in the corresponding scope // . if on an `async` or `await token, highlights all yield points for that async context // . if on a `return` or `fn` keyword, `?` character or `->` return type arrow, highlights all exit points for that context // . if on a `break`, `loop`, `while` or `for` token, highlights all break points for that loop or block context +// . if on a `move` or `|` token that belongs to a closure, highlights all captures of the closure. // -// Note: `?` and `->` do not currently trigger this behavior in the VSCode editor. +// Note: `?`, `|` and `->` do not currently trigger this behavior in the VSCode editor. pub(crate) fn highlight_related( sema: &Semantics<'_, RootDatabase>, config: HighlightRelatedConfig, @@ -53,11 +58,13 @@ pub(crate) fn highlight_related( let token = pick_best_token(syntax.token_at_offset(offset), |kind| match kind { T![?] => 4, // prefer `?` when the cursor is sandwiched like in `await$0?` - T![->] => 3, - kind if kind.is_keyword() => 2, - IDENT | INT_NUMBER => 1, + T![->] => 4, + kind if kind.is_keyword() => 3, + IDENT | INT_NUMBER => 2, + T![|] => 1, _ => 0, })?; + // most if not all of these should be re-implemented with information seeded from hir match token.kind() { T![?] if config.exit_points && token.parent().and_then(ast::TryExpr::cast).is_some() => { highlight_exit_points(sema, token) @@ -70,18 +77,64 @@ pub(crate) fn highlight_related( T![break] | T![loop] | T![while] | T![continue] if config.break_points => { highlight_break_points(token) } + T![|] if config.closure_captures => highlight_closure_captures(sema, token, file_id), + T![move] if config.closure_captures => highlight_closure_captures(sema, token, file_id), _ if config.references => highlight_references(sema, &syntax, token, file_id), _ => None, } } +fn highlight_closure_captures( + sema: &Semantics<'_, RootDatabase>, + token: SyntaxToken, + file_id: FileId, +) -> Option> { + let closure = token.parent_ancestors().take(2).find_map(ast::ClosureExpr::cast)?; + let search_range = closure.body()?.syntax().text_range(); + let ty = &sema.type_of_expr(&closure.into())?.original; + let c = ty.as_closure()?; + Some( + c.captured_items(sema.db) + .into_iter() + .map(|capture| capture.local()) + .flat_map(|local| { + let usages = Definition::Local(local) + .usages(sema) + .set_scope(Some(SearchScope::file_range(FileRange { + file_id, + range: search_range, + }))) + .include_self_refs() + .all() + .references + .remove(&file_id) + .into_iter() + .flatten() + .map(|FileReference { category, range, .. }| HighlightedRange { + range, + category, + }); + let category = local.is_mut(sema.db).then_some(ReferenceCategory::Write); + local + .sources(sema.db) + .into_iter() + .map(|x| x.to_nav(sema.db)) + .filter(|decl| decl.file_id == file_id) + .filter_map(|decl| decl.focus_range) + .map(move |range| HighlightedRange { range, category }) + .chain(usages) + }) + .collect(), + ) +} + fn highlight_references( sema: &Semantics<'_, RootDatabase>, node: &SyntaxNode, token: SyntaxToken, file_id: FileId, ) -> Option> { - let defs = find_defs(sema, token); + let defs = find_defs(sema, token.clone()); let usages = defs .iter() .filter_map(|&d| { @@ -93,12 +146,62 @@ fn highlight_references( .remove(&file_id) }) .flatten() - .map(|FileReference { category: access, range, .. }| HighlightedRange { - range, - category: access, - }); + .map(|FileReference { category, range, .. }| HighlightedRange { range, category }); let mut res = FxHashSet::default(); for &def in &defs { + // highlight trait usages + if let Definition::Trait(t) = def { + let trait_item_use_scope = (|| { + let name_ref = token.parent().and_then(ast::NameRef::cast)?; + let path = full_path_of_name_ref(&name_ref)?; + let parent = path.syntax().parent()?; + match_ast! { + match parent { + ast::UseTree(it) => it.syntax().ancestors().find(|it| { + ast::SourceFile::can_cast(it.kind()) || ast::Module::can_cast(it.kind()) + }), + ast::PathType(it) => it + .syntax() + .ancestors() + .nth(2) + .and_then(ast::TypeBoundList::cast)? + .syntax() + .parent() + .filter(|it| ast::WhereClause::can_cast(it.kind()) || ast::TypeParam::can_cast(it.kind()))? + .ancestors() + .find(|it| { + ast::Item::can_cast(it.kind()) + }), + _ => None, + } + } + })(); + if let Some(trait_item_use_scope) = trait_item_use_scope { + res.extend( + t.items_with_supertraits(sema.db) + .into_iter() + .filter_map(|item| { + Definition::from(item) + .usages(sema) + .set_scope(Some(SearchScope::file_range(FileRange { + file_id, + range: trait_item_use_scope.text_range(), + }))) + .include_self_refs() + .all() + .references + .remove(&file_id) + }) + .flatten() + .map(|FileReference { category, range, .. }| HighlightedRange { + range, + category, + }), + ); + } + } + + // highlight the defs themselves match def { Definition::Local(local) => { let category = local.is_mut(sema.db).then_some(ReferenceCategory::Write); @@ -148,9 +251,16 @@ fn highlight_exit_points( ) -> Option> { fn hl( sema: &Semantics<'_, RootDatabase>, + def_ranges: [Option; 2], body: Option, ) -> Option> { let mut highlights = Vec::new(); + highlights.extend( + def_ranges + .into_iter() + .flatten() + .map(|range| HighlightedRange { category: None, range }), + ); let body = body?; walk_expr(&body, &mut |expr| match expr { ast::Expr::ReturnExpr(expr) => { @@ -194,10 +304,21 @@ fn highlight_exit_points( for anc in token.parent_ancestors() { return match_ast! { match anc { - ast::Fn(fn_) => hl(sema, fn_.body().map(ast::Expr::BlockExpr)), - ast::ClosureExpr(closure) => hl(sema, closure.body()), + ast::Fn(fn_) => hl(sema, [fn_.fn_token().map(|it| it.text_range()), None], fn_.body().map(ast::Expr::BlockExpr)), + ast::ClosureExpr(closure) => hl( + sema, + closure.param_list().map_or([None; 2], |p| [p.l_paren_token().map(|it| it.text_range()), p.r_paren_token().map(|it| it.text_range())]), + closure.body() + ), ast::BlockExpr(block_expr) => if matches!(block_expr.modifier(), Some(ast::BlockModifier::Async(_) | ast::BlockModifier::Try(_)| ast::BlockModifier::Const(_))) { - hl(sema, Some(block_expr.into())) + hl( + sema, + [block_expr.modifier().and_then(|modifier| match modifier { + ast::BlockModifier::Async(t) | ast::BlockModifier::Try(t) | ast::BlockModifier::Const(t) => Some(t.text_range()), + _ => None, + }), None], + Some(block_expr.into()) + ) } else { continue; }, @@ -352,16 +473,17 @@ mod tests { use super::*; + const ENABLED_CONFIG: HighlightRelatedConfig = HighlightRelatedConfig { + break_points: true, + exit_points: true, + references: true, + closure_captures: true, + yield_points: true, + }; + #[track_caller] fn check(ra_fixture: &str) { - let config = HighlightRelatedConfig { - break_points: true, - exit_points: true, - references: true, - yield_points: true, - }; - - check_with_config(ra_fixture, config); + check_with_config(ra_fixture, ENABLED_CONFIG); } #[track_caller] @@ -570,6 +692,29 @@ pub async$0 fn foo() { ); } + #[test] + fn test_hl_let_else_yield_points() { + check( + r#" +pub async fn foo() { + // ^^^^^ + let x = foo() + .await$0 + // ^^^^^ + .await; + // ^^^^^ + || { 0.await }; + let Some(_) = None else { + foo().await + // ^^^^^ + }; + (async { 0.await }).await + // ^^^^^ +} +"#, + ); + } + #[test] fn test_hl_yield_nested_fn() { check( @@ -610,7 +755,8 @@ async fn foo() { fn test_hl_exit_points() { check( r#" -fn foo() -> u32 { + fn foo() -> u32 { +//^^ if true { return$0 0; // ^^^^^^ @@ -629,7 +775,8 @@ fn foo() -> u32 { fn test_hl_exit_points2() { check( r#" -fn foo() ->$0 u32 { + fn foo() ->$0 u32 { +//^^ if true { return 0; // ^^^^^^ @@ -648,7 +795,8 @@ fn foo() ->$0 u32 { fn test_hl_exit_points3() { check( r#" -fn$0 foo() -> u32 { + fn$0 foo() -> u32 { +//^^ if true { return 0; // ^^^^^^ @@ -663,6 +811,26 @@ fn$0 foo() -> u32 { ); } + #[test] + fn test_hl_let_else_exit_points() { + check( + r#" + fn$0 foo() -> u32 { +//^^ + let Some(bar) = None else { + return 0; + // ^^^^^^ + }; + + 0?; + // ^ + 0xDEAD_BEEF + // ^^^^^^^^^^^ +} +"#, + ); + } + #[test] fn test_hl_prefer_ref_over_tail_exit() { check( @@ -694,7 +862,8 @@ macro_rules! never { () => { never() } } fn never() -> ! { loop {} } -fn foo() ->$0 u32 { + fn foo() ->$0 u32 { +//^^ never(); // ^^^^^^^ never!(); @@ -714,7 +883,8 @@ fn foo() ->$0 u32 { fn test_hl_inner_tail_exit_points() { check( r#" -fn foo() ->$0 u32 { + fn foo() ->$0 u32 { +//^^ if true { unsafe { return 5; @@ -755,7 +925,8 @@ fn foo() ->$0 u32 { fn test_hl_inner_tail_exit_points_labeled_block() { check( r#" -fn foo() ->$0 u32 { + fn foo() ->$0 u32 { +//^^ 'foo: { break 'foo 0; // ^^^^^ @@ -776,7 +947,8 @@ fn foo() ->$0 u32 { fn test_hl_inner_tail_exit_points_loops() { check( r#" -fn foo() ->$0 u32 { + fn foo() ->$0 u32 { +//^^ 'foo: while { return 0; true } { // ^^^^^^ break 'foo 0; @@ -1086,12 +1258,7 @@ fn function(field: u32) { #[test] fn test_hl_disabled_ref_local() { - let config = HighlightRelatedConfig { - references: false, - break_points: true, - exit_points: true, - yield_points: true, - }; + let config = HighlightRelatedConfig { references: false, ..ENABLED_CONFIG }; check_with_config( r#" @@ -1106,12 +1273,7 @@ fn foo() { #[test] fn test_hl_disabled_ref_local_preserved_break() { - let config = HighlightRelatedConfig { - references: false, - break_points: true, - exit_points: true, - yield_points: true, - }; + let config = HighlightRelatedConfig { references: false, ..ENABLED_CONFIG }; check_with_config( r#" @@ -1146,12 +1308,7 @@ fn foo() { #[test] fn test_hl_disabled_ref_local_preserved_yield() { - let config = HighlightRelatedConfig { - references: false, - break_points: true, - exit_points: true, - yield_points: true, - }; + let config = HighlightRelatedConfig { references: false, ..ENABLED_CONFIG }; check_with_config( r#" @@ -1182,12 +1339,7 @@ async fn foo() { #[test] fn test_hl_disabled_ref_local_preserved_exit() { - let config = HighlightRelatedConfig { - references: false, - break_points: true, - exit_points: true, - yield_points: true, - }; + let config = HighlightRelatedConfig { references: false, ..ENABLED_CONFIG }; check_with_config( r#" @@ -1207,7 +1359,8 @@ fn foo() -> i32 { check_with_config( r#" -fn foo() ->$0 i32 { + fn foo() ->$0 i32 { +//^^ let x = 5; let y = x * 2; @@ -1225,12 +1378,7 @@ fn foo() ->$0 i32 { #[test] fn test_hl_disabled_break() { - let config = HighlightRelatedConfig { - references: true, - break_points: false, - exit_points: true, - yield_points: true, - }; + let config = HighlightRelatedConfig { break_points: false, ..ENABLED_CONFIG }; check_with_config( r#" @@ -1246,12 +1394,7 @@ fn foo() { #[test] fn test_hl_disabled_yield() { - let config = HighlightRelatedConfig { - references: true, - break_points: true, - exit_points: true, - yield_points: false, - }; + let config = HighlightRelatedConfig { yield_points: false, ..ENABLED_CONFIG }; check_with_config( r#" @@ -1265,12 +1408,7 @@ async$0 fn foo() { #[test] fn test_hl_disabled_exit() { - let config = HighlightRelatedConfig { - references: true, - break_points: true, - exit_points: false, - yield_points: true, - }; + let config = HighlightRelatedConfig { exit_points: false, ..ENABLED_CONFIG }; check_with_config( r#" @@ -1411,6 +1549,75 @@ impl Trait for () { type Output$0 = (); // ^^^^^^ } +"#, + ); + } + + #[test] + fn test_closure_capture_pipe() { + check( + r#" +fn f() { + let x = 1; + // ^ + let c = $0|y| x + y; + // ^ read +} +"#, + ); + } + + #[test] + fn test_closure_capture_move() { + check( + r#" +fn f() { + let x = 1; + // ^ + let c = move$0 |y| x + y; + // ^ read +} +"#, + ); + } + + #[test] + fn test_trait_highlights_assoc_item_uses() { + check( + r#" +trait Foo { + //^^^ + type T; + const C: usize; + fn f() {} + fn m(&self) {} +} +impl Foo for i32 { + //^^^ + type T = i32; + const C: usize = 0; + fn f() {} + fn m(&self) {} +} +fn f(t: T) { + //^^^ + let _: T::T; + //^ + t.m(); + //^ + T::C; + //^ + T::f(); + //^ +} + +fn f2(t: T) { + //^^^ + let _: T::T; + t.m(); + T::C; + T::f(); +} "#, ); } diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 64b2221bdeab4..5ef6ac9480721 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -6,7 +6,7 @@ mod tests; use std::iter; use either::Either; -use hir::{HasSource, Semantics}; +use hir::{db::DefDatabase, HasSource, LangItem, Semantics}; use ide_db::{ base_db::FileRange, defs::{Definition, IdentClass, OperatorClass}, @@ -27,10 +27,25 @@ use crate::{ #[derive(Clone, Debug, PartialEq, Eq)] pub struct HoverConfig { pub links_in_hover: bool, + pub memory_layout: Option, pub documentation: bool, pub keywords: bool, pub format: HoverDocFormat, - pub interpret_tests: bool, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct MemoryLayoutHoverConfig { + pub size: Option, + pub offset: Option, + pub alignment: Option, + pub niches: bool, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum MemoryLayoutHoverRenderKind { + Decimal, + Hexadecimal, + Both, } #[derive(Clone, Debug, PartialEq, Eq)] @@ -56,7 +71,7 @@ impl HoverAction { mod_path: render::path( db, it.module(db)?, - it.name(db).map(|name| name.to_string()), + it.name(db).map(|name| name.display(db).to_string()), ), nav: it.try_to_nav(db)?, }) @@ -119,8 +134,8 @@ fn hover_simple( | T![crate] | T![Self] | T![_] => 4, - // index and prefix ops - T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3, + // index and prefix ops and closure pipe + T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] | T![|] => 3, kind if kind.is_keyword() => 2, T!['('] | T![')'] => 2, kind if kind.is_trivia() => 0, @@ -219,6 +234,16 @@ fn hover_simple( }; render::type_info_of(sema, config, &Either::Left(call_expr)) }) + }) + // try closure + .or_else(|| { + descended().find_map(|token| { + if token.kind() != T![|] { + return None; + } + let c = token.parent().and_then(|x| x.parent()).and_then(ast::ClosureExpr::cast)?; + render::closure_expr(sema, config, c) + }) }); result.map(|mut res: HoverResult| { @@ -344,7 +369,14 @@ fn goto_type_action_for_def(db: &RootDatabase, def: Definition) -> Option it.ty(db), diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index da725ce502b8d..1362146413e0d 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -3,8 +3,8 @@ use std::fmt::Display; use either::Either; use hir::{ - db::DefDatabase, Adt, AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, - MirEvalError, Semantics, TypeInfo, + Adt, AsAssocItem, AttributeTemplate, CaptureKind, HasAttrs, HasSource, HirDisplay, Layout, + LayoutError, Semantics, TypeInfo, }; use ide_db::{ base_db::SourceDatabase, @@ -27,7 +27,8 @@ use syntax::{ use crate::{ doc_links::{remove_links, rewrite_links}, hover::walk_and_push_ty, - HoverAction, HoverConfig, HoverResult, Markup, + HoverAction, HoverConfig, HoverResult, Markup, MemoryLayoutHoverConfig, + MemoryLayoutHoverRenderKind, }; pub(super) fn type_info_of( @@ -35,11 +36,20 @@ pub(super) fn type_info_of( _config: &HoverConfig, expr_or_pat: &Either, ) -> Option { - let TypeInfo { original, adjusted } = match expr_or_pat { + let ty_info = match expr_or_pat { Either::Left(expr) => sema.type_of_expr(expr)?, Either::Right(pat) => sema.type_of_pat(pat)?, }; - type_info(sema, _config, original, adjusted) + type_info(sema, _config, ty_info) +} + +pub(super) fn closure_expr( + sema: &Semantics<'_, RootDatabase>, + config: &HoverConfig, + c: ast::ClosureExpr, +) -> Option { + let TypeInfo { original, .. } = sema.type_of_expr(&c.into())?; + closure_ty(sema, config, &TypeInfo { original, adjusted: None }) } pub(super) fn try_expr( @@ -361,7 +371,7 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option Definition::Variant(e) => Some(e.parent_enum(db).name(db)), _ => None, } - .map(|name| name.to_string()) + .map(|name| name.display(db).to_string()) } pub(super) fn path(db: &RootDatabase, module: hir::Module, item_name: Option) -> String { @@ -371,7 +381,7 @@ pub(super) fn path(db: &RootDatabase, module: hir::Module, item_name: Option label_and_docs(db, it), - Definition::Field(it) => label_and_layout_info_and_docs(db, it, |&it| { - let var_def = it.parent_def(db); - let id = it.index(); - let layout = it.layout(db).ok()?; - let offset = match var_def { - hir::VariantDef::Struct(s) => Adt::from(s) - .layout(db) - .ok() - .map(|layout| format!(", offset = {}", layout.fields.offset(id).bytes())), - _ => None, - }; - Some(format!( - "size = {}, align = {}{}", - layout.size.bytes(), - layout.align.abi.bytes(), - offset.as_deref().unwrap_or_default() - )) - }), - Definition::Module(it) => label_and_docs(db, it), - Definition::Function(it) => label_and_layout_info_and_docs(db, it, |_| { - if !config.interpret_tests { - return None; - } - match it.eval(db) { - Ok(()) => Some("pass".into()), - Err(MirEvalError::Panic) => Some("fail".into()), - Err(MirEvalError::MirLowerError(f, e)) => { - let name = &db.function_data(f).name; - Some(format!("error: fail to lower {name} due {e:?}")) + Definition::Field(it) => label_and_layout_info_and_docs( + db, + it, + config, + |&it| it.layout(db), + |_| { + let var_def = it.parent_def(db); + let id = it.index(); + match var_def { + hir::VariantDef::Struct(s) => { + Adt::from(s).layout(db).ok().and_then(|layout| layout.field_offset(id)) + } + _ => None, } - Err(e) => Some(format!("error: {e:?}")), - } - }), - Definition::Adt(it) => label_and_layout_info_and_docs(db, it, |&it| { - let layout = it.layout(db).ok()?; - Some(format!("size = {}, align = {}", layout.size.bytes(), layout.align.abi.bytes())) - }), - Definition::Variant(it) => label_value_and_docs(db, it, |&it| { - if !it.parent_enum(db).is_data_carrying(db) { - match it.eval(db) { - Ok(x) => Some(if x >= 10 { format!("{x} ({x:#X})") } else { format!("{x}") }), - Err(_) => it.value(db).map(|x| format!("{x:?}")), + }, + ), + Definition::Module(it) => label_and_docs(db, it), + Definition::Function(it) => label_and_docs(db, it), + Definition::Adt(it) => { + label_and_layout_info_and_docs(db, it, config, |&it| it.layout(db), |_| None) + } + Definition::Variant(it) => label_value_and_layout_info_and_docs( + db, + it, + config, + |&it| { + if !it.parent_enum(db).is_data_carrying(db) { + match it.eval(db) { + Ok(x) => { + Some(if x >= 10 { format!("{x} ({x:#X})") } else { format!("{x}") }) + } + Err(_) => it.value(db).map(|x| format!("{x:?}")), + } + } else { + None } - } else { - None - } - }), + }, + |it| it.layout(db), + |layout| layout.enum_tag_size(), + ), Definition::Const(it) => label_value_and_docs(db, it, |it| { let body = it.render_eval(db); match body { @@ -455,22 +458,26 @@ pub(super) fn definition( }), Definition::Trait(it) => label_and_docs(db, it), Definition::TraitAlias(it) => label_and_docs(db, it), - Definition::TypeAlias(it) => label_and_docs(db, it), + Definition::TypeAlias(it) => { + label_and_layout_info_and_docs(db, it, config, |&it| it.ty(db).layout(db), |_| None) + } Definition::BuiltinType(it) => { return famous_defs .and_then(|fd| builtin(fd, it)) - .or_else(|| Some(Markup::fenced_block(&it.name()))) + .or_else(|| Some(Markup::fenced_block(&it.name().display(db)))) } - Definition::Local(it) => return local(db, it), + Definition::Local(it) => return local(db, it, config), Definition::SelfType(impl_def) => { impl_def.self_ty(db).as_adt().map(|adt| label_and_docs(db, adt))? } Definition::GenericParam(it) => label_and_docs(db, it), - Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))), + Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db).display(db))), // FIXME: We should be able to show more info about these Definition::BuiltinAttr(it) => return render_builtin_attr(db, it), Definition::ToolModule(it) => return Some(Markup::fenced_block(&it.name(db))), - Definition::DeriveHelper(it) => (format!("derive_helper {}", it.name(db)), None), + Definition::DeriveHelper(it) => { + (format!("derive_helper {}", it.name(db).display(db)), None) + } }; let docs = docs @@ -490,10 +497,13 @@ pub(super) fn definition( fn type_info( sema: &Semantics<'_, RootDatabase>, - _config: &HoverConfig, - original: hir::Type, - adjusted: Option, + config: &HoverConfig, + ty: TypeInfo, ) -> Option { + if let Some(res) = closure_ty(sema, config, &ty) { + return Some(res); + }; + let TypeInfo { original, adjusted } = ty; let mut res = HoverResult::default(); let mut targets: Vec = Vec::new(); let mut push_new_def = |item: hir::ModuleDef| { @@ -523,6 +533,67 @@ fn type_info( Some(res) } +fn closure_ty( + sema: &Semantics<'_, RootDatabase>, + config: &HoverConfig, + TypeInfo { original, adjusted }: &TypeInfo, +) -> Option { + let c = original.as_closure()?; + let mut captures_rendered = c.captured_items(sema.db) + .into_iter() + .map(|it| { + let borrow_kind = match it.kind() { + CaptureKind::SharedRef => "immutable borrow", + CaptureKind::UniqueSharedRef => "unique immutable borrow ([read more](https://doc.rust-lang.org/stable/reference/types/closure.html#unique-immutable-borrows-in-captures))", + CaptureKind::MutableRef => "mutable borrow", + CaptureKind::Move => "move", + }; + format!("* `{}` by {}", it.display_place(sema.db), borrow_kind) + }) + .join("\n"); + if captures_rendered.trim().is_empty() { + captures_rendered = "This closure captures nothing".to_string(); + } + let mut targets: Vec = Vec::new(); + let mut push_new_def = |item: hir::ModuleDef| { + if !targets.contains(&item) { + targets.push(item); + } + }; + walk_and_push_ty(sema.db, original, &mut push_new_def); + c.capture_types(sema.db).into_iter().for_each(|ty| { + walk_and_push_ty(sema.db, &ty, &mut push_new_def); + }); + + let adjusted = if let Some(adjusted_ty) = adjusted { + walk_and_push_ty(sema.db, &adjusted_ty, &mut push_new_def); + format!( + "\nCoerced to: {}", + adjusted_ty.display(sema.db).with_closure_style(hir::ClosureStyle::ImplFn) + ) + } else { + String::new() + }; + let mut markup = format!("```rust\n{}", c.display_with_id(sema.db),); + + if let Some(layout) = + render_memory_layout(config.memory_layout, || original.layout(sema.db), |_| None, |_| None) + { + format_to!(markup, "{layout}"); + } + format_to!( + markup, + "\n{}\n```{adjusted}\n\n## Captures\n{}", + c.display_with_impl(sema.db), + captures_rendered, + ); + + let mut res = HoverResult::default(); + res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets)); + res.markup = markup.into(); + Some(res) +} + fn render_builtin_attr(db: &RootDatabase, attr: hir::BuiltinAttr) -> Option { let name = attr.name(db); let desc = format!("#[{name}]"); @@ -553,21 +624,59 @@ where (label, docs) } -fn label_and_layout_info_and_docs( +fn label_and_layout_info_and_docs( + db: &RootDatabase, + def: D, + config: &HoverConfig, + layout_extractor: E, + layout_offset_extractor: E2, +) -> (String, Option) +where + D: HasAttrs + HirDisplay, + E: Fn(&D) -> Result, + E2: Fn(&Layout) -> Option, +{ + let mut label = def.display(db).to_string(); + if let Some(layout) = render_memory_layout( + config.memory_layout, + || layout_extractor(&def), + layout_offset_extractor, + |_| None, + ) { + format_to!(label, "{layout}"); + } + let docs = def.attrs(db).docs(); + (label, docs) +} + +fn label_value_and_layout_info_and_docs( db: &RootDatabase, def: D, + config: &HoverConfig, value_extractor: E, + layout_extractor: E2, + layout_tag_extractor: E3, ) -> (String, Option) where D: HasAttrs + HirDisplay, E: Fn(&D) -> Option, + E2: Fn(&D) -> Result, + E3: Fn(&Layout) -> Option, V: Display, { - let label = if let Some(value) = value_extractor(&def) { - format!("{} // {value}", def.display(db)) - } else { - def.display(db).to_string() + let value = value_extractor(&def); + let mut label = match value { + Some(value) => format!("{} = {value}", def.display(db)), + None => def.display(db).to_string(), }; + if let Some(layout) = render_memory_layout( + config.memory_layout, + || layout_extractor(&def), + |_| None, + layout_tag_extractor, + ) { + format_to!(label, "{layout}"); + } let docs = def.attrs(db).docs(); (label, docs) } @@ -616,26 +725,26 @@ fn markup(docs: Option, desc: String, mod_path: Option) -> Optio fn builtin(famous_defs: &FamousDefs<'_, '_>, builtin: hir::BuiltinType) -> Option { // std exposes prim_{} modules with docstrings on the root to document the builtins - let primitive_mod = format!("prim_{}", builtin.name()); + let primitive_mod = format!("prim_{}", builtin.name().display(famous_defs.0.db)); let doc_owner = find_std_module(famous_defs, &primitive_mod)?; let docs = doc_owner.attrs(famous_defs.0.db).docs()?; - markup(Some(docs.into()), builtin.name().to_string(), None) + markup(Some(docs.into()), builtin.name().display(famous_defs.0.db).to_string(), None) } fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option { let db = famous_defs.0.db; let std_crate = famous_defs.std()?; let std_root_module = std_crate.root_module(db); - std_root_module - .children(db) - .find(|module| module.name(db).map_or(false, |module| module.to_string() == name)) + std_root_module.children(db).find(|module| { + module.name(db).map_or(false, |module| module.display(db).to_string() == name) + }) } -fn local(db: &RootDatabase, it: hir::Local) -> Option { +fn local(db: &RootDatabase, it: hir::Local, config: &HoverConfig) -> Option { let ty = it.ty(db); let ty = ty.display_truncated(db, None); let is_mut = if it.is_mut(db) { "mut " } else { "" }; - let desc = match it.primary_source(db).into_ident_pat() { + let mut desc = match it.primary_source(db).into_ident_pat() { Some(ident) => { let name = it.name(db); let let_kw = if ident @@ -647,13 +756,91 @@ fn local(db: &RootDatabase, it: hir::Local) -> Option { } else { "" }; - format!("{let_kw}{is_mut}{name}: {ty}") + format!("{let_kw}{is_mut}{}: {ty}", name.display(db)) } None => format!("{is_mut}self: {ty}"), }; + if let Some(layout) = + render_memory_layout(config.memory_layout, || it.ty(db).layout(db), |_| None, |_| None) + { + format_to!(desc, "{layout}"); + } markup(None, desc, None) } +fn render_memory_layout( + config: Option, + layout: impl FnOnce() -> Result, + offset: impl FnOnce(&Layout) -> Option, + tag: impl FnOnce(&Layout) -> Option, +) -> Option { + // field + + let config = config?; + let layout = layout().ok()?; + + let mut label = String::from(" // "); + + if let Some(render) = config.size { + let size = match tag(&layout) { + Some(tag) => layout.size() as usize - tag, + None => layout.size() as usize, + }; + format_to!(label, "size = "); + match render { + MemoryLayoutHoverRenderKind::Decimal => format_to!(label, "{size}"), + MemoryLayoutHoverRenderKind::Hexadecimal => format_to!(label, "{size:#X}"), + MemoryLayoutHoverRenderKind::Both if size >= 10 => { + format_to!(label, "{size} ({size:#X})") + } + MemoryLayoutHoverRenderKind::Both => format_to!(label, "{size}"), + } + format_to!(label, ", "); + } + + if let Some(render) = config.alignment { + let align = layout.align(); + format_to!(label, "align = "); + match render { + MemoryLayoutHoverRenderKind::Decimal => format_to!(label, "{align}",), + MemoryLayoutHoverRenderKind::Hexadecimal => format_to!(label, "{align:#X}",), + MemoryLayoutHoverRenderKind::Both if align >= 10 => { + format_to!(label, "{align} ({align:#X})") + } + MemoryLayoutHoverRenderKind::Both => { + format_to!(label, "{align}") + } + } + format_to!(label, ", "); + } + + if let Some(render) = config.offset { + if let Some(offset) = offset(&layout) { + format_to!(label, "offset = "); + match render { + MemoryLayoutHoverRenderKind::Decimal => format_to!(label, "{offset}"), + MemoryLayoutHoverRenderKind::Hexadecimal => format_to!(label, "{offset:#X}"), + MemoryLayoutHoverRenderKind::Both if offset >= 10 => { + format_to!(label, "{offset} ({offset:#X})") + } + MemoryLayoutHoverRenderKind::Both => { + format_to!(label, "{offset}") + } + } + format_to!(label, ", "); + } + } + + if config.niches { + if let Some(niches) = layout.niches() { + format_to!(label, "niches = {niches}, "); + } + } + label.pop(); // ' ' + label.pop(); // ',' + Some(label) +} + struct KeywordHint { description: String, keyword_mod: String, diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 57bf0f9ad5f3c..a2f96977581c2 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -2,14 +2,21 @@ use expect_test::{expect, Expect}; use ide_db::base_db::{FileLoader, FileRange}; use syntax::TextRange; -use crate::{fixture, HoverConfig, HoverDocFormat}; +use crate::{ + fixture, HoverConfig, HoverDocFormat, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, +}; const HOVER_BASE_CONFIG: HoverConfig = HoverConfig { links_in_hover: false, + memory_layout: Some(MemoryLayoutHoverConfig { + size: Some(MemoryLayoutHoverRenderKind::Both), + offset: Some(MemoryLayoutHoverRenderKind::Both), + alignment: Some(MemoryLayoutHoverRenderKind::Both), + niches: true, + }), documentation: true, format: HoverDocFormat::Markdown, keywords: true, - interpret_tests: false, }; fn check_hover_no_result(ra_fixture: &str) { @@ -58,6 +65,23 @@ fn check_hover_no_links(ra_fixture: &str, expect: Expect) { expect.assert_eq(&actual) } +fn check_hover_no_memory_layout(ra_fixture: &str, expect: Expect) { + let (analysis, position) = fixture::position(ra_fixture); + let hover = analysis + .hover( + &HoverConfig { memory_layout: None, ..HOVER_BASE_CONFIG }, + FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, + ) + .unwrap() + .unwrap(); + + let content = analysis.db.file_text(position.file_id); + let hovered_element = &content[hover.range]; + + let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup); + expect.assert_eq(&actual) +} + fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis @@ -97,6 +121,15 @@ fn check_hover_range(ra_fixture: &str, expect: Expect) { expect.assert_eq(hover.info.markup.as_str()) } +fn check_hover_range_actions(ra_fixture: &str, expect: Expect) { + let (analysis, range) = fixture::range(ra_fixture); + let hover = analysis + .hover(&HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, range) + .unwrap() + .unwrap(); + expect.assert_debug_eq(&hover.info.actions); +} + fn check_hover_range_no_results(ra_fixture: &str) { let (analysis, range) = fixture::range(ra_fixture); let hover = analysis.hover(&HOVER_BASE_CONFIG, range).unwrap(); @@ -124,7 +157,7 @@ fn foo() { *local* ```rust - let local: i32 + let local: i32 // size = 4, align = 4 ``` "#]], ); @@ -198,6 +231,181 @@ fn main() { ); } +#[test] +fn hover_closure() { + check( + r#" +//- minicore: copy +fn main() { + let x = 2; + let y = $0|z| x + z; +} +"#, + expect![[r#" + *|* + ```rust + {closure#0} // size = 8, align = 8, niches = 1 + impl Fn(i32) -> i32 + ``` + + ## Captures + * `x` by immutable borrow + "#]], + ); + + check( + r#" +//- minicore: copy +fn foo(x: impl Fn(i32) -> i32) { + +} +fn main() { + foo($0|x: i32| x) +} +"#, + expect![[r#" + *|* + ```rust + {closure#0} // size = 0, align = 1 + impl Fn(i32) -> i32 + ``` + + ## Captures + This closure captures nothing + "#]], + ); + + check( + r#" +//- minicore: copy + +struct Z { f: i32 } + +struct Y(&'static mut Z) + +struct X { + f1: Y, + f2: (Y, Y), +} + +fn main() { + let x: X; + let y = $0|| { + x.f1; + &mut x.f2.0 .0.f; + }; +} +"#, + expect![[r#" + *|* + ```rust + {closure#0} // size = 16 (0x10), align = 8, niches = 1 + impl FnOnce() + ``` + + ## Captures + * `x.f1` by move + * `(*x.f2.0.0).f` by mutable borrow + "#]], + ); + check( + r#" +//- minicore: copy, option + +fn do_char(c: char) {} + +fn main() { + let x = None; + let y = |$0| { + match x { + Some(c) => do_char(c), + None => x = None, + } + }; +} +"#, + expect![[r#" + *|* + ```rust + {closure#0} // size = 8, align = 8, niches = 1 + impl FnMut() + ``` + + ## Captures + * `x` by mutable borrow + "#]], + ); +} + +#[test] +fn hover_ranged_closure() { + check_hover_range( + r#" +//- minicore: fn +struct S; +struct S2; +fn main() { + let x = &S; + let y = ($0|| {x; S2}$0).call(); +} +"#, + expect![[r#" + ```rust + {closure#0} // size = 8, align = 8, niches = 1 + impl FnOnce() -> S2 + ``` + Coerced to: &impl FnOnce() -> S2 + + ## Captures + * `x` by move"#]], + ); + check_hover_range_actions( + r#" +//- minicore: fn +struct S; +struct S2; +fn main() { + let x = &S; + let y = ($0|| {x; S2}$0).call(); +} +"#, + expect![[r#" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::S2", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 10..20, + focus_range: 17..19, + name: "S2", + kind: Struct, + description: "struct S2", + }, + }, + HoverGotoTypeData { + mod_path: "test::S", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..9, + focus_range: 7..8, + name: "S", + kind: Struct, + description: "struct S", + }, + }, + ], + ), + ] + "#]], + ); +} + #[test] fn hover_shows_long_type_of_an_expression() { check( @@ -222,12 +430,12 @@ fn main() { } "#, expect![[r#" - *iter* + *iter* - ```rust - let mut iter: Iter>, |&mut u32, &u32, &mut u32| -> Option, u32>> - ``` - "#]], + ```rust + let mut iter: Iter>, impl Fn(&mut u32, &u32, &mut u32) -> Option, u32>> // size = 8, align = 4 + ``` + "#]], ); } @@ -604,12 +812,12 @@ fn main() { let zz$0 = Test { t: 23u8, k: 33 }; }"#, expect![[r#" - *zz* + *zz* - ```rust - let zz: Test - ``` - "#]], + ```rust + let zz: Test // size = 8, align = 4 + ``` + "#]], ); check_hover_range( r#" @@ -655,12 +863,12 @@ use Option::Some; fn main() { let b$0ar = Some(12); } "#, expect![[r#" - *bar* + *bar* - ```rust - let bar: Option - ``` - "#]], + ```rust + let bar: Option // size = 4, align = 4 + ``` + "#]], ); } @@ -724,12 +932,12 @@ fn hover_for_local_variable() { check( r#"fn func(foo: i32) { fo$0o; }"#, expect![[r#" - *foo* + *foo* - ```rust - foo: i32 - ``` - "#]], + ```rust + foo: i32 // size = 4, align = 4 + ``` + "#]], ) } @@ -738,12 +946,12 @@ fn hover_for_local_variable_pat() { check( r#"fn func(fo$0o: i32) {}"#, expect![[r#" - *foo* + *foo* - ```rust - foo: i32 - ``` - "#]], + ```rust + foo: i32 // size = 4, align = 4 + ``` + "#]], ) } @@ -752,12 +960,12 @@ fn hover_local_var_edge() { check( r#"fn func(foo: i32) { if true { $0foo; }; }"#, expect![[r#" - *foo* + *foo* - ```rust - foo: i32 - ``` - "#]], + ```rust + foo: i32 // size = 4, align = 4 + ``` + "#]], ) } @@ -766,12 +974,12 @@ fn hover_for_param_edge() { check( r#"fn func($0foo: i32) {}"#, expect![[r#" - *foo* + *foo* - ```rust - foo: i32 - ``` - "#]], + ```rust + foo: i32 // size = 4, align = 4 + ``` + "#]], ) } @@ -810,12 +1018,12 @@ impl Thing { fn main() { let foo_$0test = Thing::new(); } "#, expect![[r#" - *foo_test* + *foo_test* - ```rust - let foo_test: Thing - ``` - "#]], + ```rust + let foo_test: Thing // size = 4, align = 4 + ``` + "#]], ) } @@ -970,12 +1178,12 @@ fn y() { } "#, expect![[r#" - *x* + *x* - ```rust - let x: i32 - ``` - "#]], + ```rust + let x: i32 // size = 4, align = 4 + ``` + "#]], ) } @@ -1100,12 +1308,12 @@ macro_rules! id { ($($tt:tt)*) => { $($tt)* } } fn foo(bar:u32) { let a = id!(ba$0r); } "#, expect![[r#" - *bar* + *bar* - ```rust - bar: u32 - ``` - "#]], + ```rust + bar: u32 // size = 4, align = 4 + ``` + "#]], ); } @@ -1118,12 +1326,12 @@ macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } } fn foo(bar:u32) { let a = id!(ba$0r); } "#, expect![[r#" - *bar* + *bar* - ```rust - bar: u32 - ``` - "#]], + ```rust + bar: u32 // size = 4, align = 4 + ``` + "#]], ); } @@ -1320,16 +1528,16 @@ fn test_hover_function_pointer_show_identifiers() { check( r#"type foo$0 = fn(a: i32, b: i32) -> i32;"#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - type foo = fn(a: i32, b: i32) -> i32 - ``` - "#]], + ```rust + type foo = fn(a: i32, b: i32) -> i32 // size = 8, align = 8, niches = 1 + ``` + "#]], ); } @@ -1338,16 +1546,16 @@ fn test_hover_function_pointer_no_identifier() { check( r#"type foo$0 = fn(i32, _: i32) -> i32;"#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + test + ``` - ```rust - type foo = fn(i32, i32) -> i32 - ``` - "#]], + ```rust + type foo = fn(i32, i32) -> i32 // size = 8, align = 8, niches = 1 + ``` + "#]], ); } @@ -1667,6 +1875,86 @@ pub fn fo$0o() {} ); } +#[test] +fn test_hover_layout_of_variant() { + check( + r#"enum Foo { + Va$0riant1(u8, u16), + Variant2(i32, u8, i64), + }"#, + expect![[r#" + *Variant1* + + ```rust + test::Foo + ``` + + ```rust + Variant1(u8, u16) // size = 4, align = 2 + ``` + "#]], + ); +} + +#[test] +fn test_hover_layout_of_enum() { + check( + r#"enum $0Foo { + Variant1(u8, u16), + Variant2(i32, u8, i64), + }"#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + enum Foo // size = 16 (0x10), align = 8, niches = 254 + ``` + "#]], + ); +} + +#[test] +fn test_hover_no_memory_layout() { + check_hover_no_memory_layout( + r#"struct Foo { fiel$0d_a: u8, field_b: i32, field_c: i16 }"#, + expect![[r#" + *field_a* + + ```rust + test::Foo + ``` + + ```rust + field_a: u8 + ``` + "#]], + ); + + check_hover_no_memory_layout( + r#" +//- minicore: copy +fn main() { + let x = 2; + let y = $0|z| x + z; +} +"#, + expect![[r#" + *|* + ```rust + {closure#0} + impl Fn(i32) -> i32 + ``` + + ## Captures + * `x` by immutable borrow + "#]], + ); +} + #[test] fn test_hover_macro_generated_struct_fn_doc_comment() { cov_mark::check!(hover_macro_generated_struct_fn_doc_comment); @@ -2020,6 +2308,19 @@ fn main() { let s$0t = S{ f1:Arg(0) }; } ); } +#[test] +fn test_hover_generic_excludes_sized_go_to_action() { + check_actions( + r#" +//- minicore: sized +struct S(T); + "#, + expect![[r#" + [] + "#]], + ); +} + #[test] fn test_hover_generic_struct_has_flattened_goto_type_actions() { check_actions( @@ -2079,52 +2380,53 @@ mod M { fn main() { let s$0t = (A(1), B(2), M::C(3) ); } "#, expect![[r#" - [ - GoToType( - [ - HoverGotoTypeData { - mod_path: "test::A", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 0..14, - focus_range: 7..8, - name: "A", - kind: Struct, - description: "struct A", - }, + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::A", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..14, + focus_range: 7..8, + name: "A", + kind: Struct, + description: "struct A", }, - HoverGotoTypeData { - mod_path: "test::B", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 15..29, - focus_range: 22..23, - name: "B", - kind: Struct, - description: "struct B", - }, + }, + HoverGotoTypeData { + mod_path: "test::B", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 15..29, + focus_range: 22..23, + name: "B", + kind: Struct, + description: "struct B", }, - HoverGotoTypeData { - mod_path: "test::M::C", - nav: NavigationTarget { - file_id: FileId( - 0, - ), - full_range: 42..60, - focus_range: 53..54, - name: "C", - kind: Struct, - description: "pub struct C", - }, + }, + HoverGotoTypeData { + mod_path: "test::M::C", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 42..60, + focus_range: 53..54, + name: "C", + kind: Struct, + container_name: "M", + description: "pub struct C", }, - ], - ), - ] - "#]], + }, + ], + ), + ] + "#]], ); } @@ -2453,6 +2755,7 @@ pub mod future { focus_range: 60..66, name: "Future", kind: Trait, + container_name: "future", description: "pub trait Future", }, }, @@ -2908,7 +3211,7 @@ fn main() { *f* ```rust - f: &i32 + f: &i32 // size = 8, align = 8, niches = 1 ``` --- @@ -2958,7 +3261,7 @@ fn main() { *value* ```rust - let value: Const<1> + let value: Const<1> // size = 0, align = 1 ``` "#]], ); @@ -2978,7 +3281,7 @@ fn main() { *value* ```rust - let value: Const<0> + let value: Const<0> // size = 0, align = 1 ``` "#]], ); @@ -2998,7 +3301,7 @@ fn main() { *value* ```rust - let value: Const<-1> + let value: Const<-1> // size = 0, align = 1 ``` "#]], ); @@ -3018,7 +3321,7 @@ fn main() { *value* ```rust - let value: Const + let value: Const // size = 0, align = 1 ``` "#]], ); @@ -3038,7 +3341,7 @@ fn main() { *value* ```rust - let value: Const<'🦀'> + let value: Const<'🦀'> // size = 0, align = 1 ``` "#]], ); @@ -3054,12 +3357,12 @@ impl Foo { } "#, expect![[r#" - *self* + *self* - ```rust - self: &Foo - ``` - "#]], + ```rust + self: &Foo // size = 8, align = 8, niches = 1 + ``` + "#]], ); } @@ -3074,12 +3377,12 @@ impl Foo { } "#, expect![[r#" - *self* + *self* - ```rust - self: Arc - ``` - "#]], + ```rust + self: Arc // size = 0, align = 1 + ``` + "#]], ); } @@ -3115,7 +3418,7 @@ mod Foo$0 { } #[test] -fn hover_doc_outer_inner_attribue() { +fn hover_doc_outer_inner_attribute() { check( r#" #[doc = "Be quick;"] @@ -3146,7 +3449,7 @@ mod Foo$0 { } #[test] -fn hover_doc_block_style_indentend() { +fn hover_doc_block_style_indent_end() { check( r#" /** @@ -3455,16 +3758,16 @@ struct Foo; type Fo$0o2 = Foo<2>; "#, expect![[r#" - *Foo2* + *Foo2* - ```rust - test - ``` + ```rust + test + ``` - ```rust - type Foo2 = Foo<2> - ``` - "#]], + ```rust + type Foo2 = Foo<2> // size = 0, align = 1 + ``` + "#]], ); } @@ -3504,7 +3807,7 @@ enum E { ``` ```rust - A = 8 + A = 8 // size = 1, align = 1 ``` --- @@ -3529,7 +3832,7 @@ enum E { ``` ```rust - A = 12 (0xC) + A = 12 (0xC) // size = 1, align = 1 ``` --- @@ -3555,7 +3858,7 @@ enum E { ``` ```rust - B = 2 + B = 2 // size = 1, align = 1 ``` --- @@ -3581,7 +3884,7 @@ enum E { ``` ```rust - B = 5 + B = 5 // size = 1, align = 1 ``` --- @@ -4034,6 +4337,235 @@ const FOO$0: f64 = 1.0f64; ); } +#[test] +fn hover_const_eval_floating_point() { + check( + r#" +extern "rust-intrinsic" { + pub fn expf64(x: f64) -> f64; +} + +const FOO$0: f64 = expf64(1.2); +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: f64 = 3.3201169227365472 + ``` + "#]], + ); +} + +#[test] +fn hover_const_eval_enum() { + check( + r#" +enum Enum { + V1, + V2, +} + +const VX: Enum = Enum::V1; + +const FOO$0: Enum = VX; +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: Enum = V1 + ``` + "#]], + ); + check( + r#" +//- minicore: option +const FOO$0: Option = Some(2); +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: Option = Some(2) + ``` + "#]], + ); + check( + r#" +//- minicore: option +const FOO$0: Option<&i32> = Some(2).as_ref(); +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: Option<&i32> = Some(&2) + ``` + "#]], + ); +} + +#[test] +fn hover_const_eval_slice() { + check( + r#" +//- minicore: slice, index, coerce_unsized +const FOO$0: &[i32] = &[1, 2, 3 + 4]; +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: &[i32] = &[1, 2, 7] + ``` + "#]], + ); + check( + r#" +//- minicore: slice, index, coerce_unsized +const FOO$0: &[i32; 5] = &[12; 5]; +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: &[i32; 5] = &[12, 12, 12, 12, 12] + ``` + "#]], + ); + check( + r#" +//- minicore: slice, index, coerce_unsized + +const FOO$0: (&i32, &[i32], &i32) = { + let a: &[i32] = &[1, 2, 3]; + (&a[0], a, &a[0]) +} +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: (&i32, &[i32], &i32) = (&1, &[1, 2, 3], &1) + ``` + "#]], + ); + check( + r#" +//- minicore: slice, index, coerce_unsized + +struct Tree(&[Tree]); + +const FOO$0: Tree = { + let x = &[Tree(&[]), Tree(&[Tree(&[])])]; + Tree(&[Tree(x), Tree(x)]) +} +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: Tree = Tree(&[Tree(&[Tree(&[]), Tree(&[Tree(&[])])]), Tree(&[Tree(&[]), Tree(&[Tree(&[])])])]) + ``` + "#]], + ); +} + +#[test] +fn hover_const_eval_str() { + check( + r#" +const FOO$0: &str = "foo"; +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: &str = "foo" + ``` + "#]], + ); + check( + r#" +struct X { + a: &'static str, + b: &'static str, +} +const FOO$0: X = X { + a: "axiom", + b: "buy N large", +}; +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: X = X { a: "axiom", b: "buy N large" } + ``` + "#]], + ); + check( + r#" +const FOO$0: (&str, &str) = { + let x = "foo"; + (x, x) +}; +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: (&str, &str) = ("foo", "foo") + ``` + "#]], + ); +} + #[test] fn hover_const_eval_in_generic_trait() { // Doesn't compile, but we shouldn't crash. @@ -4115,7 +4647,7 @@ fn foo(e: E) { ``` ```rust - A = 3 + A = 3 // size = 0, align = 1 ``` --- @@ -4137,9 +4669,9 @@ fn main() { *tile4* ```rust - let tile4: [u32; 8] + let tile4: [u32; 8] // size = 32 (0x20), align = 4 ``` - "#]], + "#]], ); } @@ -4242,7 +4774,7 @@ fn foo() { /// [threads]: ../book/ch16-01-threads.html#using-move-closures-with-threads mod move_keyword {} "#, - expect![[r##" + expect![[r#" *move* ```rust @@ -4251,11 +4783,11 @@ mod move_keyword {} --- - [closure](https://doc.rust-lang.org/nightly/book/ch13-01-closures.html) - [closures](https://doc.rust-lang.org/nightly/book/ch13-01-closures.html) - [threads](https://doc.rust-lang.org/nightly/book/ch16-01-threads.html#using-move-closures-with-threads) + [closure](https://doc.rust-lang.org/stable/book/ch13-01-closures.html) + [closures](https://doc.rust-lang.org/stable/book/ch13-01-closures.html) + [threads](https://doc.rust-lang.org/stable/book/ch16-01-threads.html#using-move-closures-with-threads) - "##]], + "#]], ); } @@ -4288,7 +4820,7 @@ fn hover_builtin() { check( r#" //- /main.rs crate:main deps:std -cosnt _: &str$0 = ""; } +const _: &str$0 = ""; } //- /libstd.rs crate:std /// Docs for prim_str @@ -5009,7 +5541,7 @@ fn foo() { fn hover_try_expr_res() { check_hover_range( r#" -//- minicore:result +//- minicore: try, from, result struct FooError; fn foo() -> Result<(), FooError> { @@ -5023,7 +5555,7 @@ fn foo() -> Result<(), FooError> { ); check_hover_range( r#" -//- minicore:result +//- minicore: try, from, result struct FooError; struct BarError; @@ -5044,6 +5576,7 @@ fn foo() -> Result<(), FooError> { fn hover_try_expr() { check_hover_range( r#" +//- minicore: try struct NotResult(T, U); struct Short; struct Looooong; @@ -5061,6 +5594,7 @@ fn foo() -> NotResult<(), Looooong> { ); check_hover_range( r#" +//- minicore: try struct NotResult(T, U); struct Short; struct Looooong; @@ -5092,7 +5626,7 @@ fn foo() -> Option<()> { "#, expect![[r#" ```rust - as Try>::Output + i32 ```"#]], ); } @@ -5312,7 +5846,7 @@ enum Enum { ``` ```rust - RecordV { field: u32 } + RecordV { field: u32 } // size = 4, align = 4 ``` "#]], ); diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index ac477339ec233..292591674191c 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -5,7 +5,8 @@ use std::{ use either::Either; use hir::{ - known, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef, ModuleDefId, Semantics, + known, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef, + ModuleDefId, Semantics, }; use ide_db::{base_db::FileRange, famous_defs::FamousDefs, RootDatabase}; use itertools::Itertools; @@ -13,21 +14,23 @@ use smallvec::{smallvec, SmallVec}; use stdx::never; use syntax::{ ast::{self, AstNode}, - match_ast, NodeOrToken, SyntaxNode, TextRange, + match_ast, NodeOrToken, SyntaxNode, TextRange, TextSize, }; +use text_edit::TextEdit; use crate::{navigation_target::TryToNav, FileId}; -mod closing_brace; -mod implicit_static; -mod fn_lifetime_fn; -mod closure_ret; mod adjustment; -mod chaining; -mod param_name; -mod binding_mode; mod bind_pat; +mod binding_mode; +mod chaining; +mod closing_brace; +mod closure_ret; +mod closure_captures; mod discriminant; +mod fn_lifetime_fn; +mod implicit_static; +mod param_name; #[derive(Clone, Debug, PartialEq, Eq)] pub struct InlayHintsConfig { @@ -40,11 +43,13 @@ pub struct InlayHintsConfig { pub adjustment_hints_mode: AdjustmentHintsMode, pub adjustment_hints_hide_outside_unsafe: bool, pub closure_return_type_hints: ClosureReturnTypeHints, + pub closure_capture_hints: bool, pub binding_mode_hints: bool, pub lifetime_elision_hints: LifetimeElisionHints, pub param_names_for_lifetime_elision_hints: bool, pub hide_named_constructor_hints: bool, pub hide_closure_initialization_hints: bool, + pub closure_style: ClosureStyle, pub max_length: Option, pub closing_brace_hints_min_lines: Option, } @@ -87,38 +92,61 @@ pub enum AdjustmentHintsMode { #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum InlayKind { + Adjustment, BindingMode, Chaining, ClosingBrace, - ClosureReturnType, + ClosureCapture, + Discriminant, GenericParamList, - Adjustment, - AdjustmentPostfix, Lifetime, Parameter, Type, - Discriminant, - OpeningParenthesis, - ClosingParenthesis, +} + +#[derive(Debug)] +pub enum InlayHintPosition { + Before, + After, } #[derive(Debug)] pub struct InlayHint { /// The text range this inlay hint applies to. pub range: TextRange, - /// The kind of this inlay hint. This is used to determine side and padding of the hint for - /// rendering purposes. + pub position: InlayHintPosition, + pub pad_left: bool, + pub pad_right: bool, + /// The kind of this inlay hint. pub kind: InlayKind, /// The actual label to show in the inlay hint. pub label: InlayHintLabel, + /// Text edit to apply when "accepting" this inlay hint. + pub text_edit: Option, } impl InlayHint { - fn closing_paren(range: TextRange) -> InlayHint { - InlayHint { range, kind: InlayKind::ClosingParenthesis, label: InlayHintLabel::from(")") } + fn closing_paren_after(kind: InlayKind, range: TextRange) -> InlayHint { + InlayHint { + range, + kind, + label: InlayHintLabel::from(")"), + text_edit: None, + position: InlayHintPosition::After, + pad_left: false, + pad_right: false, + } } - fn opening_paren(range: TextRange) -> InlayHint { - InlayHint { range, kind: InlayKind::OpeningParenthesis, label: InlayHintLabel::from("(") } + fn opening_paren_before(kind: InlayKind, range: TextRange) -> InlayHint { + InlayHint { + range, + kind, + label: InlayHintLabel::from("("), + text_edit: None, + position: InlayHintPosition::Before, + pad_left: false, + pad_right: false, + } } } @@ -283,14 +311,15 @@ impl InlayHintLabelBuilder<'_> { fn label_of_ty( famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - ty: hir::Type, + ty: &hir::Type, ) -> Option { fn rec( sema: &Semantics<'_, RootDatabase>, famous_defs: &FamousDefs<'_, '_>, mut max_length: Option, - ty: hir::Type, + ty: &hir::Type, label_builder: &mut InlayHintLabelBuilder<'_>, + config: &InlayHintsConfig, ) -> Result<(), HirDisplayError> { let iter_item_type = hint_iterator(sema, famous_defs, &ty); match iter_item_type { @@ -321,11 +350,14 @@ fn label_of_ty( label_builder.write_str(LABEL_ITEM)?; label_builder.end_location_link(); label_builder.write_str(LABEL_MIDDLE2)?; - rec(sema, famous_defs, max_length, ty, label_builder)?; + rec(sema, famous_defs, max_length, &ty, label_builder, config)?; label_builder.write_str(LABEL_END)?; Ok(()) } - None => ty.display_truncated(sema.db, max_length).write_to(label_builder), + None => ty + .display_truncated(sema.db, max_length) + .with_closure_style(config.closure_style) + .write_to(label_builder), } } @@ -335,11 +367,28 @@ fn label_of_ty( location: None, result: InlayHintLabel::default(), }; - let _ = rec(sema, famous_defs, config.max_length, ty, &mut label_builder); + let _ = rec(sema, famous_defs, config.max_length, ty, &mut label_builder, config); let r = label_builder.finish(); Some(r) } +fn ty_to_text_edit( + sema: &Semantics<'_, RootDatabase>, + node_for_hint: &SyntaxNode, + ty: &hir::Type, + offset_to_insert: TextSize, + prefix: String, +) -> Option { + let scope = sema.scope(node_for_hint)?; + // FIXME: Limit the length and bail out on excess somehow? + let rendered = ty.display_source_code(scope.db, scope.module().into(), false).ok()?; + + let mut builder = TextEdit::builder(); + builder.insert(offset_to_insert, prefix); + builder.insert(offset_to_insert, rendered); + Some(builder.finish()) +} + // Feature: Inlay Hints // // rust-analyzer shows additional information inline with the source code. @@ -408,10 +457,10 @@ fn hints( ast::Expr::MethodCallExpr(it) => { param_name::hints(hints, sema, config, ast::Expr::from(it)) } - ast::Expr::ClosureExpr(it) => closure_ret::hints(hints, famous_defs, config, file_id, it), - // We could show reborrows for all expressions, but usually that is just noise to the user - // and the main point here is to show why "moving" a mutable reference doesn't necessarily move it - // ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr), + ast::Expr::ClosureExpr(it) => { + closure_captures::hints(hints, famous_defs, config, file_id, it.clone()); + closure_ret::hints(hints, famous_defs, config, file_id, it) + }, _ => None, } }, @@ -481,6 +530,7 @@ fn closure_has_block_body(closure: &ast::ClosureExpr) -> bool { #[cfg(test)] mod tests { use expect_test::Expect; + use hir::ClosureStyle; use itertools::Itertools; use test_utils::extract_annotations; @@ -498,12 +548,14 @@ mod tests { chaining_hints: false, lifetime_elision_hints: LifetimeElisionHints::Never, closure_return_type_hints: ClosureReturnTypeHints::Never, + closure_capture_hints: false, adjustment_hints: AdjustmentHints::Never, adjustment_hints_mode: AdjustmentHintsMode::Prefix, adjustment_hints_hide_outside_unsafe: false, binding_mode_hints: false, hide_named_constructor_hints: false, hide_closure_initialization_hints: false, + closure_style: ClosureStyle::ImplFn, param_names_for_lifetime_elision_hints: false, max_length: None, closing_brace_hints_min_lines: None, @@ -530,7 +582,8 @@ mod tests { let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); let actual = inlay_hints .into_iter() - .map(|it| (it.range, it.label.to_string())) + // FIXME: We trim the start because some inlay produces leading whitespace which is not properly supported by our annotation extraction + .map(|it| (it.range, it.label.to_string().trim_start().to_owned())) .sorted_by_key(|(range, _)| range.start()) .collect::>(); expected.sort_by_key(|(range, _)| range.start()); @@ -545,6 +598,37 @@ mod tests { expect.assert_debug_eq(&inlay_hints) } + /// Computes inlay hints for the fixture, applies all the provided text edits and then runs + /// expect test. + #[track_caller] + pub(super) fn check_edit(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { + let (analysis, file_id) = fixture::file(ra_fixture); + let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); + + let edits = inlay_hints + .into_iter() + .filter_map(|hint| hint.text_edit) + .reduce(|mut acc, next| { + acc.union(next).expect("merging text edits failed"); + acc + }) + .expect("no edit returned"); + + let mut actual = analysis.file_text(file_id).unwrap().to_string(); + edits.apply(&mut actual); + expect.assert_eq(&actual); + } + + #[track_caller] + pub(super) fn check_no_edit(config: InlayHintsConfig, ra_fixture: &str) { + let (analysis, file_id) = fixture::file(ra_fixture); + let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); + + let edits: Vec<_> = inlay_hints.into_iter().filter_map(|hint| hint.text_edit).collect(); + + assert!(edits.is_empty(), "unexpected edits: {edits:?}"); + } + #[test] fn hints_disabled() { check_with_config( diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs index 46505b3044109..10bee2a6accfe 100644 --- a/crates/ide/src/inlay_hints/adjustment.rs +++ b/crates/ide/src/inlay_hints/adjustment.rs @@ -3,7 +3,11 @@ //! let _: u32 = /* */ loop {}; //! let _: &u32 = /* &* */ &mut 0; //! ``` -use hir::{Adjust, Adjustment, AutoBorrow, HirDisplay, Mutability, PointerCast, Safety, Semantics}; +use either::Either; +use hir::{ + Adjust, Adjustment, AutoBorrow, HirDisplay, Mutability, OverloadedDeref, PointerCast, Safety, + Semantics, +}; use ide_db::RootDatabase; use stdx::never; @@ -13,8 +17,8 @@ use syntax::{ }; use crate::{ - AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind, - InlayTooltip, + AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintPosition, + InlayHintsConfig, InlayKind, InlayTooltip, }; pub(super) fn hints( @@ -60,22 +64,26 @@ pub(super) fn hints( mode_and_needs_parens_for_adjustment_hints(expr, config.adjustment_hints_mode); if needs_outer_parens { - acc.push(InlayHint::opening_paren(expr.syntax().text_range())); + acc.push(InlayHint::opening_paren_before( + InlayKind::Adjustment, + expr.syntax().text_range(), + )); } if postfix && needs_inner_parens { - acc.push(InlayHint::opening_paren(expr.syntax().text_range())); - acc.push(InlayHint::closing_paren(expr.syntax().text_range())); + acc.push(InlayHint::opening_paren_before( + InlayKind::Adjustment, + expr.syntax().text_range(), + )); + acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range())); } - let (mut tmp0, mut tmp1); - let iter: &mut dyn Iterator = if postfix { - tmp0 = adjustments.into_iter(); - &mut tmp0 + let mut iter = if postfix { + Either::Left(adjustments.into_iter()) } else { - tmp1 = adjustments.into_iter().rev(); - &mut tmp1 + Either::Right(adjustments.into_iter().rev()) }; + let iter: &mut dyn Iterator = iter.as_mut().either(|it| it as _, |it| it as _); for Adjustment { source, target, kind } in iter { if source == target { @@ -88,7 +96,13 @@ pub(super) fn hints( Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => { ("", "never to any") } - Adjust::Deref(_) => ("*", "dereference"), + Adjust::Deref(None) => ("*", "dereference"), + Adjust::Deref(Some(OverloadedDeref(Mutability::Shared))) => { + ("*", "`Deref` dereference") + } + Adjust::Deref(Some(OverloadedDeref(Mutability::Mut))) => { + ("*", "`DerefMut` dereference") + } Adjust::Borrow(AutoBorrow::Ref(Mutability::Shared)) => ("&", "borrow"), Adjust::Borrow(AutoBorrow::Ref(Mutability::Mut)) => ("&mut ", "unique borrow"), Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Shared)) => { @@ -125,7 +139,10 @@ pub(super) fn hints( }; acc.push(InlayHint { range: expr.syntax().text_range(), - kind: if postfix { InlayKind::AdjustmentPostfix } else { InlayKind::Adjustment }, + pad_left: false, + pad_right: false, + position: if postfix { InlayHintPosition::After } else { InlayHintPosition::Before }, + kind: InlayKind::Adjustment, label: InlayHintLabel::simple( if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() }, Some(InlayTooltip::Markdown(format!( @@ -135,19 +152,23 @@ pub(super) fn hints( ))), None, ), + text_edit: None, }); } if !postfix && needs_inner_parens { - acc.push(InlayHint::opening_paren(expr.syntax().text_range())); - acc.push(InlayHint::closing_paren(expr.syntax().text_range())); + acc.push(InlayHint::opening_paren_before( + InlayKind::Adjustment, + expr.syntax().text_range(), + )); + acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range())); } if needs_outer_parens { - acc.push(InlayHint::closing_paren(expr.syntax().text_range())); + acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range())); } Some(()) } -/// Returns whatever the hint should be postfix and if we need to add paretheses on the inside and/or outside of `expr`, +/// Returns whatever the hint should be postfix and if we need to add parentheses on the inside and/or outside of `expr`, /// if we are going to add (`postfix`) adjustments hints to it. fn mode_and_needs_parens_for_adjustment_hints( expr: &ast::Expr, @@ -182,7 +203,7 @@ fn mode_and_needs_parens_for_adjustment_hints( } } -/// Returns whatever we need to add paretheses on the inside and/or outside of `expr`, +/// Returns whatever we need to add parentheses on the inside and/or outside of `expr`, /// if we are going to add (`postfix`) adjustments hints to it. fn needs_parens_for_adjustment_hints(expr: &ast::Expr, postfix: bool) -> (bool, bool) { // This is a very miserable pile of hacks... @@ -193,10 +214,10 @@ fn needs_parens_for_adjustment_hints(expr: &ast::Expr, postfix: bool) -> (bool, // But we want to check what would happen if we add `*`/`.*` to the inner expression. // To check for inner we need `` expr.needs_parens_in(`*expr`) ``, // to check for outer we need `` `*expr`.needs_parens_in(parent) ``, - // where "expr" is the `expr` parameter, `*expr` is the editted `expr`, + // where "expr" is the `expr` parameter, `*expr` is the edited `expr`, // and "parent" is the parent of the original expression... // - // For this we utilize mutable mutable trees, which is a HACK, but it works. + // For this we utilize mutable trees, which is a HACK, but it works. // // FIXME: comeup with a better API for `needs_parens_in`, so that we don't have to do *this* @@ -242,7 +263,7 @@ fn needs_parens_for_adjustment_hints(expr: &ast::Expr, postfix: bool) -> (bool, }; // At this point - // - `parent` is the parrent of the original expression + // - `parent` is the parent of the original expression // - `dummy_expr` is the original expression wrapped in the operator we want (`*`/`.*`) // - `expr` is the clone of the original expression (with `dummy_expr` as the parent) @@ -264,7 +285,7 @@ mod tests { check_with_config( InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG }, r#" -//- minicore: coerce_unsized, fn, eq +//- minicore: coerce_unsized, fn, eq, index fn main() { let _: u32 = loop {}; //^^^^^^^ @@ -315,6 +336,8 @@ fn main() { (&Struct).consume(); //^^^^^^^* (&Struct).by_ref(); + //^^^^^^^& + //^^^^^^^* (&mut Struct).consume(); //^^^^^^^^^^^* @@ -322,6 +345,8 @@ fn main() { //^^^^^^^^^^^& //^^^^^^^^^^^* (&mut Struct).by_ref_mut(); + //^^^^^^^^^^^&mut $ + //^^^^^^^^^^^* // Check that block-like expressions don't duplicate hints let _: &mut [u32] = (&mut []); @@ -360,6 +385,19 @@ fn main() { (()) == {()}; // ^^& // ^^^^& + let closure: dyn Fn = || (); + closure(); + //^^^^^^^( + //^^^^^^^& + //^^^^^^^) + Struct[0]; + //^^^^^^( + //^^^^^^& + //^^^^^^) + &mut Struct[0]; + //^^^^^^( + //^^^^^^&mut $ + //^^^^^^) } #[derive(Copy, Clone)] @@ -369,8 +407,13 @@ impl Struct { fn by_ref(&self) {} fn by_ref_mut(&mut self) {} } +struct StructMut; +impl core::ops::Index for Struct { + type Output = (); +} +impl core::ops::IndexMut for Struct {} "#, - ) + ); } #[test] @@ -382,7 +425,7 @@ impl Struct { ..DISABLED_CONFIG }, r#" -//- minicore: coerce_unsized, fn, eq +//- minicore: coerce_unsized, fn, eq, index fn main() { Struct.consume(); @@ -396,6 +439,10 @@ fn main() { //^^^^^^^) //^^^^^^^.* (&Struct).by_ref(); + //^^^^^^^( + //^^^^^^^) + //^^^^^^^.* + //^^^^^^^.& (&mut Struct).consume(); //^^^^^^^^^^^( @@ -407,6 +454,10 @@ fn main() { //^^^^^^^^^^^.* //^^^^^^^^^^^.& (&mut Struct).by_ref_mut(); + //^^^^^^^^^^^( + //^^^^^^^^^^^) + //^^^^^^^^^^^.* + //^^^^^^^^^^^.&mut // Check that block-like expressions don't duplicate hints let _: &mut [u32] = (&mut []); @@ -457,6 +508,13 @@ fn main() { (()) == {()}; // ^^.& // ^^^^.& + let closure: dyn Fn = || (); + closure(); + //^^^^^^^.& + Struct[0]; + //^^^^^^.& + &mut Struct[0]; + //^^^^^^.&mut } #[derive(Copy, Clone)] @@ -466,6 +524,11 @@ impl Struct { fn by_ref(&self) {} fn by_ref_mut(&mut self) {} } +struct StructMut; +impl core::ops::Index for Struct { + type Output = (); +} +impl core::ops::IndexMut for Struct {} "#, ); } diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs index 6a50927333d4f..07b9f9cc1fff6 100644 --- a/crates/ide/src/inlay_hints/bind_pat.rs +++ b/crates/ide/src/inlay_hints/bind_pat.rs @@ -3,7 +3,7 @@ //! fn f(a: i32, b: i32) -> i32 { a + b } //! let _x /* i32 */= f(4, 4); //! ``` -use hir::{Semantics, TypeInfo}; +use hir::Semantics; use ide_db::{base_db::FileId, famous_defs::FamousDefs, RootDatabase}; use itertools::Itertools; @@ -12,9 +12,10 @@ use syntax::{ match_ast, }; -use crate::{inlay_hints::closure_has_block_body, InlayHint, InlayHintsConfig, InlayKind}; - -use super::label_of_ty; +use crate::{ + inlay_hints::{closure_has_block_body, label_of_ty, ty_to_text_edit}, + InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, +}; pub(super) fn hints( acc: &mut Vec, @@ -27,15 +28,45 @@ pub(super) fn hints( return None; } + let parent = pat.syntax().parent()?; + let type_ascriptable = match_ast! { + match parent { + ast::Param(it) => { + if it.ty().is_some() { + return None; + } + Some(it.colon_token()) + }, + ast::LetStmt(it) => { + if config.hide_closure_initialization_hints { + if let Some(ast::Expr::ClosureExpr(closure)) = it.initializer() { + if closure_has_block_body(&closure) { + return None; + } + } + } + if it.ty().is_some() { + return None; + } + Some(it.colon_token()) + }, + _ => None + } + }; + let descended = sema.descend_node_into_attributes(pat.clone()).pop(); let desc_pat = descended.as_ref().unwrap_or(pat); - let ty = sema.type_of_pat(&desc_pat.clone().into())?.original; + let ty = sema.type_of_binding_in_pat(desc_pat)?; - if should_not_display_type_hint(sema, config, pat, &ty) { + if ty.is_unknown() { return None; } - let label = label_of_ty(famous_defs, config, ty)?; + if sema.resolve_bind_pat_to_const(pat).is_some() { + return None; + } + + let mut label = label_of_ty(famous_defs, config, &ty)?; if config.hide_named_constructor_hints && is_named_constructor(sema, pat, &label.to_string()).is_some() @@ -43,69 +74,46 @@ pub(super) fn hints( return None; } + let text_edit = if let Some(colon_token) = &type_ascriptable { + ty_to_text_edit( + sema, + desc_pat.syntax(), + &ty, + colon_token + .as_ref() + .map_or_else(|| pat.syntax().text_range(), |t| t.text_range()) + .end(), + if colon_token.is_some() { String::new() } else { String::from(": ") }, + ) + } else { + None + }; + + let render_colons = config.render_colons && !matches!(type_ascriptable, Some(Some(_))); + if render_colons { + label.prepend_str(": "); + } + + let text_range = match pat.name() { + Some(name) => name.syntax().text_range(), + None => pat.syntax().text_range(), + }; acc.push(InlayHint { - range: match pat.name() { - Some(name) => name.syntax().text_range(), - None => pat.syntax().text_range(), + range: match type_ascriptable { + Some(Some(t)) => text_range.cover(t.text_range()), + _ => text_range, }, kind: InlayKind::Type, label, + text_edit, + position: InlayHintPosition::After, + pad_left: !render_colons, + pad_right: false, }); Some(()) } -fn should_not_display_type_hint( - sema: &Semantics<'_, RootDatabase>, - config: &InlayHintsConfig, - bind_pat: &ast::IdentPat, - pat_ty: &hir::Type, -) -> bool { - let db = sema.db; - - if pat_ty.is_unknown() { - return true; - } - - if sema.resolve_bind_pat_to_const(bind_pat).is_some() { - return true; - } - - for node in bind_pat.syntax().ancestors() { - match_ast! { - match node { - ast::LetStmt(it) => { - if config.hide_closure_initialization_hints { - if let Some(ast::Expr::ClosureExpr(closure)) = it.initializer() { - if closure_has_block_body(&closure) { - return true; - } - } - } - return it.ty().is_some() - }, - // FIXME: We might wanna show type hints in parameters for non-top level patterns as well - ast::Param(it) => return it.ty().is_some(), - ast::MatchArm(_) => return pat_is_enum_variant(db, bind_pat, pat_ty), - ast::LetExpr(_) => return pat_is_enum_variant(db, bind_pat, pat_ty), - ast::IfExpr(_) => return false, - ast::WhileExpr(_) => return false, - ast::ForExpr(it) => { - // We *should* display hint only if user provided "in {expr}" and we know the type of expr (and it's not unit). - // Type of expr should be iterable. - return it.in_token().is_none() || - it.iterable() - .and_then(|iterable_expr| sema.type_of_expr(&iterable_expr)) - .map(TypeInfo::original) - .map_or(true, |iterable_ty| iterable_ty.is_unknown() || iterable_ty.is_unit()) - }, - _ => (), - } - } - } - false -} - fn is_named_constructor( sema: &Semantics<'_, RootDatabase>, pat: &ast::IdentPat, @@ -159,30 +167,20 @@ fn is_named_constructor( (ctor_name == ty_name).then_some(()) } -fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &hir::Type) -> bool { - if let Some(hir::Adt::Enum(enum_data)) = pat_ty.as_adt() { - let pat_text = bind_pat.to_string(); - enum_data - .variants(db) - .into_iter() - .map(|variant| variant.name(db).to_smol_str()) - .any(|enum_name| enum_name == pat_text) - } else { - false - } -} - #[cfg(test)] mod tests { // This module also contains tests for super::closure_ret + use expect_test::expect; + use hir::ClosureStyle; use syntax::{TextRange, TextSize}; use test_utils::extract_annotations; - use crate::{fixture, inlay_hints::InlayHintsConfig}; + use crate::{fixture, inlay_hints::InlayHintsConfig, ClosureReturnTypeHints}; - use crate::inlay_hints::tests::{check, check_with_config, DISABLED_CONFIG, TEST_CONFIG}; - use crate::ClosureReturnTypeHints; + use crate::inlay_hints::tests::{ + check, check_edit, check_no_edit, check_with_config, DISABLED_CONFIG, TEST_CONFIG, + }; #[track_caller] fn check_types(ra_fixture: &str) { @@ -235,7 +233,7 @@ fn main() { let zz_ref = &zz; //^^^^^^ &Test let test = || zz; - //^^^^ || -> Test + //^^^^ impl FnOnce() -> Test }"#, ); } @@ -528,24 +526,7 @@ fn main() { struct Test { a: Option, b: u8 } fn main() { - let test = Some(Test { a: Some(3), b: 1 }); - //^^^^ Option - if let None = &test {}; - if let test = &test {}; - //^^^^ &Option - if let Some(test) = &test {}; - //^^^^ &Test - if let Some(Test { a, b }) = &test {}; - //^ &Option ^ &u8 - if let Some(Test { a: x, b: y }) = &test {}; - //^ &Option ^ &u8 - if let Some(Test { a: Some(x), b: y }) = &test {}; - //^ &u32 ^ &u8 - if let Some(Test { a: None, b: y }) = &test {}; - //^ &u8 - if let Some(Test { b: y, .. }) = &test {}; - //^ &u8 - if test == None {} + }"#, ); } @@ -560,8 +541,8 @@ struct Test { a: Option, b: u8 } fn main() { let test = Some(Test { a: Some(3), b: 1 }); //^^^^ Option - while let Some(Test { a: Some(x), b: y }) = &test {}; - //^ &u32 ^ &u8 + while let Some(Test { a: Some(x), b: y }) = &test {}; + //^ &u32 ^ &u8 }"#, ); } @@ -753,7 +734,7 @@ fn main() { let func = times2; // ^^^^ fn times2(i32) -> i32 let closure = |x: i32| x * 2; - // ^^^^^^^ |i32| -> i32 + // ^^^^^^^ impl Fn(i32) -> i32 } fn fallible() -> ControlFlow<()> { @@ -811,49 +792,90 @@ fn fallible() -> ControlFlow<()> { } #[test] - fn closures() { - check( + fn closure_style() { + check_with_config( + InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, r#" +//- minicore: fn fn main() { - let mut start = 0; - //^^^^^ i32 - (0..2).for_each(|increment | { start += increment; }); - //^^^^^^^^^ i32 - - let multiply = - //^^^^^^^^ |i32, i32| -> i32 - | a, b| a * b - //^ i32 ^ i32 - - ; - - let _: i32 = multiply(1, 2); - //^ a ^ b - let multiply_ref = &multiply; - //^^^^^^^^^^^^ &|i32, i32| -> i32 - - let return_42 = || 42; - //^^^^^^^^^ || -> i32 - || { 42 }; - //^^ i32 -}"#, + let x = || 2; + //^ impl Fn() -> i32 + let y = |t: i32| x() + t; + //^ impl Fn(i32) -> i32 + let mut t = 5; + //^ i32 + let z = |k: i32| { t += k; }; + //^ impl FnMut(i32) + let p = (y, z); + //^ (impl Fn(i32) -> i32, impl FnMut(i32)) +} + "#, ); - } - - #[test] - fn return_type_hints_for_closure_without_block() { check_with_config( InlayHintsConfig { - closure_return_type_hints: ClosureReturnTypeHints::Always, + type_hints: true, + closure_style: ClosureStyle::RANotation, ..DISABLED_CONFIG }, r#" +//- minicore: fn fn main() { - let a = || { 0 }; - //^^ i32 - let b = || 0; - //^^ i32 -}"#, + let x = || 2; + //^ || -> i32 + let y = |t: i32| x() + t; + //^ |i32| -> i32 + let mut t = 5; + //^ i32 + let z = |k: i32| { t += k; }; + //^ |i32| -> () + let p = (y, z); + //^ (|i32| -> i32, |i32| -> ()) +} + "#, + ); + check_with_config( + InlayHintsConfig { + type_hints: true, + closure_style: ClosureStyle::ClosureWithId, + ..DISABLED_CONFIG + }, + r#" +//- minicore: fn +fn main() { + let x = || 2; + //^ {closure#0} + let y = |t: i32| x() + t; + //^ {closure#1} + let mut t = 5; + //^ i32 + let z = |k: i32| { t += k; }; + //^ {closure#2} + let p = (y, z); + //^ ({closure#1}, {closure#2}) +} + "#, + ); + check_with_config( + InlayHintsConfig { + type_hints: true, + closure_style: ClosureStyle::Hide, + ..DISABLED_CONFIG + }, + r#" +//- minicore: fn +fn main() { + let x = || 2; + //^ … + let y = |t: i32| x() + t; + //^ … + let mut t = 5; + //^ i32 + let z = |k: i32| { t += k; }; + //^ … + let p = (y, z); + //^ (…, …) +} + "#, ); } @@ -871,13 +893,13 @@ fn main() { let multiple_2 = |x: i32| { x * 2 }; let multiple_2 = |x: i32| x * 2; - // ^^^^^^^^^^ |i32| -> i32 + // ^^^^^^^^^^ impl Fn(i32) -> i32 let (not) = (|x: bool| { !x }); - // ^^^ |bool| -> bool + // ^^^ impl Fn(bool) -> bool let (is_zero, _b) = (|x: usize| { x == 0 }, false); - // ^^^^^^^ |usize| -> bool + // ^^^^^^^ impl Fn(usize) -> bool // ^^ bool let plus_one = |x| { x + 1 }; @@ -923,4 +945,160 @@ fn main() { }"#, ); } + + #[test] + fn edit_for_let_stmt() { + check_edit( + TEST_CONFIG, + r#" +struct S(T); +fn test(v: S<(S, S<()>)>, f: F) { + let a = v; + let S((b, c)) = v; + let a @ S((b, c)) = v; + let a = f; +} +"#, + expect![[r#" + struct S(T); + fn test(v: S<(S, S<()>)>, f: F) { + let a: S<(S, S<()>)> = v; + let S((b, c)) = v; + let a @ S((b, c)): S<(S, S<()>)> = v; + let a: F = f; + } + "#]], + ); + } + + #[test] + fn edit_for_closure_param() { + check_edit( + TEST_CONFIG, + r#" +fn test(t: T) { + let f = |a, b, c| {}; + let result = f(42, "", t); +} +"#, + expect![[r#" + fn test(t: T) { + let f = |a: i32, b: &str, c: T| {}; + let result: () = f(42, "", t); + } + "#]], + ); + } + + #[test] + fn edit_for_closure_ret() { + check_edit( + TEST_CONFIG, + r#" +struct S(T); +fn test() { + let f = || { 3 }; + let f = |a: S| { S(a) }; +} +"#, + expect![[r#" + struct S(T); + fn test() { + let f = || -> i32 { 3 }; + let f = |a: S| -> S> { S(a) }; + } + "#]], + ); + } + + #[test] + fn edit_prefixes_paths() { + check_edit( + TEST_CONFIG, + r#" +pub struct S(T); +mod middle { + pub struct S(T, U); + pub fn make() -> S, super::S> { loop {} } + + mod inner { + pub struct S(T); + } + + fn test() { + let a = make(); + } +} +"#, + expect![[r#" + pub struct S(T); + mod middle { + pub struct S(T, U); + pub fn make() -> S, super::S> { loop {} } + + mod inner { + pub struct S(T); + } + + fn test() { + let a: S, crate::S> = make(); + } + } + "#]], + ); + } + + #[test] + fn no_edit_for_top_pat_where_type_annotation_is_invalid() { + check_no_edit( + TEST_CONFIG, + r#" +fn test() { + if let a = 42 {} + while let a = 42 {} + match 42 { + a => (), + } +} +"#, + ) + } + + #[test] + fn no_edit_for_opaque_type() { + check_no_edit( + TEST_CONFIG, + r#" +trait Trait {} +struct S(T); +fn foo() -> impl Trait {} +fn bar() -> S {} +fn test() { + let a = foo(); + let a = bar(); + let f = || { foo() }; + let f = || { bar() }; +} +"#, + ); + } + + #[test] + fn no_edit_for_closure_return_without_body_block() { + // We can lift this limitation; see FIXME in closure_ret module. + let config = InlayHintsConfig { + closure_return_type_hints: ClosureReturnTypeHints::Always, + ..TEST_CONFIG + }; + check_no_edit( + config, + r#" +struct S(T); +fn test() { + let f = || 3; + let f = |a: S| S(a); +} +"#, + ); + } } diff --git a/crates/ide/src/inlay_hints/binding_mode.rs b/crates/ide/src/inlay_hints/binding_mode.rs index 5d9729263c270..343cf17e50e0c 100644 --- a/crates/ide/src/inlay_hints/binding_mode.rs +++ b/crates/ide/src/inlay_hints/binding_mode.rs @@ -7,7 +7,7 @@ use ide_db::RootDatabase; use syntax::ast::{self, AstNode}; -use crate::{InlayHint, InlayHintsConfig, InlayKind}; +use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind}; pub(super) fn hints( acc: &mut Vec, @@ -49,7 +49,15 @@ pub(super) fn hints( (true, false) => "&", _ => return, }; - acc.push(InlayHint { range, kind: InlayKind::BindingMode, label: r.to_string().into() }); + acc.push(InlayHint { + range, + kind: InlayKind::BindingMode, + label: r.to_string().into(), + text_edit: None, + position: InlayHintPosition::Before, + pad_left: false, + pad_right: mut_reference, + }); }); match pat { ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => { @@ -63,11 +71,21 @@ pub(super) fn hints( range: pat.syntax().text_range(), kind: InlayKind::BindingMode, label: bm.to_string().into(), + text_edit: None, + position: InlayHintPosition::Before, + pad_left: false, + pad_right: true, }); } ast::Pat::OrPat(pat) if !pattern_adjustments.is_empty() && outer_paren_pat.is_none() => { - acc.push(InlayHint::opening_paren(pat.syntax().text_range())); - acc.push(InlayHint::closing_paren(pat.syntax().text_range())); + acc.push(InlayHint::opening_paren_before( + InlayKind::BindingMode, + pat.syntax().text_range(), + )); + acc.push(InlayHint::closing_paren_after( + InlayKind::BindingMode, + pat.syntax().text_range(), + )); } _ => (), } @@ -142,7 +160,6 @@ struct Struct { field: &'static str, } fn foo(s @ Struct { field, .. }: &Struct) {} - //^^^^^^^^^^^^^^^^^^^^^^^^ref //^^^^^^^^^^^^^^^^^^^^& //^^^^^ref "#, diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs index 1e1771259b1ba..ce1e03a069b24 100644 --- a/crates/ide/src/inlay_hints/chaining.rs +++ b/crates/ide/src/inlay_hints/chaining.rs @@ -5,7 +5,7 @@ use syntax::{ Direction, NodeOrToken, SyntaxKind, T, }; -use crate::{FileId, InlayHint, InlayHintsConfig, InlayKind}; +use crate::{FileId, InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind}; use super::label_of_ty; @@ -60,7 +60,11 @@ pub(super) fn hints( acc.push(InlayHint { range: expr.syntax().text_range(), kind: InlayKind::Chaining, - label: label_of_ty(famous_defs, config, ty)?, + label: label_of_ty(famous_defs, config, &ty)?, + text_edit: None, + position: InlayHintPosition::After, + pad_left: true, + pad_right: false, }); } } @@ -103,6 +107,9 @@ fn main() { [ InlayHint { range: 147..172, + position: After, + pad_left: true, + pad_right: false, kind: Chaining, label: [ "", @@ -120,9 +127,13 @@ fn main() { }, "", ], + text_edit: None, }, InlayHint { range: 147..154, + position: After, + pad_left: true, + pad_right: false, kind: Chaining, label: [ "", @@ -140,6 +151,7 @@ fn main() { }, "", ], + text_edit: None, }, ] "#]], @@ -188,6 +200,9 @@ fn main() { [ InlayHint { range: 143..190, + position: After, + pad_left: true, + pad_right: false, kind: Chaining, label: [ "", @@ -205,9 +220,13 @@ fn main() { }, "", ], + text_edit: None, }, InlayHint { range: 143..179, + position: After, + pad_left: true, + pad_right: false, kind: Chaining, label: [ "", @@ -225,6 +244,7 @@ fn main() { }, "", ], + text_edit: None, }, ] "#]], @@ -257,6 +277,9 @@ fn main() { [ InlayHint { range: 143..190, + position: After, + pad_left: true, + pad_right: false, kind: Chaining, label: [ "", @@ -274,9 +297,13 @@ fn main() { }, "", ], + text_edit: None, }, InlayHint { range: 143..179, + position: After, + pad_left: true, + pad_right: false, kind: Chaining, label: [ "", @@ -294,6 +321,7 @@ fn main() { }, "", ], + text_edit: None, }, ] "#]], @@ -327,6 +355,9 @@ fn main() { [ InlayHint { range: 246..283, + position: After, + pad_left: true, + pad_right: false, kind: Chaining, label: [ "", @@ -357,9 +388,13 @@ fn main() { }, ">", ], + text_edit: None, }, InlayHint { range: 246..265, + position: After, + pad_left: true, + pad_right: false, kind: Chaining, label: [ "", @@ -390,6 +425,7 @@ fn main() { }, ">", ], + text_edit: None, }, ] "#]], @@ -425,6 +461,9 @@ fn main() { [ InlayHint { range: 174..241, + position: After, + pad_left: true, + pad_right: false, kind: Chaining, label: [ "impl ", @@ -435,7 +474,7 @@ fn main() { file_id: FileId( 1, ), - range: 3415..3423, + range: 9332..9340, }, ), tooltip: "", @@ -448,16 +487,20 @@ fn main() { file_id: FileId( 1, ), - range: 3447..3451, + range: 9364..9368, }, ), tooltip: "", }, " = ()>", ], + text_edit: None, }, InlayHint { range: 174..224, + position: After, + pad_left: true, + pad_right: false, kind: Chaining, label: [ "impl ", @@ -468,7 +511,7 @@ fn main() { file_id: FileId( 1, ), - range: 3415..3423, + range: 9332..9340, }, ), tooltip: "", @@ -481,16 +524,20 @@ fn main() { file_id: FileId( 1, ), - range: 3447..3451, + range: 9364..9368, }, ), tooltip: "", }, " = ()>", ], + text_edit: None, }, InlayHint { range: 174..206, + position: After, + pad_left: true, + pad_right: false, kind: Chaining, label: [ "impl ", @@ -501,7 +548,7 @@ fn main() { file_id: FileId( 1, ), - range: 3415..3423, + range: 9332..9340, }, ), tooltip: "", @@ -514,16 +561,20 @@ fn main() { file_id: FileId( 1, ), - range: 3447..3451, + range: 9364..9368, }, ), tooltip: "", }, " = ()>", ], + text_edit: None, }, InlayHint { range: 174..189, + position: After, + pad_left: true, + pad_right: false, kind: Chaining, label: [ "&mut ", @@ -541,6 +592,7 @@ fn main() { }, "", ], + text_edit: None, }, ] "#]], @@ -573,6 +625,9 @@ fn main() { [ InlayHint { range: 124..130, + position: After, + pad_left: true, + pad_right: false, kind: Type, label: [ "", @@ -590,9 +645,22 @@ fn main() { }, "", ], + text_edit: Some( + TextEdit { + indels: [ + Indel { + insert: ": Struct", + delete: 130..130, + }, + ], + }, + ), }, InlayHint { range: 145..185, + position: After, + pad_left: true, + pad_right: false, kind: Chaining, label: [ "", @@ -610,9 +678,13 @@ fn main() { }, "", ], + text_edit: None, }, InlayHint { range: 145..168, + position: After, + pad_left: true, + pad_right: false, kind: Chaining, label: [ "", @@ -630,9 +702,13 @@ fn main() { }, "", ], + text_edit: None, }, InlayHint { range: 222..228, + position: Before, + pad_left: false, + pad_right: true, kind: Parameter, label: [ InlayHintLabelPart { @@ -648,6 +724,7 @@ fn main() { tooltip: "", }, ], + text_edit: None, }, ] "#]], diff --git a/crates/ide/src/inlay_hints/closing_brace.rs b/crates/ide/src/inlay_hints/closing_brace.rs index 14c11be54ef54..2cefd5acdc2e4 100644 --- a/crates/ide/src/inlay_hints/closing_brace.rs +++ b/crates/ide/src/inlay_hints/closing_brace.rs @@ -10,7 +10,7 @@ use syntax::{ match_ast, SyntaxKind, SyntaxNode, T, }; -use crate::{FileId, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind}; +use crate::{FileId, InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind}; pub(super) fn hints( acc: &mut Vec, @@ -35,7 +35,7 @@ pub(super) fn hints( let ty = imp.self_ty(sema.db); let trait_ = imp.trait_(sema.db); let hint_text = match trait_ { - Some(tr) => format!("impl {} for {}", tr.name(sema.db), ty.display_truncated(sema.db, config.max_length)), + Some(tr) => format!("impl {} for {}", tr.name(sema.db).display(sema.db), ty.display_truncated(sema.db, config.max_length)), None => format!("impl {}", ty.display_truncated(sema.db, config.max_length)), }; (hint_text, None) @@ -112,6 +112,10 @@ pub(super) fn hints( range: closing_token.text_range(), kind: InlayKind::ClosingBrace, label: InlayHintLabel::simple(label, None, linked_location), + text_edit: None, + position: InlayHintPosition::After, + pad_left: true, + pad_right: false, }); None diff --git a/crates/ide/src/inlay_hints/closure_captures.rs b/crates/ide/src/inlay_hints/closure_captures.rs new file mode 100644 index 0000000000000..9d5defcbb71a9 --- /dev/null +++ b/crates/ide/src/inlay_hints/closure_captures.rs @@ -0,0 +1,207 @@ +//! Implementation of "closure return type" inlay hints. +//! +//! Tests live in [`bind_pat`][super::bind_pat] module. +use ide_db::{base_db::FileId, famous_defs::FamousDefs}; +use syntax::ast::{self, AstNode}; +use text_edit::{TextRange, TextSize}; + +use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind}; + +pub(super) fn hints( + acc: &mut Vec, + FamousDefs(sema, _): &FamousDefs<'_, '_>, + config: &InlayHintsConfig, + _file_id: FileId, + closure: ast::ClosureExpr, +) -> Option<()> { + if !config.closure_capture_hints { + return None; + } + let ty = &sema.type_of_expr(&closure.clone().into())?.original; + let c = ty.as_closure()?; + let captures = c.captured_items(sema.db); + + if captures.is_empty() { + return None; + } + + let move_kw_range = match closure.move_token() { + Some(t) => t.text_range(), + None => { + let range = closure.syntax().first_token()?.prev_token()?.text_range(); + let range = TextRange::new(range.end() - TextSize::from(1), range.end()); + acc.push(InlayHint { + range, + kind: InlayKind::ClosureCapture, + label: InlayHintLabel::simple("move", None, None), + text_edit: None, + position: InlayHintPosition::After, + pad_left: false, + pad_right: false, + }); + range + } + }; + acc.push(InlayHint { + range: move_kw_range, + kind: InlayKind::ClosureCapture, + label: InlayHintLabel::from("("), + text_edit: None, + position: InlayHintPosition::After, + pad_left: false, + pad_right: false, + }); + let last = captures.len() - 1; + for (idx, capture) in captures.into_iter().enumerate() { + let local = capture.local(); + let source = local.primary_source(sema.db); + + // force cache the source file, otherwise sema lookup will potentially panic + _ = sema.parse_or_expand(source.file()); + + acc.push(InlayHint { + range: move_kw_range, + kind: InlayKind::ClosureCapture, + label: InlayHintLabel::simple( + format!( + "{}{}", + match capture.kind() { + hir::CaptureKind::SharedRef => "&", + hir::CaptureKind::UniqueSharedRef => "&unique ", + hir::CaptureKind::MutableRef => "&mut ", + hir::CaptureKind::Move => "", + }, + capture.display_place(sema.db) + ), + None, + source.name().and_then(|name| name.syntax().original_file_range_opt(sema.db)), + ), + text_edit: None, + position: InlayHintPosition::After, + pad_left: false, + pad_right: false, + }); + + if idx != last { + acc.push(InlayHint { + range: move_kw_range, + kind: InlayKind::ClosureCapture, + label: InlayHintLabel::simple(", ", None, None), + text_edit: None, + position: InlayHintPosition::After, + pad_left: false, + pad_right: false, + }); + } + } + acc.push(InlayHint { + range: move_kw_range, + kind: InlayKind::ClosureCapture, + label: InlayHintLabel::from(")"), + text_edit: None, + position: InlayHintPosition::After, + pad_left: false, + pad_right: true, + }); + + Some(()) +} + +#[cfg(test)] +mod tests { + use crate::{ + inlay_hints::tests::{check_with_config, DISABLED_CONFIG}, + InlayHintsConfig, + }; + + #[test] + fn all_capture_kinds() { + check_with_config( + InlayHintsConfig { closure_capture_hints: true, ..DISABLED_CONFIG }, + r#" +//- minicore: copy, derive + + +#[derive(Copy, Clone)] +struct Copy; + +struct NonCopy; + +fn main() { + let foo = Copy; + let bar = NonCopy; + let mut baz = NonCopy; + let qux = &mut NonCopy; + || { +// ^ move +// ^ ( +// ^ &foo +// ^ , $ +// ^ bar +// ^ , $ +// ^ baz +// ^ , $ +// ^ qux +// ^ ) + foo; + bar; + baz; + qux; + }; + || { +// ^ move +// ^ ( +// ^ &foo +// ^ , $ +// ^ &bar +// ^ , $ +// ^ &baz +// ^ , $ +// ^ &qux +// ^ ) + &foo; + &bar; + &baz; + &qux; + }; + || { +// ^ move +// ^ ( +// ^ &mut baz +// ^ ) + &mut baz; + }; + || { +// ^ move +// ^ ( +// ^ &mut baz +// ^ , $ +// ^ &mut *qux +// ^ ) + baz = NonCopy; + *qux = NonCopy; + }; +} +"#, + ); + } + + #[test] + fn move_token() { + check_with_config( + InlayHintsConfig { closure_capture_hints: true, ..DISABLED_CONFIG }, + r#" +//- minicore: copy, derive +fn main() { + let foo = u32; + move || { +// ^^^^ ( +// ^^^^ foo +// ^^^^ ) + foo; + }; +} +"#, + ); + } +} diff --git a/crates/ide/src/inlay_hints/closure_ret.rs b/crates/ide/src/inlay_hints/closure_ret.rs index f03a18b8e960f..3b41db0f13d0a 100644 --- a/crates/ide/src/inlay_hints/closure_ret.rs +++ b/crates/ide/src/inlay_hints/closure_ret.rs @@ -1,14 +1,14 @@ //! Implementation of "closure return type" inlay hints. +//! +//! Tests live in [`bind_pat`][super::bind_pat] module. use ide_db::{base_db::FileId, famous_defs::FamousDefs}; use syntax::ast::{self, AstNode}; use crate::{ - inlay_hints::closure_has_block_body, ClosureReturnTypeHints, InlayHint, InlayHintsConfig, - InlayKind, + inlay_hints::{closure_has_block_body, label_of_ty, ty_to_text_edit}, + ClosureReturnTypeHints, InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, }; -use super::label_of_ty; - pub(super) fn hints( acc: &mut Vec, famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, @@ -20,29 +20,81 @@ pub(super) fn hints( return None; } - if closure.ret_type().is_some() { - return None; - } + let ret_type = closure.ret_type().map(|rt| (rt.thin_arrow_token(), rt.ty().is_some())); + let arrow = match ret_type { + Some((_, true)) => return None, + Some((arrow, _)) => arrow, + None => None, + }; - if !closure_has_block_body(&closure) - && config.closure_return_type_hints == ClosureReturnTypeHints::WithBlock - { + let has_block_body = closure_has_block_body(&closure); + if !has_block_body && config.closure_return_type_hints == ClosureReturnTypeHints::WithBlock { return None; } let param_list = closure.param_list()?; let closure = sema.descend_node_into_attributes(closure).pop()?; - let ty = sema.type_of_expr(&ast::Expr::ClosureExpr(closure))?.adjusted(); + let ty = sema.type_of_expr(&ast::Expr::ClosureExpr(closure.clone()))?.adjusted(); let callable = ty.as_callable(sema.db)?; let ty = callable.return_type(); - if ty.is_unit() { + if arrow.is_none() && ty.is_unit() { return None; } + + let mut label = label_of_ty(famous_defs, config, &ty)?; + + if arrow.is_none() { + label.prepend_str(" -> "); + } + // FIXME?: We could provide text edit to insert braces for closures with non-block body. + let text_edit = if has_block_body { + ty_to_text_edit( + sema, + closure.syntax(), + &ty, + arrow + .as_ref() + .map_or_else(|| param_list.syntax().text_range(), |t| t.text_range()) + .end(), + if arrow.is_none() { String::from(" -> ") } else { String::new() }, + ) + } else { + None + }; + acc.push(InlayHint { range: param_list.syntax().text_range(), - kind: InlayKind::ClosureReturnType, - label: label_of_ty(famous_defs, config, ty)?, + kind: InlayKind::Type, + label, + text_edit, + position: InlayHintPosition::After, + pad_left: false, + pad_right: false, }); Some(()) } + +#[cfg(test)] +mod tests { + use crate::inlay_hints::tests::{check_with_config, DISABLED_CONFIG}; + + use super::*; + + #[test] + fn return_type_hints_for_closure_without_block() { + check_with_config( + InlayHintsConfig { + closure_return_type_hints: ClosureReturnTypeHints::Always, + ..DISABLED_CONFIG + }, + r#" +fn main() { + let a = || { 0 }; + //^^ -> i32 + let b = || 0; + //^^ -> i32 +}"#, + ); + } +} diff --git a/crates/ide/src/inlay_hints/discriminant.rs b/crates/ide/src/inlay_hints/discriminant.rs index 67eaa553ada4e..c4d2ac75cfa97 100644 --- a/crates/ide/src/inlay_hints/discriminant.rs +++ b/crates/ide/src/inlay_hints/discriminant.rs @@ -9,7 +9,8 @@ use ide_db::{base_db::FileId, famous_defs::FamousDefs, RootDatabase}; use syntax::ast::{self, AstNode, HasName}; use crate::{ - DiscriminantHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind, InlayTooltip, + DiscriminantHints, InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind, + InlayTooltip, }; pub(super) fn enum_hints( @@ -19,21 +20,23 @@ pub(super) fn enum_hints( _: FileId, enum_: ast::Enum, ) -> Option<()> { - let enabled = match config.discriminant_hints { - DiscriminantHints::Always => true, - DiscriminantHints::Fieldless => { - !sema.to_def(&enum_)?.is_data_carrying(sema.db) - || enum_.variant_list()?.variants().any(|v| v.expr().is_some()) - } - DiscriminantHints::Never => false, - }; - if !enabled { + if let DiscriminantHints::Never = config.discriminant_hints { + return None; + } + + let def = sema.to_def(&enum_)?; + let data_carrying = def.is_data_carrying(sema.db); + if matches!(config.discriminant_hints, DiscriminantHints::Fieldless) && data_carrying { + return None; + } + // data carrying enums without a primitive repr have no stable discriminants + if data_carrying && def.repr(sema.db).map_or(true, |r| r.int.is_none()) { return None; } for variant in enum_.variant_list()?.variants() { variant_hints(acc, sema, &variant); } - None + Some(()) } fn variant_hints( @@ -41,10 +44,11 @@ fn variant_hints( sema: &Semantics<'_, RootDatabase>, variant: &ast::Variant, ) -> Option<()> { - if variant.eq_token().is_some() { + if variant.expr().is_some() { return None; } + let eq_token = variant.eq_token(); let name = variant.name()?; let descended = sema.descend_node_into_attributes(variant.clone()).pop(); @@ -52,34 +56,43 @@ fn variant_hints( let v = sema.to_def(desc_pat)?; let d = v.eval(sema.db); + let range = match variant.field_list() { + Some(field_list) => name.syntax().text_range().cover(field_list.syntax().text_range()), + None => name.syntax().text_range(), + }; + let eq_ = if eq_token.is_none() { " =" } else { "" }; + let label = InlayHintLabel::simple( + match d { + Ok(x) => { + if x >= 10 { + format!("{eq_} {x} ({x:#X})") + } else { + format!("{eq_} {x}") + } + } + Err(_) => format!("{eq_} ?"), + }, + Some(InlayTooltip::String(match &d { + Ok(_) => "enum variant discriminant".into(), + Err(e) => format!("{e:?}").into(), + })), + None, + ); acc.push(InlayHint { - range: match variant.field_list() { - Some(field_list) => name.syntax().text_range().cover(field_list.syntax().text_range()), - None => name.syntax().text_range(), + range: match eq_token { + Some(t) => range.cover(t.text_range()), + _ => range, }, kind: InlayKind::Discriminant, - label: InlayHintLabel::simple( - match d { - Ok(x) => { - if x >= 10 { - format!("{x} ({x:#X})") - } else { - format!("{x}") - } - } - Err(_) => "?".into(), - }, - Some(InlayTooltip::String(match &d { - Ok(_) => "enum variant discriminant".into(), - Err(e) => format!("{e:?}").into(), - })), - None, - ), + label, + text_edit: None, + position: InlayHintPosition::After, + pad_left: false, + pad_right: false, }); Some(()) } - #[cfg(test)] mod tests { use crate::inlay_hints::{ @@ -111,30 +124,30 @@ mod tests { check_discriminants( r#" enum Enum { - Variant, -//^^^^^^^0 - Variant1, -//^^^^^^^^1 - Variant2, -//^^^^^^^^2 - Variant5 = 5, - Variant6, -//^^^^^^^^6 + Variant, +// ^^^^^^^ = 0$ + Variant1, +// ^^^^^^^^ = 1$ + Variant2, +// ^^^^^^^^ = 2$ + Variant5 = 5, + Variant6, +// ^^^^^^^^ = 6$ } "#, ); check_discriminants_fieldless( r#" enum Enum { - Variant, -//^^^^^^^0 - Variant1, -//^^^^^^^^1 - Variant2, -//^^^^^^^^2 - Variant5 = 5, - Variant6, -//^^^^^^^^6 + Variant, +// ^^^^^^^ = 0 + Variant1, +// ^^^^^^^^ = 1 + Variant2, +// ^^^^^^^^ = 2 + Variant5 = 5, + Variant6, +// ^^^^^^^^ = 6 } "#, ); @@ -144,26 +157,23 @@ enum Enum { fn datacarrying_mixed() { check_discriminants( r#" +#[repr(u8)] enum Enum { Variant(), - //^^^^^^^^^0 +// ^^^^^^^^^ = 0 Variant1, - //^^^^^^^^1 +// ^^^^^^^^ = 1 Variant2 {}, - //^^^^^^^^^^^2 +// ^^^^^^^^^^^ = 2 Variant3, - //^^^^^^^^3 +// ^^^^^^^^ = 3 Variant5 = 5, Variant6, - //^^^^^^^^6 +// ^^^^^^^^ = 6 } "#, ); - } - - #[test] - fn datacarrying_mixed_fieldless_set() { - check_discriminants_fieldless( + check_discriminants( r#" enum Enum { Variant(), @@ -175,20 +185,20 @@ enum Enum { } "#, ); + } + + #[test] + fn datacarrying_mixed_fieldless_set() { check_discriminants_fieldless( r#" +#[repr(u8)] enum Enum { Variant(), - //^^^^^^^^^0 Variant1, - //^^^^^^^^1 Variant2 {}, - //^^^^^^^^^^^2 Variant3, - //^^^^^^^^3 - Variant5 = 5, + Variant5, Variant6, - //^^^^^^^^6 } "#, ); diff --git a/crates/ide/src/inlay_hints/fn_lifetime_fn.rs b/crates/ide/src/inlay_hints/fn_lifetime_fn.rs index b7182085b312e..5fce11b785a7a 100644 --- a/crates/ide/src/inlay_hints/fn_lifetime_fn.rs +++ b/crates/ide/src/inlay_hints/fn_lifetime_fn.rs @@ -10,7 +10,7 @@ use syntax::{ SyntaxToken, }; -use crate::{InlayHint, InlayHintsConfig, InlayKind, LifetimeElisionHints}; +use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, LifetimeElisionHints}; pub(super) fn hints( acc: &mut Vec, @@ -25,6 +25,10 @@ pub(super) fn hints( range: t.text_range(), kind: InlayKind::Lifetime, label: label.into(), + text_edit: None, + position: InlayHintPosition::After, + pad_left: false, + pad_right: true, }; let param_list = func.param_list()?; @@ -189,12 +193,20 @@ pub(super) fn hints( if is_empty { "" } else { ", " } ) .into(), + text_edit: None, + position: InlayHintPosition::After, + pad_left: false, + pad_right: true, }); } (None, allocated_lifetimes) => acc.push(InlayHint { range: func.name()?.syntax().text_range(), kind: InlayKind::GenericParamList, label: format!("<{}>", allocated_lifetimes.iter().format(", "),).into(), + text_edit: None, + position: InlayHintPosition::After, + pad_left: false, + pad_right: false, }), } Some(()) diff --git a/crates/ide/src/inlay_hints/implicit_static.rs b/crates/ide/src/inlay_hints/implicit_static.rs index 1122ee2e3925d..fc297a8d824f2 100644 --- a/crates/ide/src/inlay_hints/implicit_static.rs +++ b/crates/ide/src/inlay_hints/implicit_static.rs @@ -8,7 +8,7 @@ use syntax::{ SyntaxKind, }; -use crate::{InlayHint, InlayHintsConfig, InlayKind, LifetimeElisionHints}; +use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, LifetimeElisionHints}; pub(super) fn hints( acc: &mut Vec, @@ -34,6 +34,10 @@ pub(super) fn hints( range: t.text_range(), kind: InlayKind::Lifetime, label: "'static".to_owned().into(), + text_edit: None, + position: InlayHintPosition::After, + pad_left: false, + pad_right: true, }); } } diff --git a/crates/ide/src/inlay_hints/param_name.rs b/crates/ide/src/inlay_hints/param_name.rs index 9cdae63241044..c4f43f411753e 100644 --- a/crates/ide/src/inlay_hints/param_name.rs +++ b/crates/ide/src/inlay_hints/param_name.rs @@ -10,7 +10,7 @@ use ide_db::{base_db::FileRange, RootDatabase}; use stdx::to_lower_snake_case; use syntax::ast::{self, AstNode, HasArgList, HasName, UnaryOp}; -use crate::{InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind}; +use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind}; pub(super) fn hints( acc: &mut Vec, @@ -31,16 +31,16 @@ pub(super) fn hints( // Only annotate hints for expressions that exist in the original file let range = sema.original_range_opt(arg.syntax())?; let (param_name, name_syntax) = match param.as_ref()? { - Either::Left(pat) => ("self".to_string(), pat.name()), + Either::Left(pat) => (pat.name()?, pat.name()), Either::Right(pat) => match pat { - ast::Pat::IdentPat(it) => (it.name()?.to_string(), it.name()), + ast::Pat::IdentPat(it) => (it.name()?, it.name()), _ => return None, }, }; Some((name_syntax, param_name, arg, range)) }) .filter(|(_, param_name, arg, _)| { - !should_hide_param_name_hint(sema, &callable, param_name, arg) + !should_hide_param_name_hint(sema, &callable, ¶m_name.text(), arg) }) .map(|(param, param_name, _, FileRange { range, .. })| { let mut linked_location = None; @@ -53,10 +53,17 @@ pub(super) fn hints( } } + let colon = if config.render_colons { ":" } else { "" }; + let label = + InlayHintLabel::simple(format!("{param_name}{colon}"), None, linked_location); InlayHint { range, kind: InlayKind::Parameter, - label: InlayHintLabel::simple(param_name, None, linked_location), + label, + text_edit: None, + position: InlayHintPosition::Before, + pad_left: false, + pad_right: true, } }); diff --git a/crates/ide/src/interpret_function.rs b/crates/ide/src/interpret_function.rs new file mode 100644 index 0000000000000..cbcbb4b09db48 --- /dev/null +++ b/crates/ide/src/interpret_function.rs @@ -0,0 +1,46 @@ +use hir::Semantics; +use ide_db::base_db::SourceDatabaseExt; +use ide_db::RootDatabase; +use ide_db::{base_db::FilePosition, LineIndexDatabase}; +use std::{fmt::Write, time::Instant}; +use syntax::TextRange; +use syntax::{algo::find_node_at_offset, ast, AstNode}; + +// Feature: Interpret Function +// +// |=== +// | Editor | Action Name +// +// | VS Code | **rust-analyzer: Interpret Function** +// |=== +pub(crate) fn interpret_function(db: &RootDatabase, position: FilePosition) -> String { + let start_time = Instant::now(); + let mut result = find_and_interpret(db, position) + .unwrap_or_else(|| "Not inside a function body".to_string()); + let duration = Instant::now() - start_time; + writeln!(result, "").unwrap(); + writeln!(result, "----------------------").unwrap(); + writeln!(result, " Finished in {}s", duration.as_secs_f32()).unwrap(); + result +} + +fn find_and_interpret(db: &RootDatabase, position: FilePosition) -> Option { + let sema = Semantics::new(db); + let source_file = sema.parse(position.file_id); + + let item = find_node_at_offset::(source_file.syntax(), position.offset)?; + let def = match item { + ast::Item::Fn(it) => sema.to_def(&it)?, + _ => return None, + }; + let span_formatter = |file_id, text_range: TextRange| { + let line_col = db.line_index(file_id).line_col(text_range.start()); + let path = &db + .source_root(db.file_source_root(file_id)) + .path_for_file(&file_id) + .map(|x| x.to_string()); + let path = path.as_deref().unwrap_or(""); + format!("file://{path}#{}:{}", line_col.line + 1, line_col.col) + }; + Some(def.eval(db, span_formatter)) +} diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 078b66dd3955f..87e769e423073 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -56,20 +56,24 @@ mod typing; mod view_crate_graph; mod view_hir; mod view_mir; +mod interpret_function; mod view_item_tree; mod shuffle_crate_graph; +mod fetch_crates; -use std::sync::Arc; +use std::ffi::OsStr; use cfg::CfgOptions; +use fetch_crates::CrateInfo; use ide_db::{ base_db::{ salsa::{self, ParallelDatabase}, CrateOrigin, Env, FileLoader, FileSet, SourceDatabase, VfsPath, }, - symbol_index, LineIndexDatabase, + symbol_index, FxHashMap, FxIndexSet, LineIndexDatabase, }; use syntax::SourceFile; +use triomphe::Arc; use crate::navigation_target::{ToNav, TryToNav}; @@ -80,11 +84,14 @@ pub use crate::{ file_structure::{StructureNode, StructureNodeKind}, folding_ranges::{Fold, FoldKind}, highlight_related::{HighlightRelatedConfig, HighlightedRange}, - hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult}, + hover::{ + HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult, + MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, + }, inlay_hints::{ AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints, InlayHint, - InlayHintLabel, InlayHintLabelPart, InlayHintsConfig, InlayKind, InlayTooltip, - LifetimeElisionHints, + InlayHintLabel, InlayHintLabelPart, InlayHintPosition, InlayHintsConfig, InlayKind, + InlayTooltip, LifetimeElisionHints, }, join_lines::JoinLinesConfig, markup::Markup, @@ -154,7 +161,11 @@ impl AnalysisHost { } pub fn update_lru_capacity(&mut self, lru_capacity: Option) { - self.db.update_lru_capacity(lru_capacity); + self.db.update_parse_query_lru_capacity(lru_capacity); + } + + pub fn update_lru_capacities(&mut self, lru_capacities: &FxHashMap, usize>) { + self.db.update_lru_capacities(lru_capacities); } /// Returns a snapshot of the current state, which you can query for @@ -233,14 +244,14 @@ impl Analysis { None, None, cfg_options.clone(), - cfg_options, + None, Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("Analysis::from_single_file has no target layout".into()), + None, ); - change.change_file(file_id, Some(Arc::new(text))); + change.change_file(file_id, Some(Arc::from(text))); change.set_crate_graph(crate_graph); host.apply_change(change); (host.analysis(), file_id) @@ -259,7 +270,7 @@ impl Analysis { } /// Gets the text of the source file. - pub fn file_text(&self, file_id: FileId) -> Cancellable> { + pub fn file_text(&self, file_id: FileId) -> Cancellable> { self.with_db(|db| db.file_text(file_id)) } @@ -313,6 +324,10 @@ impl Analysis { self.with_db(|db| view_mir::view_mir(db, position)) } + pub fn interpret_function(&self, position: FilePosition) -> Cancellable { + self.with_db(|db| interpret_function::interpret_function(db, position)) + } + pub fn view_item_tree(&self, file_id: FileId) -> Cancellable { self.with_db(|db| view_item_tree::view_item_tree(db, file_id)) } @@ -322,6 +337,10 @@ impl Analysis { self.with_db(|db| view_crate_graph::view_crate_graph(db, full)) } + pub fn fetch_crates(&self) -> Cancellable> { + self.with_db(|db| fetch_crates::fetch_crates(db)) + } + pub fn expand_macro(&self, position: FilePosition) -> Cancellable> { self.with_db(|db| expand_macro::expand_macro(db, position)) } @@ -452,12 +471,19 @@ impl Analysis { self.with_db(|db| moniker::moniker(db, position)) } - /// Return URL(s) for the documentation of the symbol under the cursor. + /// Returns URL(s) for the documentation of the symbol under the cursor. + /// # Arguments + /// * `position` - Position in the file. + /// * `target_dir` - Directory where the build output is storeda. pub fn external_docs( &self, position: FilePosition, - ) -> Cancellable> { - self.with_db(|db| doc_links::external_docs(db, &position)) + target_dir: Option<&OsStr>, + sysroot: Option<&OsStr>, + ) -> Cancellable { + self.with_db(|db| { + doc_links::external_docs(db, &position, target_dir, sysroot).unwrap_or_default() + }) } /// Computes parameter information at the given position. @@ -508,6 +534,11 @@ impl Analysis { self.with_db(|db| db.crate_graph()[crate_id].edition) } + /// Returns true if this crate has `no_std` or `no_core` specified. + pub fn is_crate_no_std(&self, crate_id: CrateId) -> Cancellable { + self.with_db(|db| hir::db::DefDatabase::crate_def_map(db, crate_id).is_no_std()) + } + /// Returns the root file of the given crate. pub fn crate_root(&self, crate_id: CrateId) -> Cancellable { self.with_db(|db| db.crate_graph()[crate_id].root_file_id) diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs index 349e79ecfdda0..0d57e63d29c91 100644 --- a/crates/ide/src/moniker.rs +++ b/crates/ide/src/moniker.rs @@ -1,7 +1,7 @@ //! This module generates [moniker](https://microsoft.github.io/language-server-protocol/specifications/lsif/0.6.0/specification/#exportsImports) //! for LSIF and LSP. -use hir::{AsAssocItem, AssocItemContainer, Crate, Name, Semantics}; +use hir::{AsAssocItem, AssocItemContainer, Crate, Semantics}; use ide_db::{ base_db::{CrateOrigin, FilePosition, LangCrateOrigin}, defs::{Definition, IdentClass}, @@ -27,7 +27,7 @@ pub enum MonikerDescriptorKind { #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MonikerDescriptor { - pub name: Name, + pub name: String, pub desc: MonikerDescriptorKind, } @@ -41,11 +41,7 @@ impl ToString for MonikerIdentifier { fn to_string(&self) -> String { match self { MonikerIdentifier { description, crate_name } => { - format!( - "{}::{}", - crate_name, - description.iter().map(|x| x.name.to_string()).join("::") - ) + format!("{}::{}", crate_name, description.iter().map(|x| &x.name).join("::")) } } } @@ -136,7 +132,10 @@ pub(crate) fn def_to_moniker( let krate = module.krate(); let mut description = vec![]; description.extend(module.path_to_root(db).into_iter().filter_map(|x| { - Some(MonikerDescriptor { name: x.name(db)?, desc: MonikerDescriptorKind::Namespace }) + Some(MonikerDescriptor { + name: x.name(db)?.display(db).to_string(), + desc: MonikerDescriptorKind::Namespace, + }) })); // Handle associated items within a trait @@ -147,7 +146,7 @@ pub(crate) fn def_to_moniker( // Because different traits can have functions with the same name, // we have to include the trait name as part of the moniker for uniqueness. description.push(MonikerDescriptor { - name: trait_.name(db), + name: trait_.name(db).display(db).to_string(), desc: MonikerDescriptorKind::Type, }); } @@ -156,14 +155,14 @@ pub(crate) fn def_to_moniker( // we add both the struct name and the trait name to the path if let Some(adt) = impl_.self_ty(db).as_adt() { description.push(MonikerDescriptor { - name: adt.name(db), + name: adt.name(db).display(db).to_string(), desc: MonikerDescriptorKind::Type, }); } if let Some(trait_) = impl_.trait_(db) { description.push(MonikerDescriptor { - name: trait_.name(db), + name: trait_.name(db).display(db).to_string(), desc: MonikerDescriptorKind::Type, }); } @@ -173,7 +172,7 @@ pub(crate) fn def_to_moniker( if let Definition::Field(it) = def { description.push(MonikerDescriptor { - name: it.parent_def(db).name(db), + name: it.parent_def(db).name(db).display(db).to_string(), desc: MonikerDescriptorKind::Type, }); } @@ -191,48 +190,63 @@ pub(crate) fn def_to_moniker( return None; } - MonikerDescriptor { name: local.name(db), desc: MonikerDescriptorKind::Parameter } - } - Definition::Macro(m) => { - MonikerDescriptor { name: m.name(db), desc: MonikerDescriptorKind::Macro } - } - Definition::Function(f) => { - MonikerDescriptor { name: f.name(db), desc: MonikerDescriptorKind::Method } - } - Definition::Variant(v) => { - MonikerDescriptor { name: v.name(db), desc: MonikerDescriptorKind::Type } - } - Definition::Const(c) => { - MonikerDescriptor { name: c.name(db)?, desc: MonikerDescriptorKind::Term } - } - Definition::Trait(trait_) => { - MonikerDescriptor { name: trait_.name(db), desc: MonikerDescriptorKind::Type } - } - Definition::TraitAlias(ta) => { - MonikerDescriptor { name: ta.name(db), desc: MonikerDescriptorKind::Type } - } - Definition::TypeAlias(ta) => { - MonikerDescriptor { name: ta.name(db), desc: MonikerDescriptorKind::TypeParameter } - } - Definition::Module(m) => { - MonikerDescriptor { name: m.name(db)?, desc: MonikerDescriptorKind::Namespace } - } - Definition::BuiltinType(b) => { - MonikerDescriptor { name: b.name(), desc: MonikerDescriptorKind::Type } + MonikerDescriptor { + name: local.name(db).display(db).to_string(), + desc: MonikerDescriptorKind::Parameter, + } } + Definition::Macro(m) => MonikerDescriptor { + name: m.name(db).display(db).to_string(), + desc: MonikerDescriptorKind::Macro, + }, + Definition::Function(f) => MonikerDescriptor { + name: f.name(db).display(db).to_string(), + desc: MonikerDescriptorKind::Method, + }, + Definition::Variant(v) => MonikerDescriptor { + name: v.name(db).display(db).to_string(), + desc: MonikerDescriptorKind::Type, + }, + Definition::Const(c) => MonikerDescriptor { + name: c.name(db)?.display(db).to_string(), + desc: MonikerDescriptorKind::Term, + }, + Definition::Trait(trait_) => MonikerDescriptor { + name: trait_.name(db).display(db).to_string(), + desc: MonikerDescriptorKind::Type, + }, + Definition::TraitAlias(ta) => MonikerDescriptor { + name: ta.name(db).display(db).to_string(), + desc: MonikerDescriptorKind::Type, + }, + Definition::TypeAlias(ta) => MonikerDescriptor { + name: ta.name(db).display(db).to_string(), + desc: MonikerDescriptorKind::TypeParameter, + }, + Definition::Module(m) => MonikerDescriptor { + name: m.name(db)?.display(db).to_string(), + desc: MonikerDescriptorKind::Namespace, + }, + Definition::BuiltinType(b) => MonikerDescriptor { + name: b.name().display(db).to_string(), + desc: MonikerDescriptorKind::Type, + }, Definition::SelfType(imp) => MonikerDescriptor { - name: imp.self_ty(db).as_adt()?.name(db), + name: imp.self_ty(db).as_adt()?.name(db).display(db).to_string(), desc: MonikerDescriptorKind::Type, }, - Definition::Field(it) => { - MonikerDescriptor { name: it.name(db), desc: MonikerDescriptorKind::Term } - } - Definition::Adt(adt) => { - MonikerDescriptor { name: adt.name(db), desc: MonikerDescriptorKind::Type } - } - Definition::Static(s) => { - MonikerDescriptor { name: s.name(db), desc: MonikerDescriptorKind::Meta } - } + Definition::Field(it) => MonikerDescriptor { + name: it.name(db).display(db).to_string(), + desc: MonikerDescriptorKind::Term, + }, + Definition::Adt(adt) => MonikerDescriptor { + name: adt.name(db).display(db).to_string(), + desc: MonikerDescriptorKind::Type, + }, + Definition::Static(s) => MonikerDescriptor { + name: s.name(db).display(db).to_string(), + desc: MonikerDescriptorKind::Meta, + }, }; description.push(name_desc); @@ -245,11 +259,17 @@ pub(crate) fn def_to_moniker( kind: if krate == from_crate { MonikerKind::Export } else { MonikerKind::Import }, package_information: { let (name, repo, version) = match krate.origin(db) { - CrateOrigin::CratesIo { repo, name } => ( + CrateOrigin::Library { repo, name } => (name, repo, krate.version(db)), + CrateOrigin::Local { repo, name } => ( name.unwrap_or(krate.display_name(db)?.canonical_name().to_string()), repo, krate.version(db), ), + CrateOrigin::Rustc { name } => ( + name.clone(), + Some("https://github.com/rust-lang/rust/".to_string()), + Some(format!("https://github.com/rust-lang/rust/compiler/{name}",)), + ), CrateOrigin::Lang(lang) => ( krate.display_name(db)?.canonical_name().to_string(), Some("https://github.com/rust-lang/rust/".to_string()), diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs index 6aae82f981600..385c1b0c00816 100644 --- a/crates/ide/src/navigation_target.rs +++ b/crates/ide/src/navigation_target.rs @@ -4,8 +4,8 @@ use std::fmt; use either::Either; use hir::{ - symbols::FileSymbol, AssocItem, Documentation, FieldSource, HasAttrs, HasSource, HirDisplay, - InFile, LocalSource, ModuleSource, Semantics, + symbols::FileSymbol, AssocItem, Documentation, FieldSource, HasAttrs, HasContainer, HasSource, + HirDisplay, HirFileId, InFile, LocalSource, ModuleSource, }; use ide_db::{ base_db::{FileId, FileRange}, @@ -15,7 +15,7 @@ use ide_db::{defs::Definition, RootDatabase}; use stdx::never; use syntax::{ ast::{self, HasName}, - match_ast, AstNode, SmolStr, SyntaxNode, TextRange, + AstNode, SmolStr, SyntaxNode, TextRange, }; /// `NavigationTarget` represents an element in the editor's UI which you can @@ -45,6 +45,9 @@ pub struct NavigationTarget { pub container_name: Option, pub description: Option, pub docs: Option, + /// In addition to a `name` field, a `NavigationTarget` may also be aliased + /// In such cases we want a `NavigationTarget` to be accessible by its alias + pub alias: Option, } impl fmt::Debug for NavigationTarget { @@ -89,10 +92,9 @@ impl NavigationTarget { pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { let name = module.name(db).map(|it| it.to_smol_str()).unwrap_or_default(); - if let Some(src @ InFile { value, .. }) = &module.declaration_source(db) { - let FileRange { file_id, range: full_range } = src.syntax().original_file_range(db); - let focus_range = - value.name().and_then(|it| orig_focus_range(db, src.file_id, it.syntax())); + if let Some(InFile { value, file_id }) = &module.declaration_source(db) { + let (file_id, full_range, focus_range) = + orig_range_with_focus(db, *file_id, value.syntax(), value.name()); let mut res = NavigationTarget::from_syntax( file_id, name, @@ -128,14 +130,15 @@ impl NavigationTarget { /// Allows `NavigationTarget` to be created from a `NameOwner` pub(crate) fn from_named( db: &RootDatabase, - node @ InFile { file_id, value }: InFile<&dyn ast::HasName>, + InFile { file_id, value }: InFile<&dyn ast::HasName>, kind: SymbolKind, ) -> NavigationTarget { let name = value.name().map(|it| it.text().into()).unwrap_or_else(|| "_".into()); - let focus_range = value.name().and_then(|it| orig_focus_range(db, file_id, it.syntax())); - let FileRange { file_id, range } = node.map(|it| it.syntax()).original_file_range(db); - NavigationTarget::from_syntax(file_id, name, focus_range, range, kind) + let (file_id, full_range, focus_range) = + orig_range_with_focus(db, file_id, value.syntax(), value.name()); + + NavigationTarget::from_syntax(file_id, name, focus_range, full_range, kind) } fn from_syntax( @@ -154,23 +157,43 @@ impl NavigationTarget { container_name: None, description: None, docs: None, + alias: None, } } } impl TryToNav for FileSymbol { fn try_to_nav(&self, db: &RootDatabase) -> Option { - let full_range = self.loc.original_range(db)?; - let name_range = self.loc.original_name_range(db)?; + let full_range = self.loc.original_range(db); + let focus_range = self.loc.original_name_range(db).and_then(|it| { + if it.file_id == full_range.file_id { + Some(it.range) + } else { + None + } + }); Some(NavigationTarget { file_id: full_range.file_id, - name: self.name.clone(), - kind: Some(self.kind.into()), + name: if self.is_alias { self.def.name(db)?.to_smol_str() } else { self.name.clone() }, + alias: if self.is_alias { Some(self.name.clone()) } else { None }, + kind: Some(hir::ModuleDefId::from(self.def).into()), full_range: full_range.range, - focus_range: Some(name_range.range), + focus_range, container_name: self.container_name.clone(), - description: description_from_symbol(db, self), + description: match self.def { + hir::ModuleDef::Module(it) => Some(it.display(db).to_string()), + hir::ModuleDef::Function(it) => Some(it.display(db).to_string()), + hir::ModuleDef::Adt(it) => Some(it.display(db).to_string()), + hir::ModuleDef::Variant(it) => Some(it.display(db).to_string()), + hir::ModuleDef::Const(it) => Some(it.display(db).to_string()), + hir::ModuleDef::Static(it) => Some(it.display(db).to_string()), + hir::ModuleDef::Trait(it) => Some(it.display(db).to_string()), + hir::ModuleDef::TraitAlias(it) => Some(it.display(db).to_string()), + hir::ModuleDef::TypeAlias(it) => Some(it.display(db).to_string()), + hir::ModuleDef::Macro(it) => Some(it.display(db).to_string()), + hir::ModuleDef::BuiltinType(_) => None, + }, docs: None, }) } @@ -221,38 +244,80 @@ impl TryToNav for hir::ModuleDef { } } -pub(crate) trait ToNavFromAst { +pub(crate) trait ToNavFromAst: Sized { const KIND: SymbolKind; + fn container_name(self, db: &RootDatabase) -> Option { + _ = db; + None + } } + +fn container_name(db: &RootDatabase, t: impl HasContainer) -> Option { + match t.container(db) { + hir::ItemContainer::Trait(it) => Some(it.name(db).to_smol_str()), + // FIXME: Handle owners of blocks correctly here + hir::ItemContainer::Module(it) => it.name(db).map(|name| name.to_smol_str()), + _ => None, + } +} + impl ToNavFromAst for hir::Function { const KIND: SymbolKind = SymbolKind::Function; + fn container_name(self, db: &RootDatabase) -> Option { + container_name(db, self) + } } + impl ToNavFromAst for hir::Const { const KIND: SymbolKind = SymbolKind::Const; + fn container_name(self, db: &RootDatabase) -> Option { + container_name(db, self) + } } impl ToNavFromAst for hir::Static { const KIND: SymbolKind = SymbolKind::Static; + fn container_name(self, db: &RootDatabase) -> Option { + container_name(db, self) + } } impl ToNavFromAst for hir::Struct { const KIND: SymbolKind = SymbolKind::Struct; + fn container_name(self, db: &RootDatabase) -> Option { + container_name(db, self) + } } impl ToNavFromAst for hir::Enum { const KIND: SymbolKind = SymbolKind::Enum; + fn container_name(self, db: &RootDatabase) -> Option { + container_name(db, self) + } } impl ToNavFromAst for hir::Variant { const KIND: SymbolKind = SymbolKind::Variant; } impl ToNavFromAst for hir::Union { const KIND: SymbolKind = SymbolKind::Union; + fn container_name(self, db: &RootDatabase) -> Option { + container_name(db, self) + } } impl ToNavFromAst for hir::TypeAlias { const KIND: SymbolKind = SymbolKind::TypeAlias; + fn container_name(self, db: &RootDatabase) -> Option { + container_name(db, self) + } } impl ToNavFromAst for hir::Trait { const KIND: SymbolKind = SymbolKind::Trait; + fn container_name(self, db: &RootDatabase) -> Option { + container_name(db, self) + } } impl ToNavFromAst for hir::TraitAlias { const KIND: SymbolKind = SymbolKind::TraitAlias; + fn container_name(self, db: &RootDatabase) -> Option { + container_name(db, self) + } } impl TryToNav for D @@ -269,6 +334,7 @@ where ); res.docs = self.docs(db); res.description = Some(self.display(db).to_string()); + res.container_name = self.container_name(db); Some(res) } } @@ -280,15 +346,11 @@ impl ToNav for hir::Module { let name = self.name(db).map(|it| it.to_smol_str()).unwrap_or_default(); let (syntax, focus) = match &value { ModuleSource::SourceFile(node) => (node.syntax(), None), - ModuleSource::Module(node) => ( - node.syntax(), - node.name().and_then(|it| orig_focus_range(db, file_id, it.syntax())), - ), + ModuleSource::Module(node) => (node.syntax(), node.name()), ModuleSource::BlockExpr(node) => (node.syntax(), None), }; - let FileRange { file_id, range: full_range } = - InFile::new(file_id, syntax).original_file_range(db); - NavigationTarget::from_syntax(file_id, name, focus, full_range, SymbolKind::Module) + let (file_id, full_range, focus_range) = orig_range_with_focus(db, file_id, syntax, focus); + NavigationTarget::from_syntax(file_id, name, focus_range, full_range, SymbolKind::Module) } } @@ -297,17 +359,14 @@ impl TryToNav for hir::Impl { let InFile { file_id, value } = self.source(db)?; let derive_attr = self.is_builtin_derive(db); - let focus_range = if derive_attr.is_some() { - None - } else { - value.self_ty().and_then(|ty| orig_focus_range(db, file_id, ty.syntax())) - }; + let focus = if derive_attr.is_some() { None } else { value.self_ty() }; - let FileRange { file_id, range: full_range } = match &derive_attr { - Some(attr) => attr.syntax().original_file_range(db), - None => InFile::new(file_id, value.syntax()).original_file_range(db), + let syntax = match &derive_attr { + Some(attr) => attr.value.syntax(), + None => value.syntax(), }; + let (file_id, full_range, focus_range) = orig_range_with_focus(db, file_id, syntax, focus); Some(NavigationTarget::from_syntax( file_id, "impl".into(), @@ -396,9 +455,8 @@ impl ToNav for LocalSource { Either::Left(bind_pat) => (bind_pat.syntax(), bind_pat.name()), Either::Right(it) => (it.syntax(), it.name()), }; - let focus_range = name.and_then(|it| orig_focus_range(db, file_id, it.syntax())); - let FileRange { file_id, range: full_range } = - InFile::new(file_id, node).original_file_range(db); + + let (file_id, full_range, focus_range) = orig_range_with_focus(db, file_id, node, name); let name = local.name(db).to_smol_str(); let kind = if local.is_self(db) { @@ -411,6 +469,7 @@ impl ToNav for LocalSource { NavigationTarget { file_id, name, + alias: None, kind: Some(kind), full_range, focus_range, @@ -432,13 +491,13 @@ impl ToNav for hir::Label { let InFile { file_id, value } = self.source(db); let name = self.name(db).to_smol_str(); - let range = |syntax: &_| InFile::new(file_id, syntax).original_file_range(db); - let FileRange { file_id, range: full_range } = range(value.syntax()); - let focus_range = value.lifetime().map(|lt| range(lt.syntax()).range); + let (file_id, full_range, focus_range) = + orig_range_with_focus(db, file_id, value.syntax(), value.lifetime()); NavigationTarget { file_id, name, + alias: None, kind: Some(SymbolKind::Label), full_range, focus_range, @@ -463,22 +522,18 @@ impl TryToNav for hir::TypeParam { Either::Right(x) => Either::Right(x), }; - let range = |syntax: &_| InFile::new(file_id, syntax).original_file_range(db); - let focus_range = |syntax: &_| InFile::new(file_id, syntax).original_file_range_opt(db); - let FileRange { file_id, range: full_range } = match &value { - Either::Left(type_param) => range(type_param.syntax()), - Either::Right(trait_) => trait_ - .name() - .and_then(|name| focus_range(name.syntax())) - .unwrap_or_else(|| range(trait_.syntax())), + let syntax = match &value { + Either::Left(type_param) => type_param.syntax(), + Either::Right(trait_) => trait_.syntax(), }; - let focus_range = value - .either(|it| it.name(), |it| it.name()) - .and_then(|it| focus_range(it.syntax())) - .map(|it| it.range); + let focus = value.as_ref().either(|it| it.name(), |it| it.name()); + + let (file_id, full_range, focus_range) = orig_range_with_focus(db, file_id, syntax, focus); + Some(NavigationTarget { file_id, name, + alias: None, kind: Some(SymbolKind::TypeParam), full_range, focus_range, @@ -500,14 +555,15 @@ impl TryToNav for hir::LifetimeParam { let InFile { file_id, value } = self.source(db)?; let name = self.name(db).to_smol_str(); - let FileRange { file_id, range: full_range } = + let FileRange { file_id, range } = InFile::new(file_id, value.syntax()).original_file_range(db); Some(NavigationTarget { file_id, name, + alias: None, kind: Some(SymbolKind::LifetimeParam), - full_range, - focus_range: Some(full_range), + full_range: range, + focus_range: Some(range), container_name: None, description: None, docs: None, @@ -528,12 +584,12 @@ impl TryToNav for hir::ConstParam { } }; - let focus_range = value.name().and_then(|it| orig_focus_range(db, file_id, it.syntax())); - let FileRange { file_id, range: full_range } = - InFile::new(file_id, value.syntax()).original_file_range(db); + let (file_id, full_range, focus_range) = + orig_range_with_focus(db, file_id, value.syntax(), value.name()); Some(NavigationTarget { file_id, name, + alias: None, kind: Some(SymbolKind::ConstParam), full_range, focus_range, @@ -544,38 +600,19 @@ impl TryToNav for hir::ConstParam { } } -/// Get a description of a symbol. -/// -/// e.g. `struct Name`, `enum Name`, `fn Name` -pub(crate) fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option { - let sema = Semantics::new(db); - let node = symbol.loc.syntax(&sema)?; - - match_ast! { - match node { - ast::Fn(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::Struct(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::Enum(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::Trait(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::TraitAlias(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::Module(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::TypeAlias(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::Const(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::Static(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::RecordField(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::Variant(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - ast::Union(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), - _ => None, - } - } -} - -fn orig_focus_range( +fn orig_range_with_focus( db: &RootDatabase, - file_id: hir::HirFileId, - syntax: &SyntaxNode, -) -> Option { - InFile::new(file_id, syntax).original_file_range_opt(db).map(|it| it.range) + hir_file: HirFileId, + value: &SyntaxNode, + name: Option, +) -> (FileId, TextRange, Option) { + let FileRange { file_id, range: full_range } = + InFile::new(hir_file, value).original_file_range(db); + let focus_range = name + .and_then(|it| InFile::new(hir_file, it.syntax()).original_file_range_opt(db)) + .and_then(|range| if range.file_id == file_id { Some(range.range) } else { None }); + + (file_id, full_range, focus_range) } #[cfg(test)] diff --git a/crates/ide/src/prime_caches.rs b/crates/ide/src/prime_caches.rs index 87b3ef380c594..d704d12a05b23 100644 --- a/crates/ide/src/prime_caches.rs +++ b/crates/ide/src/prime_caches.rs @@ -12,9 +12,8 @@ use ide_db::{ salsa::{Database, ParallelDatabase, Snapshot}, Cancelled, CrateGraph, CrateId, SourceDatabase, SourceDatabaseExt, }, - FxIndexMap, + FxHashSet, FxIndexMap, }; -use stdx::hash::NoHashHashSet; use crate::RootDatabase; @@ -81,7 +80,11 @@ pub(crate) fn parallel_prime_caches( for _ in 0..num_worker_threads { let worker = prime_caches_worker.clone(); let db = db.snapshot(); - std::thread::spawn(move || Cancelled::catch(|| worker(db))); + + stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) + .allow_leak(true) + .spawn(move || Cancelled::catch(|| worker(db))) + .expect("failed to spawn thread"); } (work_sender, progress_receiver) @@ -142,7 +145,7 @@ pub(crate) fn parallel_prime_caches( } } -fn compute_crates_to_prime(db: &RootDatabase, graph: &CrateGraph) -> NoHashHashSet { +fn compute_crates_to_prime(db: &RootDatabase, graph: &CrateGraph) -> FxHashSet { // We're only interested in the workspace crates and the `ImportMap`s of their direct // dependencies, though in practice the latter also compute the `DefMap`s. // We don't prime transitive dependencies because they're generally not visible in diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 3684c1033f32f..fdc5261ac38b2 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -17,7 +17,7 @@ use ide_db::{ RootDatabase, }; use itertools::Itertools; -use stdx::hash::NoHashHashMap; +use nohash_hasher::IntMap; use syntax::{ algo::find_node_at_offset, ast::{self, HasName}, @@ -31,7 +31,7 @@ use crate::{FilePosition, NavigationTarget, TryToNav}; #[derive(Debug, Clone)] pub struct ReferenceSearchResult { pub declaration: Option, - pub references: NoHashHashMap)>>, + pub references: IntMap)>>, } #[derive(Debug, Clone)] @@ -715,7 +715,7 @@ fn f() { } "#, expect![[r#" - Foo Struct FileId(1) 17..51 28..31 + Foo Struct FileId(1) 17..51 28..31 foo FileId(0) 53..56 FileId(2) 79..82 @@ -803,7 +803,7 @@ pub(super) struct Foo$0 { } "#, expect![[r#" - Foo Struct FileId(2) 0..41 18..21 + Foo Struct FileId(2) 0..41 18..21 some FileId(1) 20..23 Import FileId(1) 47..50 @@ -1289,7 +1289,7 @@ trait Foo where Self$0 { impl Foo for () {} "#, expect![[r#" - Self TypeParam FileId(0) 6..9 6..9 + Self TypeParam FileId(0) 0..44 6..9 FileId(0) 16..20 FileId(0) 37..41 @@ -1380,7 +1380,7 @@ fn foo(_: impl Bar, _: &dyn Bar) {} trait Foo = where Self$0: ; "#, expect![[r#" - Self TypeParam FileId(0) 6..9 6..9 + Self TypeParam FileId(0) 0..25 6..9 FileId(0) 18..22 "#]], @@ -1542,7 +1542,7 @@ fn f() { FileId(0) 161..165 - func Function FileId(0) 137..146 140..144 + func Function FileId(0) 137..146 140..144 module FileId(0) 181..185 "#]], @@ -1581,7 +1581,7 @@ trait Trait { } "#, expect![[r#" - func Function FileId(0) 48..87 51..55 + func Function FileId(0) 48..87 51..55 Trait FileId(0) 74..78 "#]], @@ -1692,7 +1692,7 @@ fn f() { } "#, expect![[r#" - CONST Const FileId(0) 18..37 24..29 + CONST Const FileId(0) 18..37 24..29 Trait FileId(0) 71..76 FileId(0) 125..130 @@ -1721,7 +1721,7 @@ fn f() { } "#, expect![[r#" - TypeAlias TypeAlias FileId(0) 18..33 23..32 + TypeAlias TypeAlias FileId(0) 18..33 23..32 Trait FileId(0) 66..75 FileId(0) 117..126 @@ -1750,7 +1750,7 @@ fn f() { } "#, expect![[r#" - function Function FileId(0) 18..34 21..29 + function Function FileId(0) 18..34 21..29 Trait FileId(0) 65..73 FileId(0) 112..120 @@ -1894,7 +1894,7 @@ fn f() { } "#, expect![[r#" - TypeAlias TypeAlias FileId(0) 18..33 23..32 + TypeAlias TypeAlias FileId(0) 18..33 23..32 Trait FileId(0) 66..75 FileId(0) 117..126 @@ -1950,7 +1950,7 @@ impl Foo for Bar { fn method() {} "#, expect![[r#" - method Function FileId(0) 16..39 19..25 + method Function FileId(0) 16..39 19..25 Foo FileId(0) 101..107 "#]], diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 8a8a9151c4257..27ad63d820d6c 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -349,8 +349,13 @@ pub(crate) fn runnable_mod( if !has_test_function_or_multiple_test_submodules(sema, &def) { return None; } - let path = - def.path_to_root(sema.db).into_iter().rev().filter_map(|it| it.name(sema.db)).join("::"); + let path = def + .path_to_root(sema.db) + .into_iter() + .rev() + .filter_map(|it| it.name(sema.db)) + .map(|it| it.display(sema.db).to_string()) + .join("::"); let attrs = def.attrs(sema.db); let cfg = attrs.cfg(); @@ -376,7 +381,7 @@ pub(crate) fn runnable_impl( } else { String::new() }; - let mut test_id = format!("{adt_name}{params}"); + let mut test_id = format!("{}{params}", adt_name.display(sema.db)); test_id.retain(|c| c != ' '); let test_id = TestId::Path(test_id); @@ -391,8 +396,13 @@ fn runnable_mod_outline_definition( if !has_test_function_or_multiple_test_submodules(sema, &def) { return None; } - let path = - def.path_to_root(sema.db).into_iter().rev().filter_map(|it| it.name(sema.db)).join("::"); + let path = def + .path_to_root(sema.db) + .into_iter() + .rev() + .filter_map(|it| it.name(sema.db)) + .map(|it| it.display(sema.db).to_string()) + .join("::"); let attrs = def.attrs(sema.db); let cfg = attrs.cfg(); @@ -430,7 +440,7 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option { let mut path = String::new(); def.canonical_module_path(db)? .flat_map(|it| it.name(db)) - .for_each(|name| format_to!(path, "{}::", name)); + .for_each(|name| format_to!(path, "{}::", name.display(db))); // This probably belongs to canonical_path? if let Some(assoc_item) = def.as_assoc_item(db) { if let hir::AssocItemContainer::Impl(imp) = assoc_item.container(db) { @@ -438,17 +448,17 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option { if let Some(adt) = ty.as_adt() { let name = adt.name(db); let mut ty_args = ty.generic_parameters(db).peekable(); - format_to!(path, "{}", name); + format_to!(path, "{}", name.display(db)); if ty_args.peek().is_some() { format_to!(path, "<{}>", ty_args.format_with(",", |ty, cb| cb(&ty))); } - format_to!(path, "::{}", def_name); + format_to!(path, "::{}", def_name.display(db)); path.retain(|c| c != ' '); return Some(path); } } } - format_to!(path, "{}", def_name); + format_to!(path, "{}", def_name.display(db)); Some(path) })(); @@ -2232,14 +2242,14 @@ mod tests { file_id: FileId( 0, ), - full_range: 52..115, - focus_range: 67..75, - name: "foo_test", + full_range: 121..185, + focus_range: 136..145, + name: "foo2_test", kind: Function, }, kind: Test { test_id: Path( - "tests::foo_test", + "tests::foo2_test", ), attr: TestAttr { ignore: false, @@ -2253,14 +2263,14 @@ mod tests { file_id: FileId( 0, ), - full_range: 121..185, - focus_range: 136..145, - name: "foo2_test", + full_range: 52..115, + focus_range: 67..75, + name: "foo_test", kind: Function, }, kind: Test { test_id: Path( - "tests::foo2_test", + "tests::foo_test", ), attr: TestAttr { ignore: false, @@ -2579,6 +2589,7 @@ mod r#mod { ), full_range: 47..84, name: "r#for", + container_name: "r#mod", }, kind: DocTest { test_id: Path( @@ -2595,6 +2606,7 @@ mod r#mod { ), full_range: 90..146, name: "r#struct", + container_name: "r#mod", }, kind: DocTest { test_id: Path( diff --git a/crates/ide/src/shuffle_crate_graph.rs b/crates/ide/src/shuffle_crate_graph.rs index e606072a82375..f85700daf1f78 100644 --- a/crates/ide/src/shuffle_crate_graph.rs +++ b/crates/ide/src/shuffle_crate_graph.rs @@ -1,9 +1,8 @@ -use std::sync::Arc; - use ide_db::{ - base_db::{salsa::Durability, CrateGraph, SourceDatabase}, + base_db::{salsa::Durability, CrateGraph, ProcMacros, SourceDatabase}, FxHashMap, RootDatabase, }; +use triomphe::Arc; // Feature: Shuffle Crate Graph // @@ -16,6 +15,7 @@ use ide_db::{ // |=== pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) { let crate_graph = db.crate_graph(); + let proc_macros = db.proc_macros(); let mut shuffled_ids = crate_graph.iter().collect::>(); @@ -23,6 +23,7 @@ pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) { stdx::rand::shuffle(&mut shuffled_ids, |i| rng.rand_range(0..i as u32) as usize); let mut new_graph = CrateGraph::default(); + let mut new_proc_macros = ProcMacros::default(); let mut map = FxHashMap::default(); for old_id in shuffled_ids.iter().copied() { @@ -35,11 +36,12 @@ pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) { data.cfg_options.clone(), data.potential_cfg_options.clone(), data.env.clone(), - data.proc_macro.clone(), data.is_proc_macro, data.origin.clone(), data.target_layout.clone(), + data.channel, ); + new_proc_macros.insert(new_id, proc_macros[&old_id].clone()); map.insert(old_id, new_id); } @@ -53,4 +55,5 @@ pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) { } db.set_crate_graph_with_durability(Arc::new(new_graph), Durability::HIGH); + db.set_proc_macros_with_durability(Arc::new(new_proc_macros), Durability::HIGH); } diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs index 4b2c139f6f455..7795be54e264c 100644 --- a/crates/ide/src/signature_help.rs +++ b/crates/ide/src/signature_help.rs @@ -15,8 +15,9 @@ use ide_db::{ use stdx::format_to; use syntax::{ algo, - ast::{self, HasArgList}, - match_ast, AstNode, Direction, SyntaxElementChildren, SyntaxToken, TextRange, TextSize, + ast::{self, AstChildren, HasArgList}, + match_ast, AstNode, Direction, NodeOrToken, SyntaxElementChildren, SyntaxNode, SyntaxToken, + TextRange, TextSize, T, }; use crate::RootDatabase; @@ -116,6 +117,20 @@ pub(crate) fn signature_help(db: &RootDatabase, position: FilePosition) -> Optio } return signature_help_for_tuple_struct_pat(&sema, tuple_pat, token); }, + ast::TuplePat(tuple_pat) => { + let cursor_outside = tuple_pat.r_paren_token().as_ref() == Some(&token); + if cursor_outside { + continue; + } + return signature_help_for_tuple_pat(&sema, tuple_pat, token); + }, + ast::TupleExpr(tuple_expr) => { + let cursor_outside = tuple_expr.r_paren_token().as_ref() == Some(&token); + if cursor_outside { + continue; + } + return signature_help_for_tuple_expr(&sema, tuple_expr, token); + }, _ => (), } } @@ -162,7 +177,7 @@ fn signature_help_for_call( match callable.kind() { hir::CallableKind::Function(func) => { res.doc = func.docs(db).map(|it| it.into()); - format_to!(res.signature, "fn {}", func.name(db)); + format_to!(res.signature, "fn {}", func.name(db).display(db)); fn_params = Some(match callable.receiver_param(db) { Some(_self) => func.params_without_self(db), None => func.assoc_fn_params(db), @@ -170,15 +185,15 @@ fn signature_help_for_call( } hir::CallableKind::TupleStruct(strukt) => { res.doc = strukt.docs(db).map(|it| it.into()); - format_to!(res.signature, "struct {}", strukt.name(db)); + format_to!(res.signature, "struct {}", strukt.name(db).display(db)); } hir::CallableKind::TupleEnumVariant(variant) => { res.doc = variant.docs(db).map(|it| it.into()); format_to!( res.signature, "enum {}::{}", - variant.parent_enum(db).name(db), - variant.name(db) + variant.parent_enum(db).name(db).display(db), + variant.name(db).display(db) ); } hir::CallableKind::Closure | hir::CallableKind::FnPtr | hir::CallableKind::Other => (), @@ -248,31 +263,31 @@ fn signature_help_for_generics( match generics_def { hir::GenericDef::Function(it) => { res.doc = it.docs(db).map(|it| it.into()); - format_to!(res.signature, "fn {}", it.name(db)); + format_to!(res.signature, "fn {}", it.name(db).display(db)); } hir::GenericDef::Adt(hir::Adt::Enum(it)) => { res.doc = it.docs(db).map(|it| it.into()); - format_to!(res.signature, "enum {}", it.name(db)); + format_to!(res.signature, "enum {}", it.name(db).display(db)); } hir::GenericDef::Adt(hir::Adt::Struct(it)) => { res.doc = it.docs(db).map(|it| it.into()); - format_to!(res.signature, "struct {}", it.name(db)); + format_to!(res.signature, "struct {}", it.name(db).display(db)); } hir::GenericDef::Adt(hir::Adt::Union(it)) => { res.doc = it.docs(db).map(|it| it.into()); - format_to!(res.signature, "union {}", it.name(db)); + format_to!(res.signature, "union {}", it.name(db).display(db)); } hir::GenericDef::Trait(it) => { res.doc = it.docs(db).map(|it| it.into()); - format_to!(res.signature, "trait {}", it.name(db)); + format_to!(res.signature, "trait {}", it.name(db).display(db)); } hir::GenericDef::TraitAlias(it) => { res.doc = it.docs(db).map(|it| it.into()); - format_to!(res.signature, "trait {}", it.name(db)); + format_to!(res.signature, "trait {}", it.name(db).display(db)); } hir::GenericDef::TypeAlias(it) => { res.doc = it.docs(db).map(|it| it.into()); - format_to!(res.signature, "type {}", it.name(db)); + format_to!(res.signature, "type {}", it.name(db).display(db)); } hir::GenericDef::Variant(it) => { // In paths, generics of an enum can be specified *after* one of its variants. @@ -280,7 +295,7 @@ fn signature_help_for_generics( // We'll use the signature of the enum, but include the docs of the variant. res.doc = it.docs(db).map(|it| it.into()); let enum_ = it.parent_enum(db); - format_to!(res.signature, "enum {}", enum_.name(db)); + format_to!(res.signature, "enum {}", enum_.name(db).display(db)); generics_def = enum_.into(); } // These don't have generic args that can be specified @@ -395,24 +410,26 @@ fn signature_help_for_tuple_struct_pat( pat: ast::TupleStructPat, token: SyntaxToken, ) -> Option { - let rest_pat = pat.fields().find(|it| matches!(it, ast::Pat::RestPat(_))); - let is_left_of_rest_pat = - rest_pat.map_or(true, |it| token.text_range().start() < it.syntax().text_range().end()); - + let path = pat.path()?; + let path_res = sema.resolve_path(&path)?; let mut res = SignatureHelp { doc: None, signature: String::new(), parameters: vec![], active_parameter: None, }; - let db = sema.db; - let path_res = sema.resolve_path(&pat.path()?)?; + let fields: Vec<_> = if let PathResolution::Def(ModuleDef::Variant(variant)) = path_res { let en = variant.parent_enum(db); res.doc = en.docs(db).map(|it| it.into()); - format_to!(res.signature, "enum {}::{} (", en.name(db), variant.name(db)); + format_to!( + res.signature, + "enum {}::{} (", + en.name(db).display(db), + variant.name(db).display(db) + ); variant.fields(db) } else { let adt = match path_res { @@ -424,36 +441,78 @@ fn signature_help_for_tuple_struct_pat( match adt { hir::Adt::Struct(it) => { res.doc = it.docs(db).map(|it| it.into()); - format_to!(res.signature, "struct {} (", it.name(db)); + format_to!(res.signature, "struct {} (", it.name(db).display(db)); it.fields(db) } _ => return None, } }; - let commas = pat - .syntax() - .children_with_tokens() - .filter_map(syntax::NodeOrToken::into_token) - .filter(|t| t.kind() == syntax::T![,]); - res.active_parameter = Some(if is_left_of_rest_pat { - commas.take_while(|t| t.text_range().start() <= token.text_range().start()).count() - } else { - let n_commas = commas - .collect::>() - .into_iter() - .rev() - .take_while(|t| t.text_range().start() > token.text_range().start()) - .count(); - fields.len().saturating_sub(1).saturating_sub(n_commas) - }); + Some(signature_help_for_tuple_pat_ish( + db, + res, + pat.syntax(), + token, + pat.fields(), + fields.into_iter().map(|it| it.ty(db)), + )) +} + +fn signature_help_for_tuple_pat( + sema: &Semantics<'_, RootDatabase>, + pat: ast::TuplePat, + token: SyntaxToken, +) -> Option { + let db = sema.db; + let field_pats = pat.fields(); + let pat = pat.into(); + let ty = sema.type_of_pat(&pat)?; + let fields = ty.original.tuple_fields(db); + + Some(signature_help_for_tuple_pat_ish( + db, + SignatureHelp { + doc: None, + signature: String::from('('), + parameters: vec![], + active_parameter: None, + }, + pat.syntax(), + token, + field_pats, + fields.into_iter(), + )) +} +fn signature_help_for_tuple_expr( + sema: &Semantics<'_, RootDatabase>, + expr: ast::TupleExpr, + token: SyntaxToken, +) -> Option { + let active_parameter = Some( + expr.syntax() + .children_with_tokens() + .filter_map(NodeOrToken::into_token) + .filter(|t| t.kind() == T![,]) + .take_while(|t| t.text_range().start() <= token.text_range().start()) + .count(), + ); + + let db = sema.db; + let mut res = SignatureHelp { + doc: None, + signature: String::from('('), + parameters: vec![], + active_parameter, + }; + let expr = sema.type_of_expr(&expr.into())?; + let fields = expr.original.tuple_fields(db); let mut buf = String::new(); - for ty in fields.into_iter().map(|it| it.ty(db)) { + for ty in fields { format_to!(buf, "{}", ty.display_truncated(db, Some(20))); res.push_call_param(&buf); buf.clear(); } - res.signature.push_str(")"); + res.signature.push(')'); Some(res) } @@ -465,8 +524,8 @@ fn signature_help_for_record_( token: SyntaxToken, ) -> Option { let active_parameter = field_list_children - .filter_map(syntax::NodeOrToken::into_token) - .filter(|t| t.kind() == syntax::T![,]) + .filter_map(NodeOrToken::into_token) + .filter(|t| t.kind() == T![,]) .take_while(|t| t.text_range().start() <= token.text_range().start()) .count(); @@ -486,7 +545,12 @@ fn signature_help_for_record_( let en = variant.parent_enum(db); res.doc = en.docs(db).map(|it| it.into()); - format_to!(res.signature, "enum {}::{} {{ ", en.name(db), variant.name(db)); + format_to!( + res.signature, + "enum {}::{} {{ ", + en.name(db).display(db), + variant.name(db).display(db) + ); } else { let adt = match path_res { PathResolution::SelfType(imp) => imp.self_ty(db).as_adt()?, @@ -498,12 +562,12 @@ fn signature_help_for_record_( hir::Adt::Struct(it) => { fields = it.fields(db); res.doc = it.docs(db).map(|it| it.into()); - format_to!(res.signature, "struct {} {{ ", it.name(db)); + format_to!(res.signature, "struct {} {{ ", it.name(db).display(db)); } hir::Adt::Union(it) => { fields = it.fields(db); res.doc = it.docs(db).map(|it| it.into()); - format_to!(res.signature, "union {} {{ ", it.name(db)); + format_to!(res.signature, "union {} {{ ", it.name(db).display(db)); } _ => return None, } @@ -514,7 +578,7 @@ fn signature_help_for_record_( let mut buf = String::new(); for (field, ty) in fields2 { let name = field.name(db); - format_to!(buf, "{name}: {}", ty.display_truncated(db, Some(20))); + format_to!(buf, "{}: {}", name.display(db), ty.display_truncated(db, Some(20))); res.push_record_field(&buf); buf.clear(); @@ -524,7 +588,7 @@ fn signature_help_for_record_( } for (name, field) in fields { let Some(field) = field else { continue }; - format_to!(buf, "{name}: {}", field.ty(db).display_truncated(db, Some(20))); + format_to!(buf, "{}: {}", name.display(db), field.ty(db).display_truncated(db, Some(20))); res.push_record_field(&buf); buf.clear(); } @@ -532,6 +596,46 @@ fn signature_help_for_record_( Some(res) } +fn signature_help_for_tuple_pat_ish( + db: &RootDatabase, + mut res: SignatureHelp, + pat: &SyntaxNode, + token: SyntaxToken, + mut field_pats: AstChildren, + fields: impl ExactSizeIterator, +) -> SignatureHelp { + let rest_pat = field_pats.find(|it| matches!(it, ast::Pat::RestPat(_))); + let is_left_of_rest_pat = + rest_pat.map_or(true, |it| token.text_range().start() < it.syntax().text_range().end()); + + let commas = pat + .children_with_tokens() + .filter_map(NodeOrToken::into_token) + .filter(|t| t.kind() == T![,]); + + res.active_parameter = { + Some(if is_left_of_rest_pat { + commas.take_while(|t| t.text_range().start() <= token.text_range().start()).count() + } else { + let n_commas = commas + .collect::>() + .into_iter() + .rev() + .take_while(|t| t.text_range().start() > token.text_range().start()) + .count(); + fields.len().saturating_sub(1).saturating_sub(n_commas) + }) + }; + + let mut buf = String::new(); + for ty in fields { + format_to!(buf, "{}", ty.display_truncated(db, Some(20))); + res.push_call_param(&buf); + buf.clear(); + } + res.signature.push_str(")"); + res +} #[cfg(test)] mod tests { use std::iter; @@ -1227,6 +1331,24 @@ fn main() { ) } + #[test] + fn call_info_for_fn_def_over_reference() { + check( + r#" +struct S; +fn foo(s: S) -> i32 { 92 } +fn main() { + let bar = &&&&&foo; + bar($0); +} + "#, + expect![[r#" + fn foo(s: S) -> i32 + ^^^^ + "#]], + ) + } + #[test] fn call_info_for_fn_ptr() { check( @@ -1823,4 +1945,290 @@ fn main() { "#]], ); } + + #[test] + fn test_tuple_expr_free() { + check( + r#" +fn main() { + (0$0, 1, 3); +} +"#, + expect![[r#" + (i32, i32, i32) + ^^^ --- --- + "#]], + ); + check( + r#" +fn main() { + ($0 1, 3); +} +"#, + expect![[r#" + (i32, i32) + ^^^ --- + "#]], + ); + check( + r#" +fn main() { + (1, 3 $0); +} +"#, + expect![[r#" + (i32, i32) + --- ^^^ + "#]], + ); + check( + r#" +fn main() { + (1, 3 $0,); +} +"#, + expect![[r#" + (i32, i32) + --- ^^^ + "#]], + ); + } + + #[test] + fn test_tuple_expr_expected() { + check( + r#" +fn main() { + let _: (&str, u32, u32)= ($0, 1, 3); +} +"#, + expect![[r#" + (&str, u32, u32) + ^^^^ --- --- + "#]], + ); + // FIXME: Should typeck report a 4-ary tuple for the expression here? + check( + r#" +fn main() { + let _: (&str, u32, u32, u32) = ($0, 1, 3); +} +"#, + expect![[r#" + (&str, u32, u32) + ^^^^ --- --- + "#]], + ); + check( + r#" +fn main() { + let _: (&str, u32, u32)= ($0, 1, 3, 5); +} +"#, + expect![[r#" + (&str, u32, u32, i32) + ^^^^ --- --- --- + "#]], + ); + } + + #[test] + fn test_tuple_pat_free() { + check( + r#" +fn main() { + let ($0, 1, 3); +} +"#, + expect![[r#" + ({unknown}, i32, i32) + ^^^^^^^^^ --- --- + "#]], + ); + check( + r#" +fn main() { + let (0$0, 1, 3); +} +"#, + expect![[r#" + (i32, i32, i32) + ^^^ --- --- + "#]], + ); + check( + r#" +fn main() { + let ($0 1, 3); +} +"#, + expect![[r#" + (i32, i32) + ^^^ --- + "#]], + ); + check( + r#" +fn main() { + let (1, 3 $0); +} +"#, + expect![[r#" + (i32, i32) + --- ^^^ + "#]], + ); + check( + r#" +fn main() { + let (1, 3 $0,); +} +"#, + expect![[r#" + (i32, i32) + --- ^^^ + "#]], + ); + check( + r#" +fn main() { + let (1, 3 $0, ..); +} +"#, + expect![[r#" + (i32, i32) + --- ^^^ + "#]], + ); + check( + r#" +fn main() { + let (1, 3, .., $0); +} +"#, + // FIXME: This is wrong, this should not mark the last as active + expect![[r#" + (i32, i32) + --- ^^^ + "#]], + ); + } + + #[test] + fn test_tuple_pat_expected() { + check( + r#" +fn main() { + let (0$0, 1, 3): (i32, i32, i32); +} +"#, + expect![[r#" + (i32, i32, i32) + ^^^ --- --- + "#]], + ); + check( + r#" +fn main() { + let ($0, 1, 3): (i32, i32, i32); +} +"#, + expect![[r#" + (i32, i32, i32) + ^^^ --- --- + "#]], + ); + check( + r#" +fn main() { + let (1, 3 $0): (i32,); +} +"#, + expect![[r#" + (i32, i32) + --- ^^^ + "#]], + ); + check( + r#" +fn main() { + let (1, 3 $0, ..): (i32, i32, i32, i32); +} +"#, + expect![[r#" + (i32, i32, i32, i32) + --- ^^^ --- --- + "#]], + ); + check( + r#" +fn main() { + let (1, 3, .., $0): (i32, i32, i32); +} +"#, + expect![[r#" + (i32, i32, i32) + --- --- ^^^ + "#]], + ); + } + #[test] + fn test_tuple_pat_expected_inferred() { + check( + r#" +fn main() { + let (0$0, 1, 3) = (1, 2 ,3); +} +"#, + expect![[r#" + (i32, i32, i32) + ^^^ --- --- + "#]], + ); + check( + r#" +fn main() { + let ($0 1, 3) = (1, 2, 3); +} +"#, + // FIXME: Should typeck report a 3-ary tuple for the pattern here? + expect![[r#" + (i32, i32) + ^^^ --- + "#]], + ); + check( + r#" +fn main() { + let (1, 3 $0) = (1,); +} +"#, + expect![[r#" + (i32, i32) + --- ^^^ + "#]], + ); + check( + r#" +fn main() { + let (1, 3 $0, ..) = (1, 2, 3, 4); +} +"#, + expect![[r#" + (i32, i32, i32, i32) + --- ^^^ --- --- + "#]], + ); + check( + r#" +fn main() { + let (1, 3, .., $0) = (1, 2, 3); +} +"#, + expect![[r#" + (i32, i32, i32) + --- --- ^^^ + "#]], + ); + } } diff --git a/crates/ide/src/ssr.rs b/crates/ide/src/ssr.rs index 497eb1cc130d5..deaf3c9c416b4 100644 --- a/crates/ide/src/ssr.rs +++ b/crates/ide/src/ssr.rs @@ -56,8 +56,6 @@ pub(crate) fn ssr_assists( #[cfg(test)] mod tests { - use std::sync::Arc; - use expect_test::expect; use ide_assists::{Assist, AssistResolveStrategy}; use ide_db::{ @@ -65,6 +63,7 @@ mod tests { symbol_index::SymbolsDatabase, FxHashSet, RootDatabase, }; + use triomphe::Arc; use super::ssr_assists; diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index c97691b14a57f..3e3d9f8f85c45 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -118,9 +118,11 @@ impl StaticIndex<'_> { adjustment_hints_hide_outside_unsafe: false, hide_named_constructor_hints: false, hide_closure_initialization_hints: false, + closure_style: hir::ClosureStyle::ImplFn, param_names_for_lifetime_elision_hints: false, binding_mode_hints: false, max_length: Some(25), + closure_capture_hints: false, closing_brace_hints_min_lines: Some(25), }, file_id, @@ -136,10 +138,10 @@ impl StaticIndex<'_> { }); let hover_config = HoverConfig { links_in_hover: true, + memory_layout: None, documentation: true, keywords: true, format: crate::HoverDocFormat::Markdown, - interpret_tests: false, }; let tokens = tokens.filter(|token| { matches!( diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs index 7ce782f93be14..d2c77e2dc7975 100644 --- a/crates/ide/src/status.rs +++ b/crates/ide/src/status.rs @@ -1,9 +1,18 @@ -use std::{fmt, sync::Arc}; +use std::{fmt, marker::PhantomData}; -use hir::{ExpandResult, MacroFile}; -use ide_db::base_db::{ - salsa::debug::{DebugQueryTable, TableEntry}, - CrateId, FileId, FileTextQuery, SourceDatabase, SourceRootId, +use hir::{ + db::{AstIdMapQuery, AttrsQuery, BlockDefMapQuery, ParseMacroExpansionQuery}, + Attr, Attrs, ExpandResult, MacroFile, Module, +}; +use ide_db::{ + base_db::{ + salsa::{ + debug::{DebugQueryTable, TableEntry}, + Query, QueryTable, + }, + CrateId, FileId, FileTextQuery, ParseQuery, SourceDatabase, SourceRootId, + }, + symbol_index::ModuleSymbolsQuery, }; use ide_db::{ symbol_index::{LibrarySymbolsQuery, SymbolIndex}, @@ -14,13 +23,7 @@ use profile::{memory_usage, Bytes}; use std::env; use stdx::format_to; use syntax::{ast, Parse, SyntaxNode}; - -fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { - ide_db::base_db::ParseQuery.in_db(db).entries::() -} -fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { - hir::db::ParseMacroExpansionQuery.in_db(db).entries::() -} +use triomphe::Arc; // Feature: Status // @@ -34,15 +37,22 @@ fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { // image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[] pub(crate) fn status(db: &RootDatabase, file_id: Option) -> String { let mut buf = String::new(); - format_to!(buf, "{}\n", FileTextQuery.in_db(db).entries::()); - format_to!(buf, "{}\n", LibrarySymbolsQuery.in_db(db).entries::()); - format_to!(buf, "{}\n", syntax_tree_stats(db)); - format_to!(buf, "{} (Macros)\n", macro_syntax_tree_stats(db)); + + format_to!(buf, "{}\n", collect_query(FileTextQuery.in_db(db))); + format_to!(buf, "{}\n", collect_query(ParseQuery.in_db(db))); + format_to!(buf, "{}\n", collect_query(ParseMacroExpansionQuery.in_db(db))); + format_to!(buf, "{}\n", collect_query(LibrarySymbolsQuery.in_db(db))); + format_to!(buf, "{}\n", collect_query(ModuleSymbolsQuery.in_db(db))); format_to!(buf, "{} in total\n", memory_usage()); if env::var("RA_COUNT").is_ok() { format_to!(buf, "\nCounts:\n{}", profile::countme::get_all()); } + format_to!(buf, "\nDebug info:\n"); + format_to!(buf, "{}\n", collect_query(AttrsQuery.in_db(db))); + format_to!(buf, "{} ast id maps\n", collect_query_count(AstIdMapQuery.in_db(db))); + format_to!(buf, "{} block def maps\n", collect_query_count(BlockDefMapQuery.in_db(db))); + if let Some(file_id) = file_id { format_to!(buf, "\nFile info:\n"); let crates = crate::parent_module::crates_for(db, file_id); @@ -52,8 +62,8 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option) -> String { let crate_graph = db.crate_graph(); for krate in crates { let display_crate = |krate: CrateId| match &crate_graph[krate].display_name { - Some(it) => format!("{it}({krate:?})"), - None => format!("{krate:?}"), + Some(it) => format!("{it}({})", krate.into_raw()), + None => format!("{}", krate.into_raw()), }; format_to!(buf, "Crate: {}\n", display_crate(krate)); let deps = crate_graph[krate] @@ -68,6 +78,82 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option) -> String { buf.trim().to_string() } +fn collect_query<'q, Q>(table: QueryTable<'q, Q>) -> ::Collector +where + QueryTable<'q, Q>: DebugQueryTable, + Q: QueryCollect, + ::Storage: 'q, + ::Collector: StatCollect< + as DebugQueryTable>::Key, + as DebugQueryTable>::Value, + >, +{ + struct StatCollectorWrapper(C); + impl, K, V> FromIterator> for StatCollectorWrapper { + fn from_iter(iter: T) -> StatCollectorWrapper + where + T: IntoIterator>, + { + let mut res = C::default(); + for entry in iter { + res.collect_entry(entry.key, entry.value); + } + StatCollectorWrapper(res) + } + } + table.entries::::Collector>>().0 +} + +fn collect_query_count<'q, Q>(table: QueryTable<'q, Q>) -> usize +where + QueryTable<'q, Q>: DebugQueryTable, + Q: Query, + ::Storage: 'q, +{ + struct EntryCounter(usize); + impl FromIterator> for EntryCounter { + fn from_iter(iter: T) -> EntryCounter + where + T: IntoIterator>, + { + EntryCounter(iter.into_iter().count()) + } + } + table.entries::().0 +} + +trait QueryCollect: Query { + type Collector; +} + +impl QueryCollect for LibrarySymbolsQuery { + type Collector = SymbolsStats; +} + +impl QueryCollect for ParseQuery { + type Collector = SyntaxTreeStats; +} + +impl QueryCollect for ParseMacroExpansionQuery { + type Collector = SyntaxTreeStats; +} + +impl QueryCollect for FileTextQuery { + type Collector = FilesStats; +} + +impl QueryCollect for ModuleSymbolsQuery { + type Collector = SymbolsStats; +} + +impl QueryCollect for AttrsQuery { + type Collector = AttrsStats; +} + +trait StatCollect: Default { + fn collect_entry(&mut self, key: K, value: Option); +} + #[derive(Default)] struct FilesStats { total: usize, @@ -80,85 +166,98 @@ impl fmt::Display for FilesStats { } } -impl FromIterator>> for FilesStats { - fn from_iter(iter: T) -> FilesStats - where - T: IntoIterator>>, - { - let mut res = FilesStats::default(); - for entry in iter { - res.total += 1; - res.size += entry.value.unwrap().len(); - } - res +impl StatCollect> for FilesStats { + fn collect_entry(&mut self, _: FileId, value: Option>) { + self.total += 1; + self.size += value.unwrap().len(); } } #[derive(Default)] -pub(crate) struct SyntaxTreeStats { +pub(crate) struct SyntaxTreeStats { total: usize, pub(crate) retained: usize, } -impl fmt::Display for SyntaxTreeStats { +impl fmt::Display for SyntaxTreeStats { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "{} trees, {} preserved", self.total, self.retained) + write!( + fmt, + "{} trees, {} preserved{}", + self.total, + self.retained, + if MACROS { " (macros)" } else { "" } + ) } } -impl FromIterator>> for SyntaxTreeStats { - fn from_iter(iter: T) -> SyntaxTreeStats - where - T: IntoIterator>>, - { - let mut res = SyntaxTreeStats::default(); - for entry in iter { - res.total += 1; - res.retained += entry.value.is_some() as usize; - } - res +impl StatCollect> for SyntaxTreeStats { + fn collect_entry(&mut self, _: FileId, value: Option>) { + self.total += 1; + self.retained += value.is_some() as usize; } } -impl FromIterator, M)>>>> - for SyntaxTreeStats -{ - fn from_iter(iter: T) -> SyntaxTreeStats - where - T: IntoIterator, M)>>>>, - { - let mut res = SyntaxTreeStats::default(); - for entry in iter { - res.total += 1; - res.retained += entry.value.is_some() as usize; +impl StatCollect, M)>> for SyntaxTreeStats { + fn collect_entry(&mut self, _: MacroFile, value: Option, M)>>) { + self.total += 1; + self.retained += value.is_some() as usize; + } +} + +struct SymbolsStats { + total: usize, + size: Bytes, + phantom: PhantomData, +} + +impl Default for SymbolsStats { + fn default() -> Self { + Self { total: Default::default(), size: Default::default(), phantom: PhantomData } + } +} + +impl fmt::Display for SymbolsStats { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "{} of module index symbols ({})", self.size, self.total) + } +} +impl fmt::Display for SymbolsStats { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "{} of library index symbols ({})", self.size, self.total) + } +} +impl StatCollect> for SymbolsStats { + fn collect_entry(&mut self, _: Key, value: Option>) { + if let Some(symbols) = value { + self.total += symbols.len(); + self.size += symbols.memory_size(); } - res } } #[derive(Default)] -struct LibrarySymbolsStats { +struct AttrsStats { + entries: usize, total: usize, - size: Bytes, } -impl fmt::Display for LibrarySymbolsStats { +impl fmt::Display for AttrsStats { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "{} of index symbols ({})", self.size, self.total) + let size = + self.entries * std::mem::size_of::() + self.total * std::mem::size_of::(); + let size = Bytes::new(size as _); + write!( + fmt, + "{} attribute query entries, {} total attributes ({} for storing entries)", + self.entries, self.total, size + ) } } -impl FromIterator>> for LibrarySymbolsStats { - fn from_iter(iter: T) -> LibrarySymbolsStats - where - T: IntoIterator>>, - { - let mut res = LibrarySymbolsStats::default(); - for entry in iter { - let symbols = entry.value.unwrap(); - res.total += symbols.len(); - res.size += symbols.memory_size(); - } - res +impl StatCollect for AttrsStats { + fn collect_entry(&mut self, _: Key, value: Option) { + self.entries += 1; + self.total += value.map_or(0, |it| it.len()); } } diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 454a250f3ded4..8c02fe81648a5 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs @@ -16,13 +16,19 @@ mod tests; use hir::{Name, Semantics}; use ide_db::{FxHashMap, RootDatabase, SymbolKind}; use syntax::{ - ast, AstNode, AstToken, NodeOrToken, SyntaxKind::*, SyntaxNode, TextRange, WalkEvent, T, + ast::{self, IsString}, + AstNode, AstToken, NodeOrToken, + SyntaxKind::*, + SyntaxNode, TextRange, WalkEvent, T, }; use crate::{ syntax_highlighting::{ - escape::highlight_escape_string, format::highlight_format_string, highlights::Highlights, - macro_::MacroHighlighter, tags::Highlight, + escape::{highlight_escape_char, highlight_escape_string}, + format::highlight_format_string, + highlights::Highlights, + macro_::MacroHighlighter, + tags::Highlight, }, FileId, HlMod, HlOperator, HlPunct, HlTag, }; @@ -163,6 +169,7 @@ pub struct HighlightConfig { // injected:: Emitted for doc-string injected highlighting like rust source blocks in documentation. // intraDocLink:: Emitted for intra doc links in doc-strings. // library:: Emitted for items that are defined outside of the current crate. +// macro:: Emitted for tokens inside macro calls. // mutable:: Emitted for mutable locals and statics as well as functions taking `&mut self`. // public:: Emitted for items that are from the current crate and are `pub`. // reference:: Emitted for locals behind a reference and functions taking `self` by reference. @@ -237,6 +244,7 @@ fn traverse( let mut current_macro: Option = None; let mut macro_highlighter = MacroHighlighter::default(); let mut inside_attribute = false; + let mut inside_macro_call = false; // Walk all nodes, keeping track of whether we are inside a macro or not. // If in macro, expand it first and highlight the expanded code. @@ -267,46 +275,50 @@ fn traverse( inside_attribute = false } - Enter(NodeOrToken::Node(node)) if ast::Item::can_cast(node.kind()) => { - match ast::Item::cast(node.clone()) { - Some(ast::Item::MacroRules(mac)) => { - macro_highlighter.init(); - current_macro = Some(mac.into()); - continue; - } - Some(ast::Item::MacroDef(mac)) => { - macro_highlighter.init(); - current_macro = Some(mac.into()); - continue; - } - Some(item) => { - if matches!(node.kind(), FN | CONST | STATIC) { - bindings_shadow_count.clear(); + Enter(NodeOrToken::Node(node)) => match ast::Item::cast(node.clone()) { + Some(item) => { + match item { + ast::Item::MacroRules(mac) => { + macro_highlighter.init(); + current_macro = Some(mac.into()); + continue; + } + ast::Item::MacroDef(mac) => { + macro_highlighter.init(); + current_macro = Some(mac.into()); + continue; + } + ast::Item::Fn(_) | ast::Item::Const(_) | ast::Item::Static(_) => { + bindings_shadow_count.clear() + } + ast::Item::MacroCall(_) => { + inside_macro_call = true; } + _ => (), + } - if attr_or_derive_item.is_none() { - if sema.is_attr_macro_call(&item) { - attr_or_derive_item = Some(AttrOrDerive::Attr(item)); - } else { - let adt = match item { - ast::Item::Enum(it) => Some(ast::Adt::Enum(it)), - ast::Item::Struct(it) => Some(ast::Adt::Struct(it)), - ast::Item::Union(it) => Some(ast::Adt::Union(it)), - _ => None, - }; - match adt { - Some(adt) if sema.is_derive_annotated(&adt) => { - attr_or_derive_item = - Some(AttrOrDerive::Derive(ast::Item::from(adt))); - } - _ => (), + if attr_or_derive_item.is_none() { + if sema.is_attr_macro_call(&item) { + attr_or_derive_item = Some(AttrOrDerive::Attr(item)); + } else { + let adt = match item { + ast::Item::Enum(it) => Some(ast::Adt::Enum(it)), + ast::Item::Struct(it) => Some(ast::Adt::Struct(it)), + ast::Item::Union(it) => Some(ast::Adt::Union(it)), + _ => None, + }; + match adt { + Some(adt) if sema.is_derive_annotated(&adt) => { + attr_or_derive_item = + Some(AttrOrDerive::Derive(ast::Item::from(adt))); } + _ => (), } } } - _ => (), } - } + _ => (), + }, Leave(NodeOrToken::Node(node)) if ast::Item::can_cast(node.kind()) => { match ast::Item::cast(node.clone()) { Some(ast::Item::MacroRules(mac)) => { @@ -324,6 +336,9 @@ fn traverse( { attr_or_derive_item = None; } + Some(ast::Item::MacroCall(_)) => { + inside_macro_call = false; + } _ => (), } } @@ -419,14 +434,35 @@ fn traverse( continue; } highlight_format_string(hl, &string, &expanded_string, range); - highlight_escape_string(hl, &string, range.start()); + + if !string.is_raw() { + highlight_escape_string(hl, &string, range.start()); + } } } else if ast::ByteString::can_cast(token.kind()) && ast::ByteString::can_cast(descended_token.kind()) { if let Some(byte_string) = ast::ByteString::cast(token) { - highlight_escape_string(hl, &byte_string, range.start()); + if !byte_string.is_raw() { + highlight_escape_string(hl, &byte_string, range.start()); + } } + } else if ast::CString::can_cast(token.kind()) + && ast::CString::can_cast(descended_token.kind()) + { + if let Some(c_string) = ast::CString::cast(token) { + if !c_string.is_raw() { + highlight_escape_string(hl, &c_string, range.start()); + } + } + } else if ast::Char::can_cast(token.kind()) + && ast::Char::can_cast(descended_token.kind()) + { + let Some(char) = ast::Char::cast(token) else { + continue; + }; + + highlight_escape_char(hl, &char, range.start()) } } @@ -455,32 +491,42 @@ fn traverse( } // apply config filtering - match &mut highlight.tag { - HlTag::StringLiteral if !config.strings => continue, - // If punctuation is disabled, make the macro bang part of the macro call again. - tag @ HlTag::Punctuation(HlPunct::MacroBang) => { - if !config.macro_bang { - *tag = HlTag::Symbol(SymbolKind::Macro); - } else if !config.specialize_punctuation { - *tag = HlTag::Punctuation(HlPunct::Other); - } - } - HlTag::Punctuation(_) if !config.punctuation => continue, - tag @ HlTag::Punctuation(_) if !config.specialize_punctuation => { - *tag = HlTag::Punctuation(HlPunct::Other); - } - HlTag::Operator(_) if !config.operator && highlight.mods.is_empty() => continue, - tag @ HlTag::Operator(_) if !config.specialize_operator => { - *tag = HlTag::Operator(HlOperator::Other); - } - _ => (), + if !filter_by_config(&mut highlight, config) { + continue; } if inside_attribute { highlight |= HlMod::Attribute } + if inside_macro_call && tt_level > 0 { + highlight |= HlMod::Macro + } hl.add(HlRange { range, highlight, binding_hash }); } } } + +fn filter_by_config(highlight: &mut Highlight, config: HighlightConfig) -> bool { + match &mut highlight.tag { + HlTag::StringLiteral if !config.strings => return false, + // If punctuation is disabled, make the macro bang part of the macro call again. + tag @ HlTag::Punctuation(HlPunct::MacroBang) => { + if !config.macro_bang { + *tag = HlTag::Symbol(SymbolKind::Macro); + } else if !config.specialize_punctuation { + *tag = HlTag::Punctuation(HlPunct::Other); + } + } + HlTag::Punctuation(_) if !config.punctuation => return false, + tag @ HlTag::Punctuation(_) if !config.specialize_punctuation => { + *tag = HlTag::Punctuation(HlPunct::Other); + } + HlTag::Operator(_) if !config.operator && highlight.mods.is_empty() => return false, + tag @ HlTag::Operator(_) if !config.specialize_operator => { + *tag = HlTag::Operator(HlOperator::Other); + } + _ => (), + } + true +} diff --git a/crates/ide/src/syntax_highlighting/escape.rs b/crates/ide/src/syntax_highlighting/escape.rs index 6a1236c793b83..211e3588095cf 100644 --- a/crates/ide/src/syntax_highlighting/escape.rs +++ b/crates/ide/src/syntax_highlighting/escape.rs @@ -1,8 +1,8 @@ //! Syntax highlighting for escape sequences use crate::syntax_highlighting::highlights::Highlights; use crate::{HlRange, HlTag}; -use syntax::ast::IsString; -use syntax::TextSize; +use syntax::ast::{Char, IsString}; +use syntax::{AstToken, TextRange, TextSize}; pub(super) fn highlight_escape_string( stack: &mut Highlights, @@ -23,3 +23,23 @@ pub(super) fn highlight_escape_string( } }); } + +pub(super) fn highlight_escape_char(stack: &mut Highlights, char: &Char, start: TextSize) { + if char.value().is_none() { + return; + } + + let text = char.text(); + if !text.starts_with('\'') || !text.ends_with('\'') { + return; + } + + let text = &text[1..text.len() - 1]; + if !text.starts_with('\\') { + return; + } + + let range = + TextRange::new(start + TextSize::from(1), start + TextSize::from(text.len() as u32 + 1)); + stack.add(HlRange { range, highlight: HlTag::EscapeSequence.into(), binding_hash: None }) +} diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs index 2111baad74d74..3c40246a69d37 100644 --- a/crates/ide/src/syntax_highlighting/highlight.rs +++ b/crates/ide/src/syntax_highlighting/highlight.rs @@ -26,7 +26,7 @@ pub(super) fn token(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> O } let highlight: Highlight = match token.kind() { - STRING | BYTE_STRING => HlTag::StringLiteral.into(), + STRING | BYTE_STRING | C_STRING => HlTag::StringLiteral.into(), INT_NUMBER if token.parent_ancestors().nth(1).map(|it| it.kind()) == Some(FIELD_EXPR) => { SymbolKind::Field.into() } @@ -340,7 +340,7 @@ fn highlight_def( Definition::Field(_) => Highlight::new(HlTag::Symbol(SymbolKind::Field)), Definition::Module(module) => { let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Module)); - if module.is_crate_root(db) { + if module.is_crate_root() { h |= HlMod::CrateRoot; } h @@ -675,14 +675,12 @@ fn is_consumed_lvalue(node: &SyntaxNode, local: &hir::Local, db: &RootDatabase) /// Returns true if the parent nodes of `node` all match the `SyntaxKind`s in `kinds` exactly. fn parents_match(mut node: NodeOrToken, mut kinds: &[SyntaxKind]) -> bool { - while let (Some(parent), [kind, rest @ ..]) = (&node.parent(), kinds) { + while let (Some(parent), [kind, rest @ ..]) = (node.parent(), kinds) { if parent.kind() != *kind { return false; } - // FIXME: Would be nice to get parent out of the match, but binding by-move and by-value - // in the same pattern is unstable: rust-lang/rust#68354. - node = node.parent().unwrap().into(); + node = parent.into(); kinds = rest; } diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs index 3c4cfc78152dd..901df147d32c0 100644 --- a/crates/ide/src/syntax_highlighting/inject.rs +++ b/crates/ide/src/syntax_highlighting/inject.rs @@ -52,7 +52,11 @@ pub(super) fn ra_fixture( if let Some(next) = text.strip_prefix(marker) { if let Some(range) = literal.map_range_up(TextRange::at(offset, TextSize::of(marker))) { - hl.add(HlRange { range, highlight: HlTag::Keyword.into(), binding_hash: None }); + hl.add(HlRange { + range, + highlight: HlTag::Keyword | HlMod::Injected, + binding_hash: None, + }); } text = next; @@ -66,7 +70,16 @@ pub(super) fn ra_fixture( for mut hl_range in analysis .highlight( - HighlightConfig { syntactic_name_ref_highlighting: false, ..config }, + HighlightConfig { + syntactic_name_ref_highlighting: false, + punctuation: true, + operator: true, + strings: true, + specialize_punctuation: config.specialize_punctuation, + specialize_operator: config.operator, + inject_doc_comment: config.inject_doc_comment, + macro_bang: config.macro_bang, + }, tmp_file_id, ) .unwrap() @@ -74,6 +87,7 @@ pub(super) fn ra_fixture( for range in inj.map_range_up(hl_range.range) { if let Some(range) = literal.map_range_up(range) { hl_range.range = range; + hl_range.highlight |= HlMod::Injected; hl.add(hl_range); } } @@ -217,7 +231,16 @@ pub(super) fn doc_comment( if let Ok(ranges) = analysis.with_db(|db| { super::highlight( db, - HighlightConfig { syntactic_name_ref_highlighting: true, ..config }, + HighlightConfig { + syntactic_name_ref_highlighting: true, + punctuation: true, + operator: true, + strings: true, + specialize_punctuation: config.specialize_punctuation, + specialize_operator: config.operator, + inject_doc_comment: config.inject_doc_comment, + macro_bang: config.macro_bang, + }, tmp_file_id, None, ) diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs index a81c4ee0cbd41..f983109115f6c 100644 --- a/crates/ide/src/syntax_highlighting/tags.rs +++ b/crates/ide/src/syntax_highlighting/tags.rs @@ -49,7 +49,7 @@ pub enum HlMod { Associated = 0, /// Used with keywords like `async` and `await`. Async, - /// Used to differentiate individual elements within attributes. + /// Used to differentiate individual elements within attribute calls. Attribute, /// Callable item or value. Callable, @@ -72,6 +72,8 @@ pub enum HlMod { IntraDocLink, /// Used for items from other crates. Library, + /// Used to differentiate individual elements within macro calls. + Macro, /// Mutable binding. Mutable, /// Used for public items. @@ -200,7 +202,7 @@ impl fmt::Display for HlTag { } impl HlMod { - const ALL: &'static [HlMod; 19] = &[ + const ALL: &'static [HlMod; HlMod::Unsafe as usize + 1] = &[ HlMod::Associated, HlMod::Async, HlMod::Attribute, @@ -214,6 +216,7 @@ impl HlMod { HlMod::Injected, HlMod::IntraDocLink, HlMod::Library, + HlMod::Macro, HlMod::Mutable, HlMod::Public, HlMod::Reference, @@ -237,6 +240,7 @@ impl HlMod { HlMod::Injected => "injected", HlMod::IntraDocLink => "intra_doc_link", HlMod::Library => "library", + HlMod::Macro => "macro", HlMod::Mutable => "mutable", HlMod::Public => "public", HlMod::Reference => "reference", diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html index 18045f1f55afd..35f240d428471 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html @@ -93,7 +93,7 @@ /// let foo = Foo::new(); /// /// // calls bar on foo - /// assert!(foo.bar()); + /// assert!(foo.bar()); /// /// let bar = foo.bar || Foo::bar; /// @@ -145,7 +145,7 @@ /// ``` /// macro_rules! noop { ($expr:expr) => { $expr }} -/// noop!(1); +/// noop!(1); /// ``` macro_rules! noop { ($expr:expr) => { @@ -165,7 +165,7 @@ /// #[cfg_attr(feature = "alloc", doc = "```rust")] #[cfg_attr(not(feature = "alloc"), doc = "```ignore")] -/// let _ = example(&alloc::vec![1, 2, 3]); +/// let _ = example(&alloc::vec![1, 2, 3]); /// ``` pub fn mix_and_match() {} diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html index af41796e2169b..87b9da46e2cc8 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html @@ -43,5 +43,5 @@ .unresolved_reference { color: #FC5555; text-decoration: wavy underline; }

extern crate std;
-extern crate alloc as abc;
+extern crate alloc as abc;
 
\ No newline at end of file diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html index 9f2b1926b511d..6b049f379ac1d 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html @@ -178,7 +178,7 @@ impl<T> Option<T> { fn and<U>(self, other: Option<U>) -> Option<(T, U)> { match other { - None => unimplemented!(), + None => unimplemented!(), Nope => Nope, } } @@ -192,7 +192,7 @@ async fn async_main() { let f1 = learn_and_sing(); let f2 = dance(); - futures::join!(f1, f2); + futures::join!(f1, f2); } fn use_foo_items() { @@ -204,7 +204,7 @@ let control_flow = foo::identity(foo::ControlFlow::Continue); if control_flow.should_die() { - foo::die!(); + foo::die!(); } } diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html index abcd80c280bf3..d9c3db6fbb510 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html @@ -45,18 +45,18 @@
fn fixture(ra_fixture: &str) {}
 
 fn main() {
-    fixture(r#"
-trait Foo {
-    fn foo() {
-        println!("2 + 2 = {}", 4);
-    }
-}"#
+    fixture(r#"
+trait Foo {
+    fn foo() {
+        println!("2 + 2 = {}", 4);
+    }
+}"#
     );
-    fixture(r"
-fn foo() {
-    foo($0{
-        92
-    }$0)
-}"
+    fixture(r"
+fn foo() {
+    foo($0{
+        92
+    }$0)
+}"
     );
 }
\ No newline at end of file diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html index 66f9ede96295f..3900959bedf8d 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html @@ -53,6 +53,6 @@ macro_rules! void { ($($tt:tt)*) => {} } -void!(Self); +void!(Self); struct __ where Self:; fn __(_: Self) {} \ No newline at end of file diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html index 54d4279525dd5..2cbbf69641525 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html @@ -42,21 +42,21 @@ .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } -
proc_macros::mirror! {
-    {
-        ,i32 :x pub
-        ,i32 :y pub
-    } Foo struct
-}
+
proc_macros::mirror! {
+    {
+        ,i32 :x pub
+        ,i32 :y pub
+    } Foo struct
+}
 macro_rules! def_fn {
     ($($tt:tt)*) => {$($tt)*}
 }
 
-def_fn! {
-    fn bar() -> u32 {
-        100
-    }
-}
+def_fn! {
+    fn bar() -> u32 {
+        100
+    }
+}
 
 macro_rules! dont_color_me_braces {
     () => {0}
@@ -90,7 +90,7 @@
 }
 
 fn main() {
-    println!("Hello, {}!", 92);
-    dont_color_me_braces!();
-    noop!(noop!(1));
+    println!("Hello, {}!", 92);
+    dont_color_me_braces!();
+    noop!(noop!(1));
 }
\ No newline at end of file diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index a626cda3fe8b4..327e1502d19e0 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html @@ -93,72 +93,83 @@ } fn main() { - println!("Hello {{Hello}}"); + let a = '\n'; + let a = '\t'; + let a = '\e'; // invalid escape + let a = 'e'; + let a = ' '; + let a = '\u{48}'; + let a = '\u{4823}'; + let a = '\x65'; + let a = '\x00'; + + println!("Hello {{Hello}}"); // from https://doc.rust-lang.org/std/fmt/index.html - println!("Hello"); // => "Hello" - println!("Hello, {}!", "world"); // => "Hello, world!" - println!("The number is {}", 1); // => "The number is 1" - println!("{:?}", (3, 4)); // => "(3, 4)" - println!("{value}", value=4); // => "4" - println!("{} {}", 1, 2); // => "1 2" - println!("{:04}", 42); // => "0042" with leading zerosV - println!("{1} {} {0} {}", 1, 2); // => "2 1 1 2" - println!("{argument}", argument = "test"); // => "test" - println!("{name} {}", 1, name = 2); // => "2 1" - println!("{a} {c} {b}", a="a", b='b', c=3); // => "a 3 b" - println!("{{{}}}", 2); // => "{2}" - println!("Hello {:5}!", "x"); - println!("Hello {:1$}!", "x", 5); - println!("Hello {1:0$}!", 5, "x"); - println!("Hello {:width$}!", "x", width = 5); - println!("Hello {:<5}!", "x"); - println!("Hello {:-<5}!", "x"); - println!("Hello {:^5}!", "x"); - println!("Hello {:>5}!", "x"); - println!("Hello {:+}!", 5); - println!("{:#x}!", 27); - println!("Hello {:05}!", 5); - println!("Hello {:05}!", -5); - println!("{:#010x}!", 27); - println!("Hello {0} is {1:.5}", "x", 0.01); - println!("Hello {1} is {2:.0$}", 5, "x", 0.01); - println!("Hello {0} is {2:.1$}", "x", 5, 0.01); - println!("Hello {} is {:.*}", "x", 5, 0.01); - println!("Hello {} is {2:.*}", "x", 5, 0.01); - println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01); - println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56); - println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56"); - println!("{}, `{name:>8.*}` has 3 right-aligned characters", "Hello", 3, name="1234.56"); + println!("Hello"); // => "Hello" + println!("Hello, {}!", "world"); // => "Hello, world!" + println!("The number is {}", 1); // => "The number is 1" + println!("{:?}", (3, 4)); // => "(3, 4)" + println!("{value}", value=4); // => "4" + println!("{} {}", 1, 2); // => "1 2" + println!("{:04}", 42); // => "0042" with leading zerosV + println!("{1} {} {0} {}", 1, 2); // => "2 1 1 2" + println!("{argument}", argument = "test"); // => "test" + println!("{name} {}", 1, name = 2); // => "2 1" + println!("{a} {c} {b}", a="a", b='b', c=3); // => "a 3 b" + println!("{{{}}}", 2); // => "{2}" + println!("Hello {:5}!", "x"); + println!("Hello {:1$}!", "x", 5); + println!("Hello {1:0$}!", 5, "x"); + println!("Hello {:width$}!", "x", width = 5); + println!("Hello {:<5}!", "x"); + println!("Hello {:-<5}!", "x"); + println!("Hello {:^5}!", "x"); + println!("Hello {:>5}!", "x"); + println!("Hello {:+}!", 5); + println!("{:#x}!", 27); + println!("Hello {:05}!", 5); + println!("Hello {:05}!", -5); + println!("{:#010x}!", 27); + println!("Hello {0} is {1:.5}", "x", 0.01); + println!("Hello {1} is {2:.0$}", 5, "x", 0.01); + println!("Hello {0} is {2:.1$}", "x", 5, 0.01); + println!("Hello {} is {:.*}", "x", 5, 0.01); + println!("Hello {} is {2:.*}", "x", 5, 0.01); + println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01); + println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56); + println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56"); + println!("{}, `{name:>8.*}` has 3 right-aligned characters", "Hello", 3, name="1234.56"); let _ = "{}" let _ = "{{}}"; - println!("Hello {{}}"); - println!("{{ Hello"); - println!("Hello }}"); - println!("{{Hello}}"); - println!("{{ Hello }}"); - println!("{{Hello }}"); - println!("{{ Hello}}"); + println!("Hello {{}}"); + println!("{{ Hello"); + println!("Hello }}"); + println!("{{Hello}}"); + println!("{{ Hello }}"); + println!("{{Hello }}"); + println!("{{ Hello}}"); - println!(r"Hello, {}!", "world"); + println!(r"Hello, {}!", "world"); // escape sequences - println!("Hello\nWorld"); - println!("\u{48}\x65\x6C\x6C\x6F World"); + println!("Hello\nWorld"); + println!("\u{48}\x65\x6C\x6C\x6F World"); let _ = "\x28\x28\x00\x63\n"; let _ = b"\x28\x28\x00\x63\n"; + let _ = r"\\"; - println!("{\x41}", A = 92); - println!("{ничоси}", ничоси = 92); + println!("{\x41}", A = 92); + println!("{ничоси}", ничоси = 92); - println!("{:x?} {} ", thingy, n2); - panic!("{}", 0); - panic!("more {}", 1); - assert!(true, "{}", 1); - assert!(true, "{} asdasd", 1); - toho!("{}fmt", 0); - asm!("mov eax, {0}"); - format_args!(concat!("{}"), "{}"); + println!("{:x?} {} ", thingy, n2); + panic!("{}", 0); + panic!("more {}", 1); + assert!(true, "{}", 1); + assert!(true, "{} asdasd", 1); + toho!("{}fmt", 0); + asm!("mov eax, {0}"); + format_args!(concat!("{}"), "{}"); }
\ No newline at end of file diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html index 1992bdc6ae35f..654d51b8a43d9 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html @@ -89,13 +89,13 @@ let x = &5 as *const _ as *const usize; let u = Union { b: 0 }; - id! { - unsafe { unsafe_deref!() } - }; + id! { + unsafe { unsafe_deref!() } + }; unsafe { - unsafe_deref!(); - id! { unsafe_deref!() }; + unsafe_deref!(); + id! { unsafe_deref!() }; // unsafe fn and method calls unsafe_fn(); diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index ac9bd8e39dc02..887d18b989a14 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -439,6 +439,16 @@ macro_rules! toho { } fn main() { + let a = '\n'; + let a = '\t'; + let a = '\e'; // invalid escape + let a = 'e'; + let a = ' '; + let a = '\u{48}'; + let a = '\u{4823}'; + let a = '\x65'; + let a = '\x00'; + println!("Hello {{Hello}}"); // from https://doc.rust-lang.org/std/fmt/index.html println!("Hello"); // => "Hello" @@ -495,6 +505,7 @@ fn main() { let _ = "\x28\x28\x00\x63\n"; let _ = b"\x28\x28\x00\x63\n"; + let _ = r"\\"; println!("{\x41}", A = 92); println!("{ничоси}", ничоси = 92); @@ -1126,5 +1137,5 @@ fn benchmark_syntax_highlighting_parser() { .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Function)) .count() }; - assert_eq!(hash, 1608); + assert_eq!(hash, 1169); } diff --git a/crates/ide/src/syntax_tree.rs b/crates/ide/src/syntax_tree.rs index bb6827e8a44e4..df1971242657d 100644 --- a/crates/ide/src/syntax_tree.rs +++ b/crates/ide/src/syntax_tree.rs @@ -1,5 +1,7 @@ -use ide_db::base_db::{FileId, SourceDatabase}; -use ide_db::RootDatabase; +use ide_db::{ + base_db::{FileId, SourceDatabase}, + RootDatabase, +}; use syntax::{ AstNode, NodeOrToken, SourceFile, SyntaxKind::STRING, SyntaxToken, TextRange, TextSize, }; diff --git a/crates/ide/src/view_crate_graph.rs b/crates/ide/src/view_crate_graph.rs index 17a1e385b7724..8c84461f659f7 100644 --- a/crates/ide/src/view_crate_graph.rs +++ b/crates/ide/src/view_crate_graph.rs @@ -1,11 +1,9 @@ -use std::sync::Arc; - use dot::{Id, LabelText}; use ide_db::{ base_db::{CrateGraph, CrateId, Dependency, SourceDatabase, SourceDatabaseExt}, - RootDatabase, + FxHashSet, RootDatabase, }; -use stdx::hash::NoHashHashSet; +use triomphe::Arc; // Feature: View Crate Graph // @@ -42,7 +40,7 @@ pub(crate) fn view_crate_graph(db: &RootDatabase, full: bool) -> Result, - crates_to_render: NoHashHashSet, + crates_to_render: FxHashSet, } type Edge<'a> = (CrateId, &'a Dependency); @@ -80,7 +78,7 @@ impl<'a> dot::Labeller<'a, CrateId, Edge<'a>> for DotCrateGraph { } fn node_id(&'a self, n: &CrateId) -> Id<'a> { - Id::new(format!("_{}", n.0)).unwrap() + Id::new(format!("_{}", u32::from(n.into_raw()))).unwrap() } fn node_shape(&'a self, _node: &CrateId) -> Option> { diff --git a/crates/ide/src/view_item_tree.rs b/crates/ide/src/view_item_tree.rs index 9c1f93356ee2d..e072df430fc0d 100644 --- a/crates/ide/src/view_item_tree.rs +++ b/crates/ide/src/view_item_tree.rs @@ -12,5 +12,5 @@ use ide_db::RootDatabase; // | VS Code | **rust-analyzer: Debug ItemTree** // |=== pub(crate) fn view_item_tree(db: &RootDatabase, file_id: FileId) -> String { - db.file_item_tree(file_id.into()).pretty_print() + db.file_item_tree(file_id.into()).pretty_print(db) } diff --git a/crates/intern/Cargo.toml b/crates/intern/Cargo.toml index c73c368a14e0c..dcd0d78812554 100644 --- a/crates/intern/Cargo.toml +++ b/crates/intern/Cargo.toml @@ -18,3 +18,4 @@ dashmap = { version = "=5.4.0", features = ["raw-api"] } hashbrown = { version = "0.12.1", default-features = false } once_cell = "1.17.0" rustc-hash = "1.1.0" +triomphe.workspace = true diff --git a/crates/intern/src/lib.rs b/crates/intern/src/lib.rs index fb2903696b373..dabbf3a38b502 100644 --- a/crates/intern/src/lib.rs +++ b/crates/intern/src/lib.rs @@ -6,13 +6,13 @@ use std::{ fmt::{self, Debug, Display}, hash::{BuildHasherDefault, Hash, Hasher}, ops::Deref, - sync::Arc, }; use dashmap::{DashMap, SharedValue}; -use hashbrown::HashMap; +use hashbrown::{hash_map::RawEntryMut, HashMap}; use once_cell::sync::OnceCell; use rustc_hash::FxHasher; +use triomphe::Arc; type InternMap = DashMap, (), BuildHasherDefault>; type Guard = dashmap::RwLockWriteGuard< @@ -26,56 +26,58 @@ pub struct Interned { impl Interned { pub fn new(obj: T) -> Self { - match Interned::lookup(&obj) { - Ok(this) => this, - Err(shard) => { - let arc = Arc::new(obj); - Self::alloc(arc, shard) - } + let (mut shard, hash) = Self::select(&obj); + // Atomically, + // - check if `obj` is already in the map + // - if so, clone its `Arc` and return it + // - if not, box it up, insert it, and return a clone + // This needs to be atomic (locking the shard) to avoid races with other thread, which could + // insert the same object between us looking it up and inserting it. + match shard.raw_entry_mut().from_key_hashed_nocheck(hash as u64, &obj) { + RawEntryMut::Occupied(occ) => Self { arc: occ.key().clone() }, + RawEntryMut::Vacant(vac) => Self { + arc: vac + .insert_hashed_nocheck(hash as u64, Arc::new(obj), SharedValue::new(())) + .0 + .clone(), + }, } } } -impl Interned { - fn lookup(obj: &T) -> Result> { - let storage = T::storage().get(); - let shard_idx = storage.determine_map(obj); - let shard = &storage.shards()[shard_idx]; - let shard = shard.write(); - +impl Interned { + pub fn new_str(s: &str) -> Self { + let (mut shard, hash) = Self::select(s); // Atomically, // - check if `obj` is already in the map // - if so, clone its `Arc` and return it // - if not, box it up, insert it, and return a clone // This needs to be atomic (locking the shard) to avoid races with other thread, which could // insert the same object between us looking it up and inserting it. - - // FIXME: avoid double lookup/hashing by using raw entry API (once stable, or when - // hashbrown can be plugged into dashmap) - match shard.get_key_value(obj) { - Some((arc, _)) => Ok(Self { arc: arc.clone() }), - None => Err(shard), + match shard.raw_entry_mut().from_key_hashed_nocheck(hash as u64, s) { + RawEntryMut::Occupied(occ) => Self { arc: occ.key().clone() }, + RawEntryMut::Vacant(vac) => Self { + arc: vac + .insert_hashed_nocheck(hash as u64, Arc::from(s), SharedValue::new(())) + .0 + .clone(), + }, } } - - fn alloc(arc: Arc, mut shard: Guard) -> Self { - let arc2 = arc.clone(); - - shard.insert(arc2, SharedValue::new(())); - - Self { arc } - } } -impl Interned { - pub fn new_str(s: &str) -> Self { - match Interned::lookup(s) { - Ok(this) => this, - Err(shard) => { - let arc = Arc::::from(s); - Self::alloc(arc, shard) - } - } +impl Interned { + #[inline] + fn select(obj: &T) -> (Guard, u64) { + let storage = T::storage().get(); + let hash = { + let mut hasher = std::hash::BuildHasher::build_hasher(storage.hasher()); + obj.hash(&mut hasher); + hasher.finish() + }; + let shard_idx = storage.determine_shard(hash as usize); + let shard = &storage.shards()[shard_idx]; + (shard.write(), hash) } } @@ -83,7 +85,7 @@ impl Drop for Interned { #[inline] fn drop(&mut self) { // When the last `Ref` is dropped, remove the object from the global map. - if Arc::strong_count(&self.arc) == 2 { + if Arc::count(&self.arc) == 2 { // Only `self` and the global map point to the object. self.drop_slow(); @@ -94,20 +96,17 @@ impl Drop for Interned { impl Interned { #[cold] fn drop_slow(&mut self) { - let storage = T::storage().get(); - let shard_idx = storage.determine_map(&self.arc); - let shard = &storage.shards()[shard_idx]; - let mut shard = shard.write(); - - // FIXME: avoid double lookup - let (arc, _) = shard.get_key_value(&self.arc).expect("interned value removed prematurely"); + let (mut shard, hash) = Self::select(&self.arc); - if Arc::strong_count(arc) != 2 { + if Arc::count(&self.arc) != 2 { // Another thread has interned another copy return; } - shard.remove(&self.arc); + match shard.raw_entry_mut().from_key_hashed_nocheck(hash, &self.arc) { + RawEntryMut::Occupied(occ) => occ.remove(), + RawEntryMut::Vacant(_) => unreachable!(), + }; // Shrink the backing storage if the shard is less than 50% occupied. if shard.len() * 2 < shard.capacity() { diff --git a/crates/limit/src/lib.rs b/crates/limit/src/lib.rs index 6b2534aa4619d..7fb4b513a7157 100644 --- a/crates/limit/src/lib.rs +++ b/crates/limit/src/lib.rs @@ -6,6 +6,7 @@ use std::sync::atomic::AtomicUsize; /// Represents a struct used to enforce a numerical limit. +#[derive(Debug)] pub struct Limit { upper_bound: usize, #[cfg(feature = "tracking")] diff --git a/crates/mbe/src/benchmark.rs b/crates/mbe/src/benchmark.rs index 894355fcbc9b3..d28dd17def378 100644 --- a/crates/mbe/src/benchmark.rs +++ b/crates/mbe/src/benchmark.rs @@ -20,7 +20,10 @@ fn benchmark_parse_macro_rules() { let rules = macro_rules_fixtures_tt(); let hash: usize = { let _pt = bench("mbe parse macro rules"); - rules.values().map(|it| DeclarativeMacro::parse_macro_rules(it).unwrap().rules.len()).sum() + rules + .values() + .map(|it| DeclarativeMacro::parse_macro_rules(it, true).unwrap().rules.len()) + .sum() }; assert_eq!(hash, 1144); } @@ -50,7 +53,7 @@ fn benchmark_expand_macro_rules() { fn macro_rules_fixtures() -> FxHashMap { macro_rules_fixtures_tt() .into_iter() - .map(|(id, tt)| (id, DeclarativeMacro::parse_macro_rules(&tt).unwrap())) + .map(|(id, tt)| (id, DeclarativeMacro::parse_macro_rules(&tt, true).unwrap())) .collect() } @@ -76,7 +79,7 @@ fn invocation_fixtures(rules: &FxHashMap) -> Vec<(Stri let mut res = Vec::new(); for (name, it) in rules { - for rule in &it.rules { + for rule in it.rules.iter() { // Generate twice for _ in 0..2 { // The input are generated by filling the `Op` randomly. @@ -108,7 +111,7 @@ fn invocation_fixtures(rules: &FxHashMap) -> Vec<(Stri } try_cnt += 1; if try_cnt > 100 { - panic!("invocaton fixture {name} cannot be generated.\n"); + panic!("invocation fixture {name} cannot be generated.\n"); } } } @@ -192,10 +195,10 @@ fn invocation_fixtures(rules: &FxHashMap) -> Vec<(Stri }); parent.token_trees.push(subtree.into()); } - Op::Ignore { .. } | Op::Index { .. } => {} + Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } => {} }; - // Simple linear congruential generator for determistic result + // Simple linear congruential generator for deterministic result fn rand(seed: &mut usize) -> usize { let a = 1664525; let c = 1013904223; diff --git a/crates/mbe/src/expander.rs b/crates/mbe/src/expander.rs index 7537dc3226149..8e2181e977e1d 100644 --- a/crates/mbe/src/expander.rs +++ b/crates/mbe/src/expander.rs @@ -13,10 +13,11 @@ use crate::{parser::MetaVarKind, tt, ExpandError, ExpandResult}; pub(crate) fn expand_rules( rules: &[crate::Rule], input: &tt::Subtree, + is_2021: bool, ) -> ExpandResult { let mut match_: Option<(matcher::Match, &crate::Rule)> = None; for rule in rules { - let new_match = matcher::match_(&rule.lhs, input); + let new_match = matcher::match_(&rule.lhs, input, is_2021); if new_match.err.is_none() { // If we find a rule that applies without errors, we're done. @@ -45,7 +46,7 @@ pub(crate) fn expand_rules( transcriber::transcribe(&rule.rhs, &match_.bindings); ExpandResult { value, err: match_.err.or(transcribe_err) } } else { - ExpandResult::with_err( + ExpandResult::new( tt::Subtree { delimiter: tt::Delimiter::unspecified(), token_trees: vec![] }, ExpandError::NoMatchingRule, ) diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs index f4ea9e5c81658..474826079d733 100644 --- a/crates/mbe/src/expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs @@ -111,8 +111,8 @@ impl Match { } /// Matching errors are added to the `Match`. -pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree) -> Match { - let mut res = match_loop(pattern, input); +pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree, is_2021: bool) -> Match { + let mut res = match_loop(pattern, input, is_2021); res.bound_count = count(res.bindings.bindings()); return res; @@ -332,7 +332,7 @@ struct MatchState<'t> { /// Cached result of meta variable parsing meta_result: Option<(TtIter<'t>, ExpandResult>)>, - /// Is error occuried in this state, will `poised` to "parent" + /// Is error occurred in this state, will `poised` to "parent" is_error: bool, } @@ -354,6 +354,7 @@ struct MatchState<'t> { /// - `eof_items`: the set of items that would be valid if this was the EOF. /// - `bb_items`: the set of items that are waiting for the black-box parser. /// - `error_items`: the set of items in errors, used for error-resilient parsing +#[inline] fn match_loop_inner<'t>( src: TtIter<'t>, stack: &[TtIter<'t>], @@ -364,6 +365,7 @@ fn match_loop_inner<'t>( next_items: &mut Vec>, eof_items: &mut SmallVec<[MatchState<'t>; 1]>, error_items: &mut SmallVec<[MatchState<'t>; 1]>, + is_2021: bool, ) { macro_rules! try_push { ($items: expr, $it:expr) => { @@ -474,7 +476,7 @@ fn match_loop_inner<'t>( OpDelimited::Op(Op::Var { kind, name, .. }) => { if let &Some(kind) = kind { let mut fork = src.clone(); - let match_res = match_meta_var(kind, &mut fork); + let match_res = match_meta_var(kind, &mut fork, is_2021); match match_res.err { None => { // Some meta variables are optional (e.g. vis) @@ -565,7 +567,9 @@ fn match_loop_inner<'t>( item.is_error = true; error_items.push(item); } - OpDelimited::Op(Op::Ignore { .. } | Op::Index { .. }) => {} + OpDelimited::Op(Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. }) => { + stdx::never!("metavariable expression in lhs found"); + } OpDelimited::Open => { if matches!(src.peek_n(0), Some(tt::TokenTree::Subtree(..))) { item.dot.next(); @@ -583,7 +587,7 @@ fn match_loop_inner<'t>( } } -fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match { +fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree, is_2021: bool) -> Match { let mut src = TtIter::new(src); let mut stack: SmallVec<[TtIter<'_>; 1]> = SmallVec::new(); let mut res = Match::default(); @@ -622,6 +626,7 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match { &mut next_items, &mut eof_items, &mut error_items, + is_2021, ); stdx::always!(cur_items.is_empty()); @@ -731,14 +736,17 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match { } } -fn match_meta_var(kind: MetaVarKind, input: &mut TtIter<'_>) -> ExpandResult> { +fn match_meta_var( + kind: MetaVarKind, + input: &mut TtIter<'_>, + is_2021: bool, +) -> ExpandResult> { let fragment = match kind { MetaVarKind::Path => parser::PrefixEntryPoint::Path, MetaVarKind::Ty => parser::PrefixEntryPoint::Ty, - // FIXME: These two should actually behave differently depending on the edition. - // - // https://doc.rust-lang.org/edition-guide/rust-2021/or-patterns-macro-rules.html - MetaVarKind::Pat | MetaVarKind::PatParam => parser::PrefixEntryPoint::Pat, + MetaVarKind::Pat if is_2021 => parser::PrefixEntryPoint::PatTop, + MetaVarKind::Pat => parser::PrefixEntryPoint::Pat, + MetaVarKind::PatParam => parser::PrefixEntryPoint::Pat, MetaVarKind::Stmt => parser::PrefixEntryPoint::Stmt, MetaVarKind::Block => parser::PrefixEntryPoint::Block, MetaVarKind::Meta => parser::PrefixEntryPoint::MetaItem, @@ -805,7 +813,9 @@ fn collect_vars(collector_fun: &mut impl FnMut(SmolStr), pattern: &MetaTemplate) Op::Var { name, .. } => collector_fun(name.clone()), Op::Subtree { tokens, .. } => collect_vars(collector_fun, tokens), Op::Repeat { tokens, .. } => collect_vars(collector_fun, tokens), - Op::Ignore { .. } | Op::Index { .. } | Op::Literal(_) | Op::Ident(_) | Op::Punct(_) => { + Op::Literal(_) | Op::Ident(_) | Op::Punct(_) => {} + Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } => { + stdx::never!("metavariable expression in lhs found"); } } } diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs index dffb40d4bc886..6161af185871d 100644 --- a/crates/mbe/src/expander/transcriber.rs +++ b/crates/mbe/src/expander/transcriber.rs @@ -7,7 +7,7 @@ use crate::{ expander::{Binding, Bindings, Fragment}, parser::{MetaVarKind, Op, RepeatKind, Separator}, tt::{self, Delimiter}, - ExpandError, ExpandResult, MetaTemplate, + CountError, ExpandError, ExpandResult, MetaTemplate, }; impl Bindings { @@ -15,13 +15,23 @@ impl Bindings { self.inner.contains_key(name) } - fn get(&self, name: &str, nesting: &mut [NestingState]) -> Result { + fn get(&self, name: &str) -> Result<&Binding, ExpandError> { + match self.inner.get(name) { + Some(binding) => Ok(binding), + None => Err(ExpandError::binding_error(format!("could not find binding `{name}`"))), + } + } + + fn get_fragment( + &self, + name: &str, + nesting: &mut [NestingState], + ) -> Result { macro_rules! binding_err { ($($arg:tt)*) => { ExpandError::binding_error(format!($($arg)*)) }; } - let mut b: &Binding = - self.inner.get(name).ok_or_else(|| binding_err!("could not find binding `{name}`"))?; + let mut b = self.get(name)?; for nesting_state in nesting.iter_mut() { nesting_state.hit = true; b = match b { @@ -133,7 +143,7 @@ fn expand_subtree( // remember how many elements are in the arena now - when returning, we want to drain exactly how many elements we added. This way, the recursive uses of the arena get their own "view" of the arena, but will reuse the allocation let start_elements = arena.len(); let mut err = None; - for op in template.iter() { + 'ops: for op in template.iter() { match op { Op::Literal(it) => arena.push(tt::Leaf::from(it.clone()).into()), Op::Ident(it) => arena.push(tt::Leaf::from(it.clone()).into()), @@ -161,13 +171,12 @@ fn expand_subtree( } Op::Ignore { name, id } => { // Expand the variable, but ignore the result. This registers the repetition count. + // FIXME: Any emitted errors are dropped. expand_var(ctx, name, *id); } Op::Index { depth } => { - let index = ctx - .nesting - .get(ctx.nesting.len() - 1 - (*depth as usize)) - .map_or(0, |nest| nest.idx); + let index = + ctx.nesting.get(ctx.nesting.len() - 1 - depth).map_or(0, |nest| nest.idx); arena.push( tt::Leaf::Literal(tt::Literal { text: index.to_string().into(), @@ -176,6 +185,65 @@ fn expand_subtree( .into(), ); } + Op::Count { name, depth } => { + let mut binding = match ctx.bindings.get(name.as_str()) { + Ok(b) => b, + Err(e) => { + if err.is_none() { + err = Some(e); + } + continue; + } + }; + for state in ctx.nesting.iter_mut() { + state.hit = true; + match binding { + Binding::Fragment(_) | Binding::Missing(_) => { + // `count()` will report an error. + break; + } + Binding::Nested(bs) => { + if let Some(b) = bs.get(state.idx) { + binding = b; + } else { + state.at_end = true; + continue 'ops; + } + } + Binding::Empty => { + state.at_end = true; + // FIXME: Breaking here and proceeding to `count()` isn't the most + // correct thing to do here. This could be a binding of some named + // fragment which we don't know the depth of, so `count()` will just + // return 0 for this no matter what `depth` is. See test + // `count_interaction_with_empty_binding` for example. + break; + } + } + } + + let c = match count(ctx, binding, 0, *depth) { + Ok(c) => c, + Err(e) => { + // XXX: It *might* make sense to emit a dummy integer value like `0` here. + // That would type inference a bit more robust in cases like + // `v[${count(t)}]` where index doesn't matter, but also coult also lead to + // wrong infefrence for cases like `tup.${count(t)}` where index itself + // does matter. + if err.is_none() { + err = Some(e.into()); + } + continue; + } + }; + arena.push( + tt::Leaf::Literal(tt::Literal { + text: c.to_string().into(), + span: tt::TokenId::unspecified(), + }) + .into(), + ); + } } } // drain the elements added in this instance of expand_subtree @@ -218,12 +286,9 @@ fn expand_var(ctx: &mut ExpandCtx<'_>, v: &SmolStr, id: tt::TokenId) -> ExpandRe .into(); ExpandResult::ok(Fragment::Tokens(tt)) } else { - ctx.bindings.get(v, &mut ctx.nesting).map_or_else( + ctx.bindings.get_fragment(v, &mut ctx.nesting).map_or_else( |e| ExpandResult { - value: Fragment::Tokens(tt::TokenTree::Subtree(tt::Subtree { - delimiter: tt::Delimiter::unspecified(), - token_trees: vec![], - })), + value: Fragment::Tokens(tt::TokenTree::Subtree(tt::Subtree::empty())), err: Some(e), }, ExpandResult::ok, @@ -245,6 +310,7 @@ fn expand_repeat( let limit = 65536; let mut has_seps = 0; let mut counter = 0; + let mut err = None; loop { let ExpandResult { value: mut t, err: e } = expand_subtree(ctx, template, None, arena); @@ -272,6 +338,7 @@ fn expand_repeat( } if e.is_some() { + err = err.or(e); continue; } @@ -317,7 +384,7 @@ fn expand_repeat( err: Some(ExpandError::UnexpectedToken), }; } - ExpandResult::ok(Fragment::Tokens(tt)) + ExpandResult { value: Fragment::Tokens(tt), err } } fn push_fragment(buf: &mut Vec, fragment: Fragment) { @@ -343,3 +410,34 @@ fn push_subtree(buf: &mut Vec, tt: tt::Subtree) { _ => buf.push(tt.into()), } } + +/// Handles `${count(t, depth)}`. `our_depth` is the recursion depth and `count_depth` is the depth +/// defined by the metavar expression. +fn count( + ctx: &ExpandCtx<'_>, + binding: &Binding, + our_depth: usize, + count_depth: Option, +) -> Result { + match binding { + Binding::Nested(bs) => match count_depth { + None => bs.iter().map(|b| count(ctx, b, our_depth + 1, None)).sum(), + Some(0) => Ok(bs.len()), + Some(d) => bs.iter().map(|b| count(ctx, b, our_depth + 1, Some(d - 1))).sum(), + }, + Binding::Empty => Ok(0), + Binding::Fragment(_) | Binding::Missing(_) => { + if our_depth == 0 { + // `${count(t)}` is placed inside the innermost repetition. This includes cases + // where `t` is not a repeated fragment. + Err(CountError::Misplaced) + } else if count_depth.is_none() { + Ok(1) + } else { + // We've reached at the innermost repeated fragment, but the user wants us to go + // further! + Err(CountError::OutOfBounds) + } + } + } +} diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs index ac107a0d6d6d1..5ef20ff8a9b05 100644 --- a/crates/mbe/src/lib.rs +++ b/crates/mbe/src/lib.rs @@ -19,6 +19,7 @@ mod benchmark; mod token_map; use ::tt::token_id as tt; +use stdx::impl_from; use std::fmt; @@ -69,7 +70,7 @@ impl fmt::Display for ParseError { } } -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Hash)] pub enum ExpandError { BindingError(Box>), LeftoverTokens, @@ -77,8 +78,11 @@ pub enum ExpandError { LimitExceeded, NoMatchingRule, UnexpectedToken, + CountError(CountError), } +impl_from!(CountError for ExpandError); + impl ExpandError { fn binding_error(e: impl Into>) -> ExpandError { ExpandError::BindingError(Box::new(e.into())) @@ -94,6 +98,23 @@ impl fmt::Display for ExpandError { ExpandError::ConversionError => f.write_str("could not convert tokens"), ExpandError::LimitExceeded => f.write_str("Expand exceed limit"), ExpandError::LeftoverTokens => f.write_str("leftover tokens"), + ExpandError::CountError(e) => e.fmt(f), + } + } +} + +// FIXME: Showing these errors could be nicer. +#[derive(Debug, PartialEq, Eq, Clone, Hash)] +pub enum CountError { + OutOfBounds, + Misplaced, +} + +impl fmt::Display for CountError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + CountError::OutOfBounds => f.write_str("${count} out of bounds"), + CountError::Misplaced => f.write_str("${count} misplaced"), } } } @@ -104,9 +125,12 @@ impl fmt::Display for ExpandError { /// and `$()*` have special meaning (see `Var` and `Repeat` data structures) #[derive(Clone, Debug, PartialEq, Eq)] pub struct DeclarativeMacro { - rules: Vec, + rules: Box<[Rule]>, /// Highest id of the token we have in TokenMap shift: Shift, + // This is used for correctly determining the behavior of the pat fragment + // FIXME: This should be tracked by hygiene of the fragment identifier! + is_2021: bool, } #[derive(Clone, Debug, PartialEq, Eq)] @@ -190,7 +214,10 @@ pub enum Origin { impl DeclarativeMacro { /// The old, `macro_rules! m {}` flavor. - pub fn parse_macro_rules(tt: &tt::Subtree) -> Result { + pub fn parse_macro_rules( + tt: &tt::Subtree, + is_2021: bool, + ) -> Result { // Note: this parsing can be implemented using mbe machinery itself, by // matching against `$($lhs:tt => $rhs:tt);*` pattern, but implementing // manually seems easier. @@ -211,11 +238,11 @@ impl DeclarativeMacro { validate(lhs)?; } - Ok(DeclarativeMacro { rules, shift: Shift::new(tt) }) + Ok(DeclarativeMacro { rules: rules.into_boxed_slice(), shift: Shift::new(tt), is_2021 }) } /// The new, unstable `macro m {}` flavor. - pub fn parse_macro2(tt: &tt::Subtree) -> Result { + pub fn parse_macro2(tt: &tt::Subtree, is_2021: bool) -> Result { let mut src = TtIter::new(tt); let mut rules = Vec::new(); @@ -244,14 +271,14 @@ impl DeclarativeMacro { validate(lhs)?; } - Ok(DeclarativeMacro { rules, shift: Shift::new(tt) }) + Ok(DeclarativeMacro { rules: rules.into_boxed_slice(), shift: Shift::new(tt), is_2021 }) } pub fn expand(&self, tt: &tt::Subtree) -> ExpandResult { // apply shift let mut tt = tt.clone(); self.shift.shift_all(&mut tt); - expander::expand_rules(&self.rules, &tt) + expander::expand_rules(&self.rules, &tt, self.is_2021) } pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId { @@ -324,12 +351,12 @@ pub struct ValueResult { } impl ValueResult { - pub fn ok(value: T) -> Self { - Self { value, err: None } + pub fn new(value: T, err: E) -> Self { + Self { value, err: Some(err) } } - pub fn with_err(value: T, err: E) -> Self { - Self { value, err: Some(err) } + pub fn ok(value: T) -> Self { + Self { value, err: None } } pub fn only_err(err: E) -> Self diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs index fd3d64719ac9a..7a143e7466a93 100644 --- a/crates/mbe/src/parser.rs +++ b/crates/mbe/src/parser.rs @@ -20,7 +20,7 @@ use crate::{tt, tt_iter::TtIter, ParseError}; /// Stuff to the right is a [`MetaTemplate`] template which is used to produce /// output. #[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) struct MetaTemplate(pub(crate) Vec); +pub(crate) struct MetaTemplate(pub(crate) Box<[Op]>); impl MetaTemplate { pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Result { @@ -44,7 +44,7 @@ impl MetaTemplate { res.push(op); } - Ok(MetaTemplate(res)) + Ok(MetaTemplate(res.into_boxed_slice())) } } @@ -52,7 +52,8 @@ impl MetaTemplate { pub(crate) enum Op { Var { name: SmolStr, kind: Option, id: tt::TokenId }, Ignore { name: SmolStr, id: tt::TokenId }, - Index { depth: u32 }, + Index { depth: usize }, + Count { name: SmolStr, depth: Option }, Repeat { tokens: MetaTemplate, kind: RepeatKind, separator: Option }, Subtree { tokens: MetaTemplate, delimiter: tt::Delimiter }, Literal(tt::Literal), @@ -295,9 +296,13 @@ fn parse_metavar_expr(src: &mut TtIter<'_>) -> Result { let ident = args.expect_ident()?; Op::Ignore { name: ident.text.clone(), id: ident.span } } - "index" => { - let depth = if args.len() == 0 { 0 } else { args.expect_u32_literal()? }; - Op::Index { depth } + "index" => Op::Index { depth: parse_depth(&mut args)? }, + "count" => { + let ident = args.expect_ident()?; + // `${count(t)}` and `${count(t,)}` have different meanings. Not sure if this is a bug + // but that's how it's implemented in rustc as of this writing. See rust-lang/rust#111904. + let depth = if try_eat_comma(&mut args) { Some(parse_depth(&mut args)?) } else { None }; + Op::Count { name: ident.text.clone(), depth } } _ => return Err(()), }; @@ -308,3 +313,22 @@ fn parse_metavar_expr(src: &mut TtIter<'_>) -> Result { Ok(op) } + +fn parse_depth(src: &mut TtIter<'_>) -> Result { + if src.len() == 0 { + Ok(0) + } else if let tt::Leaf::Literal(lit) = src.expect_literal()? { + // Suffixes are not allowed. + lit.text.parse().map_err(|_| ()) + } else { + Err(()) + } +} + +fn try_eat_comma(src: &mut TtIter<'_>) -> bool { + if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', .. }))) = src.peek_n(0) { + let _ = src.next(); + return true; + } + false +} diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs index fb5313401088d..8cbf0f8fc0bd4 100644 --- a/crates/mbe/src/syntax_bridge.rs +++ b/crates/mbe/src/syntax_bridge.rs @@ -190,20 +190,13 @@ fn convert_tokens(conv: &mut C) -> tt::Subtree { let kind = token.kind(conv); if kind == COMMENT { - if let Some(tokens) = conv.convert_doc_comment(&token) { - // FIXME: There has to be a better way to do this - // Add the comments token id to the converted doc string + // Since `convert_doc_comment` can fail, we need to peek the next id, so that we can + // figure out which token id to use for the doc comment, if it is converted successfully. + let next_id = conv.id_alloc().peek_next_id(); + if let Some(tokens) = conv.convert_doc_comment(&token, next_id) { let id = conv.id_alloc().alloc(range, synth_id); - result.extend(tokens.into_iter().map(|mut tt| { - if let tt::TokenTree::Subtree(sub) = &mut tt { - if let Some(tt::TokenTree::Leaf(tt::Leaf::Literal(lit))) = - sub.token_trees.get_mut(2) - { - lit.span = id - } - } - tt - })); + debug_assert_eq!(id, next_id); + result.extend(tokens); } continue; } @@ -382,49 +375,46 @@ fn doc_comment_text(comment: &ast::Comment) -> SmolStr { text.into() } -fn convert_doc_comment(token: &syntax::SyntaxToken) -> Option> { +fn convert_doc_comment( + token: &syntax::SyntaxToken, + span: tt::TokenId, +) -> Option> { cov_mark::hit!(test_meta_doc_comments); let comment = ast::Comment::cast(token.clone())?; let doc = comment.kind().doc?; // Make `doc="\" Comments\"" - let meta_tkns = vec![mk_ident("doc"), mk_punct('='), mk_doc_literal(&comment)]; + let meta_tkns = + vec![mk_ident("doc", span), mk_punct('=', span), mk_doc_literal(&comment, span)]; // Make `#![]` let mut token_trees = Vec::with_capacity(3); - token_trees.push(mk_punct('#')); + token_trees.push(mk_punct('#', span)); if let ast::CommentPlacement::Inner = doc { - token_trees.push(mk_punct('!')); + token_trees.push(mk_punct('!', span)); } token_trees.push(tt::TokenTree::from(tt::Subtree { - delimiter: tt::Delimiter { - open: tt::TokenId::UNSPECIFIED, - close: tt::TokenId::UNSPECIFIED, - kind: tt::DelimiterKind::Bracket, - }, + delimiter: tt::Delimiter { open: span, close: span, kind: tt::DelimiterKind::Bracket }, token_trees: meta_tkns, })); return Some(token_trees); // Helper functions - fn mk_ident(s: &str) -> tt::TokenTree { - tt::TokenTree::from(tt::Leaf::from(tt::Ident { - text: s.into(), - span: tt::TokenId::unspecified(), - })) + fn mk_ident(s: &str, span: tt::TokenId) -> tt::TokenTree { + tt::TokenTree::from(tt::Leaf::from(tt::Ident { text: s.into(), span })) } - fn mk_punct(c: char) -> tt::TokenTree { + fn mk_punct(c: char, span: tt::TokenId) -> tt::TokenTree { tt::TokenTree::from(tt::Leaf::from(tt::Punct { char: c, spacing: tt::Spacing::Alone, - span: tt::TokenId::unspecified(), + span, })) } - fn mk_doc_literal(comment: &ast::Comment) -> tt::TokenTree { - let lit = tt::Literal { text: doc_comment_text(comment), span: tt::TokenId::unspecified() }; + fn mk_doc_literal(comment: &ast::Comment, span: tt::TokenId) -> tt::TokenTree { + let lit = tt::Literal { text: doc_comment_text(comment), span }; tt::TokenTree::from(tt::Leaf::from(lit)) } @@ -480,6 +470,10 @@ impl TokenIdAlloc { } } } + + fn peek_next_id(&self) -> tt::TokenId { + tt::TokenId(self.next_id) + } } /// A raw token (straight from lexer) converter @@ -502,7 +496,11 @@ trait SrcToken: std::fmt::Debug { trait TokenConverter: Sized { type Token: SrcToken; - fn convert_doc_comment(&self, token: &Self::Token) -> Option>; + fn convert_doc_comment( + &self, + token: &Self::Token, + span: tt::TokenId, + ) -> Option>; fn bump(&mut self) -> Option<(Self::Token, TextRange)>; @@ -532,9 +530,9 @@ impl<'a> SrcToken> for usize { impl<'a> TokenConverter for RawConverter<'a> { type Token = usize; - fn convert_doc_comment(&self, &token: &usize) -> Option> { + fn convert_doc_comment(&self, &token: &usize, span: tt::TokenId) -> Option> { let text = self.lexed.text(token); - convert_doc_comment(&doc_comment(text)) + convert_doc_comment(&doc_comment(text), span) } fn bump(&mut self) -> Option<(Self::Token, TextRange)> { @@ -681,8 +679,12 @@ impl SrcToken for SynToken { impl TokenConverter for Converter { type Token = SynToken; - fn convert_doc_comment(&self, token: &Self::Token) -> Option> { - convert_doc_comment(token.token()?) + fn convert_doc_comment( + &self, + token: &Self::Token, + span: tt::TokenId, + ) -> Option> { + convert_doc_comment(token.token()?, span) } fn bump(&mut self) -> Option<(Self::Token, TextRange)> { diff --git a/crates/mbe/src/tt_iter.rs b/crates/mbe/src/tt_iter.rs index f744481f3aecb..59dbf156800d4 100644 --- a/crates/mbe/src/tt_iter.rs +++ b/crates/mbe/src/tt_iter.rs @@ -73,13 +73,6 @@ impl<'a> TtIter<'a> { } } - pub(crate) fn expect_u32_literal(&mut self) -> Result { - match self.expect_literal()? { - tt::Leaf::Literal(lit) => lit.text.parse().map_err(drop), - _ => Err(()), - } - } - pub(crate) fn expect_single_punct(&mut self) -> Result<&'a tt::Punct, ()> { match self.expect_leaf()? { tt::Leaf::Punct(it) => Ok(it), diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index 6e962abd75477..09e62c35278e9 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -13,7 +13,7 @@ doctest = false [dependencies] drop_bomb = "0.1.5" -rustc_lexer = { version = "727.0.0", package = "rustc-ap-rustc_lexer" } +rustc_lexer.workspace = true limit.workspace = true diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 15435a26cea98..1814e0e54c592 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -66,6 +66,10 @@ pub(crate) mod entry { patterns::pattern_single(p); } + pub(crate) fn pat_top(p: &mut Parser<'_>) { + patterns::pattern_top(p); + } + pub(crate) fn ty(p: &mut Parser<'_>) { types::type_(p); } @@ -218,17 +222,22 @@ fn opt_visibility(p: &mut Parser<'_>, in_tuple_field: bool) -> bool { // pub(self) struct S; // pub(super) struct S; + // test_err crate_visibility_empty_recover + // pub() struct S; + // test pub_parens_typepath // struct B(pub (super::A)); // struct B(pub (crate::A,)); - T![crate] | T![self] | T![super] | T![ident] if p.nth(2) != T![:] => { + T![crate] | T![self] | T![super] | T![ident] | T![')'] if p.nth(2) != T![:] => { // If we are in a tuple struct, then the parens following `pub` // might be an tuple field, not part of the visibility. So in that // case we don't want to consume an identifier. // test pub_tuple_field // struct MyStruct(pub (u32, u32)); - if !(in_tuple_field && matches!(p.nth(1), T![ident])) { + // struct MyStruct(pub (u32)); + // struct MyStruct(pub ()); + if !(in_tuple_field && matches!(p.nth(1), T![ident] | T![')'])) { p.bump(T!['(']); paths::use_path(p); p.expect(T![')']); @@ -243,7 +252,7 @@ fn opt_visibility(p: &mut Parser<'_>, in_tuple_field: bool) -> bool { paths::use_path(p); p.expect(T![')']); } - _ => (), + _ => {} } } m.complete(p, VISIBILITY); diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs index a884d8b6ec801..1cbd1663230bd 100644 --- a/crates/parser/src/grammar/expressions.rs +++ b/crates/parser/src/grammar/expressions.rs @@ -4,8 +4,8 @@ use crate::grammar::attributes::ATTRIBUTE_FIRST; use super::*; -pub(crate) use self::atom::{block_expr, match_arm_list}; -pub(super) use self::atom::{literal, LITERAL_FIRST}; +pub(crate) use atom::{block_expr, match_arm_list}; +pub(super) use atom::{literal, LITERAL_FIRST}; #[derive(PartialEq, Eq)] pub(super) enum Semicolon { @@ -188,47 +188,56 @@ struct Restrictions { prefer_stmt: bool, } +enum Associativity { + Left, + Right, +} + /// Binding powers of operators for a Pratt parser. /// /// See +/// +/// Note that Rust doesn't define associativity for some infix operators (e.g. `==` and `..`) and +/// requires parentheses to disambiguate. We just treat them as left associative. #[rustfmt::skip] -fn current_op(p: &Parser<'_>) -> (u8, SyntaxKind) { - const NOT_AN_OP: (u8, SyntaxKind) = (0, T![@]); +fn current_op(p: &Parser<'_>) -> (u8, SyntaxKind, Associativity) { + use Associativity::*; + const NOT_AN_OP: (u8, SyntaxKind, Associativity) = (0, T![@], Left); match p.current() { - T![|] if p.at(T![||]) => (3, T![||]), - T![|] if p.at(T![|=]) => (1, T![|=]), - T![|] => (6, T![|]), - T![>] if p.at(T![>>=]) => (1, T![>>=]), - T![>] if p.at(T![>>]) => (9, T![>>]), - T![>] if p.at(T![>=]) => (5, T![>=]), - T![>] => (5, T![>]), + T![|] if p.at(T![||]) => (3, T![||], Left), + T![|] if p.at(T![|=]) => (1, T![|=], Right), + T![|] => (6, T![|], Left), + T![>] if p.at(T![>>=]) => (1, T![>>=], Right), + T![>] if p.at(T![>>]) => (9, T![>>], Left), + T![>] if p.at(T![>=]) => (5, T![>=], Left), + T![>] => (5, T![>], Left), T![=] if p.at(T![=>]) => NOT_AN_OP, - T![=] if p.at(T![==]) => (5, T![==]), - T![=] => (1, T![=]), - T![<] if p.at(T![<=]) => (5, T![<=]), - T![<] if p.at(T![<<=]) => (1, T![<<=]), - T![<] if p.at(T![<<]) => (9, T![<<]), - T![<] => (5, T![<]), - T![+] if p.at(T![+=]) => (1, T![+=]), - T![+] => (10, T![+]), - T![^] if p.at(T![^=]) => (1, T![^=]), - T![^] => (7, T![^]), - T![%] if p.at(T![%=]) => (1, T![%=]), - T![%] => (11, T![%]), - T![&] if p.at(T![&=]) => (1, T![&=]), + T![=] if p.at(T![==]) => (5, T![==], Left), + T![=] => (1, T![=], Right), + T![<] if p.at(T![<=]) => (5, T![<=], Left), + T![<] if p.at(T![<<=]) => (1, T![<<=], Right), + T![<] if p.at(T![<<]) => (9, T![<<], Left), + T![<] => (5, T![<], Left), + T![+] if p.at(T![+=]) => (1, T![+=], Right), + T![+] => (10, T![+], Left), + T![^] if p.at(T![^=]) => (1, T![^=], Right), + T![^] => (7, T![^], Left), + T![%] if p.at(T![%=]) => (1, T![%=], Right), + T![%] => (11, T![%], Left), + T![&] if p.at(T![&=]) => (1, T![&=], Right), // If you update this, remember to update `expr_let()` too. - T![&] if p.at(T![&&]) => (4, T![&&]), - T![&] => (8, T![&]), - T![/] if p.at(T![/=]) => (1, T![/=]), - T![/] => (11, T![/]), - T![*] if p.at(T![*=]) => (1, T![*=]), - T![*] => (11, T![*]), - T![.] if p.at(T![..=]) => (2, T![..=]), - T![.] if p.at(T![..]) => (2, T![..]), - T![!] if p.at(T![!=]) => (5, T![!=]), - T![-] if p.at(T![-=]) => (1, T![-=]), - T![-] => (10, T![-]), - T![as] => (12, T![as]), + T![&] if p.at(T![&&]) => (4, T![&&], Left), + T![&] => (8, T![&], Left), + T![/] if p.at(T![/=]) => (1, T![/=], Right), + T![/] => (11, T![/], Left), + T![*] if p.at(T![*=]) => (1, T![*=], Right), + T![*] => (11, T![*], Left), + T![.] if p.at(T![..=]) => (2, T![..=], Left), + T![.] if p.at(T![..]) => (2, T![..], Left), + T![!] if p.at(T![!=]) => (5, T![!=], Left), + T![-] if p.at(T![-=]) => (1, T![-=], Right), + T![-] => (10, T![-], Left), + T![as] => (12, T![as], Left), _ => NOT_AN_OP } @@ -273,7 +282,7 @@ fn expr_bp( loop { let is_range = p.at(T![..]) || p.at(T![..=]); - let (op_bp, op) = current_op(p); + let (op_bp, op, associativity) = current_op(p); if op_bp < bp { break; } @@ -306,7 +315,11 @@ fn expr_bp( } } - expr_bp(p, None, Restrictions { prefer_stmt: false, ..r }, op_bp + 1); + let op_bp = match associativity { + Associativity::Left => op_bp + 1, + Associativity::Right => op_bp, + }; + expr_bp(p, None, Restrictions { prefer_stmt: false, ..r }, op_bp); lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); } Some((lhs, BlockLike::NotBlock)) @@ -417,7 +430,7 @@ fn postfix_expr( allow_calls = true; block_like = BlockLike::NotBlock; } - return (lhs, block_like); + (lhs, block_like) } fn postfix_dot_expr( diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs index d051dd2682f94..d8553d3f95377 100644 --- a/crates/parser/src/grammar/expressions/atom.rs +++ b/crates/parser/src/grammar/expressions/atom.rs @@ -12,6 +12,8 @@ use super::*; // let _ = r"d"; // let _ = b"e"; // let _ = br"f"; +// let _ = c"g"; +// let _ = cr"h"; // } pub(crate) const LITERAL_FIRST: TokenSet = TokenSet::new(&[ T![true], @@ -22,6 +24,7 @@ pub(crate) const LITERAL_FIRST: TokenSet = TokenSet::new(&[ CHAR, STRING, BYTE_STRING, + C_STRING, ]); pub(crate) fn literal(p: &mut Parser<'_>) -> Option { @@ -181,6 +184,16 @@ fn tuple_expr(p: &mut Parser<'_>) -> CompletedMarker { let mut saw_comma = false; let mut saw_expr = false; + + // test_err tuple_expr_leading_comma + // fn foo() { + // (,); + // } + if p.eat(T![,]) { + p.error("expected expression"); + saw_comma = true; + } + while !p.at(EOF) && !p.at(T![')']) { saw_expr = true; diff --git a/crates/parser/src/grammar/generic_args.rs b/crates/parser/src/grammar/generic_args.rs index 919d9b91ebab5..e589b69934d23 100644 --- a/crates/parser/src/grammar/generic_args.rs +++ b/crates/parser/src/grammar/generic_args.rs @@ -28,6 +28,7 @@ const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[ BYTE, STRING, BYTE_STRING, + C_STRING, ]) .union(types::TYPE_FIRST); @@ -35,7 +36,7 @@ const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[ // type T = S; fn generic_arg(p: &mut Parser<'_>) -> bool { match p.current() { - LIFETIME_IDENT => lifetime_arg(p), + LIFETIME_IDENT if !p.nth_at(1, T![+]) => lifetime_arg(p), T!['{'] | T![true] | T![false] | T![-] => const_arg(p), k if k.is_literal() => const_arg(p), // test associated_type_bounds @@ -76,6 +77,29 @@ fn generic_arg(p: &mut Parser<'_>) -> bool { } } } + IDENT if p.nth_at(1, T!['(']) => { + let m = p.start(); + name_ref(p); + params::param_list_fn_trait(p); + if p.at(T![:]) && !p.at(T![::]) { + // test associated_return_type_bounds + // fn foo>() {} + generic_params::bounds(p); + m.complete(p, ASSOC_TYPE_ARG); + } else { + // test bare_dyn_types_with_paren_as_generic_args + // type A = S; + // type A = S; + // type B = S i32>; + // type C = S i32 + Send>; + opt_ret_type(p); + let m = m.complete(p, PATH_SEGMENT).precede(p).complete(p, PATH); + let m = paths::type_path_for_qualifier(p, m); + let m = m.precede(p).complete(p, PATH_TYPE); + let m = types::opt_type_bounds_as_dyn_trait_type(p, m); + m.precede(p).complete(p, TYPE_ARG); + } + } _ if p.at_ts(types::TYPE_FIRST) => type_arg(p), _ => return false, } diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs index 5e0951bf8b50a..1c056819f4b7f 100644 --- a/crates/parser/src/grammar/items.rs +++ b/crates/parser/src/grammar/items.rs @@ -19,7 +19,7 @@ use super::*; // struct S; pub(super) fn mod_contents(p: &mut Parser<'_>, stop_on_r_curly: bool) { attributes::inner_attrs(p); - while !p.at(EOF) && !(p.at(T!['}']) && stop_on_r_curly) { + while !(p.at(EOF) || (p.at(T!['}']) && stop_on_r_curly)) { item_or_macro(p, stop_on_r_curly); } } diff --git a/crates/parser/src/grammar/paths.rs b/crates/parser/src/grammar/paths.rs index 26490aa97e0a0..01b8f9e918714 100644 --- a/crates/parser/src/grammar/paths.rs +++ b/crates/parser/src/grammar/paths.rs @@ -136,6 +136,7 @@ fn opt_path_type_args(p: &mut Parser<'_>, mode: Mode) { Mode::Type => { // test typepathfn_with_coloncolon // type F = Start::(Middle) -> (Middle)::End; + // type GenericArg = S; if p.at(T![::]) && p.nth_at(2, T!['(']) { p.bump(T![::]); } diff --git a/crates/parser/src/grammar/patterns.rs b/crates/parser/src/grammar/patterns.rs index 5f4977886f6eb..39ded41bb2413 100644 --- a/crates/parser/src/grammar/patterns.rs +++ b/crates/parser/src/grammar/patterns.rs @@ -5,6 +5,7 @@ pub(super) const PATTERN_FIRST: TokenSet = T![box], T![ref], T![mut], + T![const], T!['('], T!['['], T![&], @@ -15,6 +16,10 @@ pub(super) const PATTERN_FIRST: TokenSet = const PAT_TOP_FIRST: TokenSet = PATTERN_FIRST.union(TokenSet::new(&[T![|]])); +/// Set of possible tokens at the start of a range pattern's end bound. +const RANGE_PAT_END_FIRST: TokenSet = + expressions::LITERAL_FIRST.union(paths::PATH_FIRST).union(TokenSet::new(&[T![-], T![const]])); + pub(crate) fn pattern(p: &mut Parser<'_>) { pattern_r(p, PAT_RECOVERY_SET); } @@ -105,6 +110,52 @@ fn pattern_single_r(p: &mut Parser<'_>, recovery_set: TokenSet) { return; } + // test exclusive_range_pat + // fn main() { + // match 42 { + // ..0 => {} + // 1..2 => {} + // } + // } + + // test dot_dot_pat + // fn main() { + // let .. = (); + // // + // // Tuples + // // + // let (a, ..) = (); + // let (a, ..,) = (); + // let Tuple(a, ..) = (); + // let Tuple(a, ..,) = (); + // let (.., ..) = (); + // let Tuple(.., ..) = (); + // let (.., a, ..) = (); + // let Tuple(.., a, ..) = (); + // // + // // Slices + // // + // let [..] = (); + // let [head, ..] = (); + // let [head, tail @ ..] = (); + // let [head, .., cons] = (); + // let [head, mid @ .., cons] = (); + // let [head, .., .., cons] = (); + // let [head, .., mid, tail @ ..] = (); + // let [head, .., mid, .., cons] = (); + // } + if p.at(T![..]) { + let m = p.start(); + p.bump(T![..]); + if p.at_ts(RANGE_PAT_END_FIRST) { + atom_pat(p, recovery_set); + m.complete(p, RANGE_PAT); + } else { + m.complete(p, REST_PAT); + } + return; + } + if let Some(lhs) = atom_pat(p, recovery_set) { for range_op in [T![...], T![..=], T![..]] { if p.at(range_op) { @@ -173,7 +224,6 @@ fn atom_pat(p: &mut Parser<'_>, recovery_set: TokenSet) -> Option path_or_macro_pat(p), _ if is_literal_pat_start(p) => literal_pat(p), - T![.] if p.at(T![..]) => rest_pat(p), T![_] => wildcard_pat(p), T![&] => ref_pat(p), T!['('] => tuple_pat(p), @@ -334,39 +384,6 @@ fn wildcard_pat(p: &mut Parser<'_>) -> CompletedMarker { m.complete(p, WILDCARD_PAT) } -// test dot_dot_pat -// fn main() { -// let .. = (); -// // -// // Tuples -// // -// let (a, ..) = (); -// let (a, ..,) = (); -// let Tuple(a, ..) = (); -// let Tuple(a, ..,) = (); -// let (.., ..) = (); -// let Tuple(.., ..) = (); -// let (.., a, ..) = (); -// let Tuple(.., a, ..) = (); -// // -// // Slices -// // -// let [..] = (); -// let [head, ..] = (); -// let [head, tail @ ..] = (); -// let [head, .., cons] = (); -// let [head, mid @ .., cons] = (); -// let [head, .., .., cons] = (); -// let [head, .., mid, tail @ ..] = (); -// let [head, .., mid, .., cons] = (); -// } -fn rest_pat(p: &mut Parser<'_>) -> CompletedMarker { - assert!(p.at(T![..])); - let m = p.start(); - p.bump(T![..]); - m.complete(p, REST_PAT) -} - // test ref_pat // fn main() { // let &a = (); @@ -396,6 +413,16 @@ fn tuple_pat(p: &mut Parser<'_>) -> CompletedMarker { let mut has_comma = false; let mut has_pat = false; let mut has_rest = false; + + // test_err tuple_pat_leading_comma + // fn foo() { + // let (,); + // } + if p.eat(T![,]) { + p.error("expected pattern"); + has_comma = true; + } + while !p.at(EOF) && !p.at(T![')']) { has_pat = true; if !p.at_ts(PAT_TOP_FIRST) { @@ -483,6 +510,14 @@ fn box_pat(p: &mut Parser<'_>) -> CompletedMarker { // fn main() { // let const { 15 } = (); // let const { foo(); bar() } = (); +// +// match 42 { +// const { 0 } .. const { 1 } => (), +// .. const { 0 } => (), +// const { 2 } .. => (), +// } +// +// let (const { () },) = (); // } fn const_block_pat(p: &mut Parser<'_>) -> CompletedMarker { assert!(p.at(T![const])); diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs index 7d0b156c5a06a..93ef48350270b 100644 --- a/crates/parser/src/grammar/types.rs +++ b/crates/parser/src/grammar/types.rs @@ -15,6 +15,7 @@ pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(TokenSet::new(&[ T![impl], T![dyn], T![Self], + LIFETIME_IDENT, ])); pub(super) const TYPE_RECOVERY_SET: TokenSet = TokenSet::new(&[ @@ -49,6 +50,7 @@ fn type_with_bounds_cond(p: &mut Parser<'_>, allow_bounds: bool) { // Some path types are not allowed to have bounds (no plus) T![<] => path_type_(p, allow_bounds), _ if paths::is_path_start(p) => path_or_macro_type_(p, allow_bounds), + LIFETIME_IDENT if p.nth_at(1, T![+]) => bare_dyn_trait_type(p), _ => { p.err_recover("expected type", TYPE_RECOVERY_SET); } @@ -59,7 +61,7 @@ pub(super) fn ascription(p: &mut Parser<'_>) { assert!(p.at(T![:])); p.bump(T![:]); if p.at(T![=]) { - // recover from `let x: = expr;`, `const X: = expr;` and similars + // recover from `let x: = expr;`, `const X: = expr;` and similar // hopefully no type starts with `=` p.error("missing type"); return; @@ -275,6 +277,15 @@ fn dyn_trait_type(p: &mut Parser<'_>) { m.complete(p, DYN_TRAIT_TYPE); } +// test bare_dyn_types_with_leading_lifetime +// type A = 'static + Trait; +// type B = S<'static + Trait>; +fn bare_dyn_trait_type(p: &mut Parser<'_>) { + let m = p.start(); + generic_params::bounds_without_colon(p); + m.complete(p, DYN_TRAIT_TYPE); +} + // test path_type // type A = Foo; // type B = ::Foo; @@ -326,13 +337,16 @@ pub(super) fn path_type_(p: &mut Parser<'_>, allow_bounds: bool) { /// This turns a parsed PATH_TYPE or FOR_TYPE optionally into a DYN_TRAIT_TYPE /// with a TYPE_BOUND_LIST -fn opt_type_bounds_as_dyn_trait_type(p: &mut Parser<'_>, type_marker: CompletedMarker) { +pub(super) fn opt_type_bounds_as_dyn_trait_type( + p: &mut Parser<'_>, + type_marker: CompletedMarker, +) -> CompletedMarker { assert!(matches!( type_marker.kind(), SyntaxKind::PATH_TYPE | SyntaxKind::FOR_TYPE | SyntaxKind::MACRO_TYPE )); if !p.at(T![+]) { - return; + return type_marker; } // First create a TYPE_BOUND from the completed PATH_TYPE @@ -349,5 +363,5 @@ fn opt_type_bounds_as_dyn_trait_type(p: &mut Parser<'_>, type_marker: CompletedM let m = generic_params::bounds_without_colon_m(p, m); // Finally precede everything with DYN_TRAIT_TYPE - m.precede(p).complete(p, DYN_TRAIT_TYPE); + m.precede(p).complete(p, DYN_TRAIT_TYPE) } diff --git a/crates/parser/src/lexed_str.rs b/crates/parser/src/lexed_str.rs index 100deff462d25..e4dce21f32abe 100644 --- a/crates/parser/src/lexed_str.rs +++ b/crates/parser/src/lexed_str.rs @@ -36,7 +36,7 @@ impl<'a> LexedStr<'a> { }; for token in rustc_lexer::tokenize(&text[conv.offset..]) { - let token_text = &text[conv.offset..][..token.len]; + let token_text = &text[conv.offset..][..token.len as usize]; conv.extend_token(&token.kind, token_text); } @@ -49,8 +49,8 @@ impl<'a> LexedStr<'a> { return None; } - let token = rustc_lexer::first_token(text); - if token.len != text.len() { + let token = rustc_lexer::tokenize(text).next()?; + if token.len as usize != text.len() { return None; } @@ -175,6 +175,10 @@ impl<'a> Converter<'a> { rustc_lexer::TokenKind::Ident => { SyntaxKind::from_keyword(token_text).unwrap_or(IDENT) } + rustc_lexer::TokenKind::InvalidIdent => { + err = "Ident contains invalid characters"; + IDENT + } rustc_lexer::TokenKind::RawIdent => IDENT, rustc_lexer::TokenKind::Literal { kind, .. } => { @@ -221,6 +225,7 @@ impl<'a> Converter<'a> { err = "unknown literal prefix"; IDENT } + rustc_lexer::TokenKind::Eof => EOF, } }; @@ -268,35 +273,30 @@ impl<'a> Converter<'a> { } BYTE_STRING } - rustc_lexer::LiteralKind::RawStr { err: raw_str_err, .. } => { - if let Some(raw_str_err) = raw_str_err { - err = match raw_str_err { - rustc_lexer::RawStrError::InvalidStarter { .. } => "Missing `\"` symbol after `#` symbols to begin the raw string literal", - rustc_lexer::RawStrError::NoTerminator { expected, found, .. } => if expected == found { - "Missing trailing `\"` to terminate the raw string literal" - } else { - "Missing trailing `\"` with `#` symbols to terminate the raw string literal" - }, - rustc_lexer::RawStrError::TooManyDelimiters { .. } => "Too many `#` symbols: raw strings may be delimited by up to 65535 `#` symbols", - }; - }; + rustc_lexer::LiteralKind::CStr { terminated } => { + if !terminated { + err = "Missing trailing `\"` symbol to terminate the string literal"; + } + C_STRING + } + rustc_lexer::LiteralKind::RawStr { n_hashes } => { + if n_hashes.is_none() { + err = "Invalid raw string literal"; + } STRING } - rustc_lexer::LiteralKind::RawByteStr { err: raw_str_err, .. } => { - if let Some(raw_str_err) = raw_str_err { - err = match raw_str_err { - rustc_lexer::RawStrError::InvalidStarter { .. } => "Missing `\"` symbol after `#` symbols to begin the raw byte string literal", - rustc_lexer::RawStrError::NoTerminator { expected, found, .. } => if expected == found { - "Missing trailing `\"` to terminate the raw byte string literal" - } else { - "Missing trailing `\"` with `#` symbols to terminate the raw byte string literal" - }, - rustc_lexer::RawStrError::TooManyDelimiters { .. } => "Too many `#` symbols: raw byte strings may be delimited by up to 65535 `#` symbols", - }; - }; - + rustc_lexer::LiteralKind::RawByteStr { n_hashes } => { + if n_hashes.is_none() { + err = "Invalid raw string literal"; + } BYTE_STRING } + rustc_lexer::LiteralKind::RawCStr { n_hashes } => { + if n_hashes.is_none() { + err = "Invalid raw string literal"; + } + C_STRING + } }; let err = if err.is_empty() { None } else { Some(err) }; diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 8c5aed0232ba3..1aba1f7674ffd 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -131,6 +131,7 @@ pub enum PrefixEntryPoint { Block, Stmt, Pat, + PatTop, Ty, Expr, Path, @@ -145,6 +146,7 @@ impl PrefixEntryPoint { PrefixEntryPoint::Block => grammar::entry::prefix::block, PrefixEntryPoint::Stmt => grammar::entry::prefix::stmt, PrefixEntryPoint::Pat => grammar::entry::prefix::pat, + PrefixEntryPoint::PatTop => grammar::entry::prefix::pat_top, PrefixEntryPoint::Ty => grammar::entry::prefix::ty, PrefixEntryPoint::Expr => grammar::entry::prefix::expr, PrefixEntryPoint::Path => grammar::entry::prefix::path, diff --git a/crates/parser/src/parser.rs b/crates/parser/src/parser.rs index 280416ae7c994..ef413c63754f6 100644 --- a/crates/parser/src/parser.rs +++ b/crates/parser/src/parser.rs @@ -205,7 +205,7 @@ impl<'t> Parser<'t> { marker.bomb.defuse(); marker = new_marker; }; - self.pos += 1 as usize; + self.pos += 1; self.push_event(Event::FloatSplitHack { ends_in_dot }); (ends_in_dot, marker) } diff --git a/crates/parser/src/shortcuts.rs b/crates/parser/src/shortcuts.rs index 47e4adcbbe695..5cdb39700dda3 100644 --- a/crates/parser/src/shortcuts.rs +++ b/crates/parser/src/shortcuts.rs @@ -46,10 +46,8 @@ impl<'a> LexedStr<'a> { // Tag the token as joint if it is float with a fractional part // we use this jointness to inform the parser about what token split // event to emit when we encounter a float literal in a field access - if kind == SyntaxKind::FLOAT_NUMBER { - if !self.text(i).ends_with('.') { - res.was_joint(); - } + if kind == SyntaxKind::FLOAT_NUMBER && !self.text(i).ends_with('.') { + res.was_joint(); } } diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs index cd87b304a2fb3..a8fbcfacf7ece 100644 --- a/crates/parser/src/syntax_kind/generated.rs +++ b/crates/parser/src/syntax_kind/generated.rs @@ -117,6 +117,7 @@ pub enum SyntaxKind { BYTE, STRING, BYTE_STRING, + C_STRING, ERROR, IDENT, WHITESPACE, @@ -245,6 +246,7 @@ pub enum SyntaxKind { GENERIC_PARAM, LIFETIME_PARAM, TYPE_PARAM, + RETURN_TYPE_ARG, CONST_PARAM, GENERIC_ARG_LIST, LIFETIME, @@ -378,7 +380,7 @@ impl SyntaxKind { ) } pub fn is_literal(self) -> bool { - matches!(self, INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE | STRING | BYTE_STRING) + matches!(self, INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE | STRING | BYTE_STRING | C_STRING) } pub fn from_keyword(ident: &str) -> Option { let kw = match ident { diff --git a/crates/parser/src/tests/prefix_entries.rs b/crates/parser/src/tests/prefix_entries.rs index 40f92e58804f9..11f9c34abdf1e 100644 --- a/crates/parser/src/tests/prefix_entries.rs +++ b/crates/parser/src/tests/prefix_entries.rs @@ -33,8 +33,7 @@ fn stmt() { fn pat() { check(PrefixEntryPoint::Pat, "x y", "x"); check(PrefixEntryPoint::Pat, "fn f() {}", "fn"); - // FIXME: This one is wrong, we should consume only one pattern. - check(PrefixEntryPoint::Pat, ".. ..", ".. .."); + check(PrefixEntryPoint::Pat, ".. ..", ".."); } #[test] diff --git a/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.rast b/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.rast index 6ec1780c30b85..cab02d38af2ed 100644 --- a/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.rast +++ b/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.rast @@ -1 +1 @@ -BYTE_STRING "br##\"" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal +BYTE_STRING "br##\"" error: Invalid raw string literal diff --git a/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.rast b/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.rast index d65f1bb2ff049..0486a1e8e1d23 100644 --- a/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.rast +++ b/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.rast @@ -1 +1 @@ -BYTE_STRING "br##\"\\x7f" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal +BYTE_STRING "br##\"\\x7f" error: Invalid raw string literal diff --git a/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.rast b/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.rast index 0f9e0a1657ad4..41e3455c1f3f8 100644 --- a/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.rast +++ b/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.rast @@ -1 +1 @@ -BYTE_STRING "br##\"🦀" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal +BYTE_STRING "br##\"🦀" error: Invalid raw string literal diff --git a/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.rast b/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.rast index 202dcd2d43e38..a11208a81fe8d 100644 --- a/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.rast +++ b/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.rast @@ -1 +1 @@ -BYTE_STRING "br##\"\\" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal +BYTE_STRING "br##\"\\" error: Invalid raw string literal diff --git a/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.rast b/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.rast index d45485b529ed6..10a47ab844757 100644 --- a/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.rast +++ b/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.rast @@ -1 +1 @@ -BYTE_STRING "br##\"\\n" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal +BYTE_STRING "br##\"\\n" error: Invalid raw string literal diff --git a/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.rast b/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.rast index 1bfabbc3ab622..b41ea3a170155 100644 --- a/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.rast +++ b/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.rast @@ -1 +1 @@ -BYTE_STRING "br##\" " error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal +BYTE_STRING "br##\" " error: Invalid raw string literal diff --git a/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.rast b/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.rast index 104ab8aaeefa4..63b8a5af80907 100644 --- a/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.rast +++ b/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.rast @@ -1 +1 @@ -BYTE_STRING "br##\"\\u{20AA}" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal +BYTE_STRING "br##\"\\u{20AA}" error: Invalid raw string literal diff --git a/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.rast b/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.rast index 71b20fd19db7c..096bb94031527 100644 --- a/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.rast +++ b/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.rast @@ -1 +1 @@ -STRING "r##\"" error: Missing trailing `"` with `#` symbols to terminate the raw string literal +STRING "r##\"" error: Invalid raw string literal diff --git a/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.rast b/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.rast index dc106dd24a111..f0ad200fea5a5 100644 --- a/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.rast +++ b/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.rast @@ -1 +1 @@ -STRING "r##\"\\x7f" error: Missing trailing `"` with `#` symbols to terminate the raw string literal +STRING "r##\"\\x7f" error: Invalid raw string literal diff --git a/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.rast b/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.rast index 30ee029f65679..bc5996d1e67ba 100644 --- a/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.rast +++ b/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.rast @@ -1 +1 @@ -STRING "r##\"🦀" error: Missing trailing `"` with `#` symbols to terminate the raw string literal +STRING "r##\"🦀" error: Invalid raw string literal diff --git a/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.rast b/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.rast index 8a6f6cc436662..b48ec5ddabbe5 100644 --- a/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.rast +++ b/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.rast @@ -1 +1 @@ -STRING "r##\"\\" error: Missing trailing `"` with `#` symbols to terminate the raw string literal +STRING "r##\"\\" error: Invalid raw string literal diff --git a/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.rast b/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.rast index f46eff2516ac4..9f32f677766c4 100644 --- a/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.rast +++ b/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.rast @@ -1 +1 @@ -STRING "r##\"\\n" error: Missing trailing `"` with `#` symbols to terminate the raw string literal +STRING "r##\"\\n" error: Invalid raw string literal diff --git a/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.rast b/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.rast index 49b6afea45a5c..2804a43cf1fee 100644 --- a/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.rast +++ b/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.rast @@ -1 +1 @@ -STRING "r##\" " error: Missing trailing `"` with `#` symbols to terminate the raw string literal +STRING "r##\" " error: Invalid raw string literal diff --git a/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.rast b/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.rast index d10d6d8e8c2fd..eb0a2d2da10af 100644 --- a/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.rast +++ b/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.rast @@ -1 +1 @@ -STRING "r##\"\\u{20AA}" error: Missing trailing `"` with `#` symbols to terminate the raw string literal +STRING "r##\"\\u{20AA}" error: Invalid raw string literal diff --git a/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.rast b/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.rast index cf942c92f3b19..52a7f03b6f559 100644 --- a/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.rast +++ b/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.rast @@ -1 +1 @@ -BYTE_STRING "br##" error: Missing `"` symbol after `#` symbols to begin the raw byte string literal +BYTE_STRING "br##" error: Invalid raw string literal diff --git a/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.rast b/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.rast index 042769c275642..da5550d4cc186 100644 --- a/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.rast +++ b/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.rast @@ -1,4 +1,4 @@ -BYTE_STRING "br## " error: Missing `"` symbol after `#` symbols to begin the raw byte string literal +BYTE_STRING "br## " error: Invalid raw string literal IDENT "I" WHITESPACE " " IDENT "lack" diff --git a/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.rast b/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.rast index 2f7c7529a95c0..50b962e77a480 100644 --- a/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.rast +++ b/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.rast @@ -1 +1 @@ -STRING "r##" error: Missing `"` symbol after `#` symbols to begin the raw string literal +STRING "r##" error: Invalid raw string literal diff --git a/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.rast b/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.rast index 4a06b0abe748e..1f484299af156 100644 --- a/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.rast +++ b/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.rast @@ -1,4 +1,4 @@ -STRING "r## " error: Missing `"` symbol after `#` symbols to begin the raw string literal +STRING "r## " error: Invalid raw string literal IDENT "I" WHITESPACE " " IDENT "lack" diff --git a/crates/parser/test_data/parser/err/0027_incomplere_where_for.rast b/crates/parser/test_data/parser/err/0027_incomplete_where_for.rast similarity index 100% rename from crates/parser/test_data/parser/err/0027_incomplere_where_for.rast rename to crates/parser/test_data/parser/err/0027_incomplete_where_for.rast diff --git a/crates/parser/test_data/parser/err/0027_incomplere_where_for.rs b/crates/parser/test_data/parser/err/0027_incomplete_where_for.rs similarity index 100% rename from crates/parser/test_data/parser/err/0027_incomplere_where_for.rs rename to crates/parser/test_data/parser/err/0027_incomplete_where_for.rs diff --git a/crates/parser/test_data/parser/err/0047_repated_extern_modifier.rast b/crates/parser/test_data/parser/err/0047_repeated_extern_modifier.rast similarity index 100% rename from crates/parser/test_data/parser/err/0047_repated_extern_modifier.rast rename to crates/parser/test_data/parser/err/0047_repeated_extern_modifier.rast diff --git a/crates/parser/test_data/parser/err/0047_repated_extern_modifier.rs b/crates/parser/test_data/parser/err/0047_repeated_extern_modifier.rs similarity index 100% rename from crates/parser/test_data/parser/err/0047_repated_extern_modifier.rs rename to crates/parser/test_data/parser/err/0047_repeated_extern_modifier.rs diff --git a/crates/parser/test_data/parser/inline/err/0018_crate_visibility_empty_recover.rast b/crates/parser/test_data/parser/inline/err/0018_crate_visibility_empty_recover.rast new file mode 100644 index 0000000000000..0fe4ca42d79dd --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/0018_crate_visibility_empty_recover.rast @@ -0,0 +1,18 @@ +SOURCE_FILE + STRUCT + VISIBILITY + PUB_KW "pub" + L_PAREN "(" + PATH + PATH_SEGMENT + ERROR + R_PAREN ")" + WHITESPACE " " + STRUCT_KW "struct" + WHITESPACE " " + NAME + IDENT "S" + SEMICOLON ";" + WHITESPACE "\n" +error 4: expected identifier +error 5: expected R_PAREN diff --git a/crates/parser/test_data/parser/inline/err/0018_crate_visibility_empty_recover.rs b/crates/parser/test_data/parser/inline/err/0018_crate_visibility_empty_recover.rs new file mode 100644 index 0000000000000..e8cf9e6696d1a --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/0018_crate_visibility_empty_recover.rs @@ -0,0 +1 @@ +pub() struct S; diff --git a/crates/parser/test_data/parser/inline/err/0019_tuple_expr_leading_comma.rast b/crates/parser/test_data/parser/inline/err/0019_tuple_expr_leading_comma.rast new file mode 100644 index 0000000000000..3fbc0da4002e4 --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/0019_tuple_expr_leading_comma.rast @@ -0,0 +1,24 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "foo" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + EXPR_STMT + TUPLE_EXPR + L_PAREN "(" + COMMA "," + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" +error 17: expected expression diff --git a/crates/parser/test_data/parser/inline/err/0019_tuple_expr_leading_comma.rs b/crates/parser/test_data/parser/inline/err/0019_tuple_expr_leading_comma.rs new file mode 100644 index 0000000000000..12fab59a77656 --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/0019_tuple_expr_leading_comma.rs @@ -0,0 +1,3 @@ +fn foo() { + (,); +} diff --git a/crates/parser/test_data/parser/inline/err/0020_tuple_pat_leading_comma.rast b/crates/parser/test_data/parser/inline/err/0020_tuple_pat_leading_comma.rast new file mode 100644 index 0000000000000..9c8837292d289 --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/0020_tuple_pat_leading_comma.rast @@ -0,0 +1,26 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "foo" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + TUPLE_PAT + L_PAREN "(" + COMMA "," + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" +error 21: expected pattern diff --git a/crates/parser/test_data/parser/inline/err/0020_tuple_pat_leading_comma.rs b/crates/parser/test_data/parser/inline/err/0020_tuple_pat_leading_comma.rs new file mode 100644 index 0000000000000..de168521e1d3f --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/0020_tuple_pat_leading_comma.rs @@ -0,0 +1,3 @@ +fn foo() { + let (,); +} diff --git a/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rast b/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rast index 403c265ea35be..fe73d9dfe4a75 100644 --- a/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rast +++ b/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rast @@ -131,6 +131,30 @@ SOURCE_FILE LITERAL BYTE_STRING "br\"f\"" SEMICOLON ";" + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + WILDCARD_PAT + UNDERSCORE "_" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + C_STRING "c\"g\"" + SEMICOLON ";" + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + WILDCARD_PAT + UNDERSCORE "_" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + C_STRING "cr\"h\"" + SEMICOLON ";" WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rs b/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rs index 2e11a5a6e68c8..e7f235a83b92c 100644 --- a/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rs +++ b/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rs @@ -9,4 +9,6 @@ fn foo() { let _ = r"d"; let _ = b"e"; let _ = br"f"; + let _ = c"g"; + let _ = cr"h"; } diff --git a/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rast b/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rast index 59de2b9f1633c..593867a7b12bb 100644 --- a/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rast +++ b/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rast @@ -74,6 +74,126 @@ SOURCE_FILE L_PAREN "(" R_PAREN ")" SEMICOLON ";" + WHITESPACE "\n\n " + EXPR_STMT + MATCH_EXPR + MATCH_KW "match" + WHITESPACE " " + LITERAL + INT_NUMBER "42" + WHITESPACE " " + MATCH_ARM_LIST + L_CURLY "{" + WHITESPACE "\n " + MATCH_ARM + RANGE_PAT + CONST_BLOCK_PAT + CONST_KW "const" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE " " + LITERAL + INT_NUMBER "0" + WHITESPACE " " + R_CURLY "}" + WHITESPACE " " + DOT2 ".." + WHITESPACE " " + CONST_BLOCK_PAT + CONST_KW "const" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE " " + LITERAL + INT_NUMBER "1" + WHITESPACE " " + R_CURLY "}" + WHITESPACE " " + FAT_ARROW "=>" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + COMMA "," + WHITESPACE "\n " + MATCH_ARM + RANGE_PAT + DOT2 ".." + WHITESPACE " " + CONST_BLOCK_PAT + CONST_KW "const" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE " " + LITERAL + INT_NUMBER "0" + WHITESPACE " " + R_CURLY "}" + WHITESPACE " " + FAT_ARROW "=>" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + COMMA "," + WHITESPACE "\n " + MATCH_ARM + RANGE_PAT + CONST_BLOCK_PAT + CONST_KW "const" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE " " + LITERAL + INT_NUMBER "2" + WHITESPACE " " + R_CURLY "}" + WHITESPACE " " + DOT2 ".." + WHITESPACE " " + FAT_ARROW "=>" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + COMMA "," + WHITESPACE "\n " + R_CURLY "}" + WHITESPACE "\n\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + TUPLE_PAT + L_PAREN "(" + CONST_BLOCK_PAT + CONST_KW "const" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + R_CURLY "}" + COMMA "," + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + SEMICOLON ";" WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rs b/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rs index dce9defac2f9f..6ecdee849b794 100644 --- a/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rs +++ b/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rs @@ -1,4 +1,12 @@ fn main() { let const { 15 } = (); let const { foo(); bar() } = (); + + match 42 { + const { 0 } .. const { 1 } => (), + .. const { 0 } => (), + const { 2 } .. => (), + } + + let (const { () },) = (); } diff --git a/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rast b/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rast index a23ddf69f25fc..c78d16f064c4a 100644 --- a/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rast +++ b/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rast @@ -28,3 +28,42 @@ SOURCE_FILE R_PAREN ")" SEMICOLON ";" WHITESPACE "\n" + STRUCT + STRUCT_KW "struct" + WHITESPACE " " + NAME + IDENT "MyStruct" + TUPLE_FIELD_LIST + L_PAREN "(" + TUPLE_FIELD + VISIBILITY + PUB_KW "pub" + WHITESPACE " " + PAREN_TYPE + L_PAREN "(" + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "u32" + R_PAREN ")" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + STRUCT + STRUCT_KW "struct" + WHITESPACE " " + NAME + IDENT "MyStruct" + TUPLE_FIELD_LIST + L_PAREN "(" + TUPLE_FIELD + VISIBILITY + PUB_KW "pub" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rs b/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rs index 00d8feba96748..6f725fb7b983a 100644 --- a/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rs +++ b/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rs @@ -1 +1,3 @@ struct MyStruct(pub (u32, u32)); +struct MyStruct(pub (u32)); +struct MyStruct(pub ()); diff --git a/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast b/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast index b47a5a5c14705..67277d0639a8d 100644 --- a/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast +++ b/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast @@ -41,3 +41,41 @@ SOURCE_FILE IDENT "End" SEMICOLON ";" WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "GenericArg" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "Start" + PARAM_LIST + L_PAREN "(" + PARAM + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Middle" + R_PAREN ")" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "End" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs b/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs index 8efd93a7ff685..8c54f6704b3fa 100644 --- a/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs +++ b/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs @@ -1 +1,2 @@ type F = Start::(Middle) -> (Middle)::End; +type GenericArg = S; diff --git a/crates/parser/test_data/parser/inline/ok/0207_exclusive_range_pat.rast b/crates/parser/test_data/parser/inline/ok/0207_exclusive_range_pat.rast new file mode 100644 index 0000000000000..fd2c422d0d191 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0207_exclusive_range_pat.rast @@ -0,0 +1,58 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "main" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + MATCH_EXPR + MATCH_KW "match" + WHITESPACE " " + LITERAL + INT_NUMBER "42" + WHITESPACE " " + MATCH_ARM_LIST + L_CURLY "{" + WHITESPACE "\n " + MATCH_ARM + RANGE_PAT + DOT2 ".." + LITERAL_PAT + LITERAL + INT_NUMBER "0" + WHITESPACE " " + FAT_ARROW "=>" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + R_CURLY "}" + WHITESPACE "\n " + MATCH_ARM + RANGE_PAT + LITERAL_PAT + LITERAL + INT_NUMBER "1" + DOT2 ".." + LITERAL_PAT + LITERAL + INT_NUMBER "2" + WHITESPACE " " + FAT_ARROW "=>" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + R_CURLY "}" + WHITESPACE "\n " + R_CURLY "}" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/0207_exclusive_range_pat.rs b/crates/parser/test_data/parser/inline/ok/0207_exclusive_range_pat.rs new file mode 100644 index 0000000000000..e80505d8bd4ba --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0207_exclusive_range_pat.rs @@ -0,0 +1,6 @@ +fn main() { + match 42 { + ..0 => {} + 1..2 => {} + } +} diff --git a/crates/parser/test_data/parser/inline/ok/0208_associated_return_type_bounds.rast b/crates/parser/test_data/parser/inline/ok/0208_associated_return_type_bounds.rast new file mode 100644 index 0000000000000..2fa52068c9b72 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0208_associated_return_type_bounds.rast @@ -0,0 +1,102 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "foo" + GENERIC_PARAM_LIST + L_ANGLE "<" + TYPE_PARAM + NAME + IDENT "T" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + GENERIC_ARG_LIST + L_ANGLE "<" + ASSOC_TYPE_ARG + NAME_REF + IDENT "foo" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Send" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "bar" + PARAM_LIST + L_PAREN "(" + PARAM + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Send" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "baz" + PARAM_LIST + L_PAREN "(" + PARAM + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + COMMA "," + WHITESPACE " " + PARAM + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Send" + R_ANGLE ">" + R_ANGLE ">" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + R_CURLY "}" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/0208_associated_return_type_bounds.rs b/crates/parser/test_data/parser/inline/ok/0208_associated_return_type_bounds.rs new file mode 100644 index 0000000000000..42029ac592702 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0208_associated_return_type_bounds.rs @@ -0,0 +1 @@ +fn foo>() {} diff --git a/crates/parser/test_data/parser/inline/ok/0208_bare_dyn_types_with_leading_lifetime.rast b/crates/parser/test_data/parser/inline/ok/0208_bare_dyn_types_with_leading_lifetime.rast new file mode 100644 index 0000000000000..d7e67fbcd15c9 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0208_bare_dyn_types_with_leading_lifetime.rast @@ -0,0 +1,58 @@ +SOURCE_FILE + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "A" + WHITESPACE " " + EQ "=" + WHITESPACE " " + DYN_TRAIT_TYPE + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'static" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Trait" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "B" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + DYN_TRAIT_TYPE + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'static" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Trait" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/0208_bare_dyn_types_with_leading_lifetime.rs b/crates/parser/test_data/parser/inline/ok/0208_bare_dyn_types_with_leading_lifetime.rs new file mode 100644 index 0000000000000..3e9a9a29ddc44 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0208_bare_dyn_types_with_leading_lifetime.rs @@ -0,0 +1,2 @@ +type A = 'static + Trait; +type B = S<'static + Trait>; diff --git a/crates/parser/test_data/parser/inline/ok/0209_bare_dyn_types_with_paren_as_generic_args.rast b/crates/parser/test_data/parser/inline/ok/0209_bare_dyn_types_with_paren_as_generic_args.rast new file mode 100644 index 0000000000000..d5f97bad898ed --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0209_bare_dyn_types_with_paren_as_generic_args.rast @@ -0,0 +1,175 @@ +SOURCE_FILE + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "A" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Fn" + PARAM_LIST + L_PAREN "(" + PARAM + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "A" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + DYN_TRAIT_TYPE + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Fn" + PARAM_LIST + L_PAREN "(" + PARAM + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Send" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "B" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Fn" + PARAM_LIST + L_PAREN "(" + PARAM + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "C" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + DYN_TRAIT_TYPE + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Fn" + PARAM_LIST + L_PAREN "(" + PARAM + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Send" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/0209_bare_dyn_types_with_paren_as_generic_args.rs b/crates/parser/test_data/parser/inline/ok/0209_bare_dyn_types_with_paren_as_generic_args.rs new file mode 100644 index 0000000000000..800002b1b8238 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0209_bare_dyn_types_with_paren_as_generic_args.rs @@ -0,0 +1,4 @@ +type A = S; +type A = S; +type B = S i32>; +type C = S i32 + Send>; diff --git a/crates/parser/test_data/parser/ok/0028_operator_binding_power.rast b/crates/parser/test_data/parser/ok/0028_operator_binding_power.rast index ae08c0756aa3a..43802572888f0 100644 --- a/crates/parser/test_data/parser/ok/0028_operator_binding_power.rast +++ b/crates/parser/test_data/parser/ok/0028_operator_binding_power.rast @@ -183,4 +183,273 @@ SOURCE_FILE COMMENT "//---&*1 - --2 * 9;" WHITESPACE "\n" R_CURLY "}" + WHITESPACE "\n\n" + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "right_associative" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + EXPR_STMT + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "a" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "b" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "c" + SEMICOLON ";" + WHITESPACE "\n " + EXPR_STMT + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "a" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "b" + WHITESPACE " " + PLUSEQ "+=" + WHITESPACE " " + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "c" + WHITESPACE " " + MINUSEQ "-=" + WHITESPACE " " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "d" + SEMICOLON ";" + WHITESPACE "\n " + EXPR_STMT + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "a" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "b" + WHITESPACE " " + STAREQ "*=" + WHITESPACE " " + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "c" + WHITESPACE " " + SLASHEQ "/=" + WHITESPACE " " + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "d" + WHITESPACE " " + PERCENTEQ "%=" + WHITESPACE " " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "e" + SEMICOLON ";" + WHITESPACE "\n " + EXPR_STMT + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "a" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "b" + WHITESPACE " " + AMPEQ "&=" + WHITESPACE " " + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "c" + WHITESPACE " " + PIPEEQ "|=" + WHITESPACE " " + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "d" + WHITESPACE " " + CARETEQ "^=" + WHITESPACE " " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "e" + SEMICOLON ";" + WHITESPACE "\n " + EXPR_STMT + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "a" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "b" + WHITESPACE " " + SHLEQ "<<=" + WHITESPACE " " + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "c" + WHITESPACE " " + SHREQ ">>=" + WHITESPACE " " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "d" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n\n" + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "mixed_associativity" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + COMMENT "// (a + b) = (c += ((d * e) = f))" + WHITESPACE "\n " + EXPR_STMT + BIN_EXPR + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "a" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "b" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "c" + WHITESPACE " " + PLUSEQ "+=" + WHITESPACE " " + BIN_EXPR + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "d" + WHITESPACE " " + STAR "*" + WHITESPACE " " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "e" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "f" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/ok/0028_operator_binding_power.rs b/crates/parser/test_data/parser/ok/0028_operator_binding_power.rs index cc9598470d84c..7ee3013a0c89e 100644 --- a/crates/parser/test_data/parser/ok/0028_operator_binding_power.rs +++ b/crates/parser/test_data/parser/ok/0028_operator_binding_power.rs @@ -12,3 +12,16 @@ fn binding_power() { //1 = 2 .. 3; //---&*1 - --2 * 9; } + +fn right_associative() { + a = b = c; + a = b += c -= d; + a = b *= c /= d %= e; + a = b &= c |= d ^= e; + a = b <<= c >>= d; +} + +fn mixed_associativity() { + // (a + b) = (c += ((d * e) = f)) + a + b = c += d * e = f; +} diff --git a/crates/parser/test_data/parser/ok/0045_block_attrs.rast b/crates/parser/test_data/parser/ok/0045_block_attrs.rast index bef1380711630..fad574a476950 100644 --- a/crates/parser/test_data/parser/ok/0045_block_attrs.rast +++ b/crates/parser/test_data/parser/ok/0045_block_attrs.rast @@ -60,7 +60,7 @@ SOURCE_FILE IDENT "doc" TOKEN_TREE L_PAREN "(" - STRING "\"Being validated is not affected by duplcates\"" + STRING "\"Being validated is not affected by duplicates\"" R_PAREN ")" R_BRACK "]" WHITESPACE "\n " diff --git a/crates/parser/test_data/parser/ok/0045_block_attrs.rs b/crates/parser/test_data/parser/ok/0045_block_attrs.rs index f16c4566e77c3..0969ea1659dd6 100644 --- a/crates/parser/test_data/parser/ok/0045_block_attrs.rs +++ b/crates/parser/test_data/parser/ok/0045_block_attrs.rs @@ -3,7 +3,7 @@ fn inner() { //! As are ModuleDoc style comments { #![doc("Inner attributes are allowed in blocks used as statements")] - #![doc("Being validated is not affected by duplcates")] + #![doc("Being validated is not affected by duplicates")] //! As are ModuleDoc style comments }; { diff --git a/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rast b/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rast index e8b836dfbd09e..ce75c55189a0c 100644 --- a/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rast +++ b/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rast @@ -168,42 +168,46 @@ SOURCE_FILE WHITESPACE "\n " EXPR_STMT BIN_EXPR - BIN_EXPR - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - ARG_LIST - L_PAREN "(" - RANGE_EXPR - DOT2 ".." - R_PAREN ")" - WHITESPACE " " - EQ "=" - WHITESPACE " " - METHOD_CALL_EXPR - CALL_EXPR - PATH_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "Some" - ARG_LIST - L_PAREN "(" - LITERAL - INT_NUMBER "0" - R_PAREN ")" - DOT "." - WHITESPACE "\n " - NAME_REF - IDENT "Ok" - ARG_LIST - L_PAREN "(" - UNDERSCORE_EXPR - UNDERSCORE "_" - R_PAREN ")" + CALL_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "Some" + ARG_LIST + L_PAREN "(" + RANGE_EXPR + DOT2 ".." + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + CALL_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "Some" + ARG_LIST + L_PAREN "(" + LITERAL + INT_NUMBER "0" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n " + EXPR_STMT + BIN_EXPR + CALL_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "Ok" + ARG_LIST + L_PAREN "(" + UNDERSCORE_EXPR + UNDERSCORE "_" + R_PAREN ")" WHITESPACE " " EQ "=" WHITESPACE " " diff --git a/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rs b/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rs index 9d3e86603f881..d223b11f239e1 100644 --- a/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rs +++ b/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rs @@ -4,7 +4,7 @@ fn foo() { (_) = ..; struct S { a: i32 } S { .. } = S { ..S::default() }; - Some(..) = Some(0). + Some(..) = Some(0); Ok(_) = 0; let (a, b); [a, .., b] = [1, .., 2]; diff --git a/crates/paths/Cargo.toml b/crates/paths/Cargo.toml index e24e6eceffbd9..28b54be5212f4 100644 --- a/crates/paths/Cargo.toml +++ b/crates/paths/Cargo.toml @@ -15,4 +15,4 @@ doctest = false # Adding this dep sadly puts a lot of rust-analyzer crates after the # serde-derive crate. Even though we don't activate the derive feature here, # someone else in the crate graph certainly does! -# serde = "1" +# serde.workspace = true diff --git a/crates/paths/src/lib.rs b/crates/paths/src/lib.rs index 6ae23ac841ada..e0c20a4143bd6 100644 --- a/crates/paths/src/lib.rs +++ b/crates/paths/src/lib.rs @@ -140,6 +140,11 @@ impl AbsPath { self.0.parent().map(AbsPath::assert) } + /// Equivalent of [`Path::join`] for `AbsPath` with an additional normalize step afterwards. + pub fn absolutize(&self, path: impl AsRef) -> AbsPathBuf { + self.join(path).normalize() + } + /// Equivalent of [`Path::join`] for `AbsPath`. pub fn join(&self, path: impl AsRef) -> AbsPathBuf { self.as_ref().join(path).try_into().unwrap() @@ -166,6 +171,10 @@ impl AbsPath { AbsPathBuf::try_from(self.0.to_path_buf()).unwrap() } + pub fn canonicalize(&self) -> ! { + panic!("We explicitly do not provide canonicalization API, as that is almost always a wrong solution, see #14430") + } + /// Equivalent of [`Path::strip_prefix`] for `AbsPath`. /// /// Returns a relative path. @@ -179,6 +188,13 @@ impl AbsPath { self.0.ends_with(&suffix.0) } + pub fn name_and_extension(&self) -> Option<(&str, Option<&str>)> { + Some(( + self.file_stem()?.to_str()?, + self.extension().and_then(|extension| extension.to_str()), + )) + } + // region:delegate-methods // Note that we deliberately don't implement `Deref` here. diff --git a/crates/proc-macro-api/Cargo.toml b/crates/proc-macro-api/Cargo.toml index 28469b832468b..d3486e75575b2 100644 --- a/crates/proc-macro-api/Cargo.toml +++ b/crates/proc-macro-api/Cargo.toml @@ -19,9 +19,10 @@ object = { version = "0.30.2", default-features = false, features = [ "macho", "pe", ] } -serde = { version = "1.0.137", features = ["derive"] } -serde_json = { version = "1.0.81", features = ["unbounded_depth"] } +serde.workspace = true +serde_json = { workspace = true, features = ["unbounded_depth"] } tracing = "0.1.37" +triomphe.workspace = true memmap2 = "0.5.4" snap = "1.1.0" diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index 90d06967e8fc0..1603458f756ee 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -12,11 +12,8 @@ mod process; mod version; use paths::AbsPathBuf; -use std::{ - ffi::OsStr, - fmt, io, - sync::{Arc, Mutex}, -}; +use std::{fmt, io, sync::Mutex}; +use triomphe::Arc; use serde::{Deserialize, Serialize}; @@ -54,18 +51,8 @@ pub struct MacroDylib { } impl MacroDylib { - // FIXME: this is buggy due to TOCTOU, we should check the version in the - // macro process instead. - pub fn new(path: AbsPathBuf) -> io::Result { - let _p = profile::span("MacroDylib::new"); - - let info = version::read_dylib_info(&path)?; - if info.version.0 < 1 || info.version.1 < 47 { - let msg = format!("proc-macro {} built by {info:#?} is not supported by rust-analyzer, please update your Rust version.", path.display()); - return Err(io::Error::new(io::ErrorKind::InvalidData, msg)); - } - - Ok(MacroDylib { path }) + pub fn new(path: AbsPathBuf) -> MacroDylib { + MacroDylib { path } } } @@ -113,11 +100,8 @@ pub struct MacroPanic { impl ProcMacroServer { /// Spawns an external process as the proc macro server and returns a client connected to it. - pub fn spawn( - process_path: AbsPathBuf, - args: impl IntoIterator> + Clone, - ) -> io::Result { - let process = ProcMacroProcessSrv::run(process_path, args)?; + pub fn spawn(process_path: AbsPathBuf) -> io::Result { + let process = ProcMacroProcessSrv::run(process_path)?; Ok(ProcMacroServer { process: Arc::new(Mutex::new(process)) }) } @@ -156,15 +140,16 @@ impl ProcMacro { attr: Option<&tt::Subtree>, env: Vec<(String, String)>, ) -> Result, ServerError> { + let version = self.process.lock().unwrap_or_else(|e| e.into_inner()).version(); let current_dir = env .iter() .find(|(name, _)| name == "CARGO_MANIFEST_DIR") .map(|(_, value)| value.clone()); let task = ExpandMacro { - macro_body: FlatTree::new(subtree), + macro_body: FlatTree::new(subtree, version), macro_name: self.name.to_string(), - attributes: attr.map(FlatTree::new), + attributes: attr.map(|subtree| FlatTree::new(subtree, version)), lib: self.dylib_path.to_path_buf().into(), env, current_dir, @@ -173,7 +158,9 @@ impl ProcMacro { let request = msg::Request::ExpandMacro(task); let response = self.process.lock().unwrap_or_else(|e| e.into_inner()).send_task(request)?; match response { - msg::Response::ExpandMacro(it) => Ok(it.map(FlatTree::to_subtree)), + msg::Response::ExpandMacro(it) => { + Ok(it.map(|tree| FlatTree::to_subtree(tree, version))) + } msg::Response::ListMacros(..) | msg::Response::ApiVersionCheck(..) => { Err(ServerError { message: "unexpected response".to_string(), io: None }) } diff --git a/crates/proc-macro-api/src/msg.rs b/crates/proc-macro-api/src/msg.rs index 4040efe93f093..4b01643c2a298 100644 --- a/crates/proc-macro-api/src/msg.rs +++ b/crates/proc-macro-api/src/msg.rs @@ -12,8 +12,12 @@ use crate::ProcMacroKind; pub use crate::msg::flat::FlatTree; +// The versions of the server protocol pub const NO_VERSION_CHECK_VERSION: u32 = 0; -pub const CURRENT_API_VERSION: u32 = 1; +pub const VERSION_CHECK_VERSION: u32 = 1; +pub const ENCODE_CLOSE_SPAN_VERSION: u32 = 2; + +pub const CURRENT_API_VERSION: u32 = ENCODE_CLOSE_SPAN_VERSION; #[derive(Debug, Serialize, Deserialize)] pub enum Request { @@ -146,7 +150,7 @@ mod tests { fn test_proc_macro_rpc_works() { let tt = fixture_token_tree(); let task = ExpandMacro { - macro_body: FlatTree::new(&tt), + macro_body: FlatTree::new(&tt, CURRENT_API_VERSION), macro_name: Default::default(), attributes: None, lib: std::env::current_dir().unwrap(), @@ -158,6 +162,6 @@ mod tests { // println!("{}", json); let back: ExpandMacro = serde_json::from_str(&json).unwrap(); - assert_eq!(tt, back.macro_body.to_subtree()); + assert_eq!(tt, back.macro_body.to_subtree(CURRENT_API_VERSION)); } } diff --git a/crates/proc-macro-api/src/msg/flat.rs b/crates/proc-macro-api/src/msg/flat.rs index fd3202e0b284c..44245336f0166 100644 --- a/crates/proc-macro-api/src/msg/flat.rs +++ b/crates/proc-macro-api/src/msg/flat.rs @@ -39,7 +39,10 @@ use std::collections::{HashMap, VecDeque}; use serde::{Deserialize, Serialize}; -use crate::tt::{self, TokenId}; +use crate::{ + msg::ENCODE_CLOSE_SPAN_VERSION, + tt::{self, TokenId}, +}; #[derive(Serialize, Deserialize, Debug)] pub struct FlatTree { @@ -52,7 +55,8 @@ pub struct FlatTree { } struct SubtreeRepr { - id: tt::TokenId, + open: tt::TokenId, + close: tt::TokenId, kind: tt::DelimiterKind, tt: [u32; 2], } @@ -74,7 +78,7 @@ struct IdentRepr { } impl FlatTree { - pub fn new(subtree: &tt::Subtree) -> FlatTree { + pub fn new(subtree: &tt::Subtree, version: u32) -> FlatTree { let mut w = Writer { string_table: HashMap::new(), work: VecDeque::new(), @@ -89,7 +93,11 @@ impl FlatTree { w.write(subtree); return FlatTree { - subtree: write_vec(w.subtree, SubtreeRepr::write), + subtree: if version >= ENCODE_CLOSE_SPAN_VERSION { + write_vec(w.subtree, SubtreeRepr::write_with_close_span) + } else { + write_vec(w.subtree, SubtreeRepr::write) + }, literal: write_vec(w.literal, LiteralRepr::write), punct: write_vec(w.punct, PunctRepr::write), ident: write_vec(w.ident, IdentRepr::write), @@ -102,9 +110,13 @@ impl FlatTree { } } - pub fn to_subtree(self) -> tt::Subtree { + pub fn to_subtree(self, version: u32) -> tt::Subtree { return Reader { - subtree: read_vec(self.subtree, SubtreeRepr::read), + subtree: if version >= ENCODE_CLOSE_SPAN_VERSION { + read_vec(self.subtree, SubtreeRepr::read_with_close_span) + } else { + read_vec(self.subtree, SubtreeRepr::read) + }, literal: read_vec(self.literal, LiteralRepr::read), punct: read_vec(self.punct, PunctRepr::read), ident: read_vec(self.ident, IdentRepr::read), @@ -130,9 +142,9 @@ impl SubtreeRepr { tt::DelimiterKind::Brace => 2, tt::DelimiterKind::Bracket => 3, }; - [self.id.0, kind, self.tt[0], self.tt[1]] + [self.open.0, kind, self.tt[0], self.tt[1]] } - fn read([id, kind, lo, len]: [u32; 4]) -> SubtreeRepr { + fn read([open, kind, lo, len]: [u32; 4]) -> SubtreeRepr { let kind = match kind { 0 => tt::DelimiterKind::Invisible, 1 => tt::DelimiterKind::Parenthesis, @@ -140,7 +152,26 @@ impl SubtreeRepr { 3 => tt::DelimiterKind::Bracket, other => panic!("bad kind {other}"), }; - SubtreeRepr { id: TokenId(id), kind, tt: [lo, len] } + SubtreeRepr { open: TokenId(open), close: TokenId::UNSPECIFIED, kind, tt: [lo, len] } + } + fn write_with_close_span(self) -> [u32; 5] { + let kind = match self.kind { + tt::DelimiterKind::Invisible => 0, + tt::DelimiterKind::Parenthesis => 1, + tt::DelimiterKind::Brace => 2, + tt::DelimiterKind::Bracket => 3, + }; + [self.open.0, self.close.0, kind, self.tt[0], self.tt[1]] + } + fn read_with_close_span([open, close, kind, lo, len]: [u32; 5]) -> SubtreeRepr { + let kind = match kind { + 0 => tt::DelimiterKind::Invisible, + 1 => tt::DelimiterKind::Parenthesis, + 2 => tt::DelimiterKind::Brace, + 3 => tt::DelimiterKind::Bracket, + other => panic!("bad kind {other}"), + }; + SubtreeRepr { open: TokenId(open), close: TokenId(close), kind, tt: [lo, len] } } } @@ -244,9 +275,10 @@ impl<'a> Writer<'a> { fn enqueue(&mut self, subtree: &'a tt::Subtree) -> u32 { let idx = self.subtree.len(); - let delimiter_id = subtree.delimiter.open; + let open = subtree.delimiter.open; + let close = subtree.delimiter.close; let delimiter_kind = subtree.delimiter.kind; - self.subtree.push(SubtreeRepr { id: delimiter_id, kind: delimiter_kind, tt: [!0, !0] }); + self.subtree.push(SubtreeRepr { open, close, kind: delimiter_kind, tt: [!0, !0] }); self.work.push_back((idx, subtree)); idx as u32 } @@ -277,11 +309,7 @@ impl Reader { let repr = &self.subtree[i]; let token_trees = &self.token_tree[repr.tt[0] as usize..repr.tt[1] as usize]; let s = tt::Subtree { - delimiter: tt::Delimiter { - open: repr.id, - close: TokenId::UNSPECIFIED, - kind: repr.kind, - }, + delimiter: tt::Delimiter { open: repr.open, close: repr.close, kind: repr.kind }, token_trees: token_trees .iter() .copied() diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs index 1ccbd780fdda3..9a20fa63ed700 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -1,7 +1,6 @@ //! Handle process life-time and message passing for proc-macro client use std::{ - ffi::{OsStr, OsString}, io::{self, BufRead, BufReader, Write}, process::{Child, ChildStdin, ChildStdout, Command, Stdio}, }; @@ -23,12 +22,9 @@ pub(crate) struct ProcMacroProcessSrv { } impl ProcMacroProcessSrv { - pub(crate) fn run( - process_path: AbsPathBuf, - args: impl IntoIterator> + Clone, - ) -> io::Result { + pub(crate) fn run(process_path: AbsPathBuf) -> io::Result { let create_srv = |null_stderr| { - let mut process = Process::run(process_path.clone(), args.clone(), null_stderr)?; + let mut process = Process::run(process_path.clone(), null_stderr)?; let (stdin, stdout) = process.stdio().expect("couldn't access child stdio"); io::Result::Ok(ProcMacroProcessSrv { _process: process, stdin, stdout, version: 0 }) @@ -56,6 +52,10 @@ impl ProcMacroProcessSrv { } } + pub(crate) fn version(&self) -> u32 { + self.version + } + pub(crate) fn version_check(&mut self) -> Result { let request = Request::ApiVersionCheck {}; let response = self.send_task(request)?; @@ -96,13 +96,8 @@ struct Process { } impl Process { - fn run( - path: AbsPathBuf, - args: impl IntoIterator>, - null_stderr: bool, - ) -> io::Result { - let args: Vec = args.into_iter().map(|s| s.as_ref().into()).collect(); - let child = JodChild(mk_child(&path, args, null_stderr)?); + fn run(path: AbsPathBuf, null_stderr: bool) -> io::Result { + let child = JodChild(mk_child(&path, null_stderr)?); Ok(Process { child }) } @@ -115,13 +110,8 @@ impl Process { } } -fn mk_child( - path: &AbsPath, - args: impl IntoIterator>, - null_stderr: bool, -) -> io::Result { +fn mk_child(path: &AbsPath, null_stderr: bool) -> io::Result { Command::new(path.as_os_str()) - .args(args) .env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable") .stdin(Stdio::piped()) .stdout(Stdio::piped()) diff --git a/crates/proc-macro-srv-cli/Cargo.toml b/crates/proc-macro-srv-cli/Cargo.toml index c402bc02253c2..8f03c6ec7b572 100644 --- a/crates/proc-macro-srv-cli/Cargo.toml +++ b/crates/proc-macro-srv-cli/Cargo.toml @@ -10,6 +10,7 @@ rust-version.workspace = true [dependencies] proc-macro-srv.workspace = true +proc-macro-api.workspace = true [features] sysroot-abi = ["proc-macro-srv/sysroot-abi"] diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs index ac9fa9f5a4ce5..bece1951872c4 100644 --- a/crates/proc-macro-srv-cli/src/main.rs +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -1,6 +1,6 @@ //! A standalone binary for `proc-macro-srv`. - -use proc_macro_srv::cli; +//! Driver for proc macro server +use std::io; fn main() -> std::io::Result<()> { let v = std::env::var("RUST_ANALYZER_INTERNALS_DO_NOT_USE"); @@ -15,5 +15,37 @@ fn main() -> std::io::Result<()> { } } - cli::run() + run() +} + +#[cfg(not(feature = "sysroot-abi"))] +fn run() -> io::Result<()> { + panic!("proc-macro-srv-cli requires the `sysroot-abi` feature to be enabled"); +} + +#[cfg(feature = "sysroot-abi")] +fn run() -> io::Result<()> { + use proc_macro_api::msg::{self, Message}; + + let read_request = |buf: &mut String| msg::Request::read(&mut io::stdin().lock(), buf); + + let write_response = |msg: msg::Response| msg.write(&mut io::stdout().lock()); + + let mut srv = proc_macro_srv::ProcMacroSrv::default(); + let mut buf = String::new(); + + while let Some(req) = read_request(&mut buf)? { + let res = match req { + msg::Request::ListMacros { dylib_path } => { + msg::Response::ListMacros(srv.list_macros(&dylib_path)) + } + msg::Request::ExpandMacro(task) => msg::Response::ExpandMacro(srv.expand(task)), + msg::Request::ApiVersionCheck {} => { + msg::Response::ApiVersionCheck(proc_macro_api::msg::CURRENT_API_VERSION) + } + }; + write_response(res)? + } + + Ok(()) } diff --git a/crates/proc-macro-srv/Cargo.toml b/crates/proc-macro-srv/Cargo.toml index f7f07cfcb2e27..d5eb157bfef97 100644 --- a/crates/proc-macro-srv/Cargo.toml +++ b/crates/proc-macro-srv/Cargo.toml @@ -22,6 +22,7 @@ object = { version = "0.30.2", default-features = false, features = [ libloading = "0.7.3" memmap2 = "0.5.4" +stdx.workspace = true tt.workspace = true mbe.workspace = true paths.workspace = true diff --git a/crates/proc-macro-srv/src/abis/abi_1_63/mod.rs b/crates/proc-macro-srv/src/abis/abi_1_63/mod.rs deleted file mode 100644 index 93805c89354a5..0000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_63/mod.rs +++ /dev/null @@ -1,106 +0,0 @@ -//! Macro ABI for version 1.63 of rustc - -#[allow(dead_code)] -#[doc(hidden)] -mod proc_macro; - -#[allow(dead_code)] -#[doc(hidden)] -mod ra_server; - -use libloading::Library; -use proc_macro_api::ProcMacroKind; - -use super::tt; -use super::PanicMessage; - -pub use ra_server::TokenStream; - -pub(crate) struct Abi { - exported_macros: Vec, -} - -impl From for PanicMessage { - fn from(p: proc_macro::bridge::PanicMessage) -> Self { - Self { message: p.as_str().map(|s| s.to_string()) } - } -} - -impl Abi { - pub unsafe fn from_lib(lib: &Library, symbol_name: String) -> Result { - let macros: libloading::Symbol<'_, &&[proc_macro::bridge::client::ProcMacro]> = - lib.get(symbol_name.as_bytes())?; - Ok(Self { exported_macros: macros.to_vec() }) - } - - pub fn expand( - &self, - macro_name: &str, - macro_body: &tt::Subtree, - attributes: Option<&tt::Subtree>, - ) -> Result { - let parsed_body = TokenStream::with_subtree(macro_body.clone()); - - let parsed_attributes = - attributes.map_or(TokenStream::new(), |attr| TokenStream::with_subtree(attr.clone())); - - for proc_macro in &self.exported_macros { - match proc_macro { - proc_macro::bridge::client::ProcMacro::CustomDerive { - trait_name, client, .. - } if *trait_name == macro_name => { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - proc_macro::bridge::client::ProcMacro::Bang { name, client } - if *name == macro_name => - { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - proc_macro::bridge::client::ProcMacro::Attr { name, client } - if *name == macro_name => - { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_attributes, - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - _ => continue, - } - } - - Err(proc_macro::bridge::PanicMessage::String("Nothing to expand".to_string()).into()) - } - - pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { - self.exported_macros - .iter() - .map(|proc_macro| match proc_macro { - proc_macro::bridge::client::ProcMacro::CustomDerive { trait_name, .. } => { - (trait_name.to_string(), ProcMacroKind::CustomDerive) - } - proc_macro::bridge::client::ProcMacro::Bang { name, .. } => { - (name.to_string(), ProcMacroKind::FuncLike) - } - proc_macro::bridge::client::ProcMacro::Attr { name, .. } => { - (name.to_string(), ProcMacroKind::Attr) - } - }) - .collect() - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/buffer.rs b/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/buffer.rs deleted file mode 100644 index 48030f8d82dca..0000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/buffer.rs +++ /dev/null @@ -1,156 +0,0 @@ -//! Buffer management for same-process client<->server communication. - -use std::io::{self, Write}; -use std::mem; -use std::ops::{Deref, DerefMut}; -use std::slice; - -#[repr(C)] -pub struct Buffer { - data: *mut u8, - len: usize, - capacity: usize, - reserve: extern "C" fn(Buffer, usize) -> Buffer, - drop: extern "C" fn(Buffer), -} - -unsafe impl Sync for Buffer {} -unsafe impl Send for Buffer {} - -impl Default for Buffer { - #[inline] - fn default() -> Self { - Self::from(vec![]) - } -} - -impl Deref for Buffer { - type Target = [u8]; - #[inline] - fn deref(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.data as *const u8, self.len) } - } -} - -impl DerefMut for Buffer { - #[inline] - fn deref_mut(&mut self) -> &mut [u8] { - unsafe { slice::from_raw_parts_mut(self.data, self.len) } - } -} - -impl Buffer { - #[inline] - pub(super) fn new() -> Self { - Self::default() - } - - #[inline] - pub(super) fn clear(&mut self) { - self.len = 0; - } - - #[inline] - pub(super) fn take(&mut self) -> Self { - mem::take(self) - } - - // We have the array method separate from extending from a slice. This is - // because in the case of small arrays, codegen can be more efficient - // (avoiding a memmove call). With extend_from_slice, LLVM at least - // currently is not able to make that optimization. - #[inline] - pub(super) fn extend_from_array(&mut self, xs: &[u8; N]) { - if xs.len() > (self.capacity - self.len) { - let b = self.take(); - *self = (b.reserve)(b, xs.len()); - } - unsafe { - xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len()); - self.len += xs.len(); - } - } - - #[inline] - pub(super) fn extend_from_slice(&mut self, xs: &[u8]) { - if xs.len() > (self.capacity - self.len) { - let b = self.take(); - *self = (b.reserve)(b, xs.len()); - } - unsafe { - xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len()); - self.len += xs.len(); - } - } - - #[inline] - pub(super) fn push(&mut self, v: u8) { - // The code here is taken from Vec::push, and we know that reserve() - // will panic if we're exceeding isize::MAX bytes and so there's no need - // to check for overflow. - if self.len == self.capacity { - let b = self.take(); - *self = (b.reserve)(b, 1); - } - unsafe { - *self.data.add(self.len) = v; - self.len += 1; - } - } -} - -impl Write for Buffer { - #[inline] - fn write(&mut self, xs: &[u8]) -> io::Result { - self.extend_from_slice(xs); - Ok(xs.len()) - } - - #[inline] - fn write_all(&mut self, xs: &[u8]) -> io::Result<()> { - self.extend_from_slice(xs); - Ok(()) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl Drop for Buffer { - #[inline] - fn drop(&mut self) { - let b = self.take(); - (b.drop)(b); - } -} - -impl From> for Buffer { - fn from(mut v: Vec) -> Self { - let (data, len, capacity) = (v.as_mut_ptr(), v.len(), v.capacity()); - mem::forget(v); - - // This utility function is nested in here because it can *only* - // be safely called on `Buffer`s created by *this* `proc_macro`. - fn to_vec(b: Buffer) -> Vec { - unsafe { - let Buffer { data, len, capacity, .. } = b; - mem::forget(b); - Vec::from_raw_parts(data, len, capacity) - } - } - - extern "C" fn reserve(b: Buffer, additional: usize) -> Buffer { - let mut v = to_vec(b); - v.reserve(additional); - Buffer::from(v) - } - - extern "C" fn drop(b: Buffer) { - mem::drop(to_vec(b)); - } - - Buffer { data, len, capacity, reserve, drop } - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/client.rs b/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/client.rs deleted file mode 100644 index b346c2c189698..0000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/client.rs +++ /dev/null @@ -1,510 +0,0 @@ -//! Client-side types. - -use super::*; - -use std::marker::PhantomData; - -macro_rules! define_handles { - ( - 'owned: $($oty:ident,)* - 'interned: $($ity:ident,)* - ) => { - #[repr(C)] - #[allow(non_snake_case)] - pub struct HandleCounters { - $($oty: AtomicUsize,)* - $($ity: AtomicUsize,)* - } - - impl HandleCounters { - // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of - // a wrapper `fn` pointer, once `const fn` can reference `static`s. - extern "C" fn get() -> &'static Self { - static COUNTERS: HandleCounters = HandleCounters { - $($oty: AtomicUsize::new(1),)* - $($ity: AtomicUsize::new(1),)* - }; - &COUNTERS - } - } - - // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. - #[repr(C)] - #[allow(non_snake_case)] - pub(super) struct HandleStore { - $($oty: handle::OwnedStore,)* - $($ity: handle::InternedStore,)* - } - - impl HandleStore { - pub(super) fn new(handle_counters: &'static HandleCounters) -> Self { - HandleStore { - $($oty: handle::OwnedStore::new(&handle_counters.$oty),)* - $($ity: handle::InternedStore::new(&handle_counters.$ity),)* - } - } - } - - $( - #[repr(C)] - pub(crate) struct $oty { - handle: handle::Handle, - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual - // way of doing this, but that requires unstable features. - // rust-analyzer uses this code and avoids unstable features. - _marker: PhantomData<*mut ()>, - } - - // Forward `Drop::drop` to the inherent `drop` method. - impl Drop for $oty { - fn drop(&mut self) { - $oty { - handle: self.handle, - _marker: PhantomData, - }.drop(); - } - } - - impl Encode for $oty { - fn encode(self, w: &mut Writer, s: &mut S) { - let handle = self.handle; - mem::forget(self); - handle.encode(w, s); - } - } - - impl DecodeMut<'_, '_, HandleStore>> - for Marked - { - fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { - s.$oty.take(handle::Handle::decode(r, &mut ())) - } - } - - impl Encode for &$oty { - fn encode(self, w: &mut Writer, s: &mut S) { - self.handle.encode(w, s); - } - } - - impl<'s, S: server::Types> Decode<'_, 's, HandleStore>> - for &'s Marked - { - fn decode(r: &mut Reader<'_>, s: &'s HandleStore>) -> Self { - &s.$oty[handle::Handle::decode(r, &mut ())] - } - } - - impl Encode for &mut $oty { - fn encode(self, w: &mut Writer, s: &mut S) { - self.handle.encode(w, s); - } - } - - impl<'s, S: server::Types> DecodeMut<'_, 's, HandleStore>> - for &'s mut Marked - { - fn decode( - r: &mut Reader<'_>, - s: &'s mut HandleStore> - ) -> Self { - &mut s.$oty[handle::Handle::decode(r, &mut ())] - } - } - - impl Encode>> - for Marked - { - fn encode(self, w: &mut Writer, s: &mut HandleStore>) { - s.$oty.alloc(self).encode(w, s); - } - } - - impl DecodeMut<'_, '_, S> for $oty { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - $oty { - handle: handle::Handle::decode(r, s), - _marker: PhantomData, - } - } - } - )* - - $( - #[repr(C)] - #[derive(Copy, Clone, PartialEq, Eq, Hash)] - pub(crate) struct $ity { - handle: handle::Handle, - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual - // way of doing this, but that requires unstable features. - // rust-analyzer uses this code and avoids unstable features. - _marker: PhantomData<*mut ()>, - } - - impl Encode for $ity { - fn encode(self, w: &mut Writer, s: &mut S) { - self.handle.encode(w, s); - } - } - - impl DecodeMut<'_, '_, HandleStore>> - for Marked - { - fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { - s.$ity.copy(handle::Handle::decode(r, &mut ())) - } - } - - impl Encode>> - for Marked - { - fn encode(self, w: &mut Writer, s: &mut HandleStore>) { - s.$ity.alloc(self).encode(w, s); - } - } - - impl DecodeMut<'_, '_, S> for $ity { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - $ity { - handle: handle::Handle::decode(r, s), - _marker: PhantomData, - } - } - } - )* - } -} -define_handles! { - 'owned: - FreeFunctions, - TokenStream, - Group, - Literal, - SourceFile, - MultiSpan, - Diagnostic, - - 'interned: - Punct, - Ident, - Span, -} - -// FIXME(eddyb) generate these impls by pattern-matching on the -// names of methods - also could use the presence of `fn drop` -// to distinguish between 'owned and 'interned, above. -// Alternatively, special "modes" could be listed of types in with_api -// instead of pattern matching on methods, here and in server decl. - -impl Clone for TokenStream { - fn clone(&self) -> Self { - self.clone() - } -} - -impl Clone for Group { - fn clone(&self) -> Self { - self.clone() - } -} - -impl Clone for Literal { - fn clone(&self) -> Self { - self.clone() - } -} - -impl fmt::Debug for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Literal") - // format the kind without quotes, as in `kind: Float` - .field("kind", &format_args!("{}", &self.debug_kind())) - .field("symbol", &self.symbol()) - // format `Some("...")` on one line even in {:#?} mode - .field("suffix", &format_args!("{:?}", &self.suffix())) - .field("span", &self.span()) - .finish() - } -} - -impl Clone for SourceFile { - fn clone(&self) -> Self { - self.clone() - } -} - -impl fmt::Debug for Span { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.debug()) - } -} - -macro_rules! define_client_side { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* - }),* $(,)?) => { - $(impl $name { - $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)* { - Bridge::with(|bridge| { - let mut buf = bridge.cached_buffer.take(); - - buf.clear(); - api_tags::Method::$name(api_tags::$name::$method).encode(&mut buf, &mut ()); - reverse_encode!(buf; $($arg),*); - - buf = bridge.dispatch.call(buf); - - let r = Result::<_, PanicMessage>::decode(&mut &buf[..], &mut ()); - - bridge.cached_buffer = buf; - - r.unwrap_or_else(|e| panic::resume_unwind(e.into())) - }) - })* - })* - } -} -with_api!(self, self, define_client_side); - -enum BridgeState<'a> { - /// No server is currently connected to this client. - NotConnected, - - /// A server is connected and available for requests. - Connected(Bridge<'a>), - - /// Access to the bridge is being exclusively acquired - /// (e.g., during `BridgeState::with`). - InUse, -} - -enum BridgeStateL {} - -impl<'a> scoped_cell::ApplyL<'a> for BridgeStateL { - type Out = BridgeState<'a>; -} - -thread_local! { - static BRIDGE_STATE: scoped_cell::ScopedCell = - scoped_cell::ScopedCell::new(BridgeState::NotConnected); -} - -impl BridgeState<'_> { - /// Take exclusive control of the thread-local - /// `BridgeState`, and pass it to `f`, mutably. - /// The state will be restored after `f` exits, even - /// by panic, including modifications made to it by `f`. - /// - /// N.B., while `f` is running, the thread-local state - /// is `BridgeState::InUse`. - fn with(f: impl FnOnce(&mut BridgeState<'_>) -> R) -> R { - BRIDGE_STATE.with(|state| { - state.replace(BridgeState::InUse, |mut state| { - // FIXME(#52812) pass `f` directly to `replace` when `RefMutL` is gone - f(&mut state) - }) - }) - } -} - -impl Bridge<'_> { - pub(crate) fn is_available() -> bool { - BridgeState::with(|state| match state { - BridgeState::Connected(_) | BridgeState::InUse => true, - BridgeState::NotConnected => false, - }) - } - - fn enter(self, f: impl FnOnce() -> R) -> R { - let force_show_panics = self.force_show_panics; - // Hide the default panic output within `proc_macro` expansions. - // NB. the server can't do this because it may use a different libstd. - static HIDE_PANICS_DURING_EXPANSION: Once = Once::new(); - HIDE_PANICS_DURING_EXPANSION.call_once(|| { - let prev = panic::take_hook(); - panic::set_hook(Box::new(move |info| { - let show = BridgeState::with(|state| match state { - BridgeState::NotConnected => true, - BridgeState::Connected(_) | BridgeState::InUse => force_show_panics, - }); - if show { - prev(info) - } - })); - }); - - BRIDGE_STATE.with(|state| state.set(BridgeState::Connected(self), f)) - } - - fn with(f: impl FnOnce(&mut Bridge<'_>) -> R) -> R { - BridgeState::with(|state| match state { - BridgeState::NotConnected => { - panic!("procedural macro API is used outside of a procedural macro"); - } - BridgeState::InUse => { - panic!("procedural macro API is used while it's already in use"); - } - BridgeState::Connected(bridge) => f(bridge), - }) - } -} - -/// A client-side RPC entry-point, which may be using a different `proc_macro` -/// from the one used by the server, but can be invoked compatibly. -/// -/// Note that the (phantom) `I` ("input") and `O` ("output") type parameters -/// decorate the `Client` with the RPC "interface" of the entry-point, but -/// do not themselves participate in ABI, at all, only facilitate type-checking. -/// -/// E.g. `Client` is the common proc macro interface, -/// used for `#[proc_macro] fn foo(input: TokenStream) -> TokenStream`, -/// indicating that the RPC input and output will be serialized token streams, -/// and forcing the use of APIs that take/return `S::TokenStream`, server-side. -#[repr(C)] -pub struct Client { - // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of - // a wrapper `fn` pointer, once `const fn` can reference `static`s. - pub(super) get_handle_counters: extern "C" fn() -> &'static HandleCounters, - - pub(super) run: extern "C" fn(Bridge<'_>) -> Buffer, - - pub(super) _marker: PhantomData O>, -} - -impl Copy for Client {} -impl Clone for Client { - fn clone(&self) -> Self { - *self - } -} - -/// Client-side helper for handling client panics, entering the bridge, -/// deserializing input and serializing output. -// FIXME(eddyb) maybe replace `Bridge::enter` with this? -fn run_client DecodeMut<'a, 's, ()>, R: Encode<()>>( - mut bridge: Bridge<'_>, - f: impl FnOnce(A) -> R, -) -> Buffer { - // The initial `cached_buffer` contains the input. - let mut buf = bridge.cached_buffer.take(); - - panic::catch_unwind(panic::AssertUnwindSafe(|| { - bridge.enter(|| { - let reader = &mut &buf[..]; - let input = A::decode(reader, &mut ()); - - // Put the `cached_buffer` back in the `Bridge`, for requests. - Bridge::with(|bridge| bridge.cached_buffer = buf.take()); - - let output = f(input); - - // Take the `cached_buffer` back out, for the output value. - buf = Bridge::with(|bridge| bridge.cached_buffer.take()); - - // HACK(eddyb) Separate encoding a success value (`Ok(output)`) - // from encoding a panic (`Err(e: PanicMessage)`) to avoid - // having handles outside the `bridge.enter(|| ...)` scope, and - // to catch panics that could happen while encoding the success. - // - // Note that panics should be impossible beyond this point, but - // this is defensively trying to avoid any accidental panicking - // reaching the `extern "C"` (which should `abort` but might not - // at the moment, so this is also potentially preventing UB). - buf.clear(); - Ok::<_, ()>(output).encode(&mut buf, &mut ()); - }) - })) - .map_err(PanicMessage::from) - .unwrap_or_else(|e| { - buf.clear(); - Err::<(), _>(e).encode(&mut buf, &mut ()); - }); - buf -} - -impl Client { - pub const fn expand1( - f: impl Fn(super::super::TokenStream) -> super::super::TokenStream + Copy, - ) -> Self { - Client { - get_handle_counters: HandleCounters::get, - run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| { - run_client(bridge, |input| f(super::super::TokenStream(input)).0) - }), - _marker: PhantomData, - } - } -} - -impl Client<(super::super::TokenStream, super::super::TokenStream), super::super::TokenStream> { - pub const fn expand2( - f: impl Fn(super::super::TokenStream, super::super::TokenStream) -> super::super::TokenStream - + Copy, - ) -> Self { - Client { - get_handle_counters: HandleCounters::get, - run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| { - run_client(bridge, |(input, input2)| { - f(super::super::TokenStream(input), super::super::TokenStream(input2)).0 - }) - }), - _marker: PhantomData, - } - } -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum ProcMacro { - CustomDerive { - trait_name: &'static str, - attributes: &'static [&'static str], - client: Client, - }, - - Attr { - name: &'static str, - client: Client< - (super::super::TokenStream, super::super::TokenStream), - super::super::TokenStream, - >, - }, - - Bang { - name: &'static str, - client: Client, - }, -} - -impl ProcMacro { - pub fn name(&self) -> &'static str { - match self { - ProcMacro::CustomDerive { trait_name, .. } => trait_name, - ProcMacro::Attr { name, .. } => name, - ProcMacro::Bang { name, .. } => name, - } - } - - pub const fn custom_derive( - trait_name: &'static str, - attributes: &'static [&'static str], - expand: impl Fn(super::super::TokenStream) -> super::super::TokenStream + Copy, - ) -> Self { - ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) } - } - - pub const fn attr( - name: &'static str, - expand: impl Fn(super::super::TokenStream, super::super::TokenStream) -> super::super::TokenStream - + Copy, - ) -> Self { - ProcMacro::Attr { name, client: Client::expand2(expand) } - } - - pub const fn bang( - name: &'static str, - expand: impl Fn(super::super::TokenStream) -> super::super::TokenStream + Copy, - ) -> Self { - ProcMacro::Bang { name, client: Client::expand1(expand) } - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/closure.rs b/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/closure.rs deleted file mode 100644 index d371ae3cea098..0000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/closure.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Closure type (equivalent to `&mut dyn FnMut(A) -> R`) that's `repr(C)`. - -use std::marker::PhantomData; - -#[repr(C)] -pub struct Closure<'a, A, R> { - call: unsafe extern "C" fn(*mut Env, A) -> R, - env: *mut Env, - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual way of doing - // this, but that requires unstable features. rust-analyzer uses this code - // and avoids unstable features. - // - // The `'a` lifetime parameter represents the lifetime of `Env`. - _marker: PhantomData<*mut &'a mut ()>, -} - -struct Env; - -impl<'a, A, R, F: FnMut(A) -> R> From<&'a mut F> for Closure<'a, A, R> { - fn from(f: &'a mut F) -> Self { - unsafe extern "C" fn call R>(env: *mut Env, arg: A) -> R { - (*(env as *mut _ as *mut F))(arg) - } - Closure { call: call::, env: f as *mut _ as *mut Env, _marker: PhantomData } - } -} - -impl<'a, A, R> Closure<'a, A, R> { - pub fn call(&mut self, arg: A) -> R { - unsafe { (self.call)(self.env, arg) } - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/handle.rs b/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/handle.rs deleted file mode 100644 index c219a9465d39f..0000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/handle.rs +++ /dev/null @@ -1,89 +0,0 @@ -//! Server-side handles and storage for per-handle data. - -use std::collections::{BTreeMap, HashMap}; -use std::hash::{BuildHasher, Hash}; -use std::num::NonZeroU32; -use std::ops::{Index, IndexMut}; -use std::sync::atomic::{AtomicUsize, Ordering}; - -pub(super) type Handle = NonZeroU32; - -/// A store that associates values of type `T` with numeric handles. A value can -/// be looked up using its handle. -pub(super) struct OwnedStore { - counter: &'static AtomicUsize, - data: BTreeMap, -} - -impl OwnedStore { - pub(super) fn new(counter: &'static AtomicUsize) -> Self { - // Ensure the handle counter isn't 0, which would panic later, - // when `NonZeroU32::new` (aka `Handle::new`) is called in `alloc`. - assert_ne!(counter.load(Ordering::SeqCst), 0); - - OwnedStore { counter, data: BTreeMap::new() } - } -} - -impl OwnedStore { - pub(super) fn alloc(&mut self, x: T) -> Handle { - let counter = self.counter.fetch_add(1, Ordering::SeqCst); - let handle = Handle::new(counter as u32).expect("`proc_macro` handle counter overflowed"); - assert!(self.data.insert(handle, x).is_none()); - handle - } - - pub(super) fn take(&mut self, h: Handle) -> T { - self.data.remove(&h).expect("use-after-free in `proc_macro` handle") - } -} - -impl Index for OwnedStore { - type Output = T; - fn index(&self, h: Handle) -> &T { - self.data.get(&h).expect("use-after-free in `proc_macro` handle") - } -} - -impl IndexMut for OwnedStore { - fn index_mut(&mut self, h: Handle) -> &mut T { - self.data.get_mut(&h).expect("use-after-free in `proc_macro` handle") - } -} - -// HACK(eddyb) deterministic `std::collections::hash_map::RandomState` replacement -// that doesn't require adding any dependencies to `proc_macro` (like `rustc-hash`). -#[derive(Clone)] -struct NonRandomState; - -impl BuildHasher for NonRandomState { - type Hasher = std::collections::hash_map::DefaultHasher; - #[inline] - fn build_hasher(&self) -> Self::Hasher { - Self::Hasher::new() - } -} - -/// Like `OwnedStore`, but avoids storing any value more than once. -pub(super) struct InternedStore { - owned: OwnedStore, - interner: HashMap, -} - -impl InternedStore { - pub(super) fn new(counter: &'static AtomicUsize) -> Self { - InternedStore { - owned: OwnedStore::new(counter), - interner: HashMap::with_hasher(NonRandomState), - } - } - - pub(super) fn alloc(&mut self, x: T) -> Handle { - let owned = &mut self.owned; - *self.interner.entry(x).or_insert_with(|| owned.alloc(x)) - } - - pub(super) fn copy(&mut self, h: Handle) -> T { - self.owned[h] - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/mod.rs b/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/mod.rs deleted file mode 100644 index 4967da4931a28..0000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/mod.rs +++ /dev/null @@ -1,451 +0,0 @@ -//! Internal interface for communicating between a `proc_macro` client -//! (a proc macro crate) and a `proc_macro` server (a compiler front-end). -//! -//! Serialization (with C ABI buffers) and unique integer handles are employed -//! to allow safely interfacing between two copies of `proc_macro` built -//! (from the same source) by different compilers with potentially mismatching -//! Rust ABIs (e.g., stage0/bin/rustc vs stage1/bin/rustc during bootstrap). - -#![deny(unsafe_code)] - -pub use super::{Delimiter, Level, LineColumn, Spacing}; -use std::fmt; -use std::hash::Hash; -use std::marker; -use std::mem; -use std::ops::Bound; -use std::panic; -use std::sync::atomic::AtomicUsize; -use std::sync::Once; -use std::thread; - -/// Higher-order macro describing the server RPC API, allowing automatic -/// generation of type-safe Rust APIs, both client-side and server-side. -/// -/// `with_api!(MySelf, my_self, my_macro)` expands to: -/// ```rust,ignore (pseudo-code) -/// my_macro! { -/// // ... -/// Literal { -/// // ... -/// fn character(ch: char) -> MySelf::Literal; -/// // ... -/// fn span(my_self: &MySelf::Literal) -> MySelf::Span; -/// fn set_span(my_self: &mut MySelf::Literal, span: MySelf::Span); -/// }, -/// // ... -/// } -/// ``` -/// -/// The first two arguments serve to customize the arguments names -/// and argument/return types, to enable several different usecases: -/// -/// If `my_self` is just `self`, then each `fn` signature can be used -/// as-is for a method. If it's anything else (`self_` in practice), -/// then the signatures don't have a special `self` argument, and -/// can, therefore, have a different one introduced. -/// -/// If `MySelf` is just `Self`, then the types are only valid inside -/// a trait or a trait impl, where the trait has associated types -/// for each of the API types. If non-associated types are desired, -/// a module name (`self` in practice) can be used instead of `Self`. -macro_rules! with_api { - ($S:ident, $self:ident, $m:ident) => { - $m! { - FreeFunctions { - fn drop($self: $S::FreeFunctions); - fn track_env_var(var: &str, value: Option<&str>); - fn track_path(path: &str); - }, - TokenStream { - fn drop($self: $S::TokenStream); - fn clone($self: &$S::TokenStream) -> $S::TokenStream; - fn is_empty($self: &$S::TokenStream) -> bool; - fn expand_expr($self: &$S::TokenStream) -> Result<$S::TokenStream, ()>; - fn from_str(src: &str) -> $S::TokenStream; - fn to_string($self: &$S::TokenStream) -> String; - fn from_token_tree( - tree: TokenTree<$S::Group, $S::Punct, $S::Ident, $S::Literal>, - ) -> $S::TokenStream; - fn concat_trees( - base: Option<$S::TokenStream>, - trees: Vec>, - ) -> $S::TokenStream; - fn concat_streams( - base: Option<$S::TokenStream>, - streams: Vec<$S::TokenStream>, - ) -> $S::TokenStream; - fn into_trees( - $self: $S::TokenStream - ) -> Vec>; - }, - Group { - fn drop($self: $S::Group); - fn clone($self: &$S::Group) -> $S::Group; - fn new(delimiter: Delimiter, stream: Option<$S::TokenStream>) -> $S::Group; - fn delimiter($self: &$S::Group) -> Delimiter; - fn stream($self: &$S::Group) -> $S::TokenStream; - fn span($self: &$S::Group) -> $S::Span; - fn span_open($self: &$S::Group) -> $S::Span; - fn span_close($self: &$S::Group) -> $S::Span; - fn set_span($self: &mut $S::Group, span: $S::Span); - }, - Punct { - fn new(ch: char, spacing: Spacing) -> $S::Punct; - fn as_char($self: $S::Punct) -> char; - fn spacing($self: $S::Punct) -> Spacing; - fn span($self: $S::Punct) -> $S::Span; - fn with_span($self: $S::Punct, span: $S::Span) -> $S::Punct; - }, - Ident { - fn new(string: &str, span: $S::Span, is_raw: bool) -> $S::Ident; - fn span($self: $S::Ident) -> $S::Span; - fn with_span($self: $S::Ident, span: $S::Span) -> $S::Ident; - }, - Literal { - fn drop($self: $S::Literal); - fn clone($self: &$S::Literal) -> $S::Literal; - fn from_str(s: &str) -> Result<$S::Literal, ()>; - fn to_string($self: &$S::Literal) -> String; - fn debug_kind($self: &$S::Literal) -> String; - fn symbol($self: &$S::Literal) -> String; - fn suffix($self: &$S::Literal) -> Option; - fn integer(n: &str) -> $S::Literal; - fn typed_integer(n: &str, kind: &str) -> $S::Literal; - fn float(n: &str) -> $S::Literal; - fn f32(n: &str) -> $S::Literal; - fn f64(n: &str) -> $S::Literal; - fn string(string: &str) -> $S::Literal; - fn character(ch: char) -> $S::Literal; - fn byte_string(bytes: &[u8]) -> $S::Literal; - fn span($self: &$S::Literal) -> $S::Span; - fn set_span($self: &mut $S::Literal, span: $S::Span); - fn subspan( - $self: &$S::Literal, - start: Bound, - end: Bound, - ) -> Option<$S::Span>; - }, - SourceFile { - fn drop($self: $S::SourceFile); - fn clone($self: &$S::SourceFile) -> $S::SourceFile; - fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool; - fn path($self: &$S::SourceFile) -> String; - fn is_real($self: &$S::SourceFile) -> bool; - }, - MultiSpan { - fn drop($self: $S::MultiSpan); - fn new() -> $S::MultiSpan; - fn push($self: &mut $S::MultiSpan, span: $S::Span); - }, - Diagnostic { - fn drop($self: $S::Diagnostic); - fn new(level: Level, msg: &str, span: $S::MultiSpan) -> $S::Diagnostic; - fn sub( - $self: &mut $S::Diagnostic, - level: Level, - msg: &str, - span: $S::MultiSpan, - ); - fn emit($self: $S::Diagnostic); - }, - Span { - fn debug($self: $S::Span) -> String; - fn def_site() -> $S::Span; - fn call_site() -> $S::Span; - fn mixed_site() -> $S::Span; - fn source_file($self: $S::Span) -> $S::SourceFile; - fn parent($self: $S::Span) -> Option<$S::Span>; - fn source($self: $S::Span) -> $S::Span; - fn start($self: $S::Span) -> LineColumn; - fn end($self: $S::Span) -> LineColumn; - fn before($self: $S::Span) -> $S::Span; - fn after($self: $S::Span) -> $S::Span; - fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>; - fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span; - fn source_text($self: $S::Span) -> Option; - fn save_span($self: $S::Span) -> usize; - fn recover_proc_macro_span(id: usize) -> $S::Span; - }, - } - }; -} - -// FIXME(eddyb) this calls `encode` for each argument, but in reverse, -// to match the ordering in `reverse_decode`. -macro_rules! reverse_encode { - ($writer:ident;) => {}; - ($writer:ident; $first:ident $(, $rest:ident)*) => { - reverse_encode!($writer; $($rest),*); - $first.encode(&mut $writer, &mut ()); - } -} - -// FIXME(eddyb) this calls `decode` for each argument, but in reverse, -// to avoid borrow conflicts from borrows started by `&mut` arguments. -macro_rules! reverse_decode { - ($reader:ident, $s:ident;) => {}; - ($reader:ident, $s:ident; $first:ident: $first_ty:ty $(, $rest:ident: $rest_ty:ty)*) => { - reverse_decode!($reader, $s; $($rest: $rest_ty),*); - let $first = <$first_ty>::decode(&mut $reader, $s); - } -} - -#[allow(unsafe_code)] -mod buffer; -#[forbid(unsafe_code)] -pub mod client; -#[allow(unsafe_code)] -mod closure; -#[forbid(unsafe_code)] -mod handle; -#[macro_use] -#[forbid(unsafe_code)] -mod rpc; -#[allow(unsafe_code)] -mod scoped_cell; -#[allow(unsafe_code)] -mod selfless_reify; -#[forbid(unsafe_code)] -pub mod server; - -use buffer::Buffer; -pub use rpc::PanicMessage; -use rpc::{Decode, DecodeMut, Encode, Reader, Writer}; - -/// An active connection between a server and a client. -/// The server creates the bridge (`Bridge::run_server` in `server.rs`), -/// then passes it to the client through the function pointer in the `run` -/// field of `client::Client`. The client holds its copy of the `Bridge` -/// in TLS during its execution (`Bridge::{enter, with}` in `client.rs`). -#[repr(C)] -pub struct Bridge<'a> { - /// Reusable buffer (only `clear`-ed, never shrunk), primarily - /// used for making requests, but also for passing input to client. - cached_buffer: Buffer, - - /// Server-side function that the client uses to make requests. - dispatch: closure::Closure<'a, Buffer, Buffer>, - - /// If 'true', always invoke the default panic hook - force_show_panics: bool, - - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual way of doing - // this, but that requires unstable features. rust-analyzer uses this code - // and avoids unstable features. - _marker: marker::PhantomData<*mut ()>, -} - -#[forbid(unsafe_code)] -#[allow(non_camel_case_types)] -mod api_tags { - use super::rpc::{DecodeMut, Encode, Reader, Writer}; - - macro_rules! declare_tags { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* - }),* $(,)?) => { - $( - pub(super) enum $name { - $($method),* - } - rpc_encode_decode!(enum $name { $($method),* }); - )* - - pub(super) enum Method { - $($name($name)),* - } - rpc_encode_decode!(enum Method { $($name(m)),* }); - } - } - with_api!(self, self, declare_tags); -} - -/// Helper to wrap associated types to allow trait impl dispatch. -/// That is, normally a pair of impls for `T::Foo` and `T::Bar` -/// can overlap, but if the impls are, instead, on types like -/// `Marked` and `Marked`, they can't. -trait Mark { - type Unmarked; - fn mark(unmarked: Self::Unmarked) -> Self; -} - -/// Unwrap types wrapped by `Mark::mark` (see `Mark` for details). -trait Unmark { - type Unmarked; - fn unmark(self) -> Self::Unmarked; -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -struct Marked { - value: T, - _marker: marker::PhantomData, -} - -impl Mark for Marked { - type Unmarked = T; - fn mark(unmarked: Self::Unmarked) -> Self { - Marked { value: unmarked, _marker: marker::PhantomData } - } -} -impl Unmark for Marked { - type Unmarked = T; - fn unmark(self) -> Self::Unmarked { - self.value - } -} -impl<'a, T, M> Unmark for &'a Marked { - type Unmarked = &'a T; - fn unmark(self) -> Self::Unmarked { - &self.value - } -} -impl<'a, T, M> Unmark for &'a mut Marked { - type Unmarked = &'a mut T; - fn unmark(self) -> Self::Unmarked { - &mut self.value - } -} - -impl Mark for Vec { - type Unmarked = Vec; - fn mark(unmarked: Self::Unmarked) -> Self { - // Should be a no-op due to std's in-place collect optimizations. - unmarked.into_iter().map(T::mark).collect() - } -} -impl Unmark for Vec { - type Unmarked = Vec; - fn unmark(self) -> Self::Unmarked { - // Should be a no-op due to std's in-place collect optimizations. - self.into_iter().map(T::unmark).collect() - } -} - -macro_rules! mark_noop { - ($($ty:ty),* $(,)?) => { - $( - impl Mark for $ty { - type Unmarked = Self; - fn mark(unmarked: Self::Unmarked) -> Self { - unmarked - } - } - impl Unmark for $ty { - type Unmarked = Self; - fn unmark(self) -> Self::Unmarked { - self - } - } - )* - } -} -mark_noop! { - (), - bool, - char, - &'_ [u8], - &'_ str, - String, - usize, - Delimiter, - Level, - LineColumn, - Spacing, -} - -rpc_encode_decode!( - enum Delimiter { - Parenthesis, - Brace, - Bracket, - None, - } -); -rpc_encode_decode!( - enum Level { - Error, - Warning, - Note, - Help, - } -); -rpc_encode_decode!(struct LineColumn { line, column }); -rpc_encode_decode!( - enum Spacing { - Alone, - Joint, - } -); - -macro_rules! mark_compound { - (enum $name:ident <$($T:ident),+> { $($variant:ident $(($field:ident))?),* $(,)? }) => { - impl<$($T: Mark),+> Mark for $name <$($T),+> { - type Unmarked = $name <$($T::Unmarked),+>; - fn mark(unmarked: Self::Unmarked) -> Self { - match unmarked { - $($name::$variant $(($field))? => { - $name::$variant $((Mark::mark($field)))? - })* - } - } - } - - impl<$($T: Unmark),+> Unmark for $name <$($T),+> { - type Unmarked = $name <$($T::Unmarked),+>; - fn unmark(self) -> Self::Unmarked { - match self { - $($name::$variant $(($field))? => { - $name::$variant $((Unmark::unmark($field)))? - })* - } - } - } - } -} - -macro_rules! compound_traits { - ($($t:tt)*) => { - rpc_encode_decode!($($t)*); - mark_compound!($($t)*); - }; -} - -compound_traits!( - enum Bound { - Included(x), - Excluded(x), - Unbounded, - } -); - -compound_traits!( - enum Option { - Some(t), - None, - } -); - -compound_traits!( - enum Result { - Ok(t), - Err(e), - } -); - -#[derive(Clone)] -pub enum TokenTree { - Group(G), - Punct(P), - Ident(I), - Literal(L), -} - -compound_traits!( - enum TokenTree { - Group(tt), - Punct(tt), - Ident(tt), - Literal(tt), - } -); diff --git a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/rpc.rs b/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/rpc.rs deleted file mode 100644 index e9d7a46c06f6d..0000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/rpc.rs +++ /dev/null @@ -1,304 +0,0 @@ -//! Serialization for client-server communication. - -use std::any::Any; -use std::char; -use std::io::Write; -use std::num::NonZeroU32; -use std::str; - -pub(super) type Writer = super::buffer::Buffer; - -pub(super) trait Encode: Sized { - fn encode(self, w: &mut Writer, s: &mut S); -} - -pub(super) type Reader<'a> = &'a [u8]; - -pub(super) trait Decode<'a, 's, S>: Sized { - fn decode(r: &mut Reader<'a>, s: &'s S) -> Self; -} - -pub(super) trait DecodeMut<'a, 's, S>: Sized { - fn decode(r: &mut Reader<'a>, s: &'s mut S) -> Self; -} - -macro_rules! rpc_encode_decode { - (le $ty:ty) => { - impl Encode for $ty { - fn encode(self, w: &mut Writer, _: &mut S) { - w.extend_from_array(&self.to_le_bytes()); - } - } - - impl DecodeMut<'_, '_, S> for $ty { - fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { - const N: usize = ::std::mem::size_of::<$ty>(); - - let mut bytes = [0; N]; - bytes.copy_from_slice(&r[..N]); - *r = &r[N..]; - - Self::from_le_bytes(bytes) - } - } - }; - (struct $name:ident $(<$($T:ident),+>)? { $($field:ident),* $(,)? }) => { - impl),+)?> Encode for $name $(<$($T),+>)? { - fn encode(self, w: &mut Writer, s: &mut S) { - $(self.$field.encode(w, s);)* - } - } - - impl<'a, S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S> - for $name $(<$($T),+>)? - { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - $name { - $($field: DecodeMut::decode(r, s)),* - } - } - } - }; - (enum $name:ident $(<$($T:ident),+>)? { $($variant:ident $(($field:ident))*),* $(,)? }) => { - impl),+)?> Encode for $name $(<$($T),+>)? { - fn encode(self, w: &mut Writer, s: &mut S) { - // HACK(eddyb): `Tag` enum duplicated between the - // two impls as there's no other place to stash it. - #[allow(non_upper_case_globals)] - mod tag { - #[repr(u8)] enum Tag { $($variant),* } - - $(pub const $variant: u8 = Tag::$variant as u8;)* - } - - match self { - $($name::$variant $(($field))* => { - tag::$variant.encode(w, s); - $($field.encode(w, s);)* - })* - } - } - } - - impl<'a, S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S> - for $name $(<$($T),+>)? - { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - // HACK(eddyb): `Tag` enum duplicated between the - // two impls as there's no other place to stash it. - #[allow(non_upper_case_globals)] - mod tag { - #[repr(u8)] enum Tag { $($variant),* } - - $(pub const $variant: u8 = Tag::$variant as u8;)* - } - - match u8::decode(r, s) { - $(tag::$variant => { - $(let $field = DecodeMut::decode(r, s);)* - $name::$variant $(($field))* - })* - _ => unreachable!(), - } - } - } - } -} - -impl Encode for () { - fn encode(self, _: &mut Writer, _: &mut S) {} -} - -impl DecodeMut<'_, '_, S> for () { - fn decode(_: &mut Reader<'_>, _: &mut S) -> Self {} -} - -impl Encode for u8 { - fn encode(self, w: &mut Writer, _: &mut S) { - w.push(self); - } -} - -impl DecodeMut<'_, '_, S> for u8 { - fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { - let x = r[0]; - *r = &r[1..]; - x - } -} - -rpc_encode_decode!(le u32); -rpc_encode_decode!(le usize); - -impl Encode for bool { - fn encode(self, w: &mut Writer, s: &mut S) { - (self as u8).encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for bool { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - match u8::decode(r, s) { - 0 => false, - 1 => true, - _ => unreachable!(), - } - } -} - -impl Encode for char { - fn encode(self, w: &mut Writer, s: &mut S) { - (self as u32).encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for char { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - char::from_u32(u32::decode(r, s)).unwrap() - } -} - -impl Encode for NonZeroU32 { - fn encode(self, w: &mut Writer, s: &mut S) { - self.get().encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for NonZeroU32 { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - Self::new(u32::decode(r, s)).unwrap() - } -} - -impl, B: Encode> Encode for (A, B) { - fn encode(self, w: &mut Writer, s: &mut S) { - self.0.encode(w, s); - self.1.encode(w, s); - } -} - -impl<'a, S, A: for<'s> DecodeMut<'a, 's, S>, B: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S> - for (A, B) -{ - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - (DecodeMut::decode(r, s), DecodeMut::decode(r, s)) - } -} - -impl Encode for &[u8] { - fn encode(self, w: &mut Writer, s: &mut S) { - self.len().encode(w, s); - w.write_all(self).unwrap(); - } -} - -impl<'a, S> DecodeMut<'a, '_, S> for &'a [u8] { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - let len = usize::decode(r, s); - let xs = &r[..len]; - *r = &r[len..]; - xs - } -} - -impl Encode for &str { - fn encode(self, w: &mut Writer, s: &mut S) { - self.as_bytes().encode(w, s); - } -} - -impl<'a, S> DecodeMut<'a, '_, S> for &'a str { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - str::from_utf8(<&[u8]>::decode(r, s)).unwrap() - } -} - -impl Encode for String { - fn encode(self, w: &mut Writer, s: &mut S) { - self[..].encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for String { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - <&str>::decode(r, s).to_string() - } -} - -impl> Encode for Vec { - fn encode(self, w: &mut Writer, s: &mut S) { - self.len().encode(w, s); - for x in self { - x.encode(w, s); - } - } -} - -impl<'a, S, T: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S> for Vec { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - let len = usize::decode(r, s); - let mut vec = Vec::with_capacity(len); - for _ in 0..len { - vec.push(T::decode(r, s)); - } - vec - } -} - -/// Simplified version of panic payloads, ignoring -/// types other than `&'static str` and `String`. -pub enum PanicMessage { - StaticStr(&'static str), - String(String), - Unknown, -} - -impl From> for PanicMessage { - fn from(payload: Box) -> Self { - if let Some(s) = payload.downcast_ref::<&'static str>() { - return PanicMessage::StaticStr(s); - } - if let Ok(s) = payload.downcast::() { - return PanicMessage::String(*s); - } - PanicMessage::Unknown - } -} - -impl Into> for PanicMessage { - fn into(self) -> Box { - match self { - PanicMessage::StaticStr(s) => Box::new(s), - PanicMessage::String(s) => Box::new(s), - PanicMessage::Unknown => { - struct UnknownPanicMessage; - Box::new(UnknownPanicMessage) - } - } - } -} - -impl PanicMessage { - pub fn as_str(&self) -> Option<&str> { - match self { - PanicMessage::StaticStr(s) => Some(s), - PanicMessage::String(s) => Some(s), - PanicMessage::Unknown => None, - } - } -} - -impl Encode for PanicMessage { - fn encode(self, w: &mut Writer, s: &mut S) { - self.as_str().encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for PanicMessage { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - match Option::::decode(r, s) { - Some(s) => PanicMessage::String(s), - None => PanicMessage::Unknown, - } - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/scoped_cell.rs b/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/scoped_cell.rs deleted file mode 100644 index 2cde1f65adf9c..0000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/scoped_cell.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! `Cell` variant for (scoped) existential lifetimes. - -use std::cell::Cell; -use std::mem; -use std::ops::{Deref, DerefMut}; - -/// Type lambda application, with a lifetime. -#[allow(unused_lifetimes)] -pub trait ApplyL<'a> { - type Out; -} - -/// Type lambda taking a lifetime, i.e., `Lifetime -> Type`. -pub trait LambdaL: for<'a> ApplyL<'a> {} - -impl ApplyL<'a>> LambdaL for T {} - -// HACK(eddyb) work around projection limitations with a newtype -// FIXME(#52812) replace with `&'a mut >::Out` -pub struct RefMutL<'a, 'b, T: LambdaL>(&'a mut >::Out); - -impl<'a, 'b, T: LambdaL> Deref for RefMutL<'a, 'b, T> { - type Target = >::Out; - fn deref(&self) -> &Self::Target { - self.0 - } -} - -impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.0 - } -} - -pub struct ScopedCell(Cell<>::Out>); - -impl ScopedCell { - pub const fn new(value: >::Out) -> Self { - ScopedCell(Cell::new(value)) - } - - /// Sets the value in `self` to `replacement` while - /// running `f`, which gets the old value, mutably. - /// The old value will be restored after `f` exits, even - /// by panic, including modifications made to it by `f`. - pub fn replace<'a, R>( - &self, - replacement: >::Out, - f: impl for<'b, 'c> FnOnce(RefMutL<'b, 'c, T>) -> R, - ) -> R { - /// Wrapper that ensures that the cell always gets filled - /// (with the original state, optionally changed by `f`), - /// even if `f` had panicked. - struct PutBackOnDrop<'a, T: LambdaL> { - cell: &'a ScopedCell, - value: Option<>::Out>, - } - - impl<'a, T: LambdaL> Drop for PutBackOnDrop<'a, T> { - fn drop(&mut self) { - self.cell.0.set(self.value.take().unwrap()); - } - } - - let mut put_back_on_drop = PutBackOnDrop { - cell: self, - value: Some(self.0.replace(unsafe { - let erased = mem::transmute_copy(&replacement); - mem::forget(replacement); - erased - })), - }; - - f(RefMutL(put_back_on_drop.value.as_mut().unwrap())) - } - - /// Sets the value in `self` to `value` while running `f`. - pub fn set(&self, value: >::Out, f: impl FnOnce() -> R) -> R { - self.replace(value, |_| f()) - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/selfless_reify.rs b/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/selfless_reify.rs deleted file mode 100644 index 4ee4bb87c2bbd..0000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/selfless_reify.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! Abstraction for creating `fn` pointers from any callable that *effectively* -//! has the equivalent of implementing `Default`, even if the compiler neither -//! provides `Default` nor allows reifying closures (i.e. creating `fn` pointers) -//! other than those with absolutely no captures. -//! -//! More specifically, for a closure-like type to be "effectively `Default`": -//! * it must be a ZST (zero-sized type): no information contained within, so -//! that `Default`'s return value (if it were implemented) is unambiguous -//! * it must be `Copy`: no captured "unique ZST tokens" or any other similar -//! types that would make duplicating values at will unsound -//! * combined with the ZST requirement, this confers a kind of "telecopy" -//! ability: similar to `Copy`, but without keeping the value around, and -//! instead "reconstructing" it (a noop given it's a ZST) when needed -//! * it must be *provably* inhabited: no captured uninhabited types or any -//! other types that cannot be constructed by the user of this abstraction -//! * the proof is a value of the closure-like type itself, in a sense the -//! "seed" for the "telecopy" process made possible by ZST + `Copy` -//! * this requirement is the only reason an abstraction limited to a specific -//! usecase is required: ZST + `Copy` can be checked with *at worst* a panic -//! at the "attempted `::default()` call" time, but that doesn't guarantee -//! that the value can be soundly created, and attempting to use the typical -//! "proof ZST token" approach leads yet again to having a ZST + `Copy` type -//! that is not proof of anything without a value (i.e. isomorphic to a -//! newtype of the type it's trying to prove the inhabitation of) -//! -//! A more flexible (and safer) solution to the general problem could exist once -//! `const`-generic parameters can have type parameters in their types: -//! -//! ```rust,ignore (needs future const-generics) -//! extern "C" fn ffi_wrapper< -//! A, R, -//! F: Fn(A) -> R, -//! const f: F, // <-- this `const`-generic is not yet allowed -//! >(arg: A) -> R { -//! f(arg) -//! } -//! ``` - -use std::mem; - -// FIXME(eddyb) this could be `trait` impls except for the `const fn` requirement. -macro_rules! define_reify_functions { - ($( - fn $name:ident $(<$($param:ident),*>)? - for $(extern $abi:tt)? fn($($arg:ident: $arg_ty:ty),*) -> $ret_ty:ty; - )+) => { - $(pub const fn $name< - $($($param,)*)? - F: Fn($($arg_ty),*) -> $ret_ty + Copy - >(f: F) -> $(extern $abi)? fn($($arg_ty),*) -> $ret_ty { - // FIXME(eddyb) describe the `F` type (e.g. via `type_name::`) once panic - // formatting becomes possible in `const fn`. - assert!(mem::size_of::() == 0, "selfless_reify: closure must be zero-sized"); - - $(extern $abi)? fn wrapper< - $($($param,)*)? - F: Fn($($arg_ty),*) -> $ret_ty + Copy - >($($arg: $arg_ty),*) -> $ret_ty { - let f = unsafe { - // SAFETY: `F` satisfies all criteria for "out of thin air" - // reconstructability (see module-level doc comment). - mem::MaybeUninit::::uninit().assume_init() - }; - f($($arg),*) - } - let _f_proof = f; - wrapper::< - $($($param,)*)? - F - > - })+ - } -} - -define_reify_functions! { - fn _reify_to_extern_c_fn_unary for extern "C" fn(arg: A) -> R; - - // HACK(eddyb) this abstraction is used with `for<'a> fn(Bridge<'a>) -> T` - // but that doesn't work with just `reify_to_extern_c_fn_unary` because of - // the `fn` pointer type being "higher-ranked" (i.e. the `for<'a>` binder). - // FIXME(eddyb) try to remove the lifetime from `Bridge`, that'd help. - fn reify_to_extern_c_fn_hrt_bridge for extern "C" fn(bridge: super::Bridge<'_>) -> R; -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/server.rs b/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/server.rs deleted file mode 100644 index 0fb3c69858947..0000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/server.rs +++ /dev/null @@ -1,332 +0,0 @@ -//! Server-side traits. - -use super::*; - -// FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. -use super::client::HandleStore; - -pub trait Types { - type FreeFunctions: 'static; - type TokenStream: 'static + Clone; - type Group: 'static + Clone; - type Punct: 'static + Copy + Eq + Hash; - type Ident: 'static + Copy + Eq + Hash; - type Literal: 'static + Clone; - type SourceFile: 'static + Clone; - type MultiSpan: 'static; - type Diagnostic: 'static; - type Span: 'static + Copy + Eq + Hash; -} - -/// Declare an associated fn of one of the traits below, adding necessary -/// default bodies. -macro_rules! associated_fn { - (fn drop(&mut self, $arg:ident: $arg_ty:ty)) => - (fn drop(&mut self, $arg: $arg_ty) { mem::drop($arg) }); - - (fn clone(&mut self, $arg:ident: $arg_ty:ty) -> $ret_ty:ty) => - (fn clone(&mut self, $arg: $arg_ty) -> $ret_ty { $arg.clone() }); - - ($($item:tt)*) => ($($item)*;) -} - -macro_rules! declare_server_traits { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - $(pub trait $name: Types { - $(associated_fn!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)* - })* - - pub trait Server: Types $(+ $name)* {} - impl Server for S {} - } -} -with_api!(Self, self_, declare_server_traits); - -pub(super) struct MarkedTypes(S); - -macro_rules! define_mark_types_impls { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - impl Types for MarkedTypes { - $(type $name = Marked;)* - } - - $(impl $name for MarkedTypes { - $(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)? { - <_>::mark($name::$method(&mut self.0, $($arg.unmark()),*)) - })* - })* - } -} -with_api!(Self, self_, define_mark_types_impls); - -struct Dispatcher { - handle_store: HandleStore, - server: S, -} - -macro_rules! define_dispatcher_impl { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - // FIXME(eddyb) `pub` only for `ExecutionStrategy` below. - pub trait DispatcherTrait { - // HACK(eddyb) these are here to allow `Self::$name` to work below. - $(type $name;)* - fn dispatch(&mut self, buf: Buffer) -> Buffer; - } - - impl DispatcherTrait for Dispatcher> { - $(type $name = as Types>::$name;)* - fn dispatch(&mut self, mut buf: Buffer) -> Buffer { - let Dispatcher { handle_store, server } = self; - - let mut reader = &buf[..]; - match api_tags::Method::decode(&mut reader, &mut ()) { - $(api_tags::Method::$name(m) => match m { - $(api_tags::$name::$method => { - let mut call_method = || { - reverse_decode!(reader, handle_store; $($arg: $arg_ty),*); - $name::$method(server, $($arg),*) - }; - // HACK(eddyb) don't use `panic::catch_unwind` in a panic. - // If client and server happen to use the same `libstd`, - // `catch_unwind` asserts that the panic counter was 0, - // even when the closure passed to it didn't panic. - let r = if thread::panicking() { - Ok(call_method()) - } else { - panic::catch_unwind(panic::AssertUnwindSafe(call_method)) - .map_err(PanicMessage::from) - }; - - buf.clear(); - r.encode(&mut buf, handle_store); - })* - }),* - } - buf - } - } - } -} -with_api!(Self, self_, define_dispatcher_impl); - -pub trait ExecutionStrategy { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(Bridge<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer; -} - -pub struct SameThread; - -impl ExecutionStrategy for SameThread { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(Bridge<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer { - let mut dispatch = |buf| dispatcher.dispatch(buf); - - run_client(Bridge { - cached_buffer: input, - dispatch: (&mut dispatch).into(), - force_show_panics, - _marker: marker::PhantomData, - }) - } -} - -// NOTE(eddyb) Two implementations are provided, the second one is a bit -// faster but neither is anywhere near as fast as same-thread execution. - -pub struct CrossThread1; - -impl ExecutionStrategy for CrossThread1 { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(Bridge<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer { - use std::sync::mpsc::channel; - - let (req_tx, req_rx) = channel(); - let (res_tx, res_rx) = channel(); - - let join_handle = thread::spawn(move || { - let mut dispatch = |buf| { - req_tx.send(buf).unwrap(); - res_rx.recv().unwrap() - }; - - run_client(Bridge { - cached_buffer: input, - dispatch: (&mut dispatch).into(), - force_show_panics, - _marker: marker::PhantomData, - }) - }); - - for b in req_rx { - res_tx.send(dispatcher.dispatch(b)).unwrap(); - } - - join_handle.join().unwrap() - } -} - -pub struct CrossThread2; - -impl ExecutionStrategy for CrossThread2 { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(Bridge<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer { - use std::sync::{Arc, Mutex}; - - enum State { - Req(T), - Res(T), - } - - let mut state = Arc::new(Mutex::new(State::Res(Buffer::new()))); - - let server_thread = thread::current(); - let state2 = state.clone(); - let join_handle = thread::spawn(move || { - let mut dispatch = |b| { - *state2.lock().unwrap() = State::Req(b); - server_thread.unpark(); - loop { - thread::park(); - if let State::Res(b) = &mut *state2.lock().unwrap() { - break b.take(); - } - } - }; - - let r = run_client(Bridge { - cached_buffer: input, - dispatch: (&mut dispatch).into(), - force_show_panics, - _marker: marker::PhantomData, - }); - - // Wake up the server so it can exit the dispatch loop. - drop(state2); - server_thread.unpark(); - - r - }); - - // Check whether `state2` was dropped, to know when to stop. - while Arc::get_mut(&mut state).is_none() { - thread::park(); - let mut b = match &mut *state.lock().unwrap() { - State::Req(b) => b.take(), - _ => continue, - }; - b = dispatcher.dispatch(b.take()); - *state.lock().unwrap() = State::Res(b); - join_handle.thread().unpark(); - } - - join_handle.join().unwrap() - } -} - -fn run_server< - S: Server, - I: Encode>>, - O: for<'a, 's> DecodeMut<'a, 's, HandleStore>>, ->( - strategy: &impl ExecutionStrategy, - handle_counters: &'static client::HandleCounters, - server: S, - input: I, - run_client: extern "C" fn(Bridge<'_>) -> Buffer, - force_show_panics: bool, -) -> Result { - let mut dispatcher = - Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) }; - - let mut buf = Buffer::new(); - input.encode(&mut buf, &mut dispatcher.handle_store); - - buf = strategy.run_bridge_and_client(&mut dispatcher, buf, run_client, force_show_panics); - - Result::decode(&mut &buf[..], &mut dispatcher.handle_store) -} - -impl client::Client { - pub fn run( - &self, - strategy: &impl ExecutionStrategy, - server: S, - input: S::TokenStream, - force_show_panics: bool, - ) -> Result - where - S: Server, - S::TokenStream: Default, - { - let client::Client { get_handle_counters, run, _marker } = *self; - run_server( - strategy, - get_handle_counters(), - server, - as Types>::TokenStream::mark(input), - run, - force_show_panics, - ) - .map(|s| as Types>::TokenStream>>::unmark(s).unwrap_or_default()) - } -} - -impl - client::Client< - (super::super::TokenStream, super::super::TokenStream), - super::super::TokenStream, - > -{ - pub fn run( - &self, - strategy: &impl ExecutionStrategy, - server: S, - input: S::TokenStream, - input2: S::TokenStream, - force_show_panics: bool, - ) -> Result - where - S: Server, - S::TokenStream: Default, - { - let client::Client { get_handle_counters, run, _marker } = *self; - run_server( - strategy, - get_handle_counters(), - server, - ( - as Types>::TokenStream::mark(input), - as Types>::TokenStream::mark(input2), - ), - run, - force_show_panics, - ) - .map(|s| as Types>::TokenStream>>::unmark(s).unwrap_or_default()) - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/diagnostic.rs b/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/diagnostic.rs deleted file mode 100644 index 3fade2dc4f9cc..0000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/diagnostic.rs +++ /dev/null @@ -1,166 +0,0 @@ -//! lib-proc-macro diagnostic -//! -//! Copy from -//! augmented with removing unstable features - -use super::Span; - -/// An enum representing a diagnostic level. -#[derive(Copy, Clone, Debug)] -#[non_exhaustive] -pub enum Level { - /// An error. - Error, - /// A warning. - Warning, - /// A note. - Note, - /// A help message. - Help, -} - -/// Trait implemented by types that can be converted into a set of `Span`s. -pub trait MultiSpan { - /// Converts `self` into a `Vec`. - fn into_spans(self) -> Vec; -} - -impl MultiSpan for Span { - fn into_spans(self) -> Vec { - vec![self] - } -} - -impl MultiSpan for Vec { - fn into_spans(self) -> Vec { - self - } -} - -impl<'a> MultiSpan for &'a [Span] { - fn into_spans(self) -> Vec { - self.to_vec() - } -} - -/// A structure representing a diagnostic message and associated children -/// messages. -#[derive(Clone, Debug)] -pub struct Diagnostic { - level: Level, - message: String, - spans: Vec, - children: Vec, -} - -macro_rules! diagnostic_child_methods { - ($spanned:ident, $regular:ident, $level:expr) => { - #[doc = concat!("Adds a new child diagnostics message to `self` with the [`", - stringify!($level), "`] level, and the given `spans` and `message`.")] - pub fn $spanned(mut self, spans: S, message: T) -> Diagnostic - where - S: MultiSpan, - T: Into, - { - self.children.push(Diagnostic::spanned(spans, $level, message)); - self - } - - #[doc = concat!("Adds a new child diagnostic message to `self` with the [`", - stringify!($level), "`] level, and the given `message`.")] - pub fn $regular>(mut self, message: T) -> Diagnostic { - self.children.push(Diagnostic::new($level, message)); - self - } - }; -} - -/// Iterator over the children diagnostics of a `Diagnostic`. -#[derive(Debug, Clone)] -pub struct Children<'a>(std::slice::Iter<'a, Diagnostic>); - -impl<'a> Iterator for Children<'a> { - type Item = &'a Diagnostic; - - fn next(&mut self) -> Option { - self.0.next() - } -} - -impl Diagnostic { - /// Creates a new diagnostic with the given `level` and `message`. - pub fn new>(level: Level, message: T) -> Diagnostic { - Diagnostic { level, message: message.into(), spans: vec![], children: vec![] } - } - - /// Creates a new diagnostic with the given `level` and `message` pointing to - /// the given set of `spans`. - pub fn spanned(spans: S, level: Level, message: T) -> Diagnostic - where - S: MultiSpan, - T: Into, - { - Diagnostic { level, message: message.into(), spans: spans.into_spans(), children: vec![] } - } - - diagnostic_child_methods!(span_error, error, Level::Error); - diagnostic_child_methods!(span_warning, warning, Level::Warning); - diagnostic_child_methods!(span_note, note, Level::Note); - diagnostic_child_methods!(span_help, help, Level::Help); - - /// Returns the diagnostic `level` for `self`. - pub fn level(&self) -> Level { - self.level - } - - /// Sets the level in `self` to `level`. - pub fn set_level(&mut self, level: Level) { - self.level = level; - } - - /// Returns the message in `self`. - pub fn message(&self) -> &str { - &self.message - } - - /// Sets the message in `self` to `message`. - pub fn set_message>(&mut self, message: T) { - self.message = message.into(); - } - - /// Returns the `Span`s in `self`. - pub fn spans(&self) -> &[Span] { - &self.spans - } - - /// Sets the `Span`s in `self` to `spans`. - pub fn set_spans(&mut self, spans: S) { - self.spans = spans.into_spans(); - } - - /// Returns an iterator over the children diagnostics of `self`. - pub fn children(&self) -> Children<'_> { - Children(self.children.iter()) - } - - /// Emit the diagnostic. - pub fn emit(self) { - fn to_internal(spans: Vec) -> super::bridge::client::MultiSpan { - let mut multi_span = super::bridge::client::MultiSpan::new(); - for span in spans { - multi_span.push(span.0); - } - multi_span - } - - let mut diag = super::bridge::client::Diagnostic::new( - self.level, - &self.message[..], - to_internal(self.spans), - ); - for c in self.children { - diag.sub(c.level, &c.message[..], to_internal(c.spans)); - } - diag.emit(); - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs b/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs deleted file mode 100644 index 89bd10da5e486..0000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs +++ /dev/null @@ -1,1106 +0,0 @@ -//! A support library for macro authors when defining new macros. -//! -//! This library, provided by the standard distribution, provides the types -//! consumed in the interfaces of procedurally defined macro definitions such as -//! function-like macros `#[proc_macro]`, macro attributes `#[proc_macro_attribute]` and -//! custom derive attributes`#[proc_macro_derive]`. -//! -//! See [the book] for more. -//! -//! [the book]: ../book/ch19-06-macros.html#procedural-macros-for-generating-code-from-attributes - -#[doc(hidden)] -pub mod bridge; - -mod diagnostic; - -pub use diagnostic::{Diagnostic, Level, MultiSpan}; - -use std::cmp::Ordering; -use std::ops::RangeBounds; -use std::path::PathBuf; -use std::str::FromStr; -use std::{error, fmt, iter, mem}; - -/// Determines whether proc_macro has been made accessible to the currently -/// running program. -/// -/// The proc_macro crate is only intended for use inside the implementation of -/// procedural macros. All the functions in this crate panic if invoked from -/// outside of a procedural macro, such as from a build script or unit test or -/// ordinary Rust binary. -/// -/// With consideration for Rust libraries that are designed to support both -/// macro and non-macro use cases, `proc_macro::is_available()` provides a -/// non-panicking way to detect whether the infrastructure required to use the -/// API of proc_macro is presently available. Returns true if invoked from -/// inside of a procedural macro, false if invoked from any other binary. -pub fn is_available() -> bool { - bridge::Bridge::is_available() -} - -/// The main type provided by this crate, representing an abstract stream of -/// tokens, or, more specifically, a sequence of token trees. -/// The type provide interfaces for iterating over those token trees and, conversely, -/// collecting a number of token trees into one stream. -/// -/// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]` -/// and `#[proc_macro_derive]` definitions. -#[derive(Clone)] -pub struct TokenStream(Option); - -/// Error returned from `TokenStream::from_str`. -#[non_exhaustive] -#[derive(Debug)] -pub struct LexError; - -impl fmt::Display for LexError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("cannot parse string into token stream") - } -} - -impl error::Error for LexError {} - -/// Error returned from `TokenStream::expand_expr`. -#[non_exhaustive] -#[derive(Debug)] -pub struct ExpandError; - -impl fmt::Display for ExpandError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("macro expansion failed") - } -} - -impl error::Error for ExpandError {} - -impl TokenStream { - /// Returns an empty `TokenStream` containing no token trees. - pub fn new() -> TokenStream { - TokenStream(None) - } - - /// Checks if this `TokenStream` is empty. - pub fn is_empty(&self) -> bool { - self.0.as_ref().map(|h| h.is_empty()).unwrap_or(true) - } - - /// Parses this `TokenStream` as an expression and attempts to expand any - /// macros within it. Returns the expanded `TokenStream`. - /// - /// Currently only expressions expanding to literals will succeed, although - /// this may be relaxed in the future. - /// - /// NOTE: In error conditions, `expand_expr` may leave macros unexpanded, - /// report an error, failing compilation, and/or return an `Err(..)`. The - /// specific behavior for any error condition, and what conditions are - /// considered errors, is unspecified and may change in the future. - pub fn expand_expr(&self) -> Result { - let stream = self.0.as_ref().ok_or(ExpandError)?; - match bridge::client::TokenStream::expand_expr(stream) { - Ok(stream) => Ok(TokenStream(Some(stream))), - Err(_) => Err(ExpandError), - } - } -} - -/// Attempts to break the string into tokens and parse those tokens into a token stream. -/// May fail for a number of reasons, for example, if the string contains unbalanced delimiters -/// or characters not existing in the language. -/// All tokens in the parsed stream get `Span::call_site()` spans. -/// -/// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to -/// change these errors into `LexError`s later. -impl FromStr for TokenStream { - type Err = LexError; - - fn from_str(src: &str) -> Result { - Ok(TokenStream(Some(bridge::client::TokenStream::from_str(src)))) - } -} - -/// Prints the token stream as a string that is supposed to be losslessly convertible back -/// into the same token stream (modulo spans), except for possibly `TokenTree::Group`s -/// with `Delimiter::None` delimiters and negative numeric literals. -impl fmt::Display for TokenStream { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - unimplemented!() - } -} - -/// Prints token in a form convenient for debugging. -impl fmt::Debug for TokenStream { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("TokenStream ")?; - f.debug_list().entries(self.clone()).finish() - } -} - -impl Default for TokenStream { - fn default() -> Self { - TokenStream::new() - } -} - -pub use quote::{quote, quote_span}; - -fn tree_to_bridge_tree( - tree: TokenTree, -) -> bridge::TokenTree< - bridge::client::Group, - bridge::client::Punct, - bridge::client::Ident, - bridge::client::Literal, -> { - match tree { - TokenTree::Group(tt) => bridge::TokenTree::Group(tt.0), - TokenTree::Punct(tt) => bridge::TokenTree::Punct(tt.0), - TokenTree::Ident(tt) => bridge::TokenTree::Ident(tt.0), - TokenTree::Literal(tt) => bridge::TokenTree::Literal(tt.0), - } -} - -/// Creates a token stream containing a single token tree. -impl From for TokenStream { - fn from(tree: TokenTree) -> TokenStream { - TokenStream(Some(bridge::client::TokenStream::from_token_tree(tree_to_bridge_tree(tree)))) - } -} - -/// Non-generic helper for implementing `FromIterator` and -/// `Extend` with less monomorphization in calling crates. -struct ConcatStreamsHelper { - streams: Vec, -} - -impl ConcatStreamsHelper { - fn new(capacity: usize) -> Self { - ConcatStreamsHelper { streams: Vec::with_capacity(capacity) } - } - - fn push(&mut self, stream: TokenStream) { - if let Some(stream) = stream.0 { - self.streams.push(stream); - } - } - - fn build(mut self) -> TokenStream { - if self.streams.len() <= 1 { - TokenStream(self.streams.pop()) - } else { - TokenStream(Some(bridge::client::TokenStream::concat_streams(None, self.streams))) - } - } - - fn append_to(mut self, stream: &mut TokenStream) { - if self.streams.is_empty() { - return; - } - let base = stream.0.take(); - if base.is_none() && self.streams.len() == 1 { - stream.0 = self.streams.pop(); - } else { - stream.0 = Some(bridge::client::TokenStream::concat_streams(base, self.streams)); - } - } -} - -/// Collects a number of token trees into a single stream. -impl FromIterator for TokenStream { - fn from_iter>(trees: I) -> Self { - trees.into_iter().map(TokenStream::from).collect() - } -} - -/// A "flattening" operation on token streams, collects token trees -/// from multiple token streams into a single stream. -impl FromIterator for TokenStream { - fn from_iter>(streams: I) -> Self { - let iter = streams.into_iter(); - let mut builder = ConcatStreamsHelper::new(iter.size_hint().0); - iter.for_each(|stream| builder.push(stream)); - builder.build() - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, trees: I) { - self.extend(trees.into_iter().map(TokenStream::from)); - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, streams: I) { - // FIXME(eddyb) Use an optimized implementation if/when possible. - *self = iter::once(mem::replace(self, Self::new())).chain(streams).collect(); - } -} - -/// Public implementation details for the `TokenStream` type, such as iterators. -pub mod token_stream { - use super::{bridge, Group, Ident, Literal, Punct, TokenStream, TokenTree}; - - /// An iterator over `TokenStream`'s `TokenTree`s. - /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups, - /// and returns whole groups as token trees. - #[derive(Clone)] - pub struct IntoIter( - std::vec::IntoIter< - bridge::TokenTree< - bridge::client::Group, - bridge::client::Punct, - bridge::client::Ident, - bridge::client::Literal, - >, - >, - ); - - impl Iterator for IntoIter { - type Item = TokenTree; - - fn next(&mut self) -> Option { - self.0.next().map(|tree| match tree { - bridge::TokenTree::Group(tt) => TokenTree::Group(Group(tt)), - bridge::TokenTree::Punct(tt) => TokenTree::Punct(Punct(tt)), - bridge::TokenTree::Ident(tt) => TokenTree::Ident(Ident(tt)), - bridge::TokenTree::Literal(tt) => TokenTree::Literal(Literal(tt)), - }) - } - } - - impl IntoIterator for TokenStream { - type Item = TokenTree; - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - IntoIter(self.0.map(|v| v.into_trees()).unwrap_or_default().into_iter()) - } - } -} - -#[doc(hidden)] -mod quote; - -/// A region of source code, along with macro expansion information. -#[derive(Copy, Clone)] -pub struct Span(bridge::client::Span); - -macro_rules! diagnostic_method { - ($name:ident, $level:expr) => { - /// Creates a new `Diagnostic` with the given `message` at the span - /// `self`. - pub fn $name>(self, message: T) -> Diagnostic { - Diagnostic::spanned(self, $level, message) - } - }; -} - -impl Span { - /// A span that resolves at the macro definition site. - pub fn def_site() -> Span { - Span(bridge::client::Span::def_site()) - } - - /// The span of the invocation of the current procedural macro. - /// Identifiers created with this span will be resolved as if they were written - /// directly at the macro call location (call-site hygiene) and other code - /// at the macro call site will be able to refer to them as well. - pub fn call_site() -> Span { - Span(bridge::client::Span::call_site()) - } - - /// A span that represents `macro_rules` hygiene, and sometimes resolves at the macro - /// definition site (local variables, labels, `$crate`) and sometimes at the macro - /// call site (everything else). - /// The span location is taken from the call-site. - pub fn mixed_site() -> Span { - Span(bridge::client::Span::mixed_site()) - } - - /// The original source file into which this span points. - pub fn source_file(&self) -> SourceFile { - SourceFile(self.0.source_file()) - } - - /// The `Span` for the tokens in the previous macro expansion from which - /// `self` was generated from, if any. - pub fn parent(&self) -> Option { - self.0.parent().map(Span) - } - - /// The span for the origin source code that `self` was generated from. If - /// this `Span` wasn't generated from other macro expansions then the return - /// value is the same as `*self`. - pub fn source(&self) -> Span { - Span(self.0.source()) - } - - /// Gets the starting line/column in the source file for this span. - pub fn start(&self) -> LineColumn { - self.0.start().add_1_to_column() - } - - /// Gets the ending line/column in the source file for this span. - pub fn end(&self) -> LineColumn { - self.0.end().add_1_to_column() - } - - /// Creates an empty span pointing to directly before this span. - pub fn before(&self) -> Span { - Span(self.0.before()) - } - - /// Creates an empty span pointing to directly after this span. - pub fn after(&self) -> Span { - Span(self.0.after()) - } - - /// Creates a new span encompassing `self` and `other`. - /// - /// Returns `None` if `self` and `other` are from different files. - pub fn join(&self, other: Span) -> Option { - self.0.join(other.0).map(Span) - } - - /// Creates a new span with the same line/column information as `self` but - /// that resolves symbols as though it were at `other`. - pub fn resolved_at(&self, other: Span) -> Span { - Span(self.0.resolved_at(other.0)) - } - - /// Creates a new span with the same name resolution behavior as `self` but - /// with the line/column information of `other`. - pub fn located_at(&self, other: Span) -> Span { - other.resolved_at(*self) - } - - /// Compares to spans to see if they're equal. - pub fn eq(&self, other: &Span) -> bool { - self.0 == other.0 - } - - /// Returns the source text behind a span. This preserves the original source - /// code, including spaces and comments. It only returns a result if the span - /// corresponds to real source code. - /// - /// Note: The observable result of a macro should only rely on the tokens and - /// not on this source text. The result of this function is a best effort to - /// be used for diagnostics only. - pub fn source_text(&self) -> Option { - self.0.source_text() - } - - // Used by the implementation of `Span::quote` - #[doc(hidden)] - pub fn save_span(&self) -> usize { - self.0.save_span() - } - - // Used by the implementation of `Span::quote` - #[doc(hidden)] - pub fn recover_proc_macro_span(id: usize) -> Span { - Span(bridge::client::Span::recover_proc_macro_span(id)) - } - - diagnostic_method!(error, Level::Error); - diagnostic_method!(warning, Level::Warning); - diagnostic_method!(note, Level::Note); - diagnostic_method!(help, Level::Help); -} - -/// Prints a span in a form convenient for debugging. -impl fmt::Debug for Span { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -/// A line-column pair representing the start or end of a `Span`. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct LineColumn { - /// The 1-indexed line in the source file on which the span starts or ends (inclusive). - pub line: usize, - /// The 1-indexed column (number of bytes in UTF-8 encoding) in the source - /// file on which the span starts or ends (inclusive). - pub column: usize, -} - -impl LineColumn { - fn add_1_to_column(self) -> Self { - LineColumn { line: self.line, column: self.column + 1 } - } -} - -impl Ord for LineColumn { - fn cmp(&self, other: &Self) -> Ordering { - self.line.cmp(&other.line).then(self.column.cmp(&other.column)) - } -} - -impl PartialOrd for LineColumn { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -/// The source file of a given `Span`. -#[derive(Clone)] -pub struct SourceFile(bridge::client::SourceFile); - -impl SourceFile { - /// Gets the path to this source file. - /// - /// ### Note - /// If the code span associated with this `SourceFile` was generated by an external macro, this - /// macro, this might not be an actual path on the filesystem. Use [`is_real`] to check. - /// - /// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on - /// the command line, the path as given might not actually be valid. - /// - /// [`is_real`]: Self::is_real - pub fn path(&self) -> PathBuf { - PathBuf::from(self.0.path()) - } - - /// Returns `true` if this source file is a real source file, and not generated by an external - /// macro's expansion. - pub fn is_real(&self) -> bool { - // This is a hack until intercrate spans are implemented and we can have real source files - // for spans generated in external macros. - // https://github.com/rust-lang/rust/pull/43604#issuecomment-333334368 - self.0.is_real() - } -} - -impl fmt::Debug for SourceFile { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SourceFile") - .field("path", &self.path()) - .field("is_real", &self.is_real()) - .finish() - } -} - -impl PartialEq for SourceFile { - fn eq(&self, other: &Self) -> bool { - self.0.eq(&other.0) - } -} - -impl Eq for SourceFile {} - -/// A single token or a delimited sequence of token trees (e.g., `[1, (), ..]`). -#[derive(Clone)] -pub enum TokenTree { - /// A token stream surrounded by bracket delimiters. - Group(Group), - /// An identifier. - Ident(Ident), - /// A single punctuation character (`+`, `,`, `$`, etc.). - Punct(Punct), - /// A literal character (`'a'`), string (`"hello"`), number (`2.3`), etc. - Literal(Literal), -} - -impl TokenTree { - /// Returns the span of this tree, delegating to the `span` method of - /// the contained token or a delimited stream. - pub fn span(&self) -> Span { - match *self { - TokenTree::Group(ref t) => t.span(), - TokenTree::Ident(ref t) => t.span(), - TokenTree::Punct(ref t) => t.span(), - TokenTree::Literal(ref t) => t.span(), - } - } - - /// Configures the span for *only this token*. - /// - /// Note that if this token is a `Group` then this method will not configure - /// the span of each of the internal tokens, this will simply delegate to - /// the `set_span` method of each variant. - pub fn set_span(&mut self, span: Span) { - match *self { - TokenTree::Group(ref mut t) => t.set_span(span), - TokenTree::Ident(ref mut t) => t.set_span(span), - TokenTree::Punct(ref mut t) => t.set_span(span), - TokenTree::Literal(ref mut t) => t.set_span(span), - } - } -} - -/// Prints token tree in a form convenient for debugging. -impl fmt::Debug for TokenTree { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Each of these has the name in the struct type in the derived debug, - // so don't bother with an extra layer of indirection - match *self { - TokenTree::Group(ref tt) => tt.fmt(f), - TokenTree::Ident(ref tt) => tt.fmt(f), - TokenTree::Punct(ref tt) => tt.fmt(f), - TokenTree::Literal(ref tt) => tt.fmt(f), - } - } -} - -impl From for TokenTree { - fn from(g: Group) -> TokenTree { - TokenTree::Group(g) - } -} - -impl From for TokenTree { - fn from(g: Ident) -> TokenTree { - TokenTree::Ident(g) - } -} - -impl From for TokenTree { - fn from(g: Punct) -> TokenTree { - TokenTree::Punct(g) - } -} - -impl From for TokenTree { - fn from(g: Literal) -> TokenTree { - TokenTree::Literal(g) - } -} - -/// Prints the token tree as a string that is supposed to be losslessly convertible back -/// into the same token tree (modulo spans), except for possibly `TokenTree::Group`s -/// with `Delimiter::None` delimiters and negative numeric literals. -impl fmt::Display for TokenTree { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - unimplemented!() - } -} - -/// A delimited token stream. -/// -/// A `Group` internally contains a `TokenStream` which is surrounded by `Delimiter`s. -#[derive(Clone)] -pub struct Group(bridge::client::Group); - -/// Describes how a sequence of token trees is delimited. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Delimiter { - /// `( ... )` - Parenthesis, - /// `{ ... }` - Brace, - /// `[ ... ]` - Bracket, - /// `Ø ... Ø` - /// An invisible delimiter, that may, for example, appear around tokens coming from a - /// "macro variable" `$var`. It is important to preserve operator priorities in cases like - /// `$var * 3` where `$var` is `1 + 2`. - /// Invisible delimiters might not survive roundtrip of a token stream through a string. - None, -} - -impl Group { - /// Creates a new `Group` with the given delimiter and token stream. - /// - /// This constructor will set the span for this group to - /// `Span::call_site()`. To change the span you can use the `set_span` - /// method below. - pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group { - Group(bridge::client::Group::new(delimiter, stream.0)) - } - - /// Returns the delimiter of this `Group` - pub fn delimiter(&self) -> Delimiter { - self.0.delimiter() - } - - /// Returns the `TokenStream` of tokens that are delimited in this `Group`. - /// - /// Note that the returned token stream does not include the delimiter - /// returned above. - pub fn stream(&self) -> TokenStream { - TokenStream(Some(self.0.stream())) - } - - /// Returns the span for the delimiters of this token stream, spanning the - /// entire `Group`. - /// - /// ```text - /// pub fn span(&self) -> Span { - /// ^^^^^^^ - /// ``` - pub fn span(&self) -> Span { - Span(self.0.span()) - } - - /// Returns the span pointing to the opening delimiter of this group. - /// - /// ```text - /// pub fn span_open(&self) -> Span { - /// ^ - /// ``` - pub fn span_open(&self) -> Span { - Span(self.0.span_open()) - } - - /// Returns the span pointing to the closing delimiter of this group. - /// - /// ```text - /// pub fn span_close(&self) -> Span { - /// ^ - /// ``` - pub fn span_close(&self) -> Span { - Span(self.0.span_close()) - } - - /// Configures the span for this `Group`'s delimiters, but not its internal - /// tokens. - /// - /// This method will **not** set the span of all the internal tokens spanned - /// by this group, but rather it will only set the span of the delimiter - /// tokens at the level of the `Group`. - pub fn set_span(&mut self, span: Span) { - self.0.set_span(span.0); - } -} - -/// Prints the group as a string that should be losslessly convertible back -/// into the same group (modulo spans), except for possibly `TokenTree::Group`s -/// with `Delimiter::None` delimiters. -impl fmt::Display for Group { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - unimplemented!() - } -} - -impl fmt::Debug for Group { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Group") - .field("delimiter", &self.delimiter()) - .field("stream", &self.stream()) - .field("span", &self.span()) - .finish() - } -} - -/// A `Punct` is a single punctuation character such as `+`, `-` or `#`. -/// -/// Multi-character operators like `+=` are represented as two instances of `Punct` with different -/// forms of `Spacing` returned. -#[derive(Clone)] -pub struct Punct(bridge::client::Punct); - -/// Describes whether a `Punct` is followed immediately by another `Punct` ([`Spacing::Joint`]) or -/// by a different token or whitespace ([`Spacing::Alone`]). -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Spacing { - /// A `Punct` is not immediately followed by another `Punct`. - /// E.g. `+` is `Alone` in `+ =`, `+ident` and `+()`. - Alone, - /// A `Punct` is immediately followed by another `Punct`. - /// E.g. `+` is `Joint` in `+=` and `++`. - /// - /// Additionally, single quote `'` can join with identifiers to form lifetimes: `'ident`. - Joint, -} - -impl Punct { - /// Creates a new `Punct` from the given character and spacing. - /// The `ch` argument must be a valid punctuation character permitted by the language, - /// otherwise the function will panic. - /// - /// The returned `Punct` will have the default span of `Span::call_site()` - /// which can be further configured with the `set_span` method below. - pub fn new(ch: char, spacing: Spacing) -> Punct { - Punct(bridge::client::Punct::new(ch, spacing)) - } - - /// Returns the value of this punctuation character as `char`. - pub fn as_char(&self) -> char { - self.0.as_char() - } - - /// Returns the spacing of this punctuation character, indicating whether it's immediately - /// followed by another `Punct` in the token stream, so they can potentially be combined into - /// a multi-character operator (`Joint`), or it's followed by some other token or whitespace - /// (`Alone`) so the operator has certainly ended. - pub fn spacing(&self) -> Spacing { - self.0.spacing() - } - - /// Returns the span for this punctuation character. - pub fn span(&self) -> Span { - Span(self.0.span()) - } - - /// Configure the span for this punctuation character. - pub fn set_span(&mut self, span: Span) { - self.0 = self.0.with_span(span.0); - } -} - -/// Prints the punctuation character as a string that should be losslessly convertible -/// back into the same character. -impl fmt::Display for Punct { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - unimplemented!() - } -} - -impl fmt::Debug for Punct { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Punct") - .field("ch", &self.as_char()) - .field("spacing", &self.spacing()) - .field("span", &self.span()) - .finish() - } -} - -impl PartialEq for Punct { - fn eq(&self, rhs: &char) -> bool { - self.as_char() == *rhs - } -} - -impl PartialEq for char { - fn eq(&self, rhs: &Punct) -> bool { - *self == rhs.as_char() - } -} - -/// An identifier (`ident`). -#[derive(Clone)] -pub struct Ident(bridge::client::Ident); - -impl Ident { - /// Creates a new `Ident` with the given `string` as well as the specified - /// `span`. - /// The `string` argument must be a valid identifier permitted by the - /// language (including keywords, e.g. `self` or `fn`). Otherwise, the function will panic. - /// - /// Note that `span`, currently in rustc, configures the hygiene information - /// for this identifier. - /// - /// As of this time `Span::call_site()` explicitly opts-in to "call-site" hygiene - /// meaning that identifiers created with this span will be resolved as if they were written - /// directly at the location of the macro call, and other code at the macro call site will be - /// able to refer to them as well. - /// - /// Later spans like `Span::def_site()` will allow to opt-in to "definition-site" hygiene - /// meaning that identifiers created with this span will be resolved at the location of the - /// macro definition and other code at the macro call site will not be able to refer to them. - /// - /// Due to the current importance of hygiene this constructor, unlike other - /// tokens, requires a `Span` to be specified at construction. - pub fn new(string: &str, span: Span) -> Ident { - Ident(bridge::client::Ident::new(string, span.0, false)) - } - - /// Same as `Ident::new`, but creates a raw identifier (`r#ident`). - /// The `string` argument be a valid identifier permitted by the language - /// (including keywords, e.g. `fn`). Keywords which are usable in path segments - /// (e.g. `self`, `super`) are not supported, and will cause a panic. - pub fn new_raw(string: &str, span: Span) -> Ident { - Ident(bridge::client::Ident::new(string, span.0, true)) - } - - /// Returns the span of this `Ident`, encompassing the entire string returned - /// by [`to_string`](Self::to_string). - pub fn span(&self) -> Span { - Span(self.0.span()) - } - - /// Configures the span of this `Ident`, possibly changing its hygiene context. - pub fn set_span(&mut self, span: Span) { - self.0 = self.0.with_span(span.0); - } -} - -/// Prints the identifier as a string that should be losslessly convertible -/// back into the same identifier. -impl fmt::Display for Ident { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - unimplemented!() - } -} - -impl fmt::Debug for Ident { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Ident") - .field("ident", &self.to_string()) - .field("span", &self.span()) - .finish() - } -} - -/// A literal string (`"hello"`), byte string (`b"hello"`), -/// character (`'a'`), byte character (`b'a'`), an integer or floating point number -/// with or without a suffix (`1`, `1u8`, `2.3`, `2.3f32`). -/// Boolean literals like `true` and `false` do not belong here, they are `Ident`s. -#[derive(Clone)] -pub struct Literal(bridge::client::Literal); - -macro_rules! suffixed_int_literals { - ($($name:ident => $kind:ident,)*) => ($( - /// Creates a new suffixed integer literal with the specified value. - /// - /// This function will create an integer like `1u32` where the integer - /// value specified is the first part of the token and the integral is - /// also suffixed at the end. - /// Literals created from negative numbers might not survive round-trips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// Literals created through this method have the `Span::call_site()` - /// span by default, which can be configured with the `set_span` method - /// below. - pub fn $name(n: $kind) -> Literal { - Literal(bridge::client::Literal::typed_integer(&n.to_string(), stringify!($kind))) - } - )*) -} - -macro_rules! unsuffixed_int_literals { - ($($name:ident => $kind:ident,)*) => ($( - /// Creates a new unsuffixed integer literal with the specified value. - /// - /// This function will create an integer like `1` where the integer - /// value specified is the first part of the token. No suffix is - /// specified on this token, meaning that invocations like - /// `Literal::i8_unsuffixed(1)` are equivalent to - /// `Literal::u32_unsuffixed(1)`. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// Literals created through this method have the `Span::call_site()` - /// span by default, which can be configured with the `set_span` method - /// below. - pub fn $name(n: $kind) -> Literal { - Literal(bridge::client::Literal::integer(&n.to_string())) - } - )*) -} - -impl Literal { - suffixed_int_literals! { - u8_suffixed => u8, - u16_suffixed => u16, - u32_suffixed => u32, - u64_suffixed => u64, - u128_suffixed => u128, - usize_suffixed => usize, - i8_suffixed => i8, - i16_suffixed => i16, - i32_suffixed => i32, - i64_suffixed => i64, - i128_suffixed => i128, - isize_suffixed => isize, - } - - unsuffixed_int_literals! { - u8_unsuffixed => u8, - u16_unsuffixed => u16, - u32_unsuffixed => u32, - u64_unsuffixed => u64, - u128_unsuffixed => u128, - usize_unsuffixed => usize, - i8_unsuffixed => i8, - i16_unsuffixed => i16, - i32_unsuffixed => i32, - i64_unsuffixed => i64, - i128_unsuffixed => i128, - isize_unsuffixed => isize, - } - - /// Creates a new unsuffixed floating-point literal. - /// - /// This constructor is similar to those like `Literal::i8_unsuffixed` where - /// the float's value is emitted directly into the token but no suffix is - /// used, so it may be inferred to be a `f64` later in the compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f32_unsuffixed(n: f32) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - let mut repr = n.to_string(); - if !repr.contains('.') { - repr.push_str(".0"); - } - Literal(bridge::client::Literal::float(&repr)) - } - - /// Creates a new suffixed floating-point literal. - /// - /// This constructor will create a literal like `1.0f32` where the value - /// specified is the preceding part of the token and `f32` is the suffix of - /// the token. This token will always be inferred to be an `f32` in the - /// compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f32_suffixed(n: f32) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - Literal(bridge::client::Literal::f32(&n.to_string())) - } - - /// Creates a new unsuffixed floating-point literal. - /// - /// This constructor is similar to those like `Literal::i8_unsuffixed` where - /// the float's value is emitted directly into the token but no suffix is - /// used, so it may be inferred to be a `f64` later in the compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f64_unsuffixed(n: f64) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - let mut repr = n.to_string(); - if !repr.contains('.') { - repr.push_str(".0"); - } - Literal(bridge::client::Literal::float(&repr)) - } - - /// Creates a new suffixed floating-point literal. - /// - /// This constructor will create a literal like `1.0f64` where the value - /// specified is the preceding part of the token and `f64` is the suffix of - /// the token. This token will always be inferred to be an `f64` in the - /// compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f64_suffixed(n: f64) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - Literal(bridge::client::Literal::f64(&n.to_string())) - } - - /// String literal. - pub fn string(string: &str) -> Literal { - Literal(bridge::client::Literal::string(string)) - } - - /// Character literal. - pub fn character(ch: char) -> Literal { - Literal(bridge::client::Literal::character(ch)) - } - - /// Byte string literal. - pub fn byte_string(bytes: &[u8]) -> Literal { - Literal(bridge::client::Literal::byte_string(bytes)) - } - - /// Returns the span encompassing this literal. - pub fn span(&self) -> Span { - Span(self.0.span()) - } - - /// Configures the span associated for this literal. - pub fn set_span(&mut self, span: Span) { - self.0.set_span(span.0); - } - - /// Returns a `Span` that is a subset of `self.span()` containing only the - /// source bytes in range `range`. Returns `None` if the would-be trimmed - /// span is outside the bounds of `self`. - // FIXME(SergioBenitez): check that the byte range starts and ends at a - // UTF-8 boundary of the source. otherwise, it's likely that a panic will - // occur elsewhere when the source text is printed. - // FIXME(SergioBenitez): there is no way for the user to know what - // `self.span()` actually maps to, so this method can currently only be - // called blindly. For example, `to_string()` for the character 'c' returns - // "'\u{63}'"; there is no way for the user to know whether the source text - // was 'c' or whether it was '\u{63}'. - pub fn subspan>(&self, range: R) -> Option { - self.0.subspan(range.start_bound().cloned(), range.end_bound().cloned()).map(Span) - } -} - -/// Parse a single literal from its stringified representation. -/// -/// In order to parse successfully, the input string must not contain anything -/// but the literal token. Specifically, it must not contain whitespace or -/// comments in addition to the literal. -/// -/// The resulting literal token will have a `Span::call_site()` span. -/// -/// NOTE: some errors may cause panics instead of returning `LexError`. We -/// reserve the right to change these errors into `LexError`s later. -impl FromStr for Literal { - type Err = LexError; - - fn from_str(src: &str) -> Result { - match bridge::client::Literal::from_str(src) { - Ok(literal) => Ok(Literal(literal)), - Err(()) => Err(LexError), - } - } -} - -/// Prints the literal as a string that should be losslessly convertible -/// back into the same literal (except for possible rounding for floating point literals). -impl fmt::Display for Literal { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - unimplemented!() - } -} - -impl fmt::Debug for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -/// Tracked access to environment variables. -pub mod tracked_env { - use std::env::{self, VarError}; - use std::ffi::OsStr; - - /// Retrieve an environment variable and add it to build dependency info. - /// Build system executing the compiler will know that the variable was accessed during - /// compilation, and will be able to rerun the build when the value of that variable changes. - /// Besides the dependency tracking this function should be equivalent to `env::var` from the - /// standard library, except that the argument must be UTF-8. - pub fn var + AsRef>(key: K) -> Result { - let key: &str = key.as_ref(); - let value = env::var(key); - super::bridge::client::FreeFunctions::track_env_var(key, value.as_deref().ok()); - value - } -} - -/// Tracked access to additional files. -pub mod tracked_path { - - /// Track a file explicitly. - /// - /// Commonly used for tracking asset preprocessing. - pub fn path>(path: P) { - let path: &str = path.as_ref(); - super::bridge::client::FreeFunctions::track_path(path); - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/quote.rs b/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/quote.rs deleted file mode 100644 index 39309faa41213..0000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/quote.rs +++ /dev/null @@ -1,139 +0,0 @@ -//! # Quasiquoter -//! This file contains the implementation internals of the quasiquoter provided by `quote!`. - -//! This quasiquoter uses macros 2.0 hygiene to reliably access -//! items from `proc_macro`, to build a `proc_macro::TokenStream`. - -use super::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; - -macro_rules! quote_tt { - (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, quote!($($t)*)) }; - ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, quote!($($t)*)) }; - ({$($t:tt)*}) => { Group::new(Delimiter::Brace, quote!($($t)*)) }; - (,) => { Punct::new(',', Spacing::Alone) }; - (.) => { Punct::new('.', Spacing::Alone) }; - (;) => { Punct::new(';', Spacing::Alone) }; - (!) => { Punct::new('!', Spacing::Alone) }; - (<) => { Punct::new('<', Spacing::Alone) }; - (>) => { Punct::new('>', Spacing::Alone) }; - (&) => { Punct::new('&', Spacing::Alone) }; - (=) => { Punct::new('=', Spacing::Alone) }; - ($i:ident) => { Ident::new(stringify!($i), Span::def_site()) }; -} - -macro_rules! quote_ts { - ((@ $($t:tt)*)) => { $($t)* }; - (::) => { - [ - TokenTree::from(Punct::new(':', Spacing::Joint)), - TokenTree::from(Punct::new(':', Spacing::Alone)), - ].iter() - .cloned() - .map(|mut x| { - x.set_span(Span::def_site()); - x - }) - .collect::() - }; - ($t:tt) => { TokenTree::from(quote_tt!($t)) }; -} - -/// Simpler version of the real `quote!` macro, implemented solely -/// through `macro_rules`, for bootstrapping the real implementation -/// (see the `quote` function), which does not have access to the -/// real `quote!` macro due to the `proc_macro` crate not being -/// able to depend on itself. -/// -/// Note: supported tokens are a subset of the real `quote!`, but -/// unquoting is different: instead of `$x`, this uses `(@ expr)`. -macro_rules! quote { - () => { TokenStream::new() }; - ($($t:tt)*) => { - [ - $(TokenStream::from(quote_ts!($t)),)* - ].iter().cloned().collect::() - }; -} - -/// Quote a `TokenStream` into a `TokenStream`. -/// This is the actual implementation of the `quote!()` proc macro. -/// -/// It is loaded by the compiler in `register_builtin_macros`. -pub fn quote(stream: TokenStream) -> TokenStream { - if stream.is_empty() { - return quote!(super::TokenStream::new()); - } - let proc_macro_crate = quote!(crate); - let mut after_dollar = false; - let tokens = stream - .into_iter() - .filter_map(|tree| { - if after_dollar { - after_dollar = false; - match tree { - TokenTree::Ident(_) => { - return Some(quote!(Into::::into( - Clone::clone(&(@ tree))),)); - } - TokenTree::Punct(ref tt) if tt.as_char() == '$' => {} - _ => panic!("`$` must be followed by an ident or `$` in `quote!`"), - } - } else if let TokenTree::Punct(ref tt) = tree { - if tt.as_char() == '$' { - after_dollar = true; - return None; - } - } - - Some(quote!(super::TokenStream::from((@ match tree { - TokenTree::Punct(tt) => quote!(super::TokenTree::Punct(super::Punct::new( - (@ TokenTree::from(Literal::character(tt.as_char()))), - (@ match tt.spacing() { - Spacing::Alone => quote!(super::Spacing::Alone), - Spacing::Joint => quote!(super::Spacing::Joint), - }), - ))), - TokenTree::Group(tt) => quote!(super::TokenTree::Group(super::Group::new( - (@ match tt.delimiter() { - Delimiter::Parenthesis => quote!(super::Delimiter::Parenthesis), - Delimiter::Brace => quote!(super::Delimiter::Brace), - Delimiter::Bracket => quote!(super::Delimiter::Bracket), - Delimiter::None => quote!(super::Delimiter::None), - }), - (@ quote(tt.stream())), - ))), - TokenTree::Ident(tt) => quote!(super::TokenTree::Ident(super::Ident::new( - (@ TokenTree::from(Literal::string(&tt.to_string()))), - (@ quote_span(proc_macro_crate.clone(), tt.span())), - ))), - TokenTree::Literal(tt) => quote!(super::TokenTree::Literal({ - let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string()))) - .parse::() - .unwrap() - .into_iter(); - if let (Some(super::TokenTree::Literal(mut lit)), None) = - (iter.next(), iter.next()) - { - lit.set_span((@ quote_span(proc_macro_crate.clone(), tt.span()))); - lit - } else { - unreachable!() - } - })) - })),)) - }) - .collect::(); - - if after_dollar { - panic!("unexpected trailing `$` in `quote!`"); - } - - quote!([(@ tokens)].iter().cloned().collect::()) -} - -/// Quote a `Span` into a `TokenStream`. -/// This is needed to implement a custom quoter. -pub fn quote_span(proc_macro_crate: TokenStream, span: Span) -> TokenStream { - let id = span.save_span(); - quote!((@ proc_macro_crate ) ::Span::recover_proc_macro_span((@ TokenTree::from(Literal::usize_unsuffixed(id))))) -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_63/ra_server.rs b/crates/proc-macro-srv/src/abis/abi_1_63/ra_server.rs deleted file mode 100644 index 30baf3a13f57f..0000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_63/ra_server.rs +++ /dev/null @@ -1,840 +0,0 @@ -//! Rustc proc-macro server implementation with tt -//! -//! Based on idea from -//! The lib-proc-macro server backend is `TokenStream`-agnostic, such that -//! we could provide any TokenStream implementation. -//! The original idea from fedochet is using proc-macro2 as backend, -//! we use tt instead for better integration with RA. -//! -//! FIXME: No span and source file information is implemented yet - -use super::proc_macro::bridge::{self, server}; - -use std::collections::HashMap; -use std::hash::Hash; -use std::ops::Bound; -use std::{ascii, vec::IntoIter}; - -use crate::tt; - -type Group = tt::Subtree; -type TokenTree = tt::TokenTree; -type Punct = tt::Punct; -type Spacing = tt::Spacing; -type Literal = tt::Literal; -type Span = tt::TokenId; - -#[derive(Debug, Default, Clone)] -pub struct TokenStream { - pub token_trees: Vec, -} - -impl TokenStream { - pub fn new() -> Self { - TokenStream::default() - } - - pub fn with_subtree(subtree: tt::Subtree) -> Self { - if subtree.delimiter.kind != tt::DelimiterKind::Invisible { - TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] } - } else { - TokenStream { token_trees: subtree.token_trees } - } - } - - pub fn into_subtree(self) -> tt::Subtree { - tt::Subtree { delimiter: tt::Delimiter::UNSPECIFIED, token_trees: self.token_trees } - } - - pub fn is_empty(&self) -> bool { - self.token_trees.is_empty() - } -} - -/// Creates a token stream containing a single token tree. -impl From for TokenStream { - fn from(tree: TokenTree) -> TokenStream { - TokenStream { token_trees: vec![tree] } - } -} - -/// Collects a number of token trees into a single stream. -impl FromIterator for TokenStream { - fn from_iter>(trees: I) -> Self { - trees.into_iter().map(TokenStream::from).collect() - } -} - -/// A "flattening" operation on token streams, collects token trees -/// from multiple token streams into a single stream. -impl FromIterator for TokenStream { - fn from_iter>(streams: I) -> Self { - let mut builder = TokenStreamBuilder::new(); - streams.into_iter().for_each(|stream| builder.push(stream)); - builder.build() - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, trees: I) { - self.extend(trees.into_iter().map(TokenStream::from)); - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, streams: I) { - for item in streams { - for tkn in item { - match tkn { - tt::TokenTree::Subtree(subtree) - if subtree.delimiter.kind == tt::DelimiterKind::Invisible => - { - self.token_trees.extend(subtree.token_trees); - } - _ => { - self.token_trees.push(tkn); - } - } - } - } - } -} - -#[derive(Clone)] -pub struct SourceFile { - // FIXME stub -} - -type Level = super::proc_macro::Level; -type LineColumn = super::proc_macro::LineColumn; - -/// A structure representing a diagnostic message and associated children -/// messages. -#[derive(Clone, Debug)] -pub struct Diagnostic { - level: Level, - message: String, - spans: Vec, - children: Vec, -} - -impl Diagnostic { - /// Creates a new diagnostic with the given `level` and `message`. - pub fn new>(level: Level, message: T) -> Diagnostic { - Diagnostic { level, message: message.into(), spans: vec![], children: vec![] } - } -} - -// Rustc Server Ident has to be `Copyable` -// We use a stub here for bypassing -#[derive(Hash, Eq, PartialEq, Copy, Clone)] -pub struct IdentId(u32); - -#[derive(Clone, Hash, Eq, PartialEq)] -struct IdentData(tt::Ident); - -#[derive(Default)] -struct IdentInterner { - idents: HashMap, - ident_data: Vec, -} - -impl IdentInterner { - fn intern(&mut self, data: &IdentData) -> u32 { - if let Some(index) = self.idents.get(data) { - return *index; - } - - let index = self.idents.len() as u32; - self.ident_data.push(data.clone()); - self.idents.insert(data.clone(), index); - index - } - - fn get(&self, index: u32) -> &IdentData { - &self.ident_data[index as usize] - } - - #[allow(unused)] - fn get_mut(&mut self, index: u32) -> &mut IdentData { - self.ident_data.get_mut(index as usize).expect("Should be consistent") - } -} - -pub struct TokenStreamBuilder { - acc: TokenStream, -} - -/// Public implementation details for the `TokenStream` type, such as iterators. -pub mod token_stream { - use std::str::FromStr; - - use super::{tt, TokenStream, TokenTree}; - - /// An iterator over `TokenStream`'s `TokenTree`s. - /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups, - /// and returns whole groups as token trees. - impl IntoIterator for TokenStream { - type Item = TokenTree; - type IntoIter = super::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.token_trees.into_iter() - } - } - - type LexError = String; - - /// Attempts to break the string into tokens and parse those tokens into a token stream. - /// May fail for a number of reasons, for example, if the string contains unbalanced delimiters - /// or characters not existing in the language. - /// All tokens in the parsed stream get `Span::call_site()` spans. - /// - /// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to - /// change these errors into `LexError`s later. - impl FromStr for TokenStream { - type Err = LexError; - - fn from_str(src: &str) -> Result { - let (subtree, _token_map) = - mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?; - - let subtree = subtree_replace_token_ids_with_unspecified(subtree); - Ok(TokenStream::with_subtree(subtree)) - } - } - - impl ToString for TokenStream { - fn to_string(&self) -> String { - ::tt::pretty(&self.token_trees) - } - } - - fn subtree_replace_token_ids_with_unspecified(subtree: tt::Subtree) -> tt::Subtree { - tt::Subtree { - delimiter: tt::Delimiter { - open: tt::TokenId::UNSPECIFIED, - close: tt::TokenId::UNSPECIFIED, - ..subtree.delimiter - }, - token_trees: subtree - .token_trees - .into_iter() - .map(token_tree_replace_token_ids_with_unspecified) - .collect(), - } - } - - fn token_tree_replace_token_ids_with_unspecified(tt: tt::TokenTree) -> tt::TokenTree { - match tt { - tt::TokenTree::Leaf(leaf) => { - tt::TokenTree::Leaf(leaf_replace_token_ids_with_unspecified(leaf)) - } - tt::TokenTree::Subtree(subtree) => { - tt::TokenTree::Subtree(subtree_replace_token_ids_with_unspecified(subtree)) - } - } - } - - fn leaf_replace_token_ids_with_unspecified(leaf: tt::Leaf) -> tt::Leaf { - match leaf { - tt::Leaf::Literal(lit) => { - tt::Leaf::Literal(tt::Literal { span: tt::TokenId::unspecified(), ..lit }) - } - tt::Leaf::Punct(punct) => { - tt::Leaf::Punct(tt::Punct { span: tt::TokenId::unspecified(), ..punct }) - } - tt::Leaf::Ident(ident) => { - tt::Leaf::Ident(tt::Ident { span: tt::TokenId::unspecified(), ..ident }) - } - } - } -} - -impl TokenStreamBuilder { - fn new() -> TokenStreamBuilder { - TokenStreamBuilder { acc: TokenStream::new() } - } - - fn push(&mut self, stream: TokenStream) { - self.acc.extend(stream.into_iter()) - } - - fn build(self) -> TokenStream { - self.acc - } -} - -pub struct FreeFunctions; - -#[derive(Clone)] -pub struct TokenStreamIter { - trees: IntoIter, -} - -#[derive(Default)] -pub struct RustAnalyzer { - ident_interner: IdentInterner, - // FIXME: store span information here. -} - -impl server::Types for RustAnalyzer { - type FreeFunctions = FreeFunctions; - type TokenStream = TokenStream; - type Group = Group; - type Punct = Punct; - type Ident = IdentId; - type Literal = Literal; - type SourceFile = SourceFile; - type Diagnostic = Diagnostic; - type Span = Span; - type MultiSpan = Vec; -} - -impl server::FreeFunctions for RustAnalyzer { - fn track_env_var(&mut self, _var: &str, _value: Option<&str>) { - // FIXME: track env var accesses - // https://github.com/rust-lang/rust/pull/71858 - } - fn track_path(&mut self, _path: &str) {} -} - -impl server::TokenStream for RustAnalyzer { - fn is_empty(&mut self, stream: &Self::TokenStream) -> bool { - stream.is_empty() - } - fn from_str(&mut self, src: &str) -> Self::TokenStream { - use std::str::FromStr; - - Self::TokenStream::from_str(src).expect("cannot parse string") - } - fn to_string(&mut self, stream: &Self::TokenStream) -> String { - stream.to_string() - } - fn from_token_tree( - &mut self, - tree: bridge::TokenTree, - ) -> Self::TokenStream { - match tree { - bridge::TokenTree::Group(group) => { - let tree = TokenTree::from(group); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Ident(IdentId(index)) => { - let IdentData(ident) = self.ident_interner.get(index).clone(); - let ident: tt::Ident = ident; - let leaf = tt::Leaf::from(ident); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Literal(literal) => { - let leaf = tt::Leaf::from(literal); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Punct(p) => { - let leaf = tt::Leaf::from(p); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - } - } - - fn expand_expr(&mut self, self_: &Self::TokenStream) -> Result { - Ok(self_.clone()) - } - - fn concat_trees( - &mut self, - base: Option, - trees: Vec>, - ) -> Self::TokenStream { - let mut builder = TokenStreamBuilder::new(); - if let Some(base) = base { - builder.push(base); - } - for tree in trees { - builder.push(self.from_token_tree(tree)); - } - builder.build() - } - - fn concat_streams( - &mut self, - base: Option, - streams: Vec, - ) -> Self::TokenStream { - let mut builder = TokenStreamBuilder::new(); - if let Some(base) = base { - builder.push(base); - } - for stream in streams { - builder.push(stream); - } - builder.build() - } - - fn into_trees( - &mut self, - stream: Self::TokenStream, - ) -> Vec> { - stream - .into_iter() - .map(|tree| match tree { - tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { - bridge::TokenTree::Ident(IdentId(self.ident_interner.intern(&IdentData(ident)))) - } - tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => bridge::TokenTree::Literal(lit), - tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => bridge::TokenTree::Punct(punct), - tt::TokenTree::Subtree(subtree) => bridge::TokenTree::Group(subtree), - }) - .collect() - } -} - -fn delim_to_internal(d: bridge::Delimiter) -> tt::Delimiter { - let kind = match d { - bridge::Delimiter::Parenthesis => tt::DelimiterKind::Parenthesis, - bridge::Delimiter::Brace => tt::DelimiterKind::Brace, - bridge::Delimiter::Bracket => tt::DelimiterKind::Bracket, - bridge::Delimiter::None => tt::DelimiterKind::Invisible, - }; - tt::Delimiter { open: tt::TokenId::unspecified(), close: tt::TokenId::unspecified(), kind } -} - -fn delim_to_external(d: tt::Delimiter) -> bridge::Delimiter { - match d.kind { - tt::DelimiterKind::Parenthesis => bridge::Delimiter::Parenthesis, - tt::DelimiterKind::Brace => bridge::Delimiter::Brace, - tt::DelimiterKind::Bracket => bridge::Delimiter::Bracket, - tt::DelimiterKind::Invisible => bridge::Delimiter::None, - } -} - -fn spacing_to_internal(spacing: bridge::Spacing) -> Spacing { - match spacing { - bridge::Spacing::Alone => Spacing::Alone, - bridge::Spacing::Joint => Spacing::Joint, - } -} - -fn spacing_to_external(spacing: Spacing) -> bridge::Spacing { - match spacing { - Spacing::Alone => bridge::Spacing::Alone, - Spacing::Joint => bridge::Spacing::Joint, - } -} - -impl server::Group for RustAnalyzer { - fn new( - &mut self, - delimiter: bridge::Delimiter, - stream: Option, - ) -> Self::Group { - Self::Group { - delimiter: delim_to_internal(delimiter), - token_trees: stream.unwrap_or_default().token_trees, - } - } - fn delimiter(&mut self, group: &Self::Group) -> bridge::Delimiter { - delim_to_external(group.delimiter) - } - - // NOTE: Return value of do not include delimiter - fn stream(&mut self, group: &Self::Group) -> Self::TokenStream { - TokenStream { token_trees: group.token_trees.clone() } - } - - fn span(&mut self, group: &Self::Group) -> Self::Span { - group.delimiter.open - } - - fn set_span(&mut self, group: &mut Self::Group, span: Self::Span) { - group.delimiter.open = span; - } - - fn span_open(&mut self, group: &Self::Group) -> Self::Span { - group.delimiter.open - } - - fn span_close(&mut self, group: &Self::Group) -> Self::Span { - group.delimiter.close - } -} - -impl server::Punct for RustAnalyzer { - fn new(&mut self, ch: char, spacing: bridge::Spacing) -> Self::Punct { - tt::Punct { - char: ch, - spacing: spacing_to_internal(spacing), - span: tt::TokenId::unspecified(), - } - } - fn as_char(&mut self, punct: Self::Punct) -> char { - punct.char - } - fn spacing(&mut self, punct: Self::Punct) -> bridge::Spacing { - spacing_to_external(punct.spacing) - } - fn span(&mut self, punct: Self::Punct) -> Self::Span { - punct.span - } - fn with_span(&mut self, punct: Self::Punct, span: Self::Span) -> Self::Punct { - tt::Punct { span: span, ..punct } - } -} - -impl server::Ident for RustAnalyzer { - fn new(&mut self, string: &str, span: Self::Span, is_raw: bool) -> Self::Ident { - IdentId(self.ident_interner.intern(&IdentData(tt::Ident { - text: if is_raw { ::tt::SmolStr::from_iter(["r#", string]) } else { string.into() }, - span, - }))) - } - - fn span(&mut self, ident: Self::Ident) -> Self::Span { - self.ident_interner.get(ident.0).0.span - } - fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident { - let data = self.ident_interner.get(ident.0); - let new = IdentData(tt::Ident { span: span, ..data.0.clone() }); - IdentId(self.ident_interner.intern(&new)) - } -} - -impl server::Literal for RustAnalyzer { - fn debug_kind(&mut self, _literal: &Self::Literal) -> String { - // r-a: debug_kind and suffix are unsupported; corresponding client code has been changed to not call these. - // They must still be present to be ABI-compatible and work with upstream proc_macro. - "".to_owned() - } - fn from_str(&mut self, s: &str) -> Result { - Ok(Literal { text: s.into(), span: tt::TokenId::unspecified() }) - } - fn symbol(&mut self, literal: &Self::Literal) -> String { - literal.text.to_string() - } - fn suffix(&mut self, _literal: &Self::Literal) -> Option { - None - } - - fn to_string(&mut self, literal: &Self::Literal) -> String { - literal.to_string() - } - - fn integer(&mut self, n: &str) -> Self::Literal { - let n = match n.parse::() { - Ok(n) => n.to_string(), - Err(_) => n.parse::().unwrap().to_string(), - }; - Literal { text: n.into(), span: tt::TokenId::unspecified() } - } - - fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal { - macro_rules! def_suffixed_integer { - ($kind:ident, $($ty:ty),*) => { - match $kind { - $( - stringify!($ty) => { - let n: $ty = n.parse().unwrap(); - format!(concat!("{}", stringify!($ty)), n) - } - )* - _ => unimplemented!("unknown args for typed_integer: n {}, kind {}", n, $kind), - } - } - } - - let text = def_suffixed_integer! {kind, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize}; - - Literal { text: text.into(), span: tt::TokenId::unspecified() } - } - - fn float(&mut self, n: &str) -> Self::Literal { - let n: f64 = n.parse().unwrap(); - let mut text = f64::to_string(&n); - if !text.contains('.') { - text += ".0" - } - Literal { text: text.into(), span: tt::TokenId::unspecified() } - } - - fn f32(&mut self, n: &str) -> Self::Literal { - let n: f32 = n.parse().unwrap(); - let text = format!("{n}f32"); - Literal { text: text.into(), span: tt::TokenId::unspecified() } - } - - fn f64(&mut self, n: &str) -> Self::Literal { - let n: f64 = n.parse().unwrap(); - let text = format!("{n}f64"); - Literal { text: text.into(), span: tt::TokenId::unspecified() } - } - - fn string(&mut self, string: &str) -> Self::Literal { - let mut escaped = String::new(); - for ch in string.chars() { - escaped.extend(ch.escape_debug()); - } - Literal { text: format!("\"{escaped}\"").into(), span: tt::TokenId::unspecified() } - } - - fn character(&mut self, ch: char) -> Self::Literal { - Literal { text: format!("'{ch}'").into(), span: tt::TokenId::unspecified() } - } - - fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal { - let string = bytes - .iter() - .cloned() - .flat_map(ascii::escape_default) - .map(Into::::into) - .collect::(); - - Literal { text: format!("b\"{string}\"").into(), span: tt::TokenId::unspecified() } - } - - fn span(&mut self, literal: &Self::Literal) -> Self::Span { - literal.span - } - - fn set_span(&mut self, literal: &mut Self::Literal, span: Self::Span) { - literal.span = span; - } - - fn subspan( - &mut self, - _literal: &Self::Literal, - _start: Bound, - _end: Bound, - ) -> Option { - // FIXME handle span - None - } -} - -impl server::SourceFile for RustAnalyzer { - // FIXME these are all stubs - fn eq(&mut self, _file1: &Self::SourceFile, _file2: &Self::SourceFile) -> bool { - true - } - fn path(&mut self, _file: &Self::SourceFile) -> String { - String::new() - } - fn is_real(&mut self, _file: &Self::SourceFile) -> bool { - true - } -} - -impl server::Diagnostic for RustAnalyzer { - fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic { - let mut diag = Diagnostic::new(level, msg); - diag.spans = spans; - diag - } - - fn sub( - &mut self, - _diag: &mut Self::Diagnostic, - _level: Level, - _msg: &str, - _spans: Self::MultiSpan, - ) { - // FIXME handle diagnostic - // - } - - fn emit(&mut self, _diag: Self::Diagnostic) { - // FIXME handle diagnostic - // diag.emit() - } -} - -impl server::Span for RustAnalyzer { - fn debug(&mut self, span: Self::Span) -> String { - format!("{:?}", span.0) - } - fn def_site(&mut self) -> Self::Span { - // MySpan(self.span_interner.intern(&MySpanData(Span::def_site()))) - // FIXME handle span - tt::TokenId::unspecified() - } - fn call_site(&mut self) -> Self::Span { - // MySpan(self.span_interner.intern(&MySpanData(Span::call_site()))) - // FIXME handle span - tt::TokenId::unspecified() - } - fn source_file(&mut self, _span: Self::Span) -> Self::SourceFile { - SourceFile {} - } - fn save_span(&mut self, _span: Self::Span) -> usize { - // FIXME stub - 0 - } - fn recover_proc_macro_span(&mut self, _id: usize) -> Self::Span { - // FIXME stub - tt::TokenId::unspecified() - } - /// Recent feature, not yet in the proc_macro - /// - /// See PR: - /// https://github.com/rust-lang/rust/pull/55780 - fn source_text(&mut self, _span: Self::Span) -> Option { - None - } - - fn parent(&mut self, _span: Self::Span) -> Option { - // FIXME handle span - None - } - fn source(&mut self, span: Self::Span) -> Self::Span { - // FIXME handle span - span - } - fn start(&mut self, _span: Self::Span) -> LineColumn { - // FIXME handle span - LineColumn { line: 0, column: 0 } - } - fn end(&mut self, _span: Self::Span) -> LineColumn { - // FIXME handle span - LineColumn { line: 0, column: 0 } - } - fn join(&mut self, first: Self::Span, _second: Self::Span) -> Option { - // Just return the first span again, because some macros will unwrap the result. - Some(first) - } - fn resolved_at(&mut self, _span: Self::Span, _at: Self::Span) -> Self::Span { - // FIXME handle span - tt::TokenId::unspecified() - } - - fn mixed_site(&mut self) -> Self::Span { - // FIXME handle span - tt::TokenId::unspecified() - } - - fn after(&mut self, _self_: Self::Span) -> Self::Span { - tt::TokenId::unspecified() - } - - fn before(&mut self, _self_: Self::Span) -> Self::Span { - tt::TokenId::unspecified() - } -} - -impl server::MultiSpan for RustAnalyzer { - fn new(&mut self) -> Self::MultiSpan { - // FIXME handle span - vec![] - } - - fn push(&mut self, other: &mut Self::MultiSpan, span: Self::Span) { - //TODP - other.push(span) - } -} - -#[cfg(test)] -mod tests { - use super::super::proc_macro::bridge::server::Literal; - use super::*; - - #[test] - fn test_ra_server_literals() { - let mut srv = RustAnalyzer { ident_interner: IdentInterner::default() }; - assert_eq!(srv.integer("1234").text, "1234"); - - assert_eq!(srv.typed_integer("12", "u8").text, "12u8"); - assert_eq!(srv.typed_integer("255", "u16").text, "255u16"); - assert_eq!(srv.typed_integer("1234", "u32").text, "1234u32"); - assert_eq!(srv.typed_integer("15846685", "u64").text, "15846685u64"); - assert_eq!(srv.typed_integer("15846685258", "u128").text, "15846685258u128"); - assert_eq!(srv.typed_integer("156788984", "usize").text, "156788984usize"); - assert_eq!(srv.typed_integer("127", "i8").text, "127i8"); - assert_eq!(srv.typed_integer("255", "i16").text, "255i16"); - assert_eq!(srv.typed_integer("1234", "i32").text, "1234i32"); - assert_eq!(srv.typed_integer("15846685", "i64").text, "15846685i64"); - assert_eq!(srv.typed_integer("15846685258", "i128").text, "15846685258i128"); - assert_eq!(srv.float("0").text, "0.0"); - assert_eq!(srv.float("15684.5867").text, "15684.5867"); - assert_eq!(srv.f32("15684.58").text, "15684.58f32"); - assert_eq!(srv.f64("15684.58").text, "15684.58f64"); - - assert_eq!(srv.string("hello_world").text, "\"hello_world\""); - assert_eq!(srv.character('c').text, "'c'"); - assert_eq!(srv.byte_string(b"1234586\x88").text, "b\"1234586\\x88\""); - - // u128::max - assert_eq!( - srv.integer("340282366920938463463374607431768211455").text, - "340282366920938463463374607431768211455" - ); - // i128::min - assert_eq!( - srv.integer("-170141183460469231731687303715884105728").text, - "-170141183460469231731687303715884105728" - ); - } - - #[test] - fn test_ra_server_to_string() { - let s = TokenStream { - token_trees: vec![ - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "struct".into(), - span: tt::TokenId::unspecified(), - })), - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "T".into(), - span: tt::TokenId::unspecified(), - })), - tt::TokenTree::Subtree(tt::Subtree { - delimiter: tt::Delimiter { - open: tt::TokenId::unspecified(), - close: tt::TokenId::unspecified(), - kind: tt::DelimiterKind::Brace, - }, - token_trees: vec![], - }), - ], - }; - - assert_eq!(s.to_string(), "struct T {}"); - } - - #[test] - fn test_ra_server_from_str() { - use std::str::FromStr; - let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree { - delimiter: tt::Delimiter { - open: tt::TokenId::unspecified(), - close: tt::TokenId::unspecified(), - kind: tt::DelimiterKind::Parenthesis, - }, - token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "a".into(), - span: tt::TokenId::unspecified(), - }))], - }); - - let t1 = TokenStream::from_str("(a)").unwrap(); - assert_eq!(t1.token_trees.len(), 1); - assert_eq!(t1.token_trees[0], subtree_paren_a); - - let t2 = TokenStream::from_str("(a);").unwrap(); - assert_eq!(t2.token_trees.len(), 2); - assert_eq!(t2.token_trees[0], subtree_paren_a); - - let underscore = TokenStream::from_str("_").unwrap(); - assert_eq!( - underscore.token_trees[0], - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "_".into(), - span: tt::TokenId::unspecified(), - })) - ); - } -} diff --git a/crates/proc-macro-srv/src/abis/mod.rs b/crates/proc-macro-srv/src/abis/mod.rs deleted file mode 100644 index 04be39cffa4ad..0000000000000 --- a/crates/proc-macro-srv/src/abis/mod.rs +++ /dev/null @@ -1,146 +0,0 @@ -//! Procedural macros are implemented by compiling the macro providing crate -//! to a dynamic library with a particular ABI which the compiler uses to expand -//! macros. Unfortunately this ABI is not specified and can change from version -//! to version of the compiler. To support this we copy the ABI from the rust -//! compiler into submodules of this module (e.g proc_macro_srv::abis::abi_1_47). -//! -//! All of these ABIs are subsumed in the `Abi` enum, which exposes a simple -//! interface the rest of rust-analyzer can use to talk to the macro -//! provider. -//! -//! # Adding a new ABI -//! -//! To add a new ABI you'll need to copy the source of the target proc_macro -//! crate from the source tree of the Rust compiler into this directory tree. -//! Then you'll need to modify it -//! - Remove any feature! or other things which won't compile on stable -//! - change any absolute imports to relative imports within the ABI tree -//! -//! Then you'll need to add a branch to the `Abi` enum and an implementation of -//! `Abi::expand`, `Abi::list_macros` and `Abi::from_lib` for the new ABI. See -//! `proc_macro_srv/src/abis/abi_1_47/mod.rs` for an example. Finally you'll -//! need to update the conditionals in `Abi::from_lib` to return your new ABI -//! for the relevant versions of the rust compiler -//! - -mod abi_1_63; -#[cfg(feature = "sysroot-abi")] -mod abi_sysroot; - -// see `build.rs` -include!(concat!(env!("OUT_DIR"), "/rustc_version.rs")); - -// Used by `test/utils.rs` -#[cfg(all(test, feature = "sysroot-abi"))] -pub(crate) use abi_sysroot::TokenStream as TestTokenStream; - -use super::dylib::LoadProcMacroDylibError; -pub(crate) use abi_1_63::Abi as Abi_1_63; -#[cfg(feature = "sysroot-abi")] -pub(crate) use abi_sysroot::Abi as Abi_Sysroot; -use libloading::Library; -use proc_macro_api::{ProcMacroKind, RustCInfo}; - -use crate::tt; - -pub struct PanicMessage { - message: Option, -} - -impl PanicMessage { - pub fn as_str(&self) -> Option { - self.message.clone() - } -} - -pub(crate) enum Abi { - Abi1_63(Abi_1_63), - #[cfg(feature = "sysroot-abi")] - AbiSysroot(Abi_Sysroot), -} - -impl Abi { - /// Load a new ABI. - /// - /// # Arguments - /// - /// *`lib` - The dynamic library containing the macro implementations - /// *`symbol_name` - The symbol name the macros can be found attributes - /// *`info` - RustCInfo about the compiler that was used to compile the - /// macro crate. This is the information we use to figure out - /// which ABI to return - pub fn from_lib( - lib: &Library, - symbol_name: String, - info: RustCInfo, - ) -> Result { - // the sysroot ABI relies on `extern proc_macro` with unstable features, - // instead of a snapshot of the proc macro bridge's source code. it's only - // enabled if we have an exact version match. - #[cfg(feature = "sysroot-abi")] - { - if info.version_string == RUSTC_VERSION_STRING { - let inner = unsafe { Abi_Sysroot::from_lib(lib, symbol_name) }?; - return Ok(Abi::AbiSysroot(inner)); - } - - // if we reached this point, versions didn't match. in testing, we - // want that to panic - this could mean that the format of `rustc - // --version` no longer matches the format of the version string - // stored in the `.rustc` section, and we want to catch that in-tree - // with `x.py test` - #[cfg(test)] - { - let allow_mismatch = std::env::var("PROC_MACRO_SRV_ALLOW_SYSROOT_MISMATCH"); - if let Ok("1") = allow_mismatch.as_deref() { - // only used by rust-analyzer developers, when working on the - // sysroot ABI from the rust-analyzer repository - which should - // only happen pre-subtree. this can be removed later. - } else { - panic!( - "sysroot ABI mismatch: dylib rustc version (read from .rustc section): {:?} != proc-macro-srv version (read from 'rustc --version'): {:?}", - info.version_string, RUSTC_VERSION_STRING - ); - } - } - } - - // FIXME: this should use exclusive ranges when they're stable - // https://github.com/rust-lang/rust/issues/37854 - match (info.version.0, info.version.1) { - (1, 63) => { - let inner = unsafe { Abi_1_63::from_lib(lib, symbol_name) }?; - Ok(Abi::Abi1_63(inner)) - } - _ => Err(LoadProcMacroDylibError::UnsupportedABI(info.version_string)), - } - } - - pub fn expand( - &self, - macro_name: &str, - macro_body: &tt::Subtree, - attributes: Option<&tt::Subtree>, - ) -> Result { - match self { - Self::Abi1_63(abi) => abi.expand(macro_name, macro_body, attributes), - #[cfg(feature = "sysroot-abi")] - Self::AbiSysroot(abi) => abi.expand(macro_name, macro_body, attributes), - } - } - - pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { - match self { - Self::Abi1_63(abi) => abi.list_macros(), - #[cfg(feature = "sysroot-abi")] - Self::AbiSysroot(abi) => abi.list_macros(), - } - } -} - -#[test] -fn test_version_check() { - let path = paths::AbsPathBuf::assert(crate::proc_macro_test_dylib_path()); - let info = proc_macro_api::read_dylib_info(&path).unwrap(); - assert!(info.version.1 >= 50); -} diff --git a/crates/proc-macro-srv/src/cli.rs b/crates/proc-macro-srv/src/cli.rs deleted file mode 100644 index 05168feb629f2..0000000000000 --- a/crates/proc-macro-srv/src/cli.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! Driver for proc macro server -use std::io; - -use proc_macro_api::msg::{self, Message}; - -use crate::ProcMacroSrv; - -pub fn run() -> io::Result<()> { - let mut srv = ProcMacroSrv::default(); - let mut buf = String::new(); - - while let Some(req) = read_request(&mut buf)? { - let res = match req { - msg::Request::ListMacros { dylib_path } => { - msg::Response::ListMacros(srv.list_macros(&dylib_path)) - } - msg::Request::ExpandMacro(task) => msg::Response::ExpandMacro(srv.expand(task)), - msg::Request::ApiVersionCheck {} => { - msg::Response::ApiVersionCheck(proc_macro_api::msg::CURRENT_API_VERSION) - } - }; - write_response(res)? - } - - Ok(()) -} - -fn read_request(buf: &mut String) -> io::Result> { - msg::Request::read(&mut io::stdin().lock(), buf) -} - -fn write_response(msg: msg::Response) -> io::Result<()> { - msg.write(&mut io::stdout().lock()) -} diff --git a/crates/proc-macro-srv/src/dylib.rs b/crates/proc-macro-srv/src/dylib.rs index 89ffd1f493e29..dd05e250c2def 100644 --- a/crates/proc-macro-srv/src/dylib.rs +++ b/crates/proc-macro-srv/src/dylib.rs @@ -13,10 +13,6 @@ use object::Object; use paths::AbsPath; use proc_macro_api::{read_dylib_info, ProcMacroKind}; -use crate::tt; - -use super::abis::Abi; - const NEW_REGISTRAR_SYMBOL: &str = "_rustc_proc_macro_decls_"; fn invalid_data_err(e: impl Into>) -> io::Error { @@ -82,14 +78,17 @@ fn load_library(file: &Path) -> Result { pub enum LoadProcMacroDylibError { Io(io::Error), LibLoading(libloading::Error), - UnsupportedABI(String), + AbiMismatch(String), } impl fmt::Display for LoadProcMacroDylibError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Io(e) => e.fmt(f), - Self::UnsupportedABI(v) => write!(f, "unsupported ABI `{v}`"), + Self::AbiMismatch(v) => { + use crate::RUSTC_VERSION_STRING; + write!(f, "mismatched ABI expected: `{RUSTC_VERSION_STRING}`, got `{v}`") + } Self::LibLoading(e) => e.fmt(f), } } @@ -110,7 +109,7 @@ impl From for LoadProcMacroDylibError { struct ProcMacroLibraryLibloading { // Hold on to the library so it doesn't unload _lib: Library, - abi: Abi, + proc_macros: crate::proc_macros::ProcMacros, } impl ProcMacroLibraryLibloading { @@ -125,8 +124,9 @@ impl ProcMacroLibraryLibloading { let version_info = read_dylib_info(abs_file)?; let lib = load_library(file).map_err(invalid_data_err)?; - let abi = Abi::from_lib(&lib, symbol_name, version_info)?; - Ok(ProcMacroLibraryLibloading { _lib: lib, abi }) + let proc_macros = + crate::proc_macros::ProcMacros::from_lib(&lib, symbol_name, version_info)?; + Ok(ProcMacroLibraryLibloading { _lib: lib, proc_macros }) } } @@ -150,15 +150,15 @@ impl Expander { pub fn expand( &self, macro_name: &str, - macro_body: &tt::Subtree, - attributes: Option<&tt::Subtree>, - ) -> Result { - let result = self.inner.abi.expand(macro_name, macro_body, attributes); + macro_body: &crate::tt::Subtree, + attributes: Option<&crate::tt::Subtree>, + ) -> Result { + let result = self.inner.proc_macros.expand(macro_name, macro_body, attributes); result.map_err(|e| e.as_str().unwrap_or_else(|| "".to_string())) } pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { - self.inner.abi.list_macros() + self.inner.proc_macros.list_macros() } } diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs index ee70fe7d4f541..84bd15efb8bee 100644 --- a/crates/proc-macro-srv/src/lib.rs +++ b/crates/proc-macro-srv/src/lib.rs @@ -10,17 +10,16 @@ //! * By **copying** the whole rustc `lib_proc_macro` code, we are able to build this with `stable` //! rustc rather than `unstable`. (Although in general ABI compatibility is still an issue)… +#![cfg(feature = "sysroot-abi")] +#![feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span)] #![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] -#![cfg_attr( - feature = "sysroot-abi", - feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span) -)] #![allow(unreachable_pub)] -mod dylib; -mod abis; +extern crate proc_macro; -pub mod cli; +mod dylib; +mod server; +mod proc_macros; use std::{ collections::{hash_map::Entry, HashMap}, @@ -33,24 +32,27 @@ use std::{ }; use proc_macro_api::{ - msg::{ExpandMacro, FlatTree, PanicMessage}, + msg::{self, CURRENT_API_VERSION}, ProcMacroKind, }; use ::tt::token_id as tt; +// see `build.rs` +include!(concat!(env!("OUT_DIR"), "/rustc_version.rs")); + #[derive(Default)] -pub(crate) struct ProcMacroSrv { +pub struct ProcMacroSrv { expanders: HashMap<(PathBuf, SystemTime), dylib::Expander>, } const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024; impl ProcMacroSrv { - pub fn expand(&mut self, task: ExpandMacro) -> Result { + pub fn expand(&mut self, task: msg::ExpandMacro) -> Result { let expander = self.expander(task.lib.as_ref()).map_err(|err| { debug_assert!(false, "should list macros before asking to expand"); - PanicMessage(format!("failed to load macro: {err}")) + msg::PanicMessage(format!("failed to load macro: {err}")) })?; let prev_env = EnvSnapshot::new(); @@ -68,8 +70,8 @@ impl ProcMacroSrv { None => None, }; - let macro_body = task.macro_body.to_subtree(); - let attributes = task.attributes.map(|it| it.to_subtree()); + let macro_body = task.macro_body.to_subtree(CURRENT_API_VERSION); + let attributes = task.attributes.map(|it| it.to_subtree(CURRENT_API_VERSION)); let result = thread::scope(|s| { let thread = thread::Builder::new() .stack_size(EXPANDER_STACK_SIZE) @@ -77,7 +79,7 @@ impl ProcMacroSrv { .spawn_scoped(s, || { expander .expand(&task.macro_name, ¯o_body, attributes.as_ref()) - .map(|it| FlatTree::new(&it)) + .map(|it| msg::FlatTree::new(&it, CURRENT_API_VERSION)) }); let res = match thread { Ok(handle) => handle.join(), @@ -102,10 +104,10 @@ impl ProcMacroSrv { } } - result.map_err(PanicMessage) + result.map_err(msg::PanicMessage) } - pub(crate) fn list_macros( + pub fn list_macros( &mut self, dylib_path: &Path, ) -> Result, String> { @@ -129,6 +131,16 @@ impl ProcMacroSrv { } } +pub struct PanicMessage { + message: Option, +} + +impl PanicMessage { + pub fn as_str(&self) -> Option { + self.message.clone() + } +} + struct EnvSnapshot { vars: HashMap, } @@ -138,10 +150,13 @@ impl EnvSnapshot { EnvSnapshot { vars: env::vars_os().collect() } } - fn rollback(self) { - let mut old_vars = self.vars; + fn rollback(self) {} +} + +impl Drop for EnvSnapshot { + fn drop(&mut self) { for (name, value) in env::vars_os() { - let old_value = old_vars.remove(&name); + let old_value = self.vars.remove(&name); if old_value != Some(value) { match old_value { None => env::remove_var(name), @@ -149,13 +164,13 @@ impl EnvSnapshot { } } } - for (name, old_value) in old_vars { + for (name, old_value) in self.vars.drain() { env::set_var(name, old_value) } } } -#[cfg(all(feature = "sysroot-abi", test))] +#[cfg(test)] mod tests; #[cfg(test)] diff --git a/crates/proc-macro-srv/src/abis/abi_sysroot/mod.rs b/crates/proc-macro-srv/src/proc_macros.rs similarity index 52% rename from crates/proc-macro-srv/src/abis/abi_sysroot/mod.rs rename to crates/proc-macro-srv/src/proc_macros.rs index 0a3b8866a7fd5..3c6f320331928 100644 --- a/crates/proc-macro-srv/src/abis/abi_sysroot/mod.rs +++ b/crates/proc-macro-srv/src/proc_macros.rs @@ -1,45 +1,55 @@ //! Proc macro ABI -extern crate proc_macro; - -#[allow(dead_code)] -#[doc(hidden)] -mod ra_server; - use libloading::Library; -use proc_macro_api::ProcMacroKind; +use proc_macro_api::{ProcMacroKind, RustCInfo}; -use super::{tt, PanicMessage}; +use crate::{dylib::LoadProcMacroDylibError, server::SYMBOL_INTERNER, tt}; -pub use ra_server::TokenStream; - -pub(crate) struct Abi { +pub(crate) struct ProcMacros { exported_macros: Vec, } -impl From for PanicMessage { +impl From for crate::PanicMessage { fn from(p: proc_macro::bridge::PanicMessage) -> Self { Self { message: p.as_str().map(|s| s.to_string()) } } } -impl Abi { - pub unsafe fn from_lib(lib: &Library, symbol_name: String) -> Result { - let macros: libloading::Symbol<'_, &&[proc_macro::bridge::client::ProcMacro]> = - lib.get(symbol_name.as_bytes())?; - Ok(Self { exported_macros: macros.to_vec() }) +impl ProcMacros { + /// Load a new ABI. + /// + /// # Arguments + /// + /// *`lib` - The dynamic library containing the macro implementations + /// *`symbol_name` - The symbol name the macros can be found attributes + /// *`info` - RustCInfo about the compiler that was used to compile the + /// macro crate. This is the information we use to figure out + /// which ABI to return + pub(crate) fn from_lib( + lib: &Library, + symbol_name: String, + info: RustCInfo, + ) -> Result { + if info.version_string == crate::RUSTC_VERSION_STRING { + let macros = unsafe { + lib.get::<&&[proc_macro::bridge::client::ProcMacro]>(symbol_name.as_bytes()) + }?; + + return Ok(Self { exported_macros: macros.to_vec() }); + } + Err(LoadProcMacroDylibError::AbiMismatch(info.version_string)) } - pub fn expand( + pub(crate) fn expand( &self, macro_name: &str, macro_body: &tt::Subtree, attributes: Option<&tt::Subtree>, - ) -> Result { - let parsed_body = ra_server::TokenStream::with_subtree(macro_body.clone()); + ) -> Result { + let parsed_body = crate::server::TokenStream::with_subtree(macro_body.clone()); - let parsed_attributes = attributes.map_or(ra_server::TokenStream::new(), |attr| { - ra_server::TokenStream::with_subtree(attr.clone()) + let parsed_attributes = attributes.map_or(crate::server::TokenStream::new(), |attr| { + crate::server::TokenStream::with_subtree(attr.clone()) }); for proc_macro in &self.exported_macros { @@ -49,34 +59,34 @@ impl Abi { } if *trait_name == macro_name => { let res = client.run( &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), + crate::server::RustAnalyzer { interner: &SYMBOL_INTERNER }, parsed_body, true, ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); + return res.map(|it| it.into_subtree()).map_err(crate::PanicMessage::from); } proc_macro::bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => { let res = client.run( &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), + crate::server::RustAnalyzer { interner: &SYMBOL_INTERNER }, parsed_body, true, ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); + return res.map(|it| it.into_subtree()).map_err(crate::PanicMessage::from); } proc_macro::bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => { let res = client.run( &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), + crate::server::RustAnalyzer { interner: &SYMBOL_INTERNER }, parsed_attributes, parsed_body, true, ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); + return res.map(|it| it.into_subtree()).map_err(crate::PanicMessage::from); } _ => continue, } @@ -85,7 +95,7 @@ impl Abi { Err(proc_macro::bridge::PanicMessage::String("Nothing to expand".to_string()).into()) } - pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { + pub(crate) fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { self.exported_macros .iter() .map(|proc_macro| match proc_macro { @@ -102,3 +112,16 @@ impl Abi { .collect() } } + +#[test] +fn test_version_check() { + let path = paths::AbsPathBuf::assert(crate::proc_macro_test_dylib_path()); + let info = proc_macro_api::read_dylib_info(&path).unwrap(); + assert_eq!( + info.version_string, + crate::RUSTC_VERSION_STRING, + "sysroot ABI mismatch: dylib rustc version (read from .rustc section): {:?} != proc-macro-srv version (read from 'rustc --version'): {:?}", + info.version_string, + crate::RUSTC_VERSION_STRING, + ); +} diff --git a/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs b/crates/proc-macro-srv/src/server.rs similarity index 91% rename from crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs rename to crates/proc-macro-srv/src/server.rs index a9cd8e705a4cf..37a45bcbb83b8 100644 --- a/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs +++ b/crates/proc-macro-srv/src/server.rs @@ -8,9 +8,9 @@ //! //! FIXME: No span and source file information is implemented yet -use super::proc_macro::{ - self, +use proc_macro::{ bridge::{self, server}, + LineColumn, }; mod token_stream; @@ -26,8 +26,10 @@ use crate::tt; type Group = tt::Subtree; type TokenTree = tt::TokenTree; +#[allow(unused)] type Punct = tt::Punct; type Spacing = tt::Spacing; +#[allow(unused)] type Literal = tt::Literal; type Span = tt::TokenId; @@ -36,14 +38,11 @@ pub struct SourceFile { // FIXME stub } -type Level = super::proc_macro::Level; -type LineColumn = super::proc_macro::LineColumn; - pub struct FreeFunctions; -#[derive(Default)] pub struct RustAnalyzer { // FIXME: store span information here. + pub(crate) interner: SymbolInternerRef, } impl server::Types for RustAnalyzer { @@ -68,7 +67,7 @@ impl server::FreeFunctions for RustAnalyzer { // FIXME: keep track of LitKind and Suffix Ok(bridge::Literal { kind: bridge::LitKind::Err, - symbol: Symbol::intern(s), + symbol: Symbol::intern(self.interner, s), suffix: None, span: tt::TokenId::unspecified(), }) @@ -109,7 +108,7 @@ impl server::TokenStream for RustAnalyzer { } bridge::TokenTree::Ident(ident) => { - let text = ident.sym.text(); + let text = ident.sym.text(self.interner); let text = if ident.is_raw { ::tt::SmolStr::from_iter(["r#", &text]) } else { text }; let ident: tt::Ident = tt::Ident { text, span: ident.span }; @@ -120,8 +119,9 @@ impl server::TokenStream for RustAnalyzer { bridge::TokenTree::Literal(literal) => { let literal = LiteralFormatter(literal); - let text = literal - .with_stringify_parts(|parts| ::tt::SmolStr::from_iter(parts.iter().copied())); + let text = literal.with_stringify_parts(self.interner, |parts| { + ::tt::SmolStr::from_iter(parts.iter().copied()) + }); let literal = tt::Literal { text, span: literal.0.span }; let leaf = tt::Leaf::from(literal); @@ -185,7 +185,7 @@ impl server::TokenStream for RustAnalyzer { .map(|tree| match tree { tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { bridge::TokenTree::Ident(bridge::Ident { - sym: Symbol::intern(ident.text.trim_start_matches("r#")), + sym: Symbol::intern(self.interner, ident.text.trim_start_matches("r#")), is_raw: ident.text.starts_with("r#"), span: ident.span, }) @@ -194,7 +194,7 @@ impl server::TokenStream for RustAnalyzer { bridge::TokenTree::Literal(bridge::Literal { // FIXME: handle literal kinds kind: bridge::LitKind::Err, - symbol: Symbol::intern(&lit.text), + symbol: Symbol::intern(self.interner, &lit.text), // FIXME: handle suffixes suffix: None, span: lit.span, @@ -240,6 +240,7 @@ fn delim_to_external(d: tt::Delimiter) -> proc_macro::Delimiter { } } +#[allow(unused)] fn spacing_to_internal(spacing: proc_macro::Spacing) -> Spacing { match spacing { proc_macro::Spacing::Alone => Spacing::Alone, @@ -247,6 +248,7 @@ fn spacing_to_internal(spacing: proc_macro::Spacing) -> Spacing { } } +#[allow(unused)] fn spacing_to_external(spacing: Spacing) -> proc_macro::Spacing { match spacing { Spacing::Alone => proc_macro::Spacing::Alone, @@ -354,11 +356,13 @@ impl server::Server for RustAnalyzer { } fn intern_symbol(ident: &str) -> Self::Symbol { - Symbol::intern(&::tt::SmolStr::from(ident)) + // FIXME: should be self.interner once the proc-macro api allows is + Symbol::intern(&SYMBOL_INTERNER, &::tt::SmolStr::from(ident)) } fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) { - f(symbol.text().as_str()) + // FIXME: should be self.interner once the proc-macro api allows is + f(symbol.text(&SYMBOL_INTERNER).as_str()) } } @@ -369,7 +373,11 @@ impl LiteralFormatter { /// literal's representation. This is done to allow the `ToString` and /// `Display` implementations to borrow references to symbol values, and /// both be optimized to reduce overhead. - fn with_stringify_parts(&self, f: impl FnOnce(&[&str]) -> R) -> R { + fn with_stringify_parts( + &self, + interner: SymbolInternerRef, + f: impl FnOnce(&[&str]) -> R, + ) -> R { /// Returns a string containing exactly `num` '#' characters. /// Uses a 256-character source string literal which is always safe to /// index with a `u8` index. @@ -384,7 +392,7 @@ impl LiteralFormatter { &HASHES[..num as usize] } - self.with_symbol_and_suffix(|symbol, suffix| match self.0.kind { + self.with_symbol_and_suffix(interner, |symbol, suffix| match self.0.kind { bridge::LitKind::Byte => f(&["b'", symbol, "'", suffix]), bridge::LitKind::Char => f(&["'", symbol, "'", suffix]), bridge::LitKind::Str => f(&["\"", symbol, "\"", suffix]), @@ -401,9 +409,13 @@ impl LiteralFormatter { }) } - fn with_symbol_and_suffix(&self, f: impl FnOnce(&str, &str) -> R) -> R { - let symbol = self.0.symbol.text(); - let suffix = self.0.suffix.map(|s| s.text()).unwrap_or_default(); + fn with_symbol_and_suffix( + &self, + interner: SymbolInternerRef, + f: impl FnOnce(&str, &str) -> R, + ) -> R { + let symbol = self.0.symbol.text(interner); + let suffix = self.0.suffix.map(|s| s.text(interner)).unwrap_or_default(); f(symbol.as_str(), suffix.as_str()) } } diff --git a/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server/symbol.rs b/crates/proc-macro-srv/src/server/symbol.rs similarity index 58% rename from crates/proc-macro-srv/src/abis/abi_sysroot/ra_server/symbol.rs rename to crates/proc-macro-srv/src/server/symbol.rs index 51dfba2ea9fb4..540d06457f2f3 100644 --- a/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server/symbol.rs +++ b/crates/proc-macro-srv/src/server/symbol.rs @@ -1,28 +1,30 @@ //! Symbol interner for proc-macro-srv -use std::{cell::RefCell, collections::HashMap}; +use std::{cell::RefCell, collections::HashMap, thread::LocalKey}; use tt::SmolStr; thread_local! { - static SYMBOL_INTERNER: RefCell = Default::default(); + pub(crate) static SYMBOL_INTERNER: RefCell = Default::default(); } // ID for an interned symbol. #[derive(Hash, Eq, PartialEq, Copy, Clone)] pub struct Symbol(u32); +pub(crate) type SymbolInternerRef = &'static LocalKey>; + impl Symbol { - pub fn intern(data: &str) -> Symbol { - SYMBOL_INTERNER.with(|i| i.borrow_mut().intern(data)) + pub(super) fn intern(interner: SymbolInternerRef, data: &str) -> Symbol { + interner.with(|i| i.borrow_mut().intern(data)) } - pub fn text(&self) -> SmolStr { - SYMBOL_INTERNER.with(|i| i.borrow().get(self).clone()) + pub(super) fn text(&self, interner: SymbolInternerRef) -> SmolStr { + interner.with(|i| i.borrow().get(self).clone()) } } #[derive(Default)] -struct SymbolInterner { +pub(crate) struct SymbolInterner { idents: HashMap, ident_data: Vec, } diff --git a/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server/token_stream.rs b/crates/proc-macro-srv/src/server/token_stream.rs similarity index 93% rename from crates/proc-macro-srv/src/abis/abi_sysroot/ra_server/token_stream.rs rename to crates/proc-macro-srv/src/server/token_stream.rs index d091d431900a0..2589d8b64d489 100644 --- a/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server/token_stream.rs +++ b/crates/proc-macro-srv/src/server/token_stream.rs @@ -4,15 +4,15 @@ use crate::tt::{self, TokenTree}; #[derive(Debug, Default, Clone)] pub struct TokenStream { - pub token_trees: Vec, + pub(super) token_trees: Vec, } impl TokenStream { - pub fn new() -> Self { + pub(crate) fn new() -> Self { TokenStream::default() } - pub fn with_subtree(subtree: tt::Subtree) -> Self { + pub(crate) fn with_subtree(subtree: tt::Subtree) -> Self { if subtree.delimiter.kind != tt::DelimiterKind::Invisible { TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] } } else { @@ -20,11 +20,11 @@ impl TokenStream { } } - pub fn into_subtree(self) -> tt::Subtree { + pub(crate) fn into_subtree(self) -> tt::Subtree { tt::Subtree { delimiter: tt::Delimiter::UNSPECIFIED, token_trees: self.token_trees } } - pub fn is_empty(&self) -> bool { + pub(super) fn is_empty(&self) -> bool { self.token_trees.is_empty() } } @@ -78,12 +78,12 @@ impl Extend for TokenStream { } } -pub struct TokenStreamBuilder { +pub(super) struct TokenStreamBuilder { acc: TokenStream, } -/// Public implementation details for the `TokenStream` type, such as iterators. -pub mod token_stream { +/// pub(super)lic implementation details for the `TokenStream` type, such as iterators. +pub(super) mod token_stream { use std::str::FromStr; use super::{tt, TokenStream, TokenTree}; diff --git a/crates/proc-macro-srv/src/tests/utils.rs b/crates/proc-macro-srv/src/tests/utils.rs index efbeb90ca9dd5..49b4d973b63bb 100644 --- a/crates/proc-macro-srv/src/tests/utils.rs +++ b/crates/proc-macro-srv/src/tests/utils.rs @@ -5,14 +5,14 @@ use std::str::FromStr; use crate::{dylib, proc_macro_test_dylib_path, ProcMacroSrv}; -fn parse_string(code: &str) -> Option { +fn parse_string(code: &str) -> Option { // This is a bit strange. We need to parse a string into a token stream into // order to create a tt::SubTree from it in fixtures. `into_subtree` is // implemented by all the ABIs we have so we arbitrarily choose one ABI to // write a `parse_string` function for and use that. The tests don't really // care which ABI we're using as the `into_subtree` function isn't part of // the ABI and shouldn't change between ABI versions. - crate::abis::TestTokenStream::from_str(code).ok() + crate::server::TokenStream::from_str(code).ok() } pub fn assert_expand(macro_name: &str, ra_fixture: &str, expect: Expect) { diff --git a/crates/profile/Cargo.toml b/crates/profile/Cargo.toml index 6273ea51db839..602e742751063 100644 --- a/crates/profile/Cargo.toml +++ b/crates/profile/Cargo.toml @@ -20,7 +20,7 @@ countme = { version = "3.0.1", features = ["enable"] } jemalloc-ctl = { version = "0.5.0", package = "tikv-jemalloc-ctl", optional = true } [target.'cfg(target_os = "linux")'.dependencies] -perf-event = "0.4.7" +perf-event = "=0.4.7" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3.9", features = ["processthreadsapi", "psapi"] } diff --git a/crates/profile/src/memory_usage.rs b/crates/profile/src/memory_usage.rs index 8017f865792b3..f089c78e0c195 100644 --- a/crates/profile/src/memory_usage.rs +++ b/crates/profile/src/memory_usage.rs @@ -90,6 +90,12 @@ fn memusage_linux() -> MemoryUsage { #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] pub struct Bytes(isize); +impl Bytes { + pub fn new(bytes: isize) -> Bytes { + Bytes(bytes) + } +} + impl Bytes { pub fn megabytes(self) -> isize { self.0 / 1024 / 1024 diff --git a/crates/project-model/Cargo.toml b/crates/project-model/Cargo.toml index 22d6a6e78957c..3abff64a83b2f 100644 --- a/crates/project-model/Cargo.toml +++ b/crates/project-model/Cargo.toml @@ -16,10 +16,12 @@ tracing = "0.1.35" rustc-hash = "1.1.0" cargo_metadata = "0.15.0" semver = "1.0.14" -serde = { version = "1.0.137", features = ["derive"] } -serde_json = "1.0.86" +serde_json.workspace = true +serde.workspace = true +triomphe.workspace = true anyhow = "1.0.62" la-arena = { version = "0.3.0", path = "../../lib/la-arena" } +itertools = "0.10.5" # local deps base-db.workspace = true diff --git a/crates/project-model/src/build_scripts.rs b/crates/project-model/src/build_scripts.rs index 4e5d640f175e4..6cbf403cb2e14 100644 --- a/crates/project-model/src/build_scripts.rs +++ b/crates/project-model/src/build_scripts.rs @@ -14,9 +14,10 @@ use std::{ }; use cargo_metadata::{camino::Utf8Path, Message}; +use itertools::Itertools; use la_arena::ArenaMap; use paths::{AbsPath, AbsPathBuf}; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use semver::Version; use serde::Deserialize; @@ -56,7 +57,10 @@ impl BuildScriptOutput { } impl WorkspaceBuildScripts { - fn build_command(config: &CargoConfig) -> io::Result { + fn build_command( + config: &CargoConfig, + allowed_features: &FxHashSet, + ) -> io::Result { let mut cmd = match config.run_build_script_command.as_deref() { Some([program, args @ ..]) => { let mut cmd = Command::new(program); @@ -88,7 +92,12 @@ impl WorkspaceBuildScripts { } if !features.is_empty() { cmd.arg("--features"); - cmd.arg(features.join(" ")); + cmd.arg( + features + .iter() + .filter(|&feat| allowed_features.contains(feat)) + .join(","), + ); } } } @@ -127,13 +136,20 @@ impl WorkspaceBuildScripts { } .as_ref(); - match Self::run_per_ws(Self::build_command(config)?, workspace, current_dir, progress) { + let allowed_features = workspace.workspace_features(); + + match Self::run_per_ws( + Self::build_command(config, &allowed_features)?, + workspace, + current_dir, + progress, + ) { Ok(WorkspaceBuildScripts { error: Some(error), .. }) if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_62) => { // building build scripts failed, attempt to build with --keep-going so // that we potentially get more build data - let mut cmd = Self::build_command(config)?; + let mut cmd = Self::build_command(config, &allowed_features)?; cmd.args(["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1"); let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?; res.error = Some(error); @@ -161,7 +177,7 @@ impl WorkspaceBuildScripts { )) } }; - let cmd = Self::build_command(config)?; + let cmd = Self::build_command(config, &Default::default())?; // NB: Cargo.toml could have been modified between `cargo metadata` and // `cargo check`. We shouldn't assume that package ids we see here are // exactly those from `config`. @@ -415,7 +431,6 @@ impl WorkspaceBuildScripts { let dir_entry = entry.ok()?; if dir_entry.file_type().ok()?.is_file() { let path = dir_entry.path(); - tracing::info!("p{:?}", path); let extension = path.extension()?; if extension == std::env::consts::DLL_EXTENSION { let name = path.file_stem()?.to_str()?.split_once('-')?.0.to_owned(); diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index 01162b1a8ba0c..92b454150c3e9 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -1,6 +1,5 @@ //! See [`CargoWorkspace`]. -use std::iter; use std::path::PathBuf; use std::str::from_utf8; use std::{ops, process::Command}; @@ -10,7 +9,7 @@ use base_db::Edition; use cargo_metadata::{CargoOpt, MetadataCommand}; use la_arena::{Arena, Idx}; use paths::{AbsPath, AbsPathBuf}; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use serde::Deserialize; use serde_json::from_value; @@ -32,6 +31,7 @@ pub struct CargoWorkspace { packages: Arena, targets: Arena, workspace_root: AbsPathBuf, + target_directory: AbsPathBuf, } impl ops::Index for CargoWorkspace { @@ -57,20 +57,6 @@ pub enum RustLibSource { Discover, } -/// Crates to disable `#[cfg(test)]` on. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum UnsetTestCrates { - None, - Only(Vec), - All, -} - -impl Default for UnsetTestCrates { - fn default() -> Self { - Self::None - } -} - #[derive(Clone, Debug, PartialEq, Eq)] pub enum CargoFeatures { All, @@ -99,8 +85,7 @@ pub struct CargoConfig { pub sysroot_src: Option, /// rustc private crate source pub rustc_source: Option, - /// crates to disable `#[cfg(test)]` on - pub unset_test_crates: UnsetTestCrates, + pub cfg_overrides: CfgOverrides, /// Invoke `cargo check` through the RUSTC_WRAPPER. pub wrap_rustc_in_build_scripts: bool, /// The command to run instead of `cargo check` for building build scripts. @@ -113,27 +98,6 @@ pub struct CargoConfig { pub invocation_location: InvocationLocation, } -impl CargoConfig { - pub fn cfg_overrides(&self) -> CfgOverrides { - match &self.unset_test_crates { - UnsetTestCrates::None => CfgOverrides::Selective(iter::empty().collect()), - UnsetTestCrates::Only(unset_test_crates) => CfgOverrides::Selective( - unset_test_crates - .iter() - .cloned() - .zip(iter::repeat_with(|| { - cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())]) - .unwrap() - })) - .collect(), - ), - UnsetTestCrates::All => CfgOverrides::Wildcard( - cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())]).unwrap(), - ), - } - } -} - pub type Package = Idx; pub type Target = Idx; @@ -293,13 +257,29 @@ impl CargoWorkspace { } meta.current_dir(current_dir.as_os_str()); + let mut other_options = vec![]; + // cargo metadata only supports a subset of flags of what cargo usually accepts, and usually + // the only relevant flags for metadata here are unstable ones, so we pass those along + // but nothing else + let mut extra_args = config.extra_args.iter(); + while let Some(arg) = extra_args.next() { + if arg == "-Z" { + if let Some(arg) = extra_args.next() { + other_options.push("-Z".to_owned()); + other_options.push(arg.to_owned()); + } + } + } + if !targets.is_empty() { - let other_options: Vec<_> = targets - .into_iter() - .flat_map(|target| ["--filter-platform".to_string(), target]) - .collect(); - meta.other_options(other_options); + other_options.append( + &mut targets + .into_iter() + .flat_map(|target| ["--filter-platform".to_owned().to_string(), target]) + .collect(), + ); } + meta.other_options(other_options); // FIXME: Fetching metadata is a slow process, as it might require // calling crates.io. We should be reporting progress here, but it's @@ -411,7 +391,10 @@ impl CargoWorkspace { let workspace_root = AbsPathBuf::assert(PathBuf::from(meta.workspace_root.into_os_string())); - CargoWorkspace { packages, targets, workspace_root } + let target_directory = + AbsPathBuf::assert(PathBuf::from(meta.target_directory.into_os_string())); + + CargoWorkspace { packages, targets, workspace_root, target_directory } } pub fn packages(&self) -> impl Iterator + ExactSizeIterator + '_ { @@ -429,6 +412,10 @@ impl CargoWorkspace { &self.workspace_root } + pub fn target_directory(&self) -> &AbsPath { + &self.target_directory + } + pub fn package_flag(&self, package: &PackageData) -> String { if self.is_unique(&package.name) { package.name.clone() @@ -467,6 +454,21 @@ impl CargoWorkspace { None } + /// Returns the union of the features of all member crates in this workspace. + pub fn workspace_features(&self) -> FxHashSet { + self.packages() + .filter_map(|package| { + let package = &self[package]; + if package.is_member { + Some(package.features.keys().cloned()) + } else { + None + } + }) + .flatten() + .collect() + } + fn is_unique(&self, name: &str) -> bool { self.packages.iter().filter(|(_, v)| v.name == name).count() == 1 } diff --git a/crates/project-model/src/cfg_flag.rs b/crates/project-model/src/cfg_flag.rs index c134b78ab3a2e..e366d441c1bd7 100644 --- a/crates/project-model/src/cfg_flag.rs +++ b/crates/project-model/src/cfg_flag.rs @@ -49,6 +49,14 @@ impl Extend for CfgOptions { } } +impl FromIterator for CfgOptions { + fn from_iter>(iter: T) -> Self { + let mut this = CfgOptions::default(); + this.extend(iter); + this + } +} + impl fmt::Display for CfgFlag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { diff --git a/crates/project-model/src/lib.rs b/crates/project-model/src/lib.rs index 70cb71ae3bde8..61acc646f8101 100644 --- a/crates/project-model/src/lib.rs +++ b/crates/project-model/src/lib.rs @@ -44,7 +44,7 @@ pub use crate::{ build_scripts::WorkspaceBuildScripts, cargo_workspace::{ CargoConfig, CargoFeatures, CargoWorkspace, Package, PackageData, PackageDependency, - RustLibSource, Target, TargetData, TargetKind, UnsetTestCrates, + RustLibSource, Target, TargetData, TargetKind, }, manifest_path::ManifestPath, project_json::{ProjectJson, ProjectJsonData}, diff --git a/crates/project-model/src/manifest_path.rs b/crates/project-model/src/manifest_path.rs index 980d92d3df9db..3f60e4dd92f43 100644 --- a/crates/project-model/src/manifest_path.rs +++ b/crates/project-model/src/manifest_path.rs @@ -34,6 +34,10 @@ impl ManifestPath { pub fn parent(&self) -> &AbsPath { self.file.parent().unwrap() } + + pub fn canonicalize(&self) -> ! { + (&**self).canonicalize() + } } impl ops::Deref for ManifestPath { diff --git a/crates/project-model/src/project_json.rs b/crates/project-model/src/project_json.rs index 4b2448e47f1ff..80897f7478cf9 100644 --- a/crates/project-model/src/project_json.rs +++ b/crates/project-model/src/project_json.rs @@ -49,12 +49,12 @@ //! user explores them belongs to that extension (it's totally valid to change //! rust-project.json over time via configuration request!) -use std::path::PathBuf; - use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, Edition}; +use la_arena::RawIdx; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::FxHashMap; use serde::{de, Deserialize}; +use std::path::PathBuf; use crate::cfg_flag::CfgFlag; @@ -98,26 +98,23 @@ impl ProjectJson { /// * `data` - The parsed contents of `rust-project.json`, or project json that's passed via /// configuration. pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson { + let absolutize_on_base = |p| base.absolutize(p); ProjectJson { - sysroot: data.sysroot.map(|it| base.join(it)), - sysroot_src: data.sysroot_src.map(|it| base.join(it)), + sysroot: data.sysroot.map(absolutize_on_base), + sysroot_src: data.sysroot_src.map(absolutize_on_base), project_root: base.to_path_buf(), crates: data .crates .into_iter() .map(|crate_data| { - let is_workspace_member = crate_data.is_workspace_member.unwrap_or_else(|| { - crate_data.root_module.is_relative() - && !crate_data.root_module.starts_with("..") - || crate_data.root_module.starts_with(base) - }); - let root_module = base.join(crate_data.root_module).normalize(); + let root_module = absolutize_on_base(crate_data.root_module); + let is_workspace_member = crate_data + .is_workspace_member + .unwrap_or_else(|| root_module.starts_with(base)); let (include, exclude) = match crate_data.source { Some(src) => { let absolutize = |dirs: Vec| { - dirs.into_iter() - .map(|it| base.join(it).normalize()) - .collect::>() + dirs.into_iter().map(absolutize_on_base).collect::>() }; (absolutize(src.include_dirs), absolutize(src.exclude_dirs)) } @@ -135,7 +132,10 @@ impl ProjectJson { .deps .into_iter() .map(|dep_data| { - Dependency::new(dep_data.name, CrateId(dep_data.krate as u32)) + Dependency::new( + dep_data.name, + CrateId::from_raw(RawIdx::from(dep_data.krate as u32)), + ) }) .collect::>(), cfg: crate_data.cfg, @@ -143,7 +143,7 @@ impl ProjectJson { env: crate_data.env, proc_macro_dylib_path: crate_data .proc_macro_dylib_path - .map(|it| base.join(it)), + .map(absolutize_on_base), is_workspace_member, include, exclude, @@ -151,7 +151,7 @@ impl ProjectJson { repository: crate_data.repository, } }) - .collect::>(), + .collect(), } } @@ -162,7 +162,10 @@ impl ProjectJson { /// Returns an iterator over the crates in the project. pub fn crates(&self) -> impl Iterator + '_ { - self.crates.iter().enumerate().map(|(idx, krate)| (CrateId(idx as u32), krate)) + self.crates + .iter() + .enumerate() + .map(|(idx, krate)| (CrateId::from_raw(RawIdx::from(idx as u32)), krate)) } /// Returns the path to the project's root folder. @@ -236,7 +239,7 @@ struct CrateSource { exclude_dirs: Vec, } -fn deserialize_crate_name<'de, D>(de: D) -> Result +fn deserialize_crate_name<'de, D>(de: D) -> std::result::Result where D: de::Deserializer<'de>, { diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs index 74e41eda76384..e3a2de927c985 100644 --- a/crates/project-model/src/sysroot.rs +++ b/crates/project-model/src/sysroot.rs @@ -12,13 +12,15 @@ use la_arena::{Arena, Idx}; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::FxHashMap; -use crate::{utf8_stdout, ManifestPath}; +use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath}; #[derive(Debug, Clone, Eq, PartialEq)] pub struct Sysroot { root: AbsPathBuf, src_root: AbsPathBuf, crates: Arena, + /// Stores the result of `cargo metadata` of the `RA_UNSTABLE_SYSROOT_HACK` workspace. + pub hack_cargo_workspace: Option, } pub(crate) type SysrootCrate = Idx; @@ -74,6 +76,23 @@ impl Sysroot { pub fn is_empty(&self) -> bool { self.crates.is_empty() } + + pub fn loading_warning(&self) -> Option { + if self.by_name("core").is_none() { + let var_note = if env::var_os("RUST_SRC_PATH").is_some() { + " (`RUST_SRC_PATH` might be incorrect, try unsetting it)" + } else { + " try running `rustup component add rust-src` to possible fix this" + }; + Some(format!( + "could not find libcore in loaded sysroot at `{}`{}", + self.src_root.as_path().display(), + var_note, + )) + } else { + None + } + } } // FIXME: Expose a builder api as loading the sysroot got way too modular and complicated. @@ -103,14 +122,36 @@ impl Sysroot { pub fn with_sysroot_dir(sysroot_dir: AbsPathBuf) -> Result { let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir).ok_or_else(|| { - format_err!("can't load standard library from sysroot {}", sysroot_dir.display()) + format_err!("can't load standard library from sysroot path {}", sysroot_dir.display()) })?; Ok(Sysroot::load(sysroot_dir, sysroot_src_dir)) } - pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Sysroot { - let mut sysroot = - Sysroot { root: sysroot_dir, src_root: sysroot_src_dir, crates: Arena::default() }; + pub fn load(sysroot_dir: AbsPathBuf, mut sysroot_src_dir: AbsPathBuf) -> Sysroot { + // FIXME: Remove this `hack_cargo_workspace` field completely once we support sysroot dependencies + let hack_cargo_workspace = if let Ok(path) = std::env::var("RA_UNSTABLE_SYSROOT_HACK") { + let cargo_toml = ManifestPath::try_from( + AbsPathBuf::try_from(&*format!("{path}/Cargo.toml")).unwrap(), + ) + .unwrap(); + sysroot_src_dir = AbsPathBuf::try_from(&*path).unwrap().join("library"); + CargoWorkspace::fetch_metadata( + &cargo_toml, + &AbsPathBuf::try_from("/").unwrap(), + &CargoConfig::default(), + &|_| (), + ) + .map(CargoWorkspace::new) + .ok() + } else { + None + }; + let mut sysroot = Sysroot { + root: sysroot_dir, + src_root: sysroot_src_dir, + crates: Arena::default(), + hack_cargo_workspace, + }; for path in SYSROOT_CRATES.trim().lines() { let name = path.split('/').last().unwrap(); @@ -153,19 +194,6 @@ impl Sysroot { } } - if sysroot.by_name("core").is_none() { - let var_note = if env::var_os("RUST_SRC_PATH").is_some() { - " (`RUST_SRC_PATH` might be incorrect, try unsetting it)" - } else { - "" - }; - tracing::error!( - "could not find libcore in sysroot path `{}`{}", - sysroot.src_root.as_path().display(), - var_note, - ); - } - sysroot } diff --git a/crates/project-model/src/target_data_layout.rs b/crates/project-model/src/target_data_layout.rs index 42c06ad0ed371..30ca7b348e84f 100644 --- a/crates/project-model/src/target_data_layout.rs +++ b/crates/project-model/src/target_data_layout.rs @@ -16,7 +16,7 @@ pub fn get( let mut cmd = Command::new(toolchain::rustc()); cmd.envs(extra_env); cmd.current_dir(cargo_toml.parent()) - .args(["-Z", "unstable-options", "rustc", "--print", "target-spec-json"]) + .args(["-Z", "unstable-options", "--print", "target-spec-json"]) .env("RUSTC_BOOTSTRAP", "1"); if let Some(target) = target { cmd.args(["--target", target]); diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index 3754accbb03d8..7815b9dda77f2 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -3,10 +3,11 @@ use std::{ path::{Path, PathBuf}, }; -use base_db::{CrateGraph, FileId}; +use base_db::{CrateGraph, FileId, ProcMacroPaths}; use cfg::{CfgAtom, CfgDiff}; -use expect_test::{expect, Expect}; +use expect_test::{expect_file, ExpectFile}; use paths::{AbsPath, AbsPathBuf}; +use rustc_hash::FxHashMap; use serde::de::DeserializeOwned; use crate::{ @@ -14,11 +15,14 @@ use crate::{ WorkspaceBuildScripts, }; -fn load_cargo(file: &str) -> CrateGraph { +fn load_cargo(file: &str) -> (CrateGraph, ProcMacroPaths) { load_cargo_with_overrides(file, CfgOverrides::default()) } -fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> CrateGraph { +fn load_cargo_with_overrides( + file: &str, + cfg_overrides: CfgOverrides, +) -> (CrateGraph, ProcMacroPaths) { let meta = get_test_json_file(file); let cargo_workspace = CargoWorkspace::new(meta); let project_workspace = ProjectWorkspace::Cargo { @@ -34,11 +38,39 @@ fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> CrateGr to_crate_graph(project_workspace) } -fn load_rust_project(file: &str) -> CrateGraph { +fn load_cargo_with_sysroot( + file_map: &mut FxHashMap, + file: &str, +) -> (CrateGraph, ProcMacroPaths) { + let meta = get_test_json_file(file); + let cargo_workspace = CargoWorkspace::new(meta); + let project_workspace = ProjectWorkspace::Cargo { + cargo: cargo_workspace, + build_scripts: WorkspaceBuildScripts::default(), + sysroot: Ok(get_fake_sysroot()), + rustc: Err(None), + rustc_cfg: Vec::new(), + cfg_overrides: Default::default(), + toolchain: None, + target_layout: Err("target_data_layout not loaded".into()), + }; + project_workspace.to_crate_graph( + &mut { + |path| { + let len = file_map.len(); + Some(*file_map.entry(path.to_path_buf()).or_insert(FileId(len as u32))) + } + }, + &Default::default(), + ) +} + +fn load_rust_project(file: &str) -> (CrateGraph, ProcMacroPaths) { let data = get_test_json_file(file); let project = rooted_project_json(data); let sysroot = Ok(get_fake_sysroot()); - let project_workspace = ProjectWorkspace::Json { project, sysroot, rustc_cfg: Vec::new() }; + let project_workspace = + ProjectWorkspace::Json { project, sysroot, rustc_cfg: Vec::new(), toolchain: None }; to_crate_graph(project_workspace) } @@ -70,6 +102,18 @@ fn replace_root(s: &mut String, direction: bool) { } } +fn replace_fake_sys_root(s: &mut String) { + let fake_sysroot_path = get_test_path("fake-sysroot"); + let fake_sysroot_path = if cfg!(windows) { + let normalized_path = + fake_sysroot_path.to_str().expect("expected str").replace(r#"\"#, r#"\\"#); + format!(r#"{}\\"#, normalized_path) + } else { + format!("{}/", fake_sysroot_path.to_str().expect("expected str")) + }; + *s = s.replace(&fake_sysroot_path, "$FAKESYSROOT$") +} + fn get_test_path(file: &str) -> PathBuf { let base = PathBuf::from(env!("CARGO_MANIFEST_DIR")); base.join("test_data").join(file) @@ -92,9 +136,8 @@ fn rooted_project_json(data: ProjectJsonData) -> ProjectJson { ProjectJson::new(base, data) } -fn to_crate_graph(project_workspace: ProjectWorkspace) -> CrateGraph { +fn to_crate_graph(project_workspace: ProjectWorkspace) -> (CrateGraph, ProcMacroPaths) { project_workspace.to_crate_graph( - &mut |_, _| Ok(Vec::new()), &mut { let mut counter = 0; move |_path| { @@ -106,1808 +149,70 @@ fn to_crate_graph(project_workspace: ProjectWorkspace) -> CrateGraph { ) } -fn check_crate_graph(crate_graph: CrateGraph, expect: Expect) { +fn check_crate_graph(crate_graph: CrateGraph, expect: ExpectFile) { let mut crate_graph = format!("{crate_graph:#?}"); replace_root(&mut crate_graph, false); + replace_fake_sys_root(&mut crate_graph); expect.assert_eq(&crate_graph); } #[test] fn cargo_hello_world_project_model_with_wildcard_overrides() { - let cfg_overrides = CfgOverrides::Wildcard( - CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(), - ); - let crate_graph = load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides); + let cfg_overrides = CfgOverrides { + global: CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(), + selective: Default::default(), + }; + let (crate_graph, _proc_macros) = + load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides); check_crate_graph( crate_graph, - expect![[r#" - CrateGraph { - arena: { - CrateId( - 0, - ): CrateData { - root_file_id: FileId( - 1, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", - ), - canonical_name: "hello-world", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - ], - ), - target_layout: Err( - "target_data_layout not loaded", - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), - }, - is_proc_macro: false, - }, - CrateId( - 1, - ): CrateData { - root_file_id: FileId( - 2, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", - ), - canonical_name: "hello-world", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - ], - ), - target_layout: Err( - "target_data_layout not loaded", - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), - }, - is_proc_macro: false, - }, - CrateId( - 2, - ): CrateData { - root_file_id: FileId( - 3, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "an_example", - ), - canonical_name: "an-example", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - ], - ), - target_layout: Err( - "target_data_layout not loaded", - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), - }, - is_proc_macro: false, - }, - CrateId( - 3, - ): CrateData { - root_file_id: FileId( - 4, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "it", - ), - canonical_name: "it", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - ], - ), - target_layout: Err( - "target_data_layout not loaded", - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), - }, - is_proc_macro: false, - }, - CrateId( - 4, - ): CrateData { - root_file_id: FileId( - 5, - ), - edition: Edition2015, - version: Some( - "0.2.98", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "libc", - ), - canonical_name: "libc", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "feature=default", - "feature=std", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "feature=align", - "feature=const-extern-fn", - "feature=default", - "feature=extra_traits", - "feature=rustc-dep-of-std", - "feature=std", - "feature=use_std", - ], - ), - target_layout: Err( - "target_data_layout not loaded", - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", - "CARGO_PKG_VERSION": "0.2.98", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "libc", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "libc", - "CARGO_PKG_VERSION_PATCH": "98", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "2", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: Some( - "https://github.com/rust-lang/libc", - ), - name: Some( - "libc", - ), - }, - is_proc_macro: false, - }, - }, - }"#]], + expect_file![ + "../test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt" + ], ) } #[test] fn cargo_hello_world_project_model_with_selective_overrides() { - let cfg_overrides = { - CfgOverrides::Selective( - std::iter::once(( - "libc".to_owned(), - CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(), - )) - .collect(), - ) + let cfg_overrides = CfgOverrides { + global: Default::default(), + selective: std::iter::once(( + "libc".to_owned(), + CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(), + )) + .collect(), }; - let crate_graph = load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides); + let (crate_graph, _proc_macros) = + load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides); check_crate_graph( crate_graph, - expect![[r#" - CrateGraph { - arena: { - CrateId( - 0, - ): CrateData { - root_file_id: FileId( - 1, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", - ), - canonical_name: "hello-world", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - target_layout: Err( - "target_data_layout not loaded", - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), - }, - is_proc_macro: false, - }, - CrateId( - 1, - ): CrateData { - root_file_id: FileId( - 2, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", - ), - canonical_name: "hello-world", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - target_layout: Err( - "target_data_layout not loaded", - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), - }, - is_proc_macro: false, - }, - CrateId( - 2, - ): CrateData { - root_file_id: FileId( - 3, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "an_example", - ), - canonical_name: "an-example", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - target_layout: Err( - "target_data_layout not loaded", - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), - }, - is_proc_macro: false, - }, - CrateId( - 3, - ): CrateData { - root_file_id: FileId( - 4, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "it", - ), - canonical_name: "it", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - target_layout: Err( - "target_data_layout not loaded", - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), - }, - is_proc_macro: false, - }, - CrateId( - 4, - ): CrateData { - root_file_id: FileId( - 5, - ), - edition: Edition2015, - version: Some( - "0.2.98", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "libc", - ), - canonical_name: "libc", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "feature=default", - "feature=std", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "feature=align", - "feature=const-extern-fn", - "feature=default", - "feature=extra_traits", - "feature=rustc-dep-of-std", - "feature=std", - "feature=use_std", - ], - ), - target_layout: Err( - "target_data_layout not loaded", - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", - "CARGO_PKG_VERSION": "0.2.98", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "libc", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "libc", - "CARGO_PKG_VERSION_PATCH": "98", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "2", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: Some( - "https://github.com/rust-lang/libc", - ), - name: Some( - "libc", - ), - }, - is_proc_macro: false, - }, - }, - }"#]], + expect_file![ + "../test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt" + ], ) } #[test] fn cargo_hello_world_project_model() { - let crate_graph = load_cargo("hello-world-metadata.json"); + let (crate_graph, _proc_macros) = load_cargo("hello-world-metadata.json"); check_crate_graph( crate_graph, - expect![[r#" - CrateGraph { - arena: { - CrateId( - 0, - ): CrateData { - root_file_id: FileId( - 1, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", - ), - canonical_name: "hello-world", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - target_layout: Err( - "target_data_layout not loaded", - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), - }, - is_proc_macro: false, - }, - CrateId( - 1, - ): CrateData { - root_file_id: FileId( - 2, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", - ), - canonical_name: "hello-world", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - target_layout: Err( - "target_data_layout not loaded", - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), - }, - is_proc_macro: false, - }, - CrateId( - 2, - ): CrateData { - root_file_id: FileId( - 3, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "an_example", - ), - canonical_name: "an-example", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - target_layout: Err( - "target_data_layout not loaded", - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), - }, - is_proc_macro: false, - }, - CrateId( - 3, - ): CrateData { - root_file_id: FileId( - 4, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "it", - ), - canonical_name: "it", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "test", - ], - ), - target_layout: Err( - "target_data_layout not loaded", - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), - }, - is_proc_macro: false, - }, - CrateId( - 4, - ): CrateData { - root_file_id: FileId( - 5, - ), - edition: Edition2015, - version: Some( - "0.2.98", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "libc", - ), - canonical_name: "libc", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "feature=default", - "feature=std", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "feature=align", - "feature=const-extern-fn", - "feature=default", - "feature=extra_traits", - "feature=rustc-dep-of-std", - "feature=std", - "feature=use_std", - ], - ), - target_layout: Err( - "target_data_layout not loaded", - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", - "CARGO_PKG_VERSION": "0.2.98", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "libc", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "libc", - "CARGO_PKG_VERSION_PATCH": "98", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "2", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: Some( - "https://github.com/rust-lang/libc", - ), - name: Some( - "libc", - ), - }, - is_proc_macro: false, - }, - }, - }"#]], + expect_file!["../test_data/output/cargo_hello_world_project_model.txt"], ) } #[test] fn rust_project_hello_world_project_model() { - let crate_graph = load_rust_project("hello-world-project.json"); + let (crate_graph, _proc_macros) = load_rust_project("hello-world-project.json"); check_crate_graph( crate_graph, - expect![[r#" - CrateGraph { - arena: { - CrateId( - 0, - ): CrateData { - root_file_id: FileId( - 1, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "alloc", - ), - canonical_name: "alloc", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), - env: Env { - entries: {}, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 1, - ), - name: CrateName( - "core", - ), - prelude: true, - }, - ], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Alloc, - ), - is_proc_macro: false, - }, - CrateId( - 1, - ): CrateData { - root_file_id: FileId( - 2, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "core", - ), - canonical_name: "core", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), - env: Env { - entries: {}, - }, - dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Core, - ), - is_proc_macro: false, - }, - CrateId( - 2, - ): CrateData { - root_file_id: FileId( - 3, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "panic_abort", - ), - canonical_name: "panic_abort", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), - env: Env { - entries: {}, - }, - dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Other, - ), - is_proc_macro: false, - }, - CrateId( - 3, - ): CrateData { - root_file_id: FileId( - 4, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "panic_unwind", - ), - canonical_name: "panic_unwind", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), - env: Env { - entries: {}, - }, - dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Other, - ), - is_proc_macro: false, - }, - CrateId( - 4, - ): CrateData { - root_file_id: FileId( - 5, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "proc_macro", - ), - canonical_name: "proc_macro", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), - env: Env { - entries: {}, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 6, - ), - name: CrateName( - "std", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 1, - ), - name: CrateName( - "core", - ), - prelude: true, - }, - ], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Other, - ), - is_proc_macro: false, - }, - CrateId( - 5, - ): CrateData { - root_file_id: FileId( - 6, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "profiler_builtins", - ), - canonical_name: "profiler_builtins", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), - env: Env { - entries: {}, - }, - dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Other, - ), - is_proc_macro: false, - }, - CrateId( - 6, - ): CrateData { - root_file_id: FileId( - 7, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "std", - ), - canonical_name: "std", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), - env: Env { - entries: {}, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "alloc", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 3, - ), - name: CrateName( - "panic_unwind", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 2, - ), - name: CrateName( - "panic_abort", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 1, - ), - name: CrateName( - "core", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 5, - ), - name: CrateName( - "profiler_builtins", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 9, - ), - name: CrateName( - "unwind", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 7, - ), - name: CrateName( - "std_detect", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 8, - ), - name: CrateName( - "test", - ), - prelude: true, - }, - ], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Std, - ), - is_proc_macro: false, - }, - CrateId( - 7, - ): CrateData { - root_file_id: FileId( - 8, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "std_detect", - ), - canonical_name: "std_detect", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), - env: Env { - entries: {}, - }, - dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Other, - ), - is_proc_macro: false, - }, - CrateId( - 8, - ): CrateData { - root_file_id: FileId( - 9, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "test", - ), - canonical_name: "test", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), - env: Env { - entries: {}, - }, - dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Test, - ), - is_proc_macro: false, - }, - CrateId( - 9, - ): CrateData { - root_file_id: FileId( - 10, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "unwind", - ), - canonical_name: "unwind", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), - env: Env { - entries: {}, - }, - dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Other, - ), - is_proc_macro: false, - }, - CrateId( - 10, - ): CrateData { - root_file_id: FileId( - 11, - ), - edition: Edition2018, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", - ), - canonical_name: "hello_world", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), - env: Env { - entries: {}, - }, - dependencies: [ - Dependency { - crate_id: CrateId( - 1, - ), - name: CrateName( - "core", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "alloc", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 6, - ), - name: CrateName( - "std", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 8, - ), - name: CrateName( - "test", - ), - prelude: false, - }, - ], - proc_macro: Err( - "no proc macro dylib present", - ), - origin: CratesIo { - repo: None, - name: Some( - "hello_world", - ), - }, - is_proc_macro: false, - }, - }, - }"#]], + expect_file!["../test_data/output/rust_project_hello_world_project_model.txt"], ); } #[test] fn rust_project_is_proc_macro_has_proc_macro_dep() { - let crate_graph = load_rust_project("is-proc-macro-project.json"); + let (crate_graph, _proc_macros) = load_rust_project("is-proc-macro-project.json"); // Since the project only defines one crate (outside the sysroot crates), // it should be the one with the biggest Id. let crate_id = crate_graph.iter().max().unwrap(); @@ -1916,3 +221,31 @@ fn rust_project_is_proc_macro_has_proc_macro_dep() { // on the proc_macro sysroot crate. crate_data.dependencies.iter().find(|&dep| dep.name.deref() == "proc_macro").unwrap(); } + +#[test] +fn crate_graph_dedup_identical() { + let (mut crate_graph, proc_macros) = + load_cargo_with_sysroot(&mut Default::default(), "regex-metadata.json"); + crate_graph.sort_deps(); + + let (d_crate_graph, mut d_proc_macros) = (crate_graph.clone(), proc_macros.clone()); + + crate_graph.extend(d_crate_graph.clone(), &mut d_proc_macros); + assert!(crate_graph.iter().eq(d_crate_graph.iter())); + assert_eq!(proc_macros, d_proc_macros); +} + +#[test] +fn crate_graph_dedup() { + let path_map = &mut Default::default(); + let (mut crate_graph, _proc_macros) = + load_cargo_with_sysroot(path_map, "ripgrep-metadata.json"); + assert_eq!(crate_graph.iter().count(), 81); + crate_graph.sort_deps(); + let (regex_crate_graph, mut regex_proc_macros) = + load_cargo_with_sysroot(path_map, "regex-metadata.json"); + assert_eq!(regex_crate_graph.iter().count(), 60); + + crate_graph.extend(regex_crate_graph, &mut regex_proc_macros); + assert_eq!(crate_graph.iter().count(), 118); +} diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index d1e53e12eebb5..0aca620a67553 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -2,53 +2,43 @@ //! metadata` or `rust-project.json`) into representation stored in the salsa //! database -- `CrateGraph`. -use std::{collections::VecDeque, fmt, fs, process::Command, sync::Arc}; +use std::{collections::VecDeque, fmt, fs, process::Command, sync}; use anyhow::{format_err, Context, Result}; use base_db::{ CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env, - FileId, LangCrateOrigin, ProcMacroLoadResult, TargetLayoutLoadResult, + FileId, LangCrateOrigin, ProcMacroPaths, ReleaseChannel, TargetLayoutLoadResult, }; use cfg::{CfgDiff, CfgOptions}; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::{FxHashMap, FxHashSet}; use semver::Version; -use stdx::{always, hash::NoHashHashMap}; +use stdx::always; +use triomphe::Arc; use crate::{ build_scripts::BuildScriptOutput, cargo_workspace::{DepKind, PackageData, RustLibSource}, cfg_flag::CfgFlag, + project_json::Crate, rustc_cfg, sysroot::SysrootCrate, target_data_layout, utf8_stdout, CargoConfig, CargoWorkspace, InvocationStrategy, ManifestPath, - Package, ProjectJson, ProjectManifest, Sysroot, TargetKind, WorkspaceBuildScripts, + Package, ProjectJson, ProjectManifest, Sysroot, TargetData, TargetKind, WorkspaceBuildScripts, }; /// A set of cfg-overrides per crate. -/// -/// `Wildcard(..)` is useful e.g. disabling `#[cfg(test)]` on all crates, -/// without having to first obtain a list of all crates. -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum CfgOverrides { - /// A single global set of overrides matching all crates. - Wildcard(CfgDiff), +#[derive(Default, Debug, Clone, Eq, PartialEq)] +pub struct CfgOverrides { + /// A global set of overrides matching all crates. + pub global: CfgDiff, /// A set of overrides matching specific crates. - Selective(FxHashMap), -} - -impl Default for CfgOverrides { - fn default() -> Self { - Self::Selective(FxHashMap::default()) - } + pub selective: FxHashMap, } impl CfgOverrides { pub fn len(&self) -> usize { - match self { - CfgOverrides::Wildcard(_) => 1, - CfgOverrides::Selective(hash_map) => hash_map.len(), - } + self.global.len() + self.selective.iter().map(|(_, it)| it.len()).sum::() } } @@ -82,7 +72,14 @@ pub enum ProjectWorkspace { target_layout: Result, }, /// Project workspace was manually specified using a `rust-project.json` file. - Json { project: ProjectJson, sysroot: Result>, rustc_cfg: Vec }, + Json { + project: ProjectJson, + sysroot: Result>, + /// Holds cfg flags for the current target. We get those by running + /// `rustc --print cfg`. + rustc_cfg: Vec, + toolchain: Option, + }, // FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning. // That's not the end user experience we should strive for. // Ideally, you should be able to just open a random detached file in existing cargo projects, and get the basic features working. @@ -96,6 +93,8 @@ pub enum ProjectWorkspace { DetachedFiles { files: Vec, sysroot: Result>, + /// Holds cfg flags for the current target. We get those by running + /// `rustc --print cfg`. rustc_cfg: Vec, }, } @@ -127,12 +126,13 @@ impl fmt::Debug for ProjectWorkspace { .field("toolchain", &toolchain) .field("data_layout", &data_layout) .finish(), - ProjectWorkspace::Json { project, sysroot, rustc_cfg } => { + ProjectWorkspace::Json { project, sysroot, rustc_cfg, toolchain } => { let mut debug_struct = f.debug_struct("Json"); debug_struct.field("n_crates", &project.n_crates()); if let Ok(sysroot) = sysroot { debug_struct.field("n_sysroot_crates", &sysroot.crates().len()); } + debug_struct.field("toolchain", &toolchain); debug_struct.field("n_rustc_cfg", &rustc_cfg.len()); debug_struct.finish() } @@ -152,6 +152,19 @@ impl ProjectWorkspace { config: &CargoConfig, progress: &dyn Fn(String), ) -> Result { + let version = |current_dir, cmd_path, prefix: &str| { + let cargo_version = utf8_stdout({ + let mut cmd = Command::new(cmd_path); + cmd.envs(&config.extra_env); + cmd.arg("--version").current_dir(current_dir); + cmd + })?; + anyhow::Ok( + cargo_version + .get(prefix.len()..) + .and_then(|it| Version::parse(it.split_whitespace().next()?).ok()), + ) + }; let res = match manifest { ProjectManifest::ProjectJson(project_json) => { let file = fs::read_to_string(&project_json).with_context(|| { @@ -161,24 +174,17 @@ impl ProjectWorkspace { format!("Failed to deserialize json file {}", project_json.display()) })?; let project_location = project_json.parent().to_path_buf(); + let toolchain = version(&*project_location, toolchain::rustc(), "rustc ")?; let project_json = ProjectJson::new(&project_location, data); ProjectWorkspace::load_inline( project_json, config.target.as_deref(), &config.extra_env, + toolchain, ) } ProjectManifest::CargoToml(cargo_toml) => { - let cargo_version = utf8_stdout({ - let mut cmd = Command::new(toolchain::cargo()); - cmd.envs(&config.extra_env); - cmd.arg("--version"); - cmd - })?; - let toolchain = cargo_version - .get("cargo ".len()..) - .and_then(|it| Version::parse(it.split_whitespace().next()?).ok()); - + let toolchain = version(cargo_toml.parent(), toolchain::cargo(), "cargo ")?; let meta = CargoWorkspace::fetch_metadata( &cargo_toml, cargo_toml.parent(), @@ -274,7 +280,7 @@ impl ProjectWorkspace { let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref(), &config.extra_env); - let cfg_overrides = config.cfg_overrides(); + let cfg_overrides = config.cfg_overrides.clone(); let data_layout = target_data_layout::get( Some(&cargo_toml), config.target.as_deref(), @@ -303,6 +309,7 @@ impl ProjectWorkspace { project_json: ProjectJson, target: Option<&str>, extra_env: &FxHashMap, + toolchain: Option, ) -> ProjectWorkspace { let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) { (Some(sysroot), Some(sysroot_src)) => Ok(Sysroot::load(sysroot, sysroot_src)), @@ -327,7 +334,7 @@ impl ProjectWorkspace { } let rustc_cfg = rustc_cfg::get(None, target, extra_env); - ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg } + ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg, toolchain } } pub fn load_detached_files( @@ -403,7 +410,7 @@ impl ProjectWorkspace { let outputs = &mut match WorkspaceBuildScripts::run_once(config, &cargo_ws, progress) { Ok(it) => Ok(it.into_iter()), // io::Error is not Clone? - Err(e) => Err(Arc::new(e)), + Err(e) => Err(sync::Arc::new(e)), }; workspaces @@ -440,18 +447,35 @@ impl ProjectWorkspace { } } - pub fn find_sysroot_proc_macro_srv(&self) -> Option { + pub fn find_sysroot_proc_macro_srv(&self) -> Result { match self { ProjectWorkspace::Cargo { sysroot: Ok(sysroot), .. } - | ProjectWorkspace::Json { sysroot: Ok(sysroot), .. } => { + | ProjectWorkspace::Json { sysroot: Ok(sysroot), .. } + | ProjectWorkspace::DetachedFiles { sysroot: Ok(sysroot), .. } => { let standalone_server_name = format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX); ["libexec", "lib"] .into_iter() .map(|segment| sysroot.root().join(segment).join(&standalone_server_name)) .find(|server_path| std::fs::metadata(server_path).is_ok()) + .ok_or_else(|| { + anyhow::anyhow!( + "cannot find proc-macro server in sysroot `{}`", + sysroot.root().display() + ) + }) + } + ProjectWorkspace::DetachedFiles { .. } => { + Err(anyhow::anyhow!("cannot find proc-macro server, no sysroot was found")) } - _ => None, + ProjectWorkspace::Cargo { cargo, .. } => Err(anyhow::anyhow!( + "cannot find proc-macro-srv, the workspace `{}` is missing a sysroot", + cargo.workspace_root().display() + )), + ProjectWorkspace::Json { project, .. } => Err(anyhow::anyhow!( + "cannot find proc-macro-srv, the workspace `{}` is missing a sysroot", + project.path().display() + )), } } @@ -469,7 +493,7 @@ impl ProjectWorkspace { }) }; match self { - ProjectWorkspace::Json { project, sysroot, rustc_cfg: _ } => project + ProjectWorkspace::Json { project, sysroot, rustc_cfg: _, toolchain: _ } => project .crates() .map(|(_, krate)| PackageRoot { is_local: krate.is_workspace_member, @@ -570,22 +594,23 @@ impl ProjectWorkspace { pub fn to_crate_graph( &self, - load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, load: &mut dyn FnMut(&AbsPath) -> Option, extra_env: &FxHashMap, - ) -> CrateGraph { + ) -> (CrateGraph, ProcMacroPaths) { let _p = profile::span("ProjectWorkspace::to_crate_graph"); - let mut crate_graph = match self { - ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph( - rustc_cfg.clone(), - load_proc_macro, - load, - project, - sysroot.as_ref().ok(), - extra_env, - Err("rust-project.json projects have no target layout set".into()), - ), + let (mut crate_graph, proc_macros) = match self { + ProjectWorkspace::Json { project, sysroot, rustc_cfg, toolchain } => { + project_json_to_crate_graph( + rustc_cfg.clone(), + load, + project, + sysroot.as_ref().ok(), + extra_env, + Err("rust-project.json projects have no target layout set".into()), + toolchain.as_ref().and_then(|it| ReleaseChannel::from_str(it.pre.as_str())), + ) + } ProjectWorkspace::Cargo { cargo, sysroot, @@ -593,21 +618,22 @@ impl ProjectWorkspace { rustc_cfg, cfg_overrides, build_scripts, - toolchain: _, + toolchain, target_layout, } => cargo_to_crate_graph( - load_proc_macro, load, rustc.as_ref().ok(), cargo, sysroot.as_ref().ok(), rustc_cfg.clone(), cfg_overrides, + None, build_scripts, match target_layout.as_ref() { Ok(it) => Ok(Arc::from(it.as_str())), Err(it) => Err(Arc::from(it.as_str())), }, + toolchain.as_ref().and_then(|it| ReleaseChannel::from_str(it.pre.as_str())), ), ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => { detached_files_to_crate_graph( @@ -624,7 +650,7 @@ impl ProjectWorkspace { } else { tracing::debug!("Did not patch std to depend on cfg-if") } - crate_graph + (crate_graph, proc_macros) } pub fn eq_ignore_build_data(&self, other: &Self) -> bool { @@ -659,9 +685,19 @@ impl ProjectWorkspace { && sysroot == o_sysroot } ( - Self::Json { project, sysroot, rustc_cfg }, - Self::Json { project: o_project, sysroot: o_sysroot, rustc_cfg: o_rustc_cfg }, - ) => project == o_project && rustc_cfg == o_rustc_cfg && sysroot == o_sysroot, + Self::Json { project, sysroot, rustc_cfg, toolchain }, + Self::Json { + project: o_project, + sysroot: o_sysroot, + rustc_cfg: o_rustc_cfg, + toolchain: o_toolchain, + }, + ) => { + project == o_project + && rustc_cfg == o_rustc_cfg + && sysroot == o_sysroot + && toolchain == o_toolchain + } ( Self::DetachedFiles { files, sysroot, rustc_cfg }, Self::DetachedFiles { files: o_files, sysroot: o_sysroot, rustc_cfg: o_rustc_cfg }, @@ -669,130 +705,146 @@ impl ProjectWorkspace { _ => false, } } + + /// Returns `true` if the project workspace is [`Json`]. + /// + /// [`Json`]: ProjectWorkspace::Json + #[must_use] + pub fn is_json(&self) -> bool { + matches!(self, Self::Json { .. }) + } } fn project_json_to_crate_graph( rustc_cfg: Vec, - load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, load: &mut dyn FnMut(&AbsPath) -> Option, project: &ProjectJson, sysroot: Option<&Sysroot>, extra_env: &FxHashMap, target_layout: TargetLayoutLoadResult, -) -> CrateGraph { - let mut crate_graph = CrateGraph::default(); + channel: Option, +) -> (CrateGraph, ProcMacroPaths) { + let mut res = (CrateGraph::default(), ProcMacroPaths::default()); + let (crate_graph, proc_macros) = &mut res; let sysroot_deps = sysroot.as_ref().map(|sysroot| { sysroot_to_crate_graph( - &mut crate_graph, + crate_graph, sysroot, rustc_cfg.clone(), target_layout.clone(), load, + channel, ) }); let mut cfg_cache: FxHashMap<&str, Vec> = FxHashMap::default(); - let crates: NoHashHashMap = project + let crates: FxHashMap = project .crates() - .filter_map(|(crate_id, krate)| { - let file_path = &krate.root_module; - let file_id = load(file_path)?; - Some((crate_id, krate, file_id)) - }) - .map(|(crate_id, krate, file_id)| { - let env = krate.env.clone().into_iter().collect(); - let proc_macro = match krate.proc_macro_dylib_path.clone() { - Some(it) => load_proc_macro( - krate.display_name.as_ref().map(|it| it.canonical_name()).unwrap_or(""), - &it, - ), - None => Err("no proc macro dylib present".into()), - }; - - let target_cfgs = match krate.target.as_deref() { - Some(target) => cfg_cache - .entry(target) - .or_insert_with(|| rustc_cfg::get(None, Some(target), extra_env)), - None => &rustc_cfg, - }; - - let mut cfg_options = CfgOptions::default(); - cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned()); - ( + .filter_map(|(crate_id, krate)| Some((crate_id, krate, load(&krate.root_module)?))) + .map( + |( crate_id, - crate_graph.add_crate_root( + Crate { + display_name, + edition, + version, + cfg, + target, + env, + proc_macro_dylib_path, + is_proc_macro, + repository, + .. + }, + file_id, + )| { + let env = env.clone().into_iter().collect(); + + let target_cfgs = match target.as_deref() { + Some(target) => cfg_cache + .entry(target) + .or_insert_with(|| rustc_cfg::get(None, Some(target), extra_env)), + None => &rustc_cfg, + }; + + let crate_graph_crate_id = crate_graph.add_crate_root( file_id, - krate.edition, - krate.display_name.clone(), - krate.version.clone(), - cfg_options.clone(), - cfg_options, + *edition, + display_name.clone(), + version.clone(), + target_cfgs.iter().chain(cfg.iter()).cloned().collect(), + None, env, - proc_macro, - krate.is_proc_macro, - if krate.display_name.is_some() { - CrateOrigin::CratesIo { - repo: krate.repository.clone(), - name: krate - .display_name - .clone() - .map(|n| n.canonical_name().to_string()), + *is_proc_macro, + if let Some(name) = display_name.clone() { + CrateOrigin::Local { + repo: repository.clone(), + name: Some(name.canonical_name().to_string()), } } else { - CrateOrigin::CratesIo { repo: None, name: None } + CrateOrigin::Local { repo: None, name: None } }, target_layout.clone(), - ), - ) - }) + channel, + ); + if *is_proc_macro { + if let Some(path) = proc_macro_dylib_path.clone() { + let node = Ok(( + display_name.as_ref().map(|it| it.canonical_name().to_owned()), + path, + )); + proc_macros.insert(crate_graph_crate_id, node); + } + } + (crate_id, crate_graph_crate_id) + }, + ) .collect(); for (from, krate) in project.crates() { if let Some(&from) = crates.get(&from) { if let Some((public_deps, libproc_macro)) = &sysroot_deps { - public_deps.add_to_crate_graph(&mut crate_graph, from); - if krate.is_proc_macro { - if let Some(proc_macro) = libproc_macro { - add_dep( - &mut crate_graph, - from, - CrateName::new("proc_macro").unwrap(), - *proc_macro, - ); - } + public_deps.add_to_crate_graph(crate_graph, from); + if let Some(proc_macro) = libproc_macro { + add_proc_macro_dep(crate_graph, from, *proc_macro, krate.is_proc_macro); } } for dep in &krate.deps { if let Some(&to) = crates.get(&dep.crate_id) { - add_dep(&mut crate_graph, from, dep.name.clone(), to) + add_dep(crate_graph, from, dep.name.clone(), to) } } } } - crate_graph + res } fn cargo_to_crate_graph( - load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, load: &mut dyn FnMut(&AbsPath) -> Option, rustc: Option<&(CargoWorkspace, WorkspaceBuildScripts)>, cargo: &CargoWorkspace, sysroot: Option<&Sysroot>, rustc_cfg: Vec, override_cfg: &CfgOverrides, + // Don't compute cfg and use this if present + forced_cfg: Option, build_scripts: &WorkspaceBuildScripts, target_layout: TargetLayoutLoadResult, -) -> CrateGraph { + channel: Option, +) -> (CrateGraph, ProcMacroPaths) { let _p = profile::span("cargo_to_crate_graph"); - let mut crate_graph = CrateGraph::default(); + let mut res = (CrateGraph::default(), ProcMacroPaths::default()); + let crate_graph = &mut res.0; + let proc_macros = &mut res.1; let (public_deps, libproc_macro) = match sysroot { Some(sysroot) => sysroot_to_crate_graph( - &mut crate_graph, + crate_graph, sysroot, rustc_cfg.clone(), target_layout.clone(), load, + channel, ), None => (SysrootPublicDeps::default(), None), }; @@ -804,37 +856,40 @@ fn cargo_to_crate_graph( cfg_options }; + // Mapping of a package to its library target let mut pkg_to_lib_crate = FxHashMap::default(); - let mut pkg_crates = FxHashMap::default(); // Does any crate signal to rust-analyzer that they need the rustc_private crates? let mut has_private = false; + // Next, create crates for each package, target pair for pkg in cargo.packages() { - let mut cfg_options = cfg_options.clone(); + has_private |= cargo[pkg].metadata.rustc_private; - let overrides = match override_cfg { - CfgOverrides::Wildcard(cfg_diff) => Some(cfg_diff), - CfgOverrides::Selective(cfg_overrides) => cfg_overrides.get(&cargo[pkg].name), - }; + let cfg_options = forced_cfg.clone().unwrap_or_else(|| { + let mut cfg_options = cfg_options.clone(); - // Add test cfg for local crates - if cargo[pkg].is_local { - cfg_options.insert_atom("test".into()); - } + // Add test cfg for local crates + if cargo[pkg].is_local { + cfg_options.insert_atom("test".into()); + } - if let Some(overrides) = overrides { - // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen - // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while - // working on rust-lang/rust as that's the only time it appears outside sysroot). - // - // A more ideal solution might be to reanalyze crates based on where the cursor is and - // figure out the set of cfgs that would have to apply to make it active. + if !override_cfg.global.is_empty() { + cfg_options.apply_diff(override_cfg.global.clone()); + }; + if let Some(diff) = override_cfg.selective.get(&cargo[pkg].name) { + // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen + // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while + // working on rust-lang/rust as that's the only time it appears outside sysroot). + // + // A more ideal solution might be to reanalyze crates based on where the cursor is and + // figure out the set of cfgs that would have to apply to make it active. - cfg_options.apply_diff(overrides.clone()); - }; + cfg_options.apply_diff(diff.clone()); + }; + cfg_options + }); - has_private |= cargo[pkg].metadata.rustc_private; let mut lib_tgt = None; for &tgt in cargo[pkg].targets.iter() { if cargo[tgt].kind != TargetKind::Lib && !cargo[pkg].is_member { @@ -845,44 +900,57 @@ fn cargo_to_crate_graph( // https://github.com/rust-lang/rust-analyzer/issues/11300 continue; } + let &TargetData { ref name, kind, is_proc_macro, ref root, .. } = &cargo[tgt]; - if let Some(file_id) = load(&cargo[tgt].root) { - let crate_id = add_target_crate_root( - &mut crate_graph, - &cargo[pkg], - build_scripts.get_output(pkg), - cfg_options.clone(), - &mut |path| load_proc_macro(&cargo[tgt].name, path), - file_id, - &cargo[tgt].name, - cargo[tgt].is_proc_macro, - target_layout.clone(), - ); - if cargo[tgt].kind == TargetKind::Lib { - lib_tgt = Some((crate_id, cargo[tgt].name.clone())); + if kind == TargetKind::Lib + && sysroot.map_or(false, |sysroot| root.starts_with(sysroot.src_root())) + { + if let Some(&(_, crate_id, _)) = + public_deps.deps.iter().find(|(dep_name, ..)| dep_name.as_smol_str() == name) + { + pkg_crates.entry(pkg).or_insert_with(Vec::new).push((crate_id, kind)); + + lib_tgt = Some((crate_id, name.clone())); pkg_to_lib_crate.insert(pkg, crate_id); + // sysroot is inside the workspace, prevent the sysroot crates from being duplicated here + continue; } - // Even crates that don't set proc-macro = true are allowed to depend on proc_macro - // (just none of the APIs work when called outside of a proc macro). - if let Some(proc_macro) = libproc_macro { - add_dep_with_prelude( - &mut crate_graph, - crate_id, - CrateName::new("proc_macro").unwrap(), - proc_macro, - cargo[tgt].is_proc_macro, - ); - } + } - pkg_crates.entry(pkg).or_insert_with(Vec::new).push((crate_id, cargo[tgt].kind)); + let Some(file_id) = load(root) else { continue }; + + let crate_id = add_target_crate_root( + crate_graph, + proc_macros, + &cargo[pkg], + build_scripts.get_output(pkg), + cfg_options.clone(), + file_id, + name, + is_proc_macro, + target_layout.clone(), + false, + channel, + ); + if kind == TargetKind::Lib { + lib_tgt = Some((crate_id, name.clone())); + pkg_to_lib_crate.insert(pkg, crate_id); } + // Even crates that don't set proc-macro = true are allowed to depend on proc_macro + // (just none of the APIs work when called outside of a proc macro). + if let Some(proc_macro) = libproc_macro { + add_proc_macro_dep(crate_graph, crate_id, proc_macro, is_proc_macro); + } + + pkg_crates.entry(pkg).or_insert_with(Vec::new).push((crate_id, kind)); } // Set deps to the core, std and to the lib target of the current package for &(from, kind) in pkg_crates.get(&pkg).into_iter().flatten() { // Add sysroot deps first so that a lib target named `core` etc. can overwrite them. - public_deps.add_to_crate_graph(&mut crate_graph, from); + public_deps.add_to_crate_graph(crate_graph, from); + // Add dep edge of all targets to the package's lib target if let Some((to, name)) = lib_tgt.clone() { if to != from && kind != TargetKind::BuildScript { // (build script can not depend on its library target) @@ -891,7 +959,7 @@ fn cargo_to_crate_graph( // cargo metadata does not do any normalization, // so we do it ourselves currently let name = CrateName::normalize_dashes(&name); - add_dep(&mut crate_graph, from, name, to); + add_dep(crate_graph, from, name, to); } } } @@ -900,21 +968,18 @@ fn cargo_to_crate_graph( // Now add a dep edge from all targets of upstream to the lib // target of downstream. for pkg in cargo.packages() { - for dep in cargo[pkg].dependencies.iter() { - let name = CrateName::new(&dep.name).unwrap(); - if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { - for &(from, kind) in pkg_crates.get(&pkg).into_iter().flatten() { - if dep.kind == DepKind::Build && kind != TargetKind::BuildScript { - // Only build scripts may depend on build dependencies. - continue; - } - if dep.kind != DepKind::Build && kind == TargetKind::BuildScript { - // Build scripts may only depend on build dependencies. - continue; - } + for dep in &cargo[pkg].dependencies { + let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) else { continue }; + let Some(targets) = pkg_crates.get(&pkg) else { continue }; - add_dep(&mut crate_graph, from, name.clone(), to) + let name = CrateName::new(&dep.name).unwrap(); + for &(from, kind) in targets { + // Build scripts may only depend on build dependencies. + if (dep.kind == DepKind::Build) != (kind == TargetKind::BuildScript) { + continue; } + + add_dep(crate_graph, from, name.clone(), to) } } } @@ -924,10 +989,10 @@ fn cargo_to_crate_graph( // and create dependencies on them for the crates which opt-in to that if let Some((rustc_workspace, rustc_build_scripts)) = rustc { handle_rustc_crates( - &mut crate_graph, + crate_graph, + proc_macros, &mut pkg_to_lib_crate, load, - load_proc_macro, rustc_workspace, cargo, &public_deps, @@ -943,10 +1008,11 @@ fn cargo_to_crate_graph( rustc_build_scripts }, target_layout, + channel, ); } } - crate_graph + res } fn detached_files_to_crate_graph( @@ -955,7 +1021,7 @@ fn detached_files_to_crate_graph( detached_files: &[AbsPathBuf], sysroot: Option<&Sysroot>, target_layout: TargetLayoutLoadResult, -) -> CrateGraph { +) -> (CrateGraph, ProcMacroPaths) { let _p = profile::span("detached_files_to_crate_graph"); let mut crate_graph = CrateGraph::default(); let (public_deps, _libproc_macro) = match sysroot { @@ -965,6 +1031,7 @@ fn detached_files_to_crate_graph( rustc_cfg.clone(), target_layout.clone(), load, + None, ), None => (SysrootPublicDeps::default(), None), }; @@ -990,27 +1057,27 @@ fn detached_files_to_crate_graph( display_name.clone(), None, cfg_options.clone(), - cfg_options.clone(), + None, Env::default(), - Ok(Vec::new()), false, - CrateOrigin::CratesIo { + CrateOrigin::Local { repo: None, name: display_name.map(|n| n.canonical_name().to_string()), }, target_layout.clone(), + None, ); public_deps.add_to_crate_graph(&mut crate_graph, detached_file_crate); } - crate_graph + (crate_graph, FxHashMap::default()) } fn handle_rustc_crates( crate_graph: &mut CrateGraph, + proc_macros: &mut ProcMacroPaths, pkg_to_lib_crate: &mut FxHashMap, load: &mut dyn FnMut(&AbsPath) -> Option, - load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, rustc_workspace: &CargoWorkspace, cargo: &CargoWorkspace, public_deps: &SysrootPublicDeps, @@ -1020,6 +1087,7 @@ fn handle_rustc_crates( override_cfg: &CfgOverrides, build_scripts: &WorkspaceBuildScripts, target_layout: TargetLayoutLoadResult, + channel: Option, ) { let mut rustc_pkg_crates = FxHashMap::default(); // The root package of the rustc-dev component is rustc_driver, so we match that @@ -1044,14 +1112,10 @@ fn handle_rustc_crates( let mut cfg_options = cfg_options.clone(); - let overrides = match override_cfg { - CfgOverrides::Wildcard(cfg_diff) => Some(cfg_diff), - CfgOverrides::Selective(cfg_overrides) => { - cfg_overrides.get(&rustc_workspace[pkg].name) - } + if !override_cfg.global.is_empty() { + cfg_options.apply_diff(override_cfg.global.clone()); }; - - if let Some(overrides) = overrides { + if let Some(diff) = override_cfg.selective.get(&rustc_workspace[pkg].name) { // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while // working on rust-lang/rust as that's the only time it appears outside sysroot). @@ -1059,7 +1123,7 @@ fn handle_rustc_crates( // A more ideal solution might be to reanalyze crates based on where the cursor is and // figure out the set of cfgs that would have to apply to make it active. - cfg_options.apply_diff(overrides.clone()); + cfg_options.apply_diff(diff.clone()); }; for &tgt in rustc_workspace[pkg].targets.iter() { @@ -1069,23 +1133,24 @@ fn handle_rustc_crates( if let Some(file_id) = load(&rustc_workspace[tgt].root) { let crate_id = add_target_crate_root( crate_graph, + proc_macros, &rustc_workspace[pkg], build_scripts.get_output(pkg), cfg_options.clone(), - &mut |path| load_proc_macro(&rustc_workspace[tgt].name, path), file_id, &rustc_workspace[tgt].name, rustc_workspace[tgt].is_proc_macro, target_layout.clone(), + true, + channel, ); pkg_to_lib_crate.insert(pkg, crate_id); // Add dependencies on core / std / alloc for this crate public_deps.add_to_crate_graph(crate_graph, crate_id); if let Some(proc_macro) = libproc_macro { - add_dep_with_prelude( + add_proc_macro_dep( crate_graph, crate_id, - CrateName::new("proc_macro").unwrap(), proc_macro, rustc_workspace[tgt].is_proc_macro, ); @@ -1134,22 +1199,29 @@ fn handle_rustc_crates( fn add_target_crate_root( crate_graph: &mut CrateGraph, + proc_macros: &mut ProcMacroPaths, pkg: &PackageData, build_data: Option<&BuildScriptOutput>, cfg_options: CfgOptions, - load_proc_macro: &mut dyn FnMut(&AbsPath) -> ProcMacroLoadResult, file_id: FileId, cargo_name: &str, is_proc_macro: bool, target_layout: TargetLayoutLoadResult, + rustc_crate: bool, + channel: Option, ) -> CrateId { let edition = pkg.edition; - let mut potential_cfg_options = cfg_options.clone(); - potential_cfg_options.extend( - pkg.features - .iter() - .map(|feat| CfgFlag::KeyValue { key: "feature".into(), value: feat.0.into() }), - ); + let potential_cfg_options = if pkg.features.is_empty() { + None + } else { + let mut potential_cfg_options = cfg_options.clone(); + potential_cfg_options.extend( + pkg.features + .iter() + .map(|feat| CfgFlag::KeyValue { key: "feature".into(), value: feat.0.into() }), + ); + Some(potential_cfg_options) + }; let cfg_options = { let mut opts = cfg_options; for feature in pkg.active_features.iter() { @@ -1170,14 +1242,8 @@ fn add_target_crate_root( } } - let proc_macro = match build_data.as_ref().map(|it| it.proc_macro_dylib_path.as_ref()) { - Some(Some(it)) => load_proc_macro(it), - Some(None) => Err("no proc macro dylib present".into()), - None => Err("crate has not (yet) been built".into()), - }; - let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string()); - crate_graph.add_crate_root( + let crate_id = crate_graph.add_crate_root( file_id, edition, Some(display_name), @@ -1185,11 +1251,28 @@ fn add_target_crate_root( cfg_options, potential_cfg_options, env, - proc_macro, is_proc_macro, - CrateOrigin::CratesIo { repo: pkg.repository.clone(), name: Some(pkg.name.clone()) }, + if rustc_crate { + CrateOrigin::Rustc { name: pkg.name.clone() } + } else if pkg.is_member { + CrateOrigin::Local { repo: pkg.repository.clone(), name: Some(pkg.name.clone()) } + } else { + CrateOrigin::Library { repo: pkg.repository.clone(), name: pkg.name.clone() } + }, target_layout, - ) + channel, + ); + if is_proc_macro { + let proc_macro = match build_data.as_ref().map(|it| it.proc_macro_dylib_path.as_ref()) { + Some(it) => it.cloned().map(|path| Ok((Some(cargo_name.to_owned()), path))), + None => Some(Err("crate has not yet been built".to_owned())), + }; + if let Some(proc_macro) = proc_macro { + proc_macros.insert(crate_id, proc_macro); + } + } + + crate_id } #[derive(Default)] @@ -1212,34 +1295,47 @@ fn sysroot_to_crate_graph( rustc_cfg: Vec, target_layout: TargetLayoutLoadResult, load: &mut dyn FnMut(&AbsPath) -> Option, + channel: Option, ) -> (SysrootPublicDeps, Option) { let _p = profile::span("sysroot_to_crate_graph"); let mut cfg_options = CfgOptions::default(); - cfg_options.extend(rustc_cfg); - let sysroot_crates: FxHashMap = sysroot - .crates() - .filter_map(|krate| { - let file_id = load(&sysroot[krate].root)?; - - let env = Env::default(); - let display_name = CrateDisplayName::from_canonical_name(sysroot[krate].name.clone()); - let crate_id = crate_graph.add_crate_root( - file_id, - Edition::CURRENT, - Some(display_name), - None, - cfg_options.clone(), - cfg_options.clone(), - env, - Err("no proc macro loaded for sysroot crate".into()), - false, - CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)), - target_layout.clone(), - ); - Some((krate, crate_id)) - }) - .collect(); - + cfg_options.extend(rustc_cfg.clone()); + let sysroot_crates: FxHashMap = match &sysroot.hack_cargo_workspace { + Some(cargo) => handle_hack_cargo_workspace( + load, + cargo, + rustc_cfg, + cfg_options, + target_layout, + channel, + crate_graph, + sysroot, + ), + None => sysroot + .crates() + .filter_map(|krate| { + let file_id = load(&sysroot[krate].root)?; + + let env = Env::default(); + let display_name = + CrateDisplayName::from_canonical_name(sysroot[krate].name.clone()); + let crate_id = crate_graph.add_crate_root( + file_id, + Edition::CURRENT, + Some(display_name), + None, + cfg_options.clone(), + None, + env, + false, + CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)), + target_layout.clone(), + channel, + ); + Some((krate, crate_id)) + }) + .collect(), + }; for from in sysroot.crates() { for &to in sysroot[from].deps.iter() { let name = CrateName::new(&sysroot[to].name).unwrap(); @@ -1260,6 +1356,63 @@ fn sysroot_to_crate_graph( (public_deps, libproc_macro) } +fn handle_hack_cargo_workspace( + load: &mut dyn FnMut(&AbsPath) -> Option, + cargo: &CargoWorkspace, + rustc_cfg: Vec, + cfg_options: CfgOptions, + target_layout: Result, Arc>, + channel: Option, + crate_graph: &mut CrateGraph, + sysroot: &Sysroot, +) -> FxHashMap { + let (cg, mut pm) = cargo_to_crate_graph( + load, + None, + cargo, + None, + rustc_cfg, + &CfgOverrides::default(), + Some(cfg_options), + &WorkspaceBuildScripts::default(), + target_layout, + channel, + ); + crate_graph.extend(cg, &mut pm); + for crate_name in ["std", "alloc", "core"] { + let original = crate_graph + .iter() + .find(|x| { + crate_graph[*x] + .display_name + .as_ref() + .map(|x| x.canonical_name() == crate_name) + .unwrap_or(false) + }) + .unwrap(); + let fake_crate_name = format!("rustc-std-workspace-{}", crate_name); + let fake = crate_graph + .iter() + .find(|x| { + crate_graph[*x] + .display_name + .as_ref() + .map(|x| x.canonical_name() == fake_crate_name) + .unwrap_or(false) + }) + .unwrap(); + crate_graph.remove_and_replace(fake, original).unwrap(); + } + sysroot + .crates() + .filter_map(|krate| { + let file_id = load(&sysroot[krate].root)?; + let crate_id = crate_graph.crate_id_for_crate_root(file_id)?; + Some((krate, crate_id)) + }) + .collect() +} + fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) { add_dep_inner(graph, from, Dependency::new(name, to)) } @@ -1274,6 +1427,10 @@ fn add_dep_with_prelude( add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude)) } +fn add_proc_macro_dep(crate_graph: &mut CrateGraph, from: CrateId, to: CrateId, prelude: bool) { + add_dep_with_prelude(crate_graph, from, CrateName::new("proc_macro").unwrap(), to, prelude); +} + fn add_dep_inner(graph: &mut CrateGraph, from: CrateId, dep: Dependency) { if let Err(err) = graph.add_dep(from, dep) { tracing::error!("{}", err) diff --git a/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/crates/project-model/test_data/output/cargo_hello_world_project_model.txt new file mode 100644 index 0000000000000..e595cd827293e --- /dev/null +++ b/crates/project-model/test_data/output/cargo_hello_world_project_model.txt @@ -0,0 +1,344 @@ +{ + 0: CrateData { + root_file_id: FileId( + 1, + ), + edition: Edition2018, + version: Some( + "0.1.0", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "hello_world", + ), + canonical_name: "hello-world", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "test", + ], + ), + potential_cfg_options: None, + env: Env { + entries: { + "CARGO_PKG_LICENSE": "", + "CARGO_PKG_VERSION_MAJOR": "0", + "CARGO_MANIFEST_DIR": "$ROOT$hello-world", + "CARGO_PKG_VERSION": "0.1.0", + "CARGO_PKG_AUTHORS": "", + "CARGO_CRATE_NAME": "hello_world", + "CARGO_PKG_LICENSE_FILE": "", + "CARGO_PKG_HOMEPAGE": "", + "CARGO_PKG_DESCRIPTION": "", + "CARGO_PKG_NAME": "hello-world", + "CARGO_PKG_VERSION_PATCH": "0", + "CARGO": "cargo", + "CARGO_PKG_REPOSITORY": "", + "CARGO_PKG_VERSION_MINOR": "1", + "CARGO_PKG_VERSION_PRE": "", + }, + }, + dependencies: [ + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", + ), + }, + is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, + }, + 1: CrateData { + root_file_id: FileId( + 2, + ), + edition: Edition2018, + version: Some( + "0.1.0", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "hello_world", + ), + canonical_name: "hello-world", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "test", + ], + ), + potential_cfg_options: None, + env: Env { + entries: { + "CARGO_PKG_LICENSE": "", + "CARGO_PKG_VERSION_MAJOR": "0", + "CARGO_MANIFEST_DIR": "$ROOT$hello-world", + "CARGO_PKG_VERSION": "0.1.0", + "CARGO_PKG_AUTHORS": "", + "CARGO_CRATE_NAME": "hello_world", + "CARGO_PKG_LICENSE_FILE": "", + "CARGO_PKG_HOMEPAGE": "", + "CARGO_PKG_DESCRIPTION": "", + "CARGO_PKG_NAME": "hello-world", + "CARGO_PKG_VERSION_PATCH": "0", + "CARGO": "cargo", + "CARGO_PKG_REPOSITORY": "", + "CARGO_PKG_VERSION_MINOR": "1", + "CARGO_PKG_VERSION_PRE": "", + }, + }, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "hello_world", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", + ), + }, + is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, + }, + 2: CrateData { + root_file_id: FileId( + 3, + ), + edition: Edition2018, + version: Some( + "0.1.0", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "an_example", + ), + canonical_name: "an-example", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "test", + ], + ), + potential_cfg_options: None, + env: Env { + entries: { + "CARGO_PKG_LICENSE": "", + "CARGO_PKG_VERSION_MAJOR": "0", + "CARGO_MANIFEST_DIR": "$ROOT$hello-world", + "CARGO_PKG_VERSION": "0.1.0", + "CARGO_PKG_AUTHORS": "", + "CARGO_CRATE_NAME": "hello_world", + "CARGO_PKG_LICENSE_FILE": "", + "CARGO_PKG_HOMEPAGE": "", + "CARGO_PKG_DESCRIPTION": "", + "CARGO_PKG_NAME": "hello-world", + "CARGO_PKG_VERSION_PATCH": "0", + "CARGO": "cargo", + "CARGO_PKG_REPOSITORY": "", + "CARGO_PKG_VERSION_MINOR": "1", + "CARGO_PKG_VERSION_PRE": "", + }, + }, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "hello_world", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", + ), + }, + is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, + }, + 3: CrateData { + root_file_id: FileId( + 4, + ), + edition: Edition2018, + version: Some( + "0.1.0", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "it", + ), + canonical_name: "it", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "test", + ], + ), + potential_cfg_options: None, + env: Env { + entries: { + "CARGO_PKG_LICENSE": "", + "CARGO_PKG_VERSION_MAJOR": "0", + "CARGO_MANIFEST_DIR": "$ROOT$hello-world", + "CARGO_PKG_VERSION": "0.1.0", + "CARGO_PKG_AUTHORS": "", + "CARGO_CRATE_NAME": "hello_world", + "CARGO_PKG_LICENSE_FILE": "", + "CARGO_PKG_HOMEPAGE": "", + "CARGO_PKG_DESCRIPTION": "", + "CARGO_PKG_NAME": "hello-world", + "CARGO_PKG_VERSION_PATCH": "0", + "CARGO": "cargo", + "CARGO_PKG_REPOSITORY": "", + "CARGO_PKG_VERSION_MINOR": "1", + "CARGO_PKG_VERSION_PRE": "", + }, + }, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "hello_world", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", + ), + }, + is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, + }, + 4: CrateData { + root_file_id: FileId( + 5, + ), + edition: Edition2015, + version: Some( + "0.2.98", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "libc", + ), + canonical_name: "libc", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "feature=default", + "feature=std", + ], + ), + potential_cfg_options: Some( + CfgOptions( + [ + "debug_assertions", + "feature=align", + "feature=const-extern-fn", + "feature=default", + "feature=extra_traits", + "feature=rustc-dep-of-std", + "feature=std", + "feature=use_std", + ], + ), + ), + env: Env { + entries: { + "CARGO_PKG_LICENSE": "", + "CARGO_PKG_VERSION_MAJOR": "0", + "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", + "CARGO_PKG_VERSION": "0.2.98", + "CARGO_PKG_AUTHORS": "", + "CARGO_CRATE_NAME": "libc", + "CARGO_PKG_LICENSE_FILE": "", + "CARGO_PKG_HOMEPAGE": "", + "CARGO_PKG_DESCRIPTION": "", + "CARGO_PKG_NAME": "libc", + "CARGO_PKG_VERSION_PATCH": "98", + "CARGO": "cargo", + "CARGO_PKG_REPOSITORY": "", + "CARGO_PKG_VERSION_MINOR": "2", + "CARGO_PKG_VERSION_PRE": "", + }, + }, + dependencies: [], + origin: Library { + repo: Some( + "https://github.com/rust-lang/libc", + ), + name: "libc", + }, + is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, + }, +} \ No newline at end of file diff --git a/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt new file mode 100644 index 0000000000000..e595cd827293e --- /dev/null +++ b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt @@ -0,0 +1,344 @@ +{ + 0: CrateData { + root_file_id: FileId( + 1, + ), + edition: Edition2018, + version: Some( + "0.1.0", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "hello_world", + ), + canonical_name: "hello-world", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "test", + ], + ), + potential_cfg_options: None, + env: Env { + entries: { + "CARGO_PKG_LICENSE": "", + "CARGO_PKG_VERSION_MAJOR": "0", + "CARGO_MANIFEST_DIR": "$ROOT$hello-world", + "CARGO_PKG_VERSION": "0.1.0", + "CARGO_PKG_AUTHORS": "", + "CARGO_CRATE_NAME": "hello_world", + "CARGO_PKG_LICENSE_FILE": "", + "CARGO_PKG_HOMEPAGE": "", + "CARGO_PKG_DESCRIPTION": "", + "CARGO_PKG_NAME": "hello-world", + "CARGO_PKG_VERSION_PATCH": "0", + "CARGO": "cargo", + "CARGO_PKG_REPOSITORY": "", + "CARGO_PKG_VERSION_MINOR": "1", + "CARGO_PKG_VERSION_PRE": "", + }, + }, + dependencies: [ + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", + ), + }, + is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, + }, + 1: CrateData { + root_file_id: FileId( + 2, + ), + edition: Edition2018, + version: Some( + "0.1.0", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "hello_world", + ), + canonical_name: "hello-world", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "test", + ], + ), + potential_cfg_options: None, + env: Env { + entries: { + "CARGO_PKG_LICENSE": "", + "CARGO_PKG_VERSION_MAJOR": "0", + "CARGO_MANIFEST_DIR": "$ROOT$hello-world", + "CARGO_PKG_VERSION": "0.1.0", + "CARGO_PKG_AUTHORS": "", + "CARGO_CRATE_NAME": "hello_world", + "CARGO_PKG_LICENSE_FILE": "", + "CARGO_PKG_HOMEPAGE": "", + "CARGO_PKG_DESCRIPTION": "", + "CARGO_PKG_NAME": "hello-world", + "CARGO_PKG_VERSION_PATCH": "0", + "CARGO": "cargo", + "CARGO_PKG_REPOSITORY": "", + "CARGO_PKG_VERSION_MINOR": "1", + "CARGO_PKG_VERSION_PRE": "", + }, + }, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "hello_world", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", + ), + }, + is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, + }, + 2: CrateData { + root_file_id: FileId( + 3, + ), + edition: Edition2018, + version: Some( + "0.1.0", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "an_example", + ), + canonical_name: "an-example", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "test", + ], + ), + potential_cfg_options: None, + env: Env { + entries: { + "CARGO_PKG_LICENSE": "", + "CARGO_PKG_VERSION_MAJOR": "0", + "CARGO_MANIFEST_DIR": "$ROOT$hello-world", + "CARGO_PKG_VERSION": "0.1.0", + "CARGO_PKG_AUTHORS": "", + "CARGO_CRATE_NAME": "hello_world", + "CARGO_PKG_LICENSE_FILE": "", + "CARGO_PKG_HOMEPAGE": "", + "CARGO_PKG_DESCRIPTION": "", + "CARGO_PKG_NAME": "hello-world", + "CARGO_PKG_VERSION_PATCH": "0", + "CARGO": "cargo", + "CARGO_PKG_REPOSITORY": "", + "CARGO_PKG_VERSION_MINOR": "1", + "CARGO_PKG_VERSION_PRE": "", + }, + }, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "hello_world", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", + ), + }, + is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, + }, + 3: CrateData { + root_file_id: FileId( + 4, + ), + edition: Edition2018, + version: Some( + "0.1.0", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "it", + ), + canonical_name: "it", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "test", + ], + ), + potential_cfg_options: None, + env: Env { + entries: { + "CARGO_PKG_LICENSE": "", + "CARGO_PKG_VERSION_MAJOR": "0", + "CARGO_MANIFEST_DIR": "$ROOT$hello-world", + "CARGO_PKG_VERSION": "0.1.0", + "CARGO_PKG_AUTHORS": "", + "CARGO_CRATE_NAME": "hello_world", + "CARGO_PKG_LICENSE_FILE": "", + "CARGO_PKG_HOMEPAGE": "", + "CARGO_PKG_DESCRIPTION": "", + "CARGO_PKG_NAME": "hello-world", + "CARGO_PKG_VERSION_PATCH": "0", + "CARGO": "cargo", + "CARGO_PKG_REPOSITORY": "", + "CARGO_PKG_VERSION_MINOR": "1", + "CARGO_PKG_VERSION_PRE": "", + }, + }, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "hello_world", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", + ), + }, + is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, + }, + 4: CrateData { + root_file_id: FileId( + 5, + ), + edition: Edition2015, + version: Some( + "0.2.98", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "libc", + ), + canonical_name: "libc", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "feature=default", + "feature=std", + ], + ), + potential_cfg_options: Some( + CfgOptions( + [ + "debug_assertions", + "feature=align", + "feature=const-extern-fn", + "feature=default", + "feature=extra_traits", + "feature=rustc-dep-of-std", + "feature=std", + "feature=use_std", + ], + ), + ), + env: Env { + entries: { + "CARGO_PKG_LICENSE": "", + "CARGO_PKG_VERSION_MAJOR": "0", + "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", + "CARGO_PKG_VERSION": "0.2.98", + "CARGO_PKG_AUTHORS": "", + "CARGO_CRATE_NAME": "libc", + "CARGO_PKG_LICENSE_FILE": "", + "CARGO_PKG_HOMEPAGE": "", + "CARGO_PKG_DESCRIPTION": "", + "CARGO_PKG_NAME": "libc", + "CARGO_PKG_VERSION_PATCH": "98", + "CARGO": "cargo", + "CARGO_PKG_REPOSITORY": "", + "CARGO_PKG_VERSION_MINOR": "2", + "CARGO_PKG_VERSION_PRE": "", + }, + }, + dependencies: [], + origin: Library { + repo: Some( + "https://github.com/rust-lang/libc", + ), + name: "libc", + }, + is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, + }, +} \ No newline at end of file diff --git a/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt new file mode 100644 index 0000000000000..f10c55d0462a2 --- /dev/null +++ b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt @@ -0,0 +1,340 @@ +{ + 0: CrateData { + root_file_id: FileId( + 1, + ), + edition: Edition2018, + version: Some( + "0.1.0", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "hello_world", + ), + canonical_name: "hello-world", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + ], + ), + potential_cfg_options: None, + env: Env { + entries: { + "CARGO_PKG_LICENSE": "", + "CARGO_PKG_VERSION_MAJOR": "0", + "CARGO_MANIFEST_DIR": "$ROOT$hello-world", + "CARGO_PKG_VERSION": "0.1.0", + "CARGO_PKG_AUTHORS": "", + "CARGO_CRATE_NAME": "hello_world", + "CARGO_PKG_LICENSE_FILE": "", + "CARGO_PKG_HOMEPAGE": "", + "CARGO_PKG_DESCRIPTION": "", + "CARGO_PKG_NAME": "hello-world", + "CARGO_PKG_VERSION_PATCH": "0", + "CARGO": "cargo", + "CARGO_PKG_REPOSITORY": "", + "CARGO_PKG_VERSION_MINOR": "1", + "CARGO_PKG_VERSION_PRE": "", + }, + }, + dependencies: [ + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", + ), + }, + is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, + }, + 1: CrateData { + root_file_id: FileId( + 2, + ), + edition: Edition2018, + version: Some( + "0.1.0", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "hello_world", + ), + canonical_name: "hello-world", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + ], + ), + potential_cfg_options: None, + env: Env { + entries: { + "CARGO_PKG_LICENSE": "", + "CARGO_PKG_VERSION_MAJOR": "0", + "CARGO_MANIFEST_DIR": "$ROOT$hello-world", + "CARGO_PKG_VERSION": "0.1.0", + "CARGO_PKG_AUTHORS": "", + "CARGO_CRATE_NAME": "hello_world", + "CARGO_PKG_LICENSE_FILE": "", + "CARGO_PKG_HOMEPAGE": "", + "CARGO_PKG_DESCRIPTION": "", + "CARGO_PKG_NAME": "hello-world", + "CARGO_PKG_VERSION_PATCH": "0", + "CARGO": "cargo", + "CARGO_PKG_REPOSITORY": "", + "CARGO_PKG_VERSION_MINOR": "1", + "CARGO_PKG_VERSION_PRE": "", + }, + }, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "hello_world", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", + ), + }, + is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, + }, + 2: CrateData { + root_file_id: FileId( + 3, + ), + edition: Edition2018, + version: Some( + "0.1.0", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "an_example", + ), + canonical_name: "an-example", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + ], + ), + potential_cfg_options: None, + env: Env { + entries: { + "CARGO_PKG_LICENSE": "", + "CARGO_PKG_VERSION_MAJOR": "0", + "CARGO_MANIFEST_DIR": "$ROOT$hello-world", + "CARGO_PKG_VERSION": "0.1.0", + "CARGO_PKG_AUTHORS": "", + "CARGO_CRATE_NAME": "hello_world", + "CARGO_PKG_LICENSE_FILE": "", + "CARGO_PKG_HOMEPAGE": "", + "CARGO_PKG_DESCRIPTION": "", + "CARGO_PKG_NAME": "hello-world", + "CARGO_PKG_VERSION_PATCH": "0", + "CARGO": "cargo", + "CARGO_PKG_REPOSITORY": "", + "CARGO_PKG_VERSION_MINOR": "1", + "CARGO_PKG_VERSION_PRE": "", + }, + }, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "hello_world", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", + ), + }, + is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, + }, + 3: CrateData { + root_file_id: FileId( + 4, + ), + edition: Edition2018, + version: Some( + "0.1.0", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "it", + ), + canonical_name: "it", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + ], + ), + potential_cfg_options: None, + env: Env { + entries: { + "CARGO_PKG_LICENSE": "", + "CARGO_PKG_VERSION_MAJOR": "0", + "CARGO_MANIFEST_DIR": "$ROOT$hello-world", + "CARGO_PKG_VERSION": "0.1.0", + "CARGO_PKG_AUTHORS": "", + "CARGO_CRATE_NAME": "hello_world", + "CARGO_PKG_LICENSE_FILE": "", + "CARGO_PKG_HOMEPAGE": "", + "CARGO_PKG_DESCRIPTION": "", + "CARGO_PKG_NAME": "hello-world", + "CARGO_PKG_VERSION_PATCH": "0", + "CARGO": "cargo", + "CARGO_PKG_REPOSITORY": "", + "CARGO_PKG_VERSION_MINOR": "1", + "CARGO_PKG_VERSION_PRE": "", + }, + }, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "hello_world", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", + ), + }, + is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, + }, + 4: CrateData { + root_file_id: FileId( + 5, + ), + edition: Edition2015, + version: Some( + "0.2.98", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "libc", + ), + canonical_name: "libc", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "feature=default", + "feature=std", + ], + ), + potential_cfg_options: Some( + CfgOptions( + [ + "debug_assertions", + "feature=align", + "feature=const-extern-fn", + "feature=default", + "feature=extra_traits", + "feature=rustc-dep-of-std", + "feature=std", + "feature=use_std", + ], + ), + ), + env: Env { + entries: { + "CARGO_PKG_LICENSE": "", + "CARGO_PKG_VERSION_MAJOR": "0", + "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", + "CARGO_PKG_VERSION": "0.2.98", + "CARGO_PKG_AUTHORS": "", + "CARGO_CRATE_NAME": "libc", + "CARGO_PKG_LICENSE_FILE": "", + "CARGO_PKG_HOMEPAGE": "", + "CARGO_PKG_DESCRIPTION": "", + "CARGO_PKG_NAME": "libc", + "CARGO_PKG_VERSION_PATCH": "98", + "CARGO": "cargo", + "CARGO_PKG_REPOSITORY": "", + "CARGO_PKG_VERSION_MINOR": "2", + "CARGO_PKG_VERSION_PRE": "", + }, + }, + dependencies: [], + origin: Library { + repo: Some( + "https://github.com/rust-lang/libc", + ), + name: "libc", + }, + is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, + }, +} \ No newline at end of file diff --git a/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt new file mode 100644 index 0000000000000..fb3f5933b178c --- /dev/null +++ b/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt @@ -0,0 +1,462 @@ +{ + 0: CrateData { + root_file_id: FileId( + 1, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "alloc", + ), + canonical_name: "alloc", + }, + ), + cfg_options: CfgOptions( + [], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [ + Dependency { + crate_id: Idx::(1), + name: CrateName( + "core", + ), + prelude: true, + }, + ], + origin: Lang( + Alloc, + ), + is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, + }, + 1: CrateData { + root_file_id: FileId( + 2, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "core", + ), + canonical_name: "core", + }, + ), + cfg_options: CfgOptions( + [], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [], + origin: Lang( + Core, + ), + is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, + }, + 2: CrateData { + root_file_id: FileId( + 3, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "panic_abort", + ), + canonical_name: "panic_abort", + }, + ), + cfg_options: CfgOptions( + [], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, + }, + 3: CrateData { + root_file_id: FileId( + 4, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "panic_unwind", + ), + canonical_name: "panic_unwind", + }, + ), + cfg_options: CfgOptions( + [], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, + }, + 4: CrateData { + root_file_id: FileId( + 5, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "proc_macro", + ), + canonical_name: "proc_macro", + }, + ), + cfg_options: CfgOptions( + [], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [ + Dependency { + crate_id: Idx::(6), + name: CrateName( + "std", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(1), + name: CrateName( + "core", + ), + prelude: true, + }, + ], + origin: Lang( + Other, + ), + is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, + }, + 5: CrateData { + root_file_id: FileId( + 6, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "profiler_builtins", + ), + canonical_name: "profiler_builtins", + }, + ), + cfg_options: CfgOptions( + [], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, + }, + 6: CrateData { + root_file_id: FileId( + 7, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "std", + ), + canonical_name: "std", + }, + ), + cfg_options: CfgOptions( + [], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "alloc", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(3), + name: CrateName( + "panic_unwind", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(2), + name: CrateName( + "panic_abort", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(1), + name: CrateName( + "core", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(5), + name: CrateName( + "profiler_builtins", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(9), + name: CrateName( + "unwind", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(7), + name: CrateName( + "std_detect", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(8), + name: CrateName( + "test", + ), + prelude: true, + }, + ], + origin: Lang( + Std, + ), + is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, + }, + 7: CrateData { + root_file_id: FileId( + 8, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "std_detect", + ), + canonical_name: "std_detect", + }, + ), + cfg_options: CfgOptions( + [], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, + }, + 8: CrateData { + root_file_id: FileId( + 9, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "test", + ), + canonical_name: "test", + }, + ), + cfg_options: CfgOptions( + [], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [], + origin: Lang( + Test, + ), + is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, + }, + 9: CrateData { + root_file_id: FileId( + 10, + ), + edition: Edition2021, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "unwind", + ), + canonical_name: "unwind", + }, + ), + cfg_options: CfgOptions( + [], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, + }, + 10: CrateData { + root_file_id: FileId( + 11, + ), + edition: Edition2018, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "hello_world", + ), + canonical_name: "hello_world", + }, + ), + cfg_options: CfgOptions( + [], + ), + potential_cfg_options: None, + env: Env { + entries: {}, + }, + dependencies: [ + Dependency { + crate_id: Idx::(1), + name: CrateName( + "core", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(0), + name: CrateName( + "alloc", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(6), + name: CrateName( + "std", + ), + prelude: true, + }, + Dependency { + crate_id: Idx::(8), + name: CrateName( + "test", + ), + prelude: false, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "proc_macro", + ), + prelude: false, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello_world", + ), + }, + is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, + }, +} \ No newline at end of file diff --git a/crates/project-model/test_data/regex-metadata.json b/crates/project-model/test_data/regex-metadata.json new file mode 100644 index 0000000000000..371464dd20aa1 --- /dev/null +++ b/crates/project-model/test_data/regex-metadata.json @@ -0,0 +1,6420 @@ +{ + "packages": [ + { + "name": "aho-corasick", + "version": "0.7.20", + "id": "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "Unlicense OR MIT", + "license_file": null, + "description": "Fast multiple substring searching.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "memchr", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2.4.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "aho_corasick", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/aho-corasick-0.7.20/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": { + "default": [ + "std" + ], + "std": [ + "memchr/std" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/aho-corasick-0.7.20/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [ + "text-processing" + ], + "keywords": [ + "string", + "search", + "text", + "aho", + "multi" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/aho-corasick", + "homepage": "https://github.com/BurntSushi/aho-corasick", + "documentation": null, + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "cc", + "version": "1.0.79", + "id": "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "A build-time dependency for Cargo build scripts to assist in invoking the native\nC compiler to compile native C code into a static archive to be linked into Rust\ncode.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "jobserver", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1.16", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "tempfile", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "cc", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "bin" + ], + "crate_types": [ + "bin" + ], + "name": "gcc-shim", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/src/bin/gcc-shim.rs", + "edition": "2018", + "doc": true, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "cc_env", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/tests/cc_env.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "cflags", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/tests/cflags.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "cxxflags", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/tests/cxxflags.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/tests/test.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + } + ], + "features": { + "jobserver": [ + "dep:jobserver" + ], + "parallel": [ + "jobserver" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Alex Crichton " + ], + "categories": [ + "development-tools::build-utils" + ], + "keywords": [ + "build-dependencies" + ], + "readme": "README.md", + "repository": "https://github.com/rust-lang/cc-rs", + "homepage": "https://github.com/rust-lang/cc-rs", + "documentation": "https://docs.rs/cc", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "cfg-if", + "version": "0.1.10", + "id": "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT/Apache-2.0", + "license_file": null, + "description": "A macro to ergonomically define an item depending on a large number of #[cfg]\nparameters. Structured like an if-else chain, the first matching branch is the\nitem that gets emitted.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "compiler_builtins", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1.2", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustc-std-workspace-core", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.0", + "kind": null, + "rename": "core", + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "cfg-if", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cfg-if-0.1.10/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "xcrate", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cfg-if-0.1.10/tests/xcrate.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + } + ], + "features": { + "compiler_builtins": [ + "dep:compiler_builtins" + ], + "core": [ + "dep:core" + ], + "rustc-dep-of-std": [ + "core", + "compiler_builtins" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cfg-if-0.1.10/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Alex Crichton " + ], + "categories": [], + "keywords": [], + "readme": "README.md", + "repository": "https://github.com/alexcrichton/cfg-if", + "homepage": "https://github.com/alexcrichton/cfg-if", + "documentation": "https://docs.rs/cfg-if", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "cfg-if", + "version": "1.0.0", + "id": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT/Apache-2.0", + "license_file": null, + "description": "A macro to ergonomically define an item depending on a large number of #[cfg]\nparameters. Structured like an if-else chain, the first matching branch is the\nitem that gets emitted.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "compiler_builtins", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1.2", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustc-std-workspace-core", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.0", + "kind": null, + "rename": "core", + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "cfg-if", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cfg-if-1.0.0/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "xcrate", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cfg-if-1.0.0/tests/xcrate.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + } + ], + "features": { + "compiler_builtins": [ + "dep:compiler_builtins" + ], + "core": [ + "dep:core" + ], + "rustc-dep-of-std": [ + "core", + "compiler_builtins" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cfg-if-1.0.0/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Alex Crichton " + ], + "categories": [], + "keywords": [], + "readme": "README.md", + "repository": "https://github.com/alexcrichton/cfg-if", + "homepage": "https://github.com/alexcrichton/cfg-if", + "documentation": "https://docs.rs/cfg-if", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "docopt", + "version": "1.1.1", + "id": "docopt 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "Unlicense/MIT", + "license_file": null, + "description": "Command line argument parsing.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "lazy_static", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.3", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.4.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [ + "std", + "unicode" + ], + "target": null, + "registry": null + }, + { + "name": "serde", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [ + "derive" + ], + "target": null, + "registry": null + }, + { + "name": "strsim", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.10", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "docopt", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/docopt-1.1.1/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "bin" + ], + "crate_types": [ + "bin" + ], + "name": "docopt-wordlist", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/docopt-1.1.1/src/wordlist.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "cargo", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/docopt-1.1.1/examples/cargo.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "cp", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/docopt-1.1.1/examples/cp.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "decode", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/docopt-1.1.1/examples/decode.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "hashmap", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/docopt-1.1.1/examples/hashmap.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "optional_command", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/docopt-1.1.1/examples/optional_command.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "verbose_multiple", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/docopt-1.1.1/examples/verbose_multiple.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/docopt-1.1.1/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [ + "command-line-interface" + ], + "keywords": [ + "docopt", + "argument", + "command", + "argv" + ], + "readme": "README.md", + "repository": "https://github.com/docopt/docopt.rs", + "homepage": "https://github.com/docopt/docopt.rs", + "documentation": "http://burntsushi.net/rustdoc/docopt/", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "getrandom", + "version": "0.2.9", + "id": "getrandom 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "A small cross-platform library for retrieving random data from system source", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "cfg-if", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "compiler_builtins", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustc-std-workspace-core", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": "core", + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "js-sys", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": "cfg(all(any(target_arch = \"wasm32\", target_arch = \"wasm64\"), target_os = \"unknown\"))", + "registry": null + }, + { + "name": "wasm-bindgen", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2.62", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": false, + "features": [], + "target": "cfg(all(any(target_arch = \"wasm32\", target_arch = \"wasm64\"), target_os = \"unknown\"))", + "registry": null + }, + { + "name": "wasm-bindgen-test", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3.18", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": "cfg(all(any(target_arch = \"wasm32\", target_arch = \"wasm64\"), target_os = \"unknown\"))", + "registry": null + }, + { + "name": "wasi", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.11", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": "cfg(target_os = \"wasi\")", + "registry": null + }, + { + "name": "libc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2.139", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": "cfg(unix)", + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "getrandom", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/getrandom-0.2.9/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "custom", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/getrandom-0.2.9/tests/custom.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "normal", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/getrandom-0.2.9/tests/normal.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "rdrand", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/getrandom-0.2.9/tests/rdrand.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "buffer", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/getrandom-0.2.9/benches/buffer.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "compiler_builtins": [ + "dep:compiler_builtins" + ], + "core": [ + "dep:core" + ], + "custom": [], + "js": [ + "wasm-bindgen", + "js-sys" + ], + "js-sys": [ + "dep:js-sys" + ], + "rdrand": [], + "rustc-dep-of-std": [ + "compiler_builtins", + "core", + "libc/rustc-dep-of-std", + "wasi/rustc-dep-of-std" + ], + "std": [], + "test-in-browser": [], + "wasm-bindgen": [ + "dep:wasm-bindgen" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/getrandom-0.2.9/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "features": [ + "std", + "custom" + ], + "rustdoc-args": [ + "--cfg", + "docsrs" + ] + } + } + }, + "publish": null, + "authors": [ + "The Rand Project Developers" + ], + "categories": [ + "os", + "no-std" + ], + "keywords": [], + "readme": "README.md", + "repository": "https://github.com/rust-random/getrandom", + "homepage": null, + "documentation": "https://docs.rs/getrandom", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "lazy_static", + "version": "1.4.0", + "id": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT/Apache-2.0", + "license_file": null, + "description": "A macro for declaring lazily evaluated statics in Rust.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "spin", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.5.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "doc-comment", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3.1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "lazy_static", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/lazy_static-1.4.0/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "no_std", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/lazy_static-1.4.0/tests/no_std.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/lazy_static-1.4.0/tests/test.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": true + } + ], + "features": { + "spin": [ + "dep:spin" + ], + "spin_no_std": [ + "spin" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/lazy_static-1.4.0/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Marvin Löbel " + ], + "categories": [ + "no-std", + "rust-patterns", + "memory-management" + ], + "keywords": [ + "macro", + "lazy", + "static" + ], + "readme": "README.md", + "repository": "https://github.com/rust-lang-nursery/lazy-static.rs", + "homepage": null, + "documentation": "https://docs.rs/lazy_static", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "libc", + "version": "0.2.142", + "id": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "Raw FFI bindings to platform libraries like libc.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "rustc-std-workspace-core", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "libc", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/libc-0.2.142/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "const_fn", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/libc-0.2.142/tests/const_fn.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/libc-0.2.142/build.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "align": [], + "const-extern-fn": [], + "default": [ + "std" + ], + "extra_traits": [], + "rustc-dep-of-std": [ + "align", + "rustc-std-workspace-core" + ], + "rustc-std-workspace-core": [ + "dep:rustc-std-workspace-core" + ], + "std": [], + "use_std": [ + "std" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/libc-0.2.142/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "features": [ + "const-extern-fn", + "extra_traits" + ] + } + } + }, + "publish": null, + "authors": [ + "The Rust Project Developers" + ], + "categories": [ + "external-ffi-bindings", + "no-std", + "os" + ], + "keywords": [ + "libc", + "ffi", + "bindings", + "operating", + "system" + ], + "readme": "README.md", + "repository": "https://github.com/rust-lang/libc", + "homepage": "https://github.com/rust-lang/libc", + "documentation": "https://docs.rs/libc/", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "memchr", + "version": "2.5.0", + "id": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "Unlicense/MIT", + "license_file": null, + "description": "Safe interface to memchr.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "compiler_builtins", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1.2", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustc-std-workspace-core", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.0", + "kind": null, + "rename": "core", + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "libc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2.18", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "quickcheck", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "memchr", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memchr-2.5.0/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memchr-2.5.0/build.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "compiler_builtins": [ + "dep:compiler_builtins" + ], + "core": [ + "dep:core" + ], + "default": [ + "std" + ], + "libc": [ + "dep:libc" + ], + "rustc-dep-of-std": [ + "core", + "compiler_builtins" + ], + "std": [], + "use_std": [ + "std" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memchr-2.5.0/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant ", + "bluss" + ], + "categories": [], + "keywords": [ + "memchr", + "char", + "scan", + "strchr", + "string" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/memchr", + "homepage": "https://github.com/BurntSushi/memchr", + "documentation": "https://docs.rs/memchr/", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "memmap", + "version": "0.6.2", + "id": "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT/Apache-2.0", + "license_file": null, + "description": "Cross-platform Rust API for memory-mapped file IO", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "tempdir", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "libc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": "cfg(unix)", + "registry": null + }, + { + "name": "winapi", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [ + "basetsd", + "handleapi", + "memoryapi", + "minwindef", + "std", + "sysinfoapi" + ], + "target": "cfg(windows)", + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "memmap", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memmap-0.6.2/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "cat", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memmap-0.6.2/examples/cat.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memmap-0.6.2/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Dan Burkert " + ], + "categories": [], + "keywords": [ + "mmap", + "memory-map", + "io", + "file" + ], + "readme": "README.md", + "repository": "https://github.com/danburkert/memmap-rs", + "homepage": null, + "documentation": "https://docs.rs/memmap", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "pkg-config", + "version": "0.3.26", + "id": "pkg-config 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "A library to run the pkg-config system tool at build time in order to be used in\nCargo build scripts.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "lazy_static", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "pkg-config", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pkg-config-0.3.26/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pkg-config-0.3.26/tests/test.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pkg-config-0.3.26/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Alex Crichton " + ], + "categories": [], + "keywords": [ + "build-dependencies" + ], + "readme": "README.md", + "repository": "https://github.com/rust-lang/pkg-config-rs", + "homepage": null, + "documentation": "https://docs.rs/pkg-config", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "proc-macro2", + "version": "1.0.56", + "id": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "A substitute implementation of the compiler's `proc_macro` API to decouple token-based libraries from the procedural macro use case.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "unicode-ident", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "quote", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustversion", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "proc-macro2", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "comments", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/comments.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "features", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/features.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "marker", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/marker.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/test.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_fmt", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/test_fmt.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_size", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/test_size.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/build.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "default": [ + "proc-macro" + ], + "nightly": [], + "proc-macro": [], + "span-locations": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "rustc-args": [ + "--cfg", + "procmacro2_semver_exempt" + ], + "rustdoc-args": [ + "--cfg", + "procmacro2_semver_exempt", + "--cfg", + "doc_cfg" + ], + "targets": [ + "x86_64-unknown-linux-gnu" + ] + } + }, + "playground": { + "features": [ + "span-locations" + ] + } + }, + "publish": null, + "authors": [ + "David Tolnay ", + "Alex Crichton " + ], + "categories": [ + "development-tools::procedural-macro-helpers" + ], + "keywords": [ + "macros", + "syn" + ], + "readme": "README.md", + "repository": "https://github.com/dtolnay/proc-macro2", + "homepage": null, + "documentation": "https://docs.rs/proc-macro2", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": "1.31" + }, + { + "name": "quickcheck", + "version": "1.0.3", + "id": "quickcheck 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "Unlicense/MIT", + "license_file": null, + "description": "Automatic property based testing with shrinking.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "env_logger", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.8.2", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "log", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rand", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.8", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [ + "getrandom", + "small_rng" + ], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "quickcheck", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quickcheck-1.0.3/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "btree_set_range", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quickcheck-1.0.3/examples/btree_set_range.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "out_of_bounds", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quickcheck-1.0.3/examples/out_of_bounds.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "reverse", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quickcheck-1.0.3/examples/reverse.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "reverse_single", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quickcheck-1.0.3/examples/reverse_single.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "sieve", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quickcheck-1.0.3/examples/sieve.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "sort", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quickcheck-1.0.3/examples/sort.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "default": [ + "regex", + "use_logging" + ], + "env_logger": [ + "dep:env_logger" + ], + "log": [ + "dep:log" + ], + "regex": [ + "env_logger/regex" + ], + "use_logging": [ + "log", + "env_logger" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quickcheck-1.0.3/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [ + "development-tools::testing" + ], + "keywords": [ + "testing", + "quickcheck", + "property", + "shrinking", + "fuzz" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/quickcheck", + "homepage": "https://github.com/BurntSushi/quickcheck", + "documentation": "https://docs.rs/quickcheck", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "quote", + "version": "1.0.26", + "id": "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "Quasi-quoting macro quote!(...)", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "proc-macro2", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.52", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustversion", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "trybuild", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.66", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [ + "diff" + ], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "quote", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "compiletest", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/tests/compiletest.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/tests/test.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/build.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "default": [ + "proc-macro" + ], + "proc-macro": [ + "proc-macro2/proc-macro" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "targets": [ + "x86_64-unknown-linux-gnu" + ] + } + } + }, + "publish": null, + "authors": [ + "David Tolnay " + ], + "categories": [ + "development-tools::procedural-macro-helpers" + ], + "keywords": [ + "macros", + "syn" + ], + "readme": "README.md", + "repository": "https://github.com/dtolnay/quote", + "homepage": null, + "documentation": "https://docs.rs/quote/", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": "1.31" + }, + { + "name": "rand", + "version": "0.8.5", + "id": "rand 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "Random number generators and other randomness functionality.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "log", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4.4", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "packed_simd_2", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3.7", + "kind": null, + "rename": "packed_simd", + "optional": true, + "uses_default_features": true, + "features": [ + "into_bits" + ], + "target": null, + "registry": null + }, + { + "name": "rand_chacha", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rand_core", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.6.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.103", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [ + "derive" + ], + "target": null, + "registry": null + }, + { + "name": "bincode", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.2.1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rand_pcg", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "libc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2.22", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": false, + "features": [], + "target": "cfg(unix)", + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "rand", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/rand-0.8.5/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": { + "alloc": [ + "rand_core/alloc" + ], + "default": [ + "std", + "std_rng" + ], + "getrandom": [ + "rand_core/getrandom" + ], + "libc": [ + "dep:libc" + ], + "log": [ + "dep:log" + ], + "min_const_gen": [], + "nightly": [], + "packed_simd": [ + "dep:packed_simd" + ], + "rand_chacha": [ + "dep:rand_chacha" + ], + "serde": [ + "dep:serde" + ], + "serde1": [ + "serde", + "rand_core/serde1" + ], + "simd_support": [ + "packed_simd" + ], + "small_rng": [], + "std": [ + "rand_core/std", + "rand_chacha/std", + "alloc", + "getrandom", + "libc" + ], + "std_rng": [ + "rand_chacha" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/rand-0.8.5/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "all-features": true, + "rustdoc-args": [ + "--cfg", + "doc_cfg" + ] + } + }, + "playground": { + "features": [ + "small_rng", + "serde1" + ] + } + }, + "publish": null, + "authors": [ + "The Rand Project Developers", + "The Rust Project Developers" + ], + "categories": [ + "algorithms", + "no-std" + ], + "keywords": [ + "random", + "rng" + ], + "readme": "README.md", + "repository": "https://github.com/rust-random/rand", + "homepage": "https://rust-random.github.io/book", + "documentation": "https://docs.rs/rand", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "rand_core", + "version": "0.6.4", + "id": "rand_core 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "Core random number generator traits and tools for implementation.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "getrandom", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [ + "derive" + ], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "rand_core", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/rand_core-0.6.4/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": { + "alloc": [], + "getrandom": [ + "dep:getrandom" + ], + "serde": [ + "dep:serde" + ], + "serde1": [ + "serde" + ], + "std": [ + "alloc", + "getrandom", + "getrandom/std" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/rand_core-0.6.4/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "all-features": true, + "rustdoc-args": [ + "--cfg", + "doc_cfg" + ] + } + }, + "playground": { + "all-features": true + } + }, + "publish": null, + "authors": [ + "The Rand Project Developers", + "The Rust Project Developers" + ], + "categories": [ + "algorithms", + "no-std" + ], + "keywords": [ + "random", + "rng" + ], + "readme": "README.md", + "repository": "https://github.com/rust-random/rand", + "homepage": "https://rust-random.github.io/book", + "documentation": "https://docs.rs/rand_core", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "regex", + "version": "1.7.1", + "id": "regex 1.7.1 (path+file:///$ROOT$regex)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "An implementation of regular expressions for Rust. This implementation uses\nfinite automata and guarantees linear time matching on all inputs.\n", + "source": null, + "dependencies": [ + { + "name": "aho-corasick", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.7.18", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "memchr", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2.4.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex-syntax", + "source": null, + "req": "^0.6.27", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$regex/regex-syntax" + }, + { + "name": "lazy_static", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "quickcheck", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rand", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.8.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [ + "getrandom", + "small_rng" + ], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "regex", + "src_path": "$ROOT$regex/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": false, + "test": true + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "shootout-regex-dna-bytes", + "src_path": "$ROOT$regex/examples/shootout-regex-dna-bytes.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "shootout-regex-dna-cheat", + "src_path": "$ROOT$regex/examples/shootout-regex-dna-cheat.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "shootout-regex-dna-replace", + "src_path": "$ROOT$regex/examples/shootout-regex-dna-replace.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "shootout-regex-dna-single-cheat", + "src_path": "$ROOT$regex/examples/shootout-regex-dna-single-cheat.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "shootout-regex-dna-single", + "src_path": "$ROOT$regex/examples/shootout-regex-dna-single.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "shootout-regex-dna", + "src_path": "$ROOT$regex/examples/shootout-regex-dna.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "default", + "src_path": "$ROOT$regex/tests/test_default.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "default-bytes", + "src_path": "$ROOT$regex/tests/test_default_bytes.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "nfa", + "src_path": "$ROOT$regex/tests/test_nfa.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "nfa-utf8bytes", + "src_path": "$ROOT$regex/tests/test_nfa_utf8bytes.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "nfa-bytes", + "src_path": "$ROOT$regex/tests/test_nfa_bytes.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "backtrack", + "src_path": "$ROOT$regex/tests/test_backtrack.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "backtrack-utf8bytes", + "src_path": "$ROOT$regex/tests/test_backtrack_utf8bytes.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "backtrack-bytes", + "src_path": "$ROOT$regex/tests/test_backtrack_bytes.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "crates-regex", + "src_path": "$ROOT$regex/tests/test_crates_regex.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + } + ], + "features": { + "aho-corasick": [ + "dep:aho-corasick" + ], + "default": [ + "std", + "perf", + "unicode", + "regex-syntax/default" + ], + "memchr": [ + "dep:memchr" + ], + "pattern": [], + "perf": [ + "perf-cache", + "perf-dfa", + "perf-inline", + "perf-literal" + ], + "perf-cache": [], + "perf-dfa": [], + "perf-inline": [], + "perf-literal": [ + "aho-corasick", + "memchr" + ], + "std": [], + "unicode": [ + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment", + "regex-syntax/unicode" + ], + "unicode-age": [ + "regex-syntax/unicode-age" + ], + "unicode-bool": [ + "regex-syntax/unicode-bool" + ], + "unicode-case": [ + "regex-syntax/unicode-case" + ], + "unicode-gencat": [ + "regex-syntax/unicode-gencat" + ], + "unicode-perl": [ + "regex-syntax/unicode-perl" + ], + "unicode-script": [ + "regex-syntax/unicode-script" + ], + "unicode-segment": [ + "regex-syntax/unicode-segment" + ], + "unstable": [ + "pattern" + ], + "use_std": [ + "std" + ] + }, + "manifest_path": "$ROOT$regex/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "The Rust Project Developers" + ], + "categories": [ + "text-processing" + ], + "keywords": [], + "readme": "README.md", + "repository": "https://github.com/rust-lang/regex", + "homepage": "https://github.com/rust-lang/regex", + "documentation": "https://docs.rs/regex", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "regex", + "version": "1.8.1", + "id": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "An implementation of regular expressions for Rust. This implementation uses\nfinite automata and guarantees linear time matching on all inputs.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "aho-corasick", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "memchr", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2.5.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex-syntax", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.7.1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "lazy_static", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "quickcheck", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rand", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.8.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [ + "getrandom", + "small_rng" + ], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "regex", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": false, + "test": true + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "shootout-regex-dna-bytes", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-bytes.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "shootout-regex-dna-cheat", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-cheat.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "shootout-regex-dna-replace", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-replace.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "shootout-regex-dna-single-cheat", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-single-cheat.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "shootout-regex-dna-single", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-single.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "shootout-regex-dna", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "default", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_default.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "default-bytes", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_default_bytes.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "nfa", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_nfa.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "nfa-utf8bytes", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_nfa_utf8bytes.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "nfa-bytes", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_nfa_bytes.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "backtrack", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_backtrack.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "backtrack-utf8bytes", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_backtrack_utf8bytes.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "backtrack-bytes", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_backtrack_bytes.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "crates-regex", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_crates_regex.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + } + ], + "features": { + "aho-corasick": [ + "dep:aho-corasick" + ], + "default": [ + "std", + "perf", + "unicode", + "regex-syntax/default" + ], + "memchr": [ + "dep:memchr" + ], + "pattern": [], + "perf": [ + "perf-cache", + "perf-dfa", + "perf-inline", + "perf-literal" + ], + "perf-cache": [], + "perf-dfa": [], + "perf-inline": [], + "perf-literal": [ + "aho-corasick", + "memchr" + ], + "std": [], + "unicode": [ + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment", + "regex-syntax/unicode" + ], + "unicode-age": [ + "regex-syntax/unicode-age" + ], + "unicode-bool": [ + "regex-syntax/unicode-bool" + ], + "unicode-case": [ + "regex-syntax/unicode-case" + ], + "unicode-gencat": [ + "regex-syntax/unicode-gencat" + ], + "unicode-perl": [ + "regex-syntax/unicode-perl" + ], + "unicode-script": [ + "regex-syntax/unicode-script" + ], + "unicode-segment": [ + "regex-syntax/unicode-segment" + ], + "unstable": [ + "pattern" + ], + "use_std": [ + "std" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "The Rust Project Developers" + ], + "categories": [ + "text-processing" + ], + "keywords": [], + "readme": "README.md", + "repository": "https://github.com/rust-lang/regex", + "homepage": "https://github.com/rust-lang/regex", + "documentation": "https://docs.rs/regex", + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": "1.60.0" + }, + { + "name": "regex-benchmark", + "version": "0.1.0", + "id": "regex-benchmark 0.1.0 (path+file:///$ROOT$regex/bench)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "Regex benchmarks for Rust's and other engines.", + "source": null, + "dependencies": [ + { + "name": "cfg-if", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "docopt", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "lazy_static", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "libc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "libpcre-sys", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "memmap", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.6.2", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "onig", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^3", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex", + "source": null, + "req": "^1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$regex" + }, + { + "name": "regex-syntax", + "source": null, + "req": "^0.6", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$regex/regex-syntax" + }, + { + "name": "serde", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [ + "derive" + ], + "target": null, + "registry": null + }, + { + "name": "cc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "build", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "pkg-config", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3.9", + "kind": "build", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "bin" + ], + "crate_types": [ + "bin" + ], + "name": "regex-run-one", + "src_path": "$ROOT$regex/bench/src/main.rs", + "edition": "2018", + "doc": true, + "doctest": false, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "bench", + "src_path": "$ROOT$regex/bench/src/bench.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$regex/bench/build.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "libpcre-sys": [ + "dep:libpcre-sys" + ], + "onig": [ + "dep:onig" + ], + "re-onig": [ + "onig" + ], + "re-pcre1": [ + "libpcre-sys" + ], + "re-pcre2": [], + "re-re2": [], + "re-rust": [], + "re-rust-bytes": [], + "re-tcl": [] + }, + "manifest_path": "$ROOT$regex/bench/Cargo.toml", + "metadata": null, + "publish": [], + "authors": [ + "The Rust Project Developers" + ], + "categories": [], + "keywords": [], + "readme": null, + "repository": "https://github.com/rust-lang/regex", + "homepage": "https://github.com/rust-lang/regex", + "documentation": "https://docs.rs/regex", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "regex-debug", + "version": "0.1.0", + "id": "regex-debug 0.1.0 (path+file:///$ROOT$regex/regex-debug)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "A tool useful for debugging regular expressions.", + "source": null, + "dependencies": [ + { + "name": "docopt", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex", + "source": null, + "req": "^1.1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$regex" + }, + { + "name": "regex-syntax", + "source": null, + "req": "^0.6", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$regex/regex-syntax" + }, + { + "name": "serde", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [ + "derive" + ], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "bin" + ], + "crate_types": [ + "bin" + ], + "name": "regex-debug", + "src_path": "$ROOT$regex/regex-debug/src/main.rs", + "edition": "2018", + "doc": true, + "doctest": false, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$regex/regex-debug/Cargo.toml", + "metadata": null, + "publish": [], + "authors": [ + "The Rust Project Developers" + ], + "categories": [], + "keywords": [], + "readme": null, + "repository": "https://github.com/rust-lang/regex", + "homepage": "https://github.com/rust-lang/regex", + "documentation": "https://docs.rs/regex", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "regex-syntax", + "version": "0.6.28", + "id": "regex-syntax 0.6.28 (path+file:///$ROOT$regex/regex-syntax)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "A regular expression parser.", + "source": null, + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "regex-syntax", + "src_path": "$ROOT$regex/regex-syntax/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "bench", + "src_path": "$ROOT$regex/regex-syntax/benches/bench.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "default": [ + "unicode" + ], + "unicode": [ + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment" + ], + "unicode-age": [], + "unicode-bool": [], + "unicode-case": [], + "unicode-gencat": [], + "unicode-perl": [], + "unicode-script": [], + "unicode-segment": [] + }, + "manifest_path": "$ROOT$regex/regex-syntax/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "The Rust Project Developers" + ], + "categories": [], + "keywords": [], + "readme": "README.md", + "repository": "https://github.com/rust-lang/regex", + "homepage": "https://github.com/rust-lang/regex", + "documentation": "https://docs.rs/regex-syntax", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "regex-syntax", + "version": "0.7.1", + "id": "regex-syntax 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "A regular expression parser.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "regex-syntax", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-syntax-0.7.1/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "bench", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-syntax-0.7.1/benches/bench.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "default": [ + "std", + "unicode" + ], + "std": [], + "unicode": [ + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment" + ], + "unicode-age": [], + "unicode-bool": [], + "unicode-case": [], + "unicode-gencat": [], + "unicode-perl": [], + "unicode-script": [], + "unicode-segment": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-syntax-0.7.1/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "all-features": true, + "rustdoc-args": [ + "--cfg", + "docsrs" + ] + } + } + }, + "publish": null, + "authors": [ + "The Rust Project Developers" + ], + "categories": [], + "keywords": [], + "readme": "README.md", + "repository": "https://github.com/rust-lang/regex", + "homepage": "https://github.com/rust-lang/regex", + "documentation": "https://docs.rs/regex-syntax", + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": "1.60.0" + }, + { + "name": "rure", + "version": "0.2.2", + "id": "rure 0.2.2 (path+file:///$ROOT$regex/regex-capi)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "A C API for Rust's regular expression library.\n", + "source": null, + "dependencies": [ + { + "name": "libc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex", + "source": null, + "req": "^1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$regex" + } + ], + "targets": [ + { + "kind": [ + "staticlib", + "cdylib", + "rlib" + ], + "crate_types": [ + "staticlib", + "cdylib", + "rlib" + ], + "name": "rure", + "src_path": "$ROOT$regex/regex-capi/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$regex/regex-capi/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "The Rust Project Developers" + ], + "categories": [], + "keywords": [], + "readme": "README.md", + "repository": "https://github.com/rust-lang/regex", + "homepage": "https://github.com/rust-lang/regex", + "documentation": "https://github.com/rust-lang/regex/tree/master/regex-capi", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "serde", + "version": "1.0.160", + "id": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "A generic serialization/deserialization framework", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "serde_derive", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "=1.0.160", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde_derive", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "serde", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-1.0.160/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-1.0.160/build.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "alloc": [], + "default": [ + "std" + ], + "derive": [ + "serde_derive" + ], + "rc": [], + "serde_derive": [ + "dep:serde_derive" + ], + "std": [], + "unstable": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-1.0.160/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "features": [ + "derive" + ], + "targets": [ + "x86_64-unknown-linux-gnu" + ] + } + }, + "playground": { + "features": [ + "derive", + "rc" + ] + } + }, + "publish": null, + "authors": [ + "Erick Tryzelaar ", + "David Tolnay " + ], + "categories": [ + "encoding", + "no-std" + ], + "keywords": [ + "serde", + "serialization", + "no_std" + ], + "readme": "crates-io.md", + "repository": "https://github.com/serde-rs/serde", + "homepage": "https://serde.rs", + "documentation": "https://docs.rs/serde", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": "1.19" + }, + { + "name": "serde_derive", + "version": "1.0.160", + "id": "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "proc-macro2", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "quote", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "syn", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2.0.3", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "proc-macro" + ], + "crate_types": [ + "proc-macro" + ], + "name": "serde_derive", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_derive-1.0.160/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_derive-1.0.160/build.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "default": [], + "deserialize_in_place": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_derive-1.0.160/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "targets": [ + "x86_64-unknown-linux-gnu" + ] + } + } + }, + "publish": null, + "authors": [ + "Erick Tryzelaar ", + "David Tolnay " + ], + "categories": [ + "no-std" + ], + "keywords": [ + "serde", + "serialization", + "no_std", + "derive" + ], + "readme": "crates-io.md", + "repository": "https://github.com/serde-rs/serde", + "homepage": "https://serde.rs", + "documentation": "https://serde.rs/derive.html", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": "1.56" + }, + { + "name": "strsim", + "version": "0.10.0", + "id": "strsim 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT", + "license_file": null, + "description": "Implementations of string similarity metrics. Includes Hamming, Levenshtein,\nOSA, Damerau-Levenshtein, Jaro, Jaro-Winkler, and Sørensen-Dice.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "strsim", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/strsim-0.10.0/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "lib", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/strsim-0.10.0/tests/lib.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "benches", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/strsim-0.10.0/benches/benches.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/strsim-0.10.0/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Danny Guo " + ], + "categories": [], + "keywords": [ + "string", + "similarity", + "Hamming", + "Levenshtein", + "Jaro" + ], + "readme": "README.md", + "repository": "https://github.com/dguo/strsim-rs", + "homepage": "https://github.com/dguo/strsim-rs", + "documentation": "https://docs.rs/strsim/", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "syn", + "version": "2.0.15", + "id": "syn 2.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "Parser for Rust source code", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "proc-macro2", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.55", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "quote", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.25", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "unicode-ident", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "anyhow", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "automod", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "flate2", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "insta", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rayon", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "ref-cast", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "reqwest", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.11", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [ + "blocking" + ], + "target": null, + "registry": null + }, + { + "name": "rustversion", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "syn-test-suite", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "tar", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4.16", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "termcolor", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "walkdir", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2.3.2", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "syn", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "regression", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/regression.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_asyncness", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_asyncness.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_attribute", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_attribute.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_derive_input", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_derive_input.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_expr", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_expr.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_generics", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_generics.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_grouping", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_grouping.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_ident", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_ident.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_item", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_item.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_iterators", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_iterators.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_lit", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_lit.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_meta", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_meta.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_parse_buffer", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_parse_buffer.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_parse_stream", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_parse_stream.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_pat", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_pat.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_path", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_path.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_precedence", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_precedence.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_receiver", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_receiver.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_round_trip", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_round_trip.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_shebang", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_shebang.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_should_parse", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_should_parse.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_size", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_size.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_stmt", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_stmt.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_token_trees", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_token_trees.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_ty", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_ty.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_visibility", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_visibility.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "zzz_stable", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/zzz_stable.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "rust", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/benches/rust.rs", + "edition": "2021", + "required-features": [ + "full", + "parsing" + ], + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "file", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/benches/file.rs", + "edition": "2021", + "required-features": [ + "full", + "parsing" + ], + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "clone-impls": [], + "default": [ + "derive", + "parsing", + "printing", + "clone-impls", + "proc-macro" + ], + "derive": [], + "extra-traits": [], + "fold": [], + "full": [], + "parsing": [], + "printing": [ + "quote" + ], + "proc-macro": [ + "proc-macro2/proc-macro", + "quote/proc-macro" + ], + "quote": [ + "dep:quote" + ], + "test": [ + "syn-test-suite/all-features" + ], + "visit": [], + "visit-mut": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "all-features": true, + "rustdoc-args": [ + "--cfg", + "doc_cfg" + ], + "targets": [ + "x86_64-unknown-linux-gnu" + ] + } + }, + "playground": { + "features": [ + "full", + "visit", + "visit-mut", + "fold", + "extra-traits" + ] + } + }, + "publish": null, + "authors": [ + "David Tolnay " + ], + "categories": [ + "development-tools::procedural-macro-helpers", + "parser-implementations" + ], + "keywords": [ + "macros", + "syn" + ], + "readme": "README.md", + "repository": "https://github.com/dtolnay/syn", + "homepage": null, + "documentation": "https://docs.rs/syn", + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": "1.56" + }, + { + "name": "unicode-ident", + "version": "1.0.8", + "id": "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "(MIT OR Apache-2.0) AND Unicode-DFS-2016", + "license_file": null, + "description": "Determine whether characters have the XID_Start or XID_Continue properties according to Unicode Standard Annex #31", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "criterion", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "fst", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rand", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.8", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [ + "small_rng" + ], + "target": null, + "registry": null + }, + { + "name": "roaring", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.10", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "ucd-trie", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "unicode-xid", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2.4", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "unicode-ident", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "compare", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/tests/compare.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "static_size", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/tests/static_size.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "xid", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/benches/xid.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "targets": [ + "x86_64-unknown-linux-gnu" + ] + } + } + }, + "publish": null, + "authors": [ + "David Tolnay " + ], + "categories": [ + "development-tools::procedural-macro-helpers", + "no-std" + ], + "keywords": [ + "unicode", + "xid" + ], + "readme": "README.md", + "repository": "https://github.com/dtolnay/unicode-ident", + "homepage": null, + "documentation": "https://docs.rs/unicode-ident", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": "1.31" + }, + { + "name": "wasi", + "version": "0.11.0+wasi-snapshot-preview1", + "id": "wasi 0.11.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", + "license_file": null, + "description": "Experimental WASI API bindings for Rust", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "compiler_builtins", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustc-std-workspace-core", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": "core", + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustc-std-workspace-alloc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "wasi", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/wasi-0.11.0+wasi-snapshot-preview1/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": { + "compiler_builtins": [ + "dep:compiler_builtins" + ], + "core": [ + "dep:core" + ], + "default": [ + "std" + ], + "rustc-dep-of-std": [ + "compiler_builtins", + "core", + "rustc-std-workspace-alloc" + ], + "rustc-std-workspace-alloc": [ + "dep:rustc-std-workspace-alloc" + ], + "std": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/wasi-0.11.0+wasi-snapshot-preview1/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "The Cranelift Project Developers" + ], + "categories": [ + "no-std", + "wasm" + ], + "keywords": [ + "webassembly", + "wasm" + ], + "readme": "README.md", + "repository": "https://github.com/bytecodealliance/wasi", + "homepage": null, + "documentation": "https://docs.rs/wasi", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "winapi", + "version": "0.3.9", + "id": "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT/Apache-2.0", + "license_file": null, + "description": "Raw FFI bindings for all of Windows API.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "winapi-i686-pc-windows-gnu", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": "i686-pc-windows-gnu", + "registry": null + }, + { + "name": "winapi-x86_64-pc-windows-gnu", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": "x86_64-pc-windows-gnu", + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "winapi", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-0.3.9/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-0.3.9/build.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "accctrl": [], + "aclapi": [], + "activation": [], + "adhoc": [], + "appmgmt": [], + "audioclient": [], + "audiosessiontypes": [], + "avrt": [], + "basetsd": [], + "bcrypt": [], + "bits": [], + "bits10_1": [], + "bits1_5": [], + "bits2_0": [], + "bits2_5": [], + "bits3_0": [], + "bits4_0": [], + "bits5_0": [], + "bitscfg": [], + "bitsmsg": [], + "bluetoothapis": [], + "bluetoothleapis": [], + "bthdef": [], + "bthioctl": [], + "bthledef": [], + "bthsdpdef": [], + "bugcodes": [], + "cderr": [], + "cfg": [], + "cfgmgr32": [], + "cguid": [], + "combaseapi": [], + "coml2api": [], + "commapi": [], + "commctrl": [], + "commdlg": [], + "commoncontrols": [], + "consoleapi": [], + "corecrt": [], + "corsym": [], + "d2d1": [], + "d2d1_1": [], + "d2d1_2": [], + "d2d1_3": [], + "d2d1effectauthor": [], + "d2d1effects": [], + "d2d1effects_1": [], + "d2d1effects_2": [], + "d2d1svg": [], + "d2dbasetypes": [], + "d3d": [], + "d3d10": [], + "d3d10_1": [], + "d3d10_1shader": [], + "d3d10effect": [], + "d3d10misc": [], + "d3d10sdklayers": [], + "d3d10shader": [], + "d3d11": [], + "d3d11_1": [], + "d3d11_2": [], + "d3d11_3": [], + "d3d11_4": [], + "d3d11on12": [], + "d3d11sdklayers": [], + "d3d11shader": [], + "d3d11tokenizedprogramformat": [], + "d3d12": [], + "d3d12sdklayers": [], + "d3d12shader": [], + "d3d9": [], + "d3d9caps": [], + "d3d9types": [], + "d3dcommon": [], + "d3dcompiler": [], + "d3dcsx": [], + "d3dkmdt": [], + "d3dkmthk": [], + "d3dukmdt": [], + "d3dx10core": [], + "d3dx10math": [], + "d3dx10mesh": [], + "datetimeapi": [], + "davclnt": [], + "dbghelp": [], + "dbt": [], + "dcommon": [], + "dcomp": [], + "dcompanimation": [], + "dcomptypes": [], + "dde": [], + "ddraw": [], + "ddrawi": [], + "ddrawint": [], + "debug": [ + "impl-debug" + ], + "debugapi": [], + "devguid": [], + "devicetopology": [], + "devpkey": [], + "devpropdef": [], + "dinput": [], + "dinputd": [], + "dispex": [], + "dmksctl": [], + "dmusicc": [], + "docobj": [], + "documenttarget": [], + "dot1x": [], + "dpa_dsa": [], + "dpapi": [], + "dsgetdc": [], + "dsound": [], + "dsrole": [], + "dvp": [], + "dwmapi": [], + "dwrite": [], + "dwrite_1": [], + "dwrite_2": [], + "dwrite_3": [], + "dxdiag": [], + "dxfile": [], + "dxgi": [], + "dxgi1_2": [], + "dxgi1_3": [], + "dxgi1_4": [], + "dxgi1_5": [], + "dxgi1_6": [], + "dxgidebug": [], + "dxgiformat": [], + "dxgitype": [], + "dxva2api": [], + "dxvahd": [], + "eaptypes": [], + "enclaveapi": [], + "endpointvolume": [], + "errhandlingapi": [], + "everything": [], + "evntcons": [], + "evntprov": [], + "evntrace": [], + "excpt": [], + "exdisp": [], + "fibersapi": [], + "fileapi": [], + "functiondiscoverykeys_devpkey": [], + "gl-gl": [], + "guiddef": [], + "handleapi": [], + "heapapi": [], + "hidclass": [], + "hidpi": [], + "hidsdi": [], + "hidusage": [], + "highlevelmonitorconfigurationapi": [], + "hstring": [], + "http": [], + "ifdef": [], + "ifmib": [], + "imm": [], + "impl-debug": [], + "impl-default": [], + "in6addr": [], + "inaddr": [], + "inspectable": [], + "interlockedapi": [], + "intsafe": [], + "ioapiset": [], + "ipexport": [], + "iphlpapi": [], + "ipifcons": [], + "ipmib": [], + "iprtrmib": [], + "iptypes": [], + "jobapi": [], + "jobapi2": [], + "knownfolders": [], + "ks": [], + "ksmedia": [], + "ktmtypes": [], + "ktmw32": [], + "l2cmn": [], + "libloaderapi": [], + "limits": [], + "lmaccess": [], + "lmalert": [], + "lmapibuf": [], + "lmat": [], + "lmcons": [], + "lmdfs": [], + "lmerrlog": [], + "lmjoin": [], + "lmmsg": [], + "lmremutl": [], + "lmrepl": [], + "lmserver": [], + "lmshare": [], + "lmstats": [], + "lmsvc": [], + "lmuse": [], + "lmwksta": [], + "lowlevelmonitorconfigurationapi": [], + "lsalookup": [], + "memoryapi": [], + "minschannel": [], + "minwinbase": [], + "minwindef": [], + "mmdeviceapi": [], + "mmeapi": [], + "mmreg": [], + "mmsystem": [], + "mprapidef": [], + "msaatext": [], + "mscat": [], + "mschapp": [], + "mssip": [], + "mstcpip": [], + "mswsock": [], + "mswsockdef": [], + "namedpipeapi": [], + "namespaceapi": [], + "nb30": [], + "ncrypt": [], + "netioapi": [], + "nldef": [], + "ntddndis": [], + "ntddscsi": [], + "ntddser": [], + "ntdef": [], + "ntlsa": [], + "ntsecapi": [], + "ntstatus": [], + "oaidl": [], + "objbase": [], + "objidl": [], + "objidlbase": [], + "ocidl": [], + "ole2": [], + "oleauto": [], + "olectl": [], + "oleidl": [], + "opmapi": [], + "pdh": [], + "perflib": [], + "physicalmonitorenumerationapi": [], + "playsoundapi": [], + "portabledevice": [], + "portabledeviceapi": [], + "portabledevicetypes": [], + "powerbase": [], + "powersetting": [], + "powrprof": [], + "processenv": [], + "processsnapshot": [], + "processthreadsapi": [], + "processtopologyapi": [], + "profileapi": [], + "propidl": [], + "propkey": [], + "propkeydef": [], + "propsys": [], + "prsht": [], + "psapi": [], + "qos": [], + "realtimeapiset": [], + "reason": [], + "restartmanager": [], + "restrictederrorinfo": [], + "rmxfguid": [], + "roapi": [], + "robuffer": [], + "roerrorapi": [], + "rpc": [], + "rpcdce": [], + "rpcndr": [], + "rtinfo": [], + "sapi": [], + "sapi51": [], + "sapi53": [], + "sapiddk": [], + "sapiddk51": [], + "schannel": [], + "sddl": [], + "securityappcontainer": [], + "securitybaseapi": [], + "servprov": [], + "setupapi": [], + "shellapi": [], + "shellscalingapi": [], + "shlobj": [], + "shobjidl": [], + "shobjidl_core": [], + "shtypes": [], + "softpub": [], + "spapidef": [], + "spellcheck": [], + "sporder": [], + "sql": [], + "sqlext": [], + "sqltypes": [], + "sqlucode": [], + "sspi": [], + "std": [], + "stralign": [], + "stringapiset": [], + "strmif": [], + "subauth": [], + "synchapi": [], + "sysinfoapi": [], + "systemtopologyapi": [], + "taskschd": [], + "tcpestats": [], + "tcpmib": [], + "textstor": [], + "threadpoolapiset": [], + "threadpoollegacyapiset": [], + "timeapi": [], + "timezoneapi": [], + "tlhelp32": [], + "transportsettingcommon": [], + "tvout": [], + "udpmib": [], + "unknwnbase": [], + "urlhist": [], + "urlmon": [], + "usb": [], + "usbioctl": [], + "usbiodef": [], + "usbscan": [], + "usbspec": [], + "userenv": [], + "usp10": [], + "utilapiset": [], + "uxtheme": [], + "vadefs": [], + "vcruntime": [], + "vsbackup": [], + "vss": [], + "vsserror": [], + "vswriter": [], + "wbemads": [], + "wbemcli": [], + "wbemdisp": [], + "wbemprov": [], + "wbemtran": [], + "wct": [], + "werapi": [], + "winbase": [], + "wincodec": [], + "wincodecsdk": [], + "wincon": [], + "wincontypes": [], + "wincred": [], + "wincrypt": [], + "windef": [], + "windot11": [], + "windowsceip": [], + "windowsx": [], + "winefs": [], + "winerror": [], + "winevt": [], + "wingdi": [], + "winhttp": [], + "wininet": [], + "winineti": [], + "winioctl": [], + "winnetwk": [], + "winnls": [], + "winnt": [], + "winreg": [], + "winsafer": [], + "winscard": [], + "winsmcrd": [], + "winsock2": [], + "winspool": [], + "winstring": [], + "winsvc": [], + "wintrust": [], + "winusb": [], + "winusbio": [], + "winuser": [], + "winver": [], + "wlanapi": [], + "wlanihv": [], + "wlanihvtypes": [], + "wlantypes": [], + "wlclient": [], + "wmistr": [], + "wnnc": [], + "wow64apiset": [], + "wpdmtpextensions": [], + "ws2bth": [], + "ws2def": [], + "ws2ipdef": [], + "ws2spi": [], + "ws2tcpip": [], + "wtsapi32": [], + "wtypes": [], + "wtypesbase": [], + "xinput": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-0.3.9/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "default-target": "x86_64-pc-windows-msvc", + "features": [ + "everything", + "impl-debug", + "impl-default" + ], + "targets": [ + "aarch64-pc-windows-msvc", + "i686-pc-windows-msvc", + "x86_64-pc-windows-msvc" + ] + } + } + }, + "publish": null, + "authors": [ + "Peter Atashian " + ], + "categories": [ + "external-ffi-bindings", + "no-std", + "os::windows-apis" + ], + "keywords": [ + "windows", + "ffi", + "win32", + "com", + "directx" + ], + "readme": "README.md", + "repository": "https://github.com/retep998/winapi-rs", + "homepage": null, + "documentation": "https://docs.rs/winapi/", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "winapi-i686-pc-windows-gnu", + "version": "0.4.0", + "id": "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT/Apache-2.0", + "license_file": null, + "description": "Import libraries for the i686-pc-windows-gnu target. Please don't use this crate directly, depend on winapi instead.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "winapi-i686-pc-windows-gnu", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-i686-pc-windows-gnu-0.4.0/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-i686-pc-windows-gnu-0.4.0/build.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-i686-pc-windows-gnu-0.4.0/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Peter Atashian " + ], + "categories": [], + "keywords": [ + "windows" + ], + "readme": null, + "repository": "https://github.com/retep998/winapi-rs", + "homepage": null, + "documentation": null, + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "winapi-x86_64-pc-windows-gnu", + "version": "0.4.0", + "id": "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT/Apache-2.0", + "license_file": null, + "description": "Import libraries for the x86_64-pc-windows-gnu target. Please don't use this crate directly, depend on winapi instead.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "winapi-x86_64-pc-windows-gnu", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-x86_64-pc-windows-gnu-0.4.0/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-x86_64-pc-windows-gnu-0.4.0/build.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-x86_64-pc-windows-gnu-0.4.0/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Peter Atashian " + ], + "categories": [], + "keywords": [ + "windows" + ], + "readme": null, + "repository": "https://github.com/retep998/winapi-rs", + "homepage": null, + "documentation": null, + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + } + ], + "workspace_members": [ + "regex-benchmark 0.1.0 (path+file:///$ROOT$regex/bench)", + "regex 1.7.1 (path+file:///$ROOT$regex)", + "regex-syntax 0.6.28 (path+file:///$ROOT$regex/regex-syntax)", + "rure 0.2.2 (path+file:///$ROOT$regex/regex-capi)", + "regex-debug 0.1.0 (path+file:///$ROOT$regex/regex-debug)" + ], + "resolve": { + "nodes": [ + { + "id": "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "memchr", + "pkg": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "default", + "std" + ] + }, + { + "id": "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "docopt 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "lazy_static", + "pkg": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "regex", + "pkg": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "serde", + "pkg": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "strsim", + "pkg": "strsim 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [] + }, + { + "id": "getrandom 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.11.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "cfg_if", + "pkg": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "libc", + "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "cfg(unix)" + } + ] + }, + { + "name": "wasi", + "pkg": "wasi 0.11.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "cfg(target_os = \"wasi\")" + } + ] + } + ], + "features": [] + }, + { + "id": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [ + "default", + "std" + ] + }, + { + "id": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [ + "default", + "std" + ] + }, + { + "id": "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "libc", + "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "cfg(unix)" + } + ] + }, + { + "name": "winapi", + "pkg": "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "cfg(windows)" + } + ] + } + ], + "features": [] + }, + { + "id": "pkg-config 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "unicode_ident", + "pkg": "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "default", + "proc-macro" + ] + }, + { + "id": "quickcheck 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "rand 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "rand", + "pkg": "rand 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [] + }, + { + "id": "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "proc_macro2", + "pkg": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "default", + "proc-macro" + ] + }, + { + "id": "rand 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "rand_core 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "rand_core", + "pkg": "rand_core 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "getrandom", + "small_rng" + ] + }, + { + "id": "rand_core 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "getrandom 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "getrandom", + "pkg": "getrandom 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "getrandom" + ] + }, + { + "id": "regex 1.7.1 (path+file:///$ROOT$regex)", + "dependencies": [ + "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quickcheck 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.28 (path+file:///$ROOT$regex/regex-syntax)" + ], + "deps": [ + { + "name": "aho_corasick", + "pkg": "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "lazy_static", + "pkg": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": "dev", + "target": null + } + ] + }, + { + "name": "memchr", + "pkg": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "quickcheck", + "pkg": "quickcheck 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": "dev", + "target": null + } + ] + }, + { + "name": "rand", + "pkg": "rand 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": "dev", + "target": null + } + ] + }, + { + "name": "regex_syntax", + "pkg": "regex-syntax 0.6.28 (path+file:///$ROOT$regex/regex-syntax)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "aho-corasick", + "default", + "memchr", + "perf", + "perf-cache", + "perf-dfa", + "perf-inline", + "perf-literal", + "std", + "unicode", + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment" + ] + }, + { + "id": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "regex-syntax 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "regex_syntax", + "pkg": "regex-syntax 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "std", + "unicode", + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment" + ] + }, + { + "id": "regex-benchmark 0.1.0 (path+file:///$ROOT$regex/bench)", + "dependencies": [ + "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "docopt 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.7.1 (path+file:///$ROOT$regex)", + "regex-syntax 0.6.28 (path+file:///$ROOT$regex/regex-syntax)", + "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "cc", + "pkg": "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": "build", + "target": null + } + ] + }, + { + "name": "cfg_if", + "pkg": "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "docopt", + "pkg": "docopt 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "lazy_static", + "pkg": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "libc", + "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "memmap", + "pkg": "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "pkg_config", + "pkg": "pkg-config 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": "build", + "target": null + } + ] + }, + { + "name": "regex", + "pkg": "regex 1.7.1 (path+file:///$ROOT$regex)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "regex_syntax", + "pkg": "regex-syntax 0.6.28 (path+file:///$ROOT$regex/regex-syntax)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "serde", + "pkg": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [] + }, + { + "id": "regex-debug 0.1.0 (path+file:///$ROOT$regex/regex-debug)", + "dependencies": [ + "docopt 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.7.1 (path+file:///$ROOT$regex)", + "regex-syntax 0.6.28 (path+file:///$ROOT$regex/regex-syntax)", + "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "docopt", + "pkg": "docopt 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "regex", + "pkg": "regex 1.7.1 (path+file:///$ROOT$regex)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "regex_syntax", + "pkg": "regex-syntax 0.6.28 (path+file:///$ROOT$regex/regex-syntax)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "serde", + "pkg": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [] + }, + { + "id": "regex-syntax 0.6.28 (path+file:///$ROOT$regex/regex-syntax)", + "dependencies": [], + "deps": [], + "features": [ + "default", + "unicode", + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment" + ] + }, + { + "id": "regex-syntax 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [ + "unicode", + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment" + ] + }, + { + "id": "rure 0.2.2 (path+file:///$ROOT$regex/regex-capi)", + "dependencies": [ + "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.7.1 (path+file:///$ROOT$regex)" + ], + "deps": [ + { + "name": "libc", + "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "regex", + "pkg": "regex 1.7.1 (path+file:///$ROOT$regex)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [] + }, + { + "id": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "serde_derive", + "pkg": "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "default", + "derive", + "serde_derive", + "std" + ] + }, + { + "id": "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 2.0.15 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "proc_macro2", + "pkg": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "quote", + "pkg": "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "syn", + "pkg": "syn 2.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "default" + ] + }, + { + "id": "strsim 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "syn 2.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "proc_macro2", + "pkg": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "quote", + "pkg": "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "unicode_ident", + "pkg": "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "clone-impls", + "default", + "derive", + "parsing", + "printing", + "proc-macro", + "quote" + ] + }, + { + "id": "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "wasi 0.11.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "winapi_i686_pc_windows_gnu", + "pkg": "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "i686-pc-windows-gnu" + } + ] + }, + { + "name": "winapi_x86_64_pc_windows_gnu", + "pkg": "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "x86_64-pc-windows-gnu" + } + ] + } + ], + "features": [ + "basetsd", + "handleapi", + "memoryapi", + "minwindef", + "std", + "sysinfoapi" + ] + }, + { + "id": "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + } + ], + "root": "regex 1.7.1 (path+file:///$ROOT$regex)" + }, + "target_directory": "$ROOT$regex/target", + "version": 1, + "workspace_root": "$ROOT$regex", + "metadata": null +} diff --git a/crates/project-model/test_data/ripgrep-metadata.json b/crates/project-model/test_data/ripgrep-metadata.json new file mode 100644 index 0000000000000..131ff5dd71571 --- /dev/null +++ b/crates/project-model/test_data/ripgrep-metadata.json @@ -0,0 +1,12816 @@ +{ + "packages": [ + { + "name": "aho-corasick", + "version": "0.7.20", + "id": "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "Unlicense OR MIT", + "license_file": null, + "description": "Fast multiple substring searching.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "memchr", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2.4.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "aho_corasick", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/aho-corasick-0.7.20/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": { + "default": [ + "std" + ], + "std": [ + "memchr/std" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/aho-corasick-0.7.20/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [ + "text-processing" + ], + "keywords": [ + "string", + "search", + "text", + "aho", + "multi" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/aho-corasick", + "homepage": "https://github.com/BurntSushi/aho-corasick", + "documentation": null, + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "aho-corasick", + "version": "1.0.1", + "id": "aho-corasick 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "Unlicense OR MIT", + "license_file": null, + "description": "Fast multiple substring searching.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "log", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4.17", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "memchr", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2.4.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "doc-comment", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "aho_corasick", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/aho-corasick-1.0.1/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": { + "default": [ + "std", + "perf-literal" + ], + "logging": [ + "dep:log" + ], + "perf-literal": [ + "dep:memchr" + ], + "std": [ + "memchr?/std" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/aho-corasick-1.0.1/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "all-features": true, + "rustdoc-args": [ + "--cfg", + "docsrs" + ] + } + } + }, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [ + "text-processing" + ], + "keywords": [ + "string", + "search", + "text", + "pattern", + "multi" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/aho-corasick", + "homepage": "https://github.com/BurntSushi/aho-corasick", + "documentation": null, + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": "1.60.0" + }, + { + "name": "atty", + "version": "0.2.14", + "id": "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT", + "license_file": null, + "description": "A simple interface for querying atty", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "hermit-abi", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1.6", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": "cfg(target_os = \"hermit\")", + "registry": null + }, + { + "name": "libc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": "cfg(unix)", + "registry": null + }, + { + "name": "winapi", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [ + "consoleapi", + "processenv", + "minwinbase", + "minwindef", + "winbase" + ], + "target": "cfg(windows)", + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "atty", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/atty-0.2.14/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "atty", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/atty-0.2.14/examples/atty.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/atty-0.2.14/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "softprops " + ], + "categories": [], + "keywords": [ + "terminal", + "tty", + "isatty" + ], + "readme": "README.md", + "repository": "https://github.com/softprops/atty", + "homepage": "https://github.com/softprops/atty", + "documentation": "http://softprops.github.io/atty", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "base64", + "version": "0.20.0", + "id": "base64 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "encodes and decodes base64 as bytes or utf8", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "criterion", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rand", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.8.5", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [ + "small_rng" + ], + "target": null, + "registry": null + }, + { + "name": "rstest", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.12.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rstest_reuse", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "structopt", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3.26", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "base64", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/base64-0.20.0/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "base64", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/base64-0.20.0/examples/base64.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "encode", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/base64-0.20.0/tests/encode.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "tests", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/base64-0.20.0/tests/tests.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "benchmarks", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/base64-0.20.0/benches/benchmarks.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "alloc": [], + "default": [ + "std" + ], + "std": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/base64-0.20.0/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Alice Maz ", + "Marshall Pierce " + ], + "categories": [ + "encoding" + ], + "keywords": [ + "base64", + "utf8", + "encode", + "decode", + "no_std" + ], + "readme": "README.md", + "repository": "https://github.com/marshallpierce/rust-base64", + "homepage": null, + "documentation": "https://docs.rs/base64", + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": "1.57.0" + }, + { + "name": "bitflags", + "version": "1.3.2", + "id": "bitflags 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT/Apache-2.0", + "license_file": null, + "description": "A macro to generate structures which behave like bitflags.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "compiler_builtins", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1.2", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustc-std-workspace-core", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.0", + "kind": null, + "rename": "core", + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustversion", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde_derive", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde_json", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "trybuild", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "walkdir", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "bitflags", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bitflags-1.3.2/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "basic", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bitflags-1.3.2/tests/basic.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "compile", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bitflags-1.3.2/tests/compile.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + } + ], + "features": { + "compiler_builtins": [ + "dep:compiler_builtins" + ], + "core": [ + "dep:core" + ], + "default": [], + "example_generated": [], + "rustc-dep-of-std": [ + "core", + "compiler_builtins" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bitflags-1.3.2/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "features": [ + "example_generated" + ] + } + } + }, + "publish": null, + "authors": [ + "The Rust Project Developers" + ], + "categories": [ + "no-std" + ], + "keywords": [ + "bit", + "bitmask", + "bitflags", + "flags" + ], + "readme": "README.md", + "repository": "https://github.com/bitflags/bitflags", + "homepage": "https://github.com/bitflags/bitflags", + "documentation": "https://docs.rs/bitflags", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "bstr", + "version": "1.4.0", + "id": "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "A string type that is not required to be valid UTF-8.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "memchr", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2.4.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "once_cell", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.14.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex-automata", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1.5", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.85", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "quickcheck", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "ucd-parse", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "unicode-segmentation", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.2.1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "bstr", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "graphemes", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/examples/graphemes.rs", + "edition": "2021", + "required-features": [ + "std", + "unicode" + ], + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "lines", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/examples/lines.rs", + "edition": "2021", + "required-features": [ + "std" + ], + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "uppercase", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/examples/uppercase.rs", + "edition": "2021", + "required-features": [ + "std", + "unicode" + ], + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "words", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/examples/words.rs", + "edition": "2021", + "required-features": [ + "std", + "unicode" + ], + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "graphemes-std", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/examples/graphemes-std.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "lines-std", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/examples/lines-std.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "uppercase-std", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/examples/uppercase-std.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "words-std", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/examples/words-std.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "alloc": [ + "serde?/alloc" + ], + "default": [ + "std", + "unicode" + ], + "serde": [ + "dep:serde" + ], + "std": [ + "alloc", + "memchr/std", + "serde?/std" + ], + "unicode": [ + "dep:once_cell", + "dep:regex-automata" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bstr-1.4.0/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "all-features": true, + "rustdoc-args": [ + "--cfg", + "docsrs" + ] + } + } + }, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [ + "text-processing", + "encoding" + ], + "keywords": [ + "string", + "str", + "byte", + "bytes", + "text" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/bstr", + "homepage": "https://github.com/BurntSushi/bstr", + "documentation": "https://docs.rs/bstr", + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": "1.60" + }, + { + "name": "bytecount", + "version": "0.6.3", + "id": "bytecount 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "Apache-2.0/MIT", + "license_file": null, + "description": "count occurrences of a given byte, or the number of UTF-8 code points, in a byte slice, fast", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "packed_simd_2", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3.8", + "kind": null, + "rename": "packed_simd", + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "criterion", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "quickcheck", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rand", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.8", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "bytecount", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bytecount-0.6.3/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "check", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bytecount-0.6.3/tests/check.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "bench", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bytecount-0.6.3/benches/bench.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "generic-simd": [ + "packed_simd" + ], + "html_report": [], + "packed_simd": [ + "dep:packed_simd" + ], + "runtime-dispatch-simd": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/bytecount-0.6.3/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andre Bogus ", + "Joshua Landau " + ], + "categories": [ + "algorithms", + "no-std" + ], + "keywords": [], + "readme": "README.md", + "repository": "https://github.com/llogiq/bytecount", + "homepage": null, + "documentation": null, + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "cc", + "version": "1.0.79", + "id": "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "A build-time dependency for Cargo build scripts to assist in invoking the native\nC compiler to compile native C code into a static archive to be linked into Rust\ncode.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "jobserver", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1.16", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "tempfile", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "cc", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "bin" + ], + "crate_types": [ + "bin" + ], + "name": "gcc-shim", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/src/bin/gcc-shim.rs", + "edition": "2018", + "doc": true, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "cc_env", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/tests/cc_env.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "cflags", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/tests/cflags.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "cxxflags", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/tests/cxxflags.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/tests/test.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + } + ], + "features": { + "jobserver": [ + "dep:jobserver" + ], + "parallel": [ + "jobserver" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cc-1.0.79/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Alex Crichton " + ], + "categories": [ + "development-tools::build-utils" + ], + "keywords": [ + "build-dependencies" + ], + "readme": "README.md", + "repository": "https://github.com/rust-lang/cc-rs", + "homepage": "https://github.com/rust-lang/cc-rs", + "documentation": "https://docs.rs/cc", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "cfg-if", + "version": "1.0.0", + "id": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT/Apache-2.0", + "license_file": null, + "description": "A macro to ergonomically define an item depending on a large number of #[cfg]\nparameters. Structured like an if-else chain, the first matching branch is the\nitem that gets emitted.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "compiler_builtins", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1.2", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustc-std-workspace-core", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.0", + "kind": null, + "rename": "core", + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "cfg-if", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cfg-if-1.0.0/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "xcrate", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cfg-if-1.0.0/tests/xcrate.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + } + ], + "features": { + "compiler_builtins": [ + "dep:compiler_builtins" + ], + "core": [ + "dep:core" + ], + "rustc-dep-of-std": [ + "core", + "compiler_builtins" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/cfg-if-1.0.0/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Alex Crichton " + ], + "categories": [], + "keywords": [], + "readme": "README.md", + "repository": "https://github.com/alexcrichton/cfg-if", + "homepage": "https://github.com/alexcrichton/cfg-if", + "documentation": "https://docs.rs/cfg-if", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "clap", + "version": "2.34.0", + "id": "clap 2.34.0 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT", + "license_file": null, + "description": "A simple to use, efficient, and full-featured Command Line Argument Parser\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "atty", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2.2", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "bitflags", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "clippy", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "~0.0.166", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "strsim", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.8", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "term_size", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "textwrap", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.11.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "unicode-width", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1.4", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "vec_map", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.8", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "yaml-rust", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3.5", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "lazy_static", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "version-sync", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.8", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "ansi_term", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.12", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": "cfg(not(windows))", + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "clap", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/clap-2.34.0/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": { + "ansi_term": [ + "dep:ansi_term" + ], + "atty": [ + "dep:atty" + ], + "clippy": [ + "dep:clippy" + ], + "color": [ + "ansi_term", + "atty" + ], + "debug": [], + "default": [ + "suggestions", + "color", + "vec_map" + ], + "doc": [ + "yaml" + ], + "nightly": [], + "no_cargo": [], + "strsim": [ + "dep:strsim" + ], + "suggestions": [ + "strsim" + ], + "term_size": [ + "dep:term_size" + ], + "unstable": [], + "vec_map": [ + "dep:vec_map" + ], + "wrap_help": [ + "term_size", + "textwrap/term_size" + ], + "yaml": [ + "yaml-rust" + ], + "yaml-rust": [ + "dep:yaml-rust" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/clap-2.34.0/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "features": [ + "doc" + ] + } + } + }, + "publish": null, + "authors": [ + "Kevin K. " + ], + "categories": [ + "command-line-interface" + ], + "keywords": [ + "argument", + "cli", + "arg", + "parser", + "parse" + ], + "readme": "README.md", + "repository": "https://github.com/clap-rs/clap", + "homepage": "https://clap.rs/", + "documentation": "https://docs.rs/clap/", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "crossbeam-channel", + "version": "0.5.8", + "id": "crossbeam-channel 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "Multi-producer multi-consumer channels for message passing", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "cfg-if", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "crossbeam-utils", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.8", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "num_cpus", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.13.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rand", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.8", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "signal-hook", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "crossbeam-channel", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "fibonacci", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/examples/fibonacci.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "matching", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/examples/matching.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "stopwatch", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/examples/stopwatch.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "after", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/after.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "array", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/array.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "golang", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/golang.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "iter", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/iter.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "list", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/list.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "mpsc", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/mpsc.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "never", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/never.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "ready", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/ready.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "same_channel", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/same_channel.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "select", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/select.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "select_macro", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/select_macro.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "thread_locals", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/thread_locals.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "tick", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/tick.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "zero", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/tests/zero.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "crossbeam", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/benches/crossbeam.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "crossbeam-utils": [ + "dep:crossbeam-utils" + ], + "default": [ + "std" + ], + "std": [ + "crossbeam-utils/std" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-channel-0.5.8/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [], + "categories": [ + "algorithms", + "concurrency", + "data-structures" + ], + "keywords": [ + "channel", + "mpmc", + "select", + "golang", + "message" + ], + "readme": "README.md", + "repository": "https://github.com/crossbeam-rs/crossbeam", + "homepage": "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-channel", + "documentation": null, + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": "1.38" + }, + { + "name": "crossbeam-utils", + "version": "0.8.15", + "id": "crossbeam-utils 0.8.15 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "Utilities for concurrent programming", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "cfg-if", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rand", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.8", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustversion", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "loom", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.5", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": "cfg(crossbeam_loom)", + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "crossbeam-utils", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "atomic_cell", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/tests/atomic_cell.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "cache_padded", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/tests/cache_padded.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "parker", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/tests/parker.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "sharded_lock", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/tests/sharded_lock.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "thread", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/tests/thread.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "wait_group", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/tests/wait_group.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "atomic_cell", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/benches/atomic_cell.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/build.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "default": [ + "std" + ], + "loom": [ + "dep:loom" + ], + "nightly": [], + "std": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/crossbeam-utils-0.8.15/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [], + "categories": [ + "algorithms", + "concurrency", + "data-structures", + "no-std" + ], + "keywords": [ + "scoped", + "thread", + "atomic", + "cache" + ], + "readme": "README.md", + "repository": "https://github.com/crossbeam-rs/crossbeam", + "homepage": "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-utils", + "documentation": null, + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": "1.38" + }, + { + "name": "encoding_rs", + "version": "0.8.32", + "id": "encoding_rs 0.8.32 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "(Apache-2.0 OR MIT) AND BSD-3-Clause", + "license_file": null, + "description": "A Gecko-oriented implementation of the Encoding Standard", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "cfg-if", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "packed_simd_2", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3.4", + "kind": null, + "rename": "packed_simd", + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "bincode", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde_derive", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde_json", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "encoding_rs", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/encoding_rs-0.8.32/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": { + "alloc": [], + "default": [ + "alloc" + ], + "fast-big5-hanzi-encode": [], + "fast-gb-hanzi-encode": [], + "fast-hangul-encode": [], + "fast-hanja-encode": [], + "fast-kanji-encode": [], + "fast-legacy-encode": [ + "fast-hangul-encode", + "fast-hanja-encode", + "fast-kanji-encode", + "fast-gb-hanzi-encode", + "fast-big5-hanzi-encode" + ], + "less-slow-big5-hanzi-encode": [], + "less-slow-gb-hanzi-encode": [], + "less-slow-kanji-encode": [], + "packed_simd": [ + "dep:packed_simd" + ], + "serde": [ + "dep:serde" + ], + "simd-accel": [ + "packed_simd", + "packed_simd/into_bits" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/encoding_rs-0.8.32/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Henri Sivonen " + ], + "categories": [ + "text-processing", + "encoding", + "web-programming", + "internationalization" + ], + "keywords": [ + "encoding", + "web", + "unicode", + "charset" + ], + "readme": "README.md", + "repository": "https://github.com/hsivonen/encoding_rs", + "homepage": "https://docs.rs/encoding_rs/", + "documentation": "https://docs.rs/encoding_rs/", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "encoding_rs_io", + "version": "0.1.7", + "id": "encoding_rs_io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "Streaming transcoding for encoding_rs", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "encoding_rs", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.8", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "encoding_rs_io", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/encoding_rs_io-0.1.7/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/encoding_rs_io-0.1.7/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [ + "text-processing", + "encoding", + "web-programming", + "email" + ], + "keywords": [ + "encoding", + "transcoding", + "stream", + "io", + "read" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/encoding_rs_io", + "homepage": null, + "documentation": "https://docs.rs/encoding_rs_io", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "fnv", + "version": "1.0.7", + "id": "fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "Apache-2.0 / MIT", + "license_file": null, + "description": "Fowler–Noll–Vo hash function", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "fnv", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/fnv-1.0.7/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": { + "default": [ + "std" + ], + "std": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/fnv-1.0.7/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Alex Crichton " + ], + "categories": [], + "keywords": [], + "readme": "README.md", + "repository": "https://github.com/servo/rust-fnv", + "homepage": null, + "documentation": "https://doc.servo.org/fnv/", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "glob", + "version": "0.3.1", + "id": "glob 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "Support for matching file paths against Unix shell style patterns.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "doc-comment", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "tempdir", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "glob", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/glob-0.3.1/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "glob-std", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/glob-0.3.1/tests/glob-std.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/glob-0.3.1/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "The Rust Project Developers" + ], + "categories": [ + "filesystem" + ], + "keywords": [], + "readme": "README.md", + "repository": "https://github.com/rust-lang/glob", + "homepage": "https://github.com/rust-lang/glob", + "documentation": "https://docs.rs/glob/0.3.1", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "globset", + "version": "0.4.10", + "id": "globset 0.4.10 (path+file:///$ROOT$ripgrep/crates/globset)", + "license": "Unlicense OR MIT", + "license_file": null, + "description": "Cross platform single glob and glob set matching. Glob set matching is the\nprocess of matching one or more glob patterns against a single candidate path\nsimultaneously, and returning all of the globs that matched.\n", + "source": null, + "dependencies": [ + { + "name": "aho-corasick", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.7.3", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "bstr", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [ + "std" + ], + "target": null, + "registry": null + }, + { + "name": "fnv", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.6", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "log", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4.5", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1.5", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [ + "perf", + "std" + ], + "target": null, + "registry": null + }, + { + "name": "serde", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.104", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "glob", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "lazy_static", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde_json", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.45", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "globset", + "src_path": "$ROOT$ripgrep/crates/globset/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "bench", + "src_path": "$ROOT$ripgrep/crates/globset/benches/bench.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "default": [ + "log" + ], + "log": [ + "dep:log" + ], + "serde": [ + "dep:serde" + ], + "serde1": [ + "serde" + ], + "simd-accel": [] + }, + "manifest_path": "$ROOT$ripgrep/crates/globset/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [], + "keywords": [ + "regex", + "glob", + "multiple", + "set", + "pattern" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/ripgrep/tree/master/crates/globset", + "homepage": "https://github.com/BurntSushi/ripgrep/tree/master/crates/globset", + "documentation": "https://docs.rs/globset", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "grep", + "version": "0.2.11", + "id": "grep 0.2.11 (path+file:///$ROOT$ripgrep/crates/grep)", + "license": "Unlicense OR MIT", + "license_file": null, + "description": "Fast line oriented regex searching as a library.\n", + "source": null, + "dependencies": [ + { + "name": "grep-cli", + "source": null, + "req": "^0.1.7", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$ripgrep/crates/cli" + }, + { + "name": "grep-matcher", + "source": null, + "req": "^0.1.6", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$ripgrep/crates/matcher" + }, + { + "name": "grep-pcre2", + "source": null, + "req": "^0.1.6", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$ripgrep/crates/pcre2" + }, + { + "name": "grep-printer", + "source": null, + "req": "^0.1.7", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$ripgrep/crates/printer" + }, + { + "name": "grep-regex", + "source": null, + "req": "^0.1.11", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$ripgrep/crates/regex" + }, + { + "name": "grep-searcher", + "source": null, + "req": "^0.1.11", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$ripgrep/crates/searcher" + }, + { + "name": "termcolor", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.4", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "walkdir", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2.2.7", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "grep", + "src_path": "$ROOT$ripgrep/crates/grep/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "simplegrep", + "src_path": "$ROOT$ripgrep/crates/grep/examples/simplegrep.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "avx-accel": [], + "grep-pcre2": [ + "dep:grep-pcre2" + ], + "pcre2": [ + "grep-pcre2" + ], + "simd-accel": [ + "grep-searcher/simd-accel" + ] + }, + "manifest_path": "$ROOT$ripgrep/crates/grep/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [], + "keywords": [ + "regex", + "grep", + "egrep", + "search", + "pattern" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/ripgrep/tree/master/crates/grep", + "homepage": "https://github.com/BurntSushi/ripgrep/tree/master/crates/grep", + "documentation": "https://docs.rs/grep", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "grep-cli", + "version": "0.1.7", + "id": "grep-cli 0.1.7 (path+file:///$ROOT$ripgrep/crates/cli)", + "license": "Unlicense OR MIT", + "license_file": null, + "description": "Utilities for search oriented command line applications.\n", + "source": null, + "dependencies": [ + { + "name": "atty", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2.11", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "bstr", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "globset", + "source": null, + "req": "^0.4.10", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$ripgrep/crates/globset" + }, + { + "name": "lazy_static", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "log", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4.5", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "same-file", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.4", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "termcolor", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.4", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "winapi-util", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1.1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": "cfg(windows)", + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "grep-cli", + "src_path": "$ROOT$ripgrep/crates/cli/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$ripgrep/crates/cli/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [], + "keywords": [ + "regex", + "grep", + "cli", + "utility", + "util" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/ripgrep/tree/master/crates/cli", + "homepage": "https://github.com/BurntSushi/ripgrep/tree/master/crates/cli", + "documentation": "https://docs.rs/grep-cli", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "grep-matcher", + "version": "0.1.6", + "id": "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", + "license": "Unlicense OR MIT", + "license_file": null, + "description": "A trait for regular expressions, with a focus on line oriented search.\n", + "source": null, + "dependencies": [ + { + "name": "memchr", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2.1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "grep-matcher", + "src_path": "$ROOT$ripgrep/crates/matcher/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "integration", + "src_path": "$ROOT$ripgrep/crates/matcher/tests/tests.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$ripgrep/crates/matcher/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [], + "keywords": [ + "regex", + "pattern", + "trait" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/ripgrep/tree/master/crates/matcher", + "homepage": "https://github.com/BurntSushi/ripgrep/tree/master/crates/matcher", + "documentation": "https://docs.rs/grep-matcher", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "grep-pcre2", + "version": "0.1.6", + "id": "grep-pcre2 0.1.6 (path+file:///$ROOT$ripgrep/crates/pcre2)", + "license": "Unlicense OR MIT", + "license_file": null, + "description": "Use PCRE2 with the 'grep' crate.\n", + "source": null, + "dependencies": [ + { + "name": "grep-matcher", + "source": null, + "req": "^0.1.6", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$ripgrep/crates/matcher" + }, + { + "name": "pcre2", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2.3", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "grep-pcre2", + "src_path": "$ROOT$ripgrep/crates/pcre2/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$ripgrep/crates/pcre2/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [], + "keywords": [ + "regex", + "grep", + "pcre", + "backreference", + "look" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/ripgrep/tree/master/crates/pcre2", + "homepage": "https://github.com/BurntSushi/ripgrep/tree/master/crates/pcre2", + "documentation": "https://docs.rs/grep-pcre2", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "grep-printer", + "version": "0.1.7", + "id": "grep-printer 0.1.7 (path+file:///$ROOT$ripgrep/crates/printer)", + "license": "Unlicense OR MIT", + "license_file": null, + "description": "An implementation of the grep crate's Sink trait that provides standard\nprinting of search results, similar to grep itself.\n", + "source": null, + "dependencies": [ + { + "name": "base64", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.20.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "bstr", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "grep-matcher", + "source": null, + "req": "^0.1.6", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$ripgrep/crates/matcher" + }, + { + "name": "grep-searcher", + "source": null, + "req": "^0.1.11", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$ripgrep/crates/searcher" + }, + { + "name": "serde", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.77", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [ + "derive" + ], + "target": null, + "registry": null + }, + { + "name": "serde_json", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.27", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "termcolor", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.4", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "grep-regex", + "source": null, + "req": "^0.1.11", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$ripgrep/crates/regex" + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "grep-printer", + "src_path": "$ROOT$ripgrep/crates/printer/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": { + "base64": [ + "dep:base64" + ], + "default": [ + "serde1" + ], + "serde": [ + "dep:serde" + ], + "serde1": [ + "base64", + "serde", + "serde_json" + ], + "serde_json": [ + "dep:serde_json" + ] + }, + "manifest_path": "$ROOT$ripgrep/crates/printer/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [], + "keywords": [ + "grep", + "pattern", + "print", + "printer", + "sink" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/ripgrep/tree/master/crates/printer", + "homepage": "https://github.com/BurntSushi/ripgrep/tree/master/crates/printer", + "documentation": "https://docs.rs/grep-printer", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "grep-regex", + "version": "0.1.11", + "id": "grep-regex 0.1.11 (path+file:///$ROOT$ripgrep/crates/regex)", + "license": "Unlicense OR MIT", + "license_file": null, + "description": "Use Rust's regex library with the 'grep' crate.\n", + "source": null, + "dependencies": [ + { + "name": "aho-corasick", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.7.3", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "bstr", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "grep-matcher", + "source": null, + "req": "^0.1.6", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$ripgrep/crates/matcher" + }, + { + "name": "log", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4.5", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex-syntax", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.6.5", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "thread_local", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1.2", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "grep-regex", + "src_path": "$ROOT$ripgrep/crates/regex/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$ripgrep/crates/regex/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [], + "keywords": [ + "regex", + "grep", + "search", + "pattern", + "line" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/ripgrep/tree/master/crates/regex", + "homepage": "https://github.com/BurntSushi/ripgrep/tree/master/crates/regex", + "documentation": "https://docs.rs/grep-regex", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "grep-searcher", + "version": "0.1.11", + "id": "grep-searcher 0.1.11 (path+file:///$ROOT$ripgrep/crates/searcher)", + "license": "Unlicense OR MIT", + "license_file": null, + "description": "Fast line oriented regex searching as a library.\n", + "source": null, + "dependencies": [ + { + "name": "bstr", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [ + "std" + ], + "target": null, + "registry": null + }, + { + "name": "bytecount", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.6", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "encoding_rs", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.8.14", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "encoding_rs_io", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1.6", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "grep-matcher", + "source": null, + "req": "^0.1.6", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$ripgrep/crates/matcher" + }, + { + "name": "log", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4.5", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "memmap2", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.5.3", + "kind": null, + "rename": "memmap", + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "grep-regex", + "source": null, + "req": "^0.1.11", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$ripgrep/crates/regex" + }, + { + "name": "regex", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "grep-searcher", + "src_path": "$ROOT$ripgrep/crates/searcher/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "search-stdin", + "src_path": "$ROOT$ripgrep/crates/searcher/examples/search-stdin.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "avx-accel": [], + "default": [ + "bytecount/runtime-dispatch-simd" + ], + "simd-accel": [ + "encoding_rs/simd-accel" + ] + }, + "manifest_path": "$ROOT$ripgrep/crates/searcher/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [], + "keywords": [ + "regex", + "grep", + "egrep", + "search", + "pattern" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/ripgrep/tree/master/crates/searcher", + "homepage": "https://github.com/BurntSushi/ripgrep/tree/master/crates/searcher", + "documentation": "https://docs.rs/grep-searcher", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "hermit-abi", + "version": "0.1.19", + "id": "hermit-abi 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT/Apache-2.0", + "license_file": null, + "description": "hermit-abi is small interface to call functions from the unikernel RustyHermit.\nIt is used to build the target `x86_64-unknown-hermit`.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "compiler_builtins", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustc-std-workspace-core", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.0", + "kind": null, + "rename": "core", + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "libc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2.51", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "hermit-abi", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/hermit-abi-0.1.19/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": { + "compiler_builtins": [ + "dep:compiler_builtins" + ], + "core": [ + "dep:core" + ], + "default": [], + "docs": [], + "rustc-dep-of-std": [ + "core", + "compiler_builtins/rustc-dep-of-std", + "libc/rustc-dep-of-std" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/hermit-abi-0.1.19/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "default-target": "x86_64-unknown-hermit", + "features": [ + "docs" + ] + } + } + }, + "publish": null, + "authors": [ + "Stefan Lankes" + ], + "categories": [ + "os" + ], + "keywords": [ + "unikernel", + "libos" + ], + "readme": "README.md", + "repository": "https://github.com/hermitcore/libhermit-rs", + "homepage": null, + "documentation": "https://hermitcore.github.io/rusty-hermit/hermit_abi", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "ignore", + "version": "0.4.20", + "id": "ignore 0.4.20 (path+file:///$ROOT$ripgrep/crates/ignore)", + "license": "Unlicense OR MIT", + "license_file": null, + "description": "A fast library for efficiently matching ignore files such as `.gitignore`\nagainst file paths.\n", + "source": null, + "dependencies": [ + { + "name": "globset", + "source": null, + "req": "^0.4.10", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$ripgrep/crates/globset" + }, + { + "name": "lazy_static", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "log", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4.5", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "memchr", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2.1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "same-file", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.4", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "thread_local", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "walkdir", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2.2.7", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "crossbeam-channel", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.5.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "winapi-util", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1.2", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": "cfg(windows)", + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "ignore", + "src_path": "$ROOT$ripgrep/crates/ignore/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "walk", + "src_path": "$ROOT$ripgrep/crates/ignore/examples/walk.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "gitignore_matched_path_or_any_parents_tests", + "src_path": "$ROOT$ripgrep/crates/ignore/tests/gitignore_matched_path_or_any_parents_tests.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + } + ], + "features": { + "simd-accel": [ + "globset/simd-accel" + ] + }, + "manifest_path": "$ROOT$ripgrep/crates/ignore/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [], + "keywords": [ + "glob", + "ignore", + "gitignore", + "pattern", + "file" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/ripgrep/tree/master/crates/ignore", + "homepage": "https://github.com/BurntSushi/ripgrep/tree/master/crates/ignore", + "documentation": "https://docs.rs/ignore", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "itoa", + "version": "1.0.6", + "id": "itoa 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "Fast integer primitive to string conversion", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "no-panic", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "itoa", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/itoa-1.0.6/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/itoa-1.0.6/tests/test.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "bench", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/itoa-1.0.6/benches/bench.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "no-panic": [ + "dep:no-panic" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/itoa-1.0.6/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "targets": [ + "x86_64-unknown-linux-gnu" + ] + } + } + }, + "publish": null, + "authors": [ + "David Tolnay " + ], + "categories": [ + "value-formatting", + "no-std" + ], + "keywords": [ + "integer" + ], + "readme": "README.md", + "repository": "https://github.com/dtolnay/itoa", + "homepage": null, + "documentation": "https://docs.rs/itoa", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": "1.36" + }, + { + "name": "jemalloc-sys", + "version": "0.5.3+5.3.0-patched", + "id": "jemalloc-sys 0.5.3+5.3.0-patched (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT/Apache-2.0", + "license_file": null, + "description": "Rust FFI bindings to jemalloc\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "libc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2.8", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "cc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.13", + "kind": "build", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "jemalloc-sys", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemalloc-sys-0.5.3+5.3.0-patched/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "malloc_conf_empty", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemalloc-sys-0.5.3+5.3.0-patched/tests/malloc_conf_empty.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "malloc_conf_set", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemalloc-sys-0.5.3+5.3.0-patched/tests/malloc_conf_set.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "unprefixed_malloc", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemalloc-sys-0.5.3+5.3.0-patched/tests/unprefixed_malloc.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemalloc-sys-0.5.3+5.3.0-patched/build.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "background_threads": [ + "background_threads_runtime_support" + ], + "background_threads_runtime_support": [], + "debug": [], + "default": [ + "background_threads_runtime_support" + ], + "disable_initial_exec_tls": [], + "profiling": [], + "stats": [], + "unprefixed_malloc_on_supported_platforms": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemalloc-sys-0.5.3+5.3.0-patched/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "rustdoc-args": [ + "--cfg", + "jemallocator_docs" + ] + } + } + }, + "publish": null, + "authors": [ + "Alex Crichton ", + "Gonzalo Brito Gadeschi ", + "The TiKV Project Developers" + ], + "categories": [], + "keywords": [ + "allocator", + "jemalloc" + ], + "readme": "README.md", + "repository": "https://github.com/tikv/jemallocator", + "homepage": "https://github.com/tikv/jemallocator", + "documentation": "https://docs.rs/jemallocator-sys", + "edition": "2018", + "links": "jemalloc", + "default_run": null, + "rust_version": null + }, + { + "name": "jemallocator", + "version": "0.5.0", + "id": "jemallocator 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT/Apache-2.0", + "license_file": null, + "description": "A Rust allocator backed by jemalloc\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "jemalloc-sys", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.5.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "libc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2.8", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "paste", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "jemallocator", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": false + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "background_thread_defaults", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/tests/background_thread_defaults.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "background_thread_enabled", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/tests/background_thread_enabled.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "ffi", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/tests/ffi.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "grow_in_place", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/tests/grow_in_place.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "malloctl", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/tests/malloctl.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "shrink_in_place", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/tests/shrink_in_place.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "smoke", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/tests/smoke.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "smoke_ffi", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/tests/smoke_ffi.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "usable_size", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/tests/usable_size.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "roundtrip", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/benches/roundtrip.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "alloc_trait": [], + "background_threads": [ + "jemalloc-sys/background_threads" + ], + "background_threads_runtime_support": [ + "jemalloc-sys/background_threads_runtime_support" + ], + "debug": [ + "jemalloc-sys/debug" + ], + "default": [ + "background_threads_runtime_support" + ], + "disable_initial_exec_tls": [ + "jemalloc-sys/disable_initial_exec_tls" + ], + "profiling": [ + "jemalloc-sys/profiling" + ], + "stats": [ + "jemalloc-sys/stats" + ], + "unprefixed_malloc_on_supported_platforms": [ + "jemalloc-sys/unprefixed_malloc_on_supported_platforms" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemallocator-0.5.0/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "features": [], + "rustdoc-args": [ + "--cfg", + "jemallocator_docs" + ] + } + } + }, + "publish": null, + "authors": [ + "Alex Crichton ", + "Gonzalo Brito Gadeschi ", + "Simon Sapin ", + "Steven Fackler ", + "The TiKV Project Developers" + ], + "categories": [ + "memory-management", + "api-bindings" + ], + "keywords": [ + "allocator", + "jemalloc" + ], + "readme": "README.md", + "repository": "https://github.com/tikv/jemallocator", + "homepage": "https://github.com/tikv/jemallocator", + "documentation": "https://docs.rs/jemallocator", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "jobserver", + "version": "0.1.26", + "id": "jobserver 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT/Apache-2.0", + "license_file": null, + "description": "An implementation of the GNU make jobserver for Rust\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "futures", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "num_cpus", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "tempfile", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "tokio-core", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "tokio-process", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "libc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2.50", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": "cfg(unix)", + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "jobserver", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jobserver-0.1.26/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "client", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jobserver-0.1.26/tests/client.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "server", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jobserver-0.1.26/tests/server.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "client-of-myself", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jobserver-0.1.26/tests/client-of-myself.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "make-as-a-client", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jobserver-0.1.26/tests/make-as-a-client.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "helper", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jobserver-0.1.26/tests/helper.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/jobserver-0.1.26/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Alex Crichton " + ], + "categories": [], + "keywords": [], + "readme": "README.md", + "repository": "https://github.com/alexcrichton/jobserver-rs", + "homepage": "https://github.com/alexcrichton/jobserver-rs", + "documentation": "https://docs.rs/jobserver", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "lazy_static", + "version": "1.4.0", + "id": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT/Apache-2.0", + "license_file": null, + "description": "A macro for declaring lazily evaluated statics in Rust.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "spin", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.5.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "doc-comment", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3.1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "lazy_static", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/lazy_static-1.4.0/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "no_std", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/lazy_static-1.4.0/tests/no_std.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/lazy_static-1.4.0/tests/test.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": true + } + ], + "features": { + "spin": [ + "dep:spin" + ], + "spin_no_std": [ + "spin" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/lazy_static-1.4.0/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Marvin Löbel " + ], + "categories": [ + "no-std", + "rust-patterns", + "memory-management" + ], + "keywords": [ + "macro", + "lazy", + "static" + ], + "readme": "README.md", + "repository": "https://github.com/rust-lang-nursery/lazy-static.rs", + "homepage": null, + "documentation": "https://docs.rs/lazy_static", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "libc", + "version": "0.2.142", + "id": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "Raw FFI bindings to platform libraries like libc.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "rustc-std-workspace-core", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "libc", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/libc-0.2.142/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "const_fn", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/libc-0.2.142/tests/const_fn.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/libc-0.2.142/build.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "align": [], + "const-extern-fn": [], + "default": [ + "std" + ], + "extra_traits": [], + "rustc-dep-of-std": [ + "align", + "rustc-std-workspace-core" + ], + "rustc-std-workspace-core": [ + "dep:rustc-std-workspace-core" + ], + "std": [], + "use_std": [ + "std" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/libc-0.2.142/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "features": [ + "const-extern-fn", + "extra_traits" + ] + } + } + }, + "publish": null, + "authors": [ + "The Rust Project Developers" + ], + "categories": [ + "external-ffi-bindings", + "no-std", + "os" + ], + "keywords": [ + "libc", + "ffi", + "bindings", + "operating", + "system" + ], + "readme": "README.md", + "repository": "https://github.com/rust-lang/libc", + "homepage": "https://github.com/rust-lang/libc", + "documentation": "https://docs.rs/libc/", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "log", + "version": "0.4.17", + "id": "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "A lightweight logging facade for Rust\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "cfg-if", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "sval", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "=1.0.0-alpha.5", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "value-bag", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "=1.0.0-alpha.9", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustversion", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [ + "derive" + ], + "target": null, + "registry": null + }, + { + "name": "serde_test", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "sval", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "=1.0.0-alpha.5", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [ + "derive" + ], + "target": null, + "registry": null + }, + { + "name": "value-bag", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "=1.0.0-alpha.9", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [ + "test" + ], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "log", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/log-0.4.17/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "filters", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/log-0.4.17/tests/filters.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "macros", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/log-0.4.17/tests/macros.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "value", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/log-0.4.17/benches/value.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/log-0.4.17/build.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "kv_unstable": [ + "value-bag" + ], + "kv_unstable_serde": [ + "kv_unstable_std", + "value-bag/serde", + "serde" + ], + "kv_unstable_std": [ + "std", + "kv_unstable", + "value-bag/error" + ], + "kv_unstable_sval": [ + "kv_unstable", + "value-bag/sval", + "sval" + ], + "max_level_debug": [], + "max_level_error": [], + "max_level_info": [], + "max_level_off": [], + "max_level_trace": [], + "max_level_warn": [], + "release_max_level_debug": [], + "release_max_level_error": [], + "release_max_level_info": [], + "release_max_level_off": [], + "release_max_level_trace": [], + "release_max_level_warn": [], + "serde": [ + "dep:serde" + ], + "std": [], + "sval": [ + "dep:sval" + ], + "value-bag": [ + "dep:value-bag" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/log-0.4.17/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "features": [ + "std", + "serde", + "kv_unstable_std", + "kv_unstable_sval", + "kv_unstable_serde" + ] + } + } + }, + "publish": null, + "authors": [ + "The Rust Project Developers" + ], + "categories": [ + "development-tools::debugging" + ], + "keywords": [ + "logging" + ], + "readme": "README.md", + "repository": "https://github.com/rust-lang/log", + "homepage": null, + "documentation": "https://docs.rs/log", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "memchr", + "version": "2.5.0", + "id": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "Unlicense/MIT", + "license_file": null, + "description": "Safe interface to memchr.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "compiler_builtins", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1.2", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustc-std-workspace-core", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.0", + "kind": null, + "rename": "core", + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "libc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2.18", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "quickcheck", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "memchr", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memchr-2.5.0/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memchr-2.5.0/build.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "compiler_builtins": [ + "dep:compiler_builtins" + ], + "core": [ + "dep:core" + ], + "default": [ + "std" + ], + "libc": [ + "dep:libc" + ], + "rustc-dep-of-std": [ + "core", + "compiler_builtins" + ], + "std": [], + "use_std": [ + "std" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memchr-2.5.0/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant ", + "bluss" + ], + "categories": [], + "keywords": [ + "memchr", + "char", + "scan", + "strchr", + "string" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/memchr", + "homepage": "https://github.com/BurntSushi/memchr", + "documentation": "https://docs.rs/memchr/", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "memmap2", + "version": "0.5.10", + "id": "memmap2 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "Cross-platform Rust API for memory-mapped file IO", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "stable_deref_trait", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "owning_ref", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4.1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "tempfile", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "libc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": "cfg(unix)", + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "memmap2", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memmap2-0.5.10/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "cat", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memmap2-0.5.10/examples/cat.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "stable_deref_trait": [ + "dep:stable_deref_trait" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/memmap2-0.5.10/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Dan Burkert ", + "Yevhenii Reizner " + ], + "categories": [], + "keywords": [ + "mmap", + "memory-map", + "io", + "file" + ], + "readme": "README.md", + "repository": "https://github.com/RazrFalcon/memmap2-rs", + "homepage": null, + "documentation": "https://docs.rs/memmap2", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "once_cell", + "version": "1.17.1", + "id": "once_cell 1.17.1 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "Single assignment cells and lazy values.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "atomic-polyfill", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": null, + "rename": "atomic_polyfill", + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "critical-section", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": null, + "rename": "critical_section", + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "parking_lot_core", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.9.3", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "critical-section", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1.1", + "kind": "dev", + "rename": "critical_section", + "optional": false, + "uses_default_features": true, + "features": [ + "std" + ], + "target": null, + "registry": null + }, + { + "name": "crossbeam-utils", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.8.7", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "lazy_static", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.2.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "once_cell", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "bench", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/examples/bench.rs", + "edition": "2021", + "required-features": [ + "std" + ], + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "bench_acquire", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/examples/bench_acquire.rs", + "edition": "2021", + "required-features": [ + "std" + ], + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "bench_vs_lazy_static", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/examples/bench_vs_lazy_static.rs", + "edition": "2021", + "required-features": [ + "std" + ], + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "lazy_static", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/examples/lazy_static.rs", + "edition": "2021", + "required-features": [ + "std" + ], + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "reentrant_init_deadlocks", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/examples/reentrant_init_deadlocks.rs", + "edition": "2021", + "required-features": [ + "std" + ], + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "regex", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/examples/regex.rs", + "edition": "2021", + "required-features": [ + "std" + ], + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "test_synchronization", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/examples/test_synchronization.rs", + "edition": "2021", + "required-features": [ + "std" + ], + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "it", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/tests/it.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + } + ], + "features": { + "alloc": [ + "race" + ], + "atomic-polyfill": [ + "critical-section" + ], + "atomic_polyfill": [ + "dep:atomic_polyfill" + ], + "critical-section": [ + "critical_section", + "atomic_polyfill" + ], + "critical_section": [ + "dep:critical_section" + ], + "default": [ + "std" + ], + "parking_lot": [ + "parking_lot_core" + ], + "parking_lot_core": [ + "dep:parking_lot_core" + ], + "race": [], + "std": [ + "alloc" + ], + "unstable": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/once_cell-1.17.1/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "all-features": true + } + } + }, + "publish": null, + "authors": [ + "Aleksey Kladov " + ], + "categories": [ + "rust-patterns", + "memory-management" + ], + "keywords": [ + "lazy", + "static" + ], + "readme": "README.md", + "repository": "https://github.com/matklad/once_cell", + "homepage": null, + "documentation": "https://docs.rs/once_cell", + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": "1.56" + }, + { + "name": "pcre2", + "version": "0.2.3", + "id": "pcre2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "Unlicense/MIT", + "license_file": null, + "description": "High level wrapper library for PCRE2.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "libc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2.46", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "log", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4.5", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "pcre2-sys", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "thread_local", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "pcre2", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pcre2-0.2.3/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pcre2-0.2.3/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [ + "text-processing" + ], + "keywords": [ + "pcre", + "pcre2", + "regex", + "jit", + "perl" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/rust-pcre2", + "homepage": "https://github.com/BurntSushi/rust-pcre2", + "documentation": "https://docs.rs/pcre2", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "pcre2-sys", + "version": "0.2.5", + "id": "pcre2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "Unlicense/MIT", + "license_file": null, + "description": "Low level bindings to PCRE2.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "libc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "cc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "build", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [ + "parallel" + ], + "target": null, + "registry": null + }, + { + "name": "pkg-config", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3.13", + "kind": "build", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "pcre2-sys", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pcre2-sys-0.2.5/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pcre2-sys-0.2.5/build.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pcre2-sys-0.2.5/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [ + "external-ffi-bindings" + ], + "keywords": [ + "pcre", + "pcre2", + "regex", + "jit" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/rust-pcre2", + "homepage": "https://github.com/BurntSushi/rust-pcre2", + "documentation": "https://docs.rs/pcre2-sys", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "pkg-config", + "version": "0.3.26", + "id": "pkg-config 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "A library to run the pkg-config system tool at build time in order to be used in\nCargo build scripts.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "lazy_static", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "pkg-config", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pkg-config-0.3.26/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pkg-config-0.3.26/tests/test.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/pkg-config-0.3.26/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Alex Crichton " + ], + "categories": [], + "keywords": [ + "build-dependencies" + ], + "readme": "README.md", + "repository": "https://github.com/rust-lang/pkg-config-rs", + "homepage": null, + "documentation": "https://docs.rs/pkg-config", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "proc-macro2", + "version": "1.0.56", + "id": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "A substitute implementation of the compiler's `proc_macro` API to decouple token-based libraries from the procedural macro use case.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "unicode-ident", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "quote", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustversion", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "proc-macro2", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "comments", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/comments.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "features", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/features.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "marker", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/marker.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/test.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_fmt", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/test_fmt.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_size", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/tests/test_size.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/build.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "default": [ + "proc-macro" + ], + "nightly": [], + "proc-macro": [], + "span-locations": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/proc-macro2-1.0.56/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "rustc-args": [ + "--cfg", + "procmacro2_semver_exempt" + ], + "rustdoc-args": [ + "--cfg", + "procmacro2_semver_exempt", + "--cfg", + "doc_cfg" + ], + "targets": [ + "x86_64-unknown-linux-gnu" + ] + } + }, + "playground": { + "features": [ + "span-locations" + ] + } + }, + "publish": null, + "authors": [ + "David Tolnay ", + "Alex Crichton " + ], + "categories": [ + "development-tools::procedural-macro-helpers" + ], + "keywords": [ + "macros", + "syn" + ], + "readme": "README.md", + "repository": "https://github.com/dtolnay/proc-macro2", + "homepage": null, + "documentation": "https://docs.rs/proc-macro2", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": "1.31" + }, + { + "name": "quote", + "version": "1.0.26", + "id": "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "Quasi-quoting macro quote!(...)", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "proc-macro2", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.52", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustversion", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "trybuild", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.66", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [ + "diff" + ], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "quote", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "compiletest", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/tests/compiletest.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/tests/test.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/build.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "default": [ + "proc-macro" + ], + "proc-macro": [ + "proc-macro2/proc-macro" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/quote-1.0.26/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "targets": [ + "x86_64-unknown-linux-gnu" + ] + } + } + }, + "publish": null, + "authors": [ + "David Tolnay " + ], + "categories": [ + "development-tools::procedural-macro-helpers" + ], + "keywords": [ + "macros", + "syn" + ], + "readme": "README.md", + "repository": "https://github.com/dtolnay/quote", + "homepage": null, + "documentation": "https://docs.rs/quote/", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": "1.31" + }, + { + "name": "regex", + "version": "1.8.1", + "id": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "An implementation of regular expressions for Rust. This implementation uses\nfinite automata and guarantees linear time matching on all inputs.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "aho-corasick", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "memchr", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2.5.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex-syntax", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.7.1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "lazy_static", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "quickcheck", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rand", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.8.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [ + "getrandom", + "small_rng" + ], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "regex", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": false, + "test": true + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "shootout-regex-dna-bytes", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-bytes.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "shootout-regex-dna-cheat", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-cheat.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "shootout-regex-dna-replace", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-replace.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "shootout-regex-dna-single-cheat", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-single-cheat.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "shootout-regex-dna-single", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna-single.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "shootout-regex-dna", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/examples/shootout-regex-dna.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "default", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_default.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "default-bytes", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_default_bytes.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "nfa", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_nfa.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "nfa-utf8bytes", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_nfa_utf8bytes.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "nfa-bytes", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_nfa_bytes.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "backtrack", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_backtrack.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "backtrack-utf8bytes", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_backtrack_utf8bytes.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "backtrack-bytes", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_backtrack_bytes.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "crates-regex", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/tests/test_crates_regex.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + } + ], + "features": { + "aho-corasick": [ + "dep:aho-corasick" + ], + "default": [ + "std", + "perf", + "unicode", + "regex-syntax/default" + ], + "memchr": [ + "dep:memchr" + ], + "pattern": [], + "perf": [ + "perf-cache", + "perf-dfa", + "perf-inline", + "perf-literal" + ], + "perf-cache": [], + "perf-dfa": [], + "perf-inline": [], + "perf-literal": [ + "aho-corasick", + "memchr" + ], + "std": [], + "unicode": [ + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment", + "regex-syntax/unicode" + ], + "unicode-age": [ + "regex-syntax/unicode-age" + ], + "unicode-bool": [ + "regex-syntax/unicode-bool" + ], + "unicode-case": [ + "regex-syntax/unicode-case" + ], + "unicode-gencat": [ + "regex-syntax/unicode-gencat" + ], + "unicode-perl": [ + "regex-syntax/unicode-perl" + ], + "unicode-script": [ + "regex-syntax/unicode-script" + ], + "unicode-segment": [ + "regex-syntax/unicode-segment" + ], + "unstable": [ + "pattern" + ], + "use_std": [ + "std" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-1.8.1/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "The Rust Project Developers" + ], + "categories": [ + "text-processing" + ], + "keywords": [], + "readme": "README.md", + "repository": "https://github.com/rust-lang/regex", + "homepage": "https://github.com/rust-lang/regex", + "documentation": "https://docs.rs/regex", + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": "1.60.0" + }, + { + "name": "regex-automata", + "version": "0.1.10", + "id": "regex-automata 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "Unlicense/MIT", + "license_file": null, + "description": "Automata construction and matching using regular expressions.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "fst", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex-syntax", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.6.16", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "bstr", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [ + "std" + ], + "target": null, + "registry": null + }, + { + "name": "lazy_static", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.2.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.82", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde_bytes", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.11", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde_derive", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.82", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "toml", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4.10", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "regex-automata", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-automata-0.1.10/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "default", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-automata-0.1.10/tests/tests.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": true + } + ], + "features": { + "default": [ + "std" + ], + "fst": [ + "dep:fst" + ], + "regex-syntax": [ + "dep:regex-syntax" + ], + "std": [ + "regex-syntax" + ], + "transducer": [ + "std", + "fst" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-automata-0.1.10/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [ + "text-processing" + ], + "keywords": [ + "regex", + "dfa", + "automata", + "automaton", + "nfa" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/regex-automata", + "homepage": "https://github.com/BurntSushi/regex-automata", + "documentation": "https://docs.rs/regex-automata", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "regex-syntax", + "version": "0.6.29", + "id": "regex-syntax 0.6.29 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "A regular expression parser.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "regex-syntax", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-syntax-0.6.29/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "bench", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-syntax-0.6.29/benches/bench.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "default": [ + "unicode" + ], + "unicode": [ + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment" + ], + "unicode-age": [], + "unicode-bool": [], + "unicode-case": [], + "unicode-gencat": [], + "unicode-perl": [], + "unicode-script": [], + "unicode-segment": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-syntax-0.6.29/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "The Rust Project Developers" + ], + "categories": [], + "keywords": [], + "readme": "README.md", + "repository": "https://github.com/rust-lang/regex", + "homepage": "https://github.com/rust-lang/regex", + "documentation": "https://docs.rs/regex-syntax", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "regex-syntax", + "version": "0.7.1", + "id": "regex-syntax 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "A regular expression parser.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "regex-syntax", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-syntax-0.7.1/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "bench", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-syntax-0.7.1/benches/bench.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "default": [ + "std", + "unicode" + ], + "std": [], + "unicode": [ + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment" + ], + "unicode-age": [], + "unicode-bool": [], + "unicode-case": [], + "unicode-gencat": [], + "unicode-perl": [], + "unicode-script": [], + "unicode-segment": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/regex-syntax-0.7.1/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "all-features": true, + "rustdoc-args": [ + "--cfg", + "docsrs" + ] + } + } + }, + "publish": null, + "authors": [ + "The Rust Project Developers" + ], + "categories": [], + "keywords": [], + "readme": "README.md", + "repository": "https://github.com/rust-lang/regex", + "homepage": "https://github.com/rust-lang/regex", + "documentation": "https://docs.rs/regex-syntax", + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": "1.60.0" + }, + { + "name": "ripgrep", + "version": "13.0.0", + "id": "ripgrep 13.0.0 (path+file:///$ROOT$ripgrep)", + "license": "Unlicense OR MIT", + "license_file": null, + "description": "ripgrep is a line-oriented search tool that recursively searches the current\ndirectory for a regex pattern while respecting gitignore rules. ripgrep has\nfirst class support on Windows, macOS and Linux.\n", + "source": null, + "dependencies": [ + { + "name": "bstr", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "clap", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2.33.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [ + "suggestions" + ], + "target": null, + "registry": null + }, + { + "name": "grep", + "source": null, + "req": "^0.2.11", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$ripgrep/crates/grep" + }, + { + "name": "ignore", + "source": null, + "req": "^0.4.19", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$ripgrep/crates/ignore" + }, + { + "name": "lazy_static", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "log", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4.5", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.3.5", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde_json", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.23", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "termcolor", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.77", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde_derive", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.77", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "walkdir", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "clap", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2.33.0", + "kind": "build", + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [ + "suggestions" + ], + "target": null, + "registry": null + }, + { + "name": "lazy_static", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.1.0", + "kind": "build", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "jemallocator", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.5.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": "cfg(all(target_env = \"musl\", target_pointer_width = \"64\"))", + "registry": null + } + ], + "targets": [ + { + "kind": [ + "bin" + ], + "crate_types": [ + "bin" + ], + "name": "rg", + "src_path": "$ROOT$ripgrep/crates/core/main.rs", + "edition": "2018", + "doc": true, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "integration", + "src_path": "$ROOT$ripgrep/tests/tests.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$ripgrep/build.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "pcre2": [ + "grep/pcre2" + ], + "simd-accel": [ + "grep/simd-accel" + ] + }, + "manifest_path": "$ROOT$ripgrep/Cargo.toml", + "metadata": { + "deb": { + "assets": [ + [ + "target/release/rg", + "usr/bin/", + "755" + ], + [ + "COPYING", + "usr/share/doc/ripgrep/", + "644" + ], + [ + "LICENSE-MIT", + "usr/share/doc/ripgrep/", + "644" + ], + [ + "UNLICENSE", + "usr/share/doc/ripgrep/", + "644" + ], + [ + "CHANGELOG.md", + "usr/share/doc/ripgrep/CHANGELOG", + "644" + ], + [ + "README.md", + "usr/share/doc/ripgrep/README", + "644" + ], + [ + "FAQ.md", + "usr/share/doc/ripgrep/FAQ", + "644" + ], + [ + "deployment/deb/rg.1", + "usr/share/man/man1/rg.1", + "644" + ], + [ + "deployment/deb/rg.bash", + "usr/share/bash-completion/completions/rg", + "644" + ], + [ + "deployment/deb/rg.fish", + "usr/share/fish/vendor_completions.d/rg.fish", + "644" + ], + [ + "deployment/deb/_rg", + "usr/share/zsh/vendor-completions/", + "644" + ] + ], + "extended-description": "ripgrep (rg) recursively searches your current directory for a regex pattern.\nBy default, ripgrep will respect your .gitignore and automatically skip hidden\nfiles/directories and binary files.\n", + "features": [ + "pcre2" + ], + "section": "utils" + } + }, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [ + "command-line-utilities", + "text-processing" + ], + "keywords": [ + "regex", + "grep", + "egrep", + "search", + "pattern" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/ripgrep", + "homepage": "https://github.com/BurntSushi/ripgrep", + "documentation": "https://github.com/BurntSushi/ripgrep", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": "1.65" + }, + { + "name": "ryu", + "version": "1.0.13", + "id": "ryu 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "Apache-2.0 OR BSL-1.0", + "license_file": null, + "description": "Fast floating point to string conversion", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "no-panic", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "num_cpus", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.8", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rand", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.8", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rand_xorshift", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "ryu", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "upstream_benchmark", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/examples/upstream_benchmark.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "common_test", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/tests/common_test.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "d2s_table_test", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/tests/d2s_table_test.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "d2s_test", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/tests/d2s_test.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "exhaustive", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/tests/exhaustive.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "f2s_test", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/tests/f2s_test.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "s2d_test", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/tests/s2d_test.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "s2f_test", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/tests/s2f_test.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "bench", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/benches/bench.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "no-panic": [ + "dep:no-panic" + ], + "small": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.13/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "targets": [ + "x86_64-unknown-linux-gnu" + ] + } + } + }, + "publish": null, + "authors": [ + "David Tolnay " + ], + "categories": [ + "value-formatting", + "no-std" + ], + "keywords": [ + "float" + ], + "readme": "README.md", + "repository": "https://github.com/dtolnay/ryu", + "homepage": null, + "documentation": "https://docs.rs/ryu", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": "1.36" + }, + { + "name": "same-file", + "version": "1.0.6", + "id": "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "Unlicense/MIT", + "license_file": null, + "description": "A simple crate for determining whether two file paths point to the same file.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "doc-comment", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "winapi-util", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1.1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": "cfg(windows)", + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "same-file", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/same-file-1.0.6/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "is_same_file", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/same-file-1.0.6/examples/is_same_file.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "is_stderr", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/same-file-1.0.6/examples/is_stderr.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/same-file-1.0.6/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [], + "keywords": [ + "same", + "file", + "equal", + "inode" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/same-file", + "homepage": "https://github.com/BurntSushi/same-file", + "documentation": "https://docs.rs/same-file", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "serde", + "version": "1.0.160", + "id": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "A generic serialization/deserialization framework", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "serde_derive", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "=1.0.160", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde_derive", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "serde", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-1.0.160/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-1.0.160/build.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "alloc": [], + "default": [ + "std" + ], + "derive": [ + "serde_derive" + ], + "rc": [], + "serde_derive": [ + "dep:serde_derive" + ], + "std": [], + "unstable": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-1.0.160/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "features": [ + "derive" + ], + "targets": [ + "x86_64-unknown-linux-gnu" + ] + } + }, + "playground": { + "features": [ + "derive", + "rc" + ] + } + }, + "publish": null, + "authors": [ + "Erick Tryzelaar ", + "David Tolnay " + ], + "categories": [ + "encoding", + "no-std" + ], + "keywords": [ + "serde", + "serialization", + "no_std" + ], + "readme": "crates-io.md", + "repository": "https://github.com/serde-rs/serde", + "homepage": "https://serde.rs", + "documentation": "https://docs.rs/serde", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": "1.19" + }, + { + "name": "serde_derive", + "version": "1.0.160", + "id": "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "proc-macro2", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "quote", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "syn", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2.0.3", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "proc-macro" + ], + "crate_types": [ + "proc-macro" + ], + "name": "serde_derive", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_derive-1.0.160/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_derive-1.0.160/build.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "default": [], + "deserialize_in_place": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_derive-1.0.160/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "targets": [ + "x86_64-unknown-linux-gnu" + ] + } + } + }, + "publish": null, + "authors": [ + "Erick Tryzelaar ", + "David Tolnay " + ], + "categories": [ + "no-std" + ], + "keywords": [ + "serde", + "serialization", + "no_std", + "derive" + ], + "readme": "crates-io.md", + "repository": "https://github.com/serde-rs/serde", + "homepage": "https://serde.rs", + "documentation": "https://serde.rs/derive.html", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": "1.56" + }, + { + "name": "serde_json", + "version": "1.0.96", + "id": "serde_json 1.0.96 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "A JSON serialization file format", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "indexmap", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.5.2", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [ + "std" + ], + "target": null, + "registry": null + }, + { + "name": "itoa", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "ryu", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.100", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "automod", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "indoc", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "ref-cast", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustversion", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.100", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [ + "derive" + ], + "target": null, + "registry": null + }, + { + "name": "serde_bytes", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.11", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde_derive", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "serde_stacker", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "trybuild", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.49", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [ + "diff" + ], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "serde_json", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "compiletest", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/tests/compiletest.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "debug", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/tests/debug.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "lexical", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/tests/lexical.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "map", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/tests/map.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "regression", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/tests/regression.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "stream", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/tests/stream.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/tests/test.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/build.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "alloc": [ + "serde/alloc" + ], + "arbitrary_precision": [], + "default": [ + "std" + ], + "float_roundtrip": [], + "indexmap": [ + "dep:indexmap" + ], + "preserve_order": [ + "indexmap", + "std" + ], + "raw_value": [], + "std": [ + "serde/std" + ], + "unbounded_depth": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde_json-1.0.96/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "features": [ + "raw_value", + "unbounded_depth" + ], + "rustdoc-args": [ + "--cfg", + "docsrs" + ], + "targets": [ + "x86_64-unknown-linux-gnu" + ] + } + }, + "playground": { + "features": [ + "raw_value" + ] + } + }, + "publish": null, + "authors": [ + "Erick Tryzelaar ", + "David Tolnay " + ], + "categories": [ + "encoding", + "parser-implementations", + "no-std" + ], + "keywords": [ + "json", + "serde", + "serialization" + ], + "readme": "README.md", + "repository": "https://github.com/serde-rs/json", + "homepage": null, + "documentation": "https://docs.rs/serde_json", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": "1.36" + }, + { + "name": "strsim", + "version": "0.8.0", + "id": "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT", + "license_file": null, + "description": "Implementations of string similarity metrics.\nIncludes Hamming, Levenshtein, OSA, Damerau-Levenshtein, Jaro, and Jaro-Winkler.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "strsim", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/strsim-0.8.0/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "lib", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/strsim-0.8.0/tests/lib.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "benches", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/strsim-0.8.0/benches/benches.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/strsim-0.8.0/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Danny Guo " + ], + "categories": [], + "keywords": [ + "string", + "similarity", + "Hamming", + "Levenshtein", + "Jaro" + ], + "readme": "README.md", + "repository": "https://github.com/dguo/strsim-rs", + "homepage": "https://github.com/dguo/strsim-rs", + "documentation": "https://docs.rs/strsim/", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "syn", + "version": "2.0.15", + "id": "syn 2.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "Parser for Rust source code", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "proc-macro2", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.55", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "quote", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.25", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "unicode-ident", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "anyhow", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "automod", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "flate2", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "insta", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rayon", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "ref-cast", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "regex", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "reqwest", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.11", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [ + "blocking" + ], + "target": null, + "registry": null + }, + { + "name": "rustversion", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "syn-test-suite", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "tar", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4.16", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "termcolor", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "walkdir", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^2.3.2", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "syn", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "regression", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/regression.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_asyncness", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_asyncness.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_attribute", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_attribute.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_derive_input", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_derive_input.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_expr", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_expr.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_generics", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_generics.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_grouping", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_grouping.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_ident", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_ident.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_item", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_item.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_iterators", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_iterators.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_lit", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_lit.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_meta", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_meta.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_parse_buffer", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_parse_buffer.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_parse_stream", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_parse_stream.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_pat", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_pat.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_path", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_path.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_precedence", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_precedence.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_receiver", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_receiver.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_round_trip", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_round_trip.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_shebang", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_shebang.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_should_parse", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_should_parse.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_size", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_size.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_stmt", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_stmt.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_token_trees", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_token_trees.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_ty", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_ty.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "test_visibility", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/test_visibility.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "zzz_stable", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/tests/zzz_stable.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "rust", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/benches/rust.rs", + "edition": "2021", + "required-features": [ + "full", + "parsing" + ], + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "file", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/benches/file.rs", + "edition": "2021", + "required-features": [ + "full", + "parsing" + ], + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "clone-impls": [], + "default": [ + "derive", + "parsing", + "printing", + "clone-impls", + "proc-macro" + ], + "derive": [], + "extra-traits": [], + "fold": [], + "full": [], + "parsing": [], + "printing": [ + "quote" + ], + "proc-macro": [ + "proc-macro2/proc-macro", + "quote/proc-macro" + ], + "quote": [ + "dep:quote" + ], + "test": [ + "syn-test-suite/all-features" + ], + "visit": [], + "visit-mut": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.15/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "all-features": true, + "rustdoc-args": [ + "--cfg", + "doc_cfg" + ], + "targets": [ + "x86_64-unknown-linux-gnu" + ] + } + }, + "playground": { + "features": [ + "full", + "visit", + "visit-mut", + "fold", + "extra-traits" + ] + } + }, + "publish": null, + "authors": [ + "David Tolnay " + ], + "categories": [ + "development-tools::procedural-macro-helpers", + "parser-implementations" + ], + "keywords": [ + "macros", + "syn" + ], + "readme": "README.md", + "repository": "https://github.com/dtolnay/syn", + "homepage": null, + "documentation": "https://docs.rs/syn", + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": "1.56" + }, + { + "name": "termcolor", + "version": "1.2.0", + "id": "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "Unlicense OR MIT", + "license_file": null, + "description": "A simple cross platform library for writing colored text to a terminal.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "winapi-util", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1.3", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": "cfg(windows)", + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "termcolor", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/termcolor-1.2.0/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/termcolor-1.2.0/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [], + "keywords": [ + "windows", + "win", + "color", + "ansi", + "console" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/termcolor", + "homepage": "https://github.com/BurntSushi/termcolor", + "documentation": "https://docs.rs/termcolor", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "textwrap", + "version": "0.11.0", + "id": "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT", + "license_file": null, + "description": "Textwrap is a small library for word wrapping, indenting, and\ndedenting strings.\n\nYou can use it to format strings (such as help and error messages) for\ndisplay in commandline applications. It is designed to be efficient\nand handle Unicode characters correctly.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "hyphenation", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.7.1", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [ + "embed_all" + ], + "target": null, + "registry": null + }, + { + "name": "term_size", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3.0", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "unicode-width", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1.3", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "lipsum", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.6", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rand", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.6", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rand_xorshift", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "version-sync", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.6", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "textwrap", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/textwrap-0.11.0/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "layout", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/textwrap-0.11.0/examples/layout.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "example" + ], + "crate_types": [ + "bin" + ], + "name": "termwidth", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/textwrap-0.11.0/examples/termwidth.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "version-numbers", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/textwrap-0.11.0/tests/version-numbers.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "linear", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/textwrap-0.11.0/benches/linear.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "hyphenation": [ + "dep:hyphenation" + ], + "term_size": [ + "dep:term_size" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/textwrap-0.11.0/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "all-features": true + } + } + }, + "publish": null, + "authors": [ + "Martin Geisler " + ], + "categories": [ + "text-processing", + "command-line-interface" + ], + "keywords": [ + "text", + "formatting", + "wrap", + "typesetting", + "hyphenation" + ], + "readme": "README.md", + "repository": "https://github.com/mgeisler/textwrap", + "homepage": null, + "documentation": "https://docs.rs/textwrap/", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "thread_local", + "version": "1.1.7", + "id": "thread_local 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT OR Apache-2.0", + "license_file": null, + "description": "Per-object thread-local storage", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "cfg-if", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.0", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "once_cell", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.5.2", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "criterion", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4.0", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "thread_local", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/thread_local-1.1.7/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "thread_local", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/thread_local-1.1.7/benches/thread_local.rs", + "edition": "2021", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "nightly": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/thread_local-1.1.7/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Amanieu d'Antras " + ], + "categories": [], + "keywords": [ + "thread_local", + "concurrent", + "thread" + ], + "readme": "README.md", + "repository": "https://github.com/Amanieu/thread_local-rs", + "homepage": null, + "documentation": "https://docs.rs/thread_local/", + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "unicode-ident", + "version": "1.0.8", + "id": "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "(MIT OR Apache-2.0) AND Unicode-DFS-2016", + "license_file": null, + "description": "Determine whether characters have the XID_Start or XID_Continue properties according to Unicode Standard Annex #31", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "criterion", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "fst", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rand", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.8", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [ + "small_rng" + ], + "target": null, + "registry": null + }, + { + "name": "roaring", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.10", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "ucd-trie", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": false, + "features": [], + "target": null, + "registry": null + }, + { + "name": "unicode-xid", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.2.4", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "unicode-ident", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "compare", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/tests/compare.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "test" + ], + "crate_types": [ + "bin" + ], + "name": "static_size", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/tests/static_size.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": true + }, + { + "kind": [ + "bench" + ], + "crate_types": [ + "bin" + ], + "name": "xid", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/benches/xid.rs", + "edition": "2018", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-ident-1.0.8/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "targets": [ + "x86_64-unknown-linux-gnu" + ] + } + } + }, + "publish": null, + "authors": [ + "David Tolnay " + ], + "categories": [ + "development-tools::procedural-macro-helpers", + "no-std" + ], + "keywords": [ + "unicode", + "xid" + ], + "readme": "README.md", + "repository": "https://github.com/dtolnay/unicode-ident", + "homepage": null, + "documentation": "https://docs.rs/unicode-ident", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": "1.31" + }, + { + "name": "unicode-width", + "version": "0.1.10", + "id": "unicode-width 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT/Apache-2.0", + "license_file": null, + "description": "Determine displayed width of `char` and `str` types\naccording to Unicode Standard Annex #11 rules.\n", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "compiler_builtins", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1", + "kind": null, + "rename": null, + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustc-std-workspace-core", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": "core", + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "rustc-std-workspace-std", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0", + "kind": null, + "rename": "std", + "optional": true, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "unicode-width", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-width-0.1.10/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": { + "bench": [], + "compiler_builtins": [ + "dep:compiler_builtins" + ], + "core": [ + "dep:core" + ], + "default": [], + "no_std": [], + "rustc-dep-of-std": [ + "std", + "core", + "compiler_builtins" + ], + "std": [ + "dep:std" + ] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/unicode-width-0.1.10/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "kwantam ", + "Manish Goregaokar " + ], + "categories": [], + "keywords": [ + "text", + "width", + "unicode" + ], + "readme": "README.md", + "repository": "https://github.com/unicode-rs/unicode-width", + "homepage": "https://github.com/unicode-rs/unicode-width", + "documentation": "https://unicode-rs.github.io/unicode-width", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "walkdir", + "version": "2.3.3", + "id": "walkdir 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "Unlicense/MIT", + "license_file": null, + "description": "Recursively walk a directory.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "same-file", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^1.0.1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "doc-comment", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null + }, + { + "name": "winapi-util", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.1.1", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": "cfg(windows)", + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "walkdir", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/walkdir-2.3.3/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/walkdir-2.3.3/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [ + "filesystem" + ], + "keywords": [ + "directory", + "recursive", + "walk", + "iterator" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/walkdir", + "homepage": "https://github.com/BurntSushi/walkdir", + "documentation": "https://docs.rs/walkdir/", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "winapi", + "version": "0.3.9", + "id": "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT/Apache-2.0", + "license_file": null, + "description": "Raw FFI bindings for all of Windows API.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "winapi-i686-pc-windows-gnu", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": "i686-pc-windows-gnu", + "registry": null + }, + { + "name": "winapi-x86_64-pc-windows-gnu", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.4", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": "x86_64-pc-windows-gnu", + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "winapi", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-0.3.9/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-0.3.9/build.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": { + "accctrl": [], + "aclapi": [], + "activation": [], + "adhoc": [], + "appmgmt": [], + "audioclient": [], + "audiosessiontypes": [], + "avrt": [], + "basetsd": [], + "bcrypt": [], + "bits": [], + "bits10_1": [], + "bits1_5": [], + "bits2_0": [], + "bits2_5": [], + "bits3_0": [], + "bits4_0": [], + "bits5_0": [], + "bitscfg": [], + "bitsmsg": [], + "bluetoothapis": [], + "bluetoothleapis": [], + "bthdef": [], + "bthioctl": [], + "bthledef": [], + "bthsdpdef": [], + "bugcodes": [], + "cderr": [], + "cfg": [], + "cfgmgr32": [], + "cguid": [], + "combaseapi": [], + "coml2api": [], + "commapi": [], + "commctrl": [], + "commdlg": [], + "commoncontrols": [], + "consoleapi": [], + "corecrt": [], + "corsym": [], + "d2d1": [], + "d2d1_1": [], + "d2d1_2": [], + "d2d1_3": [], + "d2d1effectauthor": [], + "d2d1effects": [], + "d2d1effects_1": [], + "d2d1effects_2": [], + "d2d1svg": [], + "d2dbasetypes": [], + "d3d": [], + "d3d10": [], + "d3d10_1": [], + "d3d10_1shader": [], + "d3d10effect": [], + "d3d10misc": [], + "d3d10sdklayers": [], + "d3d10shader": [], + "d3d11": [], + "d3d11_1": [], + "d3d11_2": [], + "d3d11_3": [], + "d3d11_4": [], + "d3d11on12": [], + "d3d11sdklayers": [], + "d3d11shader": [], + "d3d11tokenizedprogramformat": [], + "d3d12": [], + "d3d12sdklayers": [], + "d3d12shader": [], + "d3d9": [], + "d3d9caps": [], + "d3d9types": [], + "d3dcommon": [], + "d3dcompiler": [], + "d3dcsx": [], + "d3dkmdt": [], + "d3dkmthk": [], + "d3dukmdt": [], + "d3dx10core": [], + "d3dx10math": [], + "d3dx10mesh": [], + "datetimeapi": [], + "davclnt": [], + "dbghelp": [], + "dbt": [], + "dcommon": [], + "dcomp": [], + "dcompanimation": [], + "dcomptypes": [], + "dde": [], + "ddraw": [], + "ddrawi": [], + "ddrawint": [], + "debug": [ + "impl-debug" + ], + "debugapi": [], + "devguid": [], + "devicetopology": [], + "devpkey": [], + "devpropdef": [], + "dinput": [], + "dinputd": [], + "dispex": [], + "dmksctl": [], + "dmusicc": [], + "docobj": [], + "documenttarget": [], + "dot1x": [], + "dpa_dsa": [], + "dpapi": [], + "dsgetdc": [], + "dsound": [], + "dsrole": [], + "dvp": [], + "dwmapi": [], + "dwrite": [], + "dwrite_1": [], + "dwrite_2": [], + "dwrite_3": [], + "dxdiag": [], + "dxfile": [], + "dxgi": [], + "dxgi1_2": [], + "dxgi1_3": [], + "dxgi1_4": [], + "dxgi1_5": [], + "dxgi1_6": [], + "dxgidebug": [], + "dxgiformat": [], + "dxgitype": [], + "dxva2api": [], + "dxvahd": [], + "eaptypes": [], + "enclaveapi": [], + "endpointvolume": [], + "errhandlingapi": [], + "everything": [], + "evntcons": [], + "evntprov": [], + "evntrace": [], + "excpt": [], + "exdisp": [], + "fibersapi": [], + "fileapi": [], + "functiondiscoverykeys_devpkey": [], + "gl-gl": [], + "guiddef": [], + "handleapi": [], + "heapapi": [], + "hidclass": [], + "hidpi": [], + "hidsdi": [], + "hidusage": [], + "highlevelmonitorconfigurationapi": [], + "hstring": [], + "http": [], + "ifdef": [], + "ifmib": [], + "imm": [], + "impl-debug": [], + "impl-default": [], + "in6addr": [], + "inaddr": [], + "inspectable": [], + "interlockedapi": [], + "intsafe": [], + "ioapiset": [], + "ipexport": [], + "iphlpapi": [], + "ipifcons": [], + "ipmib": [], + "iprtrmib": [], + "iptypes": [], + "jobapi": [], + "jobapi2": [], + "knownfolders": [], + "ks": [], + "ksmedia": [], + "ktmtypes": [], + "ktmw32": [], + "l2cmn": [], + "libloaderapi": [], + "limits": [], + "lmaccess": [], + "lmalert": [], + "lmapibuf": [], + "lmat": [], + "lmcons": [], + "lmdfs": [], + "lmerrlog": [], + "lmjoin": [], + "lmmsg": [], + "lmremutl": [], + "lmrepl": [], + "lmserver": [], + "lmshare": [], + "lmstats": [], + "lmsvc": [], + "lmuse": [], + "lmwksta": [], + "lowlevelmonitorconfigurationapi": [], + "lsalookup": [], + "memoryapi": [], + "minschannel": [], + "minwinbase": [], + "minwindef": [], + "mmdeviceapi": [], + "mmeapi": [], + "mmreg": [], + "mmsystem": [], + "mprapidef": [], + "msaatext": [], + "mscat": [], + "mschapp": [], + "mssip": [], + "mstcpip": [], + "mswsock": [], + "mswsockdef": [], + "namedpipeapi": [], + "namespaceapi": [], + "nb30": [], + "ncrypt": [], + "netioapi": [], + "nldef": [], + "ntddndis": [], + "ntddscsi": [], + "ntddser": [], + "ntdef": [], + "ntlsa": [], + "ntsecapi": [], + "ntstatus": [], + "oaidl": [], + "objbase": [], + "objidl": [], + "objidlbase": [], + "ocidl": [], + "ole2": [], + "oleauto": [], + "olectl": [], + "oleidl": [], + "opmapi": [], + "pdh": [], + "perflib": [], + "physicalmonitorenumerationapi": [], + "playsoundapi": [], + "portabledevice": [], + "portabledeviceapi": [], + "portabledevicetypes": [], + "powerbase": [], + "powersetting": [], + "powrprof": [], + "processenv": [], + "processsnapshot": [], + "processthreadsapi": [], + "processtopologyapi": [], + "profileapi": [], + "propidl": [], + "propkey": [], + "propkeydef": [], + "propsys": [], + "prsht": [], + "psapi": [], + "qos": [], + "realtimeapiset": [], + "reason": [], + "restartmanager": [], + "restrictederrorinfo": [], + "rmxfguid": [], + "roapi": [], + "robuffer": [], + "roerrorapi": [], + "rpc": [], + "rpcdce": [], + "rpcndr": [], + "rtinfo": [], + "sapi": [], + "sapi51": [], + "sapi53": [], + "sapiddk": [], + "sapiddk51": [], + "schannel": [], + "sddl": [], + "securityappcontainer": [], + "securitybaseapi": [], + "servprov": [], + "setupapi": [], + "shellapi": [], + "shellscalingapi": [], + "shlobj": [], + "shobjidl": [], + "shobjidl_core": [], + "shtypes": [], + "softpub": [], + "spapidef": [], + "spellcheck": [], + "sporder": [], + "sql": [], + "sqlext": [], + "sqltypes": [], + "sqlucode": [], + "sspi": [], + "std": [], + "stralign": [], + "stringapiset": [], + "strmif": [], + "subauth": [], + "synchapi": [], + "sysinfoapi": [], + "systemtopologyapi": [], + "taskschd": [], + "tcpestats": [], + "tcpmib": [], + "textstor": [], + "threadpoolapiset": [], + "threadpoollegacyapiset": [], + "timeapi": [], + "timezoneapi": [], + "tlhelp32": [], + "transportsettingcommon": [], + "tvout": [], + "udpmib": [], + "unknwnbase": [], + "urlhist": [], + "urlmon": [], + "usb": [], + "usbioctl": [], + "usbiodef": [], + "usbscan": [], + "usbspec": [], + "userenv": [], + "usp10": [], + "utilapiset": [], + "uxtheme": [], + "vadefs": [], + "vcruntime": [], + "vsbackup": [], + "vss": [], + "vsserror": [], + "vswriter": [], + "wbemads": [], + "wbemcli": [], + "wbemdisp": [], + "wbemprov": [], + "wbemtran": [], + "wct": [], + "werapi": [], + "winbase": [], + "wincodec": [], + "wincodecsdk": [], + "wincon": [], + "wincontypes": [], + "wincred": [], + "wincrypt": [], + "windef": [], + "windot11": [], + "windowsceip": [], + "windowsx": [], + "winefs": [], + "winerror": [], + "winevt": [], + "wingdi": [], + "winhttp": [], + "wininet": [], + "winineti": [], + "winioctl": [], + "winnetwk": [], + "winnls": [], + "winnt": [], + "winreg": [], + "winsafer": [], + "winscard": [], + "winsmcrd": [], + "winsock2": [], + "winspool": [], + "winstring": [], + "winsvc": [], + "wintrust": [], + "winusb": [], + "winusbio": [], + "winuser": [], + "winver": [], + "wlanapi": [], + "wlanihv": [], + "wlanihvtypes": [], + "wlantypes": [], + "wlclient": [], + "wmistr": [], + "wnnc": [], + "wow64apiset": [], + "wpdmtpextensions": [], + "ws2bth": [], + "ws2def": [], + "ws2ipdef": [], + "ws2spi": [], + "ws2tcpip": [], + "wtsapi32": [], + "wtypes": [], + "wtypesbase": [], + "xinput": [] + }, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-0.3.9/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "default-target": "x86_64-pc-windows-msvc", + "features": [ + "everything", + "impl-debug", + "impl-default" + ], + "targets": [ + "aarch64-pc-windows-msvc", + "i686-pc-windows-msvc", + "x86_64-pc-windows-msvc" + ] + } + } + }, + "publish": null, + "authors": [ + "Peter Atashian " + ], + "categories": [ + "external-ffi-bindings", + "no-std", + "os::windows-apis" + ], + "keywords": [ + "windows", + "ffi", + "win32", + "com", + "directx" + ], + "readme": "README.md", + "repository": "https://github.com/retep998/winapi-rs", + "homepage": null, + "documentation": "https://docs.rs/winapi/", + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "winapi-i686-pc-windows-gnu", + "version": "0.4.0", + "id": "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT/Apache-2.0", + "license_file": null, + "description": "Import libraries for the i686-pc-windows-gnu target. Please don't use this crate directly, depend on winapi instead.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "winapi-i686-pc-windows-gnu", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-i686-pc-windows-gnu-0.4.0/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-i686-pc-windows-gnu-0.4.0/build.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-i686-pc-windows-gnu-0.4.0/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Peter Atashian " + ], + "categories": [], + "keywords": [ + "windows" + ], + "readme": null, + "repository": "https://github.com/retep998/winapi-rs", + "homepage": null, + "documentation": null, + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "winapi-util", + "version": "0.1.5", + "id": "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "Unlicense/MIT", + "license_file": null, + "description": "A dumping ground for high level safe wrappers over winapi.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [ + { + "name": "winapi", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "req": "^0.3", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [ + "std", + "consoleapi", + "errhandlingapi", + "fileapi", + "minwindef", + "processenv", + "winbase", + "wincon", + "winerror", + "winnt" + ], + "target": "cfg(windows)", + "registry": null + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "winapi-util", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-util-0.1.5/src/lib.rs", + "edition": "2018", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-util-0.1.5/Cargo.toml", + "metadata": { + "docs": { + "rs": { + "targets": [ + "x86_64-pc-windows-msvc" + ] + } + } + }, + "publish": null, + "authors": [ + "Andrew Gallant " + ], + "categories": [ + "os::windows-apis", + "external-ffi-bindings" + ], + "keywords": [ + "windows", + "winapi", + "util", + "win" + ], + "readme": "README.md", + "repository": "https://github.com/BurntSushi/winapi-util", + "homepage": "https://github.com/BurntSushi/winapi-util", + "documentation": "https://docs.rs/winapi-util", + "edition": "2018", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "winapi-x86_64-pc-windows-gnu", + "version": "0.4.0", + "id": "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "license": "MIT/Apache-2.0", + "license_file": null, + "description": "Import libraries for the x86_64-pc-windows-gnu target. Please don't use this crate directly, depend on winapi instead.", + "source": "registry+https://github.com/rust-lang/crates.io-index", + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "winapi-x86_64-pc-windows-gnu", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-x86_64-pc-windows-gnu-0.4.0/src/lib.rs", + "edition": "2015", + "doc": true, + "doctest": true, + "test": true + }, + { + "kind": [ + "custom-build" + ], + "crate_types": [ + "bin" + ], + "name": "build-script-build", + "src_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-x86_64-pc-windows-gnu-0.4.0/build.rs", + "edition": "2015", + "doc": false, + "doctest": false, + "test": false + } + ], + "features": {}, + "manifest_path": "$ROOT$.cargo/registry/src/index.crates.io-6f17d22bba15001f/winapi-x86_64-pc-windows-gnu-0.4.0/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [ + "Peter Atashian " + ], + "categories": [], + "keywords": [ + "windows" + ], + "readme": null, + "repository": "https://github.com/retep998/winapi-rs", + "homepage": null, + "documentation": null, + "edition": "2015", + "links": null, + "default_run": null, + "rust_version": null + } + ], + "workspace_members": [ + "globset 0.4.10 (path+file:///$ROOT$ripgrep/crates/globset)", + "grep 0.2.11 (path+file:///$ROOT$ripgrep/crates/grep)", + "grep-cli 0.1.7 (path+file:///$ROOT$ripgrep/crates/cli)", + "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", + "grep-pcre2 0.1.6 (path+file:///$ROOT$ripgrep/crates/pcre2)", + "grep-printer 0.1.7 (path+file:///$ROOT$ripgrep/crates/printer)", + "grep-searcher 0.1.11 (path+file:///$ROOT$ripgrep/crates/searcher)", + "grep-regex 0.1.11 (path+file:///$ROOT$ripgrep/crates/regex)", + "ignore 0.4.20 (path+file:///$ROOT$ripgrep/crates/ignore)", + "ripgrep 13.0.0 (path+file:///$ROOT$ripgrep)" + ], + "resolve": { + "nodes": [ + { + "id": "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "memchr", + "pkg": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "default", + "std" + ] + }, + { + "id": "aho-corasick 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "memchr", + "pkg": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "default", + "perf-literal", + "std" + ] + }, + { + "id": "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "hermit-abi 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "hermit_abi", + "pkg": "hermit-abi 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "cfg(target_os = \"hermit\")" + } + ] + }, + { + "name": "libc", + "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "cfg(unix)" + } + ] + }, + { + "name": "winapi", + "pkg": "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "cfg(windows)" + } + ] + } + ], + "features": [] + }, + { + "id": "base64 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [ + "default", + "std" + ] + }, + { + "id": "bitflags 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [ + "default" + ] + }, + { + "id": "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "once_cell 1.17.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-automata 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "memchr", + "pkg": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "once_cell", + "pkg": "once_cell 1.17.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "regex_automata", + "pkg": "regex-automata 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "serde", + "pkg": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "alloc", + "default", + "std", + "unicode" + ] + }, + { + "id": "bytecount 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [ + "runtime-dispatch-simd" + ] + }, + { + "id": "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "jobserver 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "jobserver", + "pkg": "jobserver 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "jobserver", + "parallel" + ] + }, + { + "id": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "clap 2.34.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "bitflags 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "bitflags", + "pkg": "bitflags 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "strsim", + "pkg": "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "textwrap", + "pkg": "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "unicode_width", + "pkg": "unicode-width 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "strsim", + "suggestions" + ] + }, + { + "id": "crossbeam-channel 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.8.15 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "cfg_if", + "pkg": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "crossbeam_utils", + "pkg": "crossbeam-utils 0.8.15 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "crossbeam-utils", + "default", + "std" + ] + }, + { + "id": "crossbeam-utils 0.8.15 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "cfg_if", + "pkg": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "std" + ] + }, + { + "id": "encoding_rs 0.8.32 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "cfg_if", + "pkg": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "alloc", + "default" + ] + }, + { + "id": "encoding_rs_io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "encoding_rs 0.8.32 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "encoding_rs", + "pkg": "encoding_rs 0.8.32 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [] + }, + { + "id": "fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [ + "default", + "std" + ] + }, + { + "id": "glob 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "globset 0.4.10 (path+file:///$ROOT$ripgrep/crates/globset)", + "dependencies": [ + "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", + "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.96 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "aho_corasick", + "pkg": "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "bstr", + "pkg": "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "fnv", + "pkg": "fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "glob", + "pkg": "glob 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": "dev", + "target": null + } + ] + }, + { + "name": "lazy_static", + "pkg": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": "dev", + "target": null + } + ] + }, + { + "name": "log", + "pkg": "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "regex", + "pkg": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "serde_json", + "pkg": "serde_json 1.0.96 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": "dev", + "target": null + } + ] + } + ], + "features": [ + "default", + "log" + ] + }, + { + "id": "grep 0.2.11 (path+file:///$ROOT$ripgrep/crates/grep)", + "dependencies": [ + "grep-cli 0.1.7 (path+file:///$ROOT$ripgrep/crates/cli)", + "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", + "grep-printer 0.1.7 (path+file:///$ROOT$ripgrep/crates/printer)", + "grep-regex 0.1.11 (path+file:///$ROOT$ripgrep/crates/regex)", + "grep-searcher 0.1.11 (path+file:///$ROOT$ripgrep/crates/searcher)", + "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "grep_cli", + "pkg": "grep-cli 0.1.7 (path+file:///$ROOT$ripgrep/crates/cli)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "grep_matcher", + "pkg": "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "grep_printer", + "pkg": "grep-printer 0.1.7 (path+file:///$ROOT$ripgrep/crates/printer)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "grep_regex", + "pkg": "grep-regex 0.1.11 (path+file:///$ROOT$ripgrep/crates/regex)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "grep_searcher", + "pkg": "grep-searcher 0.1.11 (path+file:///$ROOT$ripgrep/crates/searcher)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "termcolor", + "pkg": "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": "dev", + "target": null + } + ] + }, + { + "name": "walkdir", + "pkg": "walkdir 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": "dev", + "target": null + } + ] + } + ], + "features": [] + }, + { + "id": "grep-cli 0.1.7 (path+file:///$ROOT$ripgrep/crates/cli)", + "dependencies": [ + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "globset 0.4.10 (path+file:///$ROOT$ripgrep/crates/globset)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "atty", + "pkg": "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "bstr", + "pkg": "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "globset", + "pkg": "globset 0.4.10 (path+file:///$ROOT$ripgrep/crates/globset)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "lazy_static", + "pkg": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "log", + "pkg": "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "regex", + "pkg": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "same_file", + "pkg": "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "termcolor", + "pkg": "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "winapi_util", + "pkg": "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "cfg(windows)" + } + ] + } + ], + "features": [] + }, + { + "id": "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", + "dependencies": [ + "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "memchr", + "pkg": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "regex", + "pkg": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": "dev", + "target": null + } + ] + } + ], + "features": [] + }, + { + "id": "grep-pcre2 0.1.6 (path+file:///$ROOT$ripgrep/crates/pcre2)", + "dependencies": [ + "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", + "pcre2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "grep_matcher", + "pkg": "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "pcre2", + "pkg": "pcre2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [] + }, + { + "id": "grep-printer 0.1.7 (path+file:///$ROOT$ripgrep/crates/printer)", + "dependencies": [ + "base64 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", + "grep-regex 0.1.11 (path+file:///$ROOT$ripgrep/crates/regex)", + "grep-searcher 0.1.11 (path+file:///$ROOT$ripgrep/crates/searcher)", + "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.96 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "base64", + "pkg": "base64 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "bstr", + "pkg": "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "grep_matcher", + "pkg": "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "grep_regex", + "pkg": "grep-regex 0.1.11 (path+file:///$ROOT$ripgrep/crates/regex)", + "dep_kinds": [ + { + "kind": "dev", + "target": null + } + ] + }, + { + "name": "grep_searcher", + "pkg": "grep-searcher 0.1.11 (path+file:///$ROOT$ripgrep/crates/searcher)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "serde", + "pkg": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "serde_json", + "pkg": "serde_json 1.0.96 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "termcolor", + "pkg": "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "base64", + "default", + "serde", + "serde1", + "serde_json" + ] + }, + { + "id": "grep-regex 0.1.11 (path+file:///$ROOT$ripgrep/crates/regex)", + "dependencies": [ + "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", + "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", + "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.29 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "aho_corasick", + "pkg": "aho-corasick 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "bstr", + "pkg": "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "grep_matcher", + "pkg": "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "log", + "pkg": "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "regex", + "pkg": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "regex_syntax", + "pkg": "regex-syntax 0.6.29 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "thread_local", + "pkg": "thread_local 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [] + }, + { + "id": "grep-searcher 0.1.11 (path+file:///$ROOT$ripgrep/crates/searcher)", + "dependencies": [ + "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytecount 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "encoding_rs 0.8.32 (registry+https://github.com/rust-lang/crates.io-index)", + "encoding_rs_io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", + "grep-regex 0.1.11 (path+file:///$ROOT$ripgrep/crates/regex)", + "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", + "memmap2 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "bstr", + "pkg": "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "bytecount", + "pkg": "bytecount 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "encoding_rs", + "pkg": "encoding_rs 0.8.32 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "encoding_rs_io", + "pkg": "encoding_rs_io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "grep_matcher", + "pkg": "grep-matcher 0.1.6 (path+file:///$ROOT$ripgrep/crates/matcher)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "grep_regex", + "pkg": "grep-regex 0.1.11 (path+file:///$ROOT$ripgrep/crates/regex)", + "dep_kinds": [ + { + "kind": "dev", + "target": null + } + ] + }, + { + "name": "log", + "pkg": "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "memmap", + "pkg": "memmap2 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "regex", + "pkg": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": "dev", + "target": null + } + ] + } + ], + "features": [ + "default" + ] + }, + { + "id": "hermit-abi 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "libc", + "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "default" + ] + }, + { + "id": "ignore 0.4.20 (path+file:///$ROOT$ripgrep/crates/ignore)", + "dependencies": [ + "crossbeam-channel 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "globset 0.4.10 (path+file:///$ROOT$ripgrep/crates/globset)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "crossbeam_channel", + "pkg": "crossbeam-channel 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": "dev", + "target": null + } + ] + }, + { + "name": "globset", + "pkg": "globset 0.4.10 (path+file:///$ROOT$ripgrep/crates/globset)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "lazy_static", + "pkg": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "log", + "pkg": "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "memchr", + "pkg": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "regex", + "pkg": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "same_file", + "pkg": "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "thread_local", + "pkg": "thread_local 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "walkdir", + "pkg": "walkdir 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "winapi_util", + "pkg": "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "cfg(windows)" + } + ] + } + ], + "features": [] + }, + { + "id": "itoa 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "jemalloc-sys 0.5.3+5.3.0-patched (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "cc", + "pkg": "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": "build", + "target": null + } + ] + }, + { + "name": "libc", + "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "background_threads_runtime_support" + ] + }, + { + "id": "jemallocator 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "jemalloc-sys 0.5.3+5.3.0-patched (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "jemalloc_sys", + "pkg": "jemalloc-sys 0.5.3+5.3.0-patched (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "libc", + "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "background_threads_runtime_support", + "default" + ] + }, + { + "id": "jobserver 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "libc", + "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "cfg(unix)" + } + ] + } + ], + "features": [] + }, + { + "id": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [ + "default", + "std" + ] + }, + { + "id": "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "cfg_if", + "pkg": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [] + }, + { + "id": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [ + "default", + "std" + ] + }, + { + "id": "memmap2 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "libc", + "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "cfg(unix)" + } + ] + } + ], + "features": [] + }, + { + "id": "once_cell 1.17.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [ + "alloc", + "default", + "race", + "std" + ] + }, + { + "id": "pcre2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", + "pcre2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "libc", + "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "log", + "pkg": "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "pcre2_sys", + "pkg": "pcre2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "thread_local", + "pkg": "thread_local 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [] + }, + { + "id": "pcre2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "cc", + "pkg": "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": "build", + "target": null + } + ] + }, + { + "name": "libc", + "pkg": "libc 0.2.142 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "pkg_config", + "pkg": "pkg-config 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": "build", + "target": null + } + ] + } + ], + "features": [] + }, + { + "id": "pkg-config 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "unicode_ident", + "pkg": "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "default", + "proc-macro" + ] + }, + { + "id": "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "proc_macro2", + "pkg": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "default", + "proc-macro" + ] + }, + { + "id": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "aho-corasick 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "aho_corasick", + "pkg": "aho-corasick 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "memchr", + "pkg": "memchr 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "regex_syntax", + "pkg": "regex-syntax 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "aho-corasick", + "default", + "memchr", + "perf", + "perf-cache", + "perf-dfa", + "perf-inline", + "perf-literal", + "std", + "unicode", + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment" + ] + }, + { + "id": "regex-automata 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "regex-syntax 0.6.29 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [ + "default", + "unicode", + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment" + ] + }, + { + "id": "regex-syntax 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [ + "default", + "std", + "unicode", + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment" + ] + }, + { + "id": "ripgrep 13.0.0 (path+file:///$ROOT$ripgrep)", + "dependencies": [ + "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.34.0 (registry+https://github.com/rust-lang/crates.io-index)", + "grep 0.2.11 (path+file:///$ROOT$ripgrep/crates/grep)", + "ignore 0.4.20 (path+file:///$ROOT$ripgrep/crates/ignore)", + "jemallocator 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.96 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "bstr", + "pkg": "bstr 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "clap", + "pkg": "clap 2.34.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + }, + { + "kind": "build", + "target": null + } + ] + }, + { + "name": "grep", + "pkg": "grep 0.2.11 (path+file:///$ROOT$ripgrep/crates/grep)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "ignore", + "pkg": "ignore 0.4.20 (path+file:///$ROOT$ripgrep/crates/ignore)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "jemallocator", + "pkg": "jemallocator 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "cfg(all(target_env = \"musl\", target_pointer_width = \"64\"))" + } + ] + }, + { + "name": "lazy_static", + "pkg": "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + }, + { + "kind": "build", + "target": null + } + ] + }, + { + "name": "log", + "pkg": "log 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "regex", + "pkg": "regex 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "serde", + "pkg": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": "dev", + "target": null + } + ] + }, + { + "name": "serde_derive", + "pkg": "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": "dev", + "target": null + } + ] + }, + { + "name": "serde_json", + "pkg": "serde_json 1.0.96 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "termcolor", + "pkg": "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "walkdir", + "pkg": "walkdir 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": "dev", + "target": null + } + ] + } + ], + "features": [] + }, + { + "id": "ryu 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "winapi_util", + "pkg": "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "cfg(windows)" + } + ] + } + ], + "features": [] + }, + { + "id": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "serde_derive", + "pkg": "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "alloc", + "default", + "derive", + "serde_derive", + "std" + ] + }, + { + "id": "serde_derive 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 2.0.15 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "proc_macro2", + "pkg": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "quote", + "pkg": "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "syn", + "pkg": "syn 2.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "default" + ] + }, + { + "id": "serde_json 1.0.96 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "itoa 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "itoa", + "pkg": "itoa 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "ryu", + "pkg": "ryu 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "serde", + "pkg": "serde 1.0.160 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "default", + "std" + ] + }, + { + "id": "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "syn 2.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "proc_macro2", + "pkg": "proc-macro2 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "quote", + "pkg": "quote 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "unicode_ident", + "pkg": "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [ + "clone-impls", + "default", + "derive", + "parsing", + "printing", + "proc-macro", + "quote" + ] + }, + { + "id": "termcolor 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "winapi_util", + "pkg": "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "cfg(windows)" + } + ] + } + ], + "features": [] + }, + { + "id": "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "unicode-width 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "unicode_width", + "pkg": "unicode-width 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [] + }, + { + "id": "thread_local 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "once_cell 1.17.1 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "cfg_if", + "pkg": "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "once_cell", + "pkg": "once_cell 1.17.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [] + }, + { + "id": "unicode-ident 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "unicode-width 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [ + "default" + ] + }, + { + "id": "walkdir 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "same_file", + "pkg": "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + }, + { + "name": "winapi_util", + "pkg": "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "cfg(windows)" + } + ] + } + ], + "features": [] + }, + { + "id": "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "winapi_i686_pc_windows_gnu", + "pkg": "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "i686-pc-windows-gnu" + } + ] + }, + { + "name": "winapi_x86_64_pc_windows_gnu", + "pkg": "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "x86_64-pc-windows-gnu" + } + ] + } + ], + "features": [ + "consoleapi", + "errhandlingapi", + "fileapi", + "minwinbase", + "minwindef", + "processenv", + "std", + "winbase", + "wincon", + "winerror", + "winnt" + ] + }, + { + "id": "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [ + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" + ], + "deps": [ + { + "name": "winapi", + "pkg": "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "dep_kinds": [ + { + "kind": null, + "target": "cfg(windows)" + } + ] + } + ], + "features": [] + }, + { + "id": "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dependencies": [], + "deps": [], + "features": [] + } + ], + "root": "ripgrep 13.0.0 (path+file:///$ROOT$ripgrep)" + }, + "target_directory": "$ROOT$ripgrep/target", + "version": 1, + "workspace_root": "$ROOT$ripgrep", + "metadata": null +} diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index f0f1900c78c56..97bd920920601 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -29,9 +29,8 @@ parking_lot = "0.12.1" xflags = "0.3.0" oorandom = "11.1.3" rustc-hash = "1.1.0" -serde = { version = "1.0.137", features = ["derive"] } -serde_json = { version = "1.0.81", features = ["preserve_order"] } -threadpool = "1.8.1" +serde_json = { workspace = true, features = ["preserve_order"] } +serde.workspace = true rayon = "1.6.1" num_cpus = "1.15.0" mimalloc = { version = "0.1.30", default-features = false, optional = true } @@ -45,8 +44,20 @@ tracing-subscriber = { version = "0.3.16", default-features = false, features = ] } tracing-log = "0.1.3" tracing-tree = "0.2.1" +triomphe.workspace = true +nohash-hasher.workspace = true always-assert = "0.1.2" +# These dependencies are unused, but we pin them to a version here to restrict them for our transitive dependencies +# so that we don't pull in duplicates of their dependencies like windows-sys and syn 1 vs 2 +# these would pull in serde 2 +thiserror = "=1.0.39" +serde_repr = "=0.1.11" +# these would pull in windows-sys 0.45.0 +mio = "=0.8.5" +filetime = "=0.2.19" +parking_lot_core = "=0.9.6" + cfg.workspace = true flycheck.workspace = true hir-def.workspace = true @@ -57,7 +68,6 @@ ide-db.workspace = true ide-ssr.workspace = true ide.workspace = true proc-macro-api.workspace = true -proc-macro-srv.workspace = true profile.workspace = true project-model.workspace = true stdx.workspace = true @@ -75,7 +85,6 @@ jemallocator = { version = "0.5.0", package = "tikv-jemallocator", optional = tr [dev-dependencies] expect-test = "1.4.0" -jod-thread = "0.1.2" xshell = "0.2.2" test-utils.workspace = true @@ -85,8 +94,4 @@ mbe.workspace = true [features] jemalloc = ["jemallocator", "profile/jemalloc"] force-always-assert = ["always-assert/force"] -in-rust-tree = [ - "proc-macro-srv/sysroot-abi", - "ide/in-rust-tree", - "syntax/in-rust-tree", -] +in-rust-tree = ["ide/in-rust-tree", "syntax/in-rust-tree"] diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index 4de022b6ed607..91911dd180962 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -7,7 +7,11 @@ mod logger; mod rustc_wrapper; -use std::{env, fs, path::Path, process}; +use std::{ + env, fs, + path::{Path, PathBuf}, + process, +}; use lsp_server::Connection; use rust_analyzer::{cli::flags, config::Config, from_json, Result}; @@ -74,10 +78,16 @@ fn try_main(flags: flags::RustAnalyzer) -> Result<()> { println!("rust-analyzer {}", rust_analyzer::version()); return Ok(()); } - with_extra_thread("LspServer", run_server)?; - } - flags::RustAnalyzerCmd::ProcMacro(flags::ProcMacro) => { - with_extra_thread("MacroExpander", || proc_macro_srv::cli::run().map_err(Into::into))?; + + // rust-analyzer’s “main thread” is actually + // a secondary latency-sensitive thread with an increased stack size. + // We use this thread intent because any delay in the main loop + // will make actions like hitting enter in the editor slow. + with_extra_thread( + "LspServer", + stdx::thread::ThreadIntent::LatencySensitive, + run_server, + )?; } flags::RustAnalyzerCmd::Parse(cmd) => cmd.run()?, flags::RustAnalyzerCmd::Symbols(cmd) => cmd.run()?, @@ -135,14 +145,17 @@ const STACK_SIZE: usize = 1024 * 1024 * 8; /// space. fn with_extra_thread( thread_name: impl Into, + thread_intent: stdx::thread::ThreadIntent, f: impl FnOnce() -> Result<()> + Send + 'static, ) -> Result<()> { - let handle = - std::thread::Builder::new().name(thread_name.into()).stack_size(STACK_SIZE).spawn(f)?; - match handle.join() { - Ok(res) => res, - Err(panic) => std::panic::resume_unwind(panic), - } + let handle = stdx::thread::Builder::new(thread_intent) + .name(thread_name.into()) + .stack_size(STACK_SIZE) + .spawn(f)?; + + handle.join()?; + + Ok(()) } fn run_server() -> Result<()> { @@ -152,12 +165,18 @@ fn run_server() -> Result<()> { let (initialize_id, initialize_params) = connection.initialize_start()?; tracing::info!("InitializeParams: {}", initialize_params); - let initialize_params = - from_json::("InitializeParams", &initialize_params)?; - - let root_path = match initialize_params - .root_uri + let lsp_types::InitializeParams { + root_uri, + capabilities, + workspace_folders, + initialization_options, + client_info, + .. + } = from_json::("InitializeParams", &initialize_params)?; + + let root_path = match root_uri .and_then(|it| it.to_file_path().ok()) + .map(patch_path_prefix) .and_then(|it| AbsPathBuf::try_from(it).ok()) { Some(it) => it, @@ -167,19 +186,19 @@ fn run_server() -> Result<()> { } }; - let workspace_roots = initialize_params - .workspace_folders + let workspace_roots = workspace_folders .map(|workspaces| { workspaces .into_iter() .filter_map(|it| it.uri.to_file_path().ok()) + .map(patch_path_prefix) .filter_map(|it| AbsPathBuf::try_from(it).ok()) .collect::>() }) .filter(|workspaces| !workspaces.is_empty()) .unwrap_or_else(|| vec![root_path.clone()]); - let mut config = Config::new(root_path, initialize_params.capabilities, workspace_roots); - if let Some(json) = initialize_params.initialization_options { + let mut config = Config::new(root_path, capabilities, workspace_roots); + if let Some(json) = initialization_options { if let Err(e) = config.update(json) { use lsp_types::{ notification::{Notification, ShowMessage}, @@ -208,7 +227,7 @@ fn run_server() -> Result<()> { connection.initialize_finish(initialize_id, initialize_result)?; - if let Some(client_info) = initialize_params.client_info { + if let Some(client_info) = client_info { tracing::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); } @@ -222,3 +241,42 @@ fn run_server() -> Result<()> { tracing::info!("server did shut down"); Ok(()) } + +fn patch_path_prefix(path: PathBuf) -> PathBuf { + use std::path::{Component, Prefix}; + if cfg!(windows) { + // VSCode might report paths with the file drive in lowercase, but this can mess + // with env vars set by tools and build scripts executed by r-a such that it invalidates + // cargo's compilations unnecessarily. https://github.com/rust-lang/rust-analyzer/issues/14683 + // So we just uppercase the drive letter here unconditionally. + // (doing it conditionally is a pain because std::path::Prefix always reports uppercase letters on windows) + let mut comps = path.components(); + match comps.next() { + Some(Component::Prefix(prefix)) => { + let prefix = match prefix.kind() { + Prefix::Disk(d) => { + format!("{}:", d.to_ascii_uppercase() as char) + } + Prefix::VerbatimDisk(d) => { + format!(r"\\?\{}:", d.to_ascii_uppercase() as char) + } + _ => return path, + }; + let mut path = PathBuf::new(); + path.push(prefix); + path.extend(comps); + path + } + _ => path, + } + } else { + path + } +} + +#[test] +#[cfg(windows)] +fn patch_path_prefix_works() { + assert_eq!(patch_path_prefix(r"c:\foo\bar".into()), PathBuf::from(r"C:\foo\bar")); + assert_eq!(patch_path_prefix(r"\\?\c:\foo\bar".into()), PathBuf::from(r"\\?\C:\foo\bar")); +} diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index 3628670ac98b9..ab06b96814a29 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs @@ -23,13 +23,14 @@ use crate::semantic_tokens; pub fn server_capabilities(config: &Config) -> ServerCapabilities { ServerCapabilities { - position_encoding: Some(match negotiated_encoding(config.caps()) { - PositionEncoding::Utf8 => PositionEncodingKind::UTF8, + position_encoding: match negotiated_encoding(config.caps()) { + PositionEncoding::Utf8 => Some(PositionEncodingKind::UTF8), PositionEncoding::Wide(wide) => match wide { - WideEncoding::Utf16 => PositionEncodingKind::UTF16, - WideEncoding::Utf32 => PositionEncodingKind::UTF32, + WideEncoding::Utf16 => Some(PositionEncodingKind::UTF16), + WideEncoding::Utf32 => Some(PositionEncodingKind::UTF32), + _ => None, }, - }), + }, text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions { open_close: Some(true), change: Some(TextDocumentSyncKind::INCREMENTAL), diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs index cf51cf15a0e1d..c7b84c41b33e9 100644 --- a/crates/rust-analyzer/src/cargo_target_spec.rs +++ b/crates/rust-analyzer/src/cargo_target_spec.rs @@ -3,8 +3,9 @@ use std::mem; use cfg::{CfgAtom, CfgExpr}; -use ide::{Cancellable, FileId, RunnableKind, TestId}; +use ide::{Cancellable, CrateId, FileId, RunnableKind, TestId}; use project_model::{self, CargoFeatures, ManifestPath, TargetKind}; +use rustc_hash::FxHashSet; use vfs::AbsPathBuf; use crate::global_state::GlobalStateSnapshot; @@ -20,7 +21,9 @@ pub(crate) struct CargoTargetSpec { pub(crate) package: String, pub(crate) target: String, pub(crate) target_kind: TargetKind, + pub(crate) crate_id: CrateId, pub(crate) required_features: Vec, + pub(crate) features: FxHashSet, } impl CargoTargetSpec { @@ -73,12 +76,13 @@ impl CargoTargetSpec { } } - let target_required_features = if let Some(mut spec) = spec { + let (allowed_features, target_required_features) = if let Some(mut spec) = spec { + let allowed_features = mem::take(&mut spec.features); let required_features = mem::take(&mut spec.required_features); spec.push_to(&mut args, kind); - required_features + (allowed_features, required_features) } else { - Vec::new() + (Default::default(), Default::default()) }; let cargo_config = snap.config.cargo(); @@ -97,7 +101,9 @@ impl CargoTargetSpec { required_features(cfg, &mut feats); } - feats.extend(features.iter().cloned()); + feats.extend( + features.iter().filter(|&feat| allowed_features.contains(feat)).cloned(), + ); feats.extend(target_required_features); feats.dedup(); @@ -136,6 +142,8 @@ impl CargoTargetSpec { target: target_data.name.clone(), target_kind: target_data.kind, required_features: target_data.required_features.clone(), + features: package_data.features.keys().cloned().collect(), + crate_id, }; Ok(Some(res)) diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 6ce1de5d32bca..2c2a9a18d2e31 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -8,14 +8,14 @@ use std::{ use hir::{ db::{DefDatabase, ExpandDatabase, HirDatabase}, - AssocItem, Crate, Function, HasSource, HirDisplay, ModuleDef, + AssocItem, Crate, Function, HasCrate, HasSource, HirDisplay, ModuleDef, }; use hir_def::{ body::{BodySourceMap, SyntheticSyntax}, - expr::{ExprId, PatId}, + hir::{ExprId, PatId}, FunctionId, }; -use hir_ty::{Interner, TyExt, TypeFlags}; +use hir_ty::{Interner, Substitution, TyExt, TypeFlags}; use ide::{Analysis, AnalysisHost, LineCol, RootDatabase}; use ide_db::base_db::{ salsa::{self, debug::DebugQueryTable, ParallelDatabase}, @@ -121,14 +121,19 @@ impl flags::AnalysisStats { eprint!(" crates: {num_crates}"); let mut num_decls = 0; let mut funcs = Vec::new(); + let mut adts = Vec::new(); + let mut consts = Vec::new(); while let Some(module) = visit_queue.pop() { if visited_modules.insert(module) { visit_queue.extend(module.children(db)); for decl in module.declarations(db) { num_decls += 1; - if let ModuleDef::Function(f) = decl { - funcs.push(f); + match decl { + ModuleDef::Function(f) => funcs.push(f), + ModuleDef::Adt(a) => adts.push(a), + ModuleDef::Const(c) => consts.push(c), + _ => (), } } @@ -153,6 +158,13 @@ impl flags::AnalysisStats { self.run_inference(&host, db, &vfs, &funcs, verbosity); } + if !self.skip_mir_stats { + self.run_mir_lowering(db, &funcs, verbosity); + } + + self.run_data_layout(db, &adts, verbosity); + self.run_const_eval(db, &consts, verbosity); + let total_span = analysis_sw.elapsed(); eprintln!("{:<20} {total_span}", "Total:"); report_metric("total time", total_span.time.as_millis() as u64, "ms"); @@ -175,9 +187,8 @@ impl flags::AnalysisStats { let mut total_macro_file_size = Bytes::default(); for e in hir::db::ParseMacroExpansionQuery.in_db(db).entries::>() { - if let Some((val, _)) = db.parse_macro_expansion(e.key).value { - total_macro_file_size += syntax_len(val.syntax_node()) - } + let val = db.parse_macro_expansion(e.key).value.0; + total_macro_file_size += syntax_len(val.syntax_node()) } eprintln!("source files: {total_file_size}, macro files: {total_macro_file_size}"); } @@ -189,6 +200,93 @@ impl flags::AnalysisStats { Ok(()) } + fn run_data_layout(&self, db: &RootDatabase, adts: &[hir::Adt], verbosity: Verbosity) { + let mut sw = self.stop_watch(); + let mut all = 0; + let mut fail = 0; + for &a in adts { + if db.generic_params(a.into()).iter().next().is_some() { + // Data types with generics don't have layout. + continue; + } + all += 1; + let Err(e) = db.layout_of_adt(hir_def::AdtId::from(a).into(), Substitution::empty(Interner), a.krate(db).into()) else { + continue; + }; + if verbosity.is_spammy() { + let full_name = a + .module(db) + .path_to_root(db) + .into_iter() + .rev() + .filter_map(|it| it.name(db)) + .chain(Some(a.name(db))) + .map(|it| it.display(db).to_string()) + .join("::"); + println!("Data layout for {full_name} failed due {e:?}"); + } + fail += 1; + } + eprintln!("{:<20} {}", "Data layouts:", sw.elapsed()); + eprintln!("Failed data layouts: {fail} ({}%)", percentage(fail, all)); + report_metric("failed data layouts", fail, "#"); + } + + fn run_const_eval(&self, db: &RootDatabase, consts: &[hir::Const], verbosity: Verbosity) { + let mut sw = self.stop_watch(); + let mut all = 0; + let mut fail = 0; + for &c in consts { + all += 1; + let Err(e) = c.render_eval(db) else { + continue; + }; + if verbosity.is_spammy() { + let full_name = c + .module(db) + .path_to_root(db) + .into_iter() + .rev() + .filter_map(|it| it.name(db)) + .chain(c.name(db)) + .map(|it| it.display(db).to_string()) + .join("::"); + println!("Const eval for {full_name} failed due {e:?}"); + } + fail += 1; + } + eprintln!("{:<20} {}", "Const evaluation:", sw.elapsed()); + eprintln!("Failed const evals: {fail} ({}%)", percentage(fail, all)); + report_metric("failed const evals", fail, "#"); + } + + fn run_mir_lowering(&self, db: &RootDatabase, funcs: &[Function], verbosity: Verbosity) { + let mut sw = self.stop_watch(); + let all = funcs.len() as u64; + let mut fail = 0; + for f in funcs { + let Err(e) = db.mir_body(FunctionId::from(*f).into()) else { + continue; + }; + if verbosity.is_spammy() { + let full_name = f + .module(db) + .path_to_root(db) + .into_iter() + .rev() + .filter_map(|it| it.name(db)) + .chain(Some(f.name(db))) + .map(|it| it.display(db).to_string()) + .join("::"); + println!("Mir body for {full_name} failed due {e:?}"); + } + fail += 1; + } + eprintln!("{:<20} {}", "MIR lowering:", sw.elapsed()); + eprintln!("Mir failed bodies: {fail} ({}%)", percentage(fail, all)); + report_metric("mir failed bodies", fail, "#"); + } + fn run_inference( &self, host: &AnalysisHost, @@ -237,9 +335,10 @@ impl flags::AnalysisStats { .rev() .filter_map(|it| it.name(db)) .chain(Some(f.name(db))) + .map(|it| it.display(db).to_string()) .join("::"); if let Some(only_name) = self.only.as_deref() { - if name.to_string() != only_name && full_name != only_name { + if name.display(db).to_string() != only_name && full_name != only_name { continue; } } @@ -281,7 +380,7 @@ impl flags::AnalysisStats { end.col, )); } else { - bar.println(format!("{name}: Unknown type",)); + bar.println(format!("{}: Unknown type", name.display(db))); } } true @@ -336,7 +435,7 @@ impl flags::AnalysisStats { } else { bar.println(format!( "{}: Expected {}, got {}", - name, + name.display(db), mismatch.expected.display(db), mismatch.actual.display(db) )); @@ -384,7 +483,7 @@ impl flags::AnalysisStats { end.col, )); } else { - bar.println(format!("{name}: Unknown type",)); + bar.println(format!("{}: Unknown type", name.display(db))); } } true @@ -438,7 +537,7 @@ impl flags::AnalysisStats { } else { bar.println(format!( "{}: Expected {}, got {}", - name, + name.display(db), mismatch.expected.display(db), mismatch.actual.display(db) )); @@ -510,7 +609,7 @@ fn location_csv_expr( Ok(s) => s, Err(SyntheticSyntax) => return "synthetic,,".to_string(), }; - let root = db.parse_or_expand(src.file_id).unwrap(); + let root = db.parse_or_expand(src.file_id); let node = src.map(|e| e.to_node(&root).syntax().clone()); let original_range = node.as_ref().original_file_range(db); let path = vfs.file_path(original_range.file_id); @@ -532,7 +631,7 @@ fn location_csv_pat( Ok(s) => s, Err(SyntheticSyntax) => return "synthetic,,".to_string(), }; - let root = db.parse_or_expand(src.file_id).unwrap(); + let root = db.parse_or_expand(src.file_id); let node = src.map(|e| { e.either(|it| it.to_node(&root).syntax().clone(), |it| it.to_node(&root).syntax().clone()) }); @@ -554,7 +653,7 @@ fn expr_syntax_range( ) -> Option<(VfsPath, LineCol, LineCol)> { let src = sm.expr_syntax(expr_id); if let Ok(src) = src { - let root = db.parse_or_expand(src.file_id).unwrap(); + let root = db.parse_or_expand(src.file_id); let node = src.map(|e| e.to_node(&root).syntax().clone()); let original_range = node.as_ref().original_file_range(db); let path = vfs.file_path(original_range.file_id); @@ -576,7 +675,7 @@ fn pat_syntax_range( ) -> Option<(VfsPath, LineCol, LineCol)> { let src = sm.pat_syntax(pat_id); if let Ok(src) = src { - let root = db.parse_or_expand(src.file_id).unwrap(); + let root = db.parse_or_expand(src.file_id); let node = src.map(|e| { e.either( |it| it.to_node(&root).syntax().clone(), diff --git a/crates/rust-analyzer/src/cli/flags.rs b/crates/rust-analyzer/src/cli/flags.rs index 770612cc9478d..31012c01b9530 100644 --- a/crates/rust-analyzer/src/cli/flags.rs +++ b/crates/rust-analyzer/src/cli/flags.rs @@ -66,6 +66,8 @@ xflags::xflags! { optional --memory-usage /// Print the total length of all source and macro files (whitespace is not counted). optional --source-stats + /// Only type check, skip lowering to mir + optional --skip-mir-stats /// Only analyze items matching this path. optional -o, --only path: String @@ -104,14 +106,15 @@ xflags::xflags! { optional --debug snippet: String } - cmd proc-macro {} - cmd lsif { required path: PathBuf } cmd scip { required path: PathBuf + + /// The output path where the SCIP file will be written to. Defaults to `index.scip`. + optional --output path: PathBuf } } } @@ -139,7 +142,6 @@ pub enum RustAnalyzerCmd { Diagnostics(Diagnostics), Ssr(Ssr), Search(Search), - ProcMacro(ProcMacro), Lsif(Lsif), Scip(Scip), } @@ -172,6 +174,7 @@ pub struct AnalysisStats { pub parallel: bool, pub memory_usage: bool, pub source_stats: bool, + pub skip_mir_stats: bool, pub only: Option, pub with_deps: bool, pub no_sysroot: bool, @@ -200,9 +203,6 @@ pub struct Search { pub debug: Option, } -#[derive(Debug)] -pub struct ProcMacro; - #[derive(Debug)] pub struct Lsif { pub path: PathBuf, @@ -211,6 +211,7 @@ pub struct Lsif { #[derive(Debug)] pub struct Scip { pub path: PathBuf, + pub output: Option, } impl RustAnalyzer { diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 5a958d963e4b5..4e8f99971674a 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -1,14 +1,17 @@ //! Loads a Cargo project into a static instance of analysis, without support //! for incorporating changes. -use std::{convert::identity, path::Path, sync::Arc}; +use std::path::Path; -use anyhow::Result; +use anyhow::{anyhow, Result}; use crossbeam_channel::{unbounded, Receiver}; -use hir::db::DefDatabase; use ide::{AnalysisHost, Change}; -use ide_db::{base_db::CrateGraph, FxHashMap}; +use ide_db::{ + base_db::{CrateGraph, ProcMacros}, + FxHashMap, +}; use proc_macro_api::ProcMacroServer; use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace}; +use triomphe::Arc; use vfs::{loader::Handle, AbsPath, AbsPathBuf}; use crate::reload::{load_proc_macro, ProjectFolders, SourceRootConfig}; @@ -24,7 +27,7 @@ pub struct LoadCargoConfig { #[derive(Debug, Clone, PartialEq, Eq)] pub enum ProcMacroServerChoice { Sysroot, - Explicit(AbsPathBuf, Vec), + Explicit(AbsPathBuf), None, } @@ -66,23 +69,17 @@ pub fn load_workspace( Box::new(loader) }; - let proc_macro_client = match &load_config.with_proc_macro_server { + let proc_macro_server = match &load_config.with_proc_macro_server { ProcMacroServerChoice::Sysroot => ws .find_sysroot_proc_macro_srv() - .ok_or_else(|| "failed to find sysroot proc-macro server".to_owned()) - .and_then(|it| { - ProcMacroServer::spawn(it, identity::<&[&str]>(&[])).map_err(|e| e.to_string()) - }), - ProcMacroServerChoice::Explicit(path, args) => { - ProcMacroServer::spawn(path.clone(), args).map_err(|e| e.to_string()) + .and_then(|it| ProcMacroServer::spawn(it).map_err(Into::into)), + ProcMacroServerChoice::Explicit(path) => { + ProcMacroServer::spawn(path.clone()).map_err(Into::into) } - ProcMacroServerChoice::None => Err("proc macro server disabled".to_owned()), + ProcMacroServerChoice::None => Err(anyhow!("proc macro server disabled")), }; - let crate_graph = ws.to_crate_graph( - &mut |_, path: &AbsPath| { - load_proc_macro(proc_macro_client.as_ref().map_err(|e| &**e), path, &[]) - }, + let (crate_graph, proc_macros) = ws.to_crate_graph( &mut |path: &AbsPath| { let contents = loader.load_sync(path); let path = vfs::VfsPath::from(path.to_path_buf()); @@ -91,6 +88,28 @@ pub fn load_workspace( }, extra_env, ); + let proc_macros = { + let proc_macro_server = match &proc_macro_server { + Ok(it) => Ok(it), + Err(e) => Err(e.to_string()), + }; + proc_macros + .into_iter() + .map(|(crate_id, path)| { + ( + crate_id, + path.map_or_else( + |_| Err("proc macro crate is missing dylib".to_owned()), + |(_, path)| { + proc_macro_server.as_ref().map_err(Clone::clone).and_then( + |proc_macro_server| load_proc_macro(proc_macro_server, &path, &[]), + ) + }, + ), + ) + }) + .collect() + }; let project_folders = ProjectFolders::new(&[ws], &[]); loader.set_config(vfs::loader::Config { @@ -100,17 +119,23 @@ pub fn load_workspace( }); tracing::debug!("crate graph: {:?}", crate_graph); - let host = - load_crate_graph(crate_graph, project_folders.source_root_config, &mut vfs, &receiver); + let host = load_crate_graph( + crate_graph, + proc_macros, + project_folders.source_root_config, + &mut vfs, + &receiver, + ); if load_config.prefill_caches { host.analysis().parallel_prime_caches(1, |_| {})?; } - Ok((host, vfs, proc_macro_client.ok())) + Ok((host, vfs, proc_macro_server.ok())) } fn load_crate_graph( crate_graph: CrateGraph, + proc_macros: ProcMacros, source_root_config: SourceRootConfig, vfs: &mut vfs::Vfs, receiver: &Receiver, @@ -119,7 +144,7 @@ fn load_crate_graph( let mut host = AnalysisHost::new(lru_cap); let mut analysis_change = Change::new(); - host.raw_database_mut().set_enable_proc_attr_macros(true); + host.raw_database_mut().enable_proc_attr_macros(); // wait until Vfs has loaded all roots for task in receiver { @@ -139,9 +164,9 @@ fn load_crate_graph( let changes = vfs.take_changes(); for file in changes { if file.exists() { - let contents = vfs.file_contents(file.file_id).to_vec(); - if let Ok(text) = String::from_utf8(contents) { - analysis_change.change_file(file.file_id, Some(Arc::new(text))) + let contents = vfs.file_contents(file.file_id); + if let Ok(text) = std::str::from_utf8(contents) { + analysis_change.change_file(file.file_id, Some(Arc::from(text))) } } } @@ -149,6 +174,7 @@ fn load_crate_graph( analysis_change.set_roots(source_roots); analysis_change.set_crate_graph(crate_graph); + analysis_change.set_proc_macros(proc_macros); host.apply_change(analysis_change); host diff --git a/crates/rust-analyzer/src/cli/scip.rs b/crates/rust-analyzer/src/cli/scip.rs index 3e5e40750e9ca..b0b724bdfe73d 100644 --- a/crates/rust-analyzer/src/cli/scip.rs +++ b/crates/rust-analyzer/src/cli/scip.rs @@ -2,6 +2,7 @@ use std::{ collections::{HashMap, HashSet}, + path::PathBuf, time::Instant, }; @@ -9,7 +10,6 @@ use crate::{ cli::load_cargo::ProcMacroServerChoice, line_index::{LineEndings, LineIndex, PositionEncoding}, }; -use hir::Name; use ide::{ LineCol, MonikerDescriptorKind, StaticIndex, StaticIndexedFile, TextRange, TokenId, TokenStaticData, @@ -66,7 +66,6 @@ impl flags::Scip { .as_os_str() .to_str() .ok_or(anyhow::anyhow!("Unable to normalize project_root path"))? - .to_string() ), text_document_encoding: scip_types::TextEncoding::UTF8.into(), special_fields: Default::default(), @@ -167,7 +166,8 @@ impl flags::Scip { special_fields: Default::default(), }; - scip::write_message_to_file("index.scip", index) + let out_path = self.output.unwrap_or_else(|| PathBuf::from(r"index.scip")); + scip::write_message_to_file(out_path, index) .map_err(|err| anyhow::anyhow!("Failed to write scip to file: {}", err))?; eprintln!("Generating SCIP finished {:?}", now.elapsed()); @@ -210,13 +210,12 @@ fn new_descriptor_str( } } -fn new_descriptor(name: Name, suffix: scip_types::descriptor::Suffix) -> scip_types::Descriptor { - let mut name = name.to_string(); - if name.contains("'") { - name = format!("`{name}`"); +fn new_descriptor(name: &str, suffix: scip_types::descriptor::Suffix) -> scip_types::Descriptor { + if name.contains('\'') { + new_descriptor_str(&format!("`{name}`"), suffix) + } else { + new_descriptor_str(&name, suffix) } - - new_descriptor_str(name.as_str(), suffix) } /// Loosely based on `def_to_moniker` @@ -236,7 +235,7 @@ fn token_to_symbol(token: &TokenStaticData) -> Option { .iter() .map(|desc| { new_descriptor( - desc.name.clone(), + &desc.name, match desc.desc { MonikerDescriptorKind::Namespace => Namespace, MonikerDescriptorKind::Type => Type, diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index c35cce103fab6..6355c620f7802 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -7,13 +7,14 @@ //! configure the server itself, feature flags are passed into analysis, and //! tweak things like automatic insertion of `()` in completions. -use std::{fmt, iter, path::PathBuf}; +use std::{fmt, iter, ops::Not, path::PathBuf}; +use cfg::{CfgAtom, CfgDiff}; use flycheck::FlycheckConfig; use ide::{ AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode, HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayHintsConfig, - JoinLinesConfig, Snippet, SnippetScope, + JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, Snippet, SnippetScope, }; use ide_db::{ imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind}, @@ -23,11 +24,10 @@ use itertools::Itertools; use lsp_types::{ClientCapabilities, MarkupKind}; use project_model::{ CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectManifest, RustLibSource, - UnsetTestCrates, }; use rustc_hash::{FxHashMap, FxHashSet}; use serde::{de::DeserializeOwned, Deserialize}; -use vfs::AbsPathBuf; +use vfs::{AbsPath, AbsPathBuf}; use crate::{ caps::completion_item_edit_resolve, @@ -101,6 +101,8 @@ config_data! { /// Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to /// avoid checking unnecessary things. cargo_buildScripts_useRustcWrapper: bool = "true", + /// List of cfg options to enable with the given values. + cargo_cfgs: FxHashMap = "{}", /// Extra arguments that are passed to every cargo invocation. cargo_extraArgs: Vec = "[]", /// Extra environment variables that will be set when running cargo, rustc @@ -128,7 +130,7 @@ config_data! { // FIXME(@poliorcetics): move to multiple targets here too, but this will need more work // than `checkOnSave_target` cargo_target: Option = "null", - /// Unsets `#[cfg(test)]` for the specified crates. + /// Unsets the implicit `#[cfg(test)]` for the specified crates. cargo_unsetTest: Vec = "[\"core\"]", /// Run the check command for diagnostics on save. @@ -281,6 +283,8 @@ config_data! { /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords. highlightRelated_breakPoints_enable: bool = "true", + /// Enables highlighting of all captures of a closure while the cursor is on the `|` or move keyword of a closure. + highlightRelated_closureCaptures_enable: bool = "true", /// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`). highlightRelated_exitPoints_enable: bool = "true", /// Enables highlighting of related references while the cursor is on any identifier. @@ -311,8 +315,18 @@ config_data! { /// Whether to show keyword hover popups. Only applies when /// `#rust-analyzer.hover.documentation.enable#` is set. hover_documentation_keywords_enable: bool = "true", - /// Use markdown syntax for links in hover. + /// Use markdown syntax for links on hover. hover_links_enable: bool = "true", + /// How to render the align information in a memory layout hover. + hover_memoryLayout_alignment: Option = "\"hexadecimal\"", + /// Whether to show memory layout data on hover. + hover_memoryLayout_enable: bool = "true", + /// How to render the niche information in a memory layout hover. + hover_memoryLayout_niches: Option = "false", + /// How to render the offset information in a memory layout hover. + hover_memoryLayout_offset: Option = "\"hexadecimal\"", + /// How to render the size information in a memory layout hover. + hover_memoryLayout_size: Option = "\"both\"", /// Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file. imports_granularity_enforce: bool = "false", @@ -336,8 +350,12 @@ config_data! { /// Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1 /// to always show them). inlayHints_closingBraceHints_minLines: usize = "25", + /// Whether to show inlay hints for closure captures. + inlayHints_closureCaptureHints_enable: bool = "false", /// Whether to show inlay type hints for return types of closures. inlayHints_closureReturnTypeHints_enable: ClosureReturnTypeHintsDef = "\"never\"", + /// Closure notation in type and chaining inlay hints. + inlayHints_closureStyle: ClosureStyle = "\"impl_fn\"", /// Whether to show enum variant discriminant hints. inlayHints_discriminantHints_enable: DiscriminantHintsDef = "\"never\"", /// Whether to show inlay hints for type adjustments. @@ -418,6 +436,8 @@ config_data! { /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128. lru_capacity: Option = "null", + /// Sets the LRU capacity of the specified queries. + lru_query_capacities: FxHashMap, usize> = "{}", /// Whether to show `can't find Cargo.toml` error message. notifications_cargoTomlNotFound: bool = "true", @@ -433,8 +453,7 @@ config_data! { /// /// This config takes a map of crate names with the exported proc-macro names to ignore as values. procMacro_ignored: FxHashMap, Box<[Box]>> = "{}", - /// Internal config, path to proc-macro server executable (typically, - /// this is rust-analyzer itself, but we override this in tests). + /// Internal config, path to proc-macro server executable. procMacro_server: Option = "null", /// Exclude imports from find-all-references. @@ -474,6 +493,8 @@ config_data! { /// When enabled, rust-analyzer will highlight rust source in doc comments as well as intra /// doc links. semanticHighlighting_doc_comment_inject_enable: bool = "true", + /// Whether the server is allowed to emit non-standard tokens and modifiers. + semanticHighlighting_nonStandardTokens: bool = "true", /// Use semantic tokens for operators. /// /// When disabled, rust-analyzer will emit semantic tokens only for operator tokens when @@ -484,7 +505,7 @@ config_data! { /// When enabled, rust-analyzer will emit special token types for operator tokens instead /// of the generic `operator` token type. semanticHighlighting_operator_specialization_enable: bool = "false", - /// Use semantic tokens for punctuations. + /// Use semantic tokens for punctuation. /// /// When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when /// they are tagged with modifiers or have a special role. @@ -492,7 +513,7 @@ config_data! { /// When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro /// calls. semanticHighlighting_punctuation_separate_macro_bang: bool = "false", - /// Use specialized semantic tokens for punctuations. + /// Use specialized semantic tokens for punctuation. /// /// When enabled, rust-analyzer will emit special token types for punctuation tokens instead /// of the generic `punctuation` token type. @@ -531,8 +552,9 @@ impl Default for ConfigData { #[derive(Debug, Clone)] pub struct Config { - pub discovered_projects: Option>, - pub workspace_roots: Vec, + discovered_projects: Vec, + /// The workspace roots as registered by the LSP client + workspace_roots: Vec, caps: lsp_types::ClientCapabilities, root_path: AbsPathBuf, data: ConfigData, @@ -570,6 +592,7 @@ pub struct LensConfig { // runnables pub run: bool, pub debug: bool, + pub interpret: bool, // implementations pub implementations: bool, @@ -707,11 +730,11 @@ pub struct ClientCommandsConfig { } #[derive(Debug)] -pub struct ConfigUpdateError { +pub struct ConfigError { errors: Vec<(String, serde_json::Error)>, } -impl fmt::Display for ConfigUpdateError { +impl fmt::Display for ConfigError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let errors = self.errors.iter().format_with("\n", |(key, e), f| { f(key)?; @@ -720,8 +743,7 @@ impl fmt::Display for ConfigUpdateError { }); write!( f, - "rust-analyzer found {} invalid config value{}:\n{}", - self.errors.len(), + "invalid config value{}:\n{}", if self.errors.len() == 1 { "" } else { "s" }, errors ) @@ -738,7 +760,7 @@ impl Config { caps, data: ConfigData::default(), detached_files: Vec::new(), - discovered_projects: None, + discovered_projects: Vec::new(), root_path, snippets: Default::default(), workspace_roots, @@ -751,10 +773,20 @@ impl Config { if discovered.is_empty() { tracing::error!("failed to find any projects in {:?}", &self.workspace_roots); } - self.discovered_projects = Some(discovered); + self.discovered_projects = discovered; } - pub fn update(&mut self, mut json: serde_json::Value) -> Result<(), ConfigUpdateError> { + pub fn remove_workspace(&mut self, path: &AbsPath) { + if let Some(position) = self.workspace_roots.iter().position(|it| it == path) { + self.workspace_roots.remove(position); + } + } + + pub fn add_workspaces(&mut self, paths: impl Iterator) { + self.workspace_roots.extend(paths); + } + + pub fn update(&mut self, mut json: serde_json::Value) -> Result<(), ConfigError> { tracing::info!("updating config from JSON: {:#}", json); if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) { return Ok(()); @@ -801,7 +833,7 @@ impl Config { if errors.is_empty() { Ok(()) } else { - Err(ConfigUpdateError { errors }) + Err(ConfigError { errors }) } } @@ -856,25 +888,19 @@ impl Config { pub fn linked_projects(&self) -> Vec { match self.data.linkedProjects.as_slice() { [] => { - match self.discovered_projects.as_ref() { - Some(discovered_projects) => { - let exclude_dirs: Vec<_> = self - .data - .files_excludeDirs - .iter() - .map(|p| self.root_path.join(p)) - .collect(); - discovered_projects - .iter() - .filter(|(ProjectManifest::ProjectJson(path) | ProjectManifest::CargoToml(path))| { + let exclude_dirs: Vec<_> = + self.data.files_excludeDirs.iter().map(|p| self.root_path.join(p)).collect(); + self.discovered_projects + .iter() + .filter( + |(ProjectManifest::ProjectJson(path) + | ProjectManifest::CargoToml(path))| { !exclude_dirs.iter().any(|p| path.starts_with(p)) - }) - .cloned() - .map(LinkedProject::from) - .collect() - } - None => Vec::new(), - } + }, + ) + .cloned() + .map(LinkedProject::from) + .collect() } linked_projects => linked_projects .iter() @@ -1013,6 +1039,11 @@ impl Config { .is_some() } + pub fn semantics_tokens_augments_syntax_tokens(&self) -> bool { + try_!(self.caps.text_document.as_ref()?.semantic_tokens.as_ref()?.augments_syntax_tokens?) + .unwrap_or(false) + } + pub fn position_encoding(&self) -> PositionEncoding { negotiated_encoding(&self.caps) } @@ -1025,6 +1056,10 @@ impl Config { self.experimental("codeActionGroup") } + pub fn local_docs(&self) -> bool { + self.experimental("localDocs") + } + pub fn open_server_logs(&self) -> bool { self.experimental("openServerLogs") } @@ -1085,27 +1120,27 @@ impl Config { extra_env } - pub fn lru_capacity(&self) -> Option { + pub fn lru_parse_query_capacity(&self) -> Option { self.data.lru_capacity } - pub fn proc_macro_srv(&self) -> Option<(AbsPathBuf, /* is path explicitly set */ bool)> { - if !self.data.procMacro_enable { - return None; - } - Some(match &self.data.procMacro_server { - Some(it) => ( - AbsPathBuf::try_from(it.clone()).unwrap_or_else(|path| self.root_path.join(path)), - true, - ), - None => (AbsPathBuf::assert(std::env::current_exe().ok()?), false), - }) + pub fn lru_query_capacities(&self) -> Option<&FxHashMap, usize>> { + self.data.lru_query_capacities.is_empty().not().then(|| &self.data.lru_query_capacities) + } + + pub fn proc_macro_srv(&self) -> Option { + let path = self.data.procMacro_server.clone()?; + Some(AbsPathBuf::try_from(path).unwrap_or_else(|path| self.root_path.join(&path))) } pub fn dummy_replacements(&self) -> &FxHashMap, Box<[Box]>> { &self.data.procMacro_ignored } + pub fn expand_proc_macros(&self) -> bool { + self.data.procMacro_enable + } + pub fn expand_proc_attr_macros(&self) -> bool { self.data.procMacro_enable && self.data.procMacro_attributes_enable } @@ -1164,7 +1199,34 @@ impl Config { sysroot, sysroot_src, rustc_source, - unset_test_crates: UnsetTestCrates::Only(self.data.cargo_unsetTest.clone()), + cfg_overrides: project_model::CfgOverrides { + global: CfgDiff::new( + self.data + .cargo_cfgs + .iter() + .map(|(key, val)| { + if val.is_empty() { + CfgAtom::Flag(key.into()) + } else { + CfgAtom::KeyValue { key: key.into(), value: val.into() } + } + }) + .collect(), + vec![], + ) + .unwrap(), + selective: self + .data + .cargo_unsetTest + .iter() + .map(|it| { + ( + it.clone(), + CfgDiff::new(vec![], vec![CfgAtom::Flag("test".into())]).unwrap(), + ) + }) + .collect(), + }, wrap_rustc_in_build_scripts: self.data.cargo_buildScripts_useRustcWrapper, invocation_strategy: match self.data.cargo_buildScripts_invocationStrategy { InvocationStrategy::Once => project_model::InvocationStrategy::Once, @@ -1291,6 +1353,13 @@ impl Config { hide_closure_initialization_hints: self .data .inlayHints_typeHints_hideClosureInitialization, + closure_style: match self.data.inlayHints_closureStyle { + ClosureStyle::ImplFn => hir::ClosureStyle::ImplFn, + ClosureStyle::RustAnalyzer => hir::ClosureStyle::RANotation, + ClosureStyle::WithId => hir::ClosureStyle::ClosureWithId, + ClosureStyle::Hide => hir::ClosureStyle::Hide, + }, + closure_capture_hints: self.data.inlayHints_closureCaptureHints_enable, adjustment_hints: match self.data.inlayHints_expressionAdjustmentHints_enable { AdjustmentHintsDef::Always => ide::AdjustmentHints::Always, AdjustmentHintsDef::Never => match self.data.inlayHints_reborrowHints_enable { @@ -1409,6 +1478,9 @@ impl Config { LensConfig { run: self.data.lens_enable && self.data.lens_run_enable, debug: self.data.lens_enable && self.data.lens_debug_enable, + interpret: self.data.lens_enable + && self.data.lens_run_enable + && self.data.interpret_tests, implementations: self.data.lens_enable && self.data.lens_implementations_enable, method_refs: self.data.lens_enable && self.data.lens_references_method_enable, refs_adt: self.data.lens_enable && self.data.lens_references_adt_enable, @@ -1430,6 +1502,10 @@ impl Config { } } + pub fn highlighting_non_standard_tokens(&self) -> bool { + self.data.semanticHighlighting_nonStandardTokens + } + pub fn highlighting_config(&self) -> HighlightConfig { HighlightConfig { strings: self.data.semanticHighlighting_strings_enable, @@ -1446,8 +1522,19 @@ impl Config { } pub fn hover(&self) -> HoverConfig { + let mem_kind = |kind| match kind { + MemoryLayoutHoverRenderKindDef::Both => MemoryLayoutHoverRenderKind::Both, + MemoryLayoutHoverRenderKindDef::Decimal => MemoryLayoutHoverRenderKind::Decimal, + MemoryLayoutHoverRenderKindDef::Hexadecimal => MemoryLayoutHoverRenderKind::Hexadecimal, + }; HoverConfig { links_in_hover: self.data.hover_links_enable, + memory_layout: self.data.hover_memoryLayout_enable.then_some(MemoryLayoutHoverConfig { + size: self.data.hover_memoryLayout_size.map(mem_kind), + offset: self.data.hover_memoryLayout_offset.map(mem_kind), + alignment: self.data.hover_memoryLayout_alignment.map(mem_kind), + niches: self.data.hover_memoryLayout_niches.unwrap_or_default(), + }), documentation: self.data.hover_documentation_enable, format: { let is_markdown = try_or_def!(self @@ -1467,7 +1554,6 @@ impl Config { } }, keywords: self.data.hover_documentation_keywords_enable, - interpret_tests: self.data.interpret_tests, } } @@ -1537,6 +1623,7 @@ impl Config { break_points: self.data.highlightRelated_breakPoints_enable, exit_points: self.data.highlightRelated_exitPoints_enable, yield_points: self.data.highlightRelated_yieldPoints_enable, + closure_captures: self.data.highlightRelated_closureCaptures_enable, } } @@ -1657,6 +1744,9 @@ mod de_unit_v { named_unit_variant!(reborrow); named_unit_variant!(fieldless); named_unit_variant!(with_block); + named_unit_variant!(decimal); + named_unit_variant!(hexadecimal); + named_unit_variant!(both); } #[derive(Deserialize, Debug, Clone, Copy)] @@ -1797,6 +1887,15 @@ enum ClosureReturnTypeHintsDef { WithBlock, } +#[derive(Deserialize, Debug, Clone)] +#[serde(rename_all = "snake_case")] +enum ClosureStyle { + ImplFn, + RustAnalyzer, + WithId, + Hide, +} + #[derive(Deserialize, Debug, Clone)] #[serde(untagged)] enum ReborrowHintsDef { @@ -1878,6 +1977,18 @@ enum WorkspaceSymbolSearchKindDef { AllSymbols, } +#[derive(Deserialize, Debug, Copy, Clone)] +#[serde(rename_all = "snake_case")] +#[serde(untagged)] +pub enum MemoryLayoutHoverRenderKindDef { + #[serde(deserialize_with = "de_unit_v::decimal")] + Decimal, + #[serde(deserialize_with = "de_unit_v::hexadecimal")] + Hexadecimal, + #[serde(deserialize_with = "de_unit_v::both")] + Both, +} + macro_rules! _config_data { (struct $name:ident { $( @@ -1940,7 +2051,7 @@ fn get_field( alias: Option<&'static str>, default: &str, ) -> T { - // XXX: check alias first, to work-around the VS Code where it pre-fills the + // XXX: check alias first, to work around the VS Code where it pre-fills the // defaults instead of sending an empty object. alias .into_iter() @@ -1960,7 +2071,9 @@ fn get_field( None } }) - .unwrap_or_else(|| serde_json::from_str(default).unwrap()) + .unwrap_or_else(|| { + serde_json::from_str(default).unwrap_or_else(|e| panic!("{e} on: `{default}`")) + }) } fn schema(fields: &[(&'static str, &'static str, &[&str], &str)]) -> serde_json::Value { @@ -2020,6 +2133,9 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json "FxHashMap" => set! { "type": "object", }, + "FxHashMap, usize>" => set! { + "type": "object", + }, "Option" => set! { "type": ["null", "integer"], "minimum": 0, @@ -2169,8 +2285,8 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json "enumDescriptions": [ "Always show adjustment hints as prefix (`*expr`).", "Always show adjustment hints as postfix (`expr.*`).", - "Show prefix or postfix depending on which uses less parenthesis, prefering prefix.", - "Show prefix or postfix depending on which uses less parenthesis, prefering postfix.", + "Show prefix or postfix depending on which uses less parenthesis, preferring prefix.", + "Show prefix or postfix depending on which uses less parenthesis, preferring postfix.", ] }, "CargoFeaturesDef" => set! { @@ -2275,6 +2391,32 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json }, ], }, + "ClosureStyle" => set! { + "type": "string", + "enum": ["impl_fn", "rust_analyzer", "with_id", "hide"], + "enumDescriptions": [ + "`impl_fn`: `impl FnMut(i32, u64) -> i8`", + "`rust_analyzer`: `|i32, u64| -> i8`", + "`with_id`: `{closure#14352}`, where that id is the unique number of the closure in r-a internals", + "`hide`: Shows `...` for every closure type", + ], + }, + "Option" => set! { + "anyOf": [ + { + "type": "null" + }, + { + "type": "string", + "enum": ["both", "decimal", "hexadecimal", ], + "enumDescriptions": [ + "Render as 12 (0xC)", + "Render as 12", + "Render as 0xC" + ], + }, + ], + }, _ => panic!("missing entry for {ty}: {default}"), } @@ -2384,4 +2526,43 @@ mod tests { fn remove_ws(text: &str) -> String { text.replace(char::is_whitespace, "") } + + #[test] + fn proc_macro_srv_null() { + let mut config = + Config::new(AbsPathBuf::try_from(project_root()).unwrap(), Default::default(), vec![]); + config + .update(serde_json::json!({ + "procMacro_server": null, + })) + .unwrap(); + assert_eq!(config.proc_macro_srv(), None); + } + + #[test] + fn proc_macro_srv_abs() { + let mut config = + Config::new(AbsPathBuf::try_from(project_root()).unwrap(), Default::default(), vec![]); + config + .update(serde_json::json!({ + "procMacro": {"server": project_root().display().to_string()} + })) + .unwrap(); + assert_eq!(config.proc_macro_srv(), Some(AbsPathBuf::try_from(project_root()).unwrap())); + } + + #[test] + fn proc_macro_srv_rel() { + let mut config = + Config::new(AbsPathBuf::try_from(project_root()).unwrap(), Default::default(), vec![]); + config + .update(serde_json::json!({ + "procMacro": {"server": "./server"} + })) + .unwrap(); + assert_eq!( + config.proc_macro_srv(), + Some(AbsPathBuf::try_from(project_root().join("./server")).unwrap()) + ); + } } diff --git a/crates/rust-analyzer/src/diagnostics.rs b/crates/rust-analyzer/src/diagnostics.rs index 83b03fe473621..33422fd058ef0 100644 --- a/crates/rust-analyzer/src/diagnostics.rs +++ b/crates/rust-analyzer/src/diagnostics.rs @@ -1,15 +1,16 @@ //! Book keeping for keeping diagnostics easily in sync with the client. pub(crate) mod to_proto; -use std::{mem, sync::Arc}; +use std::mem; use ide::FileId; use ide_db::FxHashMap; -use stdx::hash::{NoHashHashMap, NoHashHashSet}; +use nohash_hasher::{IntMap, IntSet}; +use triomphe::Arc; use crate::lsp_ext; -pub(crate) type CheckFixes = Arc>>>; +pub(crate) type CheckFixes = Arc>>>; #[derive(Debug, Default, Clone)] pub struct DiagnosticsMapConfig { @@ -20,12 +21,12 @@ pub struct DiagnosticsMapConfig { #[derive(Debug, Default, Clone)] pub(crate) struct DiagnosticCollection { - // FIXME: should be NoHashHashMap> - pub(crate) native: NoHashHashMap>, + // FIXME: should be IntMap> + pub(crate) native: IntMap>, // FIXME: should be Vec - pub(crate) check: NoHashHashMap>>, + pub(crate) check: IntMap>>, pub(crate) check_fixes: CheckFixes, - changes: NoHashHashSet, + changes: IntSet, } #[derive(Debug, Clone)] @@ -105,7 +106,7 @@ impl DiagnosticCollection { native.chain(check) } - pub(crate) fn take_changes(&mut self) -> Option> { + pub(crate) fn take_changes(&mut self) -> Option> { if self.changes.is_empty() { return None; } diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index 415fa4e02f20c..e1d1130ff1b87 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs @@ -3,7 +3,6 @@ use std::collections::HashMap; use flycheck::{Applicability, DiagnosticLevel, DiagnosticSpan}; -use ide_db::line_index::WideEncoding; use itertools::Itertools; use stdx::format_to; use vfs::{AbsPath, AbsPathBuf}; @@ -80,37 +79,33 @@ fn position( position_encoding: &PositionEncoding, span: &DiagnosticSpan, line_offset: usize, - column_offset: usize, + column_offset_utf32: usize, ) -> lsp_types::Position { let line_index = line_offset - span.line_start; - let mut true_column_offset = column_offset; - if let Some(line) = span.text.get(line_index) { - if line.text.chars().count() == line.text.len() { - // all one byte utf-8 char - return lsp_types::Position { - line: (line_offset as u32).saturating_sub(1), - character: (column_offset as u32).saturating_sub(1), - }; - } - let mut char_offset = 0; - let len_func = match position_encoding { - PositionEncoding::Utf8 => char::len_utf8, - PositionEncoding::Wide(WideEncoding::Utf16) => char::len_utf16, - PositionEncoding::Wide(WideEncoding::Utf32) => |_| 1, - }; - for c in line.text.chars() { - char_offset += 1; - if char_offset > column_offset { - break; + let column_offset_encoded = match span.text.get(line_index) { + // Fast path. + Some(line) if line.text.is_ascii() => column_offset_utf32, + Some(line) => { + let line_prefix_len = line + .text + .char_indices() + .take(column_offset_utf32) + .last() + .map(|(pos, c)| pos + c.len_utf8()) + .unwrap_or(0); + let line_prefix = &line.text[..line_prefix_len]; + match position_encoding { + PositionEncoding::Utf8 => line_prefix.len(), + PositionEncoding::Wide(enc) => enc.measure(line_prefix), } - true_column_offset += len_func(c) - 1; } - } + None => column_offset_utf32, + }; lsp_types::Position { line: (line_offset as u32).saturating_sub(1), - character: (true_column_offset as u32).saturating_sub(1), + character: (column_offset_encoded as u32).saturating_sub(1), } } diff --git a/crates/rust-analyzer/src/dispatch.rs b/crates/rust-analyzer/src/dispatch.rs index 313bb2ec8dffa..ebe77b8dfe721 100644 --- a/crates/rust-analyzer/src/dispatch.rs +++ b/crates/rust-analyzer/src/dispatch.rs @@ -4,6 +4,7 @@ use std::{fmt, panic, thread}; use ide::Cancelled; use lsp_server::ExtractError; use serde::{de::DeserializeOwned, Serialize}; +use stdx::thread::ThreadIntent; use crate::{ global_state::{GlobalState, GlobalStateSnapshot}, @@ -87,7 +88,8 @@ impl<'a> RequestDispatcher<'a> { self } - /// Dispatches the request onto thread pool + /// Dispatches a non-latency-sensitive request onto the thread pool + /// without retrying it if it panics. pub(crate) fn on_no_retry( &mut self, f: fn(GlobalStateSnapshot, R::Params) -> Result, @@ -102,7 +104,7 @@ impl<'a> RequestDispatcher<'a> { None => return self, }; - self.global_state.task_pool.handle.spawn({ + self.global_state.task_pool.handle.spawn(ThreadIntent::Worker, { let world = self.global_state.snapshot(); move || { let result = panic::catch_unwind(move || { @@ -123,11 +125,49 @@ impl<'a> RequestDispatcher<'a> { self } - /// Dispatches the request onto thread pool + /// Dispatches a non-latency-sensitive request onto the thread pool. pub(crate) fn on( &mut self, f: fn(GlobalStateSnapshot, R::Params) -> Result, ) -> &mut Self + where + R: lsp_types::request::Request + 'static, + R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug, + R::Result: Serialize, + { + self.on_with_thread_intent::(ThreadIntent::Worker, f) + } + + /// Dispatches a latency-sensitive request onto the thread pool. + pub(crate) fn on_latency_sensitive( + &mut self, + f: fn(GlobalStateSnapshot, R::Params) -> Result, + ) -> &mut Self + where + R: lsp_types::request::Request + 'static, + R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug, + R::Result: Serialize, + { + self.on_with_thread_intent::(ThreadIntent::LatencySensitive, f) + } + + pub(crate) fn finish(&mut self) { + if let Some(req) = self.req.take() { + tracing::error!("unknown request: {:?}", req); + let response = lsp_server::Response::new_err( + req.id, + lsp_server::ErrorCode::MethodNotFound as i32, + "unknown request".to_string(), + ); + self.global_state.respond(response); + } + } + + fn on_with_thread_intent( + &mut self, + intent: ThreadIntent, + f: fn(GlobalStateSnapshot, R::Params) -> Result, + ) -> &mut Self where R: lsp_types::request::Request + 'static, R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug, @@ -138,7 +178,7 @@ impl<'a> RequestDispatcher<'a> { None => return self, }; - self.global_state.task_pool.handle.spawn({ + self.global_state.task_pool.handle.spawn(intent, { let world = self.global_state.snapshot(); move || { let result = panic::catch_unwind(move || { @@ -155,18 +195,6 @@ impl<'a> RequestDispatcher<'a> { self } - pub(crate) fn finish(&mut self) { - if let Some(req) = self.req.take() { - tracing::error!("unknown request: {:?}", req); - let response = lsp_server::Response::new_err( - req.id, - lsp_server::ErrorCode::MethodNotFound as i32, - "unknown request".to_string(), - ); - self.global_state.respond(response); - } - } - fn parse(&mut self) -> Option<(lsp_server::Request, R::Params, String)> where R: lsp_types::request::Request, diff --git a/crates/rust-analyzer/src/from_proto.rs b/crates/rust-analyzer/src/from_proto.rs index 50af38cd6fe37..cd74a5500d0a9 100644 --- a/crates/rust-analyzer/src/from_proto.rs +++ b/crates/rust-analyzer/src/from_proto.rs @@ -31,7 +31,10 @@ pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> R PositionEncoding::Utf8 => LineCol { line: position.line, col: position.character }, PositionEncoding::Wide(enc) => { let line_col = WideLineCol { line: position.line, col: position.character }; - line_index.index.to_utf8(enc, line_col) + line_index + .index + .to_utf8(enc, line_col) + .ok_or_else(|| format_err!("Invalid wide col offset"))? } }; let text_size = @@ -98,13 +101,18 @@ pub(crate) fn assist_kind(kind: lsp_types::CodeActionKind) -> Option pub(crate) fn annotation( snap: &GlobalStateSnapshot, code_lens: lsp_types::CodeLens, -) -> Result { +) -> Result> { let data = code_lens.data.ok_or_else(|| invalid_params_error("code lens without data".to_string()))?; let resolve = from_json::("CodeLensResolveData", &data)?; - match resolve { - lsp_ext::CodeLensResolveData::Impls(params) => { + match resolve.kind { + lsp_ext::CodeLensResolveDataKind::Impls(params) => { + if snap.url_file_version(¶ms.text_document_position_params.text_document.uri) + != Some(resolve.version) + { + return Ok(None); + } let pos @ FilePosition { file_id, .. } = file_position(snap, params.text_document_position_params)?; let line_index = snap.file_line_index(file_id)?; @@ -114,7 +122,10 @@ pub(crate) fn annotation( kind: AnnotationKind::HasImpls { pos, data: None }, }) } - lsp_ext::CodeLensResolveData::References(params) => { + lsp_ext::CodeLensResolveDataKind::References(params) => { + if snap.url_file_version(¶ms.text_document.uri) != Some(resolve.version) { + return Ok(None); + } let pos @ FilePosition { file_id, .. } = file_position(snap, params)?; let line_index = snap.file_line_index(file_id)?; @@ -124,4 +135,5 @@ pub(crate) fn annotation( }) } } + .map(Some) } diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index aca6c92357070..9f4dc4440202d 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -3,22 +3,23 @@ //! //! Each tick provides an immutable snapshot of the state as `WorldSnapshot`. -use std::{sync::Arc, time::Instant}; +use std::time::Instant; use crossbeam_channel::{unbounded, Receiver, Sender}; use flycheck::FlycheckHandle; use ide::{Analysis, AnalysisHost, Cancellable, Change, FileId}; -use ide_db::base_db::{CrateId, FileLoader, SourceDatabase}; +use ide_db::base_db::{CrateId, FileLoader, ProcMacroPaths, SourceDatabase}; use lsp_types::{SemanticTokens, Url}; +use nohash_hasher::IntMap; use parking_lot::{Mutex, RwLock}; use proc_macro_api::ProcMacroServer; use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts}; use rustc_hash::FxHashMap; -use stdx::hash::NoHashHashMap; +use triomphe::Arc; use vfs::AnchoredPathBuf; use crate::{ - config::Config, + config::{Config, ConfigError}, diagnostics::{CheckFixes, DiagnosticCollection}, from_proto, line_index::{LineEndings, LineIndex}, @@ -51,24 +52,34 @@ pub(crate) type ReqQueue = lsp_server::ReqQueue<(String, Instant), ReqHandler>; pub(crate) struct GlobalState { sender: Sender, req_queue: ReqQueue, + pub(crate) task_pool: Handle, Receiver>, - pub(crate) loader: Handle, Receiver>, + pub(crate) config: Arc, + pub(crate) config_errors: Option, pub(crate) analysis_host: AnalysisHost, pub(crate) diagnostics: DiagnosticCollection, pub(crate) mem_docs: MemDocs, + pub(crate) source_root_config: SourceRootConfig, pub(crate) semantic_tokens_cache: Arc>>, + + // status pub(crate) shutdown_requested: bool, - pub(crate) proc_macro_changed: bool, pub(crate) last_reported_status: Option, - pub(crate) source_root_config: SourceRootConfig, - pub(crate) proc_macro_clients: Vec>, + // proc macros + pub(crate) proc_macro_changed: bool, + pub(crate) proc_macro_clients: Arc<[anyhow::Result]>, + + // Flycheck pub(crate) flycheck: Arc<[FlycheckHandle]>, pub(crate) flycheck_sender: Sender, pub(crate) flycheck_receiver: Receiver, + pub(crate) last_flycheck_error: Option, - pub(crate) vfs: Arc)>>, + // VFS + pub(crate) loader: Handle, Receiver>, + pub(crate) vfs: Arc)>>, pub(crate) vfs_config_version: u32, pub(crate) vfs_progress_config_version: u32, pub(crate) vfs_progress_n_total: usize, @@ -92,7 +103,7 @@ pub(crate) struct GlobalState { /// first phase is much faster, and is much less likely to fail. /// /// This creates a complication -- by the time the second phase completes, - /// the results of the fist phase could be invalid. That is, while we run + /// the results of the first phase could be invalid. That is, while we run /// `cargo check`, the user edits `Cargo.toml`, we notice this, and the new /// `cargo metadata` completes before `cargo check`. /// @@ -100,11 +111,13 @@ pub(crate) struct GlobalState { /// the user just adds comments or whitespace to Cargo.toml, we do not want /// to invalidate any salsa caches. pub(crate) workspaces: Arc>, - pub(crate) fetch_workspaces_queue: OpQueue>>>, - pub(crate) fetch_build_data_queue: - OpQueue<(Arc>, Vec>)>, - pub(crate) prime_caches_queue: OpQueue<()>, + // op queues + pub(crate) fetch_workspaces_queue: OpQueue<(), Option>>>, + pub(crate) fetch_build_data_queue: + OpQueue<(), (Arc>, Vec>)>, + pub(crate) fetch_proc_macros_queue: OpQueue, bool>, + pub(crate) prime_caches_queue: OpQueue, } /// An immutable snapshot of the world's state at a point in time. @@ -114,8 +127,9 @@ pub(crate) struct GlobalStateSnapshot { pub(crate) check_fixes: CheckFixes, mem_docs: MemDocs, pub(crate) semantic_tokens_cache: Arc>>, - vfs: Arc)>>, + vfs: Arc)>>, pub(crate) workspaces: Arc>, + // used to signal semantic highlighting to fall back to syntax based highlighting until proc-macros have been loaded pub(crate) proc_macros_loaded: bool, pub(crate) flycheck: Arc<[FlycheckHandle]>, } @@ -138,7 +152,10 @@ impl GlobalState { Handle { handle, receiver } }; - let analysis_host = AnalysisHost::new(config.lru_capacity()); + let mut analysis_host = AnalysisHost::new(config.lru_parse_query_capacity()); + if let Some(capacities) = config.lru_query_capacities() { + analysis_host.update_lru_capacities(capacities); + } let (flycheck_sender, flycheck_receiver) = unbounded(); let mut this = GlobalState { sender, @@ -151,16 +168,21 @@ impl GlobalState { mem_docs: MemDocs::default(), semantic_tokens_cache: Arc::new(Default::default()), shutdown_requested: false, - proc_macro_changed: false, last_reported_status: None, source_root_config: SourceRootConfig::default(), - proc_macro_clients: vec![], + config_errors: Default::default(), + + proc_macro_changed: false, + // FIXME: use `Arc::from_iter` when it becomes available + proc_macro_clients: Arc::from(Vec::new()), - flycheck: Arc::new([]), + // FIXME: use `Arc::from_iter` when it becomes available + flycheck: Arc::from(Vec::new()), flycheck_sender, flycheck_receiver, + last_flycheck_error: None, - vfs: Arc::new(RwLock::new((vfs::Vfs::default(), NoHashHashMap::default()))), + vfs: Arc::new(RwLock::new((vfs::Vfs::default(), IntMap::default()))), vfs_config_version: 0, vfs_progress_config_version: 0, vfs_progress_n_total: 0, @@ -168,9 +190,10 @@ impl GlobalState { workspaces: Arc::new(Vec::new()), fetch_workspaces_queue: OpQueue::default(), - prime_caches_queue: OpQueue::default(), - fetch_build_data_queue: OpQueue::default(), + fetch_proc_macros_queue: OpQueue::default(), + + prime_caches_queue: OpQueue::default(), }; // Apply any required database inputs from the config. this.update_configuration(config); @@ -185,7 +208,7 @@ impl GlobalState { let (change, changed_files) = { let mut change = Change::new(); let (vfs, line_endings_map) = &mut *self.vfs.write(); - let mut changed_files = vfs.take_changes(); + let changed_files = vfs.take_changes(); if changed_files.is_empty() { return false; } @@ -193,7 +216,7 @@ impl GlobalState { // We need to fix up the changed events a bit. If we have a create or modify for a file // id that is followed by a delete we actually skip observing the file text from the // earlier event, to avoid problems later on. - for changed_file in &changed_files { + for changed_file in changed_files { use vfs::ChangeKind::*; file_changes @@ -229,14 +252,13 @@ impl GlobalState { )); } - changed_files.extend( - file_changes - .into_iter() - .filter(|(_, (change_kind, just_created))| { - !matches!((change_kind, just_created), (vfs::ChangeKind::Delete, true)) - }) - .map(|(file_id, (change_kind, _))| vfs::ChangedFile { file_id, change_kind }), - ); + let changed_files: Vec<_> = file_changes + .into_iter() + .filter(|(_, (change_kind, just_created))| { + !matches!((change_kind, just_created), (vfs::ChangeKind::Delete, true)) + }) + .map(|(file_id, (change_kind, _))| vfs::ChangedFile { file_id, change_kind }) + .collect(); // A file was added or deleted let mut has_structure_changes = false; @@ -261,7 +283,7 @@ impl GlobalState { String::from_utf8(bytes).ok().and_then(|text| { let (text, line_endings) = LineEndings::normalize(text); line_endings_map.insert(file.file_id, line_endings); - Some(Arc::new(text)) + Some(Arc::from(text)) }) } else { None @@ -280,11 +302,11 @@ impl GlobalState { { let raw_database = self.analysis_host.raw_database(); // FIXME: ideally we should only trigger a workspace fetch for non-library changes - // but somethings going wrong with the source root business when we add a new local + // but something's going wrong with the source root business when we add a new local // crate see https://github.com/rust-lang/rust-analyzer/issues/13029 if let Some(path) = workspace_structure_change { self.fetch_workspaces_queue - .request_op(format!("workspace vfs file change: {}", path.display())); + .request_op(format!("workspace vfs file change: {}", path.display()), ()); } self.proc_macro_changed = changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| { @@ -307,7 +329,8 @@ impl GlobalState { check_fixes: Arc::clone(&self.diagnostics.check_fixes), mem_docs: self.mem_docs.clone(), semantic_tokens_cache: Arc::clone(&self.semantic_tokens_cache), - proc_macros_loaded: !self.fetch_build_data_queue.last_op_result().0.is_empty(), + proc_macros_loaded: !self.config.expand_proc_macros() + || *self.fetch_proc_macros_queue.last_op_result(), flycheck: self.flycheck.clone(), } } @@ -331,7 +354,7 @@ impl GlobalState { } pub(crate) fn send_notification( - &mut self, + &self, params: N::Params, ) { let not = lsp_server::Notification::new(N::METHOD.to_string(), params); @@ -372,7 +395,7 @@ impl GlobalState { self.req_queue.incoming.is_completed(&request.id) } - fn send(&mut self, message: lsp_server::Message) { + fn send(&self, message: lsp_server::Message) { self.sender.send(message).unwrap() } } @@ -431,6 +454,10 @@ impl GlobalStateSnapshot { ProjectWorkspace::DetachedFiles { .. } => None, }) } + + pub(crate) fn vfs_memory_usage(&self) -> usize { + self.vfs.read().0.memory_usage() + } } pub(crate) fn file_id_to_url(vfs: &vfs::Vfs, id: FileId) -> Url { diff --git a/crates/rust-analyzer/src/handlers/notification.rs b/crates/rust-analyzer/src/handlers/notification.rs new file mode 100644 index 0000000000000..09de6900c8fb5 --- /dev/null +++ b/crates/rust-analyzer/src/handlers/notification.rs @@ -0,0 +1,334 @@ +//! This module is responsible for implementing handlers for Language Server +//! Protocol. This module specifically handles notifications. + +use std::ops::Deref; + +use itertools::Itertools; +use lsp_types::{ + CancelParams, DidChangeConfigurationParams, DidChangeTextDocumentParams, + DidChangeWatchedFilesParams, DidChangeWorkspaceFoldersParams, DidCloseTextDocumentParams, + DidOpenTextDocumentParams, DidSaveTextDocumentParams, WorkDoneProgressCancelParams, +}; +use triomphe::Arc; +use vfs::{AbsPathBuf, ChangeKind, VfsPath}; + +use crate::{ + config::Config, from_proto, global_state::GlobalState, lsp_ext::RunFlycheckParams, + lsp_utils::apply_document_changes, mem_docs::DocumentData, reload, Result, +}; + +pub(crate) fn handle_cancel(state: &mut GlobalState, params: CancelParams) -> Result<()> { + let id: lsp_server::RequestId = match params.id { + lsp_types::NumberOrString::Number(id) => id.into(), + lsp_types::NumberOrString::String(id) => id.into(), + }; + state.cancel(id); + Ok(()) +} + +pub(crate) fn handle_work_done_progress_cancel( + state: &mut GlobalState, + params: WorkDoneProgressCancelParams, +) -> Result<()> { + if let lsp_types::NumberOrString::String(s) = ¶ms.token { + if let Some(id) = s.strip_prefix("rust-analyzer/flycheck/") { + if let Ok(id) = u32::from_str_radix(id, 10) { + if let Some(flycheck) = state.flycheck.get(id as usize) { + flycheck.cancel(); + } + } + } + } + + // Just ignore this. It is OK to continue sending progress + // notifications for this token, as the client can't know when + // we accepted notification. + Ok(()) +} + +pub(crate) fn handle_did_open_text_document( + state: &mut GlobalState, + params: DidOpenTextDocumentParams, +) -> Result<()> { + let _p = profile::span("handle_did_open_text_document"); + + if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { + let already_exists = state + .mem_docs + .insert(path.clone(), DocumentData::new(params.text_document.version)) + .is_err(); + if already_exists { + tracing::error!("duplicate DidOpenTextDocument: {}", path); + } + state.vfs.write().0.set_file_contents(path, Some(params.text_document.text.into_bytes())); + } + Ok(()) +} + +pub(crate) fn handle_did_change_text_document( + state: &mut GlobalState, + params: DidChangeTextDocumentParams, +) -> Result<()> { + let _p = profile::span("handle_did_change_text_document"); + + if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { + match state.mem_docs.get_mut(&path) { + Some(doc) => { + // The version passed in DidChangeTextDocument is the version after all edits are applied + // so we should apply it before the vfs is notified. + doc.version = params.text_document.version; + } + None => { + tracing::error!("unexpected DidChangeTextDocument: {}", path); + return Ok(()); + } + }; + + let vfs = &mut state.vfs.write().0; + let file_id = vfs.file_id(&path).unwrap(); + let text = apply_document_changes( + state.config.position_encoding(), + || std::str::from_utf8(vfs.file_contents(file_id)).unwrap().into(), + params.content_changes, + ); + + vfs.set_file_contents(path, Some(text.into_bytes())); + } + Ok(()) +} + +pub(crate) fn handle_did_close_text_document( + state: &mut GlobalState, + params: DidCloseTextDocumentParams, +) -> Result<()> { + let _p = profile::span("handle_did_close_text_document"); + + if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { + if state.mem_docs.remove(&path).is_err() { + tracing::error!("orphan DidCloseTextDocument: {}", path); + } + + state.semantic_tokens_cache.lock().remove(¶ms.text_document.uri); + + if let Some(path) = path.as_path() { + state.loader.handle.invalidate(path.to_path_buf()); + } + } + Ok(()) +} + +pub(crate) fn handle_did_save_text_document( + state: &mut GlobalState, + params: DidSaveTextDocumentParams, +) -> Result<()> { + if let Ok(vfs_path) = from_proto::vfs_path(¶ms.text_document.uri) { + // Re-fetch workspaces if a workspace related file has changed + if let Some(abs_path) = vfs_path.as_path() { + if reload::should_refresh_for_change(abs_path, ChangeKind::Modify) { + state + .fetch_workspaces_queue + .request_op(format!("DidSaveTextDocument {}", abs_path.display()), ()); + } + } + + if !state.config.check_on_save() || run_flycheck(state, vfs_path) { + return Ok(()); + } + } else if state.config.check_on_save() { + // No specific flycheck was triggered, so let's trigger all of them. + for flycheck in state.flycheck.iter() { + flycheck.restart(); + } + } + Ok(()) +} + +pub(crate) fn handle_did_change_configuration( + state: &mut GlobalState, + _params: DidChangeConfigurationParams, +) -> Result<()> { + // As stated in https://github.com/microsoft/language-server-protocol/issues/676, + // this notification's parameters should be ignored and the actual config queried separately. + state.send_request::( + lsp_types::ConfigurationParams { + items: vec![lsp_types::ConfigurationItem { + scope_uri: None, + section: Some("rust-analyzer".to_string()), + }], + }, + |this, resp| { + tracing::debug!("config update response: '{:?}", resp); + let lsp_server::Response { error, result, .. } = resp; + + match (error, result) { + (Some(err), _) => { + tracing::error!("failed to fetch the server settings: {:?}", err) + } + (None, Some(mut configs)) => { + if let Some(json) = configs.get_mut(0) { + // Note that json can be null according to the spec if the client can't + // provide a configuration. This is handled in Config::update below. + let mut config = Config::clone(&*this.config); + this.config_errors = config.update(json.take()).err(); + this.update_configuration(config); + } + } + (None, None) => { + tracing::error!("received empty server settings response from the client") + } + } + }, + ); + + Ok(()) +} + +pub(crate) fn handle_did_change_workspace_folders( + state: &mut GlobalState, + params: DidChangeWorkspaceFoldersParams, +) -> Result<()> { + let config = Arc::make_mut(&mut state.config); + + for workspace in params.event.removed { + let Ok(path) = workspace.uri.to_file_path() else { continue }; + let Ok(path) = AbsPathBuf::try_from(path) else { continue }; + config.remove_workspace(&path); + } + + let added = params + .event + .added + .into_iter() + .filter_map(|it| it.uri.to_file_path().ok()) + .filter_map(|it| AbsPathBuf::try_from(it).ok()); + config.add_workspaces(added); + + if !config.has_linked_projects() && config.detached_files().is_empty() { + config.rediscover_workspaces(); + state.fetch_workspaces_queue.request_op("client workspaces changed".to_string(), ()) + } + + Ok(()) +} + +pub(crate) fn handle_did_change_watched_files( + state: &mut GlobalState, + params: DidChangeWatchedFilesParams, +) -> Result<()> { + for change in params.changes { + if let Ok(path) = from_proto::abs_path(&change.uri) { + state.loader.handle.invalidate(path); + } + } + Ok(()) +} + +fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { + let _p = profile::span("run_flycheck"); + + let file_id = state.vfs.read().0.file_id(&vfs_path); + if let Some(file_id) = file_id { + let world = state.snapshot(); + let mut updated = false; + let task = move || -> std::result::Result<(), ide::Cancelled> { + // Trigger flychecks for all workspaces that depend on the saved file + // Crates containing or depending on the saved file + let crate_ids: Vec<_> = world + .analysis + .crates_for(file_id)? + .into_iter() + .flat_map(|id| world.analysis.transitive_rev_deps(id)) + .flatten() + .sorted() + .unique() + .collect(); + + let crate_root_paths: Vec<_> = crate_ids + .iter() + .filter_map(|&crate_id| { + world + .analysis + .crate_root(crate_id) + .map(|file_id| { + world.file_id_to_file_path(file_id).as_path().map(ToOwned::to_owned) + }) + .transpose() + }) + .collect::>()?; + let crate_root_paths: Vec<_> = crate_root_paths.iter().map(Deref::deref).collect(); + + // Find all workspaces that have at least one target containing the saved file + let workspace_ids = world.workspaces.iter().enumerate().filter(|(_, ws)| match ws { + project_model::ProjectWorkspace::Cargo { cargo, .. } => { + cargo.packages().any(|pkg| { + cargo[pkg] + .targets + .iter() + .any(|&it| crate_root_paths.contains(&cargo[it].root.as_path())) + }) + } + project_model::ProjectWorkspace::Json { project, .. } => { + project.crates().any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c)) + } + project_model::ProjectWorkspace::DetachedFiles { .. } => false, + }); + + // Find and trigger corresponding flychecks + for flycheck in world.flycheck.iter() { + for (id, _) in workspace_ids.clone() { + if id == flycheck.id() { + updated = true; + flycheck.restart(); + continue; + } + } + } + // No specific flycheck was triggered, so let's trigger all of them. + if !updated { + for flycheck in world.flycheck.iter() { + flycheck.restart(); + } + } + Ok(()) + }; + state.task_pool.handle.spawn_with_sender(stdx::thread::ThreadIntent::Worker, move |_| { + if let Err(e) = std::panic::catch_unwind(task) { + tracing::error!("flycheck task panicked: {e:?}") + } + }); + true + } else { + false + } +} + +pub(crate) fn handle_cancel_flycheck(state: &mut GlobalState, _: ()) -> Result<()> { + let _p = profile::span("handle_stop_flycheck"); + state.flycheck.iter().for_each(|flycheck| flycheck.cancel()); + Ok(()) +} + +pub(crate) fn handle_clear_flycheck(state: &mut GlobalState, _: ()) -> Result<()> { + let _p = profile::span("handle_clear_flycheck"); + state.diagnostics.clear_check_all(); + Ok(()) +} + +pub(crate) fn handle_run_flycheck( + state: &mut GlobalState, + params: RunFlycheckParams, +) -> Result<()> { + let _p = profile::span("handle_run_flycheck"); + if let Some(text_document) = params.text_document { + if let Ok(vfs_path) = from_proto::vfs_path(&text_document.uri) { + if run_flycheck(state, vfs_path) { + return Ok(()); + } + } + } + // No specific flycheck was triggered, so let's trigger all of them. + for flycheck in state.flycheck.iter() { + flycheck.restart(); + } + Ok(()) +} diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers/request.rs similarity index 91% rename from crates/rust-analyzer/src/handlers.rs rename to crates/rust-analyzer/src/handlers/request.rs index 2fca2ab851d41..3f365c05942f0 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -1,35 +1,36 @@ //! This module is responsible for implementing handlers for Language Server -//! Protocol. The majority of requests are fulfilled by calling into the -//! `ide` crate. +//! Protocol. This module specifically handles requests. use std::{ + fs, io::Write as _, process::{self, Stdio}, }; use anyhow::Context; use ide::{ - AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, FileId, FilePosition, - FileRange, HoverAction, HoverGotoTypeData, Query, RangeInfo, ReferenceCategory, Runnable, - RunnableKind, SingleResolve, SourceChange, TextEdit, + AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, FilePosition, FileRange, + HoverAction, HoverGotoTypeData, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind, + SingleResolve, SourceChange, TextEdit, }; use ide_db::SymbolKind; use lsp_server::ErrorCode; use lsp_types::{ CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, - CodeLens, CompletionItem, Diagnostic, DiagnosticTag, DocumentFormattingParams, FoldingRange, - FoldingRangeParams, HoverContents, InlayHint, InlayHintParams, Location, LocationLink, - NumberOrString, Position, PrepareRenameResponse, Range, RenameParams, - SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams, - SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, - SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit, + CodeLens, CompletionItem, DocumentFormattingParams, FoldingRange, FoldingRangeParams, + HoverContents, InlayHint, InlayHintParams, Location, LocationLink, Position, + PrepareRenameResponse, Range, RenameParams, SemanticTokensDeltaParams, + SemanticTokensFullDeltaResult, SemanticTokensParams, SemanticTokensRangeParams, + SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, SymbolTag, + TextDocumentIdentifier, Url, WorkspaceEdit, }; use project_model::{ManifestPath, ProjectWorkspace, TargetKind}; use serde_json::json; use stdx::{format_to, never}; use syntax::{algo, ast, AstNode, TextRange, TextSize}; -use vfs::{AbsPath, AbsPathBuf}; +use triomphe::Arc; +use vfs::{AbsPath, AbsPathBuf, VfsPath}; use crate::{ cargo_target_spec::CargoTargetSpec, @@ -38,23 +39,29 @@ use crate::{ from_proto, global_state::{GlobalState, GlobalStateSnapshot}, line_index::LineEndings, - lsp_ext::{self, PositionOrRange, ViewCrateGraphParams, WorkspaceSymbolParams}, + lsp_ext::{ + self, CrateInfoResult, ExternalDocsPair, ExternalDocsResponse, FetchDependencyListParams, + FetchDependencyListResult, PositionOrRange, ViewCrateGraphParams, WorkspaceSymbolParams, + }, lsp_utils::{all_edits_are_disjoint, invalid_params_error}, to_proto, LspError, Result, }; pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result<()> { - state.proc_macro_clients.clear(); + // FIXME: use `Arc::from_iter` when it becomes available + state.proc_macro_clients = Arc::from(Vec::new()); state.proc_macro_changed = false; - state.fetch_workspaces_queue.request_op("reload workspace request".to_string()); - state.fetch_build_data_queue.request_op("reload workspace request".to_string()); + state.fetch_workspaces_queue.request_op("reload workspace request".to_string(), ()); Ok(()) } -pub(crate) fn handle_cancel_flycheck(state: &mut GlobalState, _: ()) -> Result<()> { - let _p = profile::span("handle_stop_flycheck"); - state.flycheck.iter().for_each(|flycheck| flycheck.cancel()); +pub(crate) fn handle_proc_macros_rebuild(state: &mut GlobalState, _: ()) -> Result<()> { + // FIXME: use `Arc::from_iter` when it becomes available + state.proc_macro_clients = Arc::from(Vec::new()); + state.proc_macro_changed = false; + + state.fetch_build_data_queue.request_op("rebuild proc macros request".to_string(), ()); Ok(()) } @@ -95,6 +102,7 @@ pub(crate) fn handle_analyzer_status( .collect::>() ); } + format_to!(buf, "\nVfs memory usage: {}\n", profile::Bytes::new(snap.vfs_memory_usage() as _)); buf.push_str("\nAnalysis:\n"); buf.push_str( &snap @@ -154,6 +162,16 @@ pub(crate) fn handle_view_mir( Ok(res) } +pub(crate) fn handle_interpret_function( + snap: GlobalStateSnapshot, + params: lsp_types::TextDocumentPositionParams, +) -> Result { + let _p = profile::span("handle_interpret_function"); + let position = from_proto::file_position(&snap, params)?; + let res = snap.analysis.interpret_function(position)?; + Ok(res) +} + pub(crate) fn handle_view_file_text( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentIdentifier, @@ -502,7 +520,10 @@ pub(crate) fn handle_workspace_symbol( #[allow(deprecated)] let info = SymbolInformation { - name: nav.name.to_string(), + name: match &nav.alias { + Some(alias) => format!("{} (alias for {})", alias, nav.name), + None => format!("{}", nav.name), + }, kind: nav .kind .map(to_proto::symbol_kind) @@ -747,20 +768,25 @@ pub(crate) fn handle_runnables( let config = snap.config.runnables(); match cargo_spec { Some(spec) => { + let all_targets = !snap.analysis.is_crate_no_std(spec.crate_id)?; for cmd in ["check", "test"] { + let mut cargo_args = + vec![cmd.to_owned(), "--package".to_owned(), spec.package.clone()]; + if all_targets { + cargo_args.push("--all-targets".to_owned()); + } res.push(lsp_ext::Runnable { - label: format!("cargo {cmd} -p {} --all-targets", spec.package), + label: format!( + "cargo {cmd} -p {}{all_targets}", + spec.package, + all_targets = if all_targets { " --all-targets" } else { "" } + ), location: None, kind: lsp_ext::RunnableKind::Cargo, args: lsp_ext::CargoRunnable { workspace_root: Some(spec.workspace_root.clone().into()), override_cargo: config.override_cargo.clone(), - cargo_args: vec![ - cmd.to_string(), - "--package".to_string(), - spec.package.clone(), - "--all-targets".to_string(), - ], + cargo_args, cargo_extra_args: config.cargo_extra_args.clone(), executable_args: Vec::new(), expect_test: None, @@ -769,14 +795,7 @@ pub(crate) fn handle_runnables( } } None => { - if !snap.config.linked_projects().is_empty() - || !snap - .config - .discovered_projects - .as_ref() - .map(|projects| projects.is_empty()) - .unwrap_or(true) - { + if !snap.config.linked_projects().is_empty() { res.push(lsp_ext::Runnable { label: "cargo check --workspace".to_string(), location: None, @@ -1262,7 +1281,7 @@ pub(crate) fn handle_code_lens_resolve( snap: GlobalStateSnapshot, code_lens: CodeLens, ) -> Result { - let annotation = from_proto::annotation(&snap, code_lens.clone())?; + let Some(annotation) = from_proto::annotation(&snap, code_lens.clone())? else { return Ok(code_lens) }; let annotation = snap.analysis.resolve_annotation(annotation)?; let mut acc = Vec::new(); @@ -1321,38 +1340,6 @@ pub(crate) fn handle_ssr( to_proto::workspace_edit(&snap, source_change).map_err(Into::into) } -pub(crate) fn publish_diagnostics( - snap: &GlobalStateSnapshot, - file_id: FileId, -) -> Result> { - let _p = profile::span("publish_diagnostics"); - let line_index = snap.file_line_index(file_id)?; - - let diagnostics: Vec = snap - .analysis - .diagnostics(&snap.config.diagnostics(), AssistResolveStrategy::None, file_id)? - .into_iter() - .map(|d| Diagnostic { - range: to_proto::range(&line_index, d.range), - severity: Some(to_proto::diagnostic_severity(d.severity)), - code: Some(NumberOrString::String(d.code.as_str().to_string())), - code_description: Some(lsp_types::CodeDescription { - href: lsp_types::Url::parse(&format!( - "https://rust-analyzer.github.io/manual.html#{}", - d.code.as_str() - )) - .unwrap(), - }), - source: Some("rust-analyzer".to_string()), - message: d.message, - related_information: None, - tags: if d.unused { Some(vec![DiagnosticTag::UNNECESSARY]) } else { None }, - data: None, - }) - .collect(); - Ok(diagnostics) -} - pub(crate) fn handle_inlay_hints( snap: GlobalStateSnapshot, params: InlayHintParams, @@ -1370,9 +1357,7 @@ pub(crate) fn handle_inlay_hints( snap.analysis .inlay_hints(&inlay_hints_config, file_id, Some(range))? .into_iter() - .map(|it| { - to_proto::inlay_hint(&snap, &line_index, inlay_hints_config.render_colons, it) - }) + .map(|it| to_proto::inlay_hint(&snap, &line_index, it)) .collect::>>()?, )) } @@ -1493,7 +1478,13 @@ pub(crate) fn handle_semantic_tokens_full( snap.workspaces.is_empty() || !snap.proc_macros_loaded; let highlights = snap.analysis.highlight(highlight_config, file_id)?; - let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); + let semantic_tokens = to_proto::semantic_tokens( + &text, + &line_index, + highlights, + snap.config.semantics_tokens_augments_syntax_tokens(), + snap.config.highlighting_non_standard_tokens(), + ); // Unconditionally cache the tokens snap.semantic_tokens_cache.lock().insert(params.text_document.uri, semantic_tokens.clone()); @@ -1517,7 +1508,13 @@ pub(crate) fn handle_semantic_tokens_full_delta( snap.workspaces.is_empty() || !snap.proc_macros_loaded; let highlights = snap.analysis.highlight(highlight_config, file_id)?; - let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); + let semantic_tokens = to_proto::semantic_tokens( + &text, + &line_index, + highlights, + snap.config.semantics_tokens_augments_syntax_tokens(), + snap.config.highlighting_non_standard_tokens(), + ); let mut cache = snap.semantic_tokens_cache.lock(); let cached_tokens = cache.entry(params.text_document.uri).or_default(); @@ -1551,20 +1548,53 @@ pub(crate) fn handle_semantic_tokens_range( snap.workspaces.is_empty() || !snap.proc_macros_loaded; let highlights = snap.analysis.highlight_range(highlight_config, frange)?; - let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); + let semantic_tokens = to_proto::semantic_tokens( + &text, + &line_index, + highlights, + snap.config.semantics_tokens_augments_syntax_tokens(), + snap.config.highlighting_non_standard_tokens(), + ); Ok(Some(semantic_tokens.into())) } pub(crate) fn handle_open_docs( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, -) -> Result> { +) -> Result { let _p = profile::span("handle_open_docs"); let position = from_proto::file_position(&snap, params)?; - let remote = snap.analysis.external_docs(position)?; + let ws_and_sysroot = snap.workspaces.iter().find_map(|ws| match ws { + ProjectWorkspace::Cargo { cargo, sysroot, .. } => Some((cargo, sysroot.as_ref().ok())), + ProjectWorkspace::Json { .. } => None, + ProjectWorkspace::DetachedFiles { .. } => None, + }); + + let (cargo, sysroot) = match ws_and_sysroot { + Some((ws, sysroot)) => (Some(ws), sysroot), + _ => (None, None), + }; + + let sysroot = sysroot.map(|p| p.root().as_os_str()); + let target_dir = cargo.map(|cargo| cargo.target_directory()).map(|p| p.as_os_str()); + + let Ok(remote_urls) = snap.analysis.external_docs(position, target_dir, sysroot) else { + return if snap.config.local_docs() { + Ok(ExternalDocsResponse::WithLocal(Default::default())) + } else { + Ok(ExternalDocsResponse::Simple(None)) + } + }; - Ok(remote.and_then(|remote| Url::parse(&remote).ok())) + let web = remote_urls.web_url.and_then(|it| Url::parse(&it).ok()); + let local = remote_urls.local_url.and_then(|it| Url::parse(&it).ok()); + + if snap.config.local_docs() { + Ok(ExternalDocsResponse::WithLocal(ExternalDocsPair { web, local })) + } else { + Ok(ExternalDocsResponse::Simple(web)) + } } pub(crate) fn handle_open_cargo_toml( @@ -1908,3 +1938,52 @@ fn run_rustfmt( Ok(Some(to_proto::text_edit_vec(&line_index, diff(&file, &new_text)))) } } + +pub(crate) fn fetch_dependency_list( + state: GlobalStateSnapshot, + _params: FetchDependencyListParams, +) -> Result { + let crates = state.analysis.fetch_crates()?; + let crate_infos = crates + .into_iter() + .filter_map(|it| { + let root_file_path = state.file_id_to_file_path(it.root_file_id); + crate_path(root_file_path).and_then(to_url).map(|path| CrateInfoResult { + name: it.name, + version: it.version, + path, + }) + }) + .collect(); + Ok(FetchDependencyListResult { crates: crate_infos }) +} + +/// Searches for the directory of a Rust crate given this crate's root file path. +/// +/// # Arguments +/// +/// * `root_file_path`: The path to the root file of the crate. +/// +/// # Returns +/// +/// An `Option` value representing the path to the directory of the crate with the given +/// name, if such a crate is found. If no crate with the given name is found, this function +/// returns `None`. +fn crate_path(root_file_path: VfsPath) -> Option { + let mut current_dir = root_file_path.parent(); + while let Some(path) = current_dir { + let cargo_toml_path = path.join("../Cargo.toml")?; + if fs::metadata(cargo_toml_path.as_path()?).is_ok() { + let crate_path = cargo_toml_path.parent()?; + return Some(crate_path); + } + current_dir = path.parent(); + } + None +} + +fn to_url(path: VfsPath) -> Option { + let path = path.as_path()?; + let str_path = path.as_os_str().to_str()?; + Url::from_file_path(str_path).ok() +} diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs index e8912b90796ac..bd9f471a46d11 100644 --- a/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/crates/rust-analyzer/src/integrated_benchmarks.rs @@ -10,8 +10,6 @@ //! in release mode in VS Code. There's however "rust-analyzer: Copy Run Command Line" //! which you can use to paste the command in terminal and add `--release` manually. -use std::sync::Arc; - use ide::{CallableSnippets, Change, CompletionConfig, FilePosition, TextSize}; use ide_db::{ imports::insert_use::{ImportGranularity, InsertUseConfig}, @@ -19,6 +17,7 @@ use ide_db::{ }; use project_model::CargoConfig; use test_utils::project_root; +use triomphe::Arc; use vfs::{AbsPathBuf, VfsPath}; use crate::cli::load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice}; @@ -65,7 +64,7 @@ fn integrated_highlighting_benchmark() { let mut text = host.analysis().file_text(file_id).unwrap().to_string(); text.push_str("\npub fn _dummy() {}\n"); let mut change = Change::new(); - change.change_file(file_id, Some(Arc::new(text))); + change.change_file(file_id, Some(Arc::from(text))); host.apply_change(change); } @@ -121,7 +120,7 @@ fn integrated_completion_benchmark() { patch(&mut text, "db.struct_data(self.id)", "sel;\ndb.struct_data(self.id)") + "sel".len(); let mut change = Change::new(); - change.change_file(file_id, Some(Arc::new(text))); + change.change_file(file_id, Some(Arc::from(text))); host.apply_change(change); completion_offset }; @@ -160,7 +159,7 @@ fn integrated_completion_benchmark() { patch(&mut text, "sel;\ndb.struct_data(self.id)", "self.;\ndb.struct_data(self.id)") + "self.".len(); let mut change = Change::new(); - change.change_file(file_id, Some(Arc::new(text))); + change.change_file(file_id, Some(Arc::from(text))); host.apply_change(change); completion_offset }; diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index 32dc3750fdf6b..65de4366e9f61 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs @@ -25,7 +25,6 @@ mod diff; mod dispatch; mod from_proto; mod global_state; -mod handlers; mod line_index; mod lsp_utils; mod main_loop; @@ -38,6 +37,11 @@ mod task_pool; mod to_proto; mod version; +mod handlers { + pub(crate) mod notification; + pub(crate) mod request; +} + pub mod config; pub mod lsp_ext; diff --git a/crates/rust-analyzer/src/line_index.rs b/crates/rust-analyzer/src/line_index.rs index 791cd931d42a6..15450303ff250 100644 --- a/crates/rust-analyzer/src/line_index.rs +++ b/crates/rust-analyzer/src/line_index.rs @@ -5,9 +5,8 @@ //! This module does line ending conversion and detection (so that we can //! convert back to `\r\n` on the way out). -use std::sync::Arc; - use ide_db::line_index::WideEncoding; +use triomphe::Arc; #[derive(Clone, Copy)] pub enum PositionEncoding { diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index c7b513db981ea..4d67c8b305fe3 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -4,11 +4,11 @@ use std::{collections::HashMap, path::PathBuf}; use ide_db::line_index::WideEncoding; use lsp_types::request::Request; -use lsp_types::PositionEncodingKind; use lsp_types::{ notification::Notification, CodeActionKind, DocumentOnTypeFormattingParams, PartialResultParams, Position, Range, TextDocumentIdentifier, WorkDoneProgressParams, }; +use lsp_types::{PositionEncodingKind, Url}; use serde::{Deserialize, Serialize}; use crate::line_index::PositionEncoding; @@ -27,6 +27,31 @@ pub struct AnalyzerStatusParams { pub text_document: Option, } +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct CrateInfoResult { + pub name: Option, + pub version: Option, + pub path: Url, +} +pub enum FetchDependencyList {} + +impl Request for FetchDependencyList { + type Params = FetchDependencyListParams; + type Result = FetchDependencyListResult; + const METHOD: &'static str = "rust-analyzer/fetchDependencyList"; +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct FetchDependencyListParams {} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct FetchDependencyListResult { + pub crates: Vec, +} + pub enum MemoryUsage {} impl Request for MemoryUsage { @@ -51,6 +76,14 @@ impl Request for ReloadWorkspace { const METHOD: &'static str = "rust-analyzer/reloadWorkspace"; } +pub enum RebuildProcMacros {} + +impl Request for RebuildProcMacros { + type Params = (); + type Result = (); + const METHOD: &'static str = "rust-analyzer/rebuildProcMacros"; +} + pub enum SyntaxTree {} impl Request for SyntaxTree { @@ -82,6 +115,14 @@ impl Request for ViewMir { const METHOD: &'static str = "rust-analyzer/viewMir"; } +pub enum InterpretFunction {} + +impl Request for InterpretFunction { + type Params = lsp_types::TextDocumentPositionParams; + type Result = String; + const METHOD: &'static str = "rust-analyzer/interpretFunction"; +} + pub enum ViewFileText {} impl Request for ViewFileText { @@ -343,6 +384,7 @@ impl Request for CodeActionRequest { } pub enum CodeActionResolveRequest {} + impl Request for CodeActionResolveRequest { type Params = CodeAction; type Result = CodeAction; @@ -418,7 +460,7 @@ pub enum HoverRequest {} impl Request for HoverRequest { type Params = HoverParams; type Result = Option; - const METHOD: &'static str = "textDocument/hover"; + const METHOD: &'static str = lsp_types::request::HoverRequest::METHOD; } #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] @@ -466,10 +508,24 @@ pub enum ExternalDocs {} impl Request for ExternalDocs { type Params = lsp_types::TextDocumentPositionParams; - type Result = Option; + type Result = ExternalDocsResponse; const METHOD: &'static str = "experimental/externalDocs"; } +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] +#[serde(untagged)] +pub enum ExternalDocsResponse { + Simple(Option), + WithLocal(ExternalDocsPair), +} + +#[derive(Debug, Default, PartialEq, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ExternalDocsPair { + pub web: Option, + pub local: Option, +} + pub enum OpenCargoToml {} impl Request for OpenCargoToml { @@ -487,7 +543,14 @@ pub struct OpenCargoTomlParams { /// Information about CodeLens, that is to be resolved. #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub(crate) enum CodeLensResolveData { +pub struct CodeLensResolveData { + pub version: i32, + pub kind: CodeLensResolveDataKind, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum CodeLensResolveDataKind { Impls(lsp_types::request::GotoImplementationParams), References(lsp_types::TextDocumentPositionParams), } diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs index 12e5caf2cc9e4..74e79e8e6050a 100644 --- a/crates/rust-analyzer/src/lsp_utils.rs +++ b/crates/rust-analyzer/src/lsp_utils.rs @@ -1,8 +1,9 @@ //! Utilities for LSP-related boilerplate code. -use std::{mem, ops::Range, sync::Arc}; +use std::{mem, ops::Range}; use lsp_server::Notification; use lsp_types::request::Request; +use triomphe::Arc; use crate::{ from_proto, @@ -80,39 +81,14 @@ impl GlobalState { match additional_info { Some(additional_info) => { tracing::error!("{}:\n{}", &message, &additional_info); - match self.config.open_server_logs() && tracing::enabled!(tracing::Level::ERROR) { - true => self.send_request::( - lsp_types::ShowMessageRequestParams { - typ: lsp_types::MessageType::ERROR, - message, - actions: Some(vec![lsp_types::MessageActionItem { - title: "Open server logs".to_owned(), - properties: Default::default(), - }]), - }, - |this, resp| { - let lsp_server::Response { error: None, result: Some(result), .. } = resp - else { return }; - if let Ok(Some(_item)) = crate::from_json::< - ::Result, - >( - lsp_types::request::ShowMessageRequest::METHOD, &result - ) { - this.send_notification::(()); - } - }, - ), - false => self.send_notification::( - lsp_types::ShowMessageParams { - typ: lsp_types::MessageType::ERROR, - message, - }, - ), - } + self.show_message( + lsp_types::MessageType::ERROR, + message, + tracing::enabled!(tracing::Level::ERROR), + ); } None => { tracing::error!("{}", &message); - self.send_notification::( lsp_types::ShowMessageParams { typ: lsp_types::MessageType::ERROR, message }, ); diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 67a54cde68c6f..12bc638929d66 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -2,8 +2,6 @@ //! requests/replies and notifications back to the client. use std::{ fmt, - ops::Deref, - sync::Arc, time::{Duration, Instant}, }; @@ -11,20 +9,19 @@ use always_assert::always; use crossbeam_channel::{select, Receiver}; use flycheck::FlycheckHandle; use ide_db::base_db::{SourceDatabaseExt, VfsPath}; -use itertools::Itertools; use lsp_server::{Connection, Notification, Request}; use lsp_types::notification::Notification as _; -use vfs::{AbsPathBuf, ChangeKind, FileId}; +use triomphe::Arc; +use vfs::FileId; use crate::{ config::Config, dispatch::{NotificationDispatcher, RequestDispatcher}, from_proto, global_state::{file_id_to_url, url_to_file_id, GlobalState}, - handlers, lsp_ext, - lsp_utils::{apply_document_changes, notification_is, Progress}, - mem_docs::DocumentData, - reload::{self, BuildDataProgress, ProjectWorkspaceProgress}, + lsp_ext, + lsp_utils::{notification_is, Progress}, + reload::{BuildDataProgress, ProcMacroProgress, ProjectWorkspaceProgress}, Result, }; @@ -36,7 +33,7 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> { // temporary bumped. This optimization backfires in our case: each time the // `main_loop` schedules a task to run on a threadpool, the worker threads // gets a higher priority, and (on a machine with fewer cores) displaces the - // main loop! We work-around this by marking the main loop as a + // main loop! We work around this by marking the main loop as a // higher-priority thread. // // https://docs.microsoft.com/en-us/windows/win32/procthread/scheduling-priorities @@ -68,6 +65,7 @@ pub(crate) enum Task { PrimeCaches(PrimeCachesProgress), FetchWorkspace(ProjectWorkspaceProgress), FetchBuildData(BuildDataProgress), + LoadProcMacros(ProcMacroProgress), } #[derive(Debug)] @@ -79,7 +77,7 @@ pub(crate) enum PrimeCachesProgress { impl fmt::Debug for Event { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let debug_verbose_not = |not: &Notification, f: &mut fmt::Formatter<'_>| { + let debug_non_verbose = |not: &Notification, f: &mut fmt::Formatter<'_>| { f.debug_struct("Notification").field("method", ¬.method).finish() }; @@ -88,7 +86,7 @@ impl fmt::Debug for Event { if notification_is::(not) || notification_is::(not) { - return debug_verbose_not(not, f); + return debug_non_verbose(not, f); } } Event::Task(Task::Response(resp)) => { @@ -114,57 +112,63 @@ impl GlobalState { self.update_status_or_notify(); if self.config.did_save_text_document_dynamic_registration() { - let save_registration_options = lsp_types::TextDocumentSaveRegistrationOptions { - include_text: Some(false), - text_document_registration_options: lsp_types::TextDocumentRegistrationOptions { - document_selector: Some(vec![ - lsp_types::DocumentFilter { - language: None, - scheme: None, - pattern: Some("**/*.rs".into()), - }, - lsp_types::DocumentFilter { - language: None, - scheme: None, - pattern: Some("**/Cargo.toml".into()), - }, - lsp_types::DocumentFilter { - language: None, - scheme: None, - pattern: Some("**/Cargo.lock".into()), - }, - ]), - }, - }; - - let registration = lsp_types::Registration { - id: "textDocument/didSave".to_string(), - method: "textDocument/didSave".to_string(), - register_options: Some(serde_json::to_value(save_registration_options).unwrap()), - }; - self.send_request::( - lsp_types::RegistrationParams { registrations: vec![registration] }, - |_, _| (), - ); + self.register_did_save_capability(); } - self.fetch_workspaces_queue.request_op("startup".to_string()); - if let Some(cause) = self.fetch_workspaces_queue.should_start_op() { + self.fetch_workspaces_queue.request_op("startup".to_string(), ()); + if let Some((cause, ())) = self.fetch_workspaces_queue.should_start_op() { self.fetch_workspaces(cause); } while let Some(event) = self.next_event(&inbox) { - if let Event::Lsp(lsp_server::Message::Notification(not)) = &event { - if not.method == lsp_types::notification::Exit::METHOD { - return Ok(()); - } + if matches!( + &event, + Event::Lsp(lsp_server::Message::Notification(Notification { method, .. })) + if method == lsp_types::notification::Exit::METHOD + ) { + return Ok(()); } - self.handle_event(event)? + self.handle_event(event)?; } Err("client exited without proper shutdown sequence".into()) } + fn register_did_save_capability(&mut self) { + let save_registration_options = lsp_types::TextDocumentSaveRegistrationOptions { + include_text: Some(false), + text_document_registration_options: lsp_types::TextDocumentRegistrationOptions { + document_selector: Some(vec![ + lsp_types::DocumentFilter { + language: None, + scheme: None, + pattern: Some("**/*.rs".into()), + }, + lsp_types::DocumentFilter { + language: None, + scheme: None, + pattern: Some("**/Cargo.toml".into()), + }, + lsp_types::DocumentFilter { + language: None, + scheme: None, + pattern: Some("**/Cargo.lock".into()), + }, + ]), + }, + }; + + let registration = lsp_types::Registration { + id: "textDocument/didSave".to_string(), + method: "textDocument/didSave".to_string(), + register_options: Some(serde_json::to_value(save_registration_options).unwrap()), + }; + self.send_request::( + lsp_types::RegistrationParams { registrations: vec![registration] }, + |_, _| (), + ); + } + fn next_event(&self, inbox: &Receiver) -> Option { select! { recv(inbox) -> msg => @@ -186,19 +190,20 @@ impl GlobalState { // NOTE: don't count blocking select! call as a loop-turn time let _p = profile::span("GlobalState::handle_event"); - tracing::debug!("{:?} handle_event({:?})", loop_start, event); - let task_queue_len = self.task_pool.handle.len(); - if task_queue_len > 0 { - tracing::info!("task queue len: {}", task_queue_len); + let event_dbg_msg = format!("{event:?}"); + tracing::debug!("{:?} handle_event({})", loop_start, event_dbg_msg); + if tracing::enabled!(tracing::Level::INFO) { + let task_queue_len = self.task_pool.handle.len(); + if task_queue_len > 0 { + tracing::info!("task queue len: {}", task_queue_len); + } } let was_quiescent = self.is_quiescent(); match event { Event::Lsp(msg) => match msg { lsp_server::Message::Request(req) => self.on_new_request(loop_start, req), - lsp_server::Message::Notification(not) => { - self.on_notification(not)?; - } + lsp_server::Message::Notification(not) => self.on_notification(not)?, lsp_server::Message::Response(resp) => self.complete_request(resp), }, Event::Task(task) => { @@ -247,7 +252,7 @@ impl GlobalState { self.prime_caches_queue.op_completed(()); if cancelled { self.prime_caches_queue - .request_op("restart after cancellation".to_string()); + .request_op("restart after cancellation".to_string(), ()); } } }; @@ -279,7 +284,8 @@ impl GlobalState { if self.is_quiescent() { let became_quiescent = !(was_quiescent || self.fetch_workspaces_queue.op_requested() - || self.fetch_build_data_queue.op_requested()); + || self.fetch_build_data_queue.op_requested() + || self.fetch_proc_macros_queue.op_requested()); if became_quiescent { if self.config.check_on_save() { @@ -287,11 +293,12 @@ impl GlobalState { self.flycheck.iter().for_each(FlycheckHandle::restart); } if self.config.prefill_caches() { - self.prime_caches_queue.request_op("became quiescent".to_string()); + self.prime_caches_queue.request_op("became quiescent".to_string(), ()); } } - if !was_quiescent || state_changed { + let client_refresh = !was_quiescent || state_changed; + if client_refresh { // Refresh semantic tokens if the client supports it. if self.config.semantic_tokens_refresh() { self.semantic_tokens_cache.lock().clear(); @@ -309,9 +316,9 @@ impl GlobalState { } } - if (!was_quiescent || state_changed || memdocs_added_or_removed) - && self.config.publish_diagnostics() - { + let update_diagnostics = (!was_quiescent || state_changed || memdocs_added_or_removed) + && self.config.publish_diagnostics(); + if update_diagnostics { self.update_diagnostics() } } @@ -357,48 +364,54 @@ impl GlobalState { } if self.config.cargo_autoreload() { - if let Some(cause) = self.fetch_workspaces_queue.should_start_op() { + if let Some((cause, ())) = self.fetch_workspaces_queue.should_start_op() { self.fetch_workspaces(cause); } } if !self.fetch_workspaces_queue.op_in_progress() { - if let Some(cause) = self.fetch_build_data_queue.should_start_op() { + if let Some((cause, ())) = self.fetch_build_data_queue.should_start_op() { self.fetch_build_data(cause); + } else if let Some((cause, paths)) = self.fetch_proc_macros_queue.should_start_op() { + self.fetch_proc_macros(cause, paths); } } - if let Some(cause) = self.prime_caches_queue.should_start_op() { - tracing::debug!(%cause, "will prime caches"); - let num_worker_threads = self.config.prime_caches_num_threads(); - - self.task_pool.handle.spawn_with_sender({ - let analysis = self.snapshot().analysis; - move |sender| { - sender.send(Task::PrimeCaches(PrimeCachesProgress::Begin)).unwrap(); - let res = analysis.parallel_prime_caches(num_worker_threads, |progress| { - let report = PrimeCachesProgress::Report(progress); - sender.send(Task::PrimeCaches(report)).unwrap(); - }); - sender - .send(Task::PrimeCaches(PrimeCachesProgress::End { - cancelled: res.is_err(), - })) - .unwrap(); - } - }); + if let Some((cause, ())) = self.prime_caches_queue.should_start_op() { + self.prime_caches(cause); } self.update_status_or_notify(); let loop_duration = loop_start.elapsed(); if loop_duration > Duration::from_millis(100) && was_quiescent { - tracing::warn!("overly long loop turn: {:?}", loop_duration); - self.poke_rust_analyzer_developer(format!("overly long loop turn: {loop_duration:?}")); + tracing::warn!("overly long loop turn took {loop_duration:?}: {event_dbg_msg}"); + self.poke_rust_analyzer_developer(format!( + "overly long loop turn took {loop_duration:?}: {event_dbg_msg}" + )); } Ok(()) } + fn prime_caches(&mut self, cause: String) { + tracing::debug!(%cause, "will prime caches"); + let num_worker_threads = self.config.prime_caches_num_threads(); + + self.task_pool.handle.spawn_with_sender(stdx::thread::ThreadIntent::Worker, { + let analysis = self.snapshot().analysis; + move |sender| { + sender.send(Task::PrimeCaches(PrimeCachesProgress::Begin)).unwrap(); + let res = analysis.parallel_prime_caches(num_worker_threads, |progress| { + let report = PrimeCachesProgress::Report(progress); + sender.send(Task::PrimeCaches(report)).unwrap(); + }); + sender + .send(Task::PrimeCaches(PrimeCachesProgress::End { cancelled: res.is_err() })) + .unwrap(); + } + }); + } + fn update_status_or_notify(&mut self) { let status = self.current_status(); if self.last_reported_status.as_ref() != Some(&status) { @@ -406,7 +419,11 @@ impl GlobalState { if self.config.server_status_notification() { self.send_notification::(status); - } else if let (health, Some(message)) = (status.health, &status.message) { + } else if let ( + health @ (lsp_ext::Health::Warning | lsp_ext::Health::Error), + Some(message), + ) = (status.health, &status.message) + { let open_log_button = tracing::enabled!(tracing::Level::ERROR) && (self.fetch_build_data_error().is_err() || self.fetch_workspace_error().is_err()); @@ -462,7 +479,8 @@ impl GlobalState { let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces); if self.config.run_build_scripts() && workspaces_updated { - self.fetch_build_data_queue.request_op(format!("workspace updated")); + self.fetch_build_data_queue + .request_op(format!("workspace updated"), ()); } (Progress::End, None) @@ -487,6 +505,22 @@ impl GlobalState { } }; + if let Some(state) = state { + self.report_progress("Building", state, msg, None, None); + } + } + Task::LoadProcMacros(progress) => { + let (state, msg) = match progress { + ProcMacroProgress::Begin => (Some(Progress::Begin), None), + ProcMacroProgress::Report(msg) => (Some(Progress::Report), Some(msg)), + ProcMacroProgress::End(proc_macro_load_result) => { + self.fetch_proc_macros_queue.op_completed(true); + self.set_proc_macros(proc_macro_load_result); + + (Some(Progress::End), None) + } + }; + if let Some(state) = state { self.report_progress("Loading", state, msg, None, None); } @@ -568,21 +602,18 @@ impl GlobalState { (Progress::Begin, None) } flycheck::Progress::DidCheckCrate(target) => (Progress::Report, Some(target)), - flycheck::Progress::DidCancel => (Progress::End, None), + flycheck::Progress::DidCancel => { + self.last_flycheck_error = None; + (Progress::End, None) + } flycheck::Progress::DidFailToRestart(err) => { - self.show_and_log_error( - "cargo check failed to start".to_string(), - Some(err), - ); + self.last_flycheck_error = + Some(format!("cargo check failed to start: {err}")); return; } flycheck::Progress::DidFinish(result) => { - if let Err(err) = result { - self.show_and_log_error( - "cargo check failed".to_string(), - Some(err.to_string()), - ); - } + self.last_flycheck_error = + result.err().map(|err| format!("cargo check failed to start: {err}")); (Progress::End, None) } }; @@ -631,18 +662,54 @@ impl GlobalState { _ => (), } + use crate::handlers::request as handlers; + dispatcher + // Request handlers that must run on the main thread + // because they mutate GlobalState: .on_sync_mut::(handlers::handle_workspace_reload) + .on_sync_mut::(handlers::handle_proc_macros_rebuild) .on_sync_mut::(handlers::handle_memory_usage) .on_sync_mut::(handlers::handle_shuffle_crate_graph) + // Request handlers which are related to the user typing + // are run on the main thread to reduce latency: .on_sync::(handlers::handle_join_lines) .on_sync::(handlers::handle_on_enter) .on_sync::(handlers::handle_selection_range) .on_sync::(handlers::handle_matching_brace) + .on_sync::(handlers::handle_on_type_formatting) + // We can’t run latency-sensitive request handlers which do semantic + // analysis on the main thread because that would block other + // requests. Instead, we run these request handlers on higher priority + // threads in the threadpool. + .on_latency_sensitive::(handlers::handle_completion) + .on_latency_sensitive::( + handlers::handle_completion_resolve, + ) + .on_latency_sensitive::( + handlers::handle_semantic_tokens_full, + ) + .on_latency_sensitive::( + handlers::handle_semantic_tokens_full_delta, + ) + .on_latency_sensitive::( + handlers::handle_semantic_tokens_range, + ) + // Formatting is not caused by the user typing, + // but it does qualify as latency-sensitive + // because a delay before formatting is applied + // can be confusing for the user. + .on_latency_sensitive::(handlers::handle_formatting) + .on_latency_sensitive::( + handlers::handle_range_formatting, + ) + // All other request handlers + .on::(handlers::fetch_dependency_list) .on::(handlers::handle_analyzer_status) .on::(handlers::handle_syntax_tree) .on::(handlers::handle_view_hir) .on::(handlers::handle_view_mir) + .on::(handlers::handle_interpret_function) .on::(handlers::handle_view_file_text) .on::(handlers::handle_view_crate_graph) .on::(handlers::handle_view_item_tree) @@ -657,7 +724,6 @@ impl GlobalState { .on::(handlers::handle_open_cargo_toml) .on::(handlers::handle_move_item) .on::(handlers::handle_workspace_symbol) - .on::(handlers::handle_on_type_formatting) .on::(handlers::handle_document_symbol) .on::(handlers::handle_goto_definition) .on::(handlers::handle_goto_declaration) @@ -665,8 +731,6 @@ impl GlobalState { .on::(handlers::handle_goto_type_definition) .on_no_retry::(handlers::handle_inlay_hints) .on::(handlers::handle_inlay_hints_resolve) - .on::(handlers::handle_completion) - .on::(handlers::handle_completion_resolve) .on::(handlers::handle_code_lens) .on::(handlers::handle_code_lens_resolve) .on::(handlers::handle_folding_range) @@ -674,8 +738,6 @@ impl GlobalState { .on::(handlers::handle_prepare_rename) .on::(handlers::handle_rename) .on::(handlers::handle_references) - .on::(handlers::handle_formatting) - .on::(handlers::handle_range_formatting) .on::(handlers::handle_document_highlight) .on::(handlers::handle_call_hierarchy_prepare) .on::( @@ -684,15 +746,6 @@ impl GlobalState { .on::( handlers::handle_call_hierarchy_outgoing, ) - .on::( - handlers::handle_semantic_tokens_full, - ) - .on::( - handlers::handle_semantic_tokens_full_delta, - ) - .on::( - handlers::handle_semantic_tokens_range, - ) .on::(handlers::handle_will_rename_files) .on::(handlers::handle_ssr) .finish(); @@ -700,282 +753,22 @@ impl GlobalState { /// Handles an incoming notification. fn on_notification(&mut self, not: Notification) -> Result<()> { - // FIXME: Move these implementations out into a module similar to on_request - fn run_flycheck(this: &mut GlobalState, vfs_path: VfsPath) -> bool { - let file_id = this.vfs.read().0.file_id(&vfs_path); - if let Some(file_id) = file_id { - let world = this.snapshot(); - let mut updated = false; - let task = move || -> std::result::Result<(), ide::Cancelled> { - // Trigger flychecks for all workspaces that depend on the saved file - // Crates containing or depending on the saved file - let crate_ids: Vec<_> = world - .analysis - .crates_for(file_id)? - .into_iter() - .flat_map(|id| world.analysis.transitive_rev_deps(id)) - .flatten() - .sorted() - .unique() - .collect(); - - let crate_root_paths: Vec<_> = crate_ids - .iter() - .filter_map(|&crate_id| { - world - .analysis - .crate_root(crate_id) - .map(|file_id| { - world - .file_id_to_file_path(file_id) - .as_path() - .map(ToOwned::to_owned) - }) - .transpose() - }) - .collect::>()?; - let crate_root_paths: Vec<_> = - crate_root_paths.iter().map(Deref::deref).collect(); - - // Find all workspaces that have at least one target containing the saved file - let workspace_ids = - world.workspaces.iter().enumerate().filter(|(_, ws)| match ws { - project_model::ProjectWorkspace::Cargo { cargo, .. } => { - cargo.packages().any(|pkg| { - cargo[pkg].targets.iter().any(|&it| { - crate_root_paths.contains(&cargo[it].root.as_path()) - }) - }) - } - project_model::ProjectWorkspace::Json { project, .. } => project - .crates() - .any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c)), - project_model::ProjectWorkspace::DetachedFiles { .. } => false, - }); - - // Find and trigger corresponding flychecks - for flycheck in world.flycheck.iter() { - for (id, _) in workspace_ids.clone() { - if id == flycheck.id() { - updated = true; - flycheck.restart(); - continue; - } - } - } - // No specific flycheck was triggered, so let's trigger all of them. - if !updated { - for flycheck in world.flycheck.iter() { - flycheck.restart(); - } - } - Ok(()) - }; - this.task_pool.handle.spawn_with_sender(move |_| { - if let Err(e) = std::panic::catch_unwind(task) { - tracing::error!("flycheck task panicked: {e:?}") - } - }); - true - } else { - false - } - } + use crate::handlers::notification as handlers; + use lsp_types::notification as notifs; NotificationDispatcher { not: Some(not), global_state: self } - .on::(|this, params| { - let id: lsp_server::RequestId = match params.id { - lsp_types::NumberOrString::Number(id) => id.into(), - lsp_types::NumberOrString::String(id) => id.into(), - }; - this.cancel(id); - Ok(()) - })? - .on::(|this, params| { - if let lsp_types::NumberOrString::String(s) = ¶ms.token { - if let Some(id) = s.strip_prefix("rust-analyzer/flycheck/") { - if let Ok(id) = u32::from_str_radix(id, 10) { - if let Some(flycheck) = this.flycheck.get(id as usize) { - flycheck.cancel(); - } - } - } - } - // Just ignore this. It is OK to continue sending progress - // notifications for this token, as the client can't know when - // we accepted notification. - Ok(()) - })? - .on::(|this, params| { - if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { - let already_exists = this - .mem_docs - .insert(path.clone(), DocumentData::new(params.text_document.version)) - .is_err(); - if already_exists { - tracing::error!("duplicate DidOpenTextDocument: {}", path); - } - this.vfs - .write() - .0 - .set_file_contents(path, Some(params.text_document.text.into_bytes())); - } - Ok(()) - })? + .on::(handlers::handle_cancel)? + .on::(handlers::handle_work_done_progress_cancel)? + .on::(handlers::handle_did_open_text_document)? + .on::(handlers::handle_did_change_text_document)? + .on::(handlers::handle_did_close_text_document)? + .on::(handlers::handle_did_save_text_document)? + .on::(handlers::handle_did_change_configuration)? + .on::(handlers::handle_did_change_workspace_folders)? + .on::(handlers::handle_did_change_watched_files)? .on::(handlers::handle_cancel_flycheck)? - .on::(|this, params| { - if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { - match this.mem_docs.get_mut(&path) { - Some(doc) => { - // The version passed in DidChangeTextDocument is the version after all edits are applied - // so we should apply it before the vfs is notified. - doc.version = params.text_document.version; - } - None => { - tracing::error!("unexpected DidChangeTextDocument: {}", path); - return Ok(()); - } - }; - - let vfs = &mut this.vfs.write().0; - let file_id = vfs.file_id(&path).unwrap(); - let text = apply_document_changes( - this.config.position_encoding(), - || std::str::from_utf8(vfs.file_contents(file_id)).unwrap().into(), - params.content_changes, - ); - - vfs.set_file_contents(path, Some(text.into_bytes())); - } - Ok(()) - })? - .on::(|this, params| { - if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { - if this.mem_docs.remove(&path).is_err() { - tracing::error!("orphan DidCloseTextDocument: {}", path); - } - - this.semantic_tokens_cache.lock().remove(¶ms.text_document.uri); - - if let Some(path) = path.as_path() { - this.loader.handle.invalidate(path.to_path_buf()); - } - } - Ok(()) - })? - .on::(|this, ()| { - this.diagnostics.clear_check_all(); - Ok(()) - })? - .on::(|this, params| { - if let Some(text_document) = params.text_document { - if let Ok(vfs_path) = from_proto::vfs_path(&text_document.uri) { - if run_flycheck(this, vfs_path) { - return Ok(()); - } - } - } - // No specific flycheck was triggered, so let's trigger all of them. - for flycheck in this.flycheck.iter() { - flycheck.restart(); - } - Ok(()) - })? - .on::(|this, params| { - if let Ok(vfs_path) = from_proto::vfs_path(¶ms.text_document.uri) { - // Re-fetch workspaces if a workspace related file has changed - if let Some(abs_path) = vfs_path.as_path() { - if reload::should_refresh_for_change(abs_path, ChangeKind::Modify) { - this.fetch_workspaces_queue - .request_op(format!("DidSaveTextDocument {}", abs_path.display())); - } - } - - if !this.config.check_on_save() || run_flycheck(this, vfs_path) { - return Ok(()); - } - } else if this.config.check_on_save() { - // No specific flycheck was triggered, so let's trigger all of them. - for flycheck in this.flycheck.iter() { - flycheck.restart(); - } - } - Ok(()) - })? - .on::(|this, _params| { - // As stated in https://github.com/microsoft/language-server-protocol/issues/676, - // this notification's parameters should be ignored and the actual config queried separately. - this.send_request::( - lsp_types::ConfigurationParams { - items: vec![lsp_types::ConfigurationItem { - scope_uri: None, - section: Some("rust-analyzer".to_string()), - }], - }, - |this, resp| { - tracing::debug!("config update response: '{:?}", resp); - let lsp_server::Response { error, result, .. } = resp; - - match (error, result) { - (Some(err), _) => { - tracing::error!("failed to fetch the server settings: {:?}", err) - } - (None, Some(mut configs)) => { - if let Some(json) = configs.get_mut(0) { - // Note that json can be null according to the spec if the client can't - // provide a configuration. This is handled in Config::update below. - let mut config = Config::clone(&*this.config); - if let Err(error) = config.update(json.take()) { - this.show_message( - lsp_types::MessageType::WARNING, - error.to_string(), - false, - ); - } - this.update_configuration(config); - } - } - (None, None) => tracing::error!( - "received empty server settings response from the client" - ), - } - }, - ); - - Ok(()) - })? - .on::(|this, params| { - let config = Arc::make_mut(&mut this.config); - - for workspace in params.event.removed { - let Ok(path) = workspace.uri.to_file_path() else { continue }; - let Ok(path) = AbsPathBuf::try_from(path) else { continue }; - let Some(position) = config.workspace_roots.iter().position(|it| it == &path) else { continue }; - config.workspace_roots.remove(position); - } - - let added = params - .event - .added - .into_iter() - .filter_map(|it| it.uri.to_file_path().ok()) - .filter_map(|it| AbsPathBuf::try_from(it).ok()); - config.workspace_roots.extend(added); - if !config.has_linked_projects() && config.detached_files().is_empty() { - config.rediscover_workspaces(); - this.fetch_workspaces_queue.request_op("client workspaces changed".to_string()) - } - - Ok(()) - })? - .on::(|this, params| { - for change in params.changes { - if let Ok(path) = from_proto::abs_path(&change.uri) { - this.loader.handle.invalidate(path); - } - } - Ok(()) - })? + .on::(handlers::handle_clear_flycheck)? + .on::(handlers::handle_run_flycheck)? .finish(); Ok(()) } @@ -1000,16 +793,60 @@ impl GlobalState { tracing::trace!("updating notifications for {:?}", subscriptions); let snapshot = self.snapshot(); - self.task_pool.handle.spawn(move || { + + // Diagnostics are triggered by the user typing + // so we run them on a latency sensitive thread. + self.task_pool.handle.spawn(stdx::thread::ThreadIntent::LatencySensitive, move || { + let _p = profile::span("publish_diagnostics"); + let _ctx = stdx::panic_context::enter("publish_diagnostics".to_owned()); let diagnostics = subscriptions .into_iter() .filter_map(|file_id| { - handlers::publish_diagnostics(&snapshot, file_id) - .ok() - .map(|diags| (file_id, diags)) + let line_index = snapshot.file_line_index(file_id).ok()?; + Some(( + file_id, + line_index, + snapshot + .analysis + .diagnostics( + &snapshot.config.diagnostics(), + ide::AssistResolveStrategy::None, + file_id, + ) + .ok()?, + )) }) - .collect::>(); - Task::Diagnostics(diagnostics) - }) + .map(|(file_id, line_index, it)| { + ( + file_id, + it.into_iter() + .map(move |d| lsp_types::Diagnostic { + range: crate::to_proto::range(&line_index, d.range), + severity: Some(crate::to_proto::diagnostic_severity(d.severity)), + code: Some(lsp_types::NumberOrString::String( + d.code.as_str().to_string(), + )), + code_description: Some(lsp_types::CodeDescription { + href: lsp_types::Url::parse(&format!( + "https://rust-analyzer.github.io/manual.html#{}", + d.code.as_str() + )) + .unwrap(), + }), + source: Some("rust-analyzer".to_string()), + message: d.message, + related_information: None, + tags: if d.unused { + Some(vec![lsp_types::DiagnosticTag::UNNECESSARY]) + } else { + None + }, + data: None, + }) + .collect::>(), + ) + }); + Task::Diagnostics(diagnostics.collect()) + }); } } diff --git a/crates/rust-analyzer/src/markdown.rs b/crates/rust-analyzer/src/markdown.rs index 912ed1e764275..58426c66a85c1 100644 --- a/crates/rust-analyzer/src/markdown.rs +++ b/crates/rust-analyzer/src/markdown.rs @@ -28,7 +28,7 @@ pub(crate) fn format_docs(src: &str) -> String { if in_code_block { let trimmed = line.trim_start(); - if trimmed.starts_with("##") { + if is_rust && trimmed.starts_with("##") { line = &trimmed[1..]; } } @@ -154,4 +154,12 @@ let s = "foo assert_eq!(format_docs(comment), "```rust\nlet s = \"foo\n# bar # baz\";\n```"); } + + #[test] + fn test_format_docs_handles_double_hashes_non_rust() { + let comment = r#"```markdown +## A second-level heading +```"#; + assert_eq!(format_docs(comment), "```markdown\n## A second-level heading\n```"); + } } diff --git a/crates/rust-analyzer/src/op_queue.rs b/crates/rust-analyzer/src/op_queue.rs index 97aca0161873e..932730fc234b4 100644 --- a/crates/rust-analyzer/src/op_queue.rs +++ b/crates/rust-analyzer/src/op_queue.rs @@ -3,23 +3,23 @@ pub(crate) type Cause = String; -pub(crate) struct OpQueue { - op_requested: Option, +pub(crate) struct OpQueue { + op_requested: Option<(Cause, Args)>, op_in_progress: bool, last_op_result: Output, } -impl Default for OpQueue { +impl Default for OpQueue { fn default() -> Self { Self { op_requested: None, op_in_progress: false, last_op_result: Default::default() } } } -impl OpQueue { - pub(crate) fn request_op(&mut self, reason: Cause) { - self.op_requested = Some(reason); +impl OpQueue { + pub(crate) fn request_op(&mut self, reason: Cause, args: Args) { + self.op_requested = Some((reason, args)); } - pub(crate) fn should_start_op(&mut self) -> Option { + pub(crate) fn should_start_op(&mut self) -> Option<(Cause, Args)> { if self.op_in_progress { return None; } diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 1a6e1af2eb7ed..6e8c8ea91a1b3 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -12,22 +12,24 @@ //! correct. Instead, we try to provide a best-effort service. Even if the //! project is currently loading and we don't have a full project model, we //! still want to respond to various requests. -use std::{collections::hash_map::Entry, mem, sync::Arc}; +use std::{collections::hash_map::Entry, iter, mem, sync}; use flycheck::{FlycheckConfig, FlycheckHandle}; use hir::db::DefDatabase; use ide::Change; use ide_db::{ base_db::{ - CrateGraph, Env, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, - ProcMacroLoadResult, SourceRoot, VfsPath, + salsa::Durability, CrateGraph, Env, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, + ProcMacroKind, ProcMacroLoadResult, ProcMacroPaths, ProcMacros, SourceRoot, VfsPath, }, FxHashMap, }; use itertools::Itertools; use proc_macro_api::{MacroDylib, ProcMacroServer}; use project_model::{PackageRoot, ProjectWorkspace, WorkspaceBuildScripts}; +use stdx::{format_to, thread::ThreadIntent}; use syntax::SmolStr; +use triomphe::Arc; use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind}; use crate::{ @@ -54,11 +56,19 @@ pub(crate) enum BuildDataProgress { End((Arc>, Vec>)), } +#[derive(Debug)] +pub(crate) enum ProcMacroProgress { + Begin, + Report(String), + End(ProcMacros), +} + impl GlobalState { pub(crate) fn is_quiescent(&self) -> bool { !(self.last_reported_status.is_none() || self.fetch_workspaces_queue.op_in_progress() || self.fetch_build_data_queue.op_in_progress() + || self.fetch_proc_macros_queue.op_in_progress() || self.vfs_progress_config_version < self.vfs_config_version || self.vfs_progress_n_done < self.vfs_progress_n_total) } @@ -66,21 +76,27 @@ impl GlobalState { pub(crate) fn update_configuration(&mut self, config: Config) { let _p = profile::span("GlobalState::update_configuration"); let old_config = mem::replace(&mut self.config, Arc::new(config)); - if self.config.lru_capacity() != old_config.lru_capacity() { - self.analysis_host.update_lru_capacity(self.config.lru_capacity()); + if self.config.lru_parse_query_capacity() != old_config.lru_parse_query_capacity() { + self.analysis_host.update_lru_capacity(self.config.lru_parse_query_capacity()); + } + if self.config.lru_query_capacities() != old_config.lru_query_capacities() { + self.analysis_host.update_lru_capacities( + &self.config.lru_query_capacities().cloned().unwrap_or_default(), + ); } if self.config.linked_projects() != old_config.linked_projects() { - self.fetch_workspaces_queue.request_op("linked projects changed".to_string()) + self.fetch_workspaces_queue.request_op("linked projects changed".to_string(), ()) } else if self.config.flycheck() != old_config.flycheck() { self.reload_flycheck(); } - if self.analysis_host.raw_database().enable_proc_attr_macros() + if self.analysis_host.raw_database().expand_proc_attr_macros() != self.config.expand_proc_attr_macros() { - self.analysis_host - .raw_database_mut() - .set_enable_proc_attr_macros(self.config.expand_proc_attr_macros()); + self.analysis_host.raw_database_mut().set_expand_proc_attr_macros_with_durability( + self.config.expand_proc_attr_macros(), + Durability::HIGH, + ); } } @@ -94,12 +110,16 @@ impl GlobalState { if self.proc_macro_changed { status.health = lsp_ext::Health::Warning; - message.push_str("Reload required due to source changes of a procedural macro.\n\n"); + message.push_str("Proc-macros have changed and need to be rebuild.\n\n"); } if let Err(_) = self.fetch_build_data_error() { status.health = lsp_ext::Health::Warning; message.push_str("Failed to run build scripts of some packages.\n\n"); } + if self.proc_macro_clients.iter().any(|it| it.is_err()) { + status.health = lsp_ext::Health::Warning; + message.push_str("Failed to spawn one or more proc-macro servers.\n\n"); + } if !self.config.cargo_autoreload() && self.is_quiescent() && self.fetch_workspaces_queue.op_requested() @@ -112,17 +132,37 @@ impl GlobalState { && self.config.notifications().cargo_toml_not_found { status.health = lsp_ext::Health::Warning; - message.push_str("Failed to discover workspace.\n\n"); + message.push_str("Failed to discover workspace.\n"); + message.push_str("Consider adding the `Cargo.toml` of the workspace to the [`linkedProjects`](https://rust-analyzer.github.io/manual.html#rust-analyzer.linkedProjects) setting.\n\n"); + } + if let Some(err) = &self.config_errors { + status.health = lsp_ext::Health::Warning; + format_to!(message, "{err}\n"); + } + if let Some(err) = &self.last_flycheck_error { + status.health = lsp_ext::Health::Warning; + message.push_str(err); + message.push('\n'); } for ws in self.workspaces.iter() { let (ProjectWorkspace::Cargo { sysroot, .. } | ProjectWorkspace::Json { sysroot, .. } | ProjectWorkspace::DetachedFiles { sysroot, .. }) = ws; - if let Err(Some(e)) = sysroot { - status.health = lsp_ext::Health::Warning; - message.push_str(e); - message.push_str("\n\n"); + match sysroot { + Err(None) => (), + Err(Some(e)) => { + status.health = lsp_ext::Health::Warning; + message.push_str(e); + message.push_str("\n\n"); + } + Ok(s) => { + if let Some(e) = s.loading_warning() { + status.health = lsp_ext::Health::Warning; + message.push_str(&e); + message.push_str("\n\n"); + } + } } if let ProjectWorkspace::Cargo { rustc: Err(Some(e)), .. } = ws { status.health = lsp_ext::Health::Warning; @@ -145,7 +185,7 @@ impl GlobalState { pub(crate) fn fetch_workspaces(&mut self, cause: Cause) { tracing::info!(%cause, "will fetch workspaces"); - self.task_pool.handle.spawn_with_sender({ + self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, { let linked_projects = self.config.linked_projects(); let detached_files = self.config.detached_files().to_vec(); let cargo_config = self.config.cargo(); @@ -177,11 +217,30 @@ impl GlobalState { it.clone(), cargo_config.target.as_deref(), &cargo_config.extra_env, + None, )) } }) .collect::>(); + let mut i = 0; + while i < workspaces.len() { + if let Ok(w) = &workspaces[i] { + let dupes: Vec<_> = workspaces + .iter() + .enumerate() + .skip(i + 1) + .filter_map(|(i, it)| { + it.as_ref().ok().filter(|ws| ws.eq_ignore_build_data(w)).map(|_| i) + }) + .collect(); + dupes.into_iter().rev().for_each(|d| { + _ = workspaces.remove(d); + }); + } + i += 1; + } + if !detached_files.is_empty() { workspaces.push(project_model::ProjectWorkspace::load_detached_files( detached_files, @@ -201,7 +260,7 @@ impl GlobalState { tracing::info!(%cause, "will fetch build data"); let workspaces = Arc::clone(&self.workspaces); let config = self.config.cargo(); - self.task_pool.handle.spawn_with_sender(move |sender| { + self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| { sender.send(Task::FetchBuildData(BuildDataProgress::Begin)).unwrap(); let progress = { @@ -216,6 +275,63 @@ impl GlobalState { }); } + pub(crate) fn fetch_proc_macros(&mut self, cause: Cause, paths: Vec) { + tracing::info!(%cause, "will load proc macros"); + let dummy_replacements = self.config.dummy_replacements().clone(); + let proc_macro_clients = self.proc_macro_clients.clone(); + + self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| { + sender.send(Task::LoadProcMacros(ProcMacroProgress::Begin)).unwrap(); + + let dummy_replacements = &dummy_replacements; + let progress = { + let sender = sender.clone(); + &move |msg| { + sender.send(Task::LoadProcMacros(ProcMacroProgress::Report(msg))).unwrap() + } + }; + + let mut res = FxHashMap::default(); + let chain = proc_macro_clients + .iter() + .map(|res| res.as_ref().map_err(|e| e.to_string())) + .chain(iter::repeat_with(|| Err("Proc macros servers are not running".into()))); + for (client, paths) in chain.zip(paths) { + res.extend(paths.into_iter().map(move |(crate_id, res)| { + ( + crate_id, + res.map_or_else( + |_| Err("proc macro crate is missing dylib".to_owned()), + |(crate_name, path)| { + progress(path.display().to_string()); + client.as_ref().map_err(Clone::clone).and_then(|client| { + load_proc_macro( + client, + &path, + crate_name + .as_deref() + .and_then(|crate_name| { + dummy_replacements.get(crate_name).map(|v| &**v) + }) + .unwrap_or_default(), + ) + }) + }, + ), + ) + })); + } + + sender.send(Task::LoadProcMacros(ProcMacroProgress::End(res))).unwrap(); + }); + } + + pub(crate) fn set_proc_macros(&mut self, proc_macros: ProcMacros) { + let mut change = Change::new(); + change.set_proc_macros(proc_macros); + self.analysis_host.apply_change(change); + } + pub(crate) fn switch_workspaces(&mut self, cause: Cause) { let _p = profile::span("GlobalState::switch_workspaces"); tracing::info!(%cause, "will switch workspaces"); @@ -303,43 +419,39 @@ impl GlobalState { ); } - let mut change = Change::new(); - let files_config = self.config.files(); let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude); - if self.proc_macro_clients.is_empty() { - if let Some((path, path_manually_set)) = self.config.proc_macro_srv() { + if self.proc_macro_clients.is_empty() || !same_workspaces { + if self.config.expand_proc_macros() { tracing::info!("Spawning proc-macro servers"); - self.proc_macro_clients = self - .workspaces - .iter() - .map(|ws| { - let (path, args): (_, &[_]) = if path_manually_set { - tracing::debug!( - "Pro-macro server path explicitly set: {}", - path.display() - ); - (path.clone(), &[]) - } else { - match ws.find_sysroot_proc_macro_srv() { - Some(server_path) => (server_path, &[]), - None => (path.clone(), &["proc-macro"]), - } - }; - - tracing::info!(?args, "Using proc-macro server at {}", path.display(),); - ProcMacroServer::spawn(path.clone(), args).map_err(|err| { - let error = format!( - "Failed to run proc-macro server from path {}, error: {:?}", - path.display(), - err - ); - tracing::error!(error); - error + + // FIXME: use `Arc::from_iter` when it becomes available + self.proc_macro_clients = Arc::from( + self.workspaces + .iter() + .map(|ws| { + let path = match self.config.proc_macro_srv() { + Some(path) => path, + None => ws.find_sysroot_proc_macro_srv()?, + }; + + tracing::info!("Using proc-macro server at {}", path.display(),); + ProcMacroServer::spawn(path.clone()).map_err(|err| { + tracing::error!( + "Failed to run proc-macro server from path {}, error: {:?}", + path.display(), + err + ); + anyhow::anyhow!( + "Failed to run proc-macro server from path {}, error: {:?}", + path.display(), + err + ) + }) }) - }) - .collect() + .collect::>(), + ) }; } @@ -353,56 +465,48 @@ impl GlobalState { watch, version: self.vfs_config_version, }); + self.source_root_config = project_folders.source_root_config; // Create crate graph from all the workspaces - let crate_graph = { - let dummy_replacements = self.config.dummy_replacements(); - + let (crate_graph, proc_macro_paths) = { let vfs = &mut self.vfs.write().0; let loader = &mut self.loader; - let mem_docs = &self.mem_docs; - let mut load = move |path: &AbsPath| { + let mut load = |path: &AbsPath| { let _p = profile::span("switch_workspaces::load"); let vfs_path = vfs::VfsPath::from(path.to_path_buf()); - if !mem_docs.contains(&vfs_path) { - let contents = loader.handle.load_sync(path); - vfs.set_file_contents(vfs_path.clone(), contents); - } - let res = vfs.file_id(&vfs_path); - if res.is_none() { - tracing::warn!("failed to load {}", path.display()) + match vfs.file_id(&vfs_path) { + Some(file_id) => Some(file_id), + None => { + if !self.mem_docs.contains(&vfs_path) { + let contents = loader.handle.load_sync(path); + vfs.set_file_contents(vfs_path.clone(), contents); + } + vfs.file_id(&vfs_path) + } } - res }; let mut crate_graph = CrateGraph::default(); - for (idx, ws) in self.workspaces.iter().enumerate() { - let proc_macro_client = match self.proc_macro_clients.get(idx) { - Some(res) => res.as_ref().map_err(|e| &**e), - None => Err("Proc macros are disabled"), - }; - let mut load_proc_macro = move |crate_name: &str, path: &AbsPath| { - load_proc_macro( - proc_macro_client, - path, - dummy_replacements.get(crate_name).map(|v| &**v).unwrap_or_default(), - ) - }; - crate_graph.extend(ws.to_crate_graph( - &mut load_proc_macro, - &mut load, - &self.config.cargo().extra_env, - )); + let mut proc_macros = Vec::default(); + for ws in &**self.workspaces { + let (other, mut crate_proc_macros) = + ws.to_crate_graph(&mut load, &self.config.extra_env()); + crate_graph.extend(other, &mut crate_proc_macros); + proc_macros.push(crate_proc_macros); } - crate_graph + (crate_graph, proc_macros) }; - change.set_crate_graph(crate_graph); - - self.source_root_config = project_folders.source_root_config; + let mut change = Change::new(); + if self.config.expand_proc_macros() { + self.fetch_proc_macros_queue.request_op(cause, proc_macro_paths); + } + change.set_crate_graph(crate_graph); self.analysis_host.apply_change(change); self.process_changes(); + self.reload_flycheck(); + tracing::info!("did switch workspaces"); } @@ -642,14 +746,12 @@ impl SourceRootConfig { /// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace` /// with an identity dummy expander. pub(crate) fn load_proc_macro( - server: Result<&ProcMacroServer, &str>, + server: &ProcMacroServer, path: &AbsPath, dummy_replace: &[Box], ) -> ProcMacroLoadResult { - let server = server.map_err(ToOwned::to_owned)?; let res: Result, String> = (|| { - let dylib = MacroDylib::new(path.to_path_buf()) - .map_err(|io| format!("Proc-macro dylib loading failed: {io}"))?; + let dylib = MacroDylib::new(path.to_path_buf()); let vec = server.load_dylib(dylib).map_err(|e| format!("{e}"))?; if vec.is_empty() { return Err("proc macro library returned no proc macros".to_string()); @@ -684,14 +786,14 @@ pub(crate) fn load_proc_macro( proc_macro_api::ProcMacroKind::FuncLike => ProcMacroKind::FuncLike, proc_macro_api::ProcMacroKind::Attr => ProcMacroKind::Attr, }; - let expander: Arc = + let expander: sync::Arc = if dummy_replace.iter().any(|replace| &**replace == name) { match kind { - ProcMacroKind::Attr => Arc::new(IdentityExpander), - _ => Arc::new(EmptyExpander), + ProcMacroKind::Attr => sync::Arc::new(IdentityExpander), + _ => sync::Arc::new(EmptyExpander), } } else { - Arc::new(Expander(expander)) + sync::Arc::new(Expander(expander)) }; ProcMacro { name, kind, expander } } diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index c2cc3f422d206..d4bb20c8f448e 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs @@ -13,7 +13,7 @@ macro_rules! define_semantic_token_types { $($standard:ident),*$(,)? } custom { - $(($custom:ident, $string:literal)),*$(,)? + $(($custom:ident, $string:literal) $(=> $fallback:ident)?),*$(,)? } ) => { @@ -24,6 +24,15 @@ macro_rules! define_semantic_token_types { $(SemanticTokenType::$standard,)* $($custom),* ]; + + pub(crate) fn standard_fallback_type(token: SemanticTokenType) -> Option { + $( + if token == $custom { + None $(.or(Some(SemanticTokenType::$fallback)))? + } else + )* + { Some(token )} + } }; } @@ -51,42 +60,46 @@ define_semantic_token_types![ custom { (ANGLE, "angle"), - (ARITHMETIC, "arithmetic"), - (ATTRIBUTE, "attribute"), - (ATTRIBUTE_BRACKET, "attributeBracket"), - (BITWISE, "bitwise"), + (ARITHMETIC, "arithmetic") => OPERATOR, + (ATTRIBUTE, "attribute") => DECORATOR, + (ATTRIBUTE_BRACKET, "attributeBracket") => DECORATOR, + (BITWISE, "bitwise") => OPERATOR, (BOOLEAN, "boolean"), (BRACE, "brace"), (BRACKET, "bracket"), - (BUILTIN_ATTRIBUTE, "builtinAttribute"), + (BUILTIN_ATTRIBUTE, "builtinAttribute") => DECORATOR, (BUILTIN_TYPE, "builtinType"), - (CHAR, "character"), + (CHAR, "character") => STRING, (COLON, "colon"), (COMMA, "comma"), - (COMPARISON, "comparison"), + (COMPARISON, "comparison") => OPERATOR, (CONST_PARAMETER, "constParameter"), - (DERIVE, "derive"), - (DERIVE_HELPER, "deriveHelper"), + (DERIVE, "derive") => DECORATOR, + (DERIVE_HELPER, "deriveHelper") => DECORATOR, (DOT, "dot"), - (ESCAPE_SEQUENCE, "escapeSequence"), - (FORMAT_SPECIFIER, "formatSpecifier"), - (GENERIC, "generic"), + (ESCAPE_SEQUENCE, "escapeSequence") => STRING, + (FORMAT_SPECIFIER, "formatSpecifier") => STRING, + (GENERIC, "generic") => TYPE_PARAMETER, (LABEL, "label"), (LIFETIME, "lifetime"), - (LOGICAL, "logical"), - (MACRO_BANG, "macroBang"), + (LOGICAL, "logical") => OPERATOR, + (MACRO_BANG, "macroBang") => MACRO, (PARENTHESIS, "parenthesis"), (PUNCTUATION, "punctuation"), - (SELF_KEYWORD, "selfKeyword"), - (SELF_TYPE_KEYWORD, "selfTypeKeyword"), + (SELF_KEYWORD, "selfKeyword") => KEYWORD, + (SELF_TYPE_KEYWORD, "selfTypeKeyword") => KEYWORD, (SEMICOLON, "semicolon"), (TYPE_ALIAS, "typeAlias"), - (TOOL_MODULE, "toolModule"), + (TOOL_MODULE, "toolModule") => DECORATOR, (UNION, "union"), (UNRESOLVED_REFERENCE, "unresolvedReference"), } ]; +macro_rules! count_tts { + () => {0usize}; + ($_head:tt $($tail:tt)*) => {1usize + count_tts!($($tail)*)}; +} macro_rules! define_semantic_token_modifiers { ( standard { @@ -105,6 +118,8 @@ macro_rules! define_semantic_token_modifiers { $(SemanticTokenModifier::$standard,)* $($custom),* ]; + + const LAST_STANDARD_MOD: usize = count_tts!($($standard)*); }; } @@ -126,6 +141,7 @@ define_semantic_token_modifiers![ (INJECTED, "injected"), (INTRA_DOC_LINK, "intraDocLink"), (LIBRARY, "library"), + (MACRO_MODIFIER, "macro"), (MUTABLE, "mutable"), (PUBLIC, "public"), (REFERENCE, "reference"), @@ -137,6 +153,13 @@ define_semantic_token_modifiers![ #[derive(Default)] pub(crate) struct ModifierSet(pub(crate) u32); +impl ModifierSet { + pub(crate) fn standard_fallback(&mut self) { + // Remove all non standard modifiers + self.0 = self.0 & !(!0u32 << LAST_STANDARD_MOD) + } +} + impl ops::BitOrAssign for ModifierSet { fn bitor_assign(&mut self, rhs: SemanticTokenModifier) { let idx = SUPPORTED_MODIFIERS.iter().position(|it| it == &rhs).unwrap(); diff --git a/crates/rust-analyzer/src/task_pool.rs b/crates/rust-analyzer/src/task_pool.rs index 616e449984ae6..a5a10e86914e0 100644 --- a/crates/rust-analyzer/src/task_pool.rs +++ b/crates/rust-analyzer/src/task_pool.rs @@ -1,53 +1,42 @@ -//! A thin wrapper around `ThreadPool` to make sure that we join all things -//! properly. +//! A thin wrapper around [`stdx::thread::Pool`] which threads a sender through spawned jobs. +//! It is used in [`crate::global_state::GlobalState`] throughout the main loop. + use crossbeam_channel::Sender; +use stdx::thread::{Pool, ThreadIntent}; pub(crate) struct TaskPool { sender: Sender, - inner: threadpool::ThreadPool, + pool: Pool, } impl TaskPool { pub(crate) fn new_with_threads(sender: Sender, threads: usize) -> TaskPool { - const STACK_SIZE: usize = 8 * 1024 * 1024; - - let inner = threadpool::Builder::new() - .thread_name("Worker".into()) - .thread_stack_size(STACK_SIZE) - .num_threads(threads) - .build(); - TaskPool { sender, inner } + TaskPool { sender, pool: Pool::new(threads) } } - pub(crate) fn spawn(&mut self, task: F) + pub(crate) fn spawn(&mut self, intent: ThreadIntent, task: F) where F: FnOnce() -> T + Send + 'static, T: Send + 'static, { - self.inner.execute({ + self.pool.spawn(intent, { let sender = self.sender.clone(); move || sender.send(task()).unwrap() }) } - pub(crate) fn spawn_with_sender(&mut self, task: F) + pub(crate) fn spawn_with_sender(&mut self, intent: ThreadIntent, task: F) where F: FnOnce(Sender) + Send + 'static, T: Send + 'static, { - self.inner.execute({ + self.pool.spawn(intent, { let sender = self.sender.clone(); move || task(sender) }) } pub(crate) fn len(&self) -> usize { - self.inner.queued_count() - } -} - -impl Drop for TaskPool { - fn drop(&mut self) { - self.inner.join() + self.pool.len() } } diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 7d97b69f8ea05..8a9e947ded0ad 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -24,7 +24,7 @@ use crate::{ line_index::{LineEndings, LineIndex, PositionEncoding}, lsp_ext, lsp_utils::invalid_params_error, - semantic_tokens, + semantic_tokens::{self, standard_fallback_type}, }; pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { @@ -32,7 +32,7 @@ pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::P match line_index.encoding { PositionEncoding::Utf8 => lsp_types::Position::new(line_col.line, line_col.col), PositionEncoding::Wide(enc) => { - let line_col = line_index.index.to_wide(enc, line_col); + let line_col = line_index.index.to_wide(enc, line_col).unwrap(); lsp_types::Position::new(line_col.line, line_col.col) } } @@ -279,7 +279,7 @@ fn completion_item( let mut lsp_item = lsp_types::CompletionItem { label: item.label.to_string(), - detail: item.detail.map(|it| it.to_string()), + detail: item.detail, filter_text: Some(lookup), kind: Some(completion_item_kind(item.kind)), text_edit: Some(text_edit), @@ -306,12 +306,10 @@ fn completion_item( let imports: Vec<_> = item .import_to_add .into_iter() - .filter_map(|import_edit| { - let import_path = &import_edit.import_path; - let import_name = import_path.segments().last()?; + .filter_map(|(import_path, import_name)| { Some(lsp_ext::CompletionImport { - full_import_path: import_path.to_string(), - imported_name: import_name.to_string(), + full_import_path: import_path, + imported_name: import_name, }) }) .collect(); @@ -434,83 +432,23 @@ pub(crate) fn signature_help( pub(crate) fn inlay_hint( snap: &GlobalStateSnapshot, line_index: &LineIndex, - render_colons: bool, - mut inlay_hint: InlayHint, + inlay_hint: InlayHint, ) -> Cancellable { - match inlay_hint.kind { - InlayKind::Parameter if render_colons => inlay_hint.label.append_str(":"), - InlayKind::Type if render_colons => inlay_hint.label.prepend_str(": "), - InlayKind::ClosureReturnType => inlay_hint.label.prepend_str(" -> "), - InlayKind::Discriminant => inlay_hint.label.prepend_str(" = "), - _ => {} - } - let (label, tooltip) = inlay_hint_label(snap, inlay_hint.label)?; Ok(lsp_types::InlayHint { - position: match inlay_hint.kind { - // before annotated thing - InlayKind::OpeningParenthesis - | InlayKind::Parameter - | InlayKind::Adjustment - | InlayKind::BindingMode => position(line_index, inlay_hint.range.start()), - // after annotated thing - InlayKind::ClosureReturnType - | InlayKind::Type - | InlayKind::Discriminant - | InlayKind::Chaining - | InlayKind::GenericParamList - | InlayKind::ClosingParenthesis - | InlayKind::AdjustmentPostfix - | InlayKind::Lifetime - | InlayKind::ClosingBrace => position(line_index, inlay_hint.range.end()), + position: match inlay_hint.position { + ide::InlayHintPosition::Before => position(line_index, inlay_hint.range.start()), + ide::InlayHintPosition::After => position(line_index, inlay_hint.range.end()), }, - padding_left: Some(match inlay_hint.kind { - InlayKind::Type => !render_colons, - InlayKind::Chaining | InlayKind::ClosingBrace => true, - InlayKind::ClosingParenthesis - | InlayKind::Discriminant - | InlayKind::OpeningParenthesis - | InlayKind::BindingMode - | InlayKind::ClosureReturnType - | InlayKind::GenericParamList - | InlayKind::Adjustment - | InlayKind::AdjustmentPostfix - | InlayKind::Lifetime - | InlayKind::Parameter => false, - }), - padding_right: Some(match inlay_hint.kind { - InlayKind::ClosingParenthesis - | InlayKind::OpeningParenthesis - | InlayKind::Chaining - | InlayKind::ClosureReturnType - | InlayKind::GenericParamList - | InlayKind::Adjustment - | InlayKind::AdjustmentPostfix - | InlayKind::Type - | InlayKind::Discriminant - | InlayKind::ClosingBrace => false, - InlayKind::BindingMode => { - matches!(&label, lsp_types::InlayHintLabel::String(s) if s != "&") - } - InlayKind::Parameter | InlayKind::Lifetime => true, - }), + padding_left: Some(inlay_hint.pad_left), + padding_right: Some(inlay_hint.pad_right), kind: match inlay_hint.kind { InlayKind::Parameter => Some(lsp_types::InlayHintKind::PARAMETER), - InlayKind::ClosureReturnType | InlayKind::Type | InlayKind::Chaining => { - Some(lsp_types::InlayHintKind::TYPE) - } - InlayKind::ClosingParenthesis - | InlayKind::Discriminant - | InlayKind::OpeningParenthesis - | InlayKind::BindingMode - | InlayKind::GenericParamList - | InlayKind::Lifetime - | InlayKind::Adjustment - | InlayKind::AdjustmentPostfix - | InlayKind::ClosingBrace => None, + InlayKind::Type | InlayKind::Chaining => Some(lsp_types::InlayHintKind::TYPE), + _ => None, }, - text_edits: None, + text_edits: inlay_hint.text_edit.map(|it| text_edit_vec(line_index, it)), data: None, tooltip, label, @@ -580,6 +518,8 @@ pub(crate) fn semantic_tokens( text: &str, line_index: &LineIndex, highlights: Vec, + semantics_tokens_augments_syntax_tokens: bool, + non_standard_tokens: bool, ) -> lsp_types::SemanticTokens { let id = TOKEN_RESULT_COUNTER.fetch_add(1, Ordering::SeqCst).to_string(); let mut builder = semantic_tokens::SemanticTokensBuilder::new(id); @@ -589,7 +529,35 @@ pub(crate) fn semantic_tokens( continue; } - let (ty, mods) = semantic_token_type_and_modifiers(highlight_range.highlight); + if semantics_tokens_augments_syntax_tokens { + match highlight_range.highlight.tag { + HlTag::BoolLiteral + | HlTag::ByteLiteral + | HlTag::CharLiteral + | HlTag::Comment + | HlTag::Keyword + | HlTag::NumericLiteral + | HlTag::Operator(_) + | HlTag::Punctuation(_) + | HlTag::StringLiteral + | HlTag::None + if highlight_range.highlight.mods.is_empty() => + { + continue + } + _ => (), + } + } + + let (mut ty, mut mods) = semantic_token_type_and_modifiers(highlight_range.highlight); + + if !non_standard_tokens { + ty = match standard_fallback_type(ty) { + Some(ty) => ty, + None => continue, + }; + mods.standard_fallback(); + } let token_index = semantic_tokens::type_index(ty); let modifier_bitset = mods.0; @@ -710,6 +678,7 @@ fn semantic_token_type_and_modifiers( HlMod::Injected => semantic_tokens::INJECTED, HlMod::IntraDocLink => semantic_tokens::INTRA_DOC_LINK, HlMod::Library => semantic_tokens::LIBRARY, + HlMod::Macro => semantic_tokens::MACRO_MODIFIER, HlMod::Mutable => semantic_tokens::MUTABLE, HlMod::Public => semantic_tokens::PUBLIC, HlMod::Reference => semantic_tokens::REFERENCE, @@ -1215,6 +1184,14 @@ pub(crate) fn code_lens( data: None, }) } + if lens_config.interpret { + let command = command::interpret_single(&r); + acc.push(lsp_types::CodeLens { + range: annotation_range, + command: Some(command), + data: None, + }) + } } AnnotationKind::HasImpls { pos: file_range, data } => { if !client_commands_config.show_reference { @@ -1257,7 +1234,16 @@ pub(crate) fn code_lens( acc.push(lsp_types::CodeLens { range: annotation_range, command, - data: Some(to_value(lsp_ext::CodeLensResolveData::Impls(goto_params)).unwrap()), + data: (|| { + let version = snap.url_file_version(&url)?; + Some( + to_value(lsp_ext::CodeLensResolveData { + version, + kind: lsp_ext::CodeLensResolveDataKind::Impls(goto_params), + }) + .unwrap(), + ) + })(), }) } AnnotationKind::HasReferences { pos: file_range, data } => { @@ -1287,7 +1273,16 @@ pub(crate) fn code_lens( acc.push(lsp_types::CodeLens { range: annotation_range, command, - data: Some(to_value(lsp_ext::CodeLensResolveData::References(doc_pos)).unwrap()), + data: (|| { + let version = snap.url_file_version(&url)?; + Some( + to_value(lsp_ext::CodeLensResolveData { + version, + kind: lsp_ext::CodeLensResolveDataKind::References(doc_pos), + }) + .unwrap(), + ) + })(), }) } } @@ -1341,6 +1336,15 @@ pub(crate) mod command { } } + pub(crate) fn interpret_single(_runnable: &lsp_ext::Runnable) -> lsp_types::Command { + lsp_types::Command { + title: "Interpret".into(), + command: "rust-analyzer.interpretFunction".into(), + // FIXME: use the `_runnable` here. + arguments: Some(vec![]), + } + } + pub(crate) fn goto_location( snap: &GlobalStateSnapshot, nav: &NavigationTarget, @@ -1406,9 +1410,8 @@ pub(crate) fn rename_error(err: RenameError) -> crate::LspError { #[cfg(test)] mod tests { - use std::sync::Arc; - use ide::Analysis; + use triomphe::Arc; use super::*; diff --git a/crates/rust-analyzer/tests/slow-tests/main.rs b/crates/rust-analyzer/tests/slow-tests/main.rs index 587d640969aac..e130c762fc48a 100644 --- a/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/crates/rust-analyzer/tests/slow-tests/main.rs @@ -59,7 +59,7 @@ use std::collections::Spam; "#, ) .with_config(serde_json::json!({ - "cargo": { "sysroot": "discover" } + "cargo": { "sysroot": "discover" }, })) .server() .wait_until_workspace_is_loaded(); @@ -508,7 +508,7 @@ fn main() {} #[test] fn test_missing_module_code_action_in_json_project() { if skip_slow_tests() { - // return; + return; } let tmp_dir = TestDir::new(); @@ -612,7 +612,7 @@ fn main() {{}} "# )) .with_config(serde_json::json!({ - "cargo": { "sysroot": "discover" } + "cargo": { "sysroot": "discover" }, })) .server() .wait_until_workspace_is_loaded(); @@ -685,7 +685,7 @@ version = \"0.0.0\" #[test] fn out_dirs_check() { if skip_slow_tests() { - // return; + return; } let server = Project::with_fixture( @@ -711,10 +711,21 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); } //- /src/main.rs -#[rustc_builtin_macro] macro_rules! include {} -#[rustc_builtin_macro] macro_rules! include_str {} -#[rustc_builtin_macro] macro_rules! concat {} -#[rustc_builtin_macro] macro_rules! env {} +#![allow(warnings)] +#![feature(rustc_attrs)] +#[rustc_builtin_macro] macro_rules! include { + ($file:expr $(,)?) => {{ /* compiler built-in */ }}; +} +#[rustc_builtin_macro] macro_rules! include_str { + ($file:expr $(,)?) => {{ /* compiler built-in */ }}; +} +#[rustc_builtin_macro] macro_rules! concat { + ($($e:ident),+ $(,)?) => {{ /* compiler built-in */ }}; +} +#[rustc_builtin_macro] macro_rules! env { + ($name:expr $(,)?) => {{ /* compiler built-in */ }}; + ($name:expr, $error_msg:expr $(,)?) => {{ /* compiler built-in */ }}; +} include!(concat!(env!("OUT_DIR"), "/hello.rs")); @@ -741,6 +752,9 @@ fn main() { "enable": true }, "sysroot": null, + "extraEnv": { + "RUSTC_BOOTSTRAP": "1" + } } })) .server() @@ -749,7 +763,7 @@ fn main() { let res = server.send_request::(HoverParams { text_document_position_params: TextDocumentPositionParams::new( server.doc_id("src/main.rs"), - Position::new(19, 10), + Position::new(30, 10), ), work_done_progress_params: Default::default(), }); @@ -758,7 +772,7 @@ fn main() { let res = server.send_request::(HoverParams { text_document_position_params: TextDocumentPositionParams::new( server.doc_id("src/main.rs"), - Position::new(20, 10), + Position::new(31, 10), ), work_done_progress_params: Default::default(), }); @@ -768,23 +782,23 @@ fn main() { GotoDefinitionParams { text_document_position_params: TextDocumentPositionParams::new( server.doc_id("src/main.rs"), - Position::new(17, 9), + Position::new(28, 9), ), work_done_progress_params: Default::default(), partial_result_params: Default::default(), }, json!([{ "originSelectionRange": { - "end": { "character": 10, "line": 17 }, - "start": { "character": 8, "line": 17 } + "end": { "character": 10, "line": 28 }, + "start": { "character": 8, "line": 28 } }, "targetRange": { - "end": { "character": 9, "line": 8 }, - "start": { "character": 0, "line": 7 } + "end": { "character": 9, "line": 19 }, + "start": { "character": 0, "line": 18 } }, "targetSelectionRange": { - "end": { "character": 8, "line": 8 }, - "start": { "character": 7, "line": 8 } + "end": { "character": 8, "line": 19 }, + "start": { "character": 7, "line": 19 } }, "targetUri": "file:///[..]src/main.rs" }]), @@ -794,23 +808,23 @@ fn main() { GotoDefinitionParams { text_document_position_params: TextDocumentPositionParams::new( server.doc_id("src/main.rs"), - Position::new(18, 9), + Position::new(29, 9), ), work_done_progress_params: Default::default(), partial_result_params: Default::default(), }, json!([{ "originSelectionRange": { - "end": { "character": 10, "line": 18 }, - "start": { "character": 8, "line": 18 } + "end": { "character": 10, "line": 29 }, + "start": { "character": 8, "line": 29 } }, "targetRange": { - "end": { "character": 9, "line": 12 }, - "start": { "character": 0, "line":11 } + "end": { "character": 9, "line": 23 }, + "start": { "character": 0, "line": 22 } }, "targetSelectionRange": { - "end": { "character": 8, "line": 12 }, - "start": { "character": 7, "line": 12 } + "end": { "character": 8, "line": 23 }, + "start": { "character": 7, "line": 23 } }, "targetUri": "file:///[..]src/main.rs" }]), @@ -818,8 +832,7 @@ fn main() { } #[test] -// FIXME: Re-enable once we can run proc-macro tests on rust-lang/rust-analyzer again -#[cfg(any())] +#[cfg(feature = "sysroot-abi")] fn resolve_proc_macro() { use expect_test::expect; if skip_slow_tests() { @@ -837,6 +850,7 @@ edition = "2021" bar = {path = "../bar"} //- /foo/src/main.rs +#![feature(rustc_attrs, decl_macro)] use bar::Bar; #[rustc_builtin_macro] @@ -913,7 +927,7 @@ pub fn foo(_input: TokenStream) -> TokenStream { let res = server.send_request::(HoverParams { text_document_position_params: TextDocumentPositionParams::new( server.doc_id("foo/src/main.rs"), - Position::new(10, 9), + Position::new(11, 9), ), work_done_progress_params: Default::default(), }); @@ -1083,10 +1097,18 @@ version = "0.0.0" //- /bar/src/lib.rs pub fn bar() {} + +//- /baz/Cargo.toml +[package] +name = "baz" +version = "0.0.0" + +//- /baz/src/lib.rs "#, ) .root("foo") .root("bar") + .root("baz") .with_config(json!({ "files": { "excludeDirs": ["foo", "bar"] diff --git a/crates/rust-analyzer/tests/slow-tests/support.rs b/crates/rust-analyzer/tests/slow-tests/support.rs index 037fc89ace090..b2a8041ae9b57 100644 --- a/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/crates/rust-analyzer/tests/slow-tests/support.rs @@ -9,11 +9,10 @@ use std::{ use crossbeam_channel::{after, select, Receiver}; use lsp_server::{Connection, Message, Notification, Request}; use lsp_types::{notification::Exit, request::Shutdown, TextDocumentIdentifier, Url}; -use project_model::ProjectManifest; use rust_analyzer::{config::Config, lsp_ext, main_loop}; use serde::Serialize; use serde_json::{json, to_string_pretty, Value}; -use test_utils::Fixture; +use test_utils::FixtureWithProjectMeta; use vfs::AbsPathBuf; use crate::testdir::TestDir; @@ -37,8 +36,12 @@ impl<'a> Project<'a> { "sysroot": null, // Can't use test binary as rustc wrapper. "buildScripts": { - "useRustcWrapper": false + "useRustcWrapper": false, + "enable": false, }, + }, + "procMacro": { + "enable": false, } }), } @@ -80,10 +83,12 @@ impl<'a> Project<'a> { profile::init_from(crate::PROFILE); }); - let (mini_core, proc_macros, fixtures) = Fixture::parse(self.fixture); - assert!(proc_macros.is_empty()); + let FixtureWithProjectMeta { fixture, mini_core, proc_macro_names, toolchain } = + FixtureWithProjectMeta::parse(self.fixture); + assert!(proc_macro_names.is_empty()); assert!(mini_core.is_none()); - for entry in fixtures { + assert!(toolchain.is_none()); + for entry in fixture { let path = tmp_dir.path().join(&entry.path['/'.len_utf8()..]); fs::create_dir_all(path.parent().unwrap()).unwrap(); fs::write(path.as_path(), entry.text.as_bytes()).unwrap(); @@ -95,10 +100,6 @@ impl<'a> Project<'a> { if roots.is_empty() { roots.push(tmp_dir_path.clone()); } - let discovered_projects = roots - .into_iter() - .map(|it| ProjectManifest::discover_single(&it).unwrap()) - .collect::>(); let mut config = Config::new( tmp_dir_path, @@ -138,10 +139,10 @@ impl<'a> Project<'a> { })), ..Default::default() }, - Vec::new(), + roots, ); - config.discovered_projects = Some(discovered_projects); config.update(self.config).expect("invalid config"); + config.rediscover_workspaces(); Server::new(tmp_dir, config) } @@ -154,7 +155,7 @@ pub(crate) fn project(fixture: &str) -> Server { pub(crate) struct Server { req_id: Cell, messages: RefCell>, - _thread: jod_thread::JoinHandle<()>, + _thread: stdx::thread::JoinHandle, client: Connection, /// XXX: remove the tempdir last dir: TestDir, @@ -164,7 +165,7 @@ impl Server { fn new(dir: TestDir, config: Config) -> Server { let (connection, client) = Connection::memory(); - let _thread = jod_thread::Builder::new() + let _thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) .name("test server".to_string()) .spawn(move || main_loop(config, connection).unwrap()) .expect("failed to spawn a thread"); @@ -251,6 +252,9 @@ impl Server { .clone() .extract::("experimental/serverStatus") .unwrap(); + if status.health != lsp_ext::Health::Ok { + panic!("server errored/warned while loading workspace: {:?}", status.message); + } status.quiescent } _ => false, diff --git a/crates/rust-analyzer/tests/slow-tests/tidy.rs b/crates/rust-analyzer/tests/slow-tests/tidy.rs index 8e3097fce4230..f230cba2bf828 100644 --- a/crates/rust-analyzer/tests/slow-tests/tidy.rs +++ b/crates/rust-analyzer/tests/slow-tests/tidy.rs @@ -257,6 +257,8 @@ fn check_dbg(path: &Path, text: &str) { "ide-db/src/generated/lints.rs", // test for doc test for remove_dbg "src/tests/generated.rs", + // `expect!` string can contain `dbg!` (due to .dbg postfix) + "ide-completion/src/tests/special.rs", ]; if need_dbg.iter().any(|p| path.ends_with(p)) { return; diff --git a/crates/sourcegen/src/lib.rs b/crates/sourcegen/src/lib.rs index 72d26635c3369..c5da6ceb4d198 100644 --- a/crates/sourcegen/src/lib.rs +++ b/crates/sourcegen/src/lib.rs @@ -58,21 +58,19 @@ impl CommentBlock { assert!(tag.starts_with(char::is_uppercase)); let tag = format!("{tag}:"); - // Would be nice if we had `.retain_mut` here! - CommentBlock::extract_untagged(text) - .into_iter() - .filter_map(|mut block| { - let first = block.contents.remove(0); - first.strip_prefix(&tag).map(|id| { - if block.is_doc { - panic!("Use plain (non-doc) comments with tags like {tag}:\n {first}"); - } + let mut blocks = CommentBlock::extract_untagged(text); + blocks.retain_mut(|block| { + let first = block.contents.remove(0); + let Some(id) = first.strip_prefix(&tag) else { return false; }; + + if block.is_doc { + panic!("Use plain (non-doc) comments with tags like {tag}:\n {first}"); + } - block.id = id.trim().to_string(); - block - }) - }) - .collect() + block.id = id.trim().to_string(); + true + }); + blocks } pub fn extract_untagged(text: &str) -> Vec { diff --git a/crates/stdx/Cargo.toml b/crates/stdx/Cargo.toml index c881f2fd3f45e..a67f36ae9006a 100644 --- a/crates/stdx/Cargo.toml +++ b/crates/stdx/Cargo.toml @@ -15,6 +15,8 @@ doctest = false libc = "0.2.135" backtrace = { version = "0.3.65", optional = true } always-assert = { version = "0.1.2", features = ["log"] } +jod-thread = "0.1.2" +crossbeam-channel = "0.5.5" # Think twice before adding anything here [target.'cfg(windows)'.dependencies] diff --git a/crates/stdx/src/hash.rs b/crates/stdx/src/hash.rs deleted file mode 100644 index 0c21d2674b1a0..0000000000000 --- a/crates/stdx/src/hash.rs +++ /dev/null @@ -1,80 +0,0 @@ -//! A none hashing [`Hasher`] implementation. -use std::{ - hash::{BuildHasher, Hasher}, - marker::PhantomData, -}; - -pub type NoHashHashMap = std::collections::HashMap>; -pub type NoHashHashSet = std::collections::HashSet>; - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct NoHashHasherBuilder(PhantomData); - -impl Default for NoHashHasherBuilder { - fn default() -> Self { - Self(Default::default()) - } -} - -pub trait NoHashHashable {} -impl NoHashHashable for usize {} -impl NoHashHashable for u32 {} - -pub struct NoHashHasher(u64); - -impl BuildHasher for NoHashHasherBuilder { - type Hasher = NoHashHasher; - fn build_hasher(&self) -> Self::Hasher { - NoHashHasher(0) - } -} - -impl Hasher for NoHashHasher { - fn finish(&self) -> u64 { - self.0 - } - - fn write(&mut self, _: &[u8]) { - unimplemented!("NoHashHasher should only be used for hashing primitive integers") - } - - fn write_u8(&mut self, i: u8) { - self.0 = i as u64; - } - - fn write_u16(&mut self, i: u16) { - self.0 = i as u64; - } - - fn write_u32(&mut self, i: u32) { - self.0 = i as u64; - } - - fn write_u64(&mut self, i: u64) { - self.0 = i; - } - - fn write_usize(&mut self, i: usize) { - self.0 = i as u64; - } - - fn write_i8(&mut self, i: i8) { - self.0 = i as u64; - } - - fn write_i16(&mut self, i: i16) { - self.0 = i as u64; - } - - fn write_i32(&mut self, i: i32) { - self.0 = i as u64; - } - - fn write_i64(&mut self, i: i64) { - self.0 = i as u64; - } - - fn write_isize(&mut self, i: isize) { - self.0 = i as u64; - } -} diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index 5639aaf57cd97..24990d6a0e714 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs @@ -7,11 +7,11 @@ use std::process::Command; use std::{cmp::Ordering, ops, time::Instant}; mod macros; -pub mod hash; pub mod process; pub mod panic_context; pub mod non_empty_vec; pub mod rand; +pub mod thread; pub use always_assert::{always, never}; diff --git a/crates/stdx/src/thread.rs b/crates/stdx/src/thread.rs new file mode 100644 index 0000000000000..e577eb4313714 --- /dev/null +++ b/crates/stdx/src/thread.rs @@ -0,0 +1,102 @@ +//! A utility module for working with threads that automatically joins threads upon drop +//! and abstracts over operating system quality of service (QoS) APIs +//! through the concept of a “thread intent”. +//! +//! The intent of a thread is frozen at thread creation time, +//! i.e. there is no API to change the intent of a thread once it has been spawned. +//! +//! As a system, rust-analyzer should have the property that +//! old manual scheduling APIs are replaced entirely by QoS. +//! To maintain this invariant, we panic when it is clear that +//! old scheduling APIs have been used. +//! +//! Moreover, we also want to ensure that every thread has an intent set explicitly +//! to force a decision about its importance to the system. +//! Thus, [`ThreadIntent`] has no default value +//! and every entry point to creating a thread requires a [`ThreadIntent`] upfront. + +use std::fmt; + +mod intent; +mod pool; + +pub use intent::ThreadIntent; +pub use pool::Pool; + +pub fn spawn(intent: ThreadIntent, f: F) -> JoinHandle +where + F: FnOnce() -> T, + F: Send + 'static, + T: Send + 'static, +{ + Builder::new(intent).spawn(f).expect("failed to spawn thread") +} + +pub struct Builder { + intent: ThreadIntent, + inner: jod_thread::Builder, + allow_leak: bool, +} + +impl Builder { + pub fn new(intent: ThreadIntent) -> Builder { + Builder { intent, inner: jod_thread::Builder::new(), allow_leak: false } + } + + pub fn name(self, name: String) -> Builder { + Builder { inner: self.inner.name(name), ..self } + } + + pub fn stack_size(self, size: usize) -> Builder { + Builder { inner: self.inner.stack_size(size), ..self } + } + + pub fn allow_leak(self, b: bool) -> Builder { + Builder { allow_leak: b, ..self } + } + + pub fn spawn(self, f: F) -> std::io::Result> + where + F: FnOnce() -> T, + F: Send + 'static, + T: Send + 'static, + { + let inner_handle = self.inner.spawn(move || { + self.intent.apply_to_current_thread(); + f() + })?; + + Ok(JoinHandle { inner: Some(inner_handle), allow_leak: self.allow_leak }) + } +} + +pub struct JoinHandle { + // `inner` is an `Option` so that we can + // take ownership of the contained `JoinHandle`. + inner: Option>, + allow_leak: bool, +} + +impl JoinHandle { + pub fn join(mut self) -> T { + self.inner.take().unwrap().join() + } +} + +impl Drop for JoinHandle { + fn drop(&mut self) { + if !self.allow_leak { + return; + } + + if let Some(join_handle) = self.inner.take() { + join_handle.detach(); + } + } +} + +impl fmt::Debug for JoinHandle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("JoinHandle { .. }") + } +} diff --git a/crates/stdx/src/thread/intent.rs b/crates/stdx/src/thread/intent.rs new file mode 100644 index 0000000000000..7b65db30cc5b0 --- /dev/null +++ b/crates/stdx/src/thread/intent.rs @@ -0,0 +1,287 @@ +//! An opaque façade around platform-specific QoS APIs. + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +// Please maintain order from least to most priority for the derived `Ord` impl. +pub enum ThreadIntent { + /// Any thread which does work that isn’t in the critical path of the user typing + /// (e.g. processing Go To Definition). + Worker, + + /// Any thread which does work caused by the user typing + /// (e.g. processing syntax highlighting). + LatencySensitive, +} + +impl ThreadIntent { + // These APIs must remain private; + // we only want consumers to set thread intent + // either during thread creation or using our pool impl. + + pub(super) fn apply_to_current_thread(self) { + let class = thread_intent_to_qos_class(self); + set_current_thread_qos_class(class); + } + + pub(super) fn assert_is_used_on_current_thread(self) { + if IS_QOS_AVAILABLE { + let class = thread_intent_to_qos_class(self); + assert_eq!(get_current_thread_qos_class(), Some(class)); + } + } +} + +use imp::QoSClass; + +const IS_QOS_AVAILABLE: bool = imp::IS_QOS_AVAILABLE; + +fn set_current_thread_qos_class(class: QoSClass) { + imp::set_current_thread_qos_class(class) +} + +fn get_current_thread_qos_class() -> Option { + imp::get_current_thread_qos_class() +} + +fn thread_intent_to_qos_class(intent: ThreadIntent) -> QoSClass { + imp::thread_intent_to_qos_class(intent) +} + +// All Apple platforms use XNU as their kernel +// and thus have the concept of QoS. +#[cfg(target_vendor = "apple")] +mod imp { + use super::ThreadIntent; + + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] + // Please maintain order from least to most priority for the derived `Ord` impl. + pub(super) enum QoSClass { + // Documentation adapted from https://github.com/apple-oss-distributions/libpthread/blob/67e155c94093be9a204b69637d198eceff2c7c46/include/sys/qos.h#L55 + // + /// TLDR: invisible maintenance tasks + /// + /// Contract: + /// + /// * **You do not care about how long it takes for work to finish.** + /// * **You do not care about work being deferred temporarily.** + /// (e.g. if the device’s battery is in a critical state) + /// + /// Examples: + /// + /// * in a video editor: + /// creating periodic backups of project files + /// * in a browser: + /// cleaning up cached sites which have not been accessed in a long time + /// * in a collaborative word processor: + /// creating a searchable index of all documents + /// + /// Use this QoS class for background tasks + /// which the user did not initiate themselves + /// and which are invisible to the user. + /// It is expected that this work will take significant time to complete: + /// minutes or even hours. + /// + /// This QoS class provides the most energy and thermally-efficient execution possible. + /// All other work is prioritized over background tasks. + Background, + + /// TLDR: tasks that don’t block using your app + /// + /// Contract: + /// + /// * **Your app remains useful even as the task is executing.** + /// + /// Examples: + /// + /// * in a video editor: + /// exporting a video to disk – + /// the user can still work on the timeline + /// * in a browser: + /// automatically extracting a downloaded zip file – + /// the user can still switch tabs + /// * in a collaborative word processor: + /// downloading images embedded in a document – + /// the user can still make edits + /// + /// Use this QoS class for tasks which + /// may or may not be initiated by the user, + /// but whose result is visible. + /// It is expected that this work will take a few seconds to a few minutes. + /// Typically your app will include a progress bar + /// for tasks using this class. + /// + /// This QoS class provides a balance between + /// performance, responsiveness and efficiency. + Utility, + + /// TLDR: tasks that block using your app + /// + /// Contract: + /// + /// * **You need this work to complete + /// before the user can keep interacting with your app.** + /// * **Your work will not take more than a few seconds to complete.** + /// + /// Examples: + /// + /// * in a video editor: + /// opening a saved project + /// * in a browser: + /// loading a list of the user’s bookmarks and top sites + /// when a new tab is created + /// * in a collaborative word processor: + /// running a search on the document’s content + /// + /// Use this QoS class for tasks which were initiated by the user + /// and block the usage of your app while they are in progress. + /// It is expected that this work will take a few seconds or less to complete; + /// not long enough to cause the user to switch to something else. + /// Your app will likely indicate progress on these tasks + /// through the display of placeholder content or modals. + /// + /// This QoS class is not energy-efficient. + /// Rather, it provides responsiveness + /// by prioritizing work above other tasks on the system + /// except for critical user-interactive work. + UserInitiated, + + /// TLDR: render loops and nothing else + /// + /// Contract: + /// + /// * **You absolutely need this work to complete immediately + /// or your app will appear to freeze.** + /// * **Your work will always complete virtually instantaneously.** + /// + /// Examples: + /// + /// * the main thread in a GUI application + /// * the update & render loop in a game + /// * a secondary thread which progresses an animation + /// + /// Use this QoS class for any work which, if delayed, + /// will make your user interface unresponsive. + /// It is expected that this work will be virtually instantaneous. + /// + /// This QoS class is not energy-efficient. + /// Specifying this class is a request to run with + /// nearly all available system CPU and I/O bandwidth even under contention. + UserInteractive, + } + + pub(super) const IS_QOS_AVAILABLE: bool = true; + + pub(super) fn set_current_thread_qos_class(class: QoSClass) { + let c = match class { + QoSClass::UserInteractive => libc::qos_class_t::QOS_CLASS_USER_INTERACTIVE, + QoSClass::UserInitiated => libc::qos_class_t::QOS_CLASS_USER_INITIATED, + QoSClass::Utility => libc::qos_class_t::QOS_CLASS_UTILITY, + QoSClass::Background => libc::qos_class_t::QOS_CLASS_BACKGROUND, + }; + + let code = unsafe { libc::pthread_set_qos_class_self_np(c, 0) }; + + if code == 0 { + return; + } + + let errno = unsafe { *libc::__error() }; + + match errno { + libc::EPERM => { + // This thread has been excluded from the QoS system + // due to a previous call to a function such as `pthread_setschedparam` + // which is incompatible with QoS. + // + // Panic instead of returning an error + // to maintain the invariant that we only use QoS APIs. + panic!("tried to set QoS of thread which has opted out of QoS (os error {errno})") + } + + libc::EINVAL => { + // This is returned if we pass something other than a qos_class_t + // to `pthread_set_qos_class_self_np`. + // + // This is impossible, so again panic. + unreachable!( + "invalid qos_class_t value was passed to pthread_set_qos_class_self_np" + ) + } + + _ => { + // `pthread_set_qos_class_self_np`’s documentation + // does not mention any other errors. + unreachable!("`pthread_set_qos_class_self_np` returned unexpected error {errno}") + } + } + } + + pub(super) fn get_current_thread_qos_class() -> Option { + let current_thread = unsafe { libc::pthread_self() }; + let mut qos_class_raw = libc::qos_class_t::QOS_CLASS_UNSPECIFIED; + let code = unsafe { + libc::pthread_get_qos_class_np(current_thread, &mut qos_class_raw, std::ptr::null_mut()) + }; + + if code != 0 { + // `pthread_get_qos_class_np`’s documentation states that + // an error value is placed into errno if the return code is not zero. + // However, it never states what errors are possible. + // Inspecting the source[0] shows that, as of this writing, it always returns zero. + // + // Whatever errors the function could report in future are likely to be + // ones which we cannot handle anyway + // + // 0: https://github.com/apple-oss-distributions/libpthread/blob/67e155c94093be9a204b69637d198eceff2c7c46/src/qos.c#L171-L177 + let errno = unsafe { *libc::__error() }; + unreachable!("`pthread_get_qos_class_np` failed unexpectedly (os error {errno})"); + } + + match qos_class_raw { + libc::qos_class_t::QOS_CLASS_USER_INTERACTIVE => Some(QoSClass::UserInteractive), + libc::qos_class_t::QOS_CLASS_USER_INITIATED => Some(QoSClass::UserInitiated), + libc::qos_class_t::QOS_CLASS_DEFAULT => None, // QoS has never been set + libc::qos_class_t::QOS_CLASS_UTILITY => Some(QoSClass::Utility), + libc::qos_class_t::QOS_CLASS_BACKGROUND => Some(QoSClass::Background), + + libc::qos_class_t::QOS_CLASS_UNSPECIFIED => { + // Using manual scheduling APIs causes threads to “opt out” of QoS. + // At this point they become incompatible with QoS, + // and as such have the “unspecified” QoS class. + // + // Panic instead of returning an error + // to maintain the invariant that we only use QoS APIs. + panic!("tried to get QoS of thread which has opted out of QoS") + } + } + } + + pub(super) fn thread_intent_to_qos_class(intent: ThreadIntent) -> QoSClass { + match intent { + ThreadIntent::Worker => QoSClass::Utility, + ThreadIntent::LatencySensitive => QoSClass::UserInitiated, + } + } +} + +// FIXME: Windows has QoS APIs, we should use them! +#[cfg(not(target_vendor = "apple"))] +mod imp { + use super::ThreadIntent; + + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] + pub(super) enum QoSClass { + Default, + } + + pub(super) const IS_QOS_AVAILABLE: bool = false; + + pub(super) fn set_current_thread_qos_class(_: QoSClass) {} + + pub(super) fn get_current_thread_qos_class() -> Option { + None + } + + pub(super) fn thread_intent_to_qos_class(_: ThreadIntent) -> QoSClass { + QoSClass::Default + } +} diff --git a/crates/stdx/src/thread/pool.rs b/crates/stdx/src/thread/pool.rs new file mode 100644 index 0000000000000..2ddd7da74c291 --- /dev/null +++ b/crates/stdx/src/thread/pool.rs @@ -0,0 +1,92 @@ +//! [`Pool`] implements a basic custom thread pool +//! inspired by the [`threadpool` crate](http://docs.rs/threadpool). +//! When you spawn a task you specify a thread intent +//! so the pool can schedule it to run on a thread with that intent. +//! rust-analyzer uses this to prioritize work based on latency requirements. +//! +//! The thread pool is implemented entirely using +//! the threading utilities in [`crate::thread`]. + +use std::sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, +}; + +use crossbeam_channel::{Receiver, Sender}; + +use super::{Builder, JoinHandle, ThreadIntent}; + +pub struct Pool { + // `_handles` is never read: the field is present + // only for its `Drop` impl. + + // The worker threads exit once the channel closes; + // make sure to keep `job_sender` above `handles` + // so that the channel is actually closed + // before we join the worker threads! + job_sender: Sender, + _handles: Vec, + extant_tasks: Arc, +} + +struct Job { + requested_intent: ThreadIntent, + f: Box, +} + +impl Pool { + pub fn new(threads: usize) -> Pool { + const STACK_SIZE: usize = 8 * 1024 * 1024; + const INITIAL_INTENT: ThreadIntent = ThreadIntent::Worker; + + let (job_sender, job_receiver) = crossbeam_channel::unbounded(); + let extant_tasks = Arc::new(AtomicUsize::new(0)); + + let mut handles = Vec::with_capacity(threads); + for _ in 0..threads { + let handle = Builder::new(INITIAL_INTENT) + .stack_size(STACK_SIZE) + .name("Worker".into()) + .spawn({ + let extant_tasks = Arc::clone(&extant_tasks); + let job_receiver: Receiver = job_receiver.clone(); + move || { + let mut current_intent = INITIAL_INTENT; + for job in job_receiver { + if job.requested_intent != current_intent { + job.requested_intent.apply_to_current_thread(); + current_intent = job.requested_intent; + } + extant_tasks.fetch_add(1, Ordering::SeqCst); + (job.f)(); + extant_tasks.fetch_sub(1, Ordering::SeqCst); + } + } + }) + .expect("failed to spawn thread"); + + handles.push(handle); + } + + Pool { _handles: handles, extant_tasks, job_sender } + } + + pub fn spawn(&self, intent: ThreadIntent, f: F) + where + F: FnOnce() + Send + 'static, + { + let f = Box::new(move || { + if cfg!(debug_assertions) { + intent.assert_is_used_on_current_thread(); + } + f() + }); + + let job = Job { requested_intent: intent, f }; + self.job_sender.send(job).unwrap(); + } + + pub fn len(&self) -> usize { + self.extant_tasks.load(Ordering::SeqCst) + } +} diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 305cf2d394b44..fb38d25ab541e 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml @@ -16,12 +16,14 @@ doctest = false cov-mark = "2.0.0-pre.1" either = "1.7.0" itertools = "0.10.5" -rowan = "0.15.10" -rustc_lexer = { version = "727.0.0", package = "rustc-ap-rustc_lexer" } +rowan = "0.15.11" rustc-hash = "1.1.0" once_cell = "1.17.0" indexmap = "1.9.1" -smol_str = "0.1.23" +smol_str.workspace = true +triomphe.workspace = true + +rustc_lexer.workspace = true parser.workspace = true profile.workspace = true diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram index 548b5ba8b8b6d..4c9027dec68e9 100644 --- a/crates/syntax/rust.ungram +++ b/crates/syntax/rust.ungram @@ -51,7 +51,9 @@ TypeArg = Type AssocTypeArg = - NameRef GenericArgList? (':' TypeBoundList | ('=' Type | ConstArg)) + NameRef + (GenericArgList | ParamList RetType?)? + (':' TypeBoundList | ('=' Type | ConstArg)) LifetimeArg = Lifetime @@ -581,7 +583,7 @@ ImplTraitType = 'impl' TypeBoundList DynTraitType = - 'dyn' TypeBoundList + 'dyn'? TypeBoundList TypeBoundList = bounds:(TypeBound ('+' TypeBound)* '+'?) @@ -613,7 +615,7 @@ Pat = | ConstBlockPat LiteralPat = - Literal + '-'? Literal IdentPat = Attr* 'ref'? 'mut'? Name ('@' Pat)? diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index a493c92e7dae9..b3ea6ca8d46a1 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs @@ -236,6 +236,21 @@ impl ast::GenericParamList { } } + /// Removes the existing generic param + pub fn remove_generic_param(&self, generic_param: ast::GenericParam) { + if let Some(previous) = generic_param.syntax().prev_sibling() { + if let Some(next_token) = previous.next_sibling_or_token() { + ted::remove_all(next_token..=generic_param.syntax().clone().into()); + } + } else if let Some(next) = generic_param.syntax().next_sibling() { + if let Some(next_token) = next.prev_sibling_or_token() { + ted::remove_all(generic_param.syntax().clone().into()..=next_token); + } + } else { + ted::remove(generic_param.syntax()); + } + } + /// Constructs a matching [`ast::GenericArgList`] pub fn to_generic_args(&self) -> ast::GenericArgList { let args = self.generic_params().filter_map(|param| match param { @@ -465,6 +480,8 @@ impl ast::Impl { } impl ast::AssocItemList { + /// Attention! This function does align the first line of `item` with respect to `self`, + /// but it does _not_ change indentation of other lines (if any). pub fn add_item(&self, item: ast::AssocItem) { let (indent, position, whitespace) = match self.assoc_items().last() { Some(last_item) => ( diff --git a/crates/syntax/src/ast/expr_ext.rs b/crates/syntax/src/ast/expr_ext.rs index c43d0830b9e24..36980b146ef56 100644 --- a/crates/syntax/src/ast/expr_ext.rs +++ b/crates/syntax/src/ast/expr_ext.rs @@ -288,6 +288,7 @@ impl ast::ArrayExpr { pub enum LiteralKind { String(ast::String), ByteString(ast::ByteString), + CString(ast::CString), IntNumber(ast::IntNumber), FloatNumber(ast::FloatNumber), Char(ast::Char), @@ -319,6 +320,9 @@ impl ast::Literal { if let Some(t) = ast::ByteString::cast(token.clone()) { return LiteralKind::ByteString(t); } + if let Some(t) = ast::CString::cast(token.clone()) { + return LiteralKind::CString(t); + } if let Some(t) = ast::Char::cast(token.clone()) { return LiteralKind::Char(t); } @@ -366,8 +370,7 @@ impl ast::BlockExpr { match parent.kind() { FOR_EXPR | IF_EXPR => parent .children() - .filter(|it| ast::Expr::can_cast(it.kind())) - .next() + .find(|it| ast::Expr::can_cast(it.kind())) .map_or(true, |it| it == *self.syntax()), LET_ELSE | FN | WHILE_EXPR | LOOP_EXPR | CONST_BLOCK_PAT => false, _ => true, diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index fe324845360d7..61f6a04c98d38 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -121,6 +121,8 @@ impl ast::HasTypeBounds for AssocTypeArg {} impl AssocTypeArg { pub fn name_ref(&self) -> Option { support::child(&self.syntax) } pub fn generic_arg_list(&self) -> Option { support::child(&self.syntax) } + pub fn param_list(&self) -> Option { support::child(&self.syntax) } + pub fn ret_type(&self) -> Option { support::child(&self.syntax) } pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } pub fn ty(&self) -> Option { support::child(&self.syntax) } pub fn const_arg(&self) -> Option { support::child(&self.syntax) } @@ -1375,6 +1377,7 @@ pub struct LiteralPat { pub(crate) syntax: SyntaxNode, } impl LiteralPat { + pub fn minus_token(&self) -> Option { support::token(&self.syntax, T![-]) } pub fn literal(&self) -> Option { support::child(&self.syntax) } } diff --git a/crates/syntax/src/ast/generated/tokens.rs b/crates/syntax/src/ast/generated/tokens.rs index a3209c5abd23e..f5863e9efe0da 100644 --- a/crates/syntax/src/ast/generated/tokens.rs +++ b/crates/syntax/src/ast/generated/tokens.rs @@ -90,6 +90,27 @@ impl AstToken for ByteString { fn syntax(&self) -> &SyntaxToken { &self.syntax } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct CString { + pub(crate) syntax: SyntaxToken, +} +impl std::fmt::Display for CString { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(&self.syntax, f) + } +} +impl AstToken for CString { + fn can_cast(kind: SyntaxKind) -> bool { kind == C_STRING } + fn cast(syntax: SyntaxToken) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxToken { &self.syntax } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct IntNumber { pub(crate) syntax: SyntaxToken, diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 5aebe4cd9f53a..a07561e79a28b 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -158,34 +158,148 @@ fn ty_from_text(text: &str) -> ast::Type { ast_from_text(&format!("type _T = {text};")) } +pub fn ty_alias( + ident: &str, + generic_param_list: Option, + type_param_bounds: Option, + where_clause: Option, + assignment: Option<(ast::Type, Option)>, +) -> ast::TypeAlias { + let mut s = String::new(); + s.push_str(&format!("type {} ", ident)); + + if let Some(list) = generic_param_list { + s.push_str(&list.to_string()); + } + + if let Some(list) = type_param_bounds { + s.push_str(&format!(" : {}", &list)); + } + + if let Some(cl) = where_clause { + s.push_str(&format!(" {}", &cl.to_string())); + } + + if let Some(exp) = assignment { + if let Some(cl) = exp.1 { + s.push_str(&format!("= {} {}", &exp.0.to_string(), &cl.to_string())); + } else { + s.push_str(&format!("= {}", &exp.0.to_string())); + } + } + + s.push(';'); + ast_from_text(&s) +} + pub fn assoc_item_list() -> ast::AssocItemList { ast_from_text("impl C for D {}") } -// FIXME: `ty_params` should be `ast::GenericArgList` +fn merge_gen_params( + ps: Option, + bs: Option, +) -> Option { + match (ps, bs) { + (None, None) => None, + (None, Some(bs)) => Some(bs), + (Some(ps), None) => Some(ps), + (Some(ps), Some(bs)) => { + for b in bs.generic_params() { + ps.add_generic_param(b); + } + Some(ps) + } + } +} + pub fn impl_( - ty: ast::Path, - params: Option, - ty_params: Option, + generic_params: Option, + generic_args: Option, + path_type: ast::Type, + where_clause: Option, + body: Option>>, ) -> ast::Impl { - let params = match params { - Some(params) => params.to_string(), - None => String::new(), + let (gen_params, tr_gen_args) = match (generic_params, generic_args) { + (None, None) => (String::new(), String::new()), + (None, Some(args)) => (String::new(), args.to_generic_args().to_string()), + (Some(params), None) => (params.to_string(), params.to_generic_args().to_string()), + (Some(params), Some(args)) => match merge_gen_params(Some(params.clone()), Some(args)) { + Some(merged) => (params.to_string(), merged.to_generic_args().to_string()), + None => (params.to_string(), String::new()), + }, }; - let ty_params = match ty_params { - Some(params) => params.to_string(), + + let where_clause = match where_clause { + Some(pr) => pr.to_string(), + None => " ".to_string(), + }; + + let body = match body { + Some(bd) => bd.iter().map(|elem| elem.to_string()).join(""), None => String::new(), }; - ast_from_text(&format!("impl{params} {ty}{ty_params} {{}}")) + + ast_from_text(&format!("impl{gen_params} {path_type}{tr_gen_args}{where_clause}{{{}}}", body)) } +// FIXME : We must make *_gen_args' type ast::GenericArgList but in order to do so we must implement in `edit_in_place.rs` +// `add_generic_arg()` just like `add_generic_param()` +// is implemented for `ast::GenericParamList` pub fn impl_trait( - trait_: ast::Path, - ty: ast::Path, - ty_params: Option, + is_unsafe: bool, + trait_gen_params: Option, + trait_gen_args: Option, + type_gen_params: Option, + type_gen_args: Option, + is_negative: bool, + path_type: ast::Type, + ty: ast::Type, + trait_where_clause: Option, + ty_where_clause: Option, + body: Option>>, ) -> ast::Impl { - let ty_params = ty_params.map_or_else(String::new, |params| params.to_string()); - ast_from_text(&format!("impl{ty_params} {trait_} for {ty}{ty_params} {{}}")) + let is_unsafe = if is_unsafe { "unsafe " } else { "" }; + let ty_gen_args = match merge_gen_params(type_gen_params.clone(), type_gen_args) { + Some(pars) => pars.to_generic_args().to_string(), + None => String::new(), + }; + + let tr_gen_args = match merge_gen_params(trait_gen_params.clone(), trait_gen_args) { + Some(pars) => pars.to_generic_args().to_string(), + None => String::new(), + }; + + let gen_params = match merge_gen_params(trait_gen_params, type_gen_params) { + Some(pars) => pars.to_string(), + None => String::new(), + }; + + let is_negative = if is_negative { "! " } else { "" }; + + let where_clause = match (ty_where_clause, trait_where_clause) { + (None, None) => " ".to_string(), + (None, Some(tr)) => format!("\n{}\n", tr).to_string(), + (Some(ty), None) => format!("\n{}\n", ty).to_string(), + (Some(ty), Some(tr)) => { + let updated = ty.clone_for_update(); + tr.predicates().for_each(|p| { + ty.add_predicate(p); + }); + format!("\n{}\n", updated).to_string() + } + }; + + let body = match body { + Some(bd) => bd.iter().map(|elem| elem.to_string()).join(""), + None => String::new(), + }; + + ast_from_text(&format!("{is_unsafe}impl{gen_params} {is_negative}{path_type}{tr_gen_args} for {ty}{ty_gen_args}{where_clause}{{{}}}" , body)) +} + +pub fn impl_trait_type(bounds: ast::TypeBoundList) -> ast::ImplTraitType { + ast_from_text(&format!("fn f(x: impl {bounds}) {{}}")) } pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment { @@ -355,7 +469,7 @@ pub fn hacky_block_expr( format_to!(buf, " {t}\n") } else if kind == SyntaxKind::WHITESPACE { let content = t.text().trim_matches(|c| c != '\n'); - if content.len() >= 1 { + if !content.is_empty() { format_to!(buf, "{}", &content[1..]) } } @@ -827,6 +941,8 @@ pub fn fn_( body: ast::BlockExpr, ret_type: Option, is_async: bool, + is_const: bool, + is_unsafe: bool, ) -> ast::Fn { let type_params = match type_params { Some(type_params) => format!("{type_params}"), @@ -846,12 +962,13 @@ pub fn fn_( }; let async_literal = if is_async { "async " } else { "" }; + let const_literal = if is_const { "const " } else { "" }; + let unsafe_literal = if is_unsafe { "unsafe " } else { "" }; ast_from_text(&format!( - "{visibility}{async_literal}fn {fn_name}{type_params}{params} {ret_type}{where_clause}{body}", + "{visibility}{async_literal}{const_literal}{unsafe_literal}fn {fn_name}{type_params}{params} {ret_type}{where_clause}{body}", )) } - pub fn struct_( visibility: Option, strukt_name: ast::Name, @@ -901,7 +1018,7 @@ pub mod tokens { pub(super) static SOURCE_FILE: Lazy> = Lazy::new(|| { SourceFile::parse( - "const C: <()>::Item = (1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p)\n;\n\n", + "const C: <()>::Item = (1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p, &p , &mut p)\n;\n\n", ) }); diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index 2cd312e7f4f8c..090eb89f47040 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs @@ -145,6 +145,10 @@ impl QuoteOffsets { } pub trait IsString: AstToken { + const RAW_PREFIX: &'static str; + fn is_raw(&self) -> bool { + self.text().starts_with(Self::RAW_PREFIX) + } fn quote_offsets(&self) -> Option { let text = self.text(); let offsets = QuoteOffsets::new(text)?; @@ -183,20 +187,18 @@ pub trait IsString: AstToken { cb(text_range + offset, unescaped_char); }); } -} - -impl IsString for ast::String {} - -impl ast::String { - pub fn is_raw(&self) -> bool { - self.text().starts_with('r') - } - pub fn map_range_up(&self, range: TextRange) -> Option { + fn map_range_up(&self, range: TextRange) -> Option { let contents_range = self.text_range_between_quotes()?; assert!(TextRange::up_to(contents_range.len()).contains_range(range)); Some(range + contents_range.start()) } +} +impl IsString for ast::String { + const RAW_PREFIX: &'static str = "r"; +} + +impl ast::String { pub fn value(&self) -> Option> { if self.is_raw() { let text = self.text(); @@ -235,13 +237,11 @@ impl ast::String { } } -impl IsString for ast::ByteString {} +impl IsString for ast::ByteString { + const RAW_PREFIX: &'static str = "br"; +} impl ast::ByteString { - pub fn is_raw(&self) -> bool { - self.text().starts_with("br") - } - pub fn value(&self) -> Option> { if self.is_raw() { let text = self.text(); @@ -280,6 +280,49 @@ impl ast::ByteString { } } +impl IsString for ast::CString { + const RAW_PREFIX: &'static str = "cr"; +} + +impl ast::CString { + pub fn value(&self) -> Option> { + if self.is_raw() { + let text = self.text(); + let text = + &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; + return Some(Cow::Borrowed(text)); + } + + let text = self.text(); + let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; + + let mut buf = String::new(); + let mut prev_end = 0; + let mut has_error = false; + unescape_literal(text, Mode::Str, &mut |char_range, unescaped_char| match ( + unescaped_char, + buf.capacity() == 0, + ) { + (Ok(c), false) => buf.push(c), + (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => { + prev_end = char_range.end + } + (Ok(c), true) => { + buf.reserve_exact(text.len()); + buf.push_str(&text[..prev_end]); + buf.push(c); + } + (Err(_), _) => has_error = true, + }); + + match (has_error, buf.capacity() == 0) { + (true, _) => None, + (false, true) => Some(Cow::Borrowed(text)), + (false, false) => Some(Cow::Owned(buf)), + } + } +} + impl ast::IntNumber { pub fn radix(&self) -> Radix { match self.text().get(..2).unwrap_or_default() { diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index 6f57cbad66b16..efbf87966448a 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -43,10 +43,11 @@ pub mod utils; pub mod ted; pub mod hacks; -use std::{marker::PhantomData, sync::Arc}; +use std::marker::PhantomData; use stdx::format_to; use text_edit::Indel; +use triomphe::Arc; pub use crate::{ ast::{AstNode, AstToken}, diff --git a/crates/syntax/src/parsing/reparsing.rs b/crates/syntax/src/parsing/reparsing.rs index 701e6232d5898..45e5916098282 100644 --- a/crates/syntax/src/parsing/reparsing.rs +++ b/crates/syntax/src/parsing/reparsing.rs @@ -39,7 +39,7 @@ fn reparse_token( let prev_token = root.covering_element(edit.delete).as_token()?.clone(); let prev_token_kind = prev_token.kind(); match prev_token_kind { - WHITESPACE | COMMENT | IDENT | STRING => { + WHITESPACE | COMMENT | IDENT | STRING | BYTE_STRING | C_STRING => { if prev_token_kind == WHITESPACE || prev_token_kind == COMMENT { // removing a new line may extends previous token let deleted_range = edit.delete - prev_token.text_range().start(); @@ -166,8 +166,8 @@ fn merge_errors( } res.extend(new_errors.into_iter().map(|new_err| { // fighting borrow checker with a variable ;) - let offseted_range = new_err.range() + range_before_reparse.start(); - new_err.with_range(offseted_range) + let offsetted_range = new_err.range() + range_before_reparse.start(); + new_err.with_range(offsetted_range) })); res } @@ -408,7 +408,7 @@ enum Foo { #[test] fn reparse_str_token_with_error_fixed() { - do_check(r#""unterinated$0$0"#, "\"", 12); + do_check(r#""unterminated$0$0"#, "\"", 13); } #[test] diff --git a/crates/syntax/src/tests/ast_src.rs b/crates/syntax/src/tests/ast_src.rs index ccce71966ff88..c5783b91a0fdb 100644 --- a/crates/syntax/src/tests/ast_src.rs +++ b/crates/syntax/src/tests/ast_src.rs @@ -71,7 +71,7 @@ pub(crate) const KINDS_SRC: KindsSrc<'_> = KindsSrc { "super", "trait", "true", "try", "type", "unsafe", "use", "where", "while", "yield", ], contextual_keywords: &["auto", "default", "existential", "union", "raw", "macro_rules", "yeet"], - literals: &["INT_NUMBER", "FLOAT_NUMBER", "CHAR", "BYTE", "STRING", "BYTE_STRING"], + literals: &["INT_NUMBER", "FLOAT_NUMBER", "CHAR", "BYTE", "STRING", "BYTE_STRING", "C_STRING"], tokens: &["ERROR", "IDENT", "WHITESPACE", "LIFETIME_IDENT", "COMMENT", "SHEBANG"], nodes: &[ "SOURCE_FILE", @@ -199,6 +199,7 @@ pub(crate) const KINDS_SRC: KindsSrc<'_> = KindsSrc { "GENERIC_PARAM", "LIFETIME_PARAM", "TYPE_PARAM", + "RETURN_TYPE_ARG", "CONST_PARAM", "GENERIC_ARG_LIST", "LIFETIME", diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs index e954b58251faa..c49c5fa108b62 100644 --- a/crates/syntax/src/tests/sourcegen_ast.rs +++ b/crates/syntax/src/tests/sourcegen_ast.rs @@ -535,6 +535,7 @@ impl Field { "!" => "excl", "*" => "star", "&" => "amp", + "-" => "minus", "_" => "underscore", "." => "dot", ".." => "dotdot", @@ -572,10 +573,11 @@ impl Field { fn lower(grammar: &Grammar) -> AstSrc { let mut res = AstSrc { - tokens: "Whitespace Comment String ByteString IntNumber FloatNumber Char Byte Ident" - .split_ascii_whitespace() - .map(|it| it.to_string()) - .collect::>(), + tokens: + "Whitespace Comment String ByteString CString IntNumber FloatNumber Char Byte Ident" + .split_ascii_whitespace() + .map(|it| it.to_string()) + .collect::>(), ..Default::default() }; diff --git a/crates/syntax/src/token_text.rs b/crates/syntax/src/token_text.rs index 913b24d42bcfd..09c080c0c2301 100644 --- a/crates/syntax/src/token_text.rs +++ b/crates/syntax/src/token_text.rs @@ -3,6 +3,7 @@ use std::{cmp::Ordering, fmt, ops}; use rowan::GreenToken; +use smol_str::SmolStr; pub struct TokenText<'a>(pub(crate) Repr<'a>); @@ -47,6 +48,12 @@ impl From> for String { } } +impl From> for SmolStr { + fn from(token_text: TokenText<'_>) -> Self { + SmolStr::new(token_text.as_str()) + } +} + impl PartialEq<&'_ str> for TokenText<'_> { fn eq(&self, other: &&str) -> bool { self.as_str() == *other diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs index fb2381110bfe2..e0ec6a242ffa7 100644 --- a/crates/syntax/src/validation.rs +++ b/crates/syntax/src/validation.rs @@ -5,11 +5,11 @@ mod block; use rowan::Direction; -use rustc_lexer::unescape::{self, unescape_byte, unescape_char, unescape_literal, Mode}; +use rustc_lexer::unescape::{self, unescape_literal, Mode}; use crate::{ algo, - ast::{self, HasAttrs, HasVisibility}, + ast::{self, HasAttrs, HasVisibility, IsString}, match_ast, AstNode, SyntaxError, SyntaxKind::{CONST, FN, INT_NUMBER, TYPE_ALIAS}, SyntaxNode, SyntaxToken, TextSize, T, @@ -44,7 +44,7 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec { errors } -fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> &'static str { +fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> (&'static str, bool) { use unescape::EscapeError as EE; #[rustfmt::skip] @@ -103,12 +103,15 @@ fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> &'static str { EE::UnicodeEscapeInByte => { "Byte literals must not contain unicode escapes" } - EE::NonAsciiCharInByte | EE::NonAsciiCharInByteString => { + EE::NonAsciiCharInByte => { "Byte literals must not contain non-ASCII characters" } + EE::UnskippedWhitespaceWarning => "Whitespace after this escape is not skipped", + EE::MultipleSkippedLinesWarning => "Multiple lines are skipped by this escape", + }; - err_message + (err_message, err.is_fatal()) } fn validate_literal(literal: ast::Literal, acc: &mut Vec) { @@ -121,9 +124,13 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec) { let text = token.text(); // FIXME: lift this lambda refactor to `fn` (https://github.com/rust-lang/rust-analyzer/pull/2834#discussion_r366199205) - let mut push_err = |prefix_len, (off, err): (usize, unescape::EscapeError)| { + let mut push_err = |prefix_len, off, err: unescape::EscapeError| { let off = token.text_range().start() + TextSize::try_from(off + prefix_len).unwrap(); - acc.push(SyntaxError::new_at_offset(rustc_unescape_error_to_string(err), off)); + let (message, is_err) = rustc_unescape_error_to_string(err); + // FIXME: Emit lexer warnings + if is_err { + acc.push(SyntaxError::new_at_offset(message, off)); + } }; match literal.kind() { @@ -132,7 +139,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec) { if let Some(without_quotes) = unquote(text, 1, '"') { unescape_literal(without_quotes, Mode::Str, &mut |range, char| { if let Err(err) = char { - push_err(1, (range.start, err)); + push_err(1, range.start, err); } }); } @@ -143,20 +150,39 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec) { if let Some(without_quotes) = unquote(text, 2, '"') { unescape_literal(without_quotes, Mode::ByteStr, &mut |range, char| { if let Err(err) = char { - push_err(2, (range.start, err)); + push_err(1, range.start, err); + } + }); + } + } + } + ast::LiteralKind::CString(s) => { + if !s.is_raw() { + if let Some(without_quotes) = unquote(text, 2, '"') { + unescape_literal(without_quotes, Mode::ByteStr, &mut |range, char| { + if let Err(err) = char { + push_err(1, range.start, err); } }); } } } ast::LiteralKind::Char(_) => { - if let Some(Err(e)) = unquote(text, 1, '\'').map(unescape_char) { - push_err(1, e); + if let Some(without_quotes) = unquote(text, 1, '\'') { + unescape_literal(without_quotes, Mode::Char, &mut |range, char| { + if let Err(err) = char { + push_err(1, range.start, err); + } + }); } } ast::LiteralKind::Byte(_) => { - if let Some(Err(e)) = unquote(text, 2, '\'').map(unescape_byte) { - push_err(2, e); + if let Some(without_quotes) = unquote(text, 2, '\'') { + unescape_literal(without_quotes, Mode::Byte, &mut |range, char| { + if let Err(err) = char { + push_err(2, range.start, err); + } + }); } } ast::LiteralKind::IntNumber(_) @@ -175,14 +201,14 @@ pub(crate) fn validate_block_structure(root: &SyntaxNode) { assert_eq!( node.parent(), pair.parent(), - "\nunpaired curlys:\n{}\n{:#?}\n", + "\nunpaired curlies:\n{}\n{:#?}\n", root.text(), root, ); assert!( node.next_sibling_or_token().is_none() && pair.prev_sibling_or_token().is_none(), - "\nfloating curlys at {:?}\nfile:\n{}\nerror:\n{}\n", + "\nfloating curlies at {:?}\nfile:\n{}\nerror:\n{}\n", node, root.text(), node, diff --git a/crates/syntax/test_data/parser/fuzz-failures/0000.rs b/crates/syntax/test_data/parser/fuzz-failures/0000.rs index f977d23c48090..13852aa78b84f 100644 --- a/crates/syntax/test_data/parser/fuzz-failures/0000.rs +++ b/crates/syntax/test_data/parser/fuzz-failures/0000.rs @@ -39,13 +39,13 @@ ast::Root::cast(self.syntax()).unwrap() } pub fn syntax(&self) -> SyntaxNodeRef { - self.root.brroowed() + self.root.borrowed() } mp_tree(root), ); assert!( node.next_sibling().is_none() && pair.prev_sibling().is_none(), - "\nfloating curlys at {:?}\nfile:\n{}\nerror:\n{}\n", + "\nfloating curlies at {:?}\nfile:\n{}\nerror:\n{}\n", node, root.text(), node.text(), diff --git a/crates/test-utils/Cargo.toml b/crates/test-utils/Cargo.toml index 92b1ef23e69ce..2b5b6f4956166 100644 --- a/crates/test-utils/Cargo.toml +++ b/crates/test-utils/Cargo.toml @@ -14,7 +14,7 @@ doctest = false [dependencies] # Avoid adding deps here, this crate is widely used in tests it should compile fast! dissimilar = "1.0.4" -text-size = "1.1.0" +text-size.workspace = true rustc-hash = "1.1.0" stdx.workspace = true diff --git a/crates/test-utils/src/fixture.rs b/crates/test-utils/src/fixture.rs index cd1235fa6dc4e..05f32f8e51ea4 100644 --- a/crates/test-utils/src/fixture.rs +++ b/crates/test-utils/src/fixture.rs @@ -86,7 +86,14 @@ pub struct MiniCore { valid_flags: Vec, } -impl Fixture { +pub struct FixtureWithProjectMeta { + pub fixture: Vec, + pub mini_core: Option, + pub proc_macro_names: Vec, + pub toolchain: Option, +} + +impl FixtureWithProjectMeta { /// Parses text which looks like this: /// /// ```not_rust @@ -96,37 +103,41 @@ impl Fixture { /// //- other meta /// ``` /// - /// Fixture can also start with a proc_macros and minicore declaration(in that order): + /// Fixture can also start with a proc_macros and minicore declaration (in that order): /// /// ``` + /// //- toolchain: nightly /// //- proc_macros: identity /// //- minicore: sized /// ``` /// - /// That will include predefined proc macros and a subset of `libcore` into the fixture, see - /// `minicore.rs` for what's available. - pub fn parse(ra_fixture: &str) -> (Option, Vec, Vec) { + /// That will set toolchain to nightly and include predefined proc macros and a subset of + /// `libcore` into the fixture, see `minicore.rs` for what's available. Note that toolchain + /// defaults to stable. + pub fn parse(ra_fixture: &str) -> Self { let fixture = trim_indent(ra_fixture); let mut fixture = fixture.as_str(); + let mut toolchain = None; let mut mini_core = None; let mut res: Vec = Vec::new(); - let mut test_proc_macros = vec![]; - - if fixture.starts_with("//- proc_macros:") { - let first_line = fixture.split_inclusive('\n').next().unwrap(); - test_proc_macros = first_line - .strip_prefix("//- proc_macros:") - .unwrap() - .split(',') - .map(|it| it.trim().to_string()) - .collect(); - fixture = &fixture[first_line.len()..]; + let mut proc_macro_names = vec![]; + + if let Some(meta) = fixture.strip_prefix("//- toolchain:") { + let (meta, remain) = meta.split_once('\n').unwrap(); + toolchain = Some(meta.trim().to_string()); + fixture = remain; + } + + if let Some(meta) = fixture.strip_prefix("//- proc_macros:") { + let (meta, remain) = meta.split_once('\n').unwrap(); + proc_macro_names = meta.split(',').map(|it| it.trim().to_string()).collect(); + fixture = remain; } - if fixture.starts_with("//- minicore:") { - let first_line = fixture.split_inclusive('\n').next().unwrap(); - mini_core = Some(MiniCore::parse(first_line)); - fixture = &fixture[first_line.len()..]; + if let Some(meta) = fixture.strip_prefix("//- minicore:") { + let (meta, remain) = meta.split_once('\n').unwrap(); + mini_core = Some(MiniCore::parse(meta)); + fixture = remain; } let default = if fixture.contains("//-") { None } else { Some("//- /main.rs") }; @@ -142,7 +153,7 @@ impl Fixture { } if line.starts_with("//-") { - let meta = Fixture::parse_meta_line(line); + let meta = Self::parse_meta_line(line); res.push(meta); } else { if line.starts_with("// ") @@ -160,7 +171,7 @@ impl Fixture { } } - (mini_core, test_proc_macros, res) + Self { fixture: res, mini_core, proc_macro_names, toolchain } } //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo @@ -243,10 +254,19 @@ impl Fixture { } impl MiniCore { + const RAW_SOURCE: &str = include_str!("./minicore.rs"); + fn has_flag(&self, flag: &str) -> bool { self.activated_flags.iter().any(|it| it == flag) } + pub fn from_flags<'a>(flags: impl IntoIterator) -> Self { + MiniCore { + activated_flags: flags.into_iter().map(|x| x.to_owned()).collect(), + valid_flags: Vec::new(), + } + } + #[track_caller] fn assert_valid_flag(&self, flag: &str) { if !self.valid_flags.iter().any(|it| it == flag) { @@ -257,8 +277,7 @@ impl MiniCore { fn parse(line: &str) -> MiniCore { let mut res = MiniCore { activated_flags: Vec::new(), valid_flags: Vec::new() }; - let line = line.strip_prefix("//- minicore:").unwrap().trim(); - for entry in line.split(", ") { + for entry in line.trim().split(", ") { if res.has_flag(entry) { panic!("duplicate minicore flag: {entry:?}"); } @@ -268,13 +287,21 @@ impl MiniCore { res } + pub fn available_flags() -> impl Iterator { + let lines = MiniCore::RAW_SOURCE.split_inclusive('\n'); + lines + .map_while(|x| x.strip_prefix("//!")) + .skip_while(|line| !line.contains("Available flags:")) + .skip(1) + .map(|x| x.split_once(':').unwrap().0.trim()) + } + /// Strips parts of minicore.rs which are flagged by inactive flags. /// /// This is probably over-engineered to support flags dependencies. pub fn source_code(mut self) -> String { let mut buf = String::new(); - let raw_mini_core = include_str!("./minicore.rs"); - let mut lines = raw_mini_core.split_inclusive('\n'); + let mut lines = MiniCore::RAW_SOURCE.split_inclusive('\n'); let mut implications = Vec::new(); @@ -372,7 +399,7 @@ impl MiniCore { #[test] #[should_panic] fn parse_fixture_checks_further_indented_metadata() { - Fixture::parse( + FixtureWithProjectMeta::parse( r" //- /lib.rs mod bar; @@ -386,15 +413,18 @@ fn parse_fixture_checks_further_indented_metadata() { #[test] fn parse_fixture_gets_full_meta() { - let (mini_core, proc_macros, parsed) = Fixture::parse( - r#" + let FixtureWithProjectMeta { fixture: parsed, mini_core, proc_macro_names, toolchain } = + FixtureWithProjectMeta::parse( + r#" +//- toolchain: nightly //- proc_macros: identity //- minicore: coerce_unsized //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b,atom env:OUTDIR=path/to,OTHER=foo mod m; "#, - ); - assert_eq!(proc_macros, vec!["identity".to_string()]); + ); + assert_eq!(toolchain, Some("nightly".to_string())); + assert_eq!(proc_macro_names, vec!["identity".to_string()]); assert_eq!(mini_core.unwrap().activated_flags, vec!["coerce_unsized".to_string()]); assert_eq!(1, parsed.len()); diff --git a/crates/test-utils/src/lib.rs b/crates/test-utils/src/lib.rs index a7a52e08e75a8..fd3e68e2d2c63 100644 --- a/crates/test-utils/src/lib.rs +++ b/crates/test-utils/src/lib.rs @@ -27,7 +27,7 @@ pub use rustc_hash::FxHashMap; pub use crate::{ assert_linear::AssertLinear, - fixture::{Fixture, MiniCore}, + fixture::{Fixture, FixtureWithProjectMeta, MiniCore}, }; pub const CURSOR_MARKER: &str = "$0"; @@ -95,7 +95,7 @@ fn try_extract_range(text: &str) -> Option<(TextRange, String)> { Some((TextRange::new(start, end), text)) } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum RangeOrOffset { Range(TextRange), Offset(TextSize), diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index ca6de4061a4b8..c79b4e966d67e 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -11,6 +11,8 @@ //! add: //! as_ref: sized //! bool_impl: option, fn +//! builtin_impls: +//! cell: copy, drop //! clone: sized //! coerce_unsized: unsize //! copy: clone @@ -21,19 +23,23 @@ //! drop: //! eq: sized //! error: fmt -//! fmt: result +//! fmt: result, transmute, coerce_unsized //! fn: //! from: sized //! future: pin //! generator: pin //! hash: +//! include: //! index: sized //! infallible: //! iterator: option //! iterators: iterator, fn +//! manually_drop: drop //! non_zero: -//! option: +//! option: panic //! ord: eq, option +//! panic: fmt +//! phantom_data: //! pin: //! range: //! result: @@ -41,6 +47,7 @@ //! sized: //! slice: //! sync: sized +//! transmute: //! try: infallible //! unsize: sized @@ -106,6 +113,7 @@ pub mod marker { impl Copy for *const T {} impl Copy for *mut T {} impl Copy for &T {} + impl Copy for ! {} } // endregion:copy @@ -113,6 +121,11 @@ pub mod marker { #[lang = "tuple_trait"] pub trait Tuple {} // endregion:fn + + // region:phantom_data + #[lang = "phantom_data"] + pub struct PhantomData; + // endregion:phantom_data } // region:default @@ -124,6 +137,27 @@ pub mod default { #[rustc_builtin_macro(Default, attributes(default))] pub macro Default($item:item) {} // endregion:derive + + // region:builtin_impls + macro_rules! impl_default { + ($v:literal; $($t:ty)*) => { + $( + impl const Default for $t { + fn default() -> Self { + $v + } + } + )* + } + } + + impl_default! { + 0; usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 + } + impl_default! { + 0.0; f32 f64 + } + // endregion:builtin_impls } // endregion:default @@ -134,15 +168,100 @@ pub mod hash { pub trait Hash { fn hash(&self, state: &mut H); } + + // region:derive + #[rustc_builtin_macro] + pub macro Hash($item:item) {} + // endregion:derive } // endregion:hash +// region:cell +pub mod cell { + use crate::mem; + + #[lang = "unsafe_cell"] + pub struct UnsafeCell { + value: T, + } + + impl UnsafeCell { + pub const fn new(value: T) -> UnsafeCell { + UnsafeCell { value } + } + + pub const fn get(&self) -> *mut T { + self as *const UnsafeCell as *const T as *mut T + } + } + + pub struct Cell { + value: UnsafeCell, + } + + impl Cell { + pub const fn new(value: T) -> Cell { + Cell { value: UnsafeCell::new(value) } + } + + pub fn set(&self, val: T) { + let old = self.replace(val); + mem::drop(old); + } + + pub fn replace(&self, val: T) -> T { + mem::replace(unsafe { &mut *self.value.get() }, val) + } + } + + impl Cell { + pub fn get(&self) -> T { + unsafe { *self.value.get() } + } + } +} +// endregion:cell + // region:clone pub mod clone { #[lang = "clone"] pub trait Clone: Sized { fn clone(&self) -> Self; } + + impl Clone for &T { + fn clone(&self) -> Self { + *self + } + } + + // region:builtin_impls + macro_rules! impl_clone { + ($($t:ty)*) => { + $( + impl const Clone for $t { + fn clone(&self) -> Self { + *self + } + } + )* + } + } + + impl_clone! { + usize u8 u16 u32 u64 u128 + isize i8 i16 i32 i64 i128 + f32 f64 + bool char + } + + impl Clone for ! { + fn clone(&self) { + *self + } + } + // endregion:builtin_impls + // region:derive #[rustc_builtin_macro] pub macro Clone($item:item) {} @@ -181,10 +300,68 @@ pub mod convert { } // endregion:as_ref // region:infallible - pub enum Infallibe {} + pub enum Infallible {} // endregion:infallible } +pub mod mem { + // region:drop + // region:manually_drop + #[lang = "manually_drop"] + #[repr(transparent)] + pub struct ManuallyDrop { + value: T, + } + + impl ManuallyDrop { + pub const fn new(value: T) -> ManuallyDrop { + ManuallyDrop { value } + } + } + + // region:deref + impl crate::ops::Deref for ManuallyDrop { + type Target = T; + fn deref(&self) -> &T { + &self.value + } + } + // endregion:deref + + // endregion:manually_drop + + pub fn drop(_x: T) {} + pub const fn replace(dest: &mut T, src: T) -> T { + unsafe { + let result = crate::ptr::read(dest); + crate::ptr::write(dest, src); + result + } + } + // endregion:drop + + // region:transmute + extern "rust-intrinsic" { + pub fn transmute(src: Src) -> Dst; + } + // endregion:transmute +} + +pub mod ptr { + // region:drop + #[lang = "drop_in_place"] + pub unsafe fn drop_in_place(to_drop: *mut T) { + unsafe { drop_in_place(to_drop) } + } + pub const unsafe fn read(src: *const T) -> T { + *src + } + pub const unsafe fn write(dst: *mut T, src: T) { + *dst = src; + } + // endregion:drop +} + pub mod ops { // region:coerce_unsized mod unsize { @@ -309,12 +486,6 @@ pub mod ops { pub use self::index::{Index, IndexMut}; // endregion:index - // region:drop - pub mod mem { - pub fn drop(_x: T) {} - } - // endregion:drop - // region:range mod range { #[lang = "RangeFull"] @@ -375,16 +546,82 @@ pub mod ops { type Output; extern "rust-call" fn call_once(self, args: Args) -> Self::Output; } + + mod impls { + use crate::marker::Tuple; + + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl const Fn
for &F + where + F: ~const Fn, + { + extern "rust-call" fn call(&self, args: A) -> F::Output { + (**self).call(args) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl const FnMut for &F + where + F: ~const Fn, + { + extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { + (**self).call(args) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl const FnOnce for &F + where + F: ~const Fn, + { + type Output = F::Output; + + extern "rust-call" fn call_once(self, args: A) -> F::Output { + (*self).call(args) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl const FnMut for &mut F + where + F: ~const FnMut, + { + extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { + (*self).call_mut(args) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl const FnOnce for &mut F + where + F: ~const FnMut, + { + type Output = F::Output; + extern "rust-call" fn call_once(self, args: A) -> F::Output { + (*self).call_mut(args) + } + } + } } pub use self::function::{Fn, FnMut, FnOnce}; // endregion:fn // region:try mod try_ { + use super::super::convert::Infallible; + pub enum ControlFlow { + #[lang = "Continue"] Continue(C), + #[lang = "Break"] Break(B), } - pub trait FromResidual { + pub trait FromResidual::Residual> { #[lang = "from_residual"] fn from_residual(residual: R) -> Self; } @@ -400,14 +637,80 @@ pub mod ops { impl Try for ControlFlow { type Output = C; - type Residual = ControlFlow; - fn from_output(output: Self::Output) -> Self {} - fn branch(self) -> ControlFlow {} + type Residual = ControlFlow; + fn from_output(output: Self::Output) -> Self { + ControlFlow::Continue(output) + } + fn branch(self) -> ControlFlow { + match self { + ControlFlow::Continue(x) => ControlFlow::Continue(x), + ControlFlow::Break(x) => ControlFlow::Break(ControlFlow::Break(x)), + } + } } impl FromResidual for ControlFlow { - fn from_residual(residual: ControlFlow) -> Self {} + fn from_residual(residual: ControlFlow) -> Self { + match residual { + ControlFlow::Break(b) => ControlFlow::Break(b), + ControlFlow::Continue(_) => loop {}, + } + } + } + // region:option + impl Try for Option { + type Output = T; + type Residual = Option; + fn from_output(output: Self::Output) -> Self { + Some(output) + } + fn branch(self) -> ControlFlow { + match self { + Some(x) => ControlFlow::Continue(x), + None => ControlFlow::Break(None), + } + } + } + + impl FromResidual for Option { + fn from_residual(x: Option) -> Self { + match x { + None => None, + Some(_) => loop {}, + } + } + } + // endregion:option + // region:result + // region:from + use super::super::convert::From; + + impl Try for Result { + type Output = T; + type Residual = Result; + + fn from_output(output: Self::Output) -> Self { + Ok(output) + } + + fn branch(self) -> ControlFlow { + match self { + Ok(v) => ControlFlow::Continue(v), + Err(e) => ControlFlow::Break(Err(e)), + } + } } + + impl> FromResidual> for Result { + fn from_residual(residual: Result) -> Self { + match residual { + Err(e) => Err(From::from(e)), + Ok(_) => loop {}, + } + } + } + // endregion:from + // endregion:result } pub use self::try_::{ControlFlow, FromResidual, Try}; // endregion:try @@ -424,6 +727,19 @@ pub mod ops { pub trait AddAssign { fn add_assign(&mut self, rhs: Rhs); } + + // region:builtin_impls + macro_rules! add_impl { + ($($t:ty)*) => ($( + impl const Add for $t { + type Output = $t; + fn add(self, other: $t) -> $t { self + other } + } + )*) + } + + add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } + // endregion:builtin_impls // endregion:add // region:generator @@ -499,12 +815,114 @@ pub mod fmt { pub struct Error; pub type Result = Result<(), Error>; pub struct Formatter<'a>; + pub struct DebugTuple; + pub struct DebugStruct; + impl Formatter<'_> { + pub fn debug_tuple(&mut self, name: &str) -> DebugTuple { + DebugTuple + } + + pub fn debug_struct(&mut self, name: &str) -> DebugStruct { + DebugStruct + } + } + + impl DebugTuple { + pub fn field(&mut self, value: &dyn Debug) -> &mut Self { + self + } + + pub fn finish(&mut self) -> Result { + Ok(()) + } + } + + impl DebugStruct { + pub fn field(&mut self, name: &str, value: &dyn Debug) -> &mut Self { + self + } + + pub fn finish(&mut self) -> Result { + Ok(()) + } + } + pub trait Debug { fn fmt(&self, f: &mut Formatter<'_>) -> Result; } pub trait Display { fn fmt(&self, f: &mut Formatter<'_>) -> Result; } + + extern "C" { + type Opaque; + } + + #[lang = "format_argument"] + pub struct ArgumentV1<'a> { + value: &'a Opaque, + formatter: fn(&Opaque, &mut Formatter<'_>) -> Result, + } + + impl<'a> ArgumentV1<'a> { + pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> ArgumentV1<'b> { + use crate::mem::transmute; + unsafe { ArgumentV1 { formatter: transmute(f), value: transmute(x) } } + } + } + + #[lang = "format_arguments"] + pub struct Arguments<'a> { + pieces: &'a [&'static str], + args: &'a [ArgumentV1<'a>], + } + + impl<'a> Arguments<'a> { + pub const fn new_v1( + pieces: &'a [&'static str], + args: &'a [ArgumentV1<'a>], + ) -> Arguments<'a> { + Arguments { pieces, args } + } + } + + // region:derive + #[rustc_builtin_macro] + pub macro Debug($item:item) {} + // endregion:derive + + // region:builtin_impls + macro_rules! impl_debug { + ($($t:ty)*) => { + $( + impl const Debug for $t { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + Ok(()) + } + } + )* + } + } + + impl_debug! { + usize u8 u16 u32 u64 u128 + isize i8 i16 i32 i64 i128 + f32 f64 + bool char + } + + impl Debug for [T] { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + Ok(()) + } + } + + impl Debug for &T { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + (&**self).fmt(f) + } + } + // endregion:builtin_impls } // endregion:fmt @@ -537,12 +955,30 @@ pub mod option { } } + pub const fn as_ref(&self) -> Option<&T> { + match self { + Some(x) => Some(x), + None => None, + } + } + pub fn and(self, optb: Option) -> Option { loop {} } pub fn unwrap_or(self, default: T) -> T { - loop {} + match self { + Some(val) => val, + None => default, + } } + // region:result + pub const fn ok_or(self, err: E) -> Result { + match self { + Some(v) => Ok(v), + None => Err(err), + } + } + // endregion:result // region:fn pub fn and_then(self, f: F) -> Option where @@ -713,8 +1149,6 @@ pub mod iter { mod traits { mod iterator { - use super::super::Take; - pub trait Iterator { type Item; #[lang = "next"] @@ -764,12 +1198,19 @@ pub mod iter { self } } - pub struct IntoIter([T; N]); + struct IndexRange { + start: usize, + end: usize, + } + pub struct IntoIter { + data: [T; N], + range: IndexRange, + } impl IntoIterator for [T; N] { type Item = T; type IntoIter = IntoIter; fn into_iter(self) -> I { - IntoIter(self) + IntoIter { data: self, range: IndexRange { start: 0, end: loop {} } } } } impl Iterator for IntoIter { @@ -785,16 +1226,64 @@ pub mod iter { } // endregion:iterator -// region:derive +// region:panic +mod panic { + pub macro panic_2021 { + ($($t:tt)+) => ( + $crate::panicking::panic_fmt($crate::const_format_args!($($t)+)) + ), + } +} + +mod panicking { + #[lang = "panic_fmt"] + pub const fn panic_fmt(fmt: crate::fmt::Arguments<'_>) -> ! { + loop {} + } +} +// endregion:panic + mod macros { + // region:panic + #[macro_export] + #[rustc_builtin_macro(std_panic)] + macro_rules! panic { + ($($arg:tt)*) => { + /* compiler built-in */ + }; + } + + pub(crate) use panic; + // endregion:panic + + // region:fmt + #[macro_export] + #[rustc_builtin_macro] + macro_rules! const_format_args { + ($fmt:expr) => {{ /* compiler built-in */ }}; + ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }}; + } + + pub(crate) use const_format_args; + // endregion:fmt + + // region:derive pub(crate) mod builtin { #[rustc_builtin_macro] pub macro derive($item:item) { /* compiler built-in */ } } + // endregion:derive + + // region:include + #[rustc_builtin_macro] + #[macro_export] + macro_rules! include { + ($file:expr $(,)?) => {{ /* compiler built-in */ }}; + } + // endregion:include } -// endregion:derive // region:non_zero pub mod num { @@ -848,6 +1337,7 @@ pub mod prelude { ops::Drop, // :drop ops::{Fn, FnMut, FnOnce}, // :fn option::Option::{self, None, Some}, // :option + panic, // :panic result::Result::{self, Err, Ok}, // :result }; } diff --git a/crates/text-edit/Cargo.toml b/crates/text-edit/Cargo.toml index 337cd234739c8..76d0ca5ccb601 100644 --- a/crates/text-edit/Cargo.toml +++ b/crates/text-edit/Cargo.toml @@ -13,4 +13,4 @@ doctest = false [dependencies] itertools = "0.10.5" -text-size = "1.1.0" +text-size.workspace = true diff --git a/crates/text-edit/src/lib.rs b/crates/text-edit/src/lib.rs index 9bb4271b65f7f..4705d18187af8 100644 --- a/crates/text-edit/src/lib.rs +++ b/crates/text-edit/src/lib.rs @@ -176,6 +176,7 @@ impl TextEditBuilder { pub fn finish(self) -> TextEdit { let mut indels = self.indels; assert_disjoint_or_equal(&mut indels); + indels = coalesce_indels(indels); TextEdit { indels } } pub fn invalidates_offset(&self, offset: TextSize) -> bool { @@ -205,6 +206,21 @@ where indels.clone().zip(indels.skip(1)).all(|(l, r)| l.delete.end() <= r.delete.start() || l == r) } +fn coalesce_indels(indels: Vec) -> Vec { + indels + .into_iter() + .coalesce(|mut a, b| { + if a.delete.end() == b.delete.start() { + a.insert.push_str(&b.insert); + a.delete = TextRange::new(a.delete.start(), b.delete.end()); + Ok(a) + } else { + Err((a, b)) + } + }) + .collect_vec() +} + #[cfg(test)] mod tests { use super::{TextEdit, TextEditBuilder, TextRange}; @@ -261,4 +277,40 @@ mod tests { let edit2 = TextEdit::delete(range(9, 13)); assert!(edit1.union(edit2).is_err()); } + + #[test] + fn test_coalesce_disjoint() { + let mut builder = TextEditBuilder::default(); + builder.replace(range(1, 3), "aa".into()); + builder.replace(range(5, 7), "bb".into()); + let edit = builder.finish(); + + assert_eq!(edit.indels.len(), 2); + } + + #[test] + fn test_coalesce_adjacent() { + let mut builder = TextEditBuilder::default(); + builder.replace(range(1, 3), "aa".into()); + builder.replace(range(3, 5), "bb".into()); + + let edit = builder.finish(); + assert_eq!(edit.indels.len(), 1); + assert_eq!(edit.indels[0].insert, "aabb"); + assert_eq!(edit.indels[0].delete, range(1, 5)); + } + + #[test] + fn test_coalesce_adjacent_series() { + let mut builder = TextEditBuilder::default(); + builder.replace(range(1, 3), "au".into()); + builder.replace(range(3, 5), "www".into()); + builder.replace(range(5, 8), "".into()); + builder.replace(range(8, 9), "ub".into()); + + let edit = builder.finish(); + assert_eq!(edit.indels.len(), 1); + assert_eq!(edit.indels[0].insert, "auwwwub"); + assert_eq!(edit.indels[0].delete, range(1, 9)); + } } diff --git a/crates/tt/Cargo.toml b/crates/tt/Cargo.toml index b8469383183b6..a28ee5f1ca2bb 100644 --- a/crates/tt/Cargo.toml +++ b/crates/tt/Cargo.toml @@ -12,6 +12,6 @@ rust-version.workspace = true doctest = false [dependencies] -smol_str = "0.1.23" +smol_str.workspace = true stdx.workspace = true diff --git a/crates/tt/src/lib.rs b/crates/tt/src/lib.rs index b7dbc82e1d66e..c2ebf03746a87 100644 --- a/crates/tt/src/lib.rs +++ b/crates/tt/src/lib.rs @@ -153,6 +153,12 @@ pub struct Ident { pub span: Span, } +impl Ident { + pub fn new(text: impl Into, span: S) -> Self { + Ident { text: text.into(), span } + } +} + fn print_debug_subtree( f: &mut fmt::Formatter<'_>, subtree: &Subtree, diff --git a/crates/vfs-notify/Cargo.toml b/crates/vfs-notify/Cargo.toml index e06b98d8118b6..5d61a227284ed 100644 --- a/crates/vfs-notify/Cargo.toml +++ b/crates/vfs-notify/Cargo.toml @@ -13,10 +13,10 @@ doctest = false [dependencies] tracing = "0.1.35" -jod-thread = "0.1.2" walkdir = "2.3.2" crossbeam-channel = "0.5.5" notify = "5.0" +stdx.workspace = true vfs.workspace = true paths.workspace = true diff --git a/crates/vfs-notify/src/lib.rs b/crates/vfs-notify/src/lib.rs index c95304e55ac10..abfc51dfec66f 100644 --- a/crates/vfs-notify/src/lib.rs +++ b/crates/vfs-notify/src/lib.rs @@ -21,7 +21,7 @@ use walkdir::WalkDir; pub struct NotifyHandle { // Relative order of fields below is significant. sender: Sender, - _thread: jod_thread::JoinHandle, + _thread: stdx::thread::JoinHandle, } #[derive(Debug)] @@ -34,7 +34,7 @@ impl loader::Handle for NotifyHandle { fn spawn(sender: loader::Sender) -> NotifyHandle { let actor = NotifyActor::new(sender); let (sender, receiver) = unbounded::(); - let thread = jod_thread::Builder::new() + let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) .name("VfsLoader".to_owned()) .spawn(move || actor.run(receiver)) .expect("failed to spawn thread"); diff --git a/crates/vfs/Cargo.toml b/crates/vfs/Cargo.toml index 802a300060fa1..3ae3dc83ca9b3 100644 --- a/crates/vfs/Cargo.toml +++ b/crates/vfs/Cargo.toml @@ -15,6 +15,7 @@ doctest = false rustc-hash = "1.1.0" fst = "0.4.7" indexmap = "1.9.1" +nohash-hasher.workspace = true paths.workspace = true stdx.workspace = true diff --git a/crates/vfs/src/file_set.rs b/crates/vfs/src/file_set.rs index 700aebe0b34f1..0392ef3cebe96 100644 --- a/crates/vfs/src/file_set.rs +++ b/crates/vfs/src/file_set.rs @@ -5,8 +5,8 @@ use std::fmt; use fst::{IntoStreamer, Streamer}; +use nohash_hasher::IntMap; use rustc_hash::FxHashMap; -use stdx::hash::NoHashHashMap; use crate::{AnchoredPath, FileId, Vfs, VfsPath}; @@ -14,7 +14,7 @@ use crate::{AnchoredPath, FileId, Vfs, VfsPath}; #[derive(Default, Clone, Eq, PartialEq)] pub struct FileSet { files: FxHashMap, - paths: NoHashHashMap, + paths: IntMap, } impl FileSet { diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs index 14972d2907416..fe3dfe6196864 100644 --- a/crates/vfs/src/lib.rs +++ b/crates/vfs/src/lib.rs @@ -62,7 +62,8 @@ pub use paths::{AbsPath, AbsPathBuf}; #[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct FileId(pub u32); -impl stdx::hash::NoHashHashable for FileId {} +/// safe because `FileId` is a newtype of `u32` +impl nohash_hasher::IsEnabled for FileId {} /// Storage for all files read by rust-analyzer. /// @@ -108,13 +109,6 @@ pub enum ChangeKind { } impl Vfs { - /// Amount of files currently stored. - /// - /// Note that this includes deleted files. - pub fn len(&self) -> usize { - self.data.len() - } - /// Id of the given path if it exists in the `Vfs` and is not deleted. pub fn file_id(&self, path: &VfsPath) -> Option { self.interner.get(path).filter(|&it| self.get(it).is_some()) @@ -139,6 +133,11 @@ impl Vfs { self.get(file_id).as_deref().unwrap() } + /// Returns the overall memory usage for the stored files. + pub fn memory_usage(&self) -> usize { + self.data.iter().flatten().map(|d| d.capacity()).sum() + } + /// Returns an iterator over the stored ids and their corresponding paths. /// /// This will skip deleted files. @@ -158,16 +157,18 @@ impl Vfs { /// /// If the path does not currently exists in the `Vfs`, allocates a new /// [`FileId`] for it. - pub fn set_file_contents(&mut self, path: VfsPath, contents: Option>) -> bool { + pub fn set_file_contents(&mut self, path: VfsPath, mut contents: Option>) -> bool { let file_id = self.alloc_file_id(path); - let change_kind = match (&self.get(file_id), &contents) { + let change_kind = match (self.get(file_id), &contents) { (None, None) => return false, (Some(old), Some(new)) if old == new => return false, (None, Some(_)) => ChangeKind::Create, (Some(_), None) => ChangeKind::Delete, (Some(_), Some(_)) => ChangeKind::Modify, }; - + if let Some(contents) = &mut contents { + contents.shrink_to_fit(); + } *self.get_mut(file_id) = contents; self.changes.push(ChangedFile { file_id, change_kind }); true diff --git a/crates/vfs/src/vfs_path.rs b/crates/vfs/src/vfs_path.rs index 38501a8ba5a34..d327f2edf1444 100644 --- a/crates/vfs/src/vfs_path.rs +++ b/crates/vfs/src/vfs_path.rs @@ -107,10 +107,7 @@ impl VfsPath { /// Returns `self`'s base name and file extension. pub fn name_and_extension(&self) -> Option<(&str, Option<&str>)> { match &self.0 { - VfsPathRepr::PathBuf(p) => Some(( - p.file_stem()?.to_str()?, - p.extension().and_then(|extension| extension.to_str()), - )), + VfsPathRepr::PathBuf(p) => p.name_and_extension(), VfsPathRepr::VirtualPath(p) => p.name_and_extension(), } } diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index de1422032088f..bc58aa7220dc0 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@ [^\n]+\n/m, ""); } - let value; - if (errorCode) { - if (typeof diag.code === "string" || typeof diag.code === "number") { - value = diag.code; - } else { - value = diag.code?.value; - } - } diag.code = { target: vscode.Uri.from({ scheme: diagnostics.URI_SCHEME, @@ -153,7 +210,8 @@ export async function createClient( fragment: uri.toString(), query: idx.toString(), }), - value: value ?? "Click for full compiler diagnostic", + value: + errorCode && value ? value : "Click for full compiler diagnostic", }; } }); @@ -308,6 +366,7 @@ export async function createClient( // To turn on all proposed features use: client.registerProposedFeatures(); client.registerFeature(new ExperimentalFeatures()); + client.registerFeature(new OverrideFeatures()); return client; } @@ -343,6 +402,25 @@ class ExperimentalFeatures implements lc.StaticFeature { dispose(): void {} } +class OverrideFeatures implements lc.StaticFeature { + getState(): lc.FeatureState { + return { kind: "static" }; + } + fillClientCapabilities(capabilities: lc.ClientCapabilities): void { + // Force disable `augmentsSyntaxTokens`, VSCode's textmate grammar is somewhat incomplete + // making the experience generally worse + const caps = capabilities.textDocument?.semanticTokens; + if (caps) { + caps.augmentsSyntaxTokens = false; + } + } + initialize( + _capabilities: lc.ServerCapabilities, + _documentSelector: lc.DocumentSelector | undefined + ): void {} + dispose(): void {} +} + function isCodeActionWithoutEditsAndCommands(value: any): boolean { const candidate: lc.CodeAction = value; return ( diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 8a953577e99d3..98ccd50dc0406 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -8,10 +8,18 @@ import { applySnippetWorkspaceEdit, applySnippetTextEdits } from "./snippets"; import { spawnSync } from "child_process"; import { RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run"; import { AstInspector } from "./ast_inspector"; -import { isRustDocument, isCargoTomlDocument, sleep, isRustEditor } from "./util"; +import { + isRustDocument, + isCargoTomlDocument, + sleep, + isRustEditor, + RustEditor, + RustDocument, +} from "./util"; import { startDebugSession, makeDebugConfig } from "./debug"; import { LanguageClient } from "vscode-languageclient/node"; import { LINKED_COMMANDS } from "./client"; +import { DependencyId } from "./dependencies_provider"; export * from "./ast_inspector"; export * from "./run"; @@ -89,7 +97,13 @@ export function shuffleCrateGraph(ctx: CtxInit): Cmd { export function triggerParameterHints(_: CtxInit): Cmd { return async () => { - await vscode.commands.executeCommand("editor.action.triggerParameterHints"); + const parameterHintsEnabled = vscode.workspace + .getConfiguration("editor") + .get("parameterHints.enabled"); + + if (parameterHintsEnabled) { + await vscode.commands.executeCommand("editor.action.triggerParameterHints"); + } }; } @@ -260,6 +274,71 @@ export function openCargoToml(ctx: CtxInit): Cmd { }; } +export function revealDependency(ctx: CtxInit): Cmd { + return async (editor: RustEditor) => { + if (!ctx.dependencies?.isInitialized()) { + return; + } + const documentPath = editor.document.uri.fsPath; + const dep = ctx.dependencies?.getDependency(documentPath); + if (dep) { + await ctx.treeView?.reveal(dep, { select: true, expand: true }); + } else { + await revealParentChain(editor.document, ctx); + } + }; +} + +/** + * This function calculates the parent chain of a given file until it reaches it crate root contained in ctx.dependencies. + * This is need because the TreeView is Lazy, so at first it only has the root dependencies: For example if we have the following crates: + * - core + * - alloc + * - std + * + * if I want to reveal alloc/src/str.rs, I have to: + + * 1. reveal every children of alloc + * - core + * - alloc\ + *  |-beches\ + *  |-src\ + *  |- ... + * - std + * 2. reveal every children of src: + * core + * alloc\ + *  |-beches\ + *  |-src\ + *   |- lib.rs\ + *   |- str.rs <------- FOUND IT!\ + *   |- ...\ + *  |- ...\ + * std + */ +async function revealParentChain(document: RustDocument, ctx: CtxInit) { + let documentPath = document.uri.fsPath; + const maxDepth = documentPath.split(path.sep).length - 1; + const parentChain: DependencyId[] = [{ id: documentPath.toLowerCase() }]; + do { + documentPath = path.dirname(documentPath); + parentChain.push({ id: documentPath.toLowerCase() }); + if (parentChain.length >= maxDepth) { + // this is an odd case that can happen when we change a crate version but we'd still have + // a open file referencing the old version + return; + } + } while (!ctx.dependencies?.contains(documentPath)); + parentChain.reverse(); + for (const idx in parentChain) { + await ctx.treeView?.reveal(parentChain[idx], { select: true, expand: true }); + } +} + +export async function execRevealDependency(e: RustEditor): Promise { + await vscode.commands.executeCommand("rust-analyzer.revealDependency", e); +} + export function ssr(ctx: CtxInit): Cmd { return async () => { const editor = vscode.window.activeTextEditor; @@ -416,8 +495,20 @@ export function syntaxTree(ctx: CtxInit): Cmd { function viewHirOrMir(ctx: CtxInit, xir: "hir" | "mir"): Cmd { const viewXir = xir === "hir" ? "viewHir" : "viewMir"; const requestType = xir === "hir" ? ra.viewHir : ra.viewMir; + const uri = `rust-analyzer-${xir}://${viewXir}/${xir}.rs`; + const scheme = `rust-analyzer-${xir}`; + return viewFileUsingTextDocumentContentProvider(ctx, requestType, uri, scheme, true); +} + +function viewFileUsingTextDocumentContentProvider( + ctx: CtxInit, + requestType: lc.RequestType, + uri: string, + scheme: string, + shouldUpdate: boolean +): Cmd { const tdcp = new (class implements vscode.TextDocumentContentProvider { - readonly uri = vscode.Uri.parse(`rust-analyzer-${xir}://${viewXir}/${xir}.rs`); + readonly uri = vscode.Uri.parse(uri); readonly eventEmitter = new vscode.EventEmitter(); constructor() { vscode.workspace.onDidChangeTextDocument( @@ -433,14 +524,14 @@ function viewHirOrMir(ctx: CtxInit, xir: "hir" | "mir"): Cmd { } private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { - if (isRustDocument(event.document)) { + if (isRustDocument(event.document) && shouldUpdate) { // We need to order this after language server updates, but there's no API for that. // Hence, good old sleep(). void sleep(10).then(() => this.eventEmitter.fire(this.uri)); } } private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) { - if (editor && isRustEditor(editor)) { + if (editor && isRustEditor(editor) && shouldUpdate) { this.eventEmitter.fire(this.uri); } } @@ -467,9 +558,7 @@ function viewHirOrMir(ctx: CtxInit, xir: "hir" | "mir"): Cmd { } })(); - ctx.pushExtCleanup( - vscode.workspace.registerTextDocumentContentProvider(`rust-analyzer-${xir}`, tdcp) - ); + ctx.pushExtCleanup(vscode.workspace.registerTextDocumentContentProvider(scheme, tdcp)); return async () => { const document = await vscode.workspace.openTextDocument(tdcp.uri); @@ -495,6 +584,20 @@ export function viewMir(ctx: CtxInit): Cmd { return viewHirOrMir(ctx, "mir"); } +// Opens the virtual file that will show the MIR of the function containing the cursor position +// +// The contents of the file come from the `TextDocumentContentProvider` +export function interpretFunction(ctx: CtxInit): Cmd { + const uri = `rust-analyzer-interpret-function://interpretFunction/result.log`; + return viewFileUsingTextDocumentContentProvider( + ctx, + ra.interpretFunction, + uri, + `rust-analyzer-interpret-function`, + false + ); +} + export function viewFileText(ctx: CtxInit): Cmd { const tdcp = new (class implements vscode.TextDocumentContentProvider { readonly uri = vscode.Uri.parse("rust-analyzer-file-text://viewFileText/file.rs"); @@ -663,21 +766,26 @@ function crateGraph(ctx: CtxInit, full: boolean): Cmd { - +
`; @@ -699,7 +807,7 @@ export function viewFullCrateGraph(ctx: CtxInit): Cmd { // The contents of the file come from the `TextDocumentContentProvider` export function expandMacro(ctx: CtxInit): Cmd { function codeFormat(expanded: ra.ExpandedMacro): string { - let result = `// Recursive expansion of ${expanded.name}! macro\n`; + let result = `// Recursive expansion of ${expanded.name} macro\n`; result += "// " + "=".repeat(result.length - 3); result += "\n\n"; result += expanded.expansion; @@ -749,6 +857,10 @@ export function reloadWorkspace(ctx: CtxInit): Cmd { return async () => ctx.client.sendRequest(ra.reloadWorkspace); } +export function rebuildProcMacros(ctx: CtxInit): Cmd { + return async () => ctx.client.sendRequest(ra.rebuildProcMacros); +} + export function addProject(ctx: CtxInit): Cmd { return async () => { const discoverProjectCommand = ctx.config.discoverProjectCommand; @@ -757,12 +869,13 @@ export function addProject(ctx: CtxInit): Cmd { } const workspaces: JsonProject[] = await Promise.all( - vscode.workspace.workspaceFolders!.map(async (folder): Promise => { - const rustDocuments = vscode.workspace.textDocuments.filter(isRustDocument); - return discoverWorkspace(rustDocuments, discoverProjectCommand, { - cwd: folder.uri.fsPath, - }); - }) + vscode.workspace.textDocuments + .filter(isRustDocument) + .map(async (file): Promise => { + return discoverWorkspace([file], discoverProjectCommand, { + cwd: path.dirname(file.uri.fsPath), + }); + }) ); ctx.addToDiscoveredWorkspaces(workspaces); diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index da7c74c28bae9..c6d2bcc2b2a97 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -21,7 +21,6 @@ export class Config { "serverPath", "server", "files", - "lens", // works as lens.* ].map((opt) => `${this.rootSection}.${opt}`); readonly package: { @@ -70,7 +69,7 @@ export class Config { if (!requiresReloadOpt) return; if (this.restartServerOnConfigChange) { - await vscode.commands.executeCommand("rust-analyzer.reload"); + await vscode.commands.executeCommand("rust-analyzer.restartServer"); return; } @@ -78,7 +77,7 @@ export class Config { const userResponse = await vscode.window.showInformationMessage(message, "Restart now"); if (userResponse) { - const command = "rust-analyzer.reload"; + const command = "rust-analyzer.restartServer"; await vscode.commands.executeCommand(command); } } @@ -285,6 +284,10 @@ export class Config { get useRustcErrorCode() { return this.get("diagnostics.useRustcErrorCode"); } + + get showDependenciesExplorer() { + return this.get("showDependenciesExplorer"); + } } // the optional `cb?` parameter is meant to be used to add additional diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index c2dca733df8f5..a72b5391ff130 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -1,11 +1,13 @@ import * as vscode from "vscode"; import * as lc from "vscode-languageclient/node"; import * as ra from "./lsp_ext"; +import * as path from "path"; import { Config, prepareVSCodeConfig } from "./config"; import { createClient } from "./client"; import { executeDiscoverProject, + isDocumentInWorkspace, isRustDocument, isRustEditor, LazyOutputChannel, @@ -13,6 +15,13 @@ import { RustEditor, } from "./util"; import { ServerStatusParams } from "./lsp_ext"; +import { + Dependency, + DependencyFile, + RustDependenciesProvider, + DependencyId, +} from "./dependencies_provider"; +import { execRevealDependency } from "./commands"; import { PersistentState } from "./persistent_state"; import { bootstrap } from "./bootstrap"; import { ExecOptions } from "child_process"; @@ -82,11 +91,22 @@ export class Ctx { private state: PersistentState; private commandFactories: Record; private commandDisposables: Disposable[]; + private unlinkedFiles: vscode.Uri[]; + private _dependencies: RustDependenciesProvider | undefined; + private _treeView: vscode.TreeView | undefined; get client() { return this._client; } + get treeView() { + return this._treeView; + } + + get dependencies() { + return this._dependencies; + } + constructor( readonly extCtx: vscode.ExtensionContext, commandFactories: Record, @@ -94,12 +114,11 @@ export class Ctx { ) { extCtx.subscriptions.push(this); this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); - this.statusBar.show(); this.workspace = workspace; this.clientSubscriptions = []; this.commandDisposables = []; this.commandFactories = commandFactories; - + this.unlinkedFiles = []; this.state = new PersistentState(extCtx.globalState); this.config = new Config(extCtx); @@ -191,12 +210,13 @@ export class Ctx { const discoverProjectCommand = this.config.discoverProjectCommand; if (discoverProjectCommand) { const workspaces: JsonProject[] = await Promise.all( - vscode.workspace.workspaceFolders!.map(async (folder): Promise => { - const rustDocuments = vscode.workspace.textDocuments.filter(isRustDocument); - return discoverWorkspace(rustDocuments, discoverProjectCommand, { - cwd: folder.uri.fsPath, - }); - }) + vscode.workspace.textDocuments + .filter(isRustDocument) + .map(async (file): Promise => { + return discoverWorkspace([file], discoverProjectCommand, { + cwd: path.dirname(file.uri.fsPath), + }); + }) ); this.addToDiscoveredWorkspaces(workspaces); @@ -218,7 +238,8 @@ export class Ctx { this.outputChannel, initializationOptions, serverOptions, - this.config + this.config, + this.unlinkedFiles ); this.pushClientCleanup( this._client.onNotification(ra.serverStatus, (params) => @@ -242,6 +263,56 @@ export class Ctx { } await client.start(); this.updateCommands(); + + if (this.config.showDependenciesExplorer) { + this.prepareTreeDependenciesView(client); + } + } + + private prepareTreeDependenciesView(client: lc.LanguageClient) { + const ctxInit: CtxInit = { + ...this, + client: client, + }; + this._dependencies = new RustDependenciesProvider(ctxInit); + this._treeView = vscode.window.createTreeView("rustDependencies", { + treeDataProvider: this._dependencies, + showCollapseAll: true, + }); + + this.pushExtCleanup(this._treeView); + vscode.window.onDidChangeActiveTextEditor(async (e) => { + // we should skip documents that belong to the current workspace + if (this.shouldRevealDependency(e)) { + try { + await execRevealDependency(e); + } catch (reason) { + await vscode.window.showErrorMessage(`Dependency error: ${reason}`); + } + } + }); + + this.treeView?.onDidChangeVisibility(async (e) => { + if (e.visible) { + const activeEditor = vscode.window.activeTextEditor; + if (this.shouldRevealDependency(activeEditor)) { + try { + await execRevealDependency(activeEditor); + } catch (reason) { + await vscode.window.showErrorMessage(`Dependency error: ${reason}`); + } + } + } + }); + } + + private shouldRevealDependency(e: vscode.TextEditor | undefined): e is RustEditor { + return ( + e !== undefined && + isRustEditor(e) && + !isDocumentInWorkspace(e.document) && + (this.treeView?.visible || false) + ); } async restart() { @@ -335,6 +406,7 @@ export class Ctx { setServerStatus(status: ServerStatusParams | { health: "stopped" }) { let icon = ""; const statusBar = this.statusBar; + statusBar.show(); statusBar.tooltip = new vscode.MarkdownString("", true); statusBar.tooltip.isTrusted = true; switch (status.health) { @@ -343,6 +415,7 @@ export class Ctx { statusBar.color = undefined; statusBar.backgroundColor = undefined; statusBar.command = "rust-analyzer.stopServer"; + this.dependencies?.refresh(); break; case "warning": if (status.message) { @@ -378,12 +451,17 @@ export class Ctx { if (statusBar.tooltip.value) { statusBar.tooltip.appendText("\n\n"); } + statusBar.tooltip.appendMarkdown("\n\n[Open logs](command:rust-analyzer.openLogs)"); statusBar.tooltip.appendMarkdown( "\n\n[Reload Workspace](command:rust-analyzer.reloadWorkspace)" ); - statusBar.tooltip.appendMarkdown("\n\n[Open logs](command:rust-analyzer.openLogs)"); - statusBar.tooltip.appendMarkdown("\n\n[Restart server](command:rust-analyzer.startServer)"); - statusBar.tooltip.appendMarkdown("[Stop server](command:rust-analyzer.stopServer)"); + statusBar.tooltip.appendMarkdown( + "\n\n[Rebuild Proc Macros](command:rust-analyzer.rebuildProcMacros)" + ); + statusBar.tooltip.appendMarkdown( + "\n\n[Restart server](command:rust-analyzer.restartServer)" + ); + statusBar.tooltip.appendMarkdown("\n\n[Stop server](command:rust-analyzer.stopServer)"); if (!status.quiescent) icon = "$(sync~spin) "; statusBar.text = `${icon}rust-analyzer`; } @@ -400,4 +478,5 @@ export class Ctx { export interface Disposable { dispose(): void; } + export type Cmd = (...args: any[]) => unknown; diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts index 268b70b4fbbc7..cffee1de6af7b 100644 --- a/editors/code/src/debug.ts +++ b/editors/code/src/debug.ts @@ -118,8 +118,8 @@ async function getDebugConfiguration( return path.normalize(p).replace(wsFolder, "${workspaceFolder" + workspaceQualifier + "}"); } - const executable = await getDebugExecutable(runnable); const env = prepareEnv(runnable, ctx.config.runnableEnv); + const executable = await getDebugExecutable(runnable, env); let sourceFileMap = debugOptions.sourceFileMap; if (sourceFileMap === "auto") { // let's try to use the default toolchain @@ -156,8 +156,11 @@ async function getDebugConfiguration( return debugConfig; } -async function getDebugExecutable(runnable: ra.Runnable): Promise { - const cargo = new Cargo(runnable.args.workspaceRoot || ".", debugOutput); +async function getDebugExecutable( + runnable: ra.Runnable, + env: Record +): Promise { + const cargo = new Cargo(runnable.args.workspaceRoot || ".", debugOutput, env); const executable = await cargo.executableFromArgs(runnable.args.cargoArgs); // if we are here, there were no compilation errors. diff --git a/editors/code/src/dependencies_provider.ts b/editors/code/src/dependencies_provider.ts new file mode 100644 index 0000000000000..8900aa9a5f35f --- /dev/null +++ b/editors/code/src/dependencies_provider.ts @@ -0,0 +1,148 @@ +import * as vscode from "vscode"; +import * as fspath from "path"; +import * as fs from "fs"; +import { CtxInit } from "./ctx"; +import * as ra from "./lsp_ext"; +import { FetchDependencyListResult } from "./lsp_ext"; + +export class RustDependenciesProvider + implements vscode.TreeDataProvider +{ + dependenciesMap: { [id: string]: Dependency | DependencyFile }; + ctx: CtxInit; + + constructor(ctx: CtxInit) { + this.dependenciesMap = {}; + this.ctx = ctx; + } + + private _onDidChangeTreeData: vscode.EventEmitter< + Dependency | DependencyFile | undefined | null | void + > = new vscode.EventEmitter(); + + readonly onDidChangeTreeData: vscode.Event< + Dependency | DependencyFile | undefined | null | void + > = this._onDidChangeTreeData.event; + + getDependency(filePath: string): Dependency | DependencyFile | undefined { + return this.dependenciesMap[filePath.toLowerCase()]; + } + + contains(filePath: string): boolean { + return filePath.toLowerCase() in this.dependenciesMap; + } + + isInitialized(): boolean { + return Object.keys(this.dependenciesMap).length !== 0; + } + + refresh(): void { + this.dependenciesMap = {}; + this._onDidChangeTreeData.fire(); + } + + getParent?( + element: Dependency | DependencyFile + ): vscode.ProviderResult { + if (element instanceof Dependency) return undefined; + return element.parent; + } + + getTreeItem(element: Dependency | DependencyFile): vscode.TreeItem | Thenable { + if (element.id! in this.dependenciesMap) return this.dependenciesMap[element.id!]; + return element; + } + + getChildren( + element?: Dependency | DependencyFile + ): vscode.ProviderResult { + return new Promise((resolve, _reject) => { + if (!vscode.workspace.workspaceFolders) { + void vscode.window.showInformationMessage("No dependency in empty workspace"); + return Promise.resolve([]); + } + if (element) { + const files = fs.readdirSync(element.dependencyPath).map((fileName) => { + const filePath = fspath.join(element.dependencyPath, fileName); + const collapsibleState = fs.lstatSync(filePath).isDirectory() + ? vscode.TreeItemCollapsibleState.Collapsed + : vscode.TreeItemCollapsibleState.None; + const dep = new DependencyFile(fileName, filePath, element, collapsibleState); + this.dependenciesMap[dep.dependencyPath.toLowerCase()] = dep; + return dep; + }); + return resolve(files); + } else { + return resolve(this.getRootDependencies()); + } + }); + } + + private async getRootDependencies(): Promise { + const dependenciesResult: FetchDependencyListResult = await this.ctx.client.sendRequest( + ra.fetchDependencyList, + {} + ); + const crates = dependenciesResult.crates; + + return crates + .map((crate) => { + const dep = this.toDep(crate.name || "unknown", crate.version || "", crate.path); + this.dependenciesMap[dep.dependencyPath.toLowerCase()] = dep; + return dep; + }) + .sort((a, b) => { + return a.label.localeCompare(b.label); + }); + } + + private toDep(moduleName: string, version: string, path: string): Dependency { + return new Dependency( + moduleName, + version, + vscode.Uri.parse(path).fsPath, + vscode.TreeItemCollapsibleState.Collapsed + ); + } +} + +export class Dependency extends vscode.TreeItem { + constructor( + public readonly label: string, + private version: string, + readonly dependencyPath: string, + public readonly collapsibleState: vscode.TreeItemCollapsibleState + ) { + super(label, collapsibleState); + this.resourceUri = vscode.Uri.file(dependencyPath); + this.id = this.resourceUri.fsPath.toLowerCase(); + this.description = this.version; + if (this.version) { + this.tooltip = `${this.label}-${this.version}`; + } else { + this.tooltip = this.label; + } + } +} + +export class DependencyFile extends vscode.TreeItem { + constructor( + readonly label: string, + readonly dependencyPath: string, + readonly parent: Dependency | DependencyFile, + public readonly collapsibleState: vscode.TreeItemCollapsibleState + ) { + super(vscode.Uri.file(dependencyPath), collapsibleState); + this.id = this.resourceUri!.fsPath.toLowerCase(); + const isDir = fs.lstatSync(this.resourceUri!.fsPath).isDirectory(); + if (!isDir) { + this.command = { + command: "vscode.open", + title: "Open File", + arguments: [this.resourceUri], + }; + } + } +} + +export type DependencyId = { id: string }; diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index 872d7199b838a..b72804e510ce4 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts @@ -10,12 +10,9 @@ export const hover = new lc.RequestType< HoverParams, (lc.Hover & { actions: CommandLinkGroup[] }) | null, void ->("textDocument/hover"); -export type HoverParams = { position: lc.Position | lc.Range } & Omit< - lc.TextDocumentPositionParams, - "position" -> & - lc.WorkDoneProgressParams; +>(lc.HoverRequest.method); +export type HoverParams = { position: lc.Position | lc.Range } & Omit; + export type CommandLink = { /** * A tooltip for the command, when represented in the UI. @@ -43,6 +40,7 @@ export const relatedTests = new lc.RequestType("rust-analyzer/reloadWorkspace"); +export const rebuildProcMacros = new lc.RequestType0("rust-analyzer/rebuildProcMacros"); export const runFlycheck = new lc.NotificationType<{ textDocument: lc.TextDocumentIdentifier | null; @@ -63,12 +61,47 @@ export const viewHir = new lc.RequestType( "rust-analyzer/viewMir" ); +export const interpretFunction = new lc.RequestType( + "rust-analyzer/interpretFunction" +); export const viewItemTree = new lc.RequestType( "rust-analyzer/viewItemTree" ); export type AnalyzerStatusParams = { textDocument?: lc.TextDocumentIdentifier }; +export interface FetchDependencyListParams {} + +export interface FetchDependencyListResult { + crates: { + name: string | undefined; + version: string | undefined; + path: string; + }[]; +} + +export const fetchDependencyList = new lc.RequestType< + FetchDependencyListParams, + FetchDependencyListResult, + void +>("rust-analyzer/fetchDependencyList"); + +export interface FetchDependencyGraphParams {} + +export interface FetchDependencyGraphResult { + crates: { + name: string; + version: string; + path: string; + }[]; +} + +export const fetchDependencyGraph = new lc.RequestType< + FetchDependencyGraphParams, + FetchDependencyGraphResult, + void +>("rust-analyzer/fetchDependencyGraph"); + export type ExpandMacroParams = { textDocument: lc.TextDocumentIdentifier; position: lc.Position; diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index d5de00561b123..be9bc9d363ce6 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -120,13 +120,11 @@ function createCommands(): Record { enabled: commands.onEnter, disabled: (_) => () => vscode.commands.executeCommand("default:type", { text: "\n" }), }, - reload: { + restartServer: { enabled: (ctx) => async () => { - void vscode.window.showInformationMessage("Reloading rust-analyzer..."); await ctx.restart(); }, disabled: (ctx) => async () => { - void vscode.window.showInformationMessage("Reloading rust-analyzer..."); await ctx.start(); }, }, @@ -153,6 +151,7 @@ function createCommands(): Record { memoryUsage: { enabled: commands.memoryUsage }, shuffleCrateGraph: { enabled: commands.shuffleCrateGraph }, reloadWorkspace: { enabled: commands.reloadWorkspace }, + rebuildProcMacros: { enabled: commands.rebuildProcMacros }, addProject: { enabled: commands.addProject }, matchingBrace: { enabled: commands.matchingBrace }, joinLines: { enabled: commands.joinLines }, @@ -160,6 +159,7 @@ function createCommands(): Record { syntaxTree: { enabled: commands.syntaxTree }, viewHir: { enabled: commands.viewHir }, viewMir: { enabled: commands.viewMir }, + interpretFunction: { enabled: commands.interpretFunction }, viewFileText: { enabled: commands.viewFileText }, viewItemTree: { enabled: commands.viewItemTree }, viewCrateGraph: { enabled: commands.viewCrateGraph }, @@ -190,5 +190,6 @@ function createCommands(): Record { showReferences: { enabled: commands.showReferences }, triggerParameterHints: { enabled: commands.triggerParameterHints }, openLogs: { enabled: commands.openLogs }, + revealDependency: { enabled: commands.revealDependency }, }; } diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts index 35627e2fc6beb..623fb102953bc 100644 --- a/editors/code/src/run.ts +++ b/editors/code/src/run.ts @@ -157,7 +157,7 @@ export async function createTask(runnable: ra.Runnable, config: Config): Promise cargoTask.presentationOptions.clear = true; // Sadly, this doesn't prevent focus stealing if the terminal is currently - // hidden, and will become revealed due to task exucution. + // hidden, and will become revealed due to task execution. cargoTask.presentationOptions.focus = false; return cargoTask; diff --git a/editors/code/src/tasks.ts b/editors/code/src/tasks.ts index e6239deeb21af..d6509d9aa6e71 100644 --- a/editors/code/src/tasks.ts +++ b/editors/code/src/tasks.ts @@ -128,7 +128,7 @@ export async function buildCargoTask( name, TASK_SOURCE, exec, - ["$rustc"] + ["$rustc", "$rust-panic"] ); } diff --git a/editors/code/src/toolchain.ts b/editors/code/src/toolchain.ts index eb70b88871e3d..917a1d6b0997b 100644 --- a/editors/code/src/toolchain.ts +++ b/editors/code/src/toolchain.ts @@ -18,7 +18,11 @@ export interface ArtifactSpec { } export class Cargo { - constructor(readonly rootFolder: string, readonly output: vscode.OutputChannel) {} + constructor( + readonly rootFolder: string, + readonly output: vscode.OutputChannel, + readonly env: Record + ) {} // Made public for testing purposes static artifactSpec(args: readonly string[]): ArtifactSpec { @@ -102,6 +106,7 @@ export class Cargo { const cargo = cp.spawn(path, cargoArgs, { stdio: ["ignore", "pipe", "pipe"], cwd: this.rootFolder, + env: this.env, }); cargo.on("error", (err) => reject(new Error(`could not launch cargo: ${err}`))); diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts index 922fbcbcf35a5..b6b779e266013 100644 --- a/editors/code/src/util.ts +++ b/editors/code/src/util.ts @@ -112,6 +112,19 @@ export function isRustEditor(editor: vscode.TextEditor): editor is RustEditor { return isRustDocument(editor.document); } +export function isDocumentInWorkspace(document: RustDocument): boolean { + const workspaceFolders = vscode.workspace.workspaceFolders; + if (!workspaceFolders) { + return false; + } + for (const folder of workspaceFolders) { + if (document.uri.fsPath.startsWith(folder.uri.fsPath)) { + return true; + } + } + return false; +} + export function isValidExecutable(path: string): boolean { log.debug("Checking availability of a binary at", path); diff --git a/lib/README.md b/lib/README.md index 6b2eeac2c0d76..ed55e31d6bb7b 100644 --- a/lib/README.md +++ b/lib/README.md @@ -1,2 +1,5 @@ -Crates in this directory are published to crates.io and obey semver. -They *could* live in a separate repo, but we want to experiment with a monorepo setup. +# lib + +Crates in this directory are published to [crates.io](https://crates.io) and obey semver. + +They _could_ live in a separate repo, but we want to experiment with a monorepo setup. diff --git a/lib/la-arena/src/lib.rs b/lib/la-arena/src/lib.rs index ccaaf3991769e..5107f294394bc 100644 --- a/lib/la-arena/src/lib.rs +++ b/lib/la-arena/src/lib.rs @@ -4,8 +4,9 @@ #![warn(missing_docs)] use std::{ - fmt, + cmp, fmt, hash::{Hash, Hasher}, + iter::{Enumerate, FusedIterator}, marker::PhantomData, ops::{Index, IndexMut, Range, RangeInclusive}, }; @@ -17,13 +18,27 @@ pub use map::{ArenaMap, Entry, OccupiedEntry, VacantEntry}; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct RawIdx(u32); +impl RawIdx { + /// Constructs a [`RawIdx`] from a u32. + pub const fn from_u32(u32: u32) -> Self { + RawIdx(u32) + } + + /// Deconstructs a [`RawIdx`] into the underlying u32. + pub const fn into_u32(self) -> u32 { + self.0 + } +} + impl From for u32 { + #[inline] fn from(raw: RawIdx) -> u32 { raw.0 } } impl From for RawIdx { + #[inline] fn from(idx: u32) -> RawIdx { RawIdx(idx) } @@ -47,6 +62,18 @@ pub struct Idx { _ty: PhantomData T>, } +impl Ord for Idx { + fn cmp(&self, other: &Self) -> cmp::Ordering { + self.raw.cmp(&other.raw) + } +} + +impl PartialOrd for Idx { + fn partial_cmp(&self, other: &Self) -> Option { + self.raw.partial_cmp(&other.raw) + } +} + impl Clone for Idx { fn clone(&self) -> Self { *self @@ -79,12 +106,12 @@ impl fmt::Debug for Idx { impl Idx { /// Creates a new index from a [`RawIdx`]. - pub fn from_raw(raw: RawIdx) -> Self { + pub const fn from_raw(raw: RawIdx) -> Self { Idx { raw, _ty: PhantomData } } /// Converts this index into the underlying [`RawIdx`]. - pub fn into_raw(self) -> RawIdx { + pub const fn into_raw(self) -> RawIdx { self.raw } } @@ -147,13 +174,46 @@ impl IdxRange { pub fn is_empty(&self) -> bool { self.range.is_empty() } + + /// Returns the start of the index range. + pub fn start(&self) -> Idx { + Idx::from_raw(RawIdx::from(self.range.start)) + } + + /// Returns the end of the index range. + pub fn end(&self) -> Idx { + Idx::from_raw(RawIdx::from(self.range.end)) + } } impl Iterator for IdxRange { type Item = Idx; + fn next(&mut self) -> Option { self.range.next().map(|raw| Idx::from_raw(raw.into())) } + + fn size_hint(&self) -> (usize, Option) { + self.range.size_hint() + } + + fn count(self) -> usize + where + Self: Sized, + { + self.range.count() + } + + fn last(self) -> Option + where + Self: Sized, + { + self.range.last().map(|raw| Idx::from_raw(raw.into())) + } + + fn nth(&mut self, n: usize) -> Option { + self.range.nth(n).map(|raw| Idx::from_raw(raw.into())) + } } impl DoubleEndedIterator for IdxRange { @@ -162,6 +222,10 @@ impl DoubleEndedIterator for IdxRange { } } +impl ExactSizeIterator for IdxRange {} + +impl FusedIterator for IdxRange {} + impl fmt::Debug for IdxRange { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple(&format!("IdxRange::<{}>", std::any::type_name::())) @@ -280,6 +344,21 @@ impl Arena { idx } + /// Densely allocates multiple values, returning the values’ index range. + /// + /// ``` + /// let mut arena = la_arena::Arena::new(); + /// let range = arena.alloc_many(0..4); + /// + /// assert_eq!(arena[range], [0, 1, 2, 3]); + /// ``` + pub fn alloc_many>(&mut self, iter: II) -> IdxRange { + let start = self.next_idx(); + self.extend(iter); + let end = self.next_idx(); + IdxRange::new(start..end) + } + /// Returns an iterator over the arena’s elements. /// /// ``` @@ -295,7 +374,7 @@ impl Arena { /// ``` pub fn iter( &self, - ) -> impl Iterator, &T)> + ExactSizeIterator + DoubleEndedIterator { + ) -> impl Iterator, &T)> + ExactSizeIterator + DoubleEndedIterator + Clone { self.data.iter().enumerate().map(|(idx, value)| (Idx::from_raw(RawIdx(idx as u32)), value)) } @@ -335,7 +414,7 @@ impl Arena { /// assert_eq!(iterator.next(), Some(&40)); /// assert_eq!(iterator.next(), Some(&60)); /// ``` - pub fn values(&mut self) -> impl Iterator + ExactSizeIterator + DoubleEndedIterator { + pub fn values(&self) -> impl Iterator + ExactSizeIterator + DoubleEndedIterator { self.data.iter() } @@ -410,3 +489,32 @@ impl FromIterator for Arena { Arena { data: Vec::from_iter(iter) } } } + +/// An iterator over the arena’s elements. +pub struct IntoIter(Enumerate< as IntoIterator>::IntoIter>); + +impl Iterator for IntoIter { + type Item = (Idx, T); + + fn next(&mut self) -> Option { + self.0.next().map(|(idx, value)| (Idx::from_raw(RawIdx(idx as u32)), value)) + } +} + +impl IntoIterator for Arena { + type Item = (Idx, T); + + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter(self.data.into_iter().enumerate()) + } +} + +impl Extend for Arena { + fn extend>(&mut self, iter: II) { + for t in iter { + self.alloc(t); + } + } +} diff --git a/lib/la-arena/src/map.rs b/lib/la-arena/src/map.rs index 7fff2b09c97b5..750f345b5398d 100644 --- a/lib/la-arena/src/map.rs +++ b/lib/la-arena/src/map.rs @@ -1,3 +1,4 @@ +use std::iter::Enumerate; use std::marker::PhantomData; use crate::Idx; @@ -72,17 +73,17 @@ impl ArenaMap, V> { } /// Returns an iterator over the values in the map. - pub fn values(&self) -> impl Iterator { + pub fn values(&self) -> impl Iterator + DoubleEndedIterator { self.v.iter().filter_map(|o| o.as_ref()) } /// Returns an iterator over mutable references to the values in the map. - pub fn values_mut(&mut self) -> impl Iterator { + pub fn values_mut(&mut self) -> impl Iterator + DoubleEndedIterator { self.v.iter_mut().filter_map(|o| o.as_mut()) } /// Returns an iterator over the arena indexes and values in the map. - pub fn iter(&self) -> impl Iterator, &V)> { + pub fn iter(&self) -> impl Iterator, &V)> + DoubleEndedIterator { self.v.iter().enumerate().filter_map(|(idx, o)| Some((Self::from_idx(idx), o.as_ref()?))) } @@ -94,12 +95,6 @@ impl ArenaMap, V> { .filter_map(|(idx, o)| Some((Self::from_idx(idx), o.as_mut()?))) } - /// Returns an iterator over the arena indexes and values in the map. - // FIXME: Implement `IntoIterator` trait. - pub fn into_iter(self) -> impl Iterator, V)> { - self.v.into_iter().enumerate().filter_map(|(idx, o)| Some((Self::from_idx(idx), o?))) - } - /// Gets the given key's corresponding entry in the map for in-place manipulation. pub fn entry(&mut self, idx: Idx) -> Entry<'_, Idx, V> { let idx = Self::to_idx(idx); @@ -154,6 +149,63 @@ impl FromIterator<(Idx, T)> for ArenaMap, T> { } } +pub struct ArenaMapIter { + iter: Enumerate>>, + _ty: PhantomData, +} + +impl IntoIterator for ArenaMap, V> { + type Item = (Idx, V); + + type IntoIter = ArenaMapIter, V>; + + fn into_iter(self) -> Self::IntoIter { + let iter = self.v.into_iter().enumerate(); + Self::IntoIter { iter, _ty: PhantomData } + } +} + +impl ArenaMapIter, V> { + fn mapper((idx, o): (usize, Option)) -> Option<(Idx, V)> { + Some((ArenaMap::, V>::from_idx(idx), o?)) + } +} + +impl Iterator for ArenaMapIter, V> { + type Item = (Idx, V); + + #[inline] + fn next(&mut self) -> Option { + for next in self.iter.by_ref() { + match Self::mapper(next) { + Some(r) => return Some(r), + None => continue, + } + } + + None + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl DoubleEndedIterator for ArenaMapIter, V> { + #[inline] + fn next_back(&mut self) -> Option { + while let Some(next_back) = self.iter.next_back() { + match Self::mapper(next_back) { + Some(r) => return Some(r), + None => continue, + } + } + + None + } +} + /// A view into a single entry in a map, which may either be vacant or occupied. /// /// This `enum` is constructed from the [`entry`] method on [`ArenaMap`]. diff --git a/lib/line-index/Cargo.toml b/lib/line-index/Cargo.toml new file mode 100644 index 0000000000000..019ad3a53ba0e --- /dev/null +++ b/lib/line-index/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "line-index" +version = "0.1.0-pre.1" +description = "Maps flat `TextSize` offsets to/from `(line, column)` representation." +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/rust-analyzer/tree/master/lib/line-index" +edition = "2021" + +[dependencies] +text-size.workspace = true +nohash-hasher.workspace = true diff --git a/lib/line-index/src/lib.rs b/lib/line-index/src/lib.rs new file mode 100644 index 0000000000000..ad67d3f246eca --- /dev/null +++ b/lib/line-index/src/lib.rs @@ -0,0 +1,237 @@ +//! See [`LineIndex`]. + +#![deny(missing_debug_implementations, missing_docs, rust_2018_idioms)] + +#[cfg(test)] +mod tests; + +use nohash_hasher::IntMap; + +pub use text_size::{TextRange, TextSize}; + +/// `(line, column)` information in the native, UTF-8 encoding. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct LineCol { + /// Zero-based. + pub line: u32, + /// Zero-based UTF-8 offset. + pub col: u32, +} + +/// A kind of wide character encoding. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[non_exhaustive] +pub enum WideEncoding { + /// UTF-16. + Utf16, + /// UTF-32. + Utf32, +} + +impl WideEncoding { + /// Returns the number of code units it takes to encode `text` in this encoding. + pub fn measure(&self, text: &str) -> usize { + match self { + WideEncoding::Utf16 => text.encode_utf16().count(), + WideEncoding::Utf32 => text.chars().count(), + } + } +} + +/// `(line, column)` information in wide encodings. +/// +/// See [`WideEncoding`] for the kinds of wide encodings available. +// +// Deliberately not a generic type and different from `LineCol`. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct WideLineCol { + /// Zero-based. + pub line: u32, + /// Zero-based. + pub col: u32, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +struct WideChar { + /// Start offset of a character inside a line, zero-based. + start: TextSize, + /// End offset of a character inside a line, zero-based. + end: TextSize, +} + +impl WideChar { + /// Returns the length in 8-bit UTF-8 code units. + fn len(&self) -> TextSize { + self.end - self.start + } + + /// Returns the length in UTF-16 or UTF-32 code units. + fn wide_len(&self, enc: WideEncoding) -> u32 { + match enc { + WideEncoding::Utf16 => { + if self.len() == TextSize::from(4) { + 2 + } else { + 1 + } + } + WideEncoding::Utf32 => 1, + } + } +} + +/// Maps flat [`TextSize`] offsets to/from `(line, column)` representation. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct LineIndex { + /// Offset the beginning of each line (except the first, which always has offset 0). + newlines: Box<[TextSize]>, + /// List of non-ASCII characters on each line. + line_wide_chars: IntMap>, + /// The length of the entire text. + len: TextSize, +} + +impl LineIndex { + /// Returns a `LineIndex` for the `text`. + pub fn new(text: &str) -> LineIndex { + let mut newlines = Vec::::with_capacity(16); + let mut line_wide_chars = IntMap::>::default(); + + let mut wide_chars = Vec::::new(); + let mut cur_row = TextSize::from(0); + let mut cur_col = TextSize::from(0); + let mut line = 0u32; + + for c in text.chars() { + let c_len = TextSize::of(c); + cur_row += c_len; + if c == '\n' { + newlines.push(cur_row); + + // Save any wide characters seen in the previous line + if !wide_chars.is_empty() { + let cs = std::mem::take(&mut wide_chars).into_boxed_slice(); + line_wide_chars.insert(line, cs); + } + + // Prepare for processing the next line + cur_col = TextSize::from(0); + line += 1; + continue; + } + + if !c.is_ascii() { + wide_chars.push(WideChar { start: cur_col, end: cur_col + c_len }); + } + + cur_col += c_len; + } + + // Save any wide characters seen in the last line + if !wide_chars.is_empty() { + line_wide_chars.insert(line, wide_chars.into_boxed_slice()); + } + + LineIndex { + newlines: newlines.into_boxed_slice(), + line_wide_chars, + len: TextSize::of(text), + } + } + + /// Transforms the `TextSize` into a `LineCol`. + /// + /// # Panics + /// + /// If the offset is invalid. See [`Self::try_line_col`]. + pub fn line_col(&self, offset: TextSize) -> LineCol { + self.try_line_col(offset).expect("invalid offset") + } + + /// Transforms the `TextSize` into a `LineCol`. + /// + /// Returns `None` if the `offset` was invalid, e.g. if it extends past the end of the text or + /// points to the middle of a multi-byte character. + pub fn try_line_col(&self, offset: TextSize) -> Option { + if offset > self.len { + return None; + } + let line = self.newlines.partition_point(|&it| it <= offset); + let start = self.start_offset(line)?; + let col = offset - start; + let ret = LineCol { line: line as u32, col: col.into() }; + self.line_wide_chars + .get(&ret.line) + .into_iter() + .flat_map(|it| it.iter()) + .all(|it| col <= it.start || it.end <= col) + .then_some(ret) + } + + /// Transforms the `LineCol` into a `TextSize`. + pub fn offset(&self, line_col: LineCol) -> Option { + self.start_offset(line_col.line as usize).map(|start| start + TextSize::from(line_col.col)) + } + + fn start_offset(&self, line: usize) -> Option { + match line.checked_sub(1) { + None => Some(TextSize::from(0)), + Some(it) => self.newlines.get(it).copied(), + } + } + + /// Transforms the `LineCol` with the given `WideEncoding` into a `WideLineCol`. + pub fn to_wide(&self, enc: WideEncoding, line_col: LineCol) -> Option { + let mut col = line_col.col; + if let Some(wide_chars) = self.line_wide_chars.get(&line_col.line) { + for c in wide_chars.iter() { + if u32::from(c.end) <= line_col.col { + col = col.checked_sub(u32::from(c.len()) - c.wide_len(enc))?; + } else { + // From here on, all utf16 characters come *after* the character we are mapping, + // so we don't need to take them into account + break; + } + } + } + Some(WideLineCol { line: line_col.line, col }) + } + + /// Transforms the `WideLineCol` with the given `WideEncoding` into a `LineCol`. + pub fn to_utf8(&self, enc: WideEncoding, line_col: WideLineCol) -> Option { + let mut col = line_col.col; + if let Some(wide_chars) = self.line_wide_chars.get(&line_col.line) { + for c in wide_chars.iter() { + if col > u32::from(c.start) { + col = col.checked_add(u32::from(c.len()) - c.wide_len(enc))?; + } else { + // From here on, all utf16 characters come *after* the character we are mapping, + // so we don't need to take them into account + break; + } + } + } + Some(LineCol { line: line_col.line, col }) + } + + /// Given a range [start, end), returns a sorted iterator of non-empty ranges [start, x1), [x1, + /// x2), ..., [xn, end) where all the xi, which are positions of newlines, are inside the range + /// [start, end). + pub fn lines(&self, range: TextRange) -> impl Iterator + '_ { + let lo = self.newlines.partition_point(|&it| it < range.start()); + let hi = self.newlines.partition_point(|&it| it <= range.end()); + let all = std::iter::once(range.start()) + .chain(self.newlines[lo..hi].iter().copied()) + .chain(std::iter::once(range.end())); + + all.clone() + .zip(all.skip(1)) + .map(|(lo, hi)| TextRange::new(lo, hi)) + .filter(|it| !it.is_empty()) + } + + /// Returns the length of the original text. + pub fn len(&self) -> TextSize { + self.len + } +} diff --git a/lib/line-index/src/tests.rs b/lib/line-index/src/tests.rs new file mode 100644 index 0000000000000..31c01c20ee36f --- /dev/null +++ b/lib/line-index/src/tests.rs @@ -0,0 +1,11 @@ +use super::LineIndex; + +#[test] +fn test_empty_index() { + let col_index = LineIndex::new( + " +const C: char = 'x'; +", + ); + assert_eq!(col_index.line_wide_chars.len(), 0); +} diff --git a/lib/line-index/tests/it.rs b/lib/line-index/tests/it.rs new file mode 100644 index 0000000000000..ce1c0bc6f143d --- /dev/null +++ b/lib/line-index/tests/it.rs @@ -0,0 +1,62 @@ +use line_index::{LineCol, LineIndex, TextRange}; + +#[test] +fn test_line_index() { + let text = "hello\nworld"; + let table = [ + (00, 0, 0), + (01, 0, 1), + (05, 0, 5), + (06, 1, 0), + (07, 1, 1), + (08, 1, 2), + (10, 1, 4), + (11, 1, 5), + ]; + + let index = LineIndex::new(text); + for (offset, line, col) in table { + assert_eq!(index.line_col(offset.into()), LineCol { line, col }); + } + + let text = "\nhello\nworld"; + let table = [(0, 0, 0), (1, 1, 0), (2, 1, 1), (6, 1, 5), (7, 2, 0)]; + let index = LineIndex::new(text); + for (offset, line, col) in table { + assert_eq!(index.line_col(offset.into()), LineCol { line, col }); + } +} + +#[test] +fn test_char_len() { + assert_eq!('メ'.len_utf8(), 3); + assert_eq!('メ'.len_utf16(), 1); +} + +#[test] +fn test_splitlines() { + fn r(lo: u32, hi: u32) -> TextRange { + TextRange::new(lo.into(), hi.into()) + } + + let text = "a\nbb\nccc\n"; + let line_index = LineIndex::new(text); + + let actual = line_index.lines(r(0, 9)).collect::>(); + let expected = vec![r(0, 2), r(2, 5), r(5, 9)]; + assert_eq!(actual, expected); + + let text = ""; + let line_index = LineIndex::new(text); + + let actual = line_index.lines(r(0, 0)).collect::>(); + let expected = vec![]; + assert_eq!(actual, expected); + + let text = "\n"; + let line_index = LineIndex::new(text); + + let actual = line_index.lines(r(0, 1)).collect::>(); + let expected = vec![r(0, 1)]; + assert_eq!(actual, expected) +} diff --git a/lib/lsp-server/Cargo.toml b/lib/lsp-server/Cargo.toml index 6e32e3960526f..e78a9d2eb1674 100644 --- a/lib/lsp-server/Cargo.toml +++ b/lib/lsp-server/Cargo.toml @@ -8,8 +8,8 @@ edition = "2021" [dependencies] log = "0.4.17" -serde_json = "1.0.86" -serde = { version = "1.0.144", features = ["derive"] } +serde_json.workspace = true +serde.workspace = true crossbeam-channel = "0.5.6" [dev-dependencies] diff --git a/lib/lsp-server/src/error.rs b/lib/lsp-server/src/error.rs index 4c934d9ecca5d..755b3fd959624 100644 --- a/lib/lsp-server/src/error.rs +++ b/lib/lsp-server/src/error.rs @@ -2,7 +2,7 @@ use std::fmt; use crate::{Notification, Request}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct ProtocolError(pub(crate) String); impl std::error::Error for ProtocolError {} diff --git a/lib/lsp-server/src/lib.rs b/lib/lsp-server/src/lib.rs index beccde40a8978..affab60a22783 100644 --- a/lib/lsp-server/src/lib.rs +++ b/lib/lsp-server/src/lib.rs @@ -126,6 +126,9 @@ impl Connection { self.sender.send(resp.into()).unwrap(); continue; } + Ok(Message::Notification(n)) if !n.is_exit() => { + continue; + } Ok(msg) => Err(ProtocolError(format!("expected initialize request, got {msg:?}"))), Err(e) => { Err(ProtocolError(format!("expected initialize request, got error: {e}"))) @@ -212,3 +215,70 @@ impl Connection { Ok(true) } } + +#[cfg(test)] +mod tests { + use crossbeam_channel::unbounded; + use lsp_types::notification::{Exit, Initialized, Notification}; + use lsp_types::request::{Initialize, Request}; + use lsp_types::{InitializeParams, InitializedParams}; + use serde_json::to_value; + + use crate::{Connection, Message, ProtocolError, RequestId}; + + struct TestCase { + test_messages: Vec, + expected_resp: Result<(RequestId, serde_json::Value), ProtocolError>, + } + + fn initialize_start_test(test_case: TestCase) { + let (reader_sender, reader_receiver) = unbounded::(); + let (writer_sender, writer_receiver) = unbounded::(); + let conn = Connection { sender: writer_sender, receiver: reader_receiver }; + + for msg in test_case.test_messages { + assert!(reader_sender.send(msg).is_ok()); + } + + let resp = conn.initialize_start(); + assert_eq!(test_case.expected_resp, resp); + + assert!(writer_receiver.recv_timeout(std::time::Duration::from_secs(1)).is_err()); + } + + #[test] + fn not_exit_notification() { + let notification = crate::Notification { + method: Initialized::METHOD.to_string(), + params: to_value(InitializedParams {}).unwrap(), + }; + + let params_as_value = to_value(InitializeParams::default()).unwrap(); + let req_id = RequestId::from(234); + let request = crate::Request { + id: req_id.clone(), + method: Initialize::METHOD.to_string(), + params: params_as_value.clone(), + }; + + initialize_start_test(TestCase { + test_messages: vec![notification.into(), request.into()], + expected_resp: Ok((req_id, params_as_value)), + }); + } + + #[test] + fn exit_notification() { + let notification = + crate::Notification { method: Exit::METHOD.to_string(), params: to_value(()).unwrap() }; + let notification_msg = Message::from(notification); + + initialize_start_test(TestCase { + test_messages: vec![notification_msg.clone()], + expected_resp: Err(ProtocolError(format!( + "expected initialize request, got {:?}", + notification_msg + ))), + }); + } +} From bbd695589e54feb7ca94028ce9efae3763ad7fe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 5 Jun 2023 15:10:05 +0300 Subject: [PATCH 159/465] Merge commit 'ed87e0a20a9d196a5ea659ea46ae9574be666d4f' into sync-from-ra --- Cargo.lock | 1 + crates/rust-analyzer/Cargo.toml | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 322a67383b030..e36aef6a6aa8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1505,6 +1505,7 @@ dependencies = [ "parking_lot 0.12.1", "parking_lot_core 0.9.6", "proc-macro-api", + "proc-macro-srv-cli", "profile", "project-model", "rayon", diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 97bd920920601..77f02a83101e3 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -68,6 +68,7 @@ ide-db.workspace = true ide-ssr.workspace = true ide.workspace = true proc-macro-api.workspace = true +proc-macro-srv-cli.workspace = true profile.workspace = true project-model.workspace = true stdx.workspace = true @@ -94,4 +95,5 @@ mbe.workspace = true [features] jemalloc = ["jemallocator", "profile/jemalloc"] force-always-assert = ["always-assert/force"] -in-rust-tree = ["ide/in-rust-tree", "syntax/in-rust-tree"] +sysroot-abi = ["proc-macro-srv-cli/sysroot-abi"] +in-rust-tree = ["sysroot-abi", "ide/in-rust-tree", "syntax/in-rust-tree"] From 094c1e7b86e2280a5ca95f3cee4a2d7aa9f382d9 Mon Sep 17 00:00:00 2001 From: Viktor Lott Date: Mon, 29 May 2023 21:15:14 +0200 Subject: [PATCH 160/465] feat: inline const expr as static str --- crates/ide-assists/src/handlers/raw_string.rs | 281 +++++++++++++++++- crates/ide-assists/src/lib.rs | 1 + crates/ide-assists/src/tests/generated.rs | 21 ++ 3 files changed, 300 insertions(+), 3 deletions(-) diff --git a/crates/ide-assists/src/handlers/raw_string.rs b/crates/ide-assists/src/handlers/raw_string.rs index 40ee4771d1707..4852b0220e91a 100644 --- a/crates/ide-assists/src/handlers/raw_string.rs +++ b/crates/ide-assists/src/handlers/raw_string.rs @@ -1,6 +1,7 @@ use std::borrow::Cow; -use syntax::{ast, ast::IsString, AstToken, TextRange, TextSize}; +use ide_db::syntax_helpers::insert_whitespace_into_node::insert_ws_into; +use syntax::{ast, ast::IsString, AstNode, AstToken, TextRange, TextSize}; use crate::{utils::required_hashes, AssistContext, AssistId, AssistKind, Assists}; @@ -156,11 +157,76 @@ pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< }) } +// Assist: inline_str_literal +// +// Inline const variable as static str literal. +// +// ``` +// const STRING: &str = "Hello, World!"; +// +// fn something() -> &'static str { +// STR$0ING +// } +// ``` +// -> +// ``` +// const STRING: &str = "Hello, World!"; +// +// fn something() -> &'static str { +// "Hello, World!" +// } +// ``` +pub(crate) fn inline_str_literal(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let variable = ctx.find_node_at_offset::()?; + + if let hir::PathResolution::Def(hir::ModuleDef::Const(konst)) = + ctx.sema.resolve_path(&variable.path()?)? + { + if !konst.ty(ctx.sema.db).as_reference()?.0.as_builtin()?.is_str() { + return None; + } + + // FIXME: Make sure it's not possible to eval during diagnostic error + let value = match konst.value(ctx.sema.db)? { + ast::Expr::Literal(lit) => lit.to_string(), + ast::Expr::BlockExpr(_) + | ast::Expr::IfExpr(_) + | ast::Expr::MatchExpr(_) + | ast::Expr::CallExpr(_) => match konst.render_eval(ctx.sema.db) { + Ok(result) => result, + Err(_) => return None, + }, + ast::Expr::MacroExpr(makro) => { + let makro_call = makro.syntax().children().find_map(ast::MacroCall::cast)?; + let makro_hir = ctx.sema.resolve_macro_call(&makro_call)?; + + // This should not be necessary because of the `makro_call` check + if !makro_hir.is_fn_like(ctx.sema.db) { + return None; + } + + // FIXME: Make procedural/build-in macro tests + insert_ws_into(ctx.sema.expand(&makro_call)?).to_string() + } + _ => return None, + }; + + let id = AssistId("inline_str_literal", AssistKind::RefactorInline); + let label = "Inline as static `&str` literal"; + let target = variable.syntax().text_range(); + + acc.add(id, label, target, |edit| { + edit.replace(variable.syntax().text_range(), value); + }); + } + + Some(()) +} + #[cfg(test)] mod tests { - use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; - use super::*; + use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; #[test] fn make_raw_string_target() { @@ -483,4 +549,213 @@ string"###; "#, ); } + + #[test] + fn inline_expr_as_str_lit() { + check_assist( + inline_str_literal, + r#" + const STRING: &str = "Hello, World!"; + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + const STRING: &str = "Hello, World!"; + + fn something() -> &'static str { + "Hello, World!" + } + "#, + ); + } + + #[test] + fn inline_eval_const_block_expr_to_str_lit() { + check_assist( + inline_str_literal, + r#" + const STRING: &str = { + let x = 9; + if x + 10 == 21 { + "Hello, World!" + } else { + "World, Hello!" + } + }; + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + const STRING: &str = { + let x = 9; + if x + 10 == 21 { + "Hello, World!" + } else { + "World, Hello!" + } + }; + + fn something() -> &'static str { + "World, Hello!" + } + "#, + ); + } + + #[test] + fn inline_eval_const_block_macro_expr_to_str_lit() { + check_assist( + inline_str_literal, + r#" + macro_rules! co {() => {"World, Hello!"};} + const STRING: &str = { co!() }; + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + macro_rules! co {() => {"World, Hello!"};} + const STRING: &str = { co!() }; + + fn something() -> &'static str { + "World, Hello!" + } + "#, + ); + } + + #[test] + fn inline_eval_const_match_expr_to_str_lit() { + check_assist( + inline_str_literal, + r#" + const STRING: &str = match 9 + 10 { + 0..18 => "Hello, World!", + _ => "World, Hello!" + }; + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + const STRING: &str = match 9 + 10 { + 0..18 => "Hello, World!", + _ => "World, Hello!" + }; + + fn something() -> &'static str { + "World, Hello!" + } + "#, + ); + } + + #[test] + fn inline_eval_const_if_expr_to_str_lit() { + check_assist( + inline_str_literal, + r#" + const STRING: &str = if 1 + 2 == 4 { + "Hello, World!" + } else { + "World, Hello!" + } + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + const STRING: &str = if 1 + 2 == 4 { + "Hello, World!" + } else { + "World, Hello!" + } + + fn something() -> &'static str { + "World, Hello!" + } + "#, + ); + } + + #[test] + fn inline_eval_const_macro_expr_to_str_lit() { + check_assist( + inline_str_literal, + r#" + macro_rules! co {() => {"World, Hello!"};} + const STRING: &str = co!(); + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + macro_rules! co {() => {"World, Hello!"};} + const STRING: &str = co!(); + + fn something() -> &'static str { + "World, Hello!" + } + "#, + ); + } + + #[test] + fn inline_eval_const_call_expr_to_str_lit() { + check_assist( + inline_str_literal, + r#" + const fn const_call() -> &'static str {"World, Hello!"} + const STRING: &str = const_call(); + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + const fn const_call() -> &'static str {"World, Hello!"} + const STRING: &str = const_call(); + + fn something() -> &'static str { + "World, Hello!" + } + "#, + ); + } + + #[test] + fn inline_expr_as_str_lit_not_applicable() { + check_assist_not_applicable( + inline_str_literal, + r#" + const STRING: &str = "Hello, World!"; + + fn something() -> &'static str { + STRING $0 + } + "#, + ); + } + + #[test] + fn inline_expr_as_str_lit_not_applicable_const() { + check_assist_not_applicable( + inline_str_literal, + r#" + const STR$0ING: &str = "Hello, World!"; + + fn something() -> &'static str { + STRING + } + "#, + ); + } } diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index bd282e5343409..bf6b4fdf85c6f 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -288,6 +288,7 @@ mod handlers { raw_string::add_hash, raw_string::make_usual_string, raw_string::remove_hash, + raw_string::inline_str_literal, remove_mut::remove_mut, remove_unused_param::remove_unused_param, remove_parentheses::remove_parentheses, diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 8a35fd290e686..3249b6a25e05e 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -1567,6 +1567,27 @@ fn main() { ) } +#[test] +fn doctest_inline_str_literal() { + check_doc_test( + "inline_str_literal", + r#####" +const STRING: &str = "Hello, World!"; + +fn something() -> &'static str { + STR$0ING +} +"#####, + r#####" +const STRING: &str = "Hello, World!"; + +fn something() -> &'static str { + "Hello, World!" +} +"#####, + ) +} + #[test] fn doctest_inline_type_alias() { check_doc_test( From 8103a10a78e065f866b5b1000468df5c43408889 Mon Sep 17 00:00:00 2001 From: Viktor Lott Date: Wed, 31 May 2023 00:14:38 +0200 Subject: [PATCH 161/465] update assist to include more literals --- crates/hir/src/lib.rs | 8 + .../src/handlers/inline_const_as_literal.rs | 695 ++++++++++++++++++ crates/ide-assists/src/handlers/raw_string.rs | 278 +------ crates/ide-assists/src/lib.rs | 3 +- crates/ide-assists/src/tests/generated.rs | 42 +- 5 files changed, 727 insertions(+), 299 deletions(-) create mode 100644 crates/ide-assists/src/handlers/inline_const_as_literal.rs diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 5926d8654210d..294105dc02ac9 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -3494,6 +3494,14 @@ impl Type { } } + pub fn is_scalar(&self) -> bool { + matches!(self.ty.kind(Interner), TyKind::Scalar(_)) + } + + pub fn is_tuple(&self) -> bool { + matches!(self.ty.kind(Interner), TyKind::Tuple(..)) + } + pub fn remove_ref(&self) -> Option { match &self.ty.kind(Interner) { TyKind::Ref(.., ty) => Some(self.derived(ty.clone())), diff --git a/crates/ide-assists/src/handlers/inline_const_as_literal.rs b/crates/ide-assists/src/handlers/inline_const_as_literal.rs new file mode 100644 index 0000000000000..2503fb0b99a74 --- /dev/null +++ b/crates/ide-assists/src/handlers/inline_const_as_literal.rs @@ -0,0 +1,695 @@ +use syntax::{ast, AstNode}; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +// Assist: inline_const_as_literal +// +// Evaluate and inline const variable as literal. +// +// ``` +// const STRING: &str = "Hello, World!"; +// +// fn something() -> &'static str { +// STRING$0 +// } +// ``` +// -> +// ``` +// const STRING: &str = "Hello, World!"; +// +// fn something() -> &'static str { +// "Hello, World!" +// } +// ``` +pub(crate) fn inline_const_as_literal(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let variable = ctx.find_node_at_offset::()?; + + if let hir::PathResolution::Def(hir::ModuleDef::Const(konst)) = + ctx.sema.resolve_path(&variable.path()?)? + { + let konst_ty = konst.ty(ctx.sema.db); + + let fuel = 20; + + // FIXME: Add support to handle type aliases for builtin scalar types. + // + // There is no way to have a const static reference to a type that contains a interior + // mutability cell. + validate_type_recursively(ctx, Some(&konst_ty), false, fuel)?; + + let expr = konst.value(ctx.sema.db)?; + + // FIXME: Tuples and other sequence types will be inlined even though + // they might contain inner block expressions. + // e.g `(1, { 2 + 3 })` will be inline as it is. + let value = eval_and_inline_recursively(ctx, &konst, &expr, fuel)?; + + let id = AssistId("inline_const_as_literal", AssistKind::RefactorInline); + + let label = format!("Inline as literal"); + let target = variable.syntax().text_range(); + + return acc.add(id, label, target, |edit| { + edit.replace(variable.syntax().text_range(), value); + }); + } + None +} + +fn eval_and_inline_recursively( + ctx: &AssistContext<'_>, + konst: &hir::Const, + expr: &ast::Expr, + fuel: i32, +) -> Option { + match (fuel > 0, expr) { + (true, ast::Expr::BlockExpr(block)) if block.is_standalone() => { + eval_and_inline_recursively(ctx, konst, &block.tail_expr()?, fuel - 1) + } + (_, ast::Expr::Literal(lit)) => Some(lit.to_string()), + + // NOTE: For some expressions, `render_eval` will crash. + // e.g. `{ &[&[&[&[&[&[10, 20, 30]]]]]] }` will fail for `render_eval`. + // + // If these (Ref, Array or Tuple) contain evaluable expression, then we could + // visit/evaluate/walk them one by one, but I think this is enough for now. + // + // Add these if inlining without evaluation is preferred. + // (_, ast::Expr::RefExpr(expr)) => Some(expr.to_string()), + // (_, ast::Expr::ArrayExpr(expr)) => Some(expr.to_string()), + // (_, ast::Expr::TupleExpr(expr)) => Some(expr.to_string()), + + // We should fail on (false, BlockExpr) && is_standalone because we've run out of fuel. BUT + // what is the harm in trying to evaluate the block anyway? Worst case would be that it + // behaves differently when for example: fuel = 1 + // > const A: &[u32] = { &[10] }; OK because we inline ref expression. + // > const B: &[u32] = { { &[10] } }; ERROR because we evaluate block. + (_, ast::Expr::BlockExpr(_)) + | (_, ast::Expr::RefExpr(_)) + | (_, ast::Expr::ArrayExpr(_)) + | (_, ast::Expr::TupleExpr(_)) + | (_, ast::Expr::IfExpr(_)) + | (_, ast::Expr::ParenExpr(_)) + | (_, ast::Expr::MatchExpr(_)) + | (_, ast::Expr::MacroExpr(_)) + | (_, ast::Expr::BinExpr(_)) + | (_, ast::Expr::CallExpr(_)) => match konst.render_eval(ctx.sema.db) { + Ok(result) => Some(result), + Err(_) => return None, + }, + _ => return None, + } +} + +fn validate_type_recursively( + ctx: &AssistContext<'_>, + ty_hir: Option<&hir::Type>, + refed: bool, + fuel: i32, +) -> Option<()> { + match (fuel > 0, ty_hir) { + (true, Some(ty)) if ty.is_reference() => validate_type_recursively( + ctx, + ty.as_reference().map(|(ty, _)| ty).as_ref(), + true, + // FIXME: Saving fuel when `&` repeating. Might not be a good idea. + if refed { fuel } else { fuel - 1 }, + ), + (true, Some(ty)) if ty.is_array() => validate_type_recursively( + ctx, + ty.as_array(ctx.db()).map(|(ty, _)| ty).as_ref(), + false, + fuel - 1, + ), + (true, Some(ty)) if ty.is_tuple() => ty + .tuple_fields(ctx.db()) + .iter() + .all(|ty| validate_type_recursively(ctx, Some(ty), false, fuel - 1).is_some()) + .then_some(()), + (true, Some(ty)) if refed && ty.is_slice() => { + validate_type_recursively(ctx, ty.as_slice().as_ref(), false, fuel - 1) + } + (_, Some(ty)) => match ty.as_builtin() { + // `const A: str` is not correct, `const A: &builtin` is always correct. + Some(builtin) if refed || (!refed && !builtin.is_str()) => Some(()), + _ => None, + }, + _ => None, + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::tests::{check_assist, check_assist_not_applicable}; + + const NUMBER: u8 = 1; + const BOOL: u8 = 2; + const STR: u8 = 4; + const CHAR: u8 = 8; + + const TEST_PAIRS: &[(&str, &str, u8)] = &[ + ("u8", "0", NUMBER), + ("u16", "0", NUMBER), + ("u32", "0", NUMBER), + ("u64", "0", NUMBER), + ("u128", "0", NUMBER), + ("usize", "0", NUMBER), + ("i8", "0", NUMBER), + ("i16", "0", NUMBER), + ("i32", "0", NUMBER), + ("i64", "0", NUMBER), + ("i128", "0", NUMBER), + ("isize", "0", NUMBER), + ("bool", "false", BOOL), + ("&str", "\"str\"", STR), + ("char", "'c'", CHAR), + ]; + + // -----------Not supported----------- + + #[test] + fn inline_const_as_literal_const_fn_call_array() { + TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + check_assist_not_applicable( + inline_const_as_literal, + &format!( + r#" + const fn abc() -> [{ty}; 1] {{ [{val}] }} + const ABC: [{ty}; 1] = abc(); + fn a() {{ A$0BC }} + "# + ), + ); + }); + } + + #[test] + fn inline_const_as_literal_const_fn_call_slice() { + TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + check_assist_not_applicable( + inline_const_as_literal, + &format!( + r#" + const fn abc() -> &[{ty}] {{ &[{val}] }} + const ABC: &[{ty}] = abc(); + fn a() {{ A$0BC }} + "# + ), + ); + }); + } + + #[test] + fn inline_const_as_literal_expr_as_str_lit_not_applicable_const() { + check_assist_not_applicable( + inline_const_as_literal, + r#" + const STR$0ING: &str = "Hello, World!"; + + fn something() -> &'static str { + STRING + } + "#, + ); + } + + // ---------------------------- + + #[test] + fn inline_const_as_literal_const_expr() { + TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + check_assist( + inline_const_as_literal, + &format!( + r#" + const ABC: {ty} = {val}; + fn a() {{ A$0BC }} + "# + ), + &format!( + r#" + const ABC: {ty} = {val}; + fn a() {{ {val} }} + "# + ), + ); + }); + } + + #[test] + fn inline_const_as_literal_const_block_expr() { + TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + check_assist( + inline_const_as_literal, + &format!( + r#" + const ABC: {ty} = {{ {val} }}; + fn a() {{ A$0BC }} + "# + ), + &format!( + r#" + const ABC: {ty} = {{ {val} }}; + fn a() {{ {val} }} + "# + ), + ); + }); + } + + #[test] + fn inline_const_as_literal_const_block_eval_expr() { + TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + check_assist( + inline_const_as_literal, + &format!( + r#" + const ABC: {ty} = {{ true; {val} }}; + fn a() {{ A$0BC }} + "# + ), + &format!( + r#" + const ABC: {ty} = {{ true; {val} }}; + fn a() {{ {val} }} + "# + ), + ); + }); + } + + #[test] + fn inline_const_as_literal_const_block_eval_block_expr() { + TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + check_assist( + inline_const_as_literal, + &format!( + r#" + const ABC: {ty} = {{ true; {{ {val} }} }}; + fn a() {{ A$0BC }} + "# + ), + &format!( + r#" + const ABC: {ty} = {{ true; {{ {val} }} }}; + fn a() {{ {val} }} + "# + ), + ); + }); + } + + #[test] + fn inline_const_as_literal_const_fn_call_block_nested_builtin() { + TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + check_assist( + inline_const_as_literal, + &format!( + r#" + const fn abc() -> {ty} {{ {{ {{ {{ {val} }} }} }} }} + const ABC: {ty} = abc(); + fn a() {{ A$0BC }} + "# + ), + &format!( + r#" + const fn abc() -> {ty} {{ {{ {{ {{ {val} }} }} }} }} + const ABC: {ty} = abc(); + fn a() {{ {val} }} + "# + ), + ); + }); + } + + #[test] + fn inline_const_as_literal_const_fn_call_tuple() { + // FIXME: + // const fn abc() -> (i32) { (1) } + // - results in `1` instead of `(1)`. It handles it as a paren expr + // + // const fn abc() -> (&str, &str) { ("a", "a") } + // - results in `("", "")` instead of `("a", "a")`. + TEST_PAIRS.into_iter().for_each(|(ty, val, bit)| { + // Everything except `&str` + if bit & STR == 0 { + check_assist( + inline_const_as_literal, + &format!( + r#" + const fn abc() -> ({ty}, {ty}) {{ ({val}, {val}) }} + const ABC: ({ty}, {ty}) = abc(); + fn a() {{ A$0BC }} + "# + ), + &format!( + r#" + const fn abc() -> ({ty}, {ty}) {{ ({val}, {val}) }} + const ABC: ({ty}, {ty}) = abc(); + fn a() {{ ({val}, {val}) }} + "# + ), + ); + } + }); + } + + #[test] + fn inline_const_as_literal_const_fn_call_builtin() { + TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + check_assist( + inline_const_as_literal, + &format!( + r#" + const fn abc() -> {ty} {{ {val} }} + const ABC: {ty} = abc(); + fn a() {{ A$0BC }} + "# + ), + &format!( + r#" + const fn abc() -> {ty} {{ {val} }} + const ABC: {ty} = abc(); + fn a() {{ {val} }} + "# + ), + ); + }); + } + + #[test] + fn inline_const_as_literal_scalar_operators() { + check_assist( + inline_const_as_literal, + r#" + const ABC: i32 = 1 + 2 + 3; + fn a() { A$0BC } + "#, + r#" + const ABC: i32 = 1 + 2 + 3; + fn a() { 6 } + "#, + ); + } + #[test] + fn inline_const_as_literal_block_scalar_calculate_expr() { + check_assist( + inline_const_as_literal, + r#" + const ABC: i32 = { 1 + 2 + 3 }; + fn a() { A$0BC } + "#, + r#" + const ABC: i32 = { 1 + 2 + 3 }; + fn a() { 6 } + "#, + ); + } + + #[test] + fn inline_const_as_literal_block_scalar_calculate_param_expr() { + check_assist( + inline_const_as_literal, + r#" + const ABC: i32 = { (1 + 2 + 3) }; + fn a() { A$0BC } + "#, + r#" + const ABC: i32 = { (1 + 2 + 3) }; + fn a() { 6 } + "#, + ); + } + + #[test] + fn inline_const_as_literal_block_tuple_scalar_calculate_block_expr() { + check_assist( + inline_const_as_literal, + r#" + const ABC: (i32, i32) = { (1, { 2 + 3 }) }; + fn a() { A$0BC } + "#, + r#" + const ABC: (i32, i32) = { (1, { 2 + 3 }) }; + fn a() { (1, 5) } + "#, + ); + } + + // FIXME: These won't work with `konst.render_eval(ctx.sema.db)` + // #[test] + // fn inline_const_as_literal_block_slice() { + // check_assist( + // inline_const_as_literal, + // r#" + // const ABC: &[&[&[&[&[&[i32]]]]]] = { &[&[&[&[&[&[10, 20, 30]]]]]] }; + // fn a() { A$0BC } + // "#, + // r#" + // const ABC: &[&[&[&[&[&[i32]]]]]] = { &[&[&[&[&[&[10, 20, 30]]]]]] }; + // fn a() { &[&[&[&[&[&[10, 20, 30]]]]]] } + // "#, + // ); + // } + + // #[test] + // fn inline_const_as_literal_block_array() { + // check_assist( + // inline_const_as_literal, + // r#" + // const ABC: [[[i32; 1]; 1]; 1] = { [[[10]]] }; + // fn a() { A$0BC } + // "#, + // r#" + // const ABC: [[[i32; 1]; 1]; 1] = { [[[10]]] }; + // fn a() { [[[10]]] } + // "#, + // ); + // } + + // #[test] + // fn inline_const_as_literal_block_tuple() { + // check_assist( + // inline_const_as_literal, + // r#" + // const ABC: (([i32; 3]), (i32), ((&str, i32), i32), i32) = { (([1, 2, 3]), (10), (("hello", 10), 20), 30) }; + // fn a() { A$0BC } + // "#, + // r#" + // const ABC: (([i32; 3]), (i32), ((&str, i32), i32), i32) = { (([1, 2, 3]), (10), (("hello", 10), 20), 30) }; + // fn a() { (([1, 2, 3]), (10), (("hello", 10), 20), 30) } + // "#, + // ); + // } + + #[test] + fn inline_const_as_literal_block_recursive() { + check_assist( + inline_const_as_literal, + r#" + const ABC: &str = { { { { "hello" } } } }; + fn a() { A$0BC } + "#, + r#" + const ABC: &str = { { { { "hello" } } } }; + fn a() { "hello" } + "#, + ); + } + + #[test] + fn inline_const_as_literal_expr_as_str_lit() { + check_assist( + inline_const_as_literal, + r#" + const STRING: &str = "Hello, World!"; + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + const STRING: &str = "Hello, World!"; + + fn something() -> &'static str { + "Hello, World!" + } + "#, + ); + } + + #[test] + fn inline_const_as_literal_eval_const_block_expr_to_str_lit() { + check_assist( + inline_const_as_literal, + r#" + const STRING: &str = { + let x = 9; + if x + 10 == 21 { + "Hello, World!" + } else { + "World, Hello!" + } + }; + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + const STRING: &str = { + let x = 9; + if x + 10 == 21 { + "Hello, World!" + } else { + "World, Hello!" + } + }; + + fn something() -> &'static str { + "World, Hello!" + } + "#, + ); + } + + #[test] + fn inline_const_as_literal_eval_const_block_macro_expr_to_str_lit() { + check_assist( + inline_const_as_literal, + r#" + macro_rules! co {() => {"World, Hello!"};} + const STRING: &str = { co!() }; + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + macro_rules! co {() => {"World, Hello!"};} + const STRING: &str = { co!() }; + + fn something() -> &'static str { + "World, Hello!" + } + "#, + ); + } + + #[test] + fn inline_const_as_literal_eval_const_match_expr_to_str_lit() { + check_assist( + inline_const_as_literal, + r#" + const STRING: &str = match 9 + 10 { + 0..18 => "Hello, World!", + _ => "World, Hello!" + }; + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + const STRING: &str = match 9 + 10 { + 0..18 => "Hello, World!", + _ => "World, Hello!" + }; + + fn something() -> &'static str { + "World, Hello!" + } + "#, + ); + } + + #[test] + fn inline_const_as_literal_eval_const_if_expr_to_str_lit() { + check_assist( + inline_const_as_literal, + r#" + const STRING: &str = if 1 + 2 == 4 { + "Hello, World!" + } else { + "World, Hello!" + } + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + const STRING: &str = if 1 + 2 == 4 { + "Hello, World!" + } else { + "World, Hello!" + } + + fn something() -> &'static str { + "World, Hello!" + } + "#, + ); + } + + #[test] + fn inline_const_as_literal_eval_const_macro_expr_to_str_lit() { + check_assist( + inline_const_as_literal, + r#" + macro_rules! co {() => {"World, Hello!"};} + const STRING: &str = co!(); + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + macro_rules! co {() => {"World, Hello!"};} + const STRING: &str = co!(); + + fn something() -> &'static str { + "World, Hello!" + } + "#, + ); + } + + #[test] + fn inline_const_as_literal_eval_const_call_expr_to_str_lit() { + check_assist( + inline_const_as_literal, + r#" + const fn const_call() -> &'static str {"World, Hello!"} + const STRING: &str = const_call(); + + fn something() -> &'static str { + STR$0ING + } + "#, + r#" + const fn const_call() -> &'static str {"World, Hello!"} + const STRING: &str = const_call(); + + fn something() -> &'static str { + "World, Hello!" + } + "#, + ); + } + + #[test] + fn inline_const_as_literal_expr_as_str_lit_not_applicable() { + check_assist_not_applicable( + inline_const_as_literal, + r#" + const STRING: &str = "Hello, World!"; + + fn something() -> &'static str { + STRING $0 + } + "#, + ); + } +} diff --git a/crates/ide-assists/src/handlers/raw_string.rs b/crates/ide-assists/src/handlers/raw_string.rs index 4852b0220e91a..63db60633611f 100644 --- a/crates/ide-assists/src/handlers/raw_string.rs +++ b/crates/ide-assists/src/handlers/raw_string.rs @@ -1,7 +1,6 @@ use std::borrow::Cow; -use ide_db::syntax_helpers::insert_whitespace_into_node::insert_ws_into; -use syntax::{ast, ast::IsString, AstNode, AstToken, TextRange, TextSize}; +use syntax::{ast, ast::IsString, AstToken, TextRange, TextSize}; use crate::{utils::required_hashes, AssistContext, AssistId, AssistKind, Assists}; @@ -157,72 +156,6 @@ pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< }) } -// Assist: inline_str_literal -// -// Inline const variable as static str literal. -// -// ``` -// const STRING: &str = "Hello, World!"; -// -// fn something() -> &'static str { -// STR$0ING -// } -// ``` -// -> -// ``` -// const STRING: &str = "Hello, World!"; -// -// fn something() -> &'static str { -// "Hello, World!" -// } -// ``` -pub(crate) fn inline_str_literal(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let variable = ctx.find_node_at_offset::()?; - - if let hir::PathResolution::Def(hir::ModuleDef::Const(konst)) = - ctx.sema.resolve_path(&variable.path()?)? - { - if !konst.ty(ctx.sema.db).as_reference()?.0.as_builtin()?.is_str() { - return None; - } - - // FIXME: Make sure it's not possible to eval during diagnostic error - let value = match konst.value(ctx.sema.db)? { - ast::Expr::Literal(lit) => lit.to_string(), - ast::Expr::BlockExpr(_) - | ast::Expr::IfExpr(_) - | ast::Expr::MatchExpr(_) - | ast::Expr::CallExpr(_) => match konst.render_eval(ctx.sema.db) { - Ok(result) => result, - Err(_) => return None, - }, - ast::Expr::MacroExpr(makro) => { - let makro_call = makro.syntax().children().find_map(ast::MacroCall::cast)?; - let makro_hir = ctx.sema.resolve_macro_call(&makro_call)?; - - // This should not be necessary because of the `makro_call` check - if !makro_hir.is_fn_like(ctx.sema.db) { - return None; - } - - // FIXME: Make procedural/build-in macro tests - insert_ws_into(ctx.sema.expand(&makro_call)?).to_string() - } - _ => return None, - }; - - let id = AssistId("inline_str_literal", AssistKind::RefactorInline); - let label = "Inline as static `&str` literal"; - let target = variable.syntax().text_range(); - - acc.add(id, label, target, |edit| { - edit.replace(variable.syntax().text_range(), value); - }); - } - - Some(()) -} - #[cfg(test)] mod tests { use super::*; @@ -549,213 +482,4 @@ string"###; "#, ); } - - #[test] - fn inline_expr_as_str_lit() { - check_assist( - inline_str_literal, - r#" - const STRING: &str = "Hello, World!"; - - fn something() -> &'static str { - STR$0ING - } - "#, - r#" - const STRING: &str = "Hello, World!"; - - fn something() -> &'static str { - "Hello, World!" - } - "#, - ); - } - - #[test] - fn inline_eval_const_block_expr_to_str_lit() { - check_assist( - inline_str_literal, - r#" - const STRING: &str = { - let x = 9; - if x + 10 == 21 { - "Hello, World!" - } else { - "World, Hello!" - } - }; - - fn something() -> &'static str { - STR$0ING - } - "#, - r#" - const STRING: &str = { - let x = 9; - if x + 10 == 21 { - "Hello, World!" - } else { - "World, Hello!" - } - }; - - fn something() -> &'static str { - "World, Hello!" - } - "#, - ); - } - - #[test] - fn inline_eval_const_block_macro_expr_to_str_lit() { - check_assist( - inline_str_literal, - r#" - macro_rules! co {() => {"World, Hello!"};} - const STRING: &str = { co!() }; - - fn something() -> &'static str { - STR$0ING - } - "#, - r#" - macro_rules! co {() => {"World, Hello!"};} - const STRING: &str = { co!() }; - - fn something() -> &'static str { - "World, Hello!" - } - "#, - ); - } - - #[test] - fn inline_eval_const_match_expr_to_str_lit() { - check_assist( - inline_str_literal, - r#" - const STRING: &str = match 9 + 10 { - 0..18 => "Hello, World!", - _ => "World, Hello!" - }; - - fn something() -> &'static str { - STR$0ING - } - "#, - r#" - const STRING: &str = match 9 + 10 { - 0..18 => "Hello, World!", - _ => "World, Hello!" - }; - - fn something() -> &'static str { - "World, Hello!" - } - "#, - ); - } - - #[test] - fn inline_eval_const_if_expr_to_str_lit() { - check_assist( - inline_str_literal, - r#" - const STRING: &str = if 1 + 2 == 4 { - "Hello, World!" - } else { - "World, Hello!" - } - - fn something() -> &'static str { - STR$0ING - } - "#, - r#" - const STRING: &str = if 1 + 2 == 4 { - "Hello, World!" - } else { - "World, Hello!" - } - - fn something() -> &'static str { - "World, Hello!" - } - "#, - ); - } - - #[test] - fn inline_eval_const_macro_expr_to_str_lit() { - check_assist( - inline_str_literal, - r#" - macro_rules! co {() => {"World, Hello!"};} - const STRING: &str = co!(); - - fn something() -> &'static str { - STR$0ING - } - "#, - r#" - macro_rules! co {() => {"World, Hello!"};} - const STRING: &str = co!(); - - fn something() -> &'static str { - "World, Hello!" - } - "#, - ); - } - - #[test] - fn inline_eval_const_call_expr_to_str_lit() { - check_assist( - inline_str_literal, - r#" - const fn const_call() -> &'static str {"World, Hello!"} - const STRING: &str = const_call(); - - fn something() -> &'static str { - STR$0ING - } - "#, - r#" - const fn const_call() -> &'static str {"World, Hello!"} - const STRING: &str = const_call(); - - fn something() -> &'static str { - "World, Hello!" - } - "#, - ); - } - - #[test] - fn inline_expr_as_str_lit_not_applicable() { - check_assist_not_applicable( - inline_str_literal, - r#" - const STRING: &str = "Hello, World!"; - - fn something() -> &'static str { - STRING $0 - } - "#, - ); - } - - #[test] - fn inline_expr_as_str_lit_not_applicable_const() { - check_assist_not_applicable( - inline_str_literal, - r#" - const STR$0ING: &str = "Hello, World!"; - - fn something() -> &'static str { - STRING - } - "#, - ); - } } diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index bf6b4fdf85c6f..111753bf30979 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -161,6 +161,7 @@ mod handlers { mod generate_delegate_methods; mod add_return_type; mod inline_call; + mod inline_const_as_literal; mod inline_local_variable; mod inline_macro; mod inline_type_alias; @@ -265,6 +266,7 @@ mod handlers { generate_new::generate_new, inline_call::inline_call, inline_call::inline_into_callers, + inline_const_as_literal::inline_const_as_literal, inline_local_variable::inline_local_variable, inline_type_alias::inline_type_alias, inline_type_alias::inline_type_alias_uses, @@ -288,7 +290,6 @@ mod handlers { raw_string::add_hash, raw_string::make_usual_string, raw_string::remove_hash, - raw_string::inline_str_literal, remove_mut::remove_mut, remove_unused_param::remove_unused_param, remove_parentheses::remove_parentheses, diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 3249b6a25e05e..c097e073980cc 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -1479,6 +1479,27 @@ fn foo(name: Option<&str>) { ) } +#[test] +fn doctest_inline_const_as_literal() { + check_doc_test( + "inline_const_as_literal", + r#####" +const STRING: &str = "Hello, World!"; + +fn something() -> &'static str { + STRING$0 +} +"#####, + r#####" +const STRING: &str = "Hello, World!"; + +fn something() -> &'static str { + "Hello, World!" +} +"#####, + ) +} + #[test] fn doctest_inline_into_callers() { check_doc_test( @@ -1567,27 +1588,6 @@ fn main() { ) } -#[test] -fn doctest_inline_str_literal() { - check_doc_test( - "inline_str_literal", - r#####" -const STRING: &str = "Hello, World!"; - -fn something() -> &'static str { - STR$0ING -} -"#####, - r#####" -const STRING: &str = "Hello, World!"; - -fn something() -> &'static str { - "Hello, World!" -} -"#####, - ) -} - #[test] fn doctest_inline_type_alias() { check_doc_test( From 2d4cb780b69e4c80ec45b7f160985a8857b41b79 Mon Sep 17 00:00:00 2001 From: Viktor Lott Date: Sun, 4 Jun 2023 21:34:25 +0200 Subject: [PATCH 162/465] fix: Use render_eval for all builtins --- .../src/handlers/inline_const_as_literal.rs | 48 ++++++++++++------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/crates/ide-assists/src/handlers/inline_const_as_literal.rs b/crates/ide-assists/src/handlers/inline_const_as_literal.rs index 2503fb0b99a74..c2b537c7420bb 100644 --- a/crates/ide-assists/src/handlers/inline_const_as_literal.rs +++ b/crates/ide-assists/src/handlers/inline_const_as_literal.rs @@ -66,8 +66,6 @@ fn eval_and_inline_recursively( (true, ast::Expr::BlockExpr(block)) if block.is_standalone() => { eval_and_inline_recursively(ctx, konst, &block.tail_expr()?, fuel - 1) } - (_, ast::Expr::Literal(lit)) => Some(lit.to_string()), - // NOTE: For some expressions, `render_eval` will crash. // e.g. `{ &[&[&[&[&[&[10, 20, 30]]]]]] }` will fail for `render_eval`. // @@ -85,6 +83,7 @@ fn eval_and_inline_recursively( // > const A: &[u32] = { &[10] }; OK because we inline ref expression. // > const B: &[u32] = { { &[10] } }; ERROR because we evaluate block. (_, ast::Expr::BlockExpr(_)) + | (_, ast::Expr::Literal(_)) | (_, ast::Expr::RefExpr(_)) | (_, ast::Expr::ArrayExpr(_)) | (_, ast::Expr::TupleExpr(_)) @@ -130,7 +129,7 @@ fn validate_type_recursively( validate_type_recursively(ctx, ty.as_slice().as_ref(), false, fuel - 1) } (_, Some(ty)) => match ty.as_builtin() { - // `const A: str` is not correct, `const A: &builtin` is always correct. + // `const A: str` is not correct, but `const A: &builtin` is. Some(builtin) if refed || (!refed && !builtin.is_str()) => Some(()), _ => None, }, @@ -438,20 +437,35 @@ mod tests { } // FIXME: These won't work with `konst.render_eval(ctx.sema.db)` - // #[test] - // fn inline_const_as_literal_block_slice() { - // check_assist( - // inline_const_as_literal, - // r#" - // const ABC: &[&[&[&[&[&[i32]]]]]] = { &[&[&[&[&[&[10, 20, 30]]]]]] }; - // fn a() { A$0BC } - // "#, - // r#" - // const ABC: &[&[&[&[&[&[i32]]]]]] = { &[&[&[&[&[&[10, 20, 30]]]]]] }; - // fn a() { &[&[&[&[&[&[10, 20, 30]]]]]] } - // "#, - // ); - // } + #[test] + fn inline_const_as_literal_block_slice() { + check_assist( + inline_const_as_literal, + r#" + const ABC: &[&[&[&[&[&[i32]]]]]] = { &[&[&[&[&[&[10, 20, 30]]]]]] }; + fn a() { A$0BC } + "#, + r#" + const ABC: &[&[&[&[&[&[i32]]]]]] = { &[&[&[&[&[&[10, 20, 30]]]]]] }; + fn a() { &[&[&[&[&[&[10, 20, 30]]]]]] } + "#, + ); + } + + #[test] + fn inline_const_as_literal_block_slice_single() { + check_assist( + inline_const_as_literal, + r#" + const ABC: [i32; 1] = { [10] }; + fn a() { A$0BC } + "#, + r#" + const ABC: [i32; 1] = { [10] }; + fn a() { [10] } + "#, + ); + } // #[test] // fn inline_const_as_literal_block_array() { From eef716d5f2a0536a77f59ee7ec1150b811682f7a Mon Sep 17 00:00:00 2001 From: Viktor Lott Date: Tue, 6 Jun 2023 00:33:55 +0200 Subject: [PATCH 163/465] fix: use render_eval instead of inlined expr --- .../src/handlers/inline_const_as_literal.rs | 343 +++++++++--------- 1 file changed, 178 insertions(+), 165 deletions(-) diff --git a/crates/ide-assists/src/handlers/inline_const_as_literal.rs b/crates/ide-assists/src/handlers/inline_const_as_literal.rs index c2b537c7420bb..5b1540b50ca4a 100644 --- a/crates/ide-assists/src/handlers/inline_const_as_literal.rs +++ b/crates/ide-assists/src/handlers/inline_const_as_literal.rs @@ -29,24 +29,38 @@ pub(crate) fn inline_const_as_literal(acc: &mut Assists, ctx: &AssistContext<'_> { let konst_ty = konst.ty(ctx.sema.db); + // Used as the upper limit for recursive calls if no TCO is available let fuel = 20; - // FIXME: Add support to handle type aliases for builtin scalar types. - // // There is no way to have a const static reference to a type that contains a interior // mutability cell. + + // FIXME: Add support to handle type aliases for builtin scalar types. validate_type_recursively(ctx, Some(&konst_ty), false, fuel)?; let expr = konst.value(ctx.sema.db)?; - // FIXME: Tuples and other sequence types will be inlined even though - // they might contain inner block expressions. - // e.g `(1, { 2 + 3 })` will be inline as it is. - let value = eval_and_inline_recursively(ctx, &konst, &expr, fuel)?; + let value = match expr { + ast::Expr::BlockExpr(_) + | ast::Expr::Literal(_) + | ast::Expr::RefExpr(_) + | ast::Expr::ArrayExpr(_) + | ast::Expr::TupleExpr(_) + | ast::Expr::IfExpr(_) + | ast::Expr::ParenExpr(_) + | ast::Expr::MatchExpr(_) + | ast::Expr::MacroExpr(_) + | ast::Expr::BinExpr(_) + | ast::Expr::CallExpr(_) => match konst.render_eval(ctx.sema.db) { + Ok(result) => result, + Err(_) => return None, + }, + _ => return None, + }; let id = AssistId("inline_const_as_literal", AssistKind::RefactorInline); - let label = format!("Inline as literal"); + let label = format!("Inline const as literal"); let target = variable.syntax().text_range(); return acc.add(id, label, target, |edit| { @@ -56,50 +70,6 @@ pub(crate) fn inline_const_as_literal(acc: &mut Assists, ctx: &AssistContext<'_> None } -fn eval_and_inline_recursively( - ctx: &AssistContext<'_>, - konst: &hir::Const, - expr: &ast::Expr, - fuel: i32, -) -> Option { - match (fuel > 0, expr) { - (true, ast::Expr::BlockExpr(block)) if block.is_standalone() => { - eval_and_inline_recursively(ctx, konst, &block.tail_expr()?, fuel - 1) - } - // NOTE: For some expressions, `render_eval` will crash. - // e.g. `{ &[&[&[&[&[&[10, 20, 30]]]]]] }` will fail for `render_eval`. - // - // If these (Ref, Array or Tuple) contain evaluable expression, then we could - // visit/evaluate/walk them one by one, but I think this is enough for now. - // - // Add these if inlining without evaluation is preferred. - // (_, ast::Expr::RefExpr(expr)) => Some(expr.to_string()), - // (_, ast::Expr::ArrayExpr(expr)) => Some(expr.to_string()), - // (_, ast::Expr::TupleExpr(expr)) => Some(expr.to_string()), - - // We should fail on (false, BlockExpr) && is_standalone because we've run out of fuel. BUT - // what is the harm in trying to evaluate the block anyway? Worst case would be that it - // behaves differently when for example: fuel = 1 - // > const A: &[u32] = { &[10] }; OK because we inline ref expression. - // > const B: &[u32] = { { &[10] } }; ERROR because we evaluate block. - (_, ast::Expr::BlockExpr(_)) - | (_, ast::Expr::Literal(_)) - | (_, ast::Expr::RefExpr(_)) - | (_, ast::Expr::ArrayExpr(_)) - | (_, ast::Expr::TupleExpr(_)) - | (_, ast::Expr::IfExpr(_)) - | (_, ast::Expr::ParenExpr(_)) - | (_, ast::Expr::MatchExpr(_)) - | (_, ast::Expr::MacroExpr(_)) - | (_, ast::Expr::BinExpr(_)) - | (_, ast::Expr::CallExpr(_)) => match konst.render_eval(ctx.sema.db) { - Ok(result) => Some(result), - Err(_) => return None, - }, - _ => return None, - } -} - fn validate_type_recursively( ctx: &AssistContext<'_>, ty_hir: Option<&hir::Type>, @@ -111,7 +81,7 @@ fn validate_type_recursively( ctx, ty.as_reference().map(|(ty, _)| ty).as_ref(), true, - // FIXME: Saving fuel when `&` repeating. Might not be a good idea. + // FIXME: Saving fuel when `&` repeating might not be a good idea if there's no TCO. if refed { fuel } else { fuel - 1 }, ), (true, Some(ty)) if ty.is_array() => validate_type_recursively( @@ -166,23 +136,6 @@ mod tests { ]; // -----------Not supported----------- - - #[test] - fn inline_const_as_literal_const_fn_call_array() { - TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { - check_assist_not_applicable( - inline_const_as_literal, - &format!( - r#" - const fn abc() -> [{ty}; 1] {{ [{val}] }} - const ABC: [{ty}; 1] = abc(); - fn a() {{ A$0BC }} - "# - ), - ); - }); - } - #[test] fn inline_const_as_literal_const_fn_call_slice() { TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { @@ -190,10 +143,10 @@ mod tests { inline_const_as_literal, &format!( r#" - const fn abc() -> &[{ty}] {{ &[{val}] }} - const ABC: &[{ty}] = abc(); - fn a() {{ A$0BC }} - "# + const fn abc() -> &[{ty}] {{ &[{val}] }} + const ABC: &[{ty}] = abc(); + fn a() {{ A$0BC }} + "# ), ); }); @@ -213,6 +166,76 @@ mod tests { ); } + #[test] + fn inline_const_as_struct_() { + check_assist_not_applicable( + inline_const_as_literal, + r#" + struct A; + const STRUKT: A = A; + + fn something() -> A { + STRU$0KT + } + "#, + ); + } + + #[test] + fn inline_const_as_enum_() { + check_assist_not_applicable( + inline_const_as_literal, + r#" + enum A { A, B, C } + const ENUM: A = A::A; + + fn something() -> A { + EN$0UM + } + "#, + ); + } + + #[test] + fn inline_const_as_tuple_closure() { + check_assist_not_applicable( + inline_const_as_literal, + r#" + const CLOSURE: (&dyn Fn(i32) -> i32) = (&|num| -> i32 { num }); + fn something() -> (&dyn Fn(i32) -> i32) { + STRU$0KT + } + "#, + ); + } + + #[test] + fn inline_const_as_closure_() { + check_assist_not_applicable( + inline_const_as_literal, + r#" + const CLOSURE: &dyn Fn(i32) -> i32 = &|num| -> i32 { num }; + fn something() -> &dyn Fn(i32) -> i32 { + STRU$0KT + } + "#, + ); + } + + #[test] + fn inline_const_as_fn_() { + check_assist_not_applicable( + inline_const_as_literal, + r#" + struct S(i32); + const CON: fn(i32) -> S = S; + fn something() { + let x = CO$0N; + } + "#, + ); + } + // ---------------------------- #[test] @@ -222,15 +245,15 @@ mod tests { inline_const_as_literal, &format!( r#" - const ABC: {ty} = {val}; - fn a() {{ A$0BC }} - "# + const ABC: {ty} = {val}; + fn a() {{ A$0BC }} + "# ), &format!( r#" - const ABC: {ty} = {val}; - fn a() {{ {val} }} - "# + const ABC: {ty} = {val}; + fn a() {{ {val} }} + "# ), ); }); @@ -243,15 +266,15 @@ mod tests { inline_const_as_literal, &format!( r#" - const ABC: {ty} = {{ {val} }}; - fn a() {{ A$0BC }} - "# + const ABC: {ty} = {{ {val} }}; + fn a() {{ A$0BC }} + "# ), &format!( r#" - const ABC: {ty} = {{ {val} }}; - fn a() {{ {val} }} - "# + const ABC: {ty} = {{ {val} }}; + fn a() {{ {val} }} + "# ), ); }); @@ -264,15 +287,15 @@ mod tests { inline_const_as_literal, &format!( r#" - const ABC: {ty} = {{ true; {val} }}; - fn a() {{ A$0BC }} - "# + const ABC: {ty} = {{ true; {val} }}; + fn a() {{ A$0BC }} + "# ), &format!( r#" - const ABC: {ty} = {{ true; {val} }}; - fn a() {{ {val} }} - "# + const ABC: {ty} = {{ true; {val} }}; + fn a() {{ {val} }} + "# ), ); }); @@ -285,15 +308,15 @@ mod tests { inline_const_as_literal, &format!( r#" - const ABC: {ty} = {{ true; {{ {val} }} }}; - fn a() {{ A$0BC }} - "# + const ABC: {ty} = {{ true; {{ {val} }} }}; + fn a() {{ A$0BC }} + "# ), &format!( r#" - const ABC: {ty} = {{ true; {{ {val} }} }}; - fn a() {{ {val} }} - "# + const ABC: {ty} = {{ true; {{ {val} }} }}; + fn a() {{ {val} }} + "# ), ); }); @@ -306,17 +329,17 @@ mod tests { inline_const_as_literal, &format!( r#" - const fn abc() -> {ty} {{ {{ {{ {{ {val} }} }} }} }} - const ABC: {ty} = abc(); - fn a() {{ A$0BC }} - "# + const fn abc() -> {ty} {{ {{ {{ {{ {val} }} }} }} }} + const ABC: {ty} = abc(); + fn a() {{ A$0BC }} + "# ), &format!( r#" - const fn abc() -> {ty} {{ {{ {{ {{ {val} }} }} }} }} - const ABC: {ty} = abc(); - fn a() {{ {val} }} - "# + const fn abc() -> {ty} {{ {{ {{ {{ {val} }} }} }} }} + const ABC: {ty} = abc(); + fn a() {{ {val} }} + "# ), ); }); @@ -324,33 +347,24 @@ mod tests { #[test] fn inline_const_as_literal_const_fn_call_tuple() { - // FIXME: - // const fn abc() -> (i32) { (1) } - // - results in `1` instead of `(1)`. It handles it as a paren expr - // - // const fn abc() -> (&str, &str) { ("a", "a") } - // - results in `("", "")` instead of `("a", "a")`. - TEST_PAIRS.into_iter().for_each(|(ty, val, bit)| { - // Everything except `&str` - if bit & STR == 0 { - check_assist( - inline_const_as_literal, - &format!( - r#" - const fn abc() -> ({ty}, {ty}) {{ ({val}, {val}) }} - const ABC: ({ty}, {ty}) = abc(); - fn a() {{ A$0BC }} - "# - ), - &format!( - r#" - const fn abc() -> ({ty}, {ty}) {{ ({val}, {val}) }} - const ABC: ({ty}, {ty}) = abc(); - fn a() {{ ({val}, {val}) }} - "# - ), - ); - } + TEST_PAIRS.into_iter().for_each(|(ty, val, _)| { + check_assist( + inline_const_as_literal, + &format!( + r#" + const fn abc() -> ({ty}, {ty}) {{ ({val}, {val}) }} + const ABC: ({ty}, {ty}) = abc(); + fn a() {{ A$0BC }} + "# + ), + &format!( + r#" + const fn abc() -> ({ty}, {ty}) {{ ({val}, {val}) }} + const ABC: ({ty}, {ty}) = abc(); + fn a() {{ ({val}, {val}) }} + "# + ), + ); }); } @@ -436,18 +450,32 @@ mod tests { ); } - // FIXME: These won't work with `konst.render_eval(ctx.sema.db)` + // FIXME: Add support for nested ref slices when using `render_eval` #[test] fn inline_const_as_literal_block_slice() { - check_assist( + check_assist_not_applicable( inline_const_as_literal, r#" const ABC: &[&[&[&[&[&[i32]]]]]] = { &[&[&[&[&[&[10, 20, 30]]]]]] }; fn a() { A$0BC } "#, + ); + } + + // FIXME: Add support for unary tuple expressions when using `render_eval`. + // `const fn abc() -> (i32) { (1) }` will results in `1` instead of `(1)` because it's evaluated + // as a paren expr. + #[test] + fn inline_const_as_literal_block_tuple() { + check_assist( + inline_const_as_literal, r#" - const ABC: &[&[&[&[&[&[i32]]]]]] = { &[&[&[&[&[&[10, 20, 30]]]]]] }; - fn a() { &[&[&[&[&[&[10, 20, 30]]]]]] } + const ABC: (([i32; 3]), (i32), ((&str, i32), i32), i32) = { (([1, 2, 3]), (10), (("hello", 10), 20), 30) }; + fn a() { A$0BC } + "#, + r#" + const ABC: (([i32; 3]), (i32), ((&str, i32), i32), i32) = { (([1, 2, 3]), (10), (("hello", 10), 20), 30) }; + fn a() { ([1, 2, 3], 10, (("hello", 10), 20), 30) } "#, ); } @@ -467,35 +495,20 @@ mod tests { ); } - // #[test] - // fn inline_const_as_literal_block_array() { - // check_assist( - // inline_const_as_literal, - // r#" - // const ABC: [[[i32; 1]; 1]; 1] = { [[[10]]] }; - // fn a() { A$0BC } - // "#, - // r#" - // const ABC: [[[i32; 1]; 1]; 1] = { [[[10]]] }; - // fn a() { [[[10]]] } - // "#, - // ); - // } - - // #[test] - // fn inline_const_as_literal_block_tuple() { - // check_assist( - // inline_const_as_literal, - // r#" - // const ABC: (([i32; 3]), (i32), ((&str, i32), i32), i32) = { (([1, 2, 3]), (10), (("hello", 10), 20), 30) }; - // fn a() { A$0BC } - // "#, - // r#" - // const ABC: (([i32; 3]), (i32), ((&str, i32), i32), i32) = { (([1, 2, 3]), (10), (("hello", 10), 20), 30) }; - // fn a() { (([1, 2, 3]), (10), (("hello", 10), 20), 30) } - // "#, - // ); - // } + #[test] + fn inline_const_as_literal_block_array() { + check_assist( + inline_const_as_literal, + r#" + const ABC: [[[i32; 1]; 1]; 1] = { [[[10]]] }; + fn a() { A$0BC } + "#, + r#" + const ABC: [[[i32; 1]; 1]; 1] = { [[[10]]] }; + fn a() { [[[10]]] } + "#, + ); + } #[test] fn inline_const_as_literal_block_recursive() { From ef095585756108e901af637993932e5be2a1fe28 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 6 Jun 2023 23:02:58 +0200 Subject: [PATCH 164/465] fix: Fix ci never running on nightly when proc-macro things change --- .github/workflows/ci.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 622da105fdd44..92e353ba8f305 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -24,6 +24,7 @@ jobs: pull-requests: read outputs: typescript: ${{ steps.filter.outputs.typescript }} + proc_macros: ${{ steps.filter.outputs.proc_macros }} steps: - uses: actions/checkout@v3 - uses: dorny/paths-filter@4067d885736b84de7c414f582ac45897079b0a78 @@ -45,8 +46,8 @@ jobs: runs-on: ${{ matrix.os }} env: CC: deny_c - RUST_CHANNEL: "${{ needs.changes.outputs.proc_macros == 'true' && 'nightly' || 'stable'}}" - USE_SYSROOT_ABI: "${{ needs.changes.outputs.proc_macros == 'true' && '--features sysroot-abi' || ''}}" + RUST_CHANNEL: "${{ needs.changes.outputs.proc_macros == 'true' && 'nightly' || 'stable' }}" + USE_SYSROOT_ABI: "${{ needs.changes.outputs.proc_macros == 'true' && '--features sysroot-abi' || '' }}" strategy: fail-fast: false From 4bf00613eedd086189afeb59856ac39a1642775a Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Tue, 6 Jun 2023 23:28:15 +0200 Subject: [PATCH 165/465] Fix ICE for nested test function with arguments. --- compiler/rustc_builtin_macros/src/test.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 49ee276af4e6f..af8e92ef88654 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -122,11 +122,7 @@ pub fn expand_test_or_bench( let ast::ItemKind::Fn(fn_) = &item.kind else { not_testable_error(cx, attr_sp, Some(&item)); return if is_stmt { - vec![Annotatable::Stmt(P(ast::Stmt { - id: ast::DUMMY_NODE_ID, - span: item.span, - kind: ast::StmtKind::Item(item), - }))] + vec![Annotatable::Stmt(P(cx.stmt_item(item.span, item)))] } else { vec![Annotatable::Item(item)] }; @@ -138,7 +134,11 @@ pub fn expand_test_or_bench( if (!is_bench && !has_test_signature(cx, &item)) || (is_bench && !has_bench_signature(cx, &item)) { - return vec![Annotatable::Item(item)]; + return if is_stmt { + vec![Annotatable::Stmt(P(cx.stmt_item(item.span, item)))] + } else { + vec![Annotatable::Item(item)] + }; } let sp = cx.with_def_site_ctxt(item.span); From 774f7825cb822142eb7274d3fa1b67411d50d3c1 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Tue, 6 Jun 2023 23:29:29 +0200 Subject: [PATCH 166/465] Deny non-lifetime generics for test functions. Previously, these were allowed if the function returned `()`, but always led to an ambiguity error. --- compiler/rustc_builtin_macros/src/test.rs | 33 +++++++++++------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index af8e92ef88654..fcc68010a34c6 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -3,7 +3,7 @@ use crate::errors; /// Ideally, this code would be in libtest but for efficiency and error messages it lives here. use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute}; use rustc_ast::ptr::P; -use rustc_ast::{self as ast, attr}; +use rustc_ast::{self as ast, attr, GenericParamKind}; use rustc_ast_pretty::pprust; use rustc_errors::Applicability; use rustc_expand::base::*; @@ -550,24 +550,21 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { return false; } - match (has_output, has_should_panic_attr) { - (true, true) => { - sd.span_err(i.span, "functions using `#[should_panic]` must return `()`"); - false - } - (true, false) => { - if !generics.params.is_empty() { - sd.span_err( - i.span, - "functions used as tests must have signature fn() -> ()", - ); - false - } else { - true - } - } - (false, _) => true, + if has_should_panic_attr && has_output { + sd.span_err(i.span, "functions using `#[should_panic]` must return `()`"); + return false; } + + if generics.params.iter().any(|param| !matches!(param.kind, GenericParamKind::Lifetime)) + { + sd.span_err( + i.span, + "functions used as tests can not have any non-lifetime generic parameters", + ); + return false; + } + + true } _ => { // should be unreachable because `is_test_fn_item` should catch all non-fn items From 5049743be2e278e48fcdbb8385820de6cc705cf5 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Tue, 6 Jun 2023 23:32:17 +0200 Subject: [PATCH 167/465] Add test for test function signature verification. --- .../ui/test-attrs/test-function-signature.rs | 31 +++++++++++++++ .../test-attrs/test-function-signature.stderr | 39 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 tests/ui/test-attrs/test-function-signature.rs create mode 100644 tests/ui/test-attrs/test-function-signature.stderr diff --git a/tests/ui/test-attrs/test-function-signature.rs b/tests/ui/test-attrs/test-function-signature.rs new file mode 100644 index 0000000000000..9e86e9209e320 --- /dev/null +++ b/tests/ui/test-attrs/test-function-signature.rs @@ -0,0 +1,31 @@ +// compile-flags: --test + +#[test] +fn foo() -> Result<(), ()> { + Ok(()) +} + +#[test] +fn bar() -> i32 { //~ ERROR the trait bound `i32: Termination` is not satisfied + 0 +} + +#[test] +fn baz(val: i32) {} //~ ERROR functions used as tests can not have any arguments + +#[test] +fn lifetime_generic<'a>() -> Result<(), &'a str> { + Err("coerce me to any lifetime") +} + +#[test] +fn type_generic() {} //~ ERROR functions used as tests can not have any non-lifetime generic parameters + +#[test] +fn const_generic() {} //~ ERROR functions used as tests can not have any non-lifetime generic parameters + +// Regression test for . This used to ICE. +fn nested() { + #[test] + fn foo(arg: ()) {} //~ ERROR functions used as tests can not have any arguments +} diff --git a/tests/ui/test-attrs/test-function-signature.stderr b/tests/ui/test-attrs/test-function-signature.stderr new file mode 100644 index 0000000000000..abdb30dc9312b --- /dev/null +++ b/tests/ui/test-attrs/test-function-signature.stderr @@ -0,0 +1,39 @@ +error: functions used as tests can not have any arguments + --> $DIR/test-function-signature.rs:14:1 + | +LL | fn baz(val: i32) {} + | ^^^^^^^^^^^^^^^^^^^ + +error: functions used as tests can not have any non-lifetime generic parameters + --> $DIR/test-function-signature.rs:22:1 + | +LL | fn type_generic() {} + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions used as tests can not have any non-lifetime generic parameters + --> $DIR/test-function-signature.rs:25:1 + | +LL | fn const_generic() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions used as tests can not have any arguments + --> $DIR/test-function-signature.rs:30:5 + | +LL | fn foo(arg: ()) {} + | ^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `i32: Termination` is not satisfied + --> $DIR/test-function-signature.rs:9:13 + | +LL | #[test] + | ------- in this procedural macro expansion +LL | fn bar() -> i32 { + | ^^^ the trait `Termination` is not implemented for `i32` + | +note: required by a bound in `assert_test_result` + --> $SRC_DIR/test/src/lib.rs:LL:COL + = note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. From a6bef7808fa2ef47d1e44cbed5b9632a46290c0d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 7 Jun 2023 07:02:49 +0200 Subject: [PATCH 168/465] fix: Fix proc-macro slow test --- .github/workflows/ci.yaml | 3 ++- crates/rust-analyzer/tests/slow-tests/main.rs | 13 ++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 92e353ba8f305..31bb7eed8d73f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -63,7 +63,8 @@ jobs: - name: Install Rust toolchain run: | rustup update --no-self-update ${{ env.RUST_CHANNEL }} - rustup component add rustfmt rust-src + rustup component add --toolchain ${{ env.RUST_CHANNEL }} rustfmt rust-src + rustup default ${{ env.RUST_CHANNEL }} - name: Cache Dependencies uses: Swatinem/rust-cache@988c164c3d0e93c4dbab36aaf5bbeb77425b2894 diff --git a/crates/rust-analyzer/tests/slow-tests/main.rs b/crates/rust-analyzer/tests/slow-tests/main.rs index e130c762fc48a..0bb29e7080fb2 100644 --- a/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/crates/rust-analyzer/tests/slow-tests/main.rs @@ -839,6 +839,17 @@ fn resolve_proc_macro() { return; } + // skip using the sysroot config as to prevent us from loading the sysroot sources + let mut rustc = std::process::Command::new(toolchain::rustc()); + rustc.args(["--print", "sysroot"]); + let output = rustc.output().unwrap(); + let sysroot = + vfs::AbsPathBuf::try_from(std::str::from_utf8(&output.stdout).unwrap().trim()).unwrap(); + + let standalone_server_name = + format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX); + let proc_macro_server_path = sysroot.join("libexec").join(&standalone_server_name); + let server = Project::with_fixture( r###" //- /foo/Cargo.toml @@ -916,7 +927,7 @@ pub fn foo(_input: TokenStream) -> TokenStream { }, "procMacro": { "enable": true, - "server": PathBuf::from(env!("CARGO_BIN_EXE_rust-analyzer")), + "server": proc_macro_server_path.as_path().as_ref(), } })) .root("foo") From 08ef169435378b7d49e9f7d7d7ef81abd2171eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 7 Jun 2023 12:33:14 +0300 Subject: [PATCH 169/465] Fix dependency warning --- Cargo.lock | 1 - crates/rust-analyzer/Cargo.toml | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e36aef6a6aa8d..322a67383b030 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1505,7 +1505,6 @@ dependencies = [ "parking_lot 0.12.1", "parking_lot_core 0.9.6", "proc-macro-api", - "proc-macro-srv-cli", "profile", "project-model", "rayon", diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 77f02a83101e3..5b72d57560b24 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -68,7 +68,6 @@ ide-db.workspace = true ide-ssr.workspace = true ide.workspace = true proc-macro-api.workspace = true -proc-macro-srv-cli.workspace = true profile.workspace = true project-model.workspace = true stdx.workspace = true @@ -95,5 +94,5 @@ mbe.workspace = true [features] jemalloc = ["jemallocator", "profile/jemalloc"] force-always-assert = ["always-assert/force"] -sysroot-abi = ["proc-macro-srv-cli/sysroot-abi"] +sysroot-abi = [] in-rust-tree = ["sysroot-abi", "ide/in-rust-tree", "syntax/in-rust-tree"] From 4f0c6fac176d136687436390ae085ac0279b3ba6 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Wed, 7 Jun 2023 18:37:09 +0900 Subject: [PATCH 170/465] fix: only generate trait bound for associated types in field types --- .../builtin_derive_macro.rs | 60 ++++++++ crates/hir-expand/src/builtin_derive_macro.rs | 140 +++++++++--------- crates/hir-ty/src/tests/traits.rs | 10 +- 3 files changed, 139 insertions(+), 71 deletions(-) diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs index 80474bc154d08..1a5ab19e1c254 100644 --- a/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs +++ b/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs @@ -114,6 +114,66 @@ impl core::clone::Clone for Com ); } +#[test] +fn test_clone_expand_with_associated_types() { + check( + r#" +//- minicore: derive, clone +trait Trait { + type InWc; + type InFieldQualified; + type InFieldShorthand; + type InGenericArg; +} +trait Marker {} +struct Vec(T); + +#[derive(Clone)] +struct Foo +where + ::InWc: Marker, +{ + qualified: ::InFieldQualified, + shorthand: T::InFieldShorthand, + generic: Vec, +} +"#, + expect![[r#" +trait Trait { + type InWc; + type InFieldQualified; + type InFieldShorthand; + type InGenericArg; +} +trait Marker {} +struct Vec(T); + +#[derive(Clone)] +struct Foo +where + ::InWc: Marker, +{ + qualified: ::InFieldQualified, + shorthand: T::InFieldShorthand, + generic: Vec, +} + +impl core::clone::Clone for Foo where T: Trait, T::InFieldShorthand: core::clone::Clone, T::InGenericArg: core::clone::Clone, { + fn clone(&self ) -> Self { + match self { + Foo { + qualified: qualified, shorthand: shorthand, generic: generic, + } + =>Foo { + qualified: qualified.clone(), shorthand: shorthand.clone(), generic: generic.clone(), + } + , + } + } +}"#]], + ); +} + #[test] fn test_clone_expand_with_const_generics() { check( diff --git a/crates/hir-expand/src/builtin_derive_macro.rs b/crates/hir-expand/src/builtin_derive_macro.rs index 54706943ac4fd..da34f50660afb 100644 --- a/crates/hir-expand/src/builtin_derive_macro.rs +++ b/crates/hir-expand/src/builtin_derive_macro.rs @@ -4,17 +4,16 @@ use ::tt::Ident; use base_db::{CrateOrigin, LangCrateOrigin}; use itertools::izip; use mbe::TokenMap; -use std::collections::HashSet; +use rustc_hash::FxHashSet; use stdx::never; use tracing::debug; -use crate::tt::{self, TokenId}; -use syntax::{ - ast::{ - self, AstNode, FieldList, HasAttrs, HasGenericParams, HasModuleItem, HasName, - HasTypeBounds, PathType, - }, - match_ast, +use crate::{ + name::{AsName, Name}, + tt::{self, TokenId}, +}; +use syntax::ast::{ + self, AstNode, FieldList, HasAttrs, HasGenericParams, HasModuleItem, HasName, HasTypeBounds, }; use crate::{db::ExpandDatabase, name, quote, ExpandError, ExpandResult, MacroCallId}; @@ -201,33 +200,46 @@ fn parse_adt(tt: &tt::Subtree) -> Result { debug!("no module item parsed"); ExpandError::Other("no item found".into()) })?; - let node = item.syntax(); - let (name, params, shape) = match_ast! { - match node { - ast::Struct(it) => (it.name(), it.generic_param_list(), AdtShape::Struct(VariantShape::from(it.field_list(), &token_map)?)), - ast::Enum(it) => { - let default_variant = it.variant_list().into_iter().flat_map(|x| x.variants()).position(|x| x.attrs().any(|x| x.simple_name() == Some("default".into()))); - ( - it.name(), - it.generic_param_list(), - AdtShape::Enum { - default_variant, - variants: it.variant_list() - .into_iter() - .flat_map(|x| x.variants()) - .map(|x| Ok((name_to_token(&token_map,x.name())?, VariantShape::from(x.field_list(), &token_map)?))).collect::>()? - } - ) - }, - ast::Union(it) => (it.name(), it.generic_param_list(), AdtShape::Union), - _ => { - debug!("unexpected node is {:?}", node); - return Err(ExpandError::Other("expected struct, enum or union".into())) - }, + let adt = ast::Adt::cast(item.syntax().clone()).ok_or_else(|| { + debug!("expected adt, found: {:?}", item); + ExpandError::Other("expected struct, enum or union".into()) + })?; + let (name, generic_param_list, shape) = match &adt { + ast::Adt::Struct(it) => ( + it.name(), + it.generic_param_list(), + AdtShape::Struct(VariantShape::from(it.field_list(), &token_map)?), + ), + ast::Adt::Enum(it) => { + let default_variant = it + .variant_list() + .into_iter() + .flat_map(|x| x.variants()) + .position(|x| x.attrs().any(|x| x.simple_name() == Some("default".into()))); + ( + it.name(), + it.generic_param_list(), + AdtShape::Enum { + default_variant, + variants: it + .variant_list() + .into_iter() + .flat_map(|x| x.variants()) + .map(|x| { + Ok(( + name_to_token(&token_map, x.name())?, + VariantShape::from(x.field_list(), &token_map)?, + )) + }) + .collect::>()?, + }, + ) } + ast::Adt::Union(it) => (it.name(), it.generic_param_list(), AdtShape::Union), }; - let mut param_type_set: HashSet = HashSet::new(); - let param_types = params + + let mut param_type_set: FxHashSet = FxHashSet::default(); + let param_types = generic_param_list .into_iter() .flat_map(|param_list| param_list.type_or_const_params()) .map(|param| { @@ -235,7 +247,7 @@ fn parse_adt(tt: &tt::Subtree) -> Result { let this = param.name(); match this { Some(x) => { - param_type_set.insert(x.to_string()); + param_type_set.insert(x.as_name()); mbe::syntax_node_to_token_tree(x.syntax()).0 } None => tt::Subtree::empty(), @@ -259,37 +271,33 @@ fn parse_adt(tt: &tt::Subtree) -> Result { (name, ty, bounds) }) .collect(); - let is_associated_type = |p: &PathType| { - if let Some(p) = p.path() { - if let Some(parent) = p.qualifier() { - if let Some(x) = parent.segment() { - if let Some(x) = x.path_type() { - if let Some(x) = x.path() { - if let Some(pname) = x.as_single_name_ref() { - if param_type_set.contains(&pname.to_string()) { - // ::Assoc - return true; - } - } - } - } - } - if let Some(pname) = parent.as_single_name_ref() { - if param_type_set.contains(&pname.to_string()) { - // T::Assoc - return true; - } - } - } - } - false + + // For a generic parameter `T`, when shorthand associated type `T::Assoc` appears in field + // types (of any variant for enums), we generate trait bound for it. It sounds reasonable to + // also generate trait bound for qualified associated type `::Assoc`, but rustc + // does not do that for some unknown reason. + // + // See the analogous function in rustc [find_type_parameters()] and rust-lang/rust#50730. + // [find_type_parameters()]: https://github.com/rust-lang/rust/blob/1.70.0/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs#L378 + + // It's cumbersome to deal with the distinct structures of ADTs, so let's just get untyped + // `SyntaxNode` that contains fields and look for descendant `ast::PathType`s. Of note is that + // we should not inspect `ast::PathType`s in parameter bounds and where clauses. + let field_list = match adt { + ast::Adt::Enum(it) => it.variant_list().map(|list| list.syntax().clone()), + ast::Adt::Struct(it) => it.field_list().map(|list| list.syntax().clone()), + ast::Adt::Union(it) => it.record_field_list().map(|list| list.syntax().clone()), }; - let associated_types = node - .descendants() - .filter_map(PathType::cast) - .filter(is_associated_type) + let associated_types = field_list + .into_iter() + .flat_map(|it| it.descendants()) + .filter_map(ast::PathType::cast) + .filter_map(|p| { + let name = p.path()?.qualifier()?.as_single_name_ref()?.as_name(); + param_type_set.contains(&name).then_some(p) + }) .map(|x| mbe::syntax_node_to_token_tree(x.syntax()).0) - .collect::>(); + .collect(); let name_token = name_to_token(&token_map, name)?; Ok(BasicAdtInfo { name: name_token, shape, param_types, associated_types }) } @@ -334,18 +342,18 @@ fn name_to_token(token_map: &TokenMap, name: Option) -> Result tt::Subtree, + make_trait_body: impl FnOnce(&BasicAdtInfo) -> tt::Subtree, ) -> ExpandResult { let info = match parse_adt(tt) { Ok(info) => info, Err(e) => return ExpandResult::new(tt::Subtree::empty(), e), }; - let trait_body = trait_body(&info); + let trait_body = make_trait_body(&info); let mut where_block = vec![]; let (params, args): (Vec<_>, Vec<_>) = info .param_types diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index 829a6ab189ecc..97ae732a90463 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -4335,8 +4335,9 @@ fn derive_macro_bounds() { #[derive(Clone)] struct AssocGeneric(T::Assoc); - #[derive(Clone)] - struct AssocGeneric2(::Assoc); + // Currently rustc does not accept this. + // #[derive(Clone)] + // struct AssocGeneric2(::Assoc); #[derive(Clone)] struct AssocGeneric3(Generic); @@ -4361,9 +4362,8 @@ fn derive_macro_bounds() { let x: &AssocGeneric = &AssocGeneric(NotCopy); let x = x.clone(); //^ &AssocGeneric - let x: &AssocGeneric2 = &AssocGeneric2(NotCopy); - let x = x.clone(); - //^ &AssocGeneric2 + // let x: &AssocGeneric2 = &AssocGeneric2(NotCopy); + // let x = x.clone(); let x: &AssocGeneric3 = &AssocGeneric3(Generic(NotCopy)); let x = x.clone(); //^ &AssocGeneric3 From cdab3507eb5842a66ca04cad972a8901819da3e9 Mon Sep 17 00:00:00 2001 From: Joe Neeman Date: Sat, 3 Jun 2023 12:21:08 -0500 Subject: [PATCH 171/465] Add span to group. --- crates/proc-macro-srv/src/server.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/proc-macro-srv/src/server.rs b/crates/proc-macro-srv/src/server.rs index 37a45bcbb83b8..6fd8de59342c0 100644 --- a/crates/proc-macro-srv/src/server.rs +++ b/crates/proc-macro-srv/src/server.rs @@ -97,7 +97,7 @@ impl server::TokenStream for RustAnalyzer { match tree { bridge::TokenTree::Group(group) => { let group = Group { - delimiter: delim_to_internal(group.delimiter), + delimiter: delim_to_internal(group.delimiter, group.span), token_trees: match group.stream { Some(stream) => stream.into_iter().collect(), None => Vec::new(), @@ -221,14 +221,14 @@ impl server::TokenStream for RustAnalyzer { } } -fn delim_to_internal(d: proc_macro::Delimiter) -> tt::Delimiter { +fn delim_to_internal(d: proc_macro::Delimiter, span: bridge::DelimSpan) -> tt::Delimiter { let kind = match d { proc_macro::Delimiter::Parenthesis => tt::DelimiterKind::Parenthesis, proc_macro::Delimiter::Brace => tt::DelimiterKind::Brace, proc_macro::Delimiter::Bracket => tt::DelimiterKind::Bracket, proc_macro::Delimiter::None => tt::DelimiterKind::Invisible, }; - tt::Delimiter { open: tt::TokenId::unspecified(), close: tt::TokenId::unspecified(), kind } + tt::Delimiter { open: span.open, close: span.close, kind } } fn delim_to_external(d: tt::Delimiter) -> proc_macro::Delimiter { From ad2a0d109330952b6bc15fba43dffccce7f96a70 Mon Sep 17 00:00:00 2001 From: Joe Neeman Date: Tue, 6 Jun 2023 17:39:50 -0500 Subject: [PATCH 172/465] Add configurable proc-macro-srv path for diagnostics --- crates/rust-analyzer/src/cli/diagnostics.rs | 8 +++++++- crates/rust-analyzer/src/cli/flags.rs | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs index 4006d023def52..4306d721298d9 100644 --- a/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/crates/rust-analyzer/src/cli/diagnostics.rs @@ -17,9 +17,15 @@ impl flags::Diagnostics { pub fn run(self) -> anyhow::Result<()> { let mut cargo_config = CargoConfig::default(); cargo_config.sysroot = Some(RustLibSource::Discover); + let with_proc_macro_server = if let Some(p) = &self.proc_macro_srv { + let path = vfs::AbsPathBuf::assert(std::env::current_dir()?.join(&p)); + ProcMacroServerChoice::Explicit(path) + } else { + ProcMacroServerChoice::Sysroot + }; let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: !self.disable_build_scripts, - with_proc_macro_server: ProcMacroServerChoice::Sysroot, + with_proc_macro_server, prefill_caches: false, }; let (host, _vfs, _proc_macro) = diff --git a/crates/rust-analyzer/src/cli/flags.rs b/crates/rust-analyzer/src/cli/flags.rs index 31012c01b9530..c1ca03ceae401 100644 --- a/crates/rust-analyzer/src/cli/flags.rs +++ b/crates/rust-analyzer/src/cli/flags.rs @@ -92,6 +92,8 @@ xflags::xflags! { optional --disable-build-scripts /// Don't use expand proc macros. optional --disable-proc-macros + /// Run a custom proc-macro-srv binary. + optional --proc-macro-srv path: PathBuf } cmd ssr { @@ -189,6 +191,7 @@ pub struct Diagnostics { pub disable_build_scripts: bool, pub disable_proc_macros: bool, + pub proc_macro_srv: Option, } #[derive(Debug)] From dac660dc1df05576f85771cb47c8ec3e468bd520 Mon Sep 17 00:00:00 2001 From: beyarkay Date: Wed, 7 Jun 2023 20:55:19 +0200 Subject: [PATCH 173/465] Fix typo in reload.rs --- crates/rust-analyzer/src/reload.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 6e8c8ea91a1b3..c875c6ba42bb4 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -110,7 +110,7 @@ impl GlobalState { if self.proc_macro_changed { status.health = lsp_ext::Health::Warning; - message.push_str("Proc-macros have changed and need to be rebuild.\n\n"); + message.push_str("Proc-macros have changed and need to be rebuilt.\n\n"); } if let Err(_) = self.fetch_build_data_error() { status.health = lsp_ext::Health::Warning; From 30e16e20d0f99efc025f2e6286b46f8217a7b682 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Thu, 8 Jun 2023 00:17:22 +0330 Subject: [PATCH 174/465] Fix unwrap on None in expanding format args --- .../macro_expansion_tests/builtin_fn_macro.rs | 38 +++++++++++++++++++ crates/hir-expand/src/builtin_fn_macro.rs | 7 ++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index 977f300636f5e..541b0ad7066dd 100644 --- a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -207,6 +207,44 @@ fn main() { ); } +#[test] +fn regression_15002() { + check( + r#" +#[rustc_builtin_macro] +macro_rules! format_args { + ($fmt:expr) => ({ /* compiler built-in */ }); + ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) +} + +fn main() { + format_args!(x = 2); + format_args!(x =); + format_args!(x =, x = 2); + format_args!("{}", x =); + format_args!(=, "{}", x =); + format_args!(x = 2, "{}", 5); +} +"#, + expect![[r##" +#[rustc_builtin_macro] +macro_rules! format_args { + ($fmt:expr) => ({ /* compiler built-in */ }); + ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) +} + +fn main() { + /* error: no rule matches input tokens */; + /* error: no rule matches input tokens */; + /* error: no rule matches input tokens */; + /* error: no rule matches input tokens */::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::Argument::new(&(), ::core::fmt::Display::fmt), ]); + /* error: no rule matches input tokens */; + ::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::Argument::new(&(5), ::core::fmt::Display::fmt), ]); +} +"##]], + ); +} + #[test] fn test_format_args_expand_with_comma_exprs() { check( diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs index c7643bd0a18eb..5f47fd90c5c04 100644 --- a/crates/hir-expand/src/builtin_fn_macro.rs +++ b/crates/hir-expand/src/builtin_fn_macro.rs @@ -262,9 +262,6 @@ fn format_args_expand_general( let expand_error = ExpandResult::new(tt::Subtree::empty(), mbe::ExpandError::NoMatchingRule.into()); - if args.is_empty() { - return expand_error; - } let mut key_args = FxHashMap::default(); let mut args = args.into_iter().filter_map(|mut arg| { // Remove `key =`. @@ -281,7 +278,9 @@ fn format_args_expand_general( Some(arg) }).collect::>().into_iter(); // ^^^^^^^ we need this collect, to enforce the side effect of the filter_map closure (building the `key_args`) - let format_subtree = args.next().unwrap(); + let Some(format_subtree) = args.next() else { + return expand_error; + }; let format_string = (|| { let token_tree = format_subtree.token_trees.get(0)?; match token_tree { From 32768fe310ac9ab4f92dfc637b02632ed1c59ec7 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Thu, 8 Jun 2023 23:47:21 +0900 Subject: [PATCH 175/465] Infer return type for async function in `generate_function` --- .../src/handlers/generate_function.rs | 102 ++++++++++++++---- 1 file changed, 84 insertions(+), 18 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs index 850be21c300ca..c579f6780db85 100644 --- a/crates/ide-assists/src/handlers/generate_function.rs +++ b/crates/ide-assists/src/handlers/generate_function.rs @@ -291,12 +291,9 @@ impl FunctionBuilder { let await_expr = call.syntax().parent().and_then(ast::AwaitExpr::cast); let is_async = await_expr.is_some(); - let (ret_type, should_focus_return_type) = make_return_type( - ctx, - &ast::Expr::CallExpr(call.clone()), - target_module, - &mut necessary_generic_params, - ); + let expr_for_ret_ty = await_expr.map_or_else(|| call.clone().into(), |it| it.into()); + let (ret_type, should_focus_return_type) = + make_return_type(ctx, &expr_for_ret_ty, target_module, &mut necessary_generic_params); let (generic_param_list, where_clause) = fn_generic_params(ctx, necessary_generic_params, &target)?; @@ -338,12 +335,9 @@ impl FunctionBuilder { let await_expr = call.syntax().parent().and_then(ast::AwaitExpr::cast); let is_async = await_expr.is_some(); - let (ret_type, should_focus_return_type) = make_return_type( - ctx, - &ast::Expr::MethodCallExpr(call.clone()), - target_module, - &mut necessary_generic_params, - ); + let expr_for_ret_ty = await_expr.map_or_else(|| call.clone().into(), |it| it.into()); + let (ret_type, should_focus_return_type) = + make_return_type(ctx, &expr_for_ret_ty, target_module, &mut necessary_generic_params); let (generic_param_list, where_clause) = fn_generic_params(ctx, necessary_generic_params, &target)?; @@ -429,12 +423,12 @@ impl FunctionBuilder { /// user can change the `todo!` function body. fn make_return_type( ctx: &AssistContext<'_>, - call: &ast::Expr, + expr: &ast::Expr, target_module: Module, necessary_generic_params: &mut FxHashSet, ) -> (Option, bool) { let (ret_ty, should_focus_return_type) = { - match ctx.sema.type_of_expr(call).map(TypeInfo::original) { + match ctx.sema.type_of_expr(expr).map(TypeInfo::original) { Some(ty) if ty.is_unknown() => (Some(make::ty_placeholder()), true), None => (Some(make::ty_placeholder()), true), Some(ty) if ty.is_unit() => (None, false), @@ -2268,13 +2262,13 @@ impl Foo { check_assist( generate_function, r" -fn foo() { - $0bar(42).await(); +async fn foo() { + $0bar(42).await; } ", r" -fn foo() { - bar(42).await(); +async fn foo() { + bar(42).await; } async fn bar(arg: i32) ${0:-> _} { @@ -2284,6 +2278,28 @@ async fn bar(arg: i32) ${0:-> _} { ) } + #[test] + fn return_type_for_async_fn() { + check_assist( + generate_function, + r" +//- minicore: result +async fn foo() { + if Err(()) = $0bar(42).await {} +} +", + r" +async fn foo() { + if Err(()) = bar(42).await {} +} + +async fn bar(arg: i32) -> Result<_, ()> { + ${0:todo!()} +} +", + ); + } + #[test] fn create_method() { check_assist( @@ -2401,6 +2417,31 @@ fn foo() {S.bar();} ) } + #[test] + fn create_async_method() { + check_assist( + generate_function, + r" +//- minicore: result +struct S; +async fn foo() { + if let Err(()) = S.$0bar(42).await {} +} +", + r" +struct S; +impl S { + async fn bar(&self, arg: i32) -> Result<_, ()> { + ${0:todo!()} + } +} +async fn foo() { + if let Err(()) = S.bar(42).await {} +} +", + ) + } + #[test] fn create_static_method() { check_assist( @@ -2421,6 +2462,31 @@ fn foo() {S::bar();} ) } + #[test] + fn create_async_static_method() { + check_assist( + generate_function, + r" +//- minicore: result +struct S; +async fn foo() { + if let Err(()) = S::$0bar(42).await {} +} +", + r" +struct S; +impl S { + async fn bar(arg: i32) -> Result<_, ()> { + ${0:todo!()} + } +} +async fn foo() { + if let Err(()) = S::bar(42).await {} +} +", + ) + } + #[test] fn create_generic_static_method() { check_assist( From 5da14237eb2994a73e8864cf88359bc2308d4864 Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Thu, 8 Jun 2023 14:56:37 -0700 Subject: [PATCH 176/465] Document the sysroot field in JsonProject rust-analyzer supports both `sysroot` and `sysroot_src` in `rust-project.json`. Document `sysroot` and show example values for both fields. --- docs/user/manual.adoc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index 5b9db10b093d7..98d99bae92ae9 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -653,9 +653,28 @@ However, if you use some other build system, you'll have to describe the structu [source,TypeScript] ---- interface JsonProject { + /// Path to the sysroot directory. + /// + /// The sysroot is where rustc looks for the + /// crates that are built-in to rust, such as + /// std. + /// + /// https://doc.rust-lang.org/rustc/command-line-arguments.html#--sysroot-override-the-system-root + /// + /// To see the current value of sysroot, you + /// can query rustc: + /// + /// ``` + /// $ rustc --print sysroot + /// /Users/yourname/.rustup/toolchains/stable-x86_64-apple-darwin + /// ``` + sysroot?: string; /// Path to the directory with *source code* of /// sysroot crates. /// + /// By default, this is `lib/rustlib/src/rust/library` + /// relative to the sysroot. + /// /// It should point to the directory where std, /// core, and friends can be found: /// From a02b9b279e4c5215aab1a99ebe37b9639e20a041 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 7 Jun 2023 11:20:10 +0200 Subject: [PATCH 177/465] internal: Lazy eager macros --- crates/hir-def/src/expander.rs | 10 +- crates/hir-def/src/lib.rs | 6 +- .../macro_expansion_tests/builtin_fn_macro.rs | 10 +- crates/hir-expand/src/builtin_derive_macro.rs | 8 +- crates/hir-expand/src/builtin_fn_macro.rs | 140 +++++++----------- crates/hir-expand/src/db.rs | 108 +++++++------- crates/hir-expand/src/eager.rs | 84 ++++++----- crates/hir-expand/src/lib.rs | 72 +++++++-- crates/hir-expand/src/proc_macro.rs | 11 +- .../ide-db/src/test_data/test_doc_alias.txt | 42 ++++-- .../test_symbol_index_collection.txt | 134 +++++++++++------ .../test_data/highlight_strings.html | 3 + crates/ide/src/syntax_highlighting/tests.rs | 3 + 13 files changed, 355 insertions(+), 276 deletions(-) diff --git a/crates/hir-def/src/expander.rs b/crates/hir-def/src/expander.rs index 34ed1e72f2001..31653916f4112 100644 --- a/crates/hir-def/src/expander.rs +++ b/crates/hir-def/src/expander.rs @@ -113,10 +113,10 @@ impl Expander { call_id: MacroCallId, error: Option, ) -> ExpandResult>>> { - let file_id = call_id.as_file(); - let ExpandResult { value, err } = db.parse_or_expand_with_err(file_id); + let macro_file = call_id.as_macro_file(); + let ExpandResult { value, err } = db.parse_macro_expansion(macro_file); - ExpandResult { value: Some(InFile::new(file_id, value)), err: error.or(err) } + ExpandResult { value: Some(InFile::new(macro_file.into(), value.0)), err: error.or(err) } } pub fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { @@ -179,8 +179,8 @@ impl Expander { } else if self.recursion_limit.check(self.recursion_depth as usize + 1).is_err() { self.recursion_depth = u32::MAX; cov_mark::hit!(your_stack_belongs_to_me); - return ExpandResult::only_err(ExpandError::Other( - "reached recursion limit during macro expansion".into(), + return ExpandResult::only_err(ExpandError::other( + "reached recursion limit during macro expansion", )); } diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 9cd3dfd6f7c96..02593609e73b1 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -71,7 +71,7 @@ use hir_expand::{ builtin_derive_macro::BuiltinDeriveExpander, builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander}, db::ExpandDatabase, - eager::expand_eager_macro, + eager::expand_eager_macro_input, hygiene::Hygiene, proc_macro::ProcMacroExpander, AstId, ExpandError, ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, @@ -865,7 +865,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> { let path = self.value.path().and_then(|path| path::ModPath::from_src(db, path, &h)); let Some(path) = path else { - return Ok(ExpandResult::only_err(ExpandError::Other("malformed macro invocation".into()))); + return Ok(ExpandResult::only_err(ExpandError::other("malformed macro invocation"))); }; macro_call_as_call_id_( @@ -913,7 +913,7 @@ fn macro_call_as_call_id_( let res = if let MacroDefKind::BuiltInEager(..) = def.kind { let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db)); - expand_eager_macro(db, krate, macro_call, def, &resolver)? + expand_eager_macro_input(db, krate, macro_call, def, &resolver)? } else { ExpandResult { value: Some(def.as_lazy_macro( diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index 541b0ad7066dd..07d9baa589749 100644 --- a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -79,7 +79,7 @@ fn main() { env!("TEST_ENV_VAR"); } #[rustc_builtin_macro] macro_rules! env {() => {}} -fn main() { "__RA_UNIMPLEMENTED__"; } +fn main() { "UNRESOLVED_ENV_VAR"; } "##]], ); } @@ -442,10 +442,6 @@ macro_rules! surprise { () => { "s" }; } -macro_rules! stuff { - ($string:expr) => { concat!($string) }; -} - fn main() { concat!(surprise!()); } "##, expect![[r##" @@ -456,10 +452,6 @@ macro_rules! surprise { () => { "s" }; } -macro_rules! stuff { - ($string:expr) => { concat!($string) }; -} - fn main() { "s"; } "##]], ); diff --git a/crates/hir-expand/src/builtin_derive_macro.rs b/crates/hir-expand/src/builtin_derive_macro.rs index da34f50660afb..976cd6a4ddeb0 100644 --- a/crates/hir-expand/src/builtin_derive_macro.rs +++ b/crates/hir-expand/src/builtin_derive_macro.rs @@ -194,15 +194,15 @@ fn parse_adt(tt: &tt::Subtree) -> Result { let (parsed, token_map) = mbe::token_tree_to_syntax_node(tt, mbe::TopEntryPoint::MacroItems); let macro_items = ast::MacroItems::cast(parsed.syntax_node()).ok_or_else(|| { debug!("derive node didn't parse"); - ExpandError::Other("invalid item definition".into()) + ExpandError::other("invalid item definition") })?; let item = macro_items.items().next().ok_or_else(|| { debug!("no module item parsed"); - ExpandError::Other("no item found".into()) + ExpandError::other("no item found") })?; let adt = ast::Adt::cast(item.syntax().clone()).ok_or_else(|| { debug!("expected adt, found: {:?}", item); - ExpandError::Other("expected struct, enum or union".into()) + ExpandError::other("expected struct, enum or union") })?; let (name, generic_param_list, shape) = match &adt { ast::Adt::Struct(it) => ( @@ -305,7 +305,7 @@ fn parse_adt(tt: &tt::Subtree) -> Result { fn name_to_token(token_map: &TokenMap, name: Option) -> Result { let name = name.ok_or_else(|| { debug!("parsed item has no name"); - ExpandError::Other("missing name".into()) + ExpandError::other("missing name") })?; let name_token_id = token_map.token_by_range(name.syntax().text_range()).unwrap_or_else(TokenId::unspecified); diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs index 5f47fd90c5c04..a9f0c154b02bc 100644 --- a/crates/hir-expand/src/builtin_fn_macro.rs +++ b/crates/hir-expand/src/builtin_fn_macro.rs @@ -14,7 +14,8 @@ use syntax::{ }; use crate::{ - db::ExpandDatabase, name, quote, tt, ExpandError, ExpandResult, MacroCallId, MacroCallLoc, + db::ExpandDatabase, name, quote, tt, EagerCallInfo, ExpandError, ExpandResult, MacroCallId, + MacroCallLoc, }; macro_rules! register_builtin { @@ -49,7 +50,7 @@ macro_rules! register_builtin { db: &dyn ExpandDatabase, arg_id: MacroCallId, tt: &tt::Subtree, - ) -> ExpandResult { + ) -> ExpandResult { let expander = match *self { $( EagerExpander::$e_kind => $e_expand, )* }; @@ -67,16 +68,9 @@ macro_rules! register_builtin { }; } -#[derive(Debug)] -pub struct ExpandedEager { - pub(crate) subtree: tt::Subtree, - /// The included file ID of the include macro. - pub(crate) included_file: Option<(FileId, TokenMap)>, -} - -impl ExpandedEager { - fn new(subtree: tt::Subtree) -> Self { - ExpandedEager { subtree, included_file: None } +impl EagerExpander { + pub fn is_include(&self) -> bool { + matches!(self, EagerExpander::Include) } } @@ -237,18 +231,16 @@ fn format_args_expand( db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult { +) -> ExpandResult { format_args_expand_general(db, id, tt, "") - .map(|x| ExpandedEager { subtree: x, included_file: None }) } fn format_args_nl_expand( db: &dyn ExpandDatabase, id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult { +) -> ExpandResult { format_args_expand_general(db, id, tt, "\\n") - .map(|x| ExpandedEager { subtree: x, included_file: None }) } fn format_args_expand_general( @@ -509,23 +501,23 @@ fn compile_error_expand( _db: &dyn ExpandDatabase, _id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult { +) -> ExpandResult { let err = match &*tt.token_trees { [tt::TokenTree::Leaf(tt::Leaf::Literal(it))] => match unquote_str(it) { - Some(unquoted) => ExpandError::Other(unquoted.into()), - None => ExpandError::Other("`compile_error!` argument must be a string".into()), + Some(unquoted) => ExpandError::other(unquoted), + None => ExpandError::other("`compile_error!` argument must be a string"), }, - _ => ExpandError::Other("`compile_error!` argument must be a string".into()), + _ => ExpandError::other("`compile_error!` argument must be a string"), }; - ExpandResult { value: ExpandedEager::new(quote! {}), err: Some(err) } + ExpandResult { value: quote! {}, err: Some(err) } } fn concat_expand( _db: &dyn ExpandDatabase, _arg_id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult { +) -> ExpandResult { let mut err = None; let mut text = String::new(); for (i, mut t) in tt.token_trees.iter().enumerate() { @@ -564,14 +556,14 @@ fn concat_expand( } } } - ExpandResult { value: ExpandedEager::new(quote!(#text)), err } + ExpandResult { value: quote!(#text), err } } fn concat_bytes_expand( _db: &dyn ExpandDatabase, _arg_id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult { +) -> ExpandResult { let mut bytes = Vec::new(); let mut err = None; for (i, t) in tt.token_trees.iter().enumerate() { @@ -604,7 +596,7 @@ fn concat_bytes_expand( } } let ident = tt::Ident { text: bytes.join(", ").into(), span: tt::TokenId::unspecified() }; - ExpandResult { value: ExpandedEager::new(quote!([#ident])), err } + ExpandResult { value: quote!([#ident]), err } } fn concat_bytes_expand_subtree( @@ -637,7 +629,7 @@ fn concat_idents_expand( _db: &dyn ExpandDatabase, _arg_id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult { +) -> ExpandResult { let mut err = None; let mut ident = String::new(); for (i, t) in tt.token_trees.iter().enumerate() { @@ -652,7 +644,7 @@ fn concat_idents_expand( } } let ident = tt::Ident { text: ident.into(), span: tt::TokenId::unspecified() }; - ExpandResult { value: ExpandedEager::new(quote!(#ident)), err } + ExpandResult { value: quote!(#ident), err } } fn relative_file( @@ -665,10 +657,10 @@ fn relative_file( let path = AnchoredPath { anchor: call_site, path: path_str }; let res = db .resolve_path(path) - .ok_or_else(|| ExpandError::Other(format!("failed to load file `{path_str}`").into()))?; + .ok_or_else(|| ExpandError::other(format!("failed to load file `{path_str}`")))?; // Prevent include itself if res == call_site && !allow_recursion { - Err(ExpandError::Other(format!("recursive inclusion of `{path_str}`").into())) + Err(ExpandError::other(format!("recursive inclusion of `{path_str}`"))) } else { Ok(res) } @@ -687,38 +679,37 @@ fn parse_string(tt: &tt::Subtree) -> Result { fn include_expand( db: &dyn ExpandDatabase, arg_id: MacroCallId, - tt: &tt::Subtree, -) -> ExpandResult { - let res = (|| { - let path = parse_string(tt)?; - let file_id = relative_file(db, arg_id, &path, false)?; - - let (subtree, map) = - parse_to_token_tree(&db.file_text(file_id)).ok_or(mbe::ExpandError::ConversionError)?; - Ok((subtree, map, file_id)) - })(); - - match res { - Ok((subtree, map, file_id)) => { - ExpandResult::ok(ExpandedEager { subtree, included_file: Some((file_id, map)) }) - } - Err(e) => ExpandResult::new( - ExpandedEager { subtree: tt::Subtree::empty(), included_file: None }, - e, - ), + _tt: &tt::Subtree, +) -> ExpandResult { + match db.include_expand(arg_id) { + Ok((res, _)) => ExpandResult::ok(res.0.clone()), + Err(e) => ExpandResult::new(tt::Subtree::empty(), e), } } +pub(crate) fn include_arg_to_tt( + db: &dyn ExpandDatabase, + arg_id: MacroCallId, +) -> Result<(triomphe::Arc<(::tt::Subtree<::tt::TokenId>, TokenMap)>, FileId), ExpandError> { + let loc = db.lookup_intern_macro_call(arg_id); + let Some(EagerCallInfo {arg, arg_id: Some(arg_id), .. }) = loc.eager.as_deref() else { + panic!("include_arg_to_tt called on non include macro call: {:?}", &loc.eager); + }; + let path = parse_string(&arg.0)?; + let file_id = relative_file(db, *arg_id, &path, false)?; + + let (subtree, map) = + parse_to_token_tree(&db.file_text(file_id)).ok_or(mbe::ExpandError::ConversionError)?; + Ok((triomphe::Arc::new((subtree, map)), file_id)) +} + fn include_bytes_expand( _db: &dyn ExpandDatabase, _arg_id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult { +) -> ExpandResult { if let Err(e) = parse_string(tt) { - return ExpandResult::new( - ExpandedEager { subtree: tt::Subtree::empty(), included_file: None }, - e, - ); + return ExpandResult::new(tt::Subtree::empty(), e); } // FIXME: actually read the file here if the user asked for macro expansion @@ -729,22 +720,17 @@ fn include_bytes_expand( span: tt::TokenId::unspecified(), }))], }; - ExpandResult::ok(ExpandedEager::new(res)) + ExpandResult::ok(res) } fn include_str_expand( db: &dyn ExpandDatabase, arg_id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult { +) -> ExpandResult { let path = match parse_string(tt) { Ok(it) => it, - Err(e) => { - return ExpandResult::new( - ExpandedEager { subtree: tt::Subtree::empty(), included_file: None }, - e, - ) - } + Err(e) => return ExpandResult::new(tt::Subtree::empty(), e), }; // FIXME: we're not able to read excluded files (which is most of them because @@ -754,14 +740,14 @@ fn include_str_expand( let file_id = match relative_file(db, arg_id, &path, true) { Ok(file_id) => file_id, Err(_) => { - return ExpandResult::ok(ExpandedEager::new(quote!(""))); + return ExpandResult::ok(quote!("")); } }; let text = db.file_text(file_id); let text = &*text; - ExpandResult::ok(ExpandedEager::new(quote!(#text))) + ExpandResult::ok(quote!(#text)) } fn get_env_inner(db: &dyn ExpandDatabase, arg_id: MacroCallId, key: &str) -> Option { @@ -773,15 +759,10 @@ fn env_expand( db: &dyn ExpandDatabase, arg_id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult { +) -> ExpandResult { let key = match parse_string(tt) { Ok(it) => it, - Err(e) => { - return ExpandResult::new( - ExpandedEager { subtree: tt::Subtree::empty(), included_file: None }, - e, - ) - } + Err(e) => return ExpandResult::new(tt::Subtree::empty(), e), }; let mut err = None; @@ -789,35 +770,28 @@ fn env_expand( // The only variable rust-analyzer ever sets is `OUT_DIR`, so only diagnose that to avoid // unnecessary diagnostics for eg. `CARGO_PKG_NAME`. if key == "OUT_DIR" { - err = Some(ExpandError::Other( - r#"`OUT_DIR` not set, enable "build scripts" to fix"#.into(), - )); + err = Some(ExpandError::other(r#"`OUT_DIR` not set, enable "build scripts" to fix"#)); } // If the variable is unset, still return a dummy string to help type inference along. // We cannot use an empty string here, because for // `include!(concat!(env!("OUT_DIR"), "/foo.rs"))` will become // `include!("foo.rs"), which might go to infinite loop - "__RA_UNIMPLEMENTED__".to_string() + "UNRESOLVED_ENV_VAR".to_string() }); let expanded = quote! { #s }; - ExpandResult { value: ExpandedEager::new(expanded), err } + ExpandResult { value: expanded, err } } fn option_env_expand( db: &dyn ExpandDatabase, arg_id: MacroCallId, tt: &tt::Subtree, -) -> ExpandResult { +) -> ExpandResult { let key = match parse_string(tt) { Ok(it) => it, - Err(e) => { - return ExpandResult::new( - ExpandedEager { subtree: tt::Subtree::empty(), included_file: None }, - e, - ) - } + Err(e) => return ExpandResult::new(tt::Subtree::empty(), e), }; // FIXME: Use `DOLLAR_CRATE` when that works in eager macros. let expanded = match get_env_inner(db, arg_id, &key) { @@ -825,5 +799,5 @@ fn option_env_expand( Some(s) => quote! { ::core::option::Option::Some(#s) }, }; - ExpandResult::ok(ExpandedEager::new(expanded)) + ExpandResult::ok(expanded) } diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index 965dfa824d8f9..78b2db7306b92 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -14,9 +14,9 @@ use triomphe::Arc; use crate::{ ast_id_map::AstIdMap, builtin_attr_macro::pseudo_derive_attr_expansion, builtin_fn_macro::EagerExpander, fixup, hygiene::HygieneFrame, tt, BuiltinAttrExpander, - BuiltinDeriveExpander, BuiltinFnLikeExpander, ExpandError, ExpandResult, ExpandTo, HirFileId, - HirFileIdRepr, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, - ProcMacroExpander, + BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo, ExpandError, ExpandResult, + ExpandTo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, + MacroDefKind, MacroFile, ProcMacroExpander, }; /// Total limit on the number of tokens produced by any macro invocation. @@ -53,9 +53,7 @@ impl TokenExpander { match self { TokenExpander::DeclarativeMacro { mac, .. } => mac.expand(tt).map_err(Into::into), TokenExpander::Builtin(it) => it.expand(db, id, tt).map_err(Into::into), - TokenExpander::BuiltinEager(it) => { - it.expand(db, id, tt).map_err(Into::into).map(|res| res.subtree) - } + TokenExpander::BuiltinEager(it) => it.expand(db, id, tt).map_err(Into::into), TokenExpander::BuiltinAttr(it) => it.expand(db, id, tt), TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt), TokenExpander::ProcMacro(_) => { @@ -132,6 +130,14 @@ pub trait ExpandDatabase: SourceDatabase { /// Expand macro call to a token tree. // This query is LRU cached fn macro_expand(&self, macro_call: MacroCallId) -> ExpandResult>; + #[salsa::invoke(crate::builtin_fn_macro::include_arg_to_tt)] + fn include_expand( + &self, + arg_id: MacroCallId, + ) -> Result< + (triomphe::Arc<(::tt::Subtree<::tt::TokenId>, mbe::TokenMap)>, base_db::FileId), + ExpandError, + >; /// Special case of the previous query for procedural macros. We can't LRU /// proc macros, since they are not deterministic in general, and /// non-determinism breaks salsa in a very, very, very bad way. @@ -281,31 +287,6 @@ fn parse_macro_expansion( let _p = profile::span("parse_macro_expansion"); let mbe::ValueResult { value: tt, err } = db.macro_expand(macro_file.macro_call_id); - if let Some(err) = &err { - if tracing::enabled!(tracing::Level::DEBUG) { - // Note: - // The final goal we would like to make all parse_macro success, - // such that the following log will not call anyway. - let loc = db.lookup_intern_macro_call(macro_file.macro_call_id); - let node = loc.to_node(db); - - // collect parent information for warning log - let parents = std::iter::successors(loc.kind.file_id().call_node(db), |it| { - it.file_id.call_node(db) - }) - .map(|n| format!("{:#}", n.value)) - .collect::>() - .join("\n"); - - tracing::debug!( - "fail on macro_parse: (reason: {:?} macro_call: {:#}) parents: {}", - err, - node.value, - parents - ); - } - } - let expand_to = macro_expand_to(db, macro_file.macro_call_id); tracing::debug!("expanded = {}", tt.as_debug_string()); @@ -320,9 +301,14 @@ fn macro_arg( db: &dyn ExpandDatabase, id: MacroCallId, ) -> Option> { - let arg = db.macro_arg_text(id)?; let loc = db.lookup_intern_macro_call(id); + if let Some(EagerCallInfo { arg, arg_id: Some(_), error: _ }) = loc.eager.as_deref() { + return Some(Arc::new((arg.0.clone(), arg.1.clone(), Default::default()))); + } + + let arg = db.macro_arg_text(id)?; + let node = SyntaxNode::new_root(arg); let censor = censor_for_macro_input(&loc, &node); let mut fixups = fixup::fixup_syntax(&node); @@ -398,7 +384,17 @@ fn macro_arg_text(db: &dyn ExpandDatabase, id: MacroCallId) -> Option return None; } } - Some(arg.green().into()) + if let Some(EagerCallInfo { arg, .. }) = loc.eager.as_deref() { + Some( + mbe::token_tree_to_syntax_node(&arg.0, mbe::TopEntryPoint::Expr) + .0 + .syntax_node() + .green() + .into(), + ) + } else { + Some(arg.green().into()) + } } fn macro_def( @@ -445,23 +441,21 @@ fn macro_def( fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult> { let _p = profile::span("macro_expand"); let loc = db.lookup_intern_macro_call(id); - if let Some(eager) = &loc.eager { - return ExpandResult { value: eager.arg_or_expansion.clone(), err: eager.error.clone() }; + if let Some(EagerCallInfo { arg, arg_id: None, error }) = loc.eager.as_deref() { + // This is an input expansion for an eager macro. These are already pre-expanded + return ExpandResult { value: Arc::new(arg.0.clone()), err: error.clone() }; } - let expander = match db.macro_def(loc.def) { Ok(it) => it, - // FIXME: This is weird -- we effectively report macro *definition* - // errors lazily, when we try to expand the macro. Instead, they should - // be reported at the definition site when we construct a def map. - // (Note we do report them also at the definition site in the late diagnostic pass) + // FIXME: We should make sure to enforce a variant that invalid macro + // definitions do not get expanders that could reach this call path! Err(err) => { return ExpandResult { value: Arc::new(tt::Subtree { delimiter: tt::Delimiter::UNSPECIFIED, token_trees: vec![], }), - err: Some(ExpandError::Other(format!("invalid macro definition: {err}").into())), + err: Some(ExpandError::other(format!("invalid macro definition: {err}"))), } } }; @@ -473,13 +467,21 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult ExpandResult ExpandResult, def: MacroDefId, resolver: &dyn Fn(ModPath) -> Option, ) -> Result>, UnresolvedMacro> { - let MacroDefKind::BuiltInEager(eager, _) = def.kind else { - panic!("called `expand_eager_macro` on non-eager macro def {def:?}") + assert!(matches!(def.kind, MacroDefKind::BuiltInEager(..))); + let token_tree = macro_call.value.token_tree(); + + let Some(token_tree) = token_tree else { + return Ok(ExpandResult { value: None, err: + Some(ExpandError::other( + "invalid token tree" + )), + }); }; - let hygiene = Hygiene::new(db, macro_call.file_id); - let parsed_args = macro_call - .value - .token_tree() - .map(|tt| mbe::syntax_node_to_token_tree(tt.syntax()).0) - .unwrap_or_else(tt::Subtree::empty); + let (parsed_args, arg_token_map) = mbe::syntax_node_to_token_tree(token_tree.syntax()); let ast_map = db.ast_id_map(macro_call.file_id); let call_id = InFile::new(macro_call.file_id, ast_map.ast_id(¯o_call.value)); @@ -60,41 +62,40 @@ pub fn expand_eager_macro( def, krate, eager: Some(Box::new(EagerCallInfo { - arg_or_expansion: Arc::new(parsed_args.clone()), - included_file: None, + arg: Arc::new((parsed_args, arg_token_map)), + arg_id: None, error: None, })), kind: MacroCallKind::FnLike { ast_id: call_id, expand_to: ExpandTo::Expr }, }); - - let parsed_args = mbe::token_tree_to_syntax_node(&parsed_args, mbe::TopEntryPoint::Expr).0; - let ExpandResult { value, mut err } = eager_macro_recur( + let arg_as_expr = match db.macro_arg_text(arg_id) { + Some(it) => it, + None => { + return Ok(ExpandResult { + value: None, + err: Some(ExpandError::other("invalid token tree")), + }) + } + }; + let ExpandResult { value: expanded_eager_input, err } = eager_macro_recur( db, - &hygiene, - InFile::new(arg_id.as_file(), parsed_args.syntax_node()), + &Hygiene::new(db, macro_call.file_id), + InFile::new(arg_id.as_file(), SyntaxNode::new_root(arg_as_expr)), krate, resolver, )?; - let Some(value ) = value else { + let Some(expanded_eager_input) = expanded_eager_input else { return Ok(ExpandResult { value: None, err }) }; - let subtree = { - let mut subtree = mbe::syntax_node_to_token_tree(&value).0; - subtree.delimiter = crate::tt::Delimiter::unspecified(); - subtree - }; - - let res = eager.expand(db, arg_id, &subtree); - if err.is_none() { - err = res.err; - } + let (mut subtree, token_map) = mbe::syntax_node_to_token_tree(&expanded_eager_input); + subtree.delimiter = crate::tt::Delimiter::unspecified(); let loc = MacroCallLoc { def, krate, eager: Some(Box::new(EagerCallInfo { - arg_or_expansion: Arc::new(res.value.subtree), - included_file: res.value.included_file, + arg: Arc::new((subtree, token_map)), + arg_id: Some(arg_id), error: err.clone(), })), kind: MacroCallKind::FnLike { ast_id: call_id, expand_to }, @@ -118,8 +119,9 @@ fn lazy_expand( MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id), expand_to }, ); - let file_id = id.as_file(); - db.parse_or_expand_with_err(file_id).map(|parse| InFile::new(file_id, parse)) + let macro_file = id.as_macro_file(); + + db.parse_macro_expansion(macro_file).map(|parse| InFile::new(macro_file.into(), parse.0)) } fn eager_macro_recur( @@ -142,13 +144,13 @@ fn eager_macro_recur( let def = match child.path().and_then(|path| ModPath::from_src(db, path, hygiene)) { Some(path) => macro_resolver(path.clone()).ok_or(UnresolvedMacro { path })?, None => { - error = Some(ExpandError::Other("malformed macro invocation".into())); + error = Some(ExpandError::other("malformed macro invocation")); continue; } }; let ExpandResult { value, err } = match def.kind { MacroDefKind::BuiltInEager(..) => { - let id = match expand_eager_macro( + let ExpandResult { value, err } = match expand_eager_macro_input( db, krate, curr.with_value(child.clone()), @@ -158,9 +160,17 @@ fn eager_macro_recur( Ok(it) => it, Err(err) => return Err(err), }; - id.map(|call| { - call.map(|call| db.parse_or_expand(call.as_file()).clone_for_update()) - }) + match value { + Some(call) => { + let ExpandResult { value, err: err2 } = + db.parse_macro_expansion(call.as_macro_file()); + ExpandResult { + value: Some(value.0.syntax_node().clone_for_update()), + err: err.or(err2), + } + } + None => ExpandResult { value: None, err }, + } } MacroDefKind::Declarative(_) | MacroDefKind::BuiltIn(..) @@ -180,7 +190,7 @@ fn eager_macro_recur( krate, macro_resolver, )?; - let err = if err.is_none() { error } else { err }; + let err = err.or(error); ExpandResult { value, err } } }; diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index c8373778d32b0..e0c199328ef38 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -58,7 +58,13 @@ pub enum ExpandError { UnresolvedProcMacro(CrateId), Mbe(mbe::ExpandError), RecursionOverflowPoisoned, - Other(Box), + Other(Box>), +} + +impl ExpandError { + pub fn other(msg: impl Into>) -> Self { + ExpandError::Other(Box::new(msg.into())) + } } impl From for ExpandError { @@ -97,9 +103,15 @@ impl fmt::Display for ExpandError { /// The two variants are encoded in a single u32 which are differentiated by the MSB. /// If the MSB is 0, the value represents a `FileId`, otherwise the remaining 31 bits represent a /// `MacroCallId`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct HirFileId(u32); +impl fmt::Debug for HirFileId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.repr().fmt(f) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct MacroFile { pub macro_call_id: MacroCallId, @@ -115,6 +127,7 @@ impl_intern_key!(MacroCallId); pub struct MacroCallLoc { pub def: MacroDefId, pub(crate) krate: CrateId, + /// Some if `def` is a builtin eager macro. eager: Option>, pub kind: MacroCallKind, } @@ -140,8 +153,10 @@ pub enum MacroDefKind { #[derive(Debug, Clone, PartialEq, Eq, Hash)] struct EagerCallInfo { /// NOTE: This can be *either* the expansion result, *or* the argument to the eager macro! - arg_or_expansion: Arc, - included_file: Option<(FileId, TokenMap)>, + arg: Arc<(tt::Subtree, TokenMap)>, + /// call id of the eager macro's input file. If this is none, macro call containing this call info + /// is an eager macro's input, otherwise it is its output. + arg_id: Option, error: Option, } @@ -206,10 +221,15 @@ impl HirFileId { HirFileIdRepr::FileId(id) => break id, HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => { let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_call_id); - file_id = match loc.eager.as_deref() { - Some(&EagerCallInfo { included_file: Some((file, _)), .. }) => file.into(), + let is_include_expansion = loc.def.is_include() + && matches!( + loc.eager.as_deref(), + Some(EagerCallInfo { arg_id: Some(_), .. }) + ); + file_id = match is_include_expansion.then(|| db.include_expand(macro_call_id)) { + Some(Ok((_, file))) => file.into(), _ => loc.kind.file_id(), - }; + } } } } @@ -325,7 +345,17 @@ impl HirFileId { match self.macro_file() { Some(macro_file) => { let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - matches!(loc.eager.as_deref(), Some(EagerCallInfo { included_file: Some(..), .. })) + loc.def.is_include() + } + _ => false, + } + } + + pub fn is_eager(&self, db: &dyn db::ExpandDatabase) -> bool { + match self.macro_file() { + Some(macro_file) => { + let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); + matches!(loc.eager.as_deref(), Some(EagerCallInfo { .. })) } _ => false, } @@ -423,6 +453,10 @@ impl MacroDefId { pub fn is_attribute_derive(&self) -> bool { matches!(self.kind, MacroDefKind::BuiltInAttr(expander, ..) if expander.is_derive()) } + + pub fn is_include(&self) -> bool { + matches!(self.kind, MacroDefKind::BuiltInEager(expander, ..) if expander.is_include()) + } } impl MacroCallLoc { @@ -569,6 +603,10 @@ impl MacroCallId { pub fn as_file(self) -> HirFileId { MacroFile { macro_call_id: self }.into() } + + pub fn as_macro_file(self) -> MacroFile { + MacroFile { macro_call_id: self } + } } /// ExpansionInfo mainly describes how to map text range between src and expanded macro @@ -662,7 +700,7 @@ impl ExpansionInfo { let token_id = match token_id_in_attr_input { Some(token_id) => token_id, - // the token is not inside an attribute's input so do the lookup in the macro_arg as usual + // the token is not inside `an attribute's input so do the lookup in the macro_arg as usual None => { let relative_range = token.value.text_range().checked_sub(self.arg.value.text_range().start())?; @@ -694,14 +732,18 @@ impl ExpansionInfo { let call_id = self.expanded.file_id.macro_file()?.macro_call_id; let loc = db.lookup_intern_macro_call(call_id); - if let Some((file, map)) = loc.eager.and_then(|e| e.included_file) { - // Special case: map tokens from `include!` expansions to the included file - let range = map.first_range_by_token(token_id, token.value.kind())?; - let source = db.parse(file); + // Special case: map tokens from `include!` expansions to the included file + if loc.def.is_include() + && matches!(loc.eager.as_deref(), Some(EagerCallInfo { arg_id: Some(_), .. })) + { + if let Ok((tt_and_map, file_id)) = db.include_expand(call_id) { + let range = tt_and_map.1.first_range_by_token(token_id, token.value.kind())?; + let source = db.parse(file_id); - let token = source.syntax_node().covering_element(range).into_token()?; + let token = source.syntax_node().covering_element(range).into_token()?; - return Some((InFile::new(file.into(), token), Origin::Call)); + return Some((InFile::new(file_id.into(), token), Origin::Call)); + } } // Attributes are a bit special for us, they have two inputs, the input tokentree and the annotated item. diff --git a/crates/hir-expand/src/proc_macro.rs b/crates/hir-expand/src/proc_macro.rs index c9539210abf65..41675c630dcfe 100644 --- a/crates/hir-expand/src/proc_macro.rs +++ b/crates/hir-expand/src/proc_macro.rs @@ -46,7 +46,7 @@ impl ProcMacroExpander { never!("Non-dummy expander even though there are no proc macros"); return ExpandResult::new( tt::Subtree::empty(), - ExpandError::Other("Internal error".into()), + ExpandError::other("Internal error"), ); } }; @@ -60,7 +60,7 @@ impl ProcMacroExpander { ); return ExpandResult::new( tt::Subtree::empty(), - ExpandError::Other("Internal error".into()), + ExpandError::other("Internal error"), ); } }; @@ -75,14 +75,11 @@ impl ProcMacroExpander { ProcMacroExpansionError::System(text) if proc_macro.kind == ProcMacroKind::Attr => { - ExpandResult { - value: tt.clone(), - err: Some(ExpandError::Other(text.into())), - } + ExpandResult { value: tt.clone(), err: Some(ExpandError::other(text)) } } ProcMacroExpansionError::System(text) | ProcMacroExpansionError::Panic(text) => { - ExpandResult::new(tt::Subtree::empty(), ExpandError::Other(text.into())) + ExpandResult::new(tt::Subtree::empty(), ExpandError::other(text)) } }, } diff --git a/crates/ide-db/src/test_data/test_doc_alias.txt b/crates/ide-db/src/test_data/test_doc_alias.txt index 77714efa35040..7834c66033c00 100644 --- a/crates/ide-db/src/test_data/test_doc_alias.txt +++ b/crates/ide-db/src/test_data/test_doc_alias.txt @@ -20,8 +20,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -47,8 +49,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -74,8 +78,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -101,8 +107,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -128,8 +136,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -155,8 +165,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -182,8 +194,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, diff --git a/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/crates/ide-db/src/test_data/test_symbol_index_collection.txt index b5adfc13d9644..1a00e29384e5c 100644 --- a/crates/ide-db/src/test_data/test_symbol_index_collection.txt +++ b/crates/ide-db/src/test_data/test_symbol_index_collection.txt @@ -18,8 +18,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: TYPE_ALIAS, @@ -43,8 +45,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: CONST, @@ -68,8 +72,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: CONST, @@ -95,8 +101,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: ENUM, @@ -122,8 +130,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: MACRO_DEF, @@ -147,8 +157,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STATIC, @@ -174,8 +186,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -201,8 +215,12 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 2147483648, + hir_file_id: MacroFile( + MacroFile { + macro_call_id: MacroCallId( + 0, + ), + }, ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -228,8 +246,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -257,8 +277,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -286,8 +308,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -311,8 +335,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: TRAIT, @@ -338,8 +364,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: UNION, @@ -365,8 +393,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: MODULE, @@ -392,8 +422,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: MODULE, @@ -419,8 +451,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: MACRO_RULES, @@ -444,8 +478,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: FN, @@ -471,8 +507,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: MACRO_RULES, @@ -496,8 +534,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: FN, @@ -521,8 +561,10 @@ }, ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: FN, @@ -561,8 +603,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 0, + hir_file_id: FileId( + FileId( + 0, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -599,8 +643,10 @@ ), ), loc: DeclarationLocation { - hir_file_id: HirFileId( - 1, + hir_file_id: FileId( + FileId( + 1, + ), ), ptr: SyntaxNodePtr { kind: STRUCT, diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index 327e1502d19e0..fa374b04f1958 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html @@ -86,6 +86,8 @@ macro_rules! assert {} #[rustc_builtin_macro] macro_rules! asm {} +#[rustc_builtin_macro] +macro_rules! concat {} macro_rules! toho { () => ($crate::panic!("not yet implemented")); @@ -172,4 +174,5 @@ toho!("{}fmt", 0); asm!("mov eax, {0}"); format_args!(concat!("{}"), "{}"); + format_args!("{}", format_args!("{}", 0)); } \ No newline at end of file diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 887d18b989a14..497992f684ce7 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -432,6 +432,8 @@ macro_rules! panic {} macro_rules! assert {} #[rustc_builtin_macro] macro_rules! asm {} +#[rustc_builtin_macro] +macro_rules! concat {} macro_rules! toho { () => ($crate::panic!("not yet implemented")); @@ -518,6 +520,7 @@ fn main() { toho!("{}fmt", 0); asm!("mov eax, {0}"); format_args!(concat!("{}"), "{}"); + format_args!("{}", format_args!("{}", 0)); }"#, expect_file!["./test_data/highlight_strings.html"], false, From 6fbf6ef514876e68d98211051ef54d0dcd2b8550 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Sat, 10 Jun 2023 02:10:52 +0330 Subject: [PATCH 178/465] Fix panic in displaying const trait objects --- crates/hir-ty/src/display.rs | 16 ++++++++++++++++ crates/hir-ty/src/mir/eval.rs | 18 +++++++++++++----- crates/ide/src/hover/tests.rs | 23 +++++++++++++++++++++++ 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index f90e025c7cc62..9d5cf47da8d54 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -536,6 +536,22 @@ fn render_const_scalar( } f.write_str("]") } + TyKind::Dyn(_) => { + let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap()); + let ty_id = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap()); + let Ok(t) = memory_map.vtable.ty(ty_id) else { + return f.write_str(""); + }; + let Ok(layout) = f.db.layout_of_ty(t.clone(), krate) else { + return f.write_str(""); + }; + let size = layout.size.bytes_usize(); + let Some(bytes) = memory_map.get(addr, size) else { + return f.write_str(""); + }; + f.write_str("&")?; + render_const_scalar(f, bytes, memory_map, t) + } _ => { let addr = usize::from_le_bytes(b.try_into().unwrap()); let Ok(layout) = f.db.layout_of_ty(t.clone(), krate) else { diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index ce14f6dbad536..9acf9d39e56c9 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -77,7 +77,7 @@ impl VTableMap { id } - fn ty(&self, id: usize) -> Result<&Ty> { + pub(crate) fn ty(&self, id: usize) -> Result<&Ty> { self.id_to_ty.get(id).ok_or(MirEvalError::InvalidVTableId(id)) } @@ -1571,16 +1571,24 @@ impl Evaluator<'_> { } None => { let mut check_inner = None; + let (addr, meta) = bytes.split_at(bytes.len() / 2); let element_size = match t.kind(Interner) { TyKind::Str => 1, TyKind::Slice(t) => { check_inner = Some(t); this.size_of_sized(t, locals, "slice inner type")? } - _ => return Ok(()), // FIXME: support other kind of unsized types + TyKind::Dyn(_) => { + let t = this.vtable_map.ty_of_bytes(meta)?; + check_inner = Some(t); + this.size_of_sized(t, locals, "dyn concrete type")? + } + _ => return Ok(()), + }; + let count = match t.kind(Interner) { + TyKind::Dyn(_) => 1, + _ => from_bytes!(usize, meta), }; - let (addr, meta) = bytes.split_at(bytes.len() / 2); - let count = from_bytes!(usize, meta); let size = element_size * count; let addr = Address::from_bytes(addr)?; let b = this.read_memory(addr, size)?; @@ -1588,7 +1596,7 @@ impl Evaluator<'_> { if let Some(ty) = check_inner { for i in 0..count { let offset = element_size * i; - rec(this, &b[offset..offset + element_size], ty, locals, mm)?; + rec(this, &b[offset..offset + element_size], &ty, locals, mm)?; } } } diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index a2f96977581c2..22bbdf37a8ea9 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -4422,6 +4422,29 @@ const FOO$0: Option<&i32> = Some(2).as_ref(); ); } +#[test] +fn hover_const_eval_dyn_trait() { + check( + r#" +//- minicore: fmt, coerce_unsized, builtin_impls +use core::fmt::Debug; + +const FOO$0: &dyn Debug = &2i32; +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: &dyn Debug = &2 + ``` + "#]], + ); +} + #[test] fn hover_const_eval_slice() { check( From b6fb35f20c2db8c8845e24e981fe6d175b154aac Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 10 Jun 2023 01:21:52 +0200 Subject: [PATCH 179/465] Shrink hir_expand::attr::AttrInput by boxing a variant --- crates/hir-def/src/lib.rs | 6 +++--- crates/hir-expand/src/attrs.rs | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 02593609e73b1..98cff54cc22d9 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -1028,13 +1028,13 @@ fn attr_macro_as_call_id( def: MacroDefId, ) -> MacroCallId { let arg = match macro_attr.input.as_deref() { - Some(AttrInput::TokenTree(tt, map)) => ( + Some(AttrInput::TokenTree(tt)) => ( { - let mut tt = tt.clone(); + let mut tt = tt.0.clone(); tt.delimiter = tt::Delimiter::UNSPECIFIED; tt }, - map.clone(), + tt.1.clone(), ), _ => (tt::Subtree::empty(), Default::default()), }; diff --git a/crates/hir-expand/src/attrs.rs b/crates/hir-expand/src/attrs.rs index 0c369a18bb9cc..4c918e55b92af 100644 --- a/crates/hir-expand/src/attrs.rs +++ b/crates/hir-expand/src/attrs.rs @@ -192,14 +192,14 @@ pub enum AttrInput { /// `#[attr = "string"]` Literal(SmolStr), /// `#[attr(subtree)]` - TokenTree(tt::Subtree, mbe::TokenMap), + TokenTree(Box<(tt::Subtree, mbe::TokenMap)>), } impl fmt::Display for AttrInput { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { AttrInput::Literal(lit) => write!(f, " = \"{}\"", lit.escape_debug()), - AttrInput::TokenTree(subtree, _) => subtree.fmt(f), + AttrInput::TokenTree(tt) => tt.0.fmt(f), } } } @@ -220,7 +220,7 @@ impl Attr { Some(Interned::new(AttrInput::Literal(value))) } else if let Some(tt) = ast.token_tree() { let (tree, map) = syntax_node_to_token_tree(tt.syntax()); - Some(Interned::new(AttrInput::TokenTree(tree, map))) + Some(Interned::new(AttrInput::TokenTree(Box::new((tree, map))))) } else { None }; @@ -256,7 +256,7 @@ impl Attr { /// #[path(ident)] pub fn single_ident_value(&self) -> Option<&tt::Ident> { match self.input.as_deref()? { - AttrInput::TokenTree(subtree, _) => match &*subtree.token_trees { + AttrInput::TokenTree(tt) => match &*tt.0.token_trees { [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] => Some(ident), _ => None, }, @@ -267,7 +267,7 @@ impl Attr { /// #[path TokenTree] pub fn token_tree_value(&self) -> Option<&Subtree> { match self.input.as_deref()? { - AttrInput::TokenTree(subtree, _) => Some(subtree), + AttrInput::TokenTree(tt) => Some(&tt.0), _ => None, } } From ccce89357767d3b572839f9d9371d3265e6588d2 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 10 Jun 2023 01:49:32 +0200 Subject: [PATCH 180/465] Count query entries in memory usage command --- crates/hir-ty/src/display.rs | 12 ++++++- crates/ide-db/src/apply_change.rs | 34 +++++++++++++++++--- crates/ide/src/lib.rs | 2 +- crates/rust-analyzer/src/cli.rs | 17 ++++++---- crates/rust-analyzer/src/handlers/request.rs | 9 +++--- 5 files changed, 56 insertions(+), 18 deletions(-) diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index 9d5cf47da8d54..2e7558a7b6a81 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -553,7 +553,17 @@ fn render_const_scalar( render_const_scalar(f, bytes, memory_map, t) } _ => { - let addr = usize::from_le_bytes(b.try_into().unwrap()); + let addr = usize::from_le_bytes(match b.try_into() { + Ok(b) => b, + Err(_) => { + never!( + "tried rendering ty {:?} in const ref with incorrect byte count {}", + t, + b.len() + ); + return f.write_str(""); + } + }); let Ok(layout) = f.db.layout_of_ty(t.clone(), krate) else { return f.write_str(""); }; diff --git a/crates/ide-db/src/apply_change.rs b/crates/ide-db/src/apply_change.rs index 8edda432ce398..0dd544d0ae23a 100644 --- a/crates/ide-db/src/apply_change.rs +++ b/crates/ide-db/src/apply_change.rs @@ -1,7 +1,10 @@ //! Applies changes to the IDE state transactionally. use base_db::{ - salsa::{Database, Durability}, + salsa::{ + debug::{DebugQueryTable, TableEntry}, + Database, Durability, Query, QueryTable, + }, Change, SourceRootId, }; use profile::{memory_usage, Bytes}; @@ -47,16 +50,37 @@ impl RootDatabase { // | VS Code | **rust-analyzer: Memory Usage (Clears Database)** // |=== // image::https://user-images.githubusercontent.com/48062697/113065592-08559f00-91b1-11eb-8c96-64b88068ec02.gif[] - pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> { - let mut acc: Vec<(String, Bytes)> = vec![]; + pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes, usize)> { + let mut acc: Vec<(String, Bytes, usize)> = vec![]; + + fn collect_query_count<'q, Q>(table: &QueryTable<'q, Q>) -> usize + where + QueryTable<'q, Q>: DebugQueryTable, + Q: Query, + ::Storage: 'q, + { + struct EntryCounter(usize); + impl FromIterator> for EntryCounter { + fn from_iter(iter: T) -> EntryCounter + where + T: IntoIterator>, + { + EntryCounter(iter.into_iter().count()) + } + } + table.entries::().0 + } + macro_rules! purge_each_query { ($($q:path)*) => {$( let before = memory_usage().allocated; - $q.in_db(self).purge(); + let table = $q.in_db(self); + let count = collect_query_count(&table); + table.purge(); let after = memory_usage().allocated; let q: $q = Default::default(); let name = format!("{:?}", q); - acc.push((name, before - after)); + acc.push((name, before - after, count)); )*} } purge_each_query![ diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 87e769e423073..f195f78b3ab82 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -181,7 +181,7 @@ impl AnalysisHost { } /// NB: this clears the database - pub fn per_query_memory_usage(&mut self) -> Vec<(String, profile::Bytes)> { + pub fn per_query_memory_usage(&mut self) -> Vec<(String, profile::Bytes, usize)> { self.db.per_query_memory_usage() } pub fn request_cancellation(&mut self) { diff --git a/crates/rust-analyzer/src/cli.rs b/crates/rust-analyzer/src/cli.rs index d5d877680a09a..e3520192110ea 100644 --- a/crates/rust-analyzer/src/cli.rs +++ b/crates/rust-analyzer/src/cli.rs @@ -50,21 +50,24 @@ fn report_metric(metric: &str, value: u64, unit: &str) { } fn print_memory_usage(mut host: AnalysisHost, vfs: Vfs) { - let mut mem = host.per_query_memory_usage(); + let mem = host.per_query_memory_usage(); let before = profile::memory_usage(); drop(vfs); let vfs = before.allocated - profile::memory_usage().allocated; - mem.push(("VFS".into(), vfs)); let before = profile::memory_usage(); drop(host); - mem.push(("Unaccounted".into(), before.allocated - profile::memory_usage().allocated)); + let unaccounted = before.allocated - profile::memory_usage().allocated; + let remaining = profile::memory_usage().allocated; - mem.push(("Remaining".into(), profile::memory_usage().allocated)); - - for (name, bytes) in mem { + for (name, bytes, entries) in mem { // NOTE: Not a debug print, so avoid going through the `eprintln` defined above. - eprintln!("{bytes:>8} {name}"); + eprintln!("{bytes:>8} {entries:>6} {name}"); } + eprintln!("{vfs:>8} VFS"); + + eprintln!("{unaccounted:>8} Unaccounted"); + + eprintln!("{remaining:>8} Remaining"); } diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index 3f365c05942f0..52a85054ea31a 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -115,13 +115,14 @@ pub(crate) fn handle_analyzer_status( pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> Result { let _p = profile::span("handle_memory_usage"); - let mut mem = state.analysis_host.per_query_memory_usage(); - mem.push(("Remaining".into(), profile::memory_usage().allocated)); + let mem = state.analysis_host.per_query_memory_usage(); let mut out = String::new(); - for (name, bytes) in mem { - format_to!(out, "{:>8} {}\n", bytes, name); + for (name, bytes, entries) in mem { + format_to!(out, "{:>8} {:>6} {}\n", bytes, entries, name); } + format_to!(out, "{:>8} Remaining\n", profile::memory_usage().allocated); + Ok(out) } From 1dd76e8a9d78b58c4920f5041314d7b5e089965c Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Sat, 10 Jun 2023 11:32:37 +0330 Subject: [PATCH 181/465] Fix panic in displaying unsized structs --- crates/hir-ty/src/display.rs | 15 ++++++++++++++- crates/ide/src/hover/tests.rs | 20 ++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index 9d5cf47da8d54..bb02a15314594 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -2,7 +2,10 @@ //! HIR back into source code, and just displaying them for debugging/testing //! purposes. -use std::fmt::{self, Debug}; +use std::{ + fmt::{self, Debug}, + mem::size_of, +}; use base_db::CrateId; use chalk_ir::{BoundVar, TyKind}; @@ -552,6 +555,16 @@ fn render_const_scalar( f.write_str("&")?; render_const_scalar(f, bytes, memory_map, t) } + TyKind::Adt(adt, _) if b.len() == 2 * size_of::() => match adt.0 { + hir_def::AdtId::StructId(s) => { + let data = f.db.struct_data(s); + write!(f, "&{}", data.name.display(f.db.upcast()))?; + Ok(()) + } + _ => { + return f.write_str(""); + } + }, _ => { let addr = usize::from_le_bytes(b.try_into().unwrap()); let Ok(layout) = f.db.layout_of_ty(t.clone(), krate) else { diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 22bbdf37a8ea9..f75ebfa12eb26 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -4525,6 +4525,26 @@ const FOO$0: Tree = { ``` "#]], ); + // FIXME: Show the data of unsized structs + check( + r#" +//- minicore: slice, index, coerce_unsized, transmute +#[repr(transparent)] +struct S(T); +const FOO$0: &S<[u8]> = core::mem::transmute::<&[u8], _>(&[1, 2, 3]); +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: &S<[u8]> = &S + ``` + "#]], + ); } #[test] From 78fab7d5d54a485be6e9450b20e4fc03c26574c7 Mon Sep 17 00:00:00 2001 From: max-heller Date: Sun, 4 Jun 2023 09:35:03 -0400 Subject: [PATCH 182/465] format documentation for `SignatureHelpRequest`s --- crates/rust-analyzer/src/to_proto.rs | 33 ++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 8a9e947ded0ad..648bc995ad5e2 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -410,7 +410,7 @@ pub(crate) fn signature_help( let documentation = call_info.doc.filter(|_| config.docs).map(|doc| { lsp_types::Documentation::MarkupContent(lsp_types::MarkupContent { kind: lsp_types::MarkupKind::Markdown, - value: doc, + value: crate::markdown::format_docs(&doc), }) }); @@ -1410,7 +1410,8 @@ pub(crate) fn rename_error(err: RenameError) -> crate::LspError { #[cfg(test)] mod tests { - use ide::Analysis; + use ide::{Analysis, FilePosition}; + use test_utils::extract_offset; use triomphe::Arc; use super::*; @@ -1451,6 +1452,34 @@ fn main() { } } + #[test] + fn calling_function_with_ignored_code_in_signature() { + let text = r#" +fn foo() { + bar($0); +} +/// ``` +/// # use crate::bar; +/// bar(5); +/// ``` +fn bar(_: usize) {} +"#; + + let (offset, text) = extract_offset(text); + let (analysis, file_id) = Analysis::from_single_file(text); + let help = signature_help( + analysis.signature_help(FilePosition { file_id, offset }).unwrap().unwrap(), + CallInfoConfig { params_only: false, docs: true }, + false, + ); + let docs = match &help.signatures[help.active_signature.unwrap() as usize].documentation { + Some(lsp_types::Documentation::MarkupContent(content)) => &content.value, + _ => panic!("documentation contains markup"), + }; + assert!(docs.contains("bar(5)")); + assert!(!docs.contains("use crate::bar")); + } + // `Url` is not able to parse windows paths on unix machines. #[test] #[cfg(target_os = "windows")] From a481e004b037540b5c1c6355bac26677677a802e Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Mon, 5 Jun 2023 14:57:19 +0330 Subject: [PATCH 183/465] Lower const params with a bad id --- crates/base-db/src/fixture.rs | 6 +- crates/base-db/src/input.rs | 21 ++++ crates/hir-def/src/body.rs | 20 ++-- crates/hir-def/src/body/pretty.rs | 1 + crates/hir-def/src/db.rs | 11 +- crates/hir-def/src/expander.rs | 2 +- crates/hir-def/src/hir/type_ref.rs | 109 ++++++++++-------- crates/hir-def/src/lib.rs | 76 +++++++++--- crates/hir-def/src/path.rs | 4 +- crates/hir-def/src/path/lower.rs | 4 +- crates/hir-def/src/resolver.rs | 15 ++- crates/hir-expand/src/ast_id_map.rs | 1 + crates/hir-ty/src/chalk_db.rs | 2 +- crates/hir-ty/src/consteval.rs | 22 ++-- crates/hir-ty/src/consteval/tests.rs | 11 ++ crates/hir-ty/src/db.rs | 1 + crates/hir-ty/src/diagnostics/unsafe_check.rs | 7 +- crates/hir-ty/src/infer.rs | 34 ++++-- crates/hir-ty/src/infer/expr.rs | 1 + crates/hir-ty/src/infer/path.rs | 17 ++- crates/hir-ty/src/interner.rs | 2 +- crates/hir-ty/src/layout/tests.rs | 35 +++++- crates/hir-ty/src/lower.rs | 106 ++++++++++------- crates/hir-ty/src/method_resolution.rs | 2 +- crates/hir-ty/src/mir/lower.rs | 1 + crates/hir-ty/src/mir/pretty.rs | 3 + crates/hir-ty/src/tests.rs | 2 + crates/hir-ty/src/tests/regression.rs | 23 ++++ crates/hir/src/from_id.rs | 3 + crates/hir/src/lib.rs | 33 +++++- crates/hir/src/semantics.rs | 8 +- crates/hir/src/source_analyzer.rs | 3 +- crates/hir/src/symbols.rs | 1 + crates/ide-db/src/search.rs | 2 + crates/ide/src/inlay_hints/chaining.rs | 12 +- crates/project-model/src/workspace.rs | 6 + .../rust-analyzer/src/cli/analysis_stats.rs | 21 ++-- crates/test-utils/src/minicore.rs | 27 +++++ 38 files changed, 473 insertions(+), 182 deletions(-) diff --git a/crates/base-db/src/fixture.rs b/crates/base-db/src/fixture.rs index 5b11343173b30..d3abc3870b70f 100644 --- a/crates/base-db/src/fixture.rs +++ b/crates/base-db/src/fixture.rs @@ -215,7 +215,7 @@ impl ChangeFixture { None, default_cfg, Default::default(), - Env::default(), + Env::new_for_test_fixture(), false, CrateOrigin::Local { repo: None, name: None }, default_target_data_layout @@ -259,7 +259,7 @@ impl ChangeFixture { None, Default::default(), Default::default(), - Env::default(), + Env::new_for_test_fixture(), false, CrateOrigin::Lang(LangCrateOrigin::Core), target_layout.clone(), @@ -298,7 +298,7 @@ impl ChangeFixture { None, Default::default(), Default::default(), - Env::default(), + Env::new_for_test_fixture(), true, CrateOrigin::Local { repo: None, name: None }, target_layout, diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index e8d521b42f868..64b026f4da562 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -151,6 +151,12 @@ pub enum CrateOrigin { Lang(LangCrateOrigin), } +impl CrateOrigin { + pub fn is_local(&self) -> bool { + matches!(self, CrateOrigin::Local { .. }) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum LangCrateOrigin { Alloc, @@ -333,6 +339,17 @@ pub struct Env { entries: FxHashMap, } +impl Env { + pub fn new_for_test_fixture() -> Self { + Env { + entries: FxHashMap::from_iter([( + String::from("__ra_is_test_fixture"), + String::from("__ra_is_test_fixture"), + )]), + } + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Dependency { pub crate_id: CrateId, @@ -456,6 +473,10 @@ impl CrateGraph { self.arena.iter().map(|(idx, _)| idx) } + pub fn iter_mut(&mut self) -> impl Iterator + '_ { + self.arena.iter_mut() + } + /// Returns an iterator over all transitive dependencies of the given crate, /// including the crate itself. pub fn transitive_deps(&self, of: CrateId) -> impl Iterator { diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index 36626ed1a9b1f..28a450081919f 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -118,7 +118,7 @@ impl Body { let _p = profile::span("body_with_source_map_query"); let mut params = None; - let (file_id, module, body, is_async_fn) = { + let (file_id, body, is_async_fn) = { match def { DefWithBodyId::FunctionId(f) => { let data = db.function_data(f); @@ -138,31 +138,29 @@ impl Body { }), ) }); - ( - src.file_id, - f.module(db), - src.value.body().map(ast::Expr::from), - data.has_async_kw(), - ) + (src.file_id, src.value.body().map(ast::Expr::from), data.has_async_kw()) } DefWithBodyId::ConstId(c) => { let c = c.lookup(db); let src = c.source(db); - (src.file_id, c.module(db), src.value.body(), false) + (src.file_id, src.value.body(), false) } DefWithBodyId::StaticId(s) => { let s = s.lookup(db); let src = s.source(db); - (src.file_id, s.module(db), src.value.body(), false) + (src.file_id, src.value.body(), false) } DefWithBodyId::VariantId(v) => { - let e = v.parent.lookup(db); let src = v.parent.child_source(db); let variant = &src.value[v.local_id]; - (src.file_id, e.container, variant.expr(), false) + (src.file_id, variant.expr(), false) + } + DefWithBodyId::InTypeConstId(c) => { + (c.lookup(db).0.file_id, Some(c.source(db)), false) } } }; + let module = def.module(db); let expander = Expander::new(db, file_id, module); let (mut body, source_map) = Body::new(db, def, expander, params, body, module.krate, is_async_fn); diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs index 88380aa355d16..cd6df0e6325ce 100644 --- a/crates/hir-def/src/body/pretty.rs +++ b/crates/hir-def/src/body/pretty.rs @@ -40,6 +40,7 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo }; format!("const {name} = ") } + DefWithBodyId::InTypeConstId(_) => format!("In type const = "), DefWithBodyId::VariantId(it) => { let src = it.parent.child_source(db); let variant = &src.value[it.local_id]; diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 6d18e3f56cabc..3257667780260 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -1,7 +1,7 @@ //! Defines database & queries for name resolution. use base_db::{salsa, CrateId, SourceDatabase, Upcast}; use either::Either; -use hir_expand::{db::ExpandDatabase, HirFileId}; +use hir_expand::{db::ExpandDatabase, AstId, HirFileId}; use intern::Interned; use la_arena::ArenaMap; use syntax::{ast, AstPtr}; @@ -24,9 +24,10 @@ use crate::{ visibility::{self, Visibility}, AnonymousConstId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, ExternBlockId, ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, - LocalEnumVariantId, LocalFieldId, Macro2Id, Macro2Loc, MacroRulesId, MacroRulesLoc, - ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitAliasId, - TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, VariantId, + InTypeConstId, LocalEnumVariantId, LocalFieldId, Macro2Id, Macro2Loc, MacroRulesId, + MacroRulesLoc, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, + TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, TypeOwnerId, + UnionId, UnionLoc, VariantId, }; #[salsa::query_group(InternDatabaseStorage)] @@ -63,6 +64,8 @@ pub trait InternDatabase: SourceDatabase { fn intern_macro_rules(&self, loc: MacroRulesLoc) -> MacroRulesId; #[salsa::interned] fn intern_anonymous_const(&self, id: (DefWithBodyId, ExprId)) -> AnonymousConstId; + #[salsa::interned] + fn intern_in_type_const(&self, id: (AstId, TypeOwnerId)) -> InTypeConstId; } #[salsa::query_group(DefDatabaseStorage)] diff --git a/crates/hir-def/src/expander.rs b/crates/hir-def/src/expander.rs index 31653916f4112..a588827c8d394 100644 --- a/crates/hir-def/src/expander.rs +++ b/crates/hir-def/src/expander.rs @@ -155,7 +155,7 @@ impl Expander { } pub(crate) fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option { - let ctx = LowerCtx::with_hygiene(db, &self.cfg_expander.hygiene); + let ctx = LowerCtx::new(db, &self.cfg_expander.hygiene, self.current_file_id); Path::from_src(path, &ctx) } diff --git a/crates/hir-def/src/hir/type_ref.rs b/crates/hir-def/src/hir/type_ref.rs index 0573c9a6f8af4..b4451c0426e3a 100644 --- a/crates/hir-def/src/hir/type_ref.rs +++ b/crates/hir-def/src/hir/type_ref.rs @@ -118,7 +118,7 @@ pub enum TypeRef { Reference(Box, Option, Mutability), // FIXME: for full const generics, the latter element (length) here is going to have to be an // expression that is further lowered later in hir_ty. - Array(Box, ConstRefOrPath), + Array(Box, ConstRef), Slice(Box), /// A fn pointer. Last element of the vector is the return type. Fn(Vec<(Option, TypeRef)>, bool /*varargs*/, bool /*is_unsafe*/), @@ -190,7 +190,7 @@ impl TypeRef { // `hir_def::body::lower` to lower this into an `Expr` and then evaluate it at the // `hir_ty` level, which would allow knowing the type of: // let v: [u8; 2 + 2] = [0u8; 4]; - let len = ConstRefOrPath::from_expr_opt(inner.expr()); + let len = ConstRef::from_expr_opt(ctx, inner.expr()); TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len) } ast::Type::SliceType(inner) => { @@ -380,73 +380,84 @@ impl TypeBound { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ConstRefOrPath { - Scalar(ConstRef), +pub enum ConstRef { + Scalar(LiteralConstRef), Path(Name), + Complex(AstId), } -impl ConstRefOrPath { - pub(crate) fn from_expr_opt(expr: Option) -> Self { +impl ConstRef { + pub(crate) fn from_expr_opt(lower_ctx: &LowerCtx<'_>, expr: Option) -> Self { match expr { - Some(x) => Self::from_expr(x), - None => Self::Scalar(ConstRef::Unknown), + Some(x) => { + let ast_id = lower_ctx.ast_id(&x); + Self::from_expr(x, ast_id) + } + None => Self::Scalar(LiteralConstRef::Unknown), } } pub fn display<'a>(&'a self, db: &'a dyn ExpandDatabase) -> impl fmt::Display + 'a { - struct Display<'a>(&'a dyn ExpandDatabase, &'a ConstRefOrPath); + struct Display<'a>(&'a dyn ExpandDatabase, &'a ConstRef); impl fmt::Display for Display<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.1 { - ConstRefOrPath::Scalar(s) => s.fmt(f), - ConstRefOrPath::Path(n) => n.display(self.0).fmt(f), + ConstRef::Scalar(s) => s.fmt(f), + ConstRef::Path(n) => n.display(self.0).fmt(f), + ConstRef::Complex(_) => f.write_str("{const}"), } } } Display(db, self) } - // FIXME: as per the comments on `TypeRef::Array`, this evaluation should not happen at this - // parse stage. - fn from_expr(expr: ast::Expr) -> Self { + // We special case literals and single identifiers, to speed up things. + fn from_expr(expr: ast::Expr, ast_id: Option>) -> Self { + fn is_path_ident(p: &ast::PathExpr) -> bool { + let Some(path) = p.path() else { + return false; + }; + if path.coloncolon_token().is_some() { + return false; + } + if let Some(s) = path.segment() { + if s.coloncolon_token().is_some() || s.generic_arg_list().is_some() { + return false; + } + } + true + } match expr { - ast::Expr::PathExpr(p) => { + ast::Expr::PathExpr(p) if is_path_ident(&p) => { match p.path().and_then(|x| x.segment()).and_then(|x| x.name_ref()) { Some(x) => Self::Path(x.as_name()), - None => Self::Scalar(ConstRef::Unknown), + None => Self::Scalar(LiteralConstRef::Unknown), } } - ast::Expr::PrefixExpr(prefix_expr) => match prefix_expr.op_kind() { - Some(ast::UnaryOp::Neg) => { - let unsigned = Self::from_expr_opt(prefix_expr.expr()); - // Add sign - match unsigned { - Self::Scalar(ConstRef::UInt(num)) => { - Self::Scalar(ConstRef::Int(-(num as i128))) - } - other => other, - } - } - _ => Self::from_expr_opt(prefix_expr.expr()), - }, ast::Expr::Literal(literal) => Self::Scalar(match literal.kind() { ast::LiteralKind::IntNumber(num) => { - num.value().map(ConstRef::UInt).unwrap_or(ConstRef::Unknown) + num.value().map(LiteralConstRef::UInt).unwrap_or(LiteralConstRef::Unknown) } ast::LiteralKind::Char(c) => { - c.value().map(ConstRef::Char).unwrap_or(ConstRef::Unknown) + c.value().map(LiteralConstRef::Char).unwrap_or(LiteralConstRef::Unknown) } - ast::LiteralKind::Bool(f) => ConstRef::Bool(f), - _ => ConstRef::Unknown, + ast::LiteralKind::Bool(f) => LiteralConstRef::Bool(f), + _ => LiteralConstRef::Unknown, }), - _ => Self::Scalar(ConstRef::Unknown), + _ => { + if let Some(ast_id) = ast_id { + Self::Complex(ast_id) + } else { + Self::Scalar(LiteralConstRef::Unknown) + } + } } } } -/// A concrete constant value +/// A literal constant value #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ConstRef { +pub enum LiteralConstRef { Int(i128), UInt(u128), Bool(bool), @@ -460,18 +471,20 @@ pub enum ConstRef { Unknown, } -impl ConstRef { +impl LiteralConstRef { pub fn builtin_type(&self) -> BuiltinType { match self { - ConstRef::UInt(_) | ConstRef::Unknown => BuiltinType::Uint(BuiltinUint::U128), - ConstRef::Int(_) => BuiltinType::Int(BuiltinInt::I128), - ConstRef::Char(_) => BuiltinType::Char, - ConstRef::Bool(_) => BuiltinType::Bool, + LiteralConstRef::UInt(_) | LiteralConstRef::Unknown => { + BuiltinType::Uint(BuiltinUint::U128) + } + LiteralConstRef::Int(_) => BuiltinType::Int(BuiltinInt::I128), + LiteralConstRef::Char(_) => BuiltinType::Char, + LiteralConstRef::Bool(_) => BuiltinType::Bool, } } } -impl From for ConstRef { +impl From for LiteralConstRef { fn from(literal: Literal) -> Self { match literal { Literal::Char(c) => Self::Char(c), @@ -483,14 +496,14 @@ impl From for ConstRef { } } -impl std::fmt::Display for ConstRef { +impl std::fmt::Display for LiteralConstRef { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { match self { - ConstRef::Int(num) => num.fmt(f), - ConstRef::UInt(num) => num.fmt(f), - ConstRef::Bool(flag) => flag.fmt(f), - ConstRef::Char(c) => write!(f, "'{c}'"), - ConstRef::Unknown => f.write_char('_'), + LiteralConstRef::Int(num) => num.fmt(f), + LiteralConstRef::UInt(num) => num.fmt(f), + LiteralConstRef::Bool(flag) => flag.fmt(f), + LiteralConstRef::Char(c) => write!(f, "'{c}'"), + LiteralConstRef::Unknown => f.write_char('_'), } } } diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 98cff54cc22d9..44dd0a7b38cc7 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -89,8 +89,8 @@ use crate::{ builtin_type::BuiltinType, data::adt::VariantData, item_tree::{ - Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, MacroDef, MacroRules, ModItem, - Static, Struct, Trait, TraitAlias, TypeAlias, Union, + Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, MacroDef, MacroRules, Static, + Struct, Trait, TraitAlias, TypeAlias, Union, }, }; @@ -476,20 +476,55 @@ impl_from!( for ModuleDefId ); -// FIXME: make this a DefWithBodyId +/// Id of the anonymous const block expression and patterns. This is very similar to `ClosureId` and +/// shouldn't be a `DefWithBodyId` since its type inference is dependent on its parent. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub struct AnonymousConstId(InternId); impl_intern_key!(AnonymousConstId); +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub enum TypeOwnerId { + ModuleId(ModuleId), + DefWithBodyId(DefWithBodyId), + GenericDefId(GenericDefId), +} + +impl TypeOwnerId { + fn as_generic_def_id(self) -> Option { + match self { + TypeOwnerId::ModuleId(_) => None, + TypeOwnerId::DefWithBodyId(x) => x.as_generic_def_id(), + TypeOwnerId::GenericDefId(x) => Some(x), + } + } +} + +impl_from!(ModuleId, DefWithBodyId(FunctionId, ConstId, StaticId), GenericDefId(AdtId, TypeAliasId, ImplId) for TypeOwnerId); + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub struct InTypeConstId(InternId); +type InTypeConstLoc = (AstId, TypeOwnerId); +impl_intern!(InTypeConstId, InTypeConstLoc, intern_in_type_const, lookup_intern_in_type_const); + +impl InTypeConstId { + pub fn source(&self, db: &dyn db::DefDatabase) -> ast::Expr { + let src = self.lookup(db).0; + let file_id = src.file_id; + let root = &db.parse_or_expand(file_id); + db.ast_id_map(file_id).get(src.value).to_node(root) + } +} + /// A constant, which might appears as a const item, an annonymous const block in expressions /// or patterns, or as a constant in types with const generics. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum GeneralConstId { ConstId(ConstId), AnonymousConstId(AnonymousConstId), + InTypeConstId(InTypeConstId), } -impl_from!(ConstId, AnonymousConstId for GeneralConstId); +impl_from!(ConstId, AnonymousConstId, InTypeConstId for GeneralConstId); impl GeneralConstId { pub fn generic_def(self, db: &dyn db::DefDatabase) -> Option { @@ -499,6 +534,10 @@ impl GeneralConstId { let (parent, _) = db.lookup_intern_anonymous_const(x); parent.as_generic_def_id() } + GeneralConstId::InTypeConstId(x) => { + let (_, parent) = x.lookup(db); + parent.as_generic_def_id() + } } } @@ -512,6 +551,7 @@ impl GeneralConstId { .unwrap_or("_") .to_owned(), GeneralConstId::AnonymousConstId(id) => format!("{{anonymous const {id:?}}}"), + GeneralConstId::InTypeConstId(id) => format!("{{in type const {id:?}}}"), } } } @@ -522,10 +562,11 @@ pub enum DefWithBodyId { FunctionId(FunctionId), StaticId(StaticId), ConstId(ConstId), + InTypeConstId(InTypeConstId), VariantId(EnumVariantId), } -impl_from!(FunctionId, ConstId, StaticId for DefWithBodyId); +impl_from!(FunctionId, ConstId, StaticId, InTypeConstId for DefWithBodyId); impl From for DefWithBodyId { fn from(id: EnumVariantId) -> Self { @@ -540,6 +581,9 @@ impl DefWithBodyId { DefWithBodyId::StaticId(_) => None, DefWithBodyId::ConstId(c) => Some(c.into()), DefWithBodyId::VariantId(c) => Some(c.into()), + // FIXME: stable rust doesn't allow generics in constants, but we should + // use `TypeOwnerId::as_generic_def_id` when it does. + DefWithBodyId::InTypeConstId(_) => None, } } } @@ -734,24 +778,24 @@ impl HasModule for MacroId { } } -impl HasModule for DefWithBodyId { +impl HasModule for TypeOwnerId { fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { match self { - DefWithBodyId::FunctionId(it) => it.lookup(db).module(db), - DefWithBodyId::StaticId(it) => it.lookup(db).module(db), - DefWithBodyId::ConstId(it) => it.lookup(db).module(db), - DefWithBodyId::VariantId(it) => it.parent.lookup(db).container, + TypeOwnerId::ModuleId(x) => *x, + TypeOwnerId::DefWithBodyId(x) => x.module(db), + TypeOwnerId::GenericDefId(x) => x.module(db), } } } -impl DefWithBodyId { - pub fn as_mod_item(self, db: &dyn db::DefDatabase) -> ModItem { +impl HasModule for DefWithBodyId { + fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { match self { - DefWithBodyId::FunctionId(it) => it.lookup(db).id.value.into(), - DefWithBodyId::StaticId(it) => it.lookup(db).id.value.into(), - DefWithBodyId::ConstId(it) => it.lookup(db).id.value.into(), - DefWithBodyId::VariantId(it) => it.parent.lookup(db).id.value.into(), + DefWithBodyId::FunctionId(it) => it.lookup(db).module(db), + DefWithBodyId::StaticId(it) => it.lookup(db).module(db), + DefWithBodyId::ConstId(it) => it.lookup(db).module(db), + DefWithBodyId::VariantId(it) => it.parent.lookup(db).container, + DefWithBodyId::InTypeConstId(it) => it.lookup(db).1.module(db), } } } diff --git a/crates/hir-def/src/path.rs b/crates/hir-def/src/path.rs index b9b8082549718..ff4ae69546cf6 100644 --- a/crates/hir-def/src/path.rs +++ b/crates/hir-def/src/path.rs @@ -9,7 +9,7 @@ use std::{ use crate::{ lang_item::LangItemTarget, lower::LowerCtx, - type_ref::{ConstRefOrPath, LifetimeRef, TypeBound, TypeRef}, + type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef}, }; use hir_expand::name::Name; use intern::Interned; @@ -90,7 +90,7 @@ pub struct AssociatedTypeBinding { pub enum GenericArg { Type(TypeRef), Lifetime(LifetimeRef), - Const(ConstRefOrPath), + Const(ConstRef), } impl Path { diff --git a/crates/hir-def/src/path/lower.rs b/crates/hir-def/src/path/lower.rs index 26d2706175ca9..c8f6526ee8670 100644 --- a/crates/hir-def/src/path/lower.rs +++ b/crates/hir-def/src/path/lower.rs @@ -2,7 +2,7 @@ use std::iter; -use crate::{lower::LowerCtx, type_ref::ConstRefOrPath}; +use crate::{lower::LowerCtx, type_ref::ConstRef}; use either::Either; use hir_expand::name::{name, AsName}; @@ -217,7 +217,7 @@ pub(super) fn lower_generic_args( } } ast::GenericArg::ConstArg(arg) => { - let arg = ConstRefOrPath::from_expr_opt(arg.expr()); + let arg = ConstRef::from_expr_opt(lower_ctx, arg.expr()); args.push(GenericArg::Const(arg)) } } diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 06f5b2526a459..751649623a554 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -24,8 +24,8 @@ use crate::{ AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, - StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, - VariantId, + StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeOwnerId, + TypeParamId, VariantId, }; #[derive(Debug, Clone)] @@ -1009,6 +1009,16 @@ impl HasResolver for ExternBlockId { } } +impl HasResolver for TypeOwnerId { + fn resolver(self, db: &dyn DefDatabase) -> Resolver { + match self { + TypeOwnerId::ModuleId(it) => it.resolver(db), + TypeOwnerId::DefWithBodyId(it) => it.resolver(db), + TypeOwnerId::GenericDefId(it) => it.resolver(db), + } + } +} + impl HasResolver for DefWithBodyId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { match self { @@ -1016,6 +1026,7 @@ impl HasResolver for DefWithBodyId { DefWithBodyId::FunctionId(f) => f.resolver(db), DefWithBodyId::StaticId(s) => s.resolver(db), DefWithBodyId::VariantId(v) => v.parent.resolver(db), + DefWithBodyId::InTypeConstId(c) => c.lookup(db).1.resolver(db), } } } diff --git a/crates/hir-expand/src/ast_id_map.rs b/crates/hir-expand/src/ast_id_map.rs index 400442de94b98..023a9c8677721 100644 --- a/crates/hir-expand/src/ast_id_map.rs +++ b/crates/hir-expand/src/ast_id_map.rs @@ -98,6 +98,7 @@ impl AstIdMap { || ast::Variant::can_cast(kind) || ast::RecordField::can_cast(kind) || ast::TupleField::can_cast(kind) + || ast::Expr::can_cast(kind) { res.alloc(&it); true diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs index ac962c9e3e1f0..2a31e5cab8a2c 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -497,7 +497,7 @@ pub(crate) fn associated_ty_data_query( let generic_params = generics(db.upcast(), type_alias.into()); // let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST); let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast()); - let ctx = crate::TyLoweringContext::new(db, &resolver) + let ctx = crate::TyLoweringContext::new(db, &resolver, type_alias.into()) .with_type_param_mode(crate::lower::ParamLoweringMode::Variable); let trait_subst = TyBuilder::subst_for_def(db, trait_, None) diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 40b63b17b5aa4..0b762d96ae751 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -6,7 +6,7 @@ use hir_def::{ hir::Expr, path::Path, resolver::{Resolver, ValueNs}, - type_ref::ConstRef, + type_ref::LiteralConstRef, EnumVariantId, GeneralConstId, StaticId, }; use la_arena::{Idx, RawIdx}; @@ -129,23 +129,28 @@ pub fn intern_const_scalar(value: ConstScalar, ty: Ty) -> Const { } /// Interns a constant scalar with the given type -pub fn intern_const_ref(db: &dyn HirDatabase, value: &ConstRef, ty: Ty, krate: CrateId) -> Const { +pub fn intern_const_ref( + db: &dyn HirDatabase, + value: &LiteralConstRef, + ty: Ty, + krate: CrateId, +) -> Const { let layout = db.layout_of_ty(ty.clone(), krate); let bytes = match value { - ConstRef::Int(i) => { + LiteralConstRef::Int(i) => { // FIXME: We should handle failure of layout better. let size = layout.map(|x| x.size.bytes_usize()).unwrap_or(16); ConstScalar::Bytes(i.to_le_bytes()[0..size].to_vec(), MemoryMap::default()) } - ConstRef::UInt(i) => { + LiteralConstRef::UInt(i) => { let size = layout.map(|x| x.size.bytes_usize()).unwrap_or(16); ConstScalar::Bytes(i.to_le_bytes()[0..size].to_vec(), MemoryMap::default()) } - ConstRef::Bool(b) => ConstScalar::Bytes(vec![*b as u8], MemoryMap::default()), - ConstRef::Char(c) => { + LiteralConstRef::Bool(b) => ConstScalar::Bytes(vec![*b as u8], MemoryMap::default()), + LiteralConstRef::Char(c) => { ConstScalar::Bytes((*c as u32).to_le_bytes().to_vec(), MemoryMap::default()) } - ConstRef::Unknown => ConstScalar::Unknown, + LiteralConstRef::Unknown => ConstScalar::Unknown, }; intern_const_scalar(bytes, ty) } @@ -154,7 +159,7 @@ pub fn intern_const_ref(db: &dyn HirDatabase, value: &ConstRef, ty: Ty, krate: C pub fn usize_const(db: &dyn HirDatabase, value: Option, krate: CrateId) -> Const { intern_const_ref( db, - &value.map_or(ConstRef::Unknown, ConstRef::UInt), + &value.map_or(LiteralConstRef::Unknown, LiteralConstRef::UInt), TyBuilder::usize(), krate, ) @@ -221,6 +226,7 @@ pub(crate) fn const_eval_query( db.trait_environment_for_body(def), )?) } + GeneralConstId::InTypeConstId(c) => db.mir_body(c.into())?, }; let c = interpret_mir(db, &body, false).0?; Ok(c) diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 06fff08b7d35b..0db1fefbfef5b 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -2051,6 +2051,17 @@ fn extern_weak_statics() { ); } +#[test] +fn from_ne_bytes() { + check_number( + r#" +//- minicore: int_impl +const GOAL: u32 = u32::from_ne_bytes([44, 1, 0, 0]); + "#, + 300, + ); +} + #[test] fn enums() { check_number( diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index ca8a394e360dc..9dd810f844d4a 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -278,6 +278,7 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc DefWithBodyId::VariantId(it) => { db.enum_data(it.parent).variants[it.local_id].name.display(db.upcast()).to_string() } + DefWithBodyId::InTypeConstId(it) => format!("in type const {it:?}"), }); db.infer_query(def) } diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs index 7c38e6583a75f..9f9a56ffab06a 100644 --- a/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -18,9 +18,10 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec { let is_unsafe = match def { DefWithBodyId::FunctionId(it) => db.function_data(it).has_unsafe_kw(), - DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) | DefWithBodyId::VariantId(_) => { - false - } + DefWithBodyId::StaticId(_) + | DefWithBodyId::ConstId(_) + | DefWithBodyId::VariantId(_) + | DefWithBodyId::InTypeConstId(_) => false, }; if is_unsafe { return res; diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 80f32e96ee63f..ef1fd6d458d49 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -42,9 +42,9 @@ use triomphe::Arc; use crate::{ db::HirDatabase, fold_tys, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode, - static_lifetime, to_assoc_type_id, traits::FnTrait, AliasEq, AliasTy, ClosureId, DomainGoal, - GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, RpitId, Substitution, - TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, + static_lifetime, to_assoc_type_id, traits::FnTrait, utils::UnevaluatedConstEvaluatorFolder, + AliasEq, AliasTy, ClosureId, DomainGoal, GenericArg, Goal, ImplTraitId, InEnvironment, + Interner, ProjectionTy, RpitId, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, }; // This lint has a false positive here. See the link below for details. @@ -102,6 +102,10 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc { + // FIXME: We should know the expected type here. + ctx.return_ty = ctx.table.new_type_var(); + } } ctx.infer_body(); @@ -684,7 +688,7 @@ impl<'a> InferenceContext<'a> { fn collect_fn(&mut self, func: FunctionId) { let data = self.db.function_data(func); - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, func.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Param); let mut param_tys = data.params.iter().map(|type_ref| ctx.lower_ty(type_ref)).collect::>(); @@ -708,7 +712,7 @@ impl<'a> InferenceContext<'a> { } let return_ty = &*data.ret_type; - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); let return_ty = ctx.lower_ty(return_ty); let return_ty = self.insert_type_vars(return_ty); @@ -823,7 +827,7 @@ impl<'a> InferenceContext<'a> { } fn make_ty(&mut self, type_ref: &TypeRef) -> Ty { - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); let ty = ctx.lower_ty(type_ref); let ty = self.insert_type_vars(ty); self.normalize_associated_types_in(ty) @@ -850,7 +854,21 @@ impl<'a> InferenceContext<'a> { } fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { - self.table.unify(ty1, ty2) + let ty1 = ty1 + .clone() + .try_fold_with( + &mut UnevaluatedConstEvaluatorFolder { db: self.db }, + DebruijnIndex::INNERMOST, + ) + .unwrap(); + let ty2 = ty2 + .clone() + .try_fold_with( + &mut UnevaluatedConstEvaluatorFolder { db: self.db }, + DebruijnIndex::INNERMOST, + ) + .unwrap(); + self.table.unify(&ty1, &ty2) } /// Attempts to returns the deeply last field of nested structures, but @@ -973,7 +991,7 @@ impl<'a> InferenceContext<'a> { Some(path) => path, None => return (self.err_ty(), None), }; - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); let (resolution, unresolved) = if value_ns { match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path) { Some(ResolveValueResult::ValueNs(value)) => match value { diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 33e98ac86cf6b..e1efa0b6d8cc5 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -1715,6 +1715,7 @@ impl<'a> InferenceContext<'a> { const_or_path_to_chalk( this.db, &this.resolver, + this.owner.into(), ty, c, ParamLoweringMode::Placeholder, diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs index 95a20f983f1b4..79d9e21e797cd 100644 --- a/crates/hir-ty/src/infer/path.rs +++ b/crates/hir-ty/src/infer/path.rs @@ -44,7 +44,8 @@ impl InferenceContext<'_> { let last = path.segments().last()?; // Don't use `self.make_ty()` here as we need `orig_ns`. - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); + let ctx = + crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); let (ty, orig_ns) = ctx.lower_ty_ext(type_ref); let ty = self.table.insert_type_vars(ty); let ty = self.table.normalize_associated_types_in(ty); @@ -108,7 +109,7 @@ impl InferenceContext<'_> { } }; - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); let substs = ctx.substs_from_path(path, value_def, true); let substs = substs.as_slice(Interner); let parent_substs = self_subst.or_else(|| { @@ -190,7 +191,11 @@ impl InferenceContext<'_> { (TypeNs::TraitId(trait_), true) => { let segment = remaining_segments.last().expect("there should be at least one segment here"); - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); + let ctx = crate::lower::TyLoweringContext::new( + self.db, + &self.resolver, + self.owner.into(), + ); let trait_ref = ctx.lower_trait_ref_from_resolved_path(trait_, resolved_segment, None); self.resolve_trait_assoc_item(trait_ref, segment, id) @@ -202,7 +207,11 @@ impl InferenceContext<'_> { // as Iterator>::Item::default`) let remaining_segments_for_ty = remaining_segments.take(remaining_segments.len() - 1); - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); + let ctx = crate::lower::TyLoweringContext::new( + self.db, + &self.resolver, + self.owner.into(), + ); let (ty, _) = ctx.lower_partly_resolved_path( def, resolved_segment, diff --git a/crates/hir-ty/src/interner.rs b/crates/hir-ty/src/interner.rs index 89f7d9c4f4abc..e4dd4b86cf99c 100644 --- a/crates/hir-ty/src/interner.rs +++ b/crates/hir-ty/src/interner.rs @@ -266,7 +266,7 @@ impl chalk_ir::interner::Interner for Interner { c1: &Self::InternedConcreteConst, c2: &Self::InternedConcreteConst, ) -> bool { - (c1 == &ConstScalar::Unknown) || (c2 == &ConstScalar::Unknown) || (c1 == c2) + !matches!(c1, ConstScalar::Bytes(..)) || !matches!(c2, ConstScalar::Bytes(..)) || (c1 == c2) } fn intern_generic_arg( diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs index fca2e09ff0a99..0ff8c532d47ca 100644 --- a/crates/hir-ty/src/layout/tests.rs +++ b/crates/hir-ty/src/layout/tests.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use base_db::fixture::WithFixture; use chalk_ir::{AdtId, TyKind}; +use either::Either; use hir_def::db::DefDatabase; use triomphe::Arc; @@ -25,27 +26,38 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result, LayoutErro ); let (db, file_ids) = TestDB::with_many_files(&ra_fixture); - let (adt_id, module_id) = file_ids + let (adt_or_type_alias_id, module_id) = file_ids .into_iter() .find_map(|file_id| { let module_id = db.module_for_file(file_id); let def_map = module_id.def_map(&db); let scope = &def_map[module_id.local_id].scope; - let adt_id = scope.declarations().find_map(|x| match x { + let adt_or_type_alias_id = scope.declarations().find_map(|x| match x { hir_def::ModuleDefId::AdtId(x) => { let name = match x { hir_def::AdtId::StructId(x) => db.struct_data(x).name.to_smol_str(), hir_def::AdtId::UnionId(x) => db.union_data(x).name.to_smol_str(), hir_def::AdtId::EnumId(x) => db.enum_data(x).name.to_smol_str(), }; - (name == "Goal").then_some(x) + (name == "Goal").then_some(Either::Left(x)) + } + hir_def::ModuleDefId::TypeAliasId(x) => { + let name = db.type_alias_data(x).name.to_smol_str(); + (name == "Goal").then_some(Either::Right(x)) } _ => None, })?; - Some((adt_id, module_id)) + Some((adt_or_type_alias_id, module_id)) }) .unwrap(); - let goal_ty = TyKind::Adt(AdtId(adt_id), Substitution::empty(Interner)).intern(Interner); + let goal_ty = match adt_or_type_alias_id { + Either::Left(adt_id) => { + TyKind::Adt(AdtId(adt_id), Substitution::empty(Interner)).intern(Interner) + } + Either::Right(ty_id) => { + db.ty(ty_id.into()).substitute(Interner, &Substitution::empty(Interner)) + } + }; db.layout_of_ty(goal_ty, module_id.krate()) } @@ -379,10 +391,23 @@ fn niche_optimization() { #[test] fn const_eval() { + size_and_align! { + struct Goal([i32; 2 + 2]); + } size_and_align! { const X: usize = 5; struct Goal([i32; X]); } + size_and_align! { + mod foo { + pub(super) const BAR: usize = 5; + } + struct Ar([T; foo::BAR]); + struct Goal(Ar>); + } + size_and_align! { + type Goal = [u8; 2 + 2]; + } } #[test] diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 0c68891fe4932..65884b28ffdc1 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -27,10 +27,11 @@ use hir_def::{ nameres::MacroSubNs, path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, - type_ref::{ConstRefOrPath, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef}, + type_ref::{ConstRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef}, AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, StaticId, - StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId, + StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeOwnerId, TypeParamId, UnionId, + VariantId, }; use hir_expand::{name::Name, ExpandResult}; use intern::Interned; @@ -43,17 +44,21 @@ use triomphe::Arc; use crate::{ all_super_traits, - consteval::{intern_const_ref, path_to_const, unknown_const, unknown_const_as_generic}, + consteval::{ + intern_const_ref, intern_const_scalar, path_to_const, unknown_const, + unknown_const_as_generic, + }, db::HirDatabase, make_binders, mapping::{from_chalk_trait_id, ToChalk}, static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, utils::Generics, utils::{all_super_trait_refs, associated_type_by_name_including_super_traits, generics}, - AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, DebruijnIndex, DynTy, FnPointer, - FnSig, FnSubst, GenericArgData, ImplTraitId, Interner, ParamKind, PolyFnSig, ProjectionTy, - QuantifiedWhereClause, QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, - Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause, + AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy, + FnPointer, FnSig, FnSubst, GenericArgData, ImplTraitId, Interner, ParamKind, PolyFnSig, + ProjectionTy, QuantifiedWhereClause, QuantifiedWhereClauses, ReturnTypeImplTrait, + ReturnTypeImplTraits, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, + TyKind, WhereClause, }; #[derive(Debug)] @@ -106,6 +111,7 @@ pub struct TyLoweringContext<'a> { pub db: &'a dyn HirDatabase, resolver: &'a Resolver, in_binders: DebruijnIndex, + owner: TypeOwnerId, /// Note: Conceptually, it's thinkable that we could be in a location where /// some type params should be represented as placeholders, and others /// should be converted to variables. I think in practice, this isn't @@ -118,13 +124,14 @@ pub struct TyLoweringContext<'a> { } impl<'a> TyLoweringContext<'a> { - pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self { + pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver, owner: TypeOwnerId) -> Self { let impl_trait_mode = ImplTraitLoweringState::Disallowed; let type_param_mode = ParamLoweringMode::Placeholder; let in_binders = DebruijnIndex::INNERMOST; Self { db, resolver, + owner, in_binders, impl_trait_mode, type_param_mode, @@ -235,6 +242,7 @@ impl<'a> TyLoweringContext<'a> { let const_len = const_or_path_to_chalk( self.db, self.resolver, + self.owner, TyBuilder::usize(), len, self.type_param_mode, @@ -840,6 +848,7 @@ impl<'a> TyLoweringContext<'a> { const_or_path_to_chalk( self.db, self.resolver, + self.owner, ty, c, self.type_param_mode, @@ -1356,8 +1365,8 @@ pub(crate) fn field_types_query( }; let generics = generics(db.upcast(), def); let mut res = ArenaMap::default(); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, GenericDefId::from(variant_id.adt_id()).into()) + .with_type_param_mode(ParamLoweringMode::Variable); for (field_id, field_data) in var_data.fields().iter() { res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref))); } @@ -1379,8 +1388,8 @@ pub(crate) fn generic_predicates_for_param_query( assoc_name: Option, ) -> Arc<[Binders]> { let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, def.into()) + .with_type_param_mode(ParamLoweringMode::Variable); let generics = generics(db.upcast(), def); let mut predicates: Vec<_> = resolver .where_predicates_in_scope() @@ -1468,8 +1477,8 @@ pub(crate) fn trait_environment_query( def: GenericDefId, ) -> Arc { let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Placeholder); + let ctx = TyLoweringContext::new(db, &resolver, def.into()) + .with_type_param_mode(ParamLoweringMode::Placeholder); let mut traits_in_scope = Vec::new(); let mut clauses = Vec::new(); for pred in resolver.where_predicates_in_scope() { @@ -1527,8 +1536,8 @@ pub(crate) fn generic_predicates_query( def: GenericDefId, ) -> Arc<[Binders]> { let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, def.into()) + .with_type_param_mode(ParamLoweringMode::Variable); let generics = generics(db.upcast(), def); let mut predicates = resolver @@ -1582,8 +1591,8 @@ pub(crate) fn generic_defaults_query( def: GenericDefId, ) -> Arc<[Binders>]> { let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, def.into()) + .with_type_param_mode(ParamLoweringMode::Variable); let generic_params = generics(db.upcast(), def); let parent_start_idx = generic_params.len_self(); @@ -1648,11 +1657,11 @@ pub(crate) fn generic_defaults_recover( fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { let data = db.function_data(def); let resolver = def.resolver(db.upcast()); - let ctx_params = TyLoweringContext::new(db, &resolver) + let ctx_params = TyLoweringContext::new(db, &resolver, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Variable) .with_type_param_mode(ParamLoweringMode::Variable); let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr)).collect::>(); - let ctx_ret = TyLoweringContext::new(db, &resolver) + let ctx_ret = TyLoweringContext::new(db, &resolver, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) .with_type_param_mode(ParamLoweringMode::Variable); let ret = ctx_ret.lower_ty(&data.ret_type); @@ -1683,8 +1692,8 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders { let data = db.const_data(def); let generics = generics(db.upcast(), def.into()); let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, def.into()) + .with_type_param_mode(ParamLoweringMode::Variable); make_binders(db, &generics, ctx.lower_ty(&data.type_ref)) } @@ -1693,7 +1702,7 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders { fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders { let data = db.static_data(def); let resolver = def.resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver); + let ctx = TyLoweringContext::new(db, &resolver, def.into()); Binders::empty(Interner, ctx.lower_ty(&data.type_ref)) } @@ -1702,8 +1711,8 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS let struct_data = db.struct_data(def); let fields = struct_data.variant_data.fields(); let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, AdtId::from(def).into()) + .with_type_param_mode(ParamLoweringMode::Variable); let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::>(); let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders(); Binders::new(binders, CallableSig::from_params_and_return(params, ret, false, Safety::Safe)) @@ -1715,7 +1724,7 @@ fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Binders>(); let (ret, binders) = type_for_adt(db, def.parent.into()).into_value_and_skipped_binders(); Binders::new(binders, CallableSig::from_params_and_return(params, ret, false, Safety::Safe)) @@ -1762,8 +1771,8 @@ fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders { fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders { let generics = generics(db.upcast(), t.into()); let resolver = t.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, t.into()) + .with_type_param_mode(ParamLoweringMode::Variable); if db.type_alias_data(t).is_extern { Binders::empty(Interner, TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner)) } else { @@ -1884,8 +1893,8 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde "impl_self_ty_query({impl_id:?} -> {impl_loc:?} -> {impl_data:?})" )); let generics = generics(db.upcast(), impl_id.into()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, impl_id.into()) + .with_type_param_mode(ParamLoweringMode::Variable); make_binders(db, &generics, ctx.lower_ty(&impl_data.self_ty)) } @@ -1894,7 +1903,7 @@ pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> T let parent_data = db.generic_params(def.parent()); let data = &parent_data.type_or_consts[def.local_id()]; let resolver = def.parent().resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver); + let ctx = TyLoweringContext::new(db, &resolver, def.parent().into()); match data { TypeOrConstParamData::TypeParamData(_) => { never!(); @@ -1920,8 +1929,8 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option< let _cx = stdx::panic_context::enter(format!( "impl_trait_query({impl_id:?} -> {impl_loc:?} -> {impl_data:?})" )); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, impl_id.into()) + .with_type_param_mode(ParamLoweringMode::Variable); let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders(); let target_trait = impl_data.target_trait.as_ref()?; Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, Some(self_ty))?)) @@ -1934,7 +1943,7 @@ pub(crate) fn return_type_impl_traits( // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe let data = db.function_data(def); let resolver = def.resolver(db.upcast()); - let ctx_ret = TyLoweringContext::new(db, &resolver) + let ctx_ret = TyLoweringContext::new(db, &resolver, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) .with_type_param_mode(ParamLoweringMode::Variable); let _ret = ctx_ret.lower_ty(&data.ret_type); @@ -1969,7 +1978,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( arg: &'a GenericArg, this: &mut T, for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a, - for_const: impl FnOnce(&mut T, &ConstRefOrPath, Ty) -> Const + 'a, + for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a, ) -> Option { let kind = match kind_id { Either::Left(_) => ParamKind::Type, @@ -1997,7 +2006,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( let p = p.mod_path()?; if p.kind == PathKind::Plain { if let [n] = p.segments() { - let c = ConstRefOrPath::Path(n.clone()); + let c = ConstRef::Path(n.clone()); return Some( GenericArgData::Const(for_const(this, &c, c_ty)).intern(Interner), ); @@ -2013,15 +2022,16 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( pub(crate) fn const_or_path_to_chalk( db: &dyn HirDatabase, resolver: &Resolver, + owner: TypeOwnerId, expected_ty: Ty, - value: &ConstRefOrPath, + value: &ConstRef, mode: ParamLoweringMode, args: impl FnOnce() -> Generics, debruijn: DebruijnIndex, ) -> Const { match value { - ConstRefOrPath::Scalar(s) => intern_const_ref(db, s, expected_ty, resolver.krate()), - ConstRefOrPath::Path(n) => { + ConstRef::Scalar(s) => intern_const_ref(db, s, expected_ty, resolver.krate()), + ConstRef::Path(n) => { let path = ModPath::from_segments(PathKind::Plain, Some(n.clone())); path_to_const( db, @@ -2034,6 +2044,20 @@ pub(crate) fn const_or_path_to_chalk( ) .unwrap_or_else(|| unknown_const(expected_ty)) } + &ConstRef::Complex(x) => { + let crate_data = &db.crate_graph()[owner.module(db.upcast()).krate()]; + if crate_data.env.get("__ra_is_test_fixture").is_none() && crate_data.origin.is_local() + { + // FIXME: current `InTypeConstId` is very unstable, so we only use it in non local crate + // that are unlikely to be edited. + return unknown_const(expected_ty); + } + let c = db.intern_in_type_const((x, owner)).into(); + intern_const_scalar( + ConstScalar::UnevaluatedConst(c, Substitution::empty(Interner)), + expected_ty, + ) + } } } diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 6fa3d1351a916..ab6430e8f1955 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -570,7 +570,7 @@ impl ReceiverAdjustments { .intern(Interner); } } - never!("unsize_array with non-reference-to-array {:?}", ty); + // FIXME: report diagnostic if array unsizing happens without indirection. ty }; adjust.push(Adjustment { diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index aad1a82f2981c..e3401a36ceba7 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -1876,6 +1876,7 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result { db.enum_data(it.parent).variants[it.local_id].name.display(db.upcast()).to_string() } + DefWithBodyId::InTypeConstId(it) => format!("in type const {it:?}"), }); let body = db.body(def); let infer = db.infer(def); diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs index 58662b01b99b1..ac23e77bd2bb6 100644 --- a/crates/hir-ty/src/mir/pretty.rs +++ b/crates/hir-ty/src/mir/pretty.rs @@ -60,6 +60,9 @@ impl MirBody { let data = db.enum_data(id.parent); w!(this, "enum {} = ", data.name.display(db.upcast())); } + hir_def::DefWithBodyId::InTypeConstId(id) => { + w!(this, "in type const {id:?} = "); + } }); ctx.result } diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index 2db04024b7b64..8571412800615 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -146,6 +146,7 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour let loc = db.lookup_intern_enum(it.parent); loc.source(&db).value.syntax().text_range().start() } + DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(), }); let mut unexpected_type_mismatches = String::new(); for def in defs { @@ -391,6 +392,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { let loc = db.lookup_intern_enum(it.parent); loc.source(&db).value.syntax().text_range().start() } + DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(), }); for def in defs { let (body, source_map) = db.body_with_source_map(def); diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index f18c953a7afd2..047900a324e9f 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -1955,3 +1955,26 @@ impl Inner<1> { "#, ); } + +#[test] +fn dont_crash_on_slice_unsizing() { + check_no_mismatches( + r#" +//- minicore: slice, unsize, coerce_unsized +trait Tr { + fn f(self); +} + +impl Tr for [i32] { + fn f(self) { + let t; + x(t); + } +} + +fn x(a: [i32; 4]) { + let b = a.f(); +} + "#, + ); +} diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs index 883e6a29b06a6..de23902199f55 100644 --- a/crates/hir/src/from_id.rs +++ b/crates/hir/src/from_id.rs @@ -40,6 +40,7 @@ from_id![ (hir_def::TraitAliasId, crate::TraitAlias), (hir_def::StaticId, crate::Static), (hir_def::ConstId, crate::Const), + (hir_def::InTypeConstId, crate::InTypeConst), (hir_def::FunctionId, crate::Function), (hir_def::ImplId, crate::Impl), (hir_def::TypeOrConstParamId, crate::TypeOrConstParam), @@ -144,6 +145,7 @@ impl From for DefWithBodyId { DefWithBody::Static(it) => DefWithBodyId::StaticId(it.id), DefWithBody::Const(it) => DefWithBodyId::ConstId(it.id), DefWithBody::Variant(it) => DefWithBodyId::VariantId(it.into()), + DefWithBody::InTypeConst(it) => DefWithBodyId::InTypeConstId(it.id), } } } @@ -155,6 +157,7 @@ impl From for DefWithBody { DefWithBodyId::StaticId(it) => DefWithBody::Static(it.into()), DefWithBodyId::ConstId(it) => DefWithBody::Const(it.into()), DefWithBodyId::VariantId(it) => DefWithBody::Variant(it.into()), + DefWithBodyId::InTypeConstId(it) => DefWithBody::InTypeConst(it.into()), } } } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 5527eb59387ae..a11e25c79a21c 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -52,9 +52,10 @@ use hir_def::{ resolver::{HasResolver, Resolver}, src::HasSource as _, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, - EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId, - LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, - TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, + EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, InTypeConstId, ItemContainerId, + LifetimeParamId, LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, + StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, + UnionId, }; use hir_expand::{name::name, MacroCallKind}; use hir_ty::{ @@ -1375,8 +1376,9 @@ pub enum DefWithBody { Static(Static), Const(Const), Variant(Variant), + InTypeConst(InTypeConst), } -impl_from!(Function, Const, Static, Variant for DefWithBody); +impl_from!(Function, Const, Static, Variant, InTypeConst for DefWithBody); impl DefWithBody { pub fn module(self, db: &dyn HirDatabase) -> Module { @@ -1385,6 +1387,7 @@ impl DefWithBody { DefWithBody::Function(f) => f.module(db), DefWithBody::Static(s) => s.module(db), DefWithBody::Variant(v) => v.module(db), + DefWithBody::InTypeConst(c) => c.module(db), } } @@ -1394,6 +1397,7 @@ impl DefWithBody { DefWithBody::Static(s) => Some(s.name(db)), DefWithBody::Const(c) => c.name(db), DefWithBody::Variant(v) => Some(v.name(db)), + DefWithBody::InTypeConst(_) => None, } } @@ -1404,6 +1408,11 @@ impl DefWithBody { DefWithBody::Static(it) => it.ty(db), DefWithBody::Const(it) => it.ty(db), DefWithBody::Variant(it) => it.parent.variant_body_ty(db), + DefWithBody::InTypeConst(it) => Type::new_with_resolver_inner( + db, + &DefWithBodyId::from(it.id).resolver(db.upcast()), + TyKind::Error.intern(Interner), + ), } } @@ -1413,6 +1422,7 @@ impl DefWithBody { DefWithBody::Static(it) => it.id.into(), DefWithBody::Const(it) => it.id.into(), DefWithBody::Variant(it) => it.into(), + DefWithBody::InTypeConst(it) => it.id.into(), } } @@ -1797,6 +1807,8 @@ impl DefWithBody { DefWithBody::Static(it) => it.into(), DefWithBody::Const(it) => it.into(), DefWithBody::Variant(it) => it.into(), + // FIXME: don't ignore diagnostics for in type const + DefWithBody::InTypeConst(_) => return, }; for diag in hir_ty::diagnostics::incorrect_case(db, krate, def.into()) { acc.push(diag.into()) @@ -2085,6 +2097,17 @@ impl HasVisibility for Function { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct InTypeConst { + pub(crate) id: InTypeConstId, +} + +impl InTypeConst { + pub fn module(self, db: &dyn HirDatabase) -> Module { + Module { id: self.id.lookup(db.upcast()).1.module(db.upcast()) } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Const { pub(crate) id: ConstId, @@ -2515,7 +2538,7 @@ impl AsAssocItem for DefWithBody { match self { DefWithBody::Function(it) => it.as_assoc_item(db), DefWithBody::Const(it) => it.as_assoc_item(db), - DefWithBody::Static(_) | DefWithBody::Variant(_) => None, + DefWithBody::Static(_) | DefWithBody::Variant(_) | DefWithBody::InTypeConst(_) => None, } } } diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 2d2b00b147e55..d29d73387a90f 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -1074,8 +1074,12 @@ impl<'db> SemanticsImpl<'db> { fn resolve_type(&self, ty: &ast::Type) -> Option { let analyze = self.analyze(ty.syntax())?; let ctx = LowerCtx::with_file_id(self.db.upcast(), analyze.file_id); - let ty = hir_ty::TyLoweringContext::new(self.db, &analyze.resolver) - .lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone())); + let ty = hir_ty::TyLoweringContext::new( + self.db, + &analyze.resolver, + analyze.resolver.module().into(), + ) + .lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone())); Some(Type::new_with_resolver(self.db, &analyze.resolver, ty)) } diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 1374fa332c648..c5a22db045b2e 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -978,7 +978,8 @@ fn resolve_hir_path_( let types = || { let (ty, unresolved) = match path.type_anchor() { Some(type_ref) => { - let (_, res) = TyLoweringContext::new(db, resolver).lower_ty_ext(type_ref); + let (_, res) = TyLoweringContext::new(db, resolver, resolver.module().into()) + .lower_ty_ext(type_ref); res.map(|ty_ns| (ty_ns, path.segments().first())) } None => { diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs index 207e8206c92d5..43d957412bc8f 100644 --- a/crates/hir/src/symbols.rs +++ b/crates/hir/src/symbols.rs @@ -233,6 +233,7 @@ impl<'a> SymbolCollector<'a> { DefWithBodyId::VariantId(id) => { Some(self.db.enum_data(id.parent).variants[id.local_id].name.to_smol_str()) } + DefWithBodyId::InTypeConstId(_) => Some("in type const".into()), } } diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index 73cd5dcaf23fc..e8ff107bd4955 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -243,6 +243,8 @@ impl Definition { DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()), DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()), DefWithBody::Variant(v) => v.source(db).map(|src| src.syntax().cloned()), + // FIXME: implement + DefWithBody::InTypeConst(_) => return SearchScope::empty(), }; return match def { Some(def) => SearchScope::file_range(def.as_ref().original_file_range_full(db)), diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs index ce1e03a069b24..fd4e347d259f9 100644 --- a/crates/ide/src/inlay_hints/chaining.rs +++ b/crates/ide/src/inlay_hints/chaining.rs @@ -474,7 +474,7 @@ fn main() { file_id: FileId( 1, ), - range: 9332..9340, + range: 9333..9341, }, ), tooltip: "", @@ -487,7 +487,7 @@ fn main() { file_id: FileId( 1, ), - range: 9364..9368, + range: 9365..9369, }, ), tooltip: "", @@ -511,7 +511,7 @@ fn main() { file_id: FileId( 1, ), - range: 9332..9340, + range: 9333..9341, }, ), tooltip: "", @@ -524,7 +524,7 @@ fn main() { file_id: FileId( 1, ), - range: 9364..9368, + range: 9365..9369, }, ), tooltip: "", @@ -548,7 +548,7 @@ fn main() { file_id: FileId( 1, ), - range: 9332..9340, + range: 9333..9341, }, ), tooltip: "", @@ -561,7 +561,7 @@ fn main() { file_id: FileId( 1, ), - range: 9364..9368, + range: 9365..9369, }, ), tooltip: "", diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 0aca620a67553..b5fe237fc4c10 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -1403,6 +1403,12 @@ fn handle_hack_cargo_workspace( .unwrap(); crate_graph.remove_and_replace(fake, original).unwrap(); } + for (_, c) in crate_graph.iter_mut() { + if c.origin.is_local() { + // LangCrateOrigin::Other is good enough for a hack. + c.origin = CrateOrigin::Lang(LangCrateOrigin::Other); + } + } sysroot .crates() .filter_map(|krate| { diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 2c2a9a18d2e31..4c0a08d926bd4 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -328,14 +328,21 @@ impl flags::AnalysisStats { let analysis = host.analysis(); for f in funcs.iter().copied() { let name = f.name(db); - let full_name = f - .module(db) - .path_to_root(db) + let module = f.module(db); + let full_name = module + .krate() + .display_name(db) + .map(|x| x.canonical_name().to_string()) .into_iter() - .rev() - .filter_map(|it| it.name(db)) - .chain(Some(f.name(db))) - .map(|it| it.display(db).to_string()) + .chain( + module + .path_to_root(db) + .into_iter() + .filter_map(|it| it.name(db)) + .rev() + .chain(Some(f.name(db))) + .map(|it| it.display(db).to_string()), + ) .join("::"); if let Some(only_name) = self.only.as_deref() { if name.display(db).to_string() != only_name && full_name != only_name { diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index c79b4e966d67e..1484a4497a41d 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -32,6 +32,7 @@ //! include: //! index: sized //! infallible: +//! int_impl: size_of, transmute //! iterator: option //! iterators: iterator, fn //! manually_drop: drop @@ -44,6 +45,7 @@ //! range: //! result: //! send: sized +//! size_of: sized //! sized: //! slice: //! sync: sized @@ -345,6 +347,12 @@ pub mod mem { pub fn transmute(src: Src) -> Dst; } // endregion:transmute + + // region:size_of + extern "rust-intrinsic" { + pub fn size_of() -> usize; + } + // endregion:size_of } pub mod ptr { @@ -1307,6 +1315,25 @@ impl bool { } // endregion:bool_impl +// region:int_impl +macro_rules! impl_int { + ($($t:ty)*) => { + $( + impl $t { + pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { + unsafe { mem::transmute(bytes) } + } + } + )* + } +} + +impl_int! { + usize u8 u16 u32 u64 u128 + isize i8 i16 i32 i64 i128 +} +// endregion:int_impl + // region:error pub mod error { #[rustc_has_incoherent_inherent_impls] From d9136df9e56f8a6cb306e0f1df938edc9b864e33 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Wed, 7 Jun 2023 03:12:41 +0330 Subject: [PATCH 184/465] Handle return types for in type const bodies --- crates/hir-def/src/db.rs | 11 +++++---- crates/hir-def/src/lib.rs | 40 ++++++++++++++++++++++++++++--- crates/hir-ty/src/infer.rs | 15 ++++++++---- crates/hir-ty/src/lower.rs | 13 ++++++++-- crates/hir-ty/src/tests/simple.rs | 32 +++++++++++++++++++++++++ crates/hir-ty/src/utils.rs | 30 +++++++++++++++++++++-- 6 files changed, 125 insertions(+), 16 deletions(-) diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 3257667780260..28e76fb5a82a6 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -25,9 +25,9 @@ use crate::{ AnonymousConstId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, ExternBlockId, ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, InTypeConstId, LocalEnumVariantId, LocalFieldId, Macro2Id, Macro2Loc, MacroRulesId, - MacroRulesLoc, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, - TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, TypeOwnerId, - UnionId, UnionLoc, VariantId, + MacroRulesLoc, OpaqueInternableThing, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, + StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, + TypeOwnerId, UnionId, UnionLoc, VariantId, }; #[salsa::query_group(InternDatabaseStorage)] @@ -65,7 +65,10 @@ pub trait InternDatabase: SourceDatabase { #[salsa::interned] fn intern_anonymous_const(&self, id: (DefWithBodyId, ExprId)) -> AnonymousConstId; #[salsa::interned] - fn intern_in_type_const(&self, id: (AstId, TypeOwnerId)) -> InTypeConstId; + fn intern_in_type_const( + &self, + id: (AstId, TypeOwnerId, Box), + ) -> InTypeConstId; } #[salsa::query_group(DefDatabaseStorage)] diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 44dd0a7b38cc7..e90572ec97d9c 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -57,7 +57,10 @@ mod test_db; mod macro_expansion_tests; mod pretty; -use std::hash::{Hash, Hasher}; +use std::{ + hash::{Hash, Hasher}, + panic::{RefUnwindSafe, UnwindSafe}, +}; use base_db::{ impl_intern_key, @@ -501,9 +504,40 @@ impl TypeOwnerId { impl_from!(ModuleId, DefWithBodyId(FunctionId, ConstId, StaticId), GenericDefId(AdtId, TypeAliasId, ImplId) for TypeOwnerId); +/// A thing that we want to store in interned ids, but we don't know its type in `hir-def` +pub trait OpaqueInternableThing: + std::any::Any + std::fmt::Debug + Sync + Send + UnwindSafe + RefUnwindSafe +{ + fn as_any(&self) -> &dyn std::any::Any; + fn box_any(&self) -> Box; + fn dyn_hash(&self, state: &mut dyn Hasher); + fn dyn_eq(&self, other: &dyn OpaqueInternableThing) -> bool; + fn dyn_clone(&self) -> Box; +} + +impl Hash for dyn OpaqueInternableThing { + fn hash(&self, state: &mut H) { + self.dyn_hash(state); + } +} + +impl PartialEq for dyn OpaqueInternableThing { + fn eq(&self, other: &Self) -> bool { + self.dyn_eq(other) + } +} + +impl Eq for dyn OpaqueInternableThing {} + +impl Clone for Box { + fn clone(&self) -> Self { + self.dyn_clone() + } +} + #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub struct InTypeConstId(InternId); -type InTypeConstLoc = (AstId, TypeOwnerId); +type InTypeConstLoc = (AstId, TypeOwnerId, Box); impl_intern!(InTypeConstId, InTypeConstLoc, intern_in_type_const, lookup_intern_in_type_const); impl InTypeConstId { @@ -535,7 +569,7 @@ impl GeneralConstId { parent.as_generic_def_id() } GeneralConstId::InTypeConstId(x) => { - let (_, parent) = x.lookup(db); + let (_, parent, _) = x.lookup(db); parent.as_generic_def_id() } } diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index ef1fd6d458d49..6399fa052bc42 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -41,8 +41,13 @@ use stdx::{always, never}; use triomphe::Arc; use crate::{ - db::HirDatabase, fold_tys, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode, - static_lifetime, to_assoc_type_id, traits::FnTrait, utils::UnevaluatedConstEvaluatorFolder, + db::HirDatabase, + fold_tys, + infer::coerce::CoerceMany, + lower::ImplTraitLoweringMode, + static_lifetime, to_assoc_type_id, + traits::FnTrait, + utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder}, AliasEq, AliasTy, ClosureId, DomainGoal, GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, RpitId, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, }; @@ -102,9 +107,9 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc { - // FIXME: We should know the expected type here. - ctx.return_ty = ctx.table.new_type_var(); + DefWithBodyId::InTypeConstId(c) => { + ctx.return_ty = + c.lookup(db.upcast()).2.box_any().downcast::().unwrap().0; } } diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 65884b28ffdc1..c0bcf790b1f73 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -53,7 +53,10 @@ use crate::{ mapping::{from_chalk_trait_id, ToChalk}, static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, utils::Generics, - utils::{all_super_trait_refs, associated_type_by_name_including_super_traits, generics}, + utils::{ + all_super_trait_refs, associated_type_by_name_including_super_traits, generics, + InTypeConstIdMetadata, + }, AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy, FnPointer, FnSig, FnSubst, GenericArgData, ImplTraitId, Interner, ParamKind, PolyFnSig, ProjectionTy, QuantifiedWhereClause, QuantifiedWhereClauses, ReturnTypeImplTrait, @@ -2052,7 +2055,13 @@ pub(crate) fn const_or_path_to_chalk( // that are unlikely to be edited. return unknown_const(expected_ty); } - let c = db.intern_in_type_const((x, owner)).into(); + let c = db + .intern_in_type_const(( + x, + owner, + Box::new(InTypeConstIdMetadata(expected_ty.clone())), + )) + .into(); intern_const_scalar( ConstScalar::UnevaluatedConst(c, Substitution::empty(Interner)), expected_ty, diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs index 3ece40486dde8..fb0aa2faf1f24 100644 --- a/crates/hir-ty/src/tests/simple.rs +++ b/crates/hir-ty/src/tests/simple.rs @@ -1828,6 +1828,38 @@ impl Foo for u8 { ); } +#[test] +fn const_eval_in_function_signature() { + check_types( + r#" +const fn foo() -> usize { + 5 +} + +fn f() -> [u8; foo()] { + loop {} +} + +fn main() { + let t = f(); + //^ [u8; 5] +}"#, + ); + check_types( + r#" +//- minicore: default, builtin_impls +fn f() -> [u8; Default::default()] { + loop {} +} + +fn main() { + let t = f(); + //^ [u8; 0] +} + "#, + ); +} + #[test] fn shadowing_primitive_with_inner_items() { check_types( diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs index 681d087ede6ea..3636580630df8 100644 --- a/crates/hir-ty/src/utils.rs +++ b/crates/hir-ty/src/utils.rs @@ -1,7 +1,7 @@ //! Helper functions for working with def, which don't need to be a separate //! query, but can't be computed directly from `*Data` (ie, which need a `db`). -use std::iter; +use std::{hash::Hash, iter}; use base_db::CrateId; use chalk_ir::{ @@ -20,7 +20,8 @@ use hir_def::{ resolver::{HasResolver, TypeNs}, type_ref::{TraitBoundModifier, TypeRef}, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, ItemContainerId, - LocalEnumVariantId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, + LocalEnumVariantId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId, TypeOrConstParamId, + TypeParamId, }; use hir_expand::name::Name; use intern::Interned; @@ -464,3 +465,28 @@ pub(crate) fn detect_variant_from_bytes<'a>( }; Some((var_id, var_layout)) } + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub(crate) struct InTypeConstIdMetadata(pub(crate) Ty); + +impl OpaqueInternableThing for InTypeConstIdMetadata { + fn dyn_hash(&self, mut state: &mut dyn std::hash::Hasher) { + self.hash(&mut state); + } + + fn dyn_eq(&self, other: &dyn OpaqueInternableThing) -> bool { + other.as_any().downcast_ref::().map_or(false, |x| self == x) + } + + fn dyn_clone(&self) -> Box { + Box::new(self.clone()) + } + + fn as_any(&self) -> &dyn std::any::Any { + self + } + + fn box_any(&self) -> Box { + Box::new(self.clone()) + } +} From f8594f78bbb424e240120f02f423a81568b7d037 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Thu, 8 Jun 2023 23:47:45 +0330 Subject: [PATCH 185/465] Use `ConstArg` instead of `Expr` for `AstId` of `InTypeConstId` --- crates/hir-def/src/body.rs | 2 +- crates/hir-def/src/db.rs | 2 +- crates/hir-def/src/hir/type_ref.rs | 22 ++++++++----------- crates/hir-def/src/lib.rs | 4 ++-- crates/hir-def/src/path/lower.rs | 2 +- crates/hir-expand/src/ast_id_map.rs | 2 +- .../src/handlers/extract_type_alias.rs | 2 +- crates/parser/src/grammar/types.rs | 2 ++ .../parser/inline/ok/0017_array_type.rast | 5 +++-- .../test_data/parser/ok/0030_traits.rast | 5 +++-- .../parser/ok/0043_complex_assignment.rast | 5 +++-- crates/syntax/rust.ungram | 2 +- crates/syntax/src/ast/generated/nodes.rs | 2 +- 13 files changed, 29 insertions(+), 28 deletions(-) diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index 28a450081919f..3ed7dfefc0fcd 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -156,7 +156,7 @@ impl Body { (src.file_id, variant.expr(), false) } DefWithBodyId::InTypeConstId(c) => { - (c.lookup(db).0.file_id, Some(c.source(db)), false) + (c.lookup(db).0.file_id, c.source(db).expr(), false) } } }; diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 28e76fb5a82a6..b1a2d2028a87c 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -67,7 +67,7 @@ pub trait InternDatabase: SourceDatabase { #[salsa::interned] fn intern_in_type_const( &self, - id: (AstId, TypeOwnerId, Box), + id: (AstId, TypeOwnerId, Box), ) -> InTypeConstId; } diff --git a/crates/hir-def/src/hir/type_ref.rs b/crates/hir-def/src/hir/type_ref.rs index b4451c0426e3a..fa1f4933a2665 100644 --- a/crates/hir-def/src/hir/type_ref.rs +++ b/crates/hir-def/src/hir/type_ref.rs @@ -186,11 +186,7 @@ impl TypeRef { TypeRef::RawPtr(Box::new(inner_ty), mutability) } ast::Type::ArrayType(inner) => { - // FIXME: This is a hack. We should probably reuse the machinery of - // `hir_def::body::lower` to lower this into an `Expr` and then evaluate it at the - // `hir_ty` level, which would allow knowing the type of: - // let v: [u8; 2 + 2] = [0u8; 4]; - let len = ConstRef::from_expr_opt(ctx, inner.expr()); + let len = ConstRef::from_const_arg(ctx, inner.const_arg()); TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len) } ast::Type::SliceType(inner) => { @@ -383,18 +379,18 @@ impl TypeBound { pub enum ConstRef { Scalar(LiteralConstRef), Path(Name), - Complex(AstId), + Complex(AstId), } impl ConstRef { - pub(crate) fn from_expr_opt(lower_ctx: &LowerCtx<'_>, expr: Option) -> Self { - match expr { - Some(x) => { - let ast_id = lower_ctx.ast_id(&x); - Self::from_expr(x, ast_id) + pub(crate) fn from_const_arg(lower_ctx: &LowerCtx<'_>, arg: Option) -> Self { + if let Some(arg) = arg { + let ast_id = lower_ctx.ast_id(&arg); + if let Some(expr) = arg.expr() { + return Self::from_expr(expr, ast_id); } - None => Self::Scalar(LiteralConstRef::Unknown), } + Self::Scalar(LiteralConstRef::Unknown) } pub fn display<'a>(&'a self, db: &'a dyn ExpandDatabase) -> impl fmt::Display + 'a { @@ -412,7 +408,7 @@ impl ConstRef { } // We special case literals and single identifiers, to speed up things. - fn from_expr(expr: ast::Expr, ast_id: Option>) -> Self { + fn from_expr(expr: ast::Expr, ast_id: Option>) -> Self { fn is_path_ident(p: &ast::PathExpr) -> bool { let Some(path) = p.path() else { return false; diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index e90572ec97d9c..06b5dde1fc4a4 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -537,11 +537,11 @@ impl Clone for Box { #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub struct InTypeConstId(InternId); -type InTypeConstLoc = (AstId, TypeOwnerId, Box); +type InTypeConstLoc = (AstId, TypeOwnerId, Box); impl_intern!(InTypeConstId, InTypeConstLoc, intern_in_type_const, lookup_intern_in_type_const); impl InTypeConstId { - pub fn source(&self, db: &dyn db::DefDatabase) -> ast::Expr { + pub fn source(&self, db: &dyn db::DefDatabase) -> ast::ConstArg { let src = self.lookup(db).0; let file_id = src.file_id; let root = &db.parse_or_expand(file_id); diff --git a/crates/hir-def/src/path/lower.rs b/crates/hir-def/src/path/lower.rs index c8f6526ee8670..1cb17ff0d2618 100644 --- a/crates/hir-def/src/path/lower.rs +++ b/crates/hir-def/src/path/lower.rs @@ -217,7 +217,7 @@ pub(super) fn lower_generic_args( } } ast::GenericArg::ConstArg(arg) => { - let arg = ConstRef::from_expr_opt(lower_ctx, arg.expr()); + let arg = ConstRef::from_const_arg(lower_ctx, Some(arg)); args.push(GenericArg::Const(arg)) } } diff --git a/crates/hir-expand/src/ast_id_map.rs b/crates/hir-expand/src/ast_id_map.rs index 023a9c8677721..02efaace43707 100644 --- a/crates/hir-expand/src/ast_id_map.rs +++ b/crates/hir-expand/src/ast_id_map.rs @@ -98,7 +98,7 @@ impl AstIdMap { || ast::Variant::can_cast(kind) || ast::RecordField::can_cast(kind) || ast::TupleField::can_cast(kind) - || ast::Expr::can_cast(kind) + || ast::ConstArg::can_cast(kind) { res.alloc(&it); true diff --git a/crates/ide-assists/src/handlers/extract_type_alias.rs b/crates/ide-assists/src/handlers/extract_type_alias.rs index 71b45d88cb8c5..b6e7d6209c9cd 100644 --- a/crates/ide-assists/src/handlers/extract_type_alias.rs +++ b/crates/ide-assists/src/handlers/extract_type_alias.rs @@ -158,7 +158,7 @@ fn collect_used_generics<'gp>( .and_then(|lt| known_generics.iter().find(find_lifetime(<.text()))), ), ast::Type::ArrayType(ar) => { - if let Some(ast::Expr::PathExpr(p)) = ar.expr() { + if let Some(ast::Expr::PathExpr(p)) = ar.const_arg().and_then(|x| x.expr()) { if let Some(path) = p.path() { if let Some(name_ref) = path.as_single_name_ref() { if let Some(param) = known_generics.iter().find(|gp| { diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs index 93ef48350270b..96a6cdeaafffc 100644 --- a/crates/parser/src/grammar/types.rs +++ b/crates/parser/src/grammar/types.rs @@ -153,7 +153,9 @@ fn array_or_slice_type(p: &mut Parser<'_>) { // type T = [(); 92]; T![;] => { p.bump(T![;]); + let m = p.start(); expressions::expr(p); + m.complete(p, CONST_ARG); p.expect(T![']']); ARRAY_TYPE } diff --git a/crates/parser/test_data/parser/inline/ok/0017_array_type.rast b/crates/parser/test_data/parser/inline/ok/0017_array_type.rast index 2a5c644d46713..0d50144b73005 100644 --- a/crates/parser/test_data/parser/inline/ok/0017_array_type.rast +++ b/crates/parser/test_data/parser/inline/ok/0017_array_type.rast @@ -14,8 +14,9 @@ SOURCE_FILE R_PAREN ")" SEMICOLON ";" WHITESPACE " " - LITERAL - INT_NUMBER "92" + CONST_ARG + LITERAL + INT_NUMBER "92" R_BRACK "]" SEMICOLON ";" WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/ok/0030_traits.rast b/crates/parser/test_data/parser/ok/0030_traits.rast index 44423581e6abd..3965ae9596b50 100644 --- a/crates/parser/test_data/parser/ok/0030_traits.rast +++ b/crates/parser/test_data/parser/ok/0030_traits.rast @@ -51,8 +51,9 @@ SOURCE_FILE IDENT "i32" SEMICOLON ";" WHITESPACE " " - LITERAL - INT_NUMBER "1" + CONST_ARG + LITERAL + INT_NUMBER "1" R_BRACK "]" R_PAREN ")" SEMICOLON ";" diff --git a/crates/parser/test_data/parser/ok/0043_complex_assignment.rast b/crates/parser/test_data/parser/ok/0043_complex_assignment.rast index 3b02c3f96ae02..f3c85b45b6bd1 100644 --- a/crates/parser/test_data/parser/ok/0043_complex_assignment.rast +++ b/crates/parser/test_data/parser/ok/0043_complex_assignment.rast @@ -24,8 +24,9 @@ SOURCE_FILE IDENT "u8" SEMICOLON ";" WHITESPACE " " - LITERAL - INT_NUMBER "1" + CONST_ARG + LITERAL + INT_NUMBER "1" R_BRACK "]" WHITESPACE " " R_CURLY "}" diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram index 4c9027dec68e9..b096c9974489f 100644 --- a/crates/syntax/rust.ungram +++ b/crates/syntax/rust.ungram @@ -565,7 +565,7 @@ RefType = '&' Lifetime? 'mut'? Type ArrayType = - '[' Type ';' Expr ']' + '[' Type ';' ConstArg ']' SliceType = '[' Type ']' diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 61f6a04c98d38..e520801ea2ed6 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -1207,7 +1207,7 @@ impl ArrayType { pub fn l_brack_token(&self) -> Option { support::token(&self.syntax, T!['[']) } pub fn ty(&self) -> Option { support::child(&self.syntax) } pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } - pub fn expr(&self) -> Option { support::child(&self.syntax) } + pub fn const_arg(&self) -> Option { support::child(&self.syntax) } pub fn r_brack_token(&self) -> Option { support::token(&self.syntax, T![']']) } } From e83b56739f32e9cb71b0c8acf60f310539bc8dd2 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Sun, 11 Jun 2023 01:36:32 +0330 Subject: [PATCH 186/465] Flatten the `TypeOwnerId` --- crates/hir-def/src/lib.rs | 85 +++++++++++++++++++++++++++---- crates/hir-def/src/resolver.rs | 14 +++-- crates/hir/src/source_analyzer.rs | 4 +- 3 files changed, 89 insertions(+), 14 deletions(-) diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 06b5dde1fc4a4..69e4afe94f577 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -487,22 +487,81 @@ impl_intern_key!(AnonymousConstId); #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub enum TypeOwnerId { + FunctionId(FunctionId), + StaticId(StaticId), + ConstId(ConstId), + InTypeConstId(InTypeConstId), + AdtId(AdtId), + TraitId(TraitId), + TraitAliasId(TraitAliasId), + TypeAliasId(TypeAliasId), + ImplId(ImplId), + EnumVariantId(EnumVariantId), + // FIXME(const-generic-body): ModuleId should not be a type owner. This needs to be fixed to make `TypeOwnerId` actually + // useful for assigning ids to in type consts. ModuleId(ModuleId), - DefWithBodyId(DefWithBodyId), - GenericDefId(GenericDefId), } impl TypeOwnerId { fn as_generic_def_id(self) -> Option { - match self { - TypeOwnerId::ModuleId(_) => None, - TypeOwnerId::DefWithBodyId(x) => x.as_generic_def_id(), - TypeOwnerId::GenericDefId(x) => Some(x), + Some(match self { + TypeOwnerId::FunctionId(x) => GenericDefId::FunctionId(x), + TypeOwnerId::ConstId(x) => GenericDefId::ConstId(x), + TypeOwnerId::AdtId(x) => GenericDefId::AdtId(x), + TypeOwnerId::TraitId(x) => GenericDefId::TraitId(x), + TypeOwnerId::TraitAliasId(x) => GenericDefId::TraitAliasId(x), + TypeOwnerId::TypeAliasId(x) => GenericDefId::TypeAliasId(x), + TypeOwnerId::ImplId(x) => GenericDefId::ImplId(x), + TypeOwnerId::EnumVariantId(x) => GenericDefId::EnumVariantId(x), + TypeOwnerId::InTypeConstId(_) | TypeOwnerId::ModuleId(_) | TypeOwnerId::StaticId(_) => { + return None + } + }) + } +} + +impl_from!( + FunctionId, + StaticId, + ConstId, + InTypeConstId, + AdtId, + TraitId, + TraitAliasId, + TypeAliasId, + ImplId, + EnumVariantId, + ModuleId + for TypeOwnerId +); + +// Every `DefWithBodyId` is a type owner, since bodies can contain type (e.g. `{ let x: Type = _; }`) +impl From for TypeOwnerId { + fn from(value: DefWithBodyId) -> Self { + match value { + DefWithBodyId::FunctionId(x) => x.into(), + DefWithBodyId::StaticId(x) => x.into(), + DefWithBodyId::ConstId(x) => x.into(), + DefWithBodyId::InTypeConstId(x) => x.into(), + DefWithBodyId::VariantId(x) => x.into(), } } } -impl_from!(ModuleId, DefWithBodyId(FunctionId, ConstId, StaticId), GenericDefId(AdtId, TypeAliasId, ImplId) for TypeOwnerId); +impl From for TypeOwnerId { + fn from(value: GenericDefId) -> Self { + match value { + GenericDefId::FunctionId(x) => x.into(), + GenericDefId::AdtId(x) => x.into(), + GenericDefId::TraitId(x) => x.into(), + GenericDefId::TraitAliasId(x) => x.into(), + GenericDefId::TypeAliasId(x) => x.into(), + GenericDefId::ImplId(x) => x.into(), + GenericDefId::EnumVariantId(x) => x.into(), + GenericDefId::ConstId(x) => x.into(), + } + } +} /// A thing that we want to store in interned ids, but we don't know its type in `hir-def` pub trait OpaqueInternableThing: @@ -815,9 +874,17 @@ impl HasModule for MacroId { impl HasModule for TypeOwnerId { fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { match self { + TypeOwnerId::FunctionId(x) => x.lookup(db).module(db), + TypeOwnerId::StaticId(x) => x.lookup(db).module(db), + TypeOwnerId::ConstId(x) => x.lookup(db).module(db), + TypeOwnerId::InTypeConstId(x) => x.lookup(db).1.module(db), + TypeOwnerId::AdtId(x) => x.module(db), + TypeOwnerId::TraitId(x) => x.lookup(db).container, + TypeOwnerId::TraitAliasId(x) => x.lookup(db).container, + TypeOwnerId::TypeAliasId(x) => x.lookup(db).module(db), + TypeOwnerId::ImplId(x) => x.lookup(db).container, + TypeOwnerId::EnumVariantId(x) => x.parent.lookup(db).container, TypeOwnerId::ModuleId(x) => *x, - TypeOwnerId::DefWithBodyId(x) => x.module(db), - TypeOwnerId::GenericDefId(x) => x.module(db), } } } diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 751649623a554..880a76f2b85d0 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -1012,9 +1012,17 @@ impl HasResolver for ExternBlockId { impl HasResolver for TypeOwnerId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { match self { - TypeOwnerId::ModuleId(it) => it.resolver(db), - TypeOwnerId::DefWithBodyId(it) => it.resolver(db), - TypeOwnerId::GenericDefId(it) => it.resolver(db), + TypeOwnerId::FunctionId(x) => x.resolver(db), + TypeOwnerId::StaticId(x) => x.resolver(db), + TypeOwnerId::ConstId(x) => x.resolver(db), + TypeOwnerId::InTypeConstId(x) => x.lookup(db).1.resolver(db), + TypeOwnerId::AdtId(x) => x.resolver(db), + TypeOwnerId::TraitId(x) => x.resolver(db), + TypeOwnerId::TraitAliasId(x) => x.resolver(db), + TypeOwnerId::TypeAliasId(x) => x.resolver(db), + TypeOwnerId::ImplId(x) => x.resolver(db), + TypeOwnerId::EnumVariantId(x) => x.resolver(db), + TypeOwnerId::ModuleId(x) => x.resolver(db), } } } diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index c5a22db045b2e..ecb1b306a6687 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -38,8 +38,8 @@ use hir_ty::{ UnsafeExpr, }, lang_items::lang_items_for_bin_op, - method_resolution::{self}, - Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext, + method_resolution, Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, + TyLoweringContext, }; use itertools::Itertools; use smallvec::SmallVec; From 5f56956b3c7edb9801585850d1f41b0aeb1888ff Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Mon, 1 May 2023 22:22:43 -0400 Subject: [PATCH 187/465] implement `Sync` for `mpsc::Sender` --- library/std/src/sync/mpsc/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index 0e0c87d1c748e..71ff4237d007d 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -347,8 +347,8 @@ pub struct Sender { #[stable(feature = "rust1", since = "1.0.0")] unsafe impl Send for Sender {} -#[stable(feature = "rust1", since = "1.0.0")] -impl !Sync for Sender {} +#[stable(feature = "mpsc_sender_sync", since = "CURRENT_RUSTC_VERSION")] +unsafe impl Sync for Sender {} /// The sending-half of Rust's synchronous [`sync_channel`] type. /// From 008f5065d17d69e97a2e9ff4d80542ce677aea35 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Tue, 6 Jun 2023 01:40:51 +0900 Subject: [PATCH 188/465] fix(assist): derive source scope from syntax node to be transformed --- .../src/handlers/add_missing_impl_members.rs | 87 ++++++++++++++++--- .../replace_derive_with_manual_impl.rs | 34 ++++---- crates/ide-assists/src/utils.rs | 85 +++++++++++------- 3 files changed, 146 insertions(+), 60 deletions(-) diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 0cf7a848d8be6..c7f9fa5bd655a 100644 --- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -1,5 +1,4 @@ use hir::HasSource; -use ide_db::syntax_helpers::insert_whitespace_into_node::insert_ws_into; use syntax::ast::{self, make, AstNode}; use crate::{ @@ -129,20 +128,9 @@ fn add_missing_impl_members_inner( let target = impl_def.syntax().text_range(); acc.add(AssistId(assist_id, AssistKind::QuickFix), label, target, |edit| { let new_impl_def = edit.make_mut(impl_def.clone()); - let missing_items = missing_items - .into_iter() - .map(|it| { - if ctx.sema.hir_file_for(it.syntax()).is_macro() { - if let Some(it) = ast::AssocItem::cast(insert_ws_into(it.syntax().clone())) { - return it; - } - } - it.clone_for_update() - }) - .collect(); let first_new_item = add_trait_assoc_items_to_impl( &ctx.sema, - missing_items, + &missing_items, trait_, &new_impl_def, target_scope, @@ -1730,4 +1718,77 @@ impl m::Foo for S { }"#, ) } + + #[test] + fn nested_macro_should_not_cause_crash() { + check_assist( + add_missing_impl_members, + r#" +macro_rules! ty { () => { i32 } } +trait SomeTrait { type Output; } +impl SomeTrait for i32 { type Output = i64; } +macro_rules! define_method { + () => { + fn method(&mut self, params: ::Output); + }; +} +trait AnotherTrait { define_method!(); } +impl $0AnotherTrait for () { +} +"#, + r#" +macro_rules! ty { () => { i32 } } +trait SomeTrait { type Output; } +impl SomeTrait for i32 { type Output = i64; } +macro_rules! define_method { + () => { + fn method(&mut self, params: ::Output); + }; +} +trait AnotherTrait { define_method!(); } +impl AnotherTrait for () { + $0fn method(&mut self,params: ::Output) { + todo!() + } +} +"#, + ); + } + + // FIXME: `T` in `ty!(T)` should be replaced by `PathTransform`. + #[test] + fn paths_in_nested_macro_should_get_transformed() { + check_assist( + add_missing_impl_members, + r#" +macro_rules! ty { ($me:ty) => { $me } } +trait SomeTrait { type Output; } +impl SomeTrait for i32 { type Output = i64; } +macro_rules! define_method { + ($t:ty) => { + fn method(&mut self, params: ::Output); + }; +} +trait AnotherTrait { define_method!(T); } +impl $0AnotherTrait for () { +} +"#, + r#" +macro_rules! ty { ($me:ty) => { $me } } +trait SomeTrait { type Output; } +impl SomeTrait for i32 { type Output = i64; } +macro_rules! define_method { + ($t:ty) => { + fn method(&mut self, params: ::Output); + }; +} +trait AnotherTrait { define_method!(T); } +impl AnotherTrait for () { + $0fn method(&mut self,params: ::Output) { + todo!() + } +} +"#, + ); + } } diff --git a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index 1b0a8e0a8dae3..0469343dbfb1f 100644 --- a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -1,8 +1,5 @@ use hir::{InFile, ModuleDef}; -use ide_db::{ - helpers::mod_path_to_ast, imports::import_assets::NameToImport, items_locator, - syntax_helpers::insert_whitespace_into_node::insert_ws_into, -}; +use ide_db::{helpers::mod_path_to_ast, imports::import_assets::NameToImport, items_locator}; use itertools::Itertools; use syntax::{ ast::{self, AstNode, HasName}, @@ -202,19 +199,24 @@ fn impl_def_from_trait( node }; - let trait_items = trait_items - .into_iter() - .map(|it| { - if sema.hir_file_for(it.syntax()).is_macro() { - if let Some(it) = ast::AssocItem::cast(insert_ws_into(it.syntax().clone())) { - return it; - } - } - it.clone_for_update() - }) - .collect(); + // <<<<<<< HEAD + // let trait_items = trait_items + // .into_iter() + // .map(|it| { + // if sema.hir_file_for(it.syntax()).is_macro() { + // if let Some(it) = ast::AssocItem::cast(insert_ws_into(it.syntax().clone())) { + // return it; + // } + // } + // it.clone_for_update() + // }) + // .collect(); + // let first_assoc_item = + // add_trait_assoc_items_to_impl(sema, trait_items, trait_, &impl_def, target_scope); + // ======= let first_assoc_item = - add_trait_assoc_items_to_impl(sema, trait_items, trait_, &impl_def, target_scope); + add_trait_assoc_items_to_impl(sema, &trait_items, trait_, &impl_def, target_scope); + // >>>>>>> fix(assist): derive source scope from syntax node to be transformed // Generate a default `impl` function body for the derived trait. if let ast::AssocItem::Fn(ref func) = first_assoc_item { diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs index cc4a7f3c0adbe..03d8553506f14 100644 --- a/crates/ide-assists/src/utils.rs +++ b/crates/ide-assists/src/utils.rs @@ -3,8 +3,11 @@ use std::ops; pub(crate) use gen_trait_fn_body::gen_trait_fn_body; -use hir::{db::HirDatabase, HirDisplay, Semantics}; -use ide_db::{famous_defs::FamousDefs, path_transform::PathTransform, RootDatabase, SnippetCap}; +use hir::{db::HirDatabase, HirDisplay, InFile, Semantics}; +use ide_db::{ + famous_defs::FamousDefs, path_transform::PathTransform, + syntax_helpers::insert_whitespace_into_node::insert_ws_into, RootDatabase, SnippetCap, +}; use stdx::format_to; use syntax::{ ast::{ @@ -91,30 +94,21 @@ pub fn filter_assoc_items( sema: &Semantics<'_, RootDatabase>, items: &[hir::AssocItem], default_methods: DefaultMethods, -) -> Vec { - fn has_def_name(item: &ast::AssocItem) -> bool { - match item { - ast::AssocItem::Fn(def) => def.name(), - ast::AssocItem::TypeAlias(def) => def.name(), - ast::AssocItem::Const(def) => def.name(), - ast::AssocItem::MacroCall(_) => None, - } - .is_some() - } - - items +) -> Vec> { + return items .iter() // Note: This throws away items with no source. - .filter_map(|&i| { - let item = match i { - hir::AssocItem::Function(i) => ast::AssocItem::Fn(sema.source(i)?.value), - hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(sema.source(i)?.value), - hir::AssocItem::Const(i) => ast::AssocItem::Const(sema.source(i)?.value), + .copied() + .filter_map(|assoc_item| { + let item = match assoc_item { + hir::AssocItem::Function(it) => sema.source(it)?.map(ast::AssocItem::Fn), + hir::AssocItem::TypeAlias(it) => sema.source(it)?.map(ast::AssocItem::TypeAlias), + hir::AssocItem::Const(it) => sema.source(it)?.map(ast::AssocItem::Const), }; Some(item) }) .filter(has_def_name) - .filter(|it| match it { + .filter(|it| match &it.value { ast::AssocItem::Fn(def) => matches!( (default_methods, def.body()), (DefaultMethods::Only, Some(_)) | (DefaultMethods::No, None) @@ -125,26 +119,55 @@ pub fn filter_assoc_items( ), _ => default_methods == DefaultMethods::No, }) - .collect::>() + .collect(); + + fn has_def_name(item: &InFile) -> bool { + match &item.value { + ast::AssocItem::Fn(def) => def.name(), + ast::AssocItem::TypeAlias(def) => def.name(), + ast::AssocItem::Const(def) => def.name(), + ast::AssocItem::MacroCall(_) => None, + } + .is_some() + } } +/// Given `original_items` retrieved from the trait definition (usually by +/// [`filter_assoc_items()`]), clones each item for update and applies path transformation to it, +/// then inserts into `impl_`. Returns the modified `impl_` and the first associated item that got +/// inserted. pub fn add_trait_assoc_items_to_impl( sema: &Semantics<'_, RootDatabase>, - items: Vec, + original_items: &[InFile], trait_: hir::Trait, impl_: &ast::Impl, target_scope: hir::SemanticsScope<'_>, ) -> ast::AssocItem { - let source_scope = sema.scope_for_def(trait_); - - let transform = PathTransform::trait_impl(&target_scope, &source_scope, trait_, impl_.clone()); - let new_indent_level = IndentLevel::from_node(impl_.syntax()) + 1; - let items = items.into_iter().map(|assoc_item| { - transform.apply(assoc_item.syntax()); - assoc_item.remove_attrs_and_docs(); - assoc_item.reindent_to(new_indent_level); - assoc_item + let items = original_items.into_iter().map(|InFile { file_id, value: original_item }| { + let cloned_item = { + if file_id.is_macro() { + if let Some(formatted) = + ast::AssocItem::cast(insert_ws_into(original_item.syntax().clone())) + { + return formatted; + } else { + stdx::never!("formatted `AssocItem` could not be cast back to `AssocItem`"); + } + } + original_item.clone_for_update() + }; + + if let Some(source_scope) = sema.scope(original_item.syntax()) { + // FIXME: Paths in nested macros are not handled well. See + // `add_missing_impl_members::paths_in_nested_macro_should_get_transformed` test. + let transform = + PathTransform::trait_impl(&target_scope, &source_scope, trait_, impl_.clone()); + transform.apply(cloned_item.syntax()); + } + cloned_item.remove_attrs_and_docs(); + cloned_item.reindent_to(new_indent_level); + cloned_item }); let assoc_item_list = impl_.get_or_create_assoc_item_list(); From d091991491631faab8a13d7c119575d4a9f7316d Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Tue, 6 Jun 2023 03:07:24 +0900 Subject: [PATCH 189/465] fix(completion): derive source scope from syntax node to be transformed --- crates/hir/src/semantics.rs | 10 --- .../src/completions/item_list/trait_impl.rs | 81 ++++++++++++++++++- 2 files changed, 79 insertions(+), 12 deletions(-) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 2d2b00b147e55..36ded659b46da 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -483,10 +483,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.scope_at_offset(node, offset) } - pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> { - self.imp.scope_for_def(def) - } - pub fn assert_contains_node(&self, node: &SyntaxNode) { self.imp.assert_contains_node(node) } @@ -1307,12 +1303,6 @@ impl<'db> SemanticsImpl<'db> { ) } - fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> { - let file_id = self.db.lookup_intern_trait(def.id).id.file_id(); - let resolver = def.id.resolver(self.db.upcast()); - SemanticsScope { db: self.db, file_id, resolver } - } - fn source(&self, def: Def) -> Option> where Def::Ast: AstNode, diff --git a/crates/ide-completion/src/completions/item_list/trait_impl.rs b/crates/ide-completion/src/completions/item_list/trait_impl.rs index 664aa7b8397ea..269e40e6ef513 100644 --- a/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -227,9 +227,8 @@ fn get_transformed_assoc_item( assoc_item: ast::AssocItem, impl_def: hir::Impl, ) -> Option { - let assoc_item = assoc_item.clone_for_update(); let trait_ = impl_def.trait_(ctx.db)?; - let source_scope = &ctx.sema.scope_for_def(trait_); + let source_scope = &ctx.sema.scope(assoc_item.syntax())?; let target_scope = &ctx.sema.scope(ctx.sema.source(impl_def)?.syntax().value)?; let transform = PathTransform::trait_impl( target_scope, @@ -238,6 +237,9 @@ fn get_transformed_assoc_item( ctx.sema.source(impl_def)?.value, ); + let assoc_item = assoc_item.clone_for_update(); + // FIXME: Paths in nested macros are not handled well. See + // `macro_generated_assoc_item2` test. transform.apply(assoc_item.syntax()); assoc_item.remove_attrs_and_docs(); Some(assoc_item) @@ -1220,6 +1222,81 @@ impl Foo for Test { ); } + #[test] + fn macro_generated_assoc_item() { + check_edit( + "fn method", + r#" +macro_rules! ty { () => { i32 } } +trait SomeTrait { type Output; } +impl SomeTrait for i32 { type Output = i64; } +macro_rules! define_method { + () => { + fn method(&mut self, params: ::Output); + }; +} +trait AnotherTrait { define_method!(); } +impl AnotherTrait for () { + $0 +} +"#, + r#" +macro_rules! ty { () => { i32 } } +trait SomeTrait { type Output; } +impl SomeTrait for i32 { type Output = i64; } +macro_rules! define_method { + () => { + fn method(&mut self, params: ::Output); + }; +} +trait AnotherTrait { define_method!(); } +impl AnotherTrait for () { + fn method(&mut self,params: ::Output) { + $0 +} +} +"#, + ); + } + + // FIXME: `T` in `ty!(T)` should be replaced by `PathTransform`. + #[test] + fn macro_generated_assoc_item2() { + check_edit( + "fn method", + r#" +macro_rules! ty { ($me:ty) => { $me } } +trait SomeTrait { type Output; } +impl SomeTrait for i32 { type Output = i64; } +macro_rules! define_method { + ($t:ty) => { + fn method(&mut self, params: ::Output); + }; +} +trait AnotherTrait { define_method!(T); } +impl AnotherTrait for () { + $0 +} +"#, + r#" +macro_rules! ty { ($me:ty) => { $me } } +trait SomeTrait { type Output; } +impl SomeTrait for i32 { type Output = i64; } +macro_rules! define_method { + ($t:ty) => { + fn method(&mut self, params: ::Output); + }; +} +trait AnotherTrait { define_method!(T); } +impl AnotherTrait for () { + fn method(&mut self,params: ::Output) { + $0 +} +} +"#, + ); + } + #[test] fn includes_gat_generics() { check_edit( From ed8c58a3b1cb6f7d5264fa939bf46e3c6cf39046 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Sun, 11 Jun 2023 17:11:24 +0900 Subject: [PATCH 190/465] Remove commented out conflicts --- .../handlers/replace_derive_with_manual_impl.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index 0469343dbfb1f..3bdd795bea8a2 100644 --- a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -199,24 +199,8 @@ fn impl_def_from_trait( node }; - // <<<<<<< HEAD - // let trait_items = trait_items - // .into_iter() - // .map(|it| { - // if sema.hir_file_for(it.syntax()).is_macro() { - // if let Some(it) = ast::AssocItem::cast(insert_ws_into(it.syntax().clone())) { - // return it; - // } - // } - // it.clone_for_update() - // }) - // .collect(); - // let first_assoc_item = - // add_trait_assoc_items_to_impl(sema, trait_items, trait_, &impl_def, target_scope); - // ======= let first_assoc_item = add_trait_assoc_items_to_impl(sema, &trait_items, trait_, &impl_def, target_scope); - // >>>>>>> fix(assist): derive source scope from syntax node to be transformed // Generate a default `impl` function body for the derived trait. if let ast::AssocItem::Fn(ref func) = first_assoc_item { From b4795507e3e654bb3efe1b9fe2651ad4966ccc4d Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Sun, 11 Jun 2023 19:12:02 +0900 Subject: [PATCH 191/465] autoderef: completely resolve and deduplicate types --- crates/hir-ty/src/autoderef.rs | 24 ++++++++++- crates/hir/src/lib.rs | 8 ++-- crates/ide-completion/src/completions/dot.rs | 42 ++++++++++++++++++++ 3 files changed, 69 insertions(+), 5 deletions(-) diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs index f5b3f176b12e5..3860bccec8bbb 100644 --- a/crates/hir-ty/src/autoderef.rs +++ b/crates/hir-ty/src/autoderef.rs @@ -22,17 +22,37 @@ pub(crate) enum AutoderefKind { Overloaded, } +/// Returns types that `ty` transitively dereferences to. This function is only meant to be used +/// outside `hir-ty`. +/// +/// It is guaranteed that: +/// - the yielded types don't contain inference variables (but may contain `TyKind::Error`). +/// - a type won't be yielded more than once; in other words, the returned iterator will stop if it +/// detects a cycle in the deref chain. pub fn autoderef( db: &dyn HirDatabase, env: Arc, ty: Canonical, -) -> impl Iterator> + '_ { +) -> impl Iterator { let mut table = InferenceTable::new(db, env); let ty = table.instantiate_canonical(ty); let mut autoderef = Autoderef::new(&mut table, ty); let mut v = Vec::new(); while let Some((ty, _steps)) = autoderef.next() { - v.push(autoderef.table.canonicalize(ty).value); + // `ty` may contain unresolved inference variables. Since there's no chance they would be + // resolved, just replace with fallback type. + let resolved = autoderef.table.resolve_completely(ty); + + // If the deref chain contains a cycle (e.g. `A` derefs to `B` and `B` derefs to `A`), we + // would revisit some already visited types. Stop here to avoid duplication. + // + // XXX: The recursion limit for `Autoderef` is currently 10, so `Vec::contains()` shouldn't + // be too expensive. Replace this duplicate check with `FxHashSet` if it proves to be more + // performant. + if v.contains(&resolved) { + break; + } + v.push(resolved); } v.into_iter() } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 5527eb59387ae..c890c83bd4308 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -3795,14 +3795,16 @@ impl Type { } } - pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator + 'a { + /// Returns types that this type dereferences to (including this type itself). The returned + /// iterator won't yield the same type more than once even if the deref chain contains a cycle. + pub fn autoderef(&self, db: &dyn HirDatabase) -> impl Iterator + '_ { self.autoderef_(db).map(move |ty| self.derived(ty)) } - fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator + 'a { + fn autoderef_(&self, db: &dyn HirDatabase) -> impl Iterator { // There should be no inference vars in types passed here let canonical = hir_ty::replace_errors_with_variables(&self.ty); - autoderef(db, self.env.clone(), canonical).map(|canonical| canonical.value) + autoderef(db, self.env.clone(), canonical) } // This would be nicer if it just returned an iterator, but that runs into diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs index 57a784c45b614..78f6c034ba251 100644 --- a/crates/ide-completion/src/completions/dot.rs +++ b/crates/ide-completion/src/completions/dot.rs @@ -979,4 +979,46 @@ fn test(thing: impl Encrypt) { "#]], ) } + + #[test] + fn only_consider_same_type_once() { + check( + r#" +//- minicore: deref +struct A(u8); +struct B(u16); +impl core::ops::Deref for A { + type Target = B; + fn deref(&self) -> &Self::Target { loop {} } +} +impl core::ops::Deref for B { + type Target = A; + fn deref(&self) -> &Self::Target { loop {} } +} +fn test(a: A) { + a.$0 +} +"#, + expect![[r#" + fd 0 u16 + fd 0 u8 + me deref() (use core::ops::Deref) fn(&self) -> &::Target + "#]], + ); + } + + #[test] + fn no_inference_var_in_completion() { + check( + r#" +struct S(T); +fn test(s: S) { + s.$0 +} +"#, + expect![[r#" + fd 0 {unknown} + "#]], + ); + } } From 42eab5e10048869ab5119efd57adc6790f63bad3 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Sun, 11 Jun 2023 19:16:13 +0900 Subject: [PATCH 192/465] Deduplicate field names for completion --- crates/ide-completion/src/completions/dot.rs | 52 +++++++++++++++++++- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs index 78f6c034ba251..a00c6ecb91f07 100644 --- a/crates/ide-completion/src/completions/dot.rs +++ b/crates/ide-completion/src/completions/dot.rs @@ -105,9 +105,12 @@ fn complete_fields( mut named_field: impl FnMut(&mut Completions, hir::Field, hir::Type), mut tuple_index: impl FnMut(&mut Completions, usize, hir::Type), ) { + let mut seen_names = FxHashSet::default(); for receiver in receiver.autoderef(ctx.db) { for (field, ty) in receiver.fields(ctx.db) { - named_field(acc, field, ty); + if seen_names.insert(field.name(ctx.db)) { + named_field(acc, field, ty); + } } for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() { // Tuple fields are always public (tuple struct fields are handled above). @@ -671,6 +674,52 @@ impl T { ); } + #[test] + fn test_field_no_same_name() { + check( + r#" +//- minicore: deref +struct A { field: u8 } +struct B { field: u16, another: u32 } +impl core::ops::Deref for A { + type Target = B; + fn deref(&self) -> &Self::Target { loop {} } +} +fn test(a: A) { + a.$0 +} +"#, + expect![[r#" + fd another u32 + fd field u8 + me deref() (use core::ops::Deref) fn(&self) -> &::Target + "#]], + ); + } + + #[test] + fn test_tuple_field_no_same_index() { + check( + r#" +//- minicore: deref +struct A(u8); +struct B(u16, u32); +impl core::ops::Deref for A { + type Target = B; + fn deref(&self) -> &Self::Target { loop {} } +} +fn test(a: A) { + a.$0 +} +"#, + expect![[r#" + fd 0 u8 + fd 1 u32 + me deref() (use core::ops::Deref) fn(&self) -> &::Target + "#]], + ); + } + #[test] fn test_completion_works_in_consts() { check( @@ -1000,7 +1049,6 @@ fn test(a: A) { } "#, expect![[r#" - fd 0 u16 fd 0 u8 me deref() (use core::ops::Deref) fn(&self) -> &::Target "#]], From 8c2b14f7088c31c442f1ebc5c0ad7d5e22011963 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 11 Jun 2023 11:41:06 -0400 Subject: [PATCH 193/465] Update to nightly-2023-06-11 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 933ecd45baadb..90f9a621077a6 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-03-02" +channel = "nightly-2023-06-11" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] From c8376e4c78cfdc4d55b6c818fc888a6d62dc08fe Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 3 Jun 2023 09:04:12 -0400 Subject: [PATCH 194/465] Add usage of git subtree to readme --- Readme.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index bb74194389254..593cd3f9bbf43 100644 --- a/Readme.md +++ b/Readme.md @@ -193,7 +193,7 @@ Using git-subtree with `rustc` requires a patched git to make it work. The PR that is needed is [here](https://github.com/gitgitgadget/git/pull/493). Use the following instructions to install it: -``` +```bash git clone git@github.com:tqc/git.git cd git git checkout tqc/subtree @@ -204,6 +204,12 @@ make cp git-subtree ~/bin ``` +Then, do a sync with this command: + +```bash +PATH="$HOME/bin:$PATH" ~/bin/git-subtree push -P compiler/rustc_codegen_gcc/ ../rustc_codegen_gcc/ sync_branch_name +``` + ### How to use [mem-trace](https://github.com/antoyo/mem-trace) `rustc` needs to be built without `jemalloc` so that `mem-trace` can overload `malloc` since `jemalloc` is linked statically, so a `LD_PRELOAD`-ed library won't a chance to intercept the calls to `malloc`. From 94e5c2701228b6fc8d765136967ddc6d51dff6a9 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 3 Jun 2023 09:34:56 -0400 Subject: [PATCH 195/465] Update libgccjit and mini_core --- Cargo.lock | 4 ++-- example/mini_core.rs | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f2e152f8ce56..1c8754bf675ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,7 +35,7 @@ dependencies = [ [[package]] name = "gccjit" version = "1.0.0" -source = "git+https://github.com/antoyo/gccjit.rs#fe242b7eb26980e6c78859d51c8d4cc1e43381a3" +source = "git+https://github.com/antoyo/gccjit.rs#d6e52626cfc6f487094a5d5ac66302baf3439984" dependencies = [ "gccjit_sys", ] @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "gccjit_sys" version = "0.0.1" -source = "git+https://github.com/antoyo/gccjit.rs#fe242b7eb26980e6c78859d51c8d4cc1e43381a3" +source = "git+https://github.com/antoyo/gccjit.rs#d6e52626cfc6f487094a5d5ac66302baf3439984" dependencies = [ "libc", ] diff --git a/example/mini_core.rs b/example/mini_core.rs index 637b8dc53fefd..f0347db00cc26 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -451,6 +451,9 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { drop_in_place(to_drop); } +#[lang = "unpin"] +pub auto trait Unpin {} + #[lang = "deref"] pub trait Deref { type Target: ?Sized; @@ -486,7 +489,18 @@ impl DispatchFromDyn> for Unique where T: Uns #[lang = "owned_box"] pub struct Box(Unique, A); -impl, U: ?Sized, A: Allocator> CoerceUnsized> for Box {} +impl, U: ?Sized> CoerceUnsized> for Box {} + +impl Box { + pub fn new(val: T) -> Box { + unsafe { + let size = intrinsics::size_of::(); + let ptr = libc::malloc(size); + intrinsics::copy(&val as *const T as *const u8, ptr, size); + Box(Unique { pointer: NonNull(ptr as *const T), _marker: PhantomData }, Global) + } + } +} impl Drop for Box { fn drop(&mut self) { From 4115e09c13a975b42d506e2db6119d7c3ff1876e Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 4 Jun 2023 13:14:55 -0400 Subject: [PATCH 196/465] Fix for opaque pointers --- Cargo.toml | 2 +- src/builder.rs | 40 ++++++++++++++++++++++++++-------------- src/type_of.rs | 6 +++--- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7285e3eaf5198..81066d9ce1f0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ master = ["gccjit/master"] gccjit = { git = "https://github.com/antoyo/gccjit.rs" } # Local copy. -# gccjit = { path = "../gccjit.rs" } +#gccjit = { path = "../gccjit.rs" } smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } diff --git a/src/builder.rs b/src/builder.rs index f9ea0f004564b..d578a0df51d6f 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -280,8 +280,17 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } } - fn function_ptr_call(&mut self, func_ptr: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> { - let gcc_func = func_ptr.get_type().dyncast_function_ptr_type().expect("function ptr"); + fn function_ptr_call(&mut self, typ: Type<'gcc>, mut func_ptr: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> { + let gcc_func = + match func_ptr.get_type().dyncast_function_ptr_type() { + Some(func) => func, + None => { + // NOTE: due to opaque pointers now being used, we need to cast here. + let new_func_type = typ.dyncast_function_ptr_type().expect("function ptr"); + func_ptr = self.context.new_cast(None, func_ptr, typ); + new_func_type + }, + }; let func_name = format!("{:?}", func_ptr); let previous_arg_count = args.len(); let orig_args = args; @@ -424,16 +433,17 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.llbb().end_with_void_return(None) } - fn ret(&mut self, value: RValue<'gcc>) { - let value = - if self.structs_as_pointer.borrow().contains(&value) { - // NOTE: hack to workaround a limitation of the rustc API: see comment on - // CodegenCx.structs_as_pointer - value.dereference(None).to_rvalue() - } - else { - value - }; + fn ret(&mut self, mut value: RValue<'gcc>) { + if self.structs_as_pointer.borrow().contains(&value) { + // NOTE: hack to workaround a limitation of the rustc API: see comment on + // CodegenCx.structs_as_pointer + value = value.dereference(None).to_rvalue(); + } + let expected_return_type = self.current_func().get_return_type(); + if !expected_return_type.is_compatible_with(value.get_type()) { + // NOTE: due to opaque pointers now being used, we need to cast here. + value = self.context.new_cast(None, value, expected_return_type); + } self.llbb().end_with_return(None, value); } @@ -938,6 +948,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { element.get_address(None) } else if let Some(struct_type) = value_type.is_struct() { + // NOTE: due to opaque pointers now being used, we need to bitcast here. + let ptr = self.bitcast_if_needed(ptr, value_type.make_pointer()); ptr.dereference_field(None, struct_type.get_field(idx as i32)).get_address(None) } else { @@ -1356,7 +1368,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn call( &mut self, - _typ: Type<'gcc>, + typ: Type<'gcc>, _fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, @@ -1370,7 +1382,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } else { // If it's a not function that was defined, it's a function pointer. - self.function_ptr_call(func, args, funclet) + self.function_ptr_call(typ, func, args, funclet) }; if let Some(_fn_abi) = fn_abi { // TODO(bjorn3): Apply function attributes diff --git a/src/type_of.rs b/src/type_of.rs index 30a3fe67b8543..74f016cf90ae5 100644 --- a/src/type_of.rs +++ b/src/type_of.rs @@ -383,8 +383,8 @@ impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { unimplemented!(); } - fn fn_decl_backend_type(&self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> { - // FIXME(antoyo): return correct type. - self.type_void() + fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> { + let (return_type, param_types, variadic, _) = fn_abi.gcc_type(self); + self.context.new_function_pointer_type(None, return_type, ¶m_types, variadic) } } From e74bc5113dac9f00b2eabcd1963d05e0f1a84ec2 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 4 Jun 2023 18:21:44 -0400 Subject: [PATCH 197/465] Attempt to fix the tests --- build_sysroot/prepare_sysroot_src.sh | 8 ++++---- src/intrinsic/simd.rs | 9 +++++++-- src/lib.rs | 2 ++ test.sh | 15 ++++++++++++--- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/build_sysroot/prepare_sysroot_src.sh b/build_sysroot/prepare_sysroot_src.sh index 56768bbf1d015..71b3876bac2cf 100755 --- a/build_sysroot/prepare_sysroot_src.sh +++ b/build_sysroot/prepare_sysroot_src.sh @@ -29,10 +29,10 @@ git config user.name || git config user.name "None" git commit -m "Initial commit" -q for file in $(ls ../../patches/ | grep -v patcha); do -echo "[GIT] apply" $file -git apply ../../patches/$file -git add -A -git commit --no-gpg-sign -m "Patch $file" + echo "[GIT] apply" $file + git apply ../../patches/$file + git add -A + git commit --no-gpg-sign -m "Patch $file" done popd diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index b59c3a64f5728..36b9c9b636412 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -165,10 +165,15 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( InvalidMonomorphizationReturnIntegerType { span, name, ret_ty, out_ty } ); + let arg1 = args[0].immediate(); + // NOTE: we get different vector types for the same vector type and libgccjit doesn't + // compare them as equal, so bitcast. + // FIXME(antoyo): allow comparing vector types as equal in libgccjit. + let arg2 = bx.context.new_bitcast(None, args[1].immediate(), arg1.get_type()); return Ok(compare_simd_types( bx, - args[0].immediate(), - args[1].immediate(), + arg1, + arg2, in_elem, llret_ty, cmp_op, diff --git a/src/lib.rs b/src/lib.rs index 204741ca3c1b2..3bf92c063022c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +// FIXME: simple programs now segfault with a sysroot compile in release mode. + /* * TODO(antoyo): implement equality in libgccjit based on https://zpz.github.io/blog/overloading-equality-operator-in-cpp-class-hierarchy/ (for type equality?) * TODO(antoyo): support #[inline] attributes. diff --git a/test.sh b/test.sh index 6139892aefca7..c62c49cef994e 100755 --- a/test.sh +++ b/test.sh @@ -214,12 +214,14 @@ function setup_rustc() { rm config.toml || true cat > config.toml < Date: Thu, 8 Jun 2023 20:51:29 -0400 Subject: [PATCH 198/465] Add missing cast to fix another issue caused by opaque pointers --- src/builder.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/builder.rs b/src/builder.rs index d578a0df51d6f..f2775421ccd08 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -919,7 +919,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.context.new_bitcast(None, result, ptr_type) } - fn inbounds_gep(&mut self, _typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> { + fn inbounds_gep(&mut self, typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> { + // NOTE: due to opaque pointers now being used, we need to cast here. + let ptr = self.context.new_cast(None, ptr, typ.make_pointer()); // NOTE: array indexing is always considered in bounds in GCC (TODO(antoyo): to be verified). let mut indices = indices.into_iter(); let index = indices.next().expect("first index in inbounds_gep"); From 984b9c52ccc0d493d2215167ecb03d76e9cb30ec Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 9 Jun 2023 10:00:50 -0400 Subject: [PATCH 199/465] Improve sync instructions --- Readme.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Readme.md b/Readme.md index 593cd3f9bbf43..a93637d9038dc 100644 --- a/Readme.md +++ b/Readme.md @@ -208,8 +208,17 @@ Then, do a sync with this command: ```bash PATH="$HOME/bin:$PATH" ~/bin/git-subtree push -P compiler/rustc_codegen_gcc/ ../rustc_codegen_gcc/ sync_branch_name +cd ../rustc_codegen_gcc +git checkout master +git pull +git checkout sync_branch_name +git merge master ``` +TODO: write a script that does the above. + +https://rust-lang.zulipchat.com/#narrow/stream/301329-t-devtools/topic/subtree.20madness/near/258877725 + ### How to use [mem-trace](https://github.com/antoyo/mem-trace) `rustc` needs to be built without `jemalloc` so that `mem-trace` can overload `malloc` since `jemalloc` is linked statically, so a `LD_PRELOAD`-ed library won't a chance to intercept the calls to `malloc`. From e9708ebcefe398d5d8669e80260a4c73415ddc1d Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 10 Jun 2023 14:08:33 -0400 Subject: [PATCH 200/465] Add note --- test.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test.sh b/test.sh index c62c49cef994e..7c8fe55da14e2 100755 --- a/test.sh +++ b/test.sh @@ -356,11 +356,12 @@ function test_rustc() { # We need to overwrite the sysroot in the tests, now. # TODO(antoyo): find a faster way to do this. # FIXME: this makes the stderr different since it changes the line numbers. - for file in $(find tests/ui -type f -name '*.rs'); do - sed -ie "1i // compile-flags: --sysroot "$(pwd)"/../build_sysroot/sysroot\n" $file - done + #for file in $(find tests/ui -type f -name '*.rs'); do + #sed -ie "1i // compile-flags: --sysroot "$(pwd)"/../build_sysroot/sysroot\n" $file + #done - RUSTC_ARGS="$TEST_FLAGS -Csymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext"" + # TODO: copy the sysroot at the correct location to not have to use the --sysroot flag. + RUSTC_ARGS="$TEST_FLAGS -Csymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot" if [ $# -eq 0 ]; then # No argument supplied to the function. Doing nothing. From a0edbfb2d3f163f899156a2f2050b227463ba659 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 11 Jun 2023 11:35:35 -0400 Subject: [PATCH 201/465] Test to fix UI tests --- test.sh | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/test.sh b/test.sh index 7c8fe55da14e2..5c5c26699b094 100755 --- a/test.sh +++ b/test.sh @@ -213,6 +213,13 @@ function setup_rustc() { rm config.toml || true + # TODO: copy in build_sysroot/build_sysroot.sh instead to avoid having to rebuild stage0 libraries everytime? + my_toolchain_dir=$HOME/.rustup/toolchains/my_toolchain + rm -rf $my_toolchain_dir + cp -r $HOME/.rustup/toolchains/$rust_toolchain-$TARGET_TRIPLE $my_toolchain_dir + rm -rf $my_toolchain_dir/lib/rustlib/x86_64-unknown-linux-gnu/ + cp -r ../build_sysroot/sysroot/* $my_toolchain_dir + cat > config.toml < ../trace + COMPILETEST_FORCE_STAGE0=1 ./x.py test --run always --stage 0 tests/ui/zero-sized/zero-sized-linkedlist-push.rs --rustc-args "$RUSTC_ARGS" } function test_failing_rustc() { From 52bb94d697d369819e2edca77902ed7b4e74e813 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 11 Jun 2023 19:56:24 +0200 Subject: [PATCH 202/465] internal: Give rustfmt jobs a separate thread --- crates/rust-analyzer/src/dispatch.rs | 46 ++++++++++++++------ crates/rust-analyzer/src/global_state.rs | 7 +++ crates/rust-analyzer/src/handlers/request.rs | 13 +++--- crates/rust-analyzer/src/main_loop.rs | 17 ++++---- 4 files changed, 54 insertions(+), 29 deletions(-) diff --git a/crates/rust-analyzer/src/dispatch.rs b/crates/rust-analyzer/src/dispatch.rs index ebe77b8dfe721..8a0ad88b654dc 100644 --- a/crates/rust-analyzer/src/dispatch.rs +++ b/crates/rust-analyzer/src/dispatch.rs @@ -135,7 +135,7 @@ impl<'a> RequestDispatcher<'a> { R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug, R::Result: Serialize, { - self.on_with_thread_intent::(ThreadIntent::Worker, f) + self.on_with_thread_intent::(ThreadIntent::Worker, f) } /// Dispatches a latency-sensitive request onto the thread pool. @@ -148,7 +148,22 @@ impl<'a> RequestDispatcher<'a> { R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug, R::Result: Serialize, { - self.on_with_thread_intent::(ThreadIntent::LatencySensitive, f) + self.on_with_thread_intent::(ThreadIntent::LatencySensitive, f) + } + + /// Formatting requests should never block on waiting a for task thread to open up, editors will wait + /// on the response and a late formatting update might mess with the document and user. + /// We can't run this on the main thread though as we invoke rustfmt which may take arbitrary time to complete! + pub(crate) fn on_fmt_thread( + &mut self, + f: fn(GlobalStateSnapshot, R::Params) -> Result, + ) -> &mut Self + where + R: lsp_types::request::Request + 'static, + R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug, + R::Result: Serialize, + { + self.on_with_thread_intent::(ThreadIntent::LatencySensitive, f) } pub(crate) fn finish(&mut self) { @@ -163,7 +178,7 @@ impl<'a> RequestDispatcher<'a> { } } - fn on_with_thread_intent( + fn on_with_thread_intent( &mut self, intent: ThreadIntent, f: fn(GlobalStateSnapshot, R::Params) -> Result, @@ -178,17 +193,20 @@ impl<'a> RequestDispatcher<'a> { None => return self, }; - self.global_state.task_pool.handle.spawn(intent, { - let world = self.global_state.snapshot(); - move || { - let result = panic::catch_unwind(move || { - let _pctx = stdx::panic_context::enter(panic_context); - f(world, params) - }); - match thread_result_to_response::(req.id.clone(), result) { - Ok(response) => Task::Response(response), - Err(_) => Task::Retry(req), - } + let world = self.global_state.snapshot(); + if MAIN_POOL { + &mut self.global_state.task_pool.handle + } else { + &mut self.global_state.fmt_pool.handle + } + .spawn(intent, move || { + let result = panic::catch_unwind(move || { + let _pctx = stdx::panic_context::enter(panic_context); + f(world, params) + }); + match thread_result_to_response::(req.id.clone(), result) { + Ok(response) => Task::Response(response), + Err(_) => Task::Retry(req), } }); diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 9f4dc4440202d..9f2fda025356e 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -54,6 +54,7 @@ pub(crate) struct GlobalState { req_queue: ReqQueue, pub(crate) task_pool: Handle, Receiver>, + pub(crate) fmt_pool: Handle, Receiver>, pub(crate) config: Arc, pub(crate) config_errors: Option, @@ -151,6 +152,11 @@ impl GlobalState { let handle = TaskPool::new_with_threads(sender, config.main_loop_num_threads()); Handle { handle, receiver } }; + let fmt_pool = { + let (sender, receiver) = unbounded(); + let handle = TaskPool::new_with_threads(sender, 1); + Handle { handle, receiver } + }; let mut analysis_host = AnalysisHost::new(config.lru_parse_query_capacity()); if let Some(capacities) = config.lru_query_capacities() { @@ -161,6 +167,7 @@ impl GlobalState { sender, req_queue: ReqQueue::default(), task_pool, + fmt_pool, loader, config: Arc::new(config.clone()), analysis_host, diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index 52a85054ea31a..fc1076b65b0f4 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -18,12 +18,11 @@ use lsp_server::ErrorCode; use lsp_types::{ CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, - CodeLens, CompletionItem, DocumentFormattingParams, FoldingRange, FoldingRangeParams, - HoverContents, InlayHint, InlayHintParams, Location, LocationLink, Position, - PrepareRenameResponse, Range, RenameParams, SemanticTokensDeltaParams, - SemanticTokensFullDeltaResult, SemanticTokensParams, SemanticTokensRangeParams, - SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, SymbolTag, - TextDocumentIdentifier, Url, WorkspaceEdit, + CodeLens, CompletionItem, FoldingRange, FoldingRangeParams, HoverContents, InlayHint, + InlayHintParams, Location, LocationLink, Position, PrepareRenameResponse, Range, RenameParams, + SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams, + SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, + SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit, }; use project_model::{ManifestPath, ProjectWorkspace, TargetKind}; use serde_json::json; @@ -1077,7 +1076,7 @@ pub(crate) fn handle_references( pub(crate) fn handle_formatting( snap: GlobalStateSnapshot, - params: DocumentFormattingParams, + params: lsp_types::DocumentFormattingParams, ) -> Result>> { let _p = profile::span("handle_formatting"); diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 12bc638929d66..dafdc2b8ac246 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -175,6 +175,9 @@ impl GlobalState { msg.ok().map(Event::Lsp), recv(self.task_pool.receiver) -> task => + Some(Event::Task(task.unwrap())), + + recv(self.fmt_pool.receiver) -> task => Some(Event::Task(task.unwrap())), recv(self.loader.receiver) -> task => @@ -678,6 +681,12 @@ impl GlobalState { .on_sync::(handlers::handle_selection_range) .on_sync::(handlers::handle_matching_brace) .on_sync::(handlers::handle_on_type_formatting) + // Formatting should be done immediately as the editor might wait on it, but we can't + // put it on the main thread as we do not want the main thread to block on rustfmt. + // So we have an extra thread just for formatting requests to make sure it gets handled + // as fast as possible. + .on_fmt_thread::(handlers::handle_formatting) + .on_fmt_thread::(handlers::handle_range_formatting) // We can’t run latency-sensitive request handlers which do semantic // analysis on the main thread because that would block other // requests. Instead, we run these request handlers on higher priority @@ -695,14 +704,6 @@ impl GlobalState { .on_latency_sensitive::( handlers::handle_semantic_tokens_range, ) - // Formatting is not caused by the user typing, - // but it does qualify as latency-sensitive - // because a delay before formatting is applied - // can be confusing for the user. - .on_latency_sensitive::(handlers::handle_formatting) - .on_latency_sensitive::( - handlers::handle_range_formatting, - ) // All other request handlers .on::(handlers::fetch_dependency_list) .on::(handlers::handle_analyzer_status) From 179b8d7efc171aaf9daa75217acc9d88c472e9cc Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 11 Jun 2023 20:11:26 +0200 Subject: [PATCH 203/465] Formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Laurențiu Nicola --- crates/rust-analyzer/src/main_loop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index dafdc2b8ac246..eb5d7f495f790 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -175,7 +175,7 @@ impl GlobalState { msg.ok().map(Event::Lsp), recv(self.task_pool.receiver) -> task => - Some(Event::Task(task.unwrap())), + Some(Event::Task(task.unwrap())), recv(self.fmt_pool.receiver) -> task => Some(Event::Task(task.unwrap())), From 90527b81c9c767adfef2c895fb8b776eb3ac3212 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 11 Jun 2023 16:04:00 -0400 Subject: [PATCH 204/465] Some fixes and cleanups --- rust-toolchain | 2 +- src/lib.rs | 2 +- test.sh | 17 ++++------------- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/rust-toolchain b/rust-toolchain index 90f9a621077a6..2614fa081a863 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-06-11" +channel = "nightly-2023-06-10" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/src/lib.rs b/src/lib.rs index 3bf92c063022c..7a89a449b6923 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,7 +79,7 @@ use rustc_codegen_ssa::target_features::supported_target_features; use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, Handler, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::query::Providers; diff --git a/test.sh b/test.sh index 5c5c26699b094..7c68e00771d6e 100755 --- a/test.sh +++ b/test.sh @@ -213,7 +213,8 @@ function setup_rustc() { rm config.toml || true - # TODO: copy in build_sysroot/build_sysroot.sh instead to avoid having to rebuild stage0 libraries everytime? + # TODO: move these lines to build_sysroot/build_sysroot.sh instead to avoid having to rebuild stage0 libraries everytime? + # Since we can't override the sysroot anymore, we create a new toolchain and manually overwrite the sysroot directory. my_toolchain_dir=$HOME/.rustup/toolchains/my_toolchain rm -rf $my_toolchain_dir cp -r $HOME/.rustup/toolchains/$rust_toolchain-$TARGET_TRIPLE $my_toolchain_dir @@ -362,16 +363,7 @@ function test_rustc() { git checkout tests/ui/type-alias-impl-trait/auxiliary/cross_crate_ice2.rs git checkout tests/ui/macros/rfc-2011-nicer-assert-messages/auxiliary/common.rs - # We need to overwrite the sysroot in the tests, now. - # TODO(antoyo): find a faster way to do this. - # FIXME: this makes the stderr different since it changes the line numbers. - #for file in $(find tests/ui -type f -name '*.rs'); do - #sed -ie "1i // compile-flags: --sysroot "$(pwd)"/../build_sysroot/sysroot\n" $file - #done - - # TODO: copy the sysroot at the correct location to not have to use the --sysroot flag. - #RUSTC_ARGS="$TEST_FLAGS -Csymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext"" - RUSTC_ARGS="$TEST_FLAGS -Csymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot $HOME/.rustup/toolchains/$rust_toolchain-$TARGET_TRIPLE/bin/rustc" + RUSTC_ARGS="$TEST_FLAGS -Csymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext"" if [ $# -eq 0 ]; then @@ -404,8 +396,7 @@ function test_rustc() { fi echo "[TEST] rustc test suite" - #COMPILETEST_FORCE_STAGE0=1 strace -f ./x.py test --run always --stage 0 tests/ui/ --rustc-args "$RUSTC_ARGS" &> ../trace - COMPILETEST_FORCE_STAGE0=1 ./x.py test --run always --stage 0 tests/ui/zero-sized/zero-sized-linkedlist-push.rs --rustc-args "$RUSTC_ARGS" + COMPILETEST_FORCE_STAGE0=1 ./x.py test --run always --stage 0 tests/ui --rustc-args "$RUSTC_ARGS" } function test_failing_rustc() { From a4695788caa4370136d3df38f9f20d0bb12060fa Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Mon, 12 Jun 2023 00:37:11 +0330 Subject: [PATCH 205/465] Add a bunch of fixme comments --- crates/hir-def/src/db.rs | 6 +++--- crates/hir-def/src/hir.rs | 4 ++-- crates/hir-def/src/lib.rs | 39 ++++++++++++++++++++++++++++------ crates/hir-ty/src/consteval.rs | 2 +- crates/hir-ty/src/infer.rs | 1 + 5 files changed, 39 insertions(+), 13 deletions(-) diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index b1a2d2028a87c..e6a6eb03497fe 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -22,8 +22,8 @@ use crate::{ lang_item::{LangItem, LangItemTarget, LangItems}, nameres::{diagnostics::DefDiagnostic, DefMap}, visibility::{self, Visibility}, - AnonymousConstId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, - EnumLoc, ExternBlockId, ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, + AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, + ExternBlockId, ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, InTypeConstId, LocalEnumVariantId, LocalFieldId, Macro2Id, Macro2Loc, MacroRulesId, MacroRulesLoc, OpaqueInternableThing, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, @@ -63,7 +63,7 @@ pub trait InternDatabase: SourceDatabase { #[salsa::interned] fn intern_macro_rules(&self, loc: MacroRulesLoc) -> MacroRulesId; #[salsa::interned] - fn intern_anonymous_const(&self, id: (DefWithBodyId, ExprId)) -> AnonymousConstId; + fn intern_anonymous_const(&self, id: (DefWithBodyId, ExprId)) -> ConstBlockId; #[salsa::interned] fn intern_in_type_const( &self, diff --git a/crates/hir-def/src/hir.rs b/crates/hir-def/src/hir.rs index 4ad8a7aa8eb12..77d879a77ba50 100644 --- a/crates/hir-def/src/hir.rs +++ b/crates/hir-def/src/hir.rs @@ -26,7 +26,7 @@ use crate::{ builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, path::{GenericArgs, Path}, type_ref::{Mutability, Rawness, TypeRef}, - AnonymousConstId, BlockId, + BlockId, ConstBlockId, }; pub use syntax::ast::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp}; @@ -181,7 +181,7 @@ pub enum Expr { statements: Box<[Statement]>, tail: Option, }, - Const(AnonymousConstId), + Const(ConstBlockId), Unsafe { id: Option, statements: Box<[Statement]>, diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 69e4afe94f577..4f68093bcbe2c 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -482,8 +482,8 @@ impl_from!( /// Id of the anonymous const block expression and patterns. This is very similar to `ClosureId` and /// shouldn't be a `DefWithBodyId` since its type inference is dependent on its parent. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -pub struct AnonymousConstId(InternId); -impl_intern_key!(AnonymousConstId); +pub struct ConstBlockId(InternId); +impl_intern_key!(ConstBlockId); #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub enum TypeOwnerId { @@ -563,7 +563,10 @@ impl From for TypeOwnerId { } } -/// A thing that we want to store in interned ids, but we don't know its type in `hir-def` +/// A thing that we want to store in interned ids, but we don't know its type in `hir-def`. This is +/// currently only used in `InTypeConstId` for storing the type (which has type `Ty` defined in +/// the `hir-ty` crate) of the constant in its id, which is a temporary hack so we may want +/// to remove this after removing that. pub trait OpaqueInternableThing: std::any::Any + std::fmt::Debug + Sync + Send + UnwindSafe + RefUnwindSafe { @@ -594,6 +597,28 @@ impl Clone for Box { } } +// FIXME(const-generic-body): Use an stable id for in type consts. +// +// The current id uses `AstId` which will be changed by every change in the code. Ideally +// we should use an id which is relative to the type owner, so that every change will only invalidate the +// id if it happens inside of the type owner. +// +// The solution probably is to have some query on `TypeOwnerId` to traverse its constant children and store +// their `AstId` in a list (vector or arena), and use the index of that list in the id here. That query probably +// needs name resolution, and might go far and handles the whole path lowering or type lowering for a `TypeOwnerId`. +// +// Whatever path the solution takes, it should answer 3 questions at the same time: +// * Is the id stable enough? +// * How to find a constant id using an ast node / position in the source code? This is needed when we want to +// provide ide functionalities inside an in type const (which we currently don't support) e.g. go to definition +// for a local defined there. A complex id might have some trouble in this reverse mapping. +// * How to find the return type of a constant using its id? We have this data when we are doing type lowering +// and the name of the struct that contains this constant is resolved, so a query that only traverses the +// type owner by its syntax tree might have a hard time here. + +/// A constant in a type as a substitution for const generics (like `Foo<{ 2 + 2 }>`) or as an array +/// length (like `[u8; 2 + 2]`). These constants are body owner and are a variant of `DefWithBodyId`. These +/// are not called `AnonymousConstId` to prevent confusion with [`ConstBlockId`]. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub struct InTypeConstId(InternId); type InTypeConstLoc = (AstId, TypeOwnerId, Box); @@ -613,17 +638,17 @@ impl InTypeConstId { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum GeneralConstId { ConstId(ConstId), - AnonymousConstId(AnonymousConstId), + ConstBlockId(ConstBlockId), InTypeConstId(InTypeConstId), } -impl_from!(ConstId, AnonymousConstId, InTypeConstId for GeneralConstId); +impl_from!(ConstId, ConstBlockId, InTypeConstId for GeneralConstId); impl GeneralConstId { pub fn generic_def(self, db: &dyn db::DefDatabase) -> Option { match self { GeneralConstId::ConstId(x) => Some(x.into()), - GeneralConstId::AnonymousConstId(x) => { + GeneralConstId::ConstBlockId(x) => { let (parent, _) = db.lookup_intern_anonymous_const(x); parent.as_generic_def_id() } @@ -643,7 +668,7 @@ impl GeneralConstId { .and_then(|x| x.as_str()) .unwrap_or("_") .to_owned(), - GeneralConstId::AnonymousConstId(id) => format!("{{anonymous const {id:?}}}"), + GeneralConstId::ConstBlockId(id) => format!("{{anonymous const {id:?}}}"), GeneralConstId::InTypeConstId(id) => format!("{{in type const {id:?}}}"), } } diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 0b762d96ae751..7a7c12e5b4424 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -215,7 +215,7 @@ pub(crate) fn const_eval_query( GeneralConstId::ConstId(c) => { db.monomorphized_mir_body(c.into(), subst, db.trait_environment(c.into()))? } - GeneralConstId::AnonymousConstId(c) => { + GeneralConstId::ConstBlockId(c) => { let (def, root) = db.lookup_intern_anonymous_const(c); let body = db.body(def); let infer = db.infer(def); diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 6399fa052bc42..2506ae5bb6f34 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -108,6 +108,7 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc { + // FIXME(const-generic-body): We should not get the return type in this way. ctx.return_ty = c.lookup(db.upcast()).2.box_any().downcast::().unwrap().0; } From 3371fce044f1f4aafe258d21f3e03774d30a1cab Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 11 Jun 2023 18:21:00 -0400 Subject: [PATCH 206/465] Fix tests --- failing-ui-tests.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/failing-ui-tests.txt b/failing-ui-tests.txt index 8539e27ea6a58..1b0e30c920a55 100644 --- a/failing-ui-tests.txt +++ b/failing-ui-tests.txt @@ -54,8 +54,8 @@ tests/ui/issues/issue-40883.rs tests/ui/issues/issue-43853.rs tests/ui/issues/issue-47364.rs tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs -tests/ui/rfc-2091-track-caller/std-panic-locations.rs -tests/ui/rfcs/rfc1857-drop-order.rs +tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs +tests/ui/rfcs/rfc-1857-stabilize-drop-order/drop-order.rs tests/ui/simd/issue-17170.rs tests/ui/simd/issue-39720.rs tests/ui/simd/issue-89193.rs From ef037e6d30b21363c48c47045b325a780fdde6d3 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 11 Jun 2023 19:27:39 -0400 Subject: [PATCH 207/465] Fix tests --- build_sysroot/Cargo.toml | 1 + failing-ui-tests.txt | 2 ++ src/declare.rs | 2 +- test.sh | 2 ++ 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/build_sysroot/Cargo.toml b/build_sysroot/Cargo.toml index cfadf47cc3f86..a84f86a821898 100644 --- a/build_sysroot/Cargo.toml +++ b/build_sysroot/Cargo.toml @@ -9,6 +9,7 @@ compiler_builtins = "0.1" alloc = { path = "./sysroot_src/library/alloc" } std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] } test = { path = "./sysroot_src/library/test" } +proc_macro = { path = "./sysroot_src/library/proc_macro" } [patch.crates-io] rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" } diff --git a/failing-ui-tests.txt b/failing-ui-tests.txt index 1b0e30c920a55..801464daae9a5 100644 --- a/failing-ui-tests.txt +++ b/failing-ui-tests.txt @@ -66,3 +66,5 @@ tests/ui/generator/panic-safe.rs tests/ui/issues/issue-14875.rs tests/ui/issues/issue-29948.rs tests/ui/panic-while-printing.rs +tests/ui/enum-discriminant/get_discr.rs +tests/ui/panics/nested_panic_caught.rs diff --git a/src/declare.rs b/src/declare.rs index 4748e7e4be2a3..493626c3cf5de 100644 --- a/src/declare.rs +++ b/src/declare.rs @@ -132,7 +132,7 @@ fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*ll pub fn mangle_name(name: &str) -> String { name.replace(|char: char| { if !char.is_alphanumeric() && char != '_' { - debug_assert!("$.".contains(char), "Unsupported char in function name: {}", char); + debug_assert!("$.*".contains(char), "Unsupported char in function name {}: {}", name, char); true } else { diff --git a/test.sh b/test.sh index 7c68e00771d6e..72753e1d46662 100755 --- a/test.sh +++ b/test.sh @@ -350,6 +350,8 @@ function test_rustc() { for test in $(rg -i --files-with-matches "//(\[\w+\])?~|// error-pattern:|// build-fail|// run-fail|-Cllvm-args" tests/ui); do rm $test done + rm tests/ui/consts/const_cmp_type_id.rs + rm tests/ui/consts/issue-73976-monomorphic.rs git checkout -- tests/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed From 8bba64673c4fa7b19524efa563ae6233e0bda217 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 11 Jun 2023 20:01:24 -0400 Subject: [PATCH 208/465] Cleanup --- build_sysroot/build_sysroot.sh | 8 ++++++++ src/lib.rs | 2 -- test.sh | 8 -------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/build_sysroot/build_sysroot.sh b/build_sysroot/build_sysroot.sh index 9d692d599f6be..dc80e4fff806d 100755 --- a/build_sysroot/build_sysroot.sh +++ b/build_sysroot/build_sysroot.sh @@ -28,3 +28,11 @@ fi # Copy files to sysroot mkdir -p sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ cp -r target/$TARGET_TRIPLE/$sysroot_channel/deps/* sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ + +# Since we can't override the sysroot for the UI tests anymore, we create a new toolchain and manually overwrite the sysroot directory. +my_toolchain_dir=$HOME/.rustup/toolchains/my_toolchain +rm -rf $my_toolchain_dir +rust_toolchain=$(cat ../rust-toolchain | grep channel | sed 's/channel = "\(.*\)"/\1/') +cp -r $HOME/.rustup/toolchains/$rust_toolchain-$TARGET_TRIPLE $my_toolchain_dir +rm -rf $my_toolchain_dir/lib/rustlib/$TARGET_TRIPLE/ +cp -r ../build_sysroot/sysroot/* $my_toolchain_dir diff --git a/src/lib.rs b/src/lib.rs index 7a89a449b6923..2a6b642782dfd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,3 @@ -// FIXME: simple programs now segfault with a sysroot compile in release mode. - /* * TODO(antoyo): implement equality in libgccjit based on https://zpz.github.io/blog/overloading-equality-operator-in-cpp-class-hierarchy/ (for type equality?) * TODO(antoyo): support #[inline] attributes. diff --git a/test.sh b/test.sh index 72753e1d46662..a6e87fca16233 100755 --- a/test.sh +++ b/test.sh @@ -213,13 +213,7 @@ function setup_rustc() { rm config.toml || true - # TODO: move these lines to build_sysroot/build_sysroot.sh instead to avoid having to rebuild stage0 libraries everytime? - # Since we can't override the sysroot anymore, we create a new toolchain and manually overwrite the sysroot directory. my_toolchain_dir=$HOME/.rustup/toolchains/my_toolchain - rm -rf $my_toolchain_dir - cp -r $HOME/.rustup/toolchains/$rust_toolchain-$TARGET_TRIPLE $my_toolchain_dir - rm -rf $my_toolchain_dir/lib/rustlib/x86_64-unknown-linux-gnu/ - cp -r ../build_sysroot/sysroot/* $my_toolchain_dir cat > config.toml < Date: Sun, 4 Jun 2023 09:09:28 -0700 Subject: [PATCH 209/465] Remove rustc-workspace-hack --- Cargo.lock | 7 ------- Cargo.toml | 5 ----- 2 files changed, 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 24166d51c51fa..5b0fd5ae7352c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -468,12 +468,6 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" -[[package]] -name = "rustc-workspace-hack" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" - [[package]] name = "rustfmt-config_proc_macro" version = "0.3.0" @@ -502,7 +496,6 @@ dependencies = [ "lazy_static", "log", "regex", - "rustc-workspace-hack", "rustfmt-config_proc_macro", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 87ce59d0217e8..12ed65453e19e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,11 +59,6 @@ unicode_categories = "0.1" rustfmt-config_proc_macro = { version = "0.3", path = "config_proc_macro" } -# A noop dependency that changes in the Rust repository, it's a bit of a hack. -# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` -# for more information. -rustc-workspace-hack = "1.0.0" - # Rustc dependencies are loaded from the sysroot, Cargo doesn't know about them. [package.metadata.rust-analyzer] From 5f9de6bfc9f1a3308d97bf6598acd56229cbe293 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sat, 10 Jun 2023 17:27:24 +0000 Subject: [PATCH 210/465] Recover comments between attrs and generic param Fixes #5320. --- src/overflow.rs | 4 ++ src/types.rs | 76 +++++++++++++++++------------ tests/target/doc-of-generic-item.rs | 18 +++++++ 3 files changed, 67 insertions(+), 31 deletions(-) diff --git a/src/overflow.rs b/src/overflow.rs index af0b95430a197..d81bf24dbd1cd 100644 --- a/src/overflow.rs +++ b/src/overflow.rs @@ -589,6 +589,8 @@ impl<'a> Context<'a> { fn rewrite_items(&self) -> Option<(bool, String)> { let span = self.items_span(); + debug!("items: {:?}", self.items); + let items = itemize_list( self.context.snippet_provider, self.items.iter(), @@ -603,6 +605,8 @@ impl<'a> Context<'a> { ); let mut list_items: Vec<_> = items.collect(); + debug!("items: {list_items:?}"); + // Try letting the last argument overflow to the next line with block // indentation. If its first line fits on one line with the other arguments, // we format the function arguments horizontally. diff --git a/src/types.rs b/src/types.rs index 01e2fb6e61e15..b4be6546efbdb 100644 --- a/src/types.rs +++ b/src/types.rs @@ -572,49 +572,41 @@ impl Rewrite for ast::GenericBounds { impl Rewrite for ast::GenericParam { fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - let mut result = String::with_capacity(128); // FIXME: If there are more than one attributes, this will force multiline. - match self.attrs.rewrite(context, shape) { - Some(ref rw) if !rw.is_empty() => { - result.push_str(rw); - // When rewriting generic params, an extra newline should be put - // if the attributes end with a doc comment - if let Some(true) = self.attrs.last().map(|a| a.is_doc_comment()) { - result.push_str(&shape.indent.to_string_with_newline(context.config)); - } else { - result.push(' '); - } - } - _ => (), - } + let mut result = self.attrs.rewrite(context, shape).unwrap_or(String::new()); + let has_attrs = !result.is_empty(); - if let ast::GenericParamKind::Const { + let mut param = String::with_capacity(128); + + let param_start = if let ast::GenericParamKind::Const { ref ty, - kw_span: _, + kw_span, default, } = &self.kind { - result.push_str("const "); - result.push_str(rewrite_ident(context, self.ident)); - result.push_str(": "); - result.push_str(&ty.rewrite(context, shape)?); + param.push_str("const "); + param.push_str(rewrite_ident(context, self.ident)); + param.push_str(": "); + param.push_str(&ty.rewrite(context, shape)?); if let Some(default) = default { let eq_str = match context.config.type_punctuation_density() { TypeDensity::Compressed => "=", TypeDensity::Wide => " = ", }; - result.push_str(eq_str); - let budget = shape.width.checked_sub(result.len())?; + param.push_str(eq_str); + let budget = shape.width.checked_sub(param.len())?; let rewrite = default.rewrite(context, Shape::legacy(budget, shape.indent))?; - result.push_str(&rewrite); + param.push_str(&rewrite); } + kw_span.lo() } else { - result.push_str(rewrite_ident(context, self.ident)); - } + param.push_str(rewrite_ident(context, self.ident)); + self.ident.span.lo() + }; if !self.bounds.is_empty() { - result.push_str(type_bound_colon(context)); - result.push_str(&self.bounds.rewrite(context, shape)?) + param.push_str(type_bound_colon(context)); + param.push_str(&self.bounds.rewrite(context, shape)?) } if let ast::GenericParamKind::Type { default: Some(ref def), @@ -624,11 +616,33 @@ impl Rewrite for ast::GenericParam { TypeDensity::Compressed => "=", TypeDensity::Wide => " = ", }; - result.push_str(eq_str); - let budget = shape.width.checked_sub(result.len())?; + param.push_str(eq_str); + let budget = shape.width.checked_sub(param.len())?; let rewrite = - def.rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?; - result.push_str(&rewrite); + def.rewrite(context, Shape::legacy(budget, shape.indent + param.len()))?; + param.push_str(&rewrite); + } + + if let Some(last_attr) = self.attrs.last().filter(|last_attr| { + contains_comment(context.snippet(mk_sp(last_attr.span.hi(), param_start))) + }) { + result = combine_strs_with_missing_comments( + context, + &result, + ¶m, + mk_sp(last_attr.span.hi(), param_start), + shape, + !last_attr.is_doc_comment(), + )?; + } else { + // When rewriting generic params, an extra newline should be put + // if the attributes end with a doc comment + if let Some(true) = self.attrs.last().map(|a| a.is_doc_comment()) { + result.push_str(&shape.indent.to_string_with_newline(context.config)); + } else if has_attrs { + result.push(' '); + } + result.push_str(¶m); } Some(result) diff --git a/tests/target/doc-of-generic-item.rs b/tests/target/doc-of-generic-item.rs index 2efc5e09a3d34..80886e74f83e3 100644 --- a/tests/target/doc-of-generic-item.rs +++ b/tests/target/doc-of-generic-item.rs @@ -12,3 +12,21 @@ struct Foo< /// doc of N const N: item, >; + +// Non-doc pre-comment of Foo +/// doc of Foo +// Non-doc post-comment of Foo +struct Foo< + // Non-doc pre-comment of 'a + /// doc of 'a + // Non-doc post-comment of 'a + 'a, + // Non-doc pre-comment of T + /// doc of T + // Non-doc post-comment of T + T, + // Non-doc pre-comment of N + /// doc of N + // Non-doc post-comment of N + const N: item, +>; From 696cd98e6b51d657247cd61ee1babcf0ee4b9a8a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 12 Jun 2023 00:35:23 +0000 Subject: [PATCH 211/465] Don't record adjustments twice in note_source_of_type_mismatch_constraint --- compiler/rustc_hir_typeck/src/demand.rs | 7 ++--- .../rustc_hir_typeck/src/method/confirm.rs | 26 +++++++++++++++-- compiler/rustc_hir_typeck/src/method/mod.rs | 21 ++++++++++++++ ...record-adjustments-when-pointing-at-arg.rs | 29 +++++++++++++++++++ ...rd-adjustments-when-pointing-at-arg.stderr | 17 +++++++++++ 5 files changed, 93 insertions(+), 7 deletions(-) create mode 100644 tests/ui/typeck/dont-record-adjustments-when-pointing-at-arg.rs create mode 100644 tests/ui/typeck/dont-record-adjustments-when-pointing-at-arg.stderr diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index b62f689ec6b89..9ce03060e0fe9 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -370,13 +370,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Fudge the receiver, so we can do new inference on it. let possible_rcvr_ty = possible_rcvr_ty.fold_with(&mut fudger); let method = self - .lookup_method( + .lookup_method_for_diagnostic( possible_rcvr_ty, segment, DUMMY_SP, call_expr, binding, - args, ) .ok()?; // Unify the method signature with our incompatible arg, to @@ -435,14 +434,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else { continue; }; let rcvr_ty = rcvr_ty.fold_with(&mut fudger); let Ok(method) = - self.lookup_method(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr, args) + self.lookup_method_for_diagnostic(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr) else { continue; }; let ideal_rcvr_ty = rcvr_ty.fold_with(&mut fudger); let ideal_method = self - .lookup_method(ideal_rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr, args) + .lookup_method_for_diagnostic(ideal_rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr) .ok() .and_then(|method| { let _ = self.at(&ObligationCause::dummy(), self.param_env) diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 98529b66602fa..6cd7bd5d196df 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -26,6 +26,7 @@ struct ConfirmContext<'a, 'tcx> { span: Span, self_expr: &'tcx hir::Expr<'tcx>, call_expr: &'tcx hir::Expr<'tcx>, + skip_record_for_diagnostics: bool, } impl<'a, 'tcx> Deref for ConfirmContext<'a, 'tcx> { @@ -59,6 +60,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr); confirm_cx.confirm(unadjusted_self_ty, pick, segment) } + + pub fn confirm_method_for_diagnostic( + &self, + span: Span, + self_expr: &'tcx hir::Expr<'tcx>, + call_expr: &'tcx hir::Expr<'tcx>, + unadjusted_self_ty: Ty<'tcx>, + pick: &probe::Pick<'tcx>, + segment: &hir::PathSegment<'_>, + ) -> ConfirmResult<'tcx> { + let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr); + confirm_cx.skip_record_for_diagnostics = true; + confirm_cx.confirm(unadjusted_self_ty, pick, segment) + } } impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { @@ -68,7 +83,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self_expr: &'tcx hir::Expr<'tcx>, call_expr: &'tcx hir::Expr<'tcx>, ) -> ConfirmContext<'a, 'tcx> { - ConfirmContext { fcx, span, self_expr, call_expr } + ConfirmContext { fcx, span, self_expr, call_expr, skip_record_for_diagnostics: false } } fn confirm( @@ -219,7 +234,9 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.register_predicates(autoderef.into_obligations()); // Write out the final adjustments. - self.apply_adjustments(self.self_expr, adjustments); + if !self.skip_record_for_diagnostics { + self.apply_adjustments(self.self_expr, adjustments); + } target } @@ -453,7 +470,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { }); debug!("instantiate_method_substs: user_type_annotation={:?}", user_type_annotation); - self.fcx.write_user_type_annotation(self.call_expr.hir_id, user_type_annotation); + + if !self.skip_record_for_diagnostics { + self.fcx.write_user_type_annotation(self.call_expr.hir_id, user_type_annotation); + } } self.normalize(self.span, substs) diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 6f4d674ba103b..dabade3658974 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -254,6 +254,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(result.callee) } + pub fn lookup_method_for_diagnostic( + &self, + self_ty: Ty<'tcx>, + segment: &hir::PathSegment<'_>, + span: Span, + call_expr: &'tcx hir::Expr<'tcx>, + self_expr: &'tcx hir::Expr<'tcx>, + ) -> Result, MethodError<'tcx>> { + let pick = self.lookup_probe_for_diagnostic( + segment.ident, + self_ty, + call_expr, + ProbeScope::TraitsInScope, + None, + )?; + + Ok(self + .confirm_method_for_diagnostic(span, self_expr, call_expr, self_ty, &pick, segment) + .callee) + } + #[instrument(level = "debug", skip(self, call_expr))] pub fn lookup_probe( &self, diff --git a/tests/ui/typeck/dont-record-adjustments-when-pointing-at-arg.rs b/tests/ui/typeck/dont-record-adjustments-when-pointing-at-arg.rs new file mode 100644 index 0000000000000..0c2d71707c9f0 --- /dev/null +++ b/tests/ui/typeck/dont-record-adjustments-when-pointing-at-arg.rs @@ -0,0 +1,29 @@ +pub trait NSWindow: Sized { + fn frame(self) -> () { + unimplemented!() + } + fn setFrame_display_(self, display: ()) {} +} +impl NSWindow for () {} + +pub struct NSRect {} + +use std::ops::Deref; +struct MainThreadSafe(T); +impl Deref for MainThreadSafe { + type Target = T; + + fn deref(&self) -> &T { + unimplemented!() + } +} + +fn main() { + || { + let ns_window = MainThreadSafe(()); + // Don't record adjustments twice for `*ns_window` + (*ns_window).frame(); + ns_window.setFrame_display_(0); + //~^ ERROR mismatched types + }; +} diff --git a/tests/ui/typeck/dont-record-adjustments-when-pointing-at-arg.stderr b/tests/ui/typeck/dont-record-adjustments-when-pointing-at-arg.stderr new file mode 100644 index 0000000000000..02e87d701b687 --- /dev/null +++ b/tests/ui/typeck/dont-record-adjustments-when-pointing-at-arg.stderr @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/dont-record-adjustments-when-pointing-at-arg.rs:26:37 + | +LL | ns_window.setFrame_display_(0); + | ----------------- ^ expected `()`, found integer + | | + | arguments to this method are incorrect + | +note: method defined here + --> $DIR/dont-record-adjustments-when-pointing-at-arg.rs:5:8 + | +LL | fn setFrame_display_(self, display: ()) {} + | ^^^^^^^^^^^^^^^^^ ----------- + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From 0cac8455e6f7587228458ef5607e8d3e6f71f347 Mon Sep 17 00:00:00 2001 From: Andrew Xie Date: Sun, 11 Jun 2023 22:45:04 -0400 Subject: [PATCH 212/465] Applied nits --- compiler/rustc_data_structures/src/unord.rs | 8 ++++---- compiler/rustc_incremental/src/persist/dirty_clean.rs | 10 ++++------ compiler/rustc_incremental/src/persist/fs.rs | 11 +++++------ 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index e18c7b415f6cf..2b21815b687d5 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -107,6 +107,10 @@ impl> UnordItems { { UnordItems(self.0.flat_map(f)) } + + pub fn collect>>(self) -> C { + self.into() + } } impl UnordItems> { @@ -161,10 +165,6 @@ impl> UnordItems { items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx)); items } - - pub fn collect>>(self) -> C { - self.into() - } } /// This is a set collection type that tries very hard to not expose diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index cbe77e7b16de8..f9cd01fd80dbb 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -198,7 +198,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { let (name, mut auto) = self.auto_labels(item_id, attr); let except = self.except(attr); let loaded_from_disk = self.loaded_from_disk(attr); - for e in except.items().map(|x| x.as_str()).into_sorted_stable_ord() { + for e in except.items().into_sorted_stable_ord() { if !auto.remove(e) { self.tcx.sess.emit_fatal(errors::AssertionAuto { span: attr.span, name, e }); } @@ -377,17 +377,15 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { continue; }; self.checked_attrs.insert(attr.id); - for label in assertion.clean.items().map(|x| x.as_str()).into_sorted_stable_ord() { + for label in assertion.clean.items().into_sorted_stable_ord() { let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap(); self.assert_clean(item_span, dep_node); } - for label in assertion.dirty.items().map(|x| x.as_str()).into_sorted_stable_ord() { + for label in assertion.dirty.items().into_sorted_stable_ord() { let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap(); self.assert_dirty(item_span, dep_node); } - for label in - assertion.loaded_from_disk.items().map(|x| x.as_str()).into_sorted_stable_ord() - { + for label in assertion.loaded_from_disk.items().into_sorted_stable_ord() { let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap(); self.assert_loaded_from_disk(item_span, dep_node); } diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 243057b99bca2..7708deecec713 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -855,12 +855,11 @@ fn all_except_most_recent( let most_recent = deletion_candidates.items().map(|(&(timestamp, _), _)| timestamp).max(); if let Some(most_recent) = most_recent { - UnordMap::from( - deletion_candidates - .into_items() - .filter(|&((timestamp, _), _)| timestamp != most_recent) - .map(|((_, path), lock)| (path, lock)), - ) + deletion_candidates + .into_items() + .filter(|&((timestamp, _), _)| timestamp != most_recent) + .map(|((_, path), lock)| (path, lock)) + .collect() } else { UnordMap::default() } From 942b39215080abc75f94be1e924c5dcac441fa73 Mon Sep 17 00:00:00 2001 From: Andreas Backx Date: Sun, 11 Jun 2023 22:53:58 -0700 Subject: [PATCH 213/465] Exclude Markdown injection grammar from .vscodeignore. Enables Markdown injection introduced in #14866 but wasn't included in release due to it being ignored. --- editors/code/.vscodeignore | 1 + 1 file changed, 1 insertion(+) diff --git a/editors/code/.vscodeignore b/editors/code/.vscodeignore index 09dc27056b37a..6e118f0b3ae69 100644 --- a/editors/code/.vscodeignore +++ b/editors/code/.vscodeignore @@ -10,5 +10,6 @@ !package-lock.json !package.json !ra_syntax_tree.tmGrammar.json +!rustdoc.markdown.injection.tmGrammar.json !server !README.md From 5ce65a1d922fd7f6440f998c39d91a1763d6453f Mon Sep 17 00:00:00 2001 From: ponyii Date: Mon, 12 Jun 2023 20:16:22 +0400 Subject: [PATCH 214/465] the "implement missing members" assist's const transformation implemented --- .../src/handlers/add_missing_impl_members.rs | 31 ++++++++++ crates/ide-db/src/path_transform.rs | 56 ++++++++++++------- 2 files changed, 66 insertions(+), 21 deletions(-) diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs index ae5118e950abe..4d572c604b0ea 100644 --- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -418,6 +418,37 @@ impl<'x, 'y, T, V, U: Default> Trait<'x, 'y, T, V, U> for () { ); } + #[test] + fn test_const_substitution() { + check_assist( + add_missing_default_members, + r#" +trait Foo { + fn get_n_sq(&self, arg: &T) -> usize { N * N } +} + +struct S { + wrapped: T +} + +impl Foo for S { + $0 +}"#, + r#" +trait Foo { + fn get_n_sq(&self, arg: &T) -> usize { N * N } +} + +struct S { + wrapped: T +} + +impl Foo for S { + $0fn get_n_sq(&self, arg: &Z) -> usize { X * X } +}"#, + ) + } + #[test] fn test_cursor_after_empty_impl_def() { check_assist( diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs index 6afd61e84dc62..887c2feee16f3 100644 --- a/crates/ide-db/src/path_transform.rs +++ b/crates/ide-db/src/path_transform.rs @@ -11,7 +11,9 @@ use syntax::{ #[derive(Default)] struct AstSubsts { - types: Vec, + // ast::TypeArgs stands in fact for both type and const params + // as consts declared elsewhere look just like type params. + types_and_consts: Vec, lifetimes: Vec, } @@ -108,7 +110,7 @@ impl<'a> PathTransform<'a> { Some(hir::GenericDef::Trait(_)) => 1, _ => 0, }; - let type_substs: FxHashMap<_, _> = self + let type_and_const_substs: FxHashMap<_, _> = self .generic_def .into_iter() .flat_map(|it| it.type_params(db)) @@ -119,19 +121,17 @@ impl<'a> PathTransform<'a> { // can still hit those trailing values and check if they actually have // a default type. If they do, go for that type from `hir` to `ast` so // the resulting change can be applied correctly. - .zip(self.substs.types.iter().map(Some).chain(std::iter::repeat(None))) - .filter_map(|(k, v)| match k.split(db) { - Either::Left(_) => None, // FIXME: map const types too - Either::Right(t) => match v { - Some(v) => Some((k, v.ty()?.clone())), - None => { - let default = t.default(db)?; - let v = ast::make::ty( - &default.display_source_code(db, source_module.into(), false).ok()?, - ); - Some((k, v)) - } - }, + .zip(self.substs.types_and_consts.iter().map(Some).chain(std::iter::repeat(None))) + .filter_map(|(k, v)| match (k.split(db), v) { + (_, Some(v)) => Some((k, v.ty()?.clone())), + (Either::Right(t), None) => { + let default = t.default(db)?; + let v = ast::make::ty( + &default.display_source_code(db, source_module.into(), false).ok()?, + ); + Some((k, v)) + } + (Either::Left(_), None) => None, // FIXME: get default const value }) .collect(); let lifetime_substs: FxHashMap<_, _> = self @@ -141,12 +141,17 @@ impl<'a> PathTransform<'a> { .zip(self.substs.lifetimes.clone()) .filter_map(|(k, v)| Some((k.name(db).display(db.upcast()).to_string(), v.lifetime()?))) .collect(); - Ctx { type_substs, lifetime_substs, target_module, source_scope: self.source_scope } + Ctx { + type_and_const_substs, + lifetime_substs, + target_module, + source_scope: self.source_scope, + } } } struct Ctx<'a> { - type_substs: FxHashMap, + type_and_const_substs: FxHashMap, lifetime_substs: FxHashMap, target_module: hir::Module, source_scope: &'a SemanticsScope<'a>, @@ -203,7 +208,7 @@ impl<'a> Ctx<'a> { match resolution { hir::PathResolution::TypeParam(tp) => { - if let Some(subst) = self.type_substs.get(&tp.merge()) { + if let Some(subst) = self.type_and_const_substs.get(&tp.merge()) { let parent = path.syntax().parent()?; if let Some(parent) = ast::Path::cast(parent.clone()) { // Path inside path means that there is an associated @@ -270,8 +275,12 @@ impl<'a> Ctx<'a> { } ted::replace(path.syntax(), res.syntax()) } + hir::PathResolution::ConstParam(cp) => { + if let Some(subst) = self.type_and_const_substs.get(&cp.merge()) { + ted::replace(path.syntax(), subst.clone_subtree().clone_for_update().syntax()); + } + } hir::PathResolution::Local(_) - | hir::PathResolution::ConstParam(_) | hir::PathResolution::SelfType(_) | hir::PathResolution::Def(_) | hir::PathResolution::BuiltinAttr(_) @@ -298,9 +307,14 @@ fn get_syntactic_substs(impl_def: ast::Impl) -> Option { fn get_type_args_from_arg_list(generic_arg_list: ast::GenericArgList) -> Option { let mut result = AstSubsts::default(); generic_arg_list.generic_args().for_each(|generic_arg| match generic_arg { - ast::GenericArg::TypeArg(type_arg) => result.types.push(type_arg), + // Const params are marked as consts on definition only, + // being passed to the trait they are indistguishable from type params; + // anyway, we don't really need to distinguish them here. + ast::GenericArg::TypeArg(type_or_const_arg) => { + result.types_and_consts.push(type_or_const_arg) + } ast::GenericArg::LifetimeArg(l_arg) => result.lifetimes.push(l_arg), - _ => (), // FIXME: don't filter out const params + _ => (), }); Some(result) From abe249559d51b91888b01326dab914c10715b019 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 12 Jun 2023 18:21:17 +0200 Subject: [PATCH 215/465] internal: Give ConstBlockId and InTypeConstId named Location types --- crates/base-db/src/input.rs | 2 + crates/hir-def/src/body.rs | 17 ++++----- crates/hir-def/src/body/lower.rs | 7 +++- crates/hir-def/src/db.rs | 29 +++++++------- crates/hir-def/src/lib.rs | 54 ++++++++++++++++----------- crates/hir-def/src/resolver.rs | 4 +- crates/hir-ty/src/consteval.rs | 12 +++--- crates/hir-ty/src/infer.rs | 9 ++++- crates/hir-ty/src/infer/expr.rs | 4 +- crates/hir-ty/src/infer/mutability.rs | 4 +- crates/hir-ty/src/lower.rs | 16 ++++---- crates/hir/src/lib.rs | 2 +- 12 files changed, 90 insertions(+), 70 deletions(-) diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index 64b026f4da562..f2e523675bcf9 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -473,6 +473,8 @@ impl CrateGraph { self.arena.iter().map(|(idx, _)| idx) } + // FIXME: used for `handle_hack_cargo_workspace`, should be removed later + #[doc(hidden)] pub fn iter_mut(&mut self) -> impl Iterator + '_ { self.arena.iter_mut() } diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index 3ed7dfefc0fcd..a78bcd6c67fa6 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -118,7 +118,8 @@ impl Body { let _p = profile::span("body_with_source_map_query"); let mut params = None; - let (file_id, body, is_async_fn) = { + let mut is_async_fn = false; + let InFile { file_id, value: body } = { match def { DefWithBodyId::FunctionId(f) => { let data = db.function_data(f); @@ -138,26 +139,24 @@ impl Body { }), ) }); - (src.file_id, src.value.body().map(ast::Expr::from), data.has_async_kw()) + is_async_fn = data.has_async_kw(); + src.map(|it| it.body().map(ast::Expr::from)) } DefWithBodyId::ConstId(c) => { let c = c.lookup(db); let src = c.source(db); - (src.file_id, src.value.body(), false) + src.map(|it| it.body()) } DefWithBodyId::StaticId(s) => { let s = s.lookup(db); let src = s.source(db); - (src.file_id, src.value.body(), false) + src.map(|it| it.body()) } DefWithBodyId::VariantId(v) => { let src = v.parent.child_source(db); - let variant = &src.value[v.local_id]; - (src.file_id, variant.expr(), false) - } - DefWithBodyId::InTypeConstId(c) => { - (c.lookup(db).0.file_id, c.source(db).expr(), false) + src.map(|it| it[v.local_id].expr()) } + DefWithBodyId::InTypeConstId(c) => c.lookup(db).id.map(|_| c.source(db).expr()), } }; let module = def.module(db); diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index 7b88e525bf184..71b42f31a24a7 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -40,7 +40,7 @@ use crate::{ nameres::{DefMap, MacroSubNs}, path::{GenericArgs, Path}, type_ref::{Mutability, Rawness, TypeRef}, - AdtId, BlockId, BlockLoc, DefWithBodyId, ModuleDefId, UnresolvedMacro, + AdtId, BlockId, BlockLoc, ConstBlockLoc, DefWithBodyId, ModuleDefId, UnresolvedMacro, }; pub(super) fn lower( @@ -297,7 +297,10 @@ impl ExprCollector<'_> { let (result_expr_id, prev_binding_owner) = this.initialize_binding_owner(syntax_ptr); let inner_expr = this.collect_block(e); - let x = this.db.intern_anonymous_const((this.owner, inner_expr)); + let x = this.db.intern_anonymous_const(ConstBlockLoc { + parent: this.owner, + root: inner_expr, + }); this.body.exprs[result_expr_id] = Expr::Const(x); this.current_binding_owner = prev_binding_owner; result_expr_id diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index e6a6eb03497fe..04ec47f84caa6 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -1,7 +1,7 @@ //! Defines database & queries for name resolution. use base_db::{salsa, CrateId, SourceDatabase, Upcast}; use either::Either; -use hir_expand::{db::ExpandDatabase, AstId, HirFileId}; +use hir_expand::{db::ExpandDatabase, HirFileId}; use intern::Interned; use la_arena::ArenaMap; use syntax::{ast, AstPtr}; @@ -16,22 +16,22 @@ use crate::{ TraitAliasData, TraitData, TypeAliasData, }, generics::GenericParams, - hir::ExprId, import_map::ImportMap, item_tree::{AttrOwner, ItemTree}, lang_item::{LangItem, LangItemTarget, LangItems}, nameres::{diagnostics::DefDiagnostic, DefMap}, visibility::{self, Visibility}, - AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, - ExternBlockId, ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, - InTypeConstId, LocalEnumVariantId, LocalFieldId, Macro2Id, Macro2Loc, MacroRulesId, - MacroRulesLoc, OpaqueInternableThing, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, - StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, - TypeOwnerId, UnionId, UnionLoc, VariantId, + AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId, + EnumId, EnumLoc, ExternBlockId, ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, + ImplLoc, InTypeConstId, InTypeConstLoc, LocalEnumVariantId, LocalFieldId, Macro2Id, Macro2Loc, + MacroRulesId, MacroRulesLoc, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, + StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, + UnionLoc, VariantId, }; #[salsa::query_group(InternDatabaseStorage)] pub trait InternDatabase: SourceDatabase { + // region: items #[salsa::interned] fn intern_function(&self, loc: FunctionLoc) -> FunctionId; #[salsa::interned] @@ -55,20 +55,19 @@ pub trait InternDatabase: SourceDatabase { #[salsa::interned] fn intern_extern_block(&self, loc: ExternBlockLoc) -> ExternBlockId; #[salsa::interned] - fn intern_block(&self, loc: BlockLoc) -> BlockId; - #[salsa::interned] fn intern_macro2(&self, loc: Macro2Loc) -> Macro2Id; #[salsa::interned] fn intern_proc_macro(&self, loc: ProcMacroLoc) -> ProcMacroId; #[salsa::interned] fn intern_macro_rules(&self, loc: MacroRulesLoc) -> MacroRulesId; + // endregion: items + #[salsa::interned] - fn intern_anonymous_const(&self, id: (DefWithBodyId, ExprId)) -> ConstBlockId; + fn intern_block(&self, loc: BlockLoc) -> BlockId; #[salsa::interned] - fn intern_in_type_const( - &self, - id: (AstId, TypeOwnerId, Box), - ) -> InTypeConstId; + fn intern_anonymous_const(&self, id: ConstBlockLoc) -> ConstBlockId; + #[salsa::interned] + fn intern_in_type_const(&self, id: InTypeConstLoc) -> InTypeConstId; } #[salsa::query_group(DefDatabaseStorage)] diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 4f68093bcbe2c..4d76484394cda 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -62,11 +62,7 @@ use std::{ panic::{RefUnwindSafe, UnwindSafe}, }; -use base_db::{ - impl_intern_key, - salsa::{self, InternId}, - CrateId, ProcMacroKind, -}; +use base_db::{impl_intern_key, salsa, CrateId, ProcMacroKind}; use hir_expand::{ ast_id_map::FileAstId, attrs::{Attr, AttrId, AttrInput}, @@ -482,8 +478,16 @@ impl_from!( /// Id of the anonymous const block expression and patterns. This is very similar to `ClosureId` and /// shouldn't be a `DefWithBodyId` since its type inference is dependent on its parent. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -pub struct ConstBlockId(InternId); -impl_intern_key!(ConstBlockId); +pub struct ConstBlockId(salsa::InternId); +impl_intern!(ConstBlockId, ConstBlockLoc, intern_anonymous_const, lookup_intern_anonymous_const); + +#[derive(Debug, Hash, PartialEq, Eq, Clone)] +pub struct ConstBlockLoc { + /// The parent of the anonymous const block. + pub parent: DefWithBodyId, + /// The root expression of this const block in the parent body. + pub root: hir::ExprId, +} #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub enum TypeOwnerId { @@ -563,6 +567,7 @@ impl From for TypeOwnerId { } } +// FIXME: This should not be a thing /// A thing that we want to store in interned ids, but we don't know its type in `hir-def`. This is /// currently only used in `InTypeConstId` for storing the type (which has type `Ty` defined in /// the `hir-ty` crate) of the constant in its id, which is a temporary hack so we may want @@ -620,13 +625,26 @@ impl Clone for Box { /// length (like `[u8; 2 + 2]`). These constants are body owner and are a variant of `DefWithBodyId`. These /// are not called `AnonymousConstId` to prevent confusion with [`ConstBlockId`]. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -pub struct InTypeConstId(InternId); -type InTypeConstLoc = (AstId, TypeOwnerId, Box); +pub struct InTypeConstId(salsa::InternId); impl_intern!(InTypeConstId, InTypeConstLoc, intern_in_type_const, lookup_intern_in_type_const); +#[derive(Debug, Hash, Eq, Clone)] +pub struct InTypeConstLoc { + pub id: AstId, + /// The thing this const arg appears in + pub owner: TypeOwnerId, + pub thing: Box, +} + +impl PartialEq for InTypeConstLoc { + fn eq(&self, other: &Self) -> bool { + self.id == other.id && self.owner == other.owner && &*self.thing == &*other.thing + } +} + impl InTypeConstId { pub fn source(&self, db: &dyn db::DefDatabase) -> ast::ConstArg { - let src = self.lookup(db).0; + let src = self.lookup(db).id; let file_id = src.file_id; let root = &db.parse_or_expand(file_id); db.ast_id_map(file_id).get(src.value).to_node(root) @@ -647,15 +665,9 @@ impl_from!(ConstId, ConstBlockId, InTypeConstId for GeneralConstId); impl GeneralConstId { pub fn generic_def(self, db: &dyn db::DefDatabase) -> Option { match self { - GeneralConstId::ConstId(x) => Some(x.into()), - GeneralConstId::ConstBlockId(x) => { - let (parent, _) = db.lookup_intern_anonymous_const(x); - parent.as_generic_def_id() - } - GeneralConstId::InTypeConstId(x) => { - let (_, parent, _) = x.lookup(db); - parent.as_generic_def_id() - } + GeneralConstId::ConstId(it) => Some(it.into()), + GeneralConstId::ConstBlockId(it) => it.lookup(db).parent.as_generic_def_id(), + GeneralConstId::InTypeConstId(it) => it.lookup(db).owner.as_generic_def_id(), } } @@ -902,7 +914,7 @@ impl HasModule for TypeOwnerId { TypeOwnerId::FunctionId(x) => x.lookup(db).module(db), TypeOwnerId::StaticId(x) => x.lookup(db).module(db), TypeOwnerId::ConstId(x) => x.lookup(db).module(db), - TypeOwnerId::InTypeConstId(x) => x.lookup(db).1.module(db), + TypeOwnerId::InTypeConstId(x) => x.lookup(db).owner.module(db), TypeOwnerId::AdtId(x) => x.module(db), TypeOwnerId::TraitId(x) => x.lookup(db).container, TypeOwnerId::TraitAliasId(x) => x.lookup(db).container, @@ -921,7 +933,7 @@ impl HasModule for DefWithBodyId { DefWithBodyId::StaticId(it) => it.lookup(db).module(db), DefWithBodyId::ConstId(it) => it.lookup(db).module(db), DefWithBodyId::VariantId(it) => it.parent.lookup(db).container, - DefWithBodyId::InTypeConstId(it) => it.lookup(db).1.module(db), + DefWithBodyId::InTypeConstId(it) => it.lookup(db).owner.module(db), } } } diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 880a76f2b85d0..c497c09aff007 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -1015,7 +1015,7 @@ impl HasResolver for TypeOwnerId { TypeOwnerId::FunctionId(x) => x.resolver(db), TypeOwnerId::StaticId(x) => x.resolver(db), TypeOwnerId::ConstId(x) => x.resolver(db), - TypeOwnerId::InTypeConstId(x) => x.lookup(db).1.resolver(db), + TypeOwnerId::InTypeConstId(x) => x.lookup(db).owner.resolver(db), TypeOwnerId::AdtId(x) => x.resolver(db), TypeOwnerId::TraitId(x) => x.resolver(db), TypeOwnerId::TraitAliasId(x) => x.resolver(db), @@ -1034,7 +1034,7 @@ impl HasResolver for DefWithBodyId { DefWithBodyId::FunctionId(f) => f.resolver(db), DefWithBodyId::StaticId(s) => s.resolver(db), DefWithBodyId::VariantId(v) => v.parent.resolver(db), - DefWithBodyId::InTypeConstId(c) => c.lookup(db).1.resolver(db), + DefWithBodyId::InTypeConstId(c) => c.lookup(db).owner.resolver(db), } } } diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 7a7c12e5b4424..262341c6e9ee9 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -7,7 +7,7 @@ use hir_def::{ path::Path, resolver::{Resolver, ValueNs}, type_ref::LiteralConstRef, - EnumVariantId, GeneralConstId, StaticId, + ConstBlockLoc, EnumVariantId, GeneralConstId, StaticId, }; use la_arena::{Idx, RawIdx}; use stdx::never; @@ -216,14 +216,14 @@ pub(crate) fn const_eval_query( db.monomorphized_mir_body(c.into(), subst, db.trait_environment(c.into()))? } GeneralConstId::ConstBlockId(c) => { - let (def, root) = db.lookup_intern_anonymous_const(c); - let body = db.body(def); - let infer = db.infer(def); + let ConstBlockLoc { parent, root } = db.lookup_intern_anonymous_const(c); + let body = db.body(parent); + let infer = db.infer(parent); Arc::new(monomorphize_mir_body_bad( db, - lower_to_mir(db, def, &body, &infer, root)?, + lower_to_mir(db, parent, &body, &infer, root)?, subst, - db.trait_environment_for_body(def), + db.trait_environment_for_body(parent), )?) } GeneralConstId::InTypeConstId(c) => db.mir_body(c.into())?, diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 2506ae5bb6f34..1ac0837b5b2cc 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -109,8 +109,13 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc { // FIXME(const-generic-body): We should not get the return type in this way. - ctx.return_ty = - c.lookup(db.upcast()).2.box_any().downcast::().unwrap().0; + ctx.return_ty = c + .lookup(db.upcast()) + .thing + .box_any() + .downcast::() + .unwrap() + .0; } } diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index e1efa0b6d8cc5..194471f0048f8 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -173,8 +173,8 @@ impl<'a> InferenceContext<'a> { } Expr::Const(id) => { self.with_breakable_ctx(BreakableKind::Border, None, None, |this| { - let (_, expr) = this.db.lookup_intern_anonymous_const(*id); - this.infer_expr(expr, expected) + let loc = this.db.lookup_intern_anonymous_const(*id); + this.infer_expr(loc.root, expected) }) .1 } diff --git a/crates/hir-ty/src/infer/mutability.rs b/crates/hir-ty/src/infer/mutability.rs index 447834243908a..46f2e1d7d125a 100644 --- a/crates/hir-ty/src/infer/mutability.rs +++ b/crates/hir-ty/src/infer/mutability.rs @@ -43,8 +43,8 @@ impl<'a> InferenceContext<'a> { } } Expr::Const(id) => { - let (_, expr) = self.db.lookup_intern_anonymous_const(*id); - self.infer_mut_expr(expr, Mutability::Not); + let loc = self.db.lookup_intern_anonymous_const(*id); + self.infer_mut_expr(loc.root, Mutability::Not); } Expr::Let { pat, expr } => self.infer_mut_expr(*expr, self.pat_bound_mutability(*pat)), Expr::Block { id: _, statements, tail, label: _ } diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index c0bcf790b1f73..9951a1c750bd0 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -29,9 +29,9 @@ use hir_def::{ resolver::{HasResolver, Resolver, TypeNs}, type_ref::{ConstRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef}, AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, - GenericDefId, HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, StaticId, - StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeOwnerId, TypeParamId, UnionId, - VariantId, + GenericDefId, HasModule, ImplId, InTypeConstLoc, ItemContainerId, LocalFieldId, Lookup, + ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeOwnerId, + TypeParamId, UnionId, VariantId, }; use hir_expand::{name::Name, ExpandResult}; use intern::Interned; @@ -2047,7 +2047,7 @@ pub(crate) fn const_or_path_to_chalk( ) .unwrap_or_else(|| unknown_const(expected_ty)) } - &ConstRef::Complex(x) => { + &ConstRef::Complex(it) => { let crate_data = &db.crate_graph()[owner.module(db.upcast()).krate()]; if crate_data.env.get("__ra_is_test_fixture").is_none() && crate_data.origin.is_local() { @@ -2056,11 +2056,11 @@ pub(crate) fn const_or_path_to_chalk( return unknown_const(expected_ty); } let c = db - .intern_in_type_const(( - x, + .intern_in_type_const(InTypeConstLoc { + id: it, owner, - Box::new(InTypeConstIdMetadata(expected_ty.clone())), - )) + thing: Box::new(InTypeConstIdMetadata(expected_ty.clone())), + }) .into(); intern_const_scalar( ConstScalar::UnevaluatedConst(c, Substitution::empty(Interner)), diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index cf7d7f6c4f85d..17c491e4360dc 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2104,7 +2104,7 @@ pub struct InTypeConst { impl InTypeConst { pub fn module(self, db: &dyn HirDatabase) -> Module { - Module { id: self.id.lookup(db.upcast()).1.module(db.upcast()) } + Module { id: self.id.lookup(db.upcast()).owner.module(db.upcast()) } } } From 0b441ca6a59ccf8bdc515b361944ba97408bd468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 13 Jun 2023 08:50:27 +0300 Subject: [PATCH 216/465] Use a more obscure hasher name in derive expansion --- .../src/macro_expansion_tests/builtin_derive_macro.rs | 10 +++++----- crates/hir-expand/src/builtin_derive_macro.rs | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs index 1a5ab19e1c254..f41f971904354 100644 --- a/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs +++ b/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs @@ -396,18 +396,18 @@ enum Command { } impl < > core::hash::Hash for Command< > where { - fn hash(&self , state: &mut H) { - core::mem::discriminant(self ).hash(state); + fn hash(&self , ra_expand_state: &mut H) { + core::mem::discriminant(self ).hash(ra_expand_state); match self { Command::Move { x: x, y: y, } => { - x.hash(state); - y.hash(state); + x.hash(ra_expand_state); + y.hash(ra_expand_state); } , Command::Do(f0, )=> { - f0.hash(state); + f0.hash(ra_expand_state); } , Command::Jump=> {} , diff --git a/crates/hir-expand/src/builtin_derive_macro.rs b/crates/hir-expand/src/builtin_derive_macro.rs index 976cd6a4ddeb0..3d1e272b90063 100644 --- a/crates/hir-expand/src/builtin_derive_macro.rs +++ b/crates/hir-expand/src/builtin_derive_macro.rs @@ -613,7 +613,7 @@ fn hash_expand( span: tt::TokenId::unspecified(), }; return quote! { - fn hash(&self, state: &mut H) { + fn hash(&self, ra_expand_state: &mut H) { match #star self {} } }; @@ -621,7 +621,7 @@ fn hash_expand( let arms = adt.shape.as_pattern(&adt.name).into_iter().zip(adt.shape.field_names()).map( |(pat, names)| { let expr = { - let it = names.iter().map(|x| quote! { #x . hash(state); }); + let it = names.iter().map(|x| quote! { #x . hash(ra_expand_state); }); quote! { { ##it } } @@ -633,8 +633,8 @@ fn hash_expand( }, ); quote! { - fn hash(&self, state: &mut H) { - #krate::mem::discriminant(self).hash(state); + fn hash(&self, ra_expand_state: &mut H) { + #krate::mem::discriminant(self).hash(ra_expand_state); match self { ##arms } From d01283b1f7e36ce81579fa524cd449cd5de7a3d4 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Tue, 13 Jun 2023 17:32:00 +0900 Subject: [PATCH 217/465] Deduplicate tuple indices for completion --- crates/ide-completion/src/completions/dot.rs | 30 ++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs index a00c6ecb91f07..c5bbb7f8d755d 100644 --- a/crates/ide-completion/src/completions/dot.rs +++ b/crates/ide-completion/src/completions/dot.rs @@ -113,8 +113,12 @@ fn complete_fields( } } for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() { - // Tuple fields are always public (tuple struct fields are handled above). - tuple_index(acc, i, ty); + // Tuples are always the last type in a deref chain, so just check if the name is + // already seen without inserting into the hashset. + if !seen_names.contains(&hir::Name::new_tuple_field(i)) { + // Tuple fields are always public (tuple struct fields are handled above). + tuple_index(acc, i, ty); + } } } } @@ -720,6 +724,28 @@ fn test(a: A) { ); } + #[test] + fn test_tuple_struct_deref_to_tuple_no_same_index() { + check( + r#" +//- minicore: deref +struct A(u8); +impl core::ops::Deref for A { + type Target = (u16, u32); + fn deref(&self) -> &Self::Target { loop {} } +} +fn test(a: A) { + a.$0 +} +"#, + expect![[r#" + fd 0 u8 + fd 1 u32 + me deref() (use core::ops::Deref) fn(&self) -> &::Target + "#]], + ); + } + #[test] fn test_completion_works_in_consts() { check( From b32280591811e10524a461b02a9282496ff5a175 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 13 Jun 2023 12:25:04 +0200 Subject: [PATCH 218/465] internal: Record file dependencies in crate graph construction --- crates/ide/src/syntax_highlighting.rs | 3 ++ crates/rust-analyzer/src/global_state.rs | 28 +++++++----- .../src/handlers/notification.rs | 4 +- crates/rust-analyzer/src/handlers/request.rs | 2 +- crates/rust-analyzer/src/main_loop.rs | 19 +++++--- crates/rust-analyzer/src/reload.rs | 43 ++++++++++++++----- 6 files changed, 68 insertions(+), 31 deletions(-) diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 8c02fe81648a5..dc06591ffea59 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs @@ -243,6 +243,9 @@ fn traverse( let mut attr_or_derive_item = None; let mut current_macro: Option = None; let mut macro_highlighter = MacroHighlighter::default(); + + // FIXME: these are not perfectly accurate, we determine them by the real file's syntax tree + // an an attribute nested in a macro call will not emit `inside_attribute` let mut inside_attribute = false; let mut inside_macro_call = false; diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 9f2fda025356e..d5b0e3a570535 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -14,7 +14,7 @@ use nohash_hasher::IntMap; use parking_lot::{Mutex, RwLock}; use proc_macro_api::ProcMacroServer; use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts}; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use triomphe::Arc; use vfs::AnchoredPathBuf; @@ -112,9 +112,11 @@ pub(crate) struct GlobalState { /// the user just adds comments or whitespace to Cargo.toml, we do not want /// to invalidate any salsa caches. pub(crate) workspaces: Arc>, + pub(crate) crate_graph_file_dependencies: FxHashSet, // op queues - pub(crate) fetch_workspaces_queue: OpQueue<(), Option>>>, + pub(crate) fetch_workspaces_queue: + OpQueue>, bool)>>, pub(crate) fetch_build_data_queue: OpQueue<(), (Arc>, Vec>)>, pub(crate) fetch_proc_macros_queue: OpQueue, bool>, @@ -196,6 +198,7 @@ impl GlobalState { vfs_progress_n_done: 0, workspaces: Arc::new(Vec::new()), + crate_graph_file_dependencies: FxHashSet::default(), fetch_workspaces_queue: OpQueue::default(), fetch_build_data_queue: OpQueue::default(), fetch_proc_macros_queue: OpQueue::default(), @@ -209,10 +212,9 @@ impl GlobalState { pub(crate) fn process_changes(&mut self) -> bool { let _p = profile::span("GlobalState::process_changes"); - let mut workspace_structure_change = None; let mut file_changes = FxHashMap::default(); - let (change, changed_files) = { + let (change, changed_files, workspace_structure_change) = { let mut change = Change::new(); let (vfs, line_endings_map) = &mut *self.vfs.write(); let changed_files = vfs.take_changes(); @@ -267,16 +269,20 @@ impl GlobalState { .map(|(file_id, (change_kind, _))| vfs::ChangedFile { file_id, change_kind }) .collect(); + let mut workspace_structure_change = None; // A file was added or deleted let mut has_structure_changes = false; for file in &changed_files { - if let Some(path) = vfs.file_path(file.file_id).as_path() { + let vfs_path = &vfs.file_path(file.file_id); + if let Some(path) = vfs_path.as_path() { let path = path.to_path_buf(); if reload::should_refresh_for_change(&path, file.change_kind) { - workspace_structure_change = Some(path); + workspace_structure_change = Some((path.clone(), false)); } if file.is_created_or_deleted() { has_structure_changes = true; + workspace_structure_change = + Some((path, self.crate_graph_file_dependencies.contains(vfs_path))); } } @@ -301,7 +307,7 @@ impl GlobalState { let roots = self.source_root_config.partition(vfs); change.set_roots(roots); } - (change, changed_files) + (change, changed_files, workspace_structure_change) }; self.analysis_host.apply_change(change); @@ -311,9 +317,11 @@ impl GlobalState { // FIXME: ideally we should only trigger a workspace fetch for non-library changes // but something's going wrong with the source root business when we add a new local // crate see https://github.com/rust-lang/rust-analyzer/issues/13029 - if let Some(path) = workspace_structure_change { - self.fetch_workspaces_queue - .request_op(format!("workspace vfs file change: {}", path.display()), ()); + if let Some((path, force_crate_graph_reload)) = workspace_structure_change { + self.fetch_workspaces_queue.request_op( + format!("workspace vfs file change: {}", path.display()), + force_crate_graph_reload, + ); } self.proc_macro_changed = changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| { diff --git a/crates/rust-analyzer/src/handlers/notification.rs b/crates/rust-analyzer/src/handlers/notification.rs index 09de6900c8fb5..ae1dc23153cd7 100644 --- a/crates/rust-analyzer/src/handlers/notification.rs +++ b/crates/rust-analyzer/src/handlers/notification.rs @@ -127,7 +127,7 @@ pub(crate) fn handle_did_save_text_document( if reload::should_refresh_for_change(abs_path, ChangeKind::Modify) { state .fetch_workspaces_queue - .request_op(format!("DidSaveTextDocument {}", abs_path.display()), ()); + .request_op(format!("DidSaveTextDocument {}", abs_path.display()), false); } } @@ -205,7 +205,7 @@ pub(crate) fn handle_did_change_workspace_folders( if !config.has_linked_projects() && config.detached_files().is_empty() { config.rediscover_workspaces(); - state.fetch_workspaces_queue.request_op("client workspaces changed".to_string(), ()) + state.fetch_workspaces_queue.request_op("client workspaces changed".to_string(), false) } Ok(()) diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index fc1076b65b0f4..a6a72552d57c5 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -51,7 +51,7 @@ pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result< state.proc_macro_clients = Arc::from(Vec::new()); state.proc_macro_changed = false; - state.fetch_workspaces_queue.request_op("reload workspace request".to_string(), ()); + state.fetch_workspaces_queue.request_op("reload workspace request".to_string(), false); Ok(()) } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index eb5d7f495f790..40ab658eeadb1 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -115,9 +115,11 @@ impl GlobalState { self.register_did_save_capability(); } - self.fetch_workspaces_queue.request_op("startup".to_string(), ()); - if let Some((cause, ())) = self.fetch_workspaces_queue.should_start_op() { - self.fetch_workspaces(cause); + self.fetch_workspaces_queue.request_op("startup".to_string(), false); + if let Some((cause, force_crate_graph_reload)) = + self.fetch_workspaces_queue.should_start_op() + { + self.fetch_workspaces(cause, force_crate_graph_reload); } while let Some(event) = self.next_event(&inbox) { @@ -367,8 +369,10 @@ impl GlobalState { } if self.config.cargo_autoreload() { - if let Some((cause, ())) = self.fetch_workspaces_queue.should_start_op() { - self.fetch_workspaces(cause); + if let Some((cause, force_crate_graph_reload)) = + self.fetch_workspaces_queue.should_start_op() + { + self.fetch_workspaces(cause, force_crate_graph_reload); } } @@ -471,8 +475,9 @@ impl GlobalState { let (state, msg) = match progress { ProjectWorkspaceProgress::Begin => (Progress::Begin, None), ProjectWorkspaceProgress::Report(msg) => (Progress::Report, Some(msg)), - ProjectWorkspaceProgress::End(workspaces) => { - self.fetch_workspaces_queue.op_completed(Some(workspaces)); + ProjectWorkspaceProgress::End(workspaces, force_reload_crate_graph) => { + self.fetch_workspaces_queue + .op_completed(Some((workspaces, force_reload_crate_graph))); if let Err(e) = self.fetch_workspace_error() { tracing::error!("FetchWorkspaceError:\n{e}"); } diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index c875c6ba42bb4..310c6b076c07a 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -27,6 +27,7 @@ use ide_db::{ use itertools::Itertools; use proc_macro_api::{MacroDylib, ProcMacroServer}; use project_model::{PackageRoot, ProjectWorkspace, WorkspaceBuildScripts}; +use rustc_hash::FxHashSet; use stdx::{format_to, thread::ThreadIntent}; use syntax::SmolStr; use triomphe::Arc; @@ -46,7 +47,7 @@ use ::tt::token_id as tt; pub(crate) enum ProjectWorkspaceProgress { Begin, Report(String), - End(Vec>), + End(Vec>, bool), } #[derive(Debug)] @@ -85,7 +86,7 @@ impl GlobalState { ); } if self.config.linked_projects() != old_config.linked_projects() { - self.fetch_workspaces_queue.request_op("linked projects changed".to_string(), ()) + self.fetch_workspaces_queue.request_op("linked projects changed".to_string(), false) } else if self.config.flycheck() != old_config.flycheck() { self.reload_flycheck(); } @@ -182,7 +183,7 @@ impl GlobalState { status } - pub(crate) fn fetch_workspaces(&mut self, cause: Cause) { + pub(crate) fn fetch_workspaces(&mut self, cause: Cause, force_crate_graph_reload: bool) { tracing::info!(%cause, "will fetch workspaces"); self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, { @@ -250,7 +251,10 @@ impl GlobalState { tracing::info!("did fetch workspaces {:?}", workspaces); sender - .send(Task::FetchWorkspace(ProjectWorkspaceProgress::End(workspaces))) + .send(Task::FetchWorkspace(ProjectWorkspaceProgress::End( + workspaces, + force_crate_graph_reload, + ))) .unwrap(); } }); @@ -336,15 +340,19 @@ impl GlobalState { let _p = profile::span("GlobalState::switch_workspaces"); tracing::info!(%cause, "will switch workspaces"); + let Some((workspaces, force_reload_crate_graph)) = self.fetch_workspaces_queue.last_op_result() else { return; }; + if let Err(_) = self.fetch_workspace_error() { if !self.workspaces.is_empty() { + if *force_reload_crate_graph { + self.recreate_crate_graph(cause); + } // It only makes sense to switch to a partially broken workspace // if we don't have any workspace at all yet. return; } } - let Some(workspaces) = self.fetch_workspaces_queue.last_op_result() else { return; }; let workspaces = workspaces.iter().filter_map(|res| res.as_ref().ok().cloned()).collect::>(); @@ -373,6 +381,9 @@ impl GlobalState { self.workspaces = Arc::new(workspaces); } else { tracing::info!("build scripts do not match the version of the active workspace"); + if *force_reload_crate_graph { + self.recreate_crate_graph(cause); + } // Current build scripts do not match the version of the active // workspace, so there's nothing for us to update. return; @@ -467,13 +478,24 @@ impl GlobalState { }); self.source_root_config = project_folders.source_root_config; + self.recreate_crate_graph(cause); + + tracing::info!("did switch workspaces"); + } + + fn recreate_crate_graph(&mut self, cause: String) { // Create crate graph from all the workspaces - let (crate_graph, proc_macro_paths) = { + let (crate_graph, proc_macro_paths, crate_graph_file_dependencies) = { let vfs = &mut self.vfs.write().0; let loader = &mut self.loader; + // crate graph construction relies on these paths, record them so when one of them gets + // deleted or created we trigger a reconstruction of the crate graph + let mut crate_graph_file_dependencies = FxHashSet::default(); + let mut load = |path: &AbsPath| { let _p = profile::span("switch_workspaces::load"); let vfs_path = vfs::VfsPath::from(path.to_path_buf()); + crate_graph_file_dependencies.insert(vfs_path.clone()); match vfs.file_id(&vfs_path) { Some(file_id) => Some(file_id), None => { @@ -494,26 +516,25 @@ impl GlobalState { crate_graph.extend(other, &mut crate_proc_macros); proc_macros.push(crate_proc_macros); } - (crate_graph, proc_macros) + (crate_graph, proc_macros, crate_graph_file_dependencies) }; - let mut change = Change::new(); if self.config.expand_proc_macros() { self.fetch_proc_macros_queue.request_op(cause, proc_macro_paths); } + let mut change = Change::new(); change.set_crate_graph(crate_graph); self.analysis_host.apply_change(change); + self.crate_graph_file_dependencies = crate_graph_file_dependencies; self.process_changes(); self.reload_flycheck(); - - tracing::info!("did switch workspaces"); } pub(super) fn fetch_workspace_error(&self) -> Result<(), String> { let mut buf = String::new(); - let Some(last_op_result) = self.fetch_workspaces_queue.last_op_result() else { return Ok(()) }; + let Some((last_op_result, _)) = self.fetch_workspaces_queue.last_op_result() else { return Ok(()) }; if last_op_result.is_empty() { stdx::format_to!(buf, "rust-analyzer failed to discover workspace"); } else { From 9483008d71851eb9009d652f34c8dca4615cb737 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 12 Jun 2023 20:51:29 -0400 Subject: [PATCH 219/465] Tests for the CI --- build_sysroot/build_sysroot.sh | 2 +- test.sh | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/build_sysroot/build_sysroot.sh b/build_sysroot/build_sysroot.sh index dc80e4fff806d..063219aabd27d 100755 --- a/build_sysroot/build_sysroot.sh +++ b/build_sysroot/build_sysroot.sh @@ -30,7 +30,7 @@ mkdir -p sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ cp -r target/$TARGET_TRIPLE/$sysroot_channel/deps/* sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ # Since we can't override the sysroot for the UI tests anymore, we create a new toolchain and manually overwrite the sysroot directory. -my_toolchain_dir=$HOME/.rustup/toolchains/my_toolchain +my_toolchain_dir=$HOME/.rustup/toolchains/codegen_gcc_ui_tests rm -rf $my_toolchain_dir rust_toolchain=$(cat ../rust-toolchain | grep channel | sed 's/channel = "\(.*\)"/\1/') cp -r $HOME/.rustup/toolchains/$rust_toolchain-$TARGET_TRIPLE $my_toolchain_dir diff --git a/test.sh b/test.sh index a6e87fca16233..6213ed49183c2 100755 --- a/test.sh +++ b/test.sh @@ -213,7 +213,7 @@ function setup_rustc() { rm config.toml || true - my_toolchain_dir=$HOME/.rustup/toolchains/my_toolchain + my_toolchain_dir=$HOME/.rustup/toolchains/codegen_gcc_ui_tests cat > config.toml < Date: Tue, 13 Jun 2023 20:41:15 +0000 Subject: [PATCH 220/465] Suggest correct signature on missing fn returning RPITIT/AFIT --- compiler/rustc_hir_analysis/src/check/mod.rs | 31 +++++++++++++++++-- .../in-trait/suggest-missing-item.fixed | 22 +++++++++++++ .../in-trait/suggest-missing-item.rs | 19 ++++++++++++ .../in-trait/suggest-missing-item.stderr | 18 +++++++++++ 4 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 tests/ui/impl-trait/in-trait/suggest-missing-item.fixed create mode 100644 tests/ui/impl-trait/in-trait/suggest-missing-item.rs create mode 100644 tests/ui/impl-trait/in-trait/suggest-missing-item.stderr diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index c9e74896ac08e..d8e9e5a01528e 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -403,7 +403,32 @@ fn fn_sig_suggestion<'tcx>( .flatten() .collect::>() .join(", "); - let output = sig.output(); + let mut output = sig.output(); + + let asyncness = if tcx.asyncness(assoc.def_id).is_async() { + output = if let ty::Alias(_, alias_ty) = *output.kind() { + tcx.explicit_item_bounds(alias_ty.def_id) + .subst_iter_copied(tcx, alias_ty.substs) + .find_map(|(bound, _)| { + bound.to_opt_poly_projection_pred()?.no_bound_vars()?.term.ty() + }) + .unwrap_or_else(|| { + span_bug!( + ident.span, + "expected async fn to have `impl Future` output, but it returns {output}" + ) + }) + } else { + span_bug!( + ident.span, + "expected async fn to have `impl Future` output, but it returns {output}" + ) + }; + "async " + } else { + "" + }; + let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() }; let unsafety = sig.unsafety.prefix_str(); @@ -414,7 +439,9 @@ fn fn_sig_suggestion<'tcx>( // lifetimes between the `impl` and the `trait`, but this should be good enough to // fill in a significant portion of the missing code, and other subsequent // suggestions can help the user fix the code. - format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}") + format!( + "{unsafety}{asyncness}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}" + ) } pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> { diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed b/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed new file mode 100644 index 0000000000000..16c4d15ddcd60 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed @@ -0,0 +1,22 @@ +// edition:2021 +// run-rustfix + +#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] + +trait Trait { + async fn foo(); + + async fn bar() -> i32; + + fn test(&self) -> impl Sized + '_; +} + +struct S; + +impl Trait for S {fn test(&self) -> impl Sized + '_ { todo!() } +async fn bar() -> i32 { todo!() } +async fn foo() { todo!() } +} +//~^ ERROR not all trait items implemented + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.rs b/tests/ui/impl-trait/in-trait/suggest-missing-item.rs new file mode 100644 index 0000000000000..f218e6cb581e3 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.rs @@ -0,0 +1,19 @@ +// edition:2021 +// run-rustfix + +#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] + +trait Trait { + async fn foo(); + + async fn bar() -> i32; + + fn test(&self) -> impl Sized + '_; +} + +struct S; + +impl Trait for S {} +//~^ ERROR not all trait items implemented + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr b/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr new file mode 100644 index 0000000000000..d96641fe16335 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr @@ -0,0 +1,18 @@ +error[E0046]: not all trait items implemented, missing: `foo`, `bar`, `test` + --> $DIR/suggest-missing-item.rs:16:1 + | +LL | async fn foo(); + | --------------- `foo` from trait +LL | +LL | async fn bar() -> i32; + | ---------------------- `bar` from trait +LL | +LL | fn test(&self) -> impl Sized + '_; + | ---------------------------------- `test` from trait +... +LL | impl Trait for S {} + | ^^^^^^^^^^^^^^^^ missing `foo`, `bar`, `test` in implementation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0046`. From 3a9a8d4abf440eab3465b18ed65a1bade78666d5 Mon Sep 17 00:00:00 2001 From: ltdk Date: Tue, 13 Jun 2023 22:30:38 -0400 Subject: [PATCH 221/465] Alter `Display` for `Ipv6Addr` for IPv4-compatible addresses --- library/core/src/net/ip_addr.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 954d88d548e82..c51913fa8ab8d 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -1770,14 +1770,8 @@ impl fmt::Display for Ipv6Addr { f.write_str("::") } else if self.is_loopback() { f.write_str("::1") - } else if let Some(ipv4) = self.to_ipv4() { - match segments[5] { - // IPv4 Compatible address - 0 => write!(f, "::{}", ipv4), - // IPv4 Mapped address - 0xffff => write!(f, "::ffff:{}", ipv4), - _ => unreachable!(), - } + } else if let Some(ipv4) = self.to_ipv4_mapped() { + write!(f, "::ffff:{}", ipv4) } else { #[derive(Copy, Clone, Default)] struct Span { From 6d6354e5b57011480a959c287ca5a81bda57074e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 14 Jun 2023 07:33:37 +0300 Subject: [PATCH 222/465] Rename minicore ArgumentV1 to match libcore --- crates/ide/src/inlay_hints/chaining.rs | 12 ++++++------ crates/test-utils/src/minicore.rs | 15 ++++++--------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs index fd4e347d259f9..6603f6e55b748 100644 --- a/crates/ide/src/inlay_hints/chaining.rs +++ b/crates/ide/src/inlay_hints/chaining.rs @@ -474,7 +474,7 @@ fn main() { file_id: FileId( 1, ), - range: 9333..9341, + range: 9286..9294, }, ), tooltip: "", @@ -487,7 +487,7 @@ fn main() { file_id: FileId( 1, ), - range: 9365..9369, + range: 9318..9322, }, ), tooltip: "", @@ -511,7 +511,7 @@ fn main() { file_id: FileId( 1, ), - range: 9333..9341, + range: 9286..9294, }, ), tooltip: "", @@ -524,7 +524,7 @@ fn main() { file_id: FileId( 1, ), - range: 9365..9369, + range: 9318..9322, }, ), tooltip: "", @@ -548,7 +548,7 @@ fn main() { file_id: FileId( 1, ), - range: 9333..9341, + range: 9286..9294, }, ), tooltip: "", @@ -561,7 +561,7 @@ fn main() { file_id: FileId( 1, ), - range: 9365..9369, + range: 9318..9322, }, ), tooltip: "", diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 1484a4497a41d..3dc2d9f28d816 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -867,29 +867,26 @@ pub mod fmt { } #[lang = "format_argument"] - pub struct ArgumentV1<'a> { + pub struct Argument<'a> { value: &'a Opaque, formatter: fn(&Opaque, &mut Formatter<'_>) -> Result, } - impl<'a> ArgumentV1<'a> { - pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> ArgumentV1<'b> { + impl<'a> Argument<'a> { + pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b> { use crate::mem::transmute; - unsafe { ArgumentV1 { formatter: transmute(f), value: transmute(x) } } + unsafe { Argument { formatter: transmute(f), value: transmute(x) } } } } #[lang = "format_arguments"] pub struct Arguments<'a> { pieces: &'a [&'static str], - args: &'a [ArgumentV1<'a>], + args: &'a [Argument<'a>], } impl<'a> Arguments<'a> { - pub const fn new_v1( - pieces: &'a [&'static str], - args: &'a [ArgumentV1<'a>], - ) -> Arguments<'a> { + pub const fn new_v1(pieces: &'a [&'static str], args: &'a [Argument<'a>]) -> Arguments<'a> { Arguments { pieces, args } } } From 5be14f5fda8da0f9169bcb798488d3b90011207a Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 14 Jun 2023 12:30:17 +0200 Subject: [PATCH 223/465] ensure test harness test works on panic=abort targets --- tests/ui/test-attrs/test-type.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/test-attrs/test-type.rs b/tests/ui/test-attrs/test-type.rs index 8416270fd8159..9c7b8b96d6908 100644 --- a/tests/ui/test-attrs/test-type.rs +++ b/tests/ui/test-attrs/test-type.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +// compile-flags: --test -Zpanic-abort-tests // run-flags: --test-threads=1 // check-run-results // normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" From 0526267ffd2d59305319f73c4a63055c34281e45 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 14 Jun 2023 12:19:21 +0200 Subject: [PATCH 224/465] mark relevant tests as requiring unwinding --- tests/ui/asm/aarch64/may_unwind.rs | 1 + tests/ui/test-attrs/test-panic-abort-disabled.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/ui/asm/aarch64/may_unwind.rs b/tests/ui/asm/aarch64/may_unwind.rs index 6af8728bbaa96..cfb75078264df 100644 --- a/tests/ui/asm/aarch64/may_unwind.rs +++ b/tests/ui/asm/aarch64/may_unwind.rs @@ -1,6 +1,7 @@ // only-aarch64 // run-pass // needs-asm-support +// needs-unwind #![feature(asm_unwind)] diff --git a/tests/ui/test-attrs/test-panic-abort-disabled.rs b/tests/ui/test-attrs/test-panic-abort-disabled.rs index 874dbdb42c33c..fa67a784de47f 100644 --- a/tests/ui/test-attrs/test-panic-abort-disabled.rs +++ b/tests/ui/test-attrs/test-panic-abort-disabled.rs @@ -3,6 +3,7 @@ // compile-flags: --test -Cpanic=abort -Zpanic-abort-tests=no // run-flags: --test-threads=1 +// needs-unwind // ignore-wasm no panic or subprocess support // ignore-emscripten no panic or subprocess support From f5d3de2abccd0de94d96367b35e33a776a242d69 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 14 Jun 2023 12:31:00 +0200 Subject: [PATCH 225/465] update codegent test to be independent of panic strategy --- tests/codegen/naked-nocoverage.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/codegen/naked-nocoverage.rs b/tests/codegen/naked-nocoverage.rs index 91a6260bf2aa2..3c755e49c6dba 100644 --- a/tests/codegen/naked-nocoverage.rs +++ b/tests/codegen/naked-nocoverage.rs @@ -11,7 +11,7 @@ use std::arch::asm; #[naked] #[no_mangle] pub unsafe extern "C" fn f() { - // CHECK: define void @f() + // CHECK: define {{(dso_local )?}}void @f() // CHECK-NEXT: start: // CHECK-NEXT: call void asm // CHECK-NEXT: unreachable From 9395e2771ab0fab5d89f9422610b571096c87a3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 14 Jun 2023 12:14:19 +0000 Subject: [PATCH 226/465] make mir dataflow graphviz dumps opt-in --- .../rustc_mir_dataflow/src/framework/engine.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 4bdfa35fc708b..c755d7588c254 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -287,9 +287,11 @@ where let mut results = Results { analysis, entry_sets, _marker: PhantomData }; - let res = write_graphviz_results(tcx, body, &mut results, pass_name); - if let Err(e) = res { - error!("Failed to write graphviz dataflow results: {}", e); + if tcx.sess.opts.unstable_opts.dump_mir_dataflow { + let res = write_graphviz_results(tcx, &body, &mut results, pass_name); + if let Err(e) = res { + error!("Failed to write graphviz dataflow results: {}", e); + } } results @@ -299,7 +301,7 @@ where // Graphviz /// Writes a DOT file containing the results of a dataflow analysis if the user requested it via -/// `rustc_mir` attributes. +/// `rustc_mir` attributes and `-Z dump-mir-dataflow`. fn write_graphviz_results<'tcx, A>( tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>, @@ -328,9 +330,7 @@ where io::BufWriter::new(fs::File::create(&path)?) } - None if tcx.sess.opts.unstable_opts.dump_mir_dataflow - && dump_enabled(tcx, A::NAME, def_id) => - { + None if dump_enabled(tcx, A::NAME, def_id) => { create_dump_file(tcx, ".dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)? } From b07490ffe9bdf2b4d71006bee09d2b0dc6ab0a19 Mon Sep 17 00:00:00 2001 From: ponyii Date: Wed, 14 Jun 2023 17:37:34 +0400 Subject: [PATCH 227/465] made the `add_missing_impl_members` and `add_missing_default_members` assists transform default generic types --- .../src/handlers/add_missing_impl_members.rs | 109 ++++++++++++++++++ crates/ide-db/src/path_transform.rs | 80 ++++++++----- 2 files changed, 157 insertions(+), 32 deletions(-) diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 4d572c604b0ea..e827f277b1e1d 100644 --- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -830,6 +830,115 @@ impl Foo for S { ) } + #[test] + fn test_qualify_generic_default_parameter() { + check_assist( + add_missing_impl_members, + r#" +mod m { + pub struct S; + pub trait Foo { + fn bar(&self, other: &T); + } +} + +struct S; +impl m::Foo for S { $0 }"#, + r#" +mod m { + pub struct S; + pub trait Foo { + fn bar(&self, other: &T); + } +} + +struct S; +impl m::Foo for S { + fn bar(&self, other: &m::S) { + ${0:todo!()} + } +}"#, + ) + } + + #[test] + fn test_qualify_generic_default_parameter_2() { + check_assist( + add_missing_impl_members, + r#" +mod m { + pub struct Wrapper { + one: T, + another: V + }; + pub struct S; + pub trait Foo> { + fn bar(&self, other: &T); + } +} + +struct S; +impl m::Foo for S { $0 }"#, + r#" +mod m { + pub struct Wrapper { + one: T, + another: V + }; + pub struct S; + pub trait Foo> { + fn bar(&self, other: &T); + } +} + +struct S; +impl m::Foo for S { + fn bar(&self, other: &m::Wrapper) { + ${0:todo!()} + } +}"#, + ); + } + + #[test] + fn test_qualify_generic_default_parameter_3() { + check_assist( + add_missing_impl_members, + r#" +mod m { + pub struct Wrapper { + one: T, + another: V + }; + pub struct S; + pub trait Foo> { + fn bar(&self, other: &V); + } +} + +struct S; +impl m::Foo for S { $0 }"#, + r#" +mod m { + pub struct Wrapper { + one: T, + another: V + }; + pub struct S; + pub trait Foo> { + fn bar(&self, other: &V); + } +} + +struct S; +impl m::Foo for S { + fn bar(&self, other: &m::Wrapper) { + ${0:todo!()} + } +}"#, + ); + } + #[test] fn test_assoc_type_bounds_are_removed() { check_assist( diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs index 887c2feee16f3..f990fbd0e8f5d 100644 --- a/crates/ide-db/src/path_transform.rs +++ b/crates/ide-db/src/path_transform.rs @@ -17,6 +17,11 @@ struct AstSubsts { lifetimes: Vec, } +struct TypeOrConstSubst { + subst: ast::Type, + to_be_transformed: bool, +} + type LifetimeName = String; /// `PathTransform` substitutes path in SyntaxNodes in bulk. @@ -123,13 +128,21 @@ impl<'a> PathTransform<'a> { // the resulting change can be applied correctly. .zip(self.substs.types_and_consts.iter().map(Some).chain(std::iter::repeat(None))) .filter_map(|(k, v)| match (k.split(db), v) { - (_, Some(v)) => Some((k, v.ty()?.clone())), + (_, Some(v)) => { + let subst = + TypeOrConstSubst { subst: v.ty()?.clone(), to_be_transformed: false }; + Some((k, subst)) + } (Either::Right(t), None) => { let default = t.default(db)?; - let v = ast::make::ty( - &default.display_source_code(db, source_module.into(), false).ok()?, - ); - Some((k, v)) + let subst = TypeOrConstSubst { + subst: ast::make::ty( + &default.display_source_code(db, source_module.into(), false).ok()?, + ) + .clone_for_update(), + to_be_transformed: true, + }; + Some((k, subst)) } (Either::Left(_), None) => None, // FIXME: get default const value }) @@ -151,45 +164,44 @@ impl<'a> PathTransform<'a> { } struct Ctx<'a> { - type_and_const_substs: FxHashMap, + type_and_const_substs: FxHashMap, lifetime_substs: FxHashMap, target_module: hir::Module, source_scope: &'a SemanticsScope<'a>, } +fn preorder(item: &SyntaxNode) -> impl Iterator { + item.preorder().filter_map(|event| match event { + syntax::WalkEvent::Enter(_) => None, + syntax::WalkEvent::Leave(node) => Some(node), + }) +} + impl<'a> Ctx<'a> { fn apply(&self, item: &SyntaxNode) { + for (_, subst) in &self.type_and_const_substs { + if subst.to_be_transformed { + let paths = + preorder(&subst.subst.syntax()).filter_map(ast::Path::cast).collect::>(); + for path in paths { + self.transform_path(path); + } + } + } + // `transform_path` may update a node's parent and that would break the // tree traversal. Thus all paths in the tree are collected into a vec // so that such operation is safe. - let paths = item - .preorder() - .filter_map(|event| match event { - syntax::WalkEvent::Enter(_) => None, - syntax::WalkEvent::Leave(node) => Some(node), - }) - .filter_map(ast::Path::cast) - .collect::>(); - + let paths = preorder(item).filter_map(ast::Path::cast).collect::>(); for path in paths { self.transform_path(path); } - item.preorder() - .filter_map(|event| match event { - syntax::WalkEvent::Enter(_) => None, - syntax::WalkEvent::Leave(node) => Some(node), - }) - .filter_map(ast::Lifetime::cast) - .for_each(|lifetime| { - if let Some(subst) = self.lifetime_substs.get(&lifetime.syntax().text().to_string()) - { - ted::replace( - lifetime.syntax(), - subst.clone_subtree().clone_for_update().syntax(), - ); - } - }); + preorder(item).filter_map(ast::Lifetime::cast).for_each(|lifetime| { + if let Some(subst) = self.lifetime_substs.get(&lifetime.syntax().text().to_string()) { + ted::replace(lifetime.syntax(), subst.clone_subtree().clone_for_update().syntax()); + } + }); } fn transform_path(&self, path: ast::Path) -> Option<()> { @@ -208,7 +220,9 @@ impl<'a> Ctx<'a> { match resolution { hir::PathResolution::TypeParam(tp) => { - if let Some(subst) = self.type_and_const_substs.get(&tp.merge()) { + if let Some(TypeOrConstSubst { subst, .. }) = + self.type_and_const_substs.get(&tp.merge()) + { let parent = path.syntax().parent()?; if let Some(parent) = ast::Path::cast(parent.clone()) { // Path inside path means that there is an associated @@ -276,7 +290,9 @@ impl<'a> Ctx<'a> { ted::replace(path.syntax(), res.syntax()) } hir::PathResolution::ConstParam(cp) => { - if let Some(subst) = self.type_and_const_substs.get(&cp.merge()) { + if let Some(TypeOrConstSubst { subst, .. }) = + self.type_and_const_substs.get(&cp.merge()) + { ted::replace(path.syntax(), subst.clone_subtree().clone_for_update().syntax()); } } From cf178cba8f362013aaecf758be891da34f949717 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 13 Jun 2023 12:59:52 +0200 Subject: [PATCH 228/465] internal: Add a CrateRootModuleId that encodes a module id that is always a crate root --- crates/hir-def/src/find_path.rs | 4 +- crates/hir-def/src/item_tree.rs | 6 --- crates/hir-def/src/lib.rs | 45 +++++++++++++++++-- crates/hir-def/src/nameres.rs | 23 ++++++---- crates/hir-def/src/nameres/collector.rs | 58 ++++++++++--------------- crates/hir-def/src/resolver.rs | 19 +++++--- crates/hir-expand/src/ast_id_map.rs | 6 +-- crates/hir/src/lib.rs | 4 +- crates/rust-analyzer/src/main_loop.rs | 2 - 9 files changed, 102 insertions(+), 65 deletions(-) diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs index e8cc2eab4617e..8c49ae1c4afe8 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -81,7 +81,7 @@ fn find_path_inner( } let def_map = from.def_map(db); - let crate_root = def_map.crate_root(); + let crate_root = def_map.crate_root().into(); // - if the item is a module, jump straight to module search if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item { let mut visited_modules = FxHashSet::default(); @@ -374,7 +374,7 @@ fn calculate_best_path( } } if let Some(module) = item.module(db) { - if module.def_map(db).block_id().is_some() && prefixed.is_some() { + if module.containing_block().is_some() && prefixed.is_some() { cov_mark::hit!(prefixed_in_block_expression); prefixed = Some(PrefixKind::Plain); } diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 590ed64af5d80..e74b71888c2be 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -101,7 +101,6 @@ pub struct ItemTree { top_level: SmallVec<[ModItem; 1]>, attrs: FxHashMap, - // FIXME: Remove this indirection, an item tree is almost always non-empty? data: Option>, } @@ -718,7 +717,6 @@ pub struct Mod { pub enum ModKind { /// `mod m { ... }` Inline { items: Box<[ModItem]> }, - /// `mod m;` Outline, } @@ -892,10 +890,6 @@ impl ModItem { } } - pub fn downcast(self) -> Option> { - N::id_from_mod_item(self) - } - pub fn ast_id(&self, tree: &ItemTree) -> FileAstId { match self { ModItem::Import(it) => tree[it.index].ast_id().upcast(), diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 4f68093bcbe2c..b0ab9727c9dca 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -97,6 +97,46 @@ use crate::{ }, }; +/// A `ModuleId` that is always a crate's root module. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct CrateRootModuleId { + krate: CrateId, +} + +impl CrateRootModuleId { + pub fn def_map(&self, db: &dyn db::DefDatabase) -> Arc { + db.crate_def_map(self.krate) + } + + pub fn krate(self) -> CrateId { + self.krate + } +} + +impl From for ModuleId { + fn from(CrateRootModuleId { krate }: CrateRootModuleId) -> Self { + ModuleId { krate, block: None, local_id: DefMap::ROOT } + } +} + +impl From for ModuleDefId { + fn from(value: CrateRootModuleId) -> Self { + ModuleDefId::ModuleId(value.into()) + } +} + +impl TryFrom for CrateRootModuleId { + type Error = (); + + fn try_from(ModuleId { krate, block, local_id }: ModuleId) -> Result { + if block.is_none() && local_id == DefMap::ROOT { + Ok(CrateRootModuleId { krate }) + } else { + Err(()) + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ModuleId { krate: CrateId, @@ -318,8 +358,7 @@ impl_intern!(MacroRulesId, MacroRulesLoc, intern_macro_rules, lookup_intern_macr pub struct ProcMacroId(salsa::InternId); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ProcMacroLoc { - // FIXME: this should be a crate? or just a crate-root module - pub container: ModuleId, + pub container: CrateRootModuleId, pub id: ItemTreeId, pub expander: ProcMacroExpander, pub kind: ProcMacroKind, @@ -891,7 +930,7 @@ impl HasModule for MacroId { match self { MacroId::MacroRulesId(it) => it.lookup(db).container, MacroId::Macro2Id(it) => it.lookup(db).container, - MacroId::ProcMacroId(it) => it.lookup(db).container, + MacroId::ProcMacroId(it) => it.lookup(db).container.into(), } } } diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 9b520bc3030f0..0ab1bd8490c55 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -77,8 +77,8 @@ use crate::{ path::ModPath, per_ns::PerNs, visibility::Visibility, - AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, - ProcMacroId, + AstId, BlockId, BlockLoc, CrateRootModuleId, FunctionId, LocalModuleId, Lookup, MacroExpander, + MacroId, ModuleId, ProcMacroId, }; /// Contains the results of (early) name resolution. @@ -93,7 +93,10 @@ use crate::{ #[derive(Debug, PartialEq, Eq)] pub struct DefMap { _c: Count, + /// When this is a block def map, this will hold the block id of the the block and module that + /// contains this block. block: Option, + /// The modules and their data declared in this crate. modules: Arena, krate: CrateId, /// The prelude module for this crate. This either comes from an import @@ -111,15 +114,18 @@ pub struct DefMap { /// attributes. derive_helpers_in_scope: FxHashMap, Vec<(Name, MacroId, MacroCallId)>>, + /// The diagnostics that need to be emitted for this crate. diagnostics: Vec, + /// The crate data that is shared between a crate's def map and all its block def maps. data: Arc, } /// Data that belongs to a crate which is shared between a crate's def map and all its block def maps. #[derive(Clone, Debug, PartialEq, Eq)] struct DefMapCrateData { - extern_prelude: FxHashMap, + /// The extern prelude which contains all root modules of external crates that are in scope. + extern_prelude: FxHashMap, /// Side table for resolving derive helpers. exported_derives: FxHashMap>, @@ -279,6 +285,7 @@ pub struct ModuleData { } impl DefMap { + /// The module id of a crate or block root. pub const ROOT: LocalModuleId = LocalModuleId::from_raw(la_arena::RawIdx::from_u32(0)); pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc { @@ -419,11 +426,11 @@ impl DefMap { } pub(crate) fn extern_prelude(&self) -> impl Iterator + '_ { - self.data.extern_prelude.iter().map(|(name, def)| (name, *def)) + self.data.extern_prelude.iter().map(|(name, &def)| (name, def.into())) } pub(crate) fn macro_use_prelude(&self) -> impl Iterator + '_ { - self.macro_use_prelude.iter().map(|(name, def)| (name, *def)) + self.macro_use_prelude.iter().map(|(name, &def)| (name, def)) } pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId { @@ -431,8 +438,8 @@ impl DefMap { ModuleId { krate: self.krate, local_id, block } } - pub(crate) fn crate_root(&self) -> ModuleId { - ModuleId { krate: self.krate, block: None, local_id: DefMap::ROOT } + pub fn crate_root(&self) -> CrateRootModuleId { + CrateRootModuleId { krate: self.krate } } pub(crate) fn resolve_path( @@ -476,7 +483,7 @@ impl DefMap { /// /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns /// `None`, iteration continues. - pub fn with_ancestor_maps( + pub(crate) fn with_ancestor_maps( &self, db: &dyn DefDatabase, local_mod: LocalModuleId, diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 06542b4b1e999..97481ea7df776 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -51,11 +51,11 @@ use crate::{ per_ns::PerNs, tt, visibility::{RawVisibility, Visibility}, - AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, ExternBlockLoc, FunctionId, - FunctionLoc, ImplLoc, Intern, ItemContainerId, LocalModuleId, Macro2Id, Macro2Loc, - MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, ModuleDefId, ModuleId, ProcMacroId, - ProcMacroLoc, StaticLoc, StructLoc, TraitAliasLoc, TraitLoc, TypeAliasLoc, UnionLoc, - UnresolvedMacro, + AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantId, + ExternBlockLoc, FunctionId, FunctionLoc, ImplLoc, Intern, ItemContainerId, LocalModuleId, + Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, ModuleDefId, + ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc, TraitAliasLoc, TraitLoc, + TypeAliasLoc, UnionLoc, UnresolvedMacro, }; static GLOB_RECURSION_LIMIT: Limit = Limit::new(100); @@ -274,8 +274,6 @@ impl DefCollector<'_> { let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; let item_tree = self.db.file_item_tree(file_id.into()); - let module_id = DefMap::ROOT; - let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate); let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap(); @@ -285,10 +283,9 @@ impl DefCollector<'_> { for (name, dep) in &self.deps { if dep.is_prelude() { - crate_data.extern_prelude.insert( - name.clone(), - ModuleId { krate: dep.crate_id, block: None, local_id: DefMap::ROOT }, - ); + crate_data + .extern_prelude + .insert(name.clone(), CrateRootModuleId { krate: dep.crate_id }); } } @@ -374,7 +371,7 @@ impl DefCollector<'_> { ModCollector { def_collector: self, macro_depth: 0, - module_id, + module_id: DefMap::ROOT, tree_id: TreeId::new(file_id.into(), None), item_tree: &item_tree, mod_dir: ModDir::root(), @@ -384,8 +381,6 @@ impl DefCollector<'_> { fn seed_with_inner(&mut self, tree_id: TreeId) { let item_tree = tree_id.item_tree(self.db); - let module_id = DefMap::ROOT; - let is_cfg_enabled = item_tree .top_level_attrs(self.db, self.def_map.krate) .cfg() @@ -394,7 +389,7 @@ impl DefCollector<'_> { ModCollector { def_collector: self, macro_depth: 0, - module_id, + module_id: DefMap::ROOT, tree_id, item_tree: &item_tree, mod_dir: ModDir::root(), @@ -604,8 +599,6 @@ impl DefCollector<'_> { if self.def_map.block.is_some() { return; } - let crate_root = self.def_map.module_id(DefMap::ROOT); - let kind = def.kind.to_basedb_kind(); let (expander, kind) = match self.proc_macros.as_ref().map(|it| it.iter().find(|(n, _)| n == &def.name)) { @@ -614,7 +607,8 @@ impl DefCollector<'_> { }; let proc_macro_id = - ProcMacroLoc { container: crate_root, id, expander, kind }.intern(self.db); + ProcMacroLoc { container: self.def_map.crate_root(), id, expander, kind } + .intern(self.db); self.define_proc_macro(def.name.clone(), proc_macro_id); let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap(); if let ProcMacroKind::CustomDerive { helpers } = def.kind { @@ -831,16 +825,12 @@ impl DefCollector<'_> { } } - fn resolve_extern_crate(&self, name: &Name) -> Option { + fn resolve_extern_crate(&self, name: &Name) -> Option { if *name == name!(self) { cov_mark::hit!(extern_crate_self_as); Some(self.def_map.crate_root()) } else { - self.deps.get(name).map(|dep| ModuleId { - krate: dep.crate_id, - block: None, - local_id: DefMap::ROOT, - }) + self.deps.get(name).map(|dep| CrateRootModuleId { krate: dep.crate_id }) } } @@ -883,10 +873,12 @@ impl DefCollector<'_> { { if let (Some(ModuleDefId::ModuleId(def)), Some(name)) = (def.take_types(), name) { - Arc::get_mut(&mut self.def_map.data) - .unwrap() - .extern_prelude - .insert(name.clone(), def); + if let Ok(def) = def.try_into() { + Arc::get_mut(&mut self.def_map.data) + .unwrap() + .extern_prelude + .insert(name.clone(), def); + } } } @@ -1791,13 +1783,11 @@ impl ModCollector<'_, '_> { let target_crate = match self.def_collector.resolve_extern_crate(&self.item_tree[extern_crate].name) { - Some(m) => { - if m == self.def_collector.def_map.module_id(self.module_id) { - cov_mark::hit!(ignore_macro_use_extern_crate_self); - return; - } - m.krate + Some(m) if m.krate == self.def_collector.def_map.krate => { + cov_mark::hit!(ignore_macro_use_extern_crate_self); + return; } + Some(m) => m.krate, None => return, }; diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 880a76f2b85d0..edfa905e34c49 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -21,11 +21,11 @@ use crate::{ path::{ModPath, Path, PathKind}, per_ns::PerNs, visibility::{RawVisibility, Visibility}, - AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, - FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, - LocalModuleId, Lookup, Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, - StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeOwnerId, - TypeParamId, VariantId, + AdtId, AssocItemId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, + EnumVariantId, ExternBlockId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, + ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, MacroId, MacroRulesId, + ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, + TypeOrConstParamId, TypeOwnerId, TypeParamId, VariantId, }; #[derive(Debug, Clone)] @@ -946,6 +946,15 @@ impl HasResolver for ModuleId { } } +impl HasResolver for CrateRootModuleId { + fn resolver(self, db: &dyn DefDatabase) -> Resolver { + Resolver { + scopes: vec![], + module_scope: ModuleItemMap { def_map: self.def_map(db), module_id: DefMap::ROOT }, + } + } +} + impl HasResolver for TraitId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) diff --git a/crates/hir-expand/src/ast_id_map.rs b/crates/hir-expand/src/ast_id_map.rs index 02efaace43707..c2b0d5985e3c5 100644 --- a/crates/hir-expand/src/ast_id_map.rs +++ b/crates/hir-expand/src/ast_id_map.rs @@ -20,7 +20,7 @@ use syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; /// `AstId` points to an AST node in a specific file. pub struct FileAstId { raw: ErasedFileAstId, - _ty: PhantomData N>, + covariant: PhantomData N>, } impl Clone for FileAstId { @@ -54,7 +54,7 @@ impl FileAstId { where N: Into, { - FileAstId { raw: self.raw, _ty: PhantomData } + FileAstId { raw: self.raw, covariant: PhantomData } } } @@ -122,7 +122,7 @@ impl AstIdMap { pub fn ast_id(&self, item: &N) -> FileAstId { let raw = self.erased_ast_id(item.syntax()); - FileAstId { raw, _ty: PhantomData } + FileAstId { raw, covariant: PhantomData } } pub fn get(&self, id: FileAstId) -> AstPtr { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index cf7d7f6c4f85d..12b3c0a69b192 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -203,7 +203,7 @@ impl Crate { pub fn root_module(self, db: &dyn HirDatabase) -> Module { let def_map = db.crate_def_map(self.id); - Module { id: def_map.module_id(DefMap::ROOT) } + Module { id: def_map.crate_root().into() } } pub fn modules(self, db: &dyn HirDatabase) -> Vec { @@ -476,7 +476,7 @@ impl Module { /// in the module tree of any target in `Cargo.toml`. pub fn crate_root(self, db: &dyn HirDatabase) -> Module { let def_map = db.crate_def_map(self.id.krate()); - Module { id: def_map.module_id(DefMap::ROOT) } + Module { id: def_map.crate_root().into() } } pub fn is_crate_root(self) -> bool { diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index eb5d7f495f790..be89def2a74e0 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -549,7 +549,6 @@ impl GlobalState { self.vfs_progress_n_total = n_total; self.vfs_progress_n_done = n_done; - // if n_total != 0 { let state = if n_done == 0 { Progress::Begin } else if n_done < n_total { @@ -565,7 +564,6 @@ impl GlobalState { Some(Progress::fraction(n_done, n_total)), None, ); - // } } } } From 2f2c3f55a967dc8e48f3a9755980757f06233bef Mon Sep 17 00:00:00 2001 From: ltdk Date: Wed, 14 Jun 2023 14:25:25 -0400 Subject: [PATCH 229/465] Fix `Ipv6Addr: Display` tests --- library/core/tests/net/ip_addr.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/tests/net/ip_addr.rs b/library/core/tests/net/ip_addr.rs index 5a6ac08c08815..7530fc084874d 100644 --- a/library/core/tests/net/ip_addr.rs +++ b/library/core/tests/net/ip_addr.rs @@ -139,7 +139,7 @@ fn ipv6_addr_to_string() { // ipv4-compatible address let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280); - assert_eq!(a1.to_string(), "::192.0.2.128"); + assert_eq!(a1.to_string(), "::c000:280"); // v6 address with no zero segments assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f"); @@ -316,7 +316,7 @@ fn ip_properties() { check!("::", unspec); check!("::1", loopback); - check!("::0.0.0.2", global); + check!("::2", global); check!("1::", global); check!("fc00::"); check!("fdff:ffff::"); @@ -607,7 +607,7 @@ fn ipv6_properties() { check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback); - check!("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global); + check!("::2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global); check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global); From 2dce58d0f624b20633f4e6d22335b4681ec48089 Mon Sep 17 00:00:00 2001 From: ltdk Date: Wed, 14 Jun 2023 14:59:11 -0400 Subject: [PATCH 230/465] Fix `SocketAddrV6: Display` tests --- library/core/tests/net/socket_addr.rs | 2 +- library/std/src/net/socket_addr/tests.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/tests/net/socket_addr.rs b/library/core/tests/net/socket_addr.rs index 68c7cd94d322f..35a69cead4826 100644 --- a/library/core/tests/net/socket_addr.rs +++ b/library/core/tests/net/socket_addr.rs @@ -34,7 +34,7 @@ fn ipv6_socket_addr_to_string() { // IPv4-compatible address. assert_eq!( SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280), 8080, 0, 0).to_string(), - "[::192.0.2.128]:8080" + "[::c000:280]:8080" ); // IPv6 address with no zero segments. diff --git a/library/std/src/net/socket_addr/tests.rs b/library/std/src/net/socket_addr/tests.rs index dfc6dabbed1ed..6a065cfba2105 100644 --- a/library/std/src/net/socket_addr/tests.rs +++ b/library/std/src/net/socket_addr/tests.rs @@ -85,7 +85,7 @@ fn ipv6_socket_addr_to_string() { // IPv4-compatible address. assert_eq!( SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280), 8080, 0, 0).to_string(), - "[::192.0.2.128]:8080" + "[::c000:280]:8080" ); // IPv6 address with no zero segments. From 0d6da78b06e0fa4e1df1fe6795f3e17f0320071a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 15 Jun 2023 03:18:12 +0000 Subject: [PATCH 231/465] Always register sized obligation for argument --- compiler/rustc_hir_typeck/src/check.rs | 5 +---- .../closures/cannot-call-unsized-via-ptr-2.rs | 11 ++++++++++ .../cannot-call-unsized-via-ptr-2.stderr | 21 +++++++++++++++++++ .../closures/cannot-call-unsized-via-ptr.rs | 10 +++++++++ .../cannot-call-unsized-via-ptr.stderr | 12 +++++++++++ tests/ui/issues/issue-5883.rs | 2 +- tests/ui/issues/issue-5883.stderr | 18 +--------------- 7 files changed, 57 insertions(+), 22 deletions(-) create mode 100644 tests/ui/closures/cannot-call-unsized-via-ptr-2.rs create mode 100644 tests/ui/closures/cannot-call-unsized-via-ptr-2.stderr create mode 100644 tests/ui/closures/cannot-call-unsized-via-ptr.rs create mode 100644 tests/ui/closures/cannot-call-unsized-via-ptr.stderr diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 69ccbf0b58ff3..0a1b639af5157 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -92,10 +92,7 @@ pub(super) fn check_fn<'a, 'tcx>( fcx.check_pat_top(¶m.pat, param_ty, ty_span, None); // Check that argument is Sized. - // The check for a non-trivial pattern is a hack to avoid duplicate warnings - // for simple cases like `fn foo(x: Trait)`, - // where we would error once on the parameter as a whole, and once on the binding `x`. - if param.pat.simple_ident().is_none() && !params_can_be_unsized { + if !params_can_be_unsized { fcx.require_type_is_sized( param_ty, param.pat.span, diff --git a/tests/ui/closures/cannot-call-unsized-via-ptr-2.rs b/tests/ui/closures/cannot-call-unsized-via-ptr-2.rs new file mode 100644 index 0000000000000..2d8565517e897 --- /dev/null +++ b/tests/ui/closures/cannot-call-unsized-via-ptr-2.rs @@ -0,0 +1,11 @@ +#![feature(unsized_fn_params)] + +fn main() { + // CoerceMany "LUB" + let f = if true { |_a| {} } else { |_b| {} }; + //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time + //~| ERROR the size for values of type `[u8]` cannot be known at compilation time + + let slice: Box<[u8]> = Box::new([1; 8]); + f(*slice); +} diff --git a/tests/ui/closures/cannot-call-unsized-via-ptr-2.stderr b/tests/ui/closures/cannot-call-unsized-via-ptr-2.stderr new file mode 100644 index 0000000000000..d88b84365dfae --- /dev/null +++ b/tests/ui/closures/cannot-call-unsized-via-ptr-2.stderr @@ -0,0 +1,21 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/cannot-call-unsized-via-ptr-2.rs:5:24 + | +LL | let f = if true { |_a| {} } else { |_b| {} }; + | ^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all function arguments must have a statically known size + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/cannot-call-unsized-via-ptr-2.rs:5:41 + | +LL | let f = if true { |_a| {} } else { |_b| {} }; + | ^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all function arguments must have a statically known size + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/closures/cannot-call-unsized-via-ptr.rs b/tests/ui/closures/cannot-call-unsized-via-ptr.rs new file mode 100644 index 0000000000000..5ce4650b0333c --- /dev/null +++ b/tests/ui/closures/cannot-call-unsized-via-ptr.rs @@ -0,0 +1,10 @@ +#![feature(unsized_fn_params)] + +fn main() { + // Simple coercion + let f: fn([u8]) = |_result| {}; + //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time + + let slice: Box<[u8]> = Box::new([1; 8]); + f(*slice); +} diff --git a/tests/ui/closures/cannot-call-unsized-via-ptr.stderr b/tests/ui/closures/cannot-call-unsized-via-ptr.stderr new file mode 100644 index 0000000000000..9ecc66d5ce897 --- /dev/null +++ b/tests/ui/closures/cannot-call-unsized-via-ptr.stderr @@ -0,0 +1,12 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/cannot-call-unsized-via-ptr.rs:5:24 + | +LL | let f: fn([u8]) = |_result| {}; + | ^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all function arguments must have a statically known size + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/issues/issue-5883.rs b/tests/ui/issues/issue-5883.rs index 82866b355573c..f9dd2c54d997f 100644 --- a/tests/ui/issues/issue-5883.rs +++ b/tests/ui/issues/issue-5883.rs @@ -6,7 +6,7 @@ struct Struct { fn new_struct( r: dyn A + 'static //~ ERROR the size for values of type -) -> Struct { //~ ERROR the size for values of type +) -> Struct { Struct { r: r } } diff --git a/tests/ui/issues/issue-5883.stderr b/tests/ui/issues/issue-5883.stderr index ffff403e0d465..a3e2531b5caa4 100644 --- a/tests/ui/issues/issue-5883.stderr +++ b/tests/ui/issues/issue-5883.stderr @@ -15,22 +15,6 @@ help: function arguments must have a statically known size, borrowed types alway LL | r: &dyn A + 'static | + -error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time - --> $DIR/issue-5883.rs:9:6 - | -LL | ) -> Struct { - | ^^^^^^ doesn't have a size known at compile-time -LL | Struct { r: r } - | --------------- this returned value is of type `Struct` - | - = help: within `Struct`, the trait `Sized` is not implemented for `(dyn A + 'static)` -note: required because it appears within the type `Struct` - --> $DIR/issue-5883.rs:3:8 - | -LL | struct Struct { - | ^^^^^^ - = note: the return type of a function must have a statically known size - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0277`. From 922be8714dbcd6139c390aabd61f1fb9b7e6e724 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Thu, 15 Jun 2023 12:05:15 +0330 Subject: [PATCH 232/465] Add more log in "terminator is none" assert --- crates/hir-ty/src/mir/borrowck.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/crates/hir-ty/src/mir/borrowck.rs b/crates/hir-ty/src/mir/borrowck.rs index a0ea1cc5ef7d9..a5dd0182eb658 100644 --- a/crates/hir-ty/src/mir/borrowck.rs +++ b/crates/hir-ty/src/mir/borrowck.rs @@ -240,10 +240,14 @@ fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> Projectio /// Returns a map from basic blocks to the set of locals that might be ever initialized before /// the start of the block. Only `StorageDead` can remove something from this map, and we ignore /// `Uninit` and `drop` and similar after initialization. -fn ever_initialized_map(body: &MirBody) -> ArenaMap> { +fn ever_initialized_map( + db: &dyn HirDatabase, + body: &MirBody, +) -> ArenaMap> { let mut result: ArenaMap> = body.basic_blocks.iter().map(|x| (x.0, ArenaMap::default())).collect(); fn dfs( + db: &dyn HirDatabase, body: &MirBody, b: BasicBlockId, l: LocalId, @@ -267,7 +271,7 @@ fn ever_initialized_map(body: &MirBody) -> ArenaMap ArenaMap spans.push(span), x @ MutabilityReason::Not => *x = MutabilityReason::Mut { spans: vec![span] }, }; - let ever_init_maps = ever_initialized_map(body); + let ever_init_maps = ever_initialized_map(db, body); for (block_id, mut ever_init_map) in ever_init_maps.into_iter() { let block = &body.basic_blocks[block_id]; for statement in &block.statements { From e72618a89755e8408b9937c053e6eca36ff9a9c7 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Wed, 14 Jun 2023 22:27:17 +0000 Subject: [PATCH 233/465] Don't capture &[T; N] when contents isn't read --- .../rustc_hir_typeck/src/expr_use_visitor.rs | 2 +- .../match/patterns-capture-analysis.rs | 25 ++++++++ .../match/patterns-capture-analysis.stderr | 58 +++++++++++++------ 3 files changed, 66 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index e14e8ac2ce000..82d9f03b1451e 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -443,7 +443,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { if matches!((lhs, wild, rhs), (&[], Some(_), &[])) // Arrays have a statically known size, so // there is no need to read their length - || discr_place.place.base_ty.is_array() + || place.place.ty().peel_refs().is_array() { } else { needs_to_be_read = true; diff --git a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs index 41b09ba03702b..c3898afa967f8 100644 --- a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs +++ b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs @@ -87,6 +87,31 @@ fn test_4_should_not_capture_array() { } }; c(); + + // We also do not need to capture an array + // behind a reference (#112607) + let array: &[i32; 3] = &[0; 3]; + let c = #[rustc_capture_analysis] + || { + //~^ First Pass analysis includes: + match array { + [_, _, _] => {} + } + }; + c(); + + // We should still not insert a read if the array is inside an + // irrefutable pattern + struct Foo(T); + let f = &Foo(&[10; 3]); + let c = #[rustc_capture_analysis] + || { + //~^ First Pass analysis includes: + match f { + Foo([_, _, _]) => () + } + }; + c(); } // Testing MultiVariant patterns diff --git a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr index e137af1a0bd40..c3c3f8b847772 100644 --- a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr +++ b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr @@ -109,7 +109,29 @@ LL | | }; | |_____^ error: First Pass analysis includes: - --> $DIR/patterns-capture-analysis.rs:105:5 + --> $DIR/patterns-capture-analysis.rs:95:5 + | +LL | / || { +LL | | +LL | | match array { +LL | | [_, _, _] => {} +LL | | } +LL | | }; + | |_____^ + +error: First Pass analysis includes: + --> $DIR/patterns-capture-analysis.rs:108:5 + | +LL | / || { +LL | | +LL | | match f { +LL | | Foo([_, _, _]) => () +LL | | } +LL | | }; + | |_____^ + +error: First Pass analysis includes: + --> $DIR/patterns-capture-analysis.rs:130:5 | LL | / || { LL | | @@ -121,13 +143,13 @@ LL | | }; | |_____^ | note: Capturing variant[] -> ImmBorrow - --> $DIR/patterns-capture-analysis.rs:108:15 + --> $DIR/patterns-capture-analysis.rs:133:15 | LL | match variant { | ^^^^^^^ error: Min Capture analysis includes: - --> $DIR/patterns-capture-analysis.rs:105:5 + --> $DIR/patterns-capture-analysis.rs:130:5 | LL | / || { LL | | @@ -139,13 +161,13 @@ LL | | }; | |_____^ | note: Min Capture variant[] -> ImmBorrow - --> $DIR/patterns-capture-analysis.rs:108:15 + --> $DIR/patterns-capture-analysis.rs:133:15 | LL | match variant { | ^^^^^^^ error: First Pass analysis includes: - --> $DIR/patterns-capture-analysis.rs:123:5 + --> $DIR/patterns-capture-analysis.rs:148:5 | LL | / || { LL | | @@ -157,13 +179,13 @@ LL | | }; | |_____^ | note: Capturing slice[] -> ImmBorrow - --> $DIR/patterns-capture-analysis.rs:126:15 + --> $DIR/patterns-capture-analysis.rs:151:15 | LL | match slice { | ^^^^^ error: Min Capture analysis includes: - --> $DIR/patterns-capture-analysis.rs:123:5 + --> $DIR/patterns-capture-analysis.rs:148:5 | LL | / || { LL | | @@ -175,13 +197,13 @@ LL | | }; | |_____^ | note: Min Capture slice[] -> ImmBorrow - --> $DIR/patterns-capture-analysis.rs:126:15 + --> $DIR/patterns-capture-analysis.rs:151:15 | LL | match slice { | ^^^^^ error: First Pass analysis includes: - --> $DIR/patterns-capture-analysis.rs:135:5 + --> $DIR/patterns-capture-analysis.rs:160:5 | LL | / || { LL | | @@ -193,13 +215,13 @@ LL | | }; | |_____^ | note: Capturing slice[] -> ImmBorrow - --> $DIR/patterns-capture-analysis.rs:138:15 + --> $DIR/patterns-capture-analysis.rs:163:15 | LL | match slice { | ^^^^^ error: Min Capture analysis includes: - --> $DIR/patterns-capture-analysis.rs:135:5 + --> $DIR/patterns-capture-analysis.rs:160:5 | LL | / || { LL | | @@ -211,13 +233,13 @@ LL | | }; | |_____^ | note: Min Capture slice[] -> ImmBorrow - --> $DIR/patterns-capture-analysis.rs:138:15 + --> $DIR/patterns-capture-analysis.rs:163:15 | LL | match slice { | ^^^^^ error: First Pass analysis includes: - --> $DIR/patterns-capture-analysis.rs:147:5 + --> $DIR/patterns-capture-analysis.rs:172:5 | LL | / || { LL | | @@ -229,13 +251,13 @@ LL | | }; | |_____^ | note: Capturing slice[] -> ImmBorrow - --> $DIR/patterns-capture-analysis.rs:150:15 + --> $DIR/patterns-capture-analysis.rs:175:15 | LL | match slice { | ^^^^^ error: Min Capture analysis includes: - --> $DIR/patterns-capture-analysis.rs:147:5 + --> $DIR/patterns-capture-analysis.rs:172:5 | LL | / || { LL | | @@ -247,13 +269,13 @@ LL | | }; | |_____^ | note: Min Capture slice[] -> ImmBorrow - --> $DIR/patterns-capture-analysis.rs:150:15 + --> $DIR/patterns-capture-analysis.rs:175:15 | LL | match slice { | ^^^^^ error: First Pass analysis includes: - --> $DIR/patterns-capture-analysis.rs:164:5 + --> $DIR/patterns-capture-analysis.rs:189:5 | LL | / || { LL | | @@ -264,5 +286,5 @@ LL | | } LL | | }; | |_____^ -error: aborting due to 16 previous errors +error: aborting due to 18 previous errors From 8a3c21442e7000cb3b70b92c220f71ceeed1abe1 Mon Sep 17 00:00:00 2001 From: ponyii Date: Thu, 15 Jun 2023 17:56:08 +0400 Subject: [PATCH 234/465] refactoring --- crates/ide-db/src/path_transform.rs | 96 ++++++++++++++--------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs index f990fbd0e8f5d..d280185c4cee8 100644 --- a/crates/ide-db/src/path_transform.rs +++ b/crates/ide-db/src/path_transform.rs @@ -17,11 +17,6 @@ struct AstSubsts { lifetimes: Vec, } -struct TypeOrConstSubst { - subst: ast::Type, - to_be_transformed: bool, -} - type LifetimeName = String; /// `PathTransform` substitutes path in SyntaxNodes in bulk. @@ -115,8 +110,10 @@ impl<'a> PathTransform<'a> { Some(hir::GenericDef::Trait(_)) => 1, _ => 0, }; - let type_and_const_substs: FxHashMap<_, _> = self - .generic_def + let mut type_substs: FxHashMap = Default::default(); + let mut const_substs: FxHashMap = Default::default(); + let mut default_types: Vec = Default::default(); + self.generic_def .into_iter() .flat_map(|it| it.type_params(db)) .skip(skip) @@ -127,26 +124,29 @@ impl<'a> PathTransform<'a> { // a default type. If they do, go for that type from `hir` to `ast` so // the resulting change can be applied correctly. .zip(self.substs.types_and_consts.iter().map(Some).chain(std::iter::repeat(None))) - .filter_map(|(k, v)| match (k.split(db), v) { - (_, Some(v)) => { - let subst = - TypeOrConstSubst { subst: v.ty()?.clone(), to_be_transformed: false }; - Some((k, subst)) + .for_each(|(k, v)| match (k.split(db), v) { + (Either::Right(t), Some(v)) => { + if let Some(ty) = v.ty() { + type_substs.insert(t, ty.clone()); + } } (Either::Right(t), None) => { - let default = t.default(db)?; - let subst = TypeOrConstSubst { - subst: ast::make::ty( - &default.display_source_code(db, source_module.into(), false).ok()?, - ) - .clone_for_update(), - to_be_transformed: true, - }; - Some((k, subst)) + if let Some(default) = t.default(db) { + if let Some(default) = + &default.display_source_code(db, source_module.into(), false).ok() + { + type_substs.insert(t, ast::make::ty(default).clone_for_update()); + default_types.push(t); + } + } } - (Either::Left(_), None) => None, // FIXME: get default const value - }) - .collect(); + (Either::Left(c), Some(v)) => { + if let Some(ty) = v.ty() { + const_substs.insert(c, ty.syntax().clone()); + } + } + (Either::Left(_), None) => (), // FIXME: get default const value + }); let lifetime_substs: FxHashMap<_, _> = self .generic_def .into_iter() @@ -154,23 +154,27 @@ impl<'a> PathTransform<'a> { .zip(self.substs.lifetimes.clone()) .filter_map(|(k, v)| Some((k.name(db).display(db.upcast()).to_string(), v.lifetime()?))) .collect(); - Ctx { - type_and_const_substs, + let ctx = Ctx { + type_substs, + const_substs, lifetime_substs, target_module, source_scope: self.source_scope, - } + }; + ctx.transform_default_type_substs(default_types); + ctx } } struct Ctx<'a> { - type_and_const_substs: FxHashMap, + type_substs: FxHashMap, + const_substs: FxHashMap, lifetime_substs: FxHashMap, target_module: hir::Module, source_scope: &'a SemanticsScope<'a>, } -fn preorder(item: &SyntaxNode) -> impl Iterator { +fn postorder(item: &SyntaxNode) -> impl Iterator { item.preorder().filter_map(|event| match event { syntax::WalkEvent::Enter(_) => None, syntax::WalkEvent::Leave(node) => Some(node), @@ -179,31 +183,31 @@ fn preorder(item: &SyntaxNode) -> impl Iterator { impl<'a> Ctx<'a> { fn apply(&self, item: &SyntaxNode) { - for (_, subst) in &self.type_and_const_substs { - if subst.to_be_transformed { - let paths = - preorder(&subst.subst.syntax()).filter_map(ast::Path::cast).collect::>(); - for path in paths { - self.transform_path(path); - } - } - } - // `transform_path` may update a node's parent and that would break the // tree traversal. Thus all paths in the tree are collected into a vec // so that such operation is safe. - let paths = preorder(item).filter_map(ast::Path::cast).collect::>(); + let paths = postorder(item).filter_map(ast::Path::cast).collect::>(); for path in paths { self.transform_path(path); } - preorder(item).filter_map(ast::Lifetime::cast).for_each(|lifetime| { + postorder(item).filter_map(ast::Lifetime::cast).for_each(|lifetime| { if let Some(subst) = self.lifetime_substs.get(&lifetime.syntax().text().to_string()) { ted::replace(lifetime.syntax(), subst.clone_subtree().clone_for_update().syntax()); } }); } + fn transform_default_type_substs(&self, default_types: Vec) { + for k in default_types { + let v = self.type_substs.get(&k).unwrap(); + let paths = postorder(&v.syntax()).filter_map(ast::Path::cast).collect::>(); + for path in paths { + self.transform_path(path); + } + } + } + fn transform_path(&self, path: ast::Path) -> Option<()> { if path.qualifier().is_some() { return None; @@ -220,9 +224,7 @@ impl<'a> Ctx<'a> { match resolution { hir::PathResolution::TypeParam(tp) => { - if let Some(TypeOrConstSubst { subst, .. }) = - self.type_and_const_substs.get(&tp.merge()) - { + if let Some(subst) = self.type_substs.get(&tp) { let parent = path.syntax().parent()?; if let Some(parent) = ast::Path::cast(parent.clone()) { // Path inside path means that there is an associated @@ -290,10 +292,8 @@ impl<'a> Ctx<'a> { ted::replace(path.syntax(), res.syntax()) } hir::PathResolution::ConstParam(cp) => { - if let Some(TypeOrConstSubst { subst, .. }) = - self.type_and_const_substs.get(&cp.merge()) - { - ted::replace(path.syntax(), subst.clone_subtree().clone_for_update().syntax()); + if let Some(subst) = self.const_substs.get(&cp) { + ted::replace(path.syntax(), subst.clone_subtree().clone_for_update()); } } hir::PathResolution::Local(_) From 903b3d36db81cad9d1e23b62f09d655d93aad1ac Mon Sep 17 00:00:00 2001 From: klensy Date: Thu, 15 Jun 2023 18:58:57 +0300 Subject: [PATCH 235/465] cleanup more azure leftovers --- src/bootstrap/util.rs | 2 -- src/ci/docker/run.sh | 2 -- src/tools/build_helper/src/ci.rs | 6 +----- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 7e29f671f028b..1ec49f80d632e 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -159,8 +159,6 @@ pub fn symlink_dir(config: &Config, original: &Path, link: &Path) -> io::Result< pub enum CiEnv { /// Not a CI environment. None, - /// The Azure Pipelines environment, for Linux (including Docker), Windows, and macOS builds. - AzurePipelines, /// The GitHub Actions environment, for Linux (including Docker), Windows and macOS builds. GitHubActions, } diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 2fe3438e0fe8a..0a098467d9493 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -254,8 +254,6 @@ docker \ --env DEPLOY \ --env DEPLOY_ALT \ --env CI \ - --env TF_BUILD \ - --env BUILD_SOURCEBRANCHNAME \ --env GITHUB_ACTIONS \ --env GITHUB_REF \ --env TOOLSTATE_REPO_ACCESS_TOKEN \ diff --git a/src/tools/build_helper/src/ci.rs b/src/tools/build_helper/src/ci.rs index d106e5b339b2f..893195b69c219 100644 --- a/src/tools/build_helper/src/ci.rs +++ b/src/tools/build_helper/src/ci.rs @@ -4,8 +4,6 @@ use std::process::Command; pub enum CiEnv { /// Not a CI environment. None, - /// The Azure Pipelines environment, for Linux (including Docker), Windows, and macOS builds. - AzurePipelines, /// The GitHub Actions environment, for Linux (including Docker), Windows and macOS builds. GitHubActions, } @@ -13,9 +11,7 @@ pub enum CiEnv { impl CiEnv { /// Obtains the current CI environment. pub fn current() -> CiEnv { - if std::env::var("TF_BUILD").map_or(false, |e| e == "True") { - CiEnv::AzurePipelines - } else if std::env::var("GITHUB_ACTIONS").map_or(false, |e| e == "true") { + if std::env::var("GITHUB_ACTIONS").map_or(false, |e| e == "true") { CiEnv::GitHubActions } else { CiEnv::None From 218575a8aebbe0aedcf127954644db24724a8e2f Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 15 Jun 2023 20:45:20 -0400 Subject: [PATCH 236/465] Working, but requires a patched rustc --- build_sysroot/build_sysroot.sh | 4 ++-- test.sh | 15 +++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/build_sysroot/build_sysroot.sh b/build_sysroot/build_sysroot.sh index 063219aabd27d..6aea9b94b48ef 100755 --- a/build_sysroot/build_sysroot.sh +++ b/build_sysroot/build_sysroot.sh @@ -30,9 +30,9 @@ mkdir -p sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ cp -r target/$TARGET_TRIPLE/$sysroot_channel/deps/* sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ # Since we can't override the sysroot for the UI tests anymore, we create a new toolchain and manually overwrite the sysroot directory. -my_toolchain_dir=$HOME/.rustup/toolchains/codegen_gcc_ui_tests -rm -rf $my_toolchain_dir rust_toolchain=$(cat ../rust-toolchain | grep channel | sed 's/channel = "\(.*\)"/\1/') +my_toolchain_dir=$HOME/.rustup/toolchains/codegen_gcc_ui_tests-$rust_toolchain-$TARGET_TRIPLE +rm -rf $my_toolchain_dir cp -r $HOME/.rustup/toolchains/$rust_toolchain-$TARGET_TRIPLE $my_toolchain_dir rm -rf $my_toolchain_dir/lib/rustlib/$TARGET_TRIPLE/ cp -r ../build_sysroot/sysroot/* $my_toolchain_dir diff --git a/test.sh b/test.sh index 6213ed49183c2..2e485b927393e 100755 --- a/test.sh +++ b/test.sh @@ -209,11 +209,12 @@ function setup_rustc() { cd rust git fetch git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(') + git am ../0001-Allow-overwriting-the-sysroot-compile-flag-via-rustc.patch export RUSTFLAGS= rm config.toml || true - my_toolchain_dir=$HOME/.rustup/toolchains/codegen_gcc_ui_tests + my_toolchain_dir=$HOME/.rustup/toolchains/codegen_gcc_ui_tests-$rust_toolchain-$TARGET_TRIPLE cat > config.toml < Date: Thu, 15 Jun 2023 20:51:29 -0400 Subject: [PATCH 237/465] Handle alignment of the load instruction --- src/builder.rs | 19 ++++++++++++++----- src/intrinsic/simd.rs | 9 ++++++--- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index f2775421ccd08..bb23524d8af48 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -729,17 +729,25 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { unimplemented!(); } - fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, _align: Align) -> RValue<'gcc> { + fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { let block = self.llbb(); let function = block.get_function(); // NOTE: instead of returning the dereference here, we have to assign it to a variable in // the current basic block. Otherwise, it could be used in another basic block, causing a // dereference after a drop, for instance. - // TODO(antoyo): handle align of the load instruction. - let ptr = self.context.new_cast(None, ptr, pointee_ty.make_pointer()); + // FIXME(antoyo): this check that we don't call get_aligned() a second time on a type. + // Ideally, we shouldn't need to do this check. + let aligned_type = + if pointee_ty == self.cx.u128_type || pointee_ty == self.cx.i128_type { + pointee_ty + } + else { + pointee_ty.get_aligned(align.bytes()) + }; + let ptr = self.context.new_cast(None, ptr, aligned_type.make_pointer()); let deref = ptr.dereference(None).to_rvalue(); unsafe { RETURN_VALUE_COUNT += 1 }; - let loaded_value = function.new_local(None, pointee_ty, &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT })); + let loaded_value = function.new_local(None, aligned_type, &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT })); block.add_assignment(None, loaded_value, deref); loaded_value.to_rvalue() } @@ -1857,7 +1865,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { #[cfg(feature="master")] let (cond, element_type) = { - let then_val_vector_type = then_val.get_type().dyncast_vector().expect("vector type"); + // TODO(antoyo): dyncast_vector should not require a call to unqualified. + let then_val_vector_type = then_val.get_type().unqualified().dyncast_vector().expect("vector type"); let then_val_element_type = then_val_vector_type.get_element_type(); let then_val_element_size = then_val_element_type.get_size(); diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index 36b9c9b636412..9115cf971196e 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -346,7 +346,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( // endian and MSB-first for big endian. let vector = args[0].immediate(); - let vector_type = vector.get_type().dyncast_vector().expect("vector type"); + // TODO(antoyo): dyncast_vector should not require a call to unqualified. + let vector_type = vector.get_type().unqualified().dyncast_vector().expect("vector type"); let elem_type = vector_type.get_element_type(); let expected_int_bits = in_len.max(8); @@ -853,7 +854,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( (true, true) => { // Algorithm from: https://codereview.stackexchange.com/questions/115869/saturated-signed-addition // TODO(antoyo): improve using conditional operators if possible. - let arg_type = lhs.get_type(); + // TODO(antoyo): dyncast_vector should not require a call to unqualified. + let arg_type = lhs.get_type().unqualified(); // TODO(antoyo): convert lhs and rhs to unsigned. let sum = lhs + rhs; let vector_type = arg_type.dyncast_vector().expect("vector type"); @@ -883,7 +885,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( res & cmp }, (true, false) => { - let arg_type = lhs.get_type(); + // TODO(antoyo): dyncast_vector should not require a call to unqualified. + let arg_type = lhs.get_type().unqualified(); // TODO(antoyo): this uses the same algorithm from saturating add, but add the // negative of the right operand. Find a proper subtraction algorithm. let rhs = bx.context.new_unary_op(None, UnaryOp::Minus, arg_type, rhs); From 8560b07ebfe177049a3790f4452196250b1cfb06 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 15 Jun 2023 20:52:45 -0400 Subject: [PATCH 238/465] TO REVERT: temporarily add a patch for rustc --- ...g-the-sysroot-compile-flag-via-rustc.patch | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 0001-Allow-overwriting-the-sysroot-compile-flag-via-rustc.patch diff --git a/0001-Allow-overwriting-the-sysroot-compile-flag-via-rustc.patch b/0001-Allow-overwriting-the-sysroot-compile-flag-via-rustc.patch new file mode 100644 index 0000000000000..f7860bd9105be --- /dev/null +++ b/0001-Allow-overwriting-the-sysroot-compile-flag-via-rustc.patch @@ -0,0 +1,27 @@ +From 8d5e85607d3d52f920990334ae1cfa9798ad9259 Mon Sep 17 00:00:00 2001 +From: Antoni Boucher +Date: Thu, 8 Jun 2023 17:27:34 -0400 +Subject: [PATCH] Allow overwriting the sysroot compile flag via --rustc-args + +--- + src/tools/compiletest/src/runtest.rs | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs +index 6582b534488..d16a7d66154 100644 +--- a/src/tools/compiletest/src/runtest.rs ++++ b/src/tools/compiletest/src/runtest.rs +@@ -1951,7 +1951,9 @@ fn make_compile_args( + rustc.arg("-Ztranslate-remapped-path-to-local-path=no"); + + // Optionally prevent default --sysroot if specified in test compile-flags. +- if !self.props.compile_flags.iter().any(|flag| flag.starts_with("--sysroot")) { ++ if !self.props.compile_flags.iter().any(|flag| flag.starts_with("--sysroot")) ++ && !self.config.host_rustcflags.iter().any(|flag| flag == "--sysroot") ++ { + // In stage 0, make sure we use `stage0-sysroot` instead of the bootstrap sysroot. + rustc.arg("--sysroot").arg(&self.config.sysroot_base); + } +-- +2.41.0 + From 8cc55bfee69ad2642f540b26ac2b9257a68469fc Mon Sep 17 00:00:00 2001 From: MysticNebula70 <34984380+AlPha5130@users.noreply.github.com> Date: Fri, 16 Jun 2023 18:22:43 +0800 Subject: [PATCH 239/465] doc: remove duplicated words --- docs/user/manual.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index 98d99bae92ae9..b5c095fd9d87d 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -244,7 +244,7 @@ Any other tools or libraries you will need to acquire from Flatpak. Prerequisites: You have installed the <>. -To use `rust-analyzer`, you need to install and enable one of the two popular two popular LSP client implementations for Emacs, https://github.com/joaotavora/eglot[Eglot] or https://github.com/emacs-lsp/lsp-mode[LSP Mode]. Both enable `rust-analyzer` by default in rust buffers if it is available. +To use `rust-analyzer`, you need to install and enable one of the two popular LSP client implementations for Emacs, https://github.com/joaotavora/eglot[Eglot] or https://github.com/emacs-lsp/lsp-mode[LSP Mode]. Both enable `rust-analyzer` by default in rust buffers if it is available. ==== Eglot From 18b86468b8c47bb3d4a6b6d1068947cae5cb7c1d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 16 Jun 2023 14:56:31 +0200 Subject: [PATCH 240/465] slice::from_raw_parts: mention no-wrap-around condition --- library/core/src/slice/raw.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index 052fd34d0b6b7..48a6eb03b5e1c 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -32,7 +32,8 @@ use crate::ptr; /// * The memory referenced by the returned slice must not be mutated for the duration /// of lifetime `'a`, except inside an `UnsafeCell`. /// -/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. +/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// /// # Caveat @@ -125,7 +126,8 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] /// (not derived from the return value) for the duration of lifetime `'a`. /// Both read and write accesses are forbidden. /// -/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. +/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// /// [valid]: ptr#safety @@ -179,15 +181,16 @@ pub const fn from_mut(s: &mut T) -> &mut [T] { /// the last element, such that the offset from the end to the start pointer is /// the length of the slice. /// -/// * The range must contain `N` consecutive properly initialized values of type `T`: +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. /// -/// * The entire memory range of this slice must be contained within a single allocated object! -/// Slices can never span across multiple allocated objects. +/// * The range must contain `N` consecutive properly initialized values of type `T`. /// /// * The memory referenced by the returned slice must not be mutated for the duration /// of lifetime `'a`, except inside an `UnsafeCell`. /// -/// * The total length of the range must be no larger than `isize::MAX`. +/// * The total length of the range must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// /// Note that a range created from [`slice::as_ptr_range`] fulfills these requirements. @@ -247,16 +250,17 @@ pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] { /// the last element, such that the offset from the end to the start pointer is /// the length of the slice. /// -/// * The range must contain `N` consecutive properly initialized values of type `T`: +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. /// -/// * The entire memory range of this slice must be contained within a single allocated object! -/// Slices can never span across multiple allocated objects. +/// * The range must contain `N` consecutive properly initialized values of type `T`. /// /// * The memory referenced by the returned slice must not be accessed through any other pointer /// (not derived from the return value) for the duration of lifetime `'a`. /// Both read and write accesses are forbidden. /// -/// * The total length of the range must be no larger than `isize::MAX`. +/// * The total length of the range must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// /// Note that a range created from [`slice::as_mut_ptr_range`] fulfills these requirements. From 527dfede48522a062a41750fe17c1e8b729855e4 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Mon, 1 May 2023 00:04:11 +0330 Subject: [PATCH 241/465] Support `Pointee` trait --- Cargo.lock | 47 ++++++++++++++++---------- crates/hir-ty/Cargo.toml | 8 ++--- crates/hir-ty/src/chalk_db.rs | 2 ++ crates/hir-ty/src/tests/simple.rs | 16 +++++++++ crates/ide/src/inlay_hints/chaining.rs | 12 +++---- crates/test-utils/src/fixture.rs | 4 +++ crates/test-utils/src/minicore.rs | 9 +++++ 7 files changed, 70 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 322a67383b030..50c81ca279eee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,21 +177,21 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chalk-derive" -version = "0.89.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea176c50987dc4765961aa165001e8eb5a722a26308c5797a47303ea91686aab" +checksum = "c59178fded594fe78c47b841520e5a4399d00fe15fffee19b945958a878cd02d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.15", "synstructure", ] [[package]] name = "chalk-ir" -version = "0.89.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473b480241695428c14e8f84f1c9a47ef232450a50faf3a4041e5c9dc11e0a3b" +checksum = "8824be92876823b828d551bb792f79eb1f69c69d1948abf69fccbf84e448e57b" dependencies = [ "bitflags 1.3.2", "chalk-derive", @@ -200,9 +200,9 @@ dependencies = [ [[package]] name = "chalk-recursive" -version = "0.89.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6764b4fe67cac3a3758185084efbfbd39bf0352795824ba849ddd2b64cd4bb28" +checksum = "1e110d1260809c238072d1c8ef84060e39983e8ea9d4c6f74b19b0ebbf8904dc" dependencies = [ "chalk-derive", "chalk-ir", @@ -213,9 +213,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.89.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55a7e6160966eceb6e7dcc2f479a2af4c477aaf5bccbc640d82515995ab1a6cc" +checksum = "12200b19abf4b0633095f7bd099f3ef609d314754b6adb358c68cc04d10589e5" dependencies = [ "chalk-derive", "chalk-ir", @@ -327,7 +327,7 @@ checksum = "f3cdeb9ec472d588e539a818b2dee436825730da08ad0017c4b1a17676bdc8b7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1577,7 +1577,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1636,7 +1636,7 @@ checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1659,7 +1659,7 @@ checksum = "395627de918015623b32e7669714206363a7fc00382bf477e72c1f7533e8eafc" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1729,15 +1729,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "synstructure" -version = "0.12.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.15", "unicode-xid", ] @@ -1810,7 +1821,7 @@ checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1912,7 +1923,7 @@ checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index 6ca0dbb850399..c8bea34507c71 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -22,10 +22,10 @@ either = "1.7.0" tracing = "0.1.35" rustc-hash = "1.1.0" scoped-tls = "1.0.0" -chalk-solve = { version = "0.89.0", default-features = false } -chalk-ir = "0.89.0" -chalk-recursive = { version = "0.89.0", default-features = false } -chalk-derive = "0.89.0" +chalk-solve = { version = "0.91.0", default-features = false } +chalk-ir = "0.91.0" +chalk-recursive = { version = "0.91.0", default-features = false } +chalk-derive = "0.91.0" la-arena = { version = "0.3.0", path = "../../lib/la-arena" } once_cell = "1.17.0" triomphe.workspace = true diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs index 2a31e5cab8a2c..5dd8e2719a238 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -592,6 +592,7 @@ fn well_known_trait_from_lang_item(item: LangItem) -> Option { LangItem::Unpin => WellKnownTrait::Unpin, LangItem::Unsize => WellKnownTrait::Unsize, LangItem::Tuple => WellKnownTrait::Tuple, + LangItem::PointeeTrait => WellKnownTrait::Pointee, _ => return None, }) } @@ -612,6 +613,7 @@ fn lang_item_from_well_known_trait(trait_: WellKnownTrait) -> LangItem { WellKnownTrait::Tuple => LangItem::Tuple, WellKnownTrait::Unpin => LangItem::Unpin, WellKnownTrait::Unsize => LangItem::Unsize, + WellKnownTrait::Pointee => LangItem::PointeeTrait, } } diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs index fb0aa2faf1f24..a0ff628435f3d 100644 --- a/crates/hir-ty/src/tests/simple.rs +++ b/crates/hir-ty/src/tests/simple.rs @@ -3497,6 +3497,22 @@ fn func() { ); } +#[test] +fn pointee_trait() { + check_types( + r#" +//- minicore: pointee +use core::ptr::Pointee; +fn func() { + let x: ::Metadata; + //^ () + let x: <[u8] as Pointee>::Metadata; + //^ usize +} + "#, + ); +} + // FIXME #[test] fn castable_to() { diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs index 6603f6e55b748..84eac16b9f93f 100644 --- a/crates/ide/src/inlay_hints/chaining.rs +++ b/crates/ide/src/inlay_hints/chaining.rs @@ -474,7 +474,7 @@ fn main() { file_id: FileId( 1, ), - range: 9286..9294, + range: 9287..9295, }, ), tooltip: "", @@ -487,7 +487,7 @@ fn main() { file_id: FileId( 1, ), - range: 9318..9322, + range: 9319..9323, }, ), tooltip: "", @@ -511,7 +511,7 @@ fn main() { file_id: FileId( 1, ), - range: 9286..9294, + range: 9287..9295, }, ), tooltip: "", @@ -524,7 +524,7 @@ fn main() { file_id: FileId( 1, ), - range: 9318..9322, + range: 9319..9323, }, ), tooltip: "", @@ -548,7 +548,7 @@ fn main() { file_id: FileId( 1, ), - range: 9286..9294, + range: 9287..9295, }, ), tooltip: "", @@ -561,7 +561,7 @@ fn main() { file_id: FileId( 1, ), - range: 9318..9322, + range: 9319..9323, }, ), tooltip: "", diff --git a/crates/test-utils/src/fixture.rs b/crates/test-utils/src/fixture.rs index 05f32f8e51ea4..602baed370700 100644 --- a/crates/test-utils/src/fixture.rs +++ b/crates/test-utils/src/fixture.rs @@ -387,6 +387,10 @@ impl MiniCore { } } + if !active_regions.is_empty() { + panic!("unclosed regions: {:?} Add an `endregion` comment", active_regions); + } + for flag in &self.valid_flags { if !seen_regions.iter().any(|it| it == flag) { panic!("unused minicore flag: {flag:?}"); diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 3dc2d9f28d816..266bc2391f158 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -42,6 +42,7 @@ //! panic: fmt //! phantom_data: //! pin: +//! pointee: //! range: //! result: //! send: sized @@ -368,6 +369,14 @@ pub mod ptr { *dst = src; } // endregion:drop + + // region:pointee + #[lang = "pointee_trait"] + pub trait Pointee { + #[lang = "metadata_type"] + type Metadata; + } + // endregion:pointee } pub mod ops { From fe4aec1c4da0e92dbb727ebe5a2ee8951a6a45d9 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 16 Jun 2023 13:45:03 +0000 Subject: [PATCH 242/465] Simplify `Span::source_callee` impl --- compiler/rustc_span/src/lib.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index eae3f0fa041dd..aed1fcd3d5760 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -65,11 +65,11 @@ use rustc_data_structures::sync::{Lock, Lrc}; use std::borrow::Cow; use std::cmp::{self, Ordering}; -use std::fmt; use std::hash::Hash; use std::ops::{Add, Range, Sub}; use std::path::{Path, PathBuf}; use std::str::FromStr; +use std::{fmt, iter}; use md5::Digest; use md5::Md5; @@ -733,12 +733,15 @@ impl Span { /// else returns the `ExpnData` for the macro definition /// corresponding to the source callsite. pub fn source_callee(self) -> Option { - fn source_callee(expn_data: ExpnData) -> ExpnData { - let next_expn_data = expn_data.call_site.ctxt().outer_expn_data(); - if !next_expn_data.is_root() { source_callee(next_expn_data) } else { expn_data } - } let expn_data = self.ctxt().outer_expn_data(); - if !expn_data.is_root() { Some(source_callee(expn_data)) } else { None } + + // Create an iterator of call site expansions + iter::successors(Some(expn_data), |expn_data| { + Some(expn_data.call_site.ctxt().outer_expn_data()) + }) + // Find the last expansion which is not root + .take_while(|expn_data| !expn_data.is_root()) + .last() } /// Checks if a span is "internal" to a macro in which `#[unstable]` @@ -777,7 +780,7 @@ impl Span { pub fn macro_backtrace(mut self) -> impl Iterator { let mut prev_span = DUMMY_SP; - std::iter::from_fn(move || { + iter::from_fn(move || { loop { let expn_data = self.ctxt().outer_expn_data(); if expn_data.is_root() { From 0f7174a02ae1c07576d00933b5ae69ec4a12573f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 31 May 2023 17:10:34 +0000 Subject: [PATCH 243/465] Re-use the deref-pattern recursion instead of duplicating the logic --- .../src/thir/pattern/const_to_pat.rs | 85 ++++++------------- 1 file changed, 26 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 7976b148f75e2..a2e00d3bfc57d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -359,6 +359,15 @@ impl<'tcx> ConstToPat<'tcx> { def.non_enum_variant().fields.iter().map(|field| field.ty(self.tcx(), substs)), ))?, }, + ty::Slice(elem_ty) => PatKind::Slice { + prefix: cv + .unwrap_branch() + .iter() + .map(|val| self.recur(*val, *elem_ty, false)) + .collect::>()?, + slice: None, + suffix: Box::new([]), + }, ty::Array(elem_ty, _) => PatKind::Array { prefix: cv .unwrap_branch() @@ -372,58 +381,6 @@ impl<'tcx> ConstToPat<'tcx> { // `&str` is represented as a valtree, let's keep using this // optimization for now. ty::Str => PatKind::Constant { value: mir::ConstantKind::Ty(tcx.mk_const(cv, ty)) }, - // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when - // matching against references, you can only use byte string literals. - // The typechecker has a special case for byte string literals, by treating them - // as slices. This means we turn `&[T; N]` constants into slice patterns, which - // has no negative effects on pattern matching, even if we're actually matching on - // arrays. - ty::Array(elem_ty, _) if !self.treat_byte_string_as_slice => { - let old = self.behind_reference.replace(true); - // References have the same valtree representation as their pointee. - let array = cv; - let val = PatKind::Deref { - subpattern: Box::new(Pat { - kind: PatKind::Array { - prefix: array.unwrap_branch() - .iter() - .map(|val| self.recur(*val, elem_ty, false)) - .collect::>()?, - slice: None, - suffix: Box::new([]), - }, - span, - ty: tcx.mk_slice(elem_ty), - }), - }; - self.behind_reference.set(old); - val - } - ty::Array(elem_ty, _) | - // Cannot merge this with the catch all branch below, because the `const_deref` - // changes the type from slice to array, we need to keep the original type in the - // pattern. - ty::Slice(elem_ty) => { - let old = self.behind_reference.replace(true); - // References have the same valtree representation as their pointee. - let array = cv; - let val = PatKind::Deref { - subpattern: Box::new(Pat { - kind: PatKind::Slice { - prefix: array.unwrap_branch() - .iter() - .map(|val| self.recur(*val, elem_ty, false)) - .collect::>()?, - slice: None, - suffix: Box::new([]), - }, - span, - ty: tcx.mk_slice(elem_ty), - }), - }; - self.behind_reference.set(old); - val - } // Backwards compatibility hack: support references to non-structural types, // but hard error if we aren't behind a double reference. We could just use // the fallback code path below, but that would allow *more* of this fishy @@ -431,11 +388,9 @@ impl<'tcx> ConstToPat<'tcx> { // instead of a hard error. ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => { if self.behind_reference.get() { - if !self.saw_const_match_error.get() - && !self.saw_const_match_lint.get() - { - self.saw_const_match_lint.set(true); - tcx.emit_spanned_lint( + if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() { + self.saw_const_match_lint.set(true); + tcx.emit_spanned_lint( lint::builtin::INDIRECT_STRUCTURAL_MATCH, self.id, span, @@ -456,7 +411,7 @@ impl<'tcx> ConstToPat<'tcx> { // convert the dereferenced constant to a pattern that is the sub-pattern of the // deref pattern. _ => { - if !pointee_ty.is_sized(tcx, param_env) { + if !pointee_ty.is_sized(tcx, param_env) && !pointee_ty.is_slice() { let err = UnsizedPattern { span, non_sm_ty: *pointee_ty }; tcx.sess.emit_err(err); @@ -464,8 +419,20 @@ impl<'tcx> ConstToPat<'tcx> { PatKind::Wild } else { let old = self.behind_reference.replace(true); + // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when + // matching against references, you can only use byte string literals. + // The typechecker has a special case for byte string literals, by treating them + // as slices. This means we turn `&[T; N]` constants into slice patterns, which + // has no negative effects on pattern matching, even if we're actually matching on + // arrays. + let pointee_ty = match *pointee_ty.kind() { + ty::Array(elem_ty, _) if self.treat_byte_string_as_slice => { + tcx.mk_slice(elem_ty) + } + _ => *pointee_ty, + }; // References have the same valtree representation as their pointee. - let subpattern = self.recur(cv, *pointee_ty, false)?; + let subpattern = self.recur(cv, pointee_ty, false)?; self.behind_reference.set(old); PatKind::Deref { subpattern } } From 7e08933a26453b3075bc870814fa35bd263ef9c2 Mon Sep 17 00:00:00 2001 From: ponyii Date: Thu, 15 Jun 2023 19:04:59 +0400 Subject: [PATCH 244/465] the "implement missing members" assist's const transformation patched --- .../src/handlers/add_missing_impl_members.rs | 35 ++++++++++++++ .../ide-assists/src/handlers/inline_call.rs | 3 +- crates/ide-db/src/path_transform.rs | 47 ++++++++++++++----- 3 files changed, 70 insertions(+), 15 deletions(-) diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs index e827f277b1e1d..b61f052a1e061 100644 --- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -423,8 +423,13 @@ impl<'x, 'y, T, V, U: Default> Trait<'x, 'y, T, V, U> for () { check_assist( add_missing_default_members, r#" +struct Bar { + bar: [i32, N] +} + trait Foo { fn get_n_sq(&self, arg: &T) -> usize { N * N } + fn get_array(&self, arg: Bar) -> [i32; N] { [1; N] } } struct S { @@ -435,8 +440,13 @@ impl Foo for S { $0 }"#, r#" +struct Bar { + bar: [i32, N] +} + trait Foo { fn get_n_sq(&self, arg: &T) -> usize { N * N } + fn get_array(&self, arg: Bar) -> [i32; N] { [1; N] } } struct S { @@ -445,6 +455,31 @@ struct S { impl Foo for S { $0fn get_n_sq(&self, arg: &Z) -> usize { X * X } + + fn get_array(&self, arg: Bar) -> [i32; X] { [1; X] } +}"#, + ) + } + + #[test] + fn test_const_substitution_2() { + check_assist( + add_missing_default_members, + r#" +trait Foo { + fn get_sum(&self, arg: &T) -> usize { N + M } +} + +impl Foo<42, {20 + 22}, X> for () { + $0 +}"#, + r#" +trait Foo { + fn get_sum(&self, arg: &T) -> usize { N + M } +} + +impl Foo<42, {20 + 22}, X> for () { + $0fn get_sum(&self, arg: &X) -> usize { 42 + {20 + 22} } }"#, ) } diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs index 28d815e81b49d..797180fa18995 100644 --- a/crates/ide-assists/src/handlers/inline_call.rs +++ b/crates/ide-assists/src/handlers/inline_call.rs @@ -958,7 +958,6 @@ fn main() { ); } - // FIXME: const generics aren't being substituted, this is blocked on better support for them #[test] fn inline_substitutes_generics() { check_assist( @@ -982,7 +981,7 @@ fn foo() { fn bar() {} fn main() { - bar::(); + bar::(); } "#, ); diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs index d280185c4cee8..73e6a920ee4cd 100644 --- a/crates/ide-db/src/path_transform.rs +++ b/crates/ide-db/src/path_transform.rs @@ -11,12 +11,15 @@ use syntax::{ #[derive(Default)] struct AstSubsts { - // ast::TypeArgs stands in fact for both type and const params - // as consts declared elsewhere look just like type params. - types_and_consts: Vec, + types_and_consts: Vec, lifetimes: Vec, } +enum TypeOrConst { + Either(ast::TypeArg), // indistinguishable type or const param + Const(ast::ConstArg), +} + type LifetimeName = String; /// `PathTransform` substitutes path in SyntaxNodes in bulk. @@ -125,27 +128,38 @@ impl<'a> PathTransform<'a> { // the resulting change can be applied correctly. .zip(self.substs.types_and_consts.iter().map(Some).chain(std::iter::repeat(None))) .for_each(|(k, v)| match (k.split(db), v) { - (Either::Right(t), Some(v)) => { + (Either::Right(k), Some(TypeOrConst::Either(v))) => { if let Some(ty) = v.ty() { - type_substs.insert(t, ty.clone()); + type_substs.insert(k, ty.clone()); } } - (Either::Right(t), None) => { - if let Some(default) = t.default(db) { + (Either::Right(k), None) => { + if let Some(default) = k.default(db) { if let Some(default) = &default.display_source_code(db, source_module.into(), false).ok() { - type_substs.insert(t, ast::make::ty(default).clone_for_update()); - default_types.push(t); + type_substs.insert(k, ast::make::ty(default).clone_for_update()); + default_types.push(k); } } } - (Either::Left(c), Some(v)) => { + (Either::Left(k), Some(TypeOrConst::Either(v))) => { if let Some(ty) = v.ty() { - const_substs.insert(c, ty.syntax().clone()); + const_substs.insert(k, ty.syntax().clone()); + } + } + (Either::Left(k), Some(TypeOrConst::Const(v))) => { + if let Some(expr) = v.expr() { + // FIXME: expressions in curly brackets can cause ambiguity after insertion + // (e.g. `N * 2` -> `{1 + 1} * 2`; it's unclear whether `{1 + 1}` + // is a standalone statement or a part of another expresson) + // and sometimes require slight modifications; see + // https://doc.rust-lang.org/reference/statements.html#expression-statements + const_substs.insert(k, expr.syntax().clone()); } } (Either::Left(_), None) => (), // FIXME: get default const value + _ => (), // ignore mismatching params }); let lifetime_substs: FxHashMap<_, _> = self .generic_def @@ -201,6 +215,9 @@ impl<'a> Ctx<'a> { fn transform_default_type_substs(&self, default_types: Vec) { for k in default_types { let v = self.type_substs.get(&k).unwrap(); + // `transform_path` may update a node's parent and that would break the + // tree traversal. Thus all paths in the tree are collected into a vec + // so that such operation is safe. let paths = postorder(&v.syntax()).filter_map(ast::Path::cast).collect::>(); for path in paths { self.transform_path(path); @@ -326,8 +343,12 @@ fn get_type_args_from_arg_list(generic_arg_list: ast::GenericArgList) -> Option< // Const params are marked as consts on definition only, // being passed to the trait they are indistguishable from type params; // anyway, we don't really need to distinguish them here. - ast::GenericArg::TypeArg(type_or_const_arg) => { - result.types_and_consts.push(type_or_const_arg) + ast::GenericArg::TypeArg(type_arg) => { + result.types_and_consts.push(TypeOrConst::Either(type_arg)) + } + // Some const values are recognized correctly. + ast::GenericArg::ConstArg(const_arg) => { + result.types_and_consts.push(TypeOrConst::Const(const_arg)); } ast::GenericArg::LifetimeArg(l_arg) => result.lifetimes.push(l_arg), _ => (), From 3484b5a11607d09f88e73f956f7037386696791b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 16 Jun 2023 18:41:06 +0200 Subject: [PATCH 245/465] internal: Do not allocate unnecessarily when importing macros from parent modules --- crates/hir-def/src/item_scope.rs | 4 --- crates/hir-def/src/nameres/collector.rs | 44 +++++++++++++++++++++---- lib/la-arena/src/lib.rs | 6 ++++ 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index 3ed321d189d36..2001fb29a9e35 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -334,10 +334,6 @@ impl ItemScope { ) } - pub(crate) fn collect_legacy_macros(&self) -> FxHashMap> { - self.legacy_macros.clone() - } - /// Marks everything that is not a procedural macro as private to `this_module`. pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) { self.types diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 97481ea7df776..62fb3c7882cd3 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -3,7 +3,7 @@ //! `DefCollector::collect` contains the fixed-point iteration loop which //! resolves imports and expands macros. -use std::{iter, mem}; +use std::{cmp::Ordering, iter, mem}; use base_db::{CrateId, Dependency, Edition, FileId}; use cfg::{CfgExpr, CfgOptions}; @@ -1928,9 +1928,13 @@ impl ModCollector<'_, '_> { let modules = &mut def_map.modules; let res = modules.alloc(ModuleData::new(origin, vis)); modules[res].parent = Some(self.module_id); - for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() { - for &mac in &mac { - modules[res].scope.define_legacy_macro(name.clone(), mac); + + if let Some((target, source)) = Self::borrow_modules(modules.as_mut(), res, self.module_id) + { + for (name, macs) in source.scope.legacy_macros() { + for &mac in macs { + target.scope.define_legacy_macro(name.clone(), mac); + } } } modules[self.module_id].children.insert(name.clone(), res); @@ -2226,14 +2230,40 @@ impl ModCollector<'_, '_> { } fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) { - let macros = self.def_collector.def_map[module_id].scope.collect_legacy_macros(); - for (name, macs) in macros { + let Some((source, target)) = Self::borrow_modules(self.def_collector.def_map.modules.as_mut(), module_id, self.module_id) else { + return + }; + + for (name, macs) in source.scope.legacy_macros() { macs.last().map(|&mac| { - self.def_collector.define_legacy_macro(self.module_id, name.clone(), mac) + target.scope.define_legacy_macro(name.clone(), mac); }); } } + /// Mutably borrow two modules at once, retu + fn borrow_modules( + modules: &mut [ModuleData], + a: LocalModuleId, + b: LocalModuleId, + ) -> Option<(&mut ModuleData, &mut ModuleData)> { + let a = a.into_raw().into_u32() as usize; + let b = b.into_raw().into_u32() as usize; + + let (a, b) = match a.cmp(&b) { + Ordering::Equal => return None, + Ordering::Less => { + let (prefix, b) = modules.split_at_mut(b); + (&mut prefix[a], &mut b[0]) + } + Ordering::Greater => { + let (prefix, a) = modules.split_at_mut(a); + (&mut a[0], &mut prefix[b]) + } + }; + Some((a, b)) + } + fn is_cfg_enabled(&self, cfg: &CfgExpr) -> bool { self.def_collector.cfg_options.check(cfg) != Some(false) } diff --git a/lib/la-arena/src/lib.rs b/lib/la-arena/src/lib.rs index 5107f294394bc..f39c3a3e4ca12 100644 --- a/lib/la-arena/src/lib.rs +++ b/lib/la-arena/src/lib.rs @@ -451,6 +451,12 @@ impl Arena { } } +impl AsMut<[T]> for Arena { + fn as_mut(&mut self) -> &mut [T] { + self.data.as_mut() + } +} + impl Default for Arena { fn default() -> Arena { Arena { data: Vec::new() } From bd093d1ccda5f0c9cac75d916eca4b7673a26347 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 16 Jun 2023 18:41:25 +0200 Subject: [PATCH 246/465] Sort methods in generate_delegate_methods listing --- .../src/handlers/generate_delegate_methods.rs | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/crates/ide-assists/src/handlers/generate_delegate_methods.rs index 3667fc375b439..b68c766e6477a 100644 --- a/crates/ide-assists/src/handlers/generate_delegate_methods.rs +++ b/crates/ide-assists/src/handlers/generate_delegate_methods.rs @@ -72,29 +72,27 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' let krate = ty.krate(ctx.db()); ty.iterate_assoc_items(ctx.db(), krate, |item| { if let hir::AssocItem::Function(f) = item { + let name = f.name(ctx.db()); if f.self_param(ctx.db()).is_some() && f.is_visible_from(ctx.db(), current_module) - && seen_names.insert(f.name(ctx.db())) + && seen_names.insert(name.clone()) { - methods.push(f) + methods.push((name, f)) } } Option::<()>::None }); } - - for method in methods { + methods.sort_by(|(a, _), (b, _)| a.cmp(b)); + for (name, method) in methods { let adt = ast::Adt::Struct(strukt.clone()); - let name = method.name(ctx.db()).display(ctx.db()).to_string(); + let name = name.display(ctx.db()).to_string(); // if `find_struct_impl` returns None, that means that a function named `name` already exists. - let Some(impl_def) = find_struct_impl(ctx, &adt, &[name]) else { continue; }; + let Some(impl_def) = find_struct_impl(ctx, &adt, std::slice::from_ref(&name)) else { continue; }; acc.add_group( &GroupLabel("Generate delegate methods…".to_owned()), AssistId("generate_delegate_methods", AssistKind::Generate), - format!( - "Generate delegate for `{field_name}.{}()`", - method.name(ctx.db()).display(ctx.db()) - ), + format!("Generate delegate for `{field_name}.{name}()`",), target, |builder| { // Create the function @@ -102,9 +100,8 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' Some(source) => source.value, None => return, }; - let method_name = method.name(ctx.db()); let vis = method_source.visibility(); - let name = make::name(&method.name(ctx.db()).display(ctx.db()).to_string()); + let fn_name = make::name(&name); let params = method_source.param_list().unwrap_or_else(|| make::param_list(None, [])); let type_params = method_source.generic_param_list(); @@ -114,7 +111,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' }; let tail_expr = make::expr_method_call( make::ext::field_from_idents(["self", &field_name]).unwrap(), // This unwrap is ok because we have at least 1 arg in the list - make::name_ref(&method_name.display(ctx.db()).to_string()), + make::name_ref(&name), arg_list, ); let ret_type = method_source.ret_type(); @@ -126,7 +123,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' let body = make::block_expr([], Some(tail_expr_finished)); let f = make::fn_( vis, - name, + fn_name, type_params, None, params, From 76acf3b99269f0b54f1d0efbd0454f057a29f644 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 16 Jun 2023 19:14:46 +0200 Subject: [PATCH 247/465] internal: Analyze all bodies in analysis-stats, not just functions --- .../rust-analyzer/src/cli/analysis_stats.rs | 212 +++++++++--------- crates/rust-analyzer/src/cli/flags.rs | 14 +- 2 files changed, 120 insertions(+), 106 deletions(-) diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 4c0a08d926bd4..e0767b39ef45e 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -8,18 +8,20 @@ use std::{ use hir::{ db::{DefDatabase, ExpandDatabase, HirDatabase}, - AssocItem, Crate, Function, HasCrate, HasSource, HirDisplay, ModuleDef, + Adt, AssocItem, Crate, DefWithBody, HasCrate, HasSource, HirDisplay, ModuleDef, Name, }; use hir_def::{ body::{BodySourceMap, SyntheticSyntax}, hir::{ExprId, PatId}, - FunctionId, }; use hir_ty::{Interner, Substitution, TyExt, TypeFlags}; -use ide::{Analysis, AnalysisHost, LineCol, RootDatabase}; -use ide_db::base_db::{ - salsa::{self, debug::DebugQueryTable, ParallelDatabase}, - SourceDatabase, SourceDatabaseExt, +use ide::{LineCol, RootDatabase}; +use ide_db::{ + base_db::{ + salsa::{self, debug::DebugQueryTable, ParallelDatabase}, + SourceDatabase, SourceDatabaseExt, + }, + LineIndexDatabase, }; use itertools::Itertools; use oorandom::Rand32; @@ -120,7 +122,7 @@ impl flags::AnalysisStats { eprint!(" crates: {num_crates}"); let mut num_decls = 0; - let mut funcs = Vec::new(); + let mut bodies = Vec::new(); let mut adts = Vec::new(); let mut consts = Vec::new(); while let Some(module) = visit_queue.pop() { @@ -130,40 +132,66 @@ impl flags::AnalysisStats { for decl in module.declarations(db) { num_decls += 1; match decl { - ModuleDef::Function(f) => funcs.push(f), - ModuleDef::Adt(a) => adts.push(a), - ModuleDef::Const(c) => consts.push(c), + ModuleDef::Function(f) => bodies.push(DefWithBody::from(f)), + ModuleDef::Adt(a) => { + if let Adt::Enum(e) = a { + for v in e.variants(db) { + bodies.push(DefWithBody::from(v)); + } + } + adts.push(a) + } + ModuleDef::Const(c) => { + bodies.push(DefWithBody::from(c)); + consts.push(c) + } + ModuleDef::Static(s) => bodies.push(DefWithBody::from(s)), _ => (), - } + }; } for impl_def in module.impl_defs(db) { for item in impl_def.items(db) { num_decls += 1; - if let AssocItem::Function(f) = item { - funcs.push(f); + match item { + AssocItem::Function(f) => bodies.push(DefWithBody::from(f)), + AssocItem::Const(c) => { + bodies.push(DefWithBody::from(c)); + consts.push(c); + } + _ => (), } } } } } - eprintln!(", mods: {}, decls: {num_decls}, fns: {}", visited_modules.len(), funcs.len()); + eprintln!( + ", mods: {}, decls: {num_decls}, bodies: {}", + visited_modules.len(), + bodies.len() + ); eprintln!("{:<20} {}", "Item Collection:", analysis_sw.elapsed()); if self.randomize { - shuffle(&mut rng, &mut funcs); + shuffle(&mut rng, &mut bodies); } if !self.skip_inference { - self.run_inference(&host, db, &vfs, &funcs, verbosity); + // FIXME: Consider running inference on all body kinds? + self.run_inference(db, &vfs, &bodies, verbosity); } if !self.skip_mir_stats { - self.run_mir_lowering(db, &funcs, verbosity); + self.run_mir_lowering(db, &bodies, verbosity); } - self.run_data_layout(db, &adts, verbosity); - self.run_const_eval(db, &consts, verbosity); + if !self.skip_data_layout { + self.run_data_layout(db, &adts, verbosity); + } + + if !self.skip_const_eval { + self.run_const_eval(db, &consts, verbosity); + } let total_span = analysis_sw.elapsed(); eprintln!("{:<20} {total_span}", "Total:"); @@ -260,22 +288,22 @@ impl flags::AnalysisStats { report_metric("failed const evals", fail, "#"); } - fn run_mir_lowering(&self, db: &RootDatabase, funcs: &[Function], verbosity: Verbosity) { + fn run_mir_lowering(&self, db: &RootDatabase, bodies: &[DefWithBody], verbosity: Verbosity) { let mut sw = self.stop_watch(); - let all = funcs.len() as u64; + let all = bodies.len() as u64; let mut fail = 0; - for f in funcs { - let Err(e) = db.mir_body(FunctionId::from(*f).into()) else { + for &body in bodies { + let Err(e) = db.mir_body(body.into()) else { continue; }; if verbosity.is_spammy() { - let full_name = f + let full_name = body .module(db) .path_to_root(db) .into_iter() .rev() .filter_map(|it| it.name(db)) - .chain(Some(f.name(db))) + .chain(Some(body.name(db).unwrap_or_else(Name::missing))) .map(|it| it.display(db).to_string()) .join("::"); println!("Mir body for {full_name} failed due {e:?}"); @@ -289,27 +317,25 @@ impl flags::AnalysisStats { fn run_inference( &self, - host: &AnalysisHost, db: &RootDatabase, vfs: &Vfs, - funcs: &[Function], + bodies: &[DefWithBody], verbosity: Verbosity, ) { let mut bar = match verbosity { Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(), _ if self.parallel || self.output.is_some() => ProgressReport::hidden(), - _ => ProgressReport::new(funcs.len() as u64), + _ => ProgressReport::new(bodies.len() as u64), }; if self.parallel { let mut inference_sw = self.stop_watch(); let snap = Snap(db.snapshot()); - funcs + bodies .par_iter() - .map_with(snap, |snap, &f| { - let f_id = FunctionId::from(f); - snap.0.body(f_id.into()); - snap.0.infer(f_id.into()); + .map_with(snap, |snap, &body| { + snap.0.body(body.into()); + snap.0.infer(body.into()); }) .count(); eprintln!("{:<20} {}", "Parallel Inference:", inference_sw.elapsed()); @@ -325,36 +351,44 @@ impl flags::AnalysisStats { let mut num_pats_unknown = 0; let mut num_pats_partially_unknown = 0; let mut num_pat_type_mismatches = 0; - let analysis = host.analysis(); - for f in funcs.iter().copied() { - let name = f.name(db); - let module = f.module(db); - let full_name = module - .krate() - .display_name(db) - .map(|x| x.canonical_name().to_string()) - .into_iter() - .chain( - module - .path_to_root(db) - .into_iter() - .filter_map(|it| it.name(db)) - .rev() - .chain(Some(f.name(db))) - .map(|it| it.display(db).to_string()), - ) - .join("::"); + for &body_id in bodies { + let name = body_id.name(db).unwrap_or_else(Name::missing); + let module = body_id.module(db); + let full_name = || { + module + .krate() + .display_name(db) + .map(|it| it.canonical_name().to_string()) + .into_iter() + .chain( + module + .path_to_root(db) + .into_iter() + .filter_map(|it| it.name(db)) + .rev() + .chain(Some(name.clone())) + .map(|it| it.display(db).to_string()), + ) + .join("::") + }; if let Some(only_name) = self.only.as_deref() { - if name.display(db).to_string() != only_name && full_name != only_name { + if name.display(db).to_string() != only_name && full_name() != only_name { continue; } } - let mut msg = format!("processing: {full_name}"); + let mut msg = format!("processing: {}", full_name()); if verbosity.is_verbose() { - if let Some(src) = f.source(db) { + let source = match body_id { + DefWithBody::Function(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::Static(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::Const(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::Variant(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::InTypeConst(_) => unimplemented!(), + }; + if let Some(src) = source { let original_file = src.file_id.original_file(db); let path = vfs.file_path(original_file); - let syntax_range = src.value.syntax().text_range(); + let syntax_range = src.value.text_range(); format_to!(msg, " ({} {:?})", path, syntax_range); } } @@ -362,9 +396,8 @@ impl flags::AnalysisStats { bar.println(msg.to_string()); } bar.set_message(&msg); - let f_id = FunctionId::from(f); - let (body, sm) = db.body_with_source_map(f_id.into()); - let inference_result = db.infer(f_id.into()); + let (body, sm) = db.body_with_source_map(body_id.into()); + let inference_result = db.infer(body_id.into()); // region:expressions let (previous_exprs, previous_unknown, previous_partially_unknown) = @@ -375,9 +408,7 @@ impl flags::AnalysisStats { let unknown_or_partial = if ty.is_unknown() { num_exprs_unknown += 1; if verbosity.is_spammy() { - if let Some((path, start, end)) = - expr_syntax_range(db, &analysis, vfs, &sm, expr_id) - { + if let Some((path, start, end)) = expr_syntax_range(db, vfs, &sm, expr_id) { bar.println(format!( "{} {}:{}-{}:{}: Unknown type", path, @@ -401,9 +432,7 @@ impl flags::AnalysisStats { }; if self.only.is_some() && verbosity.is_spammy() { // in super-verbose mode for just one function, we print every single expression - if let Some((_, start, end)) = - expr_syntax_range(db, &analysis, vfs, &sm, expr_id) - { + if let Some((_, start, end)) = expr_syntax_range(db, vfs, &sm, expr_id) { bar.println(format!( "{}:{}-{}:{}: {}", start.line + 1, @@ -419,16 +448,14 @@ impl flags::AnalysisStats { if unknown_or_partial && self.output == Some(OutputFormat::Csv) { println!( r#"{},type,"{}""#, - location_csv_expr(db, &analysis, vfs, &sm, expr_id), + location_csv_expr(db, vfs, &sm, expr_id), ty.display(db) ); } if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) { num_expr_type_mismatches += 1; if verbosity.is_verbose() { - if let Some((path, start, end)) = - expr_syntax_range(db, &analysis, vfs, &sm, expr_id) - { + if let Some((path, start, end)) = expr_syntax_range(db, vfs, &sm, expr_id) { bar.println(format!( "{} {}:{}-{}:{}: Expected {}, got {}", path, @@ -451,7 +478,7 @@ impl flags::AnalysisStats { if self.output == Some(OutputFormat::Csv) { println!( r#"{},mismatch,"{}","{}""#, - location_csv_expr(db, &analysis, vfs, &sm, expr_id), + location_csv_expr(db, vfs, &sm, expr_id), mismatch.expected.display(db), mismatch.actual.display(db) ); @@ -461,7 +488,7 @@ impl flags::AnalysisStats { if verbosity.is_spammy() { bar.println(format!( "In {}: {} exprs, {} unknown, {} partial", - full_name, + full_name(), num_exprs - previous_exprs, num_exprs_unknown - previous_unknown, num_exprs_partially_unknown - previous_partially_unknown @@ -478,9 +505,7 @@ impl flags::AnalysisStats { let unknown_or_partial = if ty.is_unknown() { num_pats_unknown += 1; if verbosity.is_spammy() { - if let Some((path, start, end)) = - pat_syntax_range(db, &analysis, vfs, &sm, pat_id) - { + if let Some((path, start, end)) = pat_syntax_range(db, vfs, &sm, pat_id) { bar.println(format!( "{} {}:{}-{}:{}: Unknown type", path, @@ -504,8 +529,7 @@ impl flags::AnalysisStats { }; if self.only.is_some() && verbosity.is_spammy() { // in super-verbose mode for just one function, we print every single pattern - if let Some((_, start, end)) = pat_syntax_range(db, &analysis, vfs, &sm, pat_id) - { + if let Some((_, start, end)) = pat_syntax_range(db, vfs, &sm, pat_id) { bar.println(format!( "{}:{}-{}:{}: {}", start.line + 1, @@ -521,16 +545,14 @@ impl flags::AnalysisStats { if unknown_or_partial && self.output == Some(OutputFormat::Csv) { println!( r#"{},type,"{}""#, - location_csv_pat(db, &analysis, vfs, &sm, pat_id), + location_csv_pat(db, vfs, &sm, pat_id), ty.display(db) ); } if let Some(mismatch) = inference_result.type_mismatch_for_pat(pat_id) { num_pat_type_mismatches += 1; if verbosity.is_verbose() { - if let Some((path, start, end)) = - pat_syntax_range(db, &analysis, vfs, &sm, pat_id) - { + if let Some((path, start, end)) = pat_syntax_range(db, vfs, &sm, pat_id) { bar.println(format!( "{} {}:{}-{}:{}: Expected {}, got {}", path, @@ -553,7 +575,7 @@ impl flags::AnalysisStats { if self.output == Some(OutputFormat::Csv) { println!( r#"{},mismatch,"{}","{}""#, - location_csv_pat(db, &analysis, vfs, &sm, pat_id), + location_csv_pat(db, vfs, &sm, pat_id), mismatch.expected.display(db), mismatch.actual.display(db) ); @@ -563,7 +585,7 @@ impl flags::AnalysisStats { if verbosity.is_spammy() { bar.println(format!( "In {}: {} pats, {} unknown, {} partial", - full_name, + full_name(), num_pats - previous_pats, num_pats_unknown - previous_unknown, num_pats_partially_unknown - previous_partially_unknown @@ -605,13 +627,7 @@ impl flags::AnalysisStats { } } -fn location_csv_expr( - db: &RootDatabase, - analysis: &Analysis, - vfs: &Vfs, - sm: &BodySourceMap, - expr_id: ExprId, -) -> String { +fn location_csv_expr(db: &RootDatabase, vfs: &Vfs, sm: &BodySourceMap, expr_id: ExprId) -> String { let src = match sm.expr_syntax(expr_id) { Ok(s) => s, Err(SyntheticSyntax) => return "synthetic,,".to_string(), @@ -620,20 +636,14 @@ fn location_csv_expr( let node = src.map(|e| e.to_node(&root).syntax().clone()); let original_range = node.as_ref().original_file_range(db); let path = vfs.file_path(original_range.file_id); - let line_index = analysis.file_line_index(original_range.file_id).unwrap(); + let line_index = db.line_index(original_range.file_id); let text_range = original_range.range; let (start, end) = (line_index.line_col(text_range.start()), line_index.line_col(text_range.end())); format!("{path},{}:{},{}:{}", start.line + 1, start.col, end.line + 1, end.col) } -fn location_csv_pat( - db: &RootDatabase, - analysis: &Analysis, - vfs: &Vfs, - sm: &BodySourceMap, - pat_id: PatId, -) -> String { +fn location_csv_pat(db: &RootDatabase, vfs: &Vfs, sm: &BodySourceMap, pat_id: PatId) -> String { let src = match sm.pat_syntax(pat_id) { Ok(s) => s, Err(SyntheticSyntax) => return "synthetic,,".to_string(), @@ -644,7 +654,7 @@ fn location_csv_pat( }); let original_range = node.as_ref().original_file_range(db); let path = vfs.file_path(original_range.file_id); - let line_index = analysis.file_line_index(original_range.file_id).unwrap(); + let line_index = db.line_index(original_range.file_id); let text_range = original_range.range; let (start, end) = (line_index.line_col(text_range.start()), line_index.line_col(text_range.end())); @@ -653,7 +663,6 @@ fn location_csv_pat( fn expr_syntax_range( db: &RootDatabase, - analysis: &Analysis, vfs: &Vfs, sm: &BodySourceMap, expr_id: ExprId, @@ -664,7 +673,7 @@ fn expr_syntax_range( let node = src.map(|e| e.to_node(&root).syntax().clone()); let original_range = node.as_ref().original_file_range(db); let path = vfs.file_path(original_range.file_id); - let line_index = analysis.file_line_index(original_range.file_id).unwrap(); + let line_index = db.line_index(original_range.file_id); let text_range = original_range.range; let (start, end) = (line_index.line_col(text_range.start()), line_index.line_col(text_range.end())); @@ -675,7 +684,6 @@ fn expr_syntax_range( } fn pat_syntax_range( db: &RootDatabase, - analysis: &Analysis, vfs: &Vfs, sm: &BodySourceMap, pat_id: PatId, @@ -691,7 +699,7 @@ fn pat_syntax_range( }); let original_range = node.as_ref().original_file_range(db); let path = vfs.file_path(original_range.file_id); - let line_index = analysis.file_line_index(original_range.file_id).unwrap(); + let line_index = db.line_index(original_range.file_id); let text_range = original_range.range; let (start, end) = (line_index.line_col(text_range.start()), line_index.line_col(text_range.end())); diff --git a/crates/rust-analyzer/src/cli/flags.rs b/crates/rust-analyzer/src/cli/flags.rs index c1ca03ceae401..923be8b072882 100644 --- a/crates/rust-analyzer/src/cli/flags.rs +++ b/crates/rust-analyzer/src/cli/flags.rs @@ -66,8 +66,6 @@ xflags::xflags! { optional --memory-usage /// Print the total length of all source and macro files (whitespace is not counted). optional --source-stats - /// Only type check, skip lowering to mir - optional --skip-mir-stats /// Only analyze items matching this path. optional -o, --only path: String @@ -80,8 +78,14 @@ xflags::xflags! { optional --disable-build-scripts /// Don't use expand proc macros. optional --disable-proc-macros - /// Only resolve names, don't run type inference. + /// Skip type inference. optional --skip-inference + /// Skip lowering to mir + optional --skip-mir-stats + /// Skip data layout calculation + optional --skip-data-layout + /// Skip const evaluation + optional --skip-const-eval } cmd diagnostics { @@ -176,13 +180,15 @@ pub struct AnalysisStats { pub parallel: bool, pub memory_usage: bool, pub source_stats: bool, + pub skip_inference: bool, pub skip_mir_stats: bool, + pub skip_data_layout: bool, + pub skip_const_eval: bool, pub only: Option, pub with_deps: bool, pub no_sysroot: bool, pub disable_build_scripts: bool, pub disable_proc_macros: bool, - pub skip_inference: bool, } #[derive(Debug)] From bd762e62df617c0048f6279bc3f04c2b3da6d5de Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 16 Jun 2023 19:31:07 +0200 Subject: [PATCH 248/465] internal: Add more context to overly long loop turn message --- crates/rust-analyzer/src/dispatch.rs | 2 +- crates/rust-analyzer/src/main_loop.rs | 44 +++++++++++++++++---------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/crates/rust-analyzer/src/dispatch.rs b/crates/rust-analyzer/src/dispatch.rs index 8a0ad88b654dc..4e57c6eb65a4e 100644 --- a/crates/rust-analyzer/src/dispatch.rs +++ b/crates/rust-analyzer/src/dispatch.rs @@ -307,7 +307,7 @@ pub(crate) struct NotificationDispatcher<'a> { } impl<'a> NotificationDispatcher<'a> { - pub(crate) fn on( + pub(crate) fn on_sync_mut( &mut self, f: fn(&mut GlobalState, N::Params) -> Result<()>, ) -> Result<&mut Self> diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index c70f60513b59f..02dd94e5fa59e 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -11,6 +11,7 @@ use flycheck::FlycheckHandle; use ide_db::base_db::{SourceDatabaseExt, VfsPath}; use lsp_server::{Connection, Notification, Request}; use lsp_types::notification::Notification as _; +use stdx::thread::ThreadIntent; use triomphe::Arc; use vfs::FileId; @@ -282,6 +283,7 @@ impl GlobalState { } } } + let event_handling_duration = loop_start.elapsed(); let state_changed = self.process_changes(); let memdocs_added_or_removed = self.mem_docs.take_changes(); @@ -392,9 +394,9 @@ impl GlobalState { let loop_duration = loop_start.elapsed(); if loop_duration > Duration::from_millis(100) && was_quiescent { - tracing::warn!("overly long loop turn took {loop_duration:?}: {event_dbg_msg}"); + tracing::warn!("overly long loop turn took {loop_duration:?} (event handling took {event_handling_duration:?}): {event_dbg_msg}"); self.poke_rust_analyzer_developer(format!( - "overly long loop turn took {loop_duration:?}: {event_dbg_msg}" + "overly long loop turn took {loop_duration:?} (event handling took {event_handling_duration:?}): {event_dbg_msg}" )); } Ok(()) @@ -404,7 +406,7 @@ impl GlobalState { tracing::debug!(%cause, "will prime caches"); let num_worker_threads = self.config.prime_caches_num_threads(); - self.task_pool.handle.spawn_with_sender(stdx::thread::ThreadIntent::Worker, { + self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, { let analysis = self.snapshot().analysis; move |sender| { sender.send(Task::PrimeCaches(PrimeCachesProgress::Begin)).unwrap(); @@ -761,18 +763,28 @@ impl GlobalState { use lsp_types::notification as notifs; NotificationDispatcher { not: Some(not), global_state: self } - .on::(handlers::handle_cancel)? - .on::(handlers::handle_work_done_progress_cancel)? - .on::(handlers::handle_did_open_text_document)? - .on::(handlers::handle_did_change_text_document)? - .on::(handlers::handle_did_close_text_document)? - .on::(handlers::handle_did_save_text_document)? - .on::(handlers::handle_did_change_configuration)? - .on::(handlers::handle_did_change_workspace_folders)? - .on::(handlers::handle_did_change_watched_files)? - .on::(handlers::handle_cancel_flycheck)? - .on::(handlers::handle_clear_flycheck)? - .on::(handlers::handle_run_flycheck)? + .on_sync_mut::(handlers::handle_cancel)? + .on_sync_mut::( + handlers::handle_work_done_progress_cancel, + )? + .on_sync_mut::(handlers::handle_did_open_text_document)? + .on_sync_mut::( + handlers::handle_did_change_text_document, + )? + .on_sync_mut::(handlers::handle_did_close_text_document)? + .on_sync_mut::(handlers::handle_did_save_text_document)? + .on_sync_mut::( + handlers::handle_did_change_configuration, + )? + .on_sync_mut::( + handlers::handle_did_change_workspace_folders, + )? + .on_sync_mut::( + handlers::handle_did_change_watched_files, + )? + .on_sync_mut::(handlers::handle_cancel_flycheck)? + .on_sync_mut::(handlers::handle_clear_flycheck)? + .on_sync_mut::(handlers::handle_run_flycheck)? .finish(); Ok(()) } @@ -800,7 +812,7 @@ impl GlobalState { // Diagnostics are triggered by the user typing // so we run them on a latency sensitive thread. - self.task_pool.handle.spawn(stdx::thread::ThreadIntent::LatencySensitive, move || { + self.task_pool.handle.spawn(ThreadIntent::LatencySensitive, move || { let _p = profile::span("publish_diagnostics"); let _ctx = stdx::panic_context::enter("publish_diagnostics".to_owned()); let diagnostics = subscriptions From 3ec4eeddefcf022af3aafab708d36830f40d8a47 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 16 Jun 2023 15:21:34 -0700 Subject: [PATCH 249/465] [libs] Simplify `unchecked_{shl,shr}` There's no need for the `const_eval_select` dance here. And while I originally wrote the `.try_into().unwrap_unchecked()` implementation here, it's kinda a mess in MIR -- this new one is substantially simpler, as shown by the old one being above the inlining threshold but the new one being below it. --- library/core/src/num/mod.rs | 17 +--- tests/codegen/unchecked_shifts.rs | 4 + tests/mir-opt/inline/unchecked_shifts.rs | 12 +++ ...hl_unsigned_bigger.Inline.panic-abort.diff | 36 +++++++ ...l_unsigned_bigger.Inline.panic-unwind.diff | 36 +++++++ ...ed_bigger.PreCodegen.after.panic-abort.mir | 25 +++++ ...d_bigger.PreCodegen.after.panic-unwind.mir | 25 +++++ ...l_unsigned_smaller.Inline.panic-abort.diff | 22 ++++- ..._unsigned_smaller.Inline.panic-unwind.diff | 22 ++++- ...d_smaller.PreCodegen.after.panic-abort.mir | 21 +++- ..._smaller.PreCodegen.after.panic-unwind.mir | 21 +++- ..._shr_signed_bigger.Inline.panic-abort.diff | 36 +++++++ ...shr_signed_bigger.Inline.panic-unwind.diff | 36 +++++++ ...ed_bigger.PreCodegen.after.panic-abort.mir | 25 +++++ ...d_bigger.PreCodegen.after.panic-unwind.mir | 25 +++++ ...shr_signed_smaller.Inline.panic-abort.diff | 22 ++++- ...hr_signed_smaller.Inline.panic-unwind.diff | 22 ++++- ...d_smaller.PreCodegen.after.panic-abort.mir | 21 +++- ..._smaller.PreCodegen.after.panic-unwind.mir | 21 +++- ...ecked_ops.checked_shl.PreCodegen.after.mir | 99 ++++--------------- 20 files changed, 449 insertions(+), 99 deletions(-) create mode 100644 tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-abort.diff create mode 100644 tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-unwind.diff create mode 100644 tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-abort.mir create mode 100644 tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-unwind.mir create mode 100644 tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff create mode 100644 tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff create mode 100644 tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir create mode 100644 tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index c9baa09f4074a..95dcaf5dd7397 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -3,7 +3,6 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::ascii; -use crate::convert::TryInto; use crate::intrinsics; use crate::mem; use crate::ops::{Add, Mul, Sub}; @@ -278,18 +277,12 @@ macro_rules! widening_impl { macro_rules! conv_rhs_for_unchecked_shift { ($SelfT:ty, $x:expr) => {{ - #[inline] - fn conv(x: u32) -> $SelfT { - // FIXME(const-hack) replace with `.try_into().ok().unwrap_unchecked()`. - // SAFETY: Any legal shift amount must be losslessly representable in the self type. - unsafe { x.try_into().ok().unwrap_unchecked() } - } - #[inline] - const fn const_conv(x: u32) -> $SelfT { - x as _ + // If the `as` cast will truncate, ensure we still tell the backend + // that the pre-truncation value was also small. + if <$SelfT>::BITS < 32 { + intrinsics::assume($x <= (<$SelfT>::MAX as u32)); } - - intrinsics::const_eval_select(($x,), const_conv, conv) + $x as $SelfT }}; } diff --git a/tests/codegen/unchecked_shifts.rs b/tests/codegen/unchecked_shifts.rs index 60d0cb09acaf9..0924dda08ee66 100644 --- a/tests/codegen/unchecked_shifts.rs +++ b/tests/codegen/unchecked_shifts.rs @@ -8,6 +8,7 @@ // CHECK-LABEL: @unchecked_shl_unsigned_same #[no_mangle] pub unsafe fn unchecked_shl_unsigned_same(a: u32, b: u32) -> u32 { + // CHECK-NOT: assume // CHECK-NOT: and i32 // CHECK: shl i32 %a, %b // CHECK-NOT: and i32 @@ -30,6 +31,7 @@ pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 { // CHECK-LABEL: @unchecked_shl_unsigned_bigger #[no_mangle] pub unsafe fn unchecked_shl_unsigned_bigger(a: u64, b: u32) -> u64 { + // CHECK-NOT: assume // CHECK: %[[EXT:.+]] = zext i32 %b to i64 // CHECK: shl i64 %a, %[[EXT]] a.unchecked_shl(b) @@ -38,6 +40,7 @@ pub unsafe fn unchecked_shl_unsigned_bigger(a: u64, b: u32) -> u64 { // CHECK-LABEL: @unchecked_shr_signed_same #[no_mangle] pub unsafe fn unchecked_shr_signed_same(a: i32, b: u32) -> i32 { + // CHECK-NOT: assume // CHECK-NOT: and i32 // CHECK: ashr i32 %a, %b // CHECK-NOT: and i32 @@ -60,6 +63,7 @@ pub unsafe fn unchecked_shr_signed_smaller(a: i16, b: u32) -> i16 { // CHECK-LABEL: @unchecked_shr_signed_bigger #[no_mangle] pub unsafe fn unchecked_shr_signed_bigger(a: i64, b: u32) -> i64 { + // CHECK-NOT: assume // CHECK: %[[EXT:.+]] = zext i32 %b to i64 // CHECK: ashr i64 %a, %[[EXT]] a.unchecked_shr(b) diff --git a/tests/mir-opt/inline/unchecked_shifts.rs b/tests/mir-opt/inline/unchecked_shifts.rs index 64ec26b587d28..22f84e44a6411 100644 --- a/tests/mir-opt/inline/unchecked_shifts.rs +++ b/tests/mir-opt/inline/unchecked_shifts.rs @@ -16,3 +16,15 @@ pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 { pub unsafe fn unchecked_shr_signed_smaller(a: i16, b: u32) -> i16 { a.unchecked_shr(b) } + +// EMIT_MIR unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.diff +// EMIT_MIR unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.mir +pub unsafe fn unchecked_shl_unsigned_bigger(a: u64, b: u32) -> u64 { + a.unchecked_shl(b) +} + +// EMIT_MIR unchecked_shifts.unchecked_shr_signed_bigger.Inline.diff +// EMIT_MIR unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.mir +pub unsafe fn unchecked_shr_signed_bigger(a: i64, b: u32) -> i64 { + a.unchecked_shr(b) +} diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-abort.diff new file mode 100644 index 0000000000000..1ed65b310ac00 --- /dev/null +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-abort.diff @@ -0,0 +1,36 @@ +- // MIR for `unchecked_shl_unsigned_bigger` before Inline ++ // MIR for `unchecked_shl_unsigned_bigger` after Inline + + fn unchecked_shl_unsigned_bigger(_1: u64, _2: u32) -> u64 { + debug a => _1; + debug b => _2; + let mut _0: u64; + let mut _3: u64; + let mut _4: u32; ++ scope 1 (inlined core::num::::unchecked_shl) { ++ debug self => _3; ++ debug rhs => _4; ++ let mut _5: u64; ++ scope 2 { ++ } ++ } + + bb0: { + StorageLive(_3); + _3 = _1; + StorageLive(_4); + _4 = _2; +- _0 = core::num::::unchecked_shl(move _3, move _4) -> [return: bb1, unwind unreachable]; ++ StorageLive(_5); ++ _5 = _4 as u64 (IntToInt); ++ _0 = unchecked_shl::(_3, move _5) -> [return: bb1, unwind unreachable]; + } + + bb1: { ++ StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-unwind.diff new file mode 100644 index 0000000000000..7a27675638b01 --- /dev/null +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-unwind.diff @@ -0,0 +1,36 @@ +- // MIR for `unchecked_shl_unsigned_bigger` before Inline ++ // MIR for `unchecked_shl_unsigned_bigger` after Inline + + fn unchecked_shl_unsigned_bigger(_1: u64, _2: u32) -> u64 { + debug a => _1; + debug b => _2; + let mut _0: u64; + let mut _3: u64; + let mut _4: u32; ++ scope 1 (inlined core::num::::unchecked_shl) { ++ debug self => _3; ++ debug rhs => _4; ++ let mut _5: u64; ++ scope 2 { ++ } ++ } + + bb0: { + StorageLive(_3); + _3 = _1; + StorageLive(_4); + _4 = _2; +- _0 = core::num::::unchecked_shl(move _3, move _4) -> bb1; ++ StorageLive(_5); ++ _5 = _4 as u64 (IntToInt); ++ _0 = unchecked_shl::(_3, move _5) -> [return: bb1, unwind unreachable]; + } + + bb1: { ++ StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-abort.mir new file mode 100644 index 0000000000000..eee56b9560d06 --- /dev/null +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-abort.mir @@ -0,0 +1,25 @@ +// MIR for `unchecked_shl_unsigned_bigger` after PreCodegen + +fn unchecked_shl_unsigned_bigger(_1: u64, _2: u32) -> u64 { + debug a => _1; + debug b => _2; + let mut _0: u64; + scope 1 (inlined core::num::::unchecked_shl) { + debug self => _1; + debug rhs => _2; + let mut _3: u64; + scope 2 { + } + } + + bb0: { + StorageLive(_3); + _3 = _2 as u64 (IntToInt); + _0 = unchecked_shl::(_1, move _3) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_3); + return; + } +} diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-unwind.mir new file mode 100644 index 0000000000000..eee56b9560d06 --- /dev/null +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.PreCodegen.after.panic-unwind.mir @@ -0,0 +1,25 @@ +// MIR for `unchecked_shl_unsigned_bigger` after PreCodegen + +fn unchecked_shl_unsigned_bigger(_1: u64, _2: u32) -> u64 { + debug a => _1; + debug b => _2; + let mut _0: u64; + scope 1 (inlined core::num::::unchecked_shl) { + debug self => _1; + debug rhs => _2; + let mut _3: u64; + scope 2 { + } + } + + bb0: { + StorageLive(_3); + _3 = _2 as u64 (IntToInt); + _0 = unchecked_shl::(_1, move _3) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_3); + return; + } +} diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff index 093925b8e4fa1..6c809f0b533e7 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff @@ -7,16 +7,36 @@ let mut _0: u16; let mut _3: u16; let mut _4: u32; ++ scope 1 (inlined core::num::::unchecked_shl) { ++ debug self => _3; ++ debug rhs => _4; ++ let mut _5: u16; ++ let mut _6: bool; ++ let mut _7: u32; ++ scope 2 { ++ } ++ } bb0: { StorageLive(_3); _3 = _1; StorageLive(_4); _4 = _2; - _0 = core::num::::unchecked_shl(move _3, move _4) -> [return: bb1, unwind unreachable]; +- _0 = core::num::::unchecked_shl(move _3, move _4) -> [return: bb1, unwind unreachable]; ++ StorageLive(_5); ++ StorageLive(_6); ++ StorageLive(_7); ++ _7 = const 65535_u32; ++ _6 = Le(_4, move _7); ++ StorageDead(_7); ++ assume(move _6); ++ StorageDead(_6); ++ _5 = _4 as u16 (IntToInt); ++ _0 = unchecked_shl::(_3, move _5) -> [return: bb1, unwind unreachable]; } bb1: { ++ StorageDead(_5); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff index 50934e0439a3b..0753c1b05df44 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff @@ -7,16 +7,36 @@ let mut _0: u16; let mut _3: u16; let mut _4: u32; ++ scope 1 (inlined core::num::::unchecked_shl) { ++ debug self => _3; ++ debug rhs => _4; ++ let mut _5: u16; ++ let mut _6: bool; ++ let mut _7: u32; ++ scope 2 { ++ } ++ } bb0: { StorageLive(_3); _3 = _1; StorageLive(_4); _4 = _2; - _0 = core::num::::unchecked_shl(move _3, move _4) -> bb1; +- _0 = core::num::::unchecked_shl(move _3, move _4) -> bb1; ++ StorageLive(_5); ++ StorageLive(_6); ++ StorageLive(_7); ++ _7 = const 65535_u32; ++ _6 = Le(_4, move _7); ++ StorageDead(_7); ++ assume(move _6); ++ StorageDead(_6); ++ _5 = _4 as u16 (IntToInt); ++ _0 = unchecked_shl::(_3, move _5) -> [return: bb1, unwind unreachable]; } bb1: { ++ StorageDead(_5); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir index 46f3511b14ca9..7bf10b365a6cf 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir @@ -4,12 +4,31 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 { debug a => _1; debug b => _2; let mut _0: u16; + scope 1 (inlined core::num::::unchecked_shl) { + debug self => _1; + debug rhs => _2; + let mut _3: u32; + let mut _4: bool; + let mut _5: u16; + scope 2 { + } + } bb0: { - _0 = core::num::::unchecked_shl(_1, _2) -> [return: bb1, unwind unreachable]; + StorageLive(_5); + StorageLive(_4); + StorageLive(_3); + _3 = const 65535_u32; + _4 = Le(_2, move _3); + StorageDead(_3); + assume(move _4); + StorageDead(_4); + _5 = _2 as u16 (IntToInt); + _0 = unchecked_shl::(_1, move _5) -> [return: bb1, unwind unreachable]; } bb1: { + StorageDead(_5); return; } } diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir index 35fee449c35c8..7bf10b365a6cf 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir @@ -4,12 +4,31 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 { debug a => _1; debug b => _2; let mut _0: u16; + scope 1 (inlined core::num::::unchecked_shl) { + debug self => _1; + debug rhs => _2; + let mut _3: u32; + let mut _4: bool; + let mut _5: u16; + scope 2 { + } + } bb0: { - _0 = core::num::::unchecked_shl(_1, _2) -> bb1; + StorageLive(_5); + StorageLive(_4); + StorageLive(_3); + _3 = const 65535_u32; + _4 = Le(_2, move _3); + StorageDead(_3); + assume(move _4); + StorageDead(_4); + _5 = _2 as u16 (IntToInt); + _0 = unchecked_shl::(_1, move _5) -> [return: bb1, unwind unreachable]; } bb1: { + StorageDead(_5); return; } } diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff new file mode 100644 index 0000000000000..04ddb4e80ff56 --- /dev/null +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff @@ -0,0 +1,36 @@ +- // MIR for `unchecked_shr_signed_bigger` before Inline ++ // MIR for `unchecked_shr_signed_bigger` after Inline + + fn unchecked_shr_signed_bigger(_1: i64, _2: u32) -> i64 { + debug a => _1; + debug b => _2; + let mut _0: i64; + let mut _3: i64; + let mut _4: u32; ++ scope 1 (inlined core::num::::unchecked_shr) { ++ debug self => _3; ++ debug rhs => _4; ++ let mut _5: i64; ++ scope 2 { ++ } ++ } + + bb0: { + StorageLive(_3); + _3 = _1; + StorageLive(_4); + _4 = _2; +- _0 = core::num::::unchecked_shr(move _3, move _4) -> [return: bb1, unwind unreachable]; ++ StorageLive(_5); ++ _5 = _4 as i64 (IntToInt); ++ _0 = unchecked_shr::(_3, move _5) -> [return: bb1, unwind unreachable]; + } + + bb1: { ++ StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff new file mode 100644 index 0000000000000..762aa1564b507 --- /dev/null +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff @@ -0,0 +1,36 @@ +- // MIR for `unchecked_shr_signed_bigger` before Inline ++ // MIR for `unchecked_shr_signed_bigger` after Inline + + fn unchecked_shr_signed_bigger(_1: i64, _2: u32) -> i64 { + debug a => _1; + debug b => _2; + let mut _0: i64; + let mut _3: i64; + let mut _4: u32; ++ scope 1 (inlined core::num::::unchecked_shr) { ++ debug self => _3; ++ debug rhs => _4; ++ let mut _5: i64; ++ scope 2 { ++ } ++ } + + bb0: { + StorageLive(_3); + _3 = _1; + StorageLive(_4); + _4 = _2; +- _0 = core::num::::unchecked_shr(move _3, move _4) -> bb1; ++ StorageLive(_5); ++ _5 = _4 as i64 (IntToInt); ++ _0 = unchecked_shr::(_3, move _5) -> [return: bb1, unwind unreachable]; + } + + bb1: { ++ StorageDead(_5); + StorageDead(_4); + StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir new file mode 100644 index 0000000000000..858760d065c94 --- /dev/null +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir @@ -0,0 +1,25 @@ +// MIR for `unchecked_shr_signed_bigger` after PreCodegen + +fn unchecked_shr_signed_bigger(_1: i64, _2: u32) -> i64 { + debug a => _1; + debug b => _2; + let mut _0: i64; + scope 1 (inlined core::num::::unchecked_shr) { + debug self => _1; + debug rhs => _2; + let mut _3: i64; + scope 2 { + } + } + + bb0: { + StorageLive(_3); + _3 = _2 as i64 (IntToInt); + _0 = unchecked_shr::(_1, move _3) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_3); + return; + } +} diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir new file mode 100644 index 0000000000000..858760d065c94 --- /dev/null +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir @@ -0,0 +1,25 @@ +// MIR for `unchecked_shr_signed_bigger` after PreCodegen + +fn unchecked_shr_signed_bigger(_1: i64, _2: u32) -> i64 { + debug a => _1; + debug b => _2; + let mut _0: i64; + scope 1 (inlined core::num::::unchecked_shr) { + debug self => _1; + debug rhs => _2; + let mut _3: i64; + scope 2 { + } + } + + bb0: { + StorageLive(_3); + _3 = _2 as i64 (IntToInt); + _0 = unchecked_shr::(_1, move _3) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_3); + return; + } +} diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-abort.diff index 1659a51b090d2..5739336cb4f3c 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-abort.diff @@ -7,16 +7,36 @@ let mut _0: i16; let mut _3: i16; let mut _4: u32; ++ scope 1 (inlined core::num::::unchecked_shr) { ++ debug self => _3; ++ debug rhs => _4; ++ let mut _5: i16; ++ let mut _6: bool; ++ let mut _7: u32; ++ scope 2 { ++ } ++ } bb0: { StorageLive(_3); _3 = _1; StorageLive(_4); _4 = _2; - _0 = core::num::::unchecked_shr(move _3, move _4) -> [return: bb1, unwind unreachable]; +- _0 = core::num::::unchecked_shr(move _3, move _4) -> [return: bb1, unwind unreachable]; ++ StorageLive(_5); ++ StorageLive(_6); ++ StorageLive(_7); ++ _7 = const 32767_u32; ++ _6 = Le(_4, move _7); ++ StorageDead(_7); ++ assume(move _6); ++ StorageDead(_6); ++ _5 = _4 as i16 (IntToInt); ++ _0 = unchecked_shr::(_3, move _5) -> [return: bb1, unwind unreachable]; } bb1: { ++ StorageDead(_5); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff index cb5ec37feb360..e04912e1d1cff 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff @@ -7,16 +7,36 @@ let mut _0: i16; let mut _3: i16; let mut _4: u32; ++ scope 1 (inlined core::num::::unchecked_shr) { ++ debug self => _3; ++ debug rhs => _4; ++ let mut _5: i16; ++ let mut _6: bool; ++ let mut _7: u32; ++ scope 2 { ++ } ++ } bb0: { StorageLive(_3); _3 = _1; StorageLive(_4); _4 = _2; - _0 = core::num::::unchecked_shr(move _3, move _4) -> bb1; +- _0 = core::num::::unchecked_shr(move _3, move _4) -> bb1; ++ StorageLive(_5); ++ StorageLive(_6); ++ StorageLive(_7); ++ _7 = const 32767_u32; ++ _6 = Le(_4, move _7); ++ StorageDead(_7); ++ assume(move _6); ++ StorageDead(_6); ++ _5 = _4 as i16 (IntToInt); ++ _0 = unchecked_shr::(_3, move _5) -> [return: bb1, unwind unreachable]; } bb1: { ++ StorageDead(_5); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-abort.mir index 9f2f40002a32d..08b044f4f9e62 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-abort.mir @@ -4,12 +4,31 @@ fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 { debug a => _1; debug b => _2; let mut _0: i16; + scope 1 (inlined core::num::::unchecked_shr) { + debug self => _1; + debug rhs => _2; + let mut _3: u32; + let mut _4: bool; + let mut _5: i16; + scope 2 { + } + } bb0: { - _0 = core::num::::unchecked_shr(_1, _2) -> [return: bb1, unwind unreachable]; + StorageLive(_5); + StorageLive(_4); + StorageLive(_3); + _3 = const 32767_u32; + _4 = Le(_2, move _3); + StorageDead(_3); + assume(move _4); + StorageDead(_4); + _5 = _2 as i16 (IntToInt); + _0 = unchecked_shr::(_1, move _5) -> [return: bb1, unwind unreachable]; } bb1: { + StorageDead(_5); return; } } diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-unwind.mir index aaf3bb62e8a33..08b044f4f9e62 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.panic-unwind.mir @@ -4,12 +4,31 @@ fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 { debug a => _1; debug b => _2; let mut _0: i16; + scope 1 (inlined core::num::::unchecked_shr) { + debug self => _1; + debug rhs => _2; + let mut _3: u32; + let mut _4: bool; + let mut _5: i16; + scope 2 { + } + } bb0: { - _0 = core::num::::unchecked_shr(_1, _2) -> bb1; + StorageLive(_5); + StorageLive(_4); + StorageLive(_3); + _3 = const 32767_u32; + _4 = Le(_2, move _3); + StorageDead(_3); + assume(move _4); + StorageDead(_4); + _5 = _2 as i16 (IntToInt); + _0 = unchecked_shr::(_1, move _5) -> [return: bb1, unwind unreachable]; } bb1: { + StorageDead(_5); return; } } diff --git a/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir index 10b93a15799bd..1a7d5433e3597 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir @@ -7,17 +7,17 @@ fn checked_shl(_1: u32, _2: u32) -> Option { scope 1 (inlined core::num::::checked_shl) { debug self => _1; debug rhs => _2; - let mut _11: u32; - let mut _12: bool; + let mut _7: u32; + let mut _8: bool; scope 2 { - debug a => _11; - debug b => _10; + debug a => _7; + debug b => _6; } scope 3 (inlined core::num::::overflowing_shl) { debug self => _1; debug rhs => _2; - let mut _9: u32; - let mut _10: bool; + let mut _5: u32; + let mut _6: bool; scope 4 (inlined core::num::::wrapping_shl) { debug self => _1; debug rhs => _2; @@ -27,52 +27,7 @@ fn checked_shl(_1: u32, _2: u32) -> Option { scope 6 (inlined core::num::::unchecked_shl) { debug self => _1; debug rhs => _4; - let mut _8: u32; scope 7 { - scope 8 (inlined core::num::::unchecked_shl::conv) { - debug x => _4; - let mut _5: std::result::Result; - let mut _7: std::option::Option; - scope 9 { - scope 10 (inlined >::try_into) { - debug self => _4; - scope 11 (inlined >::try_from) { - debug value => _4; - scope 12 (inlined >::into) { - debug self => _4; - scope 13 (inlined >::from) { - debug t => _4; - } - } - } - } - scope 14 (inlined Result::::ok) { - debug self => _5; - let _6: u32; - scope 15 { - debug x => _6; - } - } - scope 16 (inlined #[track_caller] Option::::unwrap_unchecked) { - debug self => _7; - let mut _13: &std::option::Option; - scope 17 { - debug val => _8; - } - scope 18 { - scope 20 (inlined unreachable_unchecked) { - scope 21 { - scope 22 (inlined unreachable_unchecked::runtime) { - } - } - } - } - scope 19 (inlined Option::::is_some) { - debug self => _13; - } - } - } - } } } } @@ -81,46 +36,32 @@ fn checked_shl(_1: u32, _2: u32) -> Option { } bb0: { - StorageLive(_10); - StorageLive(_11); - StorageLive(_9); + StorageLive(_6); + StorageLive(_7); + StorageLive(_5); StorageLive(_4); StorageLive(_3); _3 = const 31_u32; _4 = BitAnd(_2, move _3); StorageDead(_3); - StorageLive(_8); - StorageLive(_7); - StorageLive(_5); - _5 = Result::::Ok(_4); - StorageLive(_6); - _6 = move ((_5 as Ok).0: u32); - _7 = Option::::Some(move _6); - StorageDead(_6); - StorageDead(_5); - StorageLive(_13); - _8 = move ((_7 as Some).0: u32); - StorageDead(_13); - StorageDead(_7); - _9 = unchecked_shl::(_1, move _8) -> [return: bb1, unwind unreachable]; + _5 = unchecked_shl::(_1, _4) -> [return: bb1, unwind unreachable]; } bb1: { - StorageDead(_8); StorageDead(_4); - _10 = Ge(_2, const _); - _11 = move _9; - StorageDead(_9); - StorageLive(_12); - _12 = unlikely(_10) -> [return: bb2, unwind unreachable]; + _6 = Ge(_2, const _); + _7 = move _5; + StorageDead(_5); + StorageLive(_8); + _8 = unlikely(_6) -> [return: bb2, unwind unreachable]; } bb2: { - switchInt(move _12) -> [0: bb3, otherwise: bb4]; + switchInt(move _8) -> [0: bb3, otherwise: bb4]; } bb3: { - _0 = Option::::Some(_11); + _0 = Option::::Some(_7); goto -> bb5; } @@ -130,9 +71,9 @@ fn checked_shl(_1: u32, _2: u32) -> Option { } bb5: { - StorageDead(_12); - StorageDead(_11); - StorageDead(_10); + StorageDead(_8); + StorageDead(_7); + StorageDead(_6); return; } } From 22d00dcd47e0b8e18eb254966750fb523c726e4e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 10 Jun 2023 12:06:17 -0400 Subject: [PATCH 250/465] Apply changes to fix python linting errors --- .../tools/generate_intrinsics.py | 3 +-- library/core/src/unicode/printable.py | 2 +- src/bootstrap/bootstrap.py | 4 ++-- src/bootstrap/configure.py | 10 +++++----- src/ci/cpu-usage-over-time.py | 0 .../test-various/uefi_qemu_test/run.py | 0 src/ci/docker/scripts/android-sdk-manager.py | 17 ++++++++-------- src/ci/docker/scripts/fuchsia-test-runner.py | 4 ++-- src/ci/stage-build.py | 4 ++-- src/etc/dec2flt_table.py | 4 +--- src/etc/gdb_load_rust_pretty_printers.py | 1 + src/etc/generate-deriving-span-tests.py | 4 +++- src/etc/htmldocck.py | 8 +++++--- src/etc/lldb_batchmode.py | 2 +- src/etc/lldb_providers.py | 2 +- src/etc/test-float-parse/runtests.py | 0 src/tools/miri/test-cargo-miri/run-test.py | 20 +++++++++++++------ src/tools/publish_toolstate.py | 16 +++++++-------- .../coverage-reports/sort_subviews.py | 0 .../run-make/libtest-junit/validate_junit.py | 2 +- .../rustdoc-map-file/validate_json.py | 2 +- .../sysroot-crates-are-unstable/test.py | 2 +- 22 files changed, 58 insertions(+), 49 deletions(-) mode change 100644 => 100755 src/ci/cpu-usage-over-time.py mode change 100644 => 100755 src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py mode change 100644 => 100755 src/ci/stage-build.py mode change 100644 => 100755 src/etc/dec2flt_table.py mode change 100644 => 100755 src/etc/htmldocck.py mode change 100644 => 100755 src/etc/test-float-parse/runtests.py mode change 100644 => 100755 tests/run-make/coverage-reports/sort_subviews.py diff --git a/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py b/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py index 6188924b0d50a..83abe145e64f0 100644 --- a/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py +++ b/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py @@ -3,7 +3,6 @@ import re import sys import subprocess -from os import walk def run_command(command, cwd=None): @@ -180,7 +179,7 @@ def update_intrinsics(llvm_path, llvmint, llvmint2): intrinsics[arch].sort(key=lambda x: (x[0], x[2])) out.write(' // {}\n'.format(arch)) for entry in intrinsics[arch]: - if entry[2] == True: # if it is a duplicate + if entry[2] is True: # if it is a duplicate out.write(' // [DUPLICATE]: "{}" => "{}",\n'.format(entry[0], entry[1])) elif "_round_mask" in entry[1]: out.write(' // [INVALID CONVERSION]: "{}" => "{}",\n'.format(entry[0], entry[1])) diff --git a/library/core/src/unicode/printable.py b/library/core/src/unicode/printable.py index 7c37f5f099c7f..4d39ace066c46 100755 --- a/library/core/src/unicode/printable.py +++ b/library/core/src/unicode/printable.py @@ -119,7 +119,7 @@ def print_singletons(uppers, lowers, uppersname, lowersname): print("#[rustfmt::skip]") print("const {}: &[u8] = &[".format(lowersname)) for i in range(0, len(lowers), 8): - print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8]))) + print(" {}".format(" ".join("{:#04x},".format(x) for x in lowers[i:i+8]))) print("];") def print_normal(normal, normalname): diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 473fdbe1edc27..5714613cdf512 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -620,7 +620,7 @@ def get_answer(): # The latter one does not exist on NixOS when using tmpfs as root. try: with open("/etc/os-release", "r") as f: - if not any(l.strip() in ("ID=nixos", "ID='nixos'", 'ID="nixos"') for l in f): + if not any(ln.strip() in ("ID=nixos", "ID='nixos'", 'ID="nixos"') for ln in f): return False except FileNotFoundError: return False @@ -872,7 +872,7 @@ def build_bootstrap(self, color, warnings, verbose_count): } for var_name, toml_key in var_data.items(): toml_val = self.get_toml(toml_key, build_section) - if toml_val != None: + if toml_val is not None: env["{}_{}".format(var_name, host_triple_sanitized)] = toml_val # preserve existing RUSTFLAGS diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 4481e1668b60f..a16f77317c82b 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -9,7 +9,7 @@ rust_dir = os.path.dirname(rust_dir) rust_dir = os.path.dirname(rust_dir) sys.path.append(os.path.join(rust_dir, "src", "bootstrap")) -import bootstrap +import bootstrap # noqa: E402 class Option(object): @@ -319,7 +319,7 @@ def apply_args(known_args, option_checking, config): for key in known_args: # The `set` option is special and can be passed a bunch of times if key == 'set': - for option, value in known_args[key]: + for _option, value in known_args[key]: keyval = value.split('=', 1) if len(keyval) == 1 or keyval[1] == "true": value = True @@ -401,7 +401,7 @@ def parse_example_config(known_args, config): top_level_keys = [] for line in open(rust_dir + '/config.example.toml').read().split("\n"): - if cur_section == None: + if cur_section is None: if line.count('=') == 1: top_level_key = line.split('=')[0] top_level_key = top_level_key.strip(' #') @@ -523,8 +523,8 @@ def write_uncommented(target, f): block.append(line) if len(line) == 0: if not is_comment: - for l in block: - f.write(l + "\n") + for ln in block: + f.write(ln + "\n") block = [] is_comment = True continue diff --git a/src/ci/cpu-usage-over-time.py b/src/ci/cpu-usage-over-time.py old mode 100644 new mode 100755 diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py old mode 100644 new mode 100755 diff --git a/src/ci/docker/scripts/android-sdk-manager.py b/src/ci/docker/scripts/android-sdk-manager.py index c9e2961f6eb15..66cba58427bad 100755 --- a/src/ci/docker/scripts/android-sdk-manager.py +++ b/src/ci/docker/scripts/android-sdk-manager.py @@ -2,6 +2,14 @@ # Simpler reimplementation of Android's sdkmanager # Extra features of this implementation are pinning and mirroring +import argparse +import hashlib +import os +import subprocess +import tempfile +import urllib.request +import xml.etree.ElementTree as ET + # These URLs are the Google repositories containing the list of available # packages and their versions. The list has been generated by listing the URLs # fetched while executing `tools/bin/sdkmanager --list` @@ -27,15 +35,6 @@ MIRROR_BUCKET_REGION = "us-west-1" MIRROR_BASE_DIR = "rustc/android/" -import argparse -import hashlib -import os -import subprocess -import sys -import tempfile -import urllib.request -import xml.etree.ElementTree as ET - class Package: def __init__(self, path, url, sha1, deps=None): if deps is None: diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py index ecef56f56f1d5..77144b7499634 100755 --- a/src/ci/docker/scripts/fuchsia-test-runner.py +++ b/src/ci/docker/scripts/fuchsia-test-runner.py @@ -568,8 +568,8 @@ def log(msg): env_vars += f'\n "{var_name}={var_value}",' # Default to no backtrace for test suite - if os.getenv("RUST_BACKTRACE") == None: - env_vars += f'\n "RUST_BACKTRACE=0",' + if os.getenv("RUST_BACKTRACE") is None: + env_vars += '\n "RUST_BACKTRACE=0",' cml.write( self.CML_TEMPLATE.format(env_vars=env_vars, exe_name=exe_name) diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py old mode 100644 new mode 100755 index febc0492b9433..3f30b69e8f472 --- a/src/ci/stage-build.py +++ b/src/ci/stage-build.py @@ -440,7 +440,7 @@ def retry_action(action, name: str, max_fails: int = 5): try: action() return - except: + except BaseException: # also catch ctrl+c/sysexit LOGGER.error(f"Action `{name}` has failed\n{traceback.format_exc()}") raise Exception(f"Action `{name}` has failed after {max_fails} attempts") @@ -818,7 +818,7 @@ def extract_dist_dir(name: str) -> Path: # Extract rustc, libstd, cargo and src archives to create the optimized sysroot rustc_dir = extract_dist_dir(f"rustc-nightly-{PGO_HOST}") / "rustc" libstd_dir = extract_dist_dir(f"rust-std-nightly-{PGO_HOST}") / f"rust-std-{PGO_HOST}" - cargo_dir = extract_dist_dir(f"cargo-nightly-{PGO_HOST}") / f"cargo" + cargo_dir = extract_dist_dir(f"cargo-nightly-{PGO_HOST}") / "cargo" extracted_src_dir = extract_dist_dir("rust-src-nightly") / "rust-src" # We need to manually copy libstd to the extracted rustc sysroot diff --git a/src/etc/dec2flt_table.py b/src/etc/dec2flt_table.py old mode 100644 new mode 100755 index aa5188d96c3e7..9264a8439bb71 --- a/src/etc/dec2flt_table.py +++ b/src/etc/dec2flt_table.py @@ -14,8 +14,7 @@ available here: . """ from __future__ import print_function -from math import ceil, floor, log, log2 -from fractions import Fraction +from math import ceil, floor, log from collections import deque HEADER = """ @@ -97,7 +96,6 @@ def print_proper_powers(min_exp, max_exp, bias): print('#[rustfmt::skip]') typ = '[(u64, u64); N_POWERS_OF_FIVE]' print('pub static POWER_OF_FIVE_128: {} = ['.format(typ)) - lo_mask = (1 << 64) - 1 for c, exp in powers: hi = '0x{:x}'.format(c // (1 << 64)) lo = '0x{:x}'.format(c % (1 << 64)) diff --git a/src/etc/gdb_load_rust_pretty_printers.py b/src/etc/gdb_load_rust_pretty_printers.py index 491b6ba9e9e69..e05039ce47447 100644 --- a/src/etc/gdb_load_rust_pretty_printers.py +++ b/src/etc/gdb_load_rust_pretty_printers.py @@ -4,6 +4,7 @@ self_dir = path.dirname(path.realpath(__file__)) sys.path.append(self_dir) +# ruff: noqa: E402 import gdb import gdb_lookup diff --git a/src/etc/generate-deriving-span-tests.py b/src/etc/generate-deriving-span-tests.py index d38f5add7474d..d61693460bc1f 100755 --- a/src/etc/generate-deriving-span-tests.py +++ b/src/etc/generate-deriving-span-tests.py @@ -102,7 +102,9 @@ def write_file(name, string): traits[trait] = (ALL, supers, errs) for (trait, (types, super_traits, error_count)) in traits.items(): - mk = lambda ty: create_test_case(ty, trait, super_traits, error_count) + def mk(ty, t=trait, st=super_traits, ec=error_count): + return create_test_case(ty, t, st, ec) + if types & ENUM: write_file(trait + '-enum', mk(ENUM_TUPLE)) write_file(trait + '-enum-struct-variant', mk(ENUM_STRUCT)) diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py old mode 100644 new mode 100755 index c97fb4b805473..eade9e0455912 --- a/src/etc/htmldocck.py +++ b/src/etc/htmldocck.py @@ -144,7 +144,7 @@ # Python 2 -> 3 compatibility try: - unichr + unichr # noqa: B018 FIXME: py2 except NameError: unichr = chr @@ -348,7 +348,9 @@ def get_tree(self, path): try: tree = ET.fromstringlist(f.readlines(), CustomHTMLParser()) except Exception as e: - raise RuntimeError('Cannot parse an HTML file {!r}: {}'.format(path, e)) + raise RuntimeError( # noqa: B904 FIXME: py2 + 'Cannot parse an HTML file {!r}: {}'.format(path, e) + ) self.trees[path] = tree return self.trees[path] @@ -422,7 +424,7 @@ def check_snapshot(snapshot_name, actual_tree, normalize_to_text): if bless: expected_str = None else: - raise FailedCheck('No saved snapshot value') + raise FailedCheck('No saved snapshot value') # noqa: B904 FIXME: py2 if not normalize_to_text: actual_str = ET.tostring(actual_tree).decode('utf-8') diff --git a/src/etc/lldb_batchmode.py b/src/etc/lldb_batchmode.py index fc355c87b52a2..db1e0035ea063 100644 --- a/src/etc/lldb_batchmode.py +++ b/src/etc/lldb_batchmode.py @@ -124,7 +124,7 @@ def listen(): breakpoint = lldb.SBBreakpoint.GetBreakpointFromEvent(event) print_debug("breakpoint added, id = " + str(breakpoint.id)) new_breakpoints.append(breakpoint.id) - except: + except BaseException: # explicitly catch ctrl+c/sysexit print_debug("breakpoint listener shutting down") # Start the listener and let it run as a daemon diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index c4381e202b945..4c86b2146463d 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -1,6 +1,6 @@ import sys -from lldb import SBValue, SBData, SBError, eBasicTypeLong, eBasicTypeUnsignedLong, \ +from lldb import SBData, SBError, eBasicTypeLong, eBasicTypeUnsignedLong, \ eBasicTypeUnsignedChar # from lldb.formatters import Logger diff --git a/src/etc/test-float-parse/runtests.py b/src/etc/test-float-parse/runtests.py old mode 100644 new mode 100755 diff --git a/src/tools/miri/test-cargo-miri/run-test.py b/src/tools/miri/test-cargo-miri/run-test.py index 9df90c725e40f..f022c51e59fa8 100755 --- a/src/tools/miri/test-cargo-miri/run-test.py +++ b/src/tools/miri/test-cargo-miri/run-test.py @@ -5,7 +5,11 @@ and the working directory to contain the cargo-miri-test project. ''' -import sys, subprocess, os, re, difflib +import difflib +import os +import re +import sys +import subprocess CGREEN = '\33[32m' CBOLD = '\33[1m' @@ -46,7 +50,9 @@ def check_output(actual, path, name): print(f"--- END diff {name} ---") return False -def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): +def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env=None): + if env is None: + env = {} print("Testing {}...".format(name)) ## Call `cargo miri`, capture all output p_env = os.environ.copy() @@ -64,13 +70,15 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): stdout_matches = check_output(stdout, stdout_ref, "stdout") stderr_matches = check_output(stderr, stderr_ref, "stderr") - + if p.returncode == 0 and stdout_matches and stderr_matches: # All good! return fail("exit code was {}".format(p.returncode)) -def test_no_rebuild(name, cmd, env={}): +def test_no_rebuild(name, cmd, env=None): + if env is None: + env = {} print("Testing {}...".format(name)) p_env = os.environ.copy() p_env.update(env) @@ -84,13 +92,13 @@ def test_no_rebuild(name, cmd, env={}): stdout = stdout.decode("UTF-8") stderr = stderr.decode("UTF-8") if p.returncode != 0: - fail("rebuild failed"); + fail("rebuild failed") # Also check for 'Running' as a sanity check. if stderr.count(" Compiling ") > 0 or stderr.count(" Running ") == 0: print("--- BEGIN stderr ---") print(stderr, end="") print("--- END stderr ---") - fail("Something was being rebuilt when it should not be (or we got no output)"); + fail("Something was being rebuilt when it should not be (or we got no output)") def test_cargo_miri_run(): test("`cargo miri run` (no isolation)", diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 2018c239ba068..f9421117eaa2e 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -22,7 +22,7 @@ import urllib.request as urllib2 from urllib.error import HTTPError try: - import typing + import typing # noqa: F401 FIXME: py2 except ImportError: pass @@ -152,8 +152,8 @@ def update_latest( latest = json.load(f, object_pairs_hook=collections.OrderedDict) current_status = { - os: read_current_status(current_commit, 'history/' + os + '.tsv') - for os in ['windows', 'linux'] + os_: read_current_status(current_commit, 'history/' + os_ + '.tsv') + for os_ in ['windows', 'linux'] } slug = 'rust-lang/rust' @@ -170,10 +170,10 @@ def update_latest( changed = False create_issue_for_status = None # set to the status that caused the issue - for os, s in current_status.items(): - old = status[os] + for os_, s in current_status.items(): + old = status[os_] new = s.get(tool, old) - status[os] = new + status[os_] = new maintainers = ' '.join('@'+name for name in MAINTAINERS.get(tool, ())) # comparing the strings, but they are ordered appropriately: # "test-pass" > "test-fail" > "build-fail" @@ -181,12 +181,12 @@ def update_latest( # things got fixed or at least the status quo improved changed = True message += '🎉 {} on {}: {} → {} (cc {}).\n' \ - .format(tool, os, old, new, maintainers) + .format(tool, os_, old, new, maintainers) elif new < old: # tests or builds are failing and were not failing before changed = True title = '💔 {} on {}: {} → {}' \ - .format(tool, os, old, new) + .format(tool, os_, old, new) message += '{} (cc {}).\n' \ .format(title, maintainers) # See if we need to create an issue. diff --git a/tests/run-make/coverage-reports/sort_subviews.py b/tests/run-make/coverage-reports/sort_subviews.py old mode 100644 new mode 100755 diff --git a/tests/run-make/libtest-junit/validate_junit.py b/tests/run-make/libtest-junit/validate_junit.py index 47a8e70ccc38c..0d9b34a3cf7e0 100755 --- a/tests/run-make/libtest-junit/validate_junit.py +++ b/tests/run-make/libtest-junit/validate_junit.py @@ -7,6 +7,6 @@ for line in sys.stdin: try: ET.fromstring(line) - except ET.ParseError as pe: + except ET.ParseError: print("Invalid xml: %r" % line) raise diff --git a/tests/run-make/rustdoc-map-file/validate_json.py b/tests/run-make/rustdoc-map-file/validate_json.py index 5c14c90b70d37..912dea3791bbf 100755 --- a/tests/run-make/rustdoc-map-file/validate_json.py +++ b/tests/run-make/rustdoc-map-file/validate_json.py @@ -6,7 +6,7 @@ def find_redirect_map_file(folder, errors): - for root, dirs, files in os.walk(folder): + for root, _dirs, files in os.walk(folder): for name in files: if not name.endswith("redirect-map.json"): continue diff --git a/tests/run-make/sysroot-crates-are-unstable/test.py b/tests/run-make/sysroot-crates-are-unstable/test.py index cab4faa4e645a..45cfdd195b4e2 100644 --- a/tests/run-make/sysroot-crates-are-unstable/test.py +++ b/tests/run-make/sysroot-crates-are-unstable/test.py @@ -46,7 +46,7 @@ def check_lib(lib): '--target', os.environ['TARGET'], '--extern', '{}={}'.format(lib['name'], lib['path'])], to_input=('extern crate {};'.format(lib['name'])).encode('utf-8')) - if not 'use of unstable library feature' in '{}{}'.format(stdout, stderr): + if 'use of unstable library feature' not in '{}{}'.format(stdout, stderr): print('crate {} "{}" is not unstable'.format(lib['name'], lib['path'])) print('{}{}'.format(stdout, stderr)) print('') From 64a8887a94da223de6858090ceddc8079a01aa35 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 17 Jun 2023 09:55:48 +0200 Subject: [PATCH 251/465] Add body lowering step, track time of each step separtely --- .../rust-analyzer/src/cli/analysis_stats.rs | 91 ++++++++++++++++++- crates/rust-analyzer/src/cli/flags.rs | 3 + 2 files changed, 89 insertions(+), 5 deletions(-) diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index e0767b39ef45e..f384b7840c8a3 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -176,8 +176,11 @@ impl flags::AnalysisStats { shuffle(&mut rng, &mut bodies); } + if !self.skip_lowering { + self.run_body_lowering(db, &vfs, &bodies, verbosity); + } + if !self.skip_inference { - // FIXME: Consider running inference on all body kinds? self.run_inference(db, &vfs, &bodies, verbosity); } @@ -255,9 +258,11 @@ impl flags::AnalysisStats { } fail += 1; } - eprintln!("{:<20} {}", "Data layouts:", sw.elapsed()); + let data_layout_time = sw.elapsed(); + eprintln!("{:<20} {}", "Data layouts:", data_layout_time); eprintln!("Failed data layouts: {fail} ({}%)", percentage(fail, all)); report_metric("failed data layouts", fail, "#"); + report_metric("data layout time", data_layout_time.time.as_millis() as u64, "ms"); } fn run_const_eval(&self, db: &RootDatabase, consts: &[hir::Const], verbosity: Verbosity) { @@ -283,9 +288,11 @@ impl flags::AnalysisStats { } fail += 1; } - eprintln!("{:<20} {}", "Const evaluation:", sw.elapsed()); + let const_eval_time = sw.elapsed(); + eprintln!("{:<20} {}", "Const evaluation:", const_eval_time); eprintln!("Failed const evals: {fail} ({}%)", percentage(fail, all)); report_metric("failed const evals", fail, "#"); + report_metric("const eval time", const_eval_time.time.as_millis() as u64, "ms"); } fn run_mir_lowering(&self, db: &RootDatabase, bodies: &[DefWithBody], verbosity: Verbosity) { @@ -310,9 +317,11 @@ impl flags::AnalysisStats { } fail += 1; } - eprintln!("{:<20} {}", "MIR lowering:", sw.elapsed()); + let mir_lowering_time = sw.elapsed(); + eprintln!("{:<20} {}", "MIR lowering:", mir_lowering_time); eprintln!("Mir failed bodies: {fail} ({}%)", percentage(fail, all)); report_metric("mir failed bodies", fail, "#"); + report_metric("mir lowering time", mir_lowering_time.time.as_millis() as u64, "ms"); } fn run_inference( @@ -596,6 +605,7 @@ impl flags::AnalysisStats { } bar.finish_and_clear(); + let inference_time = inference_sw.elapsed(); eprintln!( " exprs: {}, ??ty: {} ({}%), ?ty: {} ({}%), !ty: {}", num_exprs, @@ -614,12 +624,83 @@ impl flags::AnalysisStats { percentage(num_pats_partially_unknown, num_pats), num_pat_type_mismatches ); + eprintln!("{:<20} {}", "Inference:", inference_time); report_metric("unknown type", num_exprs_unknown, "#"); report_metric("type mismatches", num_expr_type_mismatches, "#"); report_metric("pattern unknown type", num_pats_unknown, "#"); report_metric("pattern type mismatches", num_pat_type_mismatches, "#"); + report_metric("inference time", inference_time.time.as_millis() as u64, "ms"); + } + + fn run_body_lowering( + &self, + db: &RootDatabase, + vfs: &Vfs, + bodies: &[DefWithBody], + verbosity: Verbosity, + ) { + let mut bar = match verbosity { + Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(), + _ if self.parallel || self.output.is_some() => ProgressReport::hidden(), + _ => ProgressReport::new(bodies.len() as u64), + }; + + let mut sw = self.stop_watch(); + bar.tick(); + for &body_id in bodies { + let name = body_id.name(db).unwrap_or_else(Name::missing); + let module = body_id.module(db); + let full_name = || { + module + .krate() + .display_name(db) + .map(|it| it.canonical_name().to_string()) + .into_iter() + .chain( + module + .path_to_root(db) + .into_iter() + .filter_map(|it| it.name(db)) + .rev() + .chain(Some(name.clone())) + .map(|it| it.display(db).to_string()), + ) + .join("::") + }; + if let Some(only_name) = self.only.as_deref() { + if name.display(db).to_string() != only_name && full_name() != only_name { + continue; + } + } + let mut msg = format!("processing: {}", full_name()); + if verbosity.is_verbose() { + let source = match body_id { + DefWithBody::Function(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::Static(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::Const(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::Variant(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::InTypeConst(_) => unimplemented!(), + }; + if let Some(src) = source { + let original_file = src.file_id.original_file(db); + let path = vfs.file_path(original_file); + let syntax_range = src.value.text_range(); + format_to!(msg, " ({} {:?})", path, syntax_range); + } + } + if verbosity.is_spammy() { + bar.println(msg.to_string()); + } + bar.set_message(&msg); + let (body, sm) = db.body_with_source_map(body_id.into()); + // endregion:patterns + bar.inc(1); + } - eprintln!("{:<20} {}", "Inference:", inference_sw.elapsed()); + bar.finish_and_clear(); + let body_lowering_time = sw.elapsed(); + eprintln!("{:<20} {}", "Body lowering:", body_lowering_time); + report_metric("body lowering time", body_lowering_time.time.as_millis() as u64, "ms"); } fn stop_watch(&self) -> StopWatch { diff --git a/crates/rust-analyzer/src/cli/flags.rs b/crates/rust-analyzer/src/cli/flags.rs index 923be8b072882..208a4e6ecd93d 100644 --- a/crates/rust-analyzer/src/cli/flags.rs +++ b/crates/rust-analyzer/src/cli/flags.rs @@ -78,6 +78,8 @@ xflags::xflags! { optional --disable-build-scripts /// Don't use expand proc macros. optional --disable-proc-macros + /// Skip body lowering. + optional --skip-lowering /// Skip type inference. optional --skip-inference /// Skip lowering to mir @@ -180,6 +182,7 @@ pub struct AnalysisStats { pub parallel: bool, pub memory_usage: bool, pub source_stats: bool, + pub skip_lowering: bool, pub skip_inference: bool, pub skip_mir_stats: bool, pub skip_data_layout: bool, From b5e0452c71807d5c270e21534a03ce3d7ef66b61 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 17 Jun 2023 10:34:44 +0200 Subject: [PATCH 252/465] Lazy progress reporting --- .../rust-analyzer/src/cli/analysis_stats.rs | 104 ++++++++++-------- .../rust-analyzer/src/cli/progress_report.rs | 41 +++---- 2 files changed, 75 insertions(+), 70 deletions(-) diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index f384b7840c8a3..01bc0d77dd5b9 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -29,7 +29,6 @@ use profile::{Bytes, StopWatch}; use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource}; use rayon::prelude::*; use rustc_hash::FxHashSet; -use stdx::format_to; use syntax::{AstNode, SyntaxNode}; use vfs::{AbsPathBuf, Vfs, VfsPath}; @@ -241,8 +240,10 @@ impl flags::AnalysisStats { continue; } all += 1; - let Err(e) = db.layout_of_adt(hir_def::AdtId::from(a).into(), Substitution::empty(Interner), a.krate(db).into()) else { - continue; + let Err(e) + = db.layout_of_adt(hir_def::AdtId::from(a).into(), Substitution::empty(Interner), a.krate(db).into()) + else { + continue }; if verbosity.is_spammy() { let full_name = a @@ -363,7 +364,7 @@ impl flags::AnalysisStats { for &body_id in bodies { let name = body_id.name(db).unwrap_or_else(Name::missing); let module = body_id.module(db); - let full_name = || { + let full_name = move || { module .krate() .display_name(db) @@ -375,7 +376,7 @@ impl flags::AnalysisStats { .into_iter() .filter_map(|it| it.name(db)) .rev() - .chain(Some(name.clone())) + .chain(Some(body_id.name(db).unwrap_or_else(Name::missing))) .map(|it| it.display(db).to_string()), ) .join("::") @@ -385,26 +386,31 @@ impl flags::AnalysisStats { continue; } } - let mut msg = format!("processing: {}", full_name()); - if verbosity.is_verbose() { - let source = match body_id { - DefWithBody::Function(it) => it.source(db).map(|it| it.syntax().cloned()), - DefWithBody::Static(it) => it.source(db).map(|it| it.syntax().cloned()), - DefWithBody::Const(it) => it.source(db).map(|it| it.syntax().cloned()), - DefWithBody::Variant(it) => it.source(db).map(|it| it.syntax().cloned()), - DefWithBody::InTypeConst(_) => unimplemented!(), - }; - if let Some(src) = source { - let original_file = src.file_id.original_file(db); - let path = vfs.file_path(original_file); - let syntax_range = src.value.text_range(); - format_to!(msg, " ({} {:?})", path, syntax_range); + let msg = move || { + if verbosity.is_verbose() { + let source = match body_id { + DefWithBody::Function(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::Static(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::Const(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::Variant(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::InTypeConst(_) => unimplemented!(), + }; + if let Some(src) = source { + let original_file = src.file_id.original_file(db); + let path = vfs.file_path(original_file); + let syntax_range = src.value.text_range(); + format!("processing: {} ({} {:?})", full_name(), path, syntax_range) + } else { + format!("processing: {}", full_name()) + } + } else { + format!("processing: {}", full_name()) } - } + }; if verbosity.is_spammy() { - bar.println(msg.to_string()); + bar.println(msg()); } - bar.set_message(&msg); + bar.set_message(msg); let (body, sm) = db.body_with_source_map(body_id.into()); let inference_result = db.infer(body_id.into()); @@ -641,16 +647,15 @@ impl flags::AnalysisStats { ) { let mut bar = match verbosity { Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(), - _ if self.parallel || self.output.is_some() => ProgressReport::hidden(), + _ if self.output.is_some() => ProgressReport::hidden(), _ => ProgressReport::new(bodies.len() as u64), }; let mut sw = self.stop_watch(); bar.tick(); for &body_id in bodies { - let name = body_id.name(db).unwrap_or_else(Name::missing); let module = body_id.module(db); - let full_name = || { + let full_name = move || { module .krate() .display_name(db) @@ -662,38 +667,45 @@ impl flags::AnalysisStats { .into_iter() .filter_map(|it| it.name(db)) .rev() - .chain(Some(name.clone())) + .chain(Some(body_id.name(db).unwrap_or_else(Name::missing))) .map(|it| it.display(db).to_string()), ) .join("::") }; if let Some(only_name) = self.only.as_deref() { - if name.display(db).to_string() != only_name && full_name() != only_name { + if body_id.name(db).unwrap_or_else(Name::missing).display(db).to_string() + != only_name + && full_name() != only_name + { continue; } } - let mut msg = format!("processing: {}", full_name()); - if verbosity.is_verbose() { - let source = match body_id { - DefWithBody::Function(it) => it.source(db).map(|it| it.syntax().cloned()), - DefWithBody::Static(it) => it.source(db).map(|it| it.syntax().cloned()), - DefWithBody::Const(it) => it.source(db).map(|it| it.syntax().cloned()), - DefWithBody::Variant(it) => it.source(db).map(|it| it.syntax().cloned()), - DefWithBody::InTypeConst(_) => unimplemented!(), - }; - if let Some(src) = source { - let original_file = src.file_id.original_file(db); - let path = vfs.file_path(original_file); - let syntax_range = src.value.text_range(); - format_to!(msg, " ({} {:?})", path, syntax_range); + let msg = move || { + if verbosity.is_verbose() { + let source = match body_id { + DefWithBody::Function(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::Static(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::Const(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::Variant(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::InTypeConst(_) => unimplemented!(), + }; + if let Some(src) = source { + let original_file = src.file_id.original_file(db); + let path = vfs.file_path(original_file); + let syntax_range = src.value.text_range(); + format!("processing: {} ({} {:?})", full_name(), path, syntax_range) + } else { + format!("processing: {}", full_name()) + } + } else { + format!("processing: {}", full_name()) } - } + }; if verbosity.is_spammy() { - bar.println(msg.to_string()); + bar.println(msg()); } - bar.set_message(&msg); - let (body, sm) = db.body_with_source_map(body_id.into()); - // endregion:patterns + bar.set_message(msg); + db.body_with_source_map(body_id.into()); bar.inc(1); } diff --git a/crates/rust-analyzer/src/cli/progress_report.rs b/crates/rust-analyzer/src/cli/progress_report.rs index d459dd115cebe..c236f9c7fe1b6 100644 --- a/crates/rust-analyzer/src/cli/progress_report.rs +++ b/crates/rust-analyzer/src/cli/progress_report.rs @@ -4,41 +4,29 @@ use std::io::{self, Write}; /// A Simple ASCII Progress Bar -pub(crate) struct ProgressReport { +pub(crate) struct ProgressReport<'a> { curr: f32, text: String, hidden: bool, len: u64, pos: u64, - msg: String, + msg: Option String + 'a>>, } -impl ProgressReport { - pub(crate) fn new(len: u64) -> ProgressReport { - ProgressReport { - curr: 0.0, - text: String::new(), - hidden: false, - len, - pos: 0, - msg: String::new(), - } +impl<'a> ProgressReport<'a> { + pub(crate) fn new(len: u64) -> ProgressReport<'a> { + ProgressReport { curr: 0.0, text: String::new(), hidden: false, len, pos: 0, msg: None } } - pub(crate) fn hidden() -> ProgressReport { - ProgressReport { - curr: 0.0, - text: String::new(), - hidden: true, - len: 0, - pos: 0, - msg: String::new(), - } + pub(crate) fn hidden() -> ProgressReport<'a> { + ProgressReport { curr: 0.0, text: String::new(), hidden: true, len: 0, pos: 0, msg: None } } - pub(crate) fn set_message(&mut self, msg: &str) { - self.msg = msg.to_string(); + pub(crate) fn set_message(&mut self, msg: impl Fn() -> String + 'a) { + if !self.hidden { + self.msg = Some(Box::new(msg)); + } self.tick(); } @@ -67,7 +55,12 @@ impl ProgressReport { return; } let percent = (self.curr * 100.0) as u32; - let text = format!("{}/{} {percent:3>}% {}", self.pos, self.len, self.msg); + let text = format!( + "{}/{} {percent:3>}% {}", + self.pos, + self.len, + self.msg.as_ref().map_or_else(|| String::new(), |it| it()) + ); self.update_text(&text); } From 3d7ec5923d2e4373a354e7aec879e09e48f21517 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 17 Jun 2023 13:19:41 -0400 Subject: [PATCH 253/465] Fix for check_ptr_call for variadic functions --- build_sysroot/build_sysroot.sh | 13 +++++++------ src/builder.rs | 9 ++++++++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/build_sysroot/build_sysroot.sh b/build_sysroot/build_sysroot.sh index 6aea9b94b48ef..7f2c8d6121d6b 100755 --- a/build_sysroot/build_sysroot.sh +++ b/build_sysroot/build_sysroot.sh @@ -30,9 +30,10 @@ mkdir -p sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ cp -r target/$TARGET_TRIPLE/$sysroot_channel/deps/* sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ # Since we can't override the sysroot for the UI tests anymore, we create a new toolchain and manually overwrite the sysroot directory. -rust_toolchain=$(cat ../rust-toolchain | grep channel | sed 's/channel = "\(.*\)"/\1/') -my_toolchain_dir=$HOME/.rustup/toolchains/codegen_gcc_ui_tests-$rust_toolchain-$TARGET_TRIPLE -rm -rf $my_toolchain_dir -cp -r $HOME/.rustup/toolchains/$rust_toolchain-$TARGET_TRIPLE $my_toolchain_dir -rm -rf $my_toolchain_dir/lib/rustlib/$TARGET_TRIPLE/ -cp -r ../build_sysroot/sysroot/* $my_toolchain_dir +# TODO: to remove. +#rust_toolchain=$(cat ../rust-toolchain | grep channel | sed 's/channel = "\(.*\)"/\1/') +#my_toolchain_dir=$HOME/.rustup/toolchains/codegen_gcc_ui_tests-$rust_toolchain-$TARGET_TRIPLE +#rm -rf $my_toolchain_dir +#cp -r $HOME/.rustup/toolchains/$rust_toolchain-$TARGET_TRIPLE $my_toolchain_dir +#rm -rf $my_toolchain_dir/lib/rustlib/$TARGET_TRIPLE/ +#cp -r ../build_sysroot/sysroot/* $my_toolchain_dir diff --git a/src/builder.rs b/src/builder.rs index bb23524d8af48..43d0aafbd50bf 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -181,6 +181,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { }) .collect(); + debug_assert_eq!(casted_args.len(), args.len()); + Cow::Owned(casted_args) } @@ -207,7 +209,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let func_name = format!("{:?}", func_ptr); - let casted_args: Vec<_> = param_types + let mut casted_args: Vec<_> = param_types .into_iter() .zip(args.iter()) .enumerate() @@ -237,6 +239,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { }) .collect(); + // NOTE: to take into account variadic functions. + for i in casted_args.len()..args.len() { + casted_args.push(args[i]); + } + Cow::Owned(casted_args) } From 22f62df337b015df73104d24999e6f4e30f18d14 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Fri, 9 Jun 2023 21:45:57 +0800 Subject: [PATCH 254/465] Fix windows `Socket::connect_timeout` overflow Signed-off-by: Eval EXEC --- library/std/src/sys/windows/net.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index 2404bbe2b893a..1ae42cb7eae63 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -159,7 +159,7 @@ impl Socket { } let mut timeout = c::timeval { - tv_sec: timeout.as_secs() as c_long, + tv_sec: cmp::min(timeout.as_secs(), c_long::MAX as u64) as c_long, tv_usec: (timeout.subsec_nanos() / 1000) as c_long, }; From fca9e6e706d1b611c81c97ccdff8265f5f1ee638 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Sun, 11 Jun 2023 08:57:16 +0800 Subject: [PATCH 255/465] Add unit test for `TcpStream::connect_timeout` Signed-off-by: Eval EXEC --- library/std/src/net/tcp/tests.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index 7a3c66e450456..08ee451dfcdb0 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -46,6 +46,26 @@ fn connect_error() { } } +#[test] +fn connect_timeout_error() { + let socket_addr = next_test_ip4(); + let result = TcpStream::connect_timeout(&socket_addr, Duration::MAX); + assert!(!matches!(result, Err(e) if e.kind() == ErrorKind::TimedOut)); + + let _listener = TcpListener::bind(&socket_addr).unwrap(); + assert!(TcpStream::connect_timeout(&socket_addr, Duration::MAX).is_ok()); +} + +#[test] +fn connect_timeout_ok_bind() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); // :0 picks some free port + let port = listener.local_addr().unwrap().port(); // obtain the port it picked + assert!( + TcpStream::connect_timeout(&format!("127.0.0.1:{port}").parse().unwrap(), Duration::MAX) + .is_ok() + ); +} + #[test] fn listen_localhost() { let socket_addr = next_test_ip4(); From b198589214e5d6e1a7dc40599e61031a0d1a7b1b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 18 Jun 2023 10:48:09 +1000 Subject: [PATCH 256/465] Don't try to auto-bless 32-bit `mir-opt` tests on ARM Mac hosts Blessing 32-bit tests on 64-bit hosts relies on having a corresponding 32-bit target that can be built "easily" on those hosts. ARM Macs don't have a corresponding 32-bit target, so trying to build one is usually going to fail. --- src/bootstrap/test.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 13a10b0d3a506..59fe57a5872f9 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -44,7 +44,8 @@ const MIR_OPT_BLESS_TARGET_MAPPING: &[(&str, &str)] = &[ ("i686-pc-windows-msvc", "x86_64-pc-windows-msvc"), ("i686-pc-windows-gnu", "x86_64-pc-windows-gnu"), ("i686-apple-darwin", "x86_64-apple-darwin"), - ("i686-apple-darwin", "aarch64-apple-darwin"), + // ARM Macs don't have a corresponding 32-bit target that they can (easily) + // build for, so there is no entry for "aarch64-apple-darwin" here. ]; fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> bool { From ed82c055c6f2026220cccc6e2202952b670c64c2 Mon Sep 17 00:00:00 2001 From: Igor Gutorov Date: Wed, 14 Jun 2023 22:40:23 +0300 Subject: [PATCH 257/465] alloc: Implement PartialOrd for `Vec`s over different allocators --- library/alloc/src/vec/mod.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index d89cdff8e366c..a1e88d1870950 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2972,9 +2972,14 @@ impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec { /// Implements comparison of vectors, [lexicographically](Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Vec { +impl PartialOrd> for Vec +where + T: PartialOrd, + A1: Allocator, + A2: Allocator, +{ #[inline] - fn partial_cmp(&self, other: &Self) -> Option { + fn partial_cmp(&self, other: &Vec) -> Option { PartialOrd::partial_cmp(&**self, &**other) } } From 89c24af133ddc3e5ee2bee03222da935b50d10e8 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sun, 18 Jun 2023 05:24:38 +0000 Subject: [PATCH 258/465] Better error for non const `PartialEq` call generated by `match` --- .../src/diagnostics/conflict_errors.rs | 7 +- .../src/diagnostics/explain_borrow.rs | 6 +- .../rustc_borrowck/src/diagnostics/mod.rs | 16 +++- compiler/rustc_borrowck/src/invalidation.rs | 2 +- compiler/rustc_borrowck/src/lib.rs | 2 +- compiler/rustc_borrowck/src/type_check/mod.rs | 8 +- compiler/rustc_codegen_cranelift/src/base.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 2 +- compiler/rustc_const_eval/messages.ftl | 3 + compiler/rustc_const_eval/src/errors.rs | 12 +++ .../src/interpret/terminator.rs | 2 +- .../src/transform/check_consts/check.rs | 12 +-- .../src/transform/check_consts/ops.rs | 94 +++++++++++-------- .../src/transform/promote_consts.rs | 6 +- compiler/rustc_middle/src/mir/syntax.rs | 32 ++++++- compiler/rustc_middle/src/mir/visit.rs | 2 +- .../src/build/custom/parse/instruction.rs | 4 +- .../src/build/expr/as_rvalue.rs | 2 +- .../rustc_mir_build/src/build/expr/into.rs | 6 +- .../rustc_mir_build/src/build/matches/test.rs | 4 +- .../rustc_mir_dataflow/src/elaborate_drops.rs | 2 +- .../src/framework/direction.rs | 10 +- .../rustc_mir_dataflow/src/framework/tests.rs | 4 +- .../src/move_paths/builder.rs | 2 +- .../rustc_mir_transform/src/coverage/tests.rs | 2 +- .../src/function_item_references.rs | 2 +- compiler/rustc_mir_transform/src/generator.rs | 2 +- compiler/rustc_mir_transform/src/lib.rs | 6 +- .../src/lower_slice_len.rs | 2 +- compiler/rustc_mir_transform/src/shim.rs | 4 +- compiler/rustc_smir/src/rustc_smir/mod.rs | 2 +- .../clippy_utils/src/qualify_min_const_fn.rs | 2 +- .../match-non-const-eq.gated.stderr | 26 +++++ .../match-non-const-eq.rs | 12 +++ .../match-non-const-eq.stock.stderr | 13 +++ 35 files changed, 213 insertions(+), 102 deletions(-) create mode 100644 tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr create mode 100644 tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.rs create mode 100644 tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.stock.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 15d73ed732f50..fd5c21cfdf627 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -14,7 +14,7 @@ use rustc_infer::traits::ObligationCause; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ - self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, + self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm, }; @@ -2579,7 +2579,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diagnostic) { let tcx = self.infcx.tcx; if let ( - Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }), + Some(Terminator { + kind: TerminatorKind::Call { call_source: CallSource::OverloadedOperator, .. }, + .. + }), Some((method_did, method_substs)), ) = ( &self.body[loan.reserve_location.block].terminator, diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 1d430a93a876d..6c01fd63b1ec7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -6,8 +6,8 @@ use rustc_hir::intravisit::Visitor; use rustc_index::IndexSlice; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::mir::{ - Body, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location, Operand, Place, - Rvalue, Statement, StatementKind, TerminatorKind, + Body, CallSource, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location, + Operand, Place, Rvalue, Statement, StatementKind, TerminatorKind, }; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::{self, RegionVid, TyCtxt}; @@ -494,7 +494,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } else if self.was_captured_by_trait_object(borrow) { LaterUseKind::TraitCapture } else if location.statement_index == block.statements.len() { - if let TerminatorKind::Call { func, from_hir_call: true, .. } = + if let TerminatorKind::Call { func, call_source: CallSource::Normal, .. } = &block.terminator().kind { // Just point to the function, to reduce the chance of overlapping spans. diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 20370e4c6ac3c..1d3cc851888cf 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -13,8 +13,9 @@ use rustc_index::IndexSlice; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ - AggregateKind, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location, Operand, Place, - PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, + AggregateKind, CallSource, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location, + Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, + TerminatorKind, }; use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; @@ -414,7 +415,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if !is_terminator { continue; } else if let Some(Terminator { - kind: TerminatorKind::Call { func, from_hir_call: false, .. }, + kind: + TerminatorKind::Call { + func, + call_source: CallSource::OverloadedOperator, + .. + }, .. }) = &bbd.terminator { @@ -839,7 +845,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("move_spans: target_temp = {:?}", target_temp); if let Some(Terminator { - kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, .. + kind: TerminatorKind::Call { fn_span, call_source, .. }, .. }) = &self.body[location.block].terminator { let Some((method_did, method_substs)) = @@ -859,7 +865,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { method_did, method_substs, *fn_span, - *from_hir_call, + call_source.from_hir_call(), Some(self.infcx.tcx.fn_arg_names(method_did)[0]), ); diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index b2ff25ecb96f4..e4fbe6ea4f438 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -128,7 +128,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { destination, target: _, unwind: _, - from_hir_call: _, + call_source: _, fn_span: _, } => { self.consume_operand(location, func); diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 99a988f2c629e..4fcdda311bfd3 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -710,7 +710,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro destination, target: _, unwind: _, - from_hir_call: _, + call_source: _, fn_span: _, } => { self.consume_operand(loc, (func, span), flow_state); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 6697e1aff7dd0..dba1993a8c356 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1370,7 +1370,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } // FIXME: check the values } - TerminatorKind::Call { func, args, destination, from_hir_call, target, .. } => { + TerminatorKind::Call { func, args, destination, call_source, target, .. } => { self.check_operand(func, term_location); for arg in args { self.check_operand(arg, term_location); @@ -1444,7 +1444,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .add_element(region_vid, term_location); } - self.check_call_inputs(body, term, &sig, args, term_location, *from_hir_call); + self.check_call_inputs(body, term, &sig, args, term_location, *call_source); } TerminatorKind::Assert { cond, msg, .. } => { self.check_operand(cond, term_location); @@ -1571,7 +1571,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { sig: &ty::FnSig<'tcx>, args: &[Operand<'tcx>], term_location: Location, - from_hir_call: bool, + call_source: CallSource, ) { debug!("check_call_inputs({:?}, {:?})", sig, args); if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) { @@ -1589,7 +1589,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let op_arg_ty = op_arg.ty(body, self.tcx()); let op_arg_ty = self.normalize(op_arg_ty, term_location); - let category = if from_hir_call { + let category = if call_source.from_hir_call() { ConstraintCategory::CallArgument(self.infcx.tcx.erase_regions(func_ty)) } else { ConstraintCategory::Boring diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 5abb4644e1b09..ce10780f9de12 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -421,7 +421,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { target, fn_span, unwind: _, - from_hir_call: _, + call_source: _, } => { fx.tcx.prof.generic_activity("codegen call").run(|| { crate::abi::codegen_terminator_call( diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index a4a8aad87269d..0cec560ba4518 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1280,7 +1280,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { destination, target, unwind, - from_hir_call: _, + call_source: _, fn_span, } => self.codegen_call_terminator( helper, diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index bf660c59cabda..e99005316b3fd 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -210,6 +210,9 @@ const_eval_long_running = .label = the const evaluator is currently interpreting this expression .help = the constant being evaluated +const_eval_match_eq_non_const = cannot match on `{$ty}` in {const_eval_const_context}s + .note = `{$ty}` cannot be compared in compile-time, and therefore cannot be used in `match`es + const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id} const_eval_memory_access_test = memory access failed diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index eed3091d481e3..ca38cce710e60 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -271,6 +271,18 @@ pub struct RawBytesNote { pub bytes: String, } +// FIXME(fee1-dead) do not use stringly typed `ConstContext` + +#[derive(Diagnostic)] +#[diag(const_eval_match_eq_non_const, code = "E0015")] +#[note] +pub struct NonConstMatchEq<'tcx> { + #[primary_span] + pub span: Span, + pub ty: Ty<'tcx>, + pub kind: ConstContext, +} + #[derive(Diagnostic)] #[diag(const_eval_for_loop_into_iter_non_const, code = "E0015")] pub struct NonConstForLoopIntoIter<'tcx> { diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 7269ff8d53cdf..719d8a14b4134 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -62,7 +62,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { destination, target, unwind, - from_hir_call: _, + call_source: _, fn_span: _, } => { let old_stack = self.frame_idx(); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 106cf1114749a..2aaf1340eb409 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -702,7 +702,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { self.super_terminator(terminator, location); match &terminator.kind { - TerminatorKind::Call { func, args, fn_span, from_hir_call, .. } => { + TerminatorKind::Call { func, args, fn_span, call_source, .. } => { let ConstCx { tcx, body, param_env, .. } = *self.ccx; let caller = self.def_id(); @@ -755,7 +755,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { callee, substs, span: *fn_span, - from_hir_call: *from_hir_call, + call_source: *call_source, feature: Some(sym::const_trait_impl), }); return; @@ -797,7 +797,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { callee, substs, span: *fn_span, - from_hir_call: *from_hir_call, + call_source: *call_source, feature: None, }); @@ -823,7 +823,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { callee, substs, span: *fn_span, - from_hir_call: *from_hir_call, + call_source: *call_source, feature: None, }); return; @@ -866,7 +866,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { callee, substs, span: *fn_span, - from_hir_call: *from_hir_call, + call_source: *call_source, feature: None, }); return; @@ -926,7 +926,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { callee, substs, span: *fn_span, - from_hir_call: *from_hir_call, + call_source: *call_source, feature: None, }); return; diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 236e43bdfcc71..32bd9cda6f2b4 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -7,7 +7,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; -use rustc_middle::mir; +use rustc_middle::mir::{self, CallSource}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::{suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, Ty}; @@ -100,7 +100,7 @@ pub struct FnCallNonConst<'tcx> { pub callee: DefId, pub substs: SubstsRef<'tcx>, pub span: Span, - pub from_hir_call: bool, + pub call_source: CallSource, pub feature: Option, } @@ -110,7 +110,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { ccx: &ConstCx<'_, 'tcx>, _: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let FnCallNonConst { caller, callee, substs, span, from_hir_call, feature } = *self; + let FnCallNonConst { caller, callee, substs, span, call_source, feature } = *self; let ConstCx { tcx, param_env, .. } = *ccx; let diag_trait = |err, self_ty: Ty<'_>, trait_id| { @@ -157,7 +157,8 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { } }; - let call_kind = call_kind(tcx, ccx.param_env, callee, substs, span, from_hir_call, None); + let call_kind = + call_kind(tcx, ccx.param_env, callee, substs, span, call_source.from_hir_call(), None); debug!(?call_kind); @@ -219,48 +220,59 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { err } CallKind::Operator { trait_id, self_ty, .. } => { - let mut sugg = None; - - if Some(trait_id) == ccx.tcx.lang_items().eq_trait() { - match (substs[0].unpack(), substs[1].unpack()) { - (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty)) - if self_ty == rhs_ty - && self_ty.is_ref() - && self_ty.peel_refs().is_primitive() => - { - let mut num_refs = 0; - let mut tmp_ty = self_ty; - while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() { - num_refs += 1; - tmp_ty = *inner_ty; - } - let deref = "*".repeat(num_refs); - - if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span) { - if let Some(eq_idx) = call_str.find("==") { - if let Some(rhs_idx) = - call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace()) - { - let rhs_pos = - span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx); - let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos); - sugg = Some(errors::ConsiderDereferencing { - deref, - span: span.shrink_to_lo(), - rhs_span, - }); + let mut err = if let CallSource::MatchCmp = call_source { + tcx.sess.create_err(errors::NonConstMatchEq { + span, + kind: ccx.const_kind(), + ty: self_ty, + }) + } else { + let mut sugg = None; + + if Some(trait_id) == ccx.tcx.lang_items().eq_trait() { + match (substs[0].unpack(), substs[1].unpack()) { + (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty)) + if self_ty == rhs_ty + && self_ty.is_ref() + && self_ty.peel_refs().is_primitive() => + { + let mut num_refs = 0; + let mut tmp_ty = self_ty; + while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() { + num_refs += 1; + tmp_ty = *inner_ty; + } + let deref = "*".repeat(num_refs); + + if let Ok(call_str) = + ccx.tcx.sess.source_map().span_to_snippet(span) + { + if let Some(eq_idx) = call_str.find("==") { + if let Some(rhs_idx) = call_str[(eq_idx + 2)..] + .find(|c: char| !c.is_whitespace()) + { + let rhs_pos = span.lo() + + BytePos::from_usize(eq_idx + 2 + rhs_idx); + let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos); + sugg = Some(errors::ConsiderDereferencing { + deref, + span: span.shrink_to_lo(), + rhs_span, + }); + } } } } + _ => {} } - _ => {} } - } - let mut err = tcx.sess.create_err(errors::NonConstOperator { - span, - kind: ccx.const_kind(), - sugg, - }); + tcx.sess.create_err(errors::NonConstOperator { + span, + kind: ccx.const_kind(), + sugg, + }) + }; + diag_trait(&mut err, self_ty, trait_id); err } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 0e2d9ee8fb2fb..809cf62d8142d 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -795,7 +795,9 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { }; match terminator.kind { - TerminatorKind::Call { mut func, mut args, from_hir_call, fn_span, .. } => { + TerminatorKind::Call { + mut func, mut args, call_source: desugar, fn_span, .. + } => { self.visit_operand(&mut func, loc); for arg in &mut args { self.visit_operand(arg, loc); @@ -811,7 +813,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { unwind: UnwindAction::Continue, destination: Place::from(new_temp), target: Some(new_target), - from_hir_call, + call_source: desugar, fn_span, }, source_info: SourceInfo::outermost(terminator.source_info.span), diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 1a65f74f4fe22..fb3841f877687 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -512,6 +512,31 @@ pub struct CopyNonOverlapping<'tcx> { pub count: Operand<'tcx>, } +/// Represents how a `TerminatorKind::Call` was constructed, used for diagnostics +#[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, PartialEq, Hash, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] +pub enum CallSource { + /// This came from something such as `a > b` or `a + b`. In THIR, if `from_hir_call` + /// is false then this is the desugaring. + OverloadedOperator, + /// This was from comparison generated by a match, used by const-eval for better errors + /// when the comparison cannot be done in compile time. + /// + /// See https://github.com/rust-lang/rust/issues/90237. + MatchCmp, + /// Other types of desugaring that did not come from the HIR, but we don't care about + /// for diagnostics (yet). + Misc, + /// Normal function call, no special source + Normal, +} + +impl CallSource { + pub fn from_hir_call(self) -> bool { + matches!(self, CallSource::Normal) + } +} + /////////////////////////////////////////////////////////////////////////// // Terminators @@ -638,11 +663,10 @@ pub enum TerminatorKind<'tcx> { target: Option, /// Action to be taken if the call unwinds. unwind: UnwindAction, - /// `true` if this is from a call in HIR rather than from an overloaded - /// operator. True for overloaded function call. - from_hir_call: bool, + /// Where this call came from in HIR/THIR. + call_source: CallSource, /// This `Span` is the span of the function, without the dot and receiver - /// (e.g. `foo(a, b)` in `x.foo(a, b)` + /// e.g. `foo(a, b)` in `x.foo(a, b)` fn_span: Span, }, diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 8d44e929afde3..ce55b770cbcb4 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -519,7 +519,7 @@ macro_rules! make_mir_visitor { destination, target: _, unwind: _, - from_hir_call: _, + call_source: _, fn_span: _ } => { self.visit_operand(func, location); diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index ebf830cb9c1f6..4cb9d7babe14f 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -128,7 +128,9 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { destination, target: Some(target), unwind: UnwindAction::Continue, - from_hir_call: *from_hir_call, + call_source: if *from_hir_call { CallSource::Normal } else { + CallSource::OverloadedOperator + }, fn_span: *fn_span, }) }, diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 3742d640e3b58..fd08b32807c40 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -173,7 +173,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination: storage, target: Some(success), unwind: UnwindAction::Continue, - from_hir_call: false, + call_source: CallSource::Misc, fn_span: expr_span, }, ); diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 29ff916d2cc9c..731f3996244ca 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -277,7 +277,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .ty .is_inhabited_from(this.tcx, this.parent_module, this.param_env) .then_some(success), - from_hir_call, + call_source: if from_hir_call { + CallSource::Normal + } else { + CallSource::OverloadedOperator + }, fn_span, }, ); diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index dbdb5b4a9a179..f431023f2b669 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -264,7 +264,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination: ref_str, target: Some(eq_block), unwind: UnwindAction::Continue, - from_hir_call: false, + call_source: CallSource::Misc, fn_span: source_info.span } ); @@ -496,7 +496,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination: eq_result, target: Some(eq_block), unwind: UnwindAction::Continue, - from_hir_call: false, + call_source: CallSource::MatchCmp, fn_span: source_info.span, }, ); diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 4fc45eaf5220d..27232b70d960b 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -654,7 +654,7 @@ where destination: unit_temp, target: Some(succ), unwind: unwind.into_action(), - from_hir_call: true, + call_source: CallSource::Misc, fn_span: self.source_info.span, }, source_info: self.source_info, diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 0c379288a0962..804b44a6bf05d 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -502,15 +502,7 @@ impl Direction for Forward { propagate(target, exit_state); } - Call { - unwind, - destination, - target, - func: _, - args: _, - from_hir_call: _, - fn_span: _, - } => { + Call { unwind, destination, target, func: _, args: _, call_source: _, fn_span: _ } => { if let UnwindAction::Cleanup(unwind) = unwind { propagate(unwind, exit_state); } diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index 45c2fe55aca9f..cb0ec144ef0b7 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -40,7 +40,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> { destination: dummy_place.clone(), target: Some(mir::START_BLOCK), unwind: mir::UnwindAction::Continue, - from_hir_call: false, + call_source: mir::CallSource::Misc, fn_span: DUMMY_SP, }, ); @@ -54,7 +54,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> { destination: dummy_place.clone(), target: Some(mir::START_BLOCK), unwind: mir::UnwindAction::Continue, - from_hir_call: false, + call_source: mir::CallSource::Misc, fn_span: DUMMY_SP, }, ); diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 096bc0acfccb9..fe9631653ea72 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -399,7 +399,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { destination, target, unwind: _, - from_hir_call: _, + call_source: _, fn_span: _, } => { self.gather_operand(func); diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index 90b58933df7c0..25891d3ca0f88 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -140,7 +140,7 @@ impl<'tcx> MockBlocks<'tcx> { destination: self.dummy_place.clone(), target: Some(TEMP_BLOCK), unwind: UnwindAction::Continue, - from_hir_call: false, + call_source: CallSource::Misc, fn_span: DUMMY_SP, }, ) diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index b1c9c4acc40e4..7f631cccddf54 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -34,7 +34,7 @@ impl<'tcx> Visitor<'tcx> for FunctionItemRefChecker<'_, 'tcx> { destination: _, target: _, unwind: _, - from_hir_call: _, + call_source: _, fn_span: _, } = &terminator.kind { diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index fe3f8ed047a70..04134eb2fb169 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1692,7 +1692,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> { destination, target: Some(_), unwind: _, - from_hir_call: _, + call_source: _, fn_span: _, } => { self.check_assigned_place(*destination, |this| { diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 9c8c0ea0be004..fa8257cf9849c 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -30,8 +30,8 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_index::IndexVec; use rustc_middle::mir::visit::Visitor as _; use rustc_middle::mir::{ - traversal, AnalysisPhase, Body, ClearCrossCrate, ConstQualifs, Constant, LocalDecl, MirPass, - MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, + traversal, AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstQualifs, Constant, LocalDecl, + MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, Statement, StatementKind, TerminatorKind, START_BLOCK, }; use rustc_middle::query::Providers; @@ -189,7 +189,7 @@ fn remap_mir_for_const_eval_select<'tcx>( }; method(place) }).collect(); - terminator.kind = TerminatorKind::Call { func, args: arguments, destination, target, unwind, from_hir_call: false, fn_span }; + terminator.kind = TerminatorKind::Call { func, args: arguments, destination, target, unwind, call_source: CallSource::Misc, fn_span }; } _ => {} } diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs index 6e40dfa0d1382..b7cc0db95597d 100644 --- a/compiler/rustc_mir_transform/src/lower_slice_len.rs +++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs @@ -54,7 +54,7 @@ fn lower_slice_len_call<'tcx>( args, destination, target: Some(bb), - from_hir_call: true, + call_source: CallSource::Normal, .. } => { // some heuristics for fast rejection diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 5f12f1937c06c..9d6ef9db4ea1b 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -500,7 +500,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { destination: dest, target: Some(next), unwind: UnwindAction::Cleanup(cleanup), - from_hir_call: true, + call_source: CallSource::Normal, fn_span: self.span, }, false, @@ -789,7 +789,7 @@ fn build_call_shim<'tcx>( } else { UnwindAction::Continue }, - from_hir_call: true, + call_source: CallSource::Misc, fn_span: span, }, false, diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 6bd030b13d1ce..5327f8a3cc37f 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -346,7 +346,7 @@ impl<'tcx> Stable for mir::Terminator<'tcx> { target: target.as_usize(), unwind: unwind.stable(), }, - Call { func, args, destination, target, unwind, from_hir_call: _, fn_span: _ } => { + Call { func, args, destination, target, unwind, call_source: _, fn_span: _ } => { Terminator::Call { func: func.stable(), args: args.iter().map(|arg| arg.stable()).collect(), diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index c0d2c835d63d4..566eecf36a777 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -317,7 +317,7 @@ fn check_terminator<'tcx>( TerminatorKind::Call { func, args, - from_hir_call: _, + call_source: _, destination: _, target: _, unwind: _, diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr new file mode 100644 index 0000000000000..bd0dd126c5e6b --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr @@ -0,0 +1,26 @@ +error[E0277]: can't compare `str` with `str` in const contexts + --> $DIR/match-non-const-eq.rs:6:9 + | +LL | "a" => (), + | ^^^ no implementation for `str == str` + | + = help: the trait `~const PartialEq` is not implemented for `str` +note: the trait `PartialEq` is implemented for `str`, but that implementation is not `const` + --> $DIR/match-non-const-eq.rs:6:9 + | +LL | "a" => (), + | ^^^ + +error[E0015]: cannot match on `str` in constant functions + --> $DIR/match-non-const-eq.rs:6:9 + | +LL | "a" => (), + | ^^^ + | + = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.rs new file mode 100644 index 0000000000000..0d04101a38307 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.rs @@ -0,0 +1,12 @@ +// revisions: stock gated +#![cfg_attr(gated, feature(const_trait_impl))] + +const fn foo(input: &'static str) { + match input { + "a" => (), //[gated]~ ERROR can't compare `str` with `str` in const contexts + //~^ ERROR cannot match on `str` in constant functions + _ => (), + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.stock.stderr new file mode 100644 index 0000000000000..dcb9b49ea04cf --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.stock.stderr @@ -0,0 +1,13 @@ +error[E0015]: cannot match on `str` in constant functions + --> $DIR/match-non-const-eq.rs:6:9 + | +LL | "a" => (), + | ^^^ + | + = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. From c4c428b6da234aea4aa639fac73828792d064a07 Mon Sep 17 00:00:00 2001 From: David Weikersdorfer <517608+Danvil@users.noreply.github.com> Date: Sun, 18 Jun 2023 00:46:51 -0700 Subject: [PATCH 259/465] Use BorrowFlag instead of explicit isize The integer type tracking borrow count has a typedef called `BorrowFlag`. This type should be used instead of explicit `isize`. --- library/core/src/cell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index c1cc892eb8607..b1b15e84dbf18 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1756,7 +1756,7 @@ impl<'b> BorrowRefMut<'b> { let borrow = self.borrow.get(); debug_assert!(is_writing(borrow)); // Prevent the borrow counter from underflowing. - assert!(borrow != isize::MIN); + assert!(borrow != BorrowFlag::MIN); self.borrow.set(borrow - 1); BorrowRefMut { borrow: self.borrow } } From f65b5d0ddf1ae0a551756424503c3cfe0e7ad8a6 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Sun, 18 Jun 2023 15:41:50 +0800 Subject: [PATCH 260/465] Add unit test to connect to an unreachable address Signed-off-by: Eval EXEC --- library/std/src/net/tcp/tests.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index 08ee451dfcdb0..4209d4b63422a 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -46,6 +46,17 @@ fn connect_error() { } } +#[test] +fn connect_timeout_to_unreachable_address() { + let now = Instant::now(); + match TcpStream::connect_timeout(&format!("1.1.1.1:9999").parse().unwrap(), Duration::MAX) { + Ok(..) => panic!("connected to an unreachable address, this is impossible"), + Err(e) => assert_eq!(e.kind(), ErrorKind::TimedOut), + } + + assert!(now.elapsed() > Duration::from_secs(20)); +} + #[test] fn connect_timeout_error() { let socket_addr = next_test_ip4(); From 09707ee12a29856453782f7dc41cfef49749e9de Mon Sep 17 00:00:00 2001 From: David Weikersdorfer <517608+Danvil@users.noreply.github.com> Date: Sun, 18 Jun 2023 01:14:45 -0700 Subject: [PATCH 261/465] Same for BorrowRef --- library/core/src/cell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index b1b15e84dbf18..909b32547e74c 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1374,7 +1374,7 @@ impl Clone for BorrowRef<'_> { debug_assert!(is_reading(borrow)); // Prevent the borrow counter from overflowing into // a writing borrow. - assert!(borrow != isize::MAX); + assert!(borrow != BorrowFlag::MAX); self.borrow.set(borrow + 1); BorrowRef { borrow: self.borrow } } From 83d7724629c3ea1800f36be28dadead5d604fcd1 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 18 Jun 2023 11:41:20 +0200 Subject: [PATCH 262/465] fix: Add binding definition for for-expr iterator desugared binding --- crates/hir-def/src/body/lower.rs | 46 +++++++++---------- crates/hir/src/lib.rs | 25 ++++++---- .../rust-analyzer/src/cli/analysis_stats.rs | 6 ++- 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index 71b42f31a24a7..53b80a17df1bd 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -188,7 +188,7 @@ impl ExprCollector<'_> { param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false)) { let ptr = AstPtr::new(&self_param); - let binding_id = self.alloc_binding( + let binding_id: la_arena::Idx = self.alloc_binding( name![self], BindingAnnotation::new( self_param.mut_token().is_some() && self_param.amp_token().is_none(), @@ -745,16 +745,14 @@ impl ExprCollector<'_> { /// } /// ``` fn collect_for_loop(&mut self, syntax_ptr: AstPtr, e: ast::ForExpr) -> ExprId { - let (into_iter_fn, iter_next_fn, option_some, option_none) = 'if_chain: { - if let Some(into_iter_fn) = LangItem::IntoIterIntoIter.path(self.db, self.krate) { - if let Some(iter_next_fn) = LangItem::IteratorNext.path(self.db, self.krate) { - if let Some(option_some) = LangItem::OptionSome.path(self.db, self.krate) { - if let Some(option_none) = LangItem::OptionNone.path(self.db, self.krate) { - break 'if_chain (into_iter_fn, iter_next_fn, option_some, option_none); - } - } - } - } + let Some((into_iter_fn, iter_next_fn, option_some, option_none)) = (|| { + Some(( + LangItem::IntoIterIntoIter.path(self.db, self.krate)?, + LangItem::IteratorNext.path(self.db, self.krate)?, + LangItem::OptionSome.path(self.db, self.krate)?, + LangItem::OptionNone.path(self.db, self.krate)?, + )) + })() else { // Some of the needed lang items are missing, so we can't desugar return self.alloc_expr(Expr::Missing, syntax_ptr); }; @@ -787,8 +785,8 @@ impl ExprCollector<'_> { }), }; let iter_name = Name::generate_new_name(); - let iter_binding = self.alloc_binding(iter_name.clone(), BindingAnnotation::Mutable); - let iter_expr = self.alloc_expr(Expr::Path(Path::from(iter_name)), syntax_ptr.clone()); + let iter_expr = + self.alloc_expr(Expr::Path(Path::from(iter_name.clone())), syntax_ptr.clone()); let iter_expr_mut = self.alloc_expr( Expr::Ref { expr: iter_expr, rawness: Rawness::Ref, mutability: Mutability::Mut }, syntax_ptr.clone(), @@ -808,7 +806,9 @@ impl ExprCollector<'_> { ); let loop_outer = self.alloc_expr(Expr::Loop { body: loop_inner, label }, syntax_ptr.clone()); + let iter_binding = self.alloc_binding(iter_name, BindingAnnotation::Mutable); let iter_pat = self.alloc_pat_desugared(Pat::Bind { id: iter_binding, subpat: None }); + self.add_definition_to_binding(iter_binding, iter_pat); self.alloc_expr( Expr::Match { expr: iterator, @@ -830,18 +830,14 @@ impl ExprCollector<'_> { /// } /// ``` fn collect_try_operator(&mut self, syntax_ptr: AstPtr, e: ast::TryExpr) -> ExprId { - let (try_branch, cf_continue, cf_break, try_from_residual) = 'if_chain: { - if let Some(try_branch) = LangItem::TryTraitBranch.path(self.db, self.krate) { - if let Some(cf_continue) = LangItem::ControlFlowContinue.path(self.db, self.krate) { - if let Some(cf_break) = LangItem::ControlFlowBreak.path(self.db, self.krate) { - if let Some(try_from_residual) = - LangItem::TryTraitFromResidual.path(self.db, self.krate) - { - break 'if_chain (try_branch, cf_continue, cf_break, try_from_residual); - } - } - } - } + let Some((try_branch, cf_continue, cf_break, try_from_residual)) = (|| { + Some(( + LangItem::TryTraitBranch.path(self.db, self.krate)?, + LangItem::ControlFlowContinue.path(self.db, self.krate)?, + LangItem::ControlFlowBreak.path(self.db, self.krate)?, + LangItem::TryTraitFromResidual.path(self.db, self.krate)?, + )) + })() else { // Some of the needed lang items are missing, so we can't desugar return self.alloc_expr(Expr::Missing, syntax_ptr); }; diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 9876503d03178..6df625380ffff 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2800,6 +2800,22 @@ impl Local { /// All definitions for this local. Example: `let (a$0, _) | (_, a$0) = x;` pub fn sources(self, db: &dyn HirDatabase) -> Vec { let (body, source_map) = db.body_with_source_map(self.parent); + self.sources_(db, &body, &source_map).collect() + } + + /// The leftmost definition for this local. Example: `let (a$0, _) | (_, a) = x;` + pub fn primary_source(self, db: &dyn HirDatabase) -> LocalSource { + let (body, source_map) = db.body_with_source_map(self.parent); + let src = self.sources_(db, &body, &source_map).next().unwrap(); + src + } + + fn sources_<'a>( + self, + db: &'a dyn HirDatabase, + body: &'a hir_def::body::Body, + source_map: &'a hir_def::body::BodySourceMap, + ) -> impl Iterator + 'a { body[self.binding_id] .definitions .iter() @@ -2812,14 +2828,7 @@ impl Local { Either::Right(it) => Either::Right(it.to_node(&root)), }) }) - .map(|source| LocalSource { local: self, source }) - .collect() - } - - /// The leftmost definition for this local. Example: `let (a$0, _) | (_, a) = x;` - pub fn primary_source(self, db: &dyn HirDatabase) -> LocalSource { - let all_sources = self.sources(db); - all_sources.into_iter().next().unwrap() + .map(move |source| LocalSource { local: self, source }) } } diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 01bc0d77dd5b9..4cb917ce290a7 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -165,9 +165,11 @@ impl flags::AnalysisStats { } } eprintln!( - ", mods: {}, decls: {num_decls}, bodies: {}", + ", mods: {}, decls: {num_decls}, bodies: {}, adts: {}, consts: {}", visited_modules.len(), - bodies.len() + bodies.len(), + adts.len(), + consts.len(), ); eprintln!("{:<20} {}", "Item Collection:", analysis_sw.elapsed()); From d25e8d79a14ebf02df437f0147de592c8ded3ea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 15 Jun 2023 19:10:45 +0200 Subject: [PATCH 263/465] Test `x.ps1` in `msvc` CI job --- src/bootstrap/mk/Makefile.in | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 779db9fffa883..d296931580337 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -60,8 +60,11 @@ prepare: ## MSVC native builders # this intentionally doesn't use `$(BOOTSTRAP)` so we can test the shebang on Windows -ci-msvc: - $(Q)$(CFG_SRC_DIR)/x.py test --stage 2 +ci-msvc-py: + $(Q)$(CFG_SRC_DIR)/x.py test --stage 2 tidy +ci-msvc-ps1: + $(Q)$(CFG_SRC_DIR)/x.ps1 test --stage 2 --exclude tidy +ci-msvc: ci-msvc-py ci-msvc-ps1 ## MingW native builders From 94f7a7931c035473565c1b2ec0a6c2ffaa3b4f79 Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Wed, 5 Apr 2023 13:06:49 +0200 Subject: [PATCH 264/465] [doc] poll_fn: explain how to pin captured state safely MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Usage of `Pin::new_unchecked(&mut …)` is dangerous with `poll_fn`, even though the `!Unpin`-infectiousness has made things smoother. Nonetheless, there are easy ways to avoid the need for any `unsafe` altogether, be it through `Box::pin`ning, or the `pin!` macro. Since the latter only works within an `async` context, showing an example artifically introducing one ought to help people navigate this subtlety with safety and confidence. --- library/core/src/future/poll_fn.rs | 87 ++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/library/core/src/future/poll_fn.rs b/library/core/src/future/poll_fn.rs index 90cb797391a08..d27a9dfc176e3 100644 --- a/library/core/src/future/poll_fn.rs +++ b/library/core/src/future/poll_fn.rs @@ -24,6 +24,93 @@ use crate::task::{Context, Poll}; /// assert_eq!(read_future.await, "Hello, World!".to_owned()); /// # } /// ``` +/// +/// ## Capturing a pinned state +/// +/// Example of a closure wrapping inner futures: +/// +/// ``` +/// # async fn run() { +/// use core::future::{self, Future}; +/// use core::task::Poll; +/// +/// /// Resolves to the first future that completes. In the event of a tie, `a` wins. +/// fn naive_select( +/// a: impl Future, +/// b: impl Future, +/// ) -> impl Future +/// { +/// let (mut a, mut b) = (Box::pin(a), Box::pin(b)); +/// future::poll_fn(move |cx| { +/// if let Poll::Ready(r) = a.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else if let Poll::Ready(r) = b.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else { +/// Poll::Pending +/// } +/// }) +/// } +/// +/// let a = async { 42 }; +/// let b = future::pending(); +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 42); +/// +/// let a = future::pending(); +/// let b = async { 27 }; +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 27); +/// +/// let a = async { 42 }; +/// let b = async { 27 }; +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 42); // biased towards `a` in case of tie! +/// # } +/// ``` +/// +/// This time without [`Box::pin`]ning: +/// +/// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin +/// +/// ``` +/// # async fn run() { +/// use core::future::{self, Future}; +/// use core::pin::pin; +/// use core::task::Poll; +/// +/// /// Resolves to the first future that completes. In the event of a tie, `a` wins. +/// fn naive_select( +/// a: impl Future, +/// b: impl Future, +/// ) -> impl Future +/// { +/// async { +/// let (mut a, mut b) = (pin!(a), pin!(b)); +/// future::poll_fn(move |cx| { +/// if let Poll::Ready(r) = a.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else if let Poll::Ready(r) = b.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else { +/// Poll::Pending +/// } +/// }).await +/// } +/// } +/// +/// let a = async { 42 }; +/// let b = future::pending(); +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 42); +/// # } +/// ``` +/// +/// - Notice how, by virtue of being in an `async` context, we have been able to make the [`pin!`] +/// macro work, thereby avoiding any need for the `unsafe` +/// [Pin::new_unchecked](&mut fut) constructor. +/// +/// [`pin!`]: crate::pin::pin! #[stable(feature = "future_poll_fn", since = "1.64.0")] pub fn poll_fn(f: F) -> PollFn where From c3186202a2bde98ad8d388e68cc3a86bc5236734 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 18 Jun 2023 12:03:04 +0200 Subject: [PATCH 265/465] Shrink size of hir::Binding --- crates/hir-def/src/body.rs | 29 +++++++++++++++++++++++++++-- crates/hir-def/src/body/lower.rs | 19 +++++++++++-------- crates/hir-def/src/hir.rs | 16 ---------------- crates/hir-ty/src/infer/closure.rs | 3 +-- crates/hir-ty/src/mir/lower.rs | 7 ++++--- 5 files changed, 43 insertions(+), 31 deletions(-) diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index a78bcd6c67fa6..94dc39b117557 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -37,6 +37,9 @@ pub struct Body { pub pats: Arena, pub bindings: Arena, pub labels: Arena
(); - //~^ ERROR evaluate(Binder(TraitPredicate(, polarity:Positive), [])) = Ok(EvaluatedToOk) + //~^ ERROR evaluate(Binder { value: TraitPredicate(, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) } diff --git a/tests/ui/traits/cache-reached-depth-ice.stderr b/tests/ui/traits/cache-reached-depth-ice.stderr index 082aa0f5cd93e..7cd75819277df 100644 --- a/tests/ui/traits/cache-reached-depth-ice.stderr +++ b/tests/ui/traits/cache-reached-depth-ice.stderr @@ -1,4 +1,4 @@ -error: evaluate(Binder(TraitPredicate(, polarity:Positive), [])) = Ok(EvaluatedToOk) +error: evaluate(Binder { value: TraitPredicate(, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) --> $DIR/cache-reached-depth-ice.rs:43:5 | LL | fn test() {} diff --git a/tests/ui/traits/issue-83538-tainted-cache-after-cycle.rs b/tests/ui/traits/issue-83538-tainted-cache-after-cycle.rs index 3cd68ff6f060e..5136aef4f7aa7 100644 --- a/tests/ui/traits/issue-83538-tainted-cache-after-cycle.rs +++ b/tests/ui/traits/issue-83538-tainted-cache-after-cycle.rs @@ -57,10 +57,10 @@ fn main() { // Key is that Vec is "ok" and Third<'_, Ty> is "ok modulo regions": forward(); - //~^ ERROR evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk) - //~| ERROR evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) + //~^ ERROR evaluate(Binder { value: TraitPredicate( as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) + //~| ERROR evaluate(Binder { value: TraitPredicate( as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) reverse(); - //~^ ERROR evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk) - //~| ERROR evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) + //~^ ERROR evaluate(Binder { value: TraitPredicate( as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) + //~| ERROR evaluate(Binder { value: TraitPredicate( as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) } diff --git a/tests/ui/traits/issue-83538-tainted-cache-after-cycle.stderr b/tests/ui/traits/issue-83538-tainted-cache-after-cycle.stderr index 7c4041144a4d2..96baec76a17ec 100644 --- a/tests/ui/traits/issue-83538-tainted-cache-after-cycle.stderr +++ b/tests/ui/traits/issue-83538-tainted-cache-after-cycle.stderr @@ -1,4 +1,4 @@ -error: evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk) +error: evaluate(Binder { value: TraitPredicate( as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) --> $DIR/issue-83538-tainted-cache-after-cycle.rs:59:5 | LL | Vec: Unpin, @@ -7,7 +7,7 @@ LL | Vec: Unpin, LL | forward(); | ^^^^^^^ -error: evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) +error: evaluate(Binder { value: TraitPredicate( as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) --> $DIR/issue-83538-tainted-cache-after-cycle.rs:59:5 | LL | Third<'a, Ty>: Unpin, @@ -16,7 +16,7 @@ LL | Third<'a, Ty>: Unpin, LL | forward(); | ^^^^^^^ -error: evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) +error: evaluate(Binder { value: TraitPredicate( as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) --> $DIR/issue-83538-tainted-cache-after-cycle.rs:63:5 | LL | Third<'a, Ty>: Unpin, @@ -25,7 +25,7 @@ LL | Third<'a, Ty>: Unpin, LL | reverse(); | ^^^^^^^ -error: evaluate(Binder(TraitPredicate( as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk) +error: evaluate(Binder { value: TraitPredicate( as std::marker::Unpin>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) --> $DIR/issue-83538-tainted-cache-after-cycle.rs:63:5 | LL | Vec: Unpin, diff --git a/tests/ui/traits/issue-85360-eval-obligation-ice.rs b/tests/ui/traits/issue-85360-eval-obligation-ice.rs index 19131684a481b..ac8bda9c01042 100644 --- a/tests/ui/traits/issue-85360-eval-obligation-ice.rs +++ b/tests/ui/traits/issue-85360-eval-obligation-ice.rs @@ -7,12 +7,12 @@ use core::marker::PhantomData; fn main() { test::>>(make()); - //~^ ERROR evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOk) - //~| ERROR evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOk) + //~^ ERROR evaluate(Binder { value: TraitPredicate(> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) + //~| ERROR evaluate(Binder { value: TraitPredicate(> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) test::>>(make()); - //~^ ERROR evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) - //~| ERROR evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) + //~^ ERROR evaluate(Binder { value: TraitPredicate(> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) + //~| ERROR evaluate(Binder { value: TraitPredicate(> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) } #[rustc_evaluate_where_clauses] diff --git a/tests/ui/traits/issue-85360-eval-obligation-ice.stderr b/tests/ui/traits/issue-85360-eval-obligation-ice.stderr index ebf977dd68051..9590ea12c05e4 100644 --- a/tests/ui/traits/issue-85360-eval-obligation-ice.stderr +++ b/tests/ui/traits/issue-85360-eval-obligation-ice.stderr @@ -1,4 +1,4 @@ -error: evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOk) +error: evaluate(Binder { value: TraitPredicate(> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) --> $DIR/issue-85360-eval-obligation-ice.rs:9:5 | LL | test::>>(make()); @@ -7,7 +7,7 @@ LL | test::>>(make()); LL | fn test(_: T) {} | - predicate -error: evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOk) +error: evaluate(Binder { value: TraitPredicate(> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) --> $DIR/issue-85360-eval-obligation-ice.rs:9:5 | LL | test::>>(make()); @@ -16,7 +16,7 @@ LL | test::>>(make()); LL | fn test(_: T) {} | ----- predicate -error: evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) +error: evaluate(Binder { value: TraitPredicate(> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) --> $DIR/issue-85360-eval-obligation-ice.rs:13:5 | LL | test::>>(make()); @@ -25,7 +25,7 @@ LL | test::>>(make()); LL | fn test(_: T) {} | - predicate -error: evaluate(Binder(TraitPredicate(> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) +error: evaluate(Binder { value: TraitPredicate(> as std::marker::Sized>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) --> $DIR/issue-85360-eval-obligation-ice.rs:13:5 | LL | test::>>(make()); diff --git a/tests/ui/traits/project-modulo-regions.rs b/tests/ui/traits/project-modulo-regions.rs index f0c0dd3ed9578..e88f21ecfe801 100644 --- a/tests/ui/traits/project-modulo-regions.rs +++ b/tests/ui/traits/project-modulo-regions.rs @@ -48,8 +48,8 @@ fn test(val: MyStruct) where Helper: HelperTrait { fn foo(val: MyStruct) { test(val); - //[with_clause]~^ ERROR evaluate(Binder(TraitPredicate(, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) - //[without_clause]~^^ ERROR evaluate(Binder(TraitPredicate(, polarity:Positive), [])) = Ok(EvaluatedToOk) + //[with_clause]~^ ERROR evaluate(Binder { value: TraitPredicate(, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) + //[without_clause]~^^ ERROR evaluate(Binder { value: TraitPredicate(, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) } fn main() {} diff --git a/tests/ui/traits/project-modulo-regions.with_clause.stderr b/tests/ui/traits/project-modulo-regions.with_clause.stderr index 2434c32c81882..dcc98e855d1b4 100644 --- a/tests/ui/traits/project-modulo-regions.with_clause.stderr +++ b/tests/ui/traits/project-modulo-regions.with_clause.stderr @@ -1,4 +1,4 @@ -error: evaluate(Binder(TraitPredicate(, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions) +error: evaluate(Binder { value: TraitPredicate(, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOkModuloRegions) --> $DIR/project-modulo-regions.rs:50:5 | LL | fn test(val: MyStruct) where Helper: HelperTrait { diff --git a/tests/ui/traits/project-modulo-regions.without_clause.stderr b/tests/ui/traits/project-modulo-regions.without_clause.stderr index 9d35690d5f0fe..e9959567e06af 100644 --- a/tests/ui/traits/project-modulo-regions.without_clause.stderr +++ b/tests/ui/traits/project-modulo-regions.without_clause.stderr @@ -1,4 +1,4 @@ -error: evaluate(Binder(TraitPredicate(, polarity:Positive), [])) = Ok(EvaluatedToOk) +error: evaluate(Binder { value: TraitPredicate(, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk) --> $DIR/project-modulo-regions.rs:50:5 | LL | fn test(val: MyStruct) where Helper: HelperTrait { From 0441cc21e3b0ce457d030aedd2cc7776fef047c1 Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Wed, 26 Apr 2023 20:23:08 -0400 Subject: [PATCH 299/465] Add release notes for closed PRs with `release-notes` label --- CHANGELOG.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60f961fa12ac8..932fdc33d2428 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,41 @@ ## [Unreleased] +### Fixed + +- When formatting doc comments with `wrap_comments = true` rustfmt will no longer wrap markdown tables [#4210](https://github.com/rust-lang/rustfmt/issues/4210) +- rustfmt will no longer use shorthand initialization when rewriting a tuple struct even when `use_field_init_shorthand = true` as this lead to code that could no longer compile. + Take the following struct as an example `struct MyStruct(u64);`. rustfmt will no longer format `MyStruct { 0: 0 }` as `MyStruct { 0 }` [#5488](https://github.com/rust-lang/rustfmt/issues/5488) +- rustfmt no longer panics when formatting an empty code block in a doc comment with `format_code_in_doc_comments = true` [#5234](https://github.com/rust-lang/rustfmt/issues/5234). For example: + ```rust + /// ``` + /// + /// ``` + fn main() {} + ``` +- Use the correct span when rewriting struct generics. This prevents rustfmt from incorrectly duplicating where clause bounds when using const expression in where clause bounds with feature `#![feature(generic_const_exprs)]` [#5691](https://github.com/rust-lang/rustfmt/issues/5691). e.g.: + ```rust + struct S + where + [(); { num_slots!(C) }]:, { + // code ... + } + ``` + +### Changed + +- Users can now control whether rustc parser errors are displayed with color using rustfmt's `--color` option. To disable colored errors pass `--color=Never` to rustfmt [#5717](https://github.com/rust-lang/rustfmt/issues/5717) + + +### Added + +- rustfmt now recognises `+` as the start of a markdown list, and won't incorrectly wrap sublists that begin with `+` when formatting doc comments with `wrap_comments = true` [#5560](https://github.com/rust-lang/rustfmt/pull/5560) + +### Misc + +- Prevent ICE when parsing invalid attributes in `cfg_if!` macros [#5728](https://github.com/rust-lang/rustfmt/issues/5728) + + ## [1.5.2] 2023-01-24 ### Fixed @@ -56,6 +91,8 @@ - Simplify the rustfmt help text by eliding the full path to the rustfmt binary path from the usage string when running `rustfmt --help` [#5214](https://github.com/rust-lang/rustfmt/issues/5214) +- Bumped the version for serveral dependencies. Most notably `dirs` `v2.0.1` -> `v4.0.0`. This changed the global user config directory on macOS from `$HOME/Library/Preferences` to `$HOME/Library/Application Support` [#5237](https://github.com/rust-lang/rustfmt/pull/5237) + ### Fixed - Remove duplicate imports when `imports_granularity` is set to `Item` [#4725](https://github.com/rust-lang/rustfmt/issues/4725) From c9ebd6ce262ec37c46ff50ac3c56ba19a99254df Mon Sep 17 00:00:00 2001 From: xxchan Date: Mon, 19 Jun 2023 16:29:57 +0200 Subject: [PATCH 300/465] doc: remove installing from source also add "run from source" in contributing.md --- Contributing.md | 10 ++++++++++ README.md | 18 ------------------ 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/Contributing.md b/Contributing.md index 3073996019ee2..b986a887c92ff 100644 --- a/Contributing.md +++ b/Contributing.md @@ -91,6 +91,16 @@ Please try to avoid leaving `TODO`s in the code. There are a few around, but I wish there weren't. You can leave `FIXME`s, preferably with an issue number. +### Run Rustfmt from source code + +You may want to run a version of rustfmt from source code as part of a test or +hacking on the rustfmt codebase. It's strongly discouraged to install a version +of rustfmt from source. Instead, run it using `cargo run`, and `--manifest-path`. + +``` +cargo run --bin cargo-fmt -- --manifest-path path/to/project/you/want2test/Cargo.toml +``` + ### Version-gate formatting changes A change that introduces a different code-formatting should be gated on the diff --git a/README.md b/README.md index ef835371b02a8..c05184fbb04b8 100644 --- a/README.md +++ b/README.md @@ -71,24 +71,6 @@ because in the future Rustfmt might work on code where it currently does not): fixes to break our stability guarantees). -## Installation - -```sh -rustup component add rustfmt -``` - -## Installing from source - -To install from source (nightly required), first checkout to the tag or branch you want to install, then issue - -```sh -cargo install --path . -``` - -This will install `rustfmt` in your `~/.cargo/bin`. Make sure to add `~/.cargo/bin` directory to -your PATH variable. - - ## Running You can run Rustfmt by just typing `rustfmt filename` if you used `cargo From 8d95c269ed83da89c53cef4fd17cca88e7ab1aa8 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 12 Apr 2023 18:52:57 +0800 Subject: [PATCH 301/465] update config_proc_macro to use `syn` 2.0 --- config_proc_macro/Cargo.lock | 30 +++++++++++++++--------------- config_proc_macro/Cargo.toml | 4 ++-- config_proc_macro/src/attrs.rs | 18 +++++++++--------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/config_proc_macro/Cargo.lock b/config_proc_macro/Cargo.lock index 49f2f72a8d219..7af746f0c9659 100644 --- a/config_proc_macro/Cargo.lock +++ b/config_proc_macro/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "proc-macro2" -version = "1.0.3" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.2" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] @@ -32,18 +32,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.99" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.99" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", @@ -52,17 +52,17 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.5" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" +checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] -name = "unicode-xid" -version = "0.2.0" +name = "unicode-ident" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" diff --git a/config_proc_macro/Cargo.toml b/config_proc_macro/Cargo.toml index d10d0469cc401..34e8c237f5564 100644 --- a/config_proc_macro/Cargo.toml +++ b/config_proc_macro/Cargo.toml @@ -13,10 +13,10 @@ proc-macro = true [dependencies] proc-macro2 = "1.0" quote = "1.0" -syn = { version = "1.0", features = ["full", "visit"] } +syn = { version = "2.0", features = ["full", "visit"] } [dev-dependencies] -serde = { version = "1.0", features = ["derive"] } +serde = { version = "1.0.160", features = ["derive"] } [features] default = [] diff --git a/config_proc_macro/src/attrs.rs b/config_proc_macro/src/attrs.rs index dd18ff572cb1c..d8de9aae088d7 100644 --- a/config_proc_macro/src/attrs.rs +++ b/config_proc_macro/src/attrs.rs @@ -51,26 +51,26 @@ pub fn is_unstable_variant(attr: &syn::Attribute) -> bool { } fn is_attr_name_value(attr: &syn::Attribute, name: &str) -> bool { - attr.parse_meta().ok().map_or(false, |meta| match meta { - syn::Meta::NameValue(syn::MetaNameValue { ref path, .. }) if path.is_ident(name) => true, + match &attr.meta { + syn::Meta::NameValue(syn::MetaNameValue { path, .. }) if path.is_ident(name) => true, _ => false, - }) + } } fn is_attr_path(attr: &syn::Attribute, name: &str) -> bool { - attr.parse_meta().ok().map_or(false, |meta| match meta { + match &attr.meta { syn::Meta::Path(path) if path.is_ident(name) => true, _ => false, - }) + } } fn get_name_value_str_lit(attr: &syn::Attribute, name: &str) -> Option { - attr.parse_meta().ok().and_then(|meta| match meta { + match &attr.meta { syn::Meta::NameValue(syn::MetaNameValue { - ref path, - lit: syn::Lit::Str(ref lit_str), + path, + value: syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Str(lit_str), .. }), .. }) if path.is_ident(name) => Some(lit_str.value()), _ => None, - }) + } } From 7d48be355a6342690b48fc0675103ae822024e71 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 12 Apr 2023 18:54:32 +0800 Subject: [PATCH 302/465] bump deps to new versions that use syn 2.0 --- Cargo.toml | 6 +++--- src/cargo-fmt/main.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 12ed65453e19e..78b970c4c9836 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ annotate-snippets = { version = "0.9", features = ["color"] } anyhow = "1.0" bytecount = "0.6" cargo_metadata = "0.14" -clap = { version = "3.1", features = ["derive"] } +clap = { version = "4.2.1", features = ["derive"] } derive-new = "0.5" diff = "0.1" dirs = "4.0" @@ -48,10 +48,10 @@ itertools = "0.10" lazy_static = "1.4" log = "0.4" regex = "1.5" -serde = { version = "1.0", features = ["derive"] } +serde = { version = "1.0.160", features = ["derive"] } serde_json = "1.0" term = "0.7" -thiserror = "1.0" +thiserror = "1.0.40" toml = "0.5" unicode-segmentation = "1.9" unicode-width = "0.1" diff --git a/src/cargo-fmt/main.rs b/src/cargo-fmt/main.rs index 2b714b68df00e..a106181ec7eb6 100644 --- a/src/cargo-fmt/main.rs +++ b/src/cargo-fmt/main.rs @@ -14,7 +14,7 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::str; -use clap::{AppSettings, CommandFactory, Parser}; +use clap::{CommandFactory, Parser}; #[path = "test/mod.rs"] #[cfg(test)] @@ -22,7 +22,7 @@ mod cargo_fmt_tests; #[derive(Parser)] #[clap( - global_setting(AppSettings::NoAutoVersion), + disable_version_flag = true, bin_name = "cargo fmt", about = "This utility formats all bin and lib files of \ the current crate using rustfmt." @@ -45,7 +45,7 @@ pub struct Opts { short = 'p', long = "package", value_name = "package", - multiple_values = true + num_args = 1.. )] packages: Vec, From a463f231f5410ceca88f3eb5dfb8a85b97a63b25 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 12 Apr 2023 18:55:07 +0800 Subject: [PATCH 303/465] remove `derive_new` dependency --- Cargo.lock | 422 +++++++++++++++++++++++++++++----------- Cargo.toml | 1 - src/attr/doc_comment.rs | 7 +- src/formatting.rs | 17 +- src/lib.rs | 2 - src/macros.rs | 5 +- src/pairs.rs | 9 +- 7 files changed, 346 insertions(+), 117 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5b0fd5ae7352c..8487dc58b4ed3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,6 +21,46 @@ dependencies = [ "yansi-term", ] +[[package]] +name = "anstream" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "342258dd14006105c2b75ab1bd7543a03bdf0cfc94383303ac212a04939dff6f" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-wincon", + "concolor-override", + "concolor-query", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2" + +[[package]] +name = "anstyle-parse" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-wincon" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa" +dependencies = [ + "anstyle", + "windows-sys 0.45.0", +] + [[package]] name = "anyhow" version = "1.0.56" @@ -33,17 +73,11 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - [[package]] name = "bitflags" version = "1.3.2" @@ -99,6 +133,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + [[package]] name = "cfg-if" version = "1.0.0" @@ -107,53 +147,69 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.1.8" +version = "4.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c" +checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3" dependencies = [ - "atty", - "bitflags", + "clap_builder", "clap_derive", - "indexmap", - "lazy_static", - "os_str_bytes", + "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f" +dependencies = [ + "anstream", + "anstyle", + "bitflags", + "clap_lex", "strsim", - "termcolor", - "textwrap", ] [[package]] name = "clap_derive" -version = "3.1.7" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3aab4734e083b809aaf5794e14e756d1c798d2c69c7f7de7a09a2f5214993c1" +checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", "syn", ] [[package]] -name = "crossbeam-utils" -version = "0.8.8" +name = "clap_lex" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" + +[[package]] +name = "concolor-override" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a855d4a1978dc52fb0536a04d384c2c0c1aa273597f08b77c8c4d3b2eec6037f" + +[[package]] +name = "concolor-query" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d11d52c3d7ca2e6d0040212be9e4dbbcd78b6447f535b6b561f449427944cf" dependencies = [ - "cfg-if", - "lazy_static", + "windows-sys 0.45.0", ] [[package]] -name = "derive-new" -version = "0.5.9" +name = "crossbeam-utils" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" dependencies = [ - "proc-macro2", - "quote", - "syn", + "cfg-if", + "lazy_static", ] [[package]] @@ -222,6 +278,27 @@ dependencies = [ "termcolor", ] +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "fnv" version = "1.0.7" @@ -261,12 +338,6 @@ dependencies = [ "regex", ] -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - [[package]] name = "heck" version = "0.4.0" @@ -282,6 +353,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "humantime" version = "2.1.0" @@ -307,13 +384,26 @@ dependencies = [ ] [[package]] -name = "indexmap" -version = "1.8.1" +name = "io-lifetimes" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" dependencies = [ - "autocfg", - "hashbrown", + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.48.0", ] [[package]] @@ -339,9 +429,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.122" +version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" [[package]] name = "libm" @@ -349,6 +439,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" +[[package]] +name = "linux-raw-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" + [[package]] name = "log" version = "0.4.16" @@ -366,18 +462,9 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "once_cell" -version = "1.10.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" - -[[package]] -name = "os_str_bytes" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" -dependencies = [ - "memchr", -] +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "packed_simd_2" @@ -389,44 +476,20 @@ dependencies = [ "libm", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" -version = "1.0.37" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.17" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] @@ -486,7 +549,6 @@ dependencies = [ "bytecount", "cargo_metadata", "clap", - "derive-new", "diff", "dirs", "env_logger", @@ -507,6 +569,20 @@ dependencies = [ "unicode_categories", ] +[[package]] +name = "rustix" +version = "0.37.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + [[package]] name = "rustversion" version = "1.0.6" @@ -539,18 +615,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.136" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", @@ -576,13 +652,13 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.91" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" +checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -605,26 +681,20 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "textwrap" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" - [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", @@ -649,6 +719,12 @@ dependencies = [ "serde", ] +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + [[package]] name = "unicode-segmentation" version = "1.9.0" @@ -661,12 +737,6 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - [[package]] name = "unicode_categories" version = "0.1.1" @@ -674,10 +744,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" [[package]] -name = "version_check" -version = "0.9.4" +name = "utf8parse" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "walkdir" @@ -727,6 +797,138 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + [[package]] name = "yansi-term" version = "0.1.2" diff --git a/Cargo.toml b/Cargo.toml index 78b970c4c9836..0093b975e8628 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,6 @@ anyhow = "1.0" bytecount = "0.6" cargo_metadata = "0.14" clap = { version = "4.2.1", features = ["derive"] } -derive-new = "0.5" diff = "0.1" dirs = "4.0" env_logger = "0.9" diff --git a/src/attr/doc_comment.rs b/src/attr/doc_comment.rs index f653a12a8afeb..25c8158df8c50 100644 --- a/src/attr/doc_comment.rs +++ b/src/attr/doc_comment.rs @@ -2,12 +2,17 @@ use crate::comment::CommentStyle; use std::fmt::{self, Display}; /// Formats a string as a doc comment using the given [`CommentStyle`]. -#[derive(new)] pub(super) struct DocCommentFormatter<'a> { literal: &'a str, style: CommentStyle<'a>, } +impl<'a> DocCommentFormatter<'a> { + pub(super) const fn new(literal: &'a str, style: CommentStyle<'a>) -> Self { + Self { literal, style } + } +} + impl Display for DocCommentFormatter<'_> { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { let opener = self.style.opener().trim_end(); diff --git a/src/formatting.rs b/src/formatting.rs index 1dfd8a514f0bc..1f4ad6960e207 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -175,7 +175,6 @@ fn format_project( } // Used for formatting files. -#[derive(new)] struct FormatContext<'a, T: FormatHandler> { krate: &'a ast::Crate, report: FormatReport, @@ -185,6 +184,22 @@ struct FormatContext<'a, T: FormatHandler> { } impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> { + fn new( + krate: &'a ast::Crate, + report: FormatReport, + parse_session: ParseSess, + config: &'a Config, + handler: &'a mut T, + ) -> Self { + FormatContext { + krate, + report, + parse_session, + config, + handler, + } + } + fn ignore_file(&self, path: &FileName) -> bool { self.parse_session.ignore_file(path) } diff --git a/src/lib.rs b/src/lib.rs index 487fcc3a0df1a..0f111f32a4a44 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,8 +4,6 @@ #![recursion_limit = "256"] #![allow(clippy::match_like_matches_macro)] -#[macro_use] -extern crate derive_new; #[cfg(test)] #[macro_use] extern crate lazy_static; diff --git a/src/macros.rs b/src/macros.rs index d58f7547fefb3..5e8bbee7722e9 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1119,12 +1119,15 @@ pub(crate) fn macro_style(mac: &ast::MacCall, context: &RewriteContext<'_>) -> D // A very simple parser that just parses a macros 2.0 definition into its branches. // Currently we do not attempt to parse any further than that. -#[derive(new)] struct MacroParser { toks: Cursor, } impl MacroParser { + const fn new(toks: Cursor) -> Self { + Self { toks } + } + // (`(` ... `)` `=>` `{` ... `}`)* fn parse(&mut self) -> Option { let mut branches = vec![]; diff --git a/src/pairs.rs b/src/pairs.rs index d1c75126ea4a7..d135da7e35919 100644 --- a/src/pairs.rs +++ b/src/pairs.rs @@ -9,7 +9,7 @@ use crate::utils::{ }; /// Sigils that decorate a binop pair. -#[derive(new, Clone, Copy)] +#[derive(Clone, Copy)] pub(crate) struct PairParts<'a> { prefix: &'a str, infix: &'a str, @@ -17,6 +17,13 @@ pub(crate) struct PairParts<'a> { } impl<'a> PairParts<'a> { + pub(crate) const fn new(prefix: &'a str, infix: &'a str, suffix: &'a str) -> Self { + Self { + prefix, + infix, + suffix, + } + } pub(crate) fn infix(infix: &'a str) -> PairParts<'a> { PairParts { prefix: "", From 2e8af07a8aa14de595b11841ce655b9e6c271f60 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 18 Jun 2023 23:11:22 +0000 Subject: [PATCH 304/465] Don't consider TAIT normalizable to hidden ty if it would result in impossible item bounds --- compiler/rustc_borrowck/src/type_check/mod.rs | 3 ++- .../rustc_infer/src/infer/opaque_types.rs | 10 ++++---- .../src/solve/eval_ctxt.rs | 13 +++++++--- .../src/solve/opaques.rs | 24 +++++++++++++++---- .../issue-76202-trait-impl-for-tait.rs | 2 ++ 5 files changed, 39 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 33f75437478b5..cbb1c307354f3 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1065,7 +1065,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { )?; ocx.infcx.add_item_bounds_for_hidden_type( - opaque_type_key, + opaque_type_key.def_id.to_def_id(), + opaque_type_key.substs, cause, param_env, hidden_ty.ty, diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 6b8293f90f10a..b19f685a4a455 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -536,7 +536,8 @@ impl<'tcx> InferCtxt<'tcx> { )?; self.add_item_bounds_for_hidden_type( - opaque_type_key, + opaque_type_key.def_id.to_def_id(), + opaque_type_key.substs, cause, param_env, hidden_ty, @@ -598,7 +599,8 @@ impl<'tcx> InferCtxt<'tcx> { pub fn add_item_bounds_for_hidden_type( &self, - OpaqueTypeKey { def_id, substs }: OpaqueTypeKey<'tcx>, + def_id: DefId, + substs: ty::SubstsRef<'tcx>, cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, hidden_ty: Ty<'tcx>, @@ -631,7 +633,7 @@ impl<'tcx> InferCtxt<'tcx> { // Replace all other mentions of the same opaque type with the hidden type, // as the bounds must hold on the hidden type after all. ty::Alias(ty::Opaque, ty::AliasTy { def_id: def_id2, substs: substs2, .. }) - if def_id.to_def_id() == def_id2 && substs == substs2 => + if def_id == def_id2 && substs == substs2 => { hidden_ty } @@ -640,7 +642,7 @@ impl<'tcx> InferCtxt<'tcx> { ty::Alias( ty::Projection, ty::AliasTy { def_id: def_id2, substs: substs2, .. }, - ) if def_id.to_def_id() == def_id2 && substs == substs2 => hidden_ty, + ) if def_id == def_id2 && substs == substs2 => hidden_ty, _ => ty, }, lt_op: |lt| lt, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 4258f9f6bd28e..106849190e039 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -835,13 +835,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn add_item_bounds_for_hidden_type( &mut self, - opaque_type_key: OpaqueTypeKey<'tcx>, + opaque_def_id: DefId, + opaque_substs: ty::SubstsRef<'tcx>, param_env: ty::ParamEnv<'tcx>, hidden_ty: Ty<'tcx>, ) { let mut obligations = Vec::new(); self.infcx.add_item_bounds_for_hidden_type( - opaque_type_key, + opaque_def_id, + opaque_substs, ObligationCause::dummy(), param_env, hidden_ty, @@ -872,7 +874,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ecx.eq(param_env, a, b)?; } ecx.eq(param_env, candidate_ty, ty)?; - ecx.add_item_bounds_for_hidden_type(candidate_key, param_env, candidate_ty); + ecx.add_item_bounds_for_hidden_type( + candidate_key.def_id.to_def_id(), + candidate_key.substs, + param_env, + candidate_ty, + ); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }, |r| CandidateKind::Candidate { name: "opaque type storage".into(), result: *r }, diff --git a/compiler/rustc_trait_selection/src/solve/opaques.rs b/compiler/rustc_trait_selection/src/solve/opaques.rs index 538c16c8ce2cd..16194f5ad69c0 100644 --- a/compiler/rustc_trait_selection/src/solve/opaques.rs +++ b/compiler/rustc_trait_selection/src/solve/opaques.rs @@ -20,8 +20,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let Some(opaque_ty_def_id) = opaque_ty.def_id.as_local() else { return Err(NoSolution); }; - let opaque_ty = - ty::OpaqueTypeKey { def_id: opaque_ty_def_id, substs: opaque_ty.substs }; // FIXME: at some point we should call queries without defining // new opaque types but having the existing opaque type definitions. // This will require moving this below "Prefer opaques registered already". @@ -41,7 +39,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Ok(()) => {} } // Prefer opaques registered already. - let matches = self.unify_existing_opaque_tys(goal.param_env, opaque_ty, expected); + let opaque_type_key = + ty::OpaqueTypeKey { def_id: opaque_ty_def_id, substs: opaque_ty.substs }; + let matches = + self.unify_existing_opaque_tys(goal.param_env, opaque_type_key, expected); if !matches.is_empty() { if let Some(response) = self.try_merge_responses(&matches) { return Ok(response); @@ -50,11 +51,24 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } // Otherwise, define a new opaque type - self.insert_hidden_type(opaque_ty, goal.param_env, expected)?; - self.add_item_bounds_for_hidden_type(opaque_ty, goal.param_env, expected); + self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?; + self.add_item_bounds_for_hidden_type( + opaque_ty.def_id, + opaque_ty.substs, + goal.param_env, + expected, + ); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } (Reveal::UserFacing, SolverMode::Coherence) => { + // An impossible opaque type bound is the only way this goal will fail + // e.g. assigning `impl Copy := NotCopy` + self.add_item_bounds_for_hidden_type( + opaque_ty.def_id, + opaque_ty.substs, + goal.param_env, + expected, + ); self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } (Reveal::All, _) => { diff --git a/tests/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs b/tests/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs index b97e444c6d0e0..386b77d4d1618 100644 --- a/tests/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs +++ b/tests/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs @@ -1,6 +1,8 @@ // Regression test for issue #76202 // Tests that we don't ICE when we have a trait impl on a TAIT. +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next // check-pass #![feature(type_alias_impl_trait)] From fca56a8d2c6f803aeec51167dd4dd22529f8bdd7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 16 Jun 2023 05:59:42 +0000 Subject: [PATCH 305/465] s/Clause/ClauseKind --- .../src/diagnostics/conflict_errors.rs | 4 +- .../src/diagnostics/region_name.rs | 4 +- .../src/region_infer/opaque_types.rs | 5 +- .../src/type_check/canonical.rs | 12 +- compiler/rustc_borrowck/src/type_check/mod.rs | 13 +- .../rustc_hir_analysis/src/astconv/errors.rs | 4 +- .../rustc_hir_analysis/src/astconv/mod.rs | 20 +-- compiler/rustc_hir_analysis/src/bounds.rs | 16 ++- .../rustc_hir_analysis/src/check/check.rs | 2 +- .../src/check/compare_impl_item.rs | 2 +- compiler/rustc_hir_analysis/src/check/mod.rs | 4 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 20 +-- .../src/coherence/builtin.rs | 2 +- .../src/collect/item_bounds.rs | 8 +- .../src/collect/predicates_of.rs | 32 +++-- .../src/collect/resolve_bound_vars.rs | 2 +- .../src/constrained_generic_params.rs | 2 +- .../rustc_hir_analysis/src/hir_wf_check.rs | 2 +- .../src/impl_wf_check/min_specialization.rs | 26 ++-- .../src/outlives/explicit.rs | 19 ++- .../rustc_hir_analysis/src/outlives/mod.rs | 10 +- .../rustc_hir_analysis/src/variance/mod.rs | 6 +- compiler/rustc_hir_typeck/src/_match.rs | 10 +- compiler/rustc_hir_typeck/src/closure.rs | 8 +- compiler/rustc_hir_typeck/src/coercion.rs | 4 +- compiler/rustc_hir_typeck/src/expr.rs | 2 +- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 22 ++-- .../src/fn_ctxt/adjust_fulfillment_errors.rs | 12 +- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 2 +- .../src/generator_interior/mod.rs | 2 +- compiler/rustc_hir_typeck/src/inherited.rs | 6 +- .../rustc_hir_typeck/src/method/confirm.rs | 2 +- compiler/rustc_hir_typeck/src/method/mod.rs | 4 +- compiler/rustc_hir_typeck/src/method/probe.rs | 14 +- .../rustc_hir_typeck/src/method/suggest.rs | 34 ++--- .../src/infer/canonical/query_response.rs | 18 +-- compiler/rustc_infer/src/infer/combine.rs | 4 +- .../src/infer/error_reporting/mod.rs | 6 +- .../rustc_infer/src/infer/opaque_types.rs | 2 +- .../rustc_infer/src/infer/outlives/mod.rs | 14 +- compiler/rustc_infer/src/infer/projection.rs | 9 +- compiler/rustc_infer/src/traits/mod.rs | 4 +- compiler/rustc_infer/src/traits/util.rs | 20 +-- compiler/rustc_lint/src/builtin.rs | 26 ++-- .../src/opaque_hidden_inferred_bound.rs | 4 +- compiler/rustc_lint/src/traits.rs | 4 +- compiler/rustc_lint/src/unused.rs | 2 +- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/query/erase.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 2 +- .../rustc_middle/src/query/on_disk_cache.rs | 2 +- compiler/rustc_middle/src/ty/codec.rs | 4 +- compiler/rustc_middle/src/ty/context.rs | 4 +- compiler/rustc_middle/src/ty/flags.rs | 17 ++- compiler/rustc_middle/src/ty/mod.rs | 121 +++++++++--------- compiler/rustc_middle/src/ty/parameterized.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 20 +-- .../rustc_middle/src/ty/structural_impls.rs | 16 +-- compiler/rustc_middle/src/ty/util.rs | 2 +- .../src/function_item_references.rs | 2 +- compiler/rustc_mir_transform/src/generator.rs | 2 +- compiler/rustc_privacy/src/lib.rs | 20 +-- .../src/solve/assembly/mod.rs | 8 +- .../src/solve/eval_ctxt.rs | 14 +- .../src/solve/fulfill.rs | 2 +- .../src/solve/project_goals.rs | 2 +- .../src/solve/trait_goals.rs | 2 +- .../src/traits/auto_trait.rs | 18 +-- .../src/traits/const_evaluatable.rs | 2 +- .../src/traits/error_reporting/ambiguity.rs | 2 +- .../src/traits/error_reporting/mod.rs | 36 +++--- .../src/traits/error_reporting/suggestions.rs | 26 ++-- .../src/traits/fulfill.rs | 28 ++-- .../rustc_trait_selection/src/traits/mod.rs | 2 +- .../src/traits/object_safety.rs | 30 ++--- .../src/traits/project.rs | 2 +- .../src/traits/query/evaluate_obligation.rs | 2 +- .../traits/query/type_op/ascribe_user_type.rs | 7 +- .../query/type_op/implied_outlives_bounds.rs | 16 +-- .../traits/query/type_op/prove_predicate.rs | 2 +- .../src/traits/select/candidate_assembly.rs | 4 +- .../src/traits/select/mod.rs | 16 +-- .../src/traits/specialize/mod.rs | 3 +- .../rustc_trait_selection/src/traits/wf.rs | 57 +++++---- compiler/rustc_traits/src/chalk/lowering.rs | 56 ++++---- .../src/normalize_erasing_regions.rs | 14 +- src/librustdoc/clean/auto_trait.rs | 6 +- src/librustdoc/clean/mod.rs | 31 +++-- src/librustdoc/clean/simplify.rs | 4 +- .../clippy/clippy_lints/src/dereference.rs | 8 +- src/tools/clippy/clippy_lints/src/derive.rs | 6 +- .../clippy_lints/src/future_not_send.rs | 4 +- .../src/methods/needless_collect.rs | 4 +- .../src/methods/unnecessary_to_owned.rs | 8 +- .../src/needless_pass_by_value.rs | 2 +- src/tools/clippy/clippy_lints/src/ptr.rs | 4 +- .../src/unit_return_expecting_ord.rs | 6 +- .../clippy/clippy_utils/src/eager_or_lazy.rs | 2 +- .../clippy_utils/src/qualify_min_const_fn.rs | 14 +- src/tools/clippy/clippy_utils/src/ty.rs | 16 +-- 101 files changed, 592 insertions(+), 544 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 15d73ed732f50..9c1c111f7f571 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -678,7 +678,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Find out if the predicates show that the type is a Fn or FnMut let find_fn_kind_from_did = |(pred, _): (ty::Predicate<'tcx>, _)| { - if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred.kind().skip_binder() + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = pred.kind().skip_binder() && pred.self_ty() == ty { if Some(pred.def_id()) == tcx.lang_items().fn_trait() { @@ -775,7 +775,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let predicates: Result, _> = errors .into_iter() .map(|err| match err.obligation.predicate.kind().skip_binder() { - PredicateKind::Clause(ty::Clause::Trait(predicate)) => { + PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { match predicate.self_ty().kind() { ty::Param(param_ty) => Ok(( generics.type_param(param_ty, tcx), diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index f38e1605fa5ca..55c9864af8c74 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -939,8 +939,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { { predicates.iter().any(|pred| { match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) if data.self_ty() == ty => {} - ty::PredicateKind::Clause(ty::Clause::Projection(data)) if data.projection_ty.self_ty() == ty => {} + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) if data.self_ty() == ty => {} + ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) if data.projection_ty.self_ty() == ty => {} _ => return false, } tcx.any_free_region_meets(pred, |r| { diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 6ca702cfdfc3e..4a872eb251c25 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -330,8 +330,9 @@ fn check_opaque_type_well_formed<'tcx>( // Require the hidden type to be well-formed with only the generics of the opaque type. // Defining use functions may have more bounds than the opaque type, which is ok, as long as the // hidden type is well formed even without those bounds. - let predicate = - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(definition_ty.into()))); + let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( + definition_ty.into(), + ))); ocx.register_obligation(Obligation::misc(tcx, definition_span, def_id, param_env, predicate)); // Check that all obligations are satisfied by the implementation's diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index f527eee7bda05..c19fbf20ca5bc 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -89,11 +89,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { category: ConstraintCategory<'tcx>, ) { self.prove_predicate( - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { - trait_ref, - constness: ty::BoundConstness::NotConst, - polarity: ty::ImplPolarity::Positive, - }))), + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Trait( + ty::TraitPredicate { + trait_ref, + constness: ty::BoundConstness::NotConst, + polarity: ty::ImplPolarity::Positive, + }, + ))), locations, category, ); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 33f75437478b5..4dbd3b8b4857c 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1420,7 +1420,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // See #91068 for an example. self.prove_predicates( sig.inputs_and_output.iter().map(|ty| { - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed( + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( ty.into(), ))) }), @@ -1852,7 +1852,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let array_ty = rvalue.ty(body.local_decls(), tcx); self.prove_predicate( - ty::PredicateKind::Clause(ty::Clause::WellFormed(array_ty.into())), + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(array_ty.into())), Locations::Single(location), ConstraintCategory::Boring, ); @@ -2025,10 +2025,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ConstraintCategory::Cast, ); - let outlives_predicate = - tcx.mk_predicate(Binder::dummy(ty::PredicateKind::Clause( - ty::Clause::TypeOutlives(ty::OutlivesPredicate(self_ty, *region)), - ))); + let outlives_predicate = tcx.mk_predicate(Binder::dummy( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( + ty::OutlivesPredicate(self_ty, *region), + )), + )); self.prove_predicate( outlives_predicate, location.to_locations(), diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index 7b922f5d52599..7f060af224556 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -343,7 +343,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let format_pred = |pred: ty::Predicate<'tcx>| { let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { let pred = bound_predicate.rebind(pred); // `::Item = String`. let projection_ty = pred.skip_binder().projection_ty; @@ -364,7 +364,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { bound_span_label(projection_ty.self_ty(), &obligation, &quiet); Some((obligation, projection_ty.self_ty())) } - ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(poly_trait_ref)) => { let p = poly_trait_ref.trait_ref; let self_ty = p.self_ty(); let path = p.print_only_trait_path(); diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 621569ab3215d..14e3ceadb104f 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -950,7 +950,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let bound_pred = pred.kind(); match bound_pred.skip_binder() { ty::PredicateKind::Clause(clause) => match clause { - ty::Clause::Trait(trait_pred) => { + ty::ClauseKind::Trait(trait_pred) => { assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive); trait_bounds.push(( bound_pred.rebind(trait_pred.trait_ref), @@ -958,16 +958,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_pred.constness, )); } - ty::Clause::Projection(proj) => { + ty::ClauseKind::Projection(proj) => { projection_bounds.push((bound_pred.rebind(proj), span)); } - ty::Clause::TypeOutlives(_) => { + ty::ClauseKind::TypeOutlives(_) => { // Do nothing, we deal with regions separately } - ty::Clause::RegionOutlives(_) - | ty::Clause::ConstArgHasType(..) - | ty::Clause::WellFormed(_) - | ty::Clause::ConstEvaluatable(_) => bug!(), + ty::ClauseKind::RegionOutlives(_) + | ty::ClauseKind::ConstArgHasType(..) + | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::ConstEvaluatable(_) => { + bug!() + } }, ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ObjectSafe(_) @@ -1064,7 +1066,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { let pred = bound_predicate.rebind(pred); associated_types.entry(span).or_default().extend( tcx.associated_items(pred.def_id()) @@ -1074,7 +1076,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .map(|item| item.def_id), ); } - ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { let pred = bound_predicate.rebind(pred); // A `Self` within the original bound will be substituted with a // `trait_object_dummy_self`, so check for that. diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 8a318e984d7ae..6bd498e142df1 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -24,7 +24,7 @@ use rustc_span::Span; /// include the self type (e.g., `trait_bounds`) but in others we do not #[derive(Default, PartialEq, Eq, Clone, Debug)] pub struct Bounds<'tcx> { - pub predicates: Vec<(Binder<'tcx, ty::Clause<'tcx>>, Span)>, + pub predicates: Vec<(Binder<'tcx, ty::ClauseKind<'tcx>>, Span)>, } impl<'tcx> Bounds<'tcx> { @@ -34,7 +34,7 @@ impl<'tcx> Bounds<'tcx> { region: ty::PolyTypeOutlivesPredicate<'tcx>, span: Span, ) { - self.predicates.push((region.map_bound(|p| ty::Clause::TypeOutlives(p)), span)); + self.predicates.push((region.map_bound(|p| ty::ClauseKind::TypeOutlives(p)), span)); } pub fn push_trait_bound( @@ -47,7 +47,7 @@ impl<'tcx> Bounds<'tcx> { ) { self.predicates.push(( trait_ref.map_bound(|trait_ref| { - ty::Clause::Trait(ty::TraitPredicate { trait_ref, constness, polarity }) + ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness, polarity }) }), span, )); @@ -59,7 +59,7 @@ impl<'tcx> Bounds<'tcx> { projection: ty::PolyProjectionPredicate<'tcx>, span: Span, ) { - self.predicates.push((projection.map_bound(|proj| ty::Clause::Projection(proj)), span)); + self.predicates.push((projection.map_bound(|proj| ty::ClauseKind::Projection(proj)), span)); } pub fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) { @@ -69,13 +69,17 @@ impl<'tcx> Bounds<'tcx> { self.predicates.insert( 0, ( - ty::Binder::dummy(ty::Clause::Trait(trait_ref.without_const().to_predicate(tcx))), + ty::Binder::dummy(ty::ClauseKind::Trait( + trait_ref.without_const().to_predicate(tcx), + )), span, ), ); } - pub fn predicates(&self) -> impl Iterator>, Span)> + '_ { + pub fn predicates( + &self, + ) -> impl Iterator>, Span)> + '_ { self.predicates.iter().cloned() } } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index c09734d6e6983..22aa3c7ff08b4 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -440,7 +440,7 @@ fn check_opaque_meets_bounds<'tcx>( // Defining use functions may have more bounds than the opaque type, which is ok, as long as the // hidden type is well formed even without those bounds. let predicate = - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(hidden_ty.into()))); + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(hidden_ty.into()))); ocx.register_obligation(Obligation::new(tcx, misc_cause, param_env, predicate)); // Check that all obligations are satisfied by the implementation's diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 838b212ef8782..b2ba566f60c74 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -321,7 +321,7 @@ fn compare_method_predicate_entailment<'tcx>( infcx.tcx, ObligationCause::dummy(), param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed( + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( unnormalized_impl_fty.into(), ))), )); diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index c9e74896ac08e..40feb67575823 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -304,7 +304,7 @@ fn bounds_from_generic_predicates<'tcx>( debug!("predicate {:?}", predicate); let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => { let entry = types.entry(trait_predicate.self_ty()).or_default(); let def_id = trait_predicate.def_id(); if Some(def_id) != tcx.lang_items().sized_trait() { @@ -313,7 +313,7 @@ fn bounds_from_generic_predicates<'tcx>( entry.push(trait_predicate.def_id()); } } - ty::PredicateKind::Clause(ty::Clause::Projection(projection_pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection_pred)) => { projections.push(bound_predicate.rebind(projection_pred)); } _ => {} diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 73a7ba005b330..51e9b4c4501d8 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -81,7 +81,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { self.tcx(), cause, param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(arg))), + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg))), )); } } @@ -419,10 +419,9 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe let mut unsatisfied_bounds: Vec<_> = required_bounds .into_iter() .filter(|clause| match clause.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate( - a, - b, - ))) => !region_known_to_outlive( + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives( + ty::OutlivesPredicate(a, b), + )) => !region_known_to_outlive( tcx, gat_def_id.def_id, param_env, @@ -430,7 +429,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe a, b, ), - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( a, b, ))) => !ty_known_to_outlive( @@ -574,7 +573,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable>>( ); // The predicate we expect to see. (In our example, // `Self: 'me`.) - let clause = ty::PredicateKind::Clause(ty::Clause::TypeOutlives( + let clause = ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( ty::OutlivesPredicate(ty_param, region_param), )); let clause = tcx.mk_predicate(ty::Binder::dummy(clause)); @@ -623,7 +622,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable>>( }, ); // The predicate we expect to see. - let clause = ty::PredicateKind::Clause(ty::Clause::RegionOutlives( + let clause = ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives( ty::OutlivesPredicate(region_a_param, region_b_param), )); let clause = tcx.mk_predicate(ty::Binder::dummy(clause)); @@ -1032,7 +1031,7 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b tcx, cause, wfcx.param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable( + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable( ty::Const::from_anon_const(tcx, discr_def_id.expect_local()), ))), )); @@ -1876,7 +1875,8 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { // We lower empty bounds like `Vec:` as // `WellFormed(Vec)`, which will later get checked by // regular WF checking - if let ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) = pred.kind().skip_binder() + if let ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) = + pred.kind().skip_binder() { continue; } diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index a98d8e17153d8..2441c8667d49a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -571,7 +571,7 @@ fn infringing_fields_error( .or_default() .push(error.obligation.cause.span); } - if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: ty::ImplPolarity::Positive, .. diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 0479efceaad90..b3e9acf0a4b33 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -36,11 +36,13 @@ fn associated_type_bounds<'tcx>( let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| { match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(tr)) => tr.self_ty() == item_ty, - ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr)) => tr.self_ty() == item_ty, + ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) => { proj.projection_ty.self_ty() == item_ty } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(outlives)) => outlives.0 == item_ty, + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => { + outlives.0 == item_ty + } _ => false, } }); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index c905db0617409..cd801202aeac1 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -190,7 +190,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen let ct = tcx.mk_const(param_const, ct_ty); let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( - ty::Clause::ConstArgHasType(ct, ct_ty), + ty::ClauseKind::ConstArgHasType(ct, ct_ty), )) .to_predicate(tcx); predicates.insert((predicate, param.span)); @@ -222,7 +222,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } else { let span = bound_pred.bounded_ty.span; let predicate = ty::Binder::bind_with_vars( - ty::PredicateKind::Clause(ty::Clause::WellFormed(ty.into())), + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty.into())), bound_vars, ); predicates.insert((predicate.to_predicate(tcx), span)); @@ -252,7 +252,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen _ => bug!(), }; let pred = ty::Binder::dummy(ty::PredicateKind::Clause( - ty::Clause::RegionOutlives(ty::OutlivesPredicate(r1, r2)), + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)), )) .to_predicate(icx.tcx); @@ -320,14 +320,14 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen }, ); predicates.push(( - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives( + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives( ty::OutlivesPredicate(orig_region, dup_region), ))) .to_predicate(icx.tcx), duplicate.span, )); predicates.push(( - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives( + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives( ty::OutlivesPredicate(dup_region, orig_region), ))) .to_predicate(icx.tcx), @@ -358,8 +358,10 @@ fn const_evaluatable_predicates_of( if let ty::ConstKind::Unevaluated(_) = ct.kind() { let span = self.tcx.def_span(c.def_id); self.preds.insert(( - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(ct))) - .to_predicate(self.tcx), + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable( + ct, + ))) + .to_predicate(self.tcx), span, )); } @@ -449,11 +451,13 @@ pub(super) fn explicit_predicates_of<'tcx>( .iter() .copied() .filter(|(pred, _)| match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(tr)) => !is_assoc_item_ty(tr.self_ty()), - ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr)) => { + !is_assoc_item_ty(tr.self_ty()) + } + ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) => { !is_assoc_item_ty(proj.projection_ty.self_ty()) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(outlives)) => { + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => { !is_assoc_item_ty(outlives.0) } _ => true, @@ -496,7 +500,7 @@ pub(super) fn explicit_predicates_of<'tcx>( .predicates .into_iter() .filter(|(pred, _)| { - if let ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, _)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _)) = pred.kind().skip_binder() { match ct.kind() { @@ -677,7 +681,7 @@ pub(super) fn implied_predicates_with_filter( if matches!(filter, PredicateFilter::SelfOnly) { for &(pred, span) in implied_bounds { debug!("superbound: {:?}", pred); - if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = pred.kind().skip_binder() + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(bound)) = pred.kind().skip_binder() && bound.polarity == ty::ImplPolarity::Positive { tcx.at(span).super_predicates_of(bound.def_id()); @@ -774,7 +778,9 @@ pub(super) fn type_param_predicates( ) .into_iter() .filter(|(predicate, _)| match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => data.self_ty().is_param(index), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { + data.self_ty().is_param(index) + } _ => false, }), ); diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 794812a5ce7d9..d20f39e9b05b9 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1761,7 +1761,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| { let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { // The order here needs to match what we would get from `subst_supertrait` let pred_bound_vars = bound_predicate.bound_vars(); let mut all_bound_vars = bound_vars.clone(); diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 9200c2aecf55c..6aecb95b484a1 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -187,7 +187,7 @@ pub fn setup_constraining_predicates<'tcx>( for j in i..predicates.len() { // Note that we don't have to care about binders here, // as the impl trait ref never contains any late-bound regions. - if let ty::PredicateKind::Clause(ty::Clause::Projection(projection)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection)) = predicates[j].0.kind().skip_binder() { // Special case: watch out for some kind of sneaky attempt diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index f2618b3daf147..f1765174d79de 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -79,7 +79,7 @@ fn diagnostic_hir_wf_check<'tcx>( self.tcx, cause, self.param_env, - ty::PredicateKind::Clause(ty::Clause::WellFormed(tcx_ty.into())), + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(tcx_ty.into())), )); for error in ocx.select_all_or_error() { diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 201cb94f0b319..97813a291da62 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -236,7 +236,7 @@ fn unconstrained_parent_impl_substs<'tcx>( // the functions in `cgp` add the constrained parameters to a list of // unconstrained parameters. for (predicate, _) in impl_generic_predicates.predicates.iter() { - if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = predicate.kind().skip_binder() { let projection_ty = proj.projection_ty; @@ -438,8 +438,8 @@ fn trait_predicates_eq<'tcx>( let pred2_kind = predicate2.kind().skip_binder(); let (trait_pred1, trait_pred2) = match (pred1_kind, pred2_kind) { ( - ty::PredicateKind::Clause(ty::Clause::Trait(pred1)), - ty::PredicateKind::Clause(ty::Clause::Trait(pred2)), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred1)), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred2)), ) => (pred1, pred2), // Just use plain syntactic equivalence if either of the predicates aren't // trait predicates or have bound vars. @@ -478,7 +478,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc _ if predicate.is_global() => (), // We allow specializing on explicitly marked traits with no associated // items. - ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity: _, @@ -498,7 +498,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc .emit(); } } - ty::PredicateKind::Clause(ty::Clause::Projection(ty::ProjectionPredicate { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term, })) => { @@ -509,7 +509,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc ) .emit(); } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => { // FIXME(min_specialization), FIXME(const_generics): // It probably isn't right to allow _every_ `ConstArgHasType` but I am somewhat unsure // about the actual rules that would be sound. Can't just always error here because otherwise @@ -532,22 +532,22 @@ fn trait_predicate_kind<'tcx>( predicate: ty::Predicate<'tcx>, ) -> Option { match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity: _, })) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind), - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(_)) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_)) - | ty::PredicateKind::Clause(ty::Clause::Projection(_)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) | ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) | ty::PredicateKind::ObjectSafe(_) | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index 79c56490f3c1a..e63549998d2ac 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -30,7 +30,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { // process predicates and convert to `RequiredPredicates` entry, see below for &(predicate, span) in predicates.predicates { match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(OutlivesPredicate( ty, reg, ))) => insert_outlives_predicate( @@ -41,10 +41,9 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { &mut required_predicates, ), - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(OutlivesPredicate( - reg1, - reg2, - ))) => insert_outlives_predicate( + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives( + OutlivesPredicate(reg1, reg2), + )) => insert_outlives_predicate( tcx, reg1.into(), reg2, @@ -52,16 +51,16 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { &mut required_predicates, ), - ty::PredicateKind::Clause(ty::Clause::Trait(..)) - | ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => (), diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs index fdbb890ce3d47..98f4a8e00ef90 100644 --- a/compiler/rustc_hir_analysis/src/outlives/mod.rs +++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs @@ -17,7 +17,7 @@ pub fn provide(providers: &mut Providers) { *providers = Providers { inferred_outlives_of, inferred_outlives_crate, ..*providers }; } -fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clause<'_>, Span)] { +fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::ClauseKind<'_>, Span)] { let id = tcx.hir().local_def_id_to_hir_id(item_def_id); if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) @@ -53,8 +53,8 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clau let mut pred: Vec = predicates .iter() .map(|(out_pred, _)| match out_pred { - ty::Clause::RegionOutlives(p) => p.to_string(), - ty::Clause::TypeOutlives(p) => p.to_string(), + ty::ClauseKind::RegionOutlives(p) => p.to_string(), + ty::ClauseKind::TypeOutlives(p) => p.to_string(), err => bug!("unexpected clause {:?}", err), }) .collect(); @@ -104,11 +104,11 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> { |(ty::OutlivesPredicate(kind1, region2), &span)| { match kind1.unpack() { GenericArgKind::Type(ty1) => Some(( - ty::Clause::TypeOutlives(ty::OutlivesPredicate(ty1, *region2)), + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty1, *region2)), span, )), GenericArgKind::Lifetime(region1) => Some(( - ty::Clause::RegionOutlives(ty::OutlivesPredicate( + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( region1, *region2, )), span, diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 3ebd9e134bfa2..8bb9ca2acf24a 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -162,7 +162,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc // which thus mentions `'a` and should thus accept hidden types that borrow 'a // instead of requiring an additional `+ 'a`. match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref: ty::TraitRef { def_id: _, substs, .. }, constness: _, polarity: _, @@ -171,7 +171,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc subst.visit_with(&mut collector); } } - ty::PredicateKind::Clause(ty::Clause::Projection(ty::ProjectionPredicate { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty: ty::AliasTy { substs, .. }, term, })) => { @@ -180,7 +180,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc } term.visit_with(&mut collector); } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( _, region, ))) => { diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 444ff90595c23..a07580fe72d4a 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -542,25 +542,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .subst_iter_copied(self.tcx, substs) { let pred = pred.kind().rebind(match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => { // FIXME(rpitit): This will need to be fixed when we move to associated types assert!(matches!( *trait_pred.trait_ref.self_ty().kind(), ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. }) if def_id == rpit_def_id && substs == alias_substs )); - ty::PredicateKind::Clause(ty::Clause::Trait( + ty::PredicateKind::Clause(ty::ClauseKind::Trait( trait_pred.with_self_ty(self.tcx, ty), )) } - ty::PredicateKind::Clause(ty::Clause::Projection(mut proj_pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection( + mut proj_pred, + )) => { assert!(matches!( *proj_pred.projection_ty.self_ty().kind(), ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. }) if def_id == rpit_def_id && substs == alias_substs )); proj_pred = proj_pred.with_self_ty(self.tcx, ty); - ty::PredicateKind::Clause(ty::Clause::Projection(proj_pred)) + ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj_pred)) } _ => continue, }); diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index dce426ca2db6a..94b37fb3450d0 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -222,7 +222,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Given a Projection predicate, we can potentially infer // the complete signature. if expected_sig.is_none() - && let ty::PredicateKind::Clause(ty::Clause::Projection(proj_predicate)) = bound_predicate.skip_binder() + && let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj_predicate)) = bound_predicate.skip_binder() { let inferred_sig = self.normalize( span, @@ -258,10 +258,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // like `F : Fn`. Note that due to subtyping we could encounter // many viable options, so pick the most restrictive. let trait_def_id = match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { Some(data.projection_ty.trait_def_id(self.tcx)) } - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => Some(data.def_id()), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => Some(data.def_id()), _ => None, }; if let Some(closure_kind) = @@ -695,7 +695,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // where R is the return type we are expecting. This type `T` // will be our output. let bound_predicate = predicate.kind(); - if let ty::PredicateKind::Clause(ty::Clause::Projection(proj_predicate)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj_predicate)) = bound_predicate.skip_binder() { self.deduce_future_output_from_projection( diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 79157eae7ed6d..c0c839b1f1862 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -631,7 +631,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { debug!("coerce_unsized resolve step: {:?}", obligation); let bound_predicate = obligation.predicate.kind(); let trait_pred = match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) if traits.contains(&trait_pred.def_id()) => { if unsize_did == trait_pred.def_id() { @@ -767,7 +767,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.tcx, self.cause.clone(), self.param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::TypeOutlives( + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( ty::OutlivesPredicate(a, b_region), ))), ), diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 3f6847be91b65..e250e68a7f176 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2983,7 +2983,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { for error in errors { match error.obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) if self.tcx.is_diagnostic_item(sym::SliceIndex, predicate.trait_ref.def_id) => { } _ => continue, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 34f98f4310ee4..b44c51ba94588 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -483,7 +483,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, cause, self.param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(arg))), + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg))), )); } @@ -647,7 +647,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.fulfillment_cx.borrow().pending_obligations().into_iter().filter_map( move |obligation| match &obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(data)) + ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) if self.self_type_matches_expected_vid( data.projection_ty.self_ty(), ty_var_root, @@ -655,23 +655,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { Some(obligation) } - ty::PredicateKind::Clause(ty::Clause::Trait(data)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) if self.self_type_matches_expected_vid(data.self_ty(), ty_var_root) => { Some(obligation) } - ty::PredicateKind::Clause(ty::Clause::Trait(..)) - | ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) // N.B., this predicate is created by breaking down a // `ClosureType: FnFoo()` predicate, where @@ -692,7 +692,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let sized_did = self.tcx.lang_items().sized_trait(); self.obligations_for_self_ty(self_ty).any(|obligation| { match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { Some(data.def_id()) == sized_did } _ => false, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index 2135643cbeb93..880437023c8b5 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -25,14 +25,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let generics = self.tcx.generics_of(def_id); let predicate_substs = match unsubstituted_pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs.to_vec(), - ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { + pred.trait_ref.substs.to_vec() + } + ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { pred.projection_ty.substs.to_vec() } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(arg, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(arg, ty)) => { vec![ty.into(), arg.into()] } - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(e)) => vec![e.into()], + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(e)) => vec![e.into()], _ => return false, }; @@ -514,7 +516,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { impl_predicates.predicates[impl_predicate_index].0.kind().skip_binder(); match relevant_broken_predicate { - ty::PredicateKind::Clause(ty::Clause::Trait(broken_trait)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(broken_trait)) => { // ... self.blame_specific_part_of_expr_corresponding_to_generic_param( broken_trait.trait_ref.self_ty().into(), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index bf8ad5faac482..f294ff0051df5 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1948,7 +1948,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // do that, so it's OK. for (predicate, span) in instantiated { - if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = predicate.kind().skip_binder() + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = predicate.kind().skip_binder() && pred.self_ty().peel_refs() == callee_ty && self.tcx.is_fn_trait(pred.def_id()) { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 630878bbf0c60..d311ebe8c327e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -226,7 +226,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { predicates: tcx.arena.alloc_from_iter( self.param_env.caller_bounds().iter().filter_map(|predicate| { match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) if data.self_ty().is_param(index) => { // HACK(eddyb) should get the original `Span`. diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index fb28233bfb1c2..dabe7749cb610 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -577,7 +577,7 @@ fn check_must_not_suspend_ty<'tcx>( let mut has_emitted = false; for &(predicate, _) in fcx.tcx.explicit_item_bounds(def).skip_binder() { // We only look at the `DefId`, so it is safe to skip the binder here. - if let ty::PredicateKind::Clause(ty::Clause::Trait(ref poly_trait_predicate)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ref poly_trait_predicate)) = predicate.kind().skip_binder() { let def_id = poly_trait_predicate.trait_ref.def_id; diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs index aa4f90b4ad8a0..c193d76180420 100644 --- a/compiler/rustc_hir_typeck/src/inherited.rs +++ b/compiler/rustc_hir_typeck/src/inherited.rs @@ -129,7 +129,7 @@ impl<'tcx> Inherited<'tcx> { let infer_var_info = &mut self.infer_var_info.borrow_mut(); // (*) binder skipped - if let ty::PredicateKind::Clause(ty::Clause::Trait(tpred)) = obligation.predicate.kind().skip_binder() + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(tpred)) = obligation.predicate.kind().skip_binder() && let Some(ty) = self.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| self.root_var(t)) && self.tcx.lang_items().sized_trait().is_some_and(|st| st != tpred.trait_ref.def_id) { @@ -143,7 +143,7 @@ impl<'tcx> Inherited<'tcx> { .kind() .rebind( // (*) binder moved here - ty::PredicateKind::Clause(ty::Clause::Trait(tpred.with_self_ty(self.tcx, new_self_ty))) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(tpred.with_self_ty(self.tcx, new_self_ty))) ), ); // Don't report overflow errors. Otherwise equivalent to may_hold. @@ -152,7 +152,7 @@ impl<'tcx> Inherited<'tcx> { } } - if let ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) = obligation.predicate.kind().skip_binder() { // If the projection predicate (Foo::Bar == X) has X as a non-TyVid, diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 6cd7bd5d196df..279ff849e3d53 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -606,7 +606,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { traits::elaborate(self.tcx, predicates.predicates.iter().copied()) // We don't care about regions here. .filter_map(|pred| match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) if trait_pred.def_id() == sized_def_id => { let span = predicates diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 59736b42cf7a8..ebd7b3123ebfd 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -473,7 +473,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx, obligation.cause, self.param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(method_ty.into()))), + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( + method_ty.into(), + ))), )); let callee = MethodCallee { def_id, substs, sig: fn_sig }; diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 91347c01327c3..e759fd6bc948a 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -825,7 +825,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| { let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => { match *trait_predicate.trait_ref.self_ty().kind() { ty::Param(p) if p == param_ty => { Some(bound_predicate.rebind(trait_predicate.trait_ref)) @@ -834,15 +834,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } ty::PredicateKind::Subtype(..) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::AliasRelate(..) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 66e771b794aad..67fb7c1d48cda 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -542,7 +542,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut unimplemented_traits = FxHashMap::default(); let mut unimplemented_traits_only = true; for (predicate, _parent_pred, cause) in unsatisfied_predicates { - if let (ty::PredicateKind::Clause(ty::Clause::Trait(p)), Some(cause)) = + if let (ty::PredicateKind::Clause(ty::ClauseKind::Trait(p)), Some(cause)) = (predicate.kind().skip_binder(), cause.as_ref()) { if p.trait_ref.self_ty() != rcvr_ty { @@ -569,7 +569,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // because of some non-Clone item being iterated over. for (predicate, _parent_pred, _cause) in unsatisfied_predicates { match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(p)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(p)) if unimplemented_traits.contains_key(&p.trait_ref.def_id) => {} _ => { unimplemented_traits_only = false; @@ -581,7 +581,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut collect_type_param_suggestions = |self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| { // We don't care about regions here, so it's fine to skip the binder here. - if let (ty::Param(_), ty::PredicateKind::Clause(ty::Clause::Trait(p))) = + if let (ty::Param(_), ty::PredicateKind::Clause(ty::ClauseKind::Trait(p))) = (self_ty.kind(), parent_pred.kind().skip_binder()) { let hir = self.tcx.hir(); @@ -641,7 +641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut format_pred = |pred: ty::Predicate<'tcx>| { let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { let pred = bound_predicate.rebind(pred); // `::Item = String`. let projection_ty = pred.skip_binder().projection_ty; @@ -665,7 +665,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bound_span_label(projection_ty.self_ty(), &obligation, &quiet); Some((obligation, projection_ty.self_ty())) } - ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(poly_trait_ref)) => { let p = poly_trait_ref.trait_ref; let self_ty = p.self_ty(); let path = p.print_only_trait_path(); @@ -698,7 +698,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Don't point out the span of `WellFormed` predicates. if !matches!( p.kind().skip_binder(), - ty::PredicateKind::Clause(ty::Clause::Projection(..) | ty::Clause::Trait(..)) + ty::PredicateKind::Clause( + ty::ClauseKind::Projection(..) | ty::ClauseKind::Trait(..) + ) ) { continue; }; @@ -740,7 +742,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let sized_pred = unsatisfied_predicates.iter().any(|(pred, _, _)| { match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { Some(pred.def_id()) == self.tcx.lang_items().sized_trait() && pred.polarity == ty::ImplPolarity::Positive } @@ -2012,16 +2014,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let all_local_types_needing_impls = errors.iter().all(|e| match e.obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => match pred.self_ty().kind() { - ty::Adt(def, _) => def.did().is_local(), - _ => false, - }, + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { + match pred.self_ty().kind() { + ty::Adt(def, _) => def.did().is_local(), + _ => false, + } + } _ => false, }); let mut preds: Vec<_> = errors .iter() .filter_map(|e| match e.obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => Some(pred), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => Some(pred), _ => None, }) .collect(); @@ -2092,7 +2096,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut derives = Vec::<(String, Span, Symbol)>::new(); let mut traits = Vec::new(); for (pred, _, _) in unsatisfied_predicates { - let Some(ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))) = + let Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))) = pred.kind().no_bound_vars() else { continue @@ -2527,10 +2531,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match p.kind().skip_binder() { // Hide traits if they are present in predicates as they can be fixed without // having to implement them. - ty::PredicateKind::Clause(ty::Clause::Trait(t)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => { t.def_id() == info.def_id } - ty::PredicateKind::Clause(ty::Clause::Projection(p)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => { p.projection_ty.def_id == info.def_id } _ => false, diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 2cf8d8c702d46..630014e23806b 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -584,12 +584,12 @@ impl<'tcx> InferCtxt<'tcx> { let ty::OutlivesPredicate(k1, r2) = predicate; let atom = match k1.unpack() { - GenericArgKind::Lifetime(r1) => { - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate(r1, r2))) - } - GenericArgKind::Type(t1) => { - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(t1, r2))) - } + GenericArgKind::Lifetime(r1) => ty::PredicateKind::Clause( + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)), + ), + GenericArgKind::Type(t1) => ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( + ty::OutlivesPredicate(t1, r2), + )), GenericArgKind::Const(..) => { // Consts cannot outlive one another, so we don't expect to // encounter this branch. @@ -739,9 +739,9 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { self.obligations.push(Obligation { cause: self.cause.clone(), param_env: self.param_env, - predicate: ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives( - ty::OutlivesPredicate(sup, sub), - ))) + predicate: ty::Binder::dummy(ty::PredicateKind::Clause( + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(sup, sub)), + )) .to_predicate(self.infcx.tcx), recursion_depth: 0, }); diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 152c56572b691..bc5ca9fcf7ae1 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -417,7 +417,9 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { self.tcx(), self.trace.cause.clone(), self.param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(b_ty.into()))), + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( + b_ty.into(), + ))), )); } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index fc1f90fdc13f4..63370eec10b29 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -408,9 +408,9 @@ impl<'tcx> InferCtxt<'tcx> { predicate .kind() .map_bound(|kind| match kind { - ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate)) - if projection_predicate.projection_ty.def_id == item_def_id => - { + ty::PredicateKind::Clause(ty::ClauseKind::Projection( + projection_predicate, + )) if projection_predicate.projection_ty.def_id == item_def_id => { projection_predicate.term.ty() } _ => None, diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 6b8293f90f10a..54ebc313d8a75 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -647,7 +647,7 @@ impl<'tcx> InferCtxt<'tcx> { ct_op: |ct| ct, }); - if let ty::PredicateKind::Clause(ty::Clause::Projection(projection)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection)) = predicate.kind().skip_binder() { if projection.term.references_error() { diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index c1f0b9253a5e8..d926f7f7cbd61 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -23,21 +23,21 @@ pub fn explicit_outlives_bounds<'tcx>( .map(ty::Predicate::kind) .filter_map(ty::Binder::no_bound_vars) .filter_map(move |kind| match kind { - ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::Clause(ty::Clause::Trait(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Subtype(..) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( r_a, r_b, ))) => Some(OutlivesBound::RegionSubRegion(r_b, r_a)), diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs index 4f8c9188cf85b..7545553318136 100644 --- a/compiler/rustc_infer/src/infer/projection.rs +++ b/compiler/rustc_infer/src/infer/projection.rs @@ -27,7 +27,7 @@ impl<'tcx> InferCtxt<'tcx> { // // The new solver correctly handles projection equality so this hack // is not necessary. if re-enabled it should emit `PredicateKind::AliasRelate` - // not `PredicateKind::Clause(Clause::Projection(..))` as in the new solver + // not `PredicateKind::Clause(ClauseKind::Projection(..))` as in the new solver // `Projection` is used as `normalizes-to` which will fail for `::Assoc eq ?0`. return projection_ty.to_ty(self.tcx); } else { @@ -36,9 +36,10 @@ impl<'tcx> InferCtxt<'tcx> { kind: TypeVariableOriginKind::NormalizeProjectionType, span: self.tcx.def_span(def_id), }); - let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Projection( - ty::ProjectionPredicate { projection_ty, term: ty_var.into() }, - ))); + let projection = + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Projection( + ty::ProjectionPredicate { projection_ty, term: ty_var.into() }, + ))); let obligation = Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection); obligations.push(obligation); diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 8ce8b4e2024eb..6da490a90ee38 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -79,8 +79,8 @@ impl<'tcx> PredicateObligation<'tcx> { pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> PredicateObligation<'tcx> { self.param_env = self.param_env.without_const(); - if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = self.predicate.kind().skip_binder() && trait_pred.is_const_if_const() { - self.predicate = tcx.mk_predicate(self.predicate.kind().map_bound(|_| ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred.without_const())))); + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = self.predicate.kind().skip_binder() && trait_pred.is_const_if_const() { + self.predicate = tcx.mk_predicate(self.predicate.kind().map_bound(|_| ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred.without_const())))); } self } diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 5622062ef7ef7..4f65a312c4ef7 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -199,7 +199,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { let bound_predicate = elaboratable.predicate().kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { // Negative trait bounds do not imply any supertrait bounds if data.polarity == ty::ImplPolarity::Negative { return; @@ -227,7 +227,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { debug!(?data, ?obligations, "super_predicates"); self.extend_deduped(obligations); } - ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) => { // Currently, we do not elaborate WF predicates, // although we easily could. } @@ -243,13 +243,13 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { // Currently, we do not "elaborate" predicates like `X -> Y`, // though conceivably we might. } - ty::PredicateKind::Clause(ty::Clause::Projection(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) => { // Nothing to elaborate in a projection predicate. } ty::PredicateKind::ClosureKind(..) => { // Nothing to elaborate when waiting for a closure's kind to be inferred. } - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) => { // Currently, we do not elaborate const-evaluatable // predicates. } @@ -257,10 +257,10 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { // Currently, we do not elaborate const-equate // predicates. } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) => { // Nothing to elaborate from `'a: 'b`. } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( ty_max, r_min, ))) => { @@ -292,7 +292,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { if r.is_late_bound() { None } else { - Some(ty::PredicateKind::Clause(ty::Clause::RegionOutlives( + Some(ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives( ty::OutlivesPredicate(r, r_min), ))) } @@ -300,7 +300,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { Component::Param(p) => { let ty = tcx.mk_ty_param(p.index, p.name); - Some(ty::PredicateKind::Clause(ty::Clause::TypeOutlives( + Some(ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( ty::OutlivesPredicate(ty, r_min), ))) } @@ -310,7 +310,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { Component::Alias(alias_ty) => { // We might end up here if we have `Foo<::Assoc>: 'a`. // With this, we can deduce that `::Assoc: 'a`. - Some(ty::PredicateKind::Clause(ty::Clause::TypeOutlives( + Some(ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( ty::OutlivesPredicate(alias_ty.to_ty(tcx), r_min), ))) } @@ -334,7 +334,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { ty::PredicateKind::AliasRelate(..) => { // No } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => { // Nothing to elaborate } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 785adc0b4fb69..9fb83bec99372 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1592,27 +1592,27 @@ declare_lint_pass!( impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { - use rustc_middle::ty::Clause; + use rustc_middle::ty::ClauseKind; use rustc_middle::ty::PredicateKind::*; if cx.tcx.features().trivial_bounds { let predicates = cx.tcx.predicates_of(item.owner_id); for &(predicate, span) in predicates.predicates { let predicate_kind_name = match predicate.kind().skip_binder() { - Clause(Clause::Trait(..)) => "trait", - Clause(Clause::TypeOutlives(..)) | - Clause(Clause::RegionOutlives(..)) => "lifetime", + Clause(ClauseKind::Trait(..)) => "trait", + Clause(ClauseKind::TypeOutlives(..)) | + Clause(ClauseKind::RegionOutlives(..)) => "lifetime", // `ConstArgHasType` is never global as `ct` is always a param - Clause(Clause::ConstArgHasType(..)) | + Clause(ClauseKind::ConstArgHasType(..)) | // Ignore projections, as they can only be global // if the trait bound is global - Clause(Clause::Projection(..)) | - AliasRelate(..) | + Clause(ClauseKind::Projection(..)) | // Ignore bounds that a user can't type - Clause(Clause::WellFormed(..)) | + Clause(ClauseKind::WellFormed(..)) | // FIXME(generic_const_exprs): `ConstEvaluatable` can be written - Clause(Clause::ConstEvaluatable(..)) | + Clause(ClauseKind::ConstEvaluatable(..)) | + AliasRelate(..) | ObjectSafe(..) | ClosureKind(..) | Subtype(..) | @@ -1984,13 +1984,13 @@ declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMEN impl ExplicitOutlivesRequirements { fn lifetimes_outliving_lifetime<'tcx>( - inferred_outlives: &'tcx [(ty::Clause<'tcx>, Span)], + inferred_outlives: &'tcx [(ty::ClauseKind<'tcx>, Span)], def_id: DefId, ) -> Vec> { inferred_outlives .iter() .filter_map(|(clause, _)| match *clause { - ty::Clause::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a { + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a { ty::ReEarlyBound(ebr) if ebr.def_id == def_id => Some(b), _ => None, }, @@ -2000,13 +2000,13 @@ impl ExplicitOutlivesRequirements { } fn lifetimes_outliving_type<'tcx>( - inferred_outlives: &'tcx [(ty::Clause<'tcx>, Span)], + inferred_outlives: &'tcx [(ty::ClauseKind<'tcx>, Span)], index: u32, ) -> Vec> { inferred_outlives .iter() .filter_map(|(clause, _)| match *clause { - ty::Clause::TypeOutlives(ty::OutlivesPredicate(a, b)) => { + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => { a.is_param(index).then_some(b) } _ => None, diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 15715c8fca039..61c23b4c255e2 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { // Liberate bound regions in the predicate since we // don't actually care about lifetimes in this check. let predicate = cx.tcx.liberate_late_bound_regions(def_id, pred.kind()); - let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = predicate else { + let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = predicate else { continue; }; // Only check types, since those are the only things that may @@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) { ( ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), - ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)), ) => Some(AddBound { suggest_span: cx.tcx.def_span(*def_id).shrink_to_hi(), trait_ref: trait_pred.print_modifiers_and_trait_path(), diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index 7ea1a138b7e60..8aba534957858 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -87,12 +87,12 @@ declare_lint_pass!( impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { - use rustc_middle::ty::Clause; + use rustc_middle::ty::ClauseKind; use rustc_middle::ty::PredicateKind::*; let predicates = cx.tcx.explicit_predicates_of(item.owner_id); for &(predicate, span) in predicates.predicates { - let Clause(Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() else { + let Clause(ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder() else { continue }; let def_id = trait_predicate.trait_ref.def_id; diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 9861610612fb0..e0033c48edbf1 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -289,7 +289,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { .filter_only_self() .find_map(|(pred, _span)| { // We only look at the `DefId`, so it is safe to skip the binder here. - if let ty::PredicateKind::Clause(ty::Clause::Trait( + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait( ref poly_trait_predicate, )) = pred.kind().skip_binder() { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 66048f3ece747..b0fe6eec3c48c 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -376,7 +376,7 @@ define_tables! { attr_flags: Table, def_path_hashes: Table, explicit_item_bounds: Table, Span)>>, - inferred_outlives_of: Table, Span)>>, + inferred_outlives_of: Table, Span)>>, inherent_impls: Table>, associated_types_for_impl_traits_in_associated_fn: Table>, opt_rpitit_info: Table>>, diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index fd02a16130fc5..4ea124e7f373d 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -317,7 +317,7 @@ tcx_lifetime! { rustc_middle::traits::query::type_op::Subtype, rustc_middle::ty::AdtDef, rustc_middle::ty::AliasTy, - rustc_middle::ty::Clause, + rustc_middle::ty::ClauseKind, rustc_middle::ty::ClosureTypeInfo, rustc_middle::ty::Const, rustc_middle::ty::DestructuredConst, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 132b11b29eb32..bdc0dc3b2d3c7 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -634,7 +634,7 @@ rustc_queries! { /// Returns the inferred outlives predicates (e.g., for `struct /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`). - query inferred_outlives_of(key: DefId) -> &'tcx [(ty::Clause<'tcx>, Span)] { + query inferred_outlives_of(key: DefId) -> &'tcx [(ty::ClauseKind<'tcx>, Span)] { desc { |tcx| "computing inferred outlives predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 220118ae5ccb8..105667ba1e6c0 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -798,7 +798,7 @@ impl<'a, 'tcx> Decodable> for &'tcx [(ty::Predicate<'tcx> } } -impl<'a, 'tcx> Decodable> for &'tcx [(ty::Clause<'tcx>, Span)] { +impl<'a, 'tcx> Decodable> for &'tcx [(ty::ClauseKind<'tcx>, Span)] { #[inline] fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { RefDecodable::decode(d) diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 76f52bc34ed14..ff8cd904ef86b 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -365,7 +365,9 @@ impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> } } -impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for [(ty::Clause<'tcx>, Span)] { +impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> + for [(ty::ClauseKind<'tcx>, Span)] +{ fn decode(decoder: &mut D) -> &'tcx Self { decoder.interner().arena.alloc_from_iter( (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::>(), diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 449129b84188b..2b4f69167bfb0 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1564,7 +1564,7 @@ impl<'tcx> TyCtxt<'tcx> { let future_trait = self.require_lang_item(LangItem::Future, None); self.explicit_item_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| { - let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() else { + let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder() else { return false; }; trait_predicate.trait_ref.def_id == future_trait @@ -1587,7 +1587,7 @@ impl<'tcx> TyCtxt<'tcx> { let generic_predicates = self.super_predicates_of(trait_did); for (predicate, _) in generic_predicates.predicates { - if let ty::PredicateKind::Clause(ty::Clause::Trait(data)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) = predicate.kind().skip_binder() { if set.insert(data.def_id()) { diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 684af1abdf6f6..cc982045c46b8 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -237,21 +237,24 @@ impl FlagComputation { fn add_predicate_atom(&mut self, atom: ty::PredicateKind<'_>) { match atom { - ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => { self.add_substs(trait_pred.trait_ref.substs); } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate(a, b))) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( + a, + b, + ))) => { self.add_region(a); self.add_region(b); } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( ty, region, ))) => { self.add_ty(ty); self.add_region(region); } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { self.add_const(ct); self.add_ty(ty); } @@ -263,21 +266,21 @@ impl FlagComputation { self.add_ty(a); self.add_ty(b); } - ty::PredicateKind::Clause(ty::Clause::Projection(ty::ProjectionPredicate { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term, })) => { self.add_alias_ty(projection_ty); self.add_term(term); } - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { self.add_substs(slice::from_ref(&arg)); } ty::PredicateKind::ObjectSafe(_def_id) => {} ty::PredicateKind::ClosureKind(_def_id, substs, _kind) => { self.add_substs(substs); } - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(uv)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { self.add_const(uv); } ty::PredicateKind::ConstEquate(expected, found) => { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 66aba98fe2965..f43be1468e894 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -487,11 +487,11 @@ impl<'tcx> Predicate<'tcx> { let kind = self .kind() .map_bound(|kind| match kind { - PredicateKind::Clause(Clause::Trait(TraitPredicate { + PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { trait_ref, constness, polarity, - })) => Some(PredicateKind::Clause(Clause::Trait(TraitPredicate { + })) => Some(PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { trait_ref, constness, polarity: polarity.flip()?, @@ -505,10 +505,10 @@ impl<'tcx> Predicate<'tcx> { } pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> Self { - if let PredicateKind::Clause(Clause::Trait(TraitPredicate { trait_ref, constness, polarity })) = self.kind().skip_binder() + if let PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { trait_ref, constness, polarity })) = self.kind().skip_binder() && constness != BoundConstness::NotConst { - self = tcx.mk_predicate(self.kind().rebind(PredicateKind::Clause(Clause::Trait(TraitPredicate { + self = tcx.mk_predicate(self.kind().rebind(PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { trait_ref, constness: BoundConstness::NotConst, polarity, @@ -520,10 +520,10 @@ impl<'tcx> Predicate<'tcx> { #[instrument(level = "debug", skip(tcx), ret)] pub fn is_coinductive(self, tcx: TyCtxt<'tcx>) -> bool { match self.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { tcx.trait_is_coinductive(data.def_id()) } - ty::PredicateKind::Clause(ty::Clause::WellFormed(_)) => true, + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => true, _ => false, } } @@ -536,18 +536,18 @@ impl<'tcx> Predicate<'tcx> { #[inline] pub fn allow_normalization(self) -> bool { match self.kind().skip_binder() { - PredicateKind::Clause(Clause::WellFormed(_)) => false, - PredicateKind::Clause(Clause::Trait(_)) - | PredicateKind::Clause(Clause::RegionOutlives(_)) - | PredicateKind::Clause(Clause::TypeOutlives(_)) - | PredicateKind::Clause(Clause::Projection(_)) - | PredicateKind::Clause(Clause::ConstArgHasType(..)) + PredicateKind::Clause(ClauseKind::WellFormed(_)) => false, + PredicateKind::Clause(ClauseKind::Trait(_)) + | PredicateKind::Clause(ClauseKind::RegionOutlives(_)) + | PredicateKind::Clause(ClauseKind::TypeOutlives(_)) + | PredicateKind::Clause(ClauseKind::Projection(_)) + | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) | PredicateKind::AliasRelate(..) | PredicateKind::ObjectSafe(_) | PredicateKind::ClosureKind(_, _, _) | PredicateKind::Subtype(_) | PredicateKind::Coerce(_) - | PredicateKind::Clause(Clause::ConstEvaluatable(_)) + | PredicateKind::Clause(ClauseKind::ConstEvaluatable(_)) | PredicateKind::ConstEquate(_, _) | PredicateKind::Ambiguous | PredicateKind::TypeWellFormedFromEnv(_) => true, @@ -565,7 +565,7 @@ impl rustc_errors::IntoDiagnosticArg for Predicate<'_> { #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] /// A clause is something that can appear in where bounds or be inferred /// by implied bounds. -pub enum Clause<'tcx> { +pub enum ClauseKind<'tcx> { /// Corresponds to `where Foo: Bar`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` /// would be the type parameters. @@ -592,9 +592,9 @@ pub enum Clause<'tcx> { ConstEvaluatable(ty::Const<'tcx>), } -impl<'tcx> Binder<'tcx, Clause<'tcx>> { +impl<'tcx> Binder<'tcx, ClauseKind<'tcx>> { pub fn as_trait_clause(self) -> Option>> { - if let ty::Clause::Trait(trait_clause) = self.skip_binder() { + if let ty::ClauseKind::Trait(trait_clause) = self.skip_binder() { Some(self.rebind(trait_clause)) } else { None @@ -602,7 +602,7 @@ impl<'tcx> Binder<'tcx, Clause<'tcx>> { } pub fn as_projection_clause(self) -> Option>> { - if let ty::Clause::Projection(projection_clause) = self.skip_binder() { + if let ty::ClauseKind::Projection(projection_clause) = self.skip_binder() { Some(self.rebind(projection_clause)) } else { None @@ -614,7 +614,7 @@ impl<'tcx> Binder<'tcx, Clause<'tcx>> { #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub enum PredicateKind<'tcx> { /// Prove a clause - Clause(Clause<'tcx>), + Clause(ClauseKind<'tcx>), /// Trait must be object-safe. ObjectSafe(DefId), @@ -653,7 +653,7 @@ pub enum PredicateKind<'tcx> { /// Used for coherence to mark opaque types as possibly equal to each other but ambiguous. Ambiguous, - /// Separate from `Clause::Projection` which is used for normalization in new solver. + /// Separate from `ClauseKind::Projection` which is used for normalization in new solver. /// This predicate requires two terms to be equal to eachother. /// /// Only used for new solver @@ -687,7 +687,8 @@ pub struct CratePredicatesMap<'tcx> { /// For each struct with outlive bounds, maps to a vector of the /// predicate of its outlive bounds. If an item has no outlives /// bounds, it will have no entry. - pub predicates: FxHashMap, Span)]>, + // FIXME(clause): should this be a `Clause`? + pub predicates: FxHashMap, Span)]>, } impl<'tcx> Predicate<'tcx> { @@ -1207,14 +1208,14 @@ impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { } } -impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> { +impl<'tcx> ToPredicate<'tcx> for ClauseKind<'tcx> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::Clause(self))) } } -impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, Clause<'tcx>> { +impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, ClauseKind<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { tcx.mk_predicate(self.map_bound(|clause| ty::PredicateKind::Clause(clause))) @@ -1228,10 +1229,10 @@ impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { } } -impl<'tcx> ToPredicate<'tcx, Binder<'tcx, Clause<'tcx>>> for TraitRef<'tcx> { +impl<'tcx> ToPredicate<'tcx, Binder<'tcx, ClauseKind<'tcx>>> for TraitRef<'tcx> { #[inline(always)] - fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Binder<'tcx, Clause<'tcx>> { - Binder::dummy(Clause::Trait(TraitPredicate { + fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Binder<'tcx, ClauseKind<'tcx>> { + Binder::dummy(ClauseKind::Trait(TraitPredicate { trait_ref: self, constness: ty::BoundConstness::NotConst, polarity: ty::ImplPolarity::Positive, @@ -1247,9 +1248,9 @@ impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> { } } -impl<'tcx> ToPredicate<'tcx, Binder<'tcx, Clause<'tcx>>> for Binder<'tcx, TraitRef<'tcx>> { +impl<'tcx> ToPredicate<'tcx, Binder<'tcx, ClauseKind<'tcx>>> for Binder<'tcx, TraitRef<'tcx>> { #[inline(always)] - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Binder<'tcx, Clause<'tcx>> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Binder<'tcx, ClauseKind<'tcx>> { let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx); pred.to_predicate(tcx) } @@ -1280,43 +1281,43 @@ impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for TraitPredicate<'tcx> impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(|p| PredicateKind::Clause(Clause::Trait(p))).to_predicate(tcx) + self.map_bound(|p| PredicateKind::Clause(ClauseKind::Trait(p))).to_predicate(tcx) } } -impl<'tcx> ToPredicate<'tcx, Binder<'tcx, Clause<'tcx>>> for PolyTraitPredicate<'tcx> { - fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Binder<'tcx, Clause<'tcx>> { - self.map_bound(|p| Clause::Trait(p)) +impl<'tcx> ToPredicate<'tcx, Binder<'tcx, ClauseKind<'tcx>>> for PolyTraitPredicate<'tcx> { + fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Binder<'tcx, ClauseKind<'tcx>> { + self.map_bound(|p| ClauseKind::Trait(p)) } } impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(|p| PredicateKind::Clause(Clause::RegionOutlives(p))).to_predicate(tcx) + self.map_bound(|p| PredicateKind::Clause(ClauseKind::RegionOutlives(p))).to_predicate(tcx) } } impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(|p| PredicateKind::Clause(Clause::TypeOutlives(p))).to_predicate(tcx) + self.map_bound(|p| PredicateKind::Clause(ClauseKind::TypeOutlives(p))).to_predicate(tcx) } } impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(|p| PredicateKind::Clause(Clause::Projection(p))).to_predicate(tcx) + self.map_bound(|p| PredicateKind::Clause(ClauseKind::Projection(p))).to_predicate(tcx) } } -impl<'tcx> ToPredicate<'tcx, Binder<'tcx, Clause<'tcx>>> for PolyProjectionPredicate<'tcx> { - fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Binder<'tcx, Clause<'tcx>> { - self.map_bound(|p| Clause::Projection(p)) +impl<'tcx> ToPredicate<'tcx, Binder<'tcx, ClauseKind<'tcx>>> for PolyProjectionPredicate<'tcx> { + fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Binder<'tcx, ClauseKind<'tcx>> { + self.map_bound(|p| ClauseKind::Projection(p)) } } impl<'tcx> ToPredicate<'tcx> for TraitPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateKind::Clause(Clause::Trait(self)).to_predicate(tcx) + PredicateKind::Clause(ClauseKind::Trait(self)).to_predicate(tcx) } } @@ -1324,18 +1325,18 @@ impl<'tcx> Predicate<'tcx> { pub fn to_opt_poly_trait_pred(self) -> Option> { let predicate = self.kind(); match predicate.skip_binder() { - PredicateKind::Clause(Clause::Trait(t)) => Some(predicate.rebind(t)), - PredicateKind::Clause(Clause::Projection(..)) - | PredicateKind::Clause(Clause::ConstArgHasType(..)) + PredicateKind::Clause(ClauseKind::Trait(t)) => Some(predicate.rebind(t)), + PredicateKind::Clause(ClauseKind::Projection(..)) + | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) - | PredicateKind::Clause(Clause::RegionOutlives(..)) - | PredicateKind::Clause(Clause::WellFormed(..)) + | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) + | PredicateKind::Clause(ClauseKind::WellFormed(..)) | PredicateKind::ObjectSafe(..) | PredicateKind::ClosureKind(..) - | PredicateKind::Clause(Clause::TypeOutlives(..)) - | PredicateKind::Clause(Clause::ConstEvaluatable(..)) + | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) + | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) | PredicateKind::ConstEquate(..) | PredicateKind::Ambiguous | PredicateKind::TypeWellFormedFromEnv(..) => None, @@ -1345,18 +1346,18 @@ impl<'tcx> Predicate<'tcx> { pub fn to_opt_poly_projection_pred(self) -> Option> { let predicate = self.kind(); match predicate.skip_binder() { - PredicateKind::Clause(Clause::Projection(t)) => Some(predicate.rebind(t)), - PredicateKind::Clause(Clause::Trait(..)) - | PredicateKind::Clause(Clause::ConstArgHasType(..)) + PredicateKind::Clause(ClauseKind::Projection(t)) => Some(predicate.rebind(t)), + PredicateKind::Clause(ClauseKind::Trait(..)) + | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) - | PredicateKind::Clause(Clause::RegionOutlives(..)) - | PredicateKind::Clause(Clause::WellFormed(..)) + | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) + | PredicateKind::Clause(ClauseKind::WellFormed(..)) | PredicateKind::ObjectSafe(..) | PredicateKind::ClosureKind(..) - | PredicateKind::Clause(Clause::TypeOutlives(..)) - | PredicateKind::Clause(Clause::ConstEvaluatable(..)) + | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) + | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) | PredicateKind::ConstEquate(..) | PredicateKind::Ambiguous | PredicateKind::TypeWellFormedFromEnv(..) => None, @@ -1366,25 +1367,25 @@ impl<'tcx> Predicate<'tcx> { pub fn to_opt_type_outlives(self) -> Option> { let predicate = self.kind(); match predicate.skip_binder() { - PredicateKind::Clause(Clause::TypeOutlives(data)) => Some(predicate.rebind(data)), - PredicateKind::Clause(Clause::Trait(..)) - | PredicateKind::Clause(Clause::ConstArgHasType(..)) - | PredicateKind::Clause(Clause::Projection(..)) + PredicateKind::Clause(ClauseKind::TypeOutlives(data)) => Some(predicate.rebind(data)), + PredicateKind::Clause(ClauseKind::Trait(..)) + | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) + | PredicateKind::Clause(ClauseKind::Projection(..)) | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) - | PredicateKind::Clause(Clause::RegionOutlives(..)) - | PredicateKind::Clause(Clause::WellFormed(..)) + | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) + | PredicateKind::Clause(ClauseKind::WellFormed(..)) | PredicateKind::ObjectSafe(..) | PredicateKind::ClosureKind(..) - | PredicateKind::Clause(Clause::ConstEvaluatable(..)) + | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) | PredicateKind::ConstEquate(..) | PredicateKind::Ambiguous | PredicateKind::TypeWellFormedFromEnv(..) => None, } } - pub fn as_clause(self) -> Option>> { + pub fn as_clause(self) -> Option>> { let predicate = self.kind(); match predicate.skip_binder() { PredicateKind::Clause(clause) => Some(predicate.rebind(clause)), diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 13be15269f4c2..97d13822adccf 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -128,6 +128,6 @@ parameterized_over_tcx! { ty::TraitRef, ty::Const, ty::Predicate, - ty::Clause, + ty::ClauseKind, ty::GeneratorDiagnosticData, } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 4bfed74f7054d..fdcc608bf8ed7 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -928,7 +928,7 @@ pub trait PrettyPrinter<'tcx>: let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { let trait_ref = bound_predicate.rebind(pred.trait_ref); // Don't print + Sized, but rather + ?Sized if absent. @@ -939,7 +939,7 @@ pub trait PrettyPrinter<'tcx>: self.insert_trait_and_projection(trait_ref, None, &mut traits, &mut fn_traits); } - ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { let proj_ref = bound_predicate.rebind(pred); let trait_ref = proj_ref.required_poly_trait_ref(tcx); @@ -953,7 +953,7 @@ pub trait PrettyPrinter<'tcx>: &mut fn_traits, ); } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(outlives)) => { + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => { lifetimes.push(outlives.1); } _ => {} @@ -2866,18 +2866,18 @@ define_print_and_forward_display! { ty::PredicateKind<'tcx> { match *self { - ty::PredicateKind::Clause(ty::Clause::Trait(ref data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(ref data)) => { p!(print(data)) } ty::PredicateKind::Subtype(predicate) => p!(print(predicate)), ty::PredicateKind::Coerce(predicate) => p!(print(predicate)), - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => p!(print(predicate)), - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => p!(print(predicate)), - ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => p!(print(predicate)), - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => p!(print(predicate)), + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => p!(print(predicate)), + ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => p!(print(predicate)), + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { p!("the constant `", print(ct), "` has type `", print(ty), "`") }, - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => p!(print(arg), " well-formed"), + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => p!(print(arg), " well-formed"), ty::PredicateKind::ObjectSafe(trait_def_id) => { p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe") } @@ -2886,7 +2886,7 @@ define_print_and_forward_display! { print_value_path(closure_def_id, &[]), write("` implements the trait `{}`", kind) ), - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(ct)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => { p!("the constant `", print(ct), "` can be evaluated") } ty::PredicateKind::ConstEquate(c1, c2) => { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index a4a2fec07ec3a..ebc4a3d22ad70 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -171,16 +171,16 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { } } -impl<'tcx> fmt::Debug for ty::Clause<'tcx> { +impl<'tcx> fmt::Debug for ty::ClauseKind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - ty::Clause::ConstArgHasType(ct, ty) => write!(f, "ConstArgHasType({ct:?}, {ty:?})"), - ty::Clause::Trait(ref a) => a.fmt(f), - ty::Clause::RegionOutlives(ref pair) => pair.fmt(f), - ty::Clause::TypeOutlives(ref pair) => pair.fmt(f), - ty::Clause::Projection(ref pair) => pair.fmt(f), - ty::Clause::WellFormed(ref data) => write!(f, "WellFormed({:?})", data), - ty::Clause::ConstEvaluatable(ct) => { + ty::ClauseKind::ConstArgHasType(ct, ty) => write!(f, "ConstArgHasType({ct:?}, {ty:?})"), + ty::ClauseKind::Trait(ref a) => a.fmt(f), + ty::ClauseKind::RegionOutlives(ref pair) => pair.fmt(f), + ty::ClauseKind::TypeOutlives(ref pair) => pair.fmt(f), + ty::ClauseKind::Projection(ref pair) => pair.fmt(f), + ty::ClauseKind::WellFormed(ref data) => write!(f, "WellFormed({:?})", data), + ty::ClauseKind::ConstEvaluatable(ct) => { write!(f, "ConstEvaluatable({ct:?})") } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index c9f69c37782e3..ca8b6e7737a6c 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -972,7 +972,7 @@ impl<'tcx> TypeFolder> for OpaqueTypeExpander<'tcx> { fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { if let ty::PredicateKind::Clause(clause) = p.kind().skip_binder() - && let ty::Clause::Projection(projection_pred) = clause + && let ty::ClauseKind::Projection(projection_pred) = clause { p.kind() .rebind(ty::ProjectionPredicate { diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index b1c9c4acc40e4..e37314209fee7 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -105,7 +105,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { /// If the given predicate is the trait `fmt::Pointer`, returns the bound parameter type. fn is_pointer_trait(&self, bound: &PredicateKind<'tcx>) -> Option> { - if let ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) = bound { + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) = bound { self.tcx .is_diagnostic_item(sym::Pointer, predicate.def_id()) .then(|| predicate.trait_ref.self_ty()) diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index fe3f8ed047a70..cda0f1ea8856c 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1808,7 +1808,7 @@ fn check_must_not_suspend_ty<'tcx>( let mut has_emitted = false; for &(predicate, _) in tcx.explicit_item_bounds(def).skip_binder() { // We only look at the `DefId`, so it is safe to skip the binder here. - if let ty::PredicateKind::Clause(ty::Clause::Trait(ref poly_trait_predicate)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ref poly_trait_predicate)) = predicate.kind().skip_binder() { let def_id = poly_trait_predicate.trait_ref.def_id; diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 620aef9883bd9..dc66c31c191a5 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -161,29 +161,31 @@ where fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity: _, })) => self.visit_trait(trait_ref), - ty::PredicateKind::Clause(ty::Clause::Projection(ty::ProjectionPredicate { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term, })) => { term.visit_with(self)?; self.visit_projection_ty(projection_ty) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( ty, _region, ))) => ty.visit_with(self), - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) => ControlFlow::Continue(()), - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) => { + ControlFlow::Continue(()) + } + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { ct.visit_with(self)?; ty.visit_with(self) } - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(ct)) => ct.visit_with(self), - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => arg.visit_with(self), + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => ct.visit_with(self), + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => arg.visit_with(self), ty::PredicateKind::ObjectSafe(_) | ty::PredicateKind::ClosureKind(_, _, _) @@ -1271,12 +1273,12 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { for (pred, _) in bounds.predicates() { match pred.skip_binder() { - ty::Clause::Trait(trait_predicate) => { + ty::ClauseKind::Trait(trait_predicate) => { if self.visit_trait(trait_predicate.trait_ref).is_break() { return; } } - ty::Clause::Projection(proj_predicate) => { + ty::ClauseKind::Projection(proj_predicate) => { let term = self.visit(proj_predicate.term); if term.is_break() || self.visit_projection_ty(proj_predicate.projection_ty).is_break() diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index d9bc8d3b1eb43..7be21d9e61924 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -106,7 +106,7 @@ pub(super) trait GoalKind<'tcx>: fn probe_and_match_goal_against_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Binder<'tcx, ty::Clause<'tcx>>, + assumption: ty::Binder<'tcx, ty::ClauseKind<'tcx>>, then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>, ) -> QueryResult<'tcx>; @@ -116,7 +116,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_implied_clause( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Binder<'tcx, ty::Clause<'tcx>>, + assumption: ty::Binder<'tcx, ty::ClauseKind<'tcx>>, requirements: impl IntoIterator>>, ) -> QueryResult<'tcx> { Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| { @@ -132,7 +132,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_alias_bound_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Binder<'tcx, ty::Clause<'tcx>>, + assumption: ty::Binder<'tcx, ty::ClauseKind<'tcx>>, ) -> QueryResult<'tcx> { Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| { ecx.validate_alias_bound_self_from_param_env(goal) @@ -145,7 +145,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_object_bound_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Binder<'tcx, ty::Clause<'tcx>>, + assumption: ty::Binder<'tcx, ty::ClauseKind<'tcx>>, ) -> QueryResult<'tcx> { Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| { let tcx = ecx.tcx(); diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 4258f9f6bd28e..501a55f63fc96 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -352,19 +352,19 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let kind = predicate.kind(); if let Some(kind) = kind.no_bound_vars() { match kind { - ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { self.compute_trait_goal(Goal { param_env, predicate }) } - ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => { self.compute_projection_goal(Goal { param_env, predicate }) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => { self.compute_type_outlives_goal(Goal { param_env, predicate }) } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => { self.compute_region_outlives_goal(Goal { param_env, predicate }) } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) }) } ty::PredicateKind::Subtype(predicate) => { @@ -381,14 +381,14 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { ty::PredicateKind::ObjectSafe(trait_def_id) => { self.compute_object_safe_goal(trait_def_id) } - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { self.compute_well_formed_goal(Goal { param_env, predicate: arg }) } ty::PredicateKind::Ambiguous => { self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } // FIXME: implement this predicate :) - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(_)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(_)) => { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } ty::PredicateKind::ConstEquate(_, _) => { diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 0e671144a29ec..f8f1239d5b40b 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -93,7 +93,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { errors.push(FulfillmentError { obligation: obligation.clone(), code: match goal.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(_)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => { FulfillmentErrorCode::CodeProjectionError( // FIXME: This could be a `Sorts` if the term is a type MismatchedProjectionTypes { err: TypeError::Mismatch }, diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index b99c3927862fc..e0e27bf851b39 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -107,7 +107,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { fn probe_and_match_goal_against_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Binder<'tcx, ty::Clause<'tcx>>, + assumption: ty::Binder<'tcx, ty::ClauseKind<'tcx>>, then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>, ) -> QueryResult<'tcx> { if let Some(projection_pred) = assumption.as_projection_clause() { diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index d9f24455a81f8..2a576ffe22051 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -85,7 +85,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn probe_and_match_goal_against_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Binder<'tcx, ty::Clause<'tcx>>, + assumption: ty::Binder<'tcx, ty::ClauseKind<'tcx>>, then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>, ) -> QueryResult<'tcx> { if let Some(trait_clause) = assumption.as_trait_clause() { diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 56fde8cd70cb3..71557e8930df0 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -400,8 +400,8 @@ impl<'tcx> AutoTraitFinder<'tcx> { let mut should_add_new = true; user_computed_preds.retain(|&old_pred| { if let ( - ty::PredicateKind::Clause(ty::Clause::Trait(new_trait)), - ty::PredicateKind::Clause(ty::Clause::Trait(old_trait)), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(new_trait)), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(old_trait)), ) = (new_pred.kind().skip_binder(), old_pred.kind().skip_binder()) { if new_trait.def_id() == old_trait.def_id() { @@ -621,14 +621,14 @@ impl<'tcx> AutoTraitFinder<'tcx> { let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(p)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(p)) => { // Add this to `predicates` so that we end up calling `select` // with it. If this predicate ends up being unimplemented, // then `evaluate_predicates` will handle adding it the `ParamEnv` // if possible. predicates.push_back(bound_predicate.rebind(p)); } - ty::PredicateKind::Clause(ty::Clause::Projection(p)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => { let p = bound_predicate.rebind(p); debug!( "evaluate_nested_obligations: examining projection predicate {:?}", @@ -758,11 +758,11 @@ impl<'tcx> AutoTraitFinder<'tcx> { } } } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(binder)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(binder)) => { let binder = bound_predicate.rebind(binder); selcx.infcx.region_outlives_predicate(&dummy_cause, binder) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(binder)) => { + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(binder)) => { let binder = bound_predicate.rebind(binder); match ( binder.no_bound_vars(), @@ -826,14 +826,14 @@ impl<'tcx> AutoTraitFinder<'tcx> { // we start out with a `ParamEnv` with no inference variables, // and these don't correspond to adding any new bounds to // the `ParamEnv`. - ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) // FIXME(generic_const_exprs): you can absolutely add this as a where clauses - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::Coerce(..) => {} ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("predicate should only exist in the environment: {bound_predicate:?}") diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index f8789b554b1ad..f9f242d29f65c 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -207,7 +207,7 @@ fn satisfied_from_param_env<'tcx>( for pred in param_env.caller_bounds() { match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(ce)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ce)) => { let b_ct = tcx.expand_abstract_consts(ce); let mut v = Visitor { ct, infcx, param_env, single_match }; let _ = b_ct.visit_with(&mut v); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs index 7ab652761a410..1351d9bb257ea 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs @@ -84,7 +84,7 @@ pub fn recompute_applicable_impls<'tcx>( tcx.predicates_of(obligation.cause.body_id.to_def_id()).instantiate_identity(tcx); for (pred, span) in elaborate(tcx, predicates.into_iter()) { let kind = pred.kind(); - if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder() + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = kind.skip_binder() && param_env_candidate_may_apply(kind.rebind(trait_pred)) { if kind.rebind(trait_pred.trait_ref) == ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_pred.def_id())) { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 398ec28a42638..75a92af714bd5 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -678,7 +678,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let bound_predicate = obligation.predicate.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => { let trait_predicate = bound_predicate.rebind(trait_predicate); let mut trait_predicate = self.resolve_vars_if_possible(trait_predicate); @@ -1021,8 +1021,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span_bug!(span, "coerce requirement gave wrong error: `{:?}`", predicate) } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) => { span_bug!( span, "outlives clauses should not error outside borrowck. obligation: `{:?}`", @@ -1030,7 +1030,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) } - ty::PredicateKind::Clause(ty::Clause::Projection(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) => { span_bug!( span, "projection clauses should be implied from elsewhere. obligation: `{:?}`", @@ -1048,7 +1048,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.report_closure_error(&obligation, closure_def_id, found_kind, kind) } - ty::PredicateKind::Clause(ty::Clause::WellFormed(ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => { match self.tcx.sess.opts.unstable_opts.trait_solver { TraitSolver::Classic => { // WF predicates cannot themselves make @@ -1069,7 +1069,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) => { // Errors for `ConstEvaluatable` predicates show up as // `SelectionError::ConstEvalFailure`, // not `Unimplemented`. @@ -1103,7 +1103,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { "AliasRelate predicate should never be the predicate cause of a SelectionError" ), - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { let mut diag = self.tcx.sess.struct_span_err( span, format!("the constant `{}` is not of type `{}`", ct, ty), @@ -1494,8 +1494,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let bound_error = error.kind(); let (cond, error) = match (cond.kind().skip_binder(), bound_error.skip_binder()) { ( - ty::PredicateKind::Clause(ty::Clause::Trait(..)), - ty::PredicateKind::Clause(ty::Clause::Trait(error)), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(error)), ) => (cond, bound_error.rebind(error)), _ => { // FIXME: make this work in other cases too. @@ -1505,7 +1505,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { for pred in super::elaborate(self.tcx, std::iter::once(cond)) { let bound_predicate = pred.kind(); - if let ty::PredicateKind::Clause(ty::Clause::Trait(implication)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(implication)) = bound_predicate.skip_binder() { let error = error.to_poly_trait_ref(); @@ -1603,7 +1603,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // this can fail if the problem was higher-ranked, in which // cause I have no idea for a good error message. let bound_predicate = predicate.kind(); - let (values, err) = if let ty::PredicateKind::Clause(ty::Clause::Projection(data)) = + let (values, err) = if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) = bound_predicate.skip_binder() { let data = self.instantiate_binder_with_fresh_vars( @@ -1686,7 +1686,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}"); let secondary_span = (|| { - let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = + let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = predicate.kind().skip_binder() else { return None; @@ -2199,7 +2199,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let bound_predicate = predicate.kind(); let mut err = match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { let trait_ref = bound_predicate.rebind(data.trait_ref); debug!(?trait_ref); @@ -2415,7 +2415,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err } - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { // Same hacky approach as above to avoid deluging user // with error messages. if arg.references_error() @@ -2453,7 +2453,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { true, ) } - ty::PredicateKind::Clause(ty::Clause::Projection(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { if predicate.references_error() || self.tainted_by_errors().is_some() { return; } @@ -2487,7 +2487,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => { if predicate.references_error() || self.tainted_by_errors().is_some() { return; } @@ -2701,7 +2701,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>, ) { - let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = obligation.predicate.kind().skip_binder() else { return; }; + let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = obligation.predicate.kind().skip_binder() else { return; }; let (ObligationCauseCode::BindingObligation(item_def_id, span) | ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..)) = *obligation.cause.code().peel_derives() else { return; }; @@ -3325,7 +3325,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(ct)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => { let ty::ConstKind::Unevaluated(uv) = ct.kind() else { bug!("const evaluatable failed for non-unevaluated const `{ct:?}`"); }; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index fcf813e3a393a..966c4a7dcf38f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -920,7 +920,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { return false; } - if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = obligation.predicate.kind().skip_binder() + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = obligation.predicate.kind().skip_binder() && Some(trait_pred.def_id()) == self.tcx.lang_items().sized_trait() { // Don't suggest calling to turn an unsized type into a sized type @@ -1157,7 +1157,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { self.tcx.item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| { - if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder() + if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = pred.kind().skip_binder() && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() // args tuple will always be substs[1] && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind() @@ -1201,7 +1201,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { DefIdOrName::Name("type parameter") }; param_env.caller_bounds().iter().find_map(|pred| { - if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder() + if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = pred.kind().skip_binder() && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() && proj.projection_ty.self_ty() == found // args tuple will always be substs[1] @@ -1639,7 +1639,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } // FIXME: account for associated `async fn`s. if let hir::Expr { span, kind: hir::ExprKind::Call(base, _), .. } = expr { - if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = obligation.predicate.kind().skip_binder() { err.span_label(*span, format!("this call returns `{}`", pred.self_ty())); @@ -2001,7 +2001,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = cause && let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx) && let Some(pred) = predicates.predicates.get(*idx) - && let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = pred.kind().skip_binder() + && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = pred.kind().skip_binder() && self.tcx.is_fn_trait(trait_pred.def_id()) { let expected_self = @@ -2015,7 +2015,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let other_pred = predicates.into_iter() .enumerate() .find(|(other_idx, (pred, _))| match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) if self.tcx.is_fn_trait(trait_pred.def_id()) && other_idx != idx // Make sure that the self type matches @@ -2141,7 +2141,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // bound was introduced. At least one generator should be present for this diagnostic to be // modified. let (mut trait_ref, mut target_ty) = match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(p)) => (Some(p), Some(p.self_ty())), + ty::PredicateKind::Clause(ty::ClauseKind::Trait(p)) => (Some(p), Some(p.self_ty())), _ => (None, None), }; let mut generator = None; @@ -2816,7 +2816,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ObligationCauseCode::SizedArgumentType(ty_span) => { if let Some(span) = ty_span { if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() - && let ty::Clause::Trait(trait_pred) = clause + && let ty::ClauseKind::Trait(trait_pred) = clause && let ty::Dynamic(..) = trait_pred.self_ty().kind() { let span = if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) @@ -3597,7 +3597,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Given the predicate `fn(&T): FnOnce<(U,)>`, extract `fn(&T)` and `(U,)`, // then suggest `Option::as_deref(_mut)` if `U` can deref to `T` - if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { trait_ref, .. })) + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, .. })) = failed_pred.kind().skip_binder() && tcx.is_fn_trait(trait_ref.def_id) && let [self_ty, found_ty] = trait_ref.substs.as_slice() @@ -3826,12 +3826,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // in. For example, this would be what `Iterator::Item` is here. let ty_var = self.infcx.next_ty_var(origin); // This corresponds to `::Item = _`. - let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Projection( - ty::ProjectionPredicate { + let projection = ty::Binder::dummy(ty::PredicateKind::Clause( + ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty: self.tcx.mk_alias_ty(proj.def_id, substs), term: ty_var.into(), - }, - ))); + }), + )); let body_def_id = self.tcx.hir().enclosing_body_owner(body_id); // Add `::Item = _` obligation. ocx.register_obligation(Obligation::misc( diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 6e4bda3df03e7..7c5260fc67bf1 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -333,7 +333,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { // Evaluation will discard candidates using the leak check. // This means we need to pass it the bound version of our // predicate. - ty::PredicateKind::Clause(ty::Clause::Trait(trait_ref)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) => { let trait_obligation = obligation.with(infcx.tcx, binder.rebind(trait_ref)); self.process_trait_obligation( @@ -342,7 +342,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { &mut pending_obligation.stalled_on, ) } - ty::PredicateKind::Clause(ty::Clause::Projection(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { let project_obligation = obligation.with(infcx.tcx, binder.rebind(data)); self.process_projection_obligation( @@ -351,15 +351,15 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { &mut pending_obligation.stalled_on, ) } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(_)) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(_)) + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) | ty::PredicateKind::ObjectSafe(_) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) => { let pred = ty::Binder::dummy(infcx.instantiate_binder_with_placeholders(binder)); @@ -374,7 +374,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } }, Some(pred) => match pred { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { let trait_obligation = obligation.with(infcx.tcx, Binder::dummy(data)); self.process_trait_obligation( @@ -384,7 +384,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ) } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => { if infcx.considering_regions { infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)); } @@ -392,7 +392,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ProcessResult::Changed(vec![]) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( t_a, r_b, ))) => { @@ -402,7 +402,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ProcessResult::Changed(vec![]) } - ty::PredicateKind::Clause(ty::Clause::Projection(ref data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(ref data)) => { let project_obligation = obligation.with(infcx.tcx, Binder::dummy(*data)); self.process_projection_obligation( @@ -433,7 +433,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { match wf::obligations( self.selcx.infcx, obligation.param_env, @@ -498,7 +498,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(uv)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { match const_evaluatable::is_const_evaluatable( self.selcx.infcx, uv, @@ -640,7 +640,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::AliasRelate(..) => { bug!("AliasRelate is only used for new solver") } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq( DefineOpaqueTypes::No, ct.ty(), diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index db9cb82585f69..15081d6568299 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -357,7 +357,7 @@ pub fn normalize_param_env_or_error<'tcx>( .extract_if(|predicate| { matches!( predicate.kind().skip_binder(), - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) ) }) .collect(); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 8c42df6e012d3..499745473a22c 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -282,11 +282,11 @@ fn predicate_references_self<'tcx>( let self_ty = tcx.types.self_param; let has_self_ty = |arg: &GenericArg<'tcx>| arg.walk().any(|arg| arg == self_ty.into()); match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(ref data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(ref data)) => { // In the case of a trait predicate, we can skip the "self" type. data.trait_ref.substs[1..].iter().any(has_self_ty).then_some(sp) } - ty::PredicateKind::Clause(ty::Clause::Projection(ref data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(ref data)) => { // And similarly for projections. This should be redundant with // the previous check because any projection should have a // matching `Trait` predicate with the same inputs, but we do @@ -304,21 +304,21 @@ fn predicate_references_self<'tcx>( // possible alternatives. data.projection_ty.substs[1..].iter().any(has_self_ty).then_some(sp) } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(_ct, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(_ct, ty)) => { has_self_ty(&ty.into()).then_some(sp) } ty::PredicateKind::AliasRelate(..) => bug!("`AliasRelate` not allowed as assumption"), - ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) | ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) // FIXME(generic_const_exprs): this can mention `Self` - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, @@ -353,19 +353,19 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { let predicates = tcx.predicates_of(def_id); let predicates = predicates.instantiate_identity(tcx).predicates; elaborate(tcx, predicates.into_iter()).any(|pred| match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(ref trait_pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(ref trait_pred)) => { trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0) } - ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Ambiguous @@ -592,7 +592,7 @@ fn virtual_call_violation_for_method<'tcx>( // only if the autotrait is one of the trait object's trait bounds, like // in `dyn Trait + AutoTrait`. This guarantees that trait objects only // implement auto traits if the underlying type does as well. - if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref: pred_trait_ref, constness: ty::BoundConstness::NotConst, polarity: ty::ImplPolarity::Positive, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 8399fbfc5be62..260805353ddce 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1649,7 +1649,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( let infcx = selcx.infcx; for predicate in env_predicates { let bound_predicate = predicate.kind(); - if let ty::PredicateKind::Clause(ty::Clause::Projection(data)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) = predicate.kind().skip_binder() { let data = bound_predicate.rebind(data); diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index f8ceee5005443..c93c30b705328 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -67,7 +67,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { let mut _orig_values = OriginalQueryValues::default(); let param_env = match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { // we ignore the value set to it. let mut _constness = pred.constness; obligation diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs index 7405ca31cdead..44671a07659bd 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs @@ -68,7 +68,7 @@ fn relate_mir_and_user_ty<'tcx>( // FIXME(#104764): We should check well-formedness before normalization. let predicate = - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(user_ty.into()))); + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(user_ty.into()))); ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate)); Ok(()) } @@ -120,7 +120,7 @@ fn relate_mir_and_user_substs<'tcx>( let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty); ocx.eq(&cause, param_env, self_ty, impl_self_ty)?; - let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed( + let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( impl_self_ty.into(), ))); ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate)); @@ -137,7 +137,8 @@ fn relate_mir_and_user_substs<'tcx>( // them? This would only be relevant if some input // type were ill-formed but did not appear in `ty`, // which...could happen with normalization... - let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(ty.into()))); + let predicate = + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty.into()))); ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate)); Ok(()) } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 8761f4fea6c2c..7d0dc740cf578 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -108,7 +108,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( // learn anything new from those. if obligation.predicate.has_non_region_infer() { match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(..)) + ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) | ty::PredicateKind::AliasRelate(..) => { ocx.register_obligation(obligation.clone()); } @@ -121,33 +121,33 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( Some(pred) => pred, }; match pred { - ty::PredicateKind::Clause(ty::Clause::Trait(..)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound // if we ever support that - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::Projection(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => {} // We need to search through *all* WellFormed predicates - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { wf_args.push(arg); } // We need to register region relationships - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( r_a, r_b, ))) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)), - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( ty_a, r_b, ))) => outlives_bounds.push(ty::OutlivesPredicate(ty_a.into(), r_b)), diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs index 47850bc330dab..789ef647246e9 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs @@ -18,7 +18,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { // `&T`, accounts for about 60% percentage of the predicates // we have to prove. No need to canonicalize and all that for // such cases. - if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_ref)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) = key.value.predicate.kind().skip_binder() { if let Some(sized_def_id) = tcx.lang_items().sized_trait() { diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index f2dfa6921f41c..0effeffaca6c9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -402,7 +402,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; for &(predicate, _) in self.tcx().predicates_of(impl_def_id).predicates { - let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) + let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = predicate.kind().skip_binder() else { continue }; if fn_ptr_trait != pred.trait_ref.def_id { continue; @@ -463,7 +463,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.tcx().mk_predicate(obligation.predicate.map_bound(|mut pred| { pred.trait_ref = ty::TraitRef::new(self.tcx(), fn_ptr_trait, [pred.trait_ref.self_ty()]); - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) })), ); if let Ok(r) = self.infcx.evaluate_obligation(&obligation) { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index ca2ae9b523509..0f0e3f1f16a6a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -643,7 +643,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ensure_sufficient_stack(|| { let bound_predicate = obligation.predicate.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(t)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => { let t = bound_predicate.rebind(t); debug_assert!(!t.has_escaping_bound_vars()); let obligation = obligation.with(self.tcx(), t); @@ -674,7 +674,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { // So, there is a bit going on here. First, `WellFormed` predicates // are coinductive, like trait predicates with auto traits. // This means that we need to detect if we have recursively @@ -760,7 +760,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(pred)) => { // A global type with no free lifetimes or generic parameters // outlives anything. if pred.0.has_free_regions() @@ -774,7 +774,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) => { // We do not consider region relationships when evaluating trait matches. Ok(EvaluatedToOkModuloRegions) } @@ -787,7 +787,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::Clause(ty::Clause::Projection(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { let data = bound_predicate.rebind(data); let project_obligation = obligation.with(self.tcx(), data); match project::poly_project_and_unify_type(self, &project_obligation) { @@ -862,7 +862,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(uv)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { match const_evaluatable::is_const_evaluatable( self.infcx, uv, @@ -974,7 +974,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { bug!("AliasRelate is only used for new solver") } ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig), - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { match self.infcx.at(&obligation.cause, obligation.param_env).eq( DefineOpaqueTypes::No, ct.ty(), @@ -1668,7 +1668,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .enumerate() .filter_map(|(idx, bound)| { let bound_predicate = bound.kind(); - if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = bound_predicate.skip_binder() { let bound = bound_predicate.rebind(pred.trait_ref); diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 9a4b72013b88d..68ba8ceaa43c5 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -521,7 +521,8 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti }); p = tcx.mk_predicate( - new_trait_pred.map_bound(|p| ty::PredicateKind::Clause(ty::Clause::Trait(p))), + new_trait_pred + .map_bound(|p| ty::PredicateKind::Clause(ty::ClauseKind::Trait(p))), ) } } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 676978fabe4d1..e80d413d97618 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -142,29 +142,32 @@ pub fn predicate_obligations<'tcx>( // It's ok to skip the binder here because wf code is prepared for it match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(t)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => { wf.compute_trait_pred(&t, Elaborate::None); } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) => {} - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(ty, _reg))) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) => {} + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( + ty, + _reg, + ))) => { wf.compute(ty.into()); } - ty::PredicateKind::Clause(ty::Clause::Projection(t)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(t)) => { wf.compute_projection(t.projection_ty); wf.compute(match t.term.unpack() { ty::TermKind::Ty(ty) => ty.into(), ty::TermKind::Const(c) => c.into(), }) } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { wf.compute(ct.into()); wf.compute(ty.into()); } - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { wf.compute(arg); } - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(ct)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => { wf.compute(ct.into()); } @@ -247,7 +250,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( // It is fine to skip the binder as we don't care about regions here. match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) => { // The obligation comes not from the current `impl` nor the `trait` being implemented, // but rather from a "second order" obligation, where an associated type has a // projection coming from another associated type. See @@ -264,7 +267,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( cause.span = impl_item_span; } } - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { // An associated item obligation born out of the `trait` failed to be met. An example // can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`. debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred); @@ -386,7 +389,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause, depth, param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(arg))), + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( + arg, + ))), ) }), ); @@ -478,7 +483,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause.clone(), depth, param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(arg))), + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( + arg, + ))), ) }), ); @@ -522,7 +529,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.extend(obligations); let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( - ty::Clause::ConstEvaluatable(ct), + ty::ClauseKind::ConstEvaluatable(ct), )); let cause = self.cause(traits::WellFormed(None)); self.out.push(traits::Obligation::with_depth( @@ -543,7 +550,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.recursion_depth, self.param_env, ty::Binder::dummy(ty::PredicateKind::Clause( - ty::Clause::WellFormed(ct.into()), + ty::ClauseKind::WellFormed(ct.into()), )), )); } @@ -556,7 +563,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // we would not be proving bounds we should. let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( - ty::Clause::ConstEvaluatable(ct), + ty::ClauseKind::ConstEvaluatable(ct), )); let cause = self.cause(traits::WellFormed(None)); self.out.push(traits::Obligation::with_depth( @@ -658,9 +665,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause, depth, param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::TypeOutlives( - ty::OutlivesPredicate(rty, r), - ))), + ty::Binder::dummy(ty::PredicateKind::Clause( + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(rty, r)), + )), )); } } @@ -788,7 +795,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause, self.recursion_depth, param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed( + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( ty.into(), ))), )); @@ -970,21 +977,21 @@ pub(crate) fn required_region_bounds<'tcx>( .filter_map(|pred| { debug!(?pred); match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::Clause(ty::Clause::Trait(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( ref t, ref r, ))) => { diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 1d4219bc0c0b1..aefe57e0ddfaa 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -96,12 +96,12 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment { chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner))) } - ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Trait( predicate.trait_ref.lower_into(interner), )) } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => { chalk_ir::DomainGoal::Holds(chalk_ir::WhereClause::LifetimeOutlives( chalk_ir::LifetimeOutlives { a: predicate.0.lower_into(interner), @@ -109,7 +109,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment { + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => { chalk_ir::DomainGoal::Holds(chalk_ir::WhereClause::TypeOutlives( chalk_ir::TypeOutlives { ty: predicate.0.lower_into(interner), @@ -117,12 +117,12 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => { chalk_ir::DomainGoal::Holds(chalk_ir::WhereClause::AliasEq( predicate.lower_into(interner), )) } - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => match arg.unpack() { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => match arg.unpack() { ty::GenericArgKind::Type(ty) => chalk_ir::DomainGoal::WellFormed( chalk_ir::WellFormed::Ty(ty.lower_into(interner)), ), @@ -132,12 +132,12 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment bug!("unexpected predicate {}", predicate), }; @@ -166,12 +166,12 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi collect_bound_vars(interner, interner.tcx, self.kind()); let value = match predicate { - ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)), )) } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => { chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { a: predicate.0.lower_into(interner), @@ -179,7 +179,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi }), )) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => { chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { ty: predicate.0.lower_into(interner), @@ -187,12 +187,12 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi }), )) } - ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => { chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)), )) } - ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => match arg.unpack() { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => match arg.unpack() { GenericArgKind::Type(ty) => match ty.kind() { // FIXME(chalk): In Chalk, a placeholder is WellFormed if it // `FromEnv`. However, when we "lower" Params, we don't update @@ -228,10 +228,10 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi // We can defer this, but ultimately we'll want to express // some of these in terms of chalk operations. ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::Ambiguous | ty::PredicateKind::ConstEquate(..) => { chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) @@ -654,33 +654,33 @@ impl<'tcx> LowerInto<'tcx, Option { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { Some(chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner))) } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => { Some(chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { a: predicate.0.lower_into(interner), b: predicate.1.lower_into(interner), })) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => { Some(chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { ty: predicate.0.lower_into(interner), lifetime: predicate.1.lower_into(interner), })) } - ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => { Some(chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner))) } - ty::PredicateKind::Clause(ty::Clause::WellFormed(_ty)) => None, - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None, + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_ty)) => None, + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => None, ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => { @@ -792,7 +792,7 @@ impl<'tcx> LowerInto<'tcx, Option { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { Some(chalk_ir::Binders::new( binders, chalk_solve::rust_ir::InlineBound::TraitBound( @@ -800,23 +800,23 @@ impl<'tcx> LowerInto<'tcx, Option { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => { Some(chalk_ir::Binders::new( binders, chalk_solve::rust_ir::InlineBound::AliasEqBound(predicate.lower_into(interner)), )) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_predicate)) => None, - ty::PredicateKind::Clause(ty::Clause::WellFormed(_ty)) => None, - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None, + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_predicate)) => None, + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_ty)) => None, + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => None, - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => { diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 7f6d53fe86043..96896526a126d 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -56,18 +56,18 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable> + Par fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool { match p.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) => false, - ty::PredicateKind::Clause(ty::Clause::Trait(..)) - | ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) => false, + ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => true, diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index c8a40e0150112..492b0b7955772 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -321,10 +321,10 @@ where let bound_predicate = pred.kind(); let tcx = self.cx.tcx; let regions = match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(poly_trait_pred)) => { tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_trait_pred)) } - ty::PredicateKind::Clause(ty::Clause::Projection(poly_proj_pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(poly_proj_pred)) => { tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_proj_pred)) } _ => return FxHashSet::default(), @@ -449,7 +449,7 @@ where .filter(|p| { !orig_bounds.contains(p) || match p.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { pred.def_id() == sized_trait } _ => false, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 29c11e1f3359d..36eac5790b8bb 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -331,22 +331,22 @@ pub(crate) fn clean_predicate<'tcx>( ) -> Option { let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { clean_poly_trait_predicate(bound_predicate.rebind(pred), cx) } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(pred)) => { clean_region_outlives_predicate(pred) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(pred)) => { clean_type_outlives_predicate(bound_predicate.rebind(pred), cx) } - ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { Some(clean_projection_predicate(bound_predicate.rebind(pred), cx)) } // FIXME(generic_const_exprs): should this do something? - ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) => None, - ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) => None, - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None, + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) => None, + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) => None, + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => None, ty::PredicateKind::Subtype(..) | ty::PredicateKind::AliasRelate(..) @@ -805,20 +805,19 @@ fn clean_ty_generics<'tcx>( let param_idx = (|| { let bound_p = p.kind(); match bound_p.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { if let ty::Param(param) = pred.self_ty().kind() { return Some(param.index); } } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( - ty, - _reg, - ))) => { + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( + ty::OutlivesPredicate(ty, _reg), + )) => { if let ty::Param(param) = ty.kind() { return Some(param.index); } } - ty::PredicateKind::Clause(ty::Clause::Projection(p)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => { if let ty::Param(param) = p.projection_ty.self_ty().kind() { projection = Some(bound_p.rebind(p)); return Some(param.index); @@ -2114,10 +2113,10 @@ fn clean_middle_opaque_bounds<'tcx>( .filter_map(|bound| { let bound_predicate = bound.kind(); let trait_ref = match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(tr)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr)) => { bound_predicate.rebind(tr.trait_ref) } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( _ty, reg, ))) => { @@ -2137,7 +2136,7 @@ fn clean_middle_opaque_bounds<'tcx>( let bindings: ThinVec<_> = bounds .iter() .filter_map(|bound| { - if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = + if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = bound.kind().skip_binder() { if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() { diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 3c72b0bf9f2f6..a8221cc944984 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -128,7 +128,9 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId) .predicates .iter() .filter_map(|(pred, _)| { - if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred.kind().skip_binder() { + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = + pred.kind().skip_binder() + { if pred.trait_ref.self_ty() == self_ty { Some(pred.def_id()) } else { None } } else { None diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index dbaf6aaa853c5..ee6aef71980e3 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -26,7 +26,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::{Rvalue, StatementKind}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{ - self, Binder, BoundVariableKind, Clause, EarlyBinder, FnSig, GenericArgKind, List, ParamEnv, ParamTy, + self, Binder, BoundVariableKind, ClauseKind, EarlyBinder, FnSig, GenericArgKind, List, ParamEnv, ParamTy, PredicateKind, ProjectionPredicate, Ty, TyCtxt, TypeVisitableExt, TypeckResults, }; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -1133,7 +1133,7 @@ fn needless_borrow_impl_arg_position<'tcx>( let projection_predicates = predicates .iter() .filter_map(|predicate| { - if let PredicateKind::Clause(Clause::Projection(projection_predicate)) = predicate.kind().skip_binder() { + if let PredicateKind::Clause(ClauseKind::Projection(projection_predicate)) = predicate.kind().skip_binder() { Some(projection_predicate) } else { None @@ -1147,7 +1147,7 @@ fn needless_borrow_impl_arg_position<'tcx>( if predicates .iter() .filter_map(|predicate| { - if let PredicateKind::Clause(Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() + if let PredicateKind::Clause(ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder() && trait_predicate.trait_ref.self_ty() == param_ty.to_ty(cx.tcx) { Some(trait_predicate.trait_ref.def_id) @@ -1209,7 +1209,7 @@ fn needless_borrow_impl_arg_position<'tcx>( } predicates.iter().all(|predicate| { - if let PredicateKind::Clause(Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() + if let PredicateKind::Clause(ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder() && cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id) && let ty::Param(param_ty) = trait_predicate.self_ty().kind() && let GenericArgKind::Type(ty) = substs_with_referent_ty[param_ty.index as usize].unpack() diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 8f5d319cd4fc1..8d84e756ff874 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -14,7 +14,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::traits::Reveal; use rustc_middle::ty::{ - self, Binder, BoundConstness, Clause, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, + self, Binder, BoundConstness, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate, Ty, TyCtxt, }; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -503,7 +503,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> let ty_predicates = tcx.predicates_of(did).predicates; for (p, _) in ty_predicates { - if let PredicateKind::Clause(Clause::Trait(p)) = p.kind().skip_binder() + if let PredicateKind::Clause(ClauseKind::Trait(p)) = p.kind().skip_binder() && p.trait_ref.def_id == eq_trait_id && let ty::Param(self_ty) = p.trait_ref.self_ty().kind() && p.constness == BoundConstness::NotConst @@ -516,7 +516,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ParamEnv::new( tcx.mk_predicates_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain( params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| { - tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(Clause::Trait(TraitPredicate { + tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]), constness: BoundConstness::NotConst, polarity: ImplPolarity::Positive, diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index d1314795f5803..a391b76910ad6 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -4,7 +4,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, AliasTy, Clause, PredicateKind}; +use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; @@ -93,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { infcx .err_ctxt() .maybe_note_obligation_cause_for_async_await(db, &obligation); - if let PredicateKind::Clause(Clause::Trait(trait_pred)) = + if let PredicateKind::Clause(ClauseKind::Trait(trait_pred)) = obligation.predicate.kind().skip_binder() { db.note(format!( diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index 99f810c27cf82..cf85d3174dbac 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -16,7 +16,7 @@ use rustc_hir::{ }; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::{self, AssocKind, Clause, EarlyBinder, GenericArg, GenericArgKind, PredicateKind, Ty}; +use rustc_middle::ty::{self, AssocKind, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, PredicateKind, Ty}; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol}; @@ -175,7 +175,7 @@ fn check_collect_into_intoiterator<'tcx>( .caller_bounds() .into_iter() .filter_map(|p| { - if let PredicateKind::Clause(Clause::Trait(t)) = p.kind().skip_binder() + if let PredicateKind::Clause(ClauseKind::Trait(t)) = p.kind().skip_binder() && cx.tcx.is_diagnostic_item(sym::IntoIterator,t.trait_ref.def_id) { Some(t.self_ty()) } else { diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 309d2157b76ee..06fa95cd657d4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -14,7 +14,7 @@ use rustc_lint::LateContext; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; -use rustc_middle::ty::{self, Clause, EarlyBinder, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty}; +use rustc_middle::ty::{self, ClauseKind, EarlyBinder, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty}; use rustc_span::{sym, Symbol}; use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause}; @@ -345,12 +345,12 @@ fn get_input_traits_and_projections<'tcx>( let mut projection_predicates = Vec::new(); for predicate in cx.tcx.param_env(callee_def_id).caller_bounds() { match predicate.kind().skip_binder() { - PredicateKind::Clause(Clause::Trait(trait_predicate)) => { + PredicateKind::Clause(ClauseKind::Trait(trait_predicate)) => { if trait_predicate.trait_ref.self_ty() == input { trait_predicates.push(trait_predicate); } }, - PredicateKind::Clause(Clause::Projection(projection_predicate)) => { + PredicateKind::Clause(ClauseKind::Projection(projection_predicate)) => { if projection_predicate.projection_ty.self_ty() == input { projection_predicates.push(projection_predicate); } @@ -407,7 +407,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< let mut trait_predicates = cx.tcx.param_env(callee_def_id) .caller_bounds().iter().filter(|predicate| { - if let PredicateKind::Clause(Clause::Trait(trait_predicate)) + if let PredicateKind::Clause(ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder() && trait_predicate.trait_ref.self_ty() == *param_ty { diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 7d53fe65658a2..3773975e9554b 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { .filter_map(|pred| { // Note that we do not want to deal with qualified predicates here. match pred.kind().no_bound_vars() { - Some(ty::PredicateKind::Clause(ty::Clause::Trait(pred))) if pred.def_id() != sized_trait => { + Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))) if pred.def_id() != sized_trait => { Some(pred) }, _ => None, diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index fc550936165e6..b8911f109076a 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -19,7 +19,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::{self, Binder, Clause, ExistentialPredicate, List, PredicateKind, Ty}; +use rustc_middle::ty::{self, Binder, ClauseKind, ExistentialPredicate, List, PredicateKind, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::sym; @@ -697,7 +697,7 @@ fn matches_preds<'tcx>( ObligationCause::dummy(), cx.param_env, cx.tcx - .mk_predicate(Binder::dummy(PredicateKind::Clause(Clause::Projection( + .mk_predicate(Binder::dummy(PredicateKind::Clause(ClauseKind::Projection( p.with_self_ty(cx.tcx, ty), )))), )), diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs index 289ca4e9bed3c..a375e5d5b4ca2 100644 --- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs +++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs @@ -4,7 +4,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{Closure, Expr, ExprKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_middle::ty::{Clause, GenericPredicates, PredicateKind, ProjectionPredicate, TraitPredicate}; +use rustc_middle::ty::{ClauseKind, GenericPredicates, PredicateKind, ProjectionPredicate, TraitPredicate}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, BytePos, Span}; @@ -45,7 +45,7 @@ fn get_trait_predicates_for_trait_id<'tcx>( let mut preds = Vec::new(); for (pred, _) in generics.predicates { if_chain! { - if let PredicateKind::Clause(Clause::Trait(poly_trait_pred)) = pred.kind().skip_binder(); + if let PredicateKind::Clause(ClauseKind::Trait(poly_trait_pred)) = pred.kind().skip_binder(); let trait_pred = cx.tcx.erase_late_bound_regions(pred.kind().rebind(poly_trait_pred)); if let Some(trait_def_id) = trait_id; if trait_def_id == trait_pred.trait_ref.def_id; @@ -63,7 +63,7 @@ fn get_projection_pred<'tcx>( trait_pred: TraitPredicate<'tcx>, ) -> Option> { generics.predicates.iter().find_map(|(proj_pred, _)| { - if let ty::PredicateKind::Clause(Clause::Projection(pred)) = proj_pred.kind().skip_binder() { + if let ty::PredicateKind::Clause(ClauseKind::Projection(pred)) = proj_pred.kind().skip_binder() { let projection_pred = cx.tcx.erase_late_bound_regions(proj_pred.kind().rebind(pred)); if projection_pred.projection_ty.substs == trait_pred.trait_ref.substs { return Some(projection_pred); diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index 3df40942e7b5a..941df3318ae8b 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -73,7 +73,7 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: .flat_map(|v| v.fields.iter()) .any(|x| matches!(cx.tcx.type_of(x.did).subst_identity().peel_refs().kind(), ty::Param(_))) && all_predicates_of(cx.tcx, fn_id).all(|(pred, _)| match pred.kind().skip_binder() { - PredicateKind::Clause(ty::Clause::Trait(pred)) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker, + PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker, _ => true, }) && subs.types().all(|x| matches!(x.peel_refs().kind(), ty::Param(_))) diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 860a489494c88..aea79984c7ad6 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -27,14 +27,14 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) for (predicate, _) in predicates.predicates { match predicate.kind().skip_binder() { ty::PredicateKind::Clause( - ty::Clause::RegionOutlives(_) - | ty::Clause::TypeOutlives(_) - | ty::Clause::Projection(_) - | ty::Clause::Trait(..) - | ty::Clause::ConstArgHasType(..), + ty::ClauseKind::RegionOutlives(_) + | ty::ClauseKind::TypeOutlives(_) + | ty::ClauseKind::Projection(_) + | ty::ClauseKind::Trait(..) + | ty::ClauseKind::ConstArgHasType(..), ) - | ty::PredicateKind::Clause(ty::Clause::WellFormed(_)) - | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue, ty::PredicateKind::AliasRelate(..) => panic!("alias relate predicate on function: {predicate:#?}"), diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 7b4ed77e8edb9..12f18614d713e 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -94,7 +94,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' match predicate.kind().skip_binder() { // For `impl Trait`, it will register a predicate of `T: Trait`, so we go through // and check substitutions to find `U`. - ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => { if trait_predicate .trait_ref .substs @@ -107,7 +107,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' }, // For `impl Trait`, it will register a predicate of `::Assoc = U`, // so we check the term for `U`. - ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection_predicate)) => { if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() { if contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen) { return true; @@ -268,7 +268,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { for (predicate, _) in cx.tcx.explicit_item_bounds(def_id).skip_binder() { - if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() { + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder() { if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) { return true; } @@ -707,7 +707,7 @@ fn sig_from_bounds<'tcx>( for pred in predicates { match pred.kind().skip_binder() { - PredicateKind::Clause(ty::Clause::Trait(p)) + PredicateKind::Clause(ty::ClauseKind::Trait(p)) if (lang_items.fn_trait() == Some(p.def_id()) || lang_items.fn_mut_trait() == Some(p.def_id()) || lang_items.fn_once_trait() == Some(p.def_id())) @@ -720,7 +720,7 @@ fn sig_from_bounds<'tcx>( } inputs = Some(i); }, - PredicateKind::Clause(ty::Clause::Projection(p)) + PredicateKind::Clause(ty::ClauseKind::Projection(p)) if Some(p.projection_ty.def_id) == lang_items.fn_once_output() && p.projection_ty.self_ty() == ty => { if output.is_some() { @@ -747,7 +747,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option .subst_iter_copied(cx.tcx, ty.substs) { match pred.kind().skip_binder() { - PredicateKind::Clause(ty::Clause::Trait(p)) + PredicateKind::Clause(ty::ClauseKind::Trait(p)) if (lang_items.fn_trait() == Some(p.def_id()) || lang_items.fn_mut_trait() == Some(p.def_id()) || lang_items.fn_once_trait() == Some(p.def_id())) => @@ -760,7 +760,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option } inputs = Some(i); }, - PredicateKind::Clause(ty::Clause::Projection(p)) + PredicateKind::Clause(ty::ClauseKind::Projection(p)) if Some(p.projection_ty.def_id) == lang_items.fn_once_output() => { if output.is_some() { @@ -950,7 +950,7 @@ pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tc predicates .iter() .try_fold(false, |found, p| { - if let PredicateKind::Clause(ty::Clause::Trait(p)) = p.kind().skip_binder() + if let PredicateKind::Clause(ty::ClauseKind::Trait(p)) = p.kind().skip_binder() && let ty::Param(self_ty) = p.trait_ref.self_ty().kind() && ty.index == self_ty.index { From ac2ebd3a78246d2dab16aec39d2aaace618a17eb Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Thu, 30 Mar 2023 13:18:28 -0400 Subject: [PATCH 306/465] Prevent ICE when calling parse_attribute without an attribute Fixes 5729 `parse_attribute` will panic if the first token is not a `#`. To prevent this we return early instead of trying to parse an invalid attribute. --- src/parse/macros/cfg_if.rs | 5 +++++ tests/rustfmt/main.rs | 2 +- tests/target/issue_5729.rs | 5 +++++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 tests/target/issue_5729.rs diff --git a/src/parse/macros/cfg_if.rs b/src/parse/macros/cfg_if.rs index ac03409a7844b..cbc4c90b8f984 100644 --- a/src/parse/macros/cfg_if.rs +++ b/src/parse/macros/cfg_if.rs @@ -34,6 +34,11 @@ fn parse_cfg_if_inner<'a>( if !parser.eat_keyword(kw::If) { return Err("Expected `if`"); } + + if !matches!(parser.token.kind, TokenKind::Pound) { + return Err("Failed to parse attributes"); + } + // Inner attributes are not actually syntactically permitted here, but we don't // care about inner vs outer attributes in this position. Our purpose with this // special case parsing of cfg_if macros is to ensure we can correctly resolve diff --git a/tests/rustfmt/main.rs b/tests/rustfmt/main.rs index f00b0e09604fe..4936a7174636f 100644 --- a/tests/rustfmt/main.rs +++ b/tests/rustfmt/main.rs @@ -178,7 +178,7 @@ fn rustfmt_emits_error_on_line_overflow_true() { #[test] #[allow(non_snake_case)] fn dont_emit_ICE() { - let files = ["tests/target/issue_5728.rs"]; + let files = ["tests/target/issue_5728.rs", "tests/target/issue_5729.rs"]; for file in files { let args = [file]; diff --git a/tests/target/issue_5729.rs b/tests/target/issue_5729.rs new file mode 100644 index 0000000000000..d63c83e88f846 --- /dev/null +++ b/tests/target/issue_5729.rs @@ -0,0 +1,5 @@ +cfg_if::cfg_if! { + if { + } else if #(&cpus) { + } else [libc::CTL_HW, libc::HW_NCPU, 0, 0] +} From 75e236375a50f0abcf455b34077dd97bae8cf4a3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 19 Jun 2023 17:09:13 +0200 Subject: [PATCH 307/465] Clean up "doc(hidden)" check --- src/librustdoc/clean/mod.rs | 6 +++--- src/librustdoc/clean/types.rs | 8 ++++++++ src/librustdoc/passes/strip_hidden.rs | 4 ++-- src/librustdoc/passes/stripper.rs | 9 ++++----- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 29c11e1f3359d..851002d5e7965 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -54,7 +54,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< let mut inserted = FxHashSet::default(); items.extend(doc.foreigns.iter().map(|(item, renamed)| { let item = clean_maybe_renamed_foreign_item(cx, item, *renamed); - if let Some(name) = item.name && !item.attrs.lists(sym::doc).has_word(sym::hidden) { + if let Some(name) = item.name && !item.is_doc_hidden() { inserted.insert((item.type_(), name)); } item @@ -64,7 +64,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< return None; } let item = clean_doc_module(x, cx); - if item.attrs.lists(sym::doc).has_word(sym::hidden) { + if item.is_doc_hidden() { // Hidden modules are stripped at a later stage. // If a hidden module has the same name as a visible one, we want // to keep both of them around. @@ -85,7 +85,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< } let v = clean_maybe_renamed_item(cx, item, *renamed, *import_id); for item in &v { - if let Some(name) = item.name && !item.attrs.lists(sym::doc).has_word(sym::hidden) { + if let Some(name) = item.name && !item.is_doc_hidden() { inserted.insert((item.type_(), name)); } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 1999a6b671d3a..fc5f03568a942 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -783,6 +783,10 @@ impl Item { } attrs } + + pub fn is_doc_hidden(&self) -> bool { + self.attrs.is_doc_hidden() + } } #[derive(Clone, Debug)] @@ -1129,6 +1133,10 @@ impl Attributes { false } + fn is_doc_hidden(&self) -> bool { + self.has_doc_flag(sym::hidden) + } + pub(crate) fn from_ast(attrs: &[ast::Attribute]) -> Attributes { Attributes::from_ast_iter(attrs.iter().map(|attr| (attr, None)), false) } diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 972b0c5ec190e..e2e38d3e79f73 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -6,7 +6,7 @@ use rustc_span::symbol::sym; use std::mem; use crate::clean; -use crate::clean::{Item, ItemIdSet, NestedAttributesExt}; +use crate::clean::{Item, ItemIdSet}; use crate::core::DocContext; use crate::fold::{strip_item, DocFolder}; use crate::passes::{ImplStripper, Pass}; @@ -85,7 +85,7 @@ impl<'a, 'tcx> Stripper<'a, 'tcx> { impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> { fn fold_item(&mut self, i: Item) -> Option { - let has_doc_hidden = i.attrs.lists(sym::doc).has_word(sym::hidden); + let has_doc_hidden = i.is_doc_hidden(); let is_impl_or_exported_macro = match *i.kind { clean::ImplItem(..) => true, // If the macro has the `#[macro_export]` attribute, it means it's accessible at the diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index 73fc26a6b043a..90c361d9d2812 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -1,10 +1,9 @@ //! A collection of utility functions for the `strip_*` passes. use rustc_hir::def_id::DefId; use rustc_middle::ty::{TyCtxt, Visibility}; -use rustc_span::symbol::sym; use std::mem; -use crate::clean::{self, Item, ItemId, ItemIdSet, NestedAttributesExt}; +use crate::clean::{self, Item, ItemId, ItemIdSet}; use crate::fold::{strip_item, DocFolder}; use crate::formats::cache::Cache; use crate::visit_lib::RustdocEffectiveVisibilities; @@ -163,7 +162,7 @@ impl<'a> ImplStripper<'a, '_> { // If the "for" item is exported and the impl block isn't `#[doc(hidden)]`, then we // need to keep it. self.cache.effective_visibilities.is_exported(self.tcx, for_def_id) - && !item.attrs.lists(sym::doc).has_word(sym::hidden) + && !item.is_doc_hidden() } else { false } @@ -240,7 +239,7 @@ impl<'tcx> ImportStripper<'tcx> { // FIXME: This should be handled the same way as for HTML output. imp.imported_item_is_doc_hidden(self.tcx) } else { - i.attrs.lists(sym::doc).has_word(sym::hidden) + i.is_doc_hidden() } } } @@ -249,7 +248,7 @@ impl<'tcx> DocFolder for ImportStripper<'tcx> { fn fold_item(&mut self, i: Item) -> Option { match *i.kind { clean::ImportItem(imp) if self.import_should_be_hidden(&i, &imp) => None, - clean::ImportItem(_) if i.attrs.lists(sym::doc).has_word(sym::hidden) => None, + clean::ImportItem(_) if i.is_doc_hidden() => None, clean::ExternCrateItem { .. } | clean::ImportItem(..) if i.visibility(self.tcx) != Some(Visibility::Public) => { From 2c30fa5a8292ab5d32a3b1129c9ab897897b1689 Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Tue, 7 Feb 2023 18:43:07 -0500 Subject: [PATCH 308/465] Adjust enum variant spans to exclude any explicit discriminant Fixes 5686 For reference, explicit discriminants were proposed in [RFC-2363]. `ast::Variant` spans extend to include explicit discriminants when they are present. Now we'll adjust the span of enum variants to exclude any explicit discriminant. [RFC-2363]: https://rust-lang.github.io/rfcs/2363-arbitrary-enum-discriminant.html --- src/items.rs | 25 ++++++++++++++++++++--- tests/source/issue_5686.rs | 40 ++++++++++++++++++++++++++++++++++++ tests/target/issue_5686.rs | 42 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 tests/source/issue_5686.rs create mode 100644 tests/target/issue_5686.rs diff --git a/src/items.rs b/src/items.rs index 3c5293b6bf5a7..714bcbc10b42e 100644 --- a/src/items.rs +++ b/src/items.rs @@ -560,7 +560,7 @@ impl<'a> FmtVisitor<'a> { let variant_body = match field.data { ast::VariantData::Tuple(..) | ast::VariantData::Struct(..) => format_struct( &context, - &StructParts::from_variant(field), + &StructParts::from_variant(field, &context), self.block_indent, Some(one_line_width), )?, @@ -951,14 +951,14 @@ impl<'a> StructParts<'a> { format_header(context, self.prefix, self.ident, self.vis, offset) } - fn from_variant(variant: &'a ast::Variant) -> Self { + fn from_variant(variant: &'a ast::Variant, context: &RewriteContext<'_>) -> Self { StructParts { prefix: "", ident: variant.ident, vis: &DEFAULT_VISIBILITY, def: &variant.data, generics: None, - span: variant.span, + span: enum_variant_span(variant, context), } } @@ -979,6 +979,25 @@ impl<'a> StructParts<'a> { } } +fn enum_variant_span(variant: &ast::Variant, context: &RewriteContext<'_>) -> Span { + use ast::VariantData::*; + if let Some(ref anon_const) = variant.disr_expr { + let span_before_consts = variant.span.until(anon_const.value.span); + let hi = match &variant.data { + Struct(..) => context + .snippet_provider + .span_after_last(span_before_consts, "}"), + Tuple(..) => context + .snippet_provider + .span_after_last(span_before_consts, ")"), + Unit(..) => variant.ident.span.hi(), + }; + mk_sp(span_before_consts.lo(), hi) + } else { + variant.span + } +} + fn format_struct( context: &RewriteContext<'_>, struct_parts: &StructParts<'_>, diff --git a/tests/source/issue_5686.rs b/tests/source/issue_5686.rs new file mode 100644 index 0000000000000..3bf96f73b2cd9 --- /dev/null +++ b/tests/source/issue_5686.rs @@ -0,0 +1,40 @@ +#[repr(u8)] +enum MyEnum { + UnitWithExplicitDiscriminant = 0, + EmptyStructSingleLineBlockComment { + /* Comment */ + } = 1, + EmptyStructMultiLineBlockComment { + /* + * Comment + */ + } = 2, + EmptyStructLineComment { + // comment + } = 3, + EmptyTupleSingleLineBlockComment( + /* Comment */ + ) = 4, + EmptyTupleMultiLineBlockComment( + /* + * Comment + */ + ) = 5, + EmptyTupleLineComment( + // comment + ) = 6, +} + +enum Animal { + Dog(/* tuple variant closer in comment -> ) */) = 1, + #[hello(world)] + Cat(/* tuple variant close in leading attribute */) = 2, + Bee(/* tuple variant closer on associated field attribute */ #[hello(world)] usize) = 3, + Fox(/* tuple variant closer on const fn call */) = some_const_fn(), + Ant(/* tuple variant closer on macro call */) = some_macro!(), + Snake {/* stuct variant closer in comment -> } */} = 6, + #[hell{world}] + Cobra {/* struct variant close in leading attribute */} = 6, + Eagle {/* struct variant closer on associated field attribute */ #[hell{world}]value: Sting} = 7, + Koala {/* struct variant closer on macro call */} = some_macro!{} +} diff --git a/tests/target/issue_5686.rs b/tests/target/issue_5686.rs new file mode 100644 index 0000000000000..993f12b5316dc --- /dev/null +++ b/tests/target/issue_5686.rs @@ -0,0 +1,42 @@ +#[repr(u8)] +enum MyEnum { + UnitWithExplicitDiscriminant = 0, + EmptyStructSingleLineBlockComment {/* Comment */} = 1, + EmptyStructMultiLineBlockComment { + /* + * Comment + */ + } = 2, + EmptyStructLineComment { + // comment + } = 3, + EmptyTupleSingleLineBlockComment(/* Comment */) = 4, + EmptyTupleMultiLineBlockComment( + /* + * Comment + */ + ) = 5, + EmptyTupleLineComment( + // comment + ) = 6, +} + +enum Animal { + Dog(/* tuple variant closer in comment -> ) */) = 1, + #[hello(world)] + Cat(/* tuple variant close in leading attribute */) = 2, + Bee( + /* tuple variant closer on associated field attribute */ #[hello(world)] usize, + ) = 3, + Fox(/* tuple variant closer on const fn call */) = some_const_fn(), + Ant(/* tuple variant closer on macro call */) = some_macro!(), + Snake {/* stuct variant closer in comment -> } */} = 6, + #[hell{world}] + Cobra {/* struct variant close in leading attribute */} = 6, + Eagle { + /* struct variant closer on associated field attribute */ + #[hell{world}] + value: Sting, + } = 7, + Koala {/* struct variant closer on macro call */} = some_macro! {}, +} From db613750a91215a89ac25fd65cdaef02df2f73d5 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Mon, 19 Jun 2023 16:21:33 +0100 Subject: [PATCH 309/465] Reformatting --- compiler/rustc_resolve/src/late.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index e700e8c9ce086..9f4573ea02594 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2247,9 +2247,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let report_error = |this: &Self, ns| { if this.should_report_errs() { let what = if ns == TypeNS { "type parameters" } else { "local variables" }; - - let err = ImportsCannotReferTo { span: ident.span, what }; - this.r.tcx.sess.create_err(err).emit(); + this.r + .tcx + .sess + .create_err(ImportsCannotReferTo { span: ident.span, what }) + .emit(); } }; From 2027e989bce7d1c2f702d7aed383bf9cbdaf51d1 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Mon, 19 Jun 2023 16:22:21 +0100 Subject: [PATCH 310/465] Remove unreachable and untested suggestion for invalid span enum derive(Default) --- compiler/rustc_resolve/messages.ftl | 3 --- compiler/rustc_resolve/src/diagnostics.rs | 14 +++++--------- compiler/rustc_resolve/src/errors.rs | 7 ------- tests/ui/enum/suggest-default-attribute.stderr | 2 +- 4 files changed, 6 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 062f9e85a9c22..60b6d74da7b9f 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -60,9 +60,6 @@ resolve_change_import_binding = resolve_consider_adding_a_derive = consider adding a derive -resolve_consider_adding_a_derive_enum = - consider adding `#[derive(Default)]` to this enum - resolve_const_not_member_of_trait = const `{$const_}` is not a member of trait `{$trait_}` .label = not a member of trait `{$trait_}` diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 2a22e1ba242c8..539b4a1d5e714 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -32,7 +32,7 @@ use thin_vec::ThinVec; use crate::errors::{ AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive, - ConsiderAddingADeriveEnum, ExplicitUnsafeTraits, + ExplicitUnsafeTraits, }; use crate::imports::{Import, ImportKind}; use crate::late::{PatternSource, Rib}; @@ -1393,14 +1393,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let span = self.def_span(def_id); let source_map = self.tcx.sess.source_map(); let head_span = source_map.guess_head_span(span); - if let Ok(head) = source_map.span_to_snippet(head_span) { - err.subdiagnostic(ConsiderAddingADerive { - span: head_span, - suggestion: format!("#[derive(Default)]\n{head}") - }); - } else { - err.subdiagnostic(ConsiderAddingADeriveEnum { span: head_span }); - } + err.subdiagnostic(ConsiderAddingADerive { + span: head_span.shrink_to_lo(), + suggestion: format!("#[derive(Default)]\n") + }); } for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] { if let Ok(binding) = self.early_resolve_ident_in_lexical_scope( diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index fb70fbe2c1faf..93b626c779419 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -646,10 +646,3 @@ pub(crate) struct ConsiderAddingADerive { pub(crate) span: Span, pub(crate) suggestion: String, } - -#[derive(Subdiagnostic)] -#[help(resolve_consider_adding_a_derive_enum)] -pub(crate) struct ConsiderAddingADeriveEnum { - #[primary_span] - pub(crate) span: Span, -} diff --git a/tests/ui/enum/suggest-default-attribute.stderr b/tests/ui/enum/suggest-default-attribute.stderr index fb830d3f78b64..b56d599a78663 100644 --- a/tests/ui/enum/suggest-default-attribute.stderr +++ b/tests/ui/enum/suggest-default-attribute.stderr @@ -7,7 +7,7 @@ LL | #[default] help: consider adding a derive | LL + #[derive(Default)] -LL ~ pub enum Test { +LL | pub enum Test { | error: aborting due to previous error From 13aa0dc1c7cf4dd4d0e527d47741f7ace790dcc3 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 19 Jun 2023 10:06:10 +0000 Subject: [PATCH 311/465] Add gha problem matcher --- src/ci/github-actions/problem_matchers.json | 40 +++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/ci/github-actions/problem_matchers.json b/src/ci/github-actions/problem_matchers.json index 37561924b7d4f..b6c7ace841e59 100644 --- a/src/ci/github-actions/problem_matchers.json +++ b/src/ci/github-actions/problem_matchers.json @@ -10,6 +10,46 @@ "message": 3 } ] + }, + { + "owner": "cargo-common", + "pattern": [ + { + "regexp": "^(warning|warn|error)(\\[(\\S*)\\])?: (.*)$", + "severity": 1, + "message": 4, + "code": 3 + }, + { + "regexp": "^\\s+-->\\s(\\S+):(\\d+):(\\d+)$", + "file": 1, + "line": 2, + "column": 3 + } + ] + }, + { + "owner": "compiler-panic", + "pattern": [ + { + "regexp": "error: internal compiler error: (.*):(\\d+):(\\d+): (.*)$", + "message": 4, + "file": 1, + "line": 2, + "column": 3 + } + ] + }, + { + "owner": "cargo-fmt", + "pattern": [ + { + "regexp": "^(Diff in (\\S+)) at line (\\d+):", + "message": 1, + "file": 2, + "line": 3 + } + ] } ] } From 21226eefb2e2465b9730c37e7d08655865610d90 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 16 Jun 2023 06:27:41 +0000 Subject: [PATCH 312/465] Fully fledged Clause type --- .../rustc_hir_analysis/src/astconv/mod.rs | 4 +- compiler/rustc_hir_analysis/src/bounds.rs | 43 +++---- .../src/collect/item_bounds.rs | 10 +- .../src/collect/predicates_of.rs | 20 ++-- compiler/rustc_infer/src/traits/util.rs | 20 ++++ compiler/rustc_middle/src/ty/mod.rs | 113 +++++++++++------- .../rustc_middle/src/ty/structural_impls.rs | 25 ++++ compiler/rustc_privacy/src/lib.rs | 4 +- .../src/solve/assembly/mod.rs | 8 +- .../src/solve/project_goals.rs | 2 +- .../src/solve/trait_goals.rs | 2 +- 11 files changed, 155 insertions(+), 96 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 14e3ceadb104f..12f667795225a 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -945,8 +945,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut trait_bounds = vec![]; let mut projection_bounds = vec![]; - for (clause, span) in bounds.predicates() { - let pred: ty::Predicate<'tcx> = clause.to_predicate(tcx); + for (clause, span) in bounds.clauses() { + let pred: ty::Predicate<'tcx> = clause.as_predicate(); let bound_pred = pred.kind(); match bound_pred.skip_binder() { ty::PredicateKind::Clause(clause) => match clause { diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 6bd498e142df1..531100e1fe61b 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -2,7 +2,6 @@ //! `ty` form from the HIR. use rustc_hir::LangItem; -use rustc_middle::ty::Binder; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use rustc_span::Span; @@ -24,62 +23,58 @@ use rustc_span::Span; /// include the self type (e.g., `trait_bounds`) but in others we do not #[derive(Default, PartialEq, Eq, Clone, Debug)] pub struct Bounds<'tcx> { - pub predicates: Vec<(Binder<'tcx, ty::ClauseKind<'tcx>>, Span)>, + pub clauses: Vec<(ty::Clause<'tcx>, Span)>, } impl<'tcx> Bounds<'tcx> { pub fn push_region_bound( &mut self, - _tcx: TyCtxt<'tcx>, + tcx: TyCtxt<'tcx>, region: ty::PolyTypeOutlivesPredicate<'tcx>, span: Span, ) { - self.predicates.push((region.map_bound(|p| ty::ClauseKind::TypeOutlives(p)), span)); + self.clauses + .push((region.map_bound(|p| ty::ClauseKind::TypeOutlives(p)).to_predicate(tcx), span)); } pub fn push_trait_bound( &mut self, - _tcx: TyCtxt<'tcx>, + tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, span: Span, constness: ty::BoundConstness, polarity: ty::ImplPolarity, ) { - self.predicates.push(( - trait_ref.map_bound(|trait_ref| { - ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness, polarity }) - }), + self.clauses.push(( + trait_ref + .map_bound(|trait_ref| { + ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness, polarity }) + }) + .to_predicate(tcx), span, )); } pub fn push_projection_bound( &mut self, - _tcx: TyCtxt<'tcx>, + tcx: TyCtxt<'tcx>, projection: ty::PolyProjectionPredicate<'tcx>, span: Span, ) { - self.predicates.push((projection.map_bound(|proj| ty::ClauseKind::Projection(proj)), span)); + self.clauses.push(( + projection.map_bound(|proj| ty::ClauseKind::Projection(proj)).to_predicate(tcx), + span, + )); } pub fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) { let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span)); let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [ty]); // Preferable to put this obligation first, since we report better errors for sized ambiguity. - self.predicates.insert( - 0, - ( - ty::Binder::dummy(ty::ClauseKind::Trait( - trait_ref.without_const().to_predicate(tcx), - )), - span, - ), - ); + self.clauses.insert(0, (trait_ref.to_predicate(tcx), span)); } - pub fn predicates( - &self, - ) -> impl Iterator>, Span)> + '_ { - self.predicates.iter().cloned() + pub fn clauses(&self) -> impl Iterator, Span)> + '_ { + self.clauses.iter().cloned() } } diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index b3e9acf0a4b33..5f35678d95d93 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -3,7 +3,6 @@ use crate::astconv::{AstConv, OnlySelfBounds}; use rustc_hir as hir; use rustc_infer::traits::util; use rustc_middle::ty::subst::InternalSubsts; -use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; @@ -49,8 +48,8 @@ fn associated_type_bounds<'tcx>( let all_bounds = tcx.arena.alloc_from_iter( bounds - .predicates() - .map(|(clause, span)| (clause.to_predicate(tcx), span)) + .clauses() + .map(|(clause, span)| (clause.as_predicate(), span)) .chain(bounds_from_parent), ); debug!( @@ -80,9 +79,8 @@ fn opaque_type_bounds<'tcx>( icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span); debug!(?bounds); - tcx.arena.alloc_from_iter( - bounds.predicates().map(|(clause, span)| (clause.to_predicate(tcx), span)), - ) + tcx.arena + .alloc_from_iter(bounds.clauses().map(|(clause, span)| (clause.as_predicate(), span))) }) } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index cd801202aeac1..3081f0c386a27 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -126,8 +126,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen predicates.extend( icx.astconv() .compute_bounds(tcx.types.self_param, self_bounds, OnlySelfBounds(false)) - .predicates() - .map(|(clause, span)| (clause.to_predicate(tcx), span)), + .clauses() + .map(|(clause, span)| (clause.as_predicate(), span)), ); } @@ -176,9 +176,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen param.span, ); trace!(?bounds); - predicates.extend( - bounds.predicates().map(|(clause, span)| (clause.to_predicate(tcx), span)), - ); + predicates + .extend(bounds.clauses().map(|(clause, span)| (clause.as_predicate(), span))); trace!(?predicates); } GenericParamKind::Const { .. } => { @@ -237,9 +236,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen bound_vars, OnlySelfBounds(false), ); - predicates.extend( - bounds.predicates().map(|(clause, span)| (clause.to_predicate(tcx), span)), - ); + predicates + .extend(bounds.clauses().map(|(clause, span)| (clause.as_predicate(), span))); } hir::WherePredicate::RegionPredicate(region_pred) => { @@ -669,8 +667,8 @@ pub(super) fn implied_predicates_with_filter( // Combine the two lists to form the complete set of superbounds: let implied_bounds = &*tcx.arena.alloc_from_iter( superbounds - .predicates() - .map(|(clause, span)| (clause.to_predicate(tcx), span)) + .clauses() + .map(|(clause, span)| (clause.as_predicate(), span)) .chain(where_bounds_that_match), ); debug!(?implied_bounds); @@ -831,7 +829,7 @@ impl<'tcx> ItemCtxt<'tcx> { ); } - bounds.predicates().map(|(clause, span)| (clause.to_predicate(self.tcx), span)).collect() + bounds.clauses().map(|(clause, span)| (clause.as_predicate(), span)).collect() } #[instrument(level = "trace", skip(self))] diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 4f65a312c4ef7..00d4934b74962 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -167,6 +167,26 @@ impl<'tcx> Elaboratable<'tcx> for (ty::Predicate<'tcx>, Span) { } } +impl<'tcx> Elaboratable<'tcx> for ty::Clause<'tcx> { + fn predicate(&self) -> ty::Predicate<'tcx> { + self.as_predicate() + } + + fn child(&self, predicate: ty::Predicate<'tcx>) -> Self { + predicate.as_clause().unwrap() + } + + fn child_with_derived_cause( + &self, + predicate: ty::Predicate<'tcx>, + _span: Span, + _parent_trait_pred: ty::PolyTraitPredicate<'tcx>, + _index: usize, + ) -> Self { + predicate.as_clause().unwrap() + } +} + pub fn elaborate<'tcx, O: Elaboratable<'tcx>>( tcx: TyCtxt<'tcx>, obligations: impl IntoIterator, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f43be1468e894..79739adbb6ddc 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -561,6 +561,42 @@ impl rustc_errors::IntoDiagnosticArg for Predicate<'_> { } } +/// TODO: doc +#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)] +#[rustc_pass_by_value] +pub struct Clause<'tcx>(Interned<'tcx, WithCachedTypeInfo>>>); + +impl<'tcx> Clause<'tcx> { + pub fn as_predicate(self) -> Predicate<'tcx> { + Predicate(self.0) + } + + pub fn kind(self) -> Binder<'tcx, ClauseKind<'tcx>> { + self.0.internee.map_bound(|kind| match kind { + PredicateKind::Clause(clause) => clause, + _ => unreachable!(), + }) + } + + pub fn as_trait_clause(self) -> Option>> { + let clause = self.kind(); + if let ty::ClauseKind::Trait(trait_clause) = clause.skip_binder() { + Some(clause.rebind(trait_clause)) + } else { + None + } + } + + pub fn as_projection_clause(self) -> Option>> { + let clause = self.kind(); + if let ty::ClauseKind::Projection(projection_clause) = clause.skip_binder() { + Some(clause.rebind(projection_clause)) + } else { + None + } + } +} + #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] /// A clause is something that can appear in where bounds or be inferred @@ -592,24 +628,6 @@ pub enum ClauseKind<'tcx> { ConstEvaluatable(ty::Const<'tcx>), } -impl<'tcx> Binder<'tcx, ClauseKind<'tcx>> { - pub fn as_trait_clause(self) -> Option>> { - if let ty::ClauseKind::Trait(trait_clause) = self.skip_binder() { - Some(self.rebind(trait_clause)) - } else { - None - } - } - - pub fn as_projection_clause(self) -> Option>> { - if let ty::ClauseKind::Projection(projection_clause) = self.skip_binder() { - Some(self.rebind(projection_clause)) - } else { - None - } - } -} - #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub enum PredicateKind<'tcx> { @@ -1222,6 +1240,13 @@ impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, ClauseKind<'tcx>> { } } +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for Binder<'tcx, ClauseKind<'tcx>> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + tcx.mk_predicate(self.map_bound(|clause| ty::PredicateKind::Clause(clause))).expect_clause() + } +} + impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { @@ -1229,14 +1254,11 @@ impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { } } -impl<'tcx> ToPredicate<'tcx, Binder<'tcx, ClauseKind<'tcx>>> for TraitRef<'tcx> { +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitRef<'tcx> { #[inline(always)] - fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Binder<'tcx, ClauseKind<'tcx>> { - Binder::dummy(ClauseKind::Trait(TraitPredicate { - trait_ref: self, - constness: ty::BoundConstness::NotConst, - polarity: ty::ImplPolarity::Positive, - })) + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let p: Predicate<'tcx> = self.to_predicate(tcx); + p.expect_clause() } } @@ -1248,9 +1270,9 @@ impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> { } } -impl<'tcx> ToPredicate<'tcx, Binder<'tcx, ClauseKind<'tcx>>> for Binder<'tcx, TraitRef<'tcx>> { +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for Binder<'tcx, TraitRef<'tcx>> { #[inline(always)] - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Binder<'tcx, ClauseKind<'tcx>> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx); pred.to_predicate(tcx) } @@ -1285,9 +1307,10 @@ impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> { } } -impl<'tcx> ToPredicate<'tcx, Binder<'tcx, ClauseKind<'tcx>>> for PolyTraitPredicate<'tcx> { - fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Binder<'tcx, ClauseKind<'tcx>> { - self.map_bound(|p| ClauseKind::Trait(p)) +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyTraitPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let p: Predicate<'tcx> = self.to_predicate(tcx); + p.expect_clause() } } @@ -1309,9 +1332,10 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { } } -impl<'tcx> ToPredicate<'tcx, Binder<'tcx, ClauseKind<'tcx>>> for PolyProjectionPredicate<'tcx> { - fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Binder<'tcx, ClauseKind<'tcx>> { - self.map_bound(|p| ClauseKind::Projection(p)) +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyProjectionPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let p: Predicate<'tcx> = self.to_predicate(tcx); + p.expect_clause() } } @@ -1385,18 +1409,17 @@ impl<'tcx> Predicate<'tcx> { } } - pub fn as_clause(self) -> Option>> { - let predicate = self.kind(); - match predicate.skip_binder() { - PredicateKind::Clause(clause) => Some(predicate.rebind(clause)), - PredicateKind::AliasRelate(..) - | PredicateKind::Subtype(..) - | PredicateKind::Coerce(..) - | PredicateKind::ObjectSafe(..) - | PredicateKind::ClosureKind(..) - | PredicateKind::ConstEquate(..) - | PredicateKind::Ambiguous - | PredicateKind::TypeWellFormedFromEnv(..) => None, + pub fn as_clause(self) -> Option> { + match self.kind().skip_binder() { + PredicateKind::Clause(..) => Some(self.expect_clause()), + _ => None, + } + } + + pub fn expect_clause(self) -> Clause<'tcx> { + match self.kind().skip_binder() { + PredicateKind::Clause(..) => Clause(self.0), + _ => bug!(), } } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index ebc4a3d22ad70..e53e1e0a54c52 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -171,6 +171,12 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { } } +impl<'tcx> fmt::Debug for ty::Clause<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self.kind()) + } +} + impl<'tcx> fmt::Debug for ty::ClauseKind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { @@ -654,12 +660,31 @@ impl<'tcx> TypeFoldable> for ty::Predicate<'tcx> { } } +// FIXME(clause): This is wonky +impl<'tcx> TypeFoldable> for ty::Clause<'tcx> { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + Ok(folder + .try_fold_predicate(self.as_predicate())? + .as_clause() + .expect("no sensible folder would do this")) + } +} + impl<'tcx> TypeVisitable> for ty::Predicate<'tcx> { fn visit_with>>(&self, visitor: &mut V) -> ControlFlow { visitor.visit_predicate(*self) } } +impl<'tcx> TypeVisitable> for ty::Clause<'tcx> { + fn visit_with>>(&self, visitor: &mut V) -> ControlFlow { + visitor.visit_predicate(self.as_predicate()) + } +} + impl<'tcx> TypeSuperFoldable> for ty::Predicate<'tcx> { fn try_super_fold_with>>( self, diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index dc66c31c191a5..b897a6198e366 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1271,8 +1271,8 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { self.tcx.types.never, ); - for (pred, _) in bounds.predicates() { - match pred.skip_binder() { + for (clause, _) in bounds.clauses() { + match clause.kind().skip_binder() { ty::ClauseKind::Trait(trait_predicate) => { if self.visit_trait(trait_predicate.trait_ref).is_break() { return; diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 7be21d9e61924..4a53f6dd24062 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -106,7 +106,7 @@ pub(super) trait GoalKind<'tcx>: fn probe_and_match_goal_against_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Binder<'tcx, ty::ClauseKind<'tcx>>, + assumption: ty::Clause<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>, ) -> QueryResult<'tcx>; @@ -116,7 +116,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_implied_clause( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Binder<'tcx, ty::ClauseKind<'tcx>>, + assumption: ty::Clause<'tcx>, requirements: impl IntoIterator>>, ) -> QueryResult<'tcx> { Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| { @@ -132,7 +132,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_alias_bound_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Binder<'tcx, ty::ClauseKind<'tcx>>, + assumption: ty::Clause<'tcx>, ) -> QueryResult<'tcx> { Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| { ecx.validate_alias_bound_self_from_param_env(goal) @@ -145,7 +145,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_object_bound_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Binder<'tcx, ty::ClauseKind<'tcx>>, + assumption: ty::Clause<'tcx>, ) -> QueryResult<'tcx> { Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| { let tcx = ecx.tcx(); diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index e0e27bf851b39..ae8ce2ebfeb9c 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -107,7 +107,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { fn probe_and_match_goal_against_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Binder<'tcx, ty::ClauseKind<'tcx>>, + assumption: ty::Clause<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>, ) -> QueryResult<'tcx> { if let Some(projection_pred) = assumption.as_projection_clause() { diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 2a576ffe22051..a4f5fa63f62d8 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -85,7 +85,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn probe_and_match_goal_against_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Binder<'tcx, ty::ClauseKind<'tcx>>, + assumption: ty::Clause<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>, ) -> QueryResult<'tcx> { if let Some(trait_clause) = assumption.as_trait_clause() { From dcee3ab4f8e66a6783fc902362bee1f1bb957818 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 18 Jun 2023 19:51:11 +0000 Subject: [PATCH 313/465] doc --- compiler/rustc_middle/src/ty/mod.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 79739adbb6ddc..cd4591308278b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -456,6 +456,11 @@ impl ty::EarlyBoundRegion { } } +/// A statement that can be proven by a trait solver. This includes things that may +/// show up in where clauses, such as trait predicates and projection predicates, +/// and also things that are emitted as part of type checking such as `ObjectSafe` +/// predicate which is emitted when a type is coerced to a trait object. +/// /// Use this rather than `PredicateKind`, whenever possible. #[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] @@ -561,7 +566,9 @@ impl rustc_errors::IntoDiagnosticArg for Predicate<'_> { } } -/// TODO: doc +/// A subset of predicates which can be assumed by the trait solver. They show up in +/// an item's where clauses, hence the name `Clause`, and may either be user-written +/// (such as traits) or may be inserted during lowering. #[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] pub struct Clause<'tcx>(Interned<'tcx, WithCachedTypeInfo>>>); @@ -1409,6 +1416,7 @@ impl<'tcx> Predicate<'tcx> { } } + /// Matches a `PredicateKind::Clause` and turns it into a `Clause`, otherwise returns `None`. pub fn as_clause(self) -> Option> { match self.kind().skip_binder() { PredicateKind::Clause(..) => Some(self.expect_clause()), @@ -1416,6 +1424,8 @@ impl<'tcx> Predicate<'tcx> { } } + /// Turns a predicate into a clause without checking that it is a `PredicateKind::Clause` + /// first. This will ICE when methods are called on `Clause`. pub fn expect_clause(self) -> Clause<'tcx> { match self.kind().skip_binder() { PredicateKind::Clause(..) => Clause(self.0), From 66b9951dcdc76bbda5e6c75b4a2974d21a9e747f Mon Sep 17 00:00:00 2001 From: KaDiWa Date: Wed, 1 Feb 2023 00:20:15 +0100 Subject: [PATCH 314/465] update some dependencies --- Cargo.lock | 98 +++++++++++++++++++++++++---------- Cargo.toml | 6 +-- src/cargo-fmt/main.rs | 7 +-- src/cargo-fmt/test/targets.rs | 22 ++++---- 4 files changed, 90 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8487dc58b4ed3..a59e0b6819bf7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -68,15 +68,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" [[package]] -name = "atty" -version = "0.2.14" +name = "autocfg" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bitflags" @@ -122,15 +117,16 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.14.2" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ "camino", "cargo-platform", "semver", "serde", "serde_json", + "thiserror", ] [[package]] @@ -267,12 +263,12 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "env_logger" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" dependencies = [ - "atty", "humantime", + "is-terminal", "log", "regex", "termcolor", @@ -339,19 +335,16 @@ dependencies = [ ] [[package]] -name = "heck" -version = "0.4.0" +name = "hashbrown" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] -name = "hermit-abi" -version = "0.1.19" +name = "heck" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] name = "hermit-abi" @@ -383,13 +376,23 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + [[package]] name = "io-lifetimes" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi", "libc", "windows-sys 0.48.0", ] @@ -400,7 +403,7 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi", "io-lifetimes", "rustix", "windows-sys 0.48.0", @@ -644,6 +647,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" +dependencies = [ + "serde", +] + [[package]] name = "strsim" version = "0.10.0" @@ -712,11 +724,36 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.8" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" dependencies = [ + "indexmap", "serde", + "serde_spanned", + "toml_datetime", + "winnow", ] [[package]] @@ -929,6 +966,15 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "winnow" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +dependencies = [ + "memchr", +] + [[package]] name = "yansi-term" version = "0.1.2" diff --git a/Cargo.toml b/Cargo.toml index 0093b975e8628..5f483693a116e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,11 +36,11 @@ generic-simd = ["bytecount/generic-simd"] annotate-snippets = { version = "0.9", features = ["color"] } anyhow = "1.0" bytecount = "0.6" -cargo_metadata = "0.14" +cargo_metadata = "0.15.4" clap = { version = "4.2.1", features = ["derive"] } diff = "0.1" dirs = "4.0" -env_logger = "0.9" +env_logger = "0.10.0" getopts = "0.2" ignore = "0.4" itertools = "0.10" @@ -51,7 +51,7 @@ serde = { version = "1.0.160", features = ["derive"] } serde_json = "1.0" term = "0.7" thiserror = "1.0.40" -toml = "0.5" +toml = "0.7.4" unicode-segmentation = "1.9" unicode-width = "0.1" unicode_categories = "0.1" diff --git a/src/cargo-fmt/main.rs b/src/cargo-fmt/main.rs index a106181ec7eb6..bc9745275f20c 100644 --- a/src/cargo-fmt/main.rs +++ b/src/cargo-fmt/main.rs @@ -14,6 +14,7 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::str; +use cargo_metadata::Edition; use clap::{CommandFactory, Parser}; #[path = "test/mod.rs"] @@ -270,7 +271,7 @@ pub struct Target { /// A kind of target (e.g., lib, bin, example, ...). kind: String, /// Rust edition for this target. - edition: String, + edition: Edition, } impl Target { @@ -281,7 +282,7 @@ impl Target { Target { path: canonicalized, kind: target.kind[0].clone(), - edition: target.edition.clone(), + edition: target.edition, } } } @@ -506,7 +507,7 @@ fn run_rustfmt( let mut command = rustfmt_command() .stdout(stdout) .args(files) - .args(&["--edition", edition]) + .args(&["--edition", edition.as_str()]) .args(fmt_args) .spawn() .map_err(|e| match e.kind() { diff --git a/src/cargo-fmt/test/targets.rs b/src/cargo-fmt/test/targets.rs index b7e7fabdf7156..34accb2136a44 100644 --- a/src/cargo-fmt/test/targets.rs +++ b/src/cargo-fmt/test/targets.rs @@ -2,7 +2,7 @@ use super::*; struct ExpTarget { path: &'static str, - edition: &'static str, + edition: Edition, kind: &'static str, } @@ -26,7 +26,7 @@ mod all_targets { for target in exp_targets { assert!(targets.contains(&Target { path: get_path(target.path), - edition: target.edition.to_owned(), + edition: target.edition, kind: target.kind.to_owned(), })); } @@ -39,17 +39,17 @@ mod all_targets { let exp_targets = vec![ ExpTarget { path: "dependency-dir-name/subdep-dir-name/src/lib.rs", - edition: "2018", + edition: Edition::E2018, kind: "lib", }, ExpTarget { path: "dependency-dir-name/src/lib.rs", - edition: "2018", + edition: Edition::E2018, kind: "lib", }, ExpTarget { path: "src/main.rs", - edition: "2018", + edition: Edition::E2018, kind: "main", }, ]; @@ -79,32 +79,32 @@ mod all_targets { let exp_targets = vec![ ExpTarget { path: "ws/a/src/main.rs", - edition: "2018", + edition: Edition::E2018, kind: "bin", }, ExpTarget { path: "ws/b/src/main.rs", - edition: "2018", + edition: Edition::E2018, kind: "bin", }, ExpTarget { path: "ws/c/src/lib.rs", - edition: "2018", + edition: Edition::E2018, kind: "lib", }, ExpTarget { path: "ws/a/d/src/lib.rs", - edition: "2018", + edition: Edition::E2018, kind: "lib", }, ExpTarget { path: "e/src/main.rs", - edition: "2018", + edition: Edition::E2018, kind: "main", }, ExpTarget { path: "ws/a/d/f/src/lib.rs", - edition: "2018", + edition: Edition::E2018, kind: "lib", }, ]; From 7d5b2e4926385bb247c4e1f2480258ca3faf4f10 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 18 Jun 2023 07:55:04 +0000 Subject: [PATCH 315/465] Make closure_saved_names_of_captured_variables a query. --- .../src/debuginfo/metadata.rs | 2 +- .../src/debuginfo/metadata/enums/mod.rs | 7 ++-- .../src/stable_hasher.rs | 14 +++++++- .../src/rmeta/decoder/cstore_impl.rs | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 2 ++ compiler/rustc_metadata/src/rmeta/mod.rs | 3 +- compiler/rustc_middle/src/arena.rs | 5 +++ compiler/rustc_middle/src/query/erase.rs | 4 +++ compiler/rustc_middle/src/query/mod.rs | 13 ++++++++ compiler/rustc_middle/src/ty/util.rs | 32 ------------------- compiler/rustc_mir_build/src/build/mod.rs | 23 +++++++++++++ compiler/rustc_mir_build/src/lib.rs | 2 ++ compiler/rustc_ty_utils/src/layout.rs | 2 +- 13 files changed, 71 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 1a8618e0c5577..4b88ab8a97a85 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1031,7 +1031,7 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>( build_field_di_node( cx, closure_or_generator_di_node, - capture_name, + capture_name.as_str(), cx.size_and_align_of(up_var_ty), layout.fields.offset(index), DIFlags::FlagZero, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index 9e0e847a15565..7a23fd31d1c6a 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -324,7 +324,7 @@ pub fn build_generator_variant_struct_type_di_node<'ll, 'tcx>( generator_type_di_node: &'ll DIType, generator_layout: &GeneratorLayout<'tcx>, state_specific_upvar_names: &IndexSlice>, - common_upvar_names: &[String], + common_upvar_names: &IndexSlice, ) -> &'ll DIType { let variant_name = GeneratorSubsts::variant_name(variant_index); let unique_type_id = UniqueTypeId::for_enum_variant_struct_type( @@ -380,12 +380,13 @@ pub fn build_generator_variant_struct_type_di_node<'ll, 'tcx>( // Fields that are common to all states let common_fields: SmallVec<_> = generator_substs .prefix_tys() + .zip(common_upvar_names) .enumerate() - .map(|(index, upvar_ty)| { + .map(|(index, (upvar_ty, upvar_name))| { build_field_di_node( cx, variant_struct_type_di_node, - &common_upvar_names[index], + upvar_name.as_str(), cx.size_and_align_of(upvar_ty), generator_type_and_layout.fields.offset(index), DIFlags::FlagZero, diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index 0c1fb7518fa3b..6d75b0fb8a0ca 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -1,6 +1,6 @@ use crate::sip128::SipHasher128; use rustc_index::bit_set::{self, BitSet}; -use rustc_index::{Idx, IndexVec}; +use rustc_index::{Idx, IndexSlice, IndexVec}; use smallvec::SmallVec; use std::fmt; use std::hash::{BuildHasher, Hash, Hasher}; @@ -597,6 +597,18 @@ where } } +impl HashStable for IndexSlice +where + T: HashStable, +{ + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for v in &self.raw { + v.hash_stable(ctx, hasher); + } + } +} + impl HashStable for IndexVec where T: HashStable, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 77f9fcfc5e6b4..848535fb39521 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -218,6 +218,7 @@ provide! { tcx, def_id, other, cdata, thir_abstract_const => { table } optimized_mir => { table } mir_for_ctfe => { table } + closure_saved_names_of_captured_variables => { table } mir_generator_witnesses => { table } promoted_mir => { table } def_span => { table } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 9c3b8780d97aa..12f3a0fc2c215 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1520,6 +1520,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { debug!("EntryBuilder::encode_mir({:?})", def_id); if encode_opt { record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id)); + record!(self.tables.closure_saved_names_of_captured_variables[def_id.to_def_id()] + <- tcx.closure_saved_names_of_captured_variables(def_id)); if tcx.sess.opts.unstable_opts.drop_tracking_mir && let DefKind::Generator = self.tcx.def_kind(def_id) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 66048f3ece747..b6b89b41a55fa 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -32,7 +32,7 @@ use rustc_span::edition::Edition; use rustc_span::hygiene::{ExpnIndex, MacroKind}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span}; -use rustc_target::abi::VariantIdx; +use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_target::spec::{PanicStrategy, TargetTriple}; use std::marker::PhantomData; @@ -416,6 +416,7 @@ define_tables! { object_lifetime_default: Table>, optimized_mir: Table>>, mir_for_ctfe: Table>>, + closure_saved_names_of_captured_variables: Table>>, mir_generator_witnesses: Table>>, promoted_mir: Table>>>, thir_abstract_const: Table>>>, diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 6c404fbb7c684..ac4cef34fdd3a 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -27,6 +27,11 @@ macro_rules! arena_types { rustc_middle::mir::Promoted, rustc_middle::mir::Body<'tcx> >, + [decode] closure_debuginfo: + rustc_index::IndexVec< + rustc_target::abi::FieldIdx, + rustc_span::symbol::Symbol, + >, [decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>, [decode] borrowck_result: rustc_middle::mir::BorrowCheckResult<'tcx>, diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index fd02a16130fc5..7d962b92caa82 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -55,6 +55,10 @@ impl EraseType for &'_ ty::List { type Result = [u8; size_of::<*const ()>()]; } +impl EraseType for &'_ rustc_index::IndexSlice { + type Result = [u8; size_of::<&'static rustc_index::IndexSlice>()]; +} + impl EraseType for Result<&'_ T, traits::query::NoSolution> { type Result = [u8; size_of::>()]; } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 132b11b29eb32..ee8f3201ddd2d 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -531,6 +531,19 @@ rustc_queries! { } } + /// Returns names of captured upvars for closures and generators. + /// + /// Here are some examples: + /// - `name__field1__field2` when the upvar is captured by value. + /// - `_ref__name__field` when the upvar is captured by reference. + /// + /// For generators this only contains upvars that are shared by all states. + query closure_saved_names_of_captured_variables(def_id: DefId) -> &'tcx IndexVec { + arena_cache + desc { |tcx| "computing debuginfo for closure `{}`", tcx.def_path_str(def_id) } + separate_provide_extern + } + query mir_generator_witnesses(key: DefId) -> &'tcx Option> { arena_cache desc { |tcx| "generator witness types for `{}`", tcx.def_path_str(key) } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index c9f69c37782e3..2e841e261fcc4 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -738,38 +738,6 @@ impl<'tcx> TyCtxt<'tcx> { if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } - /// Returns names of captured upvars for closures and generators. - /// - /// Here are some examples: - /// - `name__field1__field2` when the upvar is captured by value. - /// - `_ref__name__field` when the upvar is captured by reference. - /// - /// For generators this only contains upvars that are shared by all states. - pub fn closure_saved_names_of_captured_variables( - self, - def_id: DefId, - ) -> SmallVec<[String; 16]> { - let body = self.optimized_mir(def_id); - - body.var_debug_info - .iter() - .filter_map(|var| { - let is_ref = match var.value { - mir::VarDebugInfoContents::Place(place) - if place.local == mir::Local::new(1) => - { - // The projection is either `[.., Field, Deref]` or `[.., Field]`. It - // implies whether the variable is captured by value or by reference. - matches!(place.projection.last().unwrap(), mir::ProjectionElem::Deref) - } - _ => return None, - }; - let prefix = if is_ref { "_ref__" } else { "" }; - Some(prefix.to_owned() + var.name.as_str()) - }) - .collect() - } - // FIXME(eddyb) maybe precompute this? Right now it's computed once // per generator monomorphization, but it doesn't depend on substs. pub fn generator_layout_and_saved_local_names( diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 7f0c1d53f729a..1868496f99dc5 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -36,6 +36,29 @@ pub(crate) fn mir_built( tcx.alloc_steal_mir(mir_build(tcx, def)) } +/// Returns names of captured upvars for closures and generators. +/// +/// Here are some examples: +/// - `name__field1__field2` when the upvar is captured by value. +/// - `_ref__name__field` when the upvar is captured by reference. +/// +/// For generators this only contains upvars that are shared by all states. +pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> IndexVec { + tcx.closure_captures(def_id) + .iter() + .map(|captured_place| { + let name = captured_place.to_symbol(); + match captured_place.info.capture_kind { + ty::UpvarCapture::ByValue => name, + ty::UpvarCapture::ByRef(..) => Symbol::intern(&format!("_ref__{name}")), + } + }) + .collect() +} + /// Construct the MIR for a given `DefId`. fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { // Ensure unsafeck and abstract const building is ran before we steal the THIR. diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 0eaab9b57036c..4fdc3178c4e1f 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -33,6 +33,8 @@ pub fn provide(providers: &mut Providers) { providers.check_match = thir::pattern::check_match; providers.lit_to_const = thir::constant::lit_to_const; providers.mir_built = build::mir_built; + providers.closure_saved_names_of_captured_variables = + build::closure_saved_names_of_captured_variables; providers.thir_check_unsafety = check_unsafety::thir_check_unsafety; providers.thir_body = thir::cx::thir_body; providers.thir_tree = thir::print::thir_tree; diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 7015778e24b85..f8445c6395c6b 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -959,7 +959,7 @@ fn variant_info_for_generator<'tcx>( upvars_size = upvars_size.max(offset + field_layout.size); FieldInfo { kind: FieldKind::Upvar, - name: Symbol::intern(&name), + name: *name, offset: offset.bytes(), size: field_layout.size.bytes(), align: field_layout.align.abi.bytes(), From 3a1edd8212381d0b825a5bcb876a8f05ff3ff35a Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 18 Jun 2023 08:19:16 +0000 Subject: [PATCH 316/465] Store generator field names in GeneratorLayout. --- .../src/debuginfo/metadata/enums/cpp_like.rs | 4 +- .../src/debuginfo/metadata/enums/mod.rs | 5 +-- .../src/debuginfo/metadata/enums/native.rs | 5 +-- compiler/rustc_middle/src/mir/query.rs | 4 ++ compiler/rustc_middle/src/ty/util.rs | 44 ------------------- compiler/rustc_mir_transform/src/generator.rs | 28 +++++++++--- compiler/rustc_ty_utils/src/layout.rs | 9 ++-- 7 files changed, 36 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs index ecb0912d32881..b2765ffc93464 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs @@ -676,8 +676,7 @@ fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>( _ => unreachable!(), }; - let (generator_layout, state_specific_upvar_names) = - cx.tcx.generator_layout_and_saved_local_names(generator_def_id); + let generator_layout = cx.tcx.optimized_mir(generator_def_id).generator_layout().unwrap(); let common_upvar_names = cx.tcx.closure_saved_names_of_captured_variables(generator_def_id); let variant_range = generator_substs.variant_range(generator_def_id, cx.tcx); @@ -714,7 +713,6 @@ fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>( generator_type_and_layout, generator_type_di_node, generator_layout, - &state_specific_upvar_names, &common_upvar_names, ); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index 7a23fd31d1c6a..8746ce0c5b137 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -6,7 +6,7 @@ use rustc_hir::def::CtorKind; use rustc_index::IndexSlice; use rustc_middle::{ bug, - mir::{GeneratorLayout, GeneratorSavedLocal}, + mir::GeneratorLayout, ty::{ self, layout::{IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout}, @@ -323,7 +323,6 @@ pub fn build_generator_variant_struct_type_di_node<'ll, 'tcx>( generator_type_and_layout: TyAndLayout<'tcx>, generator_type_di_node: &'ll DIType, generator_layout: &GeneratorLayout<'tcx>, - state_specific_upvar_names: &IndexSlice>, common_upvar_names: &IndexSlice, ) -> &'ll DIType { let variant_name = GeneratorSubsts::variant_name(variant_index); @@ -357,7 +356,7 @@ pub fn build_generator_variant_struct_type_di_node<'ll, 'tcx>( .map(|field_index| { let generator_saved_local = generator_layout.variant_fields[variant_index] [FieldIdx::from_usize(field_index)]; - let field_name_maybe = state_specific_upvar_names[generator_saved_local]; + let field_name_maybe = generator_layout.field_names[generator_saved_local]; let field_name = field_name_maybe .as_ref() .map(|s| Cow::from(s.as_str())) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index 666b9762f5a76..4d1cd64865f5e 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -155,8 +155,8 @@ pub(super) fn build_generator_di_node<'ll, 'tcx>( DIFlags::FlagZero, ), |cx, generator_type_di_node| { - let (generator_layout, state_specific_upvar_names) = - cx.tcx.generator_layout_and_saved_local_names(generator_def_id); + let generator_layout = + cx.tcx.optimized_mir(generator_def_id).generator_layout().unwrap(); let Variants::Multiple { tag_encoding: TagEncoding::Direct, ref variants, .. } = generator_type_and_layout.variants else { bug!( @@ -195,7 +195,6 @@ pub(super) fn build_generator_di_node<'ll, 'tcx>( generator_type_and_layout, generator_type_di_node, generator_layout, - &state_specific_upvar_names, &common_upvar_names, ), source_info, diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index a15c419da7aca..13a1011e328ee 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -9,6 +9,7 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::BitMatrix; use rustc_index::{Idx, IndexVec}; +use rustc_span::symbol::Symbol; use rustc_span::Span; use rustc_target::abi::{FieldIdx, VariantIdx}; use smallvec::SmallVec; @@ -150,6 +151,9 @@ pub struct GeneratorLayout<'tcx> { /// The type of every local stored inside the generator. pub field_tys: IndexVec>, + /// The name for debuginfo. + pub field_names: IndexVec>, + /// Which of the above fields are in each variant. Note that one field may /// be stored in multiple variants. pub variant_fields: IndexVec>, diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 2e841e261fcc4..87a5b038a85d9 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1,7 +1,6 @@ //! Miscellaneous type-system utilities that are too small to deserve their own modules. use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use crate::mir; use crate::query::Providers; use crate::ty::layout::IntegerExt; use crate::ty::{ @@ -17,7 +16,6 @@ use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_index::bit_set::GrowableBitSet; -use rustc_index::{Idx, IndexVec}; use rustc_macros::HashStable; use rustc_session::Limit; use rustc_span::sym; @@ -738,48 +736,6 @@ impl<'tcx> TyCtxt<'tcx> { if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } - // FIXME(eddyb) maybe precompute this? Right now it's computed once - // per generator monomorphization, but it doesn't depend on substs. - pub fn generator_layout_and_saved_local_names( - self, - def_id: DefId, - ) -> ( - &'tcx ty::GeneratorLayout<'tcx>, - IndexVec>, - ) { - let tcx = self; - let body = tcx.optimized_mir(def_id); - let generator_layout = body.generator_layout().unwrap(); - let mut generator_saved_local_names = - IndexVec::from_elem(None, &generator_layout.field_tys); - - let state_arg = mir::Local::new(1); - for var in &body.var_debug_info { - let mir::VarDebugInfoContents::Place(place) = &var.value else { continue }; - if place.local != state_arg { - continue; - } - match place.projection[..] { - [ - // Deref of the `Pin<&mut Self>` state argument. - mir::ProjectionElem::Field(..), - mir::ProjectionElem::Deref, - // Field of a variant of the state. - mir::ProjectionElem::Downcast(_, variant), - mir::ProjectionElem::Field(field, _), - ] => { - let name = &mut generator_saved_local_names - [generator_layout.variant_fields[variant][field]]; - if name.is_none() { - name.replace(var.name); - } - } - _ => {} - } - } - (generator_layout, generator_saved_local_names) - } - /// Query and get an English description for the item's kind. pub fn def_descr(self, def_id: DefId) -> &'static str { self.def_kind_descr(self.def_kind(def_id), def_id) diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index fe3f8ed047a70..9706a7987d9da 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -230,7 +230,7 @@ struct TransformVisitor<'tcx> { // Mapping from Local to (type of local, generator struct index) // FIXME(eddyb) This should use `IndexVec>`. - remap: FxHashMap, VariantIdx, usize)>, + remap: FxHashMap, VariantIdx, FieldIdx)>, // A map from a suspension point in a block to the locals which have live storage at that point storage_liveness: IndexVec>>, @@ -295,11 +295,11 @@ impl<'tcx> TransformVisitor<'tcx> { } // Create a Place referencing a generator struct field - fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> { + fn make_field(&self, variant_index: VariantIdx, idx: FieldIdx, ty: Ty<'tcx>) -> Place<'tcx> { let self_place = Place::from(SELF_ARG); let base = self.tcx.mk_place_downcast_unnamed(self_place, variant_index); let mut projection = base.projection.to_vec(); - projection.push(ProjectionElem::Field(FieldIdx::new(idx), ty)); + projection.push(ProjectionElem::Field(idx, ty)); Place { local: base.local, projection: self.tcx.mk_place_elems(&projection) } } @@ -904,7 +904,7 @@ fn compute_layout<'tcx>( liveness: LivenessInfo, body: &Body<'tcx>, ) -> ( - FxHashMap, VariantIdx, usize)>, + FxHashMap, VariantIdx, FieldIdx)>, GeneratorLayout<'tcx>, IndexVec>>, ) { @@ -982,6 +982,7 @@ fn compute_layout<'tcx>( // just use the first one here. That's fine; fields do not move // around inside generators, so it doesn't matter which variant // index we access them by. + let idx = FieldIdx::from_usize(idx); remap.entry(locals[saved_local]).or_insert((tys[saved_local].ty, variant_index, idx)); } variant_fields.push(fields); @@ -990,8 +991,23 @@ fn compute_layout<'tcx>( debug!("generator variant_fields = {:?}", variant_fields); debug!("generator storage_conflicts = {:#?}", storage_conflicts); - let layout = - GeneratorLayout { field_tys: tys, variant_fields, variant_source_info, storage_conflicts }; + let mut field_names = IndexVec::from_elem(None, &tys); + for var in &body.var_debug_info { + let VarDebugInfoContents::Place(place) = &var.value else { continue }; + let Some(local) = place.as_local() else { continue }; + let Some(&(_, variant, field)) = remap.get(&local) else { continue }; + + let saved_local = variant_fields[variant][field]; + field_names.get_or_insert_with(saved_local, || var.name); + } + + let layout = GeneratorLayout { + field_tys: tys, + field_names, + variant_fields, + variant_source_info, + storage_conflicts, + }; debug!(?layout); (remap, layout, storage_liveness) diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index f8445c6395c6b..f48bba241327e 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -944,7 +944,7 @@ fn variant_info_for_generator<'tcx>( return (vec![], None); }; - let (generator, state_specific_names) = cx.tcx.generator_layout_and_saved_local_names(def_id); + let generator = cx.tcx.optimized_mir(def_id).generator_layout().unwrap(); let upvar_names = cx.tcx.closure_saved_names_of_captured_variables(def_id); let mut upvars_size = Size::ZERO; @@ -983,9 +983,10 @@ fn variant_info_for_generator<'tcx>( variant_size = variant_size.max(offset + field_layout.size); FieldInfo { kind: FieldKind::GeneratorLocal, - name: state_specific_names.get(*local).copied().flatten().unwrap_or( - Symbol::intern(&format!(".generator_field{}", local.as_usize())), - ), + name: generator.field_names[*local].unwrap_or(Symbol::intern(&format!( + ".generator_field{}", + local.as_usize() + ))), offset: offset.bytes(), size: field_layout.size.bytes(), align: field_layout.align.abi.bytes(), From 689607e7a3c601a4982fb5dbddc99ee79b08a525 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 19 Jun 2023 16:52:12 +0000 Subject: [PATCH 317/465] Remove duplicated comment. --- compiler/rustc_mir_build/src/build/mod.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 1868496f99dc5..49cbe3e2c9b4e 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -36,13 +36,6 @@ pub(crate) fn mir_built( tcx.alloc_steal_mir(mir_build(tcx, def)) } -/// Returns names of captured upvars for closures and generators. -/// -/// Here are some examples: -/// - `name__field1__field2` when the upvar is captured by value. -/// - `_ref__name__field` when the upvar is captured by reference. -/// -/// For generators this only contains upvars that are shared by all states. pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, From 86b7750ada1cc8a355dafe36f6a4bc5cebb8737e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 19 Jun 2023 16:54:28 +0000 Subject: [PATCH 318/465] Format the examples directory of cg_clif Formatting has been enforced in cg_clif's CI for a while now. --- rustfmt.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/rustfmt.toml b/rustfmt.toml index 828d492a3d19c..597ef5b90529e 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -38,6 +38,5 @@ ignore = [ # these are ignored by a standard cargo fmt run "compiler/rustc_codegen_cranelift/y.rs", # running rustfmt breaks this file - "compiler/rustc_codegen_cranelift/example", "compiler/rustc_codegen_cranelift/scripts", ] From 206b951803a5976cdb3f5fe6edb9deba65482900 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 19 Jun 2023 13:39:17 +0000 Subject: [PATCH 319/465] Fix linker failures when #[global_allocator] is used in a dependency --- compiler/rustc_codegen_ssa/src/base.rs | 18 ++++++++++++++++-- .../allocator-shim-circular-deps/Makefile | 7 +++++++ .../allocator-shim-circular-deps/main.rs | 5 +++++ .../allocator-shim-circular-deps/my_lib.rs | 10 ++++++++++ 4 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 tests/run-make/allocator-shim-circular-deps/Makefile create mode 100644 tests/run-make/allocator-shim-circular-deps/main.rs create mode 100644 tests/run-make/allocator-shim-circular-deps/my_lib.rs diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index dc4a28c866ff3..6abc56d597562 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -13,7 +13,7 @@ use crate::mir::place::PlaceRef; use crate::traits::*; use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, MemFlags, ModuleCodegen, ModuleKind}; -use rustc_ast::expand::allocator::AllocatorKind; +use rustc_ast::expand::allocator::{global_fn_name, AllocatorKind, ALLOCATOR_METHODS}; use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; @@ -921,7 +921,21 @@ impl CrateInfo { missing_weak_lang_items .iter() .map(|item| (format!("{prefix}{item}"), SymbolExportKind::Text)), - ) + ); + if tcx.allocator_kind(()).is_some() { + // At least one crate needs a global allocator. This crate may be placed + // after the crate that defines it in the linker order, in which case some + // linkers return an error. By adding the global allocator shim methods to + // the linked_symbols list, linking the generated symbols.o will ensure that + // circular dependencies involving the global allocator don't lead to linker + // errors. + linked_symbols.extend(ALLOCATOR_METHODS.iter().map(|method| { + ( + format!("{prefix}{}", global_fn_name(method.name).as_str()), + SymbolExportKind::Text, + ) + })); + } }); } diff --git a/tests/run-make/allocator-shim-circular-deps/Makefile b/tests/run-make/allocator-shim-circular-deps/Makefile new file mode 100644 index 0000000000000..4624b84680369 --- /dev/null +++ b/tests/run-make/allocator-shim-circular-deps/Makefile @@ -0,0 +1,7 @@ +# ignore-cross-compile +include ../tools.mk + +all: + rm -rf $(TMPDIR) && mkdir $(TMPDIR) + $(RUSTC) my_lib.rs + $(RUSTC) main.rs --test --extern my_lib=$(TMPDIR)/libmy_lib.rlib diff --git a/tests/run-make/allocator-shim-circular-deps/main.rs b/tests/run-make/allocator-shim-circular-deps/main.rs new file mode 100644 index 0000000000000..e317c657150a8 --- /dev/null +++ b/tests/run-make/allocator-shim-circular-deps/main.rs @@ -0,0 +1,5 @@ +#![crate_type = "bin"] + +fn main() { + my_lib::do_something(); +} diff --git a/tests/run-make/allocator-shim-circular-deps/my_lib.rs b/tests/run-make/allocator-shim-circular-deps/my_lib.rs new file mode 100644 index 0000000000000..095b103611697 --- /dev/null +++ b/tests/run-make/allocator-shim-circular-deps/my_lib.rs @@ -0,0 +1,10 @@ +#![crate_type = "lib"] + +use std::alloc::System; + +#[global_allocator] +static ALLOCATOR: System = System; + +pub fn do_something() { + format!("allocating a string!"); +} From 53003cdd86592f8a9844eef5060699e981dacf07 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Fri, 19 May 2023 10:01:49 -0700 Subject: [PATCH 320/465] Introduce `alloc::::UniqueRc` This is an `Rc` that is guaranteed to only have one strong reference. Because it is uniquely owned, it can safely implement `DerefMut`, which allows programs to have an initialization phase where structures inside the `Rc` can be mutated. The `UniqueRc` can then be converted to a regular `Rc`, allowing sharing and but read-only access. During the "initialization phase," weak references can be created, but attempting to upgrade these will fail until the `UniqueRc` has been converted to a regular `Rc`. This feature can be useful to create cyclic data structures. This API is an implementation based on the feedback provided to the ACP at https://github.com/rust-lang/libs-team/issues/90. --- library/alloc/src/rc.rs | 142 +++++++++++++++++++++++++++++++++- library/alloc/src/rc/tests.rs | 45 +++++++++++ 2 files changed, 184 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 34d3acae5464c..0f91bc8ed8023 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -258,12 +258,12 @@ use core::iter; use core::marker::{PhantomData, Unsize}; #[cfg(not(no_global_oom_handling))] use core::mem::size_of_val; -use core::mem::{self, align_of_val_raw, forget}; -use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver}; +use core::mem::{self, align_of_val_raw, forget, ManuallyDrop}; +use core::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; #[cfg(not(no_global_oom_handling))] use core::pin::Pin; -use core::ptr::{self, NonNull}; +use core::ptr::{self, drop_in_place, NonNull}; #[cfg(not(no_global_oom_handling))] use core::slice::from_raw_parts_mut; @@ -2744,3 +2744,139 @@ fn data_offset_align(align: usize) -> usize { let layout = Layout::new::>(); layout.size() + layout.padding_needed_for(align) } + +/// A uniquely owned `Rc` +/// +/// This represents an `Rc` that is known to be uniquely owned -- that is, have exactly one strong +/// reference. Multiple weak pointers can be created, but attempts to upgrade those to strong +/// references will fail unless the `UniqueRc` they point to has been converted into a regular `Rc`. +/// +/// Because they are uniquely owned, the contents of a `UniqueRc` can be freely mutated. A common +/// use case is to have an object be mutable during its initialization phase but then have it become +/// immutable and converted to a normal `Rc`. +/// +/// This can be used as a flexible way to create cyclic data structures, as in the example below. +/// +/// ``` +/// #![feature(unique_rc_arc)] +/// use std::rc::{Rc, Weak, UniqueRc}; +/// +/// struct Gadget { +/// #[allow(dead_code)] +/// me: Weak, +/// } +/// +/// fn create_gadget() -> Option> { +/// let mut rc = UniqueRc::new(Gadget { +/// me: Weak::new(), +/// }); +/// rc.me = UniqueRc::downgrade(&rc); +/// Some(UniqueRc::into_rc(rc)) +/// } +/// +/// create_gadget().unwrap(); +/// ``` +/// +/// An advantage of using `UniqueRc` over [`Rc::new_cyclic`] to build cyclic data structures is that +/// [`Rc::new_cyclic`]'s `data_fn` parameter cannot be async or return a [`Result`]. As shown in the +/// previous example, `UniqueRc` allows for more flexibility in the construction of cyclic data, +/// including fallible or async constructors. +#[unstable(feature = "unique_rc_arc", issue = "112566")] +#[derive(Debug)] +pub struct UniqueRc { + ptr: NonNull>, + phantom: PhantomData>, +} + +impl UniqueRc { + /// Creates a new `UniqueRc` + /// + /// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading + /// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`]. + /// After converting the `UniqueRc` into an [`Rc`], any weak references created beforehand will + /// point to the new [`Rc`]. + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn new(value: T) -> Self { + Self { + ptr: Box::leak(Box::new(RcBox { + strong: Cell::new(0), + // keep one weak reference so if all the weak pointers that are created are dropped + // the UniqueRc still stays valid. + weak: Cell::new(1), + value, + })) + .into(), + phantom: PhantomData, + } + } + + /// Creates a new weak reference to the `UniqueRc` + /// + /// Attempting to upgrade this weak reference will fail before the `UniqueRc` has been converted + /// to a [`Rc`] using [`UniqueRc::into_rc`]. + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn downgrade(this: &Self) -> Weak { + // SAFETY: This pointer was allocated at creation time and we guarantee that we only have + // one strong reference before converting to a regular Rc. + unsafe { + this.ptr.as_ref().inc_weak(); + } + Weak { ptr: this.ptr } + } + + /// Converts the `UniqueRc` into a regular [`Rc`] + /// + /// This consumes the `UniqueRc` and returns a regular [`Rc`] that contains the `value` that + /// is passed to `into_rc`. + /// + /// Any weak references created before this method is called can now be upgraded to strong + /// references. + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn into_rc(this: Self) -> Rc { + let mut this = ManuallyDrop::new(this); + // SAFETY: This pointer was allocated at creation time so we know it is valid. + unsafe { + // Convert our weak reference into a strong reference + this.ptr.as_mut().strong.set(1); + Rc::from_inner(this.ptr) + } + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl Deref for UniqueRc { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: This pointer was allocated at creation time so we know it is valid. + unsafe { &self.ptr.as_ref().value } + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl DerefMut for UniqueRc { + fn deref_mut(&mut self) -> &mut T { + // SAFETY: This pointer was allocated at creation time so we know it is valid. We know we + // have unique ownership and therefore it's safe to make a mutable reference because + // `UniqueRc` owns the only strong reference to itself. + unsafe { &mut (*self.ptr.as_ptr()).value } + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +unsafe impl<#[may_dangle] T> Drop for UniqueRc { + fn drop(&mut self) { + unsafe { + // destroy the contained object + drop_in_place(DerefMut::deref_mut(self)); + + // remove the implicit "strong weak" pointer now that we've destroyed the contents. + self.ptr.as_ref().dec_weak(); + + if self.ptr.as_ref().weak() == 0 { + Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); + } + } + } +} diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs index 2784108e0e635..1f221b86f120d 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloc/src/rc/tests.rs @@ -574,3 +574,48 @@ fn test_rc_cyclic_with_two_ref() { assert_eq!(Rc::strong_count(&two_refs), 3); assert_eq!(Rc::weak_count(&two_refs), 2); } + +#[test] +fn test_unique_rc_weak() { + let rc = UniqueRc::new(42); + let weak = UniqueRc::downgrade(&rc); + assert!(weak.upgrade().is_none()); + + let _rc = UniqueRc::into_rc(rc); + assert_eq!(*weak.upgrade().unwrap(), 42); +} + +#[test] +fn test_unique_rc_drop_weak() { + let rc = UniqueRc::new(42); + let weak = UniqueRc::downgrade(&rc); + mem::drop(weak); + + let rc = UniqueRc::into_rc(rc); + assert_eq!(*rc, 42); +} + +#[test] +fn test_unique_rc_drops_contents() { + let mut dropped = false; + struct DropMe<'a>(&'a mut bool); + impl Drop for DropMe<'_> { + fn drop(&mut self) { + *self.0 = true; + } + } + { + let rc = UniqueRc::new(DropMe(&mut dropped)); + drop(rc); + } + assert!(dropped); +} + +#[test] +fn test_unique_rc_weak_clone_holding_ref() { + let mut v = UniqueRc::new(0u8); + let w = UniqueRc::downgrade(&v); + let r = &mut *v; + let _ = w.clone(); // touch weak count + *r = 123; +} From 1a94b060894017055a3986fdb5603ffbbe8b9c89 Mon Sep 17 00:00:00 2001 From: "Alexis (Poliorcetics) Bourget" Date: Fri, 16 Jun 2023 23:18:57 +0200 Subject: [PATCH 321/465] rustdoc: js: change color and reduce size of typename in search result --- src/librustdoc/html/static/css/rustdoc.css | 4 ++++ src/librustdoc/html/static/js/search.js | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index b487cfa5c2553..21c1eb631e07b 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -890,6 +890,10 @@ so that we can apply CSS-filters to change the arrow color in themes */ .search-results .result-name .grey { color: var(--search-results-grey-color); } +.search-results .result-name .typename { + color: var(--search-results-grey-color); + font-size: 0.875rem; +} .popover { position: absolute; diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 3059dac820723..452348dc86507 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2024,7 +2024,9 @@ function initSearch(rawSearchIndex) { resultName.insertAdjacentHTML( "beforeend", - `${typeName} ${item.displayPath}${name}`); + `${typeName}` + + ` ${item.displayPath}${name}` + ); link.appendChild(resultName); const description = document.createElement("div"); From dd620aa73aac7dc219774c8e09fed13853d8af58 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 19 Jun 2023 19:57:44 +0000 Subject: [PATCH 322/465] Don't ICE on unnormalized struct tail in layout computation --- compiler/rustc_middle/src/ty/layout.rs | 8 ++++++- compiler/rustc_ty_utils/src/layout.rs | 20 +++++++++++------ .../issue-112505-overflow.stderr | 4 ++-- tests/ui/const-generics/transmute-fail.stderr | 4 ++-- .../cannot-transmute-unnormalizable-type.rs | 22 +++++++++++++++++++ ...annot-transmute-unnormalizable-type.stderr | 19 ++++++++++++++++ 6 files changed, 65 insertions(+), 12 deletions(-) create mode 100644 tests/ui/layout/cannot-transmute-unnormalizable-type.rs create mode 100644 tests/ui/layout/cannot-transmute-unnormalizable-type.stderr diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index c5a306fdf1f9a..c1d6856d33c92 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -318,7 +318,13 @@ impl<'tcx> SizeSkeleton<'tcx> { Ok(layout) => { return Ok(SizeSkeleton::Known(layout.size)); } - Err(err) => err, + Err(err @ LayoutError::Unknown(_)) => err, + // We can't extract SizeSkeleton info from other layout errors + Err( + e @ LayoutError::Cycle + | e @ LayoutError::SizeOverflow(_) + | e @ LayoutError::NormalizationFailure(..), + ) => return Err(e), }; match *ty.kind() { diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 7015778e24b85..f35f501b902da 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -145,17 +145,20 @@ fn layout_of_uncached<'tcx>( return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr))); } - let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env); - let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() // Projection eagerly bails out when the pointee references errors, // fall back to structurally deducing metadata. && !pointee.references_error() { - let metadata_ty = tcx.normalize_erasing_regions( + let pointee_metadata = tcx.mk_projection(metadata_def_id, [pointee]); + let metadata_ty = match tcx.try_normalize_erasing_regions( param_env, - tcx.mk_projection(metadata_def_id, [pointee]), - ); + pointee_metadata, + ) { + Ok(metadata_ty) => metadata_ty, + Err(err) => return Err(LayoutError::NormalizationFailure(pointee, err)), + }; + let metadata_layout = cx.layout_of(metadata_ty)?; // If the metadata is a 1-zst, then the pointer is thin. if metadata_layout.is_zst() && metadata_layout.align.abi.bytes() == 1 { @@ -163,10 +166,13 @@ fn layout_of_uncached<'tcx>( } let Abi::Scalar(metadata) = metadata_layout.abi else { - return Err(LayoutError::Unknown(unsized_part)); + return Err(LayoutError::Unknown(pointee)); }; + metadata } else { + let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env); + match unsized_part.kind() { ty::Foreign(..) => { return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr))); @@ -178,7 +184,7 @@ fn layout_of_uncached<'tcx>( vtable } _ => { - return Err(LayoutError::Unknown(unsized_part)); + return Err(LayoutError::Unknown(pointee)); } } }; diff --git a/tests/ui/const-generics/issue-112505-overflow.stderr b/tests/ui/const-generics/issue-112505-overflow.stderr index 0432f2fa8be5d..bd8a4feeff5e7 100644 --- a/tests/ui/const-generics/issue-112505-overflow.stderr +++ b/tests/ui/const-generics/issue-112505-overflow.stderr @@ -4,8 +4,8 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^ | - = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type `[[[u32; 8888888]; 9999999]; 777777777]` are too big for the current architecture) - = note: target type: `[[[u32; 9999999]; 777777777]; 239]` (59484438436515561504 bits) + = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type `[[u32; 8888888]; 9999999]` are too big for the current architecture) + = note: target type: `[[[u32; 9999999]; 777777777]; 239]` (values of the type `[[u32; 9999999]; 777777777]` are too big for the current architecture) error: aborting due to previous error diff --git a/tests/ui/const-generics/transmute-fail.stderr b/tests/ui/const-generics/transmute-fail.stderr index 3d1197afd0f79..9e308620a9c2e 100644 --- a/tests/ui/const-generics/transmute-fail.stderr +++ b/tests/ui/const-generics/transmute-fail.stderr @@ -43,8 +43,8 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ | - = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type `[[[u32; 8888888]; 9999999]; 777777777]` are too big for the current architecture) - = note: target type: `[[[u32; 9999999]; 777777777]; 8888888]` (values of the type `[[[u32; 9999999]; 777777777]; 8888888]` are too big for the current architecture) + = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type `[[u32; 8888888]; 9999999]` are too big for the current architecture) + = note: target type: `[[[u32; 9999999]; 777777777]; 8888888]` (values of the type `[[u32; 9999999]; 777777777]` are too big for the current architecture) error: aborting due to 6 previous errors diff --git a/tests/ui/layout/cannot-transmute-unnormalizable-type.rs b/tests/ui/layout/cannot-transmute-unnormalizable-type.rs new file mode 100644 index 0000000000000..d2b6e1d8eba66 --- /dev/null +++ b/tests/ui/layout/cannot-transmute-unnormalizable-type.rs @@ -0,0 +1,22 @@ +trait Trait { + type RefTarget; +} + +impl Trait for () +where + Missing: Trait, + //~^ ERROR cannot find type `Missing` in this scope +{ + type RefTarget = (); +} + +struct Other { + data: <() as Trait>::RefTarget, +} + +fn main() { + unsafe { + std::mem::transmute::, Option<&Other>>(None); + //~^ ERROR cannot transmute between types of different sizes, or dependently-sized types + } +} diff --git a/tests/ui/layout/cannot-transmute-unnormalizable-type.stderr b/tests/ui/layout/cannot-transmute-unnormalizable-type.stderr new file mode 100644 index 0000000000000..3cfa09ef9d499 --- /dev/null +++ b/tests/ui/layout/cannot-transmute-unnormalizable-type.stderr @@ -0,0 +1,19 @@ +error[E0412]: cannot find type `Missing` in this scope + --> $DIR/cannot-transmute-unnormalizable-type.rs:7:5 + | +LL | Missing: Trait, + | ^^^^^^^ not found in this scope + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/cannot-transmute-unnormalizable-type.rs:19:9 + | +LL | std::mem::transmute::, Option<&Other>>(None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `Option<()>` (8 bits) + = note: target type: `Option<&Other>` (unable to determine layout for `Other` because `::Metadata` cannot be normalized) + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0412, E0512. +For more information about an error, try `rustc --explain E0412`. From 32f83e18ab1891482873eea6e4337d610393c0a5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 19 Jun 2023 20:00:37 +0000 Subject: [PATCH 323/465] Better error message --- compiler/rustc_ty_utils/src/layout.rs | 17 ++++++++++++++++- .../cannot-transmute-unnormalizable-type.stderr | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index f35f501b902da..fde64cb3ee7d8 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -156,7 +156,22 @@ fn layout_of_uncached<'tcx>( pointee_metadata, ) { Ok(metadata_ty) => metadata_ty, - Err(err) => return Err(LayoutError::NormalizationFailure(pointee, err)), + Err(mut err) => { + // Usually `::Metadata` can't be normalized because + // its struct tail cannot be normalized either, so try to get a + // more descriptive layout error here, which will lead to less confusing + // diagnostics. + match tcx.try_normalize_erasing_regions( + param_env, + tcx.struct_tail_without_normalization(pointee), + ) { + Ok(_) => {}, + Err(better_err) => { + err = better_err; + } + } + return Err(LayoutError::NormalizationFailure(pointee, err)); + }, }; let metadata_layout = cx.layout_of(metadata_ty)?; diff --git a/tests/ui/layout/cannot-transmute-unnormalizable-type.stderr b/tests/ui/layout/cannot-transmute-unnormalizable-type.stderr index 3cfa09ef9d499..dd5119318ff4b 100644 --- a/tests/ui/layout/cannot-transmute-unnormalizable-type.stderr +++ b/tests/ui/layout/cannot-transmute-unnormalizable-type.stderr @@ -11,7 +11,7 @@ LL | std::mem::transmute::, Option<&Other>>(None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `Option<()>` (8 bits) - = note: target type: `Option<&Other>` (unable to determine layout for `Other` because `::Metadata` cannot be normalized) + = note: target type: `Option<&Other>` (unable to determine layout for `Other` because `<() as Trait>::RefTarget` cannot be normalized) error: aborting due to 2 previous errors From f78096f57e5ac15b6b4fdcb72e0aadc5e9607c59 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 19 Jun 2023 20:44:01 -0400 Subject: [PATCH 324/465] Update Cargo.lock --- compiler/rustc_codegen_gcc/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock index 0f2e152f8ce56..1c8754bf675ea 100644 --- a/compiler/rustc_codegen_gcc/Cargo.lock +++ b/compiler/rustc_codegen_gcc/Cargo.lock @@ -35,7 +35,7 @@ dependencies = [ [[package]] name = "gccjit" version = "1.0.0" -source = "git+https://github.com/antoyo/gccjit.rs#fe242b7eb26980e6c78859d51c8d4cc1e43381a3" +source = "git+https://github.com/antoyo/gccjit.rs#d6e52626cfc6f487094a5d5ac66302baf3439984" dependencies = [ "gccjit_sys", ] @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "gccjit_sys" version = "0.0.1" -source = "git+https://github.com/antoyo/gccjit.rs#fe242b7eb26980e6c78859d51c8d4cc1e43381a3" +source = "git+https://github.com/antoyo/gccjit.rs#d6e52626cfc6f487094a5d5ac66302baf3439984" dependencies = [ "libc", ] From f4201ef2cb89c28bcdb82cab292720eb66b75695 Mon Sep 17 00:00:00 2001 From: Lukasz Anforowicz Date: Mon, 10 Oct 2022 16:33:31 +0000 Subject: [PATCH 325/465] Handling of numbered markdown lists. Fixes issue #5416 --- src/comment.rs | 174 +++++++++++++++++++++--- tests/source/itemized-blocks/no_wrap.rs | 36 ++++- tests/source/itemized-blocks/wrap.rs | 36 ++++- tests/target/itemized-blocks/no_wrap.rs | 36 ++++- tests/target/itemized-blocks/wrap.rs | 62 ++++++++- 5 files changed, 319 insertions(+), 25 deletions(-) diff --git a/src/comment.rs b/src/comment.rs index bc0e8774f4949..85918ecc11645 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -432,12 +432,18 @@ impl CodeBlockAttribute { /// Block that is formatted as an item. /// -/// An item starts with either a star `*` a dash `-` a greater-than `>` or a plus '+'. +/// An item starts with either a star `*`, a dash `-`, a greater-than `>`, a plus '+', or a number +/// `12.` or `34)` (with at most 2 digits). An item represents CommonMark's ["list +/// items"](https://spec.commonmark.org/0.30/#list-items) and/or ["block +/// quotes"](https://spec.commonmark.org/0.30/#block-quotes), but note that only a subset of +/// CommonMark is recognized - see the doc comment of [`ItemizedBlock::get_marker_length`] for more +/// details. +/// /// Different level of indentation are handled by shrinking the shape accordingly. struct ItemizedBlock { /// the lines that are identified as part of an itemized block lines: Vec, - /// the number of characters (typically whitespaces) up to the item sigil + /// the number of characters (typically whitespaces) up to the item marker indent: usize, /// the string that marks the start of an item opener: String, @@ -446,37 +452,70 @@ struct ItemizedBlock { } impl ItemizedBlock { - /// Returns `true` if the line is formatted as an item - fn is_itemized_line(line: &str) -> bool { - let trimmed = line.trim_start(); + /// Checks whether the `trimmed` line includes an item marker. Returns `None` if there is no + /// marker. Returns the length of the marker (in bytes) if one is present. Note that the length + /// includes the whitespace that follows the marker, for example the marker in `"* list item"` + /// has the length of 2. + /// + /// This function recognizes item markers that correspond to CommonMark's + /// ["bullet list marker"](https://spec.commonmark.org/0.30/#bullet-list-marker), + /// ["block quote marker"](https://spec.commonmark.org/0.30/#block-quote-marker), and/or + /// ["ordered list marker"](https://spec.commonmark.org/0.30/#ordered-list-marker). + /// + /// Compared to CommonMark specification, the number of digits that are allowed in an ["ordered + /// list marker"](https://spec.commonmark.org/0.30/#ordered-list-marker) is more limited (to at + /// most 2 digits). Limiting the length of the marker helps reduce the risk of recognizing + /// arbitrary numbers as markers. See also + /// which gives the + /// following example where a number (i.e. "1868") doesn't signify an ordered list: + /// ```md + /// The Captain died in + /// 1868. He wes buried in... + /// ``` + fn get_marker_length(trimmed: &str) -> Option { + // https://spec.commonmark.org/0.30/#bullet-list-marker or + // https://spec.commonmark.org/0.30/#block-quote-marker let itemized_start = ["* ", "- ", "> ", "+ "]; - itemized_start.iter().any(|s| trimmed.starts_with(s)) + if itemized_start.iter().any(|s| trimmed.starts_with(s)) { + return Some(2); // All items in `itemized_start` have length 2. + } + + // https://spec.commonmark.org/0.30/#ordered-list-marker, where at most 2 digits are + // allowed. + for suffix in [". ", ") "] { + if let Some((prefix, _)) = trimmed.split_once(suffix) { + if prefix.len() <= 2 && prefix.chars().all(|c| char::is_ascii_digit(&c)) { + return Some(prefix.len() + suffix.len()); + } + } + } + + None // No markers found. } - /// Creates a new ItemizedBlock described with the given line. - /// The `is_itemized_line` needs to be called first. - fn new(line: &str) -> ItemizedBlock { - let space_to_sigil = line.chars().take_while(|c| c.is_whitespace()).count(); - // +2 = '* ', which will add the appropriate amount of whitespace to keep itemized - // content formatted correctly. - let mut indent = space_to_sigil + 2; + /// Creates a new `ItemizedBlock` described with the given `line`. + /// Returns `None` if `line` doesn't start an item. + fn new(line: &str) -> Option { + let marker_length = ItemizedBlock::get_marker_length(line.trim_start())?; + let space_to_marker = line.chars().take_while(|c| c.is_whitespace()).count(); + let mut indent = space_to_marker + marker_length; let mut line_start = " ".repeat(indent); // Markdown blockquote start with a "> " if line.trim_start().starts_with(">") { // remove the original +2 indent because there might be multiple nested block quotes // and it's easier to reason about the final indent by just taking the length - // of th new line_start. We update the indent because it effects the max width + // of the new line_start. We update the indent because it effects the max width // of each formatted line. line_start = itemized_block_quote_start(line, line_start, 2); indent = line_start.len(); } - ItemizedBlock { + Some(ItemizedBlock { lines: vec![line[indent..].to_string()], indent, opener: line[..indent].to_string(), line_start, - } + }) } /// Returns a `StringFormat` used for formatting the content of an item. @@ -495,7 +534,7 @@ impl ItemizedBlock { /// Returns `true` if the line is part of the current itemized block. /// If it is, then it is added to the internal lines list. fn add_line(&mut self, line: &str) -> bool { - if !ItemizedBlock::is_itemized_line(line) + if ItemizedBlock::get_marker_length(line.trim_start()).is_none() && self.indent <= line.chars().take_while(|c| c.is_whitespace()).count() { self.lines.push(line.to_string()); @@ -766,10 +805,11 @@ impl<'a> CommentRewrite<'a> { self.item_block = None; if let Some(stripped) = line.strip_prefix("```") { self.code_block_attr = Some(CodeBlockAttribute::new(stripped)) - } else if self.fmt.config.wrap_comments() && ItemizedBlock::is_itemized_line(line) { - let ib = ItemizedBlock::new(line); - self.item_block = Some(ib); - return false; + } else if self.fmt.config.wrap_comments() { + if let Some(ib) = ItemizedBlock::new(line) { + self.item_block = Some(ib); + return false; + } } if self.result == self.opener { @@ -2020,4 +2060,96 @@ fn main() { "#; assert_eq!(s, filter_normal_code(s_with_comment)); } + + #[test] + fn test_itemized_block_first_line_handling() { + fn run_test( + test_input: &str, + expected_line: &str, + expected_indent: usize, + expected_opener: &str, + expected_line_start: &str, + ) { + let block = ItemizedBlock::new(test_input).unwrap(); + assert_eq!(1, block.lines.len(), "test_input: {:?}", test_input); + assert_eq!( + expected_line, &block.lines[0], + "test_input: {:?}", + test_input + ); + assert_eq!( + expected_indent, block.indent, + "test_input: {:?}", + test_input + ); + assert_eq!( + expected_opener, &block.opener, + "test_input: {:?}", + test_input + ); + assert_eq!( + expected_line_start, &block.line_start, + "test_input: {:?}", + test_input + ); + } + + run_test("- foo", "foo", 2, "- ", " "); + run_test("* foo", "foo", 2, "* ", " "); + run_test("> foo", "foo", 2, "> ", "> "); + + run_test("1. foo", "foo", 3, "1. ", " "); + run_test("12. foo", "foo", 4, "12. ", " "); + run_test("1) foo", "foo", 3, "1) ", " "); + run_test("12) foo", "foo", 4, "12) ", " "); + + run_test(" - foo", "foo", 6, " - ", " "); + + // https://spec.commonmark.org/0.30 says: "A start number may begin with 0s": + run_test("0. foo", "foo", 3, "0. ", " "); + run_test("01. foo", "foo", 4, "01. ", " "); + } + + #[test] + fn test_itemized_block_nonobvious_markers_are_rejected() { + let test_inputs = vec![ + // Non-numeric item markers (e.g. `a.` or `iv.`) are not allowed by + // https://spec.commonmark.org/0.30/#ordered-list-marker. We also note that allowing + // them would risk misidentifying regular words as item markers. See also the + // discussion in https://talk.commonmark.org/t/blank-lines-before-lists-revisited/1990 + "word. rest of the paragraph.", + "a. maybe this is a list item? maybe not?", + "iv. maybe this is a list item? maybe not?", + // Numbers with 3 or more digits are not recognized as item markers, to avoid + // formatting the following example as a list: + // + // ``` + // The Captain died in + // 1868. He was buried in... + // ``` + "123. only 2-digit numbers are recognized as item markers.", + // Parens: + "123) giving some coverage to parens as well.", + "a) giving some coverage to parens as well.", + // https://spec.commonmark.org/0.30 says that "at least one space or tab is needed + // between the list marker and any following content": + "1.Not a list item.", + "1.2.3. Not a list item.", + "1)Not a list item.", + "-Not a list item.", + "+Not a list item.", + "+1 not a list item.", + // https://spec.commonmark.org/0.30 says: "A start number may not be negative": + "-1. Not a list item.", + "-1 Not a list item.", + ]; + for line in test_inputs.iter() { + let maybe_block = ItemizedBlock::new(line); + assert!( + maybe_block.is_none(), + "The following line shouldn't be classified as a list item: {}", + line + ); + } + } } diff --git a/tests/source/itemized-blocks/no_wrap.rs b/tests/source/itemized-blocks/no_wrap.rs index a7b6a10a01050..e5699e766848a 100644 --- a/tests/source/itemized-blocks/no_wrap.rs +++ b/tests/source/itemized-blocks/no_wrap.rs @@ -1,7 +1,7 @@ // rustfmt-normalize_comments: true // rustfmt-format_code_in_doc_comments: true -//! This is a list: +//! This is an itemized markdown list (see also issue #3224): //! * Outer //! * Outer //! * Inner @@ -13,6 +13,40 @@ //! - when the log level is info, the level name is green and the rest of the line is white //! - when the log level is debug, the whole line is white //! - when the log level is trace, the whole line is gray ("bright black") +//! +//! This is a numbered markdown list (see also issue #5416): +//! 1. Long long long long long long long long long long long long long long long long long line +//! 2. Another very long long long long long long long long long long long long long long long line +//! 3. Nested list +//! 1. Long long long long long long long long long long long long long long long long line +//! 2. Another very long long long long long long long long long long long long long long line +//! 4. Last item +//! +//! Using the ')' instead of '.' character after the number: +//! 1) Long long long long long long long long long long long long long long long long long line +//! 2) Another very long long long long long long long long long long long long long long long line +//! +//! Deep list that mixes various bullet and number formats: +//! 1. First level with a long long long long long long long long long long long long long long +//! long long long line +//! 2. First level with another very long long long long long long long long long long long long +//! long long long line +//! * Second level with a long long long long long long long long long long long long long +//! long long long line +//! * Second level with another very long long long long long long long long long long long +//! long long long line +//! 1) Third level with a long long long long long long long long long long long long long +//! long long long line +//! 2) Third level with another very long long long long long long long long long long +//! long long long long line +//! - Forth level with a long long long long long long long long long long long long +//! long long long long line +//! - Forth level with another very long long long long long long long long long long +//! long long long long line +//! 3) One more item at the third level +//! 4) Last item of the third level +//! * Last item of second level +//! 3. Last item of first level /// All the parameters ***except for `from_theater`*** should be inserted as sent by the remote /// theater, i.e., as passed to [`Theater::send`] on the remote actor: diff --git a/tests/source/itemized-blocks/wrap.rs b/tests/source/itemized-blocks/wrap.rs index 955cc698b79f2..768461a43f956 100644 --- a/tests/source/itemized-blocks/wrap.rs +++ b/tests/source/itemized-blocks/wrap.rs @@ -2,7 +2,7 @@ // rustfmt-format_code_in_doc_comments: true // rustfmt-max_width: 50 -//! This is a list: +//! This is an itemized markdown list (see also issue #3224): //! * Outer //! * Outer //! * Inner @@ -14,6 +14,40 @@ //! - when the log level is info, the level name is green and the rest of the line is white //! - when the log level is debug, the whole line is white //! - when the log level is trace, the whole line is gray ("bright black") +//! +//! This is a numbered markdown list (see also issue #5416): +//! 1. Long long long long long long long long long long long long long long long long long line +//! 2. Another very long long long long long long long long long long long long long long long line +//! 3. Nested list +//! 1. Long long long long long long long long long long long long long long long long line +//! 2. Another very long long long long long long long long long long long long long long line +//! 4. Last item +//! +//! Using the ')' instead of '.' character after the number: +//! 1) Long long long long long long long long long long long long long long long long long line +//! 2) Another very long long long long long long long long long long long long long long long line +//! +//! Deep list that mixes various bullet and number formats: +//! 1. First level with a long long long long long long long long long long long long long long +//! long long long line +//! 2. First level with another very long long long long long long long long long long long long +//! long long long line +//! * Second level with a long long long long long long long long long long long long long +//! long long long line +//! * Second level with another very long long long long long long long long long long long +//! long long long line +//! 1) Third level with a long long long long long long long long long long long long long +//! long long long line +//! 2) Third level with another very long long long long long long long long long long +//! long long long long line +//! - Forth level with a long long long long long long long long long long long long +//! long long long long line +//! - Forth level with another very long long long long long long long long long long +//! long long long long line +//! 3) One more item at the third level +//! 4) Last item of the third level +//! * Last item of second level +//! 3. Last item of first level // This example shows how to configure fern to output really nicely colored logs // - when the log level is error, the whole line is red diff --git a/tests/target/itemized-blocks/no_wrap.rs b/tests/target/itemized-blocks/no_wrap.rs index de88563827263..86818b4474591 100644 --- a/tests/target/itemized-blocks/no_wrap.rs +++ b/tests/target/itemized-blocks/no_wrap.rs @@ -1,7 +1,7 @@ // rustfmt-normalize_comments: true // rustfmt-format_code_in_doc_comments: true -//! This is a list: +//! This is an itemized markdown list (see also issue #3224): //! * Outer //! * Outer //! * Inner @@ -13,6 +13,40 @@ //! - when the log level is info, the level name is green and the rest of the line is white //! - when the log level is debug, the whole line is white //! - when the log level is trace, the whole line is gray ("bright black") +//! +//! This is a numbered markdown list (see also issue #5416): +//! 1. Long long long long long long long long long long long long long long long long long line +//! 2. Another very long long long long long long long long long long long long long long long line +//! 3. Nested list +//! 1. Long long long long long long long long long long long long long long long long line +//! 2. Another very long long long long long long long long long long long long long long line +//! 4. Last item +//! +//! Using the ')' instead of '.' character after the number: +//! 1) Long long long long long long long long long long long long long long long long long line +//! 2) Another very long long long long long long long long long long long long long long long line +//! +//! Deep list that mixes various bullet and number formats: +//! 1. First level with a long long long long long long long long long long long long long long +//! long long long line +//! 2. First level with another very long long long long long long long long long long long long +//! long long long line +//! * Second level with a long long long long long long long long long long long long long +//! long long long line +//! * Second level with another very long long long long long long long long long long long +//! long long long line +//! 1) Third level with a long long long long long long long long long long long long long +//! long long long line +//! 2) Third level with another very long long long long long long long long long long +//! long long long long line +//! - Forth level with a long long long long long long long long long long long long +//! long long long long line +//! - Forth level with another very long long long long long long long long long long +//! long long long long line +//! 3) One more item at the third level +//! 4) Last item of the third level +//! * Last item of second level +//! 3. Last item of first level /// All the parameters ***except for `from_theater`*** should be inserted as sent by the remote /// theater, i.e., as passed to [`Theater::send`] on the remote actor: diff --git a/tests/target/itemized-blocks/wrap.rs b/tests/target/itemized-blocks/wrap.rs index a4907303c9e1b..4826590ea59dd 100644 --- a/tests/target/itemized-blocks/wrap.rs +++ b/tests/target/itemized-blocks/wrap.rs @@ -2,7 +2,8 @@ // rustfmt-format_code_in_doc_comments: true // rustfmt-max_width: 50 -//! This is a list: +//! This is an itemized markdown list (see also +//! issue #3224): //! * Outer //! * Outer //! * Inner @@ -23,6 +24,65 @@ //! is white //! - when the log level is trace, the whole line //! is gray ("bright black") +//! +//! This is a numbered markdown list (see also +//! issue #5416): +//! 1. Long long long long long long long long +//! long long long long long long long long +//! long line +//! 2. Another very long long long long long long +//! long long long long long long long long +//! long line +//! 3. Nested list +//! 1. Long long long long long long long long +//! long long long long long long long long +//! line +//! 2. Another very long long long long long +//! long long long long long long long long +//! long line +//! 4. Last item +//! +//! Using the ')' instead of '.' character after +//! the number: +//! 1) Long long long long long long long long +//! long long long long long long long long +//! long line +//! 2) Another very long long long long long long +//! long long long long long long long long +//! long line +//! +//! Deep list that mixes various bullet and number +//! formats: +//! 1. First level with a long long long long long +//! long long long long long long long long +//! long long long long line +//! 2. First level with another very long long +//! long long long long long long long long +//! long long long long long line +//! * Second level with a long long long long +//! long long long long long long long long +//! long long long long line +//! * Second level with another very long long +//! long long long long long long long long +//! long long long long line +//! 1) Third level with a long long long +//! long long long long long long long +//! long long long long long long line +//! 2) Third level with another very long +//! long long long long long long long +//! long long long long long long line +//! - Forth level with a long long +//! long long long long long long +//! long long long long long long +//! long long line +//! - Forth level with another very +//! long long long long long long +//! long long long long long long +//! long long line +//! 3) One more item at the third level +//! 4) Last item of the third level +//! * Last item of second level +//! 3. Last item of first level // This example shows how to configure fern to // output really nicely colored logs From 0b17d7ea4605fcd3675c80069e0b5e82c4332b05 Mon Sep 17 00:00:00 2001 From: Caleb Cartwright Date: Mon, 19 Jun 2023 21:29:15 -0500 Subject: [PATCH 326/465] chore: address merge and bump toolchain --- config_proc_macro/src/attrs.rs | 7 ------- rust-toolchain | 2 +- src/macros.rs | 2 +- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/config_proc_macro/src/attrs.rs b/config_proc_macro/src/attrs.rs index 2c01b9a1321e9..d8de9aae088d7 100644 --- a/config_proc_macro/src/attrs.rs +++ b/config_proc_macro/src/attrs.rs @@ -64,13 +64,6 @@ fn is_attr_path(attr: &syn::Attribute, name: &str) -> bool { } } -fn is_attr_path(attr: &syn::Attribute, name: &str) -> bool { - attr.parse_meta().ok().map_or(false, |meta| match meta { - syn::Meta::Path(path) if path.is_ident(name) => true, - _ => false, - }) -} - fn get_name_value_str_lit(attr: &syn::Attribute, name: &str) -> Option { match &attr.meta { syn::Meta::NameValue(syn::MetaNameValue { diff --git a/rust-toolchain b/rust-toolchain index 22283b3d62002..03b909cd80c79 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-01-24" +channel = "nightly-2023-06-19" components = ["llvm-tools", "rustc-dev"] diff --git a/src/macros.rs b/src/macros.rs index 9f4beae735054..e9a298a27693d 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1124,7 +1124,7 @@ struct MacroParser { } impl MacroParser { - const fn new(toks: Cursor) -> Self { + const fn new(toks: TokenTreeCursor) -> Self { Self { toks } } From 32b98ea2a9db0337acd8cec62925e2e287f54032 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 19 Jun 2023 20:22:34 -0700 Subject: [PATCH 327/465] Disable feature(unboxed_closures, fn_traits) in weird-exprs One shouldn't need a nightly compiler in order to ~~have fun~~ call a function many times. --- tests/ui/weird-exprs.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/ui/weird-exprs.rs b/tests/ui/weird-exprs.rs index 59b4bb8ef8598..892b281357f2e 100644 --- a/tests/ui/weird-exprs.rs +++ b/tests/ui/weird-exprs.rs @@ -1,7 +1,6 @@ // run-pass #![feature(generators)] -#![feature(unboxed_closures, fn_traits)] #![allow(non_camel_case_types)] #![allow(dead_code)] @@ -17,6 +16,7 @@ extern crate core; use std::cell::Cell; use std::mem::swap; +use std::ops::Deref; // Just a grab bag of stuff that you wouldn't want to actually write. @@ -183,10 +183,10 @@ fn 𝚌𝚘𝚗𝚝𝚒𝚗𝚞𝚎() { fn function() { struct foo; - impl FnOnce<()> for foo { - type Output = foo; - extern "rust-call" fn call_once(self, _args: ()) -> Self::Output { - foo + impl Deref for foo { + type Target = fn() -> Self; + fn deref(&self) -> &Self::Target { + &((|| foo) as _) } } let foo = foo () ()() ()()() ()()()() ()()()()(); From 3f7c366fc0464e01ddcaefbd70647cb3da4202be Mon Sep 17 00:00:00 2001 From: Caleb Cartwright Date: Mon, 19 Jun 2023 22:23:11 -0500 Subject: [PATCH 328/465] chore: release v1.5.3 --- CHANGELOG.md | 40 ++++++++++------------------------------ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 12 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd7d9f8d70b6a..0d4e057223d44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,14 @@ ## [Unreleased] +## [1.5.3] 2023-06-20 + ### Fixed - When formatting doc comments with `wrap_comments = true` rustfmt will no longer wrap markdown tables [#4210](https://github.com/rust-lang/rustfmt/issues/4210) -- rustfmt will no longer use shorthand initialization when rewriting a tuple struct even when `use_field_init_shorthand = true` as this lead to code that could no longer compile. +- Properly handle wrapping comments that include a numbered list in markdown [#5416](https://github.com/rust-lang/rustfmt/issues/5416) +- Properly handle markdown sublists that utilize a `+` [#4041](https://github.com/rust-lang/rustfmt/issues/4210) +- rustfmt will no longer use shorthand initialization when rewriting a tuple struct even when `use_field_init_shorthand = true` as this leads to code that could no longer compile. Take the following struct as an example `struct MyStruct(u64);`. rustfmt will no longer format `MyStruct { 0: 0 }` as `MyStruct { 0 }` [#5488](https://github.com/rust-lang/rustfmt/issues/5488) - rustfmt no longer panics when formatting an empty code block in a doc comment with `format_code_in_doc_comments = true` [#5234](https://github.com/rust-lang/rustfmt/issues/5234). For example: ```rust @@ -14,7 +18,7 @@ /// ``` fn main() {} ``` -- Use the correct span when rewriting struct generics. This prevents rustfmt from incorrectly duplicating where clause bounds when using const expression in where clause bounds with feature `#![feature(generic_const_exprs)]` [#5691](https://github.com/rust-lang/rustfmt/issues/5691). e.g.: +- rustfmt no longer incorrectly duplicates the where clause bounds when using const expression in where clause bounds with feature `#![feature(generic_const_exprs)]` [#5691](https://github.com/rust-lang/rustfmt/issues/5691). e.g.: ```rust struct S where @@ -22,6 +26,9 @@ // code ... } ``` +- Prevent ICE when parsing invalid attributes in `cfg_if!` macros [#5728](https://github.com/rust-lang/rustfmt/issues/5728), [#5729](https://github.com/rust-lang/rustfmt/issues/5729) +- rustfmt no longer loses comments placed between a doc comment and generic params [#5320](https://github.com/rust-lang/rustfmt/issues/5320) +- Handle explicit discriminants in enums with comments present [#5686](https://github.com/rust-lang/rustfmt/issues/5686) ### Changed @@ -34,34 +41,7 @@ ### Misc -- Prevent ICE when parsing invalid attributes in `cfg_if!` macros [#5728](https://github.com/rust-lang/rustfmt/issues/5728) - - -## [1.5.2] 2023-01-24 - -### Fixed - -- Resolve issue when comments are found within const generic defaults in unit structs [#5668](https://github.com/rust-lang/rustfmt/issues/5668) -- Resolve issue when block comments are found within trait generics [#5358](https://github.com/rust-lang/rustfmt/issues/5358) -- Correctly handle alignment of comments containing unicode characters [#5504](https://github.com/rust-lang/rustfmt/issues/5504) -- Properly indent a single generic bound that requires being written across multiple lines [#4689](https://github.com/rust-lang/rustfmt/issues/4689) (n.b. this change is version gated and will only appear when the `version` configuration option is set to `Two`) - -### Changed - -- Renamed `fn_args_layout` configuration option to `fn_params_layout` [#4149](https://github.com/rust-lang/rustfmt/issues/4149). Note that `fn_args_layout` has only been soft deprecated: `fn_args_layout` will continue to work without issue, but rustfmt will display a warning to encourage users to switch to the new name - -### Added - -- New configuration option (`skip_macro_invocations`)[https://rust-lang.github.io/rustfmt/?version=master&search=#skip_macro_invocations] [#5347](https://github.com/rust-lang/rustfmt/pull/5347) that can be used to globally define a single enumerated list of macro calls that rustfmt should skip formatting. rustfmt [currently also supports this via a custom tool attribute](https://github.com/rust-lang/rustfmt#tips), however, these cannot be used in all contexts because [custom inner attributes are unstable](https://github.com/rust-lang/rust/issues/54726) - -### Misc - -- rustfmt now internally supports the ability to have both stable and unstable variants of a configuration option [#5378](https://github.com/rust-lang/rustfmt/issues/5378). This ability will allow the rustfmt team to make certain configuration options available on stable toolchains more quickly because we no longer have to wait for _every_ variant to be stable-ready before stabilizing _any_ variant. - -### Install/Download Options -- **rustup (nightly)** - nightly-2023-01-24 -- **GitHub Release Binaries** - [Release v1.5.2](https://github.com/rust-lang/rustfmt/releases/tag/v1.5.2) -- **Build from source** - [Tag v1.5.2](https://github.com/rust-lang/rustfmt/tree/v1.5.2), see instructions for how to [install rustfmt from source][install-from-source] +- Update various dependencies, including `syn`, `cargo_metadata`, `env_logger`, and `toml` ## [1.5.2] 2023-01-24 diff --git a/Cargo.lock b/Cargo.lock index a59e0b6819bf7..999125118f8f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -545,7 +545,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.5.2" +version = "1.5.3" dependencies = [ "annotate-snippets", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 5f483693a116e..a8928bfcd505b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustfmt-nightly" -version = "1.5.2" +version = "1.5.3" description = "Tool to find and fix Rust formatting issues" repository = "https://github.com/rust-lang/rustfmt" readme = "README.md" From aca66a20c63c19feb4ed9a30cd9e8290972b70f6 Mon Sep 17 00:00:00 2001 From: Caleb Cartwright Date: Mon, 19 Jun 2023 23:19:48 -0500 Subject: [PATCH 329/465] update lockfile for rustfmt sync --- Cargo.lock | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4eafda94037c3..3d0f9e8844e06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -360,7 +360,7 @@ dependencies = [ name = "cargo-miri" version = "0.1.0" dependencies = [ - "cargo_metadata 0.15.3", + "cargo_metadata", "directories", "rustc-build-sysroot", "rustc-workspace-hack", @@ -381,22 +381,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c297bd3135f558552f99a0daa180876984ea2c4ffa7470314540dff8c654109a" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", -] - -[[package]] -name = "cargo_metadata" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a1ec454bc3eead8719cb56e15dbbfecdbc14e4b3a3ae4936cc6e31f5fc0d07" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ "camino", "cargo-platform", @@ -631,7 +618,7 @@ name = "clippy_lints" version = "0.1.72" dependencies = [ "arrayvec", - "cargo_metadata 0.15.3", + "cargo_metadata", "clippy_utils", "declare_clippy_lint", "if_chain", @@ -4348,35 +4335,33 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 1.0.102", + "syn 2.0.8", ] [[package]] name = "rustfmt-nightly" -version = "1.5.2" +version = "1.5.3" dependencies = [ "annotate-snippets", "anyhow", "bytecount", - "cargo_metadata 0.14.0", - "clap 3.2.20", - "derive-new", + "cargo_metadata", + "clap 4.2.1", "diff", "dirs", - "env_logger 0.9.0", + "env_logger 0.10.0", "getopts", "ignore", "itertools", "lazy_static", "log", "regex", - "rustc-workspace-hack", "rustfmt-config_proc_macro", "serde", "serde_json", "term", "thiserror", - "toml 0.5.7", + "toml 0.7.4", "unicode-segmentation", "unicode-width", "unicode_categories", @@ -4956,7 +4941,7 @@ name = "tidy" version = "0.1.0" dependencies = [ "cargo-platform", - "cargo_metadata 0.15.3", + "cargo_metadata", "ignore", "lazy_static", "miropt-test-tools", @@ -5192,7 +5177,7 @@ checksum = "191a442639ea102fa62671026047e51d574bfda44b7fdf32151d7314624c1cd2" dependencies = [ "bstr", "cargo-platform", - "cargo_metadata 0.15.3", + "cargo_metadata", "color-eyre", "colored", "crossbeam-channel", From 657d3f43a9802a3e119c1acf6467ddc0eb41e0be Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 2 Jun 2023 05:54:52 +0000 Subject: [PATCH 330/465] Add rustc_do_not_implement_via_object --- compiler/rustc_feature/src/builtin_attrs.rs | 5 +++++ compiler/rustc_hir_analysis/src/collect.rs | 2 ++ compiler/rustc_middle/src/ty/trait_def.rs | 5 +++++ compiler/rustc_span/src/symbol.rs | 1 + .../src/solve/assembly/mod.rs | 6 +++++- library/core/src/marker.rs | 4 ++++ library/core/src/mem/transmutability.rs | 1 + library/core/src/ptr/metadata.rs | 1 + ...71659.stderr => issue-71659.current.stderr} | 4 ++-- tests/ui/unsized/issue-71659.next.stderr | 18 ++++++++++++++++++ tests/ui/unsized/issue-71659.rs | 3 +++ 11 files changed, 47 insertions(+), 3 deletions(-) rename tests/ui/unsized/{issue-71659.stderr => issue-71659.current.stderr} (89%) create mode 100644 tests/ui/unsized/issue-71659.next.stderr diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 9be28c338f64b..566f856258ac8 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -708,6 +708,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_deny_explicit_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: false, "#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls" ), + rustc_attr!( + rustc_do_not_implement_via_object, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: true, + "#[rustc_do_not_implement_via_object] marks a trait so that `dyn Trait` does not \ + implement `Trait` (without requiring `Sized` as a supertrait)" + ), rustc_attr!( rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word), ErrorFollowing, "#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \ diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index c7b9fc9a697f4..96cbe975f36df 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -985,6 +985,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { no_dups.then_some(list) }); + let do_not_implement_via_object = tcx.has_attr(def_id, sym::rustc_do_not_implement_via_object); ty::TraitDef { def_id: def_id.to_def_id(), @@ -996,6 +997,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { skip_array_during_method_dispatch, specialization_kind, must_implement_one_of, + do_not_implement_via_object, } } diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index e61037e5ea86f..1435230709474 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -52,6 +52,11 @@ pub struct TraitDef { /// List of functions from `#[rustc_must_implement_one_of]` attribute one of which /// must be implemented. pub must_implement_one_of: Option>, + + /// Whether a type's built-in `dyn Trait: Trait` implementation is explicitly + /// denied. This only applies to built-in trait, and is marked via + /// `#[rustc_do_not_implement_via_object]`. + pub do_not_implement_via_object: bool, } /// Whether this trait is treated specially by the standard library diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c5ce2575fff06..f476f89163159 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1270,6 +1270,7 @@ symbols! { rustc_diagnostic_macros, rustc_dirty, rustc_do_not_const_check, + rustc_do_not_implement_via_object, rustc_doc_primitive, rustc_dummy, rustc_dump_env_program_clauses, diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 1b749b9c854cd..ab8dd854fa4cc 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -631,6 +631,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, G>, candidates: &mut Vec>, ) { + let tcx = self.tcx(); + if !tcx.trait_def(goal.predicate.trait_def_id(tcx)).implement_via_object { + return; + } + let self_ty = goal.predicate.self_ty(); let bounds = match *self_ty.kind() { ty::Bool @@ -663,7 +668,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ty::Dynamic(bounds, ..) => bounds, }; - let tcx = self.tcx(); let own_bounds: FxIndexSet<_> = bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)).collect(); for assumption in elaborate(tcx, own_bounds.iter().copied()) diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 9a541ccaeacbc..e1359aa09a238 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -174,6 +174,7 @@ pub trait Sized { #[unstable(feature = "unsize", issue = "18598")] #[lang = "unsize"] #[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] pub trait Unsize { // Empty. } @@ -855,6 +856,7 @@ impl StructuralEq for PhantomData {} )] #[lang = "discriminant_kind"] #[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] pub trait DiscriminantKind { /// The type of the discriminant, which must satisfy the trait /// bounds required by `mem::Discriminant`. @@ -960,6 +962,7 @@ marker_impls! { #[lang = "destruct"] #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] #[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] #[const_trait] pub trait Destruct {} @@ -971,6 +974,7 @@ pub trait Destruct {} #[lang = "tuple_trait"] #[rustc_on_unimplemented(message = "`{Self}` is not a tuple")] #[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] pub trait Tuple {} /// A marker for pointer-like types. diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index a6f792ed0e3e9..8ba4313cc1e52 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -7,6 +7,7 @@ use crate::marker::ConstParamTy; /// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied. #[unstable(feature = "transmutability", issue = "99571")] #[lang = "transmute_trait"] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] pub unsafe trait BikeshedIntrinsicFrom where Src: ?Sized, diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 2ea032d4affe0..34f31fb9fc6ad 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -51,6 +51,7 @@ use crate::hash::{Hash, Hasher}; /// [`to_raw_parts`]: *const::to_raw_parts #[lang = "pointee_trait"] #[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] pub trait Pointee { /// The type for metadata in pointers and references to `Self`. #[lang = "metadata_type"] diff --git a/tests/ui/unsized/issue-71659.stderr b/tests/ui/unsized/issue-71659.current.stderr similarity index 89% rename from tests/ui/unsized/issue-71659.stderr rename to tests/ui/unsized/issue-71659.current.stderr index b57b3015e475d..6b982a73952bd 100644 --- a/tests/ui/unsized/issue-71659.stderr +++ b/tests/ui/unsized/issue-71659.current.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `dyn Foo: CastTo<[i32]>` is not satisfied - --> $DIR/issue-71659.rs:30:15 + --> $DIR/issue-71659.rs:33:15 | LL | let x = x.cast::<[i32]>(); | ^^^^ the trait `CastTo<[i32]>` is not implemented for `dyn Foo` | note: required by a bound in `Cast::cast` - --> $DIR/issue-71659.rs:19:15 + --> $DIR/issue-71659.rs:22:15 | LL | fn cast(&self) -> &T | ---- required by a bound in this associated function diff --git a/tests/ui/unsized/issue-71659.next.stderr b/tests/ui/unsized/issue-71659.next.stderr new file mode 100644 index 0000000000000..6b982a73952bd --- /dev/null +++ b/tests/ui/unsized/issue-71659.next.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `dyn Foo: CastTo<[i32]>` is not satisfied + --> $DIR/issue-71659.rs:33:15 + | +LL | let x = x.cast::<[i32]>(); + | ^^^^ the trait `CastTo<[i32]>` is not implemented for `dyn Foo` + | +note: required by a bound in `Cast::cast` + --> $DIR/issue-71659.rs:22:15 + | +LL | fn cast(&self) -> &T + | ---- required by a bound in this associated function +LL | where +LL | Self: CastTo, + | ^^^^^^^^^ required by this bound in `Cast::cast` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/unsized/issue-71659.rs b/tests/ui/unsized/issue-71659.rs index 3524ca02bbf87..db5c2e205aa13 100644 --- a/tests/ui/unsized/issue-71659.rs +++ b/tests/ui/unsized/issue-71659.rs @@ -1,3 +1,6 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + #![feature(unsize)] use std::marker::Unsize; From 91e5c3f2e5d0a20ffc9b2e80ea049e77d5721da0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 13 Jun 2023 22:31:25 +0000 Subject: [PATCH 331/465] Make rustc_deny_explicit_impl only local as well --- compiler/rustc_feature/src/builtin_attrs.rs | 2 +- compiler/rustc_hir_analysis/src/coherence/mod.rs | 3 +-- compiler/rustc_hir_analysis/src/collect.rs | 4 +++- compiler/rustc_middle/src/ty/trait_def.rs | 3 +++ 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 566f856258ac8..0e7deef0cff07 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -705,7 +705,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl." ), rustc_attr!( - rustc_deny_explicit_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: false, + rustc_deny_explicit_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: true, "#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls" ), rustc_attr!( diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 4524b87a418aa..5097f43607e85 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -10,7 +10,6 @@ use rustc_errors::{error_code, struct_span_err}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; -use rustc_span::sym; use rustc_trait_selection::traits; mod builtin; @@ -44,7 +43,7 @@ fn enforce_trait_manually_implementable( let impl_header_span = tcx.def_span(impl_def_id); // Disallow *all* explicit impls of traits marked `#[rustc_deny_explicit_impl]` - if tcx.has_attr(trait_def_id, sym::rustc_deny_explicit_impl) { + if tcx.trait_def(trait_def_id).deny_explicit_impl { let trait_name = tcx.item_name(trait_def_id); let mut err = struct_span_err!( tcx.sess, diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 96cbe975f36df..17a180a7eb2d4 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -986,6 +986,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { no_dups.then_some(list) }); let do_not_implement_via_object = tcx.has_attr(def_id, sym::rustc_do_not_implement_via_object); + let deny_explicit_impl = tcx.has_attr(def_id, sym::rustc_deny_explicit_impl); ty::TraitDef { def_id: def_id.to_def_id(), @@ -997,7 +998,8 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { skip_array_during_method_dispatch, specialization_kind, must_implement_one_of, - do_not_implement_via_object, + implement_via_object, + deny_explicit_impl, } } diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 1435230709474..325e156fba5f8 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -57,6 +57,9 @@ pub struct TraitDef { /// denied. This only applies to built-in trait, and is marked via /// `#[rustc_do_not_implement_via_object]`. pub do_not_implement_via_object: bool, + + /// Whether a trait is fully built-in, and any implementation is disallowed. + pub deny_explicit_impl: bool, } /// Whether this trait is treated specially by the standard library From ca68cf0d46ec3485be177eeec3f4a4662b21bc8c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 16 Jun 2023 23:45:01 +0000 Subject: [PATCH 332/465] Merge attrs, better validation --- compiler/rustc_feature/src/builtin_attrs.rs | 11 ++--- compiler/rustc_hir_analysis/src/collect.rs | 46 ++++++++++++++++++- compiler/rustc_middle/src/ty/trait_def.rs | 10 ++-- compiler/rustc_passes/messages.ftl | 3 -- compiler/rustc_passes/src/check_attr.rs | 43 +++-------------- compiler/rustc_passes/src/errors.rs | 7 --- compiler/rustc_span/src/symbol.rs | 2 +- .../src/traits/project.rs | 4 ++ .../src/traits/select/candidate_assembly.rs | 4 ++ library/core/src/marker.rs | 22 +++++---- library/core/src/mem/transmutability.rs | 3 +- library/core/src/ptr/metadata.rs | 4 +- .../attr-misuse.stderr | 4 ++ .../deny-builtin-object-impl.current.stderr | 15 ++++++ .../deny-builtin-object-impl.next.stderr | 15 ++++++ tests/ui/traits/deny-builtin-object-impl.rs | 20 ++++++++ 16 files changed, 140 insertions(+), 73 deletions(-) create mode 100644 tests/ui/traits/deny-builtin-object-impl.current.stderr create mode 100644 tests/ui/traits/deny-builtin-object-impl.next.stderr create mode 100644 tests/ui/traits/deny-builtin-object-impl.rs diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 0e7deef0cff07..3c5bff3812a94 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -705,14 +705,13 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl." ), rustc_attr!( - rustc_deny_explicit_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: true, + rustc_deny_explicit_impl, + AttributeType::Normal, + template!(List: "implement_via_object = (true|false)"), + ErrorFollowing, + @only_local: true, "#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls" ), - rustc_attr!( - rustc_do_not_implement_via_object, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: true, - "#[rustc_do_not_implement_via_object] marks a trait so that `dyn Trait` does not \ - implement `Trait` (without requiring `Sized` as a supertrait)" - ), rustc_attr!( rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word), ErrorFollowing, "#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \ diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 17a180a7eb2d4..ec378c0984f26 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -985,8 +985,50 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { no_dups.then_some(list) }); - let do_not_implement_via_object = tcx.has_attr(def_id, sym::rustc_do_not_implement_via_object); - let deny_explicit_impl = tcx.has_attr(def_id, sym::rustc_deny_explicit_impl); + + let mut deny_explicit_impl = false; + let mut implement_via_object = true; + if let Some(attr) = tcx.get_attr(def_id, sym::rustc_deny_explicit_impl) { + deny_explicit_impl = true; + let mut seen_attr = false; + for meta in attr.meta_item_list().iter().flatten() { + if let Some(meta) = meta.meta_item() + && meta.name_or_empty() == sym::implement_via_object + && let Some(lit) = meta.name_value_literal() + { + if seen_attr { + tcx.sess.span_err( + meta.span, + "duplicated `implement_via_object` meta item", + ); + } + seen_attr = true; + + match lit.symbol { + kw::True => { + implement_via_object = true; + } + kw::False => { + implement_via_object = false; + } + _ => { + tcx.sess.span_err( + meta.span, + format!("unknown literal passed to `implement_via_object` attribute: {}", lit.symbol), + ); + } + } + } else { + tcx.sess.span_err( + meta.span(), + format!("unknown meta item passed to `rustc_deny_explicit_impl` {:?}", meta), + ); + } + } + if !seen_attr { + tcx.sess.span_err(attr.span, "missing `implement_via_object` meta item"); + } + } ty::TraitDef { def_id: def_id.to_def_id(), diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 325e156fba5f8..98c70e330f1cc 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -53,12 +53,14 @@ pub struct TraitDef { /// must be implemented. pub must_implement_one_of: Option>, - /// Whether a type's built-in `dyn Trait: Trait` implementation is explicitly - /// denied. This only applies to built-in trait, and is marked via - /// `#[rustc_do_not_implement_via_object]`. - pub do_not_implement_via_object: bool, + /// Whether to add a builtin `dyn Trait: Trait` implementation. + /// This is enabled for all traits except ones marked with + /// `#[rustc_deny_explicit_impl(implement_via_object = false)]`. + pub implement_via_object: bool, /// Whether a trait is fully built-in, and any implementation is disallowed. + /// This only applies to built-in traits, and is marked via + /// `#[rustc_deny_explicit_impl(implement_via_object = ...)]`. pub deny_explicit_impl: bool, } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index e76f1614b9334..a607e483c97c7 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -102,9 +102,6 @@ passes_const_impl_const_trait = const `impl`s must be for traits marked with `#[const_trait]` .note = this trait must be annotated with `#[const_trait]` -passes_const_trait = - attribute should be applied to a trait - passes_continue_labeled_block = `continue` pointing to a labeled block .label = labeled blocks cannot be `continue`'d diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c35c7da266429..073760f394e8a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -110,9 +110,6 @@ impl CheckAttrVisitor<'_> { sym::no_coverage => self.check_no_coverage(hir_id, attr, span, target), sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target), sym::marker => self.check_marker(hir_id, attr, span, target), - sym::rustc_must_implement_one_of => { - self.check_rustc_must_implement_one_of(attr, span, target) - } sym::target_feature => self.check_target_feature(hir_id, attr, span, target), sym::thread_local => self.check_thread_local(attr, span, target), sym::track_caller => { @@ -159,12 +156,14 @@ impl CheckAttrVisitor<'_> { | sym::rustc_dirty | sym::rustc_if_this_changed | sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(&attr), - sym::rustc_coinductive => self.check_rustc_coinductive(&attr, span, target), + sym::rustc_coinductive + | sym::rustc_must_implement_one_of + | sym::rustc_deny_explicit_impl + | sym::const_trait => self.check_must_be_applied_to_trait(&attr, span, target), sym::cmse_nonsecure_entry => { self.check_cmse_nonsecure_entry(hir_id, attr, span, target) } sym::collapse_debuginfo => self.check_collapse_debuginfo(attr, span, target), - sym::const_trait => self.check_const_trait(attr, span, target), sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target), sym::must_use => self.check_must_use(hir_id, &attr, target), sym::rustc_pass_by_value => self.check_pass_by_value(&attr, span, target), @@ -567,25 +566,6 @@ impl CheckAttrVisitor<'_> { } } - /// Checks if the `#[rustc_must_implement_one_of]` attribute on a `target` is valid. Returns `true` if valid. - fn check_rustc_must_implement_one_of( - &self, - attr: &Attribute, - span: Span, - target: Target, - ) -> bool { - match target { - Target::Trait => true, - _ => { - self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToTrait { - attr_span: attr.span, - defn_span: span, - }); - false - } - } - } - /// Checks if the `#[target_feature]` attribute on `item` is valid. Returns `true` if valid. fn check_target_feature( &self, @@ -1591,8 +1571,8 @@ impl CheckAttrVisitor<'_> { } } - /// Checks if the `#[rustc_coinductive]` attribute is applied to a trait. - fn check_rustc_coinductive(&self, attr: &Attribute, span: Span, target: Target) -> bool { + /// Checks if the attribute is applied to a trait. + fn check_must_be_applied_to_trait(&self, attr: &Attribute, span: Span, target: Target) -> bool { match target { Target::Trait => true, _ => { @@ -1986,17 +1966,6 @@ impl CheckAttrVisitor<'_> { } } - /// `#[const_trait]` only applies to traits. - fn check_const_trait(&self, attr: &Attribute, _span: Span, target: Target) -> bool { - match target { - Target::Trait => true, - _ => { - self.tcx.sess.emit_err(errors::ConstTrait { attr_span: attr.span }); - false - } - } - } - fn check_stability_promotable(&self, attr: &Attribute, _span: Span, target: Target) -> bool { match target { Target::Expression => { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index ae624dbc9c953..7890c93d5ff0a 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -610,13 +610,6 @@ pub struct RustcStdInternalSymbol { pub span: Span, } -#[derive(Diagnostic)] -#[diag(passes_const_trait)] -pub struct ConstTrait { - #[primary_span] - pub attr_span: Span, -} - #[derive(Diagnostic)] #[diag(passes_link_ordinal)] pub struct LinkOrdinal { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f476f89163159..cd1a16a1b8966 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -817,6 +817,7 @@ symbols! { impl_trait_in_bindings, impl_trait_in_fn_trait_return, impl_trait_projections, + implement_via_object, implied_by, import, import_name_type, @@ -1270,7 +1271,6 @@ symbols! { rustc_diagnostic_macros, rustc_dirty, rustc_do_not_const_check, - rustc_do_not_implement_via_object, rustc_doc_primitive, rustc_dummy, rustc_dump_env_program_clauses, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 563cc257e0349..5554c8a0cc4de 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1586,6 +1586,10 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( let tcx = selcx.tcx(); + if !tcx.trait_def(obligation.predicate.trait_def_id(tcx)).implement_via_object { + return; + } + let self_ty = obligation.predicate.self_ty(); let object_ty = selcx.infcx.shallow_resolve(self_ty); let data = match object_ty.kind() { diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 3c223db5a0b74..9fb9385eefc9d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -554,6 +554,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { "assemble_candidates_from_object_ty", ); + if !self.tcx().trait_def(obligation.predicate.def_id()).implement_via_object { + return; + } + self.infcx.probe(|_snapshot| { if obligation.has_non_region_late_bound() { return; diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index e1359aa09a238..760e58276fc9f 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -140,7 +140,8 @@ unsafe impl Send for &T {} )] #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable #[rustc_specialization_trait] -#[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] #[rustc_coinductive] pub trait Sized { // Empty. @@ -173,8 +174,8 @@ pub trait Sized { /// [nomicon-coerce]: ../../nomicon/coercions.html #[unstable(feature = "unsize", issue = "18598")] #[lang = "unsize"] -#[rustc_deny_explicit_impl] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub trait Unsize { // Empty. } @@ -855,8 +856,8 @@ impl StructuralEq for PhantomData {} reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead" )] #[lang = "discriminant_kind"] -#[rustc_deny_explicit_impl] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub trait DiscriminantKind { /// The type of the discriminant, which must satisfy the trait /// bounds required by `mem::Discriminant`. @@ -961,8 +962,8 @@ marker_impls! { #[unstable(feature = "const_trait_impl", issue = "67792")] #[lang = "destruct"] #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] -#[rustc_deny_explicit_impl] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] #[const_trait] pub trait Destruct {} @@ -973,8 +974,8 @@ pub trait Destruct {} #[unstable(feature = "tuple_trait", issue = "none")] #[lang = "tuple_trait"] #[rustc_on_unimplemented(message = "`{Self}` is not a tuple")] -#[rustc_deny_explicit_impl] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub trait Tuple {} /// A marker for pointer-like types. @@ -1029,7 +1030,8 @@ impl ConstParamTy for () {} reason = "internal trait for implementing various traits for all function pointers" )] #[lang = "fn_ptr_trait"] -#[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub trait FnPtr: Copy + Clone { /// Returns the address of the function pointer. #[lang = "fn_ptr_addr"] diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index 8ba4313cc1e52..3805d149b704e 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -7,7 +7,8 @@ use crate::marker::ConstParamTy; /// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied. #[unstable(feature = "transmutability", issue = "99571")] #[lang = "transmute_trait"] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub unsafe trait BikeshedIntrinsicFrom where Src: ?Sized, diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 34f31fb9fc6ad..daaa44b1d9af5 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -50,8 +50,8 @@ use crate::hash::{Hash, Hasher}; /// /// [`to_raw_parts`]: *const::to_raw_parts #[lang = "pointee_trait"] -#[rustc_deny_explicit_impl] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub trait Pointee { /// The type for metadata in pointers and references to `Self`. #[lang = "metadata_type"] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.stderr index b18f33218c2db..998958cedf748 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.stderr @@ -3,12 +3,16 @@ error: attribute should be applied to a trait | LL | #[const_trait] | ^^^^^^^^^^^^^^ +LL | fn main() {} + | ------------ not a trait error: attribute should be applied to a trait --> $DIR/attr-misuse.rs:5:5 | LL | #[const_trait] | ^^^^^^^^^^^^^^ +LL | fn foo(self); + | ------------- not a trait error: aborting due to 2 previous errors diff --git a/tests/ui/traits/deny-builtin-object-impl.current.stderr b/tests/ui/traits/deny-builtin-object-impl.current.stderr new file mode 100644 index 0000000000000..5c1987426f71f --- /dev/null +++ b/tests/ui/traits/deny-builtin-object-impl.current.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `dyn NotObject: NotObject` is not satisfied + --> $DIR/deny-builtin-object-impl.rs:18:23 + | +LL | test_not_object::(); + | ^^^^^^^^^^^^^ the trait `NotObject` is not implemented for `dyn NotObject` + | +note: required by a bound in `test_not_object` + --> $DIR/deny-builtin-object-impl.rs:14:23 + | +LL | fn test_not_object() {} + | ^^^^^^^^^ required by this bound in `test_not_object` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/deny-builtin-object-impl.next.stderr b/tests/ui/traits/deny-builtin-object-impl.next.stderr new file mode 100644 index 0000000000000..5c1987426f71f --- /dev/null +++ b/tests/ui/traits/deny-builtin-object-impl.next.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `dyn NotObject: NotObject` is not satisfied + --> $DIR/deny-builtin-object-impl.rs:18:23 + | +LL | test_not_object::(); + | ^^^^^^^^^^^^^ the trait `NotObject` is not implemented for `dyn NotObject` + | +note: required by a bound in `test_not_object` + --> $DIR/deny-builtin-object-impl.rs:14:23 + | +LL | fn test_not_object() {} + | ^^^^^^^^^ required by this bound in `test_not_object` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/deny-builtin-object-impl.rs b/tests/ui/traits/deny-builtin-object-impl.rs new file mode 100644 index 0000000000000..dce03a43b682a --- /dev/null +++ b/tests/ui/traits/deny-builtin-object-impl.rs @@ -0,0 +1,20 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + +#![feature(rustc_attrs)] + +#[rustc_deny_explicit_impl(implement_via_object = true)] +trait YesObject {} + +#[rustc_deny_explicit_impl(implement_via_object = false)] +trait NotObject {} + +fn test_yes_object() {} + +fn test_not_object() {} + +fn main() { + test_yes_object::(); + test_not_object::(); + //~^ ERROR the trait bound `dyn NotObject: NotObject` is not satisfied +} From c3cdf8542d8af35d45dedfa2d9eaccd968e69db7 Mon Sep 17 00:00:00 2001 From: "Alexis (Poliorcetics) Bourget" Date: Tue, 20 Jun 2023 08:28:56 +0200 Subject: [PATCH 333/465] tests: add test for color of item kind --- tests/rustdoc-gui/search-result-color.goml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/rustdoc-gui/search-result-color.goml b/tests/rustdoc-gui/search-result-color.goml index c75e4141434e4..193a3eb3fd134 100644 --- a/tests/rustdoc-gui/search-result-color.goml +++ b/tests/rustdoc-gui/search-result-color.goml @@ -28,6 +28,12 @@ define-function: ( ".result-" + |result_kind| + ":focus ." + |result_kind|, {"color": |hover_color|}, ) + // color of the typename (struct, module, method, ...) before search results + assert-css: ( + ".result-name .typename", + {"color": "#888"}, + ALL, + ) }, ) From f5438d658ff1059fd0626ce48900b7c3e007312a Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 20 Jun 2023 12:14:11 +0200 Subject: [PATCH 334/465] split probe into 2 functions for better readability --- .../src/solve/alias_relate.rs | 14 +-- .../src/solve/assembly/mod.rs | 8 +- .../src/solve/eval_ctxt.rs | 40 ++---- .../src/solve/eval_ctxt/probe.rs | 47 +++++++ .../src/solve/project_goals.rs | 35 +++--- .../src/solve/trait_goals.rs | 115 ++++++++---------- 6 files changed, 132 insertions(+), 127 deletions(-) create mode 100644 compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index 1ceb77e91938c..ca7fcfd8ca1be 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -110,12 +110,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { direction: ty::AliasRelationDirection, invert: Invert, ) -> QueryResult<'tcx> { - self.probe( + self.probe(|r| CandidateKind::Candidate { name: "normalizes-to".into(), result: *r }).enter( |ecx| { ecx.normalizes_to_inner(param_env, alias, other, direction, invert)?; ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }, - |r| CandidateKind::Candidate { name: "normalizes-to".into(), result: *r }, ) } @@ -157,7 +156,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { alias_rhs: ty::AliasTy<'tcx>, direction: ty::AliasRelationDirection, ) -> QueryResult<'tcx> { - self.probe( + self.probe(|r| CandidateKind::Candidate { name: "substs relate".into(), result: *r }).enter( |ecx| { match direction { ty::AliasRelationDirection::Equate => { @@ -170,7 +169,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }, - |r| CandidateKind::Candidate { name: "substs relate".into(), result: *r }, ) } @@ -181,8 +179,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { rhs: ty::Term<'tcx>, direction: ty::AliasRelationDirection, ) -> QueryResult<'tcx> { - self.probe( - |ecx| { + self.probe(|r| CandidateKind::Candidate { name: "bidir normalizes-to".into(), result: *r }) + .enter(|ecx| { ecx.normalizes_to_inner( param_env, lhs.to_alias_ty(ecx.tcx()).unwrap(), @@ -198,8 +196,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Invert::Yes, )?; ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }, - |r| CandidateKind::Candidate { name: "bidir normalizes-to".into(), result: *r }, - ) + }) } } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index d9bc8d3b1eb43..6fc88afef812f 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -337,8 +337,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { return }; - let normalized_self_candidates: Result<_, NoSolution> = self.probe( - |ecx| { + let normalized_self_candidates: Result<_, NoSolution> = + self.probe(|_| CandidateKind::NormalizedSelfTyAssembly).enter(|ecx| { ecx.with_incremented_depth( |ecx| { let result = ecx.evaluate_added_goals_and_make_canonical_response( @@ -368,9 +368,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Ok(ecx.assemble_and_evaluate_candidates(goal)) }, ) - }, - |_| CandidateKind::NormalizedSelfTyAssembly, - ); + }); if let Ok(normalized_self_candidates) = normalized_self_candidates { candidates.extend(normalized_self_candidates); diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 4258f9f6bd28e..87a23961f8b6d 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -30,6 +30,7 @@ use super::SolverMode; use super::{search_graph::SearchGraph, Goal}; mod canonical; +mod probe; pub struct EvalCtxt<'a, 'tcx> { /// The inference context that backs (mostly) inference and placeholder terms @@ -529,32 +530,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } impl<'tcx> EvalCtxt<'_, 'tcx> { - /// `probe_kind` is only called when proof tree building is enabled so it can be - /// as expensive as necessary to output the desired information. - pub(super) fn probe( - &mut self, - f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T, - probe_kind: impl FnOnce(&T) -> CandidateKind<'tcx>, - ) -> T { - let mut ecx = EvalCtxt { - infcx: self.infcx, - var_values: self.var_values, - predefined_opaques_in_body: self.predefined_opaques_in_body, - max_input_universe: self.max_input_universe, - search_graph: self.search_graph, - nested_goals: self.nested_goals.clone(), - tainted: self.tainted, - inspect: self.inspect.new_goal_candidate(), - }; - let r = self.infcx.probe(|_| f(&mut ecx)); - if !self.inspect.is_noop() { - let cand_kind = probe_kind(&r); - ecx.inspect.candidate_kind(cand_kind); - self.inspect.goal_candidate(ecx.inspect); - } - r - } - pub(super) fn tcx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -866,17 +841,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { if candidate_key.def_id != key.def_id { continue; } - values.extend(self.probe( - |ecx| { + values.extend( + self.probe(|r| CandidateKind::Candidate { + name: "opaque type storage".into(), + result: *r, + }) + .enter(|ecx| { for (a, b) in std::iter::zip(candidate_key.substs, key.substs) { ecx.eq(param_env, a, b)?; } ecx.eq(param_env, candidate_ty, ty)?; ecx.add_item_bounds_for_hidden_type(candidate_key, param_env, candidate_ty); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }, - |r| CandidateKind::Candidate { name: "opaque type storage".into(), result: *r }, - )); + }), + ); } values } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs new file mode 100644 index 0000000000000..5d912fc039d59 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs @@ -0,0 +1,47 @@ +use super::EvalCtxt; +use rustc_middle::traits::solve::inspect; +use std::marker::PhantomData; + +pub(in crate::solve) struct ProbeCtxt<'me, 'a, 'tcx, F, T> { + ecx: &'me mut EvalCtxt<'a, 'tcx>, + probe_kind: F, + _result: PhantomData, +} + +impl<'tcx, F, T> ProbeCtxt<'_, '_, 'tcx, F, T> +where + F: FnOnce(&T) -> inspect::CandidateKind<'tcx>, +{ + pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T) -> T { + let ProbeCtxt { ecx: outer_ecx, probe_kind, _result } = self; + + let mut nested_ecx = EvalCtxt { + infcx: outer_ecx.infcx, + var_values: outer_ecx.var_values, + predefined_opaques_in_body: outer_ecx.predefined_opaques_in_body, + max_input_universe: outer_ecx.max_input_universe, + search_graph: outer_ecx.search_graph, + nested_goals: outer_ecx.nested_goals.clone(), + tainted: outer_ecx.tainted, + inspect: outer_ecx.inspect.new_goal_candidate(), + }; + let r = nested_ecx.infcx.probe(|_| f(&mut nested_ecx)); + if !outer_ecx.inspect.is_noop() { + let cand_kind = probe_kind(&r); + nested_ecx.inspect.candidate_kind(cand_kind); + outer_ecx.inspect.goal_candidate(nested_ecx.inspect); + } + r + } +} + +impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { + /// `probe_kind` is only called when proof tree building is enabled so it can be + /// as expensive as necessary to output the desired information. + pub(in crate::solve) fn probe(&mut self, probe_kind: F) -> ProbeCtxt<'_, 'a, 'tcx, F, T> + where + F: FnOnce(&T) -> inspect::CandidateKind<'tcx>, + { + ProbeCtxt { ecx: self, probe_kind, _result: PhantomData } + } +} diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index b99c3927862fc..569400a2f7e6d 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -112,8 +112,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ) -> QueryResult<'tcx> { if let Some(projection_pred) = assumption.as_projection_clause() { if projection_pred.projection_def_id() == goal.predicate.def_id() { - ecx.probe( - |ecx| { + ecx.probe(|r| CandidateKind::Candidate { name: "assumption".into(), result: *r }) + .enter(|ecx| { let assumption_projection_pred = ecx.instantiate_binder_with_infer(projection_pred); ecx.eq( @@ -128,9 +128,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ) .expect("expected goal term to be fully unconstrained"); then(ecx) - }, - |r| CandidateKind::Candidate { name: "assumption".into(), result: *r }, - ) + }) } else { Err(NoSolution) } @@ -154,6 +152,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { } ecx.probe( + |r| CandidateKind::Candidate { name: "impl".into(), result: *r }).enter( |ecx| { let impl_substs = ecx.fresh_substs_for_item(impl_def_id); let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); @@ -235,7 +234,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { .expect("expected goal term to be fully unconstrained"); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }, - |r| CandidateKind::Candidate { name: "impl".into(), result: *r }, ) } @@ -331,8 +329,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); - ecx.probe( - |ecx| { + ecx.probe(|r| CandidateKind::Candidate { name: "builtin pointee".into(), result: *r }) + .enter(|ecx| { let metadata_ty = match goal.predicate.self_ty().kind() { ty::Bool | ty::Char @@ -415,9 +413,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into()) .expect("expected goal term to be fully unconstrained"); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }, - |r| CandidateKind::Candidate { name: "builtin pointee".into(), result: *r }, - ) + }) } fn consider_builtin_future_candidate( @@ -552,14 +548,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ), }; - ecx.probe( - |ecx| { - ecx.eq(goal.param_env, goal.predicate.term, discriminant_ty.into()) - .expect("expected goal term to be fully unconstrained"); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }, - |r| CandidateKind::Candidate { name: "builtin discriminant kind".into(), result: *r }, - ) + ecx.probe(|r| CandidateKind::Candidate { + name: "builtin discriminant kind".into(), + result: *r, + }) + .enter(|ecx| { + ecx.eq(goal.param_env, goal.predicate.term, discriminant_ty.into()) + .expect("expected goal term to be fully unconstrained"); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } fn consider_builtin_destruct_candidate( diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index d9f24455a81f8..19a1626b2cc25 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -62,24 +62,21 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }, }; - ecx.probe( - |ecx| { - let impl_substs = ecx.fresh_substs_for_item(impl_def_id); - let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); - - ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; - let where_clause_bounds = tcx - .predicates_of(impl_def_id) - .instantiate(tcx, impl_substs) - .predicates - .into_iter() - .map(|pred| goal.with(tcx, pred)); - ecx.add_goals(where_clause_bounds); - - ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty) - }, - |r| CandidateKind::Candidate { name: "impl".into(), result: *r }, - ) + ecx.probe(|r| CandidateKind::Candidate { name: "impl".into(), result: *r }).enter(|ecx| { + let impl_substs = ecx.fresh_substs_for_item(impl_def_id); + let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); + + ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; + let where_clause_bounds = tcx + .predicates_of(impl_def_id) + .instantiate(tcx, impl_substs) + .predicates + .into_iter() + .map(|pred| goal.with(tcx, pred)); + ecx.add_goals(where_clause_bounds); + + ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty) + }) } fn probe_and_match_goal_against_assumption( @@ -93,8 +90,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { && trait_clause.polarity() == goal.predicate.polarity { // FIXME: Constness - ecx.probe( - |ecx| { + ecx.probe(|r| CandidateKind::Candidate { name: "assumption".into(), result: *r }) + .enter(|ecx| { let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause); ecx.eq( goal.param_env, @@ -102,9 +99,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { assumption_trait_pred.trait_ref, )?; then(ecx) - }, - |r| CandidateKind::Candidate { name: "assumption".into(), result: *r }, - ) + }) } else { Err(NoSolution) } @@ -141,7 +136,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let tcx = ecx.tcx(); - ecx.probe( + ecx.probe(|r| CandidateKind::Candidate { name: "trait alias".into(), result: *r }).enter( |ecx| { let nested_obligations = tcx .predicates_of(goal.predicate.def_id()) @@ -149,7 +144,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx.add_goals(nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p))); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }, - |r| CandidateKind::Candidate { name: "trait alias".into(), result: *r }, ) } @@ -356,7 +350,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { if b_ty.is_ty_var() { return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); } - ecx.probe( + ecx.probe(|r| CandidateKind::Candidate { name: "builtin unsize".into(), result: *r }).enter( |ecx| { match (a_ty.kind(), b_ty.kind()) { // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b` @@ -464,7 +458,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { _ => Err(NoSolution), } }, - |r| CandidateKind::Candidate { name: "builtin unsize".into(), result: *r }, ) } @@ -495,38 +488,36 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } let mut unsize_dyn_to_principal = |principal: Option>| { - ecx.probe( - |ecx| -> Result<_, NoSolution> { - // Require that all of the trait predicates from A match B, except for - // the auto traits. We do this by constructing a new A type with B's - // auto traits, and equating these types. - let new_a_data = principal - .into_iter() - .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait)) - .chain(a_data.iter().filter(|a| { - matches!(a.skip_binder(), ty::ExistentialPredicate::Projection(_)) - })) - .chain( - b_data - .auto_traits() - .map(ty::ExistentialPredicate::AutoTrait) - .map(ty::Binder::dummy), - ); - let new_a_data = tcx.mk_poly_existential_predicates_from_iter(new_a_data); - let new_a_ty = tcx.mk_dynamic(new_a_data, b_region, ty::Dyn); - - // We also require that A's lifetime outlives B's lifetime. - ecx.eq(goal.param_env, new_a_ty, b_ty)?; - ecx.add_goal( - goal.with( - tcx, - ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)), - ), + ecx.probe(|r| CandidateKind::Candidate { + name: "upcast dyn to principle".into(), + result: *r, + }) + .enter(|ecx| -> Result<_, NoSolution> { + // Require that all of the trait predicates from A match B, except for + // the auto traits. We do this by constructing a new A type with B's + // auto traits, and equating these types. + let new_a_data = principal + .into_iter() + .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait)) + .chain(a_data.iter().filter(|a| { + matches!(a.skip_binder(), ty::ExistentialPredicate::Projection(_)) + })) + .chain( + b_data + .auto_traits() + .map(ty::ExistentialPredicate::AutoTrait) + .map(ty::Binder::dummy), ); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }, - |r| CandidateKind::Candidate { name: "upcast dyn to principle".into(), result: *r }, - ) + let new_a_data = tcx.mk_poly_existential_predicates_from_iter(new_a_data); + let new_a_ty = tcx.mk_dynamic(new_a_data, b_region, ty::Dyn); + + // We also require that A's lifetime outlives B's lifetime. + ecx.eq(goal.param_env, new_a_ty, b_ty)?; + ecx.add_goal( + goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region))), + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) }; let mut responses = vec![]; @@ -723,8 +714,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, TraitPredicate<'tcx>>, constituent_tys: impl Fn(&EvalCtxt<'_, 'tcx>, Ty<'tcx>) -> Result>, NoSolution>, ) -> QueryResult<'tcx> { - self.probe( - |ecx| { + self.probe(|r| CandidateKind::Candidate { name: "constituent tys".into(), result: *r }) + .enter(|ecx| { ecx.add_goals( constituent_tys(ecx, goal.predicate.self_ty())? .into_iter() @@ -737,9 +728,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { .collect::>(), ); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }, - |r| CandidateKind::Candidate { name: "constituent tys".into(), result: *r }, - ) + }) } #[instrument(level = "debug", skip(self))] From f7472aa69ed0589d57ca08da690e6bb32f351eb8 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 20 Jun 2023 12:19:40 +0200 Subject: [PATCH 335/465] cleanup imports --- compiler/rustc_middle/src/traits/mod.rs | 6 ------ compiler/rustc_middle/src/traits/solve.rs | 6 ++++++ compiler/rustc_middle/src/traits/solve/inspect.rs | 8 ++++++-- .../rustc_trait_selection/src/solve/eval_ctxt.rs | 6 +++--- .../rustc_trait_selection/src/solve/inspect.rs | 15 +++++---------- 5 files changed, 20 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 739590385820e..f03802049707c 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -991,9 +991,3 @@ pub enum DefiningAnchor { /// Used to catch type mismatch errors when handling opaque types. Error, } - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)] -pub enum IsNormalizesToHack { - Yes, - No, -} diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index af482a8896070..73b332fd8ec95 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -228,3 +228,9 @@ impl<'tcx> TypeVisitable> for PredefinedOpaques<'tcx> { self.opaque_types.visit_with(visitor) } } + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)] +pub enum IsNormalizesToHack { + Yes, + No, +} diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs index 3cdf1ebbd05d6..527afa005b9f7 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect.rs @@ -1,5 +1,7 @@ -use super::{CanonicalInput, Certainty, Goal, NoSolution, QueryInput, QueryResult}; -use crate::{traits::IsNormalizesToHack, ty}; +use super::{ + CanonicalInput, Certainty, Goal, IsNormalizesToHack, NoSolution, QueryInput, QueryResult, +}; +use crate::ty; use format::ProofTreeFormatter; use std::fmt::{Debug, Write}; @@ -22,6 +24,7 @@ pub struct GoalEvaluation<'tcx> { pub result: QueryResult<'tcx>, } + #[derive(Eq, PartialEq, Hash, HashStable)] pub enum GoalEvaluationKind<'tcx> { CacheHit(CacheHit), @@ -65,6 +68,7 @@ pub struct GoalCandidate<'tcx> { pub candidates: Vec>, pub kind: CandidateKind<'tcx>, } + #[derive(Eq, PartialEq, Debug, Hash, HashStable)] pub enum CandidateKind<'tcx> { /// Probe entered when normalizing the self ty during candidate assembly diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 87a23961f8b6d..962363b60155e 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -11,10 +11,10 @@ use rustc_infer::traits::ObligationCause; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::traits::solve::inspect::{self, CandidateKind}; use rustc_middle::traits::solve::{ - CanonicalInput, CanonicalResponse, Certainty, MaybeCause, PredefinedOpaques, - PredefinedOpaquesData, QueryResult, + CanonicalInput, CanonicalResponse, Certainty, IsNormalizesToHack, MaybeCause, + PredefinedOpaques, PredefinedOpaquesData, QueryResult, }; -use rustc_middle::traits::{DefiningAnchor, IsNormalizesToHack}; +use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::{ self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, diff --git a/compiler/rustc_trait_selection/src/solve/inspect.rs b/compiler/rustc_trait_selection/src/solve/inspect.rs index c3dea5f790a43..5245f95dc580d 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect.rs @@ -1,14 +1,9 @@ -use rustc_middle::{ - traits::{ - query::NoSolution, - solve::{ - inspect::{self, CacheHit, CandidateKind}, - CanonicalInput, Certainty, Goal, QueryInput, QueryResult, - }, - IsNormalizesToHack, - }, - ty, +use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::solve::inspect::{self, CacheHit, CandidateKind}; +use rustc_middle::traits::solve::{ + CanonicalInput, Certainty, Goal, IsNormalizesToHack, QueryInput, QueryResult, }; +use rustc_middle::ty; pub mod dump; From 30e1c1a53c8354d53551f4640a41938a157b4fd0 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 20 Jun 2023 18:43:12 +0800 Subject: [PATCH 336/465] Ignore `connect_timeout` unit test on SGX platform Co-authored-by: Chris Denton --- library/std/src/net/tcp/tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index 4209d4b63422a..12979db25d366 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -58,6 +58,7 @@ fn connect_timeout_to_unreachable_address() { } #[test] +#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn connect_timeout_error() { let socket_addr = next_test_ip4(); let result = TcpStream::connect_timeout(&socket_addr, Duration::MAX); From a0c757a13f5a0090f8cb6e1a7ffba6b94dfc2fbf Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 20 Jun 2023 18:47:31 +0800 Subject: [PATCH 337/465] Remove useless unit tests --- library/std/src/net/tcp/tests.rs | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index 12979db25d366..db367cfa0f7a1 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -46,17 +46,6 @@ fn connect_error() { } } -#[test] -fn connect_timeout_to_unreachable_address() { - let now = Instant::now(); - match TcpStream::connect_timeout(&format!("1.1.1.1:9999").parse().unwrap(), Duration::MAX) { - Ok(..) => panic!("connected to an unreachable address, this is impossible"), - Err(e) => assert_eq!(e.kind(), ErrorKind::TimedOut), - } - - assert!(now.elapsed() > Duration::from_secs(20)); -} - #[test] #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn connect_timeout_error() { @@ -68,16 +57,6 @@ fn connect_timeout_error() { assert!(TcpStream::connect_timeout(&socket_addr, Duration::MAX).is_ok()); } -#[test] -fn connect_timeout_ok_bind() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); // :0 picks some free port - let port = listener.local_addr().unwrap().port(); // obtain the port it picked - assert!( - TcpStream::connect_timeout(&format!("127.0.0.1:{port}").parse().unwrap(), Duration::MAX) - .is_ok() - ); -} - #[test] fn listen_localhost() { let socket_addr = next_test_ip4(); From e4b171a198f5105460142160ca22015e2c5e9c7d Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 20 Jun 2023 12:40:18 +0200 Subject: [PATCH 338/465] inspect nits --- .../src/solve/inspect.rs | 305 +++++++++--------- 1 file changed, 158 insertions(+), 147 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/inspect.rs b/compiler/rustc_trait_selection/src/solve/inspect.rs index 5245f95dc580d..6d7804a8fad2d 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect.rs @@ -20,6 +20,7 @@ pub struct WipGoalEvaluation<'tcx> { pub result: Option>, } + impl<'tcx> WipGoalEvaluation<'tcx> { pub fn finalize(self) -> inspect::GoalEvaluation<'tcx> { inspect::GoalEvaluation { @@ -47,6 +48,7 @@ pub struct WipAddedGoalsEvaluation<'tcx> { pub evaluations: Vec>>, pub result: Option>, } + impl<'tcx> WipAddedGoalsEvaluation<'tcx> { pub fn finalize(self) -> inspect::AddedGoalsEvaluation<'tcx> { inspect::AddedGoalsEvaluation { @@ -71,6 +73,7 @@ pub struct WipGoalEvaluationStep<'tcx> { pub result: Option>, } + impl<'tcx> WipGoalEvaluationStep<'tcx> { pub fn finalize(self) -> inspect::GoalEvaluationStep<'tcx> { inspect::GoalEvaluationStep { @@ -92,6 +95,7 @@ pub struct WipGoalCandidate<'tcx> { pub candidates: Vec>, pub kind: Option>, } + impl<'tcx> WipGoalCandidate<'tcx> { pub fn finalize(self) -> inspect::GoalCandidate<'tcx> { inspect::GoalCandidate { @@ -115,10 +119,45 @@ pub enum DebugSolver<'tcx> { GoalCandidate(WipGoalCandidate<'tcx>), } -pub struct ProofTreeBuilder<'tcx>(Option>>); +impl<'tcx> From> for DebugSolver<'tcx> { + fn from(g: WipGoalEvaluation<'tcx>) -> DebugSolver<'tcx> { + DebugSolver::GoalEvaluation(g) + } +} + +impl<'tcx> From> for DebugSolver<'tcx> { + fn from(g: WipAddedGoalsEvaluation<'tcx>) -> DebugSolver<'tcx> { + DebugSolver::AddedGoalsEvaluation(g) + } +} + +impl<'tcx> From> for DebugSolver<'tcx> { + fn from(g: WipGoalEvaluationStep<'tcx>) -> DebugSolver<'tcx> { + DebugSolver::GoalEvaluationStep(g) + } +} + +impl<'tcx> From> for DebugSolver<'tcx> { + fn from(g: WipGoalCandidate<'tcx>) -> DebugSolver<'tcx> { + DebugSolver::GoalCandidate(g) + } +} + +pub struct ProofTreeBuilder<'tcx> { + state: Option>>, +} + impl<'tcx> ProofTreeBuilder<'tcx> { + fn new(state: impl Into>) -> ProofTreeBuilder<'tcx> { + ProofTreeBuilder { state: Some(Box::new(state.into())) } + } + + fn as_mut(&mut self) -> Option<&mut DebugSolver<'tcx>> { + self.state.as_mut().map(|boxed| &mut **boxed) + } + pub fn finalize(self) -> Option> { - match *(self.0?) { + match *(self.state?) { DebugSolver::GoalEvaluation(wip_goal_evaluation) => { Some(wip_goal_evaluation.finalize()) } @@ -127,15 +166,15 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } pub fn new_root() -> ProofTreeBuilder<'tcx> { - Self(Some(Box::new(DebugSolver::Root))) + ProofTreeBuilder::new(DebugSolver::Root) } pub fn new_noop() -> ProofTreeBuilder<'tcx> { - Self(None) + ProofTreeBuilder { state: None } } pub fn is_noop(&self) -> bool { - self.0.is_none() + self.state.is_none() } pub fn new_goal_evaluation( @@ -143,11 +182,11 @@ impl<'tcx> ProofTreeBuilder<'tcx> { goal: Goal<'tcx, ty::Predicate<'tcx>>, is_normalizes_to_hack: IsNormalizesToHack, ) -> ProofTreeBuilder<'tcx> { - if self.0.is_none() { - return ProofTreeBuilder(None); + if self.state.is_none() { + return ProofTreeBuilder { state: None }; } - Self(Some(Box::new(DebugSolver::GoalEvaluation(WipGoalEvaluation { + ProofTreeBuilder::new(WipGoalEvaluation { uncanonicalized_goal: goal, canonicalized_goal: None, evaluation_steps: vec![], @@ -155,62 +194,54 @@ impl<'tcx> ProofTreeBuilder<'tcx> { cache_hit: None, returned_goals: vec![], result: None, - })))) + }) } + pub fn canonicalized_goal(&mut self, canonical_goal: CanonicalInput<'tcx>) { - let this = match self.0.as_mut() { - None => return, - Some(this) => &mut **this, - }; - - match this { - DebugSolver::GoalEvaluation(goal_evaluation) => { - assert!(goal_evaluation.canonicalized_goal.is_none()); - goal_evaluation.canonicalized_goal = Some(canonical_goal) + if let Some(this) = self.as_mut() { + match this { + DebugSolver::GoalEvaluation(goal_evaluation) => { + assert_eq!(goal_evaluation.canonicalized_goal.replace(canonical_goal), None); + } + _ => unreachable!(), } - _ => unreachable!(), } } + pub fn cache_hit(&mut self, cache_hit: CacheHit) { - let this = match self.0.as_mut() { - None => return, - Some(this) => &mut **this, - }; - - match this { - DebugSolver::GoalEvaluation(goal_evaluation) => { - goal_evaluation.cache_hit = Some(cache_hit) - } - _ => unreachable!(), - }; + if let Some(this) = self.as_mut() { + match this { + DebugSolver::GoalEvaluation(goal_evaluation) => { + assert_eq!(goal_evaluation.cache_hit.replace(cache_hit), None); + } + _ => unreachable!(), + }; + } } + pub fn returned_goals(&mut self, goals: &[Goal<'tcx, ty::Predicate<'tcx>>]) { - let this = match self.0.as_mut() { - None => return, - Some(this) => &mut **this, - }; - - match this { - DebugSolver::GoalEvaluation(evaluation) => { - assert!(evaluation.returned_goals.is_empty()); - evaluation.returned_goals.extend(goals); + if let Some(this) = self.as_mut() { + match this { + DebugSolver::GoalEvaluation(evaluation) => { + assert!(evaluation.returned_goals.is_empty()); + evaluation.returned_goals.extend(goals); + } + _ => unreachable!(), } - _ => unreachable!(), } } pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<'tcx>) { - let this = match self.0.as_mut() { - None => return, - Some(this) => &mut **this, - }; - - match (this, *goal_evaluation.0.unwrap()) { - ( - DebugSolver::AddedGoalsEvaluation(WipAddedGoalsEvaluation { evaluations, .. }), - DebugSolver::GoalEvaluation(goal_evaluation), - ) => evaluations.last_mut().unwrap().push(goal_evaluation), - (this @ DebugSolver::Root, goal_evaluation) => *this = goal_evaluation, - _ => unreachable!(), + if let Some(this) = self.as_mut() { + match (this, *goal_evaluation.state.unwrap()) { + ( + DebugSolver::AddedGoalsEvaluation(WipAddedGoalsEvaluation { + evaluations, .. + }), + DebugSolver::GoalEvaluation(goal_evaluation), + ) => evaluations.last_mut().unwrap().push(goal_evaluation), + (this @ DebugSolver::Root, goal_evaluation) => *this = goal_evaluation, + _ => unreachable!(), + } } } @@ -218,144 +249,124 @@ impl<'tcx> ProofTreeBuilder<'tcx> { &mut self, instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, ) -> ProofTreeBuilder<'tcx> { - if self.0.is_none() { - return Self(None); + if self.state.is_none() { + return ProofTreeBuilder { state: None }; } - Self(Some(Box::new(DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { + ProofTreeBuilder::new(WipGoalEvaluationStep { instantiated_goal, nested_goal_evaluations: vec![], candidates: vec![], result: None, - })))) + }) } pub fn goal_evaluation_step(&mut self, goal_eval_step: ProofTreeBuilder<'tcx>) { - let this = match self.0.as_mut() { - None => return, - Some(this) => &mut **this, - }; - - match (this, *goal_eval_step.0.unwrap()) { - (DebugSolver::GoalEvaluation(goal_eval), DebugSolver::GoalEvaluationStep(step)) => { - goal_eval.evaluation_steps.push(step); + if let Some(this) = self.as_mut() { + match (this, *goal_eval_step.state.unwrap()) { + (DebugSolver::GoalEvaluation(goal_eval), DebugSolver::GoalEvaluationStep(step)) => { + goal_eval.evaluation_steps.push(step); + } + _ => unreachable!(), } - _ => unreachable!(), } } pub fn new_goal_candidate(&mut self) -> ProofTreeBuilder<'tcx> { - if self.0.is_none() { - return Self(None); + if self.state.is_none() { + return ProofTreeBuilder { state: None }; } - Self(Some(Box::new(DebugSolver::GoalCandidate(WipGoalCandidate { + ProofTreeBuilder::new(WipGoalCandidate { nested_goal_evaluations: vec![], candidates: vec![], kind: None, - })))) + }) } - pub fn candidate_kind(&mut self, kind: CandidateKind<'tcx>) { - let this = match self.0.as_mut() { - None => return, - Some(this) => &mut **this, - }; - - match this { - DebugSolver::GoalCandidate(WipGoalCandidate { kind: old_kind @ None, .. }) => { - *old_kind = Some(kind) + + pub fn candidate_kind(&mut self, candidate_kind: CandidateKind<'tcx>) { + if let Some(this) = self.as_mut() { + match this { + DebugSolver::GoalCandidate(this) => { + assert_eq!(this.kind.replace(candidate_kind), None) + } + _ => unreachable!(), } - _ => unreachable!(), } } + pub fn goal_candidate(&mut self, candidate: ProofTreeBuilder<'tcx>) { - let this = match self.0.as_mut() { - None => return, - Some(this) => &mut **this, - }; - - match (this, *candidate.0.unwrap()) { - ( - DebugSolver::GoalCandidate(WipGoalCandidate { candidates, .. }) - | DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { candidates, .. }), - DebugSolver::GoalCandidate(candidate), - ) => candidates.push(candidate), - _ => unreachable!(), + if let Some(this) = self.as_mut() { + match (this, *candidate.state.unwrap()) { + ( + DebugSolver::GoalCandidate(WipGoalCandidate { candidates, .. }) + | DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { candidates, .. }), + DebugSolver::GoalCandidate(candidate), + ) => candidates.push(candidate), + _ => unreachable!(), + } } } pub fn new_evaluate_added_goals(&mut self) -> ProofTreeBuilder<'tcx> { - if self.0.is_none() { - return Self(None); + if self.state.is_none() { + return ProofTreeBuilder { state: None }; } - Self(Some(Box::new(DebugSolver::AddedGoalsEvaluation(WipAddedGoalsEvaluation { - evaluations: vec![], - result: None, - })))) + ProofTreeBuilder::new(WipAddedGoalsEvaluation { evaluations: vec![], result: None }) } + pub fn evaluate_added_goals_loop_start(&mut self) { - let this = match self.0.as_mut() { - None => return, - Some(this) => &mut **this, - }; - - match this { - DebugSolver::AddedGoalsEvaluation(this) => { - this.evaluations.push(vec![]); + if let Some(this) = self.as_mut() { + match this { + DebugSolver::AddedGoalsEvaluation(this) => { + this.evaluations.push(vec![]); + } + _ => unreachable!(), } - _ => unreachable!(), } } + pub fn eval_added_goals_result(&mut self, result: Result) { - let this = match self.0.as_mut() { - None => return, - Some(this) => &mut **this, - }; - - match this { - DebugSolver::AddedGoalsEvaluation(this) => { - assert!(this.result.is_none()); - this.result = Some(result); + if let Some(this) = self.as_mut() { + match this { + DebugSolver::AddedGoalsEvaluation(this) => { + assert_eq!(this.result.replace(result), None); + } + _ => unreachable!(), } - _ => unreachable!(), } } + pub fn added_goals_evaluation(&mut self, goals_evaluation: ProofTreeBuilder<'tcx>) { - let this = match self.0.as_mut() { - None => return, - Some(this) => &mut **this, - }; - - match (this, *goals_evaluation.0.unwrap()) { - ( - DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { - nested_goal_evaluations, - .. - }) - | DebugSolver::GoalCandidate(WipGoalCandidate { nested_goal_evaluations, .. }), - DebugSolver::AddedGoalsEvaluation(added_goals_evaluation), - ) => nested_goal_evaluations.push(added_goals_evaluation), - _ => unreachable!(), + if let Some(this) = self.as_mut() { + match (this, *goals_evaluation.state.unwrap()) { + ( + DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { + nested_goal_evaluations, + .. + }) + | DebugSolver::GoalCandidate(WipGoalCandidate { + nested_goal_evaluations, .. + }), + DebugSolver::AddedGoalsEvaluation(added_goals_evaluation), + ) => nested_goal_evaluations.push(added_goals_evaluation), + _ => unreachable!(), + } } } pub fn query_result(&mut self, result: QueryResult<'tcx>) { - let this = match self.0.as_mut() { - None => return, - Some(this) => &mut **this, - }; - - match this { - DebugSolver::GoalEvaluation(goal_evaluation) => { - assert!(goal_evaluation.result.is_none()); - goal_evaluation.result = Some(result); - } - DebugSolver::Root - | DebugSolver::AddedGoalsEvaluation(_) - | DebugSolver::GoalCandidate(_) => unreachable!(), - DebugSolver::GoalEvaluationStep(evaluation_step) => { - assert!(evaluation_step.result.is_none()); - evaluation_step.result = Some(result); + if let Some(this) = self.as_mut() { + match this { + DebugSolver::GoalEvaluation(goal_evaluation) => { + assert_eq!(goal_evaluation.result.replace(result), None); + } + DebugSolver::GoalEvaluationStep(evaluation_step) => { + assert_eq!(evaluation_step.result.replace(result), None); + } + DebugSolver::Root + | DebugSolver::AddedGoalsEvaluation(_) + | DebugSolver::GoalCandidate(_) => unreachable!(), } } } From bc20a8e01a6c480c98f0155252b3cce57d338096 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 19 Jun 2023 21:17:39 +0200 Subject: [PATCH 339/465] Add `Item::def_id` helper --- src/librustdoc/clean/types.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index fc5f03568a942..5f5cade67a2b7 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -358,15 +358,15 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool { impl Item { pub(crate) fn stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option { - self.item_id.as_def_id().and_then(|did| tcx.lookup_stability(did)) + self.def_id().and_then(|did| tcx.lookup_stability(did)) } pub(crate) fn const_stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option { - self.item_id.as_def_id().and_then(|did| tcx.lookup_const_stability(did)) + self.def_id().and_then(|did| tcx.lookup_const_stability(did)) } pub(crate) fn deprecation(&self, tcx: TyCtxt<'_>) -> Option { - self.item_id.as_def_id().and_then(|did| tcx.lookup_deprecation(did)) + self.def_id().and_then(|did| tcx.lookup_deprecation(did)) } pub(crate) fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool { @@ -391,7 +391,7 @@ impl Item { panic!("blanket impl item has non-blanket ID") } } - _ => self.item_id.as_def_id().map(|did| rustc_span(did, tcx)), + _ => self.def_id().map(|did| rustc_span(did, tcx)), } } @@ -501,7 +501,7 @@ impl Item { } pub(crate) fn is_crate(&self) -> bool { - self.is_mod() && self.item_id.as_def_id().map_or(false, |did| did.is_crate_root()) + self.is_mod() && self.def_id().map_or(false, |did| did.is_crate_root()) } pub(crate) fn is_mod(&self) -> bool { self.type_() == ItemType::Module @@ -638,11 +638,11 @@ impl Item { } let header = match *self.kind { ItemKind::ForeignFunctionItem(_) => { - let def_id = self.item_id.as_def_id().unwrap(); + let def_id = self.def_id().unwrap(); let abi = tcx.fn_sig(def_id).skip_binder().abi(); hir::FnHeader { unsafety: if abi == Abi::RustIntrinsic { - intrinsic_operation_unsafety(tcx, self.item_id.as_def_id().unwrap()) + intrinsic_operation_unsafety(tcx, self.def_id().unwrap()) } else { hir::Unsafety::Unsafe }, @@ -659,7 +659,7 @@ impl Item { } } ItemKind::FunctionItem(_) | ItemKind::MethodItem(_, _) | ItemKind::TyMethodItem(_) => { - let def_id = self.item_id.as_def_id().unwrap(); + let def_id = self.def_id().unwrap(); build_fn_header(def_id, tcx, tcx.asyncness(def_id)) } _ => return None, @@ -738,7 +738,7 @@ impl Item { } }) .collect(); - if let Some(def_id) = self.item_id.as_def_id() && + if let Some(def_id) = self.def_id() && !def_id.is_local() && // This check is needed because `adt_def` will panic if not a compatible type otherwise... matches!(self.type_(), ItemType::Struct | ItemType::Enum | ItemType::Union) @@ -787,6 +787,10 @@ impl Item { pub fn is_doc_hidden(&self) -> bool { self.attrs.is_doc_hidden() } + + pub fn def_id(&self) -> Option { + self.item_id.as_def_id() + } } #[derive(Clone, Debug)] From 8fb4c41f35fee3b224ea87148cb2ae31a9ed4675 Mon Sep 17 00:00:00 2001 From: Ziru Niu Date: Wed, 31 May 2023 06:25:27 +0800 Subject: [PATCH 340/465] merge `BorrowKind::Unique` into `BorrowKind::Mut` --- compiler/rustc_borrowck/src/borrow_set.rs | 2 +- .../src/diagnostics/conflict_errors.rs | 40 ++++++++++++------- .../rustc_borrowck/src/diagnostics/mod.rs | 6 +-- .../src/diagnostics/mutability_errors.rs | 4 +- compiler/rustc_borrowck/src/invalidation.rs | 13 +++--- compiler/rustc_borrowck/src/lib.rs | 38 +++++++----------- .../rustc_borrowck/src/places_conflict.rs | 6 ++- .../src/transform/check_consts/check.rs | 3 +- .../src/transform/check_consts/resolver.rs | 2 +- .../src/transform/promote_consts.rs | 4 +- compiler/rustc_middle/src/mir/mod.rs | 12 +++--- compiler/rustc_middle/src/mir/syntax.rs | 24 +++++------ compiler/rustc_middle/src/mir/tcx.rs | 5 --- compiler/rustc_middle/src/mir/visit.rs | 3 -- .../src/build/expr/as_rvalue.rs | 6 +-- .../rustc_mir_build/src/check_unsafety.rs | 20 ++++++---- compiler/rustc_mir_build/src/thir/cx/expr.rs | 16 +++++--- .../rustc_mir_build/src/thir/pattern/mod.rs | 2 +- .../rustc_mir_dataflow/src/elaborate_drops.rs | 2 +- compiler/rustc_mir_transform/src/inline.rs | 2 +- compiler/rustc_mir_transform/src/shim.rs | 4 +- 21 files changed, 109 insertions(+), 105 deletions(-) diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index 6be20b0974ddb..cf17b16b63aa4 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -72,7 +72,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> { let kind = match self.kind { mir::BorrowKind::Shared => "", mir::BorrowKind::Shallow => "shallow ", - mir::BorrowKind::Unique => "uniq ", + mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ", mir::BorrowKind::Mut { .. } => "mut ", }; write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index fd5c21cfdf627..ca7b092a8a764 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -15,8 +15,9 @@ use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory, - FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, - ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm, + FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind, Operand, Place, + PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, + VarBindingForm, }; use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty}; use rustc_middle::util::CallKind; @@ -926,7 +927,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // FIXME: supply non-"" `opt_via` when appropriate let first_borrow_desc; let mut err = match (gen_borrow_kind, issued_borrow.kind) { - (BorrowKind::Shared, BorrowKind::Mut { .. }) => { + ( + BorrowKind::Shared, + BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, + ) => { first_borrow_desc = "mutable "; self.cannot_reborrow_already_borrowed( span, @@ -940,7 +944,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { None, ) } - (BorrowKind::Mut { .. }, BorrowKind::Shared) => { + ( + BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, + BorrowKind::Shared, + ) => { first_borrow_desc = "immutable "; let mut err = self.cannot_reborrow_already_borrowed( span, @@ -962,7 +969,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err } - (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => { + ( + BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, + BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, + ) => { first_borrow_desc = "first "; let mut err = self.cannot_mutably_borrow_multiply( span, @@ -985,12 +995,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err } - (BorrowKind::Unique, BorrowKind::Unique) => { + ( + BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, + BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, + ) => { first_borrow_desc = "first "; self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None) } - (BorrowKind::Mut { .. } | BorrowKind::Unique, BorrowKind::Shallow) => { + (BorrowKind::Mut { .. }, BorrowKind::Shallow) => { if let Some(immutable_section_description) = self.classify_immutable_section(issued_borrow.assigned_place) { @@ -1004,7 +1017,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_spans.var_subdiag( None, &mut err, - Some(BorrowKind::Unique), + Some(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }), |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; match kind { @@ -1038,7 +1051,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - (BorrowKind::Unique, _) => { + (BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, _) => { first_borrow_desc = "first "; self.cannot_uniquely_borrow_by_one_closure( span, @@ -1052,7 +1065,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) } - (BorrowKind::Shared, BorrowKind::Unique) => { + (BorrowKind::Shared, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => { first_borrow_desc = "first "; self.cannot_reborrow_already_uniquely_borrowed( span, @@ -1067,7 +1080,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) } - (BorrowKind::Mut { .. }, BorrowKind::Unique) => { + (BorrowKind::Mut { .. }, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => { first_borrow_desc = "first "; self.cannot_reborrow_already_uniquely_borrowed( span, @@ -1085,10 +1098,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { (BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Shallow) | ( BorrowKind::Shallow, - BorrowKind::Mut { .. } - | BorrowKind::Unique - | BorrowKind::Shared - | BorrowKind::Shallow, + BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow, ) => unreachable!(), }; diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 1d3cc851888cf..931ee8767d9b5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -629,9 +629,9 @@ impl UseSpans<'_> { Some(kd) => match kd { rustc_middle::mir::BorrowKind::Shared | rustc_middle::mir::BorrowKind::Shallow - | rustc_middle::mir::BorrowKind::Unique => { - CaptureVarKind::Immut { kind_span: capture_kind_span } - } + | rustc_middle::mir::BorrowKind::Mut { + kind: rustc_middle::mir::MutBorrowKind::ClosureCapture, + } => CaptureVarKind::Immut { kind_span: capture_kind_span }, rustc_middle::mir::BorrowKind::Mut { .. } => { CaptureVarKind::Mut { kind_span: capture_kind_span } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 34d466db2b409..1ba490e9a01c2 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -234,7 +234,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { borrow_spans.var_subdiag( None, &mut err, - Some(mir::BorrowKind::Mut { allow_two_phase_borrow: false }), + Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }), |_kind, var_span| { let place = self.describe_any_place(access_place.as_ref()); crate::session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure { @@ -300,7 +300,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { _, mir::Rvalue::Ref( _, - mir::BorrowKind::Mut { allow_two_phase_borrow: false }, + mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }, _, ), )), diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index e4fbe6ea4f438..0152d89eb8366 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -255,7 +255,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) } BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), - BorrowKind::Unique | BorrowKind::Mut { .. } => { + BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); if allow_two_phase_borrow(bk) { (Deep, Reservation(wk)) @@ -273,7 +273,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { Mutability::Mut => ( Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut { - allow_two_phase_borrow: false, + kind: mir::MutBorrowKind::Default, })), ), Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), @@ -376,14 +376,11 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { } (Read(_), BorrowKind::Shallow | BorrowKind::Shared) - | ( - Read(ReadKind::Borrow(BorrowKind::Shallow)), - BorrowKind::Unique | BorrowKind::Mut { .. }, - ) => { + | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => { // Reads don't invalidate shared or shallow borrows } - (Read(_), BorrowKind::Unique | BorrowKind::Mut { .. }) => { + (Read(_), BorrowKind::Mut { .. }) => { // Reading from mere reservations of mutable-borrows is OK. if !is_active(&this.dominators, borrow, location) { // If the borrow isn't active yet, reads don't invalidate it @@ -425,7 +422,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { // only mutable borrows should be 2-phase assert!(match borrow.kind { BorrowKind::Shared | BorrowKind::Shallow => false, - BorrowKind::Unique | BorrowKind::Mut { .. } => true, + BorrowKind::Mut { .. } => true, }); self.access_place( diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 4fcdda311bfd3..d27dc542ad505 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -29,8 +29,8 @@ use rustc_infer::infer::{ InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt, }; use rustc_middle::mir::{ - traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand, - Place, PlaceElem, PlaceRef, VarDebugInfoContents, + traversal, Body, ClearCrossCrate, Local, Location, MutBorrowKind, Mutability, + NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, VarDebugInfoContents, }; use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; @@ -1071,10 +1071,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } (Read(_), BorrowKind::Shared | BorrowKind::Shallow) - | ( - Read(ReadKind::Borrow(BorrowKind::Shallow)), - BorrowKind::Unique | BorrowKind::Mut { .. }, - ) => Control::Continue, + | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => { + Control::Continue + } (Reservation(_), BorrowKind::Shallow | BorrowKind::Shared) => { // This used to be a future compatibility warning (to be @@ -1087,7 +1086,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Control::Continue } - (Read(kind), BorrowKind::Unique | BorrowKind::Mut { .. }) => { + (Read(kind), BorrowKind::Mut { .. }) => { // Reading from mere reservations of mutable-borrows is OK. if !is_active(this.dominators(), borrow, location) { assert!(allow_two_phase_borrow(borrow.kind)); @@ -1194,7 +1193,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) } BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), - BorrowKind::Unique | BorrowKind::Mut { .. } => { + BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); if allow_two_phase_borrow(bk) { (Deep, Reservation(wk)) @@ -1231,7 +1230,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Mutability::Mut => ( Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut { - allow_two_phase_borrow: false, + kind: MutBorrowKind::Default, })), ), Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), @@ -1565,7 +1564,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // only mutable borrows should be 2-phase assert!(match borrow.kind { BorrowKind::Shared | BorrowKind::Shallow => false, - BorrowKind::Unique | BorrowKind::Mut { .. } => true, + BorrowKind::Mut { .. } => true, }); self.access_place( @@ -1959,14 +1958,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let the_place_err; match kind { - Reservation(WriteKind::MutableBorrow( - borrow_kind @ (BorrowKind::Unique | BorrowKind::Mut { .. }), - )) - | Write(WriteKind::MutableBorrow( - borrow_kind @ (BorrowKind::Unique | BorrowKind::Mut { .. }), - )) => { + Reservation(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Mut { .. })) + | Write(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Mut { .. })) => { let is_local_mutation_allowed = match borrow_kind { - BorrowKind::Unique => LocalMutationIsAllowed::Yes, + BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => { + LocalMutationIsAllowed::Yes + } BorrowKind::Mut { .. } => is_local_mutation_allowed, BorrowKind::Shared | BorrowKind::Shallow => unreachable!(), }; @@ -2031,12 +2028,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return false; } Read( - ReadKind::Borrow( - BorrowKind::Unique - | BorrowKind::Mut { .. } - | BorrowKind::Shared - | BorrowKind::Shallow, - ) + ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow) | ReadKind::Copy, ) => { // Access authorized diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 25c485b814f4a..c83d045a94e18 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -4,7 +4,9 @@ use crate::ArtificialField; use crate::Overlap; use crate::{AccessDepth, Deep, Shallow}; use rustc_hir as hir; -use rustc_middle::mir::{Body, BorrowKind, Local, Place, PlaceElem, PlaceRef, ProjectionElem}; +use rustc_middle::mir::{ + Body, BorrowKind, Local, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem, +}; use rustc_middle::ty::{self, TyCtxt}; use std::cmp::max; use std::iter; @@ -35,7 +37,7 @@ pub fn places_conflict<'tcx>( tcx, body, borrow_place, - BorrowKind::Mut { allow_two_phase_borrow: true }, + BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow }, access_place.as_ref(), AccessDepth::Deep, bias, diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 2aaf1340eb409..ee85d12a27353 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -412,7 +412,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { BorrowKind::Shallow => { PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) } - BorrowKind::Unique => PlaceContext::MutatingUse(MutatingUseContext::Borrow), BorrowKind::Mut { .. } => { PlaceContext::MutatingUse(MutatingUseContext::Borrow) } @@ -457,7 +456,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } - Rvalue::Ref(_, kind @ (BorrowKind::Mut { .. } | BorrowKind::Unique), place) => { + Rvalue::Ref(_, kind @ BorrowKind::Mut { .. }, place) => { let ty = place.ty(self.body, self.tcx).ty; let is_allowed = match ty.kind() { // Inside a `static mut`, `&mut [...]` is allowed. diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs index 65fe164f8ec76..3a869f7f54721 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs @@ -103,7 +103,7 @@ where fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool { match kind { mir::BorrowKind::Mut { .. } => true, - mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => { + mir::BorrowKind::Shared | mir::BorrowKind::Shallow => { self.shared_borrow_allows_mutation(place) } } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index f02464c7f99b6..c1abc4b5e998c 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -454,7 +454,9 @@ impl<'tcx> Validator<'_, 'tcx> { match kind { // Reject these borrow types just to be safe. // FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase. - BorrowKind::Shallow | BorrowKind::Unique => return Err(Unpromotable), + BorrowKind::Shallow | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => { + return Err(Unpromotable); + } BorrowKind::Shared => { let has_mut_interior = self.qualif_local::(place.local); diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 6aa20dbed9294..7b61c375707ae 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2035,22 +2035,24 @@ impl<'tcx> Rvalue<'tcx> { impl BorrowKind { pub fn mutability(&self) -> Mutability { match *self { - BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => Mutability::Not, + BorrowKind::Shared | BorrowKind::Shallow => Mutability::Not, BorrowKind::Mut { .. } => Mutability::Mut, } } pub fn allows_two_phase_borrow(&self) -> bool { match *self { - BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false, - BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow, + BorrowKind::Shared | BorrowKind::Shallow => false, + BorrowKind::Mut { kind } => kind == MutBorrowKind::TwoPhaseBorrow, } } // FIXME: won't be used after diagnostic migration pub fn describe_mutability(&self) -> &str { match *self { - BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => "immutable", + BorrowKind::Shared + | BorrowKind::Shallow + | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => "immutable", BorrowKind::Mut { .. } => "mutable", } } @@ -2090,7 +2092,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { let kind_str = match borrow_kind { BorrowKind::Shared => "", BorrowKind::Shallow => "shallow ", - BorrowKind::Mut { .. } | BorrowKind::Unique => "mut ", + BorrowKind::Mut { .. } => "mut ", }; // When printing regions, add trailing space if necessary. diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 10f368fc41cf0..458672676e2dc 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -182,6 +182,16 @@ pub enum BorrowKind { /// We can also report errors with this kind of borrow differently. Shallow, + /// Data is mutable and not aliasable. + Mut { kind: MutBorrowKind }, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)] +#[derive(Hash, HashStable)] +pub enum MutBorrowKind { + Default, + /// this borrow arose from method-call auto-ref. (i.e., `adjustment::Adjust::Borrow`) + TwoPhaseBorrow, /// Data must be immutable but not aliasable. This kind of borrow /// cannot currently be expressed by the user and is used only in /// implicit closure bindings. It is needed when the closure is @@ -220,19 +230,7 @@ pub enum BorrowKind { /// immutable, but not aliasable. This solves the problem. For /// simplicity, we don't give users the way to express this /// borrow, it's just used when translating closures. - /// - // FIXME(#112072): This is wrong. Unique borrows are mutable borrows except - // that they do not require their pointee to be marked as a mutable. - // They should still be treated as mutable borrows in every other way, - // e.g. for variance or overlap checking. - Unique, - - /// Data is mutable and not aliasable. - Mut { - /// `true` if this borrow arose from method-call auto-ref - /// (i.e., `adjustment::Adjust::Borrow`). - allow_two_phase_borrow: bool, - }, + ClosureCapture, } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 4a16abdd4e38f..65dff193c8067 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -269,11 +269,6 @@ impl BorrowKind { BorrowKind::Mut { .. } => hir::Mutability::Mut, BorrowKind::Shared => hir::Mutability::Not, - // We have no type corresponding to a unique imm borrow, so - // use `&mut`. It gives all the capabilities of a `&uniq` - // and hence is a safe "over approximation". - BorrowKind::Unique => hir::Mutability::Mut, - // We have no type corresponding to a shallow borrow, so use // `&` as an approximation. BorrowKind::Shallow => hir::Mutability::Not, diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index ce55b770cbcb4..b030d1e6c3edf 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -650,9 +650,6 @@ macro_rules! make_mir_visitor { BorrowKind::Shallow => PlaceContext::NonMutatingUse( NonMutatingUseContext::ShallowBorrow ), - BorrowKind::Unique => PlaceContext::MutatingUse( - MutatingUseContext::Borrow - ), BorrowKind::Mut { .. } => PlaceContext::MutatingUse(MutatingUseContext::Borrow), }; diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index fd08b32807c40..ec00f9a96be20 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -442,7 +442,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match upvar.kind { ExprKind::Borrow { borrow_kind: - BorrowKind::Mut { allow_two_phase_borrow: false }, + BorrowKind::Mut { kind: MutBorrowKind::Default }, arg, } => unpack!( block = this.limit_capture_mutability( @@ -795,8 +795,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let borrow_kind = match mutability { - Mutability::Not => BorrowKind::Unique, - Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false }, + Mutability::Not => BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, + Mutability::Mut => BorrowKind::Mut { kind: MutBorrowKind::Default }, }; let arg_place = arg_place_builder.to_place(this); diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 0506f2bf2385c..f7ef8485582fd 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -3,7 +3,7 @@ use crate::errors::*; use rustc_middle::thir::visit::{self, Visitor}; use rustc_hir as hir; -use rustc_middle::mir::BorrowKind; +use rustc_middle::mir::{BorrowKind, MutBorrowKind}; use rustc_middle::thir::*; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; @@ -254,7 +254,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { ); }; match borrow_kind { - BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => { + BorrowKind::Shallow + | BorrowKind::Shared + | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => { if !ty.is_freeze(self.tcx, self.param_env) { self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField); } @@ -440,15 +442,19 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { visit::walk_expr(&mut visitor, expr); if visitor.found { match borrow_kind { - BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique + BorrowKind::Shallow + | BorrowKind::Shared + | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) => { self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField) } - BorrowKind::Mut { .. } => { - self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField) - } - BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => {} + BorrowKind::Mut { + kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow, + } => self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField), + BorrowKind::Shallow + | BorrowKind::Shared + | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => {} } } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index b20495d602e59..7f0c2e9ca3fb2 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1095,8 +1095,12 @@ impl<'tcx> Cx<'tcx> { ty::UpvarCapture::ByRef(upvar_borrow) => { let borrow_kind = match upvar_borrow { ty::BorrowKind::ImmBorrow => BorrowKind::Shared, - ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique, - ty::BorrowKind::MutBorrow => BorrowKind::Mut { allow_two_phase_borrow: false }, + ty::BorrowKind::UniqueImmBorrow => { + BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } + } + ty::BorrowKind::MutBorrow => { + BorrowKind::Mut { kind: mir::MutBorrowKind::Default } + } }; Expr { temp_lifetime, @@ -1132,9 +1136,9 @@ impl ToBorrowKind for AutoBorrowMutability { use rustc_middle::ty::adjustment::AllowTwoPhase; match *self { AutoBorrowMutability::Mut { allow_two_phase_borrow } => BorrowKind::Mut { - allow_two_phase_borrow: match allow_two_phase_borrow { - AllowTwoPhase::Yes => true, - AllowTwoPhase::No => false, + kind: match allow_two_phase_borrow { + AllowTwoPhase::Yes => mir::MutBorrowKind::TwoPhaseBorrow, + AllowTwoPhase::No => mir::MutBorrowKind::Default, }, }, AutoBorrowMutability::Not => BorrowKind::Shared, @@ -1145,7 +1149,7 @@ impl ToBorrowKind for AutoBorrowMutability { impl ToBorrowKind for hir::Mutability { fn to_borrow_kind(&self) -> BorrowKind { match *self { - hir::Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false }, + hir::Mutability::Mut => BorrowKind::Mut { kind: mir::MutBorrowKind::Default }, hir::Mutability::Not => BorrowKind::Shared, } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 8eeb055ed82d0..c30c4b659392c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -287,7 +287,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { ty::BindByValue(mutbl) => (mutbl, BindingMode::ByValue), ty::BindByReference(hir::Mutability::Mut) => ( Mutability::Not, - BindingMode::ByRef(BorrowKind::Mut { allow_two_phase_borrow: false }), + BindingMode::ByRef(BorrowKind::Mut { kind: mir::MutBorrowKind::Default }), ), ty::BindByReference(hir::Mutability::Not) => { (Mutability::Not, BindingMode::ByRef(BorrowKind::Shared)) diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 27232b70d960b..c0102b15a1611 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -638,7 +638,7 @@ where Place::from(ref_place), Rvalue::Ref( tcx.lifetimes.re_erased, - BorrowKind::Mut { allow_two_phase_borrow: false }, + BorrowKind::Mut { kind: MutBorrowKind::Default }, self.place, ), )], diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index b28fed7159f1e..703824f5bdacf 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -522,7 +522,7 @@ impl<'tcx> Inliner<'tcx> { trace!("creating temp for return destination"); let dest = Rvalue::Ref( self.tcx.lifetimes.re_erased, - BorrowKind::Mut { allow_two_phase_borrow: false }, + BorrowKind::Mut { kind: MutBorrowKind::Default }, destination, ); let dest_ty = dest.ty(caller_body, self.tcx); diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 9d6ef9db4ea1b..2ae5ec4d9e6c8 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -188,7 +188,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) // has been put into the body. let reborrow = Rvalue::Ref( tcx.lifetimes.re_erased, - BorrowKind::Mut { allow_two_phase_borrow: false }, + BorrowKind::Mut { kind: MutBorrowKind::Default }, tcx.mk_place_deref(dropee_ptr), ); let ref_ty = reborrow.ty(body.local_decls(), tcx); @@ -712,7 +712,7 @@ fn build_call_shim<'tcx>( ) .immutable(), ); - let borrow_kind = BorrowKind::Mut { allow_two_phase_borrow: false }; + let borrow_kind = BorrowKind::Mut { kind: MutBorrowKind::Default }; statements.push(Statement { source_info, kind: StatementKind::Assign(Box::new(( From a52cc0a8c967253e0f61c7f77c820ab6e1f2e73e Mon Sep 17 00:00:00 2001 From: Ziru Niu Date: Wed, 31 May 2023 19:13:13 +0800 Subject: [PATCH 341/465] address most easy comments --- compiler/rustc_borrowck/src/borrow_set.rs | 5 ++++- .../rustc_borrowck/src/diagnostics/mod.rs | 7 +++---- compiler/rustc_borrowck/src/lib.rs | 15 +++++++------- .../src/transform/check_consts/check.rs | 8 ++------ .../src/transform/promote_consts.rs | 4 +++- compiler/rustc_middle/src/mir/mod.rs | 14 ++++--------- compiler/rustc_middle/src/ty/closure.rs | 2 ++ .../rustc_mir_build/src/check_unsafety.rs | 20 +++++++------------ 8 files changed, 33 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index cf17b16b63aa4..0b44beeb004c4 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -73,7 +73,10 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> { mir::BorrowKind::Shared => "", mir::BorrowKind::Shallow => "shallow ", mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ", - mir::BorrowKind::Mut { .. } => "mut ", + // FIXME: differentiate `TwoPhaseBorrow` + mir::BorrowKind::Mut { + kind: mir::MutBorrowKind::Default | mir::MutBorrowKind::TwoPhaseBorrow, + } => "mut ", }; write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place) } diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 931ee8767d9b5..2f8c970f806d3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -628,10 +628,9 @@ impl UseSpans<'_> { err.subdiagnostic(match kind { Some(kd) => match kd { rustc_middle::mir::BorrowKind::Shared - | rustc_middle::mir::BorrowKind::Shallow - | rustc_middle::mir::BorrowKind::Mut { - kind: rustc_middle::mir::MutBorrowKind::ClosureCapture, - } => CaptureVarKind::Immut { kind_span: capture_kind_span }, + | rustc_middle::mir::BorrowKind::Shallow => { + CaptureVarKind::Immut { kind_span: capture_kind_span } + } rustc_middle::mir::BorrowKind::Mut { .. } => { CaptureVarKind::Mut { kind_span: capture_kind_span } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index d27dc542ad505..be3a3b777971a 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1958,14 +1958,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let the_place_err; match kind { - Reservation(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Mut { .. })) - | Write(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Mut { .. })) => { - let is_local_mutation_allowed = match borrow_kind { - BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => { - LocalMutationIsAllowed::Yes + Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) + | Write(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) => { + let is_local_mutation_allowed = match mut_borrow_kind { + // `ClosureCapture` is used for mutable variable with a immutable binding. + // This is only behaviour difference between `ClosureCapture` and mutable borrows. + MutBorrowKind::ClosureCapture => LocalMutationIsAllowed::Yes, + MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow => { + is_local_mutation_allowed } - BorrowKind::Mut { .. } => is_local_mutation_allowed, - BorrowKind::Shared | BorrowKind::Shallow => unreachable!(), }; match self.is_mutable(place.as_ref(), is_local_mutation_allowed) { Ok(root_place) => { diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index ee85d12a27353..33c79ad7e5535 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -456,7 +456,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } - Rvalue::Ref(_, kind @ BorrowKind::Mut { .. }, place) => { + Rvalue::Ref(_, BorrowKind::Mut { .. }, place) => { let ty = place.ty(self.body, self.tcx).ty; let is_allowed = match ty.kind() { // Inside a `static mut`, `&mut [...]` is allowed. @@ -477,11 +477,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { }; if !is_allowed { - if let BorrowKind::Mut { .. } = kind { - self.check_mut_borrow(place.local, hir::BorrowKind::Ref) - } else { - self.check_op(ops::CellBorrow); - } + self.check_mut_borrow(place.local, hir::BorrowKind::Ref) } } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index c1abc4b5e998c..dd80f745c2f0a 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -465,7 +465,9 @@ impl<'tcx> Validator<'_, 'tcx> { } } - BorrowKind::Mut { .. } => { + // FIXME: consider changing this to only promote &mut [] for default borrows, + // also forbidding two phase borrows + BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow } => { let ty = place.ty(self.body, self.tcx).ty; // In theory, any zero-sized value could be borrowed diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 7b61c375707ae..669c609d99579 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2041,19 +2041,13 @@ impl BorrowKind { } pub fn allows_two_phase_borrow(&self) -> bool { - match *self { - BorrowKind::Shared | BorrowKind::Shallow => false, - BorrowKind::Mut { kind } => kind == MutBorrowKind::TwoPhaseBorrow, - } - } - - // FIXME: won't be used after diagnostic migration - pub fn describe_mutability(&self) -> &str { match *self { BorrowKind::Shared | BorrowKind::Shallow - | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => "immutable", - BorrowKind::Mut { .. } => "mutable", + | BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => { + false + } + BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow } => true, } } } diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index be7b2b7ec671a..bc9273745491b 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -427,6 +427,8 @@ pub enum BorrowKind { /// immutable, but not aliasable. This solves the problem. For /// simplicity, we don't give users the way to express this /// borrow, it's just used when translating closures. + /// + /// FIXME: Rename this to indicate the borrow is actually not immutable. UniqueImmBorrow, /// Data is mutable and not aliasable. diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index f7ef8485582fd..4f3a574031dbc 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -3,7 +3,7 @@ use crate::errors::*; use rustc_middle::thir::visit::{self, Visitor}; use rustc_hir as hir; -use rustc_middle::mir::{BorrowKind, MutBorrowKind}; +use rustc_middle::mir::BorrowKind; use rustc_middle::thir::*; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; @@ -254,9 +254,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { ); }; match borrow_kind { - BorrowKind::Shallow - | BorrowKind::Shared - | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => { + BorrowKind::Shallow | BorrowKind::Shared => { if !ty.is_freeze(self.tcx, self.param_env) { self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField); } @@ -442,19 +440,15 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { visit::walk_expr(&mut visitor, expr); if visitor.found { match borrow_kind { - BorrowKind::Shallow - | BorrowKind::Shared - | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } + BorrowKind::Shallow | BorrowKind::Shared if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) => { self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField) } - BorrowKind::Mut { - kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow, - } => self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField), - BorrowKind::Shallow - | BorrowKind::Shared - | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => {} + BorrowKind::Mut { .. } => { + self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField) + } + BorrowKind::Shallow | BorrowKind::Shared => {} } } } From b8a250fc4f053636c481b7543cfaa1fab2df48ad Mon Sep 17 00:00:00 2001 From: Ziru Niu Date: Wed, 7 Jun 2023 15:44:32 +0800 Subject: [PATCH 342/465] update comment on `MutBorrowKind::ClosureCapture` --- compiler/rustc_middle/src/mir/syntax.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 458672676e2dc..abb3b3d953be0 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -190,7 +190,7 @@ pub enum BorrowKind { #[derive(Hash, HashStable)] pub enum MutBorrowKind { Default, - /// this borrow arose from method-call auto-ref. (i.e., `adjustment::Adjust::Borrow`) + /// This borrow arose from method-call auto-ref. (i.e., `adjustment::Adjust::Borrow`) TwoPhaseBorrow, /// Data must be immutable but not aliasable. This kind of borrow /// cannot currently be expressed by the user and is used only in @@ -226,9 +226,12 @@ pub enum MutBorrowKind { /// user code, if awkward, but extra weird for closures, since the /// borrow is hidden. /// - /// So we introduce a "unique imm" borrow -- the referent is - /// immutable, but not aliasable. This solves the problem. For - /// simplicity, we don't give users the way to express this + /// So we introduce a `ClosureCapture` borrow -- user will not have to mark the variable + /// containing the mutable reference as `mut`, as they didn't ever + /// intend to mutate the mutable reference itself. We still mutable capture it in order to + /// mutate the pointed value through it (but not mutating the reference itself). + /// + /// This solves the problem. For simplicity, we don't give users the way to express this /// borrow, it's just used when translating closures. ClosureCapture, } From 74aad5ce56e685761ed6ea791c542a0097c7b4d7 Mon Sep 17 00:00:00 2001 From: Neven Villani Date: Tue, 20 Jun 2023 16:30:44 +0200 Subject: [PATCH 343/465] `Adt` for `Unique` may contain a reference --- compiler/rustc_mir_transform/src/add_retag.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index 187d38b385be3..d9e7339f1b274 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -28,6 +28,7 @@ fn may_contain_reference<'tcx>(ty: Ty<'tcx>, depth: u32, tcx: TyCtxt<'tcx>) -> b // References ty::Ref(..) => true, ty::Adt(..) if ty.is_box() => true, + ty::Adt(adt, _) if Some(adt.did()) == tcx.lang_items().ptr_unique() => true, // Compound types: recurse ty::Array(ty, _) | ty::Slice(ty) => { // This does not branch so we keep the depth the same. From 629b50928c3a64196c4df40a3ea6a886179824be Mon Sep 17 00:00:00 2001 From: bohan Date: Tue, 20 Jun 2023 22:47:50 +0800 Subject: [PATCH 344/465] Revert "Rollup merge of #112758 - bvanjoi:clean-up-resolve, r=petrochenkov" This reverts commit 3b059e0fdbf0257ac4921552781d070e8288233a, reversing changes made to d70be670474c98e62eefc67674b7bb3c7c4f5053. --- compiler/rustc_resolve/src/imports.rs | 93 +++++++++++++++------------ 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 23ef9bf53a195..47d8e5993fd82 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -304,23 +304,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let res = binding.res(); self.check_reserved_macro_name(key.ident, res); self.set_binding_parent_module(binding, module); - - let mut resolution = self.resolution(module, key).borrow_mut(); - let old_binding = resolution.binding(); - let mut t = Ok(()); - if let Some(old_binding) = resolution.binding { - if res == Res::Err && old_binding.res() != Res::Err { - // Do not override real bindings with `Res::Err`s from error recovery. - } else { + self.update_resolution(module, key, |this, resolution| { + if let Some(old_binding) = resolution.binding { + if res == Res::Err && old_binding.res() != Res::Err { + // Do not override real bindings with `Res::Err`s from error recovery. + return Ok(()); + } match (old_binding.is_glob_import(), binding.is_glob_import()) { (true, true) => { if res != old_binding.res() { - resolution.binding = Some(self.ambiguity( + resolution.binding = Some(this.ambiguity( AmbiguityKind::GlobVsGlob, old_binding, binding, )); - } else if !old_binding.vis.is_at_least(binding.vis, self.tcx) { + } else if !old_binding.vis.is_at_least(binding.vis, this.tcx) { // We are glob-importing the same item but with greater visibility. resolution.binding = Some(binding); } @@ -332,7 +330,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { && key.ns == MacroNS && nonglob_binding.expansion != LocalExpnId::ROOT { - resolution.binding = Some(self.ambiguity( + resolution.binding = Some(this.ambiguity( AmbiguityKind::GlobVsExpanded, nonglob_binding, glob_binding, @@ -344,12 +342,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if let Some(old_binding) = resolution.shadowed_glob { assert!(old_binding.is_glob_import()); if glob_binding.res() != old_binding.res() { - resolution.shadowed_glob = Some(self.ambiguity( + resolution.shadowed_glob = Some(this.ambiguity( AmbiguityKind::GlobVsGlob, old_binding, glob_binding, )); - } else if !old_binding.vis.is_at_least(binding.vis, self.tcx) { + } else if !old_binding.vis.is_at_least(binding.vis, this.tcx) { resolution.shadowed_glob = Some(glob_binding); } } else { @@ -357,27 +355,53 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } (false, false) => { - t = Err(old_binding); + return Err(old_binding); } } + } else { + resolution.binding = Some(binding); } - } else { - resolution.binding = Some(binding); - }; + Ok(()) + }) + } + + fn ambiguity( + &self, + kind: AmbiguityKind, + primary_binding: &'a NameBinding<'a>, + secondary_binding: &'a NameBinding<'a>, + ) -> &'a NameBinding<'a> { + self.arenas.alloc_name_binding(NameBinding { + ambiguity: Some((secondary_binding, kind)), + ..primary_binding.clone() + }) + } + + // Use `f` to mutate the resolution of the name in the module. + // If the resolution becomes a success, define it in the module's glob importers. + fn update_resolution(&mut self, module: Module<'a>, key: BindingKey, f: F) -> T + where + F: FnOnce(&mut Resolver<'a, 'tcx>, &mut NameResolution<'a>) -> T, + { // Ensure that `resolution` isn't borrowed when defining in the module's glob importers, // during which the resolution might end up getting re-defined via a glob cycle. - let (binding, t) = match resolution.binding() { - _ if old_binding.is_some() => return t, - None => return t, - Some(binding) => match old_binding { - Some(old_binding) if ptr::eq(old_binding, binding) => return t, - _ => (binding, t), - }, + let (binding, t) = { + let resolution = &mut *self.resolution(module, key).borrow_mut(); + let old_binding = resolution.binding(); + + let t = f(self, resolution); + + match resolution.binding() { + _ if old_binding.is_some() => return t, + None => return t, + Some(binding) => match old_binding { + Some(old_binding) if ptr::eq(old_binding, binding) => return t, + _ => (binding, t), + }, + } }; - drop(resolution); - // Define `binding` in `module`s glob importers. for import in module.glob_importers.borrow_mut().iter() { let mut ident = key.ident; @@ -396,18 +420,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { t } - fn ambiguity( - &self, - kind: AmbiguityKind, - primary_binding: &'a NameBinding<'a>, - secondary_binding: &'a NameBinding<'a>, - ) -> &'a NameBinding<'a> { - self.arenas.alloc_name_binding(NameBinding { - ambiguity: Some((secondary_binding, kind)), - ..primary_binding.clone() - }) - } - // Define a dummy resolution containing a `Res::Err` as a placeholder for a failed // or indeterminate resolution, also mark such failed imports as used to avoid duplicate diagnostics. fn import_dummy_binding(&mut self, import: &'a Import<'a>, is_indeterminate: bool) { @@ -757,8 +769,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .emit(); } let key = BindingKey::new(target, ns); - let mut resolution = this.resolution(parent, key).borrow_mut(); - resolution.single_imports.remove(&Interned::new_unchecked(import)); + this.update_resolution(parent, key, |_, resolution| { + resolution.single_imports.remove(&Interned::new_unchecked(import)); + }); } } } From 09d4a823d5242cf37ecb03c4aa3acf70f563b118 Mon Sep 17 00:00:00 2001 From: bohan Date: Tue, 20 Jun 2023 22:54:12 +0800 Subject: [PATCH 345/465] test(resolve): update_resolution for remove single import --- .../ui/resolve/auxiliary/issue-112831-aux.rs | 13 ++++++++++++ tests/ui/resolve/issue-112831.rs | 20 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 tests/ui/resolve/auxiliary/issue-112831-aux.rs create mode 100644 tests/ui/resolve/issue-112831.rs diff --git a/tests/ui/resolve/auxiliary/issue-112831-aux.rs b/tests/ui/resolve/auxiliary/issue-112831-aux.rs new file mode 100644 index 0000000000000..df436fb99297e --- /dev/null +++ b/tests/ui/resolve/auxiliary/issue-112831-aux.rs @@ -0,0 +1,13 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +struct Zeroable; + +#[proc_macro_derive(Zeroable)] +pub fn derive_zeroable(_: proc_macro::TokenStream) -> proc_macro::TokenStream { + proc_macro::TokenStream::default() +} diff --git a/tests/ui/resolve/issue-112831.rs b/tests/ui/resolve/issue-112831.rs new file mode 100644 index 0000000000000..ffd83ea8bc104 --- /dev/null +++ b/tests/ui/resolve/issue-112831.rs @@ -0,0 +1,20 @@ +// check-pass +// aux-build:issue-112831-aux.rs + +mod zeroable { + pub trait Zeroable {} +} + +use zeroable::*; + +mod pod { + use super::*; + pub trait Pod: Zeroable {} +} + +use pod::*; + +extern crate issue_112831_aux; +use issue_112831_aux::Zeroable; + +fn main() {} From db95734b9d41e00c17bb934b96ffd8cb660a2248 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 19 Jun 2023 21:17:57 +0200 Subject: [PATCH 346/465] Fix invalid creation of files in rustdoc --- src/librustdoc/formats/cache.rs | 5 ++++ src/librustdoc/html/render/context.rs | 41 ++++++++++++++++++++++----- src/librustdoc/visit_ast.rs | 7 +++-- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 8aaad8bce1b6e..dac762e9ff9f6 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -121,6 +121,11 @@ pub(crate) struct Cache { pub(crate) intra_doc_links: FxHashMap>, /// Cfg that have been hidden via #![doc(cfg_hide(...))] pub(crate) hidden_cfg: FxHashSet, + + /// Contains the list of `DefId`s which have been inlined. It is used when generating files + /// to check if a stripped item should get its file generated or not: if it's inside a + /// `#[doc(hidden)]` item or a private one and not inlined, it shouldn't get a file. + pub(crate) inlined_items: DefIdSet, } /// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`. diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 56af257fd5eb9..4c47626363518 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -73,6 +73,8 @@ pub(crate) struct Context<'tcx> { pub(crate) include_sources: bool, /// Collection of all types with notable traits referenced in the current module. pub(crate) types_with_notable_traits: FxHashSet, + /// Field used during rendering, to know if we're inside an inlined item. + pub(crate) is_inside_inlined_module: bool, } // `Context` is cloned a lot, so we don't want the size to grow unexpectedly. @@ -171,6 +173,19 @@ impl<'tcx> Context<'tcx> { } fn render_item(&mut self, it: &clean::Item, is_module: bool) -> String { + let mut render_redirect_pages = self.render_redirect_pages; + // If the item is stripped but inlined, links won't point to the item so no need to generate + // a file for it. + if it.is_stripped() && + let Some(def_id) = it.def_id() && + def_id.is_local() + { + if self.is_inside_inlined_module || self.shared.cache.inlined_items.contains(&def_id) { + // For now we're forced to generate a redirect page for stripped items until + // `record_extern_fqn` correctly points to external items. + render_redirect_pages = true; + } + } let mut title = String::new(); if !is_module { title.push_str(it.name.unwrap().as_str()); @@ -205,7 +220,7 @@ impl<'tcx> Context<'tcx> { tyname.as_str() }; - if !self.render_redirect_pages { + if !render_redirect_pages { let clone_shared = Rc::clone(&self.shared); let page = layout::Page { css_class: tyname_s, @@ -545,6 +560,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { shared: Rc::new(scx), include_sources, types_with_notable_traits: FxHashSet::default(), + is_inside_inlined_module: false, }; if emit_crate { @@ -574,6 +590,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { shared: Rc::clone(&self.shared), include_sources: self.include_sources, types_with_notable_traits: FxHashSet::default(), + is_inside_inlined_module: self.is_inside_inlined_module, } } @@ -768,12 +785,22 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { info!("Recursing into {}", self.dst.display()); - let buf = self.render_item(item, true); - // buf will be empty if the module is stripped and there is no redirect for it - if !buf.is_empty() { - self.shared.ensure_dir(&self.dst)?; - let joint_dst = self.dst.join("index.html"); - self.shared.fs.write(joint_dst, buf)?; + if !item.is_stripped() { + let buf = self.render_item(item, true); + // buf will be empty if the module is stripped and there is no redirect for it + if !buf.is_empty() { + self.shared.ensure_dir(&self.dst)?; + let joint_dst = self.dst.join("index.html"); + self.shared.fs.write(joint_dst, buf)?; + } + } + if !self.is_inside_inlined_module { + if let Some(def_id) = item.def_id() && self.cache().inlined_items.contains(&def_id) { + self.is_inside_inlined_module = true; + } + } else if item.is_doc_hidden() { + // We're not inside an inlined module anymore since this one cannot be re-exported. + self.is_inside_inlined_module = false; } // Render sidebar-items.js used throughout this module. diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 22c8cc092438c..fcf591a932896 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -313,7 +313,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { return false; } - let ret = match tcx.hir().get_by_def_id(res_did) { + let inlined = match tcx.hir().get_by_def_id(res_did) { // Bang macros are handled a bit on their because of how they are handled by the // compiler. If they have `#[doc(hidden)]` and the re-export doesn't have // `#[doc(inline)]`, then we don't inline it. @@ -344,7 +344,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { _ => false, }; self.view_item_stack.remove(&res_did); - ret + if inlined { + self.cx.cache.inlined_items.insert(res_did.to_def_id()); + } + inlined } /// Returns `true` if the item is visible, meaning it's not `#[doc(hidden)]` or private. From 214a0d1531cc74454b1af0a379b74436d73aa614 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 20 Jun 2023 22:19:38 +0100 Subject: [PATCH 347/465] Update cargo --- src/tools/cargo | 2 +- src/tools/tidy/src/deps.rs | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/tools/cargo b/src/tools/cargo index 0c14026aa84ee..dead4b8740c4b 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 0c14026aa84ee2ec4c67460c0a18abc8519ca6b2 +Subproject commit dead4b8740c4b6a8ed5211e37c99cf81d01c3b1c diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 0bc50c6413339..8db479af2861a 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -16,9 +16,6 @@ const LICENSES: &[&str] = &[ "Apache-2.0 OR MIT", "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", // wasi license "Apache-2.0/MIT", - "BSD-2-Clause", // arrayref from Cargo - "CC0-1.0 OR Apache-2.0", // blake3 from Cargo - "CC0-1.0 OR MIT-0 OR Apache-2.0", // constant_time_eq from cargo "ISC", "MIT / Apache-2.0", "MIT OR Apache-2.0 OR Zlib", // tinyvec_macros From 4ceca095869244ef3026fd90e2c5e10216be3fe7 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Sat, 10 Jun 2023 19:05:07 -0400 Subject: [PATCH 348/465] update failing ui tests --- ...e-70935-complex-spans.drop_tracking.stderr | 31 ++++++++++++------- ...935-complex-spans.drop_tracking_mir.stderr | 31 ++++++++++++------- ...0935-complex-spans.no_drop_tracking.stderr | 16 +++++----- .../async-await/issue-70935-complex-spans.rs | 17 ++++++---- tests/ui/closures/closure-move-sync.rs | 6 ---- tests/ui/closures/closure-move-sync.stderr | 20 +----------- tests/ui/stdlib-unit-tests/not-sync.rs | 2 -- tests/ui/stdlib-unit-tests/not-sync.stderr | 15 +-------- 8 files changed, 59 insertions(+), 79 deletions(-) diff --git a/tests/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr b/tests/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr index 721234aa4a782..f80bb4242aa70 100644 --- a/tests/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr +++ b/tests/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr @@ -1,18 +1,25 @@ -error[E0277]: `Sender` cannot be shared between threads safely - --> $DIR/issue-70935-complex-spans.rs:13:45 +error[E0277]: `*mut ()` cannot be shared between threads safely + --> $DIR/issue-70935-complex-spans.rs:18:23 | -LL | fn foo(tx: std::sync::mpsc::Sender) -> impl Future + Send { - | ^^^^^^^^^^^^^^^^^^ `Sender` cannot be shared between threads safely +LL | fn foo(x: NotSync) -> impl Future + Send { + | ^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `Sender` - = note: required for `&Sender` to implement `Send` + = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()` +note: required because it appears within the type `PhantomData<*mut ()>` + --> $SRC_DIR/core/src/marker.rs:LL:COL +note: required because it appears within the type `NotSync` + --> $DIR/issue-70935-complex-spans.rs:12:8 + | +LL | struct NotSync(PhantomData<*mut ()>); + | ^^^^^^^ + = note: required for `&NotSync` to implement `Send` note: required because it's used within this closure - --> $DIR/issue-70935-complex-spans.rs:17:13 + --> $DIR/issue-70935-complex-spans.rs:22:13 | -LL | baz(|| async{ +LL | baz(|| async { | ^^ note: required because it's used within this `async fn` body - --> $DIR/issue-70935-complex-spans.rs:10:67 + --> $DIR/issue-70935-complex-spans.rs:15:67 | LL | async fn baz(_c: impl FnMut() -> T) where T: Future { | ___________________________________________________________________^ @@ -20,11 +27,11 @@ LL | | } | |_^ = note: required because it captures the following types: `ResumeTy`, `impl Future`, `()` note: required because it's used within this `async` block - --> $DIR/issue-70935-complex-spans.rs:16:5 + --> $DIR/issue-70935-complex-spans.rs:21:5 | LL | / async move { -LL | | baz(|| async{ -LL | | foo(tx.clone()); +LL | | baz(|| async { +LL | | foo(x.clone()); LL | | }).await; LL | | } | |_____^ diff --git a/tests/ui/async-await/issue-70935-complex-spans.drop_tracking_mir.stderr b/tests/ui/async-await/issue-70935-complex-spans.drop_tracking_mir.stderr index c636be15a585c..eb9d93e229fb5 100644 --- a/tests/ui/async-await/issue-70935-complex-spans.drop_tracking_mir.stderr +++ b/tests/ui/async-await/issue-70935-complex-spans.drop_tracking_mir.stderr @@ -1,18 +1,25 @@ -error[E0277]: `Sender` cannot be shared between threads safely - --> $DIR/issue-70935-complex-spans.rs:13:45 +error[E0277]: `*mut ()` cannot be shared between threads safely + --> $DIR/issue-70935-complex-spans.rs:18:23 | -LL | fn foo(tx: std::sync::mpsc::Sender) -> impl Future + Send { - | ^^^^^^^^^^^^^^^^^^ `Sender` cannot be shared between threads safely +LL | fn foo(x: NotSync) -> impl Future + Send { + | ^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `Sender` - = note: required for `&Sender` to implement `Send` + = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()` +note: required because it appears within the type `PhantomData<*mut ()>` + --> $SRC_DIR/core/src/marker.rs:LL:COL +note: required because it appears within the type `NotSync` + --> $DIR/issue-70935-complex-spans.rs:12:8 + | +LL | struct NotSync(PhantomData<*mut ()>); + | ^^^^^^^ + = note: required for `&NotSync` to implement `Send` note: required because it's used within this closure - --> $DIR/issue-70935-complex-spans.rs:17:13 + --> $DIR/issue-70935-complex-spans.rs:22:13 | -LL | baz(|| async{ +LL | baz(|| async { | ^^ note: required because it's used within this `async fn` body - --> $DIR/issue-70935-complex-spans.rs:10:67 + --> $DIR/issue-70935-complex-spans.rs:15:67 | LL | async fn baz(_c: impl FnMut() -> T) where T: Future { | ___________________________________________________________________^ @@ -20,11 +27,11 @@ LL | | } | |_^ = note: required because it captures the following types: `impl Future` note: required because it's used within this `async` block - --> $DIR/issue-70935-complex-spans.rs:16:5 + --> $DIR/issue-70935-complex-spans.rs:21:5 | LL | / async move { -LL | | baz(|| async{ -LL | | foo(tx.clone()); +LL | | baz(|| async { +LL | | foo(x.clone()); LL | | }).await; LL | | } | |_____^ diff --git a/tests/ui/async-await/issue-70935-complex-spans.no_drop_tracking.stderr b/tests/ui/async-await/issue-70935-complex-spans.no_drop_tracking.stderr index ef0e182e5156f..d8ef6a5eedb7d 100644 --- a/tests/ui/async-await/issue-70935-complex-spans.no_drop_tracking.stderr +++ b/tests/ui/async-await/issue-70935-complex-spans.no_drop_tracking.stderr @@ -1,21 +1,21 @@ error: future cannot be sent between threads safely - --> $DIR/issue-70935-complex-spans.rs:13:45 + --> $DIR/issue-70935-complex-spans.rs:18:23 | -LL | fn foo(tx: std::sync::mpsc::Sender) -> impl Future + Send { - | ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` +LL | fn foo(x: NotSync) -> impl Future + Send { + | ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` | - = help: the trait `Sync` is not implemented for `Sender` + = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()` note: future is not `Send` as this value is used across an await - --> $DIR/issue-70935-complex-spans.rs:19:12 + --> $DIR/issue-70935-complex-spans.rs:24:12 | -LL | baz(|| async{ +LL | baz(|| async { | _____________- -LL | | foo(tx.clone()); +LL | | foo(x.clone()); LL | | }).await; | | - ^^^^^- the value is later dropped here | | | | | |_________| await occurs here, with the value maybe used later - | has type `[closure@$DIR/issue-70935-complex-spans.rs:17:13: 17:15]` which is not `Send` + | has type `[closure@$DIR/issue-70935-complex-spans.rs:22:13: 22:15]` which is not `Send` error: aborting due to previous error diff --git a/tests/ui/async-await/issue-70935-complex-spans.rs b/tests/ui/async-await/issue-70935-complex-spans.rs index 78625bd393d25..9ebde1d397733 100644 --- a/tests/ui/async-await/issue-70935-complex-spans.rs +++ b/tests/ui/async-await/issue-70935-complex-spans.rs @@ -6,16 +6,21 @@ // with newlines which lead complex diagnostics. use std::future::Future; +use std::marker::PhantomData; + +#[derive(Clone)] +struct NotSync(PhantomData<*mut ()>); +unsafe impl Send for NotSync {} async fn baz(_c: impl FnMut() -> T) where T: Future { } -fn foo(tx: std::sync::mpsc::Sender) -> impl Future + Send { +fn foo(x: NotSync) -> impl Future + Send { //[no_drop_tracking]~^ ERROR future cannot be sent between threads safely - //[drop_tracking,drop_tracking_mir]~^^ ERROR `Sender` cannot be shared between threads + //[drop_tracking,drop_tracking_mir]~^^ ERROR `*mut ()` cannot be shared between threads async move { - baz(|| async{ - foo(tx.clone()); + baz(|| async { + foo(x.clone()); }).await; } } @@ -24,6 +29,6 @@ fn bar(_s: impl Future + Send) { } fn main() { - let (tx, _rx) = std::sync::mpsc::channel(); - bar(foo(tx)); + let x = NotSync(PhantomData); + bar(foo(x)); } diff --git a/tests/ui/closures/closure-move-sync.rs b/tests/ui/closures/closure-move-sync.rs index ea2d1434c4ae7..3ee2b35f59fcc 100644 --- a/tests/ui/closures/closure-move-sync.rs +++ b/tests/ui/closures/closure-move-sync.rs @@ -13,10 +13,4 @@ fn bar() { t.join().unwrap(); } -fn foo() { - let (tx, _rx) = channel(); - thread::spawn(|| tx.send(()).unwrap()); - //~^ ERROR `Sender<()>` cannot be shared between threads safely -} - fn main() {} diff --git a/tests/ui/closures/closure-move-sync.stderr b/tests/ui/closures/closure-move-sync.stderr index 64e3b51ea713b..aee903ac9504a 100644 --- a/tests/ui/closures/closure-move-sync.stderr +++ b/tests/ui/closures/closure-move-sync.stderr @@ -20,24 +20,6 @@ LL | let t = thread::spawn(|| { note: required by a bound in `spawn` --> $SRC_DIR/std/src/thread/mod.rs:LL:COL -error[E0277]: `Sender<()>` cannot be shared between threads safely - --> $DIR/closure-move-sync.rs:18:19 - | -LL | thread::spawn(|| tx.send(()).unwrap()); - | ------------- ^^^^^^^^^^^^^^^^^^^^^^^ `Sender<()>` cannot be shared between threads safely - | | - | required by a bound introduced by this call - | - = help: the trait `Sync` is not implemented for `Sender<()>` - = note: required for `&Sender<()>` to implement `Send` -note: required because it's used within this closure - --> $DIR/closure-move-sync.rs:18:19 - | -LL | thread::spawn(|| tx.send(()).unwrap()); - | ^^ -note: required by a bound in `spawn` - --> $SRC_DIR/std/src/thread/mod.rs:LL:COL - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/stdlib-unit-tests/not-sync.rs b/tests/ui/stdlib-unit-tests/not-sync.rs index f4648994fa918..e9395ae9e81aa 100644 --- a/tests/ui/stdlib-unit-tests/not-sync.rs +++ b/tests/ui/stdlib-unit-tests/not-sync.rs @@ -17,6 +17,4 @@ fn main() { test::>(); //~^ ERROR `std::sync::mpsc::Receiver` cannot be shared between threads safely [E0277] - test::>(); - //~^ ERROR `Sender` cannot be shared between threads safely [E0277] } diff --git a/tests/ui/stdlib-unit-tests/not-sync.stderr b/tests/ui/stdlib-unit-tests/not-sync.stderr index 4e34e10e37789..b9a266e4eb9b9 100644 --- a/tests/ui/stdlib-unit-tests/not-sync.stderr +++ b/tests/ui/stdlib-unit-tests/not-sync.stderr @@ -65,19 +65,6 @@ note: required by a bound in `test` LL | fn test() {} | ^^^^ required by this bound in `test` -error[E0277]: `Sender` cannot be shared between threads safely - --> $DIR/not-sync.rs:20:12 - | -LL | test::>(); - | ^^^^^^^^^^^ `Sender` cannot be shared between threads safely - | - = help: the trait `Sync` is not implemented for `Sender` -note: required by a bound in `test` - --> $DIR/not-sync.rs:5:12 - | -LL | fn test() {} - | ^^^^ required by this bound in `test` - -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0277`. From bf27f12d941b2aea125bd629c1f30feaacf41cc6 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Tue, 20 Jun 2023 20:05:31 -0400 Subject: [PATCH 349/465] relaxed orderings in `thread::park` example --- library/std/src/thread/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 0f8b9c7668815..e9d94ba425a3a 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -893,7 +893,8 @@ pub fn sleep(dur: Duration) { /// /// Note that being unblocked does not imply a call was made to `unpark`, because /// wakeups can also be spurious. For example, a valid, but inefficient, -/// implementation could have `park` and `unpark` return immediately without doing anything. +/// implementation could have `park` and `unpark` return immediately without doing anything, +/// making *all* wakeups spurious. /// /// # Examples /// @@ -908,7 +909,7 @@ pub fn sleep(dur: Duration) { /// let parked_thread = thread::spawn(move || { /// // We want to wait until the flag is set. We *could* just spin, but using /// // park/unpark is more efficient. -/// while !flag2.load(Ordering::Acquire) { +/// while !flag2.load(Ordering::Relaxed) { /// println!("Parking thread"); /// thread::park(); /// // We *could* get here spuriously, i.e., way before the 10ms below are over! @@ -925,7 +926,7 @@ pub fn sleep(dur: Duration) { /// // There is no race condition here, if `unpark` /// // happens first, `park` will return immediately. /// // Hence there is no risk of a deadlock. -/// flag.store(true, Ordering::Release); +/// flag.store(true, Ordering::Relaxed); /// println!("Unpark the thread"); /// parked_thread.thread().unpark(); /// From 7201271fe8f8499eed8f20b282aca508ea53f855 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Wed, 21 Jun 2023 01:06:48 +0100 Subject: [PATCH 350/465] Fix typo in `eprintln` docs --- library/std/src/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index fcc5cfafd808d..ba1b8cbfa56df 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -154,7 +154,7 @@ macro_rules! println { /// /// Panics if writing to `io::stderr` fails. /// -/// Writing to non-blocking stdout can cause an error, which will lead +/// Writing to non-blocking stderr can cause an error, which will lead /// this macro to panic. /// /// # Examples @@ -189,7 +189,7 @@ macro_rules! eprint { /// /// Panics if writing to `io::stderr` fails. /// -/// Writing to non-blocking stdout can cause an error, which will lead +/// Writing to non-blocking stderr can cause an error, which will lead /// this macro to panic. /// /// # Examples From c696307a87cffb6eafee9469858450f116b26988 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 Jun 2023 17:01:51 +1000 Subject: [PATCH 351/465] Inline and remove `WorkItem::start_profiling` and `execute_work_item`. They both match on a `WorkItem`. It's simpler to do it all in one place. --- compiler/rustc_codegen_ssa/src/back/write.rs | 56 ++++++++------------ 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 109e9959aeac8..4ccef98afc3f6 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -11,9 +11,7 @@ use jobserver::{Acquired, Client}; use rustc_ast::attr; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::memmap::Mmap; -use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_data_structures::profiling::TimingGuard; -use rustc_data_structures::profiling::VerboseTimingGuard; +use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard}; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::Emitter; use rustc_errors::{translation::Translate, DiagnosticId, FatalError, Handler, Level}; @@ -705,20 +703,6 @@ impl WorkItem { } } - fn start_profiling<'a>(&self, cgcx: &'a CodegenContext) -> TimingGuard<'a> { - match *self { - WorkItem::Optimize(ref m) => { - cgcx.prof.generic_activity_with_arg("codegen_module_optimize", &*m.name) - } - WorkItem::CopyPostLtoArtifacts(ref m) => cgcx - .prof - .generic_activity_with_arg("codegen_copy_artifacts_from_incr_cache", &*m.name), - WorkItem::LTO(ref m) => { - cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", m.name()) - } - } - } - /// Generate a short description of this work item suitable for use as a thread name. fn short_description(&self) -> String { // `pthread_setname()` on *nix is limited to 15 characters and longer names are ignored. @@ -759,21 +743,6 @@ pub enum FatLTOInput { InMemory(ModuleCodegen), } -fn execute_work_item( - cgcx: &CodegenContext, - work_item: WorkItem, -) -> Result, FatalError> { - let module_config = cgcx.config(work_item.module_kind()); - - match work_item { - WorkItem::Optimize(module) => execute_optimize_work_item(cgcx, module, module_config), - WorkItem::CopyPostLtoArtifacts(module) => { - Ok(execute_copy_from_cache_work_item(cgcx, module, module_config)) - } - WorkItem::LTO(module) => execute_lto_work_item(cgcx, module, module_config), - } -} - /// Actual LTO type we end up choosing based on multiple factors. pub enum ComputedLtoType { No, @@ -1706,8 +1675,27 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem // as a diagnostic was already sent off to the main thread - just // surface that there was an error in this worker. bomb.result = { - let _prof_timer = work.start_profiling(&cgcx); - Some(execute_work_item(&cgcx, work)) + let module_config = cgcx.config(work.module_kind()); + + Some(match work { + WorkItem::Optimize(m) => { + let _timer = + cgcx.prof.generic_activity_with_arg("codegen_module_optimize", &*m.name); + execute_optimize_work_item(&cgcx, m, module_config) + } + WorkItem::CopyPostLtoArtifacts(m) => { + let _timer = cgcx.prof.generic_activity_with_arg( + "codegen_copy_artifacts_from_incr_cache", + &*m.name, + ); + Ok(execute_copy_from_cache_work_item(&cgcx, m, module_config)) + } + WorkItem::LTO(m) => { + let _timer = + cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", m.name()); + execute_lto_work_item(&cgcx, m, module_config) + } + }) }; }) .expect("failed to spawn thread"); From 1da13489247ed5b0b6694b2aabb0184f16b50afd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 21 Jun 2023 11:26:49 +1000 Subject: [PATCH 352/465] Remove Queries::ongoing_codegen. There's no need to store it in `Queries`. We can just use a local variable, because it's always used shortly after it's produced. The commit also removes the `tcx.analysis()` call in `ongoing_codegen`, because it's easy to ensure that's done beforehand. All this makes the dataflow within `run_compiler` easier to follow, at the cost of making one test slightly more verbose, which I think is a good tradeoff. --- compiler/rustc_driver_impl/src/lib.rs | 4 +-- compiler/rustc_interface/src/passes.rs | 4 +-- compiler/rustc_interface/src/queries.rs | 29 ++++++++-------------- tests/run-make-fulldeps/issue-19371/foo.rs | 11 ++++---- 4 files changed, 21 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 2f1c78197275d..0db96d4e735f6 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -424,7 +424,7 @@ fn run_compiler( return early_exit(); } - queries.ongoing_codegen()?; + let ongoing_codegen = queries.ongoing_codegen()?; if sess.opts.unstable_opts.print_type_sizes { sess.code_stats.print_type_sizes(); @@ -437,7 +437,7 @@ fn run_compiler( sess.code_stats.print_vtable_sizes(crate_name); } - let linker = queries.linker()?; + let linker = queries.linker(ongoing_codegen)?; Ok(Some(linker)) })?; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index be2af94961ffa..6b3facd041c28 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -740,8 +740,8 @@ pub fn create_global_ctxt<'tcx>( }) } -/// Runs the resolution, type-checking, region checking and other -/// miscellaneous analysis passes on the crate. +/// Runs the type-checking, region checking and other miscellaneous analysis +/// passes on the crate. fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { rustc_passes::hir_id_validator::check_crate(tcx); diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 455a8129656d4..d1ba748d7af4b 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -93,7 +93,6 @@ pub struct Queries<'tcx> { dep_graph: Query, // This just points to what's in `gcx_cell`. gcx: Query<&'tcx GlobalCtxt<'tcx>>, - ongoing_codegen: Query>, } impl<'tcx> Queries<'tcx> { @@ -110,7 +109,6 @@ impl<'tcx> Queries<'tcx> { register_plugins: Default::default(), dep_graph: Default::default(), gcx: Default::default(), - ongoing_codegen: Default::default(), } } @@ -249,23 +247,19 @@ impl<'tcx> Queries<'tcx> { }) } - pub fn ongoing_codegen(&'tcx self) -> Result>> { - self.ongoing_codegen.compute(|| { - self.global_ctxt()?.enter(|tcx| { - tcx.analysis(()).ok(); + pub fn ongoing_codegen(&'tcx self) -> Result> { + self.global_ctxt()?.enter(|tcx| { + // Don't do code generation if there were any errors + self.session().compile_status()?; - // Don't do code generation if there were any errors - self.session().compile_status()?; + // If we have any delayed bugs, for example because we created TyKind::Error earlier, + // it's likely that codegen will only cause more ICEs, obscuring the original problem + self.session().diagnostic().flush_delayed(); - // If we have any delayed bugs, for example because we created TyKind::Error earlier, - // it's likely that codegen will only cause more ICEs, obscuring the original problem - self.session().diagnostic().flush_delayed(); + // Hook for UI tests. + Self::check_for_rustc_errors_attr(tcx); - // Hook for UI tests. - Self::check_for_rustc_errors_attr(tcx); - - Ok(passes::start_codegen(&***self.codegen_backend(), tcx)) - }) + Ok(passes::start_codegen(&***self.codegen_backend(), tcx)) }) } @@ -303,7 +297,7 @@ impl<'tcx> Queries<'tcx> { } } - pub fn linker(&'tcx self) -> Result { + pub fn linker(&'tcx self, ongoing_codegen: Box) -> Result { let sess = self.session().clone(); let codegen_backend = self.codegen_backend().clone(); @@ -314,7 +308,6 @@ impl<'tcx> Queries<'tcx> { tcx.dep_graph.clone(), ) }); - let ongoing_codegen = self.ongoing_codegen()?.steal(); Ok(Linker { sess, diff --git a/tests/run-make-fulldeps/issue-19371/foo.rs b/tests/run-make-fulldeps/issue-19371/foo.rs index 6d08cfd07f89e..9cca6200050bd 100644 --- a/tests/run-make-fulldeps/issue-19371/foo.rs +++ b/tests/run-make-fulldeps/issue-19371/foo.rs @@ -63,10 +63,11 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) { }; interface::run_compiler(config, |compiler| { - // This runs all the passes prior to linking, too. - let linker = compiler.enter(|queries| queries.linker()); - if let Ok(linker) = linker { - linker.link(); - } + let linker = compiler.enter(|queries| { + queries.global_ctxt()?.enter(|tcx| tcx.analysis(()))?; + let ongoing_codegen = queries.ongoing_codegen()?; + queries.linker(ongoing_codegen) + }); + linker.unwrap().link(); }); } From fd4726f74041672c20e9e0753058bf7712dcff19 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 21 Jun 2023 09:14:47 +0200 Subject: [PATCH 353/465] remove needs-unwind attr for test with -Zpanic-abort-tests --- tests/ui/test-attrs/test-type.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/ui/test-attrs/test-type.rs b/tests/ui/test-attrs/test-type.rs index 9c7b8b96d6908..d6d44a6b4461b 100644 --- a/tests/ui/test-attrs/test-type.rs +++ b/tests/ui/test-attrs/test-type.rs @@ -3,7 +3,6 @@ // check-run-results // normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" // ignore-emscripten no threads support -// needs-unwind // run-pass #[test] From c409f05636437726251456297ff67c08ab0841aa Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 20 Jun 2023 10:04:34 +0000 Subject: [PATCH 354/465] Disable two mir opts that are known to be unsound --- .../rustc_mir_transform/src/const_goto.rs | 4 +- .../src/separate_const_switch.rs | 4 +- tests/mir-opt/const_goto_const_eval_fail.rs | 2 + ...ined_comparison.naive.PreCodegen.after.mir | 115 ++++++++++-------- ...variant_a-{closure#0}.PreCodegen.after.mir | 87 ++++++------- ...variant_b-{closure#0}.PreCodegen.after.mir | 43 ++++--- ...mut_range.PreCodegen.after.panic-abort.mir | 39 ++---- ...ut_range.PreCodegen.after.panic-unwind.mir | 39 ++---- tests/mir-opt/separate_const_switch.rs | 2 + 9 files changed, 164 insertions(+), 171 deletions(-) diff --git a/compiler/rustc_mir_transform/src/const_goto.rs b/compiler/rustc_mir_transform/src/const_goto.rs index 024bea620982a..e175f22d7a940 100644 --- a/compiler/rustc_mir_transform/src/const_goto.rs +++ b/compiler/rustc_mir_transform/src/const_goto.rs @@ -28,7 +28,9 @@ pub struct ConstGoto; impl<'tcx> MirPass<'tcx> for ConstGoto { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.mir_opt_level() >= 2 + // This pass participates in some as-of-yet untested unsoundness found + // in https://github.com/rust-lang/rust/issues/112460 + sess.mir_opt_level() >= 2 && sess.opts.unstable_opts.unsound_mir_opts } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index f35a5fb42768a..1d8e54cdca09d 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -46,7 +46,9 @@ pub struct SeparateConstSwitch; impl<'tcx> MirPass<'tcx> for SeparateConstSwitch { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.mir_opt_level() >= 2 + // This pass participates in some as-of-yet untested unsoundness found + // in https://github.com/rust-lang/rust/issues/112460 + sess.mir_opt_level() >= 2 && sess.opts.unstable_opts.unsound_mir_opts } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { diff --git a/tests/mir-opt/const_goto_const_eval_fail.rs b/tests/mir-opt/const_goto_const_eval_fail.rs index 3b85fe6ab3cd9..b2357663a90c4 100644 --- a/tests/mir-opt/const_goto_const_eval_fail.rs +++ b/tests/mir-opt/const_goto_const_eval_fail.rs @@ -1,6 +1,8 @@ #![feature(min_const_generics)] #![crate_type = "lib"] +// compile-flags: -Zunsound-mir-opts + // If const eval fails, then don't crash // EMIT_MIR const_goto_const_eval_fail.f.ConstGoto.diff pub fn f() -> u64 { diff --git a/tests/mir-opt/pre-codegen/chained_comparison.naive.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/chained_comparison.naive.PreCodegen.after.mir index 1c74ae74d53d5..c7fd397fcd4ff 100644 --- a/tests/mir-opt/pre-codegen/chained_comparison.naive.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/chained_comparison.naive.PreCodegen.after.mir @@ -7,26 +7,26 @@ fn naive(_1: &Blueprint, _2: &Blueprint) -> bool { let mut _3: u32; let mut _4: u32; let mut _5: bool; - let mut _6: u32; + let mut _6: bool; let mut _7: u32; - let mut _8: bool; + let mut _8: u32; let mut _9: bool; - let mut _10: u32; + let mut _10: bool; let mut _11: u32; - let mut _12: bool; + let mut _12: u32; let mut _13: bool; - let mut _14: u32; + let mut _14: bool; let mut _15: u32; - let mut _16: bool; + let mut _16: u32; let mut _17: bool; let mut _18: u32; let mut _19: u32; let mut _20: bool; bb0: { - StorageLive(_17); - StorageLive(_13); - StorageLive(_9); + StorageLive(_14); + StorageLive(_10); + StorageLive(_6); StorageLive(_5); StorageLive(_3); _3 = ((*_1).0: u32); @@ -39,74 +39,83 @@ fn naive(_1: &Blueprint, _2: &Blueprint) -> bool { } bb1: { - StorageDead(_8); - StorageDead(_5); + _6 = const false; goto -> bb3; } bb2: { - StorageLive(_8); - StorageLive(_6); - _6 = ((*_1).1: u32); + StorageLive(_9); StorageLive(_7); - _7 = ((*_2).1: u32); - _8 = Eq(move _6, move _7); - StorageDead(_7); - StorageDead(_6); - _9 = move _8; + _7 = ((*_1).1: u32); + StorageLive(_8); + _8 = ((*_2).1: u32); + _9 = Eq(move _7, move _8); StorageDead(_8); - StorageDead(_5); - switchInt(move _9) -> [0: bb3, otherwise: bb4]; + StorageDead(_7); + _6 = move _9; + goto -> bb3; } bb3: { - StorageDead(_12); StorageDead(_9); - goto -> bb5; + StorageDead(_5); + switchInt(move _6) -> [0: bb4, otherwise: bb5]; } bb4: { - StorageLive(_12); - StorageLive(_10); - _10 = ((*_1).2: u32); - StorageLive(_11); - _11 = ((*_2).2: u32); - _12 = Eq(move _10, move _11); - StorageDead(_11); - StorageDead(_10); - _13 = move _12; - StorageDead(_12); - StorageDead(_9); - switchInt(move _13) -> [0: bb5, otherwise: bb6]; + _10 = const false; + goto -> bb6; } bb5: { - StorageDead(_16); - StorageDead(_13); - goto -> bb7; + StorageLive(_13); + StorageLive(_11); + _11 = ((*_1).2: u32); + StorageLive(_12); + _12 = ((*_2).2: u32); + _13 = Eq(move _11, move _12); + StorageDead(_12); + StorageDead(_11); + _10 = move _13; + goto -> bb6; } bb6: { - StorageLive(_16); - StorageLive(_14); - _14 = ((*_1).3: u32); - StorageLive(_15); - _15 = ((*_2).3: u32); - _16 = Eq(move _14, move _15); - StorageDead(_15); - StorageDead(_14); - _17 = move _16; - StorageDead(_16); StorageDead(_13); - switchInt(move _17) -> [0: bb7, otherwise: bb8]; + StorageDead(_6); + switchInt(move _10) -> [0: bb7, otherwise: bb8]; } bb7: { - _0 = const false; + _14 = const false; goto -> bb9; } bb8: { + StorageLive(_17); + StorageLive(_15); + _15 = ((*_1).3: u32); + StorageLive(_16); + _16 = ((*_2).3: u32); + _17 = Eq(move _15, move _16); + StorageDead(_16); + StorageDead(_15); + _14 = move _17; + goto -> bb9; + } + + bb9: { + StorageDead(_17); + StorageDead(_10); + switchInt(move _14) -> [0: bb10, otherwise: bb11]; + } + + bb10: { + _0 = const false; + goto -> bb12; + } + + bb11: { StorageLive(_20); StorageLive(_18); _18 = ((*_1).4: u32); @@ -116,12 +125,12 @@ fn naive(_1: &Blueprint, _2: &Blueprint) -> bool { StorageDead(_19); StorageDead(_18); _0 = move _20; - goto -> bb9; + goto -> bb12; } - bb9: { + bb12: { StorageDead(_20); - StorageDead(_17); + StorageDead(_14); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir index 6c1d5096db00a..499bee2ae400a 100644 --- a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir @@ -14,10 +14,10 @@ fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:7:25: 7:39], _2 let _12: &usize; let mut _13: &&usize; let mut _18: bool; - let mut _19: &&usize; - let _20: &usize; - let mut _21: &&usize; - let mut _26: bool; + let mut _19: bool; + let mut _20: &&usize; + let _21: &usize; + let mut _22: &&usize; let mut _27: bool; let mut _28: &&usize; let _29: &usize; @@ -58,15 +58,15 @@ fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:7:25: 7:39], _2 } } scope 6 (inlined cmp::impls::::le) { - debug self => _19; - debug other => _21; - let mut _22: &usize; + debug self => _20; + debug other => _22; let mut _23: &usize; + let mut _24: &usize; scope 7 (inlined cmp::impls::::le) { - debug self => _22; - debug other => _23; - let mut _24: usize; + debug self => _23; + debug other => _24; let mut _25: usize; + let mut _26: usize; } } scope 8 (inlined cmp::impls::::le) { @@ -96,7 +96,7 @@ fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:7:25: 7:39], _2 StorageLive(_10); _9 = deref_copy (*_2); _10 = &((*_9).3: usize); - StorageLive(_27); + StorageLive(_19); StorageLive(_18); StorageLive(_11); _11 = &_4; @@ -120,38 +120,41 @@ fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:7:25: 7:39], _2 } bb1: { - StorageDead(_26); - StorageDead(_18); + _19 = const false; goto -> bb3; } bb2: { - StorageLive(_26); - StorageLive(_19); - _19 = &_10; - StorageLive(_21); + StorageLive(_27); StorageLive(_20); - _20 = _6; - _21 = &_20; - _22 = deref_copy (*_19); - _23 = deref_copy (*_21); - StorageLive(_24); - _24 = (*_22); + _20 = &_10; + StorageLive(_22); + StorageLive(_21); + _21 = _6; + _22 = &_21; + _23 = deref_copy (*_20); + _24 = deref_copy (*_22); StorageLive(_25); _25 = (*_23); - _26 = Le(move _24, move _25); + StorageLive(_26); + _26 = (*_24); + _27 = Le(move _25, move _26); + StorageDead(_26); StorageDead(_25); - StorageDead(_24); - StorageDead(_20); StorageDead(_21); - StorageDead(_19); - _27 = move _26; - StorageDead(_26); - StorageDead(_18); - switchInt(move _27) -> [0: bb3, otherwise: bb7]; + StorageDead(_22); + StorageDead(_20); + _19 = move _27; + goto -> bb3; } bb3: { + StorageDead(_27); + StorageDead(_18); + switchInt(move _19) -> [0: bb4, otherwise: bb8]; + } + + bb4: { StorageLive(_36); StorageLive(_35); StorageLive(_28); @@ -172,15 +175,15 @@ fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:7:25: 7:39], _2 StorageDead(_29); StorageDead(_30); StorageDead(_28); - switchInt(move _35) -> [0: bb4, otherwise: bb5]; + switchInt(move _35) -> [0: bb5, otherwise: bb6]; } - bb4: { + bb5: { _36 = const false; - goto -> bb6; + goto -> bb7; } - bb5: { + bb6: { StorageLive(_44); StorageLive(_37); _37 = &_6; @@ -201,24 +204,24 @@ fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:7:25: 7:39], _2 StorageDead(_39); StorageDead(_37); _36 = move _44; - goto -> bb6; + goto -> bb7; } - bb6: { + bb7: { StorageDead(_44); StorageDead(_35); _0 = move _36; - goto -> bb8; + goto -> bb9; } - bb7: { + bb8: { _0 = const true; - goto -> bb8; + goto -> bb9; } - bb8: { + bb9: { StorageDead(_36); - StorageDead(_27); + StorageDead(_19); StorageDead(_10); StorageDead(_8); StorageDead(_6); diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir index ef1036d5fafcd..bab9f0b58aae4 100644 --- a/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir @@ -32,61 +32,64 @@ fn variant_b::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:11:25: 11:41], _8 = ((*_7).2: usize); _9 = deref_copy (*_2); _10 = ((*_9).3: usize); - StorageLive(_13); + StorageLive(_12); StorageLive(_11); _11 = Le(_4, _8); switchInt(move _11) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageDead(_12); - StorageDead(_11); + _12 = const false; goto -> bb3; } bb2: { - StorageLive(_12); - _12 = Le(_10, _6); - _13 = move _12; - StorageDead(_12); - StorageDead(_11); - switchInt(move _13) -> [0: bb3, otherwise: bb7]; + StorageLive(_13); + _13 = Le(_10, _6); + _12 = move _13; + goto -> bb3; } bb3: { + StorageDead(_13); + StorageDead(_11); + switchInt(move _12) -> [0: bb4, otherwise: bb8]; + } + + bb4: { StorageLive(_15); StorageLive(_14); _14 = Le(_8, _4); - switchInt(move _14) -> [0: bb4, otherwise: bb5]; + switchInt(move _14) -> [0: bb5, otherwise: bb6]; } - bb4: { + bb5: { _15 = const false; - goto -> bb6; + goto -> bb7; } - bb5: { + bb6: { StorageLive(_16); _16 = Le(_6, _10); _15 = move _16; - goto -> bb6; + goto -> bb7; } - bb6: { + bb7: { StorageDead(_16); StorageDead(_14); _0 = move _15; - goto -> bb8; + goto -> bb9; } - bb7: { + bb8: { _0 = const true; - goto -> bb8; + goto -> bb9; } - bb8: { + bb9: { StorageDead(_15); - StorageDead(_13); + StorageDead(_12); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir index 9d914e95344e1..a337ca89992a6 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir @@ -17,50 +17,37 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> debug slice => _5; let mut _7: *mut u32; let mut _8: *mut u32; + let _14: usize; let _15: usize; - let _16: usize; scope 4 { - debug this => std::ops::Range{ .0 => _15, .1 => _16, }; + debug this => std::ops::Range{ .0 => _14, .1 => _15, }; scope 5 { let _6: usize; scope 6 { debug new_len => _6; - scope 11 (inlined ptr::mut_ptr::::as_mut_ptr) { + scope 7 (inlined ptr::mut_ptr::::as_mut_ptr) { debug self => _5; } - scope 12 (inlined ptr::mut_ptr::::add) { + scope 8 (inlined ptr::mut_ptr::::add) { debug self => _7; debug count => _3; - scope 13 { + scope 9 { } } - scope 14 (inlined slice_from_raw_parts_mut::) { + scope 10 (inlined slice_from_raw_parts_mut::) { debug data => _8; debug len => _6; let mut _9: *mut (); - scope 15 (inlined ptr::mut_ptr::::cast::<()>) { + scope 11 (inlined ptr::mut_ptr::::cast::<()>) { debug self => _8; } - scope 16 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { + scope 12 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { debug data_address => _9; debug metadata => _6; let mut _10: *const (); let mut _11: std::ptr::metadata::PtrComponents<[u32]>; let mut _12: std::ptr::metadata::PtrRepr<[u32]>; - scope 17 { - } - } - } - } - scope 7 (inlined as SliceIndex<[T]>>::get_unchecked_mut::runtime::) { - debug this => std::ops::Range{ .0 => _15, .1 => _16, }; - debug slice => _5; - scope 8 (inlined ptr::mut_ptr::::len) { - debug self => _5; - let mut _14: *const [u32]; - scope 9 (inlined std::ptr::metadata::<[u32]>) { - debug ptr => _14; - scope 10 { + scope 13 { } } } @@ -77,10 +64,9 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> StorageLive(_13); StorageLive(_5); _5 = &raw mut (*_1); - StorageLive(_6); StorageLive(_14); StorageLive(_15); - StorageLive(_16); + StorageLive(_6); _6 = SubUnchecked(_4, _3); StorageLive(_8); StorageLive(_7); @@ -101,10 +87,9 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> StorageDead(_12); StorageDead(_9); StorageDead(_8); - StorageDead(_16); - StorageDead(_15); - StorageDead(_14); StorageDead(_6); + StorageDead(_14); + StorageDead(_15); StorageDead(_5); _0 = &mut (*_13); StorageDead(_13); diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir index 9d914e95344e1..a337ca89992a6 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir @@ -17,50 +17,37 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> debug slice => _5; let mut _7: *mut u32; let mut _8: *mut u32; + let _14: usize; let _15: usize; - let _16: usize; scope 4 { - debug this => std::ops::Range{ .0 => _15, .1 => _16, }; + debug this => std::ops::Range{ .0 => _14, .1 => _15, }; scope 5 { let _6: usize; scope 6 { debug new_len => _6; - scope 11 (inlined ptr::mut_ptr::::as_mut_ptr) { + scope 7 (inlined ptr::mut_ptr::::as_mut_ptr) { debug self => _5; } - scope 12 (inlined ptr::mut_ptr::::add) { + scope 8 (inlined ptr::mut_ptr::::add) { debug self => _7; debug count => _3; - scope 13 { + scope 9 { } } - scope 14 (inlined slice_from_raw_parts_mut::) { + scope 10 (inlined slice_from_raw_parts_mut::) { debug data => _8; debug len => _6; let mut _9: *mut (); - scope 15 (inlined ptr::mut_ptr::::cast::<()>) { + scope 11 (inlined ptr::mut_ptr::::cast::<()>) { debug self => _8; } - scope 16 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { + scope 12 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { debug data_address => _9; debug metadata => _6; let mut _10: *const (); let mut _11: std::ptr::metadata::PtrComponents<[u32]>; let mut _12: std::ptr::metadata::PtrRepr<[u32]>; - scope 17 { - } - } - } - } - scope 7 (inlined as SliceIndex<[T]>>::get_unchecked_mut::runtime::) { - debug this => std::ops::Range{ .0 => _15, .1 => _16, }; - debug slice => _5; - scope 8 (inlined ptr::mut_ptr::::len) { - debug self => _5; - let mut _14: *const [u32]; - scope 9 (inlined std::ptr::metadata::<[u32]>) { - debug ptr => _14; - scope 10 { + scope 13 { } } } @@ -77,10 +64,9 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> StorageLive(_13); StorageLive(_5); _5 = &raw mut (*_1); - StorageLive(_6); StorageLive(_14); StorageLive(_15); - StorageLive(_16); + StorageLive(_6); _6 = SubUnchecked(_4, _3); StorageLive(_8); StorageLive(_7); @@ -101,10 +87,9 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> StorageDead(_12); StorageDead(_9); StorageDead(_8); - StorageDead(_16); - StorageDead(_15); - StorageDead(_14); StorageDead(_6); + StorageDead(_14); + StorageDead(_15); StorageDead(_5); _0 = &mut (*_13); StorageDead(_13); diff --git a/tests/mir-opt/separate_const_switch.rs b/tests/mir-opt/separate_const_switch.rs index c809e5629cc15..d333d4b6be2cb 100644 --- a/tests/mir-opt/separate_const_switch.rs +++ b/tests/mir-opt/separate_const_switch.rs @@ -1,6 +1,8 @@ #![feature(control_flow_enum)] #![feature(try_trait_v2)] +// compile-flags: -Zunsound-mir-opts + use std::ops::ControlFlow; // EMIT_MIR separate_const_switch.too_complex.SeparateConstSwitch.diff From 592844cf88b586a87cddf877d8f45e6ffe2a2910 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 8 Jun 2023 15:11:31 +0300 Subject: [PATCH 355/465] Warn on unused offset_of!() result --- library/core/src/mem/mod.rs | 5 +- .../offset_of.concrete.ConstProp.diff | 44 ------------ ...set_of.concrete.ConstProp.panic-abort.diff | 72 +++++++++++++++++++ ...et_of.concrete.ConstProp.panic-unwind.diff | 72 +++++++++++++++++++ .../offset_of.generic.ConstProp.diff | 40 ----------- ...fset_of.generic.ConstProp.panic-abort.diff | 68 ++++++++++++++++++ ...set_of.generic.ConstProp.panic-unwind.diff | 68 ++++++++++++++++++ tests/mir-opt/const_prop/offset_of.rs | 1 + tests/ui/offset-of/offset-of-dst-field.stderr | 28 ++++---- tests/ui/offset-of/offset-of-must-use.rs | 9 +++ tests/ui/offset-of/offset-of-must-use.stderr | 16 +++++ .../ui/offset-of/offset-of-output-type.stderr | 20 ++---- tests/ui/offset-of/offset-of-tuple.stderr | 25 ++----- 13 files changed, 333 insertions(+), 135 deletions(-) delete mode 100644 tests/mir-opt/const_prop/offset_of.concrete.ConstProp.diff create mode 100644 tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-abort.diff create mode 100644 tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff delete mode 100644 tests/mir-opt/const_prop/offset_of.generic.ConstProp.diff create mode 100644 tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-abort.diff create mode 100644 tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff create mode 100644 tests/ui/offset-of/offset-of-must-use.rs create mode 100644 tests/ui/offset-of/offset-of-must-use.stderr diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 39c9a04eea92b..2fff3f0efd73a 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1317,7 +1317,8 @@ impl SizedTypeProperties for T {} /// assert_eq!(mem::offset_of!(NestedA, b.0), 0); /// ``` #[unstable(feature = "offset_of", issue = "106655")] -#[allow_internal_unstable(builtin_syntax)] +#[allow_internal_unstable(builtin_syntax, hint_must_use)] pub macro offset_of($Container:ty, $($fields:tt).+ $(,)?) { - builtin # offset_of($Container, $($fields).+) + // The `{}` is for better error messages + crate::hint::must_use({builtin # offset_of($Container, $($fields).+)}) } diff --git a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.diff b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.diff deleted file mode 100644 index b510cecd9e07a..0000000000000 --- a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.diff +++ /dev/null @@ -1,44 +0,0 @@ -- // MIR for `concrete` before ConstProp -+ // MIR for `concrete` after ConstProp - - fn concrete() -> () { - let mut _0: (); - let _1: usize; - scope 1 { - debug x => _1; - let _2: usize; - scope 2 { - debug y => _2; - let _3: usize; - scope 3 { - debug z0 => _3; - let _4: usize; - scope 4 { - debug z1 => _4; - } - } - } - } - - bb0: { - StorageLive(_1); -- _1 = OffsetOf(Alpha, [0]); -+ _1 = const 4_usize; - StorageLive(_2); -- _2 = OffsetOf(Alpha, [1]); -+ _2 = const 0_usize; - StorageLive(_3); -- _3 = OffsetOf(Alpha, [2, 0]); -+ _3 = const 2_usize; - StorageLive(_4); -- _4 = OffsetOf(Alpha, [2, 1]); -+ _4 = const 3_usize; - _0 = const (); - StorageDead(_4); - StorageDead(_3); - StorageDead(_2); - StorageDead(_1); - return; - } - } - diff --git a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-abort.diff new file mode 100644 index 0000000000000..046a79b4bfba1 --- /dev/null +++ b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-abort.diff @@ -0,0 +1,72 @@ +- // MIR for `concrete` before ConstProp ++ // MIR for `concrete` after ConstProp + + fn concrete() -> () { + let mut _0: (); + let _1: usize; + let mut _2: usize; + let mut _4: usize; + let mut _6: usize; + let mut _8: usize; + scope 1 { + debug x => _1; + let _3: usize; + scope 2 { + debug y => _3; + let _5: usize; + scope 3 { + debug z0 => _5; + let _7: usize; + scope 4 { + debug z1 => _7; + } + } + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); +- _2 = OffsetOf(Alpha, [0]); ++ _2 = const 4_usize; + _1 = must_use::(move _2) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_2); + StorageLive(_3); + StorageLive(_4); +- _4 = OffsetOf(Alpha, [1]); ++ _4 = const 0_usize; + _3 = must_use::(move _4) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); +- _6 = OffsetOf(Alpha, [2, 0]); ++ _6 = const 2_usize; + _5 = must_use::(move _6) -> [return: bb3, unwind unreachable]; + } + + bb3: { + StorageDead(_6); + StorageLive(_7); + StorageLive(_8); +- _8 = OffsetOf(Alpha, [2, 1]); ++ _8 = const 3_usize; + _7 = must_use::(move _8) -> [return: bb4, unwind unreachable]; + } + + bb4: { + StorageDead(_8); + _0 = const (); + StorageDead(_7); + StorageDead(_5); + StorageDead(_3); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff new file mode 100644 index 0000000000000..29cad611b5404 --- /dev/null +++ b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff @@ -0,0 +1,72 @@ +- // MIR for `concrete` before ConstProp ++ // MIR for `concrete` after ConstProp + + fn concrete() -> () { + let mut _0: (); + let _1: usize; + let mut _2: usize; + let mut _4: usize; + let mut _6: usize; + let mut _8: usize; + scope 1 { + debug x => _1; + let _3: usize; + scope 2 { + debug y => _3; + let _5: usize; + scope 3 { + debug z0 => _5; + let _7: usize; + scope 4 { + debug z1 => _7; + } + } + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); +- _2 = OffsetOf(Alpha, [0]); ++ _2 = const 4_usize; + _1 = must_use::(move _2) -> bb1; + } + + bb1: { + StorageDead(_2); + StorageLive(_3); + StorageLive(_4); +- _4 = OffsetOf(Alpha, [1]); ++ _4 = const 0_usize; + _3 = must_use::(move _4) -> bb2; + } + + bb2: { + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); +- _6 = OffsetOf(Alpha, [2, 0]); ++ _6 = const 2_usize; + _5 = must_use::(move _6) -> bb3; + } + + bb3: { + StorageDead(_6); + StorageLive(_7); + StorageLive(_8); +- _8 = OffsetOf(Alpha, [2, 1]); ++ _8 = const 3_usize; + _7 = must_use::(move _8) -> bb4; + } + + bb4: { + StorageDead(_8); + _0 = const (); + StorageDead(_7); + StorageDead(_5); + StorageDead(_3); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.diff b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.diff deleted file mode 100644 index 8e0adb4275509..0000000000000 --- a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.diff +++ /dev/null @@ -1,40 +0,0 @@ -- // MIR for `generic` before ConstProp -+ // MIR for `generic` after ConstProp - - fn generic() -> () { - let mut _0: (); - let _1: usize; - scope 1 { - debug gx => _1; - let _2: usize; - scope 2 { - debug gy => _2; - let _3: usize; - scope 3 { - debug dx => _3; - let _4: usize; - scope 4 { - debug dy => _4; - } - } - } - } - - bb0: { - StorageLive(_1); - _1 = OffsetOf(Gamma, [0]); - StorageLive(_2); - _2 = OffsetOf(Gamma, [1]); - StorageLive(_3); - _3 = OffsetOf(Delta, [1]); - StorageLive(_4); - _4 = OffsetOf(Delta, [2]); - _0 = const (); - StorageDead(_4); - StorageDead(_3); - StorageDead(_2); - StorageDead(_1); - return; - } - } - diff --git a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-abort.diff new file mode 100644 index 0000000000000..7519331f6d7d4 --- /dev/null +++ b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-abort.diff @@ -0,0 +1,68 @@ +- // MIR for `generic` before ConstProp ++ // MIR for `generic` after ConstProp + + fn generic() -> () { + let mut _0: (); + let _1: usize; + let mut _2: usize; + let mut _4: usize; + let mut _6: usize; + let mut _8: usize; + scope 1 { + debug gx => _1; + let _3: usize; + scope 2 { + debug gy => _3; + let _5: usize; + scope 3 { + debug dx => _5; + let _7: usize; + scope 4 { + debug dy => _7; + } + } + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = OffsetOf(Gamma, [0]); + _1 = must_use::(move _2) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_2); + StorageLive(_3); + StorageLive(_4); + _4 = OffsetOf(Gamma, [1]); + _3 = must_use::(move _4) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); + _6 = OffsetOf(Delta, [1]); + _5 = must_use::(move _6) -> [return: bb3, unwind unreachable]; + } + + bb3: { + StorageDead(_6); + StorageLive(_7); + StorageLive(_8); + _8 = OffsetOf(Delta, [2]); + _7 = must_use::(move _8) -> [return: bb4, unwind unreachable]; + } + + bb4: { + StorageDead(_8); + _0 = const (); + StorageDead(_7); + StorageDead(_5); + StorageDead(_3); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff new file mode 100644 index 0000000000000..2a58a1a5ceb45 --- /dev/null +++ b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff @@ -0,0 +1,68 @@ +- // MIR for `generic` before ConstProp ++ // MIR for `generic` after ConstProp + + fn generic() -> () { + let mut _0: (); + let _1: usize; + let mut _2: usize; + let mut _4: usize; + let mut _6: usize; + let mut _8: usize; + scope 1 { + debug gx => _1; + let _3: usize; + scope 2 { + debug gy => _3; + let _5: usize; + scope 3 { + debug dx => _5; + let _7: usize; + scope 4 { + debug dy => _7; + } + } + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = OffsetOf(Gamma, [0]); + _1 = must_use::(move _2) -> bb1; + } + + bb1: { + StorageDead(_2); + StorageLive(_3); + StorageLive(_4); + _4 = OffsetOf(Gamma, [1]); + _3 = must_use::(move _4) -> bb2; + } + + bb2: { + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); + _6 = OffsetOf(Delta, [1]); + _5 = must_use::(move _6) -> bb3; + } + + bb3: { + StorageDead(_6); + StorageLive(_7); + StorageLive(_8); + _8 = OffsetOf(Delta, [2]); + _7 = must_use::(move _8) -> bb4; + } + + bb4: { + StorageDead(_8); + _0 = const (); + StorageDead(_7); + StorageDead(_5); + StorageDead(_3); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/const_prop/offset_of.rs b/tests/mir-opt/const_prop/offset_of.rs index 4cdcd28eeb292..164db59572b29 100644 --- a/tests/mir-opt/const_prop/offset_of.rs +++ b/tests/mir-opt/const_prop/offset_of.rs @@ -1,4 +1,5 @@ // unit-test: ConstProp +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY #![feature(offset_of)] diff --git a/tests/ui/offset-of/offset-of-dst-field.stderr b/tests/ui/offset-of/offset-of-dst-field.stderr index 3f613d947e488..658678dc4ed3c 100644 --- a/tests/ui/offset-of/offset-of-dst-field.stderr +++ b/tests/ui/offset-of/offset-of-dst-field.stderr @@ -34,6 +34,20 @@ LL | offset_of!((u8, dyn Trait), 1); = help: the trait `Sized` is not implemented for `dyn Trait` = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/offset-of-dst-field.rs:44:5 + | +LL | offset_of!(Delta, z); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `Alpha`, the trait `Sized` is not implemented for `[u8]` +note: required because it appears within the type `Alpha` + --> $DIR/offset-of-dst-field.rs:5:8 + | +LL | struct Alpha { + | ^^^^^ + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0277]: the size for values of type `Extern` cannot be known at compilation time --> $DIR/offset-of-dst-field.rs:45:5 | @@ -52,20 +66,6 @@ LL | offset_of!(Delta, z); = help: the trait `Sized` is not implemented for `dyn Trait` = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/offset-of-dst-field.rs:44:5 - | -LL | offset_of!(Delta, z); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: within `Alpha`, the trait `Sized` is not implemented for `[u8]` -note: required because it appears within the type `Alpha` - --> $DIR/offset-of-dst-field.rs:5:8 - | -LL | struct Alpha { - | ^^^^^ - = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/offset-of-dst-field.rs:50:5 | diff --git a/tests/ui/offset-of/offset-of-must-use.rs b/tests/ui/offset-of/offset-of-must-use.rs new file mode 100644 index 0000000000000..e30145d7a2fe3 --- /dev/null +++ b/tests/ui/offset-of/offset-of-must-use.rs @@ -0,0 +1,9 @@ +// check-pass + +#![feature(offset_of)] +#![warn(unused)] + +fn main() { + core::mem::offset_of!((String,), 0); + //~^ WARN unused return value of `must_use` that must be used +} diff --git a/tests/ui/offset-of/offset-of-must-use.stderr b/tests/ui/offset-of/offset-of-must-use.stderr new file mode 100644 index 0000000000000..5fe387a72553c --- /dev/null +++ b/tests/ui/offset-of/offset-of-must-use.stderr @@ -0,0 +1,16 @@ +warning: unused return value of `must_use` that must be used + --> $DIR/offset-of-must-use.rs:7:5 + | +LL | core::mem::offset_of!((String,), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/offset-of-must-use.rs:4:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_must_use)]` implied by `#[warn(unused)]` + = note: this warning originates in the macro `core::mem::offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 1 warning emitted + diff --git a/tests/ui/offset-of/offset-of-output-type.stderr b/tests/ui/offset-of/offset-of-output-type.stderr index 6f8c94750299e..6133f3263ab64 100644 --- a/tests/ui/offset-of/offset-of-output-type.stderr +++ b/tests/ui/offset-of/offset-of-output-type.stderr @@ -2,9 +2,7 @@ error[E0308]: mismatched types --> $DIR/offset-of-output-type.rs:12:17 | LL | let _: u8 = offset_of!(S, v); - | -- ^^^^^^^^^^^^^^^^ expected `u8`, found `usize` - | | - | expected due to this + | ^^^^^^^^^^^^^^^^ expected `u8`, found `usize` | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -12,9 +10,7 @@ error[E0308]: mismatched types --> $DIR/offset-of-output-type.rs:13:18 | LL | let _: u16 = offset_of!(S, v); - | --- ^^^^^^^^^^^^^^^^ expected `u16`, found `usize` - | | - | expected due to this + | ^^^^^^^^^^^^^^^^ expected `u16`, found `usize` | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -22,9 +18,7 @@ error[E0308]: mismatched types --> $DIR/offset-of-output-type.rs:14:18 | LL | let _: u32 = offset_of!(S, v); - | --- ^^^^^^^^^^^^^^^^ expected `u32`, found `usize` - | | - | expected due to this + | ^^^^^^^^^^^^^^^^ expected `u32`, found `usize` | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -32,9 +26,7 @@ error[E0308]: mismatched types --> $DIR/offset-of-output-type.rs:15:18 | LL | let _: u64 = offset_of!(S, v); - | --- ^^^^^^^^^^^^^^^^ expected `u64`, found `usize` - | | - | expected due to this + | ^^^^^^^^^^^^^^^^ expected `u64`, found `usize` | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -42,9 +34,7 @@ error[E0308]: mismatched types --> $DIR/offset-of-output-type.rs:16:20 | LL | let _: isize = offset_of!(S, v); - | ----- ^^^^^^^^^^^^^^^^ expected `isize`, found `usize` - | | - | expected due to this + | ^^^^^^^^^^^^^^^^ expected `isize`, found `usize` | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/offset-of/offset-of-tuple.stderr b/tests/ui/offset-of/offset-of-tuple.stderr index 954515f80a65e..ed9523458063d 100644 --- a/tests/ui/offset-of/offset-of-tuple.stderr +++ b/tests/ui/offset-of/offset-of-tuple.stderr @@ -90,10 +90,7 @@ error: expected identifier, found `)` --> $DIR/offset-of-tuple.rs:14:5 | LL | offset_of!((u8, u8), 1.); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | expected identifier - | in this macro invocation + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected identifier | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -110,10 +107,7 @@ error: expected identifier, found `)` --> $DIR/offset-of-tuple.rs:36:5 | LL | offset_of!(ComplexTup, 0.0.1.); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | expected identifier - | in this macro invocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected identifier | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -147,10 +141,7 @@ error: expected identifier, found `)` --> $DIR/offset-of-tuple.rs:40:5 | LL | offset_of!(ComplexTup, 0.0 .1.); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | expected identifier - | in this macro invocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected identifier | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -158,10 +149,7 @@ error: expected identifier, found `)` --> $DIR/offset-of-tuple.rs:41:5 | LL | offset_of!(ComplexTup, 0.0 . 1.); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | expected identifier - | in this macro invocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected identifier | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -169,10 +157,7 @@ error: expected identifier, found `)` --> $DIR/offset-of-tuple.rs:42:5 | LL | offset_of!(ComplexTup, 0.0. 1.); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | expected identifier - | in this macro invocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected identifier | = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) From 81e37743a506b2cf0aff1bb6c0cdd3d22699776f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 21 Jun 2023 10:25:25 +0000 Subject: [PATCH 356/465] Make queries traceable again --- compiler/rustc_query_impl/src/plumbing.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 244f0e84b43d9..cb0df1d1b820a 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -531,6 +531,8 @@ macro_rules! define_queries { key: queries::$name::Key<'tcx>, mode: QueryMode, ) -> Option>> { + #[cfg(debug_assertions)] + let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); get_query_incr( QueryType::config(tcx), QueryCtxt::new(tcx), @@ -571,10 +573,16 @@ macro_rules! define_queries { cache_on_disk: |tcx, key| ::rustc_middle::query::cached::$name(tcx, key), execute_query: |tcx, key| erase(tcx.$name(key)), compute: |tcx, key| { + #[cfg(debug_assertions)] + let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); __rust_begin_short_backtrace(|| queries::$name::provided_to_erased( tcx, - call_provider!([$($modifiers)*][tcx, $name, key]) + { + let ret = call_provider!([$($modifiers)*][tcx, $name, key]); + tracing::trace!(?ret); + ret + } ) ) }, From 3acb1d2b9b5f0ab85cb787250326c0571503f78c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 21 Jun 2023 12:43:22 +0200 Subject: [PATCH 357/465] "Memory Orderings" -> "Memory Ordering" Co-authored-by: yvt --- library/std/src/thread/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index e9d94ba425a3a..b9b14b2dc5f66 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -879,7 +879,7 @@ pub fn sleep(dur: Duration) { /// /// * It can be implemented very efficiently on many platforms. /// -/// # Memory Orderings +/// # Memory Ordering /// /// Calls to `park` _synchronize-with_ calls to `unpark`, meaning that memory /// operations performed before a call to `unpark` are made visible to the thread that From 91aef00e51d9f7500b8d76bce0917138ffa00d2f Mon Sep 17 00:00:00 2001 From: Raminder Singh Date: Wed, 21 Jun 2023 16:54:54 +0530 Subject: [PATCH 358/465] Fix msg passed to span_bug --- compiler/rustc_expand/src/mbe/macro_rules.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index ee9616a0f0a9d..4a8a14994ff11 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -535,7 +535,7 @@ pub fn compile_declarative_macro( .pop() .unwrap(); } - sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") + sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs") }) .collect::>(), _ => sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs"), From 60ec8405eb03bb3da43e11a5415968d8d8852120 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 19 Jun 2023 13:50:22 +0200 Subject: [PATCH 359/465] Add `lazy_type_alias` feature gate --- compiler/rustc_feature/src/active.rs | 2 ++ compiler/rustc_hir_analysis/src/astconv/mod.rs | 2 +- compiler/rustc_span/src/symbol.rs | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 4c53f9d8369fd..34c0e5009d38f 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -440,6 +440,8 @@ declare_features! ( (active, intra_doc_pointers, "1.51.0", Some(80896), None), // Allows setting the threshold for the `large_assignments` lint. (active, large_assignments, "1.52.0", Some(83518), None), + /// Allow to have type alias types for inter-crate use. + (active, lazy_type_alias, "CURRENT_RUSTC_VERSION", Some(112792), None), /// Allows `if/while p && let q = r && ...` chains. (active, let_chains, "1.37.0", Some(53667), None), /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 621569ab3215d..7a83447786c3c 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -896,7 +896,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let ty = self.tcx().at(span).type_of(did); if matches!(self.tcx().def_kind(did), DefKind::TyAlias) - && ty.skip_binder().has_opaque_types() + && (ty.skip_binder().has_opaque_types() || self.tcx().features().lazy_type_alias) { // Type aliases referring to types that contain opaque types (but aren't just directly // referencing a single opaque type) get encoded as a type alias that normalization will diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 388b904d1971f..d8c04f7206092 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -870,6 +870,7 @@ symbols! { large_assignments, lateout, lazy_normalization_consts, + lazy_type_alias, le, len, let_chains, From 1af48beed74e9ab652a05c8fe267541ae652eaf6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 19 Jun 2023 15:05:46 +0200 Subject: [PATCH 360/465] Add rustdoc tests for `lazy_type_alias` --- tests/rustdoc/alias-reexport.rs | 18 ++++++++++++++++++ tests/rustdoc/alias-reexport2.rs | 16 ++++++++++++++++ tests/rustdoc/auxiliary/alias-reexport.rs | 3 +++ tests/rustdoc/auxiliary/alias-reexport2.rs | 12 ++++++++++++ 4 files changed, 49 insertions(+) create mode 100644 tests/rustdoc/alias-reexport.rs create mode 100644 tests/rustdoc/alias-reexport2.rs create mode 100644 tests/rustdoc/auxiliary/alias-reexport.rs create mode 100644 tests/rustdoc/auxiliary/alias-reexport2.rs diff --git a/tests/rustdoc/alias-reexport.rs b/tests/rustdoc/alias-reexport.rs new file mode 100644 index 0000000000000..029891197fc45 --- /dev/null +++ b/tests/rustdoc/alias-reexport.rs @@ -0,0 +1,18 @@ +// aux-build:alias-reexport.rs +// aux-build:alias-reexport2.rs + +#![crate_name = "foo"] +#![feature(lazy_type_alias)] + +extern crate alias_reexport2; + +// @has 'foo/reexport/fn.foo.html' +// FIXME: should be 'pub fn foo() -> Reexport' +// @has - '//*[@class="rust item-decl"]' 'pub fn foo() -> u8' +// @has 'foo/reexport/fn.foo2.html' +// FIXME: should be 'pub fn foo2() -> Result' +// @has - '//*[@class="rust item-decl"]' 'pub fn foo2() -> Result' +// @has 'foo/reexport/type.Reexported.html' +// @has - '//*[@class="rust item-decl"]' 'pub type Reexported = u8;' +#[doc(inline)] +pub use alias_reexport2 as reexport; diff --git a/tests/rustdoc/alias-reexport2.rs b/tests/rustdoc/alias-reexport2.rs new file mode 100644 index 0000000000000..85d3cdad9623e --- /dev/null +++ b/tests/rustdoc/alias-reexport2.rs @@ -0,0 +1,16 @@ +// gate-test-lazy_type_alias +// aux-build:alias-reexport.rs + +#![crate_name = "foo"] +#![feature(lazy_type_alias)] + +extern crate alias_reexport; + +use alias_reexport::Reexported; + +// @has 'foo/fn.foo.html' +// @has - '//*[@class="rust item-decl"]' 'pub fn foo() -> Reexported' +pub fn foo() -> Reexported { 0 } +// @has 'foo/fn.foo2.html' +// @has - '//*[@class="rust item-decl"]' 'pub fn foo2() -> Result' +pub fn foo2() -> Result { Ok(0) } diff --git a/tests/rustdoc/auxiliary/alias-reexport.rs b/tests/rustdoc/auxiliary/alias-reexport.rs new file mode 100644 index 0000000000000..14fafc02d3661 --- /dev/null +++ b/tests/rustdoc/auxiliary/alias-reexport.rs @@ -0,0 +1,3 @@ +#![feature(lazy_type_alias)] + +pub type Reexported = u8; diff --git a/tests/rustdoc/auxiliary/alias-reexport2.rs b/tests/rustdoc/auxiliary/alias-reexport2.rs new file mode 100644 index 0000000000000..9f6910572add2 --- /dev/null +++ b/tests/rustdoc/auxiliary/alias-reexport2.rs @@ -0,0 +1,12 @@ +#![feature(lazy_type_alias)] + +extern crate alias_reexport; + +pub use alias_reexport::Reexported; + +// @has 'foo/fn.foo.html' +// @has - '//*[@class="docblock item-decl"]' 'pub fn foo() -> Reexported' +pub fn foo() -> Reexported { 0 } +// @has 'foo/fn.foo2.html' +// @has - '//*[@class="docblock item-decl"]' 'pub fn foo2() -> Result' +pub fn foo2() -> Result { Ok(0) } From e3e65d1e14c6372af860233b237475ebd3078b34 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Wed, 21 Jun 2023 13:30:02 +0100 Subject: [PATCH 361/465] Revert 'Rename profile=user to profile=dist' This reverts commit a45fc9465204c9fb8c6792e74e3ed10959e46001 --- src/bootstrap/setup.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index e13f3f0bd5eb7..7eb70de91f84e 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -20,7 +20,7 @@ pub enum Profile { Codegen, Library, Tools, - Dist, + User, None, } @@ -43,7 +43,7 @@ impl Profile { pub fn all() -> impl Iterator { use Profile::*; // N.B. these are ordered by how they are displayed, not alphabetically - [Library, Compiler, Codegen, Tools, Dist, None].iter().copied() + [Library, Compiler, Codegen, Tools, User, None].iter().copied() } pub fn purpose(&self) -> String { @@ -53,7 +53,7 @@ impl Profile { Compiler => "Contribute to the compiler itself", Codegen => "Contribute to the compiler, and also modify LLVM or codegen", Tools => "Contribute to tools which depend on the compiler, but do not modify it directly (e.g. rustdoc, clippy, miri)", - Dist => "Install Rust from source", + User => "Install Rust from source", None => "Do not modify `config.toml`" } .to_string() @@ -73,7 +73,7 @@ impl Profile { Profile::Codegen => "codegen", Profile::Library => "library", Profile::Tools => "tools", - Profile::Dist => "dist", + Profile::User => "user", Profile::None => "none", } } @@ -87,7 +87,7 @@ impl FromStr for Profile { "lib" | "library" => Ok(Profile::Library), "compiler" => Ok(Profile::Compiler), "llvm" | "codegen" => Ok(Profile::Codegen), - "maintainer" | "dist" => Ok(Profile::Dist), + "maintainer" | "user" => Ok(Profile::User), "tools" | "tool" | "rustdoc" | "clippy" | "miri" | "rustfmt" | "rls" => { Ok(Profile::Tools) } @@ -160,7 +160,7 @@ pub fn setup(config: &Config, profile: Profile) { "test src/tools/rustfmt", ], Profile::Library => &["check", "build", "test library/std", "doc"], - Profile::Dist => &["dist", "build"], + Profile::User => &["dist", "build"], }; println!(); @@ -170,7 +170,7 @@ pub fn setup(config: &Config, profile: Profile) { println!("- `x.py {}`", cmd); } - if profile != Profile::Dist { + if profile != Profile::User { println!( "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html" ); From 3ad595a31610b5094f66fa2855bde1f898a5d1f5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 19 Jun 2023 21:18:11 +0200 Subject: [PATCH 362/465] Add tests for invalid files generation --- tests/rustdoc/files-creation-hidden.rs | 23 +++++++++++++ tests/rustdoc/files-creation-private.rs | 18 ++++++++++ ...sue-111064-reexport-trait-from-hidden-2.rs | 8 ++--- tests/rustdoc/issue-111249-file-creation.rs | 34 +++++++++++++++++++ tests/rustdoc/redirect.rs | 2 ++ 5 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 tests/rustdoc/files-creation-hidden.rs create mode 100644 tests/rustdoc/files-creation-private.rs create mode 100644 tests/rustdoc/issue-111249-file-creation.rs diff --git a/tests/rustdoc/files-creation-hidden.rs b/tests/rustdoc/files-creation-hidden.rs new file mode 100644 index 0000000000000..bcabbfc91e869 --- /dev/null +++ b/tests/rustdoc/files-creation-hidden.rs @@ -0,0 +1,23 @@ +#![crate_name="foo"] + +// @!has "foo/struct.Foo.html" +#[doc(hidden)] +pub struct Foo; + +// @!has "foo/struct.Bar.html" +pub use crate::Foo as Bar; + +// @!has "foo/struct.Baz.html" +#[doc(hidden)] +pub use crate::Foo as Baz; + +// @!has "foo/foo/index.html" +#[doc(hidden)] +pub mod foo {} + +// @!has "foo/bar/index.html" +pub use crate::foo as bar; + +// @!has "foo/baz/index.html" +#[doc(hidden)] +pub use crate::foo as baz; diff --git a/tests/rustdoc/files-creation-private.rs b/tests/rustdoc/files-creation-private.rs new file mode 100644 index 0000000000000..ca2327e0f911a --- /dev/null +++ b/tests/rustdoc/files-creation-private.rs @@ -0,0 +1,18 @@ +#![crate_name="foo"] + +// @!has "foo/priv/index.html" +// @!has "foo/priv/struct.Foo.html" +mod private { + pub struct Foo; +} + +// @has "foo/struct.Bar.html" +pub use crate::private::Foo as Bar; + +// @!has "foo/foo/index.html" +mod foo { + pub mod subfoo {} +} + +// @has "foo/bar/index.html" +pub use crate::foo::subfoo as bar; diff --git a/tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs b/tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs index 8e1029a1ca3df..d6832bb7a0977 100644 --- a/tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs +++ b/tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs @@ -3,10 +3,10 @@ #![crate_name = "foo"] // @!has 'foo/hidden/index.html' -// FIXME: add missing `@` for the two next tests once issue is fixed! -// To be done in . -// !has 'foo/hidden/inner/index.html' -// !has 'foo/hidden/inner/trait.Foo.html' +// @!has 'foo/hidden/inner/index.html' +// FIXME: Should be `@!has`: https://github.com/rust-lang/rust/issues/111249 +// @has 'foo/hidden/inner/trait.Foo.html' +// @matchesraw - '' #[doc(hidden)] pub mod hidden { pub mod inner { diff --git a/tests/rustdoc/issue-111249-file-creation.rs b/tests/rustdoc/issue-111249-file-creation.rs new file mode 100644 index 0000000000000..d2042b231e469 --- /dev/null +++ b/tests/rustdoc/issue-111249-file-creation.rs @@ -0,0 +1,34 @@ +#![crate_name = "foo"] +#![feature(no_core)] +#![no_core] + +// The following five should not fail! +// @!has 'foo/hidden/index.html' +// @!has 'foo/hidden/inner/index.html' +// FIXME: Should be `@!has`: https://github.com/rust-lang/rust/issues/111249 +// @has 'foo/hidden/inner/trait.Foo.html' +// @matchesraw - '' +// @!has 'foo/hidden/inner/inner_hidden/index.html' +// @!has 'foo/hidden/inner/inner_hidden/trait.HiddenFoo.html' +#[doc(hidden)] +pub mod hidden { + pub mod inner { + pub trait Foo {} + + #[doc(hidden)] + pub mod inner_hidden { + pub trait HiddenFoo {} + } + } +} + +// @has 'foo/visible/index.html' +// @has 'foo/visible/trait.Foo.html' +#[doc(inline)] +pub use hidden::inner as visible; + +// @has 'foo/struct.Bar.html' +// @count - '//*[@id="impl-Foo-for-Bar"]' 1 +pub struct Bar; + +impl visible::Foo for Bar {} diff --git a/tests/rustdoc/redirect.rs b/tests/rustdoc/redirect.rs index 5b7a76e1a7739..4fb81c23d39e6 100644 --- a/tests/rustdoc/redirect.rs +++ b/tests/rustdoc/redirect.rs @@ -10,7 +10,9 @@ pub trait Foo {} // @has - '//code' 'pub use reexp_stripped::Bar' // @has - '//code/a' 'Bar' // @has - '//a[@href="../reexp_stripped/hidden/struct.Bar.html"]' 'Bar' +// FIXME: Should be `@!has`: https://github.com/rust-lang/rust/issues/111249 // @has reexp_stripped/hidden/struct.Bar.html +// @matchesraw - '' // @has 'reexp_stripped/struct.Bar.html' // @has - '//a[@href="struct.Bar.html"]' 'Bar' #[doc(no_inline)] From 53761e12226b03e742ae3c4b6e0d7716ad38b18f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 21 Jun 2023 13:37:17 +0200 Subject: [PATCH 363/465] Correctly handle Weak type aliases in rustdoc --- src/librustdoc/clean/mod.rs | 21 +++++++++++++++++---- tests/rustdoc/alias-reexport.rs | 6 ++---- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 851002d5e7965..67d433dd0ad87 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2024,8 +2024,8 @@ pub(crate) fn clean_middle_ty<'tcx>( Tuple(t.iter().map(|t| clean_middle_ty(bound_ty.rebind(t), cx, None, None)).collect()) } - ty::Alias(ty::Projection, ref data) => { - clean_projection(bound_ty.rebind(*data), cx, parent_def_id) + ty::Alias(ty::Projection, data) => { + clean_projection(bound_ty.rebind(data), cx, parent_def_id) } ty::Alias(ty::Inherent, alias_ty) => { @@ -2053,8 +2053,21 @@ pub(crate) fn clean_middle_ty<'tcx>( } ty::Alias(ty::Weak, data) => { - let ty = cx.tcx.type_of(data.def_id).subst(cx.tcx, data.substs); - clean_middle_ty(bound_ty.rebind(ty), cx, None, None) + if cx.tcx.features().lazy_type_alias { + // Weak type alias `data` represents the `type X` in `type X = Y`. If we need `Y`, + // we need to use `type_of`. + let path = external_path( + cx, + data.def_id, + false, + ThinVec::new(), + bound_ty.rebind(data.substs), + ); + Type::Path { path } + } else { + let ty = cx.tcx.type_of(data.def_id).subst(cx.tcx, data.substs); + clean_middle_ty(bound_ty.rebind(ty), cx, None, None) + } } ty::Param(ref p) => { diff --git a/tests/rustdoc/alias-reexport.rs b/tests/rustdoc/alias-reexport.rs index 029891197fc45..a2a8e651caf6d 100644 --- a/tests/rustdoc/alias-reexport.rs +++ b/tests/rustdoc/alias-reexport.rs @@ -7,11 +7,9 @@ extern crate alias_reexport2; // @has 'foo/reexport/fn.foo.html' -// FIXME: should be 'pub fn foo() -> Reexport' -// @has - '//*[@class="rust item-decl"]' 'pub fn foo() -> u8' +// @has - '//*[@class="rust item-decl"]' 'pub fn foo() -> Reexported' // @has 'foo/reexport/fn.foo2.html' -// FIXME: should be 'pub fn foo2() -> Result' -// @has - '//*[@class="rust item-decl"]' 'pub fn foo2() -> Result' +// @has - '//*[@class="rust item-decl"]' 'pub fn foo2() -> Result' // @has 'foo/reexport/type.Reexported.html' // @has - '//*[@class="rust item-decl"]' 'pub type Reexported = u8;' #[doc(inline)] From c007293e293fce01c73928bd34ad3a901262c730 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 21 Jun 2023 17:45:38 +0300 Subject: [PATCH 364/465] resolve: Minor cleanup to `fn resolve_path_with_ribs` A single-use closure is inlined and one unnecessary enum is removed. --- compiler/rustc_resolve/src/ident.rs | 89 ++++++++++++----------------- 1 file changed, 38 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index ec0a8535e7180..e29a1626aedd2 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1459,60 +1459,47 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }); } - enum FindBindingResult<'a> { - Binding(Result<&'a NameBinding<'a>, Determinacy>), - Res(Res), - } - let find_binding_in_ns = |this: &mut Self, ns| { - let binding = if let Some(module) = module { - this.resolve_ident_in_module( - module, - ident, - ns, - parent_scope, - finalize, - ignore_binding, - ) - } else if let Some(ribs) = ribs - && let Some(TypeNS | ValueNS) = opt_ns - { - match this.resolve_ident_in_lexical_scope( - ident, - ns, - parent_scope, - finalize, - &ribs[ns], - ignore_binding, - ) { - // we found a locally-imported or available item/module - Some(LexicalScopeBinding::Item(binding)) => Ok(binding), - // we found a local variable or type param - Some(LexicalScopeBinding::Res(res)) => return FindBindingResult::Res(res), - _ => Err(Determinacy::determined(finalize.is_some())), + let binding = if let Some(module) = module { + self.resolve_ident_in_module( + module, + ident, + ns, + parent_scope, + finalize, + ignore_binding, + ) + } else if let Some(ribs) = ribs && let Some(TypeNS | ValueNS) = opt_ns { + match self.resolve_ident_in_lexical_scope( + ident, + ns, + parent_scope, + finalize, + &ribs[ns], + ignore_binding, + ) { + // we found a locally-imported or available item/module + Some(LexicalScopeBinding::Item(binding)) => Ok(binding), + // we found a local variable or type param + Some(LexicalScopeBinding::Res(res)) => { + record_segment_res(self, res); + return PathResult::NonModule(PartialRes::with_unresolved_segments( + res, + path.len() - 1, + )); } - } else { - let scopes = ScopeSet::All(ns, opt_ns.is_none()); - this.early_resolve_ident_in_lexical_scope( - ident, - scopes, - parent_scope, - finalize, - finalize.is_some(), - ignore_binding, - ) - }; - FindBindingResult::Binding(binding) - }; - let binding = match find_binding_in_ns(self, ns) { - FindBindingResult::Res(res) => { - record_segment_res(self, res); - return PathResult::NonModule(PartialRes::with_unresolved_segments( - res, - path.len() - 1, - )); + _ => Err(Determinacy::determined(finalize.is_some())), } - FindBindingResult::Binding(binding) => binding, + } else { + self.early_resolve_ident_in_lexical_scope( + ident, + ScopeSet::All(ns, opt_ns.is_none()), + parent_scope, + finalize, + finalize.is_some(), + ignore_binding, + ) }; + match binding { Ok(binding) => { if segment_idx == 1 { From 6f485269632c031b6b698a8f7bf820839dca4f2b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 21 Jun 2023 17:25:19 +0200 Subject: [PATCH 365/465] Fix union fields display --- src/librustdoc/html/render/mod.rs | 5 ++--- src/librustdoc/html/templates/item_info.html | 2 +- src/librustdoc/html/templates/item_union.html | 11 ++++++----- src/librustdoc/html/templates/print_item.html | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 5bd9389a400af..c5d6771c2fdd3 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -421,11 +421,10 @@ fn document<'a, 'cx: 'a>( display_fn(move |f| { document_item_info(cx, item, parent).render_into(f).unwrap(); if parent.is_none() { - write!(f, "{}", document_full_collapsible(item, cx, heading_offset))?; + write!(f, "{}", document_full_collapsible(item, cx, heading_offset)) } else { - write!(f, "{}", document_full(item, cx, heading_offset))?; + write!(f, "{}", document_full(item, cx, heading_offset)) } - Ok(()) }) } diff --git a/src/librustdoc/html/templates/item_info.html b/src/librustdoc/html/templates/item_info.html index d2ea9bdae9c65..9e65ae95e15d2 100644 --- a/src/librustdoc/html/templates/item_info.html +++ b/src/librustdoc/html/templates/item_info.html @@ -1,5 +1,5 @@ {% if !items.is_empty() %} - {# #} + {% for item in items %} {{item|safe}} {# #} {% endfor %} diff --git a/src/librustdoc/html/templates/item_union.html b/src/librustdoc/html/templates/item_union.html index a01457971c178..f6d2fa3489081 100644 --- a/src/librustdoc/html/templates/item_union.html +++ b/src/librustdoc/html/templates/item_union.html @@ -4,14 +4,15 @@ {{ self.document() | safe }} {% if self.fields_iter().peek().is_some() %} -

{# #} + Fields§ {# #}

{% for (field, ty) in self.fields_iter() %} {% let name = field.name.expect("union field name") %} - - § - {{ name }}: {{ self.print_ty(ty) | safe }} + {# #} + § {# #} + {{ name }}: {{+ self.print_ty(ty) | safe }} {# #} {% if let Some(stability_class) = self.stability_field(field) %} diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html index edabac9a08231..68a295ae095aa 100644 --- a/src/librustdoc/html/templates/print_item.html +++ b/src/librustdoc/html/templates/print_item.html @@ -1,5 +1,5 @@
{# #} -

{# #} +

{{typ}} {# The breadcrumbs of the item path, like std::string #} {% for component in path_components %} @@ -12,7 +12,7 @@

{# #} alt="Copy item path"> {# #} {# #}

{# #} - {# #} + {% if !stability_since_raw.is_empty() %} {{ stability_since_raw|safe +}} · {#+ #} {% endif %} From 805edb0a4a028d1d0f4f7f776ac8d2d36f131dd4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 21 Jun 2023 17:42:53 +0200 Subject: [PATCH 366/465] Add test to prevent regression for fields display --- tests/rustdoc-gui/fields.goml | 18 ++++++++++++++++++ tests/rustdoc-gui/src/test_docs/lib.rs | 21 +++++++++++++++++++++ tests/rustdoc/union-fields-html.rs | 11 +++++++++++ 3 files changed, 50 insertions(+) create mode 100644 tests/rustdoc-gui/fields.goml create mode 100644 tests/rustdoc/union-fields-html.rs diff --git a/tests/rustdoc-gui/fields.goml b/tests/rustdoc-gui/fields.goml new file mode 100644 index 0000000000000..b8139a2edac10 --- /dev/null +++ b/tests/rustdoc-gui/fields.goml @@ -0,0 +1,18 @@ +// This test checks that fields are displayed as expected (one by line). +go-to: "file://" + |DOC_PATH| + "/test_docs/fields/struct.Struct.html" +store-position: ("#structfield\.a", {"y": a_y}) +store-position: ("#structfield\.b", {"y": b_y}) +assert: |a_y| < |b_y| + +go-to: "file://" + |DOC_PATH| + "/test_docs/fields/union.Union.html" +store-position: ("#structfield\.a", {"y": a_y}) +store-position: ("#structfield\.b", {"y": b_y}) +assert: |a_y| < |b_y| + +go-to: "file://" + |DOC_PATH| + "/test_docs/fields/enum.Enum.html" +store-position: ("#variant\.A\.field\.a", {"y": a_y}) +store-position: ("#variant\.A\.field\.b", {"y": b_y}) +assert: |a_y| < |b_y| +store-position: ("#variant\.B\.field\.a", {"y": a_y}) +store-position: ("#variant\.B\.field\.b", {"y": b_y}) +assert: |a_y| < |b_y| diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index 6ad1e8b4f673f..c040fa02dffeb 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -486,3 +486,24 @@ pub mod search_results { } } + +pub mod fields { + pub struct Struct { + pub a: u8, + pub b: u32, + } + pub union Union { + pub a: u8, + pub b: u32, + } + pub enum Enum { + A { + a: u8, + b: u32, + }, + B { + a: u8, + b: u32, + }, + } +} diff --git a/tests/rustdoc/union-fields-html.rs b/tests/rustdoc/union-fields-html.rs new file mode 100644 index 0000000000000..1ac01232c3e6b --- /dev/null +++ b/tests/rustdoc/union-fields-html.rs @@ -0,0 +1,11 @@ +#![crate_name = "foo"] + +// @has 'foo/union.Union.html' +// Checking that there is a whitespace after `:`. +// @has - '//*[@id="structfield.a"]/code' 'a: u8' +// @has - '//*[@id="structfield.b"]/code' 'b: u32' +pub union Union { + pub a: u8, + /// tadam + pub b: u32, +} From 7563909a28a2add4e41cb653e4d7ebd50c97bce4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 21 Jun 2023 01:57:26 +0000 Subject: [PATCH 367/465] Liberate bound vars properly when suggesting missing AFIT --- compiler/rustc_hir_analysis/src/check/mod.rs | 23 ++++++++----------- .../in-trait/suggest-missing-item.fixed | 5 +++- .../in-trait/suggest-missing-item.rs | 2 ++ .../in-trait/suggest-missing-item.stderr | 9 +++++--- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 4247869ce7603..1dfe053b21530 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -470,19 +470,16 @@ fn suggestion_signature<'tcx>( ); match assoc.kind { - ty::AssocKind::Fn => { - // We skip the binder here because the binder would deanonymize all - // late-bound regions, and we don't want method signatures to show up - // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound - // regions just fine, showing `fn(&MyType)`. - fn_sig_suggestion( - tcx, - tcx.fn_sig(assoc.def_id).subst(tcx, substs).skip_binder(), - assoc.ident(tcx), - tcx.predicates_of(assoc.def_id).instantiate_own(tcx, substs), - assoc, - ) - } + ty::AssocKind::Fn => fn_sig_suggestion( + tcx, + tcx.liberate_late_bound_regions( + assoc.def_id, + tcx.fn_sig(assoc.def_id).subst(tcx, substs), + ), + assoc.ident(tcx), + tcx.predicates_of(assoc.def_id).instantiate_own(tcx, substs), + assoc, + ), ty::AssocKind::Type => { let (generics, where_clauses) = bounds_from_generic_predicates( tcx, diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed b/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed index 16c4d15ddcd60..d9f775a6c8464 100644 --- a/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed @@ -9,11 +9,14 @@ trait Trait { async fn bar() -> i32; fn test(&self) -> impl Sized + '_; + + async fn baz(&self) -> &i32; } struct S; -impl Trait for S {fn test(&self) -> impl Sized + '_ { todo!() } +impl Trait for S {async fn baz(&self) -> &i32 { todo!() } +fn test(&self) -> impl Sized + '_ { todo!() } async fn bar() -> i32 { todo!() } async fn foo() { todo!() } } diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.rs b/tests/ui/impl-trait/in-trait/suggest-missing-item.rs index f218e6cb581e3..26979b5149b06 100644 --- a/tests/ui/impl-trait/in-trait/suggest-missing-item.rs +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.rs @@ -9,6 +9,8 @@ trait Trait { async fn bar() -> i32; fn test(&self) -> impl Sized + '_; + + async fn baz(&self) -> &i32; } struct S; diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr b/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr index d96641fe16335..44f98896eb384 100644 --- a/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr @@ -1,5 +1,5 @@ -error[E0046]: not all trait items implemented, missing: `foo`, `bar`, `test` - --> $DIR/suggest-missing-item.rs:16:1 +error[E0046]: not all trait items implemented, missing: `foo`, `bar`, `test`, `baz` + --> $DIR/suggest-missing-item.rs:18:1 | LL | async fn foo(); | --------------- `foo` from trait @@ -9,9 +9,12 @@ LL | async fn bar() -> i32; LL | LL | fn test(&self) -> impl Sized + '_; | ---------------------------------- `test` from trait +LL | +LL | async fn baz(&self) -> &i32; + | ---------------------------- `baz` from trait ... LL | impl Trait for S {} - | ^^^^^^^^^^^^^^^^ missing `foo`, `bar`, `test` in implementation + | ^^^^^^^^^^^^^^^^ missing `foo`, `bar`, `test`, `baz` in implementation error: aborting due to previous error From 5344ed23fadce0bd2af6a50cb4623704b1fe6383 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 21 Jun 2023 05:32:35 +0000 Subject: [PATCH 368/465] Don't substitute a GAT that has mismatched generics in OpaqueTypeCollector --- .../rustc_trait_selection/src/traits/mod.rs | 8 +- .../src/traits/project.rs | 42 +--------- .../rustc_trait_selection/src/traits/util.rs | 41 ++++++++++ compiler/rustc_ty_utils/src/opaque_types.rs | 80 ++++++++++++------- ...mpl-trait-in-type-alias-with-bad-substs.rs | 28 +++++++ ...trait-in-type-alias-with-bad-substs.stderr | 20 +++++ 6 files changed, 144 insertions(+), 75 deletions(-) create mode 100644 tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.rs create mode 100644 tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.stderr diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 15081d6568299..a5481714e3e5e 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -65,12 +65,12 @@ pub use self::specialize::{ pub use self::structural_match::search_for_structural_match_violation; pub use self::structural_normalize::StructurallyNormalizeExt; pub use self::util::elaborate; -pub use self::util::{expand_trait_aliases, TraitAliasExpander}; -pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices}; pub use self::util::{ - supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_item, - SupertraitDefIds, + check_substs_compatible, supertrait_def_ids, supertraits, transitive_bounds, + transitive_bounds_that_define_assoc_item, SupertraitDefIds, }; +pub use self::util::{expand_trait_aliases, TraitAliasExpander}; +pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices}; pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index de76587c7b954..81b1ecc0d8819 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1,5 +1,6 @@ //! Code for projecting associated types out of trait references. +use super::check_substs_compatible; use super::specialization_graph; use super::translate_substs; use super::util; @@ -2378,47 +2379,6 @@ fn confirm_impl_candidate<'cx, 'tcx>( } } -// Verify that the trait item and its implementation have compatible substs lists -fn check_substs_compatible<'tcx>( - tcx: TyCtxt<'tcx>, - assoc_item: ty::AssocItem, - substs: ty::SubstsRef<'tcx>, -) -> bool { - fn check_substs_compatible_inner<'tcx>( - tcx: TyCtxt<'tcx>, - generics: &'tcx ty::Generics, - args: &'tcx [ty::GenericArg<'tcx>], - ) -> bool { - if generics.count() != args.len() { - return false; - } - - let (parent_args, own_args) = args.split_at(generics.parent_count); - - if let Some(parent) = generics.parent - && let parent_generics = tcx.generics_of(parent) - && !check_substs_compatible_inner(tcx, parent_generics, parent_args) { - return false; - } - - for (param, arg) in std::iter::zip(&generics.params, own_args) { - match (¶m.kind, arg.unpack()) { - (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_)) - | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_)) - | (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {} - _ => return false, - } - } - - true - } - - let generics = tcx.generics_of(assoc_item.def_id); - // Chop off any additional substs (RPITIT) substs - let substs = &substs[0..generics.count().min(substs.len())]; - check_substs_compatible_inner(tcx, generics, substs) -} - fn confirm_impl_trait_in_trait_candidate<'tcx>( selcx: &mut SelectionContext<'_, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 906c357e8ca7e..05a7f3e3b024a 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -302,3 +302,44 @@ pub enum TupleArgumentsFlag { Yes, No, } + +// Verify that the trait item and its implementation have compatible substs lists +pub fn check_substs_compatible<'tcx>( + tcx: TyCtxt<'tcx>, + assoc_item: ty::AssocItem, + substs: ty::SubstsRef<'tcx>, +) -> bool { + fn check_substs_compatible_inner<'tcx>( + tcx: TyCtxt<'tcx>, + generics: &'tcx ty::Generics, + args: &'tcx [ty::GenericArg<'tcx>], + ) -> bool { + if generics.count() != args.len() { + return false; + } + + let (parent_args, own_args) = args.split_at(generics.parent_count); + + if let Some(parent) = generics.parent + && let parent_generics = tcx.generics_of(parent) + && !check_substs_compatible_inner(tcx, parent_generics, parent_args) { + return false; + } + + for (param, arg) in std::iter::zip(&generics.params, own_args) { + match (¶m.kind, arg.unpack()) { + (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_)) + | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_)) + | (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {} + _ => return false, + } + } + + true + } + + let generics = tcx.generics_of(assoc_item.def_id); + // Chop off any additional substs (RPITIT) substs + let substs = &substs[0..generics.count().min(substs.len())]; + check_substs_compatible_inner(tcx, generics, substs) +} diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 4e91dd380e865..34c7b9f445182 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -6,7 +6,7 @@ use rustc_middle::ty::util::{CheckRegions, NotUniqueParam}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_span::Span; -use rustc_type_ir::AliasKind; +use rustc_trait_selection::traits::check_substs_compatible; use std::ops::ControlFlow; use crate::errors::{DuplicateArg, NotParam}; @@ -36,6 +36,15 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { self.tcx.def_span(self.item) } + fn parent_trait_ref(&self) -> Option> { + let parent = self.parent()?; + if matches!(self.tcx.def_kind(parent), DefKind::Impl { .. }) { + Some(self.tcx.impl_trait_ref(parent)?.subst_identity()) + } else { + None + } + } + fn parent(&self) -> Option { match self.tcx.def_kind(self.item) { DefKind::Fn => None, @@ -56,7 +65,7 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { #[instrument(skip(self), ret, level = "trace")] fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { - ty::Alias(AliasKind::Opaque, alias_ty) if alias_ty.def_id.is_local() => { + ty::Alias(ty::Opaque, alias_ty) if alias_ty.def_id.is_local() => { if !self.seen.insert(alias_ty.def_id.expect_local()) { return ControlFlow::Continue(()); } @@ -98,37 +107,48 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { } } } - ty::Alias(AliasKind::Projection, alias_ty) => { - if let Some(parent) = self.parent() { - trace!(?alias_ty); - let (trait_ref, own_substs) = alias_ty.trait_ref_and_own_substs(self.tcx); - - trace!(?trait_ref, ?own_substs); - // This avoids having to do normalization of `Self::AssocTy` by only - // supporting the case of a method defining opaque types from assoc types - // in the same impl block. - if trait_ref.self_ty() == self.tcx.type_of(parent).subst_identity() { - for assoc in self.tcx.associated_items(parent).in_definition_order() { + ty::Alias(ty::Projection, alias_ty) => { + // This avoids having to do normalization of `Self::AssocTy` by only + // supporting the case of a method defining opaque types from assoc types + // in the same impl block. + if let Some(parent_trait_ref) = self.parent_trait_ref() { + // If the trait ref of the associated item and the impl differs, + // then we can't use the impl's identity substitutions below, so + // just skip. + if alias_ty.trait_ref(self.tcx) == parent_trait_ref { + let parent = self.parent().expect("we should have a parent here"); + + for &assoc in self.tcx.associated_items(parent).in_definition_order() { trace!(?assoc); - if assoc.trait_item_def_id == Some(alias_ty.def_id) { - // We reconstruct the generic args of the associated type within the impl - // from the impl's generics and the generic args passed to the type via the - // projection. - let substs = ty::InternalSubsts::identity_for_item( - self.tcx, - parent.to_def_id(), + if assoc.trait_item_def_id != Some(alias_ty.def_id) { + continue; + } + + // If the type is further specializable, then the type_of + // is not actually correct below. + if !assoc.defaultness(self.tcx).is_final() { + continue; + } + + let impl_substs = alias_ty.substs.rebase_onto( + self.tcx, + parent_trait_ref.def_id, + ty::InternalSubsts::identity_for_item(self.tcx, parent), + ); + + if !check_substs_compatible(self.tcx, assoc, impl_substs) { + self.tcx.sess.delay_span_bug( + self.tcx.def_span(assoc.def_id), + "item had incorrect substs", ); - trace!(?substs); - let substs: Vec<_> = - substs.iter().chain(own_substs.iter().copied()).collect(); - trace!(?substs); - // Find opaque types in this associated type. - return self - .tcx - .type_of(assoc.def_id) - .subst(self.tcx, &substs) - .visit_with(self); + return ControlFlow::Continue(()); } + + return self + .tcx + .type_of(assoc.def_id) + .subst(self.tcx, impl_substs) + .visit_with(self); } } } diff --git a/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.rs b/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.rs new file mode 100644 index 0000000000000..a3f65146f75fb --- /dev/null +++ b/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.rs @@ -0,0 +1,28 @@ +#![feature(impl_trait_in_assoc_type)] + +// We weren't checking that the trait and impl generics line up in the +// normalization-shortcut code in `OpaqueTypeCollector`. + +use std::ops::Deref; + +trait Foo { + type Bar<'a>; + + type Baz<'a>; + + fn test<'a>() -> Self::Bar<'a>; +} + +impl Foo for () { + type Bar<'a> = impl Deref>; + + type Baz = impl Sized; + //~^ ERROR type `Baz` has 1 type parameter but its trait declaration has 0 type parameters + //~| ERROR unconstrained opaque type + + fn test<'a>() -> Self::Bar<'a> { + &() + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.stderr b/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.stderr new file mode 100644 index 0000000000000..13f5d8b8ea6e2 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.stderr @@ -0,0 +1,20 @@ +error[E0049]: type `Baz` has 1 type parameter but its trait declaration has 0 type parameters + --> $DIR/impl-trait-in-type-alias-with-bad-substs.rs:19:14 + | +LL | type Baz<'a>; + | -- expected 0 type parameters +... +LL | type Baz = impl Sized; + | ^ found 1 type parameter + +error: unconstrained opaque type + --> $DIR/impl-trait-in-type-alias-with-bad-substs.rs:19:19 + | +LL | type Baz = impl Sized; + | ^^^^^^^^^^ + | + = note: `Baz` must be used in combination with a concrete type within the same impl + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0049`. From c4cd6071007d12867112eb2a9ae10d07332d1d9a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 21 Jun 2023 16:41:23 +0000 Subject: [PATCH 369/465] Additional test demonstrating check for full trait ref --- .../not-matching-trait-refs-isnt-defining.rs | 33 +++++++++++++++++++ ...t-matching-trait-refs-isnt-defining.stderr | 22 +++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 tests/ui/type-alias-impl-trait/not-matching-trait-refs-isnt-defining.rs create mode 100644 tests/ui/type-alias-impl-trait/not-matching-trait-refs-isnt-defining.stderr diff --git a/tests/ui/type-alias-impl-trait/not-matching-trait-refs-isnt-defining.rs b/tests/ui/type-alias-impl-trait/not-matching-trait-refs-isnt-defining.rs new file mode 100644 index 0000000000000..131f8d999d878 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/not-matching-trait-refs-isnt-defining.rs @@ -0,0 +1,33 @@ +#![feature(impl_trait_in_assoc_type)] + +trait Foo { + type Assoc; + + fn test() -> u32; +} + +struct DefinesOpaque; +impl Foo for () { + type Assoc = impl Sized; + + // This test's return type is `u32`, *not* the opaque that is defined above. + // Previously we were only checking that the self type of the assoc matched, + // but this doesn't account for other impls with different trait substs. + fn test() -> <() as Foo>::Assoc { + let _: >::Assoc = ""; + //~^ ERROR mismatched types + + 1 + } +} + +struct NoOpaques; +impl Foo for () { + type Assoc = u32; + + fn test() -> u32 { + 1 + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/not-matching-trait-refs-isnt-defining.stderr b/tests/ui/type-alias-impl-trait/not-matching-trait-refs-isnt-defining.stderr new file mode 100644 index 0000000000000..d2d007490915b --- /dev/null +++ b/tests/ui/type-alias-impl-trait/not-matching-trait-refs-isnt-defining.stderr @@ -0,0 +1,22 @@ +error[E0308]: mismatched types + --> $DIR/not-matching-trait-refs-isnt-defining.rs:17:54 + | +LL | type Assoc = impl Sized; + | ---------- the expected opaque type +... +LL | let _: >::Assoc = ""; + | ----------------------------------- ^^ expected opaque type, found `&str` + | | + | expected due to this + | + = note: expected opaque type `<() as Foo>::Assoc` + found reference `&'static str` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/not-matching-trait-refs-isnt-defining.rs:16:5 + | +LL | fn test() -> <() as Foo>::Assoc { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From b610be68e98fec6d182f346dced448cba436c0f4 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Wed, 21 Jun 2023 21:36:50 +0100 Subject: [PATCH 370/465] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index dead4b8740c4b..4cebd130ebca3 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit dead4b8740c4b6a8ed5211e37c99cf81d01c3b1c +Subproject commit 4cebd130ebca3bc219180a54f3e26cc1b14a91de From bdc3db944cf8da99d80e67e7bb52917512d0a5a7 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Tue, 11 Oct 2022 17:22:12 -0700 Subject: [PATCH 371/465] wip: Support Apple tvOS in libstd --- library/std/build.rs | 2 +- library/std/src/os/ios/fs.rs | 2 +- library/std/src/os/mod.rs | 3 ++ library/std/src/os/unix/mod.rs | 3 ++ library/std/src/os/unix/net/stream.rs | 3 ++ library/std/src/os/unix/ucred.rs | 4 +-- library/std/src/os/unix/ucred/tests.rs | 1 + library/std/src/personality/gcc.rs | 2 +- library/std/src/sys/unix/args.rs | 4 +-- library/std/src/sys/unix/env.rs | 11 +++++++ library/std/src/sys/unix/fs.rs | 32 ++++++++++++++++--- .../std/src/sys/unix/locks/pthread_condvar.rs | 2 ++ library/std/src/sys/unix/mod.rs | 2 +- library/std/src/sys/unix/os.rs | 12 +++++-- library/std/src/sys/unix/rand.rs | 3 +- library/std/src/sys/unix/thread.rs | 3 +- .../src/sys/unix/thread_parking/pthread.rs | 3 ++ library/std/src/sys/unix/time.rs | 6 ++-- library/std/src/sys/unix/weak.rs | 4 +-- library/std/src/sys_common/net.rs | 2 +- library/unwind/src/libunwind.rs | 2 +- 21 files changed, 84 insertions(+), 22 deletions(-) diff --git a/library/std/build.rs b/library/std/build.rs index d0b379409369f..ddf6e84d8d035 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -18,6 +18,7 @@ fn main() { || target.contains("illumos") || target.contains("apple-darwin") || target.contains("apple-ios") + || target.contains("apple-tvos") || target.contains("apple-watchos") || target.contains("uwp") || target.contains("windows") @@ -48,7 +49,6 @@ fn main() { // - mipsel-sony-psp // - nvptx64-nvidia-cuda // - arch=avr - // - tvos (aarch64-apple-tvos, x86_64-apple-tvos) // - uefi (x86_64-unknown-uefi, i686-unknown-uefi) // - JSON targets // - Any new targets that have not been explicitly added above. diff --git a/library/std/src/os/ios/fs.rs b/library/std/src/os/ios/fs.rs index 6d4d54b7c78c5..b319527a541f5 100644 --- a/library/std/src/os/ios/fs.rs +++ b/library/std/src/os/ios/fs.rs @@ -6,7 +6,7 @@ use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; use crate::time::SystemTime; #[allow(deprecated)] -use crate::os::ios::raw; +use super::raw; /// OS-specific extensions to [`fs::Metadata`]. /// diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index 5b54cc5f2e491..634c3cc4a15c4 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -137,6 +137,9 @@ pub mod redox; pub mod solaris; #[cfg(target_os = "solid_asp3")] pub mod solid; +#[cfg(target_os = "tvos")] +#[path = "ios/mod.rs"] +pub(crate) mod tvos; #[cfg(target_os = "vita")] pub mod vita; #[cfg(target_os = "vxworks")] diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs index 6fe1111188aa8..401ec1e7a0130 100644 --- a/library/std/src/os/unix/mod.rs +++ b/library/std/src/os/unix/mod.rs @@ -73,6 +73,8 @@ mod platform { pub use crate::os::redox::*; #[cfg(target_os = "solaris")] pub use crate::os::solaris::*; + #[cfg(target_os = "tvos")] + pub use crate::os::tvos::*; #[cfg(target_os = "vita")] pub use crate::os::vita::*; #[cfg(target_os = "vxworks")] @@ -96,6 +98,7 @@ pub mod thread; target_os = "dragonfly", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "macos", target_os = "netbsd", diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index bf2a51b5edb88..e20170873bbbd 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -11,6 +11,7 @@ use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, Owned target_os = "dragonfly", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "macos", target_os = "watchos", target_os = "netbsd", @@ -30,6 +31,7 @@ use crate::time::Duration; target_os = "dragonfly", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "macos", target_os = "watchos", target_os = "netbsd", @@ -238,6 +240,7 @@ impl UnixStream { target_os = "dragonfly", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "macos", target_os = "watchos", target_os = "netbsd", diff --git a/library/std/src/os/unix/ucred.rs b/library/std/src/os/unix/ucred.rs index 95967eac29520..6a0cc2d2c48ff 100644 --- a/library/std/src/os/unix/ucred.rs +++ b/library/std/src/os/unix/ucred.rs @@ -36,7 +36,7 @@ pub use self::impl_linux::peer_cred; ))] pub use self::impl_bsd::peer_cred; -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] pub use self::impl_mac::peer_cred; #[cfg(any(target_os = "linux", target_os = "android"))] @@ -98,7 +98,7 @@ pub mod impl_bsd { } } -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] pub mod impl_mac { use super::UCred; use crate::os::unix::io::AsRawFd; diff --git a/library/std/src/os/unix/ucred/tests.rs b/library/std/src/os/unix/ucred/tests.rs index e63a2fc248eb0..7c3a646ed939e 100644 --- a/library/std/src/os/unix/ucred/tests.rs +++ b/library/std/src/os/unix/ucred/tests.rs @@ -8,6 +8,7 @@ use libc::{getegid, geteuid, getpid}; target_os = "dragonfly", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "macos", target_os = "watchos", target_os = "openbsd" diff --git a/library/std/src/personality/gcc.rs b/library/std/src/personality/gcc.rs index 82edb11cbd146..6552d96ca6994 100644 --- a/library/std/src/personality/gcc.rs +++ b/library/std/src/personality/gcc.rs @@ -85,7 +85,7 @@ const UNWIND_DATA_REG: (i32, i32) = (4, 5); // a0, a1 // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c cfg_if::cfg_if! { - if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "watchos"), not(target_os = "netbsd")))] { + if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "tvos"), not(target_os = "watchos"), not(target_os = "netbsd")))] { // ARM EHABI personality routine. // https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf // diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs index 0efe2570d6775..f8fa81e6ef183 100644 --- a/library/std/src/sys/unix/args.rs +++ b/library/std/src/sys/unix/args.rs @@ -168,7 +168,7 @@ mod imp { } } -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] mod imp { use super::Args; use crate::ffi::CStr; @@ -209,7 +209,7 @@ mod imp { // for i in (0..[args count]) // res.push([args objectAtIndex:i]) // res - #[cfg(any(target_os = "ios", target_os = "watchos"))] + #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))] pub fn args() -> Args { use crate::ffi::OsString; use crate::mem; diff --git a/library/std/src/sys/unix/env.rs b/library/std/src/sys/unix/env.rs index 8c3ef88d8f8e0..929e9dae73868 100644 --- a/library/std/src/sys/unix/env.rs +++ b/library/std/src/sys/unix/env.rs @@ -31,6 +31,17 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } +#[cfg(target_os = "tvos")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "tvos"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".dylib"; + pub const DLL_EXTENSION: &str = "dylib"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + #[cfg(target_os = "watchos")] pub mod os { pub const FAMILY: &str = "unix"; diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index d2fb6238387a1..f05ece17c3718 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -32,6 +32,7 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; all(target_os = "linux", target_env = "gnu"), target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", ))] use crate::sys::weak::syscall; @@ -43,6 +44,7 @@ use libc::{c_int, mode_t}; #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "solaris", all(target_os = "linux", target_env = "gnu") @@ -519,6 +521,7 @@ impl FileAttr { target_os = "openbsd", target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", ))] pub fn created(&self) -> io::Result { @@ -530,6 +533,7 @@ impl FileAttr { target_os = "openbsd", target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "vita", )))] @@ -895,6 +899,7 @@ impl DirEntry { #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "linux", target_os = "emscripten", @@ -928,6 +933,7 @@ impl DirEntry { #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "netbsd", target_os = "openbsd", @@ -946,6 +952,7 @@ impl DirEntry { #[cfg(not(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "netbsd", target_os = "openbsd", @@ -1107,11 +1114,21 @@ impl File { cvt_r(|| unsafe { os_fsync(self.as_raw_fd()) })?; return Ok(()); - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + ))] unsafe fn os_fsync(fd: c_int) -> c_int { libc::fcntl(fd, libc::F_FULLFSYNC) } - #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "watchos")))] + #[cfg(not(any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + )))] unsafe fn os_fsync(fd: c_int) -> c_int { libc::fsync(fd) } @@ -1121,7 +1138,12 @@ impl File { cvt_r(|| unsafe { os_datasync(self.as_raw_fd()) })?; return Ok(()); - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + ))] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fcntl(fd, libc::F_FULLFSYNC) } @@ -1140,6 +1162,7 @@ impl File { target_os = "android", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -1709,6 +1732,7 @@ fn open_to_and_set_permissions( target_os = "android", target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", )))] pub fn copy(from: &Path, to: &Path) -> io::Result { @@ -1736,7 +1760,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { } } -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] pub fn copy(from: &Path, to: &Path) -> io::Result { use crate::sync::atomic::{AtomicBool, Ordering}; diff --git a/library/std/src/sys/unix/locks/pthread_condvar.rs b/library/std/src/sys/unix/locks/pthread_condvar.rs index 192fa216dfaf5..330b4affa896c 100644 --- a/library/std/src/sys/unix/locks/pthread_condvar.rs +++ b/library/std/src/sys/unix/locks/pthread_condvar.rs @@ -124,6 +124,7 @@ impl Condvar { #[cfg(not(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "android", target_os = "espidf", @@ -158,6 +159,7 @@ impl Condvar { #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "android", target_os = "espidf", diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 24566d96bcd61..0247b56935fc9 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -387,7 +387,7 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "macos")] { #[link(name = "System")] extern "C" {} - } else if #[cfg(any(target_os = "ios", target_os = "watchos"))] { + } else if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))] { #[link(name = "System")] #[link(name = "objc")] #[link(name = "Security", kind = "framework")] diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 8edfd33130442..a68c14758ff79 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -63,7 +63,13 @@ extern "C" { #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")] #[cfg_attr(target_os = "nto", link_name = "__get_errno_ptr")] #[cfg_attr( - any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "watchos"), + any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "freebsd", + target_os = "watchos" + ), link_name = "__error" )] #[cfg_attr(target_os = "haiku", link_name = "_errnop")] @@ -375,7 +381,7 @@ pub fn current_exe() -> io::Result { Ok(PathBuf::from(OsString::from_vec(e))) } -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] pub fn current_exe() -> io::Result { unsafe { let mut sz: u32 = 0; @@ -609,6 +615,7 @@ pub fn home_dir() -> Option { #[cfg(any( target_os = "android", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "emscripten", target_os = "redox", @@ -623,6 +630,7 @@ pub fn home_dir() -> Option { #[cfg(not(any( target_os = "android", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "emscripten", target_os = "redox", diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs index d8b63546b9ed1..d471be33ed559 100644 --- a/library/std/src/sys/unix/rand.rs +++ b/library/std/src/sys/unix/rand.rs @@ -14,6 +14,7 @@ pub fn hashmap_random_keys() -> (u64, u64) { unix, not(target_os = "macos"), not(target_os = "ios"), + not(target_os = "tvos"), not(target_os = "watchos"), not(target_os = "openbsd"), not(target_os = "freebsd"), @@ -198,7 +199,7 @@ mod imp { // once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is // only used on iOS where direct access to `/dev/urandom` is blocked by the // sandbox. -#[cfg(any(target_os = "ios", target_os = "watchos"))] +#[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))] mod imp { use crate::io; use crate::ptr; diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 010015667f7a2..916390f3a6692 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -150,7 +150,7 @@ impl Thread { } } - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] pub fn set_name(name: &CStr) { unsafe { let name = truncate_cstr::<{ libc::MAXTHREADNAMESIZE }>(name); @@ -299,6 +299,7 @@ pub fn available_parallelism() -> io::Result { target_os = "emscripten", target_os = "fuchsia", target_os = "ios", + target_os = "tvos", target_os = "linux", target_os = "macos", target_os = "solaris", diff --git a/library/std/src/sys/unix/thread_parking/pthread.rs b/library/std/src/sys/unix/thread_parking/pthread.rs index 8bf4bae7a3f77..ae805d8439945 100644 --- a/library/std/src/sys/unix/thread_parking/pthread.rs +++ b/library/std/src/sys/unix/thread_parking/pthread.rs @@ -46,6 +46,7 @@ unsafe fn wait_timeout( #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "espidf", target_os = "horizon", @@ -73,6 +74,7 @@ unsafe fn wait_timeout( #[cfg(not(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "espidf", target_os = "horizon", @@ -120,6 +122,7 @@ impl Parker { if #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "l4re", target_os = "android", diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index a9fbc7ab108a4..17b4130c20241 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -219,7 +219,8 @@ impl From<__timespec64> for Timespec { #[cfg(any( all(target_os = "macos", any(not(target_arch = "aarch64"))), target_os = "ios", - target_os = "watchos" + target_os = "watchos", + target_os = "tvos" ))] mod inner { use crate::sync::atomic::{AtomicU64, Ordering}; @@ -339,7 +340,8 @@ mod inner { #[cfg(not(any( all(target_os = "macos", any(not(target_arch = "aarch64"))), target_os = "ios", - target_os = "watchos" + target_os = "watchos", + target_os = "tvos" )))] mod inner { use crate::fmt; diff --git a/library/std/src/sys/unix/weak.rs b/library/std/src/sys/unix/weak.rs index 62ffee70becc3..61088ff16eddf 100644 --- a/library/std/src/sys/unix/weak.rs +++ b/library/std/src/sys/unix/weak.rs @@ -28,7 +28,7 @@ use crate::ptr; use crate::sync::atomic::{self, AtomicPtr, Ordering}; // We can use true weak linkage on ELF targets. -#[cfg(not(any(target_os = "macos", target_os = "ios")))] +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "tvos")))] pub(crate) macro weak { (fn $name:ident($($t:ty),*) -> $ret:ty) => ( let ref $name: ExternWeak $ret> = { @@ -43,7 +43,7 @@ pub(crate) macro weak { } // On non-ELF targets, use the dlsym approximation of weak linkage. -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos"))] pub(crate) use self::dlsym as weak; pub(crate) struct ExternWeak { diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 652c695fc57b0..2976a9f578ede 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -18,7 +18,7 @@ use crate::ffi::{c_int, c_void}; cfg_if::cfg_if! { if #[cfg(any( target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", target_os = "macos", target_os = "watchos", + target_os = "ios", target_os = "tvos", target_os = "macos", target_os = "watchos", target_os = "openbsd", target_os = "netbsd", target_os = "illumos", target_os = "solaris", target_os = "haiku", target_os = "l4re", target_os = "nto"))] { use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index f6a68073b2f7e..ec24e137572d4 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -117,7 +117,7 @@ extern "C" { } cfg_if::cfg_if! { -if #[cfg(any(target_os = "ios", target_os = "watchos", target_os = "netbsd", not(target_arch = "arm")))] { +if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "netbsd", not(target_arch = "arm")))] { // Not ARM EHABI #[repr(C)] #[derive(Copy, Clone, PartialEq)] From f978d7ea427b1e9e8ea23eb0bd8cd03b21092720 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Tue, 14 Mar 2023 20:02:42 -0700 Subject: [PATCH 372/465] Finish up preliminary tvos support in libstd --- library/core/src/ffi/mod.rs | 23 +++++++++++++------ library/std/src/sys/unix/fd.rs | 6 +++++ .../std/src/sys/unix/locks/pthread_condvar.rs | 1 + library/std/src/sys/unix/mod.rs | 1 + library/std/src/sys/unix/thread.rs | 8 ++++++- 5 files changed, 31 insertions(+), 8 deletions(-) diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 86ea154a8868e..7437722fd0625 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -238,7 +238,7 @@ impl fmt::Debug for c_void { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), + all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios", target_os = "tvos")), target_family = "wasm", target_arch = "asmjs", target_os = "uefi", @@ -267,7 +267,7 @@ pub struct VaListImpl<'f> { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), + all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios", target_os = "tvos")), target_family = "wasm", target_arch = "asmjs", target_os = "uefi", @@ -292,7 +292,7 @@ impl<'f> fmt::Debug for VaListImpl<'f> { /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf #[cfg(all( target_arch = "aarch64", - not(any(target_os = "macos", target_os = "ios")), + not(any(target_os = "macos", target_os = "ios", target_os = "tvos")), not(target_os = "uefi"), not(windows), ))] @@ -389,7 +389,10 @@ pub struct VaList<'a, 'f: 'a> { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), + all( + target_arch = "aarch64", + any(target_os = "macos", target_os = "ios", target_os = "tvos") + ), target_family = "wasm", target_arch = "asmjs", target_os = "uefi", @@ -404,7 +407,10 @@ pub struct VaList<'a, 'f: 'a> { target_arch = "s390x", target_arch = "x86_64" ), - any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))), + any( + not(target_arch = "aarch64"), + not(any(target_os = "macos", target_os = "ios", target_os = "tvos")) + ), not(target_family = "wasm"), not(target_arch = "asmjs"), not(target_os = "uefi"), @@ -422,7 +428,7 @@ pub struct VaList<'a, 'f: 'a> { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), + all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios", target_os = "tvos")), target_family = "wasm", target_arch = "asmjs", target_os = "uefi", @@ -449,7 +455,10 @@ impl<'f> VaListImpl<'f> { target_arch = "s390x", target_arch = "x86_64" ), - any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))), + any( + not(target_arch = "aarch64"), + not(any(target_os = "macos", target_os = "ios", target_os = "tvos")) + ), not(target_family = "wasm"), not(target_arch = "asmjs"), not(target_os = "uefi"), diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 69c93c9200367..85e020ae41328 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -44,6 +44,7 @@ const READ_LIMIT: usize = libc::ssize_t::MAX as usize; target_os = "dragonfly", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "macos", target_os = "netbsd", target_os = "openbsd", @@ -69,6 +70,7 @@ const fn max_iov() -> usize { target_os = "emscripten", target_os = "freebsd", target_os = "ios", + target_os = "tvos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -181,6 +183,7 @@ impl FileDesc { target_os = "fuchsia", target_os = "illumos", target_os = "ios", + target_os = "tvos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -222,6 +225,7 @@ impl FileDesc { #[cfg(any( all(target_os = "android", target_pointer_width = "32"), target_os = "ios", + target_os = "tvos", target_os = "macos", ))] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { @@ -320,6 +324,7 @@ impl FileDesc { target_os = "fuchsia", target_os = "illumos", target_os = "ios", + target_os = "tvos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -361,6 +366,7 @@ impl FileDesc { #[cfg(any( all(target_os = "android", target_pointer_width = "32"), target_os = "ios", + target_os = "tvos", target_os = "macos", ))] pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { diff --git a/library/std/src/sys/unix/locks/pthread_condvar.rs b/library/std/src/sys/unix/locks/pthread_condvar.rs index 330b4affa896c..2dc1b0c601e78 100644 --- a/library/std/src/sys/unix/locks/pthread_condvar.rs +++ b/library/std/src/sys/unix/locks/pthread_condvar.rs @@ -32,6 +32,7 @@ impl LazyInit for AllocatedCondvar { if #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "l4re", target_os = "android", diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 0247b56935fc9..1b72e21a83285 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -87,6 +87,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { // The poll on Darwin doesn't set POLLNVAL for closed fds. target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos", target_os = "redox", target_os = "l4re", diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 916390f3a6692..893f8b8df3f54 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -283,7 +283,13 @@ impl Drop for Thread { } } -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any( + target_os = "linux", + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", +))] fn truncate_cstr(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] { let mut result = [0; MAX_WITH_NUL]; for (src, dst) in cstr.to_bytes().iter().zip(&mut result[..MAX_WITH_NUL - 1]) { From 3785a17dd93271543cf532776d209648e1c38cb3 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Tue, 14 Mar 2023 20:03:21 -0700 Subject: [PATCH 373/465] =?UTF-8?q?Fix=20busted=20data=5Flayout=C2=A0(mism?= =?UTF-8?q?atch=20vs=20LLVM)=20in=20x86=5F64=20tvOS=20simulator=20target?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- compiler/rustc_target/src/spec/x86_64_apple_tvos.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs index 76de7d20c4c6f..ae0107efef62a 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs @@ -6,7 +6,8 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-apple-tvos".into(), pointer_width: 64, - data_layout: "e-m:o-i64:64-f80:128-n8:16:32:64-S128".into(), + data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + .into(), arch: arch.target_arch(), options: TargetOptions { max_atomic_width: Some(128), From abb191168222e57c2adb3874b7955b37d3021abb Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Tue, 14 Mar 2023 21:24:15 -0700 Subject: [PATCH 374/465] Fix the tvOS targets to use the right LLVM target and respect the deployment target environment variables --- .../rustc_target/src/spec/aarch64_apple_tvos.rs | 4 ++-- compiler/rustc_target/src/spec/apple_base.rs | 16 +++++++++++++++- .../rustc_target/src/spec/x86_64_apple_tvos.rs | 4 ++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs index bb7c39ff26bdf..f7cdfa71c4b65 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs @@ -1,10 +1,10 @@ -use super::apple_base::{opts, Arch}; +use super::apple_base::{opts, tvos_llvm_target, Arch}; use crate::spec::{FramePointer, Target, TargetOptions}; pub fn target() -> Target { let arch = Arch::Arm64; Target { - llvm_target: "arm64-apple-tvos".into(), + llvm_target: tvos_llvm_target(arch).into(), pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(), arch: arch.target_arch(), diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index ff2246318288e..7bdd867e51b35 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -240,7 +240,10 @@ fn link_env_remove(arch: Arch, os: &'static str) -> StaticCow<[StaticCow]> // Remove the `SDKROOT` environment variable if it's clearly set for the wrong platform, which // may occur when we're linking a custom build script while targeting iOS for example. if let Ok(sdkroot) = env::var("SDKROOT") { - if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("iPhoneSimulator.platform") + if sdkroot.contains("iPhoneOS.platform") + || sdkroot.contains("iPhoneSimulator.platform") + || sdkroot.contains("AppleTVOS.platform") + || sdkroot.contains("AppleTVSimulator.platform") { env_remove.push("SDKROOT".into()) } @@ -249,6 +252,7 @@ fn link_env_remove(arch: Arch, os: &'static str) -> StaticCow<[StaticCow]> // "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld", // although this is apparently ignored when using the linker at "/usr/bin/ld". env_remove.push("IPHONEOS_DEPLOYMENT_TARGET".into()); + env_remove.push("TVOS_DEPLOYMENT_TARGET".into()); env_remove.into() } else { // Otherwise if cross-compiling for a different OS/SDK, remove any part @@ -279,6 +283,16 @@ pub fn ios_llvm_target(arch: Arch) -> String { format!("{}-apple-ios{}.{}.0", arch.target_name(), major, minor) } +pub fn tvos_sim_llvm_target(arch: Arch) -> String { + let (major, minor) = tvos_deployment_target(); + format!("{}-apple-tvos{}.{}.0-simulator", arch.target_name(), major, minor) +} + +pub fn tvos_llvm_target(arch: Arch) -> String { + let (major, minor) = tvos_deployment_target(); + format!("{}-apple-tvos{}.{}.0", arch.target_name(), major, minor) +} + fn ios_lld_platform_version() -> String { let (major, minor) = ios_deployment_target(); format!("{major}.{minor}") diff --git a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs index ae0107efef62a..2ec4d9569e3ea 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs @@ -1,10 +1,10 @@ -use super::apple_base::{opts, Arch}; +use super::apple_base::{opts, tvos_sim_llvm_target, Arch}; use crate::spec::{StackProbeType, Target, TargetOptions}; pub fn target() -> Target { let arch = Arch::X86_64_sim; Target { - llvm_target: "x86_64-apple-tvos".into(), + llvm_target: tvos_sim_llvm_target(arch).into(), pointer_width: 64, data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .into(), From df9640211d5ba4d2fbafd8cd42c3fa61076185fc Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Tue, 14 Mar 2023 21:24:49 -0700 Subject: [PATCH 375/465] Add a tvOS entry to the platform-support documentation --- src/doc/rustc/src/platform-support.md | 4 +- .../rustc/src/platform-support/apple-tvos.md | 70 +++++++++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 src/doc/rustc/src/platform-support/apple-tvos.md diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index f69dcd5983d33..62f628f822933 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -214,7 +214,7 @@ host tools. target | std | host | notes -------|:---:|:----:|------- `aarch64-apple-ios-macabi` | ? | | Apple Catalyst on ARM64 -`aarch64-apple-tvos` | * | | ARM64 tvOS +[`aarch64-apple-tvos`](platform-support/apple-tvos.md) | ? | | ARM64 tvOS [`aarch64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | ARM64 Apple WatchOS Simulator [`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ | | ARM64 SOLID with TOPPERS/ASP3 [`aarch64-nintendo-switch-freestanding`](platform-support/aarch64-nintendo-switch-freestanding.md) | * | | ARM64 Nintendo Switch, Horizon @@ -316,7 +316,7 @@ target | std | host | notes `thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7a Linux with NEON, MUSL [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly `x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64 -`x86_64-apple-tvos` | * | | x86 64-bit tvOS +[`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ? | | x86 64-bit tvOS [`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator [`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS | [`x86_64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | diff --git a/src/doc/rustc/src/platform-support/apple-tvos.md b/src/doc/rustc/src/platform-support/apple-tvos.md new file mode 100644 index 0000000000000..95256178cfdfd --- /dev/null +++ b/src/doc/rustc/src/platform-support/apple-tvos.md @@ -0,0 +1,70 @@ +# `*-apple-tvos` +- aarch64-apple-tvos +- x86_64-apple-tvos + +**Tier: 3** + +Apple WatchOS targets: +- Apple tvOS on aarch64 +- Apple tvOS Simulator on x86_64 + +## Target maintainers + +* [@thomcc](https://github.com/thomcc) + +## Requirements + +These targets are cross-compiled. You will need appropriate versions of XCode +and the SDKs for tvOS (`AppleTVOS.sdk`) and/or the tvOS Simulator +(`AppleTVSimulator.sdk`) to build a toolchain and target these platforms. + +The targets support the full standard library including the allocator to the +best of my knowledge, however they are very new, not yet well-tested tested, and +it is possible that there are various bugs. + +In theory we support back to tvOS version 7.0, although the actual minimum +version you can target may be newer than this, for example due to the versions +of XCode and your SDKs. + +As with the other Apple targets, `rustc` respects the common environment +variables used by XCode to configure this, in this case +`TVOS_DEPLOYMENT_TARGET`. + +## Building the target + +The targets can be built by enabling them for a `rustc` build, for example: + +```toml +[build] +build-stage = 1 +target = ["aarch64-apple-tvos", "x86_64-apple-tvos"] +``` + +It's possible that cargo under `-Zbuild-std` may also be used to target them. + +## Building Rust programs + +*Note: Building for this target requires the corresponding TVOS SDK, as provided by Xcode.* + +Rust programs can be built for these targets + +```text +$ rustc --target aarch64-apple-tvos your-code.rs +... +$ rustc --target x86_64-apple-tvos your-code.rs +``` + +## Testing + +There is no support for running the Rust or standard library testsuite on tvOS +or the simulators at the moment. Testing has mostly been done manually with +builds of static libraries called from XCode or a simulator. + +It hopefully will be possible to improve this in the future. + +## Cross-compilation toolchains and C code + +This target can be cross-compiled from x86_64 or aarch64 macOS hosts. + +Other hosts are not supported for cross-compilation, but might work when also +providing the required Xcode SDK. From b18ff59690cbd9c5759712c312e0ee8cae04b5ed Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Tue, 14 Mar 2023 22:15:49 -0700 Subject: [PATCH 376/465] Fix rustc_target::spec::apple::tests --- compiler/rustc_target/src/spec/apple/tests.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/apple/tests.rs b/compiler/rustc_target/src/spec/apple/tests.rs index 3c90a5e7e93ea..3b23ddadcc47c 100644 --- a/compiler/rustc_target/src/spec/apple/tests.rs +++ b/compiler/rustc_target/src/spec/apple/tests.rs @@ -30,6 +30,9 @@ fn macos_link_environment_unmodified() { for target in all_macos_targets { // macOS targets should only remove information for cross-compiling, but never // for the host. - assert_eq!(target.link_env_remove, crate::spec::cvs!["IPHONEOS_DEPLOYMENT_TARGET"]); + assert_eq!( + target.link_env_remove, + crate::spec::cvs!["IPHONEOS_DEPLOYMENT_TARGET", "TVOS_DEPLOYMENT_TARGET"], + ); } } From 6e62961474878c25464c748c41d951d1d4cff1a9 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Wed, 15 Mar 2023 20:21:20 -0700 Subject: [PATCH 377/465] Fix missing link in SUMMARY.md --- src/doc/rustc/src/SUMMARY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 2b0431a159b1b..1e17a90a8428c 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -16,6 +16,7 @@ - [Target Tier Policy](target-tier-policy.md) - [Template for Target-specific Documentation](platform-support/TEMPLATE.md) - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md) + - [\*-apple-tvos](platform-support/apple-tvos.md) - [\*-apple-watchos\*](platform-support/apple-watchos.md) - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md) - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md) From a3f5566858aac8a41c3600d895626d0d2b0eeacd Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Sun, 4 Jun 2023 08:51:07 -0700 Subject: [PATCH 378/465] Apply suggestions from code review Co-authored-by: Jubilee <46493976+workingjubilee@users.noreply.github.com> --- src/doc/rustc/src/platform-support/apple-tvos.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/doc/rustc/src/platform-support/apple-tvos.md b/src/doc/rustc/src/platform-support/apple-tvos.md index 95256178cfdfd..2446c5fc10fce 100644 --- a/src/doc/rustc/src/platform-support/apple-tvos.md +++ b/src/doc/rustc/src/platform-support/apple-tvos.md @@ -4,7 +4,7 @@ **Tier: 3** -Apple WatchOS targets: +Apple tvOS targets: - Apple tvOS on aarch64 - Apple tvOS Simulator on x86_64 @@ -14,25 +14,25 @@ Apple WatchOS targets: ## Requirements -These targets are cross-compiled. You will need appropriate versions of XCode +These targets are cross-compiled. You will need appropriate versions of Xcode and the SDKs for tvOS (`AppleTVOS.sdk`) and/or the tvOS Simulator (`AppleTVSimulator.sdk`) to build a toolchain and target these platforms. The targets support the full standard library including the allocator to the -best of my knowledge, however they are very new, not yet well-tested tested, and +best of my knowledge, however they are very new, not yet well-tested, and it is possible that there are various bugs. In theory we support back to tvOS version 7.0, although the actual minimum version you can target may be newer than this, for example due to the versions -of XCode and your SDKs. +of Xcode and your SDKs. As with the other Apple targets, `rustc` respects the common environment -variables used by XCode to configure this, in this case +variables used by Xcode to configure this, in this case `TVOS_DEPLOYMENT_TARGET`. ## Building the target -The targets can be built by enabling them for a `rustc` build, for example: +The targets can be built by enabling them for a `rustc` build in `config.toml`, by adding, for example: ```toml [build] @@ -58,7 +58,7 @@ $ rustc --target x86_64-apple-tvos your-code.rs There is no support for running the Rust or standard library testsuite on tvOS or the simulators at the moment. Testing has mostly been done manually with -builds of static libraries called from XCode or a simulator. +builds of static libraries called from Xcode or a simulator. It hopefully will be possible to improve this in the future. From b80e0b7f53461a827fa007910e86560eec3a1180 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Sun, 4 Jun 2023 08:57:27 -0700 Subject: [PATCH 379/465] Reorder `tvos_*` functions in apple_base.rs to avoid breaking sorted order --- compiler/rustc_target/src/spec/apple_base.rs | 22 +++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index 7bdd867e51b35..8a8d1ab95e81e 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -244,6 +244,8 @@ fn link_env_remove(arch: Arch, os: &'static str) -> StaticCow<[StaticCow]> || sdkroot.contains("iPhoneSimulator.platform") || sdkroot.contains("AppleTVOS.platform") || sdkroot.contains("AppleTVSimulator.platform") + || sdkroot.contains("WatchOS.platform") + || sdkroot.contains("WatchSimulator.platform") { env_remove.push("SDKROOT".into()) } @@ -283,16 +285,6 @@ pub fn ios_llvm_target(arch: Arch) -> String { format!("{}-apple-ios{}.{}.0", arch.target_name(), major, minor) } -pub fn tvos_sim_llvm_target(arch: Arch) -> String { - let (major, minor) = tvos_deployment_target(); - format!("{}-apple-tvos{}.{}.0-simulator", arch.target_name(), major, minor) -} - -pub fn tvos_llvm_target(arch: Arch) -> String { - let (major, minor) = tvos_deployment_target(); - format!("{}-apple-tvos{}.{}.0", arch.target_name(), major, minor) -} - fn ios_lld_platform_version() -> String { let (major, minor) = ios_deployment_target(); format!("{major}.{minor}") @@ -313,6 +305,16 @@ fn tvos_lld_platform_version() -> String { format!("{major}.{minor}") } +pub fn tvos_llvm_target(arch: Arch) -> String { + let (major, minor) = tvos_deployment_target(); + format!("{}-apple-tvos{}.{}.0", arch.target_name(), major, minor) +} + +pub fn tvos_sim_llvm_target(arch: Arch) -> String { + let (major, minor) = tvos_deployment_target(); + format!("{}-apple-tvos{}.{}.0-simulator", arch.target_name(), major, minor) +} + fn watchos_deployment_target() -> (u32, u32) { // If you are looking for the default deployment target, prefer `rustc --print deployment-target`. from_set_deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0)) From 49da0acb7153f93a09f3f28461d4e4f23452df21 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Sun, 4 Jun 2023 09:46:18 -0700 Subject: [PATCH 380/465] Avoid fork/exec spawning on tvOS/watchOS, as those functions are marked as prohibited --- .../std/src/sys/unix/process/process_unix.rs | 52 +++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 22d9d6141f404..98564c11673c5 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -15,6 +15,8 @@ use crate::sys::weak::raw_syscall; #[cfg(any( target_os = "macos", + target_os = "watchos", + target_os = "tvos", target_os = "freebsd", all(target_os = "linux", target_env = "gnu"), all(target_os = "linux", target_env = "musl"), @@ -28,7 +30,12 @@ use libc::RTP_ID as pid_t; #[cfg(not(target_os = "vxworks"))] use libc::{c_int, pid_t}; -#[cfg(not(any(target_os = "vxworks", target_os = "l4re")))] +#[cfg(not(any( + target_os = "vxworks", + target_os = "l4re", + target_os = "tvos", + target_os = "watchos", +)))] use libc::{gid_t, uid_t}; cfg_if::cfg_if! { @@ -84,7 +91,6 @@ impl Command { if let Some(ret) = self.posix_spawn(&theirs, envp.as_ref())? { return Ok((ret, ours)); } - let (input, output) = sys::pipe::anon_pipe()?; // Whatever happens after the fork is almost for sure going to touch or @@ -166,9 +172,32 @@ impl Command { crate::sys_common::process::wait_with_output(proc, pipes) } + // WatchOS and TVOS can theoretically spawn processes using `posix_spawn*` + // (although it just fails with a runtime error AFAICT, so we don't yet + // support it in `std`), but forbid use of `fork`/`exec*`. It's unclear the + // extent to which these is restricted, but the headers say + // `__WATCHOS_PROHIBITED __TVOS_PROHIBITED`, so we go out of our way to + // avoid containing any calls to them at all, to avoid linking against their + // symbols on those targets. + #[cfg(any(target_os = "tvos", target_os = "watchos"))] + const ERR_APPLE_TV_WATCH_NO_FORK_EXEC: Error = io::const_io_error!( + ErrorKind::Unsupported, + "`fork`+`exec`-based process spawning is not supported on this target", + ); + + #[cfg(any(target_os = "tvos", target_os = "watchos"))] + unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> { + return Err(Self::ERR_APPLE_TV_WATCH_NO_FORK_EXEC); + } + // Attempts to fork the process. If successful, returns Ok((0, -1)) // in the child, and Ok((child_pid, -1)) in the parent. - #[cfg(not(any(target_os = "linux", all(target_os = "nto", target_env = "nto71"))))] + #[cfg(not(any( + target_os = "linux", + target_os = "watchos", + target_os = "tvos", + all(target_os = "nto", target_env = "nto71"), + )))] unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> { cvt(libc::fork()).map(|res| (res, -1)) } @@ -339,6 +368,7 @@ impl Command { // allocation). Instead we just close it manually. This will never // have the drop glue anyway because this code never returns (the // child will either exec() or invoke libc::exit) + #[cfg(not(any(target_os = "tvos", target_os = "watchos")))] unsafe fn do_exec( &mut self, stdio: ChildPipes, @@ -445,8 +475,19 @@ impl Command { Err(io::Error::last_os_error()) } + #[cfg(any(target_os = "tvos", target_os = "watchos"))] + unsafe fn do_exec( + &mut self, + _stdio: ChildPipes, + _maybe_envp: Option<&CStringArray>, + ) -> Result { + return Err(Self::ERR_APPLE_TV_WATCH_NO_FORK_EXEC); + } + #[cfg(not(any( target_os = "macos", + target_os = "tvos", + target_os = "watchos", target_os = "freebsd", all(target_os = "linux", target_env = "gnu"), all(target_os = "linux", target_env = "musl"), @@ -464,6 +505,9 @@ impl Command { // directly. #[cfg(any( target_os = "macos", + // FIXME: `target_os = "ios"`? + target_os = "tvos", + target_os = "watchos", target_os = "freebsd", all(target_os = "linux", target_env = "gnu"), all(target_os = "linux", target_env = "musl"), @@ -550,7 +594,7 @@ impl Command { } let addchdir = match self.get_cwd() { Some(cwd) => { - if cfg!(target_os = "macos") { + if cfg!(any(target_os = "macos", target_os = "tvos", target_os = "watchos")) { // There is a bug in macOS where a relative executable // path like "../myprogram" will cause `posix_spawn` to // successfully launch the program, but erroneously return From 37854aab76209788b0f402aa0ff0acb2a8d3acb7 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Sun, 4 Jun 2023 09:46:43 -0700 Subject: [PATCH 381/465] Update tvOS support elsewhere in the stdlib --- library/std/src/fs/tests.rs | 28 +++++++++++++++++++++++--- library/std/src/os/unix/ucred/tests.rs | 8 +++++++- library/std/src/sys/unix/fs.rs | 6 +++--- library/std/src/thread/tests.rs | 1 + 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index e2480bcbbc729..9ff01b9c35d18 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1640,6 +1640,10 @@ fn test_file_times() { use crate::os::ios::fs::FileTimesExt; #[cfg(target_os = "macos")] use crate::os::macos::fs::FileTimesExt; + #[cfg(target_os = "tvos")] + use crate::os::tvos::fs::FileTimesExt; + #[cfg(target_os = "tvos")] + use crate::os::tvos::fs::FileTimesExt; #[cfg(target_os = "watchos")] use crate::os::watchos::fs::FileTimesExt; #[cfg(windows)] @@ -1651,9 +1655,21 @@ fn test_file_times() { let accessed = SystemTime::UNIX_EPOCH + Duration::from_secs(12345); let modified = SystemTime::UNIX_EPOCH + Duration::from_secs(54321); times = times.set_accessed(accessed).set_modified(modified); - #[cfg(any(windows, target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any( + windows, + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "tvos", + ))] let created = SystemTime::UNIX_EPOCH + Duration::from_secs(32123); - #[cfg(any(windows, target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any( + windows, + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "tvos", + ))] { times = times.set_created(created); } @@ -1678,7 +1694,13 @@ fn test_file_times() { let metadata = file.metadata().unwrap(); assert_eq!(metadata.accessed().unwrap(), accessed); assert_eq!(metadata.modified().unwrap(), modified); - #[cfg(any(windows, target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any( + windows, + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "tvos", + ))] { assert_eq!(metadata.created().unwrap(), created); } diff --git a/library/std/src/os/unix/ucred/tests.rs b/library/std/src/os/unix/ucred/tests.rs index 7c3a646ed939e..dd99ecdd819a7 100644 --- a/library/std/src/os/unix/ucred/tests.rs +++ b/library/std/src/os/unix/ucred/tests.rs @@ -27,7 +27,13 @@ fn test_socket_pair() { } #[test] -#[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos", target_os = "watchos"))] +#[cfg(any( + target_os = "linux", + target_os = "ios", + target_os = "macos", + target_os = "watchos", + target_os = "tvos", +))] fn test_socket_pair_pids(arg: Type) -> RetType { // Create two connected sockets and get their peer credentials. let (sock_a, sock_b) = UnixStream::pair().unwrap(); diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index f05ece17c3718..9cf5cfcc8d552 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -362,7 +362,7 @@ pub struct FilePermissions { pub struct FileTimes { accessed: Option, modified: Option, - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos"))] created: Option, } @@ -615,7 +615,7 @@ impl FileTimes { self.modified = Some(t); } - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos"))] pub fn set_created(&mut self, t: SystemTime) { self.created = Some(t); } @@ -1272,7 +1272,7 @@ impl File { io::ErrorKind::Unsupported, "setting file times not supported", )) - } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] { + } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] { let mut buf = [mem::MaybeUninit::::uninit(); 3]; let mut num_times = 0; let mut attrlist: libc::attrlist = unsafe { mem::zeroed() }; diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index b65e2572cc5e4..5d6b9e94ee91b 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -42,6 +42,7 @@ fn test_named_thread() { all(target_os = "linux", target_env = "gnu"), target_os = "macos", target_os = "ios", + target_os = "tvos", target_os = "watchos" ))] #[test] From a7ecc71a48be74882d2b159876911e6b9edb945d Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Sun, 4 Jun 2023 10:08:10 -0700 Subject: [PATCH 382/465] Note the incomplete Command support in the apple-tvos.md document --- .../rustc/src/platform-support/apple-tvos.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc/src/platform-support/apple-tvos.md b/src/doc/rustc/src/platform-support/apple-tvos.md index 2446c5fc10fce..5a22402324c36 100644 --- a/src/doc/rustc/src/platform-support/apple-tvos.md +++ b/src/doc/rustc/src/platform-support/apple-tvos.md @@ -18,9 +18,9 @@ These targets are cross-compiled. You will need appropriate versions of Xcode and the SDKs for tvOS (`AppleTVOS.sdk`) and/or the tvOS Simulator (`AppleTVSimulator.sdk`) to build a toolchain and target these platforms. -The targets support the full standard library including the allocator to the -best of my knowledge, however they are very new, not yet well-tested, and -it is possible that there are various bugs. +The targets support most (see below) of the standard library including the +allocator to the best of my knowledge, however they are very new, not yet +well-tested, and it is possible that there are various bugs. In theory we support back to tvOS version 7.0, although the actual minimum version you can target may be newer than this, for example due to the versions @@ -30,6 +30,19 @@ As with the other Apple targets, `rustc` respects the common environment variables used by Xcode to configure this, in this case `TVOS_DEPLOYMENT_TARGET`. +#### Incompletely supported library functionality + +As mentioned, "most" of the standard library is supported, which means that some portions +are known to be unsupported. The following APIs are currently known to have +missing or incomplete support: + +- `std::process::Command`'s API will return an error if it is configured in a + manner which cannot be performed using `posix_spawn` -- this is because the + more flexible `fork`/`exec`-based approach is prohibited on these platforms in + favor of `posix_spawn{,p}`. A concrete set of cases where this will occur is + difficult to enumerate (and would quickly become stale), but in some cases it + may be worked around by tweaking the manner in which `Command` is invoked. + ## Building the target The targets can be built by enabling them for a `rustc` build in `config.toml`, by adding, for example: From 5ef4d1fb2e39f835307c40d4cde45409e22d5750 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Sun, 4 Jun 2023 10:13:16 -0700 Subject: [PATCH 383/465] Actually save all the files --- library/std/src/sys/unix/process/process_unix.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 98564c11673c5..129e7643661f0 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -172,13 +172,12 @@ impl Command { crate::sys_common::process::wait_with_output(proc, pipes) } - // WatchOS and TVOS can theoretically spawn processes using `posix_spawn*` - // (although it just fails with a runtime error AFAICT, so we don't yet - // support it in `std`), but forbid use of `fork`/`exec*`. It's unclear the - // extent to which these is restricted, but the headers say - // `__WATCHOS_PROHIBITED __TVOS_PROHIBITED`, so we go out of our way to - // avoid containing any calls to them at all, to avoid linking against their - // symbols on those targets. + // WatchOS and TVOS headers mark the `fork`/`exec*` functions with + // `__WATCHOS_PROHIBITED __TVOS_PROHIBITED`, and indicate that the + // `posix_spawn*` functions should be used instead. It isn't entirely clear + // what `PROHIBITED` means here (e.g. if calls to these functions are + // allowed to exist in dead code), but it sounds bad, so we go out of our + // way to avoid that all-together. #[cfg(any(target_os = "tvos", target_os = "watchos"))] const ERR_APPLE_TV_WATCH_NO_FORK_EXEC: Error = io::const_io_error!( ErrorKind::Unsupported, From af0662f18cf4334a267397a71c3fdb3f4297f35f Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Wed, 21 Jun 2023 15:01:12 -0700 Subject: [PATCH 384/465] Note that posix_spawnp probably still does not work the way people may want --- src/doc/rustc/src/platform-support/apple-tvos.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc/src/platform-support/apple-tvos.md b/src/doc/rustc/src/platform-support/apple-tvos.md index 5a22402324c36..d87fd1959b49c 100644 --- a/src/doc/rustc/src/platform-support/apple-tvos.md +++ b/src/doc/rustc/src/platform-support/apple-tvos.md @@ -39,9 +39,11 @@ missing or incomplete support: - `std::process::Command`'s API will return an error if it is configured in a manner which cannot be performed using `posix_spawn` -- this is because the more flexible `fork`/`exec`-based approach is prohibited on these platforms in - favor of `posix_spawn{,p}`. A concrete set of cases where this will occur is - difficult to enumerate (and would quickly become stale), but in some cases it - may be worked around by tweaking the manner in which `Command` is invoked. + favor of `posix_spawn{,p}` (which still probably will get you rejected from + app stores, so is likely sideloading-only). A concrete set of cases where this + will occur is difficult to enumerate (and would quickly become stale), but in + some cases it may be worked around by tweaking the manner in which `Command` + is invoked. ## Building the target From 757c290fba5278989a78c636a41db97204693b3e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 Jun 2023 11:45:47 +1000 Subject: [PATCH 385/465] Move `Message::CodegenItem` to a separate type. `Message` is an enum with multiple variants, for messages sent to the coordinator thread. *Except* for `Message::CodegenItem`, which is entirely disjoint, being for messages sent from the coordinator thread to the main thread. This commit move `Message::CodegenItem` into a separate type, `CguMessage`, which makes the code much clearer. --- compiler/rustc_codegen_ssa/src/back/write.rs | 21 ++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 4ccef98afc3f6..a1f252fe672ce 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -951,10 +951,13 @@ pub enum Message { work_product: WorkProduct, }, CodegenComplete, - CodegenItem, CodegenAborted, } +/// A message sent from the coordinator thread to the main thread telling it to +/// process another codegen unit. +pub struct CguMessage; + type DiagnosticArgName<'source> = Cow<'source, str>; struct Diagnostic { @@ -976,7 +979,7 @@ fn start_executing_work( tcx: TyCtxt<'_>, crate_info: &CrateInfo, shared_emitter: SharedEmitter, - codegen_worker_send: Sender>, + codegen_worker_send: Sender, coordinator_receive: Receiver>, total_cgus: usize, jobserver: Client, @@ -1284,9 +1287,9 @@ fn start_executing_work( let anticipated_running = running + additional_running + 1; if !queue_full_enough(work_items.len(), anticipated_running) { - // The queue is not full enough, codegen more items: - if codegen_worker_send.send(Message::CodegenItem).is_err() { - panic!("Could not send Message::CodegenItem to main thread") + // The queue is not full enough, process more codegen units: + if codegen_worker_send.send(CguMessage).is_err() { + panic!("Could not send CguMessage to main thread") } main_thread_worker_state = MainThreadWorkerState::Codegenning; } else { @@ -1522,7 +1525,6 @@ fn start_executing_work( codegen_done = true; codegen_aborted = true; } - Message::CodegenItem => bug!("the coordinator should not receive codegen requests"), } } @@ -1879,7 +1881,7 @@ pub struct OngoingCodegen { pub metadata: EncodedMetadata, pub metadata_module: Option, pub crate_info: CrateInfo, - pub codegen_worker_receive: Receiver>, + pub codegen_worker_receive: Receiver, pub shared_emitter_main: SharedEmitterMain, pub output_filenames: Arc, pub coordinator: Coordinator, @@ -1953,10 +1955,9 @@ impl OngoingCodegen { pub fn wait_for_signal_to_codegen_item(&self) { match self.codegen_worker_receive.recv() { - Ok(Message::CodegenItem) => { - // Nothing to do + Ok(CguMessage) => { + // Ok to proceed. } - Ok(_) => panic!("unexpected message"), Err(_) => { // One of the LLVM threads must have panicked, fall through so // error handling can be reached. From 88cd8f93247a09fb0c2e43e82e0dfedea23e9642 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 Jun 2023 12:43:29 +1000 Subject: [PATCH 386/465] Simplify `Message`. `Message` is an enum with multiple variants. Four of those variants map directly onto the four variants of `WorkItemResult`. This commit reduces those four `Message` variants to a single variant containing a `WorkItemResult`. This requires increasing `WorkItemResult`'s visibility to `pub(crate)` visibility, but `WorkItem` and `Message` can also have their visibility reduced to `pub(crate)`. This change avoids some boilerplate enum translation code, and makes `Message` easier to understand. --- compiler/rustc_codegen_ssa/src/back/write.rs | 108 ++++++++----------- 1 file changed, 44 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index a1f252fe672ce..7eb6916ec8433 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -685,7 +685,7 @@ fn produce_final_output_artifacts( // These are used in linking steps and will be cleaned up afterward. } -pub enum WorkItem { +pub(crate) enum WorkItem { /// Optimize a newly codegened, totally unoptimized module. Optimize(ModuleCodegen), /// Copy the post-LTO artifacts from the incremental cache to the output @@ -731,7 +731,7 @@ impl WorkItem { } } -enum WorkItemResult { +pub(crate) enum WorkItemResult { Compiled(CompiledModule), NeedsLink(ModuleCodegen), NeedsFatLTO(FatLTOInput), @@ -923,23 +923,10 @@ fn finish_intra_module_work( } } -pub enum Message { +pub(crate) enum Message { Token(io::Result), - NeedsFatLTO { - result: FatLTOInput, - worker_id: usize, - }, - NeedsThinLTO { - name: String, - thin_buffer: B::ThinBuffer, - worker_id: usize, - }, - NeedsLink { - module: ModuleCodegen, - worker_id: usize, - }, - Done { - result: Result>, + WorkItem { + result: Result, Option>, worker_id: usize, }, CodegenDone { @@ -1481,33 +1468,47 @@ fn start_executing_work( codegen_done = true; codegen_aborted = true; } - Message::Done { result: Ok(compiled_module), worker_id } => { + + Message::WorkItem { result, worker_id } => { free_worker(worker_id); - match compiled_module.kind { - ModuleKind::Regular => { - compiled_modules.push(compiled_module); + + match result { + Ok(WorkItemResult::Compiled(compiled_module)) => { + match compiled_module.kind { + ModuleKind::Regular => { + compiled_modules.push(compiled_module); + } + ModuleKind::Allocator => { + assert!(compiled_allocator_module.is_none()); + compiled_allocator_module = Some(compiled_module); + } + ModuleKind::Metadata => bug!("Should be handled separately"), + } + } + Ok(WorkItemResult::NeedsLink(module)) => { + needs_link.push(module); + } + Ok(WorkItemResult::NeedsFatLTO(fat_lto_input)) => { + assert!(!started_lto); + needs_fat_lto.push(fat_lto_input); + } + Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer)) => { + assert!(!started_lto); + needs_thin_lto.push((name, thin_buffer)); } - ModuleKind::Allocator => { - assert!(compiled_allocator_module.is_none()); - compiled_allocator_module = Some(compiled_module); + Err(Some(WorkerFatalError)) => { + // Like `CodegenAborted`, wait for remaining work to finish. + codegen_done = true; + codegen_aborted = true; + } + Err(None) => { + // If the thread failed that means it panicked, so + // we abort immediately. + bug!("worker thread panicked"); } - ModuleKind::Metadata => bug!("Should be handled separately"), } } - Message::NeedsLink { module, worker_id } => { - free_worker(worker_id); - needs_link.push(module); - } - Message::NeedsFatLTO { result, worker_id } => { - assert!(!started_lto); - free_worker(worker_id); - needs_fat_lto.push(result); - } - Message::NeedsThinLTO { name, thin_buffer, worker_id } => { - assert!(!started_lto); - free_worker(worker_id); - needs_thin_lto.push((name, thin_buffer)); - } + Message::AddImportOnlyModule { module_data, work_product } => { assert!(!started_lto); assert!(!codegen_done); @@ -1515,16 +1516,6 @@ fn start_executing_work( lto_import_only_modules.push((module_data, work_product)); main_thread_worker_state = MainThreadWorkerState::Idle; } - // If the thread failed that means it panicked, so we abort immediately. - Message::Done { result: Err(None), worker_id: _ } => { - bug!("worker thread panicked"); - } - Message::Done { result: Err(Some(WorkerFatalError)), worker_id } => { - // Similar to CodegenAborted, wait for remaining work to finish. - free_worker(worker_id); - codegen_done = true; - codegen_aborted = true; - } } } @@ -1643,22 +1634,11 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem fn drop(&mut self) { let worker_id = self.worker_id; let msg = match self.result.take() { - Some(Ok(WorkItemResult::Compiled(m))) => { - Message::Done:: { result: Ok(m), worker_id } - } - Some(Ok(WorkItemResult::NeedsLink(m))) => { - Message::NeedsLink:: { module: m, worker_id } - } - Some(Ok(WorkItemResult::NeedsFatLTO(m))) => { - Message::NeedsFatLTO:: { result: m, worker_id } - } - Some(Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer))) => { - Message::NeedsThinLTO:: { name, thin_buffer, worker_id } - } + Some(Ok(result)) => Message::WorkItem:: { result: Ok(result), worker_id }, Some(Err(FatalError)) => { - Message::Done:: { result: Err(Some(WorkerFatalError)), worker_id } + Message::WorkItem:: { result: Err(Some(WorkerFatalError)), worker_id } } - None => Message::Done:: { result: Err(None), worker_id }, + None => Message::WorkItem:: { result: Err(None), worker_id }, }; drop(self.coordinator_send.send(Box::new(msg))); } From a521ba400dbfb2e9907238a4e7a5650d22bf2068 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 Jun 2023 12:57:38 +1000 Subject: [PATCH 387/465] Add comments to `Message` and `WorkItem`. This is particularly useful for `Message`. --- compiler/rustc_codegen_ssa/src/back/write.rs | 30 ++++++++++++++------ 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 7eb6916ec8433..9f4d767067ec0 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -731,6 +731,7 @@ impl WorkItem { } } +/// A result produced by the backend. pub(crate) enum WorkItemResult { Compiled(CompiledModule), NeedsLink(ModuleCodegen), @@ -923,21 +924,34 @@ fn finish_intra_module_work( } } +/// Messages sent to the coordinator. pub(crate) enum Message { + /// A jobserver token has become available. Sent from the jobserver helper + /// thread. Token(io::Result), - WorkItem { - result: Result, Option>, - worker_id: usize, - }, - CodegenDone { - llvm_work_item: WorkItem, - cost: u64, - }, + + /// The backend has finished processing a work item for a codegen unit. + /// Sent from a backend worker thread. + WorkItem { result: Result, Option>, worker_id: usize }, + + /// The frontend has finished generating something (backend IR or a + /// post-LTO artifact) for a codegen unit, and it should be passed to the + /// backend. Sent from the main thread. + CodegenDone { llvm_work_item: WorkItem, cost: u64 }, + + /// Similar to `CodegenDone`, but for reusing a pre-LTO artifact + /// Sent from the main thread. AddImportOnlyModule { module_data: SerializedModule, work_product: WorkProduct, }, + + /// The frontend has finished generating everything for all codegen units. + /// Sent from the main thread. CodegenComplete, + + /// Some normal-ish compiler error occurred, and codegen should be wound + /// down. Sent from the main thread. CodegenAborted, } From f6cadae163f3d5d29a12ec11c92aca90a8d742e4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Jun 2023 15:16:38 +1000 Subject: [PATCH 388/465] Streamline some comments. --- compiler/rustc_monomorphize/src/partitioning.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 531644f0b8490..cc4ea16cf50c0 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -175,10 +175,9 @@ where debug_dump(tcx, "MERGE", &codegen_units, unique_inlined_stats); } - // In the next step, we use the inlining map to determine which additional - // monomorphizations have to go into each codegen unit. These additional - // monomorphizations can be drop-glue, functions from external crates, and - // local functions the definition of which is marked with `#[inline]`. + // Use the usage map to put additional mono items in each codegen unit: + // drop-glue, functions from external crates, and local functions the + // definition of which is marked with `#[inline]`. { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items"); place_inlined_mono_items(cx, &mut codegen_units); @@ -190,8 +189,8 @@ where debug_dump(tcx, "INLINE", &codegen_units, unique_inlined_stats); } - // Next we try to make as many symbols "internal" as possible, so LLVM has - // more freedom to optimize. + // Make as many symbols "internal" as possible, so LLVM has more freedom to + // optimize. if !tcx.sess.link_dead_code() { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); internalize_symbols(cx, &mut codegen_units, internalization_candidates); From 6f228e3420787f123aff9b06247fefcb91a941ed Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Jun 2023 15:17:01 +1000 Subject: [PATCH 389/465] Inline before merging CGUs. Because CGU merging relies on CGU sizes, but the CGU sizes before inlining aren't accurate. This requires tweaking how the sizes are updated during merging: if CGU A and B both have an inlined function F, then `size(A + B)` will be a little less than `size(A) + size(B)`, because `A + B` will only have one copy of F. Also, the minimum CGU size is increased because it now has to account for inlined functions. This change doesn't have much effect on compile perf, but it makes follow-on changes that involve more sophisticated reasoning about CGU sizes much easier. --- compiler/rustc_middle/src/mir/mono.rs | 4 --- .../rustc_monomorphize/src/partitioning.rs | 26 ++++++++++--------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 1511e25523559..1cbf1a36283f5 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -335,10 +335,6 @@ impl<'tcx> CodegenUnit<'tcx> { .expect("create_size_estimate must be called before getting a size_estimate") } - pub fn modify_size_estimate(&mut self, delta: usize) { - *self.size_estimate.as_mut().unwrap() += delta; - } - pub fn contains_item(&self, item: &MonoItem<'tcx>) -> bool { self.items().contains_key(item) } diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index cc4ea16cf50c0..3be0908fc7f01 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -166,15 +166,6 @@ where placed }; - // Merge until we have at most `max_cgu_count` codegen units. - // `merge_codegen_units` is responsible for updating the CGU size - // estimates. - { - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus"); - merge_codegen_units(cx, &mut codegen_units); - debug_dump(tcx, "MERGE", &codegen_units, unique_inlined_stats); - } - // Use the usage map to put additional mono items in each codegen unit: // drop-glue, functions from external crates, and local functions the // definition of which is marked with `#[inline]`. @@ -189,6 +180,15 @@ where debug_dump(tcx, "INLINE", &codegen_units, unique_inlined_stats); } + // Merge until we have at most `max_cgu_count` codegen units. + // `merge_codegen_units` is responsible for updating the CGU size + // estimates. + { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus"); + merge_codegen_units(cx, &mut codegen_units); + debug_dump(tcx, "MERGE", &codegen_units, unique_inlined_stats); + } + // Make as many symbols "internal" as possible, so LLVM has more freedom to // optimize. if !tcx.sess.link_dead_code() { @@ -313,7 +313,7 @@ fn merge_codegen_units<'tcx>( // worse generated code. So we don't allow CGUs smaller than this (unless // there is just one CGU, of course). Note that CGU sizes of 100,000+ are // common in larger programs, so this isn't all that large. - const NON_INCR_MIN_CGU_SIZE: usize = 1000; + const NON_INCR_MIN_CGU_SIZE: usize = 1800; // Repeatedly merge the two smallest codegen units as long as: // - we have more CGUs than the upper limit, or @@ -337,9 +337,11 @@ fn merge_codegen_units<'tcx>( let mut smallest = codegen_units.pop().unwrap(); let second_smallest = codegen_units.last_mut().unwrap(); - // Move the mono-items from `smallest` to `second_smallest` - second_smallest.modify_size_estimate(smallest.size_estimate()); + // Move the items from `smallest` to `second_smallest`. Some of them + // may be duplicate inlined items, in which case the destination CGU is + // unaffected. Recalculate size estimates afterwards. second_smallest.items_mut().extend(smallest.items_mut().drain()); + second_smallest.create_size_estimate(cx.tcx); // Record that `second_smallest` now contains all the stuff that was // in `smallest` before. From 105ac1c26d5ea9de84f6b4af583e85eb8991e749 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 21 Jun 2023 16:04:48 +1000 Subject: [PATCH 390/465] Merge root and inlined item placement. There's no longer any need for them to be separate, and putting them together reduces the amount of code. --- .../rustc_monomorphize/src/partitioning.rs | 115 +++++++----------- 1 file changed, 44 insertions(+), 71 deletions(-) diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 3be0908fc7f01..4e9a4f91ddf85 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -125,7 +125,7 @@ struct PartitioningCx<'a, 'tcx> { usage_map: &'a UsageMap<'tcx>, } -struct PlacedRootMonoItems<'tcx> { +struct PlacedMonoItems<'tcx> { /// The codegen units, sorted by name to make things deterministic. codegen_units: Vec>, @@ -150,36 +150,20 @@ where let cx = &PartitioningCx { tcx, usage_map }; - // In the first step, we place all regular monomorphizations into their - // respective 'home' codegen unit. Regular monomorphizations are all - // functions and statics defined in the local crate. - let PlacedRootMonoItems { mut codegen_units, internalization_candidates, unique_inlined_stats } = { - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots"); - let mut placed = place_root_mono_items(cx, mono_items); + // Place all mono items into a codegen unit. + let PlacedMonoItems { mut codegen_units, internalization_candidates, unique_inlined_stats } = { + let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_items"); + let mut placed = place_mono_items(cx, mono_items); for cgu in &mut placed.codegen_units { cgu.create_size_estimate(tcx); } - debug_dump(tcx, "ROOTS", &placed.codegen_units, placed.unique_inlined_stats); + debug_dump(tcx, "PLACE", &placed.codegen_units, placed.unique_inlined_stats); placed }; - // Use the usage map to put additional mono items in each codegen unit: - // drop-glue, functions from external crates, and local functions the - // definition of which is marked with `#[inline]`. - { - let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items"); - place_inlined_mono_items(cx, &mut codegen_units); - - for cgu in &mut codegen_units { - cgu.create_size_estimate(tcx); - } - - debug_dump(tcx, "INLINE", &codegen_units, unique_inlined_stats); - } - // Merge until we have at most `max_cgu_count` codegen units. // `merge_codegen_units` is responsible for updating the CGU size // estimates. @@ -211,10 +195,7 @@ where codegen_units } -fn place_root_mono_items<'tcx, I>( - cx: &PartitioningCx<'_, 'tcx>, - mono_items: I, -) -> PlacedRootMonoItems<'tcx> +fn place_mono_items<'tcx, I>(cx: &PartitioningCx<'_, 'tcx>, mono_items: I) -> PlacedMonoItems<'tcx> where I: Iterator>, { @@ -235,6 +216,8 @@ where let mut num_unique_inlined_items = 0; let mut unique_inlined_items_size = 0; for mono_item in mono_items { + // Handle only root items directly here. Inlined items are handled at + // the bottom of the loop based on reachability. match mono_item.instantiation_mode(cx.tcx) { InstantiationMode::GloballyShared { .. } => {} InstantiationMode::LocalCopy => { @@ -247,7 +230,7 @@ where let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item); let is_volatile = is_incremental_build && mono_item.is_generic_fn(); - let codegen_unit_name = match characteristic_def_id { + let cgu_name = match characteristic_def_id { Some(def_id) => compute_codegen_unit_name( cx.tcx, cgu_name_builder, @@ -258,9 +241,7 @@ where None => fallback_cgu_name(cgu_name_builder), }; - let codegen_unit = codegen_units - .entry(codegen_unit_name) - .or_insert_with(|| CodegenUnit::new(codegen_unit_name)); + let cgu = codegen_units.entry(cgu_name).or_insert_with(|| CodegenUnit::new(cgu_name)); let mut can_be_internalized = true; let (linkage, visibility) = mono_item_linkage_and_visibility( @@ -273,23 +254,52 @@ where internalization_candidates.insert(mono_item); } - codegen_unit.items_mut().insert(mono_item, (linkage, visibility)); + cgu.items_mut().insert(mono_item, (linkage, visibility)); + + // Get all inlined items that are reachable from `mono_item` without + // going via another root item. This includes drop-glue, functions from + // external crates, and local functions the definition of which is + // marked with `#[inline]`. + let mut reachable_inlined_items = FxHashSet::default(); + get_reachable_inlined_items(cx.tcx, mono_item, cx.usage_map, &mut reachable_inlined_items); + + // Add those inlined items. It's possible an inlined item is reachable + // from multiple root items within a CGU, which is fine, it just means + // the `insert` will be a no-op. + for inlined_item in reachable_inlined_items { + // This is a CGU-private copy. + cgu.items_mut().insert(inlined_item, (Linkage::Internal, Visibility::Default)); + } } // Always ensure we have at least one CGU; otherwise, if we have a // crate with just types (for example), we could wind up with no CGU. if codegen_units.is_empty() { - let codegen_unit_name = fallback_cgu_name(cgu_name_builder); - codegen_units.insert(codegen_unit_name, CodegenUnit::new(codegen_unit_name)); + let cgu_name = fallback_cgu_name(cgu_name_builder); + codegen_units.insert(cgu_name, CodegenUnit::new(cgu_name)); } let mut codegen_units: Vec<_> = codegen_units.into_values().collect(); codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); - PlacedRootMonoItems { + return PlacedMonoItems { codegen_units, internalization_candidates, unique_inlined_stats: (num_unique_inlined_items, unique_inlined_items_size), + }; + + fn get_reachable_inlined_items<'tcx>( + tcx: TyCtxt<'tcx>, + item: MonoItem<'tcx>, + usage_map: &UsageMap<'tcx>, + visited: &mut FxHashSet>, + ) { + usage_map.for_each_inlined_used_item(tcx, item, |inlined_item| { + let is_new = visited.insert(inlined_item); + if is_new { + get_reachable_inlined_items(tcx, inlined_item, usage_map, visited); + } + }); } } @@ -407,43 +417,6 @@ fn merge_codegen_units<'tcx>( codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); } -fn place_inlined_mono_items<'tcx>( - cx: &PartitioningCx<'_, 'tcx>, - codegen_units: &mut [CodegenUnit<'tcx>], -) { - for cgu in codegen_units.iter_mut() { - // Collect all inlined items that need to be available in this codegen unit. - let mut reachable_inlined_items = FxHashSet::default(); - for root in cgu.items().keys() { - // Get all inlined items that are reachable from it without going - // via another root item. - get_reachable_inlined_items(cx.tcx, *root, cx.usage_map, &mut reachable_inlined_items); - } - - // Add all monomorphizations that are not already there. - for inlined_item in reachable_inlined_items { - assert!(!cgu.items().contains_key(&inlined_item)); - - // This is a CGU-private copy. - cgu.items_mut().insert(inlined_item, (Linkage::Internal, Visibility::Default)); - } - } - - fn get_reachable_inlined_items<'tcx>( - tcx: TyCtxt<'tcx>, - item: MonoItem<'tcx>, - usage_map: &UsageMap<'tcx>, - visited: &mut FxHashSet>, - ) { - usage_map.for_each_inlined_used_item(tcx, item, |inlined_item| { - let is_new = visited.insert(inlined_item); - if is_new { - get_reachable_inlined_items(tcx, inlined_item, usage_map, visited); - } - }); - } -} - fn internalize_symbols<'tcx>( cx: &PartitioningCx<'_, 'tcx>, codegen_units: &mut [CodegenUnit<'tcx>], From 3ef510ca807452cb82cbcf7d2417fc9a5ce35b41 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 21 Jun 2023 18:56:34 -0300 Subject: [PATCH 391/465] Print def_id on EarlyBoundRegion debug --- compiler/rustc_middle/src/ty/sty.rs | 2 +- tests/ui/nll/ty-outlives/impl-trait-captures.stderr | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 3b63b08de5b96..c0627ab5c01e1 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1584,7 +1584,7 @@ pub struct EarlyBoundRegion { impl fmt::Debug for EarlyBoundRegion { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}, {}", self.index, self.name) + write!(f, "{:?}, {}, {}", self.def_id, self.index, self.name) } } diff --git a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr index da4b9595c0ee5..ba885d1b97ebd 100644 --- a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr +++ b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr @@ -1,4 +1,4 @@ -error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [ReEarlyBound(0, 'a), T, ReEarlyBound(0, 'a)])` captures lifetime that does not appear in bounds +error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [ReEarlyBound(DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a), 0, 'a), T, ReEarlyBound(DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a), 0, 'a)])` captures lifetime that does not appear in bounds --> $DIR/impl-trait-captures.rs:11:5 | LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> { @@ -8,7 +8,7 @@ LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> { LL | x | ^ | -help: to declare that `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [ReEarlyBound(0, 'a), T, ReEarlyBound(2, 'a)])` captures `ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))` lifetime bound +help: to declare that `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [ReEarlyBound(DefId(0:9 ~ impl_trait_captures[aeb9]::foo::'a), 0, 'a), T, ReEarlyBound(DefId(0:14 ~ impl_trait_captures[aeb9]::foo::{opaque#0}::'a), 2, 'a)])` captures `ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))` lifetime bound | LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_)) { | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ From 3bbf9f0128517815946a0c20efd7d80142dc050d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 Jun 2023 14:05:55 +1000 Subject: [PATCH 392/465] Introduce `CodegenState`. The codegen main loop has two bools, `codegen_done` and `codegen_aborted`. There are only three valid combinations: `(false, false)`, `(true, false)`, `(true, true)`. This commit replaces them with a single tri-state enum, which makes things clearer. --- compiler/rustc_codegen_ssa/src/back/write.rs | 49 ++++++++++++-------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 9f4d767067ec0..95de9b61515d5 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1239,10 +1239,19 @@ fn start_executing_work( let mut needs_thin_lto = Vec::new(); let mut lto_import_only_modules = Vec::new(); let mut started_lto = false; - let mut codegen_aborted = false; - // This flag tracks whether all items have gone through codegens - let mut codegen_done = false; + /// Possible state transitions: + /// - Ongoing -> Completed + /// - Ongoing -> Aborted + /// - Completed -> Aborted + #[derive(Debug, PartialEq)] + enum CodegenState { + Ongoing, + Completed, + Aborted, + } + use CodegenState::*; + let mut codegen_state = Ongoing; // This is the queue of LLVM work items that still need processing. let mut work_items = Vec::<(WorkItem, u64)>::new(); @@ -1262,10 +1271,10 @@ fn start_executing_work( // wait for all existing work to finish, so many of the conditions here // only apply if codegen hasn't been aborted as they represent pending // work to be done. - while !codegen_done + while codegen_state == Ongoing || running > 0 || main_thread_worker_state == MainThreadWorkerState::LLVMing - || (!codegen_aborted + || (codegen_state == Completed && !(work_items.is_empty() && needs_fat_lto.is_empty() && needs_thin_lto.is_empty() @@ -1275,7 +1284,7 @@ fn start_executing_work( // While there are still CGUs to be codegened, the coordinator has // to decide how to utilize the compiler processes implicit Token: // For codegenning more CGU or for running them through LLVM. - if !codegen_done { + if codegen_state == Ongoing { if main_thread_worker_state == MainThreadWorkerState::Idle { // Compute the number of workers that will be running once we've taken as many // items from the work queue as we can, plus one for the main thread. It's not @@ -1312,10 +1321,7 @@ fn start_executing_work( spawn_work(cgcx, item); } } - } else if codegen_aborted { - // don't queue up any more work if codegen was aborted, we're - // just waiting for our existing children to finish - } else { + } else if codegen_state == Completed { // If we've finished everything related to normal codegen // then it must be the case that we've got some LTO work to do. // Perform the serial work here of figuring out what we're @@ -1382,11 +1388,15 @@ fn start_executing_work( // Already making good use of that token } } + } else { + // Don't queue up any more work if codegen was aborted, we're + // just waiting for our existing children to finish. + assert!(codegen_state == Aborted); } // Spin up what work we can, only doing this while we've got available // parallelism slots and work left to spawn. - while !codegen_aborted && !work_items.is_empty() && running < tokens.len() { + while codegen_state != Aborted && !work_items.is_empty() && running < tokens.len() { let (item, _) = work_items.pop().unwrap(); maybe_start_llvm_timer(prof, cgcx.config(item.module_kind()), &mut llvm_start_time); @@ -1438,8 +1448,7 @@ fn start_executing_work( Err(e) => { let msg = &format!("failed to acquire jobserver token: {}", e); shared_emitter.fatal(msg); - codegen_done = true; - codegen_aborted = true; + codegen_state = Aborted; } } } @@ -1467,7 +1476,9 @@ fn start_executing_work( } Message::CodegenComplete => { - codegen_done = true; + if codegen_state != Aborted { + codegen_state = Completed; + } assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning); main_thread_worker_state = MainThreadWorkerState::Idle; } @@ -1479,8 +1490,7 @@ fn start_executing_work( // then conditions above will ensure no more work is spawned but // we'll keep executing this loop until `running` hits 0. Message::CodegenAborted => { - codegen_done = true; - codegen_aborted = true; + codegen_state = Aborted; } Message::WorkItem { result, worker_id } => { @@ -1512,8 +1522,7 @@ fn start_executing_work( } Err(Some(WorkerFatalError)) => { // Like `CodegenAborted`, wait for remaining work to finish. - codegen_done = true; - codegen_aborted = true; + codegen_state = Aborted; } Err(None) => { // If the thread failed that means it panicked, so @@ -1525,7 +1534,7 @@ fn start_executing_work( Message::AddImportOnlyModule { module_data, work_product } => { assert!(!started_lto); - assert!(!codegen_done); + assert_eq!(codegen_state, Ongoing); assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning); lto_import_only_modules.push((module_data, work_product)); main_thread_worker_state = MainThreadWorkerState::Idle; @@ -1533,7 +1542,7 @@ fn start_executing_work( } } - if codegen_aborted { + if codegen_state == Aborted { return Err(()); } From fae4f452141568193c1a833b16b5589beb19334e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 Jun 2023 15:08:49 +1000 Subject: [PATCH 393/465] Remove unused fields from `CodegenContext`. --- compiler/rustc_codegen_ssa/src/back/write.rs | 12 ------------ compiler/rustc_codegen_ssa/src/base.rs | 12 +++--------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 95de9b61515d5..51ac441a7a425 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -320,7 +320,6 @@ pub type ExportedSymbols = FxHashMap { // Resources needed when running LTO - pub backend: B, pub prof: SelfProfilerRef, pub lto: Lto, pub save_temps: bool, @@ -338,14 +337,10 @@ pub struct CodegenContext { pub msvc_imps_needed: bool, pub is_pe_coff: bool, pub target_can_use_split_dwarf: bool, - pub target_pointer_width: u32, pub target_arch: String, - pub debuginfo: config::DebugInfo, pub split_debuginfo: rustc_target::spec::SplitDebuginfo, pub split_dwarf_kind: rustc_session::config::SplitDwarfKind, - /// Number of cgus excluding the allocator/metadata modules - pub total_cgus: usize, /// Handler to use for diagnostics produced during codegen. pub diag_emitter: SharedEmitter, /// LLVM optimizations for which we want to print remarks. @@ -441,7 +436,6 @@ pub fn start_async_codegen( target_cpu: String, metadata: EncodedMetadata, metadata_module: Option, - total_cgus: usize, ) -> OngoingCodegen { let (coordinator_send, coordinator_receive) = channel(); let sess = tcx.sess; @@ -469,7 +463,6 @@ pub fn start_async_codegen( shared_emitter, codegen_worker_send, coordinator_receive, - total_cgus, sess.jobserver.clone(), Arc::new(regular_config), Arc::new(metadata_config), @@ -982,7 +975,6 @@ fn start_executing_work( shared_emitter: SharedEmitter, codegen_worker_send: Sender, coordinator_receive: Receiver>, - total_cgus: usize, jobserver: Client, regular_config: Arc, metadata_config: Arc, @@ -1050,7 +1042,6 @@ fn start_executing_work( }; let backend_features = tcx.global_backend_features(()); let cgcx = CodegenContext:: { - backend: backend.clone(), crate_types: sess.crate_types().to_vec(), each_linked_rlib_for_lto, lto: sess.lto(), @@ -1071,13 +1062,10 @@ fn start_executing_work( metadata_module_config: metadata_config, allocator_module_config: allocator_config, tm_factory: backend.target_machine_factory(tcx.sess, ol, backend_features), - total_cgus, msvc_imps_needed: msvc_imps_needed(tcx), is_pe_coff: tcx.sess.target.is_like_windows, target_can_use_split_dwarf: tcx.sess.target_can_use_split_dwarf(), - target_pointer_width: tcx.sess.target.pointer_width, target_arch: tcx.sess.target.arch.to_string(), - debuginfo: tcx.sess.opts.debuginfo, split_debuginfo: tcx.sess.split_debuginfo(), split_dwarf_kind: tcx.sess.opts.unstable_opts.split_dwarf_kind, }; diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 6abc56d597562..28f3c23364cf2 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -580,7 +580,7 @@ pub fn codegen_crate( ) -> OngoingCodegen { // Skip crate items and just output metadata in -Z no-codegen mode. if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { - let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, metadata, None, 1); + let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, metadata, None); ongoing_codegen.codegen_finished(tcx); @@ -631,14 +631,8 @@ pub fn codegen_crate( }) }); - let ongoing_codegen = start_async_codegen( - backend.clone(), - tcx, - target_cpu, - metadata, - metadata_module, - codegen_units.len(), - ); + let ongoing_codegen = + start_async_codegen(backend.clone(), tcx, target_cpu, metadata, metadata_module); // Codegen an allocator shim, if necessary. if let Some(kind) = allocator_kind_for_codegen(tcx) { From 5dd7550a0887eb3a4edcad3f29de909b02e2e735 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 22 Jun 2023 09:18:09 +1000 Subject: [PATCH 394/465] Avoid `Lrc>`. Because `Lrc>` is silly. (Clippy warns about `Rc>` and `Arc>`, and it would warn here if (a) we used Clippy with rustc, and (b) Clippy knew about `Lrc`.) --- compiler/rustc_driver_impl/src/lib.rs | 4 ++-- compiler/rustc_interface/src/interface.rs | 6 +++--- compiler/rustc_interface/src/queries.rs | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 0db96d4e735f6..a08d53e28c637 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -329,7 +329,7 @@ fn run_compiler( return; } let should_stop = - print_crate_info(&***compiler.codegen_backend(), compiler.session(), false); + print_crate_info(&**compiler.codegen_backend(), compiler.session(), false); if should_stop == Compilation::Stop { return; @@ -351,7 +351,7 @@ fn run_compiler( interface::run_compiler(config, |compiler| { let sess = compiler.session(); - let should_stop = print_crate_info(&***compiler.codegen_backend(), sess, true) + let should_stop = print_crate_info(&**compiler.codegen_backend(), sess, true) .and_then(|| list_metadata(sess, &*compiler.codegen_backend().metadata_loader())) .and_then(|| try_process_rlink(sess, compiler)); diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 5e3ea71f0e768..54dabb757643a 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -36,7 +36,7 @@ pub type Result = result::Result; /// Created by passing [`Config`] to [`run_compiler`]. pub struct Compiler { pub(crate) sess: Lrc, - codegen_backend: Lrc>, + codegen_backend: Lrc, pub(crate) register_lints: Option>, pub(crate) override_queries: Option, } @@ -45,7 +45,7 @@ impl Compiler { pub fn session(&self) -> &Lrc { &self.sess } - pub fn codegen_backend(&self) -> &Lrc> { + pub fn codegen_backend(&self) -> &Lrc { &self.codegen_backend } pub fn register_lints(&self) -> &Option> { @@ -318,7 +318,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se let compiler = Compiler { sess: Lrc::new(sess), - codegen_backend: Lrc::new(codegen_backend), + codegen_backend: Lrc::from(codegen_backend), register_lints: config.register_lints, override_queries: config.override_queries, }; diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index d1ba748d7af4b..8c4cdc6696a46 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -115,7 +115,7 @@ impl<'tcx> Queries<'tcx> { fn session(&self) -> &Lrc { &self.compiler.sess } - fn codegen_backend(&self) -> &Lrc> { + fn codegen_backend(&self) -> &Lrc { self.compiler.codegen_backend() } @@ -259,7 +259,7 @@ impl<'tcx> Queries<'tcx> { // Hook for UI tests. Self::check_for_rustc_errors_attr(tcx); - Ok(passes::start_codegen(&***self.codegen_backend(), tcx)) + Ok(passes::start_codegen(&**self.codegen_backend(), tcx)) }) } @@ -324,7 +324,7 @@ impl<'tcx> Queries<'tcx> { pub struct Linker { // compilation inputs sess: Lrc, - codegen_backend: Lrc>, + codegen_backend: Lrc, // compilation outputs dep_graph: DepGraph, From abde9ba527704449ae84848673b52a8ab0f5cbd1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 21 Jun 2023 16:38:47 +1000 Subject: [PATCH 395/465] Tweak CGU size estimate code. - Rename `create_size_estimate` as `compute_size_estimate`, because that makes more sense for the second and subsequent calls for each CGU. - Change `CodegenUnit::size_estimate` from `Option` to `usize`. We can still assert that `compute_size_estimate` is called first. - Move the size estimation for `place_mono_items` inside the function, for consistency with `merge_codegen_units`. --- compiler/rustc_middle/src/mir/mono.rs | 16 +++++++++------- compiler/rustc_monomorphize/src/partitioning.rs | 15 ++++++++------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 1cbf1a36283f5..ca735d5231465 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -231,7 +231,7 @@ pub struct CodegenUnit<'tcx> { /// as well as the crate name and disambiguator. name: Symbol, items: FxHashMap, (Linkage, Visibility)>, - size_estimate: Option, + size_estimate: usize, primary: bool, /// True if this is CGU is used to hold code coverage information for dead code, /// false otherwise. @@ -269,7 +269,7 @@ impl<'tcx> CodegenUnit<'tcx> { CodegenUnit { name, items: Default::default(), - size_estimate: None, + size_estimate: 0, primary: false, is_code_coverage_dead_code_cgu: false, } @@ -320,19 +320,21 @@ impl<'tcx> CodegenUnit<'tcx> { base_n::encode(hash, base_n::CASE_INSENSITIVE) } - pub fn create_size_estimate(&mut self, tcx: TyCtxt<'tcx>) { + pub fn compute_size_estimate(&mut self, tcx: TyCtxt<'tcx>) { // Estimate the size of a codegen unit as (approximately) the number of MIR // statements it corresponds to. - self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum()); + self.size_estimate = self.items.keys().map(|mi| mi.size_estimate(tcx)).sum(); } #[inline] - /// Should only be called if [`create_size_estimate`] has previously been called. + /// Should only be called if [`compute_size_estimate`] has previously been called. /// - /// [`create_size_estimate`]: Self::create_size_estimate + /// [`compute_size_estimate`]: Self::compute_size_estimate pub fn size_estimate(&self) -> usize { + // Items are never zero-sized, so if we have items the estimate must be + // non-zero, unless we forgot to call `compute_size_estimate` first. + assert!(self.items.is_empty() || self.size_estimate != 0); self.size_estimate - .expect("create_size_estimate must be called before getting a size_estimate") } pub fn contains_item(&self, item: &MonoItem<'tcx>) -> bool { diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 4e9a4f91ddf85..97e3748b8b826 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -150,14 +150,11 @@ where let cx = &PartitioningCx { tcx, usage_map }; - // Place all mono items into a codegen unit. + // Place all mono items into a codegen unit. `place_mono_items` is + // responsible for initializing the CGU size estimates. let PlacedMonoItems { mut codegen_units, internalization_candidates, unique_inlined_stats } = { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_items"); - let mut placed = place_mono_items(cx, mono_items); - - for cgu in &mut placed.codegen_units { - cgu.create_size_estimate(tcx); - } + let placed = place_mono_items(cx, mono_items); debug_dump(tcx, "PLACE", &placed.codegen_units, placed.unique_inlined_stats); @@ -282,6 +279,10 @@ where let mut codegen_units: Vec<_> = codegen_units.into_values().collect(); codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); + for cgu in codegen_units.iter_mut() { + cgu.compute_size_estimate(cx.tcx); + } + return PlacedMonoItems { codegen_units, internalization_candidates, @@ -351,7 +352,7 @@ fn merge_codegen_units<'tcx>( // may be duplicate inlined items, in which case the destination CGU is // unaffected. Recalculate size estimates afterwards. second_smallest.items_mut().extend(smallest.items_mut().drain()); - second_smallest.create_size_estimate(cx.tcx); + second_smallest.compute_size_estimate(cx.tcx); // Record that `second_smallest` now contains all the stuff that was // in `smallest` before. From aacd7028954608a2bb17fcbc8ea4c143aad206eb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 22 Jun 2023 14:11:10 +0000 Subject: [PATCH 396/465] Stop hiding const eval limit in external macros --- compiler/rustc_lint_defs/src/builtin.rs | 3 ++- tests/ui/consts/timeout.rs | 25 +++++++++++++++++++++++++ tests/ui/consts/timeout.stderr | 15 +++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 tests/ui/consts/timeout.rs create mode 100644 tests/ui/consts/timeout.stderr diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 53ece08ac3d92..cbb4458d1d49a 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3464,7 +3464,8 @@ declare_lint! { /// out an update in your own time. pub LONG_RUNNING_CONST_EVAL, Deny, - "detects long const eval operations" + "detects long const eval operations", + report_in_external_macro } declare_lint! { diff --git a/tests/ui/consts/timeout.rs b/tests/ui/consts/timeout.rs new file mode 100644 index 0000000000000..c9094999ee276 --- /dev/null +++ b/tests/ui/consts/timeout.rs @@ -0,0 +1,25 @@ +//! This test checks that external macros don't hide +//! the const eval timeout lint and then subsequently +//! ICE. + +// compile-flags: --crate-type=lib -Ztiny-const-eval-limit +// error-pattern: constant evaluation is taking a long time + +static ROOK_ATTACKS_TABLE: () = { + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); + 0_u64.count_ones(); +}; diff --git a/tests/ui/consts/timeout.stderr b/tests/ui/consts/timeout.stderr new file mode 100644 index 0000000000000..799b5ec8dd9f1 --- /dev/null +++ b/tests/ui/consts/timeout.stderr @@ -0,0 +1,15 @@ +error: constant evaluation is taking a long time + --> $SRC_DIR/core/src/num/mod.rs:LL:COL + | + = note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval. + If your compilation actually takes a long time, you can safely allow the lint. +help: the constant being evaluated + --> $DIR/timeout.rs:8:1 + | +LL | static ROOK_ATTACKS_TABLE: () = { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(long_running_const_eval)]` on by default + = note: this error originates in the macro `uint_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + From c8979e587b1851560f030065a21f28456899825a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 15 Jun 2023 07:40:17 +0000 Subject: [PATCH 397/465] Move `opaque_type_origin_unchecked` onto `TyCtxt` and re-use it where it was open coded --- compiler/rustc_hir_analysis/src/check/check.rs | 4 ++-- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 4 ++-- compiler/rustc_infer/src/infer/opaque_types.rs | 9 +-------- compiler/rustc_metadata/src/rmeta/encoder.rs | 4 ++-- compiler/rustc_middle/src/ty/context.rs | 6 ++++++ compiler/rustc_ty_utils/src/assoc.rs | 2 +- 6 files changed, 14 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 22aa3c7ff08b4..a7e81f41c6996 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -563,8 +563,8 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { check_union(tcx, id.owner_id.def_id); } DefKind::OpaqueTy => { - let opaque = tcx.hir().expect_item(id.owner_id.def_id).expect_opaque_ty(); - if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = opaque.origin + let origin = tcx.opaque_type_origin(id.owner_id.def_id); + if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin && let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id) && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() { diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 51e9b4c4501d8..f654a67831334 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1543,8 +1543,8 @@ impl<'tcx> TypeVisitor> for ImplTraitInTraitFinder<'_, 'tcx> { if let ty::Alias(ty::Opaque, unshifted_opaque_ty) = *ty.kind() && self.seen.insert(unshifted_opaque_ty.def_id) && let Some(opaque_def_id) = unshifted_opaque_ty.def_id.as_local() - && let opaque = tcx.hir().expect_item(opaque_def_id).expect_opaque_ty() - && let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = opaque.origin + && let origin = tcx.opaque_type_origin(opaque_def_id) + && let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = origin && source == self.fn_def_id { let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, _depth| { diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 3cb1788dc194a..c5659ffd5c763 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -378,7 +378,7 @@ impl<'tcx> InferCtxt<'tcx> { DefiningAnchor::Bind(bind) => bind, }; - let origin = self.opaque_type_origin_unchecked(def_id); + let origin = self.tcx.opaque_type_origin(def_id); let in_definition_scope = match origin { // Async `impl Trait` hir::OpaqueTyOrigin::AsyncFn(parent) => parent == parent_def_id, @@ -395,13 +395,6 @@ impl<'tcx> InferCtxt<'tcx> { }; in_definition_scope.then_some(origin) } - - /// Returns the origin of the opaque type `def_id` even if we are not in its - /// defining scope. - #[instrument(skip(self), level = "trace", ret)] - fn opaque_type_origin_unchecked(&self, def_id: LocalDefId) -> OpaqueTyOrigin { - self.tcx.hir().expect_item(def_id).expect_opaque_ty().origin - } } /// Visitor that requires that (almost) all regions in the type visited outlive diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 12f3a0fc2c215..eee29d2090a82 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1138,8 +1138,8 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> | DefKind::InlineConst => true, DefKind::OpaqueTy => { - let opaque = tcx.hir().expect_item(def_id).expect_opaque_ty(); - if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = opaque.origin + let origin = tcx.opaque_type_origin(def_id); + if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin && let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id) && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 2b4f69167bfb0..a123869be64a8 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1189,6 +1189,12 @@ impl<'tcx> TyCtxt<'tcx> { pub fn local_visibility(self, def_id: LocalDefId) -> Visibility { self.visibility(def_id).expect_local() } + + /// Returns the origin of the opaque type `def_id`. + #[instrument(skip(self), level = "trace", ret)] + pub fn opaque_type_origin(self, def_id: LocalDefId) -> hir::OpaqueTyOrigin { + self.hir().expect_item(def_id).expect_opaque_ty().origin + } } /// A trait implemented for all `X<'a>` types that can be safely and diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 658ab03c0f48c..5b731641e9d53 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -259,7 +259,7 @@ fn associated_type_for_impl_trait_in_trait( opaque_ty_def_id: LocalDefId, ) -> LocalDefId { let (hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id)) = - tcx.hir().expect_item(opaque_ty_def_id).expect_opaque_ty().origin + tcx.opaque_type_origin(opaque_ty_def_id) else { bug!("expected opaque for {opaque_ty_def_id:?}"); }; From bae645451e5bc3e5cec77a92b4888915356c28ba Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 15 Jun 2023 14:10:42 +0000 Subject: [PATCH 398/465] Only create the opaque collector once and visit it many times --- compiler/rustc_ty_utils/src/opaque_types.rs | 30 +++++++-------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 34c7b9f445182..7af5f847e8b6b 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -22,14 +22,8 @@ struct OpaqueTypeCollector<'tcx> { } impl<'tcx> OpaqueTypeCollector<'tcx> { - fn collect( - tcx: TyCtxt<'tcx>, - item: LocalDefId, - val: ty::Binder<'tcx, impl TypeVisitable>>, - ) -> Vec { - let mut collector = Self { tcx, opaques: Vec::new(), item, seen: Default::default() }; - val.skip_binder().visit_with(&mut collector); - collector.opaques + fn new(tcx: TyCtxt<'tcx>, item: LocalDefId) -> Self { + Self { tcx, opaques: Vec::new(), item, seen: Default::default() } } fn span(&self) -> Span { @@ -166,21 +160,17 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [ match kind { // We're also doing this for `AssocTy` for the wf checks in `check_opaque_meets_bounds` DefKind::Fn | DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { - let defined_opaques = match kind { - DefKind::Fn => { - OpaqueTypeCollector::collect(tcx, item, tcx.fn_sig(item).subst_identity()) + let mut collector = OpaqueTypeCollector::new(tcx, item); + match kind { + DefKind::AssocFn | DefKind::Fn => { + tcx.fn_sig(item).subst_identity().visit_with(&mut collector); } - DefKind::AssocFn => { - OpaqueTypeCollector::collect(tcx, item, tcx.fn_sig(item).subst_identity()) + DefKind::AssocTy | DefKind::AssocConst => { + tcx.type_of(item).subst_identity().visit_with(&mut collector); } - DefKind::AssocTy | DefKind::AssocConst => OpaqueTypeCollector::collect( - tcx, - item, - ty::Binder::dummy(tcx.type_of(item).subst_identity()), - ), _ => unreachable!(), - }; - tcx.arena.alloc_from_iter(defined_opaques) + } + tcx.arena.alloc_from_iter(collector.opaques) } DefKind::Mod | DefKind::Struct From 12243ec41586bd5b68c032ef456a369fb0350469 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 15 Jun 2023 14:34:32 +0000 Subject: [PATCH 399/465] Point to argument/return type instead of the whole function header --- .../infer/error_reporting/note_and_explain.rs | 3 +- compiler/rustc_ty_utils/src/opaque_types.rs | 36 +++++++++++++++---- .../issue-88595.stderr | 8 ++--- .../in-assoc-type-unconstrained.stderr | 4 +-- tests/ui/impl-trait/in-assoc-type.stderr | 4 +-- ...s-impl-trait-declaration-too-subtle.stderr | 8 ++--- .../higher_kinded_params3.rs | 35 ++++++++++++++++++ .../higher_kinded_params3.stderr | 15 ++++++++ .../invalid_impl_trait_in_assoc_ty.stderr | 4 +-- ...t-matching-trait-refs-isnt-defining.stderr | 4 +-- .../unnameable_type.stderr | 4 +-- 11 files changed, 100 insertions(+), 25 deletions(-) create mode 100644 tests/ui/type-alias-impl-trait/higher_kinded_params3.rs create mode 100644 tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index a723dc3f079d7..2a32f0b504737 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -260,7 +260,8 @@ impl Trait for X { (ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::AssocFn | DefKind::AssocConst) => { if tcx.is_type_alias_impl_trait(alias.def_id) { if !tcx.opaque_types_defined_by(body_owner_def_id.expect_local()).contains(&alias.def_id.expect_local()) { - diag.span_note(tcx.def_span(body_owner_def_id), "\ + let sp = tcx.def_ident_span(body_owner_def_id).unwrap_or_else(|| tcx.def_span(body_owner_def_id)); + diag.span_note(sp, "\ this item must have the opaque type in its signature \ in order to be able to register hidden types"); } diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 7af5f847e8b6b..d97b74017ed62 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -19,15 +19,26 @@ struct OpaqueTypeCollector<'tcx> { /// Avoid infinite recursion due to recursive declarations. seen: FxHashSet, + + span: Option, } impl<'tcx> OpaqueTypeCollector<'tcx> { fn new(tcx: TyCtxt<'tcx>, item: LocalDefId) -> Self { - Self { tcx, opaques: Vec::new(), item, seen: Default::default() } + Self { tcx, opaques: Vec::new(), item, seen: Default::default(), span: None } } fn span(&self) -> Span { - self.tcx.def_span(self.item) + self.span.unwrap_or_else(|| { + self.tcx.def_ident_span(self.item).unwrap_or_else(|| self.tcx.def_span(self.item)) + }) + } + + fn visit_spanned(&mut self, span: Span, value: impl TypeVisitable>) { + let old = self.span; + self.span = Some(span); + value.visit_with(self); + self.span = old; } fn parent_trait_ref(&self) -> Option> { @@ -72,13 +83,13 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { self.opaques.push(alias_ty.def_id.expect_local()); // Collect opaque types nested within the associated type bounds of this opaque type. - for (pred, _span) in self + for (pred, span) in self .tcx .explicit_item_bounds(alias_ty.def_id) .subst_iter_copied(self.tcx, alias_ty.substs) { trace!(?pred); - pred.visit_with(self)?; + self.visit_spanned(span, pred); } ControlFlow::Continue(()) @@ -163,10 +174,23 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [ let mut collector = OpaqueTypeCollector::new(tcx, item); match kind { DefKind::AssocFn | DefKind::Fn => { - tcx.fn_sig(item).subst_identity().visit_with(&mut collector); + let ty_sig = tcx.fn_sig(item).subst_identity(); + let hir_sig = tcx.hir().get_by_def_id(item).fn_sig().unwrap(); + collector.visit_spanned(hir_sig.decl.output.span(), ty_sig.output()); + for (hir, ty) in hir_sig.decl.inputs.iter().zip(ty_sig.inputs().iter()) { + collector.visit_spanned(hir.span, ty.map_bound(|x| *x)); + } } DefKind::AssocTy | DefKind::AssocConst => { - tcx.type_of(item).subst_identity().visit_with(&mut collector); + let span = match tcx.hir().get_by_def_id(item) { + rustc_hir::Node::ImplItem(it) => match it.kind { + rustc_hir::ImplItemKind::Const(ty, _) => ty.span, + rustc_hir::ImplItemKind::Type(ty) => ty.span, + other => span_bug!(tcx.def_span(item), "{other:#?}"), + }, + other => span_bug!(tcx.def_span(item), "{other:#?}"), + }; + collector.visit_spanned(span, tcx.type_of(item).subst_identity()); } _ => unreachable!(), } diff --git a/tests/ui/generic-associated-types/issue-88595.stderr b/tests/ui/generic-associated-types/issue-88595.stderr index d6caed8545993..b0f6864f6ec1a 100644 --- a/tests/ui/generic-associated-types/issue-88595.stderr +++ b/tests/ui/generic-associated-types/issue-88595.stderr @@ -1,8 +1,8 @@ error: non-defining opaque type use in defining scope - --> $DIR/issue-88595.rs:21:5 + --> $DIR/issue-88595.rs:21:23 | LL | fn a(&'a self) -> Self::B<'a> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ generic argument `'a` used twice + | ^^^^^^^^^^^ generic argument `'a` used twice | note: for this opaque type --> $DIR/issue-88595.rs:19:18 @@ -24,10 +24,10 @@ LL | fn a(&'a self) -> Self::B<'a> {} = note: expected opaque type `>::B<'a>` found unit type `()` note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/issue-88595.rs:21:5 + --> $DIR/issue-88595.rs:21:8 | LL | fn a(&'a self) -> Self::B<'a> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr b/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr index 1097cd0f452a8..8e61a65abe4be 100644 --- a/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr +++ b/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr @@ -40,10 +40,10 @@ LL | fn method() -> Self::Ty; = note: expected signature `fn() -> <() as compare_method::Trait>::Ty` found signature `fn()` note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/in-assoc-type-unconstrained.rs:22:9 + --> $DIR/in-assoc-type-unconstrained.rs:22:12 | LL | fn method() -> () {} - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^ error: unconstrained opaque type --> $DIR/in-assoc-type-unconstrained.rs:20:19 diff --git a/tests/ui/impl-trait/in-assoc-type.stderr b/tests/ui/impl-trait/in-assoc-type.stderr index f0a272dc2d5d1..ab3f3a14410d0 100644 --- a/tests/ui/impl-trait/in-assoc-type.stderr +++ b/tests/ui/impl-trait/in-assoc-type.stderr @@ -12,10 +12,10 @@ LL | fn foo(&self) -> >::Bar {} = note: expected opaque type `<() as Foo<()>>::Bar` found unit type `()` note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/in-assoc-type.rs:17:5 + --> $DIR/in-assoc-type.rs:17:8 | LL | fn foo(&self) -> >::Bar {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^ error: aborting due to previous error diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr index bbd60d4398b74..3e1981f096c77 100644 --- a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr +++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr @@ -21,10 +21,10 @@ LL | fn eq(&self, _other: &(Foo, i32)) -> bool { = note: expected signature `fn(&a::Bar, &(a::Bar, i32)) -> _` found signature `fn(&a::Bar, &(a::Foo, i32)) -> _` note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:10:9 + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:10:12 | LL | fn eq(&self, _other: &(Foo, i32)) -> bool { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ error: unconstrained opaque type --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:18:16 @@ -49,10 +49,10 @@ LL | fn eq(&self, _other: &(Bar, i32)) -> bool { = note: expected signature `fn(&b::Bar, &(b::Foo, i32)) -> _` found signature `fn(&b::Bar, &(b::Bar, i32)) -> _` note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:24:9 + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:24:12 | LL | fn eq(&self, _other: &(Bar, i32)) -> bool { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ error: aborting due to 4 previous errors diff --git a/tests/ui/type-alias-impl-trait/higher_kinded_params3.rs b/tests/ui/type-alias-impl-trait/higher_kinded_params3.rs new file mode 100644 index 0000000000000..839a611cb71a9 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/higher_kinded_params3.rs @@ -0,0 +1,35 @@ +//! This test checks that we can't actually have an opaque type behind +//! a binder that references variables from that binder. + +// edition: 2021 + +#![feature(type_alias_impl_trait)] + +trait B { + type C; +} + +struct A; + +impl<'a> B for &'a A { + type C = Tait<'a>; +} + +type Tait<'a> = impl std::fmt::Debug + 'a; + +struct Terminator; + +type Successors<'a> = impl std::fmt::Debug + 'a; + +impl Terminator { + fn successors(&self, mut f: for<'x> fn(&'x ()) -> <&'x A as B>::C) -> Successors<'_> { + f = g; + //~^ ERROR: mismatched types + } +} + +fn g(x: &()) -> &() { + x +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr b/tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr new file mode 100644 index 0000000000000..aaba9ad5ca704 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/higher_kinded_params3.rs:26:9 + | +LL | type Tait<'a> = impl std::fmt::Debug + 'a; + | ------------------------- the expected opaque type +... +LL | f = g; + | ^^^^^ one type is more general than the other + | + = note: expected fn pointer `for<'x> fn(&'x ()) -> Tait<'x>` + found fn pointer `for<'a> fn(&'a ()) -> &'a ()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.stderr b/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.stderr index 2beed73cb85c3..6ec5d13f812a7 100644 --- a/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.stderr +++ b/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.stderr @@ -12,10 +12,10 @@ LL | let x: Self::Foo = (); = note: expected opaque type `<() as Foo>::Foo` found unit type `()` note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/invalid_impl_trait_in_assoc_ty.rs:10:5 + --> $DIR/invalid_impl_trait_in_assoc_ty.rs:10:8 | LL | fn bar() { - | ^^^^^^^^ + | ^^^ error: aborting due to previous error diff --git a/tests/ui/type-alias-impl-trait/not-matching-trait-refs-isnt-defining.stderr b/tests/ui/type-alias-impl-trait/not-matching-trait-refs-isnt-defining.stderr index d2d007490915b..a621bb519cdf3 100644 --- a/tests/ui/type-alias-impl-trait/not-matching-trait-refs-isnt-defining.stderr +++ b/tests/ui/type-alias-impl-trait/not-matching-trait-refs-isnt-defining.stderr @@ -12,10 +12,10 @@ LL | let _: >::Assoc = ""; = note: expected opaque type `<() as Foo>::Assoc` found reference `&'static str` note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/not-matching-trait-refs-isnt-defining.rs:16:5 + --> $DIR/not-matching-trait-refs-isnt-defining.rs:16:8 | LL | fn test() -> <() as Foo>::Assoc { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ error: aborting due to previous error diff --git a/tests/ui/type-alias-impl-trait/unnameable_type.stderr b/tests/ui/type-alias-impl-trait/unnameable_type.stderr index 24f5cc8c7339b..c609ace919e5b 100644 --- a/tests/ui/type-alias-impl-trait/unnameable_type.stderr +++ b/tests/ui/type-alias-impl-trait/unnameable_type.stderr @@ -26,10 +26,10 @@ LL | fn dont_define_this(_private: Private) {} = note: expected signature `fn(Private)` found signature `fn(MyPrivate)` note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/unnameable_type.rs:20:5 + --> $DIR/unnameable_type.rs:20:8 | LL | fn dont_define_this(_private: MyPrivate) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors From 326a9fa8e890902abf1f4e8aaa5be9010b366f4c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 22 Jun 2023 15:02:44 +0000 Subject: [PATCH 400/465] Add tests showcasing our short circuiting behaviour in the signature checks for defining scopes --- tests/ui/type-alias-impl-trait/multi-error.rs | 25 ++++++++++ .../type-alias-impl-trait/multi-error.stderr | 49 +++++++++++++++++++ .../non-defining-method.rs | 22 +++++++++ .../non-defining-method.stderr | 33 +++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 tests/ui/type-alias-impl-trait/multi-error.rs create mode 100644 tests/ui/type-alias-impl-trait/multi-error.stderr create mode 100644 tests/ui/type-alias-impl-trait/non-defining-method.rs create mode 100644 tests/ui/type-alias-impl-trait/non-defining-method.stderr diff --git a/tests/ui/type-alias-impl-trait/multi-error.rs b/tests/ui/type-alias-impl-trait/multi-error.rs new file mode 100644 index 0000000000000..d10967abf9abb --- /dev/null +++ b/tests/ui/type-alias-impl-trait/multi-error.rs @@ -0,0 +1,25 @@ +//! This test checks that we don't follow up +//! with type mismatch errors of opaque types +//! with their hidden types if we failed the +//! defining scope check at the signature level. + +#![feature(impl_trait_in_assoc_type)] + +trait Foo { + type Bar; + type Baz; + fn foo() -> (Self::Bar, Self::Baz); +} + +impl Foo for () { + type Bar = impl Sized; + type Baz = impl Sized; + fn foo() -> (Self::Bar, Self::Baz) { + //~^ ERROR non-defining opaque type use + ((), ()) + //~^ ERROR mismatched types + //~| ERROR mismatched types + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/multi-error.stderr b/tests/ui/type-alias-impl-trait/multi-error.stderr new file mode 100644 index 0000000000000..1725937374972 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/multi-error.stderr @@ -0,0 +1,49 @@ +error: non-defining opaque type use in defining scope + --> $DIR/multi-error.rs:17:17 + | +LL | fn foo() -> (Self::Bar, Self::Baz) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument `u32` is not a generic parameter + | +note: for this opaque type + --> $DIR/multi-error.rs:15:19 + | +LL | type Bar = impl Sized; + | ^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/multi-error.rs:19:10 + | +LL | type Bar = impl Sized; + | ---------- the expected opaque type +... +LL | ((), ()) + | ^^ expected opaque type, found `()` + | + = note: expected opaque type `<() as Foo>::Bar` + found unit type `()` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/multi-error.rs:17:8 + | +LL | fn foo() -> (Self::Bar, Self::Baz) { + | ^^^ + +error[E0308]: mismatched types + --> $DIR/multi-error.rs:19:14 + | +LL | type Baz = impl Sized; + | ---------- the expected opaque type +... +LL | ((), ()) + | ^^ expected opaque type, found `()` + | + = note: expected opaque type `<() as Foo>::Baz` + found unit type `()` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/multi-error.rs:17:8 + | +LL | fn foo() -> (Self::Bar, Self::Baz) { + | ^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/non-defining-method.rs b/tests/ui/type-alias-impl-trait/non-defining-method.rs new file mode 100644 index 0000000000000..66ceedee8f7e9 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/non-defining-method.rs @@ -0,0 +1,22 @@ +//! This test checks that we don't follow up +//! with type mismatch errors of opaque types +//! with their hidden types if we failed the +//! defining scope check at the signature level. + +#![feature(impl_trait_in_assoc_type)] + +trait Foo { + type Bar; + fn foo() -> Self::Bar; + fn bar() -> Self::Bar; +} + +impl Foo for () { + type Bar = impl Sized; + fn foo() -> Self::Bar {} + //~^ ERROR non-defining opaque type use + //~| ERROR mismatched types + fn bar() -> Self::Bar {} +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/non-defining-method.stderr b/tests/ui/type-alias-impl-trait/non-defining-method.stderr new file mode 100644 index 0000000000000..f203cff903600 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/non-defining-method.stderr @@ -0,0 +1,33 @@ +error: non-defining opaque type use in defining scope + --> $DIR/non-defining-method.rs:16:17 + | +LL | fn foo() -> Self::Bar {} + | ^^^^^^^^^^^^^^ argument `u32` is not a generic parameter + | +note: for this opaque type + --> $DIR/non-defining-method.rs:15:19 + | +LL | type Bar = impl Sized; + | ^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/non-defining-method.rs:16:17 + | +LL | type Bar = impl Sized; + | ---------- the expected opaque type +LL | fn foo() -> Self::Bar {} + | --- ^^^^^^^^^^^^^^ expected opaque type, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + | + = note: expected opaque type `<() as Foo>::Bar` + found unit type `()` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/non-defining-method.rs:16:8 + | +LL | fn foo() -> Self::Bar {} + | ^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From 41881aece2aac46b21c509dadb0b101da1f7d6bb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 15 Jun 2023 15:40:31 +0000 Subject: [PATCH 401/465] Stop failing eagerly, and collect all opaque types even if some are erroneous. --- compiler/rustc_ty_utils/src/opaque_types.rs | 18 ++++++------------ tests/ui/type-alias-impl-trait/multi-error.rs | 1 - .../type-alias-impl-trait/multi-error.stderr | 19 +------------------ 3 files changed, 7 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index d97b74017ed62..d64569db56656 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -1,5 +1,4 @@ use rustc_data_structures::fx::FxHashSet; -use rustc_errors::ErrorGuaranteed; use rustc_hir::{def::DefKind, def_id::LocalDefId}; use rustc_middle::query::Providers; use rustc_middle::ty::util::{CheckRegions, NotUniqueParam}; @@ -65,10 +64,9 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { } impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { - type BreakTy = ErrorGuaranteed; - #[instrument(skip(self), ret, level = "trace")] - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + t.super_visit_with(self)?; match t.kind() { ty::Alias(ty::Opaque, alias_ty) if alias_ty.def_id.is_local() => { if !self.seen.insert(alias_ty.def_id.expect_local()) { @@ -91,24 +89,20 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { trace!(?pred); self.visit_spanned(span, pred); } - - ControlFlow::Continue(()) } Err(NotUniqueParam::NotParam(arg)) => { - let err = self.tcx.sess.emit_err(NotParam { + self.tcx.sess.emit_err(NotParam { arg, span: self.span(), opaque_span: self.tcx.def_span(alias_ty.def_id), }); - ControlFlow::Break(err) } Err(NotUniqueParam::DuplicateParam(arg)) => { - let err = self.tcx.sess.emit_err(DuplicateArg { + self.tcx.sess.emit_err(DuplicateArg { arg, span: self.span(), opaque_span: self.tcx.def_span(alias_ty.def_id), }); - ControlFlow::Break(err) } } } @@ -157,10 +151,10 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { } } } - t.super_visit_with(self) } - _ => t.super_visit_with(self), + _ => {} } + ControlFlow::Continue(()) } } diff --git a/tests/ui/type-alias-impl-trait/multi-error.rs b/tests/ui/type-alias-impl-trait/multi-error.rs index d10967abf9abb..7cae9a12cb243 100644 --- a/tests/ui/type-alias-impl-trait/multi-error.rs +++ b/tests/ui/type-alias-impl-trait/multi-error.rs @@ -18,7 +18,6 @@ impl Foo for () { //~^ ERROR non-defining opaque type use ((), ()) //~^ ERROR mismatched types - //~| ERROR mismatched types } } diff --git a/tests/ui/type-alias-impl-trait/multi-error.stderr b/tests/ui/type-alias-impl-trait/multi-error.stderr index 1725937374972..1b7b96075be08 100644 --- a/tests/ui/type-alias-impl-trait/multi-error.stderr +++ b/tests/ui/type-alias-impl-trait/multi-error.stderr @@ -27,23 +27,6 @@ note: this item must have the opaque type in its signature in order to be able t LL | fn foo() -> (Self::Bar, Self::Baz) { | ^^^ -error[E0308]: mismatched types - --> $DIR/multi-error.rs:19:14 - | -LL | type Baz = impl Sized; - | ---------- the expected opaque type -... -LL | ((), ()) - | ^^ expected opaque type, found `()` - | - = note: expected opaque type `<() as Foo>::Baz` - found unit type `()` -note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/multi-error.rs:17:8 - | -LL | fn foo() -> (Self::Bar, Self::Baz) { - | ^^^ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. From a71628c1147ce8b739799e33da352b3fa11559bb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 22 Jun 2023 15:11:07 +0000 Subject: [PATCH 402/465] Treat opaque types failing the signature defining scope check as defining, as we already errored and can hide subsequent errors this way. --- compiler/rustc_ty_utils/src/opaque_types.rs | 5 +++-- .../generic-associated-types/issue-88595.rs | 1 - .../issue-88595.stderr | 22 +------------------ tests/ui/type-alias-impl-trait/multi-error.rs | 1 - .../type-alias-impl-trait/multi-error.stderr | 20 +---------------- .../non-defining-method.rs | 1 - .../non-defining-method.stderr | 21 +----------------- 7 files changed, 6 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index d64569db56656..ab97406452e58 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -72,14 +72,15 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { if !self.seen.insert(alias_ty.def_id.expect_local()) { return ControlFlow::Continue(()); } + + self.opaques.push(alias_ty.def_id.expect_local()); + match self.tcx.uses_unique_generic_params(alias_ty.substs, CheckRegions::Bound) { Ok(()) => { // FIXME: implement higher kinded lifetime bounds on nested opaque types. They are not // supported at all, so this is sound to do, but once we want to support them, you'll // start seeing the error below. - self.opaques.push(alias_ty.def_id.expect_local()); - // Collect opaque types nested within the associated type bounds of this opaque type. for (pred, span) in self .tcx diff --git a/tests/ui/generic-associated-types/issue-88595.rs b/tests/ui/generic-associated-types/issue-88595.rs index 7de906e7ef3f3..5a40a61297233 100644 --- a/tests/ui/generic-associated-types/issue-88595.rs +++ b/tests/ui/generic-associated-types/issue-88595.rs @@ -19,5 +19,4 @@ impl<'a> A<'a> for C { type B<'b> = impl Clone; fn a(&'a self) -> Self::B<'a> {} //~ ERROR: non-defining opaque type use in defining scope - //~^ ERROR: mismatched types } diff --git a/tests/ui/generic-associated-types/issue-88595.stderr b/tests/ui/generic-associated-types/issue-88595.stderr index b0f6864f6ec1a..2b1a25acfa430 100644 --- a/tests/ui/generic-associated-types/issue-88595.stderr +++ b/tests/ui/generic-associated-types/issue-88595.stderr @@ -10,25 +10,5 @@ note: for this opaque type LL | type B<'b> = impl Clone; | ^^^^^^^^^^ -error[E0308]: mismatched types - --> $DIR/issue-88595.rs:21:23 - | -LL | type B<'b> = impl Clone; - | ---------- the expected opaque type -LL | -LL | fn a(&'a self) -> Self::B<'a> {} - | - ^^^^^^^^^^^ expected opaque type, found `()` - | | - | implicitly returns `()` as its body has no tail or `return` expression - | - = note: expected opaque type `>::B<'a>` - found unit type `()` -note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/issue-88595.rs:21:8 - | -LL | fn a(&'a self) -> Self::B<'a> {} - | ^ - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/multi-error.rs b/tests/ui/type-alias-impl-trait/multi-error.rs index 7cae9a12cb243..b5ff06572d06e 100644 --- a/tests/ui/type-alias-impl-trait/multi-error.rs +++ b/tests/ui/type-alias-impl-trait/multi-error.rs @@ -17,7 +17,6 @@ impl Foo for () { fn foo() -> (Self::Bar, Self::Baz) { //~^ ERROR non-defining opaque type use ((), ()) - //~^ ERROR mismatched types } } diff --git a/tests/ui/type-alias-impl-trait/multi-error.stderr b/tests/ui/type-alias-impl-trait/multi-error.stderr index 1b7b96075be08..6d8fa0fb021a8 100644 --- a/tests/ui/type-alias-impl-trait/multi-error.stderr +++ b/tests/ui/type-alias-impl-trait/multi-error.stderr @@ -10,23 +10,5 @@ note: for this opaque type LL | type Bar = impl Sized; | ^^^^^^^^^^ -error[E0308]: mismatched types - --> $DIR/multi-error.rs:19:10 - | -LL | type Bar = impl Sized; - | ---------- the expected opaque type -... -LL | ((), ()) - | ^^ expected opaque type, found `()` - | - = note: expected opaque type `<() as Foo>::Bar` - found unit type `()` -note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/multi-error.rs:17:8 - | -LL | fn foo() -> (Self::Bar, Self::Baz) { - | ^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/non-defining-method.rs b/tests/ui/type-alias-impl-trait/non-defining-method.rs index 66ceedee8f7e9..2f4a7052f7221 100644 --- a/tests/ui/type-alias-impl-trait/non-defining-method.rs +++ b/tests/ui/type-alias-impl-trait/non-defining-method.rs @@ -15,7 +15,6 @@ impl Foo for () { type Bar = impl Sized; fn foo() -> Self::Bar {} //~^ ERROR non-defining opaque type use - //~| ERROR mismatched types fn bar() -> Self::Bar {} } diff --git a/tests/ui/type-alias-impl-trait/non-defining-method.stderr b/tests/ui/type-alias-impl-trait/non-defining-method.stderr index f203cff903600..61bf2da20dbdb 100644 --- a/tests/ui/type-alias-impl-trait/non-defining-method.stderr +++ b/tests/ui/type-alias-impl-trait/non-defining-method.stderr @@ -10,24 +10,5 @@ note: for this opaque type LL | type Bar = impl Sized; | ^^^^^^^^^^ -error[E0308]: mismatched types - --> $DIR/non-defining-method.rs:16:17 - | -LL | type Bar = impl Sized; - | ---------- the expected opaque type -LL | fn foo() -> Self::Bar {} - | --- ^^^^^^^^^^^^^^ expected opaque type, found `()` - | | - | implicitly returns `()` as its body has no tail or `return` expression - | - = note: expected opaque type `<() as Foo>::Bar` - found unit type `()` -note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/non-defining-method.rs:16:8 - | -LL | fn foo() -> Self::Bar {} - | ^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. From d6e1b206238d032a0d13fe66e316664a7c03ded3 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 15 Jun 2023 15:43:24 +0000 Subject: [PATCH 403/465] Fix a codegen test --- ...er-cfi-emit-type-metadata-id-itanium-cxx-abi.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs b/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs index 472d921ace046..63e63c5d4aa92 100644 --- a/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs +++ b/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs @@ -61,7 +61,19 @@ pub type Type9 = impl Send; pub type Type10 = impl Send; pub type Type11 = impl Send; -pub fn fn1<'a>() { +pub fn fn1<'a>() where + Type1: 'static, + Type2: 'static, + Type3: 'static, + Type4: 'static, + Type5: 'static, + Type6: 'static, + Type7: 'static, + Type8: 'static, + Type9: 'static, + Type10: 'static, + Type11: 'static, +{ // Closure let closure1 = || { }; let _: Type1 = closure1; From 9202caaec536bf299f055f4915369aafda5e742e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 22 Jun 2023 17:38:19 +0200 Subject: [PATCH 404/465] Fix indentation for where clause in rustdoc pages --- src/librustdoc/html/format.rs | 17 ++++++++++++----- src/librustdoc/html/render/mod.rs | 4 ++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index f26d74629dd94..b710311c85872 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -347,13 +347,19 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( } } else { let mut br_with_padding = String::with_capacity(6 * indent + 28); - br_with_padding.push_str("\n"); + br_with_padding.push('\n'); - let padding_amount = - if ending == Ending::Newline { indent + 4 } else { indent + "fn where ".len() }; + let where_indent = 3; + let padding_amount = if ending == Ending::Newline { + indent + 4 + } else if indent == 0 { + 4 + } else { + indent + where_indent + "where ".len() + }; for _ in 0..padding_amount { - br_with_padding.push_str(" "); + br_with_padding.push(' '); } let where_preds = where_preds.to_string().replace('\n', &br_with_padding); @@ -370,7 +376,8 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( let where_preds = where_preds.replacen(&br_with_padding, " ", 1); let mut clause = br_with_padding; - clause.truncate(clause.len() - "where ".len()); + // +1 is for `\n`. + clause.truncate(indent + 1 + where_indent); write!(clause, "where{where_preds}")?; clause diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index c5d6771c2fdd3..0199364151d45 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -859,8 +859,8 @@ fn assoc_method( w.reserve(header_len + "{".len() + "".len()); write!( w, - "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn {name}\ - {generics}{decl}{notable_traits}{where_clause}", + "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn \ + {name}{generics}{decl}{notable_traits}{where_clause}", indent = indent_str, vis = vis, constness = constness, From b858a4745caacc1bab3e2d50f38add451030941f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 22 Jun 2023 17:39:23 +0200 Subject: [PATCH 405/465] Update existing snapshot and add more snapshots of where clause indentation --- tests/rustdoc/where.SWhere_Echo_impl.html | 2 ++ tests/rustdoc/where.SWhere_Simd_item-decl.html | 2 +- tests/rustdoc/where.alpha_trait_decl.html | 3 +++ tests/rustdoc/where.bravo_trait_decl.html | 5 +++++ tests/rustdoc/where.charlie_fn_decl.html | 2 ++ tests/rustdoc/where.golf_type_alias_decl.html | 2 ++ tests/rustdoc/where.rs | 5 +++++ 7 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 tests/rustdoc/where.SWhere_Echo_impl.html create mode 100644 tests/rustdoc/where.alpha_trait_decl.html create mode 100644 tests/rustdoc/where.bravo_trait_decl.html create mode 100644 tests/rustdoc/where.charlie_fn_decl.html create mode 100644 tests/rustdoc/where.golf_type_alias_decl.html diff --git a/tests/rustdoc/where.SWhere_Echo_impl.html b/tests/rustdoc/where.SWhere_Echo_impl.html new file mode 100644 index 0000000000000..7517eb090f496 --- /dev/null +++ b/tests/rustdoc/where.SWhere_Echo_impl.html @@ -0,0 +1,2 @@ +

impl<D> Delta<D>where + D: MyTrait,

\ No newline at end of file diff --git a/tests/rustdoc/where.SWhere_Simd_item-decl.html b/tests/rustdoc/where.SWhere_Simd_item-decl.html index ef4294c8f76d3..3e72ba2b74fe2 100644 --- a/tests/rustdoc/where.SWhere_Simd_item-decl.html +++ b/tests/rustdoc/where.SWhere_Simd_item-decl.html @@ -1,3 +1,3 @@
pub struct Simd<T>(_)
 where
-         T: MyTrait;
\ No newline at end of file + T: MyTrait
; diff --git a/tests/rustdoc/where.alpha_trait_decl.html b/tests/rustdoc/where.alpha_trait_decl.html new file mode 100644 index 0000000000000..a7700055c9a74 --- /dev/null +++ b/tests/rustdoc/where.alpha_trait_decl.html @@ -0,0 +1,3 @@ +pub struct Alpha<A>(_) +where + A: MyTrait; \ No newline at end of file diff --git a/tests/rustdoc/where.bravo_trait_decl.html b/tests/rustdoc/where.bravo_trait_decl.html new file mode 100644 index 0000000000000..00524201a8aca --- /dev/null +++ b/tests/rustdoc/where.bravo_trait_decl.html @@ -0,0 +1,5 @@ +pub trait Bravo<B>where + B: MyTrait,{ + // Required method + fn get(&self, B: B); +} \ No newline at end of file diff --git a/tests/rustdoc/where.charlie_fn_decl.html b/tests/rustdoc/where.charlie_fn_decl.html new file mode 100644 index 0000000000000..8e3bc8b01ecbd --- /dev/null +++ b/tests/rustdoc/where.charlie_fn_decl.html @@ -0,0 +1,2 @@ +pub fn charlie<C>()where + C: MyTrait, \ No newline at end of file diff --git a/tests/rustdoc/where.golf_type_alias_decl.html b/tests/rustdoc/where.golf_type_alias_decl.html new file mode 100644 index 0000000000000..8da5402f90073 --- /dev/null +++ b/tests/rustdoc/where.golf_type_alias_decl.html @@ -0,0 +1,2 @@ +pub type Golf<T>where + T: Clone, = (T, T); \ No newline at end of file diff --git a/tests/rustdoc/where.rs b/tests/rustdoc/where.rs index 8b8a126e89dd5..2aa9c8b546193 100644 --- a/tests/rustdoc/where.rs +++ b/tests/rustdoc/where.rs @@ -5,16 +5,20 @@ use std::io::Lines; pub trait MyTrait { fn dummy(&self) { } } // @has foo/struct.Alpha.html '//pre' "pub struct Alpha(_) where A: MyTrait" +// @snapshot alpha_trait_decl - '//*[@class="rust item-decl"]/code' pub struct Alpha(A) where A: MyTrait; // @has foo/trait.Bravo.html '//pre' "pub trait Bravowhere B: MyTrait" +// @snapshot bravo_trait_decl - '//*[@class="rust item-decl"]/code' pub trait Bravo where B: MyTrait { fn get(&self, B: B); } // @has foo/fn.charlie.html '//pre' "pub fn charlie()where C: MyTrait" +// @snapshot charlie_fn_decl - '//*[@class="rust item-decl"]/code' pub fn charlie() where C: MyTrait {} pub struct Delta(D); // @has foo/struct.Delta.html '//*[@class="impl"]//h3[@class="code-header"]' \ // "impl Deltawhere D: MyTrait" +// @snapshot SWhere_Echo_impl - '//*[@id="impl-Delta%3CD%3E"]/h3[@class="code-header"]' impl Delta where D: MyTrait { pub fn delta() {} } @@ -65,4 +69,5 @@ impl MyTrait for Foxtrotwhere F: MyTrait {} // @has foo/type.Golf.html '//pre[@class="rust item-decl"]' \ // "type Golfwhere T: Clone, = (T, T)" +// @snapshot golf_type_alias_decl - '//*[@class="rust item-decl"]/code' pub type Golf where T: Clone = (T, T); From 30ff127036b685aca52d121807d13e8e1d2db684 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 16 Jun 2023 20:20:39 +0000 Subject: [PATCH 406/465] Re-use error code for duplicate error --- compiler/rustc_ty_utils/src/errors.rs | 2 +- tests/ui/type-alias-impl-trait/multi-error.stderr | 3 ++- tests/ui/type-alias-impl-trait/non-defining-method.stderr | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs index 553bf40ef3a48..947d4bbe86e1c 100644 --- a/compiler/rustc_ty_utils/src/errors.rs +++ b/compiler/rustc_ty_utils/src/errors.rs @@ -113,7 +113,7 @@ pub struct DuplicateArg<'tcx> { } #[derive(Diagnostic)] -#[diag(ty_utils_impl_trait_not_param)] +#[diag(ty_utils_impl_trait_not_param, code = "E0792")] pub struct NotParam<'tcx> { pub arg: GenericArg<'tcx>, #[primary_span] diff --git a/tests/ui/type-alias-impl-trait/multi-error.stderr b/tests/ui/type-alias-impl-trait/multi-error.stderr index 6d8fa0fb021a8..b2de2effea662 100644 --- a/tests/ui/type-alias-impl-trait/multi-error.stderr +++ b/tests/ui/type-alias-impl-trait/multi-error.stderr @@ -1,4 +1,4 @@ -error: non-defining opaque type use in defining scope +error[E0792]: non-defining opaque type use in defining scope --> $DIR/multi-error.rs:17:17 | LL | fn foo() -> (Self::Bar, Self::Baz) { @@ -12,3 +12,4 @@ LL | type Bar = impl Sized; error: aborting due to previous error +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/non-defining-method.stderr b/tests/ui/type-alias-impl-trait/non-defining-method.stderr index 61bf2da20dbdb..ed5590f9d7174 100644 --- a/tests/ui/type-alias-impl-trait/non-defining-method.stderr +++ b/tests/ui/type-alias-impl-trait/non-defining-method.stderr @@ -1,4 +1,4 @@ -error: non-defining opaque type use in defining scope +error[E0792]: non-defining opaque type use in defining scope --> $DIR/non-defining-method.rs:16:17 | LL | fn foo() -> Self::Bar {} @@ -12,3 +12,4 @@ LL | type Bar = impl Sized; error: aborting due to previous error +For more information about this error, try `rustc --explain E0792`. From cb161e77ba7492524e17e077085f1fab7e0dd9b8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 19 Jun 2023 09:51:28 +0000 Subject: [PATCH 407/465] Move some field extraction logic onto a method on `Node` --- compiler/rustc_hir/src/hir.rs | 23 +++++++++++++++++++++ compiler/rustc_ty_utils/src/opaque_types.rs | 10 +++------ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 70fc66947df99..5e5001bc8b450 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3743,6 +3743,29 @@ impl<'hir> Node<'hir> { } } + /// Get the type for constants, assoc types, type aliases and statics. + pub fn ty(self) -> Option<&'hir Ty<'hir>> { + match self { + Node::Item(it) => match it.kind { + ItemKind::TyAlias(ty, _) | ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => { + Some(ty) + } + _ => None, + }, + Node::TraitItem(it) => match it.kind { + TraitItemKind::Const(ty, _) => Some(ty), + TraitItemKind::Type(_, ty) => ty, + _ => None, + }, + Node::ImplItem(it) => match it.kind { + ImplItemKind::Const(ty, _) => Some(ty), + ImplItemKind::Type(ty) => Some(ty), + _ => None, + }, + _ => None, + } + } + pub fn alias_ty(self) -> Option<&'hir Ty<'hir>> { match self { Node::Item(Item { kind: ItemKind::TyAlias(ty, ..), .. }) => Some(ty), diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index ab97406452e58..5fb5c4ad144a8 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -177,13 +177,9 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [ } } DefKind::AssocTy | DefKind::AssocConst => { - let span = match tcx.hir().get_by_def_id(item) { - rustc_hir::Node::ImplItem(it) => match it.kind { - rustc_hir::ImplItemKind::Const(ty, _) => ty.span, - rustc_hir::ImplItemKind::Type(ty) => ty.span, - other => span_bug!(tcx.def_span(item), "{other:#?}"), - }, - other => span_bug!(tcx.def_span(item), "{other:#?}"), + let span = match tcx.hir().get_by_def_id(item).ty() { + Some(ty) => ty.span, + _ => tcx.def_span(item), }; collector.visit_spanned(span, tcx.type_of(item).subst_identity()); } From 0af4a211be2c9cc345728449a2fe213f64c216b8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 19 Jun 2023 09:55:01 +0000 Subject: [PATCH 408/465] Document what is going on in `opaque_types_defined_by` --- compiler/rustc_ty_utils/src/opaque_types.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 5fb5c4ad144a8..498194a7c10f6 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -168,14 +168,17 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [ DefKind::Fn | DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { let mut collector = OpaqueTypeCollector::new(tcx, item); match kind { + // Walk over the signature of the function-like to find the opaques. DefKind::AssocFn | DefKind::Fn => { let ty_sig = tcx.fn_sig(item).subst_identity(); let hir_sig = tcx.hir().get_by_def_id(item).fn_sig().unwrap(); + // Walk over the inputs and outputs manually in order to get good spans for them. collector.visit_spanned(hir_sig.decl.output.span(), ty_sig.output()); for (hir, ty) in hir_sig.decl.inputs.iter().zip(ty_sig.inputs().iter()) { collector.visit_spanned(hir.span, ty.map_bound(|x| *x)); } } + // Walk over the type of the item to find opaques. DefKind::AssocTy | DefKind::AssocConst => { let span = match tcx.hir().get_by_def_id(item).ty() { Some(ty) => ty.span, From b0b4a0795949aee0df9bad292ba2951f8c6291ec Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 19 Jun 2023 11:19:05 +0000 Subject: [PATCH 409/465] ICE on types that should not be defining opaque types --- compiler/rustc_ty_utils/src/opaque_types.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 498194a7c10f6..b8dfff0b8abf4 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -217,7 +217,9 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [ | DefKind::GlobalAsm | DefKind::Impl { .. } | DefKind::Closure - | DefKind::Generator => &[], + | DefKind::Generator => { + span_bug!(tcx.def_span(item), "{kind:?} is type checked as part of its parent") + } } } From b323f587fcd978deff5b922e60dcc4bcd208f2ab Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 19 Jun 2023 12:42:59 +0000 Subject: [PATCH 410/465] Handle weak type aliases by immediately resolving them to their aliased type --- compiler/rustc_ty_utils/src/opaque_types.rs | 23 +++++++++++-------- ...s-impl-trait-declaration-too-subtle.stderr | 5 ---- .../unnameable_type.stderr | 5 ---- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index b8dfff0b8abf4..351c703cba128 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -107,6 +107,12 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { } } } + ty::Alias(ty::Weak, alias_ty) if alias_ty.def_id.is_local() => { + self.tcx + .type_of(alias_ty.def_id) + .subst(self.tcx, alias_ty.substs) + .visit_with(self)?; + } ty::Alias(ty::Projection, alias_ty) => { // This avoids having to do normalization of `Self::AssocTy` by only // supporting the case of a method defining opaque types from assoc types @@ -136,24 +142,23 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { ty::InternalSubsts::identity_for_item(self.tcx, parent), ); - if !check_substs_compatible(self.tcx, assoc, impl_substs) { + if check_substs_compatible(self.tcx, assoc, impl_substs) { + return self + .tcx + .type_of(assoc.def_id) + .subst(self.tcx, impl_substs) + .visit_with(self); + } else { self.tcx.sess.delay_span_bug( self.tcx.def_span(assoc.def_id), "item had incorrect substs", ); - return ControlFlow::Continue(()); } - - return self - .tcx - .type_of(assoc.def_id) - .subst(self.tcx, impl_substs) - .visit_with(self); } } } } - _ => {} + _ => trace!(kind=?t.kind()), } ControlFlow::Continue(()) } diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr index 3e1981f096c77..fe765271bd2fe 100644 --- a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr +++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr @@ -20,11 +20,6 @@ LL | fn eq(&self, _other: &(Foo, i32)) -> bool { | = note: expected signature `fn(&a::Bar, &(a::Bar, i32)) -> _` found signature `fn(&a::Bar, &(a::Foo, i32)) -> _` -note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:10:12 - | -LL | fn eq(&self, _other: &(Foo, i32)) -> bool { - | ^^ error: unconstrained opaque type --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:18:16 diff --git a/tests/ui/type-alias-impl-trait/unnameable_type.stderr b/tests/ui/type-alias-impl-trait/unnameable_type.stderr index c609ace919e5b..e9032433494a6 100644 --- a/tests/ui/type-alias-impl-trait/unnameable_type.stderr +++ b/tests/ui/type-alias-impl-trait/unnameable_type.stderr @@ -25,11 +25,6 @@ LL | fn dont_define_this(_private: Private) {} | ^^^^^^^ = note: expected signature `fn(Private)` found signature `fn(MyPrivate)` -note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/unnameable_type.rs:20:8 - | -LL | fn dont_define_this(_private: MyPrivate) {} - | ^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors From 27b386ad17720523ad7bc49e9cf481dd7f7d8da4 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 19 Jun 2023 17:58:14 +0000 Subject: [PATCH 411/465] Only walk the identity substituted version of struct fields --- compiler/rustc_ty_utils/src/opaque_types.rs | 23 +++++++++++++- ...n_behind_projection_behind_struct_field.rs | 28 +++++++++++++++++ ...hind_projection_behind_struct_field.stderr | 20 +++++++++++++ .../hidden_behind_struct_field.rs | 30 +++++++++++++++++++ .../hidden_behind_struct_field2.rs | 26 ++++++++++++++++ 5 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 tests/ui/type-alias-impl-trait/hidden_behind_projection_behind_struct_field.rs create mode 100644 tests/ui/type-alias-impl-trait/hidden_behind_projection_behind_struct_field.stderr create mode 100644 tests/ui/type-alias-impl-trait/hidden_behind_struct_field.rs create mode 100644 tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.rs diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 351c703cba128..29de8bf0e53f5 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -82,10 +82,12 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { // start seeing the error below. // Collect opaque types nested within the associated type bounds of this opaque type. + // We use identity substs here, because we already know that the opaque type uses + // only generic parameters, and thus substituting would not give us more information. for (pred, span) in self .tcx .explicit_item_bounds(alias_ty.def_id) - .subst_iter_copied(self.tcx, alias_ty.substs) + .subst_identity_iter_copied() { trace!(?pred); self.visit_spanned(span, pred); @@ -158,6 +160,25 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { } } } + ty::Adt(def, _) if def.did().is_local() => { + if !self.seen.insert(def.did().expect_local()) { + return ControlFlow::Continue(()); + } + for variant in def.variants().iter() { + for field in variant.fields.iter() { + // Don't use the `ty::Adt` substs, we either + // * found the opaque in the substs + // * will find the opaque in the unsubstituted fields + // The only other situation that can occur is that after substituting, + // some projection resolves to an opaque that we would have otherwise + // not found. While we could substitute and walk those, that would mean we + // would have to walk all substitutions of an Adt, which can quickly + // degenerate into looking at an exponential number of types. + let ty = self.tcx.type_of(field.did).subst_identity(); + self.visit_spanned(self.tcx.def_span(field.did), ty); + } + } + } _ => trace!(kind=?t.kind()), } ControlFlow::Continue(()) diff --git a/tests/ui/type-alias-impl-trait/hidden_behind_projection_behind_struct_field.rs b/tests/ui/type-alias-impl-trait/hidden_behind_projection_behind_struct_field.rs new file mode 100644 index 0000000000000..eb19b49c7e213 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/hidden_behind_projection_behind_struct_field.rs @@ -0,0 +1,28 @@ +//! This test shows that a field type that is a projection that resolves to an opaque, +//! is not a defining use. While we could substitute the struct generics, that would +//! mean we would have to walk all substitutions of an `Foo`, which can quickly +//! degenerate into looking at an exponential number of types depending on the complexity +//! of a program. + +#![feature(impl_trait_in_assoc_type)] + +struct Bar; + +trait Trait: Sized { + type Assoc; + fn foo() -> Foo; +} + +impl Trait for Bar { + type Assoc = impl std::fmt::Debug; + fn foo() -> Foo { + Foo { field: () } + //~^ ERROR: mismatched types + } +} + +struct Foo { + field: ::Assoc, +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/hidden_behind_projection_behind_struct_field.stderr b/tests/ui/type-alias-impl-trait/hidden_behind_projection_behind_struct_field.stderr new file mode 100644 index 0000000000000..648efd1cbfe7c --- /dev/null +++ b/tests/ui/type-alias-impl-trait/hidden_behind_projection_behind_struct_field.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/hidden_behind_projection_behind_struct_field.rs:19:22 + | +LL | type Assoc = impl std::fmt::Debug; + | -------------------- the expected opaque type +LL | fn foo() -> Foo { +LL | Foo { field: () } + | ^^ expected opaque type, found `()` + | + = note: expected opaque type `::Assoc` + found unit type `()` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/hidden_behind_projection_behind_struct_field.rs:18:8 + | +LL | fn foo() -> Foo { + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/hidden_behind_struct_field.rs b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field.rs new file mode 100644 index 0000000000000..58778702de666 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field.rs @@ -0,0 +1,30 @@ +//! This test shows that the appearance of an opaque type +//! in the substs of a struct are enough to make it count +//! for making the function a defining use. It doesn't matter +//! if the opaque type is actually used in the field. + +#![feature(impl_trait_in_assoc_type)] +// check-pass + +use std::marker::PhantomData; + +struct Bar; + +trait Trait: Sized { + type Assoc; + fn foo() -> Foo; +} + +impl Trait for Bar { + type Assoc = impl std::fmt::Debug; + fn foo() -> Foo { + let foo: Foo<()> = Foo { field: PhantomData }; + foo + } +} + +struct Foo { + field: PhantomData, +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.rs b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.rs new file mode 100644 index 0000000000000..e440dce5e514f --- /dev/null +++ b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.rs @@ -0,0 +1,26 @@ +//! This test shows that we can even follow projections +//! into associated types of the same impl if they are +//! indirectly mentioned in a struct field. + +#![feature(impl_trait_in_assoc_type)] +// check-pass + +struct Bar; + +trait Trait: Sized { + type Assoc; + fn foo() -> Foo; +} + +impl Trait for Bar { + type Assoc = impl std::fmt::Debug; + fn foo() -> Foo { + Foo { field: () } + } +} + +struct Foo { + field: ::Assoc, +} + +fn main() {} From 717c4817391f61953eed678607168cfea81e3111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 16 Jun 2023 18:09:54 +0000 Subject: [PATCH 412/465] Account for sealed traits in trait bound errors When implementing a public trait with a private super-trait, we now emit a note that the missing bound is not going to be able to be satisfied, and we explain the concept of a sealed trait. --- .../src/traits/error_reporting/suggestions.rs | 26 +++++++++++++++++++ .../sealed-traits/sealed-trait-local.rs | 19 ++++++++++++++ .../sealed-traits/sealed-trait-local.stderr | 16 ++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 tests/ui/privacy/sealed-traits/sealed-trait-local.rs create mode 100644 tests/ui/privacy/sealed-traits/sealed-trait-local.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 966c4a7dcf38f..dba6ffc4c96c3 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2724,6 +2724,32 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let msg = format!("required by this bound in `{short_item_name}`"); multispan.push_span_label(span, msg); err.span_note(multispan, descr); + if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() + && let ty::ClauseKind::Trait(trait_pred) = clause + { + let def_id = trait_pred.def_id(); + let visible_item = if let Some(local) = def_id.as_local() { + // Check for local traits being reachable. + let vis = &self.tcx.resolutions(()).effective_visibilities; + // Account for non-`pub` traits in the root of the local crate. + let is_locally_reachable = self.tcx.parent(def_id).is_crate_root(); + vis.is_reachable(local) || is_locally_reachable + } else { + // Check for foreign traits being reachable. + self.tcx.visible_parent_map(()).get(&def_id).is_some() + }; + if let DefKind::Trait = tcx.def_kind(item_def_id) && !visible_item { + // FIXME(estebank): extend this to search for all the types that do + // implement this trait and list them. + err.note(format!( + "`{short_item_name}` is a \"sealed trait\", because to implement \ + it you also need to implelement `{}`, which is not accessible; \ + this is usually done to force you to use one of the provided \ + types that already implement it", + with_no_trimmed_paths!(tcx.def_path_str(def_id)), + )); + } + } } else { err.span_note(tcx.def_span(item_def_id), descr); } diff --git a/tests/ui/privacy/sealed-traits/sealed-trait-local.rs b/tests/ui/privacy/sealed-traits/sealed-trait-local.rs new file mode 100644 index 0000000000000..778ddf0f81763 --- /dev/null +++ b/tests/ui/privacy/sealed-traits/sealed-trait-local.rs @@ -0,0 +1,19 @@ +// provide custom privacy error for sealed traits +pub mod a { + pub trait Sealed: self::b::Hidden { + fn foo() {} + } + + struct X; + impl Sealed for X {} + impl self::b::Hidden for X {} + + mod b { + pub trait Hidden {} + } +} + +struct S; +impl a::Sealed for S {} //~ ERROR the trait bound `S: Hidden` is not satisfied + +fn main() {} diff --git a/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr b/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr new file mode 100644 index 0000000000000..d1052ce35080c --- /dev/null +++ b/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr @@ -0,0 +1,16 @@ +error[E0277]: the trait bound `S: Hidden` is not satisfied + --> $DIR/sealed-trait-local.rs:17:20 + | +LL | impl a::Sealed for S {} + | ^ the trait `Hidden` is not implemented for `S` + | +note: required by a bound in `Sealed` + --> $DIR/sealed-trait-local.rs:3:23 + | +LL | pub trait Sealed: self::b::Hidden { + | ^^^^^^^^^^^^^^^ required by this bound in `Sealed` + = note: `Sealed` is a "sealed trait", because to implement it you also need to implelement `a::b::Hidden`, which is not accessible; this is usually done to force you to use one of the provided types that already implement it + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 7dffd24da5292cc01f18c4ab53f0b96f682fcbe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 16 Jun 2023 19:44:06 +0000 Subject: [PATCH 413/465] Tweak privacy errors to account for reachable items Suggest publicly accessible paths for items in private mod: When encountering a path in non-import situations that are not reachable due to privacy constraints, search for any public re-exports that the user could use instead. Track whether an import suggestion is offering a re-export. When encountering a path with private segments, mention if the item at the final path segment is not publicly accessible at all. Add item visibility metadata to privacy errors from imports: On unreachable imports, record the item that was being imported in order to suggest publicly available re-exports or to be explicit that the item is not available publicly from any path. In order to allow this, we add a mode to `resolve_path` that will not add new privacy errors, nor return early if it encounters one. This way we can get the `Res` corresponding to the final item in the import, which is used in the privacy error machinery. --- compiler/rustc_resolve/src/diagnostics.rs | 92 +++++++++++++------ compiler/rustc_resolve/src/ident.rs | 13 +++ compiler/rustc_resolve/src/imports.rs | 19 ++++ .../rustc_resolve/src/late/diagnostics.rs | 1 + compiler/rustc_resolve/src/lib.rs | 3 + .../ui/extern/extern-crate-visibility.stderr | 8 ++ tests/ui/issues/issue-11680.stderr | 8 +- tests/ui/macros/issue-88228.stderr | 4 +- tests/ui/privacy/export-tag-variant.stderr | 4 +- tests/ui/privacy/privacy-in-paths.stderr | 12 ++- tests/ui/privacy/privacy-ufcs.stderr | 4 +- tests/ui/privacy/privacy1.stderr | 28 +++++- .../sealed-traits/private-trait-non-local.rs | 4 + .../private-trait-non-local.stderr | 12 +++ .../ui/privacy/sealed-traits/private-trait.rs | 10 ++ .../sealed-traits/private-trait.stderr | 17 ++++ .../sealed-traits/re-exported-trait.fixed | 13 +++ .../sealed-traits/re-exported-trait.rs | 13 +++ .../sealed-traits/re-exported-trait.stderr | 19 ++++ .../proc-macro/derive-helper-shadowing.stderr | 4 +- tests/ui/reachable/unreachable-variant.stderr | 2 +- tests/ui/resolve/privacy-enum-ctor.stderr | 8 +- .../stability-in-private-module.stderr | 4 +- .../structs/struct-variant-privacy-xc.stderr | 4 +- .../ui/structs/struct-variant-privacy.stderr | 4 +- .../xcrate/xcrate-private-by-default.stderr | 20 +++- 26 files changed, 276 insertions(+), 54 deletions(-) create mode 100644 tests/ui/privacy/sealed-traits/private-trait-non-local.rs create mode 100644 tests/ui/privacy/sealed-traits/private-trait-non-local.stderr create mode 100644 tests/ui/privacy/sealed-traits/private-trait.rs create mode 100644 tests/ui/privacy/sealed-traits/private-trait.stderr create mode 100644 tests/ui/privacy/sealed-traits/re-exported-trait.fixed create mode 100644 tests/ui/privacy/sealed-traits/re-exported-trait.rs create mode 100644 tests/ui/privacy/sealed-traits/re-exported-trait.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 539b4a1d5e714..d77fb922e844d 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -103,6 +103,7 @@ pub(crate) struct ImportSuggestion { pub descr: &'static str, pub path: Path, pub accessible: bool, + pub via_import: bool, /// An extra note that should be issued if this item is suggested pub note: Option, } @@ -140,9 +141,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } let mut reported_spans = FxHashSet::default(); - for error in &self.privacy_errors { + for error in std::mem::take(&mut self.privacy_errors) { if reported_spans.insert(error.dedup_span) { - self.report_privacy_error(error); + self.report_privacy_error(&error); } } } @@ -1256,6 +1257,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { path, accessible: child_accessible, note, + via_import, }); } } @@ -1609,8 +1611,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None } - fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) { - let PrivacyError { ident, binding, .. } = *privacy_error; + fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'a>) { + let PrivacyError { ident, binding, outermost_res, parent_scope, dedup_span } = + *privacy_error; let res = binding.res(); let ctor_fields_span = self.ctor_fields_span(binding); @@ -1627,6 +1630,33 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { struct_span_err!(self.tcx.sess, ident.span, E0603, "{} `{}` is private", descr, ident); err.span_label(ident.span, format!("private {}", descr)); + if let Some((this_res, outer_ident)) = outermost_res { + let import_suggestions = self.lookup_import_candidates( + outer_ident, + this_res.ns().unwrap_or(Namespace::TypeNS), + &parent_scope, + &|res: Res| res == this_res, + ); + let point_to_def = !show_candidates( + self.tcx, + &mut err, + Some(dedup_span.until(outer_ident.span.shrink_to_hi())), + &import_suggestions, + Instead::Yes, + FoundUse::Yes, + DiagnosticMode::Import, + vec![], + "", + ); + // If we suggest importing a public re-export, don't point at the definition. + if point_to_def && ident.span != outer_ident.span { + err.span_label( + outer_ident.span, + format!("{} `{outer_ident}` is not publicly re-exported", this_res.descr()), + ); + } + } + let mut non_exhaustive = None; // If an ADT is foreign and marked as `non_exhaustive`, then that's // probably why we have the privacy error. @@ -2455,7 +2485,8 @@ pub(crate) fn import_candidates( /// When an entity with a given name is not available in scope, we search for /// entities with that name in all crates. This method allows outputting the -/// results of this search in a programmer-friendly way +/// results of this search in a programmer-friendly way. If any entities are +/// found and suggested, returns `true`, otherwise returns `false`. fn show_candidates( tcx: TyCtxt<'_>, err: &mut Diagnostic, @@ -2467,19 +2498,19 @@ fn show_candidates( mode: DiagnosticMode, path: Vec, append: &str, -) { +) -> bool { if candidates.is_empty() { - return; + return false; } - let mut accessible_path_strings: Vec<(String, &str, Option, &Option)> = + let mut accessible_path_strings: Vec<(String, &str, Option, &Option, bool)> = Vec::new(); - let mut inaccessible_path_strings: Vec<(String, &str, Option, &Option)> = + let mut inaccessible_path_strings: Vec<(String, &str, Option, &Option, bool)> = Vec::new(); candidates.iter().for_each(|c| { (if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings }) - .push((path_names_to_string(&c.path), c.descr, c.did, &c.note)) + .push((path_names_to_string(&c.path), c.descr, c.did, &c.note, c.via_import)) }); // we want consistent results across executions, but candidates are produced @@ -2493,20 +2524,25 @@ fn show_candidates( } if !accessible_path_strings.is_empty() { - let (determiner, kind, name) = if accessible_path_strings.len() == 1 { - ("this", accessible_path_strings[0].1, format!(" `{}`", accessible_path_strings[0].0)) - } else { - ("one of these", "items", String::new()) - }; + let (determiner, kind, name, through) = + if let [(name, descr, _, _, via_import)] = &accessible_path_strings[..] { + ( + "this", + *descr, + format!(" `{name}`"), + if *via_import { " through its public re-export" } else { "" }, + ) + } else { + ("one of these", "items", String::new(), "") + }; let instead = if let Instead::Yes = instead { " instead" } else { "" }; let mut msg = if let DiagnosticMode::Pattern = mode { format!( - "if you meant to match on {}{}{}, use the full path in the pattern", - kind, instead, name + "if you meant to match on {kind}{instead}{name}, use the full path in the pattern", ) } else { - format!("consider importing {} {}{}", determiner, kind, instead) + format!("consider importing {determiner} {kind}{through}{instead}") }; for note in accessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) { @@ -2522,7 +2558,7 @@ fn show_candidates( accessible_path_strings.into_iter().map(|a| a.0), Applicability::MaybeIncorrect, ); - return; + return true; } DiagnosticMode::Import => ("", ""), DiagnosticMode::Normal => ("use ", ";\n"), @@ -2563,6 +2599,7 @@ fn show_candidates( err.help(msg); } + true } else if !matches!(mode, DiagnosticMode::Import) { assert!(!inaccessible_path_strings.is_empty()); @@ -2571,13 +2608,9 @@ fn show_candidates( } else { "" }; - if inaccessible_path_strings.len() == 1 { - let (name, descr, def_id, note) = &inaccessible_path_strings[0]; + if let [(name, descr, def_id, note, _)] = &inaccessible_path_strings[..] { let msg = format!( - "{}{} `{}`{} exists but is inaccessible", - prefix, - descr, - name, + "{prefix}{descr} `{name}`{} exists but is inaccessible", if let DiagnosticMode::Pattern = mode { ", which" } else { "" } ); @@ -2594,11 +2627,11 @@ fn show_candidates( err.note(note.to_string()); } } else { - let (_, descr_first, _, _) = &inaccessible_path_strings[0]; + let (_, descr_first, _, _, _) = &inaccessible_path_strings[0]; let descr = if inaccessible_path_strings .iter() .skip(1) - .all(|(_, descr, _, _)| descr == descr_first) + .all(|(_, descr, _, _, _)| descr == descr_first) { descr_first } else { @@ -2611,7 +2644,7 @@ fn show_candidates( let mut has_colon = false; let mut spans = Vec::new(); - for (name, _, def_id, _) in &inaccessible_path_strings { + for (name, _, def_id, _, _) in &inaccessible_path_strings { if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) { let span = tcx.source_span(local_def_id); let span = tcx.sess.source_map().guess_head_span(span); @@ -2637,6 +2670,9 @@ fn show_candidates( err.span_note(multi_span, msg); } + true + } else { + false } } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index e29a1626aedd2..e5fa062967ff2 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -893,6 +893,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ident, binding, dedup_span: path_span, + outermost_res: None, + parent_scope: *parent_scope, }); } else { return Err((Determined, Weak::No)); @@ -1369,6 +1371,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let mut allow_super = true; let mut second_binding = None; + // We'll provide more context to the privacy errors later, up to `len`. + let privacy_errors_len = self.privacy_errors.len(); + for (segment_idx, &Segment { ident, id, .. }) in path.iter().enumerate() { debug!("resolve_path ident {} {:?} {:?}", segment_idx, ident, id); let record_segment_res = |this: &mut Self, res| { @@ -1506,6 +1511,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { second_binding = Some(binding); } let res = binding.res(); + + // Mark every privacy error in this path with the res to the last element. This allows us + // to detect the item the user cares about and either find an alternative import, or tell + // the user it is not accessible. + for error in &mut self.privacy_errors[privacy_errors_len..] { + error.outermost_res = Some((res, ident)); + } + let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res); if let Some(next_module) = binding.module() { module = Some(ModuleOrUniformRoot::Module(next_module)); diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 47d8e5993fd82..4445330992004 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -792,6 +792,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }; let prev_ambiguity_errors_len = self.ambiguity_errors.len(); let finalize = Finalize::with_root_span(import.root_id, import.span, import.root_span); + + // We'll provide more context to the privacy errors later, up to `len`. + let privacy_errors_len = self.privacy_errors.len(); + let path_res = self.resolve_path( &import.module_path, None, @@ -931,6 +935,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { _ => unreachable!(), }; + if self.privacy_errors.len() != privacy_errors_len { + // Get the Res for the last element, so that we can point to alternative ways of + // importing it if available. + let mut path = import.module_path.clone(); + path.push(Segment::from_ident(ident)); + if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = + self.resolve_path(&path, None, &import.parent_scope, Some(finalize), ignore_binding) + { + let res = module.res().map(|r| (r, ident)); + for error in &mut self.privacy_errors[privacy_errors_len..] { + error.outermost_res = res; + } + } + } + let mut all_ns_err = true; self.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 7284b33f09d8e..475772734ff82 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1831,6 +1831,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { path, accessible: true, note: None, + via_import: false, }, )); } else { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 82b333fee28b8..8c1cd2f155715 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -689,10 +689,13 @@ impl<'a> NameBindingKind<'a> { } } +#[derive(Debug)] struct PrivacyError<'a> { ident: Ident, binding: &'a NameBinding<'a>, dedup_span: Span, + outermost_res: Option<(Res, Ident)>, + parent_scope: ParentScope<'a>, } #[derive(Debug)] diff --git a/tests/ui/extern/extern-crate-visibility.stderr b/tests/ui/extern/extern-crate-visibility.stderr index 9eeb83ae1a73f..b239727092ae1 100644 --- a/tests/ui/extern/extern-crate-visibility.stderr +++ b/tests/ui/extern/extern-crate-visibility.stderr @@ -9,6 +9,10 @@ note: the crate import `core` is defined here | LL | extern crate core; | ^^^^^^^^^^^^^^^^^^ +help: consider importing this module instead + | +LL | use std::cell; + | ~~~~~~~~~ error[E0603]: crate import `core` is private --> $DIR/extern-crate-visibility.rs:9:10 @@ -21,6 +25,10 @@ note: the crate import `core` is defined here | LL | extern crate core; | ^^^^^^^^^^^^^^^^^^ +help: consider importing this struct instead + | +LL | std::cell::Cell::new(0); + | ~~~~~~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-11680.stderr b/tests/ui/issues/issue-11680.stderr index ea224af8ed7e2..5bcf93de811fe 100644 --- a/tests/ui/issues/issue-11680.stderr +++ b/tests/ui/issues/issue-11680.stderr @@ -2,7 +2,9 @@ error[E0603]: enum `Foo` is private --> $DIR/issue-11680.rs:6:21 | LL | let _b = other::Foo::Bar(1); - | ^^^ private enum + | ^^^ --- tuple variant `Bar` is not publicly re-exported + | | + | private enum | note: the enum `Foo` is defined here --> $DIR/auxiliary/issue-11680.rs:1:1 @@ -14,7 +16,9 @@ error[E0603]: enum `Foo` is private --> $DIR/issue-11680.rs:9:27 | LL | let _b = other::test::Foo::Bar(1); - | ^^^ private enum + | ^^^ --- tuple variant `Bar` is not publicly re-exported + | | + | private enum | note: the enum `Foo` is defined here --> $DIR/auxiliary/issue-11680.rs:6:5 diff --git a/tests/ui/macros/issue-88228.stderr b/tests/ui/macros/issue-88228.stderr index 1dbe2b77be2d9..f9d0ac95da756 100644 --- a/tests/ui/macros/issue-88228.stderr +++ b/tests/ui/macros/issue-88228.stderr @@ -4,7 +4,7 @@ error: cannot find macro `bla` in this scope LL | bla!(); | ^^^ | -help: consider importing this macro +help: consider importing this macro through its public re-export | LL + use crate::hey::bla; | @@ -23,7 +23,7 @@ error: cannot find derive macro `Bla` in this scope LL | #[derive(Bla)] | ^^^ | -help: consider importing this derive macro +help: consider importing this derive macro through its public re-export | LL + use crate::hey::Bla; | diff --git a/tests/ui/privacy/export-tag-variant.stderr b/tests/ui/privacy/export-tag-variant.stderr index f73bd454d3592..e8906985e059d 100644 --- a/tests/ui/privacy/export-tag-variant.stderr +++ b/tests/ui/privacy/export-tag-variant.stderr @@ -2,7 +2,9 @@ error[E0603]: enum `Y` is private --> $DIR/export-tag-variant.rs:7:26 | LL | fn main() { let z = foo::Y::Y1; } - | ^ private enum + | ^ -- unit variant `Y1` is not publicly re-exported + | | + | private enum | note: the enum `Y` is defined here --> $DIR/export-tag-variant.rs:4:5 diff --git a/tests/ui/privacy/privacy-in-paths.stderr b/tests/ui/privacy/privacy-in-paths.stderr index 2eb3ebb51c20a..9c3d5e97c62a3 100644 --- a/tests/ui/privacy/privacy-in-paths.stderr +++ b/tests/ui/privacy/privacy-in-paths.stderr @@ -2,7 +2,9 @@ error[E0603]: module `bar` is private --> $DIR/privacy-in-paths.rs:24:16 | LL | ::foo::bar::baz::f(); - | ^^^ private module + | ^^^ - function `f` is not publicly re-exported + | | + | private module | note: the module `bar` is defined here --> $DIR/privacy-in-paths.rs:3:5 @@ -21,12 +23,18 @@ note: the module `bar` is defined here | LL | mod bar { | ^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL | foo::S::f(); + | ~~~~~~ error[E0603]: trait `T` is private --> $DIR/privacy-in-paths.rs:26:23 | LL | <() as ::foo::T>::Assoc::f(); - | ^ private trait + | ^ ----- associated type `Assoc` is not publicly re-exported + | | + | private trait | note: the trait `T` is defined here --> $DIR/privacy-in-paths.rs:8:5 diff --git a/tests/ui/privacy/privacy-ufcs.stderr b/tests/ui/privacy/privacy-ufcs.stderr index e93a458ce6cb6..f45f3d8ec3720 100644 --- a/tests/ui/privacy/privacy-ufcs.stderr +++ b/tests/ui/privacy/privacy-ufcs.stderr @@ -2,7 +2,9 @@ error[E0603]: trait `Bar` is private --> $DIR/privacy-ufcs.rs:12:20 | LL | ::baz(); - | ^^^ private trait + | ^^^ --- associated function `baz` is not publicly re-exported + | | + | private trait | note: the trait `Bar` is defined here --> $DIR/privacy-ufcs.rs:4:5 diff --git a/tests/ui/privacy/privacy1.stderr b/tests/ui/privacy/privacy1.stderr index 6ebed8ee062ef..ca8f242e0bed2 100644 --- a/tests/ui/privacy/privacy1.stderr +++ b/tests/ui/privacy/privacy1.stderr @@ -50,7 +50,9 @@ error[E0603]: module `baz` is private --> $DIR/privacy1.rs:104:16 | LL | ::bar::baz::A::foo(); - | ^^^ private module + | ^^^ - struct `A` is not publicly re-exported + | | + | private module | note: the module `baz` is defined here --> $DIR/privacy1.rs:50:5 @@ -62,7 +64,9 @@ error[E0603]: module `baz` is private --> $DIR/privacy1.rs:105:16 | LL | ::bar::baz::A::bar(); - | ^^^ private module + | ^^^ - struct `A` is not publicly re-exported + | | + | private module | note: the module `baz` is defined here --> $DIR/privacy1.rs:50:5 @@ -74,7 +78,9 @@ error[E0603]: module `baz` is private --> $DIR/privacy1.rs:107:16 | LL | ::bar::baz::A.foo2(); - | ^^^ private module + | ^^^ - unit struct `A` is not publicly re-exported + | | + | private module | note: the module `baz` is defined here --> $DIR/privacy1.rs:50:5 @@ -86,7 +92,9 @@ error[E0603]: module `baz` is private --> $DIR/privacy1.rs:108:16 | LL | ::bar::baz::A.bar2(); - | ^^^ private module + | ^^^ - unit struct `A` is not publicly re-exported + | | + | private module | note: the module `baz` is defined here --> $DIR/privacy1.rs:50:5 @@ -98,7 +106,9 @@ error[E0603]: trait `B` is private --> $DIR/privacy1.rs:112:16 | LL | ::bar::B::foo(); - | ^ private trait + | ^ --- associated function `foo` is not publicly re-exported + | | + | private trait | note: the trait `B` is defined here --> $DIR/privacy1.rs:40:5 @@ -129,6 +139,10 @@ note: the module `baz` is defined here | LL | mod baz { | ^^^^^^^ +help: consider importing this function through its public re-export instead + | +LL | bar::foo(); + | ~~~~~~~~ error[E0603]: module `baz` is private --> $DIR/privacy1.rs:128:16 @@ -141,6 +155,10 @@ note: the module `baz` is defined here | LL | mod baz { | ^^^^^^^ +help: consider importing this function through its public re-export instead + | +LL | bar::bar(); + | ~~~~~~~~ error[E0603]: trait `B` is private --> $DIR/privacy1.rs:157:17 diff --git a/tests/ui/privacy/sealed-traits/private-trait-non-local.rs b/tests/ui/privacy/sealed-traits/private-trait-non-local.rs new file mode 100644 index 0000000000000..426f21cc7de2d --- /dev/null +++ b/tests/ui/privacy/sealed-traits/private-trait-non-local.rs @@ -0,0 +1,4 @@ +extern crate core; +use core::slice::index::private_slice_index::Sealed; //~ ERROR module `index` is private +fn main() { +} diff --git a/tests/ui/privacy/sealed-traits/private-trait-non-local.stderr b/tests/ui/privacy/sealed-traits/private-trait-non-local.stderr new file mode 100644 index 0000000000000..2949997986674 --- /dev/null +++ b/tests/ui/privacy/sealed-traits/private-trait-non-local.stderr @@ -0,0 +1,12 @@ +error[E0603]: module `index` is private + --> $DIR/private-trait-non-local.rs:2:18 + | +LL | use core::slice::index::private_slice_index::Sealed; + | ^^^^^ private module ------ trait `Sealed` is not publicly re-exported + | +note: the module `index` is defined here + --> $SRC_DIR/core/src/slice/mod.rs:LL:COL + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/privacy/sealed-traits/private-trait.rs b/tests/ui/privacy/sealed-traits/private-trait.rs new file mode 100644 index 0000000000000..bbcbaabfaf433 --- /dev/null +++ b/tests/ui/privacy/sealed-traits/private-trait.rs @@ -0,0 +1,10 @@ +pub mod a { + mod b { + pub trait Hidden {} + } +} + +struct S; +impl a::b::Hidden for S {} //~ ERROR module `b` is private + +fn main() {} diff --git a/tests/ui/privacy/sealed-traits/private-trait.stderr b/tests/ui/privacy/sealed-traits/private-trait.stderr new file mode 100644 index 0000000000000..c7ec72ff1662c --- /dev/null +++ b/tests/ui/privacy/sealed-traits/private-trait.stderr @@ -0,0 +1,17 @@ +error[E0603]: module `b` is private + --> $DIR/private-trait.rs:8:9 + | +LL | impl a::b::Hidden for S {} + | ^ ------ trait `Hidden` is not publicly re-exported + | | + | private module + | +note: the module `b` is defined here + --> $DIR/private-trait.rs:2:5 + | +LL | mod b { + | ^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/privacy/sealed-traits/re-exported-trait.fixed b/tests/ui/privacy/sealed-traits/re-exported-trait.fixed new file mode 100644 index 0000000000000..79b6a6516ab26 --- /dev/null +++ b/tests/ui/privacy/sealed-traits/re-exported-trait.fixed @@ -0,0 +1,13 @@ +// run-rustfix + +pub mod a { + pub use self::b::Trait; + mod b { + pub trait Trait {} + } +} + +struct S; +impl a::Trait for S {} //~ ERROR module `b` is private + +fn main() {} diff --git a/tests/ui/privacy/sealed-traits/re-exported-trait.rs b/tests/ui/privacy/sealed-traits/re-exported-trait.rs new file mode 100644 index 0000000000000..5f96dfdcbd6c4 --- /dev/null +++ b/tests/ui/privacy/sealed-traits/re-exported-trait.rs @@ -0,0 +1,13 @@ +// run-rustfix + +pub mod a { + pub use self::b::Trait; + mod b { + pub trait Trait {} + } +} + +struct S; +impl a::b::Trait for S {} //~ ERROR module `b` is private + +fn main() {} diff --git a/tests/ui/privacy/sealed-traits/re-exported-trait.stderr b/tests/ui/privacy/sealed-traits/re-exported-trait.stderr new file mode 100644 index 0000000000000..b630565d0237f --- /dev/null +++ b/tests/ui/privacy/sealed-traits/re-exported-trait.stderr @@ -0,0 +1,19 @@ +error[E0603]: module `b` is private + --> $DIR/re-exported-trait.rs:11:9 + | +LL | impl a::b::Trait for S {} + | ^ private module + | +note: the module `b` is defined here + --> $DIR/re-exported-trait.rs:5:5 + | +LL | mod b { + | ^^^^^ +help: consider importing this trait through its public re-export instead + | +LL | impl a::Trait for S {} + | ~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/proc-macro/derive-helper-shadowing.stderr b/tests/ui/proc-macro/derive-helper-shadowing.stderr index 7e7870b295127..566c41308468a 100644 --- a/tests/ui/proc-macro/derive-helper-shadowing.stderr +++ b/tests/ui/proc-macro/derive-helper-shadowing.stderr @@ -17,7 +17,7 @@ LL | #[derive(GenHelperUse)] | ^^^^^^^^^^^^ | = note: this error originates in the derive macro `GenHelperUse` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing this attribute macro +help: consider importing this attribute macro through its public re-export | LL + use empty_helper; | @@ -32,7 +32,7 @@ LL | gen_helper_use!(); | ----------------- in this macro invocation | = note: this error originates in the macro `gen_helper_use` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing this attribute macro +help: consider importing this attribute macro through its public re-export | LL + use crate::empty_helper; | diff --git a/tests/ui/reachable/unreachable-variant.stderr b/tests/ui/reachable/unreachable-variant.stderr index 6c27a2756f7fb..ca1d2be65ce52 100644 --- a/tests/ui/reachable/unreachable-variant.stderr +++ b/tests/ui/reachable/unreachable-variant.stderr @@ -2,7 +2,7 @@ error[E0603]: module `super_sekrit` is private --> $DIR/unreachable-variant.rs:6:21 | LL | let _x = other::super_sekrit::sooper_sekrit::baz; - | ^^^^^^^^^^^^ private module + | ^^^^^^^^^^^^ private module --- unit variant `baz` is not publicly re-exported | note: the module `super_sekrit` is defined here --> $DIR/auxiliary/unreachable_variant.rs:1:1 diff --git a/tests/ui/resolve/privacy-enum-ctor.stderr b/tests/ui/resolve/privacy-enum-ctor.stderr index 0bb09090569cb..b10eded015f8c 100644 --- a/tests/ui/resolve/privacy-enum-ctor.stderr +++ b/tests/ui/resolve/privacy-enum-ctor.stderr @@ -228,7 +228,9 @@ error[E0603]: enum `Z` is private --> $DIR/privacy-enum-ctor.rs:61:22 | LL | let _: Z = m::n::Z::Fn; - | ^ private enum + | ^ -- tuple variant `Fn` is not publicly re-exported + | | + | private enum | note: the enum `Z` is defined here --> $DIR/privacy-enum-ctor.rs:11:9 @@ -252,7 +254,9 @@ error[E0603]: enum `Z` is private --> $DIR/privacy-enum-ctor.rs:68:22 | LL | let _: Z = m::n::Z::Unit {}; - | ^ private enum + | ^ ---- variant `Unit` is not publicly re-exported + | | + | private enum | note: the enum `Z` is defined here --> $DIR/privacy-enum-ctor.rs:11:9 diff --git a/tests/ui/stability-attribute/stability-in-private-module.stderr b/tests/ui/stability-attribute/stability-in-private-module.stderr index 2f02a24960e01..cc8758714fc92 100644 --- a/tests/ui/stability-attribute/stability-in-private-module.stderr +++ b/tests/ui/stability-attribute/stability-in-private-module.stderr @@ -2,7 +2,9 @@ error[E0603]: module `thread_info` is private --> $DIR/stability-in-private-module.rs:2:26 | LL | let _ = std::thread::thread_info::current_thread(); - | ^^^^^^^^^^^ private module + | ^^^^^^^^^^^ -------------- function `current_thread` is not publicly re-exported + | | + | private module | note: the module `thread_info` is defined here --> $SRC_DIR/std/src/thread/mod.rs:LL:COL diff --git a/tests/ui/structs/struct-variant-privacy-xc.stderr b/tests/ui/structs/struct-variant-privacy-xc.stderr index 1c1caaef8b79d..7a1c84badeff2 100644 --- a/tests/ui/structs/struct-variant-privacy-xc.stderr +++ b/tests/ui/structs/struct-variant-privacy-xc.stderr @@ -14,7 +14,9 @@ error[E0603]: enum `Bar` is private --> $DIR/struct-variant-privacy-xc.rs:7:33 | LL | struct_variant_privacy::Bar::Baz { a: _a } => {} - | ^^^ private enum + | ^^^ --- variant `Baz` is not publicly re-exported + | | + | private enum | note: the enum `Bar` is defined here --> $DIR/auxiliary/struct_variant_privacy.rs:1:1 diff --git a/tests/ui/structs/struct-variant-privacy.stderr b/tests/ui/structs/struct-variant-privacy.stderr index eafd26c716f11..eabd66907f648 100644 --- a/tests/ui/structs/struct-variant-privacy.stderr +++ b/tests/ui/structs/struct-variant-privacy.stderr @@ -14,7 +14,9 @@ error[E0603]: enum `Bar` is private --> $DIR/struct-variant-privacy.rs:10:14 | LL | foo::Bar::Baz { a: _a } => {} - | ^^^ private enum + | ^^^ --- variant `Baz` is not publicly re-exported + | | + | private enum | note: the enum `Bar` is defined here --> $DIR/struct-variant-privacy.rs:2:5 diff --git a/tests/ui/xcrate/xcrate-private-by-default.stderr b/tests/ui/xcrate/xcrate-private-by-default.stderr index 0bdd4002f40ae..25bbbf5f62aa2 100644 --- a/tests/ui/xcrate/xcrate-private-by-default.stderr +++ b/tests/ui/xcrate/xcrate-private-by-default.stderr @@ -62,7 +62,9 @@ error[E0603]: module `foo` is private --> $DIR/xcrate-private-by-default.rs:35:29 | LL | static_priv_by_default::foo::a; - | ^^^ private module + | ^^^ - static `a` is not publicly re-exported + | | + | private module | note: the module `foo` is defined here --> $DIR/auxiliary/static_priv_by_default.rs:12:1 @@ -74,7 +76,9 @@ error[E0603]: module `foo` is private --> $DIR/xcrate-private-by-default.rs:37:29 | LL | static_priv_by_default::foo::b; - | ^^^ private module + | ^^^ - function `b` is not publicly re-exported + | | + | private module | note: the module `foo` is defined here --> $DIR/auxiliary/static_priv_by_default.rs:12:1 @@ -86,7 +90,9 @@ error[E0603]: module `foo` is private --> $DIR/xcrate-private-by-default.rs:39:29 | LL | static_priv_by_default::foo::c; - | ^^^ private module + | ^^^ - unit struct `c` is not publicly re-exported + | | + | private module | note: the module `foo` is defined here --> $DIR/auxiliary/static_priv_by_default.rs:12:1 @@ -98,7 +104,9 @@ error[E0603]: module `foo` is private --> $DIR/xcrate-private-by-default.rs:41:35 | LL | foo::(); - | ^^^ private module + | ^^^ - enum `d` is not publicly re-exported + | | + | private module | note: the module `foo` is defined here --> $DIR/auxiliary/static_priv_by_default.rs:12:1 @@ -110,7 +118,9 @@ error[E0603]: module `foo` is private --> $DIR/xcrate-private-by-default.rs:43:35 | LL | foo::(); - | ^^^ private module + | ^^^ - type alias `e` is not publicly re-exported + | | + | private module | note: the module `foo` is defined here --> $DIR/auxiliary/static_priv_by_default.rs:12:1 From c8960622a2aa16987d1dc2372146a36faa31087a Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Fri, 23 Jun 2023 02:17:39 +0900 Subject: [PATCH 414/465] avoid `&format` in error message code --- compiler/rustc_borrowck/src/borrowck_errors.rs | 2 +- compiler/rustc_macros/src/diagnostics/error.rs | 10 ++++------ compiler/rustc_macros/src/diagnostics/subdiagnostic.rs | 2 +- compiler/rustc_macros/src/diagnostics/utils.rs | 2 +- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index acca1a1477f25..a4e0e773a81ae 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -278,7 +278,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { move_from_span: Span, move_from_desc: &str, ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { - struct_span_err!(self, move_from_span, E0507, "cannot move out of {}", move_from_desc,) + struct_span_err!(self, move_from_span, E0507, "cannot move out of {}", move_from_desc) } /// Signal an error due to an attempt to move out of the interior diff --git a/compiler/rustc_macros/src/diagnostics/error.rs b/compiler/rustc_macros/src/diagnostics/error.rs index b37dc826d2886..84b18a6202814 100644 --- a/compiler/rustc_macros/src/diagnostics/error.rs +++ b/compiler/rustc_macros/src/diagnostics/error.rs @@ -54,7 +54,7 @@ fn path_to_string(path: &syn::Path) -> String { /// Returns an error diagnostic on span `span` with msg `msg`. #[must_use] -pub(crate) fn span_err(span: impl MultiSpan, msg: &str) -> Diagnostic { +pub(crate) fn span_err>(span: impl MultiSpan, msg: T) -> Diagnostic { Diagnostic::spanned(span, Level::Error, msg) } @@ -77,11 +77,9 @@ pub(crate) fn invalid_attr(attr: &Attribute) -> Diagnostic { let span = attr.span().unwrap(); let path = path_to_string(attr.path()); match attr.meta { - Meta::Path(_) => span_err(span, &format!("`#[{path}]` is not a valid attribute")), - Meta::NameValue(_) => { - span_err(span, &format!("`#[{path} = ...]` is not a valid attribute")) - } - Meta::List(_) => span_err(span, &format!("`#[{path}(...)]` is not a valid attribute")), + Meta::Path(_) => span_err(span, format!("`#[{path}]` is not a valid attribute")), + Meta::NameValue(_) => span_err(span, format!("`#[{path} = ...]` is not a valid attribute")), + Meta::List(_) => span_err(span, format!("`#[{path}(...)]` is not a valid attribute")), } } diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index e3d9eb96574d1..e8dc986914ed2 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -200,7 +200,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { throw_span_err!( attr.span().unwrap(), - &format!( + format!( "diagnostic slug must be first argument of a `#[{name}(...)]` attribute" ) ); diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 85dd9f6a3ce36..125632921816b 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -347,7 +347,7 @@ pub(crate) trait HasFieldMap { None => { span_err( span.unwrap(), - &format!("`{field}` doesn't refer to a field on this type"), + format!("`{field}` doesn't refer to a field on this type"), ) .emit(); quote! { From dfc5218dc83d5de02f196b182938e4ac4428a543 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Wed, 5 Apr 2023 15:02:57 -0400 Subject: [PATCH 415/465] rustc_session: default to -Z plt=yes on non-x86_64 Per the discussion in #106380 plt=no isn't a great default, and rust-lang/compiler-team#581 decided that the default should be PLT=yes for everything except x86_64. Not everyone agrees about the x86_64 part of this change, but this at least is an improvement in the state of things without changing the x86_64 situation, so I've attempted making this change in the name of not letting the perfect be the enemy of the good. --- compiler/rustc_session/src/options.rs | 2 +- compiler/rustc_session/src/session.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index edf95949d3234..270d833160250 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1613,7 +1613,7 @@ options! { plt: Option = (None, parse_opt_bool, [TRACKED], "whether to use the PLT when calling into shared libraries; only has effect for PIC code on systems with ELF binaries - (default: PLT is disabled if full relro is enabled)"), + (default: PLT is disabled if full relro is enabled on x86_64)"), polonius: bool = (false, parse_bool, [TRACKED], "enable polonius-based borrow-checker (default: no)"), polymorphize: bool = (false, parse_bool, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 5feea83edb6a3..fc54af73eabf0 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1013,7 +1013,7 @@ impl Session { pub fn needs_plt(&self) -> bool { // Check if the current target usually needs PLT to be enabled. // The user can use the command line flag to override it. - let needs_plt = self.target.needs_plt; + let needs_plt = self.target.arch != "x86_64"; let dbg_opts = &self.opts.unstable_opts; From 34d0cffcdf49f336a6b20da5a786c6d9eda950ea Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Wed, 7 Jun 2023 20:18:20 -0400 Subject: [PATCH 416/465] switch to using a target property to control plt default --- compiler/rustc_session/src/session.rs | 10 +++++----- compiler/rustc_target/src/spec/mod.rs | 8 ++++---- .../src/spec/x86_64_fortanix_unknown_sgx.rs | 1 + compiler/rustc_target/src/spec/x86_64_linux_android.rs | 1 + compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs | 1 + compiler/rustc_target/src/spec/x86_64_pc_solaris.rs | 1 + .../rustc_target/src/spec/x86_64_pc_windows_gnu.rs | 1 + .../rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs | 1 + .../rustc_target/src/spec/x86_64_pc_windows_msvc.rs | 1 + compiler/rustc_target/src/spec/x86_64_sun_solaris.rs | 1 + .../rustc_target/src/spec/x86_64_unknown_dragonfly.rs | 1 + .../rustc_target/src/spec/x86_64_unknown_freebsd.rs | 1 + .../rustc_target/src/spec/x86_64_unknown_fuchsia.rs | 1 + compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs | 1 + .../rustc_target/src/spec/x86_64_unknown_hermit.rs | 1 + .../rustc_target/src/spec/x86_64_unknown_illumos.rs | 1 + .../src/spec/x86_64_unknown_l4re_uclibc.rs | 1 + .../rustc_target/src/spec/x86_64_unknown_linux_gnu.rs | 1 + .../src/spec/x86_64_unknown_linux_gnux32.rs | 2 +- .../rustc_target/src/spec/x86_64_unknown_linux_musl.rs | 1 + .../rustc_target/src/spec/x86_64_unknown_netbsd.rs | 1 + compiler/rustc_target/src/spec/x86_64_unknown_none.rs | 1 + .../rustc_target/src/spec/x86_64_unknown_openbsd.rs | 1 + compiler/rustc_target/src/spec/x86_64_unknown_redox.rs | 1 + compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs | 1 + .../rustc_target/src/spec/x86_64_uwp_windows_gnu.rs | 1 + .../rustc_target/src/spec/x86_64_uwp_windows_msvc.rs | 1 + compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs | 1 + 28 files changed, 35 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index fc54af73eabf0..ea5beb6f8bebf 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1009,11 +1009,11 @@ impl Session { self.edition().rust_2024() } - /// Returns `true` if we cannot skip the PLT for shared library calls. + /// Returns `true` if we should use the PLT for shared library calls. pub fn needs_plt(&self) -> bool { - // Check if the current target usually needs PLT to be enabled. + // Check if the current target usually wants PLT to be enabled. // The user can use the command line flag to override it. - let needs_plt = self.target.arch != "x86_64"; + let want_plt = self.target.plt_by_default; let dbg_opts = &self.opts.unstable_opts; @@ -1025,8 +1025,8 @@ impl Session { let full_relro = RelroLevel::Full == relro_level; // If user didn't explicitly forced us to use / skip the PLT, - // then try to skip it where possible. - dbg_opts.plt.unwrap_or(needs_plt || !full_relro) + // then use it unless the target doesn't want it by default or the full relro forces it on. + dbg_opts.plt.unwrap_or(want_plt || !full_relro) } /// Checks if LLVM lifetime markers should be emitted. diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 0f26b703536a8..c15a330ee7465 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1670,7 +1670,7 @@ pub struct TargetOptions { pub static_position_independent_executables: bool, /// Determines if the target always requires using the PLT for indirect /// library calls or not. This controls the default value of the `-Z plt` flag. - pub needs_plt: bool, + pub plt_by_default: bool, /// Either partial, full, or off. Full RELRO makes the dynamic linker /// resolve all symbols at startup and marks the GOT read-only before /// starting the program, preventing overwriting the GOT. @@ -1992,7 +1992,7 @@ impl Default for TargetOptions { no_default_libraries: true, position_independent_executables: false, static_position_independent_executables: false, - needs_plt: false, + plt_by_default: true, relro_level: RelroLevel::None, pre_link_objects: Default::default(), post_link_objects: Default::default(), @@ -2665,7 +2665,7 @@ impl Target { key!(no_default_libraries, bool); key!(position_independent_executables, bool); key!(static_position_independent_executables, bool); - key!(needs_plt, bool); + key!(plt_by_default, bool); key!(relro_level, RelroLevel)?; key!(archive_format); key!(allow_asm, bool); @@ -2921,7 +2921,7 @@ impl ToJson for Target { target_option_val!(no_default_libraries); target_option_val!(position_independent_executables); target_option_val!(static_position_independent_executables); - target_option_val!(needs_plt); + target_option_val!(plt_by_default); target_option_val!(relro_level); target_option_val!(archive_format); target_option_val!(allow_asm); diff --git a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs index cba6fda19dc3e..a7ed74f47212f 100644 --- a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs +++ b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs @@ -63,6 +63,7 @@ pub fn target() -> Target { linker: Some("rust-lld".into()), max_atomic_width: Some(64), cpu: "x86-64".into(), + plt_by_default: false, features: "+rdrnd,+rdseed,+lvi-cfi,+lvi-load-hardening".into(), llvm_args: cvs!["--x86-experimental-lvi-inline-asm-hardening"], position_independent_executables: true, diff --git a/compiler/rustc_target/src/spec/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/x86_64_linux_android.rs index a3bdb5f5465b0..c110674fd870f 100644 --- a/compiler/rustc_target/src/spec/x86_64_linux_android.rs +++ b/compiler/rustc_target/src/spec/x86_64_linux_android.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, T pub fn target() -> Target { let mut base = super::android_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; // https://developer.android.com/ndk/guides/abis.html#86-64 base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".into(); base.max_atomic_width = Some(64); diff --git a/compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs b/compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs index 6fb2dfd807a0f..8424757df076c 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs @@ -10,6 +10,7 @@ pub fn target() -> Target { arch: "x86_64".into(), options: TargetOptions { cpu: "x86-64".into(), + plt_by_default: false, max_atomic_width: Some(64), pre_link_args: TargetOptions::link_args( LinkerFlavor::Gnu(Cc::Yes, Lld::No), diff --git a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs index d2906d6c4ae99..e2c59d2938e69 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs @@ -4,6 +4,7 @@ pub fn target() -> Target { let mut base = super::solaris_base::opts(); base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-m64"]); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.vendor = "pc".into(); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs index 37feaa9dbbf84..1b8885c34da78 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, Target}; pub fn target() -> Target { let mut base = super::windows_gnu_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; // Use high-entropy 64 bit address space for ASLR base.add_pre_link_args( LinkerFlavor::Gnu(Cc::No, Lld::No), diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs index 039bc2bd2bb84..8f5e398a0be91 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, Target}; pub fn target() -> Target { let mut base = super::windows_gnullvm_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.linker = Some("x86_64-w64-mingw32-clang".into()); diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs index 081806aa69819..6b897ca7070e3 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs @@ -3,6 +3,7 @@ use crate::spec::Target; pub fn target() -> Target { let mut base = super::windows_msvc_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs index 0f31ea86b3f16..650065f6330a0 100644 --- a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs +++ b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs @@ -4,6 +4,7 @@ pub fn target() -> Target { let mut base = super::solaris_base::opts(); base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-m64"]); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.vendor = "sun".into(); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs index 67ce3768db0c8..3b8e75977b5ac 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::dragonfly_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs index b41e5842aad13..b2d91d09996ff 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::freebsd_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_unknown_fuchsia.rs index a3231d19f4c72..bee9354196028 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_fuchsia.rs @@ -3,6 +3,7 @@ use crate::spec::{SanitizerSet, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::fuchsia_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::X86; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs index 9a7a3b501cfdc..16ed3150e6e2e 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::haiku_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs index fb1af33f80a86..74ef2527c36ca 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs @@ -3,6 +3,7 @@ use crate::spec::{StackProbeType, Target}; pub fn target() -> Target { let mut base = super::hermit_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.features = "+rdrnd,+rdseed".into(); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs index ca5b62e279c1c..9259cfe5f0ed6 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs @@ -4,6 +4,7 @@ pub fn target() -> Target { let mut base = super::illumos_base::opts(); base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-m64", "-std=c99"]); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs index 26da7e800114a..912d289c47f9f 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs @@ -3,6 +3,7 @@ use crate::spec::{PanicStrategy, Target}; pub fn target() -> Target { let mut base = super::l4re_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.panic_strategy = PanicStrategy::Abort; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs index deb15c02c6839..2f970f87cc642 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs index 626d5b480c632..5469d02c59239 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { base.has_thread_local = false; // BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI // breaks code gen. See LLVM bug 36743 - base.needs_plt = true; + base.plt_by_default = true; Target { llvm_target: "x86_64-unknown-linux-gnux32".into(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs index bf4cf7d7becad..7154f5fa3068f 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs index 74c434935ba88..2e7bf34f7d2f6 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, T pub fn target() -> Target { let mut base = super::netbsd_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_none.rs b/compiler/rustc_target/src/spec/x86_64_unknown_none.rs index 43c5ce78ce34e..fe3b24f2d4afa 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_none.rs @@ -10,6 +10,7 @@ use super::{RelroLevel, SanitizerSet, StackProbeType, Target, TargetOptions}; pub fn target() -> Target { let opts = TargetOptions { cpu: "x86-64".into(), + plt_by_default: false, max_atomic_width: Some(64), stack_probes: StackProbeType::X86, position_independent_executables: true, diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs index 8e4d42a0acaf3..86fa9bf7ed2a3 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::openbsd_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs index b47f15cf57897..decc973678227 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::redox_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs index a7ae17839da8c..67664a74710a3 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs @@ -10,6 +10,7 @@ use crate::spec::Target; pub fn target() -> Target { let mut base = super::uefi_msvc_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); // We disable MMX and SSE for now, even though UEFI allows using them. Problem is, you have to diff --git a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs index c3eaa6939bb13..1a9d2a57182d5 100644 --- a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, Target}; pub fn target() -> Target { let mut base = super::windows_uwp_gnu_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; // Use high-entropy 64 bit address space for ASLR base.add_pre_link_args( LinkerFlavor::Gnu(Cc::No, Lld::No), diff --git a/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs index b2769350bf66d..1ae403fa83f31 100644 --- a/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs @@ -3,6 +3,7 @@ use crate::spec::Target; pub fn target() -> Target { let mut base = super::windows_uwp_msvc_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs index 365ade6bcf9c0..a7c4aaecf9109 100644 --- a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs @@ -3,6 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::vxworks_base::opts(); base.cpu = "x86-64".into(); + base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; From 46a650f4e0783da10513e6d41c5f3c69e42b0198 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 19 Jun 2023 20:46:46 +0000 Subject: [PATCH 417/465] Migrate item_bounds to ty::Clause --- .../src/diagnostics/conflict_errors.rs | 2 +- compiler/rustc_hir_analysis/src/check/mod.rs | 4 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 4 +- .../src/collect/item_bounds.rs | 34 ++++------ .../rustc_hir_analysis/src/variance/mod.rs | 13 ++-- compiler/rustc_hir_typeck/src/_match.rs | 16 ++--- compiler/rustc_hir_typeck/src/closure.rs | 9 ++- .../src/generator_interior/mod.rs | 2 +- .../src/infer/error_reporting/mod.rs | 6 +- .../rustc_infer/src/infer/opaque_types.rs | 4 +- .../rustc_infer/src/infer/outlives/verify.rs | 2 +- compiler/rustc_infer/src/traits/util.rs | 20 ++++++ .../src/opaque_hidden_inferred_bound.rs | 4 +- compiler/rustc_lint/src/unused.rs | 5 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 10 ++- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 4 +- .../rustc_middle/src/query/on_disk_cache.rs | 7 ++ compiler/rustc_middle/src/ty/codec.rs | 21 ++++++ compiler/rustc_middle/src/ty/context.rs | 29 ++++++-- compiler/rustc_middle/src/ty/mod.rs | 27 +++++++- compiler/rustc_middle/src/ty/parameterized.rs | 1 + compiler/rustc_middle/src/ty/print/pretty.rs | 6 +- .../rustc_middle/src/ty/structural_impls.rs | 9 +++ compiler/rustc_mir_transform/src/generator.rs | 2 +- compiler/rustc_privacy/src/lib.rs | 68 ++++++++----------- .../src/solve/assembly/mod.rs | 10 ++- .../src/solve/assembly/structural_traits.rs | 6 +- .../src/traits/error_reporting/suggestions.rs | 2 +- .../src/traits/object_safety.rs | 2 +- .../src/traits/project.rs | 2 +- .../src/traits/select/confirmation.rs | 4 +- .../src/traits/select/mod.rs | 4 +- compiler/rustc_traits/src/chalk/db.rs | 6 +- src/librustdoc/clean/mod.rs | 21 +++--- .../clippy_lints/src/future_not_send.rs | 2 +- src/tools/clippy/clippy_utils/src/ty.rs | 14 ++-- 37 files changed, 232 insertions(+), 152 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 7119510849a31..5c365e98f0bab 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -705,7 +705,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx .explicit_item_bounds(def_id) .subst_iter_copied(tcx, substs) - .find_map(find_fn_kind_from_did), + .find_map(|(clause, span)| find_fn_kind_from_did((clause.as_predicate(), span))), ty::Closure(_, substs) => match substs.as_closure().kind() { ty::ClosureKind::Fn => Some(hir::Mutability::Not), ty::ClosureKind::FnMut => Some(hir::Mutability::Mut), diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 1dfe053b21530..596c5518086d6 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -409,9 +409,7 @@ fn fn_sig_suggestion<'tcx>( output = if let ty::Alias(_, alias_ty) = *output.kind() { tcx.explicit_item_bounds(alias_ty.def_id) .subst_iter_copied(tcx, alias_ty.substs) - .find_map(|(bound, _)| { - bound.to_opt_poly_projection_pred()?.no_bound_vars()?.term.ty() - }) + .find_map(|(bound, _)| bound.as_projection_clause()?.no_bound_vars()?.term.ty()) .unwrap_or_else(|| { span_bug!( ident.span, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 51e9b4c4501d8..814a290178ebc 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1086,7 +1086,7 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt wfcx.infcx, wfcx.param_env, wfcx.body_def_id, - normalized_bound, + normalized_bound.as_predicate(), bound_span, ) }); @@ -1562,7 +1562,7 @@ impl<'tcx> TypeVisitor> for ImplTraitInTraitFinder<'_, 'tcx> { self.wfcx.infcx, self.wfcx.param_env, self.wfcx.body_def_id, - bound, + bound.as_predicate(), bound_span, )); // Set the debruijn index back to innermost here, since we already eagerly diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 5f35678d95d93..e976304828895 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -19,7 +19,7 @@ fn associated_type_bounds<'tcx>( assoc_item_def_id: LocalDefId, ast_bounds: &'tcx [hir::GenericBound<'tcx>], span: Span, -) -> &'tcx [(ty::Predicate<'tcx>, Span)] { +) -> &'tcx [(ty::Clause<'tcx>, Span)] { let item_ty = tcx.mk_projection( assoc_item_def_id.to_def_id(), InternalSubsts::identity_for_item(tcx, assoc_item_def_id), @@ -33,8 +33,11 @@ fn associated_type_bounds<'tcx>( let trait_def_id = tcx.local_parent(assoc_item_def_id); let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); - let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| { - match pred.kind().skip_binder() { + let bounds_from_parent = trait_predicates + .predicates + .iter() + .copied() + .filter(|(pred, _)| match pred.kind().skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr)) => tr.self_ty() == item_ty, ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) => { proj.projection_ty.self_ty() == item_ty @@ -43,15 +46,10 @@ fn associated_type_bounds<'tcx>( outlives.0 == item_ty } _ => false, - } - }); + }) + .map(|(pred, span)| (pred.as_clause().unwrap(), span)); - let all_bounds = tcx.arena.alloc_from_iter( - bounds - .clauses() - .map(|(clause, span)| (clause.as_predicate(), span)) - .chain(bounds_from_parent), - ); + let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent)); debug!( "associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id.to_def_id()), @@ -71,7 +69,7 @@ fn opaque_type_bounds<'tcx>( ast_bounds: &'tcx [hir::GenericBound<'tcx>], item_ty: Ty<'tcx>, span: Span, -) -> &'tcx [(ty::Predicate<'tcx>, Span)] { +) -> &'tcx [(ty::Clause<'tcx>, Span)] { ty::print::with_no_queries!({ let icx = ItemCtxt::new(tcx, opaque_def_id); let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, OnlySelfBounds(false)); @@ -79,15 +77,14 @@ fn opaque_type_bounds<'tcx>( icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span); debug!(?bounds); - tcx.arena - .alloc_from_iter(bounds.clauses().map(|(clause, span)| (clause.as_predicate(), span))) + tcx.arena.alloc_from_iter(bounds.clauses()) }) } pub(super) fn explicit_item_bounds( tcx: TyCtxt<'_>, def_id: LocalDefId, -) -> ty::EarlyBinder<&'_ [(ty::Predicate<'_>, Span)]> { +) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> { match tcx.opt_rpitit_info(def_id.to_def_id()) { // RPITIT's bounds are the same as opaque type bounds, but with // a projection self type. @@ -139,11 +136,8 @@ pub(super) fn explicit_item_bounds( pub(super) fn item_bounds( tcx: TyCtxt<'_>, def_id: DefId, -) -> ty::EarlyBinder<&'_ ty::List>> { +) -> ty::EarlyBinder<&'_ ty::List>> { tcx.explicit_item_bounds(def_id).map_bound(|bounds| { - tcx.mk_predicates_from_iter(util::elaborate( - tcx, - bounds.iter().map(|&(bound, _span)| bound), - )) + tcx.mk_clauses_from_iter(util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound))) }) } diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 8bb9ca2acf24a..23d8da88a454b 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -162,28 +162,25 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc // which thus mentions `'a` and should thus accept hidden types that borrow 'a // instead of requiring an additional `+ 'a`. match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { + ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref: ty::TraitRef { def_id: _, substs, .. }, constness: _, polarity: _, - })) => { + }) => { for subst in &substs[1..] { subst.visit_with(&mut collector); } } - ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate { + ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty: ty::AliasTy { substs, .. }, term, - })) => { + }) => { for subst in &substs[1..] { subst.visit_with(&mut collector); } term.visit_with(&mut collector); } - ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( - _, - region, - ))) => { + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(_, region)) => { region.visit_with(&mut collector); } _ => { diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index a07580fe72d4a..c7fa27da1acfe 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -536,33 +536,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } for ty in [first_ty, second_ty] { - for (pred, _) in self + for (clause, _) in self .tcx .explicit_item_bounds(rpit_def_id) .subst_iter_copied(self.tcx, substs) { - let pred = pred.kind().rebind(match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => { + let pred = clause.kind().rebind(match clause.kind().skip_binder() { + ty::ClauseKind::Trait(trait_pred) => { // FIXME(rpitit): This will need to be fixed when we move to associated types assert!(matches!( *trait_pred.trait_ref.self_ty().kind(), ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. }) if def_id == rpit_def_id && substs == alias_substs )); - ty::PredicateKind::Clause(ty::ClauseKind::Trait( - trait_pred.with_self_ty(self.tcx, ty), - )) + ty::ClauseKind::Trait(trait_pred.with_self_ty(self.tcx, ty)) } - ty::PredicateKind::Clause(ty::ClauseKind::Projection( - mut proj_pred, - )) => { + ty::ClauseKind::Projection(mut proj_pred) => { assert!(matches!( *proj_pred.projection_ty.self_ty().kind(), ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. }) if def_id == rpit_def_id && substs == alias_substs )); proj_pred = proj_pred.with_self_ty(self.tcx, ty); - ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj_pred)) + ty::ClauseKind::Projection(proj_pred) } _ => continue, }); diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 94b37fb3450d0..c64b64e925a45 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -174,7 +174,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self .deduce_closure_signature_from_predicates( expected_ty, - self.tcx.explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs), + self.tcx + .explicit_item_bounds(def_id) + .subst_iter_copied(self.tcx, substs) + .map(|(c, s)| (c.as_predicate(), s)), ), ty::Dynamic(ref object_type, ..) => { let sig = object_type.projection_bounds().find_map(|pb| { @@ -717,13 +720,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .tcx .explicit_item_bounds(def_id) .subst_iter_copied(self.tcx, substs) - .find_map(|(p, s)| get_future_output(p, s))?, + .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?, ty::Error(_) => return None, ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => self .tcx .explicit_item_bounds(proj.def_id) .subst_iter_copied(self.tcx, proj.substs) - .find_map(|(p, s)| get_future_output(p, s))?, + .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?, _ => span_bug!( self.tcx.def_span(expr_def_id), "async fn generator return type not an inference variable: {ret_ty}" diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index dabe7749cb610..fdbb153ec7d44 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -577,7 +577,7 @@ fn check_must_not_suspend_ty<'tcx>( let mut has_emitted = false; for &(predicate, _) in fcx.tcx.explicit_item_bounds(def).skip_binder() { // We only look at the `DefId`, so it is safe to skip the binder here. - if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ref poly_trait_predicate)) = + if let ty::ClauseKind::Trait(ref poly_trait_predicate) = predicate.kind().skip_binder() { let def_id = poly_trait_predicate.trait_ref.def_id; diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 63370eec10b29..15213c4b0239a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -408,9 +408,9 @@ impl<'tcx> InferCtxt<'tcx> { predicate .kind() .map_bound(|kind| match kind { - ty::PredicateKind::Clause(ty::ClauseKind::Projection( - projection_predicate, - )) if projection_predicate.projection_ty.def_id == item_def_id => { + ty::ClauseKind::Projection(projection_predicate) + if projection_predicate.projection_ty.def_id == item_def_id => + { projection_predicate.term.ty() } _ => None, diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 3cb1788dc194a..0390c868c1b84 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -649,9 +649,7 @@ impl<'tcx> InferCtxt<'tcx> { ct_op: |ct| ct, }); - if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection)) = - predicate.kind().skip_binder() - { + if let ty::ClauseKind::Projection(projection) = predicate.kind().skip_binder() { if projection.term.references_error() { // No point on adding any obligations since there's a type error involved. obligations.clear(); diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 59ae2ce6c603e..871171f9447fd 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -296,7 +296,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { trace!("{:#?}", bounds.skip_binder()); bounds .subst_iter(tcx, alias_ty.substs) - .filter_map(|p| p.to_opt_type_outlives()) + .filter_map(|p| p.as_type_outlives_clause()) .filter_map(|p| p.no_bound_vars()) .map(|OutlivesPredicate(_, r)| r) } diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 00d4934b74962..a6475a766c459 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -167,6 +167,26 @@ impl<'tcx> Elaboratable<'tcx> for (ty::Predicate<'tcx>, Span) { } } +impl<'tcx> Elaboratable<'tcx> for (ty::Clause<'tcx>, Span) { + fn predicate(&self) -> ty::Predicate<'tcx> { + self.0.as_predicate() + } + + fn child(&self, predicate: ty::Predicate<'tcx>) -> Self { + (predicate.as_clause().unwrap(), self.1) + } + + fn child_with_derived_cause( + &self, + predicate: ty::Predicate<'tcx>, + _span: Span, + _parent_trait_pred: ty::PolyTraitPredicate<'tcx>, + _index: usize, + ) -> Self { + (predicate.as_clause().unwrap(), self.1) + } +} + impl<'tcx> Elaboratable<'tcx> for ty::Clause<'tcx> { fn predicate(&self) -> ty::Predicate<'tcx> { self.as_predicate() diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 61c23b4c255e2..63a56806a4578 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { // Liberate bound regions in the predicate since we // don't actually care about lifetimes in this check. let predicate = cx.tcx.liberate_late_bound_regions(def_id, pred.kind()); - let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = predicate else { + let ty::ClauseKind::Projection(proj) = predicate else { continue; }; // Only check types, since those are the only things that may @@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) { ( ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), - ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)), + ty::ClauseKind::Trait(trait_pred), ) => Some(AddBound { suggest_span: cx.tcx.def_span(*def_id).shrink_to_hi(), trait_ref: trait_pred.print_modifiers_and_trait_path(), diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index e0033c48edbf1..5015b751eeed4 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -289,9 +289,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { .filter_only_self() .find_map(|(pred, _span)| { // We only look at the `DefId`, so it is safe to skip the binder here. - if let ty::PredicateKind::Clause(ty::ClauseKind::Trait( - ref poly_trait_predicate, - )) = pred.kind().skip_binder() + if let ty::ClauseKind::Trait(ref poly_trait_predicate) = + pred.kind().skip_binder() { let def_id = poly_trait_predicate.trait_ref.def_id; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 21cbab542933c..90014bd92671d 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -25,7 +25,7 @@ use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::GeneratorDiagnosticData; -use rustc_middle::ty::{self, ParameterizedOverTcx, Predicate, Ty, TyCtxt, Visibility}; +use rustc_middle::ty::{self, ParameterizedOverTcx, Ty, TyCtxt, Visibility}; use rustc_serialize::opaque::MemDecoder; use rustc_serialize::{Decodable, Decoder}; use rustc_session::cstore::{ @@ -642,6 +642,12 @@ impl<'a, 'tcx> Decodable> for &'tcx [(ty::Predicate<'tcx } } +impl<'a, 'tcx> Decodable> for &'tcx [(ty::Clause<'tcx>, Span)] { + fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self { + ty::codec::RefDecodable::decode(d) + } +} + impl<'a, 'tcx, T> Decodable> for LazyValue { fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self { decoder.read_lazy() @@ -854,7 +860,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self, index: DefIndex, tcx: TyCtxt<'tcx>, - ) -> ty::EarlyBinder<&'tcx [(Predicate<'tcx>, Span)]> { + ) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> { let lazy = self.root.tables.explicit_item_bounds.get(self, index); let output = if lazy.is_default() { &mut [] diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index d11308196eafd..059cc0a36898a 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -375,7 +375,7 @@ define_tables! { is_type_alias_impl_trait: Table, attr_flags: Table, def_path_hashes: Table, - explicit_item_bounds: Table, Span)>>, + explicit_item_bounds: Table, Span)>>, inferred_outlives_of: Table, Span)>>, inherent_impls: Table>, associated_types_for_impl_traits_in_associated_fn: Table>, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 440dede170049..6338e1719f475 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -346,7 +346,7 @@ rustc_queries! { /// `key` is the `DefId` of the associated type or opaque type. /// /// Bounds from the parent (e.g. with nested impl trait) are not included. - query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Predicate<'tcx>, Span)]> { + query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> { desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern @@ -373,7 +373,7 @@ rustc_queries! { /// ``` /// /// Bounds from the parent (e.g. with nested impl trait) are not included. - query item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx ty::List>> { + query item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx ty::List>> { desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) } } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 105667ba1e6c0..a0fffce7071e3 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -798,6 +798,13 @@ impl<'a, 'tcx> Decodable> for &'tcx [(ty::Predicate<'tcx> } } +impl<'a, 'tcx> Decodable> for &'tcx [(ty::Clause<'tcx>, Span)] { + #[inline] + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { + RefDecodable::decode(d) + } +} + impl<'a, 'tcx> Decodable> for &'tcx [(ty::ClauseKind<'tcx>, Span)] { #[inline] fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index ff8cd904ef86b..d252a3fda5422 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -128,6 +128,12 @@ impl<'tcx, E: TyEncoder>> Encodable for ty::Predicate<'tcx> } } +impl<'tcx, E: TyEncoder>> Encodable for ty::Clause<'tcx> { + fn encode(&self, e: &mut E) { + self.as_predicate().encode(e); + } +} + impl<'tcx, E: TyEncoder>> Encodable for ty::Region<'tcx> { fn encode(&self, e: &mut E) { self.kind().encode(e); @@ -241,6 +247,13 @@ impl<'tcx, D: TyDecoder>> Decodable for ty::Predicate<'tcx> } } +impl<'tcx, D: TyDecoder>> Decodable for ty::Clause<'tcx> { + fn decode(decoder: &mut D) -> ty::Clause<'tcx> { + let pred: ty::Predicate<'tcx> = Decodable::decode(decoder); + pred.as_clause().unwrap() + } +} + impl<'tcx, D: TyDecoder>> Decodable for SubstsRef<'tcx> { fn decode(decoder: &mut D) -> Self { let len = decoder.read_usize(); @@ -365,6 +378,14 @@ impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> } } +impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for [(ty::Clause<'tcx>, Span)] { + fn decode(decoder: &mut D) -> &'tcx Self { + decoder.interner().arena.alloc_from_iter( + (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::>(), + ) + } +} + impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for [(ty::ClauseKind<'tcx>, Span)] { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 2b4f69167bfb0..b2ada4882e1a6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -25,10 +25,10 @@ use crate::traits::solve::{ ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData, }; use crate::ty::{ - self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, FloatTy, FloatVar, FloatVid, - GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, - PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, ReprOptions, - TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy, Visibility, + self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Const, ConstData, FloatTy, FloatVar, + FloatVid, GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, + ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, + ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy, Visibility, }; use crate::ty::{GenericArg, InternalSubsts, SubstsRef}; use rustc_ast::{self as ast, attr}; @@ -141,7 +141,9 @@ pub struct CtxtInterners<'tcx> { region: InternedSet<'tcx, RegionKind<'tcx>>, poly_existential_predicates: InternedSet<'tcx, List>>, predicate: InternedSet<'tcx, WithCachedTypeInfo>>>, + // FIXME(clause): remove this when all usages are moved to predicate predicates: InternedSet<'tcx, List>>, + clauses: InternedSet<'tcx, List>>, projs: InternedSet<'tcx, List>, place_elems: InternedSet<'tcx, List>>, const_: InternedSet<'tcx, ConstData<'tcx>>, @@ -167,6 +169,7 @@ impl<'tcx> CtxtInterners<'tcx> { canonical_var_infos: Default::default(), predicate: Default::default(), predicates: Default::default(), + clauses: Default::default(), projs: Default::default(), place_elems: Default::default(), const_: Default::default(), @@ -1533,6 +1536,7 @@ slice_interners!( canonical_var_infos: pub mk_canonical_var_infos(CanonicalVarInfo<'tcx>), poly_existential_predicates: intern_poly_existential_predicates(PolyExistentialPredicate<'tcx>), predicates: intern_predicates(Predicate<'tcx>), + clauses: intern_clauses(Clause<'tcx>), projs: pub mk_projs(ProjectionKind), place_elems: pub mk_place_elems(PlaceElem<'tcx>), bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind), @@ -1564,7 +1568,7 @@ impl<'tcx> TyCtxt<'tcx> { let future_trait = self.require_lang_item(LangItem::Future, None); self.explicit_item_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| { - let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder() else { + let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() else { return false; }; trait_predicate.trait_ref.def_id == future_trait @@ -2084,6 +2088,13 @@ impl<'tcx> TyCtxt<'tcx> { self.intern_predicates(preds) } + pub fn mk_clauses(self, preds: &[Clause<'tcx>]) -> &'tcx List> { + // FIXME consider asking the input slice to be sorted to avoid + // re-interning permutations, in which case that would be asserted + // here. + self.intern_clauses(preds) + } + pub fn mk_const_list_from_iter(self, iter: I) -> T::Output where I: Iterator, @@ -2135,6 +2146,14 @@ impl<'tcx> TyCtxt<'tcx> { T::collect_and_apply(iter, |xs| self.mk_predicates(xs)) } + pub fn mk_clauses_from_iter(self, iter: I) -> T::Output + where + I: Iterator, + T: CollectAndApply, &'tcx List>>, + { + T::collect_and_apply(iter, |xs| self.mk_clauses(xs)) + } + pub fn mk_type_list_from_iter(self, iter: I) -> T::Output where I: Iterator, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index cd4591308278b..84ad96084c486 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -602,6 +602,24 @@ impl<'tcx> Clause<'tcx> { None } } + + pub fn as_type_outlives_clause(self) -> Option>> { + let clause = self.kind(); + if let ty::ClauseKind::TypeOutlives(o) = clause.skip_binder() { + Some(clause.rebind(o)) + } else { + None + } + } + + pub fn as_region_outlives_clause(self) -> Option>> { + let clause = self.kind(); + if let ty::ClauseKind::RegionOutlives(o) = clause.skip_binder() { + Some(clause.rebind(o)) + } else { + None + } + } } #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] @@ -1243,7 +1261,14 @@ impl<'tcx> ToPredicate<'tcx> for ClauseKind<'tcx> { impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, ClauseKind<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - tcx.mk_predicate(self.map_bound(|clause| ty::PredicateKind::Clause(clause))) + tcx.mk_predicate(self.map_bound(ty::PredicateKind::Clause)) + } +} + +impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> { + #[inline(always)] + fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + self.as_predicate() } } diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 97d13822adccf..cc2b26a5e1457 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -128,6 +128,7 @@ parameterized_over_tcx! { ty::TraitRef, ty::Const, ty::Predicate, + ty::Clause, ty::ClauseKind, ty::GeneratorDiagnosticData, } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index fdcc608bf8ed7..7afda73862d23 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -928,7 +928,7 @@ pub trait PrettyPrinter<'tcx>: let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { + ty::ClauseKind::Trait(pred) => { let trait_ref = bound_predicate.rebind(pred.trait_ref); // Don't print + Sized, but rather + ?Sized if absent. @@ -939,7 +939,7 @@ pub trait PrettyPrinter<'tcx>: self.insert_trait_and_projection(trait_ref, None, &mut traits, &mut fn_traits); } - ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { + ty::ClauseKind::Projection(pred) => { let proj_ref = bound_predicate.rebind(pred); let trait_ref = proj_ref.required_poly_trait_ref(tcx); @@ -953,7 +953,7 @@ pub trait PrettyPrinter<'tcx>: &mut fn_traits, ); } - ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => { + ty::ClauseKind::TypeOutlives(outlives) => { lifetimes.push(outlives.1); } _ => {} diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index e53e1e0a54c52..2817d7256de84 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -713,6 +713,15 @@ impl<'tcx> TypeFoldable> for &'tcx ty::List> { } } +impl<'tcx> TypeFoldable> for &'tcx ty::List> { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + ty::util::fold_list(self, folder, |tcx, v| tcx.mk_clauses(v)) + } +} + impl<'tcx> TypeFoldable> for ty::Const<'tcx> { fn try_fold_with>>( self, diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 9f58cce276906..029fb2e9ba04c 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1824,7 +1824,7 @@ fn check_must_not_suspend_ty<'tcx>( let mut has_emitted = false; for &(predicate, _) in tcx.explicit_item_bounds(def).skip_binder() { // We only look at the `DefId`, so it is safe to skip the binder here. - if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ref poly_trait_predicate)) = + if let ty::ClauseKind::Trait(ref poly_trait_predicate) = predicate.kind().skip_binder() { let def_id = poly_trait_predicate.trait_ref.def_id; diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index b897a6198e366..8a848e5db6295 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -114,6 +114,12 @@ trait DefIdVisitor<'tcx> { ) -> ControlFlow { self.skeleton().visit_predicates(predicates) } + fn visit_clauses( + &mut self, + predicates: &[(ty::Clause<'tcx>, Span)], + ) -> ControlFlow { + self.skeleton().visit_clauses(predicates) + } } struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> { @@ -159,42 +165,23 @@ where } } - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { - match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { - trait_ref, - constness: _, - polarity: _, - })) => self.visit_trait(trait_ref), - ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate { - projection_ty, - term, - })) => { + fn visit_clause(&mut self, clause: ty::Clause<'tcx>) -> ControlFlow { + match clause.kind().skip_binder() { + ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity: _ }) => { + self.visit_trait(trait_ref) + } + ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => { term.visit_with(self)?; self.visit_projection_ty(projection_ty) } - ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( - ty, - _region, - ))) => ty.visit_with(self), - ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) => { - ControlFlow::Continue(()) - } - ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => ty.visit_with(self), + ty::ClauseKind::RegionOutlives(..) => ControlFlow::Continue(()), + ty::ClauseKind::ConstArgHasType(ct, ty) => { ct.visit_with(self)?; ty.visit_with(self) } - ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => ct.visit_with(self), - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => arg.visit_with(self), - - ty::PredicateKind::ObjectSafe(_) - | ty::PredicateKind::ClosureKind(_, _, _) - | ty::PredicateKind::Subtype(_) - | ty::PredicateKind::Coerce(_) - | ty::PredicateKind::ConstEquate(_, _) - | ty::PredicateKind::TypeWellFormedFromEnv(_) - | ty::PredicateKind::Ambiguous - | ty::PredicateKind::AliasRelate(..) => bug!("unexpected predicate: {:?}", predicate), + ty::ClauseKind::ConstEvaluatable(ct) => ct.visit_with(self), + ty::ClauseKind::WellFormed(arg) => arg.visit_with(self), } } @@ -203,7 +190,16 @@ where predicates: ty::GenericPredicates<'tcx>, ) -> ControlFlow { let ty::GenericPredicates { parent: _, predicates } = predicates; - predicates.iter().try_for_each(|&(predicate, _span)| self.visit_predicate(predicate)) + predicates.iter().try_for_each(|&(predicate, _span)| { + let clause = predicate + .as_clause() + .unwrap_or_else(|| bug!("unexpected predicate: {:?}", predicate)); + self.visit_clause(clause) + }) + } + + fn visit_clauses(&mut self, clauses: &[(ty::Clause<'tcx>, Span)]) -> ControlFlow { + clauses.iter().try_for_each(|&(clause, _span)| self.visit_clause(clause)) } } @@ -307,10 +303,7 @@ where // through the trait list (default type visitor doesn't visit those traits). // All traits in the list are considered the "primary" part of the type // and are visited by shallow visitors. - self.visit_predicates(ty::GenericPredicates { - parent: None, - predicates: tcx.explicit_item_bounds(def_id).skip_binder(), - })?; + self.visit_clauses(tcx.explicit_item_bounds(def_id).skip_binder())?; } } // These types don't have their own def-ids (but may have subcomponents @@ -1814,10 +1807,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { fn bounds(&mut self) -> &mut Self { self.in_primary_interface = false; - self.visit_predicates(ty::GenericPredicates { - parent: None, - predicates: self.tcx.explicit_item_bounds(self.item_def_id).skip_binder(), - }); + self.visit_clauses(self.tcx.explicit_item_bounds(self.item_def_id).skip_binder()); self } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index f2a39faf38368..cde8a52cdec92 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -522,13 +522,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { for assumption in self.tcx().item_bounds(alias_ty.def_id).subst(self.tcx(), alias_ty.substs) { - if let Some(clause) = assumption.as_clause() { - match G::consider_alias_bound_candidate(self, goal, clause) { - Ok(result) => { - candidates.push(Candidate { source: CandidateSource::AliasBound, result }) - } - Err(NoSolution) => (), + match G::consider_alias_bound_candidate(self, goal, assumption) { + Ok(result) => { + candidates.push(Candidate { source: CandidateSource::AliasBound, result }) } + Err(NoSolution) => (), } } } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 97b86a06c8cad..439cf788ab4f2 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -353,7 +353,11 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( // FIXME(associated_const_equality): Also add associated consts to // the requirements here. if item.kind == ty::AssocKind::Type { - requirements.extend(tcx.item_bounds(item.def_id).subst(tcx, trait_ref.substs)); + requirements.extend( + tcx.item_bounds(item.def_id) + .subst_iter(tcx, trait_ref.substs) + .map(|clause| clause.as_predicate()), + ); } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 966c4a7dcf38f..dfb122e4c8c79 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1157,7 +1157,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { self.tcx.item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| { - if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = pred.kind().skip_binder() + if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder() && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() // args tuple will always be substs[1] && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind() diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 499745473a22c..df93c4d45dc83 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -271,7 +271,7 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) .flat_map(|item| tcx.explicit_item_bounds(item.def_id).subst_identity_iter_copied()) - .filter_map(|pred_span| predicate_references_self(tcx, pred_span)) + .filter_map(|(clause, span)| predicate_references_self(tcx, (clause.as_predicate(), span))) .collect() } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 81b1ecc0d8819..2a78c5befa4da 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1585,7 +1585,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( obligation, candidate_set, ProjectionCandidate::TraitDef, - bounds.iter(), + bounds.iter().map(|clause| clause.as_predicate()), true, ); } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 3c356978d5ca8..a50af417a4436 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -170,7 +170,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let candidate_predicate = tcx.item_bounds(def_id).map_bound(|i| i[idx]).subst(tcx, substs); let candidate = candidate_predicate - .to_opt_poly_trait_pred() + .as_trait_clause() .expect("projection candidate is not a trait predicate") .map_bound(|t| t.trait_ref); let mut obligations = Vec::new(); @@ -631,7 +631,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let assoc_ty_substs = tcx.mk_substs(&substs); let bound = bound.map_bound(|b| b.kind().skip_binder()).subst(tcx, assoc_ty_substs); - tcx.mk_predicate(ty::Binder::bind_with_vars(bound, bound_vars)) + ty::Binder::bind_with_vars(bound, bound_vars).to_predicate(tcx) }; let normalized_bound = normalize_with_depth_to( self, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 0f0e3f1f16a6a..0a8b7b688e7f8 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1668,9 +1668,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .enumerate() .filter_map(|(idx, bound)| { let bound_predicate = bound.kind(); - if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = - bound_predicate.skip_binder() - { + if let ty::ClauseKind::Trait(pred) = bound_predicate.skip_binder() { let bound = bound_predicate.rebind(pred.trait_ref); if self.infcx.probe(|_| { match self.match_normalize_trait_ref( diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 38f94c3886188..7e64cbdf54a86 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -54,7 +54,9 @@ impl<'tcx> RustIrDatabase<'tcx> { .tcx .explicit_item_bounds(def_id) .subst_iter_copied(self.interner.tcx, &bound_vars) - .filter_map(|(bound, _)| LowerInto::>::lower_into(bound, self.interner)) + .filter_map(|(bound, _)| { + LowerInto::>::lower_into(bound.as_predicate(), self.interner) + }) .collect() } } @@ -520,7 +522,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t .filter_map(|bound| { LowerInto::< Option>> - >::lower_into(bound, self.interner) + >::lower_into(bound.as_predicate(), self.interner) }) .collect(); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9a815694e1b47..f86c32158e0b3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1361,8 +1361,10 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( } if let ty::TraitContainer = assoc_item.container { - let bounds = - tcx.explicit_item_bounds(assoc_item.def_id).subst_identity_iter_copied(); + let bounds = tcx + .explicit_item_bounds(assoc_item.def_id) + .subst_identity_iter_copied() + .map(|(c, s)| (c.as_predicate(), s)); let predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates; let predicates = tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied())); @@ -2117,7 +2119,7 @@ pub(crate) fn clean_middle_ty<'tcx>( fn clean_middle_opaque_bounds<'tcx>( cx: &mut DocContext<'tcx>, - bounds: Vec>, + bounds: Vec>, ) -> Type { let mut regions = vec![]; let mut has_sized = false; @@ -2126,13 +2128,8 @@ fn clean_middle_opaque_bounds<'tcx>( .filter_map(|bound| { let bound_predicate = bound.kind(); let trait_ref = match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr)) => { - bound_predicate.rebind(tr.trait_ref) - } - ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( - _ty, - reg, - ))) => { + ty::ClauseKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref), + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => { if let Some(r) = clean_middle_region(reg) { regions.push(GenericBound::Outlives(r)); } @@ -2149,9 +2146,7 @@ fn clean_middle_opaque_bounds<'tcx>( let bindings: ThinVec<_> = bounds .iter() .filter_map(|bound| { - if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = - bound.kind().skip_binder() - { + if let ty::ClauseKind::Projection(proj) = bound.kind().skip_binder() { if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() { Some(TypeBinding { assoc: projection_to_path_segment( diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index a391b76910ad6..818ebd1134de0 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { let preds = cx.tcx.explicit_item_bounds(def_id); let mut is_future = false; for (p, _span) in preds.subst_iter_copied(cx.tcx, substs) { - if let Some(trait_pred) = p.to_opt_poly_trait_pred() { + if let Some(trait_pred) = p.as_trait_clause() { if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() { is_future = true; break; diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 12f18614d713e..2b185943c59ca 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -94,7 +94,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' match predicate.kind().skip_binder() { // For `impl Trait`, it will register a predicate of `T: Trait`, so we go through // and check substitutions to find `U`. - ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => { + ty::ClauseKind::Trait(trait_predicate) => { if trait_predicate .trait_ref .substs @@ -107,7 +107,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' }, // For `impl Trait`, it will register a predicate of `::Assoc = U`, // so we check the term for `U`. - ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection_predicate)) => { + ty::ClauseKind::Projection(projection_predicate) => { if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() { if contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen) { return true; @@ -268,7 +268,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { for (predicate, _) in cx.tcx.explicit_item_bounds(def_id).skip_binder() { - if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder() { + if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() { if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) { return true; } @@ -665,7 +665,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option sig_from_bounds( cx, ty, - cx.tcx.item_bounds(def_id).subst(cx.tcx, substs), + cx.tcx.item_bounds(def_id).subst_iter(cx.tcx, substs).map(|c| c.as_predicate()), cx.tcx.opt_parent(def_id), ), ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)), @@ -698,7 +698,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option( cx: &LateContext<'tcx>, ty: Ty<'tcx>, - predicates: &'tcx [Predicate<'tcx>], + predicates: impl IntoIterator>, predicates_id: Option, ) -> Option> { let mut inputs = None; @@ -747,7 +747,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option .subst_iter_copied(cx.tcx, ty.substs) { match pred.kind().skip_binder() { - PredicateKind::Clause(ty::ClauseKind::Trait(p)) + ty::ClauseKind::Trait(p) if (lang_items.fn_trait() == Some(p.def_id()) || lang_items.fn_mut_trait() == Some(p.def_id()) || lang_items.fn_once_trait() == Some(p.def_id())) => @@ -760,7 +760,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option } inputs = Some(i); }, - PredicateKind::Clause(ty::ClauseKind::Projection(p)) + ty::ClauseKind::Projection(p) if Some(p.projection_ty.def_id) == lang_items.fn_once_output() => { if output.is_some() { From 2fa796a3c796c819b53421577d5fd2e0f6a9f920 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 19 Jun 2023 20:48:46 +0000 Subject: [PATCH 418/465] Expect clause more --- compiler/rustc_hir_analysis/src/collect/item_bounds.rs | 2 +- compiler/rustc_infer/src/traits/util.rs | 8 ++++---- compiler/rustc_middle/src/ty/codec.rs | 2 +- compiler/rustc_middle/src/ty/structural_impls.rs | 5 +---- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index e976304828895..958313fee6fb7 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -47,7 +47,7 @@ fn associated_type_bounds<'tcx>( } _ => false, }) - .map(|(pred, span)| (pred.as_clause().unwrap(), span)); + .map(|(pred, span)| (pred.expect_clause(), span)); let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent)); debug!( diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index a6475a766c459..2691987295298 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -173,7 +173,7 @@ impl<'tcx> Elaboratable<'tcx> for (ty::Clause<'tcx>, Span) { } fn child(&self, predicate: ty::Predicate<'tcx>) -> Self { - (predicate.as_clause().unwrap(), self.1) + (predicate.expect_clause(), self.1) } fn child_with_derived_cause( @@ -183,7 +183,7 @@ impl<'tcx> Elaboratable<'tcx> for (ty::Clause<'tcx>, Span) { _parent_trait_pred: ty::PolyTraitPredicate<'tcx>, _index: usize, ) -> Self { - (predicate.as_clause().unwrap(), self.1) + (predicate.expect_clause(), self.1) } } @@ -193,7 +193,7 @@ impl<'tcx> Elaboratable<'tcx> for ty::Clause<'tcx> { } fn child(&self, predicate: ty::Predicate<'tcx>) -> Self { - predicate.as_clause().unwrap() + predicate.expect_clause() } fn child_with_derived_cause( @@ -203,7 +203,7 @@ impl<'tcx> Elaboratable<'tcx> for ty::Clause<'tcx> { _parent_trait_pred: ty::PolyTraitPredicate<'tcx>, _index: usize, ) -> Self { - predicate.as_clause().unwrap() + predicate.expect_clause() } } diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index d252a3fda5422..e2771fc53e758 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -250,7 +250,7 @@ impl<'tcx, D: TyDecoder>> Decodable for ty::Predicate<'tcx> impl<'tcx, D: TyDecoder>> Decodable for ty::Clause<'tcx> { fn decode(decoder: &mut D) -> ty::Clause<'tcx> { let pred: ty::Predicate<'tcx> = Decodable::decode(decoder); - pred.as_clause().unwrap() + pred.expect_clause() } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 2817d7256de84..959bf032a83e4 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -666,10 +666,7 @@ impl<'tcx> TypeFoldable> for ty::Clause<'tcx> { self, folder: &mut F, ) -> Result { - Ok(folder - .try_fold_predicate(self.as_predicate())? - .as_clause() - .expect("no sensible folder would do this")) + Ok(folder.try_fold_predicate(self.as_predicate())?.expect_clause()) } } From 471830b3a488b203e3bfde2e58eecad826287c2d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 20 Jun 2023 03:25:40 +0000 Subject: [PATCH 419/465] migrate inferred_outlives_of to Clause --- compiler/rustc_hir_analysis/src/outlives/mod.rs | 12 +++++++----- compiler/rustc_lint/src/builtin.rs | 8 ++++---- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/query/on_disk_cache.rs | 7 ------- compiler/rustc_middle/src/ty/codec.rs | 10 ---------- compiler/rustc_middle/src/ty/mod.rs | 9 ++++++++- 7 files changed, 21 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs index 98f4a8e00ef90..48624cefe4d02 100644 --- a/compiler/rustc_hir_analysis/src/outlives/mod.rs +++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs @@ -3,7 +3,7 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_middle::query::Providers; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt}; +use rustc_middle::ty::{self, CratePredicatesMap, ToPredicate, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -17,7 +17,7 @@ pub fn provide(providers: &mut Providers) { *providers = Providers { inferred_outlives_of, inferred_outlives_crate, ..*providers }; } -fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::ClauseKind<'_>, Span)] { +fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clause<'_>, Span)] { let id = tcx.hir().local_def_id_to_hir_id(item_def_id); if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) @@ -52,7 +52,7 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clau if tcx.has_attr(item_def_id, sym::rustc_outlives) { let mut pred: Vec = predicates .iter() - .map(|(out_pred, _)| match out_pred { + .map(|(out_pred, _)| match out_pred.kind().skip_binder() { ty::ClauseKind::RegionOutlives(p) => p.to_string(), ty::ClauseKind::TypeOutlives(p) => p.to_string(), err => bug!("unexpected clause {:?}", err), @@ -104,13 +104,15 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> { |(ty::OutlivesPredicate(kind1, region2), &span)| { match kind1.unpack() { GenericArgKind::Type(ty1) => Some(( - ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty1, *region2)), + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty1, *region2)) + .to_predicate(tcx), span, )), GenericArgKind::Lifetime(region1) => Some(( ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( region1, *region2, - )), + )) + .to_predicate(tcx), span, )), GenericArgKind::Const(_) => { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 9fb83bec99372..5c5ec4528504e 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1984,12 +1984,12 @@ declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMEN impl ExplicitOutlivesRequirements { fn lifetimes_outliving_lifetime<'tcx>( - inferred_outlives: &'tcx [(ty::ClauseKind<'tcx>, Span)], + inferred_outlives: &'tcx [(ty::Clause<'tcx>, Span)], def_id: DefId, ) -> Vec> { inferred_outlives .iter() - .filter_map(|(clause, _)| match *clause { + .filter_map(|(clause, _)| match clause.kind().skip_binder() { ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a { ty::ReEarlyBound(ebr) if ebr.def_id == def_id => Some(b), _ => None, @@ -2000,12 +2000,12 @@ impl ExplicitOutlivesRequirements { } fn lifetimes_outliving_type<'tcx>( - inferred_outlives: &'tcx [(ty::ClauseKind<'tcx>, Span)], + inferred_outlives: &'tcx [(ty::Clause<'tcx>, Span)], index: u32, ) -> Vec> { inferred_outlives .iter() - .filter_map(|(clause, _)| match *clause { + .filter_map(|(clause, _)| match clause.kind().skip_binder() { ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => { a.is_param(index).then_some(b) } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 059cc0a36898a..9cffd96f4a396 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -376,7 +376,7 @@ define_tables! { attr_flags: Table, def_path_hashes: Table, explicit_item_bounds: Table, Span)>>, - inferred_outlives_of: Table, Span)>>, + inferred_outlives_of: Table, Span)>>, inherent_impls: Table>, associated_types_for_impl_traits_in_associated_fn: Table>, opt_rpitit_info: Table>>, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 6338e1719f475..5d6a477b9ad9c 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -647,7 +647,7 @@ rustc_queries! { /// Returns the inferred outlives predicates (e.g., for `struct /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`). - query inferred_outlives_of(key: DefId) -> &'tcx [(ty::ClauseKind<'tcx>, Span)] { + query inferred_outlives_of(key: DefId) -> &'tcx [(ty::Clause<'tcx>, Span)] { desc { |tcx| "computing inferred outlives predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index a0fffce7071e3..220118ae5ccb8 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -805,13 +805,6 @@ impl<'a, 'tcx> Decodable> for &'tcx [(ty::Clause<'tcx>, S } } -impl<'a, 'tcx> Decodable> for &'tcx [(ty::ClauseKind<'tcx>, Span)] { - #[inline] - fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { - RefDecodable::decode(d) - } -} - impl<'a, 'tcx> Decodable> for &'tcx [rustc_ast::InlineAsmTemplatePiece] { #[inline] fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index e2771fc53e758..248251e1ef5a1 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -386,16 +386,6 @@ impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for [(ty::Claus } } -impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> - for [(ty::ClauseKind<'tcx>, Span)] -{ - fn decode(decoder: &mut D) -> &'tcx Self { - decoder.interner().arena.alloc_from_iter( - (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::>(), - ) - } -} - impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for ty::List { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 84ad96084c486..0e604fdf6f499 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -731,7 +731,7 @@ pub struct CratePredicatesMap<'tcx> { /// predicate of its outlive bounds. If an item has no outlives /// bounds, it will have no entry. // FIXME(clause): should this be a `Clause`? - pub predicates: FxHashMap, Span)]>, + pub predicates: FxHashMap, Span)]>, } impl<'tcx> Predicate<'tcx> { @@ -1272,6 +1272,13 @@ impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> { } } +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for ClauseKind<'tcx> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + tcx.mk_predicate(Binder::dummy(ty::PredicateKind::Clause(self))).expect_clause() + } +} + impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for Binder<'tcx, ClauseKind<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { From 9637d4401481a715e4451db8a6d3744b674eea7e Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 22 Jun 2023 11:53:49 -0700 Subject: [PATCH 420/465] style-guide: Fix typo "does done fit" should have been "does not fit". --- src/doc/style-guide/src/expressions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md index 96f66c89c259f..8271b42da4c70 100644 --- a/src/doc/style-guide/src/expressions.md +++ b/src/doc/style-guide/src/expressions.md @@ -690,7 +690,7 @@ Where it is possible to use a block form on the right-hand side and avoid breaking the left-hand side, do that. E.g. ```rust - // Assuming the following line does done fit in the max width + // Assuming the following line does not fit in the max width a_very_long_pattern | another_pattern => ALongStructName { ... }, From 3747d7f593555cdf25d35aeaae8a66d5018eadbf Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 22 Jun 2023 12:30:14 -0700 Subject: [PATCH 421/465] style-guide: Move text about block vs visual indent to indentation section `principles.md` includes some high-level guiding principles for formatting, but also includes a few specific formatting provisions. While those provisions apply in many places, the same holds true for other high-level guidance, such as the indentation section. Move the text about using block indent rather than visual indent to the indentation section, so that `principles.md` can focus on guiding principles while the top level of the style guide gives concrete formatting recommendations. --- src/doc/style-guide/src/README.md | 18 ++++++++++++++++++ src/doc/style-guide/src/principles.md | 17 ----------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/doc/style-guide/src/README.md b/src/doc/style-guide/src/README.md index adb73a7eef6e0..49a4bce2f5dcd 100644 --- a/src/doc/style-guide/src/README.md +++ b/src/doc/style-guide/src/README.md @@ -30,6 +30,24 @@ typically by using a formatting tool's default settings. * The maximum width for a line is 100 characters. * A tool should be configurable for all three of these variables. +#### Block indent + +Prefer block indent over visual indent: + +```rust +// Block indent +a_function_call( + foo, + bar, +); + +// Visual indent +a_function_call(foo, + bar); +``` + +This makes for smaller diffs (e.g., if `a_function_call` is renamed in the above +example) and less rightward drift. ### Blank lines diff --git a/src/doc/style-guide/src/principles.md b/src/doc/style-guide/src/principles.md index 2d203f264e623..c3104e6d9b60f 100644 --- a/src/doc/style-guide/src/principles.md +++ b/src/doc/style-guide/src/principles.md @@ -31,23 +31,6 @@ following principles (in rough priority order): ## Overarching guidelines -Prefer block indent over visual indent. E.g., - -```rust -// Block indent -a_function_call( - foo, - bar, -); - -// Visual indent -a_function_call(foo, - bar); -``` - -This makes for smaller diffs (e.g., if `a_function_call` is renamed in the above -example) and less rightward drift. - Lists should have a trailing comma when followed by a newline, see the block indent example above. This choice makes moving code (e.g., by copy and paste) easier and makes smaller diffs. From 92805672c3703c43481103bd1e81b12844a87b74 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 22 Jun 2023 12:41:30 -0700 Subject: [PATCH 422/465] style-guide: Move and expand text about trailing commas `principles.md` includes some high-level guiding principles for formatting, but also includes a few specific formatting provisions. While those provisions apply in many places, the same holds true for other high-level guidance. Move the text about trailing commas to `README.md`, so that `principles.md` can focus on guiding principles while the top level of the style guide gives concrete formatting recommendations. --- src/doc/style-guide/src/README.md | 21 +++++++++++++++++++++ src/doc/style-guide/src/principles.md | 7 ------- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/doc/style-guide/src/README.md b/src/doc/style-guide/src/README.md index 49a4bce2f5dcd..3d47e33841a54 100644 --- a/src/doc/style-guide/src/README.md +++ b/src/doc/style-guide/src/README.md @@ -49,6 +49,27 @@ a_function_call(foo, This makes for smaller diffs (e.g., if `a_function_call` is renamed in the above example) and less rightward drift. +### Trailing commas + +Lists should have a trailing comma when followed by a newline: + +```rust +function_call( + argument, + another_argument, +); + +let array = [ + element, + another_element, + yet_another_element, +]; +``` + +This makes moving code (e.g., by copy and paste) easier, and makes diffs +smaller, as appending or removing items does not require modifying another line +to add or remove a comma. + ### Blank lines Separate items and statements by either zero or one blank lines (i.e., one or diff --git a/src/doc/style-guide/src/principles.md b/src/doc/style-guide/src/principles.md index c3104e6d9b60f..c86121e6a4697 100644 --- a/src/doc/style-guide/src/principles.md +++ b/src/doc/style-guide/src/principles.md @@ -27,10 +27,3 @@ following principles (in rough priority order): - ease of implementation (in Rustfmt, and in other tools/editors/code generators) - internal consistency - simplicity of formatting rules - - -## Overarching guidelines - -Lists should have a trailing comma when followed by a newline, see the block -indent example above. This choice makes moving code (e.g., by copy and paste) -easier and makes smaller diffs. From 2c0dd90936a5ce6a61cbe0f342b452871409b71c Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 22 Jun 2023 12:42:57 -0700 Subject: [PATCH 423/465] style-guide: s/right-ward/rightward/ We already use the word "rightward" elsewhere; avoid the unnecessarily hyphenated "right-ward". --- src/doc/style-guide/src/principles.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/style-guide/src/principles.md b/src/doc/style-guide/src/principles.md index c86121e6a4697..30fb26014f272 100644 --- a/src/doc/style-guide/src/principles.md +++ b/src/doc/style-guide/src/principles.md @@ -19,7 +19,7 @@ following principles (in rough priority order): * specifics - compatibility with version control practices - preserving diffs, merge-friendliness, etc. - - preventing right-ward drift + - preventing rightward drift - minimising vertical space * application From 4c5bb06a97515c1135e9339e6fa1fd78e7531ba2 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 22 Jun 2023 12:45:56 -0700 Subject: [PATCH 424/465] style-guide: Consistently refer to rustfmt as `rustfmt` --- src/doc/style-guide/src/README.md | 4 ++-- src/doc/style-guide/src/items.md | 4 ++-- src/doc/style-guide/src/principles.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/style-guide/src/README.md b/src/doc/style-guide/src/README.md index 3d47e33841a54..78e1d6a1fa184 100644 --- a/src/doc/style-guide/src/README.md +++ b/src/doc/style-guide/src/README.md @@ -16,8 +16,8 @@ Rust code has similar formatting, less mental effort is required to comprehend a new project, lowering the barrier to entry for new developers. Thus, there are productivity benefits to using a formatting tool (such as -rustfmt), and even larger benefits by using a community-consistent formatting, -typically by using a formatting tool's default settings. +`rustfmt`), and even larger benefits by using a community-consistent +formatting, typically by using a formatting tool's default settings. ## Formatting conventions diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md index 2835975355fca..a9c559d0bb8c9 100644 --- a/src/doc/style-guide/src/items.md +++ b/src/doc/style-guide/src/items.md @@ -505,8 +505,8 @@ use b; Because of `macro_use`, attributes must also start a new group and prevent re-ordering. -Note that tools which only have access to syntax (such as Rustfmt) cannot tell -which imports are from an external crate or the std lib, etc. +Note that tools which only have access to syntax (such as `rustfmt`) cannot +tell which imports are from an external crate or the std lib, etc. #### Ordering list import diff --git a/src/doc/style-guide/src/principles.md b/src/doc/style-guide/src/principles.md index 30fb26014f272..bbf6d76d4216e 100644 --- a/src/doc/style-guide/src/principles.md +++ b/src/doc/style-guide/src/principles.md @@ -24,6 +24,6 @@ following principles (in rough priority order): * application - ease of manual application - - ease of implementation (in Rustfmt, and in other tools/editors/code generators) + - ease of implementation (in `rustfmt`, and in other tools/editors/code generators) - internal consistency - simplicity of formatting rules From d270af31972b2673ef0b05a5749a49f8a68a3d2b Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 22 Jun 2023 12:47:24 -0700 Subject: [PATCH 425/465] style-guide: Remove inaccurate statement about rustfmt rustfmt does include a mechanism to distinguish standard library imports, which it does syntactically by crate name. Avoid making a misleading statement that implies it cannot do this. --- src/doc/style-guide/src/items.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md index a9c559d0bb8c9..06ee4e28ccbc5 100644 --- a/src/doc/style-guide/src/items.md +++ b/src/doc/style-guide/src/items.md @@ -505,10 +505,6 @@ use b; Because of `macro_use`, attributes must also start a new group and prevent re-ordering. -Note that tools which only have access to syntax (such as `rustfmt`) cannot -tell which imports are from an external crate or the std lib, etc. - - #### Ordering list import Names in a list import must be sorted ascii-betically, but with `self` and From c5f8b2c7a92bc542c0c2666dc4672493cf945982 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 22 Jun 2023 13:01:45 -0700 Subject: [PATCH 426/465] style-guide: Define (and capitalize) "ASCIIbetically" The style guide didn't give any definition for it. --- src/doc/style-guide/src/items.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md index 06ee4e28ccbc5..f1f5344f3e2cd 100644 --- a/src/doc/style-guide/src/items.md +++ b/src/doc/style-guide/src/items.md @@ -478,8 +478,8 @@ foo::{ A *group* of imports is a set of imports on the same or sequential lines. One or more blank lines or other items (e.g., a function) separate groups of imports. -Within a group of imports, imports must be sorted ascii-betically. Groups of -imports must not be merged or re-ordered. +Within a group of imports, imports must be sorted ASCIIbetically (uppercase +before lowercase). Groups of imports must not be merged or re-ordered. E.g., input: @@ -507,7 +507,7 @@ re-ordering. #### Ordering list import -Names in a list import must be sorted ascii-betically, but with `self` and +Names in a list import must be sorted ASCIIbetically, but with `self` and `super` first, and groups and glob imports last. This applies recursively. For example, `a::*` comes before `b::a` but `a::b` comes before `a::*`. E.g., `use foo::bar::{a, b::c, b::d, b::d::{x, y, z}, b::{self, r, s}};`. From 20f2828bbd37ce3d91797a2f2243c76190856301 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 22 Jun 2023 13:12:43 -0700 Subject: [PATCH 427/465] style-guide: Update cargo.md for authors being optional and not recommended Change an example using the authors field to use a long feature list instead. Change the conventions for the authors field to say "if present". --- src/doc/style-guide/src/cargo.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/doc/style-guide/src/cargo.md b/src/doc/style-guide/src/cargo.md index 13b96ca8c5e9d..5e6a62a7fd284 100644 --- a/src/doc/style-guide/src/cargo.md +++ b/src/doc/style-guide/src/cargo.md @@ -25,16 +25,17 @@ not indent any key names; start all key names at the start of a line. Use multi-line strings (rather than newline escape sequences) for any string values that include multiple lines, such as the crate description. -For array values, such as a list of authors, put the entire list on the same +For array values, such as a list of features, put the entire list on the same line as the key, if it fits. Otherwise, use block indentation: put a newline after the opening square bracket, indent each item by one indentation level, put a comma after each item (including the last), and put the closing square bracket at the start of a line by itself after the last item. ```rust -authors = [ - "A Uthor ", - "Another Author ", +some_feature = [ + "another_feature", + "yet_another_feature", + "some_dependency?/some_feature", ] ``` @@ -54,11 +55,11 @@ version = "4.5.6" ## Metadata conventions -The authors list should consist of strings that each contain an author name -followed by an email address in angle brackets: `Full Name `. -It should not contain bare email addresses, or names without email addresses. -(The authors list may also include a mailing list address without an associated -name.) +The authors list, if present, should consist of strings that each contain an +author name followed by an email address in angle brackets: `Full Name +`. It should not contain bare email addresses, or names without +email addresses. (The authors list may also include a mailing list address +without an associated name.) The license field must contain a valid [SPDX expression](https://spdx.org/spdx-specification-21-web-version#h.jxpfx0ykyb60), From 6f8f83f66d88afe1e7d40011f8862844d8fa86c4 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 22 Jun 2023 13:17:47 -0700 Subject: [PATCH 428/465] style-guide: Avoid normative recommendations for formatting tool configurability It's not within the scope of the style guide to tell formatting tools whether, or how, to allow configurability of non-default formatting. --- src/doc/style-guide/src/README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/doc/style-guide/src/README.md b/src/doc/style-guide/src/README.md index 78e1d6a1fa184..2ad834f804bd0 100644 --- a/src/doc/style-guide/src/README.md +++ b/src/doc/style-guide/src/README.md @@ -28,7 +28,7 @@ formatting, typically by using a formatting tool's default settings. * Each level of indentation must be four spaces (that is, all indentation outside of string literals and comments must be a multiple of four). * The maximum width for a line is 100 characters. -* A tool should be configurable for all three of these variables. +* A tool may choose to make some of these configurable. #### Block indent @@ -87,11 +87,7 @@ fn bar() {} fn baz() {} ``` -Formatting tools should make the bounds on blank lines configurable: there -should be separate minimum and maximum numbers of newlines between both -statements and (top-level) items (i.e., four options). As described above, the -defaults for both statements and items should be minimum: 1, maximum: 2. - +Formatting tools may wish to make the bounds on blank lines configurable. ### [Module-level items](items.md) ### [Statements](statements.md) From fec28b26b5b6252cdd153135d61f54de4f2d10fb Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 22 Jun 2023 13:21:40 -0700 Subject: [PATCH 429/465] style-guide: Clarify advice on names matching keywords In particular, specify what this advice is an alternative to (creative misspellings such as `krate`). --- src/doc/style-guide/src/advice.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/style-guide/src/advice.md b/src/doc/style-guide/src/advice.md index ab4b92b0a2478..9a617be509c38 100644 --- a/src/doc/style-guide/src/advice.md +++ b/src/doc/style-guide/src/advice.md @@ -25,9 +25,9 @@ if y { * Local variables shall be `snake_case`, * Macro names shall be `snake_case`, * Constants (`const`s and immutable `static`s) shall be `SCREAMING_SNAKE_CASE`. - * When a name is forbidden because it is a reserved word (e.g., `crate`), use a - trailing underscore to make the name legal (e.g., `crate_`), or use raw - identifiers if possible. + * When a name is forbidden because it is a reserved word (such as `crate`), + either use a raw identifier (`r#crate`) or use a trailing underscore + (`crate_`). Don't misspell the word (`krate`). ### Modules From 2828c5605eb57ead02036c3a0307932ebf8dae9d Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 22 Jun 2023 23:01:48 +0200 Subject: [PATCH 430/465] typo --- tests/ui/use/use-keyword.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/use/use-keyword.rs b/tests/ui/use/use-keyword.rs index c30c2e06c4557..840cddcb907cc 100644 --- a/tests/ui/use/use-keyword.rs +++ b/tests/ui/use/use-keyword.rs @@ -1,4 +1,4 @@ -// Check that imports with nakes super and self don't fail during parsing +// Check that imports with naked super and self don't fail during parsing // FIXME: this shouldn't fail during name resolution either mod a { From c930b21bcdf9a47fd299e150f8056fe5f7bd7a08 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 22 Jun 2023 13:28:47 -0700 Subject: [PATCH 431/465] style-guide: Reword an awkwardly phrased recommendation (and fix a typo) --- src/doc/style-guide/src/items.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md index f1f5344f3e2cd..79635e758f31b 100644 --- a/src/doc/style-guide/src/items.md +++ b/src/doc/style-guide/src/items.md @@ -15,8 +15,8 @@ Tools should make the above ordering optional. ### Function definitions -In Rust, one finds functions by searching for `fn [function-name]`; It's -important that you style your code so that it's very searchable in this way. +In Rust, people often find functions by searching for `fn [function-name]`, so +the formatting of function definitions shold enable this. The proper ordering and spacing is: From 3e2449c2b14eb676a27d2b62a162a800c6e89212 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 22 Jun 2023 13:30:06 -0700 Subject: [PATCH 432/465] style-guide: Rephrase a confusingly ordered, ambiguous sentence (and fix a typo) This sentence had a parenthetical without a closing parenthesis, and had the phrase "which doesn't require special formatting" ambiguously at the end of a list when it only applied to the last item of the list. --- src/doc/style-guide/src/items.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md index 79635e758f31b..41ac1eeca96a5 100644 --- a/src/doc/style-guide/src/items.md +++ b/src/doc/style-guide/src/items.md @@ -63,8 +63,9 @@ let y = (11, 22, 33); In the declaration, put each variant on its own line, block indented. -Format each variant accordingly as either a struct, tuple struct, or identifier, -which doesn't require special formatting (but without the `struct` keyword. +Format each variant accordingly as either a struct (but without the `struct` +keyword), a tuple struct, or an identifier (which doesn't require special +formatting): ```rust enum FooBar { From a9d1db31457f8ae619bb73234632b20ccc8b930f Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 22 Jun 2023 13:57:49 -0700 Subject: [PATCH 433/465] style-guide: Avoid hyphenating "semicolon" --- src/doc/style-guide/src/items.md | 6 +++--- src/doc/style-guide/src/statements.md | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md index 41ac1eeca96a5..8a0954f53430e 100644 --- a/src/doc/style-guide/src/items.md +++ b/src/doc/style-guide/src/items.md @@ -140,7 +140,7 @@ union Foo { Put the whole struct on one line if possible. Types in the parentheses should be separated by a comma and space with no trailing comma. No spaces around the -parentheses or semi-colon: +parentheses or semicolon: ```rust pub struct Foo(String, u8); @@ -231,7 +231,7 @@ impl Bar `extern crate foo;` -Use spaces around keywords, no spaces around the semi-colon. +Use spaces around keywords, no spaces around the semicolon. ### Modules @@ -246,7 +246,7 @@ mod foo; ``` Use spaces around keywords and before the opening brace, no spaces around the -semi-colon. +semicolon. ### macro\_rules! diff --git a/src/doc/style-guide/src/statements.md b/src/doc/style-guide/src/statements.md index 671e6d31a5775..abb6b492b9121 100644 --- a/src/doc/style-guide/src/statements.md +++ b/src/doc/style-guide/src/statements.md @@ -1,7 +1,7 @@ ### Let statements There should be spaces after the `:` and on both sides of the `=` (if they are -present). No space before the semi-colon. +present). No space before the semicolon. ```rust // A comment. @@ -194,7 +194,7 @@ used to determine whether a let-else statement is *short*. ### Macros in statement position A macro use in statement position should use parentheses or square brackets as -delimiters and should be terminated with a semi-colon. There should be no spaces +delimiters and should be terminated with a semicolon. There should be no spaces between the name, `!`, the delimiters, or the `;`. ```rust @@ -205,13 +205,13 @@ a_macro!(...); ### Expressions in statement position -There should be no space between the expression and the semi-colon. +There should be no space between the expression and the semicolon. ``` ; ``` -All expressions in statement position should be terminated with a semi-colon, +All expressions in statement position should be terminated with a semicolon, unless they end with a block or are used as the value for a block. E.g., @@ -229,7 +229,7 @@ loop { } ``` -Use a semi-colon where an expression has void type, even if it could be +Use a semicolon where an expression has void type, even if it could be propagated. E.g., ```rust From 5d637219e43ed61f05f0c4e9c48f9b692a8c1147 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 22 Jun 2023 14:02:22 -0700 Subject: [PATCH 434/465] style-guide: Make link text in SUMMARY.md match the headings in the linked pages --- src/doc/style-guide/src/SUMMARY.md | 8 ++++---- src/doc/style-guide/src/cargo.md | 2 +- src/doc/style-guide/src/statements.md | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/doc/style-guide/src/SUMMARY.md b/src/doc/style-guide/src/SUMMARY.md index 004692fa6a22b..59fe9fdc6694a 100644 --- a/src/doc/style-guide/src/SUMMARY.md +++ b/src/doc/style-guide/src/SUMMARY.md @@ -2,10 +2,10 @@ [Introduction](README.md) -- [Module-level items](items.md) +- [Items](items.md) - [Statements](statements.md) - [Expressions](expressions.md) -- [Types](types.md) -- [Non-formatting conventions](advice.md) +- [Types and Bounds](types.md) +- [Other style advice](advice.md) - [`Cargo.toml` conventions](cargo.md) -- [Principles used for deciding these guidelines](principles.md) +- [Guiding principles and rationale](principles.md) diff --git a/src/doc/style-guide/src/cargo.md b/src/doc/style-guide/src/cargo.md index 5e6a62a7fd284..d3b67ae45825d 100644 --- a/src/doc/style-guide/src/cargo.md +++ b/src/doc/style-guide/src/cargo.md @@ -1,4 +1,4 @@ -# Cargo.toml conventions +# `Cargo.toml` conventions ## Formatting conventions diff --git a/src/doc/style-guide/src/statements.md b/src/doc/style-guide/src/statements.md index abb6b492b9121..62a5a032f072e 100644 --- a/src/doc/style-guide/src/statements.md +++ b/src/doc/style-guide/src/statements.md @@ -1,3 +1,5 @@ +## Statements + ### Let statements There should be spaces after the `:` and on both sides of the `=` (if they are From f972e09f76e5d5557a56026b4ffa78eb76df6564 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 22 Jun 2023 14:06:15 -0700 Subject: [PATCH 435/465] style-guide: Define what an item is --- src/doc/style-guide/src/items.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md index 8a0954f53430e..1e0e60248bfbd 100644 --- a/src/doc/style-guide/src/items.md +++ b/src/doc/style-guide/src/items.md @@ -1,5 +1,10 @@ ## Items +Items consist of the set of things permitted at the top level of a module. +However, Rust also allows some items to appear within some other types of +items, such as within a function. The same formatting conventions apply whether +an item appears at module level or within another item. + `extern crate` statements must be first in a file. They must be ordered alphabetically. From fcc23a3bfd827b5c587e4899a6fe6b92d72c048e Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 22 Jun 2023 12:50:04 -0700 Subject: [PATCH 436/465] style-guide: Avoid referring to the style team in the past tense We live! --- src/doc/style-guide/src/principles.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/style-guide/src/principles.md b/src/doc/style-guide/src/principles.md index bbf6d76d4216e..d548693e39ed0 100644 --- a/src/doc/style-guide/src/principles.md +++ b/src/doc/style-guide/src/principles.md @@ -1,7 +1,7 @@ # Guiding principles and rationale -When deciding on style guidelines, the style team tried to be guided by the -following principles (in rough priority order): +When deciding on style guidelines, the style team follows these guiding +principles (in rough priority order): * readability - scan-ability From 2748efaba3ed81de50a8e23ce72c9bb214e11fe5 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 22 Jun 2023 14:39:15 -0700 Subject: [PATCH 437/465] style-guide: Add language disclaiming any effects on non-default Rust styles Make it clear that the style guide saying "must" doesn't forbid developers from doing differently (as though any power on this Earth could do that) and doesn't forbid tools from allowing any particular configuration options. --- src/doc/style-guide/src/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/doc/style-guide/src/README.md b/src/doc/style-guide/src/README.md index adb73a7eef6e0..d57b4be0b85d2 100644 --- a/src/doc/style-guide/src/README.md +++ b/src/doc/style-guide/src/README.md @@ -19,6 +19,18 @@ Thus, there are productivity benefits to using a formatting tool (such as rustfmt), and even larger benefits by using a community-consistent formatting, typically by using a formatting tool's default settings. +## The default Rust style + +The Rust Style Guide defines the default Rust style, and *recommends* that +developers and tools follow the default Rust style. Tools such as `rustfmt` use +the style guide as a reference for the default style. Everything in this style +guide, whether or not it uses language such as "must" or the imperative mood +such as "insert a space ..." or "break the line after ...", refers to the +default style. + +This should not be interpreted as forbidding developers from following a +non-default style, or forbidding tools from adding any particular configuration +options. ## Formatting conventions From d94d17c0bbdb61d793672aa28e835603a483c51d Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Thu, 22 Jun 2023 18:03:23 -0400 Subject: [PATCH 438/465] tests: be more permissive on attributes in one test --- tests/codegen/stack-protector.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/codegen/stack-protector.rs b/tests/codegen/stack-protector.rs index a24e6f1e4f190..eb6451b5aa299 100644 --- a/tests/codegen/stack-protector.rs +++ b/tests/codegen/stack-protector.rs @@ -24,7 +24,7 @@ pub fn foo() { // basic-NOT: attributes #0 = { {{.*}} sspreq {{.*}} } // basic-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} } - // basic: attributes #0 = { {{.*}} ssp {{.*}} } + // basic: attributes #0 = { {{.*}}ssp {{.*}} } // basic-NOT: attributes #0 = { {{.*}} sspreq {{.*}} } // basic-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} } From afe36507e84e8b7805717bc1c5054dcf4346df92 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 19 May 2023 00:10:06 +0000 Subject: [PATCH 439/465] Don't structurally resolve during method ambiguity in probe --- compiler/rustc_hir_typeck/src/method/probe.rs | 19 ++++++--- .../deref-ambiguity-becomes-nonambiguous.rs | 40 +++++++++++++++++++ ...eref-ambiguity-becomes-nonambiguous.stderr | 17 ++++++++ 3 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.rs create mode 100644 tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.stderr diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index e759fd6bc948a..762176ecfc795 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -12,6 +12,7 @@ use rustc_hir::def::DefKind; use rustc_hir_analysis::autoderef::{self, Autoderef}; use rustc_infer::infer::canonical::OriginalQueryValues; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; +use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; use rustc_middle::middle::stability; @@ -448,15 +449,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } else { - // Encountered a real ambiguity, so abort the lookup. If `ty` is not - // an `Err`, report the right "type annotations needed" error pointing - // to it. + // Ended up encountering a type variable when doing autoderef, + // but it may not be a type variable after processing obligations + // in our local `FnCtxt`, so don't call `structurally_resolved_type`. let ty = &bad_ty.ty; let ty = self .probe_instantiate_query_response(span, &orig_values, ty) .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty)); - let ty = self.structurally_resolved_type(span, ty.value); - assert!(matches!(ty.kind(), ty::Error(_))); + let ty = self.resolve_vars_if_possible(ty.value); + let guar = match *ty.kind() { + ty::Infer(ty::TyVar(_)) => self + .err_ctxt() + .emit_inference_failure_err(self.body_id, span, ty.into(), E0282, true) + .emit(), + ty::Error(guar) => guar, + _ => bug!("unexpected bad final type in method autoderef"), + }; + self.demand_eqtype(span, ty, self.tcx.ty_error(guar)); return Err(MethodError::NoMatch(NoMatchData { static_candidates: Vec::new(), unsatisfied_predicates: Vec::new(), diff --git a/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.rs b/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.rs new file mode 100644 index 0000000000000..d8034d57e8d56 --- /dev/null +++ b/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.rs @@ -0,0 +1,40 @@ +use std::ops::Deref; +use std::rc::Rc; + +struct Value(T); + +pub trait Wrap { + fn wrap() -> Self; +} + +impl Wrap R> for Value R> { + fn wrap() -> Self { + todo!() + } +} + +impl Wrap for Value R>> { + fn wrap() -> Self { + todo!() + } +} + +impl Deref for Value> { + type Target = F; + + fn deref(&self) -> &Self::Target { + &*self.0 + } +} + +fn main() { + let var_fn = Value::wrap(); + //~^ ERROR type annotations needed for `Value>` + + // The combination of `Value: Wrap` obligation plus the autoderef steps + // (caused by the `Deref` impl above) actually means that the self type + // of the method fn below is constrained to be `Value ?2>>`. + // However, that's only known to us on the error path -- we still need + // to emit an ambiguity error, though. + let _ = var_fn.clone(); +} diff --git a/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.stderr b/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.stderr new file mode 100644 index 0000000000000..06a7e90858ce7 --- /dev/null +++ b/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.stderr @@ -0,0 +1,17 @@ +error[E0282]: type annotations needed for `Value>` + --> $DIR/deref-ambiguity-becomes-nonambiguous.rs:31:9 + | +LL | let var_fn = Value::wrap(); + | ^^^^^^ +... +LL | let _ = var_fn.clone(); + | ----- type must be known at this point + | +help: consider giving `var_fn` an explicit type, where the placeholders `_` are specified + | +LL | let var_fn: Value> = Value::wrap(); + | ++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. From 48167bd4bddec03d1969e2cc2c1155cb5667d6ad Mon Sep 17 00:00:00 2001 From: Alexander Zhang Date: Thu, 22 Jun 2023 16:37:52 -0700 Subject: [PATCH 440/465] Avoid guessing unknown trait impl in suggestions When a trait is used without specifying the implementation (e.g. calling a non-member associated function without fully-qualified syntax) and there are multiple implementations available, use a placeholder comment for the implementation type in the suggestion instead of picking a random implementation. Example: ``` fn main() { let _ = Default::default(); } ``` Previous output: ``` error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type --> test.rs:2:13 | 2 | let _ = Default::default(); | ^^^^^^^^^^^^^^^^ cannot call associated function of trait | help: use a fully-qualified path to a specific available implementation (273 found) | 2 | let _ = ::default(); | +++++++++++++ + ``` New output: ``` error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type --> test.rs:2:13 | 2 | let _ = Default::default(); | ^^^^^^^^^^^^^^^^ cannot call associated function of trait | help: use a fully-qualified path to a specific available implementation (273 found) | 2 | let _ = ::default(); | +++++++++++++++++++ + ``` --- .../src/traits/error_reporting/mod.rs | 16 ++++++++++------ tests/ui/error-codes/E0283.stderr | 4 ++-- tests/ui/error-codes/E0790.stderr | 4 ++-- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 75a92af714bd5..67745f04641ab 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -2382,17 +2382,21 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { && let Some(impl_def_id) = trait_impls.non_blanket_impls().values().flatten().next() { let non_blanket_impl_count = trait_impls.non_blanket_impls().values().flatten().count(); - let message = if non_blanket_impl_count == 1 { - "use the fully-qualified path to the only available implementation".to_string() - } else { + // If there is only one implementation of the trait, suggest using it. + // Otherwise, use a placeholder comment for the implementation. + let (message, impl_suggestion) = if non_blanket_impl_count == 1 {( + "use the fully-qualified path to the only available implementation".to_string(), + format!("<{} as ", self.tcx.type_of(impl_def_id).subst_identity()) + )} else {( format!( "use a fully-qualified path to a specific available implementation ({} found)", non_blanket_impl_count - ) - }; + ), + "::create(); - | ++++++++ + +LL | let cont: u32 = ::create(); + | +++++++++++++++++++ + error[E0283]: type annotations needed --> $DIR/E0283.rs:35:24 diff --git a/tests/ui/error-codes/E0790.stderr b/tests/ui/error-codes/E0790.stderr index fc025a3fca2bf..7248766285d71 100644 --- a/tests/ui/error-codes/E0790.stderr +++ b/tests/ui/error-codes/E0790.stderr @@ -65,8 +65,8 @@ LL | MyTrait2::my_fn(); | help: use a fully-qualified path to a specific available implementation (2 found) | -LL | ::my_fn(); - | +++++++++ + +LL | ::my_fn(); + | +++++++++++++++++++ + error: aborting due to 5 previous errors From 65a7047ee470e71ccaf2a6ecdb38d7e8f1192664 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 23 Jun 2023 14:18:05 +0200 Subject: [PATCH 441/465] Add @files command --- src/etc/htmldocck.py | 54 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py index eade9e0455912..5ab1874e9ed46 100755 --- a/src/etc/htmldocck.py +++ b/src/etc/htmldocck.py @@ -110,6 +110,9 @@ * `@has-dir PATH` checks for the existence of the given directory. +* `@files FOLDER_PATH [ENTRIES]`, checks that `FOLDER_PATH` contains exactly + `[ENTRIES]`. + All conditions can be negated with `!`. `@!has foo/type.NoSuch.html` checks if the given file does not exist, for example. @@ -321,12 +324,15 @@ def resolve_path(self, path): else: return self.last_path + def get_absolute_path(self, path): + return os.path.join(self.root, path) + def get_file(self, path): path = self.resolve_path(path) if path in self.files: return self.files[path] - abspath = os.path.join(self.root, path) + abspath = self.get_absolute_path(path) if not(os.path.exists(abspath) and os.path.isfile(abspath)): raise FailedCheck('File does not exist {!r}'.format(path)) @@ -340,7 +346,7 @@ def get_tree(self, path): if path in self.trees: return self.trees[path] - abspath = os.path.join(self.root, path) + abspath = self.get_absolute_path(path) if not(os.path.exists(abspath) and os.path.isfile(abspath)): raise FailedCheck('File does not exist {!r}'.format(path)) @@ -356,7 +362,7 @@ def get_tree(self, path): def get_dir(self, path): path = self.resolve_path(path) - abspath = os.path.join(self.root, path) + abspath = self.get_absolute_path(path) if not(os.path.exists(abspath) and os.path.isdir(abspath)): raise FailedCheck('Directory does not exist {!r}'.format(path)) @@ -538,6 +544,41 @@ def get_nb_matching_elements(cache, c, regexp, stop_at_first): return check_tree_text(cache.get_tree(c.args[0]), pat, c.args[2], regexp, stop_at_first) +def check_files_in_folder(c, cache, folder, files): + files = files.strip() + if not files.startswith('[') or not files.endswith(']'): + raise InvalidCheck("Expected list as second argument of @{} (ie '[]')".format(c.cmd)) + + folder = cache.get_absolute_path(folder) + + # First we create a set of files to check if there are duplicates. + files = shlex.split(files[1:-1].replace(",", "")) + files_set = set() + for file in files: + if file in files_set: + raise InvalidCheck("Duplicated file `{}` in @{}".format(file, c.cmd)) + files_set.add(file) + folder_set = set([f for f in os.listdir(folder) if f != "." and f != ".."]) + + # Then we remove entries from both sets (we clone `folder_set` so we can iterate it while + # removing its elements). + for entry in set(folder_set): + if entry in files_set: + files_set.remove(entry) + folder_set.remove(entry) + + error = 0 + if len(files_set) != 0: + print_err(c.lineno, c.context, "Entries not found in folder `{}`: `{}`".format( + folder, files_set)) + error += 1 + if len(folder_set) != 0: + print_err(c.lineno, c.context, "Extra entries in folder `{}`: `{}`".format( + folder, folder_set)) + error += 1 + return error == 0 + + ERR_COUNT = 0 @@ -566,6 +607,13 @@ def check_command(c, cache): else: raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd)) + elif c.cmd == 'files': # check files in given folder + if len(c.args) != 2: # @files + raise InvalidCheck("Invalid number of @{} arguments".format(c.cmd)) + elif c.negated: + raise InvalidCheck("@{} doesn't support negative check".format(c.cmd)) + ret = check_files_in_folder(c, cache, c.args[0], c.args[1]) + elif c.cmd == 'count': # count test if len(c.args) == 3: # @count = count test expected = int(c.args[2]) From 752fb52ae94cfb36bb01dff5b2b31134605a7da3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 23 Jun 2023 15:12:13 +0200 Subject: [PATCH 442/465] Add @files checks in rustdoc tests --- tests/rustdoc/files-creation-hidden.rs | 1 + tests/rustdoc/files-creation-private.rs | 4 ++++ tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs | 6 ++++++ tests/rustdoc/issue-111249-file-creation.rs | 6 ++++++ 4 files changed, 17 insertions(+) diff --git a/tests/rustdoc/files-creation-hidden.rs b/tests/rustdoc/files-creation-hidden.rs index bcabbfc91e869..498d9cdaef1f0 100644 --- a/tests/rustdoc/files-creation-hidden.rs +++ b/tests/rustdoc/files-creation-hidden.rs @@ -1,5 +1,6 @@ #![crate_name="foo"] +// @files foo '["index.html", "all.html", "sidebar-items.js"]' // @!has "foo/struct.Foo.html" #[doc(hidden)] pub struct Foo; diff --git a/tests/rustdoc/files-creation-private.rs b/tests/rustdoc/files-creation-private.rs index ca2327e0f911a..e2fdbc068f8aa 100644 --- a/tests/rustdoc/files-creation-private.rs +++ b/tests/rustdoc/files-creation-private.rs @@ -1,5 +1,9 @@ #![crate_name="foo"] +// @files "foo" \ +// '["index.html", "all.html", "sidebar-items.js", "foo", "bar", "private", "struct.Bar.html"]' +// @files "foo/bar" '["index.html", "sidebar-items.js"]' + // @!has "foo/priv/index.html" // @!has "foo/priv/struct.Foo.html" mod private { diff --git a/tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs b/tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs index d6832bb7a0977..65c26d6a83751 100644 --- a/tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs +++ b/tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs @@ -2,6 +2,12 @@ #![no_core] #![crate_name = "foo"] +// @files "foo" "['sidebar-items.js', 'all.html', 'hidden', 'index.html', 'struct.Bar.html', \ +// 'visible']" +// @files "foo/hidden" "['inner']" +// @files "foo/hidden/inner" "['trait.Foo.html']" +// @files "foo/visible" "['index.html', 'sidebar-items.js', 'trait.Foo.html']" + // @!has 'foo/hidden/index.html' // @!has 'foo/hidden/inner/index.html' // FIXME: Should be `@!has`: https://github.com/rust-lang/rust/issues/111249 diff --git a/tests/rustdoc/issue-111249-file-creation.rs b/tests/rustdoc/issue-111249-file-creation.rs index d2042b231e469..afd65ddaf941f 100644 --- a/tests/rustdoc/issue-111249-file-creation.rs +++ b/tests/rustdoc/issue-111249-file-creation.rs @@ -2,6 +2,12 @@ #![feature(no_core)] #![no_core] +// @files "foo" "['all.html', 'visible', 'index.html', 'sidebar-items.js', 'hidden', \ +// 'struct.Bar.html']" +// @files "foo/visible" "['trait.Foo.html', 'index.html', 'sidebar-items.js']" +// @files "foo/hidden" "['inner']" +// @files "foo/hidden/inner" "['trait.Foo.html']" + // The following five should not fail! // @!has 'foo/hidden/index.html' // @!has 'foo/hidden/inner/index.html' From 52d50fba2a6877a83fef1c948a7c319dc6379589 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Fri, 23 Jun 2023 09:48:00 -0400 Subject: [PATCH 443/465] tests: be even more permissive on attributes in one test --- tests/codegen/stack-protector.rs | 34 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/codegen/stack-protector.rs b/tests/codegen/stack-protector.rs index eb6451b5aa299..a680789af15f2 100644 --- a/tests/codegen/stack-protector.rs +++ b/tests/codegen/stack-protector.rs @@ -10,25 +10,25 @@ pub fn foo() { // CHECK: @foo() unnamed_addr #0 - // all-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} } - // all-NOT: attributes #0 = { {{.*}} ssp {{.*}} } - // all: attributes #0 = { {{.*}} sspreq {{.*}} } - // all-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} } - // all-NOT: attributes #0 = { {{.*}} ssp {{.*}} } + // all-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } + // all-NOT: attributes #0 = { {{.*}}ssp {{.*}} } + // all: attributes #0 = { {{.*}}sspreq {{.*}} } + // all-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } + // all-NOT: attributes #0 = { {{.*}}ssp {{.*}} } - // strong-NOT: attributes #0 = { {{.*}} sspreq {{.*}} } - // strong-NOT: attributes #0 = { {{.*}} ssp {{.*}} } - // strong: attributes #0 = { {{.*}} sspstrong {{.*}} } - // strong-NOT: attributes #0 = { {{.*}} sspreq {{.*}} } - // strong-NOT: attributes #0 = { {{.*}} ssp {{.*}} } + // strong-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // strong-NOT: attributes #0 = { {{.*}}ssp {{.*}} } + // strong: attributes #0 = { {{.*}}sspstrong {{.*}} } + // strong-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // strong-NOT: attributes #0 = { {{.*}}ssp {{.*}} } - // basic-NOT: attributes #0 = { {{.*}} sspreq {{.*}} } - // basic-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} } + // basic-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // basic-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } // basic: attributes #0 = { {{.*}}ssp {{.*}} } - // basic-NOT: attributes #0 = { {{.*}} sspreq {{.*}} } - // basic-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} } + // basic-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // basic-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } - // none-NOT: attributes #0 = { {{.*}} sspreq {{.*}} } - // none-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} } - // none-NOT: attributes #0 = { {{.*}} ssp {{.*}} } + // none-NOT: attributes #0 = { {{.*}}sspreq {{.*}} } + // none-NOT: attributes #0 = { {{.*}}sspstrong {{.*}} } + // none-NOT: attributes #0 = { {{.*}}ssp {{.*}} } } From 616469aa8aa84585bbaeaee0c9e5b9e06ec15149 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 23 Jun 2023 15:50:20 +0200 Subject: [PATCH 444/465] Fix rustdoc-gui tester --- src/tools/rustdoc-gui-test/src/main.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs index dc902f8cb0242..ed91763420a59 100644 --- a/src/tools/rustdoc-gui-test/src/main.rs +++ b/src/tools/rustdoc-gui-test/src/main.rs @@ -67,7 +67,7 @@ fn find_librs>(path: P) -> Option { None } -fn main() { +fn main() -> Result<(), ()> { let config = Arc::new(Config::from_args(env::args().collect())); // The goal here is to check if the necessary packages are installed, and if not, we @@ -128,7 +128,10 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse } } - try_run(&mut cargo, config.verbose); + if !try_run(&mut cargo, config.verbose) { + eprintln!("failed to document `{}`", entry.path().display()); + panic!("Cannot run rustdoc-gui tests"); + } } } @@ -158,5 +161,5 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse command.args(&config.test_args); - try_run(&mut command, config.verbose); + if try_run(&mut command, config.verbose) { Ok(()) } else { Err(()) } } From d70faf3645d826bd8b0d76107d7b54db639fcec9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 23 Jun 2023 15:50:30 +0200 Subject: [PATCH 445/465] Fix failing rustdoc GUI test --- tests/rustdoc-gui/search-result-color.goml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/rustdoc-gui/search-result-color.goml b/tests/rustdoc-gui/search-result-color.goml index 193a3eb3fd134..e3c628b366fbd 100644 --- a/tests/rustdoc-gui/search-result-color.goml +++ b/tests/rustdoc-gui/search-result-color.goml @@ -31,7 +31,7 @@ define-function: ( // color of the typename (struct, module, method, ...) before search results assert-css: ( ".result-name .typename", - {"color": "#888"}, + {"color": |grey|}, ALL, ) }, @@ -75,6 +75,7 @@ store-value: (entry_color, "#0096cf") // color of the search entry store-value: (hover_entry_color, "#fff") // color of the hovered/focused search entry store-value: (background_color, "transparent") // background color store-value: (hover_background_color, "#3c3c3c") // hover background color +store-value: (grey, "#999") call-function: ( "check-result-color", ( @@ -186,6 +187,7 @@ store-value: (entry_color, "#ddd") // color of the search entry store-value: (hover_entry_color, "#ddd") // color of the hovered/focused search entry store-value: (background_color, "transparent") // background color store-value: (hover_background_color, "#616161") // hover background color +store-value: (grey, "#ccc") call-function: ( "check-result-color", ( @@ -282,6 +284,7 @@ store-value: (entry_color, "#000") // color of the search entry store-value: (hover_entry_color, "#000") // color of the hovered/focused search entry store-value: (background_color, "transparent") // background color store-value: (hover_background_color, "#ccc") // hover background color +store-value: (grey, "#999") call-function: ( "check-result-color", ( From 2f3bed0c4c72cf4ef8019888a3bc7a9c515e6213 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 17 Jun 2023 13:58:27 +0200 Subject: [PATCH 446/465] Add link to rustdoc book search chapter in help popover --- src/librustdoc/html/static/js/main.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index f5296abaee661..3a9e94e9f9fe4 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1072,6 +1072,9 @@ function preLoadCss(cssUrl) { div_shortcuts.innerHTML = "

Keyboard Shortcuts

" + shortcuts + "
"; const infos = [ + "For a full list of all search features, take a look here.", "Prefix searches with a type followed by a colon (e.g., fn:) to \ restrict the search to a given item kind.", "Accepted kinds are: fn, mod, struct, \ From 2f1939ab8b147b28809604d14876cb958e935cdd Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 23 Jun 2023 16:20:57 +0200 Subject: [PATCH 447/465] Link to the corresponding channel in the help popover --- src/librustdoc/clean/utils.rs | 3 +++ src/librustdoc/html/layout.rs | 2 ++ src/librustdoc/html/static/js/main.js | 11 ++++++----- src/librustdoc/html/templates/page.html | 1 + 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 294de12cea8e2..f375f0efbd17b 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -21,6 +21,7 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_span::symbol::{kw, sym, Symbol}; use std::fmt::Write as _; use std::mem; +use std::sync::LazyLock as Lazy; use thin_vec::{thin_vec, ThinVec}; #[cfg(test)] @@ -582,6 +583,8 @@ pub(crate) fn has_doc_flag(tcx: TyCtxt<'_>, did: DefId, flag: Symbol) -> bool { /// /// Set by `bootstrap::Builder::doc_rust_lang_org_channel` in order to keep tests passing on beta/stable. pub(crate) const DOC_RUST_LANG_ORG_CHANNEL: &str = env!("DOC_RUST_LANG_ORG_CHANNEL"); +pub(crate) static DOC_CHANNEL: Lazy<&'static str> = + Lazy::new(|| DOC_RUST_LANG_ORG_CHANNEL.rsplit("/").filter(|c| !c.is_empty()).next().unwrap()); /// Render a sequence of macro arms in a format suitable for displaying to the user /// as part of an item declaration. diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 6ab849c92a076..8c5871d912647 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -55,6 +55,7 @@ struct PageLayout<'a> { sidebar: String, content: String, krate_with_trailing_slash: String, + rust_channel: &'static str, pub(crate) rustdoc_version: &'a str, } @@ -82,6 +83,7 @@ pub(crate) fn render( sidebar, content, krate_with_trailing_slash, + rust_channel: *crate::clean::utils::DOC_CHANNEL, rustdoc_version, } .render() diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 3a9e94e9f9fe4..254b0d8bf5a43 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1050,9 +1050,10 @@ function preLoadCss(cssUrl) { function buildHelpMenu() { const book_info = document.createElement("span"); + const channel = getVar("channel"); book_info.className = "top"; - book_info.innerHTML = "You can find more information in \ - the rustdoc book."; + book_info.innerHTML = `You can find more information in \ +the rustdoc book.`; const shortcuts = [ ["?", "Show this help dialog"], @@ -1072,9 +1073,9 @@ function preLoadCss(cssUrl) { div_shortcuts.innerHTML = "

Keyboard Shortcuts

" + shortcuts + "
"; const infos = [ - "For a full list of all search features, take a look here.", + `For a full list of all search features, take a look here.`, "Prefix searches with a type followed by a colon (e.g., fn:) to \ restrict the search to a given item kind.", "Accepted kinds are: fn, mod, struct, \ diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 9133f899af60d..759c4fd601226 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -31,6 +31,7 @@ data-themes="{{themes|join(",") }}" {#+ #} data-resource-suffix="{{page.resource_suffix}}" {#+ #} data-rustdoc-version="{{rustdoc_version}}" {#+ #} + data-channel="{{rust_channel}}" {#+ #} data-search-js="{{files.search_js}}" {#+ #} data-settings-js="{{files.settings_js}}" {#+ #} data-settings-css="{{files.settings_css}}" {#+ #} From c996cfec8008c80c434cafbb930177e13cfbfe03 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 10 Feb 2023 10:26:26 +0000 Subject: [PATCH 448/465] Stop bubbling out hidden types from the eval obligation queries --- compiler/rustc_traits/src/evaluate_obligation.rs | 9 ++------- compiler/rustc_traits/src/type_op.rs | 14 ++++---------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index 73756caf37272..e8917d72483c6 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -1,6 +1,5 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; -use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_span::source_map::DUMMY_SP; use rustc_trait_selection::traits::query::CanonicalPredicateGoal; @@ -18,12 +17,8 @@ fn evaluate_obligation<'tcx>( ) -> Result { assert!(!tcx.next_trait_solver_globally()); debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal); - // HACK This bubble is required for this tests to pass: - // impl-trait/issue99642.rs - let (ref infcx, goal, _canonical_inference_vars) = tcx - .infer_ctxt() - .with_opaque_type_inference(DefiningAnchor::Bubble) - .build_with_canonical(DUMMY_SP, &canonical_goal); + let (ref infcx, goal, _canonical_inference_vars) = + tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal); debug!("evaluate_obligation: goal={:#?}", goal); let ParamEnvAnd { param_env, value: predicate } = goal; diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index 9904acb1c0d51..98d814d54f282 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -2,7 +2,6 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::{FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{ParamEnvAnd, Predicate}; use rustc_trait_selection::infer::InferCtxtBuilderExt; @@ -106,15 +105,10 @@ fn type_op_prove_predicate<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, ProvePredicate<'tcx>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { - // HACK This bubble is required for this test to pass: - // impl-trait/issue-99642.rs - tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter_canonical_trait_query( - &canonicalized, - |ocx, key| { - type_op_prove_predicate_with_cause(ocx, key, ObligationCause::dummy()); - Ok(()) - }, - ) + tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| { + type_op_prove_predicate_with_cause(ocx, key, ObligationCause::dummy()); + Ok(()) + }) } /// The core of the `type_op_prove_predicate` query: for diagnostics purposes in NLL HRTB errors, From 7b5577985df7e7f3132c1e8db1eb6e1022f31276 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 23 Jun 2023 16:33:59 +0200 Subject: [PATCH 449/465] Make `try_run` return a `Result<(), ()>` instead of a boolean --- src/bootstrap/download.rs | 22 ++++++++------- src/bootstrap/lib.rs | 14 ++++++---- src/bootstrap/run.rs | 11 ++++---- src/bootstrap/test.rs | 38 ++++++++++++++------------ src/bootstrap/tool.rs | 2 +- src/bootstrap/util.rs | 2 +- src/tools/build_helper/src/util.rs | 20 ++++++++------ src/tools/rustdoc-gui-test/src/main.rs | 4 +-- 8 files changed, 63 insertions(+), 50 deletions(-) diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs index 06f479808b975..cb40521dda763 100644 --- a/src/bootstrap/download.rs +++ b/src/bootstrap/download.rs @@ -54,9 +54,9 @@ impl Config { /// Runs a command, printing out nice contextual information if it fails. /// Exits if the command failed to execute at all, otherwise returns its /// `status.success()`. - pub(crate) fn try_run(&self, cmd: &mut Command) -> bool { + pub(crate) fn try_run(&self, cmd: &mut Command) -> Result<(), ()> { if self.dry_run() { - return true; + return Ok(()); } self.verbose(&format!("running: {:?}", cmd)); try_run(cmd, self.is_verbose()) @@ -156,12 +156,14 @@ impl Config { ]; } "; - nix_build_succeeded = self.try_run(Command::new("nix-build").args(&[ - Path::new("-E"), - Path::new(NIX_EXPR), - Path::new("-o"), - &nix_deps_dir, - ])); + nix_build_succeeded = self + .try_run(Command::new("nix-build").args(&[ + Path::new("-E"), + Path::new(NIX_EXPR), + Path::new("-o"), + &nix_deps_dir, + ])) + .is_ok(); nix_deps_dir }); if !nix_build_succeeded { @@ -186,7 +188,7 @@ impl Config { patchelf.args(&["--set-interpreter", dynamic_linker.trim_end()]); } - self.try_run(patchelf.arg(fname)); + self.try_run(patchelf.arg(fname)).unwrap(); } fn download_file(&self, url: &str, dest_path: &Path, help_on_error: &str) { @@ -237,7 +239,7 @@ impl Config { "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')", url, tempfile.to_str().expect("invalid UTF-8 not supported with powershell downloads"), ), - ])) { + ])).is_err() { return; } eprintln!("\nspurious failure, trying again"); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index d7e77aeb338f6..d389b568f563d 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -333,7 +333,7 @@ forward! { create(path: &Path, s: &str), remove(f: &Path), tempdir() -> PathBuf, - try_run(cmd: &mut Command) -> bool, + try_run(cmd: &mut Command) -> Result<(), ()>, llvm_link_shared() -> bool, download_rustc() -> bool, initial_rustfmt() -> Option, @@ -614,11 +614,13 @@ impl Build { } // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error). - let has_local_modifications = !self.try_run( - Command::new("git") - .args(&["diff-index", "--quiet", "HEAD"]) - .current_dir(&absolute_path), - ); + let has_local_modifications = self + .try_run( + Command::new("git") + .args(&["diff-index", "--quiet", "HEAD"]) + .current_dir(&absolute_path), + ) + .is_err(); if has_local_modifications { self.run(Command::new("git").args(&["stash", "push"]).current_dir(&absolute_path)); } diff --git a/src/bootstrap/run.rs b/src/bootstrap/run.rs index ec01f744b8250..c97b759273717 100644 --- a/src/bootstrap/run.rs +++ b/src/bootstrap/run.rs @@ -27,7 +27,8 @@ impl Step for ExpandYamlAnchors { try_run( builder, &mut builder.tool_cmd(Tool::ExpandYamlAnchors).arg("generate").arg(&builder.src), - ); + ) + .unwrap(); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -39,17 +40,17 @@ impl Step for ExpandYamlAnchors { } } -fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> bool { +fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> Result<(), ()> { if !builder.fail_fast { - if !builder.try_run(cmd) { + if let Err(e) = builder.try_run(cmd) { let mut failures = builder.delayed_failures.borrow_mut(); failures.push(format!("{:?}", cmd)); - return false; + return Err(e); } } else { builder.run(cmd); } - true + Ok(()) } #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 9212362f6c9e1..873ed61daf33c 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -48,17 +48,17 @@ const MIR_OPT_BLESS_TARGET_MAPPING: &[(&str, &str)] = &[ // build for, so there is no entry for "aarch64-apple-darwin" here. ]; -fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> bool { +fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> Result<(), ()> { if !builder.fail_fast { - if !builder.try_run(cmd) { + if let Err(e) = builder.try_run(cmd) { let mut failures = builder.delayed_failures.borrow_mut(); failures.push(format!("{:?}", cmd)); - return false; + return Err(e); } } else { builder.run(cmd); } - true + Ok(()) } fn try_run_quiet(builder: &Builder<'_>, cmd: &mut Command) -> bool { @@ -187,7 +187,8 @@ You can skip linkcheck with --exclude src/tools/linkchecker" try_run( builder, builder.tool_cmd(Tool::Linkchecker).arg(builder.out.join(host.triple).join("doc")), - ); + ) + .unwrap(); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -240,7 +241,8 @@ impl Step for HtmlCheck { builder.default_doc(&[]); builder.ensure(crate::doc::Rustc::new(builder.top_stage, self.target, builder)); - try_run(builder, builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target))); + try_run(builder, builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target))) + .unwrap(); } } @@ -286,7 +288,8 @@ impl Step for Cargotest { .args(builder.config.test_args()) .env("RUSTC", builder.rustc(compiler)) .env("RUSTDOC", builder.rustdoc(compiler)), - ); + ) + .unwrap(); } } @@ -785,7 +788,7 @@ impl Step for Clippy { cargo.add_rustc_lib_path(builder, compiler); let mut cargo = prepare_cargo_test(cargo, &[], &[], "clippy", compiler, host, builder); - if builder.try_run(&mut cargo) { + if builder.try_run(&mut cargo).is_ok() { // The tests succeeded; nothing to do. return; } @@ -858,7 +861,7 @@ impl Step for RustdocTheme { util::lld_flag_no_threads(self.compiler.host.contains("windows")), ); } - try_run(builder, &mut cmd); + try_run(builder, &mut cmd).unwrap(); } } @@ -1109,7 +1112,7 @@ help: to skip test's attempt to check tidiness, pass `--exclude src/tools/tidy` } builder.info("tidy check"); - try_run(builder, &mut cmd); + try_run(builder, &mut cmd).unwrap(); builder.ensure(ExpandYamlAnchors); @@ -1157,7 +1160,8 @@ impl Step for ExpandYamlAnchors { try_run( builder, &mut builder.tool_cmd(Tool::ExpandYamlAnchors).arg("check").arg(&builder.src), - ); + ) + .unwrap(); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -1936,7 +1940,7 @@ impl BookTest { compiler.host, ); let _time = util::timeit(&builder); - let toolstate = if try_run(builder, &mut rustbook_cmd) { + let toolstate = if try_run(builder, &mut rustbook_cmd).is_ok() { ToolState::TestPass } else { ToolState::TestFail @@ -2094,7 +2098,7 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> cmd.arg("--test-args").arg(test_args); if builder.config.verbose_tests { - try_run(builder, &mut cmd) + try_run(builder, &mut cmd).is_ok() } else { try_run_quiet(builder, &mut cmd) } @@ -2122,7 +2126,7 @@ impl Step for RustcGuide { let src = builder.src.join(relative_path); let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook); - let toolstate = if try_run(builder, rustbook_cmd.arg("linkcheck").arg(&src)) { + let toolstate = if try_run(builder, rustbook_cmd.arg("linkcheck").arg(&src)).is_ok() { ToolState::TestPass } else { ToolState::TestFail @@ -2661,7 +2665,7 @@ impl Step for Bootstrap { fn run(self, builder: &Builder<'_>) { let mut check_bootstrap = Command::new(&builder.python()); check_bootstrap.arg("bootstrap_test.py").current_dir(builder.src.join("src/bootstrap/")); - try_run(builder, &mut check_bootstrap); + try_run(builder, &mut check_bootstrap).unwrap(); let host = builder.config.build; let compiler = builder.compiler(0, host); @@ -2733,7 +2737,7 @@ impl Step for TierCheck { } builder.info("platform support check"); - try_run(builder, &mut cargo.into()); + try_run(builder, &mut cargo.into()).unwrap(); } } @@ -2813,7 +2817,7 @@ impl Step for RustInstaller { cmd.env("CARGO", &builder.initial_cargo); cmd.env("RUSTC", &builder.initial_rustc); cmd.env("TMP_DIR", &tmpdir); - try_run(builder, &mut cmd); + try_run(builder, &mut cmd).unwrap(); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 96341b69df046..126f0b1eb31a4 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -107,7 +107,7 @@ impl Step for ToolBuild { ); let mut cargo = Command::from(cargo); - let is_expected = builder.try_run(&mut cargo); + let is_expected = builder.try_run(&mut cargo).is_ok(); builder.save_toolstate( tool, diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 1ec49f80d632e..b291584b300ce 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -228,7 +228,7 @@ pub fn is_valid_test_suite_arg<'a, P: AsRef>( } pub fn run(cmd: &mut Command, print_cmd_on_fail: bool) { - if !try_run(cmd, print_cmd_on_fail) { + if try_run(cmd, print_cmd_on_fail).is_err() { crate::detail_exit_macro!(1); } } diff --git a/src/tools/build_helper/src/util.rs b/src/tools/build_helper/src/util.rs index 731095023a96e..11b8a228b8a8e 100644 --- a/src/tools/build_helper/src/util.rs +++ b/src/tools/build_helper/src/util.rs @@ -25,17 +25,21 @@ pub fn fail(s: &str) -> ! { detail_exit(1, cfg!(test)); } -pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { +pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> Result<(), ()> { let status = match cmd.status() { Ok(status) => status, Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)), }; - if !status.success() && print_cmd_on_fail { - println!( - "\n\ncommand did not execute successfully: {:?}\n\ - expected success, got: {}\n\n", - cmd, status - ); + if !status.success() { + if print_cmd_on_fail { + println!( + "\n\ncommand did not execute successfully: {:?}\n\ + expected success, got: {}\n\n", + cmd, status + ); + } + Err(()) + } else { + Ok(()) } - status.success() } diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs index ed91763420a59..0ddd2c66cf9ea 100644 --- a/src/tools/rustdoc-gui-test/src/main.rs +++ b/src/tools/rustdoc-gui-test/src/main.rs @@ -128,7 +128,7 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse } } - if !try_run(&mut cargo, config.verbose) { + if try_run(&mut cargo, config.verbose).is_err() { eprintln!("failed to document `{}`", entry.path().display()); panic!("Cannot run rustdoc-gui tests"); } @@ -161,5 +161,5 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse command.args(&config.test_args); - if try_run(&mut command, config.verbose) { Ok(()) } else { Err(()) } + try_run(&mut command, config.verbose) } From f12695b53b6b8e5105c3813f402404e12c38ca08 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 23 Jun 2023 15:58:09 +0000 Subject: [PATCH 450/465] Don't emit same goal as input during wf obligations --- compiler/rustc_trait_selection/src/traits/wf.rs | 11 +++++++++-- tests/ui/traits/new-solver/alias-bound-unsound.rs | 2 ++ .../traits/new-solver/alias-bound-unsound.stderr | 14 +++++++++++++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index e80d413d97618..e96e89ce73ceb 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -77,12 +77,19 @@ pub fn unnormalized_obligations<'tcx>( param_env: ty::ParamEnv<'tcx>, arg: GenericArg<'tcx>, ) -> Option>> { + debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg)); + + // However, if `arg` IS an unresolved inference variable, returns `None`, + // because we are not able to make any progress at all. This is to prevent + // "livelock" where we say "$0 is WF if $0 is WF". + if arg.is_non_region_infer() { + return None; + } + if let ty::GenericArgKind::Lifetime(..) = arg.unpack() { return Some(vec![]); } - debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg)); - let mut wf = WfPredicates { infcx, param_env, diff --git a/tests/ui/traits/new-solver/alias-bound-unsound.rs b/tests/ui/traits/new-solver/alias-bound-unsound.rs index 00294c708f1fa..208d4ce966a5e 100644 --- a/tests/ui/traits/new-solver/alias-bound-unsound.rs +++ b/tests/ui/traits/new-solver/alias-bound-unsound.rs @@ -23,5 +23,7 @@ fn main() { drop(<() as Foo>::copy_me(&x)); //~^ ERROR `<() as Foo>::Item: Copy` is not satisfied //~| ERROR `<() as Foo>::Item` is not well-formed + //~| ERROR `_` is not well-formed + //~| ERROR `_` is not well-formed println!("{x}"); } diff --git a/tests/ui/traits/new-solver/alias-bound-unsound.stderr b/tests/ui/traits/new-solver/alias-bound-unsound.stderr index 9a43d2a6639ce..3c2ad8f12bd5d 100644 --- a/tests/ui/traits/new-solver/alias-bound-unsound.stderr +++ b/tests/ui/traits/new-solver/alias-bound-unsound.stderr @@ -19,6 +19,18 @@ error: the type `<() as Foo>::Item` is not well-formed LL | drop(<() as Foo>::copy_me(&x)); | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: the type `_` is not well-formed + --> $DIR/alias-bound-unsound.rs:23:5 + | +LL | drop(<() as Foo>::copy_me(&x)); + | ^^^^ + +error: the type `_` is not well-formed + --> $DIR/alias-bound-unsound.rs:23:10 + | +LL | drop(<() as Foo>::copy_me(&x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. From 2eb7d693095eb1e98b9a041b43a39c9cd228254b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 23 Jun 2023 16:26:22 +0000 Subject: [PATCH 451/465] Resolve vars when reporting WF error --- .../rustc_trait_selection/src/traits/error_reporting/mod.rs | 1 + tests/ui/for/issue-20605.next.stderr | 2 +- tests/ui/for/issue-20605.rs | 2 +- tests/ui/traits/new-solver/alias-bound-unsound.rs | 4 ++-- tests/ui/traits/new-solver/alias-bound-unsound.stderr | 4 ++-- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 75a92af714bd5..89634c59df4b4 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1049,6 +1049,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => { + let ty = self.resolve_vars_if_possible(ty); match self.tcx.sess.opts.unstable_opts.trait_solver { TraitSolver::Classic => { // WF predicates cannot themselves make diff --git a/tests/ui/for/issue-20605.next.stderr b/tests/ui/for/issue-20605.next.stderr index 5362a68c834a3..a96a53ca93e4a 100644 --- a/tests/ui/for/issue-20605.next.stderr +++ b/tests/ui/for/issue-20605.next.stderr @@ -14,7 +14,7 @@ LL | for item in *things { *item = 0 } = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature -error: the type `<_ as IntoIterator>::IntoIter` is not well-formed +error: the type ` as IntoIterator>::IntoIter` is not well-formed --> $DIR/issue-20605.rs:5:17 | LL | for item in *things { *item = 0 } diff --git a/tests/ui/for/issue-20605.rs b/tests/ui/for/issue-20605.rs index 499271fa92fa9..64156b357051b 100644 --- a/tests/ui/for/issue-20605.rs +++ b/tests/ui/for/issue-20605.rs @@ -4,7 +4,7 @@ fn changer<'a>(mut things: Box>) { for item in *things { *item = 0 } //~^ ERROR the size for values of type - //[next]~^^ ERROR the type `<_ as IntoIterator>::IntoIter` is not well-formed + //[next]~^^ ERROR the type ` as IntoIterator>::IntoIter` is not well-formed //[next]~| ERROR the trait bound `dyn Iterator: IntoIterator` is not satisfied } diff --git a/tests/ui/traits/new-solver/alias-bound-unsound.rs b/tests/ui/traits/new-solver/alias-bound-unsound.rs index 208d4ce966a5e..6b6a77e2c7ee8 100644 --- a/tests/ui/traits/new-solver/alias-bound-unsound.rs +++ b/tests/ui/traits/new-solver/alias-bound-unsound.rs @@ -23,7 +23,7 @@ fn main() { drop(<() as Foo>::copy_me(&x)); //~^ ERROR `<() as Foo>::Item: Copy` is not satisfied //~| ERROR `<() as Foo>::Item` is not well-formed - //~| ERROR `_` is not well-formed - //~| ERROR `_` is not well-formed + //~| ERROR `<() as Foo>::Item` is not well-formed + //~| ERROR `<() as Foo>::Item` is not well-formed println!("{x}"); } diff --git a/tests/ui/traits/new-solver/alias-bound-unsound.stderr b/tests/ui/traits/new-solver/alias-bound-unsound.stderr index 3c2ad8f12bd5d..89abc608213e6 100644 --- a/tests/ui/traits/new-solver/alias-bound-unsound.stderr +++ b/tests/ui/traits/new-solver/alias-bound-unsound.stderr @@ -19,13 +19,13 @@ error: the type `<() as Foo>::Item` is not well-formed LL | drop(<() as Foo>::copy_me(&x)); | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: the type `_` is not well-formed +error: the type `<() as Foo>::Item` is not well-formed --> $DIR/alias-bound-unsound.rs:23:5 | LL | drop(<() as Foo>::copy_me(&x)); | ^^^^ -error: the type `_` is not well-formed +error: the type `<() as Foo>::Item` is not well-formed --> $DIR/alias-bound-unsound.rs:23:10 | LL | drop(<() as Foo>::copy_me(&x)); From 071004064869b56eb31e3e09228a0c1d0ce47c9e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 23 Jun 2023 17:21:35 +0000 Subject: [PATCH 452/465] Make sure to include default en-US ftl resources for rustc_error crate --- compiler/rustc_driver_impl/src/lib.rs | 1 + tests/run-make/target-specs/Makefile | 1 + tests/run-make/target-specs/endianness-mismatch.json | 11 +++++++++++ 3 files changed, 13 insertions(+) create mode 100644 tests/run-make/target-specs/endianness-mismatch.json diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index a08d53e28c637..984cc1557a49b 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -97,6 +97,7 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[ rustc_codegen_ssa::DEFAULT_LOCALE_RESOURCE, rustc_const_eval::DEFAULT_LOCALE_RESOURCE, rustc_error_messages::DEFAULT_LOCALE_RESOURCE, + rustc_errors::DEFAULT_LOCALE_RESOURCE, rustc_expand::DEFAULT_LOCALE_RESOURCE, rustc_hir_analysis::DEFAULT_LOCALE_RESOURCE, rustc_hir_typeck::DEFAULT_LOCALE_RESOURCE, diff --git a/tests/run-make/target-specs/Makefile b/tests/run-make/target-specs/Makefile index a33f5368e3cfd..62d5365a73d03 100644 --- a/tests/run-make/target-specs/Makefile +++ b/tests/run-make/target-specs/Makefile @@ -8,4 +8,5 @@ all: RUST_TARGET_PATH=. $(RUSTC) foo.rs --target=my-x86_64-unknown-linux-gnu-platform --crate-type=lib --emit=asm $(RUSTC) -Z unstable-options --target=my-awesome-platform.json --print target-spec-json > $(TMPDIR)/test-platform.json && $(RUSTC) -Z unstable-options --target=$(TMPDIR)/test-platform.json --print target-spec-json | diff -q $(TMPDIR)/test-platform.json - $(RUSTC) foo.rs --target=definitely-not-builtin-target 2>&1 | $(CGREP) 'may not set is_builtin' + $(RUSTC) foo.rs --target=endianness-mismatch 2>&1 | $(CGREP) '"data-layout" claims architecture is little-endian' $(RUSTC) foo.rs --target=mismatching-data-layout --crate-type=lib diff --git a/tests/run-make/target-specs/endianness-mismatch.json b/tests/run-make/target-specs/endianness-mismatch.json new file mode 100644 index 0000000000000..431053ea99b60 --- /dev/null +++ b/tests/run-make/target-specs/endianness-mismatch.json @@ -0,0 +1,11 @@ +{ + "pre-link-args": {"gcc": ["-m64"]}, + "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128", + "linker-flavor": "gcc", + "llvm-target": "x86_64-unknown-linux-gnu", + "target-endian": "big", + "target-pointer-width": "64", + "target-c-int-width": "32", + "arch": "x86_64", + "os": "linux" +} From 3b17012ac9db67be037e3ce3fa822e562a021eb4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 23 Jun 2023 19:34:37 +0200 Subject: [PATCH 453/465] Fix GUI test for popover --- tests/rustdoc-gui/help-page.goml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/rustdoc-gui/help-page.goml b/tests/rustdoc-gui/help-page.goml index 1a1c1b28f6131..6e880302f28d5 100644 --- a/tests/rustdoc-gui/help-page.goml +++ b/tests/rustdoc-gui/help-page.goml @@ -67,5 +67,5 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" set-window-size: (1000, 1000) // Popover only appears when the screen width is >700px. assert-false: "#help" click: "#help-button > a" -click: ".popover a[href='https://doc.rust-lang.org/rustdoc/']" -wait-for-document-property: {"URL": "https://doc.rust-lang.org/rustdoc/"} +click: "//*[@id='help']//a[text()='the rustdoc book']" +wait-for-document-property: ({"URL": "https://doc.rust-lang.org/"}, STARTS_WITH) From d77e55bbb9ee3b09a64c9ff770ba663688f52d79 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 23 Jun 2023 17:30:52 -0300 Subject: [PATCH 454/465] Fix return type notation errors with -Zlower-impl-trait-in-trait-to-assoc-ty --- .../rustc_hir_analysis/src/astconv/bounds.rs | 2 +- ...r => bad-inputs-and-output.current.stderr} | 12 ++--- .../bad-inputs-and-output.next.stderr | 48 +++++++++++++++++++ .../bad-inputs-and-output.rs | 2 + .../basic.current_with.stderr | 11 +++++ .../basic.current_without.stderr | 29 +++++++++++ .../basic.next_with.stderr | 11 +++++ .../basic.next_without.stderr | 29 +++++++++++ .../return-type-notation/basic.rs | 14 ++++-- ...quality.stderr => equality.current.stderr} | 4 +- .../return-type-notation/equality.next.stderr | 17 +++++++ .../return-type-notation/equality.rs | 2 + ...derr => issue-110963-early.current.stderr} | 10 ++-- .../issue-110963-early.next.stderr | 37 ++++++++++++++ .../issue-110963-early.rs | 2 + ...tderr => issue-110963-late.current.stderr} | 2 +- .../issue-110963-late.next.stderr | 11 +++++ .../return-type-notation/issue-110963-late.rs | 2 + ...derr => super-method-bound.current.stderr} | 2 +- .../super-method-bound.next.stderr | 11 +++++ .../super-method-bound.rs | 2 + ...stderr => supertrait-bound.current.stderr} | 2 +- .../supertrait-bound.next.stderr | 11 +++++ .../return-type-notation/supertrait-bound.rs | 2 + ....stderr => ty-or-ct-params.current.stderr} | 6 +-- .../ty-or-ct-params.next.stderr | 29 +++++++++++ .../return-type-notation/ty-or-ct-params.rs | 2 + 27 files changed, 287 insertions(+), 25 deletions(-) rename tests/ui/associated-type-bounds/return-type-notation/{bad-inputs-and-output.stderr => bad-inputs-and-output.current.stderr} (87%) create mode 100644 tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.next.stderr create mode 100644 tests/ui/associated-type-bounds/return-type-notation/basic.current_with.stderr create mode 100644 tests/ui/associated-type-bounds/return-type-notation/basic.current_without.stderr create mode 100644 tests/ui/associated-type-bounds/return-type-notation/basic.next_with.stderr create mode 100644 tests/ui/associated-type-bounds/return-type-notation/basic.next_without.stderr rename tests/ui/associated-type-bounds/return-type-notation/{equality.stderr => equality.current.stderr} (91%) create mode 100644 tests/ui/associated-type-bounds/return-type-notation/equality.next.stderr rename tests/ui/async-await/return-type-notation/{issue-110963-early.stderr => issue-110963-early.current.stderr} (86%) create mode 100644 tests/ui/async-await/return-type-notation/issue-110963-early.next.stderr rename tests/ui/async-await/return-type-notation/{issue-110963-late.stderr => issue-110963-late.current.stderr} (91%) create mode 100644 tests/ui/async-await/return-type-notation/issue-110963-late.next.stderr rename tests/ui/async-await/return-type-notation/{super-method-bound.stderr => super-method-bound.current.stderr} (91%) create mode 100644 tests/ui/async-await/return-type-notation/super-method-bound.next.stderr rename tests/ui/async-await/return-type-notation/{supertrait-bound.stderr => supertrait-bound.current.stderr} (92%) create mode 100644 tests/ui/async-await/return-type-notation/supertrait-bound.next.stderr rename tests/ui/async-await/return-type-notation/{ty-or-ct-params.stderr => ty-or-ct-params.current.stderr} (90%) create mode 100644 tests/ui/async-await/return-type-notation/ty-or-ct-params.next.stderr diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index e4eb0e6abd435..d29601e9008c3 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -412,7 +412,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { // an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait). let output = tcx.fn_sig(assoc_item.def_id).skip_binder().output(); let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind() - && tcx.def_kind(alias_ty.def_id) == DefKind::ImplTraitPlaceholder + && tcx.is_impl_trait_in_trait(alias_ty.def_id) { alias_ty } else { diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.current.stderr similarity index 87% rename from tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr rename to tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.current.stderr index 95ef7d82fcab8..b8be132e6b6e6 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.current.stderr @@ -1,11 +1,11 @@ error: return type notation uses `()` instead of `(..)` for elided arguments - --> $DIR/bad-inputs-and-output.rs:18:24 + --> $DIR/bad-inputs-and-output.rs:20:24 | LL | fn baz>() {} | ^^ help: remove the `..` error[E0658]: associated type bounds are unstable - --> $DIR/bad-inputs-and-output.rs:10:17 + --> $DIR/bad-inputs-and-output.rs:12:17 | LL | fn foo>() {} | ^^^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL | fn foo>() {} = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable error[E0658]: associated type bounds are unstable - --> $DIR/bad-inputs-and-output.rs:14:17 + --> $DIR/bad-inputs-and-output.rs:16:17 | LL | fn bar (): Send>>() {} | ^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | fn bar (): Send>>() {} = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/bad-inputs-and-output.rs:3:12 + --> $DIR/bad-inputs-and-output.rs:5:12 | LL | #![feature(return_type_notation, async_fn_in_trait)] | ^^^^^^^^^^^^^^^^^^^^ @@ -32,13 +32,13 @@ LL | #![feature(return_type_notation, async_fn_in_trait)] = note: `#[warn(incomplete_features)]` on by default error: argument types not allowed with return type notation - --> $DIR/bad-inputs-and-output.rs:10:23 + --> $DIR/bad-inputs-and-output.rs:12:23 | LL | fn foo>() {} | ^^^^^ help: remove the input types: `()` error: return type not allowed with return type notation - --> $DIR/bad-inputs-and-output.rs:14:25 + --> $DIR/bad-inputs-and-output.rs:16:25 | LL | fn bar (): Send>>() {} | ^^^^^^ help: remove the return type diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.next.stderr b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.next.stderr new file mode 100644 index 0000000000000..b8be132e6b6e6 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.next.stderr @@ -0,0 +1,48 @@ +error: return type notation uses `()` instead of `(..)` for elided arguments + --> $DIR/bad-inputs-and-output.rs:20:24 + | +LL | fn baz>() {} + | ^^ help: remove the `..` + +error[E0658]: associated type bounds are unstable + --> $DIR/bad-inputs-and-output.rs:12:17 + | +LL | fn foo>() {} + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #52662 for more information + = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable + +error[E0658]: associated type bounds are unstable + --> $DIR/bad-inputs-and-output.rs:16:17 + | +LL | fn bar (): Send>>() {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #52662 for more information + = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable + +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/bad-inputs-and-output.rs:5:12 + | +LL | #![feature(return_type_notation, async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: argument types not allowed with return type notation + --> $DIR/bad-inputs-and-output.rs:12:23 + | +LL | fn foo>() {} + | ^^^^^ help: remove the input types: `()` + +error: return type not allowed with return type notation + --> $DIR/bad-inputs-and-output.rs:16:25 + | +LL | fn bar (): Send>>() {} + | ^^^^^^ help: remove the return type + +error: aborting due to 5 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs index 58ce41d1a8933..771acb6c4e7f3 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs @@ -1,4 +1,6 @@ // edition: 2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_type_notation, async_fn_in_trait)] //~^ WARN the feature `return_type_notation` is incomplete diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.current_with.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.current_with.stderr new file mode 100644 index 0000000000000..98c1a282779d6 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.current_with.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/basic.rs:8:12 + | +LL | #![feature(return_type_notation, async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.current_without.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.current_without.stderr new file mode 100644 index 0000000000000..1066c420c31c2 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.current_without.stderr @@ -0,0 +1,29 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/basic.rs:8:12 + | +LL | #![feature(return_type_notation, async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: future cannot be sent between threads safely + --> $DIR/basic.rs:26:13 + | +LL | is_send(foo::()); + | ^^^^^^^^^^ future returned by `foo` is not `Send` + | + = help: within `impl Future>`, the trait `Send` is not implemented for `impl Future>` +note: future is not `Send` as it awaits another future which is not `Send` + --> $DIR/basic.rs:16:5 + | +LL | T::method().await?; + | ^^^^^^^^^^^ await occurs here on type `impl Future>`, which is not `Send` +note: required by a bound in `is_send` + --> $DIR/basic.rs:20:20 + | +LL | fn is_send(_: impl Send) {} + | ^^^^ required by this bound in `is_send` + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.next_with.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.next_with.stderr new file mode 100644 index 0000000000000..98c1a282779d6 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.next_with.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/basic.rs:8:12 + | +LL | #![feature(return_type_notation, async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.next_without.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.next_without.stderr new file mode 100644 index 0000000000000..1066c420c31c2 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.next_without.stderr @@ -0,0 +1,29 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/basic.rs:8:12 + | +LL | #![feature(return_type_notation, async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: future cannot be sent between threads safely + --> $DIR/basic.rs:26:13 + | +LL | is_send(foo::()); + | ^^^^^^^^^^ future returned by `foo` is not `Send` + | + = help: within `impl Future>`, the trait `Send` is not implemented for `impl Future>` +note: future is not `Send` as it awaits another future which is not `Send` + --> $DIR/basic.rs:16:5 + | +LL | T::method().await?; + | ^^^^^^^^^^^ await occurs here on type `impl Future>`, which is not `Send` +note: required by a bound in `is_send` + --> $DIR/basic.rs:20:20 + | +LL | fn is_send(_: impl Send) {} + | ^^^^ required by this bound in `is_send` + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.rs b/tests/ui/associated-type-bounds/return-type-notation/basic.rs index edc6a8e4caf0a..d443c9dc11ba5 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.rs @@ -1,6 +1,9 @@ -// revisions: with without +// revisions: current_with current_without next_with next_without +// [next_with] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// [next_without] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty // edition: 2021 -//[with] check-pass +// [current_with] check-pass +// [next_with] check-pass #![feature(return_type_notation, async_fn_in_trait)] //~^ WARN the feature `return_type_notation` is incomplete @@ -17,11 +20,12 @@ async fn foo() -> Result<(), ()> { fn is_send(_: impl Send) {} fn test< - #[cfg(with)] T: Foo, - #[cfg(without)] T: Foo, + #[cfg(any(current_with, next_with))] T: Foo, + #[cfg(any(current_without, next_without))] T: Foo, >() { is_send(foo::()); - //[without]~^ ERROR future cannot be sent between threads safely + //[current_without]~^ ERROR future cannot be sent between threads safely + //[next_without]~^^ ERROR future cannot be sent between threads safely } fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.stderr b/tests/ui/associated-type-bounds/return-type-notation/equality.current.stderr similarity index 91% rename from tests/ui/associated-type-bounds/return-type-notation/equality.stderr rename to tests/ui/associated-type-bounds/return-type-notation/equality.current.stderr index 490bfdc4c3c60..b631dd0ebb590 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/equality.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/equality.rs:3:12 + --> $DIR/equality.rs:5:12 | LL | #![feature(return_type_notation, async_fn_in_trait)] | ^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![feature(return_type_notation, async_fn_in_trait)] = note: `#[warn(incomplete_features)]` on by default error: return type notation is not allowed to use type equality - --> $DIR/equality.rs:12:18 + --> $DIR/equality.rs:14:18 | LL | fn test>>>() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.next.stderr b/tests/ui/associated-type-bounds/return-type-notation/equality.next.stderr new file mode 100644 index 0000000000000..b631dd0ebb590 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.next.stderr @@ -0,0 +1,17 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/equality.rs:5:12 + | +LL | #![feature(return_type_notation, async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: return type notation is not allowed to use type equality + --> $DIR/equality.rs:14:18 + | +LL | fn test>>>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.rs b/tests/ui/associated-type-bounds/return-type-notation/equality.rs index 6884305d7b37b..0d6545cc2983f 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/equality.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.rs @@ -1,4 +1,6 @@ // edition: 2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_type_notation, async_fn_in_trait)] //~^ WARN the feature `return_type_notation` is incomplete diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.current.stderr similarity index 86% rename from tests/ui/async-await/return-type-notation/issue-110963-early.stderr rename to tests/ui/async-await/return-type-notation/issue-110963-early.current.stderr index 33e22dec3f7b2..1b847b59eb5b9 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-110963-early.rs:4:12 + --> $DIR/issue-110963-early.rs:6:12 | LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![feature(return_type_notation)] = note: `#[warn(incomplete_features)]` on by default error: higher-ranked lifetime error - --> $DIR/issue-110963-early.rs:15:5 + --> $DIR/issue-110963-early.rs:17:5 | LL | / spawn(async move { LL | | let mut hc = hc; @@ -18,10 +18,10 @@ LL | | } LL | | }); | |______^ | - = note: could not prove `[async block@$DIR/issue-110963-early.rs:15:11: 20:6]: Send` + = note: could not prove `[async block@$DIR/issue-110963-early.rs:17:11: 22:6]: Send` error: higher-ranked lifetime error - --> $DIR/issue-110963-early.rs:15:5 + --> $DIR/issue-110963-early.rs:17:5 | LL | / spawn(async move { LL | | let mut hc = hc; @@ -31,7 +31,7 @@ LL | | } LL | | }); | |______^ | - = note: could not prove `[async block@$DIR/issue-110963-early.rs:15:11: 20:6]: Send` + = note: could not prove `[async block@$DIR/issue-110963-early.rs:17:11: 22:6]: Send` error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.next.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.next.stderr new file mode 100644 index 0000000000000..1b847b59eb5b9 --- /dev/null +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.next.stderr @@ -0,0 +1,37 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-110963-early.rs:6:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: higher-ranked lifetime error + --> $DIR/issue-110963-early.rs:17:5 + | +LL | / spawn(async move { +LL | | let mut hc = hc; +LL | | if !hc.check().await { +LL | | log_health_check_failure().await; +LL | | } +LL | | }); + | |______^ + | + = note: could not prove `[async block@$DIR/issue-110963-early.rs:17:11: 22:6]: Send` + +error: higher-ranked lifetime error + --> $DIR/issue-110963-early.rs:17:5 + | +LL | / spawn(async move { +LL | | let mut hc = hc; +LL | | if !hc.check().await { +LL | | log_health_check_failure().await; +LL | | } +LL | | }); + | |______^ + | + = note: could not prove `[async block@$DIR/issue-110963-early.rs:17:11: 22:6]: Send` + +error: aborting due to 2 previous errors; 1 warning emitted + diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.rs b/tests/ui/async-await/return-type-notation/issue-110963-early.rs index 0ecbca5c13bdd..eee31aa1fe5a2 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.rs +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.rs @@ -1,5 +1,7 @@ // edition: 2021 // known-bug: #110963 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_type_notation)] #![feature(async_fn_in_trait)] diff --git a/tests/ui/async-await/return-type-notation/issue-110963-late.stderr b/tests/ui/async-await/return-type-notation/issue-110963-late.current.stderr similarity index 91% rename from tests/ui/async-await/return-type-notation/issue-110963-late.stderr rename to tests/ui/async-await/return-type-notation/issue-110963-late.current.stderr index 9c6966537a73a..018f4f2207ae7 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-late.stderr +++ b/tests/ui/async-await/return-type-notation/issue-110963-late.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-110963-late.rs:4:12 + --> $DIR/issue-110963-late.rs:6:12 | LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/return-type-notation/issue-110963-late.next.stderr b/tests/ui/async-await/return-type-notation/issue-110963-late.next.stderr new file mode 100644 index 0000000000000..018f4f2207ae7 --- /dev/null +++ b/tests/ui/async-await/return-type-notation/issue-110963-late.next.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-110963-late.rs:6:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/async-await/return-type-notation/issue-110963-late.rs b/tests/ui/async-await/return-type-notation/issue-110963-late.rs index 17b5d775d4479..ea047cd3b16c3 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-late.rs +++ b/tests/ui/async-await/return-type-notation/issue-110963-late.rs @@ -1,5 +1,7 @@ // edition: 2021 // check-pass +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_type_notation)] //~^ WARN the feature `return_type_notation` is incomplete diff --git a/tests/ui/async-await/return-type-notation/super-method-bound.stderr b/tests/ui/async-await/return-type-notation/super-method-bound.current.stderr similarity index 91% rename from tests/ui/async-await/return-type-notation/super-method-bound.stderr rename to tests/ui/async-await/return-type-notation/super-method-bound.current.stderr index ac0668d3c4492..891c802c5f4a7 100644 --- a/tests/ui/async-await/return-type-notation/super-method-bound.stderr +++ b/tests/ui/async-await/return-type-notation/super-method-bound.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/super-method-bound.rs:4:31 + --> $DIR/super-method-bound.rs:6:31 | LL | #![feature(async_fn_in_trait, return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/return-type-notation/super-method-bound.next.stderr b/tests/ui/async-await/return-type-notation/super-method-bound.next.stderr new file mode 100644 index 0000000000000..891c802c5f4a7 --- /dev/null +++ b/tests/ui/async-await/return-type-notation/super-method-bound.next.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/super-method-bound.rs:6:31 + | +LL | #![feature(async_fn_in_trait, return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/async-await/return-type-notation/super-method-bound.rs b/tests/ui/async-await/return-type-notation/super-method-bound.rs index 58ea3578db62e..0163c62f545fa 100644 --- a/tests/ui/async-await/return-type-notation/super-method-bound.rs +++ b/tests/ui/async-await/return-type-notation/super-method-bound.rs @@ -1,5 +1,7 @@ // edition:2021 // check-pass +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait, return_type_notation)] //~^ WARN the feature `return_type_notation` is incomplete diff --git a/tests/ui/async-await/return-type-notation/supertrait-bound.stderr b/tests/ui/async-await/return-type-notation/supertrait-bound.current.stderr similarity index 92% rename from tests/ui/async-await/return-type-notation/supertrait-bound.stderr rename to tests/ui/async-await/return-type-notation/supertrait-bound.current.stderr index c8cec4946b4e4..05cb0ca4abd25 100644 --- a/tests/ui/async-await/return-type-notation/supertrait-bound.stderr +++ b/tests/ui/async-await/return-type-notation/supertrait-bound.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/supertrait-bound.rs:3:49 + --> $DIR/supertrait-bound.rs:5:49 | LL | #![feature(return_position_impl_trait_in_trait, return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/return-type-notation/supertrait-bound.next.stderr b/tests/ui/async-await/return-type-notation/supertrait-bound.next.stderr new file mode 100644 index 0000000000000..05cb0ca4abd25 --- /dev/null +++ b/tests/ui/async-await/return-type-notation/supertrait-bound.next.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/supertrait-bound.rs:5:49 + | +LL | #![feature(return_position_impl_trait_in_trait, return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/async-await/return-type-notation/supertrait-bound.rs b/tests/ui/async-await/return-type-notation/supertrait-bound.rs index 19bcfe3046bdc..09de32c5d4a32 100644 --- a/tests/ui/async-await/return-type-notation/supertrait-bound.rs +++ b/tests/ui/async-await/return-type-notation/supertrait-bound.rs @@ -1,4 +1,6 @@ // check-pass +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_position_impl_trait_in_trait, return_type_notation)] //~^ WARN the feature `return_type_notation` is incomplete and may not be safe to use diff --git a/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr b/tests/ui/async-await/return-type-notation/ty-or-ct-params.current.stderr similarity index 90% rename from tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr rename to tests/ui/async-await/return-type-notation/ty-or-ct-params.current.stderr index 76928c5d7a3e2..1aa008fe46924 100644 --- a/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr +++ b/tests/ui/async-await/return-type-notation/ty-or-ct-params.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/ty-or-ct-params.rs:3:31 + --> $DIR/ty-or-ct-params.rs:5:31 | LL | #![feature(async_fn_in_trait, return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![feature(async_fn_in_trait, return_type_notation)] = note: `#[warn(incomplete_features)]` on by default error: return type notation is not allowed for functions that have type parameters - --> $DIR/ty-or-ct-params.rs:14:12 + --> $DIR/ty-or-ct-params.rs:16:12 | LL | async fn bar() {} | - type parameter declared here @@ -17,7 +17,7 @@ LL | T: Foo, | ^^^^^^^^^^^ error: return type notation is not allowed for functions that have const parameters - --> $DIR/ty-or-ct-params.rs:14:25 + --> $DIR/ty-or-ct-params.rs:16:25 | LL | async fn baz() {} | -------------- const parameter declared here diff --git a/tests/ui/async-await/return-type-notation/ty-or-ct-params.next.stderr b/tests/ui/async-await/return-type-notation/ty-or-ct-params.next.stderr new file mode 100644 index 0000000000000..1aa008fe46924 --- /dev/null +++ b/tests/ui/async-await/return-type-notation/ty-or-ct-params.next.stderr @@ -0,0 +1,29 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/ty-or-ct-params.rs:5:31 + | +LL | #![feature(async_fn_in_trait, return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: return type notation is not allowed for functions that have type parameters + --> $DIR/ty-or-ct-params.rs:16:12 + | +LL | async fn bar() {} + | - type parameter declared here +... +LL | T: Foo, + | ^^^^^^^^^^^ + +error: return type notation is not allowed for functions that have const parameters + --> $DIR/ty-or-ct-params.rs:16:25 + | +LL | async fn baz() {} + | -------------- const parameter declared here +... +LL | T: Foo, + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted + diff --git a/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs b/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs index 7871a2fed03b8..3141da1d2968d 100644 --- a/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs +++ b/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs @@ -1,4 +1,6 @@ // edition: 2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait, return_type_notation)] //~^ WARN the feature `return_type_notation` is incomplete From 6d997876c1f3a9fe5b06ea2b2f64e77eecc41adb Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 23 Jun 2023 18:18:05 -0300 Subject: [PATCH 455/465] Fix associated type suggestion when -Zlower-impl-trait-in-trait-to-assoc-ty --- .../rustc_hir_analysis/src/astconv/errors.rs | 20 +++++++++----- ...te-return_type_notation.cfg_current.stderr | 27 +++++++++++++++++++ ...-gate-return_type_notation.cfg_next.stderr | 27 +++++++++++++++++++ ...ate-return_type_notation.no_current.stderr | 13 +++++++++ ...e-gate-return_type_notation.no_next.stderr | 13 +++++++++ .../feature-gate-return_type_notation.rs | 24 +++++++++++------ 6 files changed, 110 insertions(+), 14 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-return_type_notation.cfg_current.stderr create mode 100644 tests/ui/feature-gates/feature-gate-return_type_notation.cfg_next.stderr create mode 100644 tests/ui/feature-gates/feature-gate-return_type_notation.no_current.stderr create mode 100644 tests/ui/feature-gates/feature-gate-return_type_notation.no_next.stderr diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index 7f060af224556..dc17ef7048d01 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -122,9 +122,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let all_candidate_names: Vec<_> = all_candidates() .flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order()) - .filter_map( - |item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None }, - ) + .filter_map(|item| { + if item.opt_rpitit_info.is_none() && item.kind == ty::AssocKind::Type { + Some(item.name) + } else { + None + } + }) .collect(); if let (Some(suggested_name), true) = ( @@ -159,9 +163,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .flat_map(|trait_def_id| { self.tcx().associated_items(*trait_def_id).in_definition_order() }) - .filter_map( - |item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None }, - ) + .filter_map(|item| { + if item.opt_rpitit_info.is_none() && item.kind == ty::AssocKind::Type { + Some(item.name) + } else { + None + } + }) .collect(); if let (Some(suggested_name), true) = ( diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_current.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_current.stderr new file mode 100644 index 0000000000000..ce39f6b29713f --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_current.stderr @@ -0,0 +1,27 @@ +error[E0658]: return type notation is experimental + --> $DIR/feature-gate-return_type_notation.rs:17:17 + | +LL | fn foo>() {} + | ^^^^^^^^^ + | + = note: see issue #109417 for more information + = help: add `#![feature(return_type_notation)]` to the crate attributes to enable + +error: parenthesized generic arguments cannot be used in associated type constraints + --> $DIR/feature-gate-return_type_notation.rs:17:17 + | +LL | fn foo>() {} + | ^-- + | | + | help: remove these parentheses + +error[E0220]: associated type `m` not found for `Trait` + --> $DIR/feature-gate-return_type_notation.rs:17:17 + | +LL | fn foo>() {} + | ^ associated type `m` not found + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0220, E0658. +For more information about an error, try `rustc --explain E0220`. diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_next.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_next.stderr new file mode 100644 index 0000000000000..ce39f6b29713f --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg_next.stderr @@ -0,0 +1,27 @@ +error[E0658]: return type notation is experimental + --> $DIR/feature-gate-return_type_notation.rs:17:17 + | +LL | fn foo>() {} + | ^^^^^^^^^ + | + = note: see issue #109417 for more information + = help: add `#![feature(return_type_notation)]` to the crate attributes to enable + +error: parenthesized generic arguments cannot be used in associated type constraints + --> $DIR/feature-gate-return_type_notation.rs:17:17 + | +LL | fn foo>() {} + | ^-- + | | + | help: remove these parentheses + +error[E0220]: associated type `m` not found for `Trait` + --> $DIR/feature-gate-return_type_notation.rs:17:17 + | +LL | fn foo>() {} + | ^ associated type `m` not found + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0220, E0658. +For more information about an error, try `rustc --explain E0220`. diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.no_current.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.no_current.stderr new file mode 100644 index 0000000000000..d11359e7f48cd --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.no_current.stderr @@ -0,0 +1,13 @@ +warning: return type notation is experimental + --> $DIR/feature-gate-return_type_notation.rs:17:17 + | +LL | fn foo>() {} + | ^^^^^^^^^ + | + = note: see issue #109417 for more information + = help: add `#![feature(return_type_notation)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: 1 warning emitted + diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.no_next.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.no_next.stderr new file mode 100644 index 0000000000000..d11359e7f48cd --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.no_next.stderr @@ -0,0 +1,13 @@ +warning: return type notation is experimental + --> $DIR/feature-gate-return_type_notation.rs:17:17 + | +LL | fn foo>() {} + | ^^^^^^^^^ + | + = note: see issue #109417 for more information + = help: add `#![feature(return_type_notation)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: 1 warning emitted + diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.rs b/tests/ui/feature-gates/feature-gate-return_type_notation.rs index d9bcb65feba9a..7e8c1eb95ca8f 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.rs +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.rs @@ -1,7 +1,10 @@ // edition: 2021 -// revisions: cfg no +// revisions: cfg_current cfg_next no_current no_next +// [cfg_next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// [no_next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty -//[no] check-pass +// [no_current] check-pass +// [no_next] check-pass // Since we're not adding new syntax, `cfg`'d out RTN must pass. #![feature(async_fn_in_trait)] @@ -10,12 +13,17 @@ trait Trait { async fn m(); } -#[cfg(cfg)] +#[cfg(any(cfg_current, cfg_next))] fn foo>() {} -//[cfg]~^ ERROR return type notation is experimental -//[cfg]~| ERROR parenthesized generic arguments cannot be used in associated type constraints -//[cfg]~| ERROR associated type `m` not found for `Trait` -//[no]~^^^^ WARN return type notation is experimental -//[no]~| WARN unstable syntax can change at any point in the future, causing a hard error! +//[cfg_current]~^ ERROR return type notation is experimental +//[cfg_current]~| ERROR parenthesized generic arguments cannot be used in associated type constraints +//[cfg_current]~| ERROR associated type `m` not found for `Trait` +//[cfg_next]~^^^^ ERROR return type notation is experimental +//[cfg_next]~| ERROR parenthesized generic arguments cannot be used in associated type constraints +//[cfg_next]~| ERROR associated type `m` not found for `Trait` +//[no_current]~^^^^^^^ WARN return type notation is experimental +//[no_current]~| WARN unstable syntax can change at any point in the future, causing a hard error! +//[no_next]~^^^^^^^^^ WARN return type notation is experimental +//[no_next]~| WARN unstable syntax can change at any point in the future, causing a hard error! fn main() {} From 4246e5079e4ef8ee3f79b1d83de0123cc1fa8e00 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Sat, 24 Jun 2023 01:38:42 +0100 Subject: [PATCH 456/465] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 4cebd130ebca3..03bc66b55c290 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 4cebd130ebca3bc219180a54f3e26cc1b14a91de +Subproject commit 03bc66b55c290324bd46eb22e369c8fae1908f91 From cbe1578690b8967fbad44ad2210369d7cbec96cb Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 3 Jul 2022 21:52:57 +0200 Subject: [PATCH 457/465] Encode info for Fn/AssocFn in a single place. --- compiler/rustc_metadata/src/rmeta/encoder.rs | 83 ++++---------------- 1 file changed, 16 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index eee29d2090a82..f50467ab5314b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1315,6 +1315,19 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if should_encode_type(tcx, local_id, def_kind) { record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id)); } + if let DefKind::Fn | DefKind::AssocFn = def_kind { + self.tables.asyncness.set_some(def_id.index, tcx.asyncness(def_id)); + record_array!(self.tables.fn_arg_names[def_id] <- tcx.fn_arg_names(def_id)); + let constness = if self.tcx.is_const_fn_raw(def_id) { + hir::Constness::Const + } else { + hir::Constness::NotConst + }; + self.tables.constness.set_some(def_id.index, constness); + + record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); + self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id)); + } if let DefKind::TyParam = def_kind { let default = self.tcx.object_lifetime_default(def_id); record!(self.tables.object_lifetime_default[def_id] <- default); @@ -1446,19 +1459,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tables.assoc_container.set_some(def_id.index, trait_item.container); match trait_item.kind { - ty::AssocKind::Const => {} - ty::AssocKind::Fn => { - record_array!(self.tables.fn_arg_names[def_id] <- tcx.fn_arg_names(def_id)); - self.tables.asyncness.set_some(def_id.index, tcx.asyncness(def_id)); - self.tables.constness.set_some(def_id.index, hir::Constness::NotConst); - } + ty::AssocKind::Const | ty::AssocKind::Fn => {} ty::AssocKind::Type => { self.encode_explicit_item_bounds(def_id); } } - if trait_item.kind == ty::AssocKind::Fn { - record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); - } if let Some(rpitit_info) = trait_item.opt_rpitit_info { let rpitit_info = self.lazy(rpitit_info); self.tables.opt_rpitit_info.set_some(def_id.index, rpitit_info); @@ -1467,36 +1472,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_impl_item(&mut self, def_id: DefId) { debug!("EncodeContext::encode_info_for_impl_item({:?})", def_id); - let tcx = self.tcx; let defaultness = self.tcx.defaultness(def_id.expect_local()); self.tables.defaultness.set_some(def_id.index, defaultness); let impl_item = self.tcx.associated_item(def_id); self.tables.assoc_container.set_some(def_id.index, impl_item.container); - match impl_item.kind { - ty::AssocKind::Fn => { - let (sig, body) = - self.tcx.hir().expect_impl_item(def_id.expect_local()).expect_fn(); - self.tables.asyncness.set_some(def_id.index, sig.header.asyncness); - record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); - // Can be inside `impl const Trait`, so using sig.header.constness is not reliable - let constness = if self.tcx.is_const_fn_raw(def_id) { - hir::Constness::Const - } else { - hir::Constness::NotConst - }; - self.tables.constness.set_some(def_id.index, constness); - } - ty::AssocKind::Const | ty::AssocKind::Type => {} - } if let Some(trait_item_def_id) = impl_item.trait_item_def_id { self.tables.trait_item_def_id.set_some(def_id.index, trait_item_def_id.into()); } - if impl_item.kind == ty::AssocKind::Fn { - record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); - self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id)); - } if let Some(rpitit_info) = impl_item.opt_rpitit_info { let rpitit_info = self.lazy(rpitit_info); self.tables.opt_rpitit_info.set_some(def_id.index, rpitit_info); @@ -1624,7 +1608,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } fn encode_info_for_item(&mut self, item: &'tcx hir::Item<'tcx>) { - let tcx = self.tcx; let def_id = item.owner_id.to_def_id(); debug!("EncodeContext::encode_info_for_item({:?})", def_id); @@ -1636,13 +1619,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; match item.kind { - hir::ItemKind::Fn(ref sig, .., body) => { - self.tables.asyncness.set_some(def_id.index, sig.header.asyncness); - record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); - self.tables.constness.set_some(def_id.index, sig.header.constness); - record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); - self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id)); - } hir::ItemKind::Macro(ref macro_def, _) => { self.tables.is_macro_rules.set(def_id.index, macro_def.macro_rules); record!(self.tables.macro_definition[def_id] <- &*macro_def.body); @@ -1691,7 +1667,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemKind::Trait(..) => { record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); - let module_children = tcx.module_children_local(item.owner_id.def_id); + let module_children = self.tcx.module_children_local(item.owner_id.def_id); record_array!(self.tables.module_children_non_reexports[def_id] <- module_children.iter().map(|child| child.res.def_id().index)); @@ -1713,6 +1689,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { | hir::ItemKind::Union(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::GlobalAsm(..) + | hir::ItemKind::Fn(..) | hir::ItemKind::TyAlias(..) => {} } } @@ -2079,30 +2056,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } LazyArray::default() } - - fn encode_info_for_foreign_item(&mut self, def_id: DefId, nitem: &hir::ForeignItem<'_>) { - let tcx = self.tcx; - - debug!("EncodeContext::encode_info_for_foreign_item({:?})", def_id); - - match nitem.kind { - hir::ForeignItemKind::Fn(_, ref names, _) => { - self.tables.asyncness.set_some(def_id.index, hir::IsAsync::NotAsync); - record_array!(self.tables.fn_arg_names[def_id] <- *names); - let constness = if self.tcx.is_const_fn_raw(def_id) { - hir::Constness::Const - } else { - hir::Constness::NotConst - }; - self.tables.constness.set_some(def_id.index, constness); - record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); - } - hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => {} - } - if let hir::ForeignItemKind::Fn(..) = nitem.kind { - self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id)); - } - } } // FIXME(eddyb) make metadata encoding walk over all definitions, instead of HIR. @@ -2120,10 +2073,6 @@ impl<'a, 'tcx> Visitor<'tcx> for EncodeContext<'a, 'tcx> { intravisit::walk_item(self, item); self.encode_info_for_item(item); } - fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem<'tcx>) { - intravisit::walk_foreign_item(self, ni); - self.encode_info_for_foreign_item(ni.owner_id.to_def_id(), ni); - } fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { intravisit::walk_generics(self, generics); self.encode_info_for_generics(generics); From 3d9ba07a0e0a0b42a75536a6712affb61e2f2bf1 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 22 Jan 2023 18:26:38 +0000 Subject: [PATCH 458/465] Use constness query to encode constness. --- compiler/rustc_metadata/src/rmeta/encoder.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index f50467ab5314b..0c5e7d68dae74 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1317,14 +1317,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if let DefKind::Fn | DefKind::AssocFn = def_kind { self.tables.asyncness.set_some(def_id.index, tcx.asyncness(def_id)); + self.tables.constness.set_some(def_id.index, tcx.constness(def_id)); record_array!(self.tables.fn_arg_names[def_id] <- tcx.fn_arg_names(def_id)); - let constness = if self.tcx.is_const_fn_raw(def_id) { - hir::Constness::Const - } else { - hir::Constness::NotConst - }; - self.tables.constness.set_some(def_id.index, constness); - record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id)); } From 3c790b3730939dcdc4c9f534ab97dcf12743d409 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 3 Jul 2022 22:31:37 +0200 Subject: [PATCH 459/465] Encode fn_sig separately. Closures do not have a `fn_sig`, so no reason to encode one. --- compiler/rustc_metadata/src/rmeta/encoder.rs | 129 +++++++++++++------ 1 file changed, 91 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 0c5e7d68dae74..950222af540a4 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1193,6 +1193,82 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> } } +fn should_encode_fn_sig(def_kind: DefKind) -> bool { + match def_kind { + DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) => true, + + DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::Field + | DefKind::Const + | DefKind::Static(..) + | DefKind::Ctor(..) + | DefKind::TyAlias + | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder + | DefKind::ForeignTy + | DefKind::Impl { .. } + | DefKind::AssocConst + | DefKind::Closure + | DefKind::Generator + | DefKind::ConstParam + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::AssocTy + | DefKind::TyParam + | DefKind::Trait + | DefKind::TraitAlias + | DefKind::Mod + | DefKind::ForeignMod + | DefKind::Macro(..) + | DefKind::Use + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::ExternCrate => false, + } +} + +fn should_encode_constness(def_kind: DefKind) -> bool { + match def_kind { + DefKind::Fn + | DefKind::AssocFn + | DefKind::Closure + | DefKind::Impl { of_trait: true } + | DefKind::Variant + | DefKind::Ctor(..) => true, + + DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Field + | DefKind::Const + | DefKind::AssocConst + | DefKind::AnonConst + | DefKind::Static(..) + | DefKind::TyAlias + | DefKind::OpaqueTy + | DefKind::Impl { of_trait: false } + | DefKind::ImplTraitPlaceholder + | DefKind::ForeignTy + | DefKind::Generator + | DefKind::ConstParam + | DefKind::InlineConst + | DefKind::AssocTy + | DefKind::TyParam + | DefKind::Trait + | DefKind::TraitAlias + | DefKind::Mod + | DefKind::ForeignMod + | DefKind::Macro(..) + | DefKind::Use + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::ExternCrate => false, + } +} + fn should_encode_const(def_kind: DefKind) -> bool { match def_kind { DefKind::Const | DefKind::AssocConst | DefKind::AnonConst | DefKind::InlineConst => true, @@ -1305,6 +1381,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let v = self.tcx.variances_of(def_id); record_array!(self.tables.variances_of[def_id] <- v); } + if should_encode_fn_sig(def_kind) { + record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); + } if should_encode_generics(def_kind) { let g = tcx.generics_of(def_id); record!(self.tables.generics_of[def_id] <- g); @@ -1315,11 +1394,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if should_encode_type(tcx, local_id, def_kind) { record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id)); } + if should_encode_constness(def_kind) { + self.tables.constness.set_some(def_id.index, self.tcx.constness(def_id)); + } if let DefKind::Fn | DefKind::AssocFn = def_kind { self.tables.asyncness.set_some(def_id.index, tcx.asyncness(def_id)); - self.tables.constness.set_some(def_id.index, tcx.constness(def_id)); record_array!(self.tables.fn_arg_names[def_id] <- tcx.fn_arg_names(def_id)); - record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id)); } if let DefKind::TyParam = def_kind { @@ -1333,6 +1413,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); record!(self.tables.implied_predicates_of[def_id] <- self.tcx.implied_predicates_of(def_id)); } + if let DefKind::Generator = def_kind { + self.encode_info_for_generator(local_id); + } if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind { self.encode_info_for_adt(local_id); } @@ -1396,16 +1479,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; record!(self.tables.variant_data[variant.def_id] <- data); - self.tables.constness.set_some(variant.def_id.index, hir::Constness::Const); record_array!(self.tables.associated_item_or_field_def_ids[variant.def_id] <- variant.fields.iter().map(|f| { assert!(f.did.is_local()); f.did.index })); if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor { - self.tables.constness.set_some(ctor_def_id.index, hir::Constness::Const); let fn_sig = tcx.fn_sig(ctor_def_id); - record!(self.tables.fn_sig[ctor_def_id] <- fn_sig); // FIXME only encode signature for ctor_def_id record!(self.tables.fn_sig[variant.def_id] <- fn_sig); } @@ -1627,9 +1707,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }), ); } - hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => { + hir::ItemKind::Impl(hir::Impl { defaultness, .. }) => { self.tables.defaultness.set_some(def_id.index, *defaultness); - self.tables.constness.set_some(def_id.index, *constness); self.tables.impl_polarity.set_some(def_id.index, self.tcx.impl_polarity(def_id)); if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) { @@ -1689,28 +1768,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } #[instrument(level = "debug", skip(self))] - fn encode_info_for_closure(&mut self, def_id: LocalDefId) { - // NOTE(eddyb) `tcx.type_of(def_id)` isn't used because it's fully generic, - // including on the signature, which is inferred in `typeck`. + fn encode_info_for_generator(&mut self, def_id: LocalDefId) { let typeck_result: &'tcx ty::TypeckResults<'tcx> = self.tcx.typeck(def_id); - let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); - let ty = typeck_result.node_type(hir_id); - match ty.kind() { - ty::Generator(..) => { - let data = self.tcx.generator_kind(def_id).unwrap(); - let generator_diagnostic_data = typeck_result.get_generator_diagnostic_data(); - record!(self.tables.generator_kind[def_id.to_def_id()] <- data); - record!(self.tables.generator_diagnostic_data[def_id.to_def_id()] <- generator_diagnostic_data); - } - - ty::Closure(_, substs) => { - let constness = self.tcx.constness(def_id.to_def_id()); - self.tables.constness.set_some(def_id.to_def_id().index, constness); - record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder::bind(substs.as_closure().sig())); - } - - _ => bug!("closure that is neither generator nor closure"), - } + let data = self.tcx.generator_kind(def_id).unwrap(); + let generator_diagnostic_data = typeck_result.get_generator_diagnostic_data(); + record!(self.tables.generator_kind[def_id.to_def_id()] <- data); + record!(self.tables.generator_diagnostic_data[def_id.to_def_id()] <- generator_diagnostic_data); } fn encode_native_libraries(&mut self) -> LazyArray { @@ -2059,10 +2122,6 @@ impl<'a, 'tcx> Visitor<'tcx> for EncodeContext<'a, 'tcx> { fn nested_visit_map(&mut self) -> Self::Map { self.tcx.hir() } - fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { - intravisit::walk_expr(self, ex); - self.encode_info_for_expr(ex); - } fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { intravisit::walk_item(self, item); self.encode_info_for_item(item); @@ -2087,12 +2146,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } } - - fn encode_info_for_expr(&mut self, expr: &hir::Expr<'_>) { - if let hir::ExprKind::Closure(closure) = expr.kind { - self.encode_info_for_closure(closure.def_id); - } - } } /// Used to prefetch queries which will be needed later by metadata encoding. From 1a9d34fd81c68bfc8e468d9b7665294f5956af03 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 3 Jul 2022 22:38:53 +0200 Subject: [PATCH 460/465] Merge assoc_item functions. --- compiler/rustc_metadata/src/rmeta/encoder.rs | 80 ++++++++------------ 1 file changed, 30 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 950222af540a4..5cd5fc3503845 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -31,7 +31,7 @@ use rustc_middle::query::Providers; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams}; -use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; +use rustc_middle::ty::{self, AssocItemContainer, SymbolName, Ty, TyCtxt}; use rustc_middle::util::common::to_readable_str; use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder}; use rustc_session::config::{CrateType, OptLevel}; @@ -1416,6 +1416,18 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if let DefKind::Generator = def_kind { self.encode_info_for_generator(local_id); } + if let DefKind::Trait | DefKind::Impl { .. } = def_kind { + let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id); + record_array!(self.tables.associated_item_or_field_def_ids[def_id] <- + associated_item_def_ids.iter().map(|&def_id| { + assert!(def_id.is_local()); + def_id.index + }) + ); + for &def_id in associated_item_def_ids { + self.encode_info_for_assoc_item(def_id); + } + } if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind { self.encode_info_for_adt(local_id); } @@ -1523,41 +1535,28 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record_defaulted_array!(self.tables.explicit_item_bounds[def_id] <- bounds); } - fn encode_info_for_trait_item(&mut self, def_id: DefId) { - debug!("EncodeContext::encode_info_for_trait_item({:?})", def_id); + #[tracing::instrument(level = "debug", skip(self))] + fn encode_info_for_assoc_item(&mut self, def_id: DefId) { let tcx = self.tcx; + let item = tcx.associated_item(def_id); - let defaultness = tcx.defaultness(def_id.expect_local()); - self.tables.defaultness.set_some(def_id.index, defaultness); - let trait_item = tcx.associated_item(def_id); - self.tables.assoc_container.set_some(def_id.index, trait_item.container); + self.tables.defaultness.set_some(def_id.index, item.defaultness(tcx)); + self.tables.assoc_container.set_some(def_id.index, item.container); - match trait_item.kind { - ty::AssocKind::Const | ty::AssocKind::Fn => {} - ty::AssocKind::Type => { - self.encode_explicit_item_bounds(def_id); + match item.container { + AssocItemContainer::TraitContainer => { + if let ty::AssocKind::Type = item.kind { + self.encode_explicit_item_bounds(def_id); + } + } + AssocItemContainer::ImplContainer => { + if let Some(trait_item_def_id) = item.trait_item_def_id { + self.tables.trait_item_def_id.set_some(def_id.index, trait_item_def_id.into()); + } } } - if let Some(rpitit_info) = trait_item.opt_rpitit_info { - let rpitit_info = self.lazy(rpitit_info); - self.tables.opt_rpitit_info.set_some(def_id.index, rpitit_info); - } - } - - fn encode_info_for_impl_item(&mut self, def_id: DefId) { - debug!("EncodeContext::encode_info_for_impl_item({:?})", def_id); - - let defaultness = self.tcx.defaultness(def_id.expect_local()); - self.tables.defaultness.set_some(def_id.index, defaultness); - let impl_item = self.tcx.associated_item(def_id); - self.tables.assoc_container.set_some(def_id.index, impl_item.container); - - if let Some(trait_item_def_id) = impl_item.trait_item_def_id { - self.tables.trait_item_def_id.set_some(def_id.index, trait_item_def_id.into()); - } - if let Some(rpitit_info) = impl_item.opt_rpitit_info { - let rpitit_info = self.lazy(rpitit_info); - self.tables.opt_rpitit_info.set_some(def_id.index, rpitit_info); + if let Some(rpitit_info) = item.opt_rpitit_info { + record!(self.tables.opt_rpitit_info[def_id] <- rpitit_info); } } @@ -1685,13 +1684,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let def_id = item.owner_id.to_def_id(); debug!("EncodeContext::encode_info_for_item({:?})", def_id); - let record_associated_item_def_ids = |this: &mut Self, def_ids: &[DefId]| { - record_array!(this.tables.associated_item_or_field_def_ids[def_id] <- def_ids.iter().map(|&def_id| { - assert!(def_id.is_local()); - def_id.index - })) - }; - match item.kind { hir::ItemKind::Macro(ref macro_def, _) => { self.tables.is_macro_rules.set(def_id.index, macro_def.macro_rules); @@ -1730,12 +1722,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.coerce_unsized_info[def_id] <- coerce_unsized_info); } } - - let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id); - record_associated_item_def_ids(self, associated_item_def_ids); - for &trait_item_def_id in associated_item_def_ids { - self.encode_info_for_impl_item(trait_item_def_id); - } } hir::ItemKind::Trait(..) => { record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); @@ -1743,12 +1729,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let module_children = self.tcx.module_children_local(item.owner_id.def_id); record_array!(self.tables.module_children_non_reexports[def_id] <- module_children.iter().map(|child| child.res.def_id().index)); - - let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id); - record_associated_item_def_ids(self, associated_item_def_ids); - for &item_def_id in associated_item_def_ids { - self.encode_info_for_trait_item(item_def_id); - } } hir::ItemKind::TraitAlias(..) => { record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); From 45a9a5460ffafb6a2448083d2e1bb24fd63ea450 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 3 Jul 2022 22:10:14 +0200 Subject: [PATCH 461/465] Encode Trait info in def-id loop. --- compiler/rustc_metadata/src/rmeta/encoder.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 5cd5fc3503845..f3c9b1a505a43 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1407,9 +1407,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.object_lifetime_default[def_id] <- default); } if let DefKind::Trait = def_kind { + record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); + + let module_children = self.tcx.module_children_local(local_id); + record_array!(self.tables.module_children_non_reexports[def_id] <- + module_children.iter().map(|child| child.res.def_id().index)); } if let DefKind::TraitAlias = def_kind { + record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); record!(self.tables.implied_predicates_of[def_id] <- self.tcx.implied_predicates_of(def_id)); } @@ -1723,18 +1729,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } } - hir::ItemKind::Trait(..) => { - record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); - - let module_children = self.tcx.module_children_local(item.owner_id.def_id); - record_array!(self.tables.module_children_non_reexports[def_id] <- - module_children.iter().map(|child| child.res.def_id().index)); - } - hir::ItemKind::TraitAlias(..) => { - record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); - } hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) + | hir::ItemKind::Trait(..) + | hir::ItemKind::TraitAlias(..) | hir::ItemKind::Static(..) | hir::ItemKind::Const(..) | hir::ItemKind::Enum(..) From 22df32264abfd2a16b0b7e721beab31f189fa56e Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 3 Jul 2022 22:15:08 +0200 Subject: [PATCH 462/465] Encode Impl separately. --- compiler/rustc_metadata/src/rmeta/encoder.rs | 55 +++++++++++--------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index f3c9b1a505a43..8092f1f7ecfaf 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1434,6 +1434,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_info_for_assoc_item(def_id); } } + if let DefKind::Impl { of_trait } = def_kind { + self.encode_info_for_impl(def_id, of_trait) + } if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind { self.encode_info_for_adt(local_id); } @@ -1705,32 +1708,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }), ); } - hir::ItemKind::Impl(hir::Impl { defaultness, .. }) => { - self.tables.defaultness.set_some(def_id.index, *defaultness); - self.tables.impl_polarity.set_some(def_id.index, self.tcx.impl_polarity(def_id)); - - if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) { - record!(self.tables.impl_trait_ref[def_id] <- trait_ref); - - let trait_ref = trait_ref.skip_binder(); - let trait_def = self.tcx.trait_def(trait_ref.def_id); - if let Ok(mut an) = trait_def.ancestors(self.tcx, def_id) { - if let Some(specialization_graph::Node::Impl(parent)) = an.nth(1) { - self.tables.impl_parent.set_some(def_id.index, parent.into()); - } - } - - // if this is an impl of `CoerceUnsized`, create its - // "unsized info", else just store None - if Some(trait_ref.def_id) == self.tcx.lang_items().coerce_unsized_trait() { - let coerce_unsized_info = - self.tcx.at(item.span).coerce_unsized_info(def_id); - record!(self.tables.coerce_unsized_info[def_id] <- coerce_unsized_info); - } - } - } hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) + | hir::ItemKind::Impl(..) | hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) | hir::ItemKind::Static(..) @@ -1745,6 +1725,33 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } + #[tracing::instrument(level = "debug", skip(self))] + fn encode_info_for_impl(&mut self, def_id: DefId, of_trait: bool) { + let tcx = self.tcx; + + self.tables.defaultness.set_some(def_id.index, tcx.defaultness(def_id)); + self.tables.impl_polarity.set_some(def_id.index, tcx.impl_polarity(def_id)); + + if of_trait && let Some(trait_ref) = tcx.impl_trait_ref(def_id) { + record!(self.tables.impl_trait_ref[def_id] <- trait_ref); + + let trait_def_id = trait_ref.skip_binder().def_id; + let trait_def = tcx.trait_def(trait_def_id); + if let Some(mut an) = trait_def.ancestors(tcx, def_id).ok() { + if let Some(specialization_graph::Node::Impl(parent)) = an.nth(1) { + self.tables.impl_parent.set_some(def_id.index, parent.into()); + } + } + + // if this is an impl of `CoerceUnsized`, create its + // "unsized info", else just store None + if Some(trait_def_id) == tcx.lang_items().coerce_unsized_trait() { + let coerce_unsized_info = tcx.coerce_unsized_info(def_id); + record!(self.tables.coerce_unsized_info[def_id] <- coerce_unsized_info); + } + } + } + #[instrument(level = "debug", skip(self))] fn encode_info_for_generator(&mut self, def_id: LocalDefId) { let typeck_result: &'tcx ty::TypeckResults<'tcx> = self.tcx.typeck(def_id); From fd81e964b8e7003a7366a0d77b8fa80537ab05ad Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 3 Jul 2022 22:48:00 +0200 Subject: [PATCH 463/465] Retire encode_info_for_items. --- compiler/rustc_metadata/src/rmeta/encoder.rs | 116 ++++++------------- 1 file changed, 33 insertions(+), 83 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 8092f1f7ecfaf..80bcbaed10104 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -17,9 +17,8 @@ use rustc_hir::def_id::{ CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE, }; use rustc_hir::definitions::DefPathData; -use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::intravisit; use rustc_hir::lang_items::LangItem; -use rustc_middle::hir::nested_filter; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::{ @@ -450,18 +449,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { LazyArray::from_position_and_num_elems(pos, len) } - fn encode_info_for_items(&mut self) { - self.encode_info_for_mod(CRATE_DEF_ID); - - // Proc-macro crates only export proc-macro items, which are looked - // up using `proc_macro_data` - if self.is_proc_macro { - return; - } - - self.tcx.hir().visit_all_item_likes_in_crate(self); - } - fn encode_def_path_table(&mut self) { let table = self.tcx.def_path_table(); if self.is_proc_macro { @@ -607,8 +594,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { _ = stat!("def-ids", || self.encode_def_ids()); - _ = stat!("items", || self.encode_info_for_items()); - let interpret_alloc_index = stat!("interpret-alloc-index", || { let mut interpret_alloc_index = Vec::new(); let mut n = 0; @@ -1341,10 +1326,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } fn encode_def_ids(&mut self) { + self.encode_info_for_mod(CRATE_DEF_ID); + + // Proc-macro crates only export proc-macro items, which are looked + // up using `proc_macro_data` if self.is_proc_macro { return; } + let tcx = self.tcx; + for local_id in tcx.iter_local_def_id() { let def_id = local_id.to_def_id(); let def_kind = tcx.opt_def_kind(local_id); @@ -1390,6 +1381,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.explicit_predicates_of[def_id] <- self.tcx.explicit_predicates_of(def_id)); let inferred_outlives = self.tcx.inferred_outlives_of(def_id); record_defaulted_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives); + + for param in &g.params { + if let ty::GenericParamDefKind::Const { has_default: true, .. } = param.kind { + let default = self.tcx.const_param_default(param.def_id); + record!(self.tables.const_param_default[param.def_id] <- default); + } + } } if should_encode_type(tcx, local_id, def_kind) { record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id)); @@ -1440,6 +1438,18 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind { self.encode_info_for_adt(local_id); } + if let DefKind::Mod = def_kind { + self.encode_info_for_mod(local_id); + } + if let DefKind::Macro(_) = def_kind { + self.encode_info_for_macro(local_id); + } + if let DefKind::OpaqueTy = def_kind { + self.encode_explicit_item_bounds(def_id); + self.tables + .is_type_alias_impl_trait + .set(def_id.index, self.tcx.is_type_alias_impl_trait(def_id)); + } if tcx.impl_method_has_trait_impl_trait_tys(def_id) && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id) { @@ -1513,10 +1523,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } + #[tracing::instrument(level = "debug", skip(self))] fn encode_info_for_mod(&mut self, local_def_id: LocalDefId) { let tcx = self.tcx; let def_id = local_def_id.to_def_id(); - debug!("EncodeContext::encode_info_for_mod({:?})", def_id); // If we are encoding a proc-macro crates, `encode_info_for_mod` will // only ever get called for the crate root. We still want to encode @@ -1689,40 +1699,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }) } - fn encode_info_for_item(&mut self, item: &'tcx hir::Item<'tcx>) { - let def_id = item.owner_id.to_def_id(); - debug!("EncodeContext::encode_info_for_item({:?})", def_id); + #[tracing::instrument(level = "debug", skip(self))] + fn encode_info_for_macro(&mut self, def_id: LocalDefId) { + let tcx = self.tcx; - match item.kind { - hir::ItemKind::Macro(ref macro_def, _) => { - self.tables.is_macro_rules.set(def_id.index, macro_def.macro_rules); - record!(self.tables.macro_definition[def_id] <- &*macro_def.body); - } - hir::ItemKind::Mod(..) => { - self.encode_info_for_mod(item.owner_id.def_id); - } - hir::ItemKind::OpaqueTy(ref opaque) => { - self.encode_explicit_item_bounds(def_id); - self.tables.is_type_alias_impl_trait.set( - def_id.index, - matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }), - ); - } - hir::ItemKind::ExternCrate(_) - | hir::ItemKind::Use(..) - | hir::ItemKind::Impl(..) - | hir::ItemKind::Trait(..) - | hir::ItemKind::TraitAlias(..) - | hir::ItemKind::Static(..) - | hir::ItemKind::Const(..) - | hir::ItemKind::Enum(..) - | hir::ItemKind::Struct(..) - | hir::ItemKind::Union(..) - | hir::ItemKind::ForeignMod { .. } - | hir::ItemKind::GlobalAsm(..) - | hir::ItemKind::Fn(..) - | hir::ItemKind::TyAlias(..) => {} - } + let hir::ItemKind::Macro(ref macro_def, _) = tcx.hir().expect_item(def_id).kind else { bug!() }; + self.tables.is_macro_rules.set(def_id.local_def_index, macro_def.macro_rules); + record!(self.tables.macro_definition[def_id.to_def_id()] <- &*macro_def.body); } #[tracing::instrument(level = "debug", skip(self))] @@ -2100,39 +2083,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } -// FIXME(eddyb) make metadata encoding walk over all definitions, instead of HIR. -impl<'a, 'tcx> Visitor<'tcx> for EncodeContext<'a, 'tcx> { - type NestedFilter = nested_filter::OnlyBodies; - - fn nested_visit_map(&mut self) -> Self::Map { - self.tcx.hir() - } - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - intravisit::walk_item(self, item); - self.encode_info_for_item(item); - } - fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { - intravisit::walk_generics(self, generics); - self.encode_info_for_generics(generics); - } -} - -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { - fn encode_info_for_generics(&mut self, generics: &hir::Generics<'tcx>) { - for param in generics.params { - match param.kind { - hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => {} - hir::GenericParamKind::Const { ref default, .. } => { - let def_id = param.def_id.to_def_id(); - if default.is_some() { - record!(self.tables.const_param_default[def_id] <- self.tcx.const_param_default(def_id)) - } - } - } - } - } -} - /// Used to prefetch queries which will be needed later by metadata encoding. /// Only a subset of the queries are actually prefetched to keep this code smaller. fn prefetch_mir(tcx: TyCtxt<'_>) { From 845fcc193974d84793eca54105dcb55eed3e08b8 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 3 Jul 2022 22:55:46 +0200 Subject: [PATCH 464/465] Use instrument macro. --- compiler/rustc_metadata/src/rmeta/encoder.rs | 23 +++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 80bcbaed10104..7c7f47bc2c358 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1523,7 +1523,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn encode_info_for_mod(&mut self, local_def_id: LocalDefId) { let tcx = self.tcx; let def_id = local_def_id.to_def_id(); @@ -1554,7 +1554,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record_defaulted_array!(self.tables.explicit_item_bounds[def_id] <- bounds); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn encode_info_for_assoc_item(&mut self, def_id: DefId) { let tcx = self.tcx; let item = tcx.associated_item(def_id); @@ -1648,9 +1648,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn encode_stability(&mut self, def_id: DefId) { - debug!("EncodeContext::encode_stability({:?})", def_id); - // The query lookup can take a measurable amount of time in crates with many items. Check if // the stability attributes are even enabled before using their queries. if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { @@ -1660,9 +1659,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn encode_const_stability(&mut self, def_id: DefId) { - debug!("EncodeContext::encode_const_stability({:?})", def_id); - // The query lookup can take a measurable amount of time in crates with many items. Check if // the stability attributes are even enabled before using their queries. if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { @@ -1672,9 +1670,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn encode_default_body_stability(&mut self, def_id: DefId) { - debug!("EncodeContext::encode_default_body_stability({:?})", def_id); - // The query lookup can take a measurable amount of time in crates with many items. Check if // the stability attributes are even enabled before using their queries. if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { @@ -1684,8 +1681,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn encode_deprecation(&mut self, def_id: DefId) { - debug!("EncodeContext::encode_deprecation({:?})", def_id); if let Some(depr) = self.tcx.lookup_deprecation(def_id) { record!(self.tables.lookup_deprecation_entry[def_id] <- depr); } @@ -1699,7 +1696,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }) } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn encode_info_for_macro(&mut self, def_id: LocalDefId) { let tcx = self.tcx; @@ -1708,7 +1705,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.macro_definition[def_id.to_def_id()] <- &*macro_def.body); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn encode_info_for_impl(&mut self, def_id: DefId, of_trait: bool) { let tcx = self.tcx; @@ -1962,8 +1959,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } /// Encodes an index, mapping each trait to its (local) implementations. + #[instrument(level = "debug", skip(self))] fn encode_impls(&mut self) -> LazyArray { - debug!("EncodeContext::encode_traits_and_impls()"); empty_proc_macro!(self); let tcx = self.tcx; let mut fx_hash_map: FxHashMap)>> = @@ -2011,8 +2008,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy_array(&all_impls) } + #[instrument(level = "debug", skip(self))] fn encode_incoherent_impls(&mut self) -> LazyArray { - debug!("EncodeContext::encode_traits_and_impls()"); empty_proc_macro!(self); let tcx = self.tcx; let mut all_impls: Vec<_> = tcx.crate_inherent_impls(()).incoherent_impls.iter().collect(); From 0faea7728f283dca5693f79be7615f67842c55dd Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 26 Jun 2023 17:45:56 +0000 Subject: [PATCH 465/465] Encode impls in encode_impls. --- compiler/rustc_metadata/src/rmeta/encoder.rs | 77 ++++++++------------ 1 file changed, 31 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 7c7f47bc2c358..b80019bf15519 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1417,9 +1417,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); record!(self.tables.implied_predicates_of[def_id] <- self.tcx.implied_predicates_of(def_id)); } - if let DefKind::Generator = def_kind { - self.encode_info_for_generator(local_id); - } if let DefKind::Trait | DefKind::Impl { .. } = def_kind { let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id); record_array!(self.tables.associated_item_or_field_def_ids[def_id] <- @@ -1432,8 +1429,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_info_for_assoc_item(def_id); } } - if let DefKind::Impl { of_trait } = def_kind { - self.encode_info_for_impl(def_id, of_trait) + if let DefKind::Generator = def_kind { + self.encode_info_for_generator(local_id); } if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind { self.encode_info_for_adt(local_id); @@ -1705,33 +1702,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.macro_definition[def_id.to_def_id()] <- &*macro_def.body); } - #[instrument(level = "debug", skip(self))] - fn encode_info_for_impl(&mut self, def_id: DefId, of_trait: bool) { - let tcx = self.tcx; - - self.tables.defaultness.set_some(def_id.index, tcx.defaultness(def_id)); - self.tables.impl_polarity.set_some(def_id.index, tcx.impl_polarity(def_id)); - - if of_trait && let Some(trait_ref) = tcx.impl_trait_ref(def_id) { - record!(self.tables.impl_trait_ref[def_id] <- trait_ref); - - let trait_def_id = trait_ref.skip_binder().def_id; - let trait_def = tcx.trait_def(trait_def_id); - if let Some(mut an) = trait_def.ancestors(tcx, def_id).ok() { - if let Some(specialization_graph::Node::Impl(parent)) = an.nth(1) { - self.tables.impl_parent.set_some(def_id.index, parent.into()); - } - } - - // if this is an impl of `CoerceUnsized`, create its - // "unsized info", else just store None - if Some(trait_def_id) == tcx.lang_items().coerce_unsized_trait() { - let coerce_unsized_info = tcx.coerce_unsized_info(def_id); - record!(self.tables.coerce_unsized_info[def_id] <- coerce_unsized_info); - } - } - } - #[instrument(level = "debug", skip(self))] fn encode_info_for_generator(&mut self, def_id: LocalDefId) { let typeck_result: &'tcx ty::TypeckResults<'tcx> = self.tcx.typeck(def_id); @@ -1967,20 +1937,35 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { FxHashMap::default(); for id in tcx.hir().items() { - if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) { - if let Some(trait_ref) = tcx.impl_trait_ref(id.owner_id) { - let trait_ref = trait_ref.subst_identity(); - - let simplified_self_ty = fast_reject::simplify_type( - self.tcx, - trait_ref.self_ty(), - TreatParams::AsCandidateKey, - ); - - fx_hash_map - .entry(trait_ref.def_id) - .or_default() - .push((id.owner_id.def_id.local_def_index, simplified_self_ty)); + let DefKind::Impl { of_trait } = tcx.def_kind(id.owner_id) else { continue; }; + let def_id = id.owner_id.to_def_id(); + + self.tables.defaultness.set_some(def_id.index, tcx.defaultness(def_id)); + self.tables.impl_polarity.set_some(def_id.index, tcx.impl_polarity(def_id)); + + if of_trait && let Some(trait_ref) = tcx.impl_trait_ref(def_id) { + record!(self.tables.impl_trait_ref[def_id] <- trait_ref); + + let trait_ref = trait_ref.subst_identity(); + let simplified_self_ty = + fast_reject::simplify_type(self.tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey); + fx_hash_map + .entry(trait_ref.def_id) + .or_default() + .push((id.owner_id.def_id.local_def_index, simplified_self_ty)); + + let trait_def = tcx.trait_def(trait_ref.def_id); + if let Some(mut an) = trait_def.ancestors(tcx, def_id).ok() { + if let Some(specialization_graph::Node::Impl(parent)) = an.nth(1) { + self.tables.impl_parent.set_some(def_id.index, parent.into()); + } + } + + // if this is an impl of `CoerceUnsized`, create its + // "unsized info", else just store None + if Some(trait_ref.def_id) == tcx.lang_items().coerce_unsized_trait() { + let coerce_unsized_info = tcx.coerce_unsized_info(def_id); + record!(self.tables.coerce_unsized_info[def_id] <- coerce_unsized_info); } } }

- Fields§ +