diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 1ca0715606181..c85d6f454321e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1415,6 +1415,9 @@ impl<'a> State<'a> { } fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) { + if let ast::Parens::Yes = t.parens { + self.popen(); + } self.print_formal_generic_params(&t.bound_generic_params); let ast::TraitBoundModifiers { constness, asyncness, polarity } = t.modifiers; @@ -1437,7 +1440,10 @@ impl<'a> State<'a> { } } - self.print_trait_ref(&t.trait_ref) + self.print_trait_ref(&t.trait_ref); + if let ast::Parens::Yes = t.parens { + self.pclose(); + } } fn print_stmt(&mut self, st: &ast::Stmt) { diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index f0fc2a5b5e939..f8ccc8594e333 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -1,4 +1,4 @@ -use rustc_abi::Align; +use rustc_abi::{Align, Size}; use rustc_ast::{IntTy, LitIntType, LitKind, UintTy}; use rustc_hir::attrs::{IntType, ReprAttr}; @@ -229,7 +229,7 @@ fn parse_repr_align( return None; }; - match parse_alignment(&lit.kind) { + match parse_alignment(&lit.kind, cx) { Ok(literal) => Some(match align_kind { AlignKind::Packed => ReprAttr::ReprPacked(literal), AlignKind::Align => ReprAttr::ReprAlign(literal), @@ -248,23 +248,35 @@ fn parse_repr_align( } } -fn parse_alignment(node: &LitKind) -> Result { - if let LitKind::Int(literal, LitIntType::Unsuffixed) = node { - // `Align::from_bytes` accepts 0 as an input, check is_power_of_two() first - if literal.get().is_power_of_two() { - // Only possible error is larger than 2^29 - literal - .get() - .try_into() - .ok() - .and_then(|v| Align::from_bytes(v).ok()) - .ok_or("larger than 2^29") - } else { - Err("not a power of two") - } - } else { - Err("not an unsuffixed integer") +fn parse_alignment( + node: &LitKind, + cx: &AcceptContext<'_, '_, S>, +) -> Result { + let LitKind::Int(literal, LitIntType::Unsuffixed) = node else { + return Err("not an unsuffixed integer".to_string()); + }; + + // `Align::from_bytes` accepts 0 as a valid input, + // so we check if its a power of two first + if !literal.get().is_power_of_two() { + return Err("not a power of two".to_string()); + } + // lit must be < 2^29 + let align = literal + .get() + .try_into() + .ok() + .and_then(|a| Align::from_bytes(a).ok()) + .ok_or("larger than 2^29".to_string())?; + + // alignment must not be larger than the pointer width (`isize::MAX`) + let max = Size::from_bits(cx.sess.target.pointer_width).signed_int_max() as u64; + if align.bytes() > max { + return Err(format!( + "alignment larger than `isize::MAX` bytes ({max} for the current target)" + )); } + Ok(align) } /// Parse #[align(N)]. @@ -294,7 +306,7 @@ impl RustcAlignParser { return; }; - match parse_alignment(&lit.kind) { + match parse_alignment(&lit.kind, cx) { Ok(literal) => self.0 = Ord::max(self.0, Some((literal, cx.attr_span))), Err(message) => { cx.emit_err(session_diagnostics::InvalidAlignmentValue { diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 987c0cb04c84d..7c2044ec235a7 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -227,12 +227,12 @@ pub(crate) struct InvalidReprAlignNeedArg { #[derive(Diagnostic)] #[diag("invalid `repr({$repr_arg})` attribute: {$error_part}", code = E0589)] -pub(crate) struct InvalidReprGeneric<'a> { +pub(crate) struct InvalidReprGeneric { #[primary_span] pub span: Span, pub repr_arg: String, - pub error_part: &'a str, + pub error_part: String, } #[derive(Diagnostic)] @@ -479,7 +479,7 @@ pub(crate) struct InvalidTarget { pub(crate) struct InvalidAlignmentValue { #[primary_span] pub span: Span, - pub error_part: &'static str, + pub error_part: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 738e3330254b7..cbc05acef5647 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -8,7 +8,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex}; use rustc_span::def_id::DefId; -use rustc_span::{BytePos, ExpnKind, MacroKind, Span}; +use rustc_span::{BytePos, ExpnKind, MacroKind, Span, sym}; use rustc_trait_selection::error_reporting::traits::FindExprBySpan; use rustc_trait_selection::infer::InferCtxtExt; use tracing::debug; @@ -700,14 +700,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { binds_to.sort(); binds_to.dedup(); - self.add_move_error_details(err, &binds_to); + self.add_move_error_details(err, &binds_to, &[]); } } GroupedMoveError::MovesFromValue { mut binds_to, .. } => { binds_to.sort(); binds_to.dedup(); - self.add_move_error_suggestions(err, &binds_to); - self.add_move_error_details(err, &binds_to); + let desugar_spans = self.add_move_error_suggestions(err, &binds_to); + self.add_move_error_details(err, &binds_to, &desugar_spans); } // No binding. Nothing to suggest. GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => { @@ -823,7 +823,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } - fn add_move_error_suggestions(&self, err: &mut Diag<'_>, binds_to: &[Local]) { + fn add_move_error_suggestions(&self, err: &mut Diag<'_>, binds_to: &[Local]) -> Vec { /// A HIR visitor to associate each binding with a `&` or `&mut` that could be removed to /// make it bind by reference instead (if possible) struct BindingFinder<'tcx> { @@ -843,6 +843,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ref_pat_for_binding: Vec<(Span, Option<&'tcx hir::Pat<'tcx>>)>, /// Output: ref patterns that can't be removed straightforwardly cannot_remove: FxHashSet, + /// Output: binding spans from destructuring assignment desugaring + desugar_binding_spans: Vec, } impl<'tcx> Visitor<'tcx> for BindingFinder<'tcx> { type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies; @@ -883,16 +885,38 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } if let hir::PatKind::Binding(_, _, ident, _) = p.kind { - // the spans in `binding_spans` encompass both the ident and binding mode - if let Some(&bind_sp) = - self.binding_spans.iter().find(|bind_sp| bind_sp.contains(ident.span)) - { - self.ref_pat_for_binding.push((bind_sp, self.ref_pat)); + // Skip synthetic bindings from destructuring assignment desugaring + // These have name `lhs` and their parent is a `LetStmt` with + // `LocalSource::AssignDesugar` + let dominated_by_desugar_assign = ident.name == sym::lhs + && self.tcx.hir_parent_iter(p.hir_id).any(|(_, node)| { + matches!( + node, + hir::Node::LetStmt(&hir::LetStmt { + source: hir::LocalSource::AssignDesugar, + .. + }) + ) + }); + + if dominated_by_desugar_assign { + if let Some(&bind_sp) = + self.binding_spans.iter().find(|bind_sp| bind_sp.contains(ident.span)) + { + self.desugar_binding_spans.push(bind_sp); + } } else { - // we've encountered a binding that we're not reporting a move error for. - // we don't want to change its type, so don't remove the surrounding `&`. - if let Some(ref_pat) = self.ref_pat { - self.cannot_remove.insert(ref_pat.hir_id); + // the spans in `binding_spans` encompass both the ident and binding mode + if let Some(&bind_sp) = + self.binding_spans.iter().find(|bind_sp| bind_sp.contains(ident.span)) + { + self.ref_pat_for_binding.push((bind_sp, self.ref_pat)); + } else { + // we've encountered a binding that we're not reporting a move error for. + // we don't want to change its type, so don't remove the surrounding `&`. + if let Some(ref_pat) = self.ref_pat { + self.cannot_remove.insert(ref_pat.hir_id); + } } } } @@ -913,10 +937,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { binding_spans.push(bind_to.source_info.span); } } - let Some(pat_span) = pat_span else { return }; + let Some(pat_span) = pat_span else { return Vec::new() }; let tcx = self.infcx.tcx; - let Some(body) = tcx.hir_maybe_body_owned_by(self.mir_def_id()) else { return }; + let Some(body) = tcx.hir_maybe_body_owned_by(self.mir_def_id()) else { return Vec::new() }; let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); let mut finder = BindingFinder { typeck_results, @@ -928,6 +952,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { has_adjustments: false, ref_pat_for_binding: Vec::new(), cannot_remove: FxHashSet::default(), + desugar_binding_spans: Vec::new(), }; finder.visit_body(body); @@ -952,9 +977,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { for (span, msg, suggestion) in suggestions { err.span_suggestion_verbose(span, msg, suggestion, Applicability::MachineApplicable); } + finder.desugar_binding_spans } - fn add_move_error_details(&self, err: &mut Diag<'_>, binds_to: &[Local]) { + fn add_move_error_details( + &self, + err: &mut Diag<'_>, + binds_to: &[Local], + desugar_spans: &[Span], + ) { for (j, local) in binds_to.iter().enumerate() { let bind_to = &self.body.local_decls[*local]; let binding_span = bind_to.source_info.span; @@ -968,7 +999,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if binds_to.len() == 1 { let place_desc = self.local_name(*local).map(|sym| format!("`{sym}`")); - if let Some(expr) = self.find_expr(binding_span) { + if !desugar_spans.contains(&binding_span) + && let Some(expr) = self.find_expr(binding_span) + { + // The binding_span doesn't correspond to a let binding desugaring + // and is an expression where calling `.clone()` would be valid. let local_place: PlaceRef<'tcx> = (*local).into(); self.suggest_cloning(err, local_place, bind_to.ty, expr, None); } diff --git a/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch b/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch index 6a0244cfde3fb..340f6cc9b0e7c 100644 --- a/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch +++ b/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch @@ -19,7 +19,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1557,7 +1557,7 @@ fn s_nan() -> Float { name: exp, attrs: { @@ -28,7 +28,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1578,7 +1578,7 @@ fn s_nan() -> Float { name: exp2, attrs: { @@ -37,7 +37,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1598,7 +1598,7 @@ fn s_nan() -> Float { name: ln, attrs: { @@ -46,7 +46,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1620,7 +1620,7 @@ fn s_nan() -> Float { name: log, attrs: { @@ -55,7 +55,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1645,7 +1645,7 @@ fn s_nan() -> Float { name: log2, attrs: { @@ -64,7 +64,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1668,7 +1668,7 @@ fn s_nan() -> Float { name: log10, attrs: { @@ -73,7 +73,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1692,7 +1692,7 @@ fn s_nan() -> Float { name: asinh, attrs: { @@ -82,7 +82,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1725,7 +1725,7 @@ fn s_nan() -> Float { name: acosh, attrs: { @@ -91,7 +91,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1753,7 +1753,7 @@ fn s_nan() -> Float { name: atanh, attrs: { @@ -100,7 +100,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1779,7 +1779,7 @@ fn s_nan() -> Float { name: gamma, attrs: { @@ -109,7 +109,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1814,7 +1814,7 @@ fn s_nan() -> Float { name: ln_gamma, attrs: { @@ -118,7 +118,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -2027,7 +2027,7 @@ fn s_nan() -> Float { attrs: { // FIXME(f16_f128): add math tests when available @@ -127,7 +127,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { -- 2.50.1 diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index b771addb8df55..4323debd80149 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -413,7 +413,7 @@ fn valtree_into_mplace<'tcx>( Some(variant_idx), ) } - _ => (place.clone(), branches, None), + _ => (place.clone(), branches.as_slice(), None), }; debug!(?place_adjusted, ?branches); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 777610402893b..c3d8865817830 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -438,6 +438,11 @@ fn const_evaluatable_predicates_of<'tcx>( return; } + // Skip type consts as mGCA doesn't support evaluatable clauses. + if self.tcx.is_type_const(uv.def) { + return; + } + let span = self.tcx.def_span(uv.def); self.preds.insert((ty::ClauseKind::ConstEvaluatable(c).upcast(self.tcx), span)); } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index ea4edb3ccf3cd..3b5274ce89c17 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -2436,10 +2436,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .struct_span_err(pat.span, "pattern requires `..` due to inaccessible fields"); if let Some(field) = fields.last() { + let tail_span = field.span.shrink_to_hi().to(pat.span.shrink_to_hi()); + let comma_hi_offset = + self.tcx.sess.source_map().span_to_snippet(tail_span).ok().and_then(|snippet| { + let trimmed = snippet.trim_start(); + trimmed.starts_with(',').then(|| (snippet.len() - trimmed.len() + 1) as u32) + }); err.span_suggestion_verbose( - field.span.shrink_to_hi(), + if let Some(comma_hi_offset) = comma_hi_offset { + tail_span.with_hi(tail_span.lo() + BytePos(comma_hi_offset)).shrink_to_hi() + } else { + field.span.shrink_to_hi() + }, "ignore the inaccessible and unused fields", - ", ..", + if comma_hi_offset.is_some() { " .." } else { ", .." }, Applicability::MachineApplicable, ); } else { diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index d00ef84725071..640e6f9838510 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -92,7 +92,6 @@ macro_rules! arena_types { [] name_set: rustc_data_structures::unord::UnordSet, [] autodiff_item: rustc_hir::attrs::AutoDiffItem, [] ordered_name_set: rustc_data_structures::fx::FxIndexSet, - [] valtree: rustc_middle::ty::ValTreeKind>, [] stable_order_of_exportable_impls: rustc_data_structures::fx::FxIndexMap, diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 5f78f414a742a..d1987f51f6e01 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -13,6 +13,7 @@ use std::marker::{DiscriminantKind, PointeeSized}; use rustc_abi::FieldIdx; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LocalDefId; +use rustc_middle::ty::Const; use rustc_serialize::{Decodable, Encodable}; use rustc_span::source_map::Spanned; use rustc_span::{Span, SpanDecoder, SpanEncoder}; @@ -497,6 +498,7 @@ impl_decodable_via_ref! { &'tcx ty::List>, &'tcx ty::List>, &'tcx ty::ListWithCachedTypeInfo>, + &'tcx ty::List>, } #[macro_export] diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 994f7d17c5c41..50242613b3e7f 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -31,12 +31,6 @@ impl<'tcx> ty::ValTreeKind> { // recurses through pub struct ValTree<'tcx>(pub(crate) Interned<'tcx, ty::ValTreeKind>>); -impl<'tcx> rustc_type_ir::inherent::ValTree> for ValTree<'tcx> { - fn kind(&self) -> &ty::ValTreeKind> { - &self - } -} - impl<'tcx> ValTree<'tcx> { /// Returns the zero-sized valtree: `Branch([])`. pub fn zst(tcx: TyCtxt<'tcx>) -> Self { @@ -44,7 +38,7 @@ impl<'tcx> ValTree<'tcx> { } pub fn is_zst(self) -> bool { - matches!(*self, ty::ValTreeKind::Branch(box [])) + matches!(*self, ty::ValTreeKind::Branch(consts) if consts.is_empty()) } pub fn from_raw_bytes(tcx: TyCtxt<'tcx>, bytes: &[u8]) -> Self { @@ -58,7 +52,9 @@ impl<'tcx> ValTree<'tcx> { tcx: TyCtxt<'tcx>, branches: impl IntoIterator>, ) -> Self { - tcx.intern_valtree(ty::ValTreeKind::Branch(branches.into_iter().collect())) + tcx.intern_valtree(ty::ValTreeKind::Branch( + tcx.mk_const_list_from_iter(branches.into_iter()), + )) } pub fn from_scalar_int(tcx: TyCtxt<'tcx>, i: ScalarInt) -> Self { @@ -81,6 +77,14 @@ impl fmt::Debug for ValTree<'_> { } } +impl<'tcx> rustc_type_ir::inherent::IntoKind for ty::ValTree<'tcx> { + type Kind = ty::ValTreeKind>; + + fn kind(self) -> Self::Kind { + *self.0 + } +} + /// `Ok(Err(ty))` indicates the constant was fine, but the valtree couldn't be constructed /// because the value contains something of type `ty` that is not valtree-compatible. /// The caller can then show an appropriate error; the query does not have the diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 68819445a06c4..8f94fc921563d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -564,7 +564,7 @@ impl<'tcx> CommonConsts<'tcx> { )) }; - let valtree_zst = mk_valtree(ty::ValTreeKind::Branch(Box::default())); + let valtree_zst = mk_valtree(ty::ValTreeKind::Branch(List::empty())); let valtree_true = mk_valtree(ty::ValTreeKind::Leaf(ty::ScalarInt::TRUE)); let valtree_false = mk_valtree(ty::ValTreeKind::Leaf(ty::ScalarInt::FALSE)); diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index a6b3f29d7ec23..af7da06ff4798 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -95,6 +95,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type Safety = hir::Safety; type Abi = ExternAbi; type Const = ty::Const<'tcx>; + type Consts = &'tcx List; type ParamConst = ty::ParamConst; type ValueConst = ty::Value<'tcx>; diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index a34244096d20c..8b8fe522842a4 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1930,7 +1930,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } // Otherwise, print the array separated by commas (or if it's a tuple) (ty::ValTreeKind::Branch(fields), ty::Array(..) | ty::Tuple(..)) => { - let fields_iter = fields.iter().copied(); + let fields_iter = fields.iter(); match *cv.ty.kind() { ty::Array(..) => { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 9a2f1e8a13a1a..04985dd3acde5 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -797,4 +797,5 @@ list_fold! { &'tcx ty::List> : mk_place_elems, &'tcx ty::List> : mk_patterns, &'tcx ty::List> : mk_outlives, + &'tcx ty::List> : mk_const_list, } diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index d04322c320b4c..38055471e83a8 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -2941,12 +2941,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match pat.ctor() { Constructor::Variant(variant_index) => { - let ValTreeKind::Branch(box [actual_variant_idx]) = *valtree else { + let ValTreeKind::Branch(branch) = *valtree else { bug!("malformed valtree for an enum") }; - - let ValTreeKind::Leaf(actual_variant_idx) = *actual_variant_idx.to_value().valtree - else { + if branch.len() != 1 { + bug!("malformed valtree for an enum") + }; + let ValTreeKind::Leaf(actual_variant_idx) = **branch[0].to_value().valtree else { bug!("malformed valtree for an enum") }; diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 02deff6474080..c5eeb8b1aa856 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -806,6 +806,10 @@ impl<'tcx> ThirBuildCx<'tcx> { lit: ScalarInt::try_from_uint(val, Size::from_bits(32)).unwrap(), user_ty: None, }; + let mk_usize_kind = |val: u64| ExprKind::NonHirLiteral { + lit: ScalarInt::try_from_target_usize(val, tcx).unwrap(), + user_ty: None, + }; let mk_call = |thir: &mut Thir<'tcx>, ty: Ty<'tcx>, variant: VariantIdx, field: FieldIdx| { let fun_ty = @@ -842,7 +846,7 @@ impl<'tcx> ThirBuildCx<'tcx> { }); } - expr.unwrap_or(mk_u32_kind(0)) + expr.unwrap_or_else(|| mk_usize_kind(0)) } hir::ExprKind::ConstBlock(ref anon_const) => { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3e2f10df20b8f..3b77505229a30 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -9,7 +9,7 @@ use std::cell::Cell; use std::collections::hash_map::Entry; use std::slice; -use rustc_abi::{Align, ExternAbi, Size}; +use rustc_abi::ExternAbi; use rustc_ast::{AttrStyle, MetaItemKind, ast}; use rustc_attr_parsing::{AttributeParser, Late}; use rustc_data_structures::fx::FxHashMap; @@ -190,8 +190,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &Attribute::Parsed(AttributeKind::RustcPubTransparent(attr_span)) => { self.check_rustc_pub_transparent(attr_span, span, attrs) } - Attribute::Parsed(AttributeKind::RustcAlign { align, span: attr_span }) => { - self.check_align(*align, *attr_span) + Attribute::Parsed(AttributeKind::RustcAlign {..}) => { + } Attribute::Parsed(AttributeKind::Naked(..)) => { self.check_naked(hir_id, target) @@ -1335,31 +1335,27 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } } - ReprAttr::ReprAlign(align) => { - match target { - Target::Struct | Target::Union | Target::Enum => {} - Target::Fn | Target::Method(_) if self.tcx.features().fn_align() => { - self.dcx().emit_err(errors::ReprAlignShouldBeAlign { - span: *repr_span, - item: target.plural_name(), - }); - } - Target::Static if self.tcx.features().static_align() => { - self.dcx().emit_err(errors::ReprAlignShouldBeAlignStatic { - span: *repr_span, - item: target.plural_name(), - }); - } - _ => { - self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { - hint_span: *repr_span, - span, - }); - } + ReprAttr::ReprAlign(..) => match target { + Target::Struct | Target::Union | Target::Enum => {} + Target::Fn | Target::Method(_) if self.tcx.features().fn_align() => { + self.dcx().emit_err(errors::ReprAlignShouldBeAlign { + span: *repr_span, + item: target.plural_name(), + }); } - - self.check_align(*align, *repr_span); - } + Target::Static if self.tcx.features().static_align() => { + self.dcx().emit_err(errors::ReprAlignShouldBeAlignStatic { + span: *repr_span, + item: target.plural_name(), + }); + } + _ => { + self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { + hint_span: *repr_span, + span, + }); + } + }, ReprAttr::ReprPacked(_) => { if target != Target::Struct && target != Target::Union { self.dcx().emit_err(errors::AttrApplication::StructUnion { @@ -1475,25 +1471,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_align(&self, align: Align, span: Span) { - if align.bytes() > 2_u64.pow(29) { - // for values greater than 2^29, a different error will be emitted, make sure that happens - self.dcx().span_delayed_bug( - span, - "alignment greater than 2^29 should be errored on elsewhere", - ); - } else { - // only do this check when <= 2^29 to prevent duplicate errors: - // alignment greater than 2^29 not supported - // alignment is too large for the current target - - let max = Size::from_bits(self.tcx.sess.target.pointer_width).signed_int_max() as u64; - if align.bytes() > max { - self.dcx().emit_err(errors::InvalidReprAlignForTarget { span, size: max }); - } - } - } - /// Outputs an error for attributes that can only be applied to macros, such as /// `#[allow_internal_unsafe]` and `#[allow_internal_unstable]`. /// (Allows proc_macro functions) diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 8073cb257b032..bd3fd6935e8f3 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -236,15 +236,6 @@ pub(crate) struct ReprConflicting { pub hint_spans: Vec, } -#[derive(Diagnostic)] -#[diag("alignment must not be greater than `isize::MAX` bytes", code = E0589)] -#[note("`isize::MAX` is {$size} for the current target")] -pub(crate) struct InvalidReprAlignForTarget { - #[primary_span] - pub span: Span, - pub size: u64, -} - #[derive(Diagnostic)] #[diag("conflicting representation hints", code = E0566)] pub(crate) struct ReprConflictingLint; diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 52f86be310fb9..4a0a99ea27640 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -1016,17 +1016,20 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { match c.kind() { ty::ConstKind::Unevaluated(uv) => { if !c.has_escaping_bound_vars() { - let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( - ty::ClauseKind::ConstEvaluatable(c), - )); - let cause = self.cause(ObligationCauseCode::WellFormed(None)); - self.out.push(traits::Obligation::with_depth( - tcx, - cause, - self.recursion_depth, - self.param_env, - predicate, - )); + // Skip type consts as mGCA doesn't support evaluatable clauses + if !tcx.is_type_const(uv.def) { + let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( + ty::ClauseKind::ConstEvaluatable(c), + )); + let cause = self.cause(ObligationCauseCode::WellFormed(None)); + self.out.push(traits::Obligation::with_depth( + tcx, + cause, + self.recursion_depth, + self.param_env, + predicate, + )); + } if matches!(tcx.def_kind(uv.def), DefKind::AssocConst { .. }) && tcx.def_kind(tcx.parent(uv.def)) == (DefKind::Impl { of_trait: false }) diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index 1c39f31469b1c..49fb94c830e24 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -140,7 +140,7 @@ impl HashStable for InferConst { /// /// `ValTree` does not have this problem with representation, as it only contains integers or /// lists of (nested) `ty::Const`s (which may indirectly contain more `ValTree`s). -#[derive_where(Clone, Debug, Hash, Eq, PartialEq; I: Interner)] +#[derive_where(Clone, Copy, Debug, Hash, Eq, PartialEq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr( feature = "nightly", @@ -159,8 +159,7 @@ pub enum ValTreeKind { /// the fields of the variant. /// /// ZST types are represented as an empty slice. - // FIXME(mgca): Use a `List` here instead of a boxed slice - Branch(Box<[I::Const]>), + Branch(I::Consts), } impl ValTreeKind { @@ -177,9 +176,9 @@ impl ValTreeKind { /// Converts to a `ValTreeKind::Branch` value, `panic`'ing /// if this valtree is some other kind. #[inline] - pub fn to_branch(&self) -> &[I::Const] { + pub fn to_branch(&self) -> I::Consts { match self { - ValTreeKind::Branch(branch) => &**branch, + ValTreeKind::Branch(branch) => *branch, ValTreeKind::Leaf(..) => panic!("expected branch, got {:?}", self), } } @@ -193,9 +192,9 @@ impl ValTreeKind { } /// Attempts to convert to a `ValTreeKind::Branch` value. - pub fn try_to_branch(&self) -> Option<&[I::Const]> { + pub fn try_to_branch(&self) -> Option { match self { - ValTreeKind::Branch(branch) => Some(&**branch), + ValTreeKind::Branch(branch) => Some(*branch), ValTreeKind::Leaf(_) => None, } } diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 8b057e5866cd9..7e905da0785f8 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -482,8 +482,8 @@ impl FlagComputation { match cv.valtree().kind() { ty::ValTreeKind::Leaf(_) => (), ty::ValTreeKind::Branch(cts) => { - for ct in cts { - self.add_const(*ct); + for ct in cts.iter() { + self.add_const(ct); } } } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 8256ea7ed312e..116fd100bf0a9 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -294,12 +294,6 @@ pub trait ValueConst>: Copy + Debug + Hash + Eq { fn valtree(self) -> I::ValTree; } -// FIXME(mgca): This trait can be removed once we're not using a `Box` in `Branch` -pub trait ValTree>: Copy + Debug + Hash + Eq { - // This isnt' `IntoKind` because then we can't return a reference - fn kind(&self) -> &ty::ValTreeKind; -} - pub trait ExprConst>: Copy + Debug + Hash + Eq + Relate { fn args(self) -> I::GenericArgs; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 8f446cdfba6d5..e77e7af071b90 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -150,10 +150,11 @@ pub trait Interner: // Kinds of consts type Const: Const; + type Consts: Copy + Debug + Hash + Eq + SliceLike + Default; type ParamConst: Copy + Debug + Hash + Eq + ParamLike; type ValueConst: ValueConst; type ExprConst: ExprConst; - type ValTree: ValTree; + type ValTree: Copy + Debug + Hash + Eq + IntoKind>; type ScalarInt: Copy + Debug + Hash + Eq; // Kinds of regions diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 3610605462ba9..d33c6036dadd8 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -577,9 +577,9 @@ pub fn structurally_relate_consts>( if branches_a.len() == branches_b.len() => { branches_a - .into_iter() - .zip(branches_b) - .all(|(a, b)| relation.relate(*a, *b).is_ok()) + .iter() + .zip(branches_b.iter()) + .all(|(a, b)| relation.relate(a, b).is_ok()) } _ => false, } diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index b729cdf8458d7..3e39528dfbf43 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -218,31 +218,28 @@ const fn lim_for_ty(_x: T) -> T { // We have runtime ("rt") and const versions of these macros. /// Verify that floats are within a tolerance of each other. -macro_rules! assert_approx_eq_rt { - ($a:expr, $b:expr) => {{ assert_approx_eq_rt!($a, $b, $crate::floats::lim_for_ty($a)) }}; +macro_rules! assert_approx_eq { + ($a:expr, $b:expr $(,)?) => {{ assert_approx_eq!($a, $b, $crate::floats::lim_for_ty($a)) }}; ($a:expr, $b:expr, $lim:expr) => {{ let (a, b) = (&$a, &$b); let diff = (*a - *b).abs(); - assert!( + core::panic::const_assert!( diff <= $lim, + "actual value is not approximately equal to expected value", "{a:?} is not approximately equal to {b:?} (threshold {lim:?}, difference {diff:?})", - lim = $lim + // We rely on the `Float` type being brought in scope by the macros below. + a: Float = *a, + b: Float = *b, + diff: Float = diff, + lim: Float = $lim, ); }}; } -macro_rules! assert_approx_eq_const { - ($a:expr, $b:expr) => {{ assert_approx_eq_const!($a, $b, $crate::floats::lim_for_ty($a)) }}; - ($a:expr, $b:expr, $lim:expr) => {{ - let (a, b) = (&$a, &$b); - let diff = (*a - *b).abs(); - assert!(diff <= $lim); - }}; -} /// Verify that floats have the same bitwise representation. Used to avoid the default `0.0 == -0.0` /// behavior, as well as to ensure exact NaN bitpatterns. -macro_rules! assert_biteq_rt { - (@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{ +macro_rules! assert_biteq { + ($left:expr, $right:expr $(,)?) => {{ let l = $left; let r = $right; @@ -252,63 +249,21 @@ macro_rules! assert_biteq_rt { // Hack to get the width from a value let bits = (l.to_bits() - l.to_bits()).leading_zeros(); - assert!( + core::panic::const_assert!( l.to_bits() == r.to_bits(), - "{msg}{nl}l: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", - msg = format_args!($($tt)*), - nl = $msg_sep, - lb = l.to_bits(), - rb = r.to_bits(), - width = ((bits / 4) + 2) as usize, + "actual value and expected value are not bit-equal", + "actual value and expected value are not bit-equal\n\ + l: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", + // We rely on the `Float` type being brought in scope by the macros below. + l: Float = l, + r: Float = r, + lb: ::Int = l.to_bits(), + rb: ::Int = r.to_bits(), + width: usize = ((bits / 4) + 2) as usize, ); - - if !l.is_nan() && !r.is_nan() { - // Also check that standard equality holds, since most tests use `assert_biteq` rather - // than `assert_eq`. - assert_eq!(l, r); - } - }}; - ($left:expr, $right:expr , $($tt:tt)*) => { - assert_biteq_rt!(@inner $left, $right, "\n", $($tt)*) - }; - ($left:expr, $right:expr $(,)?) => { - assert_biteq_rt!(@inner $left, $right, "", "") - }; -} -macro_rules! assert_biteq_const { - (@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{ - let l = $left; - let r = $right; - - // Hack to coerce left and right to the same type - let mut _eq_ty = l; - _eq_ty = r; - - assert!(l.to_bits() == r.to_bits()); - - if !l.is_nan() && !r.is_nan() { - // Also check that standard equality holds, since most tests use `assert_biteq` rather - // than `assert_eq`. - assert!(l == r); - } }}; - ($left:expr, $right:expr , $($tt:tt)*) => { - assert_biteq_const!(@inner $left, $right, "\n", $($tt)*) - }; - ($left:expr, $right:expr $(,)?) => { - assert_biteq_const!(@inner $left, $right, "", "") - }; } -// Use the runtime version by default. -// This way, they can be shadowed by the const versions. -pub(crate) use {assert_approx_eq_rt as assert_approx_eq, assert_biteq_rt as assert_biteq}; - -// Also make the const version available for re-exports. -#[rustfmt::skip] -pub(crate) use assert_biteq_const; -pub(crate) use assert_approx_eq_const; - /// Generate float tests for all our float types, for compile-time and run-time behavior. /// /// By default all tests run for all float types. Configuration can be applied via `attrs`. @@ -341,7 +296,7 @@ macro_rules! float_test { $(f128: #[ $($f128_meta:meta),+ ] ,)? $(const f128: #[ $($f128_const_meta:meta),+ ] ,)? }, - test<$fty:ident> $test:block + test $test:block ) => { mod $name { use super::*; @@ -351,9 +306,9 @@ macro_rules! float_test { fn test_f16() { #[allow(unused_imports)] use core::f16::consts; - type $fty = f16; + type Float = f16; #[allow(unused)] - const fn flt (x: $fty) -> $fty { x } + const fn flt (x: Float) -> Float { x } $test } @@ -362,9 +317,9 @@ macro_rules! float_test { fn test_f32() { #[allow(unused_imports)] use core::f32::consts; - type $fty = f32; + type Float = f32; #[allow(unused)] - const fn flt (x: $fty) -> $fty { x } + const fn flt (x: Float) -> Float { x } $test } @@ -373,9 +328,9 @@ macro_rules! float_test { fn test_f64() { #[allow(unused_imports)] use core::f64::consts; - type $fty = f64; + type Float = f64; #[allow(unused)] - const fn flt (x: $fty) -> $fty { x } + const fn flt (x: Float) -> Float { x } $test } @@ -384,35 +339,24 @@ macro_rules! float_test { fn test_f128() { #[allow(unused_imports)] use core::f128::consts; - type $fty = f128; + type Float = f128; #[allow(unused)] - const fn flt (x: $fty) -> $fty { x } + const fn flt (x: Float) -> Float { x } $test } $( $( #[$const_meta] )+ )? mod const_ { - #[allow(unused)] - use super::TestableFloat; - #[allow(unused)] - use std::num::FpCategory as Fp; - #[allow(unused)] - use std::ops::{Add, Div, Mul, Rem, Sub}; - // Shadow the runtime versions of the macro with const-compatible versions. - #[allow(unused)] - use $crate::floats::{ - assert_approx_eq_const as assert_approx_eq, - assert_biteq_const as assert_biteq, - }; + use super::*; #[test] $( $( #[$f16_const_meta] )+ )? fn test_f16() { #[allow(unused_imports)] use core::f16::consts; - type $fty = f16; + type Float = f16; #[allow(unused)] - const fn flt (x: $fty) -> $fty { x } + const fn flt (x: Float) -> Float { x } const { $test } } @@ -421,9 +365,9 @@ macro_rules! float_test { fn test_f32() { #[allow(unused_imports)] use core::f32::consts; - type $fty = f32; + type Float = f32; #[allow(unused)] - const fn flt (x: $fty) -> $fty { x } + const fn flt (x: Float) -> Float { x } const { $test } } @@ -432,9 +376,9 @@ macro_rules! float_test { fn test_f64() { #[allow(unused_imports)] use core::f64::consts; - type $fty = f64; + type Float = f64; #[allow(unused)] - const fn flt (x: $fty) -> $fty { x } + const fn flt (x: Float) -> Float { x } const { $test } } @@ -443,9 +387,9 @@ macro_rules! float_test { fn test_f128() { #[allow(unused_imports)] use core::f128::consts; - type $fty = f128; + type Float = f128; #[allow(unused)] - const fn flt (x: $fty) -> $fty { x } + const fn flt (x: Float) -> Float { x } const { $test } } } @@ -459,7 +403,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let two: Float = 2.0; let ten: Float = 10.0; assert_biteq!(ten.add(two), ten + two); @@ -477,7 +421,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { let two: Float = 2.0; let ten: Float = 10.0; assert_biteq!(ten.rem(two), ten % two); @@ -490,7 +434,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let nan: Float = Float::NAN; assert!(nan.is_nan()); assert!(!nan.is_infinite()); @@ -510,7 +454,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let inf: Float = Float::INFINITY; assert!(inf.is_infinite()); assert!(!inf.is_finite()); @@ -528,7 +472,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let neg_inf: Float = Float::NEG_INFINITY; assert!(neg_inf.is_infinite()); assert!(!neg_inf.is_finite()); @@ -546,7 +490,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert_biteq!(0.0, Float::ZERO); assert!(!Float::ZERO.is_infinite()); assert!(Float::ZERO.is_finite()); @@ -564,7 +508,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let neg_zero: Float = -0.0; assert!(0.0 == neg_zero); assert_biteq!(-0.0, neg_zero); @@ -584,7 +528,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert_biteq!(1.0, Float::ONE); assert!(!Float::ONE.is_infinite()); assert!(Float::ONE.is_finite()); @@ -602,7 +546,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -623,7 +567,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -644,7 +588,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -665,7 +609,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -686,7 +630,7 @@ float_test! { attrs: { f16: #[cfg(any(miri, target_has_reliable_f16))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -708,7 +652,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(0.0).min(0.0), 0.0); assert_biteq!(flt(-0.0).min(-0.0), -0.0); assert_biteq!(flt(9.0).min(9.0), 9.0); @@ -738,7 +682,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(0.0).max(0.0), 0.0); assert_biteq!(flt(-0.0).max(-0.0), -0.0); assert_biteq!(flt(9.0).max(9.0), 9.0); @@ -769,7 +713,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(0.0).minimum(0.0), 0.0); assert_biteq!(flt(-0.0).minimum(0.0), -0.0); assert_biteq!(flt(-0.0).minimum(-0.0), -0.0); @@ -800,7 +744,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(0.0).maximum(0.0), 0.0); assert_biteq!(flt(-0.0).maximum(0.0), 0.0); assert_biteq!(flt(-0.0).maximum(-0.0), -0.0); @@ -832,7 +776,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(0.5).midpoint(0.5), 0.5); assert_biteq!(flt(0.5).midpoint(2.5), 1.5); assert_biteq!(flt(3.0).midpoint(4.0), 3.5); @@ -885,7 +829,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { // test if large differences in magnitude are still correctly computed. // NOTE: that because of how small x and y are, x + y can never overflow // so (x + y) / 2.0 is always correct @@ -915,7 +859,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(Float::INFINITY.abs(), Float::INFINITY); assert_biteq!(Float::ONE.abs(), Float::ONE); assert_biteq!(Float::ZERO.abs(), Float::ZERO); @@ -933,7 +877,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(1.0).copysign(-2.0), -1.0); assert_biteq!(flt(-1.0).copysign(2.0), 1.0); assert_biteq!(Float::INFINITY.copysign(-0.0), Float::NEG_INFINITY); @@ -948,7 +892,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert!(Float::INFINITY.rem_euclid(42.0).is_nan()); assert_biteq!(flt(42.0).rem_euclid(Float::INFINITY), 42.0); assert!(flt(42.0).rem_euclid(Float::NAN).is_nan()); @@ -965,7 +909,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(42.0).div_euclid(Float::INFINITY), 0.0); assert!(flt(42.0).div_euclid(Float::NAN).is_nan()); assert!(Float::INFINITY.div_euclid(Float::INFINITY).is_nan()); @@ -980,7 +924,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(1.0).floor(), 1.0); assert_biteq!(flt(1.3).floor(), 1.0); assert_biteq!(flt(1.5).floor(), 1.0); @@ -1009,7 +953,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(1.0).ceil(), 1.0); assert_biteq!(flt(1.3).ceil(), 2.0); assert_biteq!(flt(1.5).ceil(), 2.0); @@ -1038,7 +982,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(2.5).round(), 3.0); assert_biteq!(flt(1.0).round(), 1.0); assert_biteq!(flt(1.3).round(), 1.0); @@ -1068,7 +1012,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(2.5).round_ties_even(), 2.0); assert_biteq!(flt(1.0).round_ties_even(), 1.0); assert_biteq!(flt(1.3).round_ties_even(), 1.0); @@ -1098,7 +1042,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(1.0).trunc(), 1.0); assert_biteq!(flt(1.3).trunc(), 1.0); assert_biteq!(flt(1.5).trunc(), 1.0); @@ -1127,7 +1071,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(1.0).fract(), 0.0); assert_approx_eq!(flt(1.3).fract(), 0.3); // rounding differs between float types assert_biteq!(flt(1.5).fract(), 0.5); @@ -1158,7 +1102,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(Float::INFINITY.signum(), Float::ONE); assert_biteq!(Float::ONE.signum(), Float::ONE); assert_biteq!(Float::ZERO.signum(), Float::ONE); @@ -1176,7 +1120,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert!(Float::INFINITY.is_sign_positive()); assert!(Float::ONE.is_sign_positive()); assert!(Float::ZERO.is_sign_positive()); @@ -1195,7 +1139,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert!(!Float::INFINITY.is_sign_negative()); assert!(!Float::ONE.is_sign_negative()); assert!(!Float::ZERO.is_sign_negative()); @@ -1214,7 +1158,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert_biteq!(Float::NEG_INFINITY.next_up(), Float::MIN); assert_biteq!(Float::MIN.next_up(), -Float::MAX_DOWN); assert_biteq!((-Float::ONE - Float::EPSILON).next_up(), -Float::ONE); @@ -1245,7 +1189,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert_biteq!(Float::NEG_INFINITY.next_down(), Float::NEG_INFINITY); assert_biteq!(Float::MIN.next_down(), Float::NEG_INFINITY); assert_biteq!((-Float::MAX_DOWN).next_down(), Float::MIN); @@ -1278,7 +1222,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert!(Float::NAN.sqrt().is_nan()); assert!(Float::NEG_INFINITY.sqrt().is_nan()); assert!((-Float::ONE).sqrt().is_nan()); @@ -1298,7 +1242,7 @@ float_test! { f64: #[should_panic], f128: #[should_panic, cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let _ = Float::ONE.clamp(3.0, 1.0); } } @@ -1312,7 +1256,7 @@ float_test! { f64: #[should_panic], f128: #[should_panic, cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let _ = Float::ONE.clamp(Float::NAN, 1.0); } } @@ -1326,7 +1270,7 @@ float_test! { f64: #[should_panic], f128: #[should_panic, cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let _ = Float::ONE.clamp(3.0, Float::NAN); } } @@ -1337,7 +1281,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { use core::cmp::Ordering; const fn quiet_bit_mask() -> ::Int { @@ -1442,7 +1386,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { use core::cmp::Ordering; fn quiet_bit_mask() -> ::Int { @@ -1498,7 +1442,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -1522,7 +1466,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -1543,7 +1487,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -1566,7 +1510,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(1.0, flt(0.0).exp()); assert_approx_eq!(consts::E, flt(1.0).exp(), Float::EXP_APPROX); assert_approx_eq!(148.41315910257660342111558004055227962348775, flt(5.0).exp(), Float::EXP_APPROX); @@ -1587,7 +1531,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { assert_approx_eq!(32.0, flt(5.0).exp2(), Float::EXP_APPROX); assert_biteq!(1.0, flt(0.0).exp2()); @@ -1607,7 +1551,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -1629,7 +1573,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -1654,7 +1598,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -1677,7 +1621,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -1701,7 +1645,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(0.0).asinh(), 0.0); assert_biteq!(flt(-0.0).asinh(), -0.0); @@ -1734,7 +1678,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(1.0).acosh(), 0.0); assert!(flt(0.999).acosh().is_nan()); @@ -1762,7 +1706,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(0.0).atanh(), 0.0); assert_biteq!(flt(-0.0).atanh(), -0.0); @@ -1788,7 +1732,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { assert_approx_eq!(flt(1.0).gamma(), 1.0, Float::GAMMA_APPROX); assert_approx_eq!(flt(2.0).gamma(), 1.0, Float::GAMMA_APPROX); assert_approx_eq!(flt(3.0).gamma(), 2.0, Float::GAMMA_APPROX); @@ -1823,7 +1767,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { assert_approx_eq!(flt(1.0).ln_gamma().0, 0.0, Float::LNGAMMA_APPROX); assert_eq!(flt(1.0).ln_gamma().1, 1); assert_approx_eq!(flt(2.0).ln_gamma().0, 0.0, Float::LNGAMMA_APPROX); @@ -1841,7 +1785,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let pi: Float = consts::PI; let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; @@ -1862,7 +1806,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let pi: Float = consts::PI; let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; @@ -1883,7 +1827,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let a: Float = flt(123.0); let b: Float = flt(456.0); @@ -1907,7 +1851,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert_biteq!(flt(1.0), Float::RAW_1); assert_biteq!(flt(12.5), Float::RAW_12_DOT_5); assert_biteq!(flt(1337.0), Float::RAW_1337); @@ -1937,7 +1881,7 @@ float_test! { f64: #[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -1959,7 +1903,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert_biteq!(Float::from(false), Float::ZERO); assert_biteq!(Float::from(true), Float::ONE); @@ -1980,7 +1924,7 @@ float_test! { const f16: #[cfg(false)], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert_biteq!(Float::from(u16::MIN), Float::ZERO); assert_biteq!(Float::from(42_u16), 42.0); assert_biteq!(Float::from(u16::MAX), 65535.0); @@ -1999,7 +1943,7 @@ float_test! { const f32: #[cfg(false)], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert_biteq!(Float::from(u32::MIN), Float::ZERO); assert_biteq!(Float::from(42_u32), 42.0); assert_biteq!(Float::from(u32::MAX), 4294967295.0); @@ -2016,7 +1960,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { // The maximum integer that converts to a unique floating point // value. const MAX_EXACT_INTEGER: ::SInt = Float::MAX_EXACT_INTEGER; @@ -2058,7 +2002,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { // The minimum integer that converts to a unique floating point // value. const MIN_EXACT_INTEGER: ::SInt = Float::MIN_EXACT_INTEGER; @@ -2105,7 +2049,7 @@ float_test! { // f64: #[cfg(false)], // f128: #[cfg(any(miri, target_has_reliable_f128))], // }, -// test { +// test { // assert_biteq!(Float::from(u64::MIN), Float::ZERO); // assert_biteq!(Float::from(42_u64), 42.0); // assert_biteq!(Float::from(u64::MAX), 18446744073709551615.0); @@ -2123,7 +2067,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { let pi: Float = consts::PI; assert_approx_eq!(consts::FRAC_PI_2, pi / 2.0); assert_approx_eq!(consts::FRAC_PI_3, pi / 3.0, Float::APPROX); diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 5e303a3c6b790..d04b9a2d6e136 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -90,11 +90,13 @@ #![feature(nonzero_from_str_radix)] #![feature(numfmt)] #![feature(one_sided_range)] +#![feature(panic_internals)] #![feature(pattern)] #![feature(pointer_is_aligned_to)] #![feature(portable_simd)] #![feature(ptr_metadata)] #![feature(result_option_map_or_default)] +#![feature(rustc_attrs)] #![feature(signed_bigint_helpers)] #![feature(slice_from_ptr_range)] #![feature(slice_index_methods)] diff --git a/library/std/src/sys/sync/once/mod.rs b/library/std/src/sys/sync/once/mod.rs index aeea884b9f617..5796c6d207dba 100644 --- a/library/std/src/sys/sync/once/mod.rs +++ b/library/std/src/sys/sync/once/mod.rs @@ -12,7 +12,7 @@ cfg_select! { all(target_os = "windows", not(target_vendor="win7")), target_os = "linux", target_os = "android", - all(target_arch = "wasm32", target_feature = "atomics"), + all(target_family = "wasm", target_feature = "atomics"), target_os = "freebsd", target_os = "motor", target_os = "openbsd", diff --git a/library/std/src/sys/sync/thread_parking/mod.rs b/library/std/src/sys/sync/thread_parking/mod.rs index 74b5b72b19a75..9d5a0a996b115 100644 --- a/library/std/src/sys/sync/thread_parking/mod.rs +++ b/library/std/src/sys/sync/thread_parking/mod.rs @@ -3,7 +3,7 @@ cfg_select! { all(target_os = "windows", not(target_vendor = "win7")), target_os = "linux", target_os = "android", - all(target_arch = "wasm32", target_feature = "atomics"), + all(target_family = "wasm", target_feature = "atomics"), target_os = "freebsd", target_os = "openbsd", target_os = "dragonfly", diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index db7c7b69cba94..105e41ca45f63 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -696,7 +696,7 @@ def download_toolchain(self): for download_info in tarballs_download_info: download_component(download_info) - # Unpack the tarballs in parallle. + # Unpack the tarballs in parallel. # In Python 2.7, Pool cannot be used as a context manager. pool_size = min(len(tarballs_download_info), get_cpus()) if self.verbose: diff --git a/src/tools/rust-analyzer/.codecov.yml b/src/tools/rust-analyzer/.codecov.yml new file mode 100644 index 0000000000000..68eacb7d08cbb --- /dev/null +++ b/src/tools/rust-analyzer/.codecov.yml @@ -0,0 +1,10 @@ +coverage: + range: 40...60 + status: + patch: off + project: + default: + informational: true + +# Don't leave comments on PRs +comment: false diff --git a/src/tools/rust-analyzer/.github/workflows/coverage.yaml b/src/tools/rust-analyzer/.github/workflows/coverage.yaml new file mode 100644 index 0000000000000..bd4edba747ca1 --- /dev/null +++ b/src/tools/rust-analyzer/.github/workflows/coverage.yaml @@ -0,0 +1,44 @@ +name: Coverage + +on: [pull_request, push] + +env: + CARGO_INCREMENTAL: 0 + CARGO_NET_RETRY: 10 + CI: 1 + RUST_BACKTRACE: short + RUSTUP_MAX_RETRIES: 10 + +jobs: + coverage: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust toolchain + run: | + rustup update --no-self-update nightly + rustup default nightly + rustup component add --toolchain nightly rust-src rustc-dev rustfmt + # We also install a nightly rustfmt, because we use `--file-lines` in + # a test. + rustup toolchain install nightly --profile minimal --component rustfmt + + rustup toolchain install nightly --component llvm-tools-preview + + - name: Install cargo-llvm-cov + uses: taiki-e/install-action@cargo-llvm-cov + + - name: Install nextest + uses: taiki-e/install-action@nextest + + - name: Generate code coverage + run: cargo llvm-cov --workspace --lcov --output-path lcov.info + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v5 + with: + files: lcov.info + fail_ci_if_error: false + token: ${{ secrets.CODECOV_TOKEN }} + verbose: true diff --git a/src/tools/rust-analyzer/AGENTS.md b/src/tools/rust-analyzer/AGENTS.md new file mode 120000 index 0000000000000..681311eb9cf45 --- /dev/null +++ b/src/tools/rust-analyzer/AGENTS.md @@ -0,0 +1 @@ +CLAUDE.md \ No newline at end of file diff --git a/src/tools/rust-analyzer/CLAUDE.md b/src/tools/rust-analyzer/CLAUDE.md new file mode 100644 index 0000000000000..e8f699d92813a --- /dev/null +++ b/src/tools/rust-analyzer/CLAUDE.md @@ -0,0 +1,40 @@ +**Reminder: All AI usage must be disclosed in commit messages, see +CONTRIBUTING.md for more details.** + +## Build Commands + +```bash +cargo build # Build all crates +cargo test # Run all tests +cargo test -p # Run tests for a specific crate (e.g., cargo test -p hir-ty) +cargo lint # Run clippy on all targets +cargo xtask codegen # Run code generation +cargo xtask tidy # Run tidy checks +UPDATE_EXPECT=1 cargo test # Update test expectations (snapshot tests) +RUN_SLOW_TESTS=1 cargo test # Run heavy/slow tests +``` + +## Key Architectural Invariants + +- Typing in a function body never invalidates global derived data +- Parser/syntax tree is built per-file to enable parallel parsing +- The server is stateless (HTTP-like); context must be re-created from request parameters +- Cancellation uses salsa's cancellation mechanism; computations panic with a `Cancelled` payload + +### Code Generation + +Generated code is committed to the repo. Grammar and AST are generated from `ungrammar`. Run `cargo test -p xtask` after adding inline parser tests (`// test test_name` comments). + +## Testing + +Tests are snapshot-based using `expect-test`. Test fixtures use a mini-language: +- `$0` marks cursor position +- `// ^^^^` labels attach to the line above +- `//- minicore: sized, fn` includes parts of minicore (minimal core library) +- `//- /path/to/file.rs crate:name deps:dep1,dep2` declares files/crates + +## Style Notes + +- Use `stdx::never!` and `stdx::always!` instead of `assert!` for recoverable invariants +- Use `T![fn]` macro instead of `SyntaxKind::FN_KW` +- Use keyword name mangling over underscore prefixing for identifiers: `crate` → `krate`, `fn` → `func`, `struct` → `strukt`, `type` → `ty` diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 9db4dd7cb1a3a..f31dda4a107bc 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -2635,7 +2635,7 @@ dependencies = [ [[package]] name = "smol_str" -version = "0.3.5" +version = "0.3.6" dependencies = [ "arbitrary", "borsh", diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs index ccd001df69b41..cb5eed1b8b6cd 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs @@ -234,7 +234,7 @@ impl Visibility { if mod_.krate(db) == krate { Some(Visibility::Module(mod_, exp)) } else { None } } (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => { - if mod_a.krate(db) != mod_b.krate(db) { + if mod_a == mod_b { // Most module visibilities are `pub(self)`, and assuming no errors // this will be the common and thus fast path. return Some(Visibility::Module( diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs index ae8eef2bbb5d9..949b22b0adaa6 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs @@ -5,10 +5,7 @@ use std::borrow::Cow; use base_db::AnchoredPath; use cfg::CfgExpr; use either::Either; -use intern::{ - Symbol, - sym, -}; +use intern::{Symbol, sym}; use itertools::Itertools; use mbe::{DelimiterKind, expect_fragment}; use span::{Edition, FileId, Span}; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 16e7d51e8734f..45b181eff8f0a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -658,7 +658,7 @@ impl<'db> InferenceContext<'_, 'db> { } } if let RecordSpread::Expr(expr) = *spread { - self.infer_expr(expr, &Expectation::has_type(ty), ExprIsRead::Yes); + self.infer_expr_coerce_never(expr, &Expectation::has_type(ty), ExprIsRead::Yes); } ty } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/op.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/op.rs index c79c828cd4420..95d63ffb508f6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/op.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/op.rs @@ -178,9 +178,9 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // trait matching creating lifetime constraints that are too strict. // e.g., adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result // in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`. - let lhs_ty = self.infer_expr_no_expect(lhs_expr, ExprIsRead::No); + let lhs_ty = self.infer_expr_no_expect(lhs_expr, ExprIsRead::Yes); let fresh_var = self.table.next_ty_var(); - self.demand_coerce(lhs_expr, lhs_ty, fresh_var, AllowTwoPhase::No, ExprIsRead::No) + self.demand_coerce(lhs_expr, lhs_ty, fresh_var, AllowTwoPhase::No, ExprIsRead::Yes) } }; let lhs_ty = self.table.resolve_vars_with_obligations(lhs_ty); @@ -200,7 +200,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // see `NB` above let rhs_ty = - self.infer_expr_coerce(rhs_expr, &Expectation::HasType(rhs_ty_var), ExprIsRead::No); + self.infer_expr_coerce(rhs_expr, &Expectation::HasType(rhs_ty_var), ExprIsRead::Yes); let rhs_ty = self.table.resolve_vars_with_obligations(rhs_ty); let return_ty = match result { @@ -320,7 +320,11 @@ impl<'a, 'db> InferenceContext<'a, 'db> { if let Some((rhs_expr, rhs_ty)) = opt_rhs && rhs_ty.is_ty_var() { - self.infer_expr_coerce(rhs_expr, &Expectation::HasType(rhs_ty), ExprIsRead::No); + self.infer_expr_coerce( + rhs_expr, + &Expectation::HasType(rhs_ty), + ExprIsRead::Yes, + ); } // Construct an obligation `self_ty : Trait` diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index a0945c3bdce66..c49e943437933 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -40,8 +40,7 @@ use rustc_hash::FxHashSet; use rustc_type_ir::{ AliasTyKind, BoundVarIndexKind, ConstKind, DebruijnIndex, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, Interner, OutlivesPredicate, TermKind, - TyKind, - TypeFoldable, TypeVisitableExt, Upcast, UpcastFrom, elaborate, + TyKind, TypeFoldable, TypeVisitableExt, Upcast, UpcastFrom, elaborate, inherent::{Clause as _, GenericArgs as _, IntoKind as _, Region as _, Ty as _}, }; use smallvec::SmallVec; @@ -1681,10 +1680,16 @@ impl SupertraitsInfo { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -enum TypeParamAssocTypeShorthandError { - AssocTypeNotFound, - AmbiguousAssocType, +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +enum AssocTypeShorthandResolution { + Resolved(StoredEarlyBinder<(TypeAliasId, StoredGenericArgs)>), + Ambiguous { + /// If one resolution belongs to a sub-trait and one to a supertrait, this contains + /// the sub-trait's resolution. This can be `None` if there is no trait inheritance + /// relationship between the resolutions. + sub_trait_resolution: Option>, + }, + NotFound, Cycle, } @@ -1708,7 +1713,7 @@ fn resolve_type_param_assoc_type_shorthand( def: GenericDefId, param: TypeParamId, assoc_name: Name, -) -> Result, TypeParamAssocTypeShorthandError> { +) -> AssocTypeShorthandResolution { let generics = generics(db, def); let resolver = def.resolver(db); let mut ctx = TyLoweringContext::new( @@ -1719,13 +1724,13 @@ fn resolve_type_param_assoc_type_shorthand( LifetimeElisionKind::AnonymousReportError, ); let interner = ctx.interner; - let mut result = None; let param_ty = Ty::new_param( interner, param, generics.type_or_const_param_idx(param.into()).unwrap() as u32, ); + let mut this_trait_resolution = None; if let GenericDefId::TraitId(containing_trait) = param.parent() && param.local_id() == GenericParams::SELF_PARAM_ID_IN_SELF { @@ -1734,10 +1739,11 @@ fn resolve_type_param_assoc_type_shorthand( containing_trait.trait_items(db).associated_type_by_name(&assoc_name) { let args = GenericArgs::identity_for_item(interner, containing_trait.into()); - result = Some(StoredEarlyBinder::bind((assoc_type, args.store()))); + this_trait_resolution = Some(StoredEarlyBinder::bind((assoc_type, args.store()))); } } + let mut supertraits_resolution = None; for maybe_parent_generics in std::iter::successors(Some(&generics), |generics| generics.parent_generics()) { @@ -1783,34 +1789,53 @@ fn resolve_type_param_assoc_type_shorthand( TypeParamId::trait_self(bounded_trait), assoc_name.clone(), ); - let lookup_on_bounded_trait = match lookup_on_bounded_trait { - Ok(it) => it, - Err( - err @ (TypeParamAssocTypeShorthandError::AmbiguousAssocType - | TypeParamAssocTypeShorthandError::Cycle), - ) => return Err(*err), - Err(TypeParamAssocTypeShorthandError::AssocTypeNotFound) => { + let assoc_type_and_args = match &lookup_on_bounded_trait { + AssocTypeShorthandResolution::Resolved(trait_ref) => trait_ref, + AssocTypeShorthandResolution::Ambiguous { + sub_trait_resolution: Some(trait_ref), + } => trait_ref, + AssocTypeShorthandResolution::Ambiguous { sub_trait_resolution: None } => { + return AssocTypeShorthandResolution::Ambiguous { + sub_trait_resolution: this_trait_resolution, + }; + } + AssocTypeShorthandResolution::NotFound => { never!("we checked that the trait defines this assoc type"); continue; } + AssocTypeShorthandResolution::Cycle => return AssocTypeShorthandResolution::Cycle, }; - let (assoc_type, args) = lookup_on_bounded_trait - .get_with(|(assoc_type, args)| (*assoc_type, args.as_ref())) - .skip_binder(); - let args = EarlyBinder::bind(args).instantiate(interner, bounded_trait_ref.args); - let current_result = StoredEarlyBinder::bind((assoc_type, args.store())); - // If we already have a result, this is an ambiguity - unless this is the same result, then we are fine - // (e.g. rustc allows to write the same bound twice without ambiguity). - if let Some(existing_result) = result - && existing_result != current_result - { - return Err(TypeParamAssocTypeShorthandError::AmbiguousAssocType); + if let Some(this_trait_resolution) = this_trait_resolution { + return AssocTypeShorthandResolution::Ambiguous { + sub_trait_resolution: Some(this_trait_resolution), + }; + } else if supertraits_resolution.is_some() { + return AssocTypeShorthandResolution::Ambiguous { sub_trait_resolution: None }; + } else { + let (assoc_type, args) = assoc_type_and_args + .get_with(|(assoc_type, args)| (*assoc_type, args.as_ref())) + .skip_binder(); + let args = EarlyBinder::bind(args).instantiate(interner, bounded_trait_ref.args); + let current_result = StoredEarlyBinder::bind((assoc_type, args.store())); + supertraits_resolution = Some(match lookup_on_bounded_trait { + AssocTypeShorthandResolution::Resolved(_) => { + AssocTypeShorthandResolution::Resolved(current_result) + } + AssocTypeShorthandResolution::Ambiguous { .. } => { + AssocTypeShorthandResolution::Ambiguous { + sub_trait_resolution: Some(current_result), + } + } + AssocTypeShorthandResolution::NotFound + | AssocTypeShorthandResolution::Cycle => unreachable!(), + }); } - result = Some(current_result); } } - result.ok_or(TypeParamAssocTypeShorthandError::AssocTypeNotFound) + supertraits_resolution + .or_else(|| this_trait_resolution.map(AssocTypeShorthandResolution::Resolved)) + .unwrap_or(AssocTypeShorthandResolution::NotFound) } fn resolve_type_param_assoc_type_shorthand_cycle_result( @@ -1819,8 +1844,8 @@ fn resolve_type_param_assoc_type_shorthand_cycle_result( _def: GenericDefId, _param: TypeParamId, _assoc_name: Name, -) -> Result, TypeParamAssocTypeShorthandError> { - Err(TypeParamAssocTypeShorthandError::Cycle) +) -> AssocTypeShorthandResolution { + AssocTypeShorthandResolution::Cycle } #[inline] @@ -2468,7 +2493,7 @@ fn fn_sig_for_struct_constructor( let inputs_and_output = Tys::new_from_iter(DbInterner::new_no_crate(db), params.chain(Some(ret.as_ref()))); StoredEarlyBinder::bind(StoredPolyFnSig::new(Binder::dummy(FnSig { - abi: FnAbi::RustCall, + abi: FnAbi::Rust, c_variadic: false, safety: Safety::Safe, inputs_and_output, @@ -2487,7 +2512,7 @@ fn fn_sig_for_enum_variant_constructor( let inputs_and_output = Tys::new_from_iter(DbInterner::new_no_crate(db), params.chain(Some(ret.as_ref()))); StoredEarlyBinder::bind(StoredPolyFnSig::new(Binder::dummy(FnSig { - abi: FnAbi::RustCall, + abi: FnAbi::Rust, c_variadic: false, safety: Safety::Safe, inputs_and_output, @@ -2569,19 +2594,22 @@ pub(crate) fn associated_ty_item_bounds<'db>( EarlyBinder::bind(BoundExistentialPredicates::new_from_slice(&bounds)) } -pub(crate) fn associated_type_by_name_including_super_traits<'db>( +pub(crate) fn associated_type_by_name_including_super_traits_allow_ambiguity<'db>( db: &'db dyn HirDatabase, trait_ref: TraitRef<'db>, name: Name, ) -> Option<(TypeAliasId, GenericArgs<'db>)> { - let assoc_type = resolve_type_param_assoc_type_shorthand( - db, - trait_ref.def_id.0.into(), - TypeParamId::trait_self(trait_ref.def_id.0), - name.clone(), - ) - .as_ref() - .ok()?; + let (AssocTypeShorthandResolution::Resolved(assoc_type) + | AssocTypeShorthandResolution::Ambiguous { sub_trait_resolution: Some(assoc_type) }) = + resolve_type_param_assoc_type_shorthand( + db, + trait_ref.def_id.0.into(), + TypeParamId::trait_self(trait_ref.def_id.0), + name.clone(), + ) + else { + return None; + }; let (assoc_type, trait_args) = assoc_type .get_with(|(assoc_type, trait_args)| (*assoc_type, trait_args.as_ref())) .skip_binder(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs index d47d696259d54..79f29d370f5cd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs @@ -30,7 +30,10 @@ use crate::{ consteval::{unknown_const, unknown_const_as_generic}, db::HirDatabase, generics::{Generics, generics}, - lower::{GenericPredicateSource, LifetimeElisionKind, PathDiagnosticCallbackData}, + lower::{ + AssocTypeShorthandResolution, GenericPredicateSource, LifetimeElisionKind, + PathDiagnosticCallbackData, + }, next_solver::{ Binder, Clause, Const, DbInterner, EarlyBinder, ErrorGuaranteed, GenericArg, GenericArgs, Predicate, ProjectionPredicate, Region, TraitRef, Ty, @@ -38,8 +41,8 @@ use crate::{ }; use super::{ - ImplTraitLoweringMode, TyLoweringContext, associated_type_by_name_including_super_traits, - const_param_ty_query, ty_query, + ImplTraitLoweringMode, TyLoweringContext, + associated_type_by_name_including_super_traits_allow_ambiguity, const_param_ty_query, ty_query, }; type CallbackData<'a> = @@ -482,12 +485,14 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { let error_ty = || Ty::new_error(self.ctx.interner, ErrorGuaranteed); let (assoc_type, trait_args) = match res { Some(TypeNs::GenericParam(param)) => { - let Ok(assoc_type) = super::resolve_type_param_assoc_type_shorthand( - db, - def, - param, - assoc_name.clone(), - ) else { + let AssocTypeShorthandResolution::Resolved(assoc_type) = + super::resolve_type_param_assoc_type_shorthand( + db, + def, + param, + assoc_name.clone(), + ) + else { return error_ty(); }; assoc_type @@ -500,12 +505,14 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { }; let impl_trait = impl_trait.instantiate_identity(); // Searching for `Self::Assoc` in `impl Trait for Type` is like searching for `Self::Assoc` in `Trait`. - let Ok(assoc_type) = super::resolve_type_param_assoc_type_shorthand( - db, - impl_trait.def_id.0.into(), - TypeParamId::trait_self(impl_trait.def_id.0), - assoc_name.clone(), - ) else { + let AssocTypeShorthandResolution::Resolved(assoc_type) = + super::resolve_type_param_assoc_type_shorthand( + db, + impl_trait.def_id.0.into(), + TypeParamId::trait_self(impl_trait.def_id.0), + assoc_name.clone(), + ) + else { return error_ty(); }; let (assoc_type, trait_args) = assoc_type @@ -869,7 +876,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { let interner = self.ctx.interner; self.current_or_prev_segment.args_and_bindings.map(|args_and_bindings| { args_and_bindings.bindings.iter().enumerate().flat_map(move |(binding_idx, binding)| { - let found = associated_type_by_name_including_super_traits( + let found = associated_type_by_name_including_super_traits_allow_ambiguity( self.ctx.db, trait_ref, binding.name.clone(), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/abi.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/abi.rs index 80d1ea4aa4d00..1813abab86e7b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/abi.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/abi.rs @@ -62,7 +62,6 @@ impl<'db> rustc_type_ir::inherent::Abi> for FnAbi { } fn is_rust(self) -> bool { - // TODO: rustc does not consider `RustCall` to be true here, but Chalk does - matches!(self, FnAbi::Rust | FnAbi::RustCall) + matches!(self, FnAbi::Rust) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs index e4e7b4cc38859..993293bb56857 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs @@ -802,6 +802,37 @@ fn foo() { ); } +#[test] +fn binop_rhs_never_place_diverges() { + check_no_mismatches( + r#" +//- minicore: sized, add +fn foo() -> i32 { + unsafe { + let p: *mut ! = 0 as _; + let mut x: i32 = 0; + x += *p; + } +} +"#, + ); +} + +#[test] +fn binop_lhs_never_place_diverges() { + check_no_mismatches( + r#" +//- minicore: sized, add +fn foo() { + unsafe { + let p: *mut ! = 0 as _; + *p += 1; + } +} +"#, + ); +} + #[test] fn never_place_isnt_diverging() { check_infer_with_mismatches( @@ -855,3 +886,18 @@ fn foo() { "#]], ); } + +#[test] +fn never_coercion_in_struct_update_syntax() { + check_no_mismatches( + r#" +struct Struct { + field: i32, +} + +fn example() -> Struct { + Struct { ..loop {} } +} + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index 658c304aac012..1939db0ef5a76 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -2795,3 +2795,23 @@ fn foo() { "#]], ); } + +#[test] +fn regression_21742() { + check_no_mismatches( + r#" +pub trait IntoIterator { + type Item; +} + +pub trait Collection: IntoIterator::Item> { + type Item; + fn contains(&self, item: &::Item); +} + +fn contains_0>(points: &S) { + points.contains(&0) +} + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index cdf7b40003b5b..74e9a8dac0e79 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -2217,6 +2217,40 @@ fn test() { ); } +#[test] +fn tuple_struct_constructor_as_fn_trait() { + check_types( + r#" +//- minicore: fn +struct S(u32, u64); + +fn takes_fn S>(f: F) -> S { f(1, 2) } + +fn test() { + takes_fn(S); + //^^^^^^^^^^^ S +} +"#, + ); +} + +#[test] +fn enum_variant_constructor_as_fn_trait() { + check_types( + r#" +//- minicore: fn +enum E { A(u32) } + +fn takes_fn E>(f: F) -> E { f(1) } + +fn test() { + takes_fn(E::A); + //^^^^^^^^^^^^^^ E +} +"#, + ); +} + #[test] fn fn_item_fn_trait() { check_types( diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 9dbee16dae6b7..11d79e2d7bf85 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -5952,7 +5952,16 @@ impl<'db> Type<'db> { ) -> R { let module = resolver.module(); let interner = DbInterner::new_with(db, module.krate(db)); - let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); + // Most IDE operations want to operate in PostAnalysis mode, revealing opaques. This makes + // for a nicer IDE experience. However, method resolution is always done on real code (either + // existing code or code to be inserted), and there using PostAnalysis is dangerous - we may + // suggest invalid methods. So we're using the TypingMode of the body we're in. + let typing_mode = if let Some(body_owner) = resolver.body_owner() { + TypingMode::analysis_in_body(interner, body_owner.into()) + } else { + TypingMode::non_body_analysis() + }; + let infcx = interner.infer_ctxt().build(typing_mode); let unstable_features = MethodResolutionUnstableFeatures::from_def_map(resolver.top_level_def_map()); let environment = param_env_from_resolver(db, resolver); @@ -6149,6 +6158,13 @@ impl<'db> Type<'db> { Some(adt.into()) } + /// Holes in the args can come from lifetime/const params. + pub fn as_adt_with_args(&self) -> Option<(Adt, Vec>>)> { + let (adt, args) = self.ty.as_adt()?; + let args = args.iter().map(|arg| Some(self.derived(arg.ty()?))).collect(); + Some((adt.into(), args)) + } + pub fn as_builtin(&self) -> Option { self.ty.as_builtin().map(|inner| BuiltinType { inner }) } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 4bc757da44174..1cf3b98160820 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -1819,6 +1819,28 @@ impl<'db> SemanticsImpl<'db> { self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr) } + /// The type that the associated `try` block, closure or function expects. + pub fn try_expr_returned_type(&self, try_expr: &ast::TryExpr) -> Option> { + self.ancestors_with_macros(try_expr.syntax().clone()).find_map(|parent| { + if let Some(try_block) = ast::BlockExpr::cast(parent.clone()) + && try_block.try_block_modifier().is_some() + { + Some(self.type_of_expr(&try_block.into())?.original) + } else if let Some(closure) = ast::ClosureExpr::cast(parent.clone()) { + Some( + self.type_of_expr(&closure.into())? + .original + .as_callable(self.db)? + .return_type(), + ) + } else if let Some(function) = ast::Fn::cast(parent) { + Some(self.to_def(&function)?.ret_type(self.db)) + } else { + None + } + }) + } + // This does not resolve the method call to the correct trait impl! // We should probably fix that. pub fn resolve_method_call_as_callable( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 10c3ff0e4d2be..c0ce057d7798d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -44,8 +44,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) let arm_list_range = ctx.sema.original_range_opt(match_arm_list.syntax())?; if cursor_at_trivial_match_arm_list(ctx, &match_expr, &match_arm_list).is_none() { - let arm_list_range = ctx.sema.original_range(match_arm_list.syntax()).range; - let cursor_in_range = arm_list_range.contains_range(ctx.selection_trimmed()); + let cursor_in_range = arm_list_range.range.contains_range(ctx.selection_trimmed()); if cursor_in_range { cov_mark::hit!(not_applicable_outside_of_range_right); return None; @@ -348,8 +347,8 @@ fn cursor_at_trivial_match_arm_list( // $0 // } if let Some(last_arm) = match_arm_list.arms().last() { - let last_arm_range = last_arm.syntax().text_range(); - let match_expr_range = match_expr.syntax().text_range(); + let last_arm_range = ctx.sema.original_range_opt(last_arm.syntax())?.range; + let match_expr_range = ctx.sema.original_range_opt(match_expr.syntax())?.range; if last_arm_range.end() <= ctx.offset() && ctx.offset() < match_expr_range.end() { cov_mark::hit!(add_missing_match_arms_end_of_last_arm); return Some(()); @@ -1612,6 +1611,38 @@ fn foo(t: Test) { Test::B => ${2:todo!()}, Test::C => ${3:todo!()},$0 }); +}"#, + ); + + check_assist( + add_missing_match_arms, + r#" +macro_rules! m { ($expr:expr) => {$expr}} +enum Test { + A, + B, + C, +} + +fn foo(t: Test) { + m!(match t { + Test::A => (), + $0}); +}"#, + r#" +macro_rules! m { ($expr:expr) => {$expr}} +enum Test { + A, + B, + C, +} + +fn foo(t: Test) { + m!(match t { + Test::A=>(), + Test::B => ${1:todo!()}, + Test::C => ${2:todo!()},$0 + }); }"#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs index bb5d11221087e..4c4cee1d7811f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs @@ -1,15 +1,19 @@ -use hir::HasVisibility; +use hir::{HasVisibility, Semantics}; use ide_db::{ - FxHashMap, FxHashSet, + FxHashMap, FxHashSet, RootDatabase, assists::AssistId, defs::Definition, helpers::mod_path_to_ast, search::{FileReference, SearchScope}, }; use itertools::Itertools; -use syntax::ast::{HasName, syntax_factory::SyntaxFactory}; use syntax::syntax_editor::SyntaxEditor; use syntax::{AstNode, Edition, SmolStr, SyntaxNode, ToSmolStr, ast}; +use syntax::{ + SyntaxToken, + ast::{HasName, edit::IndentLevel, syntax_factory::SyntaxFactory}, + syntax_editor::Position, +}; use crate::{ assist_context::{AssistContext, Assists, SourceChangeBuilder}, @@ -44,33 +48,90 @@ use crate::{ // } // ``` pub(crate) fn destructure_struct_binding(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let ident_pat = ctx.find_node_at_offset::()?; - let data = collect_data(ident_pat, ctx)?; + let target = ctx.find_node_at_offset::()?; + let data = collect_data(target, ctx)?; acc.add( AssistId::refactor_rewrite("destructure_struct_binding"), "Destructure struct binding", - data.ident_pat.syntax().text_range(), + data.target.syntax().text_range(), |edit| destructure_struct_binding_impl(ctx, edit, &data), ); Some(()) } +enum Target { + IdentPat(ast::IdentPat), + SelfParam { param: ast::SelfParam, insert_after: SyntaxToken }, +} + +impl Target { + fn ty<'db>(&self, sema: &Semantics<'db, RootDatabase>) -> Option> { + match self { + Target::IdentPat(pat) => sema.type_of_binding_in_pat(pat), + Target::SelfParam { param, .. } => sema.type_of_self(param), + } + } + + fn is_ref(&self) -> bool { + match self { + Target::IdentPat(ident_pat) => ident_pat.ref_token().is_some(), + Target::SelfParam { .. } => false, + } + } + + fn is_mut(&self) -> bool { + match self { + Target::IdentPat(ident_pat) => ident_pat.mut_token().is_some(), + Target::SelfParam { param, .. } => { + param.mut_token().is_some() && param.amp_token().is_none() + } + } + } +} + +impl HasName for Target {} + +impl AstNode for Target { + fn cast(node: SyntaxNode) -> Option { + if ast::IdentPat::can_cast(node.kind()) { + ast::IdentPat::cast(node).map(Self::IdentPat) + } else { + let param = ast::SelfParam::cast(node)?; + let param_list = param.syntax().parent().and_then(ast::ParamList::cast)?; + let block = param_list.syntax().parent()?.children().find_map(ast::BlockExpr::cast)?; + let insert_after = block.stmt_list()?.l_curly_token()?; + Some(Self::SelfParam { param, insert_after }) + } + } + + fn can_cast(kind: syntax::SyntaxKind) -> bool { + ast::IdentPat::can_cast(kind) || ast::SelfParam::can_cast(kind) + } + + fn syntax(&self) -> &SyntaxNode { + match self { + Target::IdentPat(ident_pat) => ident_pat.syntax(), + Target::SelfParam { param, .. } => param.syntax(), + } + } +} + fn destructure_struct_binding_impl( ctx: &AssistContext<'_>, builder: &mut SourceChangeBuilder, data: &StructEditData, ) { let field_names = generate_field_names(ctx, data); - let mut editor = builder.make_editor(data.ident_pat.syntax()); + let mut editor = builder.make_editor(data.target.syntax()); destructure_pat(ctx, &mut editor, data, &field_names); update_usages(ctx, &mut editor, data, &field_names.into_iter().collect()); builder.add_file_edits(ctx.vfs_file_id(), editor); } struct StructEditData { - ident_pat: ast::IdentPat, + target: Target, name: ast::Name, kind: hir::StructKind, struct_def_path: hir::ModPath, @@ -83,11 +144,44 @@ struct StructEditData { edition: Edition, } -fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option { - let ty = ctx.sema.type_of_binding_in_pat(&ident_pat)?; +impl StructEditData { + fn apply_to_destruct( + &self, + new_pat: ast::Pat, + editor: &mut SyntaxEditor, + make: &SyntaxFactory, + ) { + match &self.target { + Target::IdentPat(pat) => { + // If the binding is nested inside a record, we need to wrap the new + // destructured pattern in a non-shorthand record field + if self.need_record_field_name { + let new_pat = + make.record_pat_field(make.name_ref(&self.name.to_string()), new_pat); + editor.replace(pat.syntax(), new_pat.syntax()) + } else { + editor.replace(pat.syntax(), new_pat.syntax()) + } + } + Target::SelfParam { insert_after, .. } => { + let indent = IndentLevel::from_token(insert_after) + 1; + let newline = make.whitespace(&format!("\n{indent}")); + let initializer = make.expr_path(make.ident_path("self")); + let let_stmt = make.let_stmt(new_pat, None, Some(initializer)); + editor.insert_all( + Position::after(insert_after), + vec![newline.into(), let_stmt.syntax().clone().into()], + ); + } + } + } +} + +fn collect_data(target: Target, ctx: &AssistContext<'_>) -> Option { + let ty = target.ty(&ctx.sema)?; let hir::Adt::Struct(struct_type) = ty.strip_references().as_adt()? else { return None }; - let module = ctx.sema.scope(ident_pat.syntax())?.module(); + let module = ctx.sema.scope(target.syntax())?.module(); let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.db()))); let struct_def = hir::ModuleDef::from(struct_type); let kind = struct_type.kind(ctx.db()); @@ -116,15 +210,17 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option ctx.sema.to_def(pat), + Target::SelfParam { param, .. } => ctx.sema.to_def(param), + }; + let usages = def .and_then(|def| { Definition::Local(def) .usages(&ctx.sema) @@ -136,11 +232,11 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option) -> Option, - ident_pat: &ast::IdentPat, + target: &Target, usages: &[FileReference], ) -> Option> { fn last_usage(usages: &[FileReference]) -> Option { @@ -165,7 +261,7 @@ fn get_names_in_scope( // If available, find names visible to the last usage of the binding // else, find names visible to the binding itself let last_usage = last_usage(usages); - let node = last_usage.as_ref().unwrap_or(ident_pat.syntax()); + let node = last_usage.as_ref().unwrap_or(target.syntax()); let scope = ctx.sema.scope(node)?; let mut names = FxHashSet::default(); @@ -183,12 +279,9 @@ fn destructure_pat( data: &StructEditData, field_names: &[(SmolStr, SmolStr)], ) { - let ident_pat = &data.ident_pat; - let name = &data.name; - let struct_path = mod_path_to_ast(&data.struct_def_path, data.edition); - let is_ref = ident_pat.ref_token().is_some(); - let is_mut = ident_pat.mut_token().is_some(); + let is_ref = data.target.is_ref(); + let is_mut = data.target.is_mut(); let make = SyntaxFactory::with_mappings(); let new_pat = match data.kind { @@ -221,16 +314,8 @@ fn destructure_pat( hir::StructKind::Unit => make.path_pat(struct_path), }; - // If the binding is nested inside a record, we need to wrap the new - // destructured pattern in a non-shorthand record field - let destructured_pat = if data.need_record_field_name { - make.record_pat_field(make.name_ref(&name.to_string()), new_pat).syntax().clone() - } else { - new_pat.syntax().clone() - }; - + data.apply_to_destruct(new_pat, editor, &make); editor.add_mappings(make.finish_with_mappings()); - editor.replace(data.ident_pat.syntax(), destructured_pat); } fn generate_field_names(ctx: &AssistContext<'_>, data: &StructEditData) -> Vec<(SmolStr, SmolStr)> { @@ -698,6 +783,84 @@ mod tests { ) } + #[test] + fn mut_self_param() { + check_assist( + destructure_struct_binding, + r#" + struct Foo { bar: i32, baz: i32 } + + impl Foo { + fn foo(mut $0self) { + self.bar = 5; + } + } + "#, + r#" + struct Foo { bar: i32, baz: i32 } + + impl Foo { + fn foo(mut self) { + let Foo { mut bar, mut baz } = self; + bar = 5; + } + } + "#, + ) + } + + #[test] + fn ref_mut_self_param() { + check_assist( + destructure_struct_binding, + r#" + struct Foo { bar: i32, baz: i32 } + + impl Foo { + fn foo(&mut $0self) { + self.bar = 5; + } + } + "#, + r#" + struct Foo { bar: i32, baz: i32 } + + impl Foo { + fn foo(&mut self) { + let Foo { bar, baz } = self; + *bar = 5; + } + } + "#, + ) + } + + #[test] + fn ref_self_param() { + check_assist( + destructure_struct_binding, + r#" + struct Foo { bar: i32, baz: i32 } + + impl Foo { + fn foo(&$0self) -> &i32 { + &self.bar + } + } + "#, + r#" + struct Foo { bar: i32, baz: i32 } + + impl Foo { + fn foo(&self) -> &i32 { + let Foo { bar, baz } = self; + bar + } + } + "#, + ) + } + #[test] fn ref_not_add_parenthesis_and_deref_record() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index b8dc59f87dee7..d51a3a26a3c7c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -164,6 +164,7 @@ enum RefType { Mutable, } struct TupleData { + // FIXME: After removing ted, it may be possible to reuse destructure_struct_binding::Target ident_pat: IdentPat, ref_type: Option, field_names: Vec, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs index fdc5a0fbda359..b4c347ff36a7c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs @@ -567,7 +567,8 @@ fn main() { match 92 { x => if true && true - && true { + && true + { { false } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs index dcadb5368d525..8ff30fce5b5d4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs @@ -972,7 +972,8 @@ fn main() { fn main() { if true { match path.strip_prefix(root_path) - .and(x) { + .and(x) + { Ok(rel_path) => { let rel_path = RelativePathBuf::from_path(rel_path) .ok()?; @@ -1012,7 +1013,8 @@ fn main() { fn main() { if true { match path.strip_prefix(root_path) - .and(x) { + .and(x) + { Ok(rel_path) => { Foo { x: 1 @@ -1046,7 +1048,8 @@ fn main() { fn main() { if true { match true - && false { + && false + { true => foo(), false => (), } @@ -1925,7 +1928,8 @@ fn main() { fn main() { if true { if let Ok(rel_path) = path.strip_prefix(root_path) - .and(x) { + .and(x) + { Foo { x: 2 } @@ -1965,7 +1969,8 @@ fn main() { fn main() { if true { if let Ok(rel_path) = path.strip_prefix(root_path) - .and(x) { + .and(x) + { let rel_path = RelativePathBuf::from_path(rel_path) .ok()?; Some((*id, rel_path)) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index a58592b1365b8..ea53aef40c2e7 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -16,7 +16,7 @@ use itertools::Itertools; use stdx::never; use syntax::{ SmolStr, - SyntaxKind::{BLOCK_EXPR, EXPR_STMT, STMT_LIST}, + SyntaxKind::{EXPR_STMT, STMT_LIST}, T, TextRange, TextSize, ToSmolStr, ast::{self, AstNode, AstToken}, format_smolstr, match_ast, @@ -52,6 +52,7 @@ pub(crate) fn complete_postfix( _ => return, }; let expr_ctx = &dot_access.ctx; + let receiver_accessor = receiver_accessor(dot_receiver); let receiver_text = get_receiver_text(&ctx.sema, dot_receiver, receiver_is_ambiguous_float_literal); @@ -90,7 +91,7 @@ pub(crate) fn complete_postfix( // 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 - let (dot_receiver_including_refs, prefix) = include_references(dot_receiver); + let (dot_receiver_including_refs, prefix) = include_references(&receiver_accessor); let mut receiver_text = receiver_text; receiver_text.insert_str(0, &prefix); let postfix_snippet = @@ -111,13 +112,8 @@ pub(crate) fn complete_postfix( .add_to(acc, ctx.db); let try_enum = TryEnum::from_ty(&ctx.sema, receiver_ty); - let mut is_in_cond = false; - if let Some(parent) = dot_receiver_including_refs.syntax().parent() - && let Some(second_ancestor) = parent.parent() - { - if let Some(parent_expr) = ast::Expr::cast(parent) { - is_in_cond = is_in_condition(&parent_expr); - } + let is_in_cond = is_in_condition(&dot_receiver_including_refs); + if let Some(parent) = dot_receiver_including_refs.syntax().parent() { let placeholder = suggest_receiver_name(dot_receiver, "0", &ctx.sema); match &try_enum { Some(try_enum) if is_in_cond => match try_enum { @@ -154,13 +150,13 @@ pub(crate) fn complete_postfix( postfix_snippet("let", "let", &format!("let $1 = {receiver_text}")) .add_to(acc, ctx.db); } - _ if matches!(second_ancestor.kind(), STMT_LIST | EXPR_STMT | BLOCK_EXPR) => { + _ if matches!(parent.kind(), STMT_LIST | EXPR_STMT) => { 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, ctx.db); } - _ if ast::MatchArm::can_cast(second_ancestor.kind()) => { + _ if ast::MatchArm::can_cast(parent.kind()) => { postfix_snippet( "let", "let", @@ -305,7 +301,7 @@ pub(crate) fn complete_postfix( postfix_snippet("const", "const {}", &const_completion_string).add_to(acc, ctx.db); } - if let ast::Expr::Literal(literal) = dot_receiver_including_refs.clone() + if let ast::Expr::Literal(literal) = dot_receiver.clone() && let Some(literal_text) = ast::String::cast(literal.token()) { add_format_like_completions(acc, ctx, &dot_receiver_including_refs, cap, &literal_text); @@ -392,14 +388,22 @@ fn escape_snippet_bits(text: &mut String) { stdx::replace(text, '$', "\\$"); } +fn receiver_accessor(receiver: &ast::Expr) -> ast::Expr { + receiver + .syntax() + .parent() + .and_then(ast::Expr::cast) + .filter(|it| { + matches!( + it, + ast::Expr::FieldExpr(_) | ast::Expr::MethodCallExpr(_) | ast::Expr::CallExpr(_) + ) + }) + .unwrap_or_else(|| receiver.clone()) +} + fn include_references(initial_element: &ast::Expr) -> (ast::Expr, String) { let mut resulting_element = initial_element.clone(); - - while let Some(field_expr) = resulting_element.syntax().parent().and_then(ast::FieldExpr::cast) - { - resulting_element = ast::Expr::from(field_expr); - } - let mut prefix = String::new(); let mut found_ref_or_deref = false; @@ -898,6 +902,30 @@ fn main() { bar => bar.$0 } } +"#, + expect![[r#" + sn box Box::new(expr) + sn call function(expr) + sn const const {} + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn deref *expr + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} + "#]], + ); + check( + r#" +fn main() { + match 2 { + bar => &bar.l$0 + } +} "#, expect![[r#" sn box Box::new(expr) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index 5fef8c44deb12..8e50ef10eca65 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -3659,3 +3659,38 @@ fn main() { "#]], ); } + +#[test] +fn rpitit_with_reference() { + check( + r#" +trait Foo { + fn foo(&self); +} + +trait Bar { + fn bar(&self) -> &impl Foo; +} + +fn baz(v: impl Bar) { + v.bar().$0 +} + "#, + expect![[r#" + me foo() (as Foo) fn(&self) + sn box Box::new(expr) + sn call function(expr) + sn const const {} + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn deref *expr + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index 3c3ac9d3bbe61..3890bcad7fc61 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -95,6 +95,13 @@ pub(crate) fn goto_definition( continue; } + let parent = token.value.parent()?; + + if let Some(question_mark_conversion) = goto_question_mark_conversions(sema, &parent) { + navs.extend(def_to_nav(sema, question_mark_conversion.into())); + continue; + } + if let Some(token) = ast::String::cast(token.value.clone()) && let Some(original_token) = ast::String::cast(original_token.clone()) && let Some((analysis, fixture_analysis)) = @@ -113,8 +120,6 @@ pub(crate) fn goto_definition( }); } - let parent = token.value.parent()?; - let token_file_id = token.file_id; if let Some(token) = ast::String::cast(token.value.clone()) && let Some(x) = @@ -149,6 +154,45 @@ pub(crate) fn goto_definition( Some(RangeInfo::new(original_token.text_range(), navs)) } +/// When the `?` operator is used on `Result`, go to the `From` impl if it exists as this provides more value. +fn goto_question_mark_conversions( + sema: &Semantics<'_, RootDatabase>, + node: &SyntaxNode, +) -> Option { + let node = ast::TryExpr::cast(node.clone())?; + let try_expr_ty = sema.type_of_expr(&node.expr()?)?.adjusted(); + + let fd = FamousDefs(sema, try_expr_ty.krate(sema.db)); + let result_enum = fd.core_result_Result()?.into(); + + let (try_expr_ty_adt, try_expr_ty_args) = try_expr_ty.as_adt_with_args()?; + if try_expr_ty_adt != result_enum { + // FIXME: Support `Poll`. + return None; + } + let original_err_ty = try_expr_ty_args.get(1)?.clone()?; + + let returned_ty = sema.try_expr_returned_type(&node)?; + let (returned_adt, returned_ty_args) = returned_ty.as_adt_with_args()?; + if returned_adt != result_enum { + return None; + } + let returned_err_ty = returned_ty_args.get(1)?.clone()?; + + if returned_err_ty.could_unify_with_deeply(sema.db, &original_err_ty) { + return None; + } + + let from_trait = fd.core_convert_From()?; + let from_fn = from_trait.function(sema.db, sym::from)?; + sema.resolve_trait_impl_method( + returned_err_ty.clone(), + from_trait, + from_fn, + [returned_err_ty, original_err_ty], + ) +} + // If the token is into(), try_into(), search the definition of From, TryFrom. fn find_definition_for_known_blanket_dual_impls( sema: &Semantics<'_, RootDatabase>, @@ -4034,4 +4078,25 @@ where "#, ) } + + #[test] + fn question_mark_on_result_goes_to_conversion() { + check( + r#" +//- minicore: try, result, from + +struct Foo; +struct Bar; +impl From for Bar { + fn from(_: Foo) -> Bar { Bar } + // ^^^^ +} + +fn foo() -> Result<(), Bar> { + Err(Foo)?$0; + Ok(()) +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs index 9c7f109a626c3..9ce88484f781f 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs @@ -164,7 +164,7 @@ pub(crate) fn make_lockfile_copy( major: 1, minor: 95, patch: 0, - pre: semver::Prerelease::new("nightly").unwrap(), + pre: semver::Prerelease::new("beta").unwrap(), build: semver::BuildMetadata::EMPTY, }; diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index 98d759aef2093..f5d1d009a579b 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -644,7 +644,8 @@ pub fn expr_await(expr: ast::Expr) -> ast::Expr { expr_from_text(&format!("{expr}.await")) } pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::MatchExpr { - expr_from_text(&format!("match {expr} {match_arm_list}")) + let ws = block_whitespace(&expr); + expr_from_text(&format!("match {expr}{ws}{match_arm_list}")) } pub fn expr_if( condition: ast::Expr, @@ -656,14 +657,17 @@ pub fn expr_if( Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {if_expr}"), None => String::new(), }; - expr_from_text(&format!("if {condition} {then_branch} {else_branch}")) + let ws = block_whitespace(&condition); + expr_from_text(&format!("if {condition}{ws}{then_branch} {else_branch}")) } pub fn expr_for_loop(pat: ast::Pat, expr: ast::Expr, block: ast::BlockExpr) -> ast::ForExpr { - expr_from_text(&format!("for {pat} in {expr} {block}")) + let ws = block_whitespace(&expr); + expr_from_text(&format!("for {pat} in {expr}{ws}{block}")) } pub fn expr_while_loop(condition: ast::Expr, block: ast::BlockExpr) -> ast::WhileExpr { - expr_from_text(&format!("while {condition} {block}")) + let ws = block_whitespace(&condition); + expr_from_text(&format!("while {condition}{ws}{block}")) } pub fn expr_loop(block: ast::BlockExpr) -> ast::Expr { @@ -723,6 +727,9 @@ pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::BinExpr { fn expr_from_text + AstNode>(text: &str) -> E { ast_from_text(&format!("const C: () = {text};")) } +fn block_whitespace(after: &impl AstNode) -> &'static str { + if after.syntax().text().contains_char('\n') { "\n" } else { " " } +} pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr { ast_from_text(&format!("const _: () = while let {pattern} = {expr} {{}};")) } @@ -880,8 +887,9 @@ pub fn ref_pat(pat: ast::Pat) -> ast::RefPat { pub fn match_arm(pat: ast::Pat, guard: Option, expr: ast::Expr) -> ast::MatchArm { let comma_str = if expr.is_block_like() { "" } else { "," }; + let ws = guard.as_ref().filter(|_| expr.is_block_like()).map_or(" ", block_whitespace); return match guard { - Some(guard) => from_text(&format!("{pat} {guard} => {expr}{comma_str}")), + Some(guard) => from_text(&format!("{pat} {guard} =>{ws}{expr}{comma_str}")), None => from_text(&format!("{pat} => {expr}{comma_str}")), }; @@ -890,19 +898,6 @@ pub fn match_arm(pat: ast::Pat, guard: Option, expr: ast::Expr) } } -pub fn match_arm_with_guard( - pats: impl IntoIterator, - guard: ast::Expr, - expr: ast::Expr, -) -> ast::MatchArm { - let pats_str = pats.into_iter().join(" | "); - return from_text(&format!("{pats_str} if {guard} => {expr}")); - - fn from_text(text: &str) -> ast::MatchArm { - ast_from_text(&format!("fn f() {{ match () {{{text}}} }}")) - } -} - pub fn match_guard(condition: ast::Expr) -> ast::MatchGuard { return from_text(&format!("if {condition}")); diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json index d3fbea2336b0b..be0bdc8d55bbf 100644 --- a/src/tools/rust-analyzer/editors/code/package-lock.json +++ b/src/tools/rust-analyzer/editors/code/package-lock.json @@ -749,9 +749,9 @@ } }, "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -810,9 +810,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -934,29 +934,6 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" - } - }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -1851,9 +1828,9 @@ } }, "node_modules/@vscode/vsce/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -3463,9 +3440,9 @@ } }, "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -3907,17 +3884,40 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/glob/node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "brace-expansion": "^5.0.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -4895,13 +4895,13 @@ } }, "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -6840,9 +6840,9 @@ } }, "node_modules/vscode-languageclient/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/req_queue.rs b/src/tools/rust-analyzer/lib/lsp-server/src/req_queue.rs index c216864bee8c2..84748bbca8d77 100644 --- a/src/tools/rust-analyzer/lib/lsp-server/src/req_queue.rs +++ b/src/tools/rust-analyzer/lib/lsp-server/src/req_queue.rs @@ -18,6 +18,12 @@ impl Default for ReqQueue { } } +impl ReqQueue { + pub fn has_pending(&self) -> bool { + self.incoming.has_pending() || self.outgoing.has_pending() + } +} + #[derive(Debug)] pub struct Incoming { pending: HashMap, @@ -51,6 +57,10 @@ impl Incoming { pub fn is_completed(&self, id: &RequestId) -> bool { !self.pending.contains_key(id) } + + pub fn has_pending(&self) -> bool { + !self.pending.is_empty() + } } impl Outgoing { @@ -64,4 +74,8 @@ impl Outgoing { pub fn complete(&mut self, id: RequestId) -> Option { self.pending.remove(&id) } + + pub fn has_pending(&self) -> bool { + !self.pending.is_empty() + } } diff --git a/src/tools/rust-analyzer/lib/smol_str/CHANGELOG.md b/src/tools/rust-analyzer/lib/smol_str/CHANGELOG.md index 4aa25fa13446f..6327275d07dcb 100644 --- a/src/tools/rust-analyzer/lib/smol_str/CHANGELOG.md +++ b/src/tools/rust-analyzer/lib/smol_str/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 0.3.6 - 2026-03-04 +- Fix the `borsh` feature. + ## 0.3.5 - 2026-01-08 - Optimise `SmolStr::clone` 4-5x speedup inline, 0.5x heap (slow down). diff --git a/src/tools/rust-analyzer/lib/smol_str/Cargo.toml b/src/tools/rust-analyzer/lib/smol_str/Cargo.toml index 4e7844b49e195..22068fe8418b4 100644 --- a/src/tools/rust-analyzer/lib/smol_str/Cargo.toml +++ b/src/tools/rust-analyzer/lib/smol_str/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "smol_str" -version = "0.3.5" +version = "0.3.6" description = "small-string optimized string type with O(1) clone" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/rust-analyzer/tree/master/lib/smol_str" diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index b6e1b2bc55df4..7c89bcb9ab045 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -c78a29473a68f07012904af11c92ecffa68fcc75 +f8704be04fe1150527fc2cf21dd44327f0fe87fb diff --git a/src/tools/rust-analyzer/triagebot.toml b/src/tools/rust-analyzer/triagebot.toml index ac4efd0a24bcb..5fd97f52d8c2c 100644 --- a/src/tools/rust-analyzer/triagebot.toml +++ b/src/tools/rust-analyzer/triagebot.toml @@ -24,4 +24,5 @@ labels = ["has-merge-commits", "S-waiting-on-author"] [transfer] # Canonicalize issue numbers to avoid closing the wrong issue when upstreaming this subtree -[canonicalize-issue-links] +[issue-links] +check-commits = "uncanonicalized" diff --git a/src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs b/src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs index 205072a6ce0cf..564d9cc24efe8 100644 --- a/src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs @@ -189,9 +189,9 @@ pub(crate) fn generate_kind_src( } } }); - PUNCT.iter().zip(used_puncts).filter(|(_, used)| !used).for_each(|((punct, _), _)| { + if let Some(punct) = PUNCT.iter().zip(used_puncts).find(|(_, used)| !used) { panic!("Punctuation {punct:?} is not used in grammar"); - }); + } keywords.extend(RESERVED.iter().copied()); keywords.sort(); keywords.dedup(); diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 51b73351fe6a5..d34706a2ba5cd 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -1553,7 +1553,10 @@ pub(crate) fn can_be_overflowed_expr( } // Handle always block-like expressions - ast::ExprKind::Gen(..) | ast::ExprKind::Block(..) | ast::ExprKind::Closure(..) => true, + ast::ExprKind::Gen(..) + | ast::ExprKind::Block(..) + | ast::ExprKind::Closure(..) + | ast::ExprKind::TryBlock(..) => true, // Handle `[]` and `{}`-like expressions ast::ExprKind::Array(..) | ast::ExprKind::Struct(..) => { diff --git a/src/tools/rustfmt/tests/source/try_block.rs b/src/tools/rustfmt/tests/source/try_block.rs index e324a13317584..62f0492f96620 100644 --- a/src/tools/rustfmt/tests/source/try_block.rs +++ b/src/tools/rustfmt/tests/source/try_block.rs @@ -27,5 +27,13 @@ fn baz() -> Option { let x: Option = try { baz()?; baz()?; baz()?; 7 }; + let _ = overflowed_expr( + x, + try { + foo()?; + bar()?; + }, + ); + return None; } diff --git a/src/tools/rustfmt/tests/source/try_blocks_heterogeneous.rs b/src/tools/rustfmt/tests/source/try_blocks_heterogeneous.rs index 7a1135cfbc764..056bedafef6cb 100644 --- a/src/tools/rustfmt/tests/source/try_blocks_heterogeneous.rs +++ b/src/tools/rustfmt/tests/source/try_blocks_heterogeneous.rs @@ -35,5 +35,15 @@ fn baz() -> Option { let x = try bikeshed Foo {}; + let x = try bikeshed Result {}; + + let _ = overflowed_expr( + x, + try bikeshed Option<_> { + foo()?; + bar()?; + }, + ); + return None; } diff --git a/src/tools/rustfmt/tests/target/try_block.rs b/src/tools/rustfmt/tests/target/try_block.rs index 61da123b735d8..f9d9909f524fe 100644 --- a/src/tools/rustfmt/tests/target/try_block.rs +++ b/src/tools/rustfmt/tests/target/try_block.rs @@ -26,5 +26,10 @@ fn baz() -> Option { 7 }; + let _ = overflowed_expr(x, try { + foo()?; + bar()?; + }); + return None; } diff --git a/src/tools/rustfmt/tests/target/try_blocks_heterogeneous.rs b/src/tools/rustfmt/tests/target/try_blocks_heterogeneous.rs index 018d53ed35e41..ce0a3cf704bbf 100644 --- a/src/tools/rustfmt/tests/target/try_blocks_heterogeneous.rs +++ b/src/tools/rustfmt/tests/target/try_blocks_heterogeneous.rs @@ -37,5 +37,16 @@ fn baz() -> Option { let x = try bikeshed Foo {}; + let x = try bikeshed Result< + VeryVeryVeryVeryVeryLongTypeForSuccess, + VeryVeryVeryVeryVeryLongTypeForFailure, + > { + }; + + let _ = overflowed_expr(x, try bikeshed Option<_> { + foo()?; + bar()?; + }); + return None; } diff --git a/tests/debuginfo/function-names.rs b/tests/debuginfo/function-names.rs index e2f106e565439..5973f63bbae9e 100644 --- a/tests/debuginfo/function-names.rs +++ b/tests/debuginfo/function-names.rs @@ -39,7 +39,7 @@ // Const generic parameter //@ gdb-command:info functions -q function_names::const_generic_fn.* //@ gdb-check:[...]static fn function_names::const_generic_fn_bool(); -//@ gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#ffa3db4ca1d52dce}>(); +//@ gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#6dd80cc0c950c171}>(); //@ gdb-check:[...]static fn function_names::const_generic_fn_signed_int<-7>(); //@ gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int<14>(); diff --git a/tests/pretty/paren-trait-bound.rs b/tests/pretty/paren-trait-bound.rs new file mode 100644 index 0000000000000..98e75308abfe8 --- /dev/null +++ b/tests/pretty/paren-trait-bound.rs @@ -0,0 +1,11 @@ +//@ pp-exact + +trait Dummy {} + +// Without parens, `+ Send` would bind to `dyn Dummy` instead of the outer `dyn`. +fn f1(_: Box Box) + Send>) {} + +// Without parens, `+ Send + Sync` would bind to `dyn Dummy` instead of the outer `impl`. +fn f2(_: impl (FnMut(&mut u8) -> &mut dyn Dummy) + Send + Sync) {} + +fn main() {} diff --git a/tests/ui/const-generics/type-const-ice-issue-151631.rs b/tests/ui/const-generics/type-const-ice-issue-151631.rs new file mode 100644 index 0000000000000..53c6d0c6dd6d4 --- /dev/null +++ b/tests/ui/const-generics/type-const-ice-issue-151631.rs @@ -0,0 +1,18 @@ +// issue: +//@ compile-flags: -Znext-solver +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait SuperTrait {} +trait Trait: SuperTrait { + type const K: u32; +} +impl Trait for () { //~ ERROR: the trait bound `(): SuperTrait` is not satisfied + type const K: u32 = const { 1 }; +} + +fn check(_: impl Trait) {} + +fn main() { + check(()); //~ ERROR: the trait bound `(): SuperTrait` is not satisfied +} diff --git a/tests/ui/const-generics/type-const-ice-issue-151631.stderr b/tests/ui/const-generics/type-const-ice-issue-151631.stderr new file mode 100644 index 0000000000000..6f287293e27cf --- /dev/null +++ b/tests/ui/const-generics/type-const-ice-issue-151631.stderr @@ -0,0 +1,37 @@ +error[E0277]: the trait bound `(): SuperTrait` is not satisfied + --> $DIR/type-const-ice-issue-151631.rs:10:16 + | +LL | impl Trait for () { + | ^^ the trait `SuperTrait` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/type-const-ice-issue-151631.rs:6:1 + | +LL | trait SuperTrait {} + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `Trait` + --> $DIR/type-const-ice-issue-151631.rs:7:14 + | +LL | trait Trait: SuperTrait { + | ^^^^^^^^^^ required by this bound in `Trait` + +error[E0277]: the trait bound `(): SuperTrait` is not satisfied + --> $DIR/type-const-ice-issue-151631.rs:17:5 + | +LL | check(()); + | ^^^^^^^^^ the trait `SuperTrait` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/type-const-ice-issue-151631.rs:6:1 + | +LL | trait SuperTrait {} + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `Trait` + --> $DIR/type-const-ice-issue-151631.rs:7:14 + | +LL | trait Trait: SuperTrait { + | ^^^^^^^^^^ required by this bound in `Trait` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/moves/invalid-suggestions-destructuring-assignment-drop.rs b/tests/ui/moves/invalid-suggestions-destructuring-assignment-drop.rs new file mode 100644 index 0000000000000..23d5d4c9e1096 --- /dev/null +++ b/tests/ui/moves/invalid-suggestions-destructuring-assignment-drop.rs @@ -0,0 +1,14 @@ +// Regression test for #152694 +// Verify that we don't emit invalid suggestions (adding `ref` or `clone()`) +// when a destructuring assignment involves a type that implements `Drop`. + +struct Thing(String); + +impl Drop for Thing { + fn drop(&mut self) {} +} + +fn main() { + Thing(*&mut String::new()) = Thing(String::new()); + //~^ ERROR cannot move out of type `Thing`, which implements the `Drop` trait +} diff --git a/tests/ui/moves/invalid-suggestions-destructuring-assignment-drop.stderr b/tests/ui/moves/invalid-suggestions-destructuring-assignment-drop.stderr new file mode 100644 index 0000000000000..c2bc85ee6beee --- /dev/null +++ b/tests/ui/moves/invalid-suggestions-destructuring-assignment-drop.stderr @@ -0,0 +1,12 @@ +error[E0509]: cannot move out of type `Thing`, which implements the `Drop` trait + --> $DIR/invalid-suggestions-destructuring-assignment-drop.rs:12:34 + | +LL | Thing(*&mut String::new()) = Thing(String::new()); + | ------------------- ^^^^^^^^^^^^^^^^^^^^ cannot move out of here + | | + | data moved here + | move occurs because the place has type `String`, which does not implement the `Copy` trait + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0509`. diff --git a/tests/ui/offset-of/offset-of-error-recovery.rs b/tests/ui/offset-of/offset-of-error-recovery.rs new file mode 100644 index 0000000000000..659140877cd14 --- /dev/null +++ b/tests/ui/offset-of/offset-of-error-recovery.rs @@ -0,0 +1,14 @@ +use std::mem::offset_of; + +struct S { + x: (), +} + +impl S { + fn a() { + offset_of!(Self, Self::x); + //~^ ERROR offset_of expects dot-separated field and variant names + } +} + +fn main() {} diff --git a/tests/ui/offset-of/offset-of-error-recovery.stderr b/tests/ui/offset-of/offset-of-error-recovery.stderr new file mode 100644 index 0000000000000..fce3616c213ec --- /dev/null +++ b/tests/ui/offset-of/offset-of-error-recovery.stderr @@ -0,0 +1,8 @@ +error: offset_of expects dot-separated field and variant names + --> $DIR/offset-of-error-recovery.rs:9:26 + | +LL | offset_of!(Self, Self::x); + | ^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/privacy/inaccessible-private-fields-trailing-comma-149787.fixed b/tests/ui/privacy/inaccessible-private-fields-trailing-comma-149787.fixed new file mode 100644 index 0000000000000..6a73475f202f4 --- /dev/null +++ b/tests/ui/privacy/inaccessible-private-fields-trailing-comma-149787.fixed @@ -0,0 +1,23 @@ +#![allow(dead_code)] +#![allow(unused)] +//@ run-rustfix + +mod m { + pub(crate) struct S { + pub(crate) visible: u64, + hidden: u64, + } + + impl S { + pub(crate) fn new() -> Self { + loop {} + } + } +} + +fn main() { + let m::S { + //~^ ERROR pattern requires `..` due to inaccessible fields + visible, .. + } = m::S::new(); +} diff --git a/tests/ui/privacy/inaccessible-private-fields-trailing-comma-149787.rs b/tests/ui/privacy/inaccessible-private-fields-trailing-comma-149787.rs new file mode 100644 index 0000000000000..1a4fed68381a1 --- /dev/null +++ b/tests/ui/privacy/inaccessible-private-fields-trailing-comma-149787.rs @@ -0,0 +1,23 @@ +#![allow(dead_code)] +#![allow(unused)] +//@ run-rustfix + +mod m { + pub(crate) struct S { + pub(crate) visible: u64, + hidden: u64, + } + + impl S { + pub(crate) fn new() -> Self { + loop {} + } + } +} + +fn main() { + let m::S { + //~^ ERROR pattern requires `..` due to inaccessible fields + visible, + } = m::S::new(); +} diff --git a/tests/ui/privacy/inaccessible-private-fields-trailing-comma-149787.stderr b/tests/ui/privacy/inaccessible-private-fields-trailing-comma-149787.stderr new file mode 100644 index 0000000000000..4eacdecc6810c --- /dev/null +++ b/tests/ui/privacy/inaccessible-private-fields-trailing-comma-149787.stderr @@ -0,0 +1,17 @@ +error: pattern requires `..` due to inaccessible fields + --> $DIR/inaccessible-private-fields-trailing-comma-149787.rs:19:9 + | +LL | let m::S { + | _________^ +LL | | +LL | | visible, +LL | | } = m::S::new(); + | |_____^ + | +help: ignore the inaccessible and unused fields + | +LL | visible, .. + | ++ + +error: aborting due to 1 previous error + diff --git a/tests/ui/repr/repr_align_greater_usize.msp430.stderr b/tests/ui/repr/repr_align_greater_usize.msp430.stderr index a7b06acb6752b..4fcd33d50d749 100644 --- a/tests/ui/repr/repr_align_greater_usize.msp430.stderr +++ b/tests/ui/repr/repr_align_greater_usize.msp430.stderr @@ -1,18 +1,14 @@ -error[E0589]: alignment must not be greater than `isize::MAX` bytes - --> $DIR/repr_align_greater_usize.rs:23:8 +error[E0589]: invalid `repr(align)` attribute: alignment larger than `isize::MAX` bytes (32767 for the current target) + --> $DIR/repr_align_greater_usize.rs:23:14 | LL | #[repr(align(32768))] - | ^^^^^^^^^^^^ - | - = note: `isize::MAX` is 32767 for the current target + | ^^^^^ -error[E0589]: alignment must not be greater than `isize::MAX` bytes - --> $DIR/repr_align_greater_usize.rs:26:8 +error[E0589]: invalid `repr(align)` attribute: alignment larger than `isize::MAX` bytes (32767 for the current target) + --> $DIR/repr_align_greater_usize.rs:26:14 | LL | #[repr(align(65536))] - | ^^^^^^^^^^^^ - | - = note: `isize::MAX` is 32767 for the current target + | ^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/repr/repr_align_greater_usize.rs b/tests/ui/repr/repr_align_greater_usize.rs index 52a4d23b1eca2..7df1fbe762661 100644 --- a/tests/ui/repr/repr_align_greater_usize.rs +++ b/tests/ui/repr/repr_align_greater_usize.rs @@ -20,8 +20,8 @@ use minicore::*; #[repr(align(16384))] struct Kitten; -#[repr(align(32768))] //[msp430]~ ERROR alignment must not be greater than `isize::MAX` +#[repr(align(32768))] //[msp430]~ ERROR invalid `repr(align)` attribute: alignment larger than `isize::MAX` bytes (32767 for the current target) [E0589] struct Cat; -#[repr(align(65536))] //[msp430]~ ERROR alignment must not be greater than `isize::MAX` +#[repr(align(65536))] //[msp430]~ ERROR invalid `repr(align)` attribute: alignment larger than `isize::MAX` bytes (32767 for the current target) [E0589] struct BigCat; diff --git a/triagebot.toml b/triagebot.toml index 8d6401c490561..14184e8f2683a 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1620,6 +1620,7 @@ dep-bumps = [ "/src/tools/rustdoc" = ["rustdoc"] "/src/tools/rustdoc-js" = ["rustdoc"] "/src/tools/rustdoc-themes" = ["rustdoc"] +"/src/tools/rustfmt" = ["rustfmt", "rustfmt-contributors"] "/src/tools/tidy" = ["bootstrap"] "/src/tools/x" = ["bootstrap"] "/src/tools/rustdoc-gui-test" = ["bootstrap"]