From 01fa7209d597c770a51c44839a97d2731419392c Mon Sep 17 00:00:00 2001 From: Marcondiro <46560192+Marcondiro@users.noreply.github.com> Date: Thu, 8 Feb 2024 12:24:27 +0100 Subject: [PATCH 01/12] Bump Unicode to version 15.1.0, regenerate tables --- library/core/src/unicode/unicode_data.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/core/src/unicode/unicode_data.rs b/library/core/src/unicode/unicode_data.rs index b25e9df286808..dd2ad9a58f679 100644 --- a/library/core/src/unicode/unicode_data.rs +++ b/library/core/src/unicode/unicode_data.rs @@ -99,21 +99,21 @@ fn skip_search( offset_idx % 2 == 1 } -pub const UNICODE_VERSION: (u8, u8, u8) = (15, 0, 0); +pub const UNICODE_VERSION: (u8, u8, u8) = (15, 1, 0); #[rustfmt::skip] pub mod alphabetic { - static SHORT_OFFSET_RUNS: [u32; 53] = [ + static SHORT_OFFSET_RUNS: [u32; 54] = [ 706, 33559113, 872420973, 952114966, 1161831606, 1310731264, 1314926597, 1394619392, 1444957632, 1447077005, 1451271693, 1459672996, 1648425216, 1658911342, 1661009214, 1707147904, 1793132343, 1887506048, 2040601600, 2392923872, 2481005466, 2504077200, 2514564144, 2520859648, 2527151687, 2529257472, 2531355193, 2533453376, 2564917240, 2596375766, 2600579056, 2606870819, 2621551356, 2642525184, 2644628480, 2665600678, 2743197440, 2791432848, 2841765072, 2850154464, 2854350336, 2887905584, 3026321408, - 3038947040, 3041048378, 3045248674, 3053644769, 3057842176, 3059939870, 3062038528, - 3064140619, 3066241968, 3071550384, + 3038947040, 3041048378, 3045248674, 3053644769, 3057839710, 3062036480, 3064134174, + 3066232832, 3068334923, 3070436272, 3075744688, ]; - static OFFSETS: [u8; 1465] = [ + static OFFSETS: [u8; 1467] = [ 65, 26, 6, 26, 47, 1, 10, 1, 4, 1, 5, 23, 1, 31, 1, 0, 4, 12, 14, 5, 7, 1, 1, 1, 86, 1, 42, 5, 1, 2, 2, 4, 1, 1, 6, 1, 1, 3, 1, 1, 1, 20, 1, 83, 1, 139, 8, 166, 1, 38, 2, 1, 6, 41, 39, 14, 1, 1, 1, 2, 1, 2, 1, 1, 8, 27, 4, 4, 29, 11, 5, 56, 1, 7, 14, 102, 1, 8, 4, 8, 4, 3, 10, @@ -167,7 +167,7 @@ pub mod alphabetic { 1, 2, 1, 15, 1, 197, 59, 68, 3, 1, 3, 1, 0, 4, 1, 27, 1, 2, 1, 1, 2, 1, 1, 10, 1, 4, 1, 1, 1, 1, 6, 1, 4, 1, 1, 1, 1, 1, 1, 3, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 4, 1, 7, 1, 4, 1, 4, 1, 1, 1, 10, 1, 17, 5, 3, 1, 5, 1, 17, 0, 26, 6, 26, 6, 26, 0, 0, 32, - 0, 6, 222, 2, 0, 14, 0, 0, 0, 0, 0, 5, 0, 0, + 0, 6, 222, 2, 0, 14, 0, 15, 0, 0, 0, 0, 0, 5, 0, 0, ]; pub fn lookup(c: char) -> bool { super::skip_search( From fffcb4c8771ad1a688bf9083d948769664d5fcb0 Mon Sep 17 00:00:00 2001 From: PizzasBear <43722034+PizzasBear@users.noreply.github.com> Date: Mon, 12 Feb 2024 16:00:15 +0200 Subject: [PATCH 02/12] Fix comment in core/src/str/validations.rs --- library/core/src/str/validations.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs index 2acef432f2063..a11d7fee8af0c 100644 --- a/library/core/src/str/validations.rs +++ b/library/core/src/str/validations.rs @@ -161,7 +161,7 @@ pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { // first E0 A0 80 last EF BF BF // excluding surrogates codepoints \u{d800} to \u{dfff} // ED A0 80 to ED BF BF - // 4-byte encoding is for codepoints \u{1000}0 to \u{10ff}ff + // 4-byte encoding is for codepoints \u{10000} to \u{10ffff} // first F0 90 80 80 last F4 8F BF BF // // Use the UTF-8 syntax from the RFC From 5233bc91da2f48f5bc79c688b5cfad846a8127da Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 14 Feb 2024 14:50:49 +1100 Subject: [PATCH 03/12] Add an `ErrorGuaranteed` to `ast::TyKind::Err`. This makes it more like `hir::TyKind::Err`, and avoids a `span_delayed_bug` call in `LoweringContext::lower_ty_direct`. It also requires adding `ast::TyKind::Dummy`, now that `ast::TyKind::Err` can't be used for that purpose in the absence of an error emission. There are a couple of cases that aren't as neat as I would have liked, marked with `FIXME` comments. --- compiler/rustc_ast/src/ast.rs | 6 +++-- compiler/rustc_ast/src/mut_visit.rs | 9 +++++-- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/lib.rs | 3 ++- .../rustc_ast_passes/src/ast_validation.rs | 3 ++- compiler/rustc_ast_pretty/src/pprust/state.rs | 7 ++++- compiler/rustc_expand/src/base.rs | 9 ++++--- .../rustc_parse/src/parser/diagnostics.rs | 20 +++++++------- compiler/rustc_parse/src/parser/item.rs | 26 +++++++++++++++---- compiler/rustc_parse/src/parser/path.rs | 7 ++--- compiler/rustc_parse/src/parser/ty.rs | 10 ++++--- compiler/rustc_passes/src/hir_stats.rs | 5 ++-- .../clippy/clippy_utils/src/ast_utils.rs | 2 +- src/tools/rustfmt/src/types.rs | 2 +- 14 files changed, 75 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 098e2606a3be9..08fc8e3c6cca8 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2136,10 +2136,12 @@ pub enum TyKind { ImplicitSelf, /// A macro in the type position. MacCall(P), - /// Placeholder for a kind that has failed to be defined. - Err, /// Placeholder for a `va_list`. CVarArgs, + /// Sometimes we need a dummy value when no error has occurred. + Dummy, + /// Placeholder for a kind that has failed to be defined. + Err(ErrorGuaranteed), } impl TyKind { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index d482ada170ee3..c42c41999732c 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -481,7 +481,12 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { let Ty { id, kind, span, tokens } = ty.deref_mut(); vis.visit_id(id); match kind { - TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err | TyKind::Never | TyKind::CVarArgs => {} + TyKind::Infer + | TyKind::ImplicitSelf + | TyKind::Err(_) + | TyKind::Dummy + | TyKind::Never + | TyKind::CVarArgs => {} TyKind::Slice(ty) => vis.visit_ty(ty), TyKind::Ptr(mt) => vis.visit_mt(mt), TyKind::Ref(lt, mt) => { @@ -1649,7 +1654,7 @@ impl DummyAstNode for Ty { fn dummy() -> Self { Ty { id: DUMMY_NODE_ID, - kind: TyKind::Err, + kind: TyKind::Dummy, span: Default::default(), tokens: Default::default(), } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 4aaaa0ba42457..83f6746bdeb23 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -447,7 +447,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl); } TyKind::Typeof(expression) => visitor.visit_anon_const(expression), - TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {} + TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Err(_) => {} TyKind::MacCall(mac) => visitor.visit_mac_call(mac), TyKind::Never | TyKind::CVarArgs => {} TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 6b5fc01424085..c1b7af94b02a0 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1285,7 +1285,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> { let kind = match &t.kind { TyKind::Infer => hir::TyKind::Infer, - TyKind::Err => hir::TyKind::Err(self.dcx().has_errors().unwrap()), + TyKind::Err(guar) => hir::TyKind::Err(*guar), // Lower the anonymous structs or unions in a nested lowering context. // // ``` @@ -1503,6 +1503,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ); hir::TyKind::Err(guar) } + TyKind::Dummy => panic!("`TyKind::Dummy` should never be lowered"), }; hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index ebc5c17a4c4f2..fa0f532619611 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -881,7 +881,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { &item.vis, errors::VisibilityNotPermittedNote::TraitImpl, ); - if let TyKind::Err = self_ty.kind { + // njn: use Dummy here + if let TyKind::Err(_) = self_ty.kind { this.dcx().emit_err(errors::ObsoleteAuto { span: item.span }); } if let (&Unsafe::Yes(span), &ImplPolarity::Negative(sp)) = (unsafety, polarity) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index cda746894e865..480506272d2ba 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1048,11 +1048,16 @@ impl<'a> State<'a> { ast::TyKind::Infer => { self.word("_"); } - ast::TyKind::Err => { + ast::TyKind::Err(_) => { self.popen(); self.word("/*ERROR*/"); self.pclose(); } + ast::TyKind::Dummy => { + self.popen(); + self.word("/*DUMMY*/"); + self.pclose(); + } ast::TyKind::ImplicitSelf => { self.word("Self"); } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index cfeb31fc4c813..20cfc72f6d362 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -567,10 +567,13 @@ impl DummyResult { } /// A plain dummy type. - pub fn raw_ty(sp: Span, is_error: bool) -> P { + pub fn raw_ty(sp: Span) -> P { + // FIXME(nnethercote): you might expect `ast::TyKind::Dummy` to be used here, but some + // values produced here end up being lowered to HIR, which `ast::TyKind::Dummy` does not + // support, so we use an empty tuple instead. P(ast::Ty { id: ast::DUMMY_NODE_ID, - kind: if is_error { ast::TyKind::Err } else { ast::TyKind::Tup(ThinVec::new()) }, + kind: ast::TyKind::Tup(ThinVec::new()), span: sp, tokens: None, }) @@ -611,7 +614,7 @@ impl MacResult for DummyResult { } fn make_ty(self: Box) -> Option> { - Some(DummyResult::raw_ty(self.span, self.is_error)) + Some(DummyResult::raw_ty(self.span)) } fn make_arms(self: Box) -> Option> { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 445d5b2ce790c..69518287f38ec 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -46,14 +46,14 @@ use std::ops::{Deref, DerefMut}; use thin_vec::{thin_vec, ThinVec}; /// Creates a placeholder argument. -pub(super) fn dummy_arg(ident: Ident) -> Param { +pub(super) fn dummy_arg(ident: Ident, guar: ErrorGuaranteed) -> Param { let pat = P(Pat { id: ast::DUMMY_NODE_ID, kind: PatKind::Ident(BindingAnnotation::NONE, ident, None), span: ident.span, tokens: None, }); - let ty = Ty { kind: TyKind::Err, span: ident.span, id: ast::DUMMY_NODE_ID, tokens: None }; + let ty = Ty { kind: TyKind::Err(guar), span: ident.span, id: ast::DUMMY_NODE_ID, tokens: None }; Param { attrs: AttrVec::default(), id: ast::DUMMY_NODE_ID, @@ -1540,14 +1540,14 @@ impl<'a> Parser<'a> { pub(super) fn maybe_recover_from_question_mark(&mut self, ty: P) -> P { if self.token == token::Question { self.bump(); - self.dcx().emit_err(QuestionMarkInType { + let guar = self.dcx().emit_err(QuestionMarkInType { span: self.prev_token.span, sugg: QuestionMarkInTypeSugg { left: ty.span.shrink_to_lo(), right: self.prev_token.span, }, }); - self.mk_ty(ty.span.to(self.prev_token.span), TyKind::Err) + self.mk_ty(ty.span.to(self.prev_token.span), TyKind::Err(guar)) } else { ty } @@ -2304,8 +2304,8 @@ impl<'a> Parser<'a> { pub(super) fn recover_bad_self_param(&mut self, mut param: Param) -> PResult<'a, Param> { let span = param.pat.span; - param.ty.kind = TyKind::Err; - self.dcx().emit_err(SelfParamNotFirst { span }); + let guar = self.dcx().emit_err(SelfParamNotFirst { span }); + param.ty.kind = TyKind::Err(guar); Ok(param) } @@ -2437,7 +2437,7 @@ impl<'a> Parser<'a> { pub(super) fn deduplicate_recovered_params_names(&self, fn_inputs: &mut ThinVec) { let mut seen_inputs = FxHashSet::default(); for input in fn_inputs.iter_mut() { - let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err) = + let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err(_)) = (&input.pat.kind, &input.ty.kind) { Some(*ident) @@ -2644,8 +2644,10 @@ impl<'a> Parser<'a> { "::", Applicability::MaybeIncorrect, ); - err.emit(); - return Ok(GenericArg::Type(self.mk_ty(start.to(expr.span), TyKind::Err))); + let guar = err.emit(); + return Ok(GenericArg::Type( + self.mk_ty(start.to(expr.span), TyKind::Err(guar)), + )); } else if token::Comma == self.token.kind || self.token.kind.should_end_const_arg() { // Avoid the following output by checking that we consumed a full const arg: diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 8050b34956ce9..a0605b8a44c3a 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -591,7 +591,23 @@ impl<'a> Parser<'a> { let ty_second = if self.token == token::DotDot { // We need to report this error after `cfg` expansion for compatibility reasons self.bump(); // `..`, do not add it to expected tokens - Some(self.mk_ty(self.prev_token.span, TyKind::Err)) + + // FIXME(nnethercote): AST validation later detects this + // `TyKind::Err` and emits an errors. So why the unchecked + // ErrorGuaranteed? + // - A `span_delayed_bug` doesn't work here, because rustfmt can + // hit this path but then not hit the follow-up path in the AST + // validator that issues the error, which results in ICEs. + // - `TyKind::Dummy` doesn't work, because it ends up reaching HIR + // lowering, which results in ICEs. Changing `TyKind::Dummy` to + // `TyKind::Err` during AST validation might fix that, but that's + // not possible because AST validation doesn't allow mutability. + // + // #121072 will hopefully remove all this special handling of the + // obsolete `impl Trait for ..` and then this can go away. + #[allow(deprecated)] + let guar = rustc_errors::ErrorGuaranteed::unchecked_error_guaranteed(); + Some(self.mk_ty(self.prev_token.span, TyKind::Err(guar))) } else if has_for || self.token.can_begin_type() { Some(self.parse_ty()?) } else { @@ -2628,13 +2644,13 @@ impl<'a> Parser<'a> { p.recover_diff_marker(); let snapshot = p.create_snapshot_for_diagnostic(); let param = p.parse_param_general(req_name, first_param).or_else(|e| { - e.emit(); + let guar = e.emit(); let lo = p.prev_token.span; p.restore_snapshot(snapshot); // Skip every token until next possible arg or end. p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(Delimiter::Parenthesis)]); // Create a placeholder argument for proper arg count (issue #34264). - Ok(dummy_arg(Ident::new(kw::Empty, lo.to(p.prev_token.span)))) + Ok(dummy_arg(Ident::new(kw::Empty, lo.to(p.prev_token.span)), guar)) }); // ...now that we've parsed the first argument, `self` is no longer allowed. first_param = false; @@ -2671,8 +2687,8 @@ impl<'a> Parser<'a> { return if let Some(ident) = this.parameter_without_type(&mut err, pat, is_name_required, first_param) { - err.emit(); - Ok((dummy_arg(ident), TrailingToken::None)) + let guar = err.emit(); + Ok((dummy_arg(ident, guar), TrailingToken::None)) } else { Err(err) }; diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index e7cad74b4dd14..681039999a652 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -678,8 +678,9 @@ impl<'a> Parser<'a> { c.into() } Some(GenericArg::Lifetime(lt)) => { - self.dcx().emit_err(errors::AssocLifetime { span, lifetime: lt.ident.span }); - self.mk_ty(span, ast::TyKind::Err).into() + let guar = + self.dcx().emit_err(errors::AssocLifetime { span, lifetime: lt.ident.span }); + self.mk_ty(span, ast::TyKind::Err(guar)).into() } None => { let after_eq = eq.shrink_to_hi(); @@ -779,7 +780,7 @@ impl<'a> Parser<'a> { // type to determine if error recovery has occurred and if the input is not a // syntactically valid type after all. if let ast::TyKind::Slice(inner_ty) | ast::TyKind::Array(inner_ty, _) = &ty.kind - && let ast::TyKind::Err = inner_ty.kind + && let ast::TyKind::Err(_) = inner_ty.kind && let Some(snapshot) = snapshot && let Some(expr) = self.recover_unbraced_const_arg_that_can_begin_ty(snapshot) diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 157fb9e505af7..f79f2a813b223 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -346,8 +346,10 @@ impl<'a> Parser<'a> { AllowCVariadic::No => { // FIXME(Centril): Should we just allow `...` syntactically // anywhere in a type and use semantic restrictions instead? - self.dcx().emit_err(NestedCVariadicType { span: lo.to(self.prev_token.span) }); - TyKind::Err + let guar = self + .dcx() + .emit_err(NestedCVariadicType { span: lo.to(self.prev_token.span) }); + TyKind::Err(guar) } } } else { @@ -493,8 +495,8 @@ impl<'a> Parser<'a> { { // Recover from `[LIT; EXPR]` and `[LIT]` self.bump(); - err.emit(); - self.mk_ty(self.prev_token.span, TyKind::Err) + let guar = err.emit(); + self.mk_ty(self.prev_token.span, TyKind::Err(guar)) } Err(err) => return Err(err), }; diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index d02e86dd45697..96429bb778882 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -616,8 +616,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { Infer, ImplicitSelf, MacCall, - Err, - CVarArgs + CVarArgs, + Dummy, + Err ] ); diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index adc35bd82ae39..0467a8a65709a 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -690,7 +690,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool { match (&l.kind, &r.kind) { (Paren(l), _) => eq_ty(l, r), (_, Paren(r)) => eq_ty(l, r), - (Never, Never) | (Infer, Infer) | (ImplicitSelf, ImplicitSelf) | (Err, Err) | (CVarArgs, CVarArgs) => true, + (Never, Never) | (Infer, Infer) | (ImplicitSelf, ImplicitSelf) | (Err(_), Err(_)) | (CVarArgs, CVarArgs) => true, (Slice(l), Slice(r)) => eq_ty(l, r), (Array(le, ls), Array(re, rs)) => eq_ty(le, re) && eq_expr(&ls.value, &rs.value), (Ptr(l), Ptr(r)) => l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty), diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 4cd8e6a703e53..7f220a456a8ee 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -859,7 +859,7 @@ impl Rewrite for ast::Ty { }) } ast::TyKind::CVarArgs => Some("...".to_owned()), - ast::TyKind::Err => Some(context.snippet(self.span).to_owned()), + ast::TyKind::Dummy | ast::TyKind::Err(_) => Some(context.snippet(self.span).to_owned()), ast::TyKind::Typeof(ref anon_const) => rewrite_call( context, "typeof", From bd546fb20a2d299a0a2e9c2062df9227e82bdb65 Mon Sep 17 00:00:00 2001 From: yukang Date: Thu, 15 Feb 2024 01:06:27 +0800 Subject: [PATCH 04/12] add extra indent spaces for rust-playground link --- src/librustdoc/doctest.rs | 18 ++++++++++++-- src/librustdoc/doctest/tests.rs | 44 ++++++++++++++++++++++++++++++++- src/librustdoc/html/markdown.rs | 7 ++++-- tests/rustdoc/playground-arg.rs | 2 +- tests/rustdoc/playground.rs | 2 +- 5 files changed, 66 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index f2e083de0ec74..f9d4d1af1140f 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -40,6 +40,9 @@ use crate::lint::init_lints; pub(crate) struct GlobalTestOptions { /// Whether to disable the default `extern crate my_crate;` when creating doctests. pub(crate) no_crate_inject: bool, + /// Whether inserting extra indent spaces in code block, + /// default is `false`, only `true` for generating code link of Rust playground + pub(crate) insert_indent_space: bool, /// Additional crate-level attributes to add to doctests. pub(crate) attrs: Vec, } @@ -221,7 +224,8 @@ pub(crate) fn run_tests( fn scrape_test_config(attrs: &[ast::Attribute]) -> GlobalTestOptions { use rustc_ast_pretty::pprust; - let mut opts = GlobalTestOptions { no_crate_inject: false, attrs: Vec::new() }; + let mut opts = + GlobalTestOptions { no_crate_inject: false, attrs: Vec::new(), insert_indent_space: false }; let test_attrs: Vec<_> = attrs .iter() @@ -725,7 +729,17 @@ pub(crate) fn make_test( // /// ``` <- end of the inner main line_offset += 1; - prog.extend([&main_pre, everything_else, &main_post].iter().cloned()); + // add extra 4 spaces for each line to offset the code block + let content = if opts.insert_indent_space { + everything_else + .lines() + .map(|line| format!(" {}", line)) + .collect::>() + .join("\n") + } else { + everything_else.to_string() + }; + prog.extend([&main_pre, content.as_str(), &main_post].iter().cloned()); } debug!("final doctest:\n{prog}"); diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index a30fe28f94f99..9629acb31eb68 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -53,7 +53,8 @@ assert_eq!(2+2, 4); fn make_test_no_crate_inject() { // Even if you do use the crate within the test, setting `opts.no_crate_inject` will skip // adding it anyway. - let opts = GlobalTestOptions { no_crate_inject: true, attrs: vec![] }; + let opts = + GlobalTestOptions { no_crate_inject: true, attrs: vec![], insert_indent_space: false }; let input = "use asdf::qwop; assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] @@ -302,3 +303,44 @@ assert_eq!(2+2, 4); make_test(input, None, false, &opts, DEFAULT_EDITION, Some("_some_unique_name")); assert_eq!((output, len), (expected, 2)); } + +#[test] +fn make_test_insert_extra_space() { + // will insert indent spaces in the code block if `insert_indent_space` is true + let opts = + GlobalTestOptions { no_crate_inject: false, attrs: vec![], insert_indent_space: true }; + let input = "use std::*; +assert_eq!(2+2, 4); +eprintln!(\"hello anan\"); +"; + let expected = "#![allow(unused)] +fn main() { + use std::*; + assert_eq!(2+2, 4); + eprintln!(\"hello anan\"); +}" + .to_string(); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); + assert_eq!((output, len), (expected, 2)); +} + +#[test] +fn make_test_insert_extra_space_fn_main() { + // if input already has a fn main, it should insert a space before it + let opts = + GlobalTestOptions { no_crate_inject: false, attrs: vec![], insert_indent_space: true }; + let input = "use std::*; +fn main() { + assert_eq!(2+2, 4); + eprintln!(\"hello anan\"); +}"; + let expected = "#![allow(unused)] +use std::*; +fn main() { + assert_eq!(2+2, 4); + eprintln!(\"hello anan\"); +}" + .to_string(); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); + assert_eq!((output, len), (expected, 1)); +} diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index ee5891c12fc5a..21f682d15b97d 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -45,6 +45,7 @@ use std::str::{self, CharIndices}; use crate::clean::RenderedLink; use crate::doctest; +use crate::doctest::GlobalTestOptions; use crate::html::escape::Escape; use crate::html::format::Buffer; use crate::html::highlight; @@ -302,8 +303,10 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { .intersperse("\n".into()) .collect::(); let krate = krate.as_ref().map(|s| s.as_str()); - let (test, _, _) = - doctest::make_test(&test, krate, false, &Default::default(), edition, None); + + let mut opts: GlobalTestOptions = Default::default(); + opts.insert_indent_space = true; + let (test, _, _) = doctest::make_test(&test, krate, false, &opts, edition, None); let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" }; let test_escaped = small_url_encode(test); diff --git a/tests/rustdoc/playground-arg.rs b/tests/rustdoc/playground-arg.rs index 2542ed657c1a7..1d7085064e5ac 100644 --- a/tests/rustdoc/playground-arg.rs +++ b/tests/rustdoc/playground-arg.rs @@ -10,4 +10,4 @@ pub fn dummy() {} // ensure that `extern crate foo;` was inserted into code snips automatically: -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0A%23%5Ballow(unused_extern_crates)%5D%0Aextern+crate+r%23foo;%0Afn+main()+%7B%0Ause+foo::dummy;%0Adummy();%0A%7D&edition=2015"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0A%23%5Ballow(unused_extern_crates)%5D%0Aextern+crate+r%23foo;%0Afn+main()+%7B%0A++++use+foo::dummy;%0A++++dummy();%0A%7D&edition=2015"]' "Run" diff --git a/tests/rustdoc/playground.rs b/tests/rustdoc/playground.rs index 5c7fa33efc5e5..a2fc9eb7387aa 100644 --- a/tests/rustdoc/playground.rs +++ b/tests/rustdoc/playground.rs @@ -22,6 +22,6 @@ //! } //! ``` -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0Aprintln!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run" // @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run" // @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&version=nightly&edition=2015"]' "Run" From cc7b4e02beecdb75b3b5ee348840b50d06ad67c1 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 25 Jan 2024 15:28:23 +0000 Subject: [PATCH 05/12] Update aarch64 target feature docs to match LLVM --- compiler/rustc_target/src/target_features.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 04943fa3879fb..2b7ac68c21dfb 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -86,7 +86,7 @@ const ARM_ALLOWED_FEATURES: &[(&str, Stability)] = &[ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[ // tidy-alphabetical-start - // FEAT_AES + // FEAT_AES & FEAT_PMULL ("aes", Stable), // FEAT_BF16 ("bf16", Stable), @@ -124,7 +124,7 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[ ("lor", Stable), // FEAT_LSE ("lse", Stable), - // FEAT_MTE + // FEAT_MTE & FEAT_MTE2 ("mte", Stable), // FEAT_AdvSimd & FEAT_FP ("neon", Stable), @@ -138,7 +138,7 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[ ("pmuv3", Stable), // FEAT_RAND ("rand", Stable), - // FEAT_RAS + // FEAT_RAS & FEAT_RASv1p1 ("ras", Stable), // FEAT_RCPC ("rcpc", Stable), @@ -156,7 +156,7 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[ ("sm4", Stable), // FEAT_SPE ("spe", Stable), - // FEAT_SSBS + // FEAT_SSBS & FEAT_SSBS2 ("ssbs", Stable), // FEAT_SVE ("sve", Stable), From 5d65b1954ef4dc6ea3a1260e1bce31524fc286f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 15 Feb 2024 00:00:00 +0000 Subject: [PATCH 06/12] Avoid debug logging entire MIR body If there is a need to examine the MIR body there is -Zmir-dump. --- compiler/rustc_mir_transform/src/lib.rs | 1 - compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index b4fa7f3bea6a0..fb174192b8492 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -653,7 +653,6 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { debug!("about to call mir_drops_elaborated..."); let body = tcx.mir_drops_elaborated_and_const_checked(did).steal(); let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::NotConst); - debug!("body: {:#?}", body); if body.tainted_by_errors.is_some() { return body; diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index 095119e2e3ff8..fb52bfa468a01 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -15,7 +15,8 @@ impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads { } fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - debug!("remove_noop_landing_pads({:?})", body); + let def_id = body.source.def_id(); + debug!(?def_id); self.remove_nop_landing_pads(body) } } @@ -81,8 +82,6 @@ impl RemoveNoopLandingPads { } fn remove_nop_landing_pads(&self, body: &mut Body<'_>) { - debug!("body: {:#?}", body); - // Skip the pass if there are no blocks with a resume terminator. let has_resume = body .basic_blocks From c763f833d14d31fbe63e0b26370a23a51b4f11c5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 15 Feb 2024 14:34:42 +0000 Subject: [PATCH 07/12] Only point out non-diverging arms for match suggestions --- compiler/rustc_hir_typeck/src/_match.rs | 14 +++++------ .../src/infer/error_reporting/mod.rs | 13 ++++++---- .../src/infer/error_reporting/suggest.rs | 11 +++++--- compiler/rustc_middle/src/traits/mod.rs | 2 +- .../ui/match/dont-highlight-diverging-arms.rs | 17 +++++++++++++ .../dont-highlight-diverging-arms.stderr | 25 +++++++++++++++++++ .../match/match-arm-resolving-to-never.stderr | 5 +++- 7 files changed, 69 insertions(+), 18 deletions(-) create mode 100644 tests/ui/match/dont-highlight-diverging-arms.rs create mode 100644 tests/ui/match/dont-highlight-diverging-arms.stderr diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 0311aa94cd485..214066814221b 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -79,7 +79,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { CoerceMany::with_coercion_sites(coerce_first, arms) }; - let mut other_arms = vec![]; // Used only for diagnostics. + let mut prior_non_diverging_arms = vec![]; // Used only for diagnostics. let mut prior_arm = None; for arm in arms { if let Some(e) = &arm.guard { @@ -120,7 +120,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { scrut_span: scrut.span, scrut_hir_id: scrut.hir_id, source: match_src, - prior_arms: other_arms.clone(), + prior_non_diverging_arms: prior_non_diverging_arms.clone(), opt_suggest_box_span, })), ), @@ -142,16 +142,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false, ); - other_arms.push(arm_span); - if other_arms.len() > 5 { - other_arms.remove(0); - } - if !arm_ty.is_never() { // When a match arm has type `!`, then it doesn't influence the expected type for // the following arm. If all of the prior arms are `!`, then the influence comes // from elsewhere and we shouldn't point to any previous arm. prior_arm = Some((arm_block_id, arm_ty, arm_span)); + + prior_non_diverging_arms.push(arm_span); + if prior_non_diverging_arms.len() > 5 { + prior_non_diverging_arms.remove(0); + } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index b953b25d6c4cf..aa92f91f24f83 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -777,7 +777,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { prior_arm_span, prior_arm_ty, source, - ref prior_arms, + ref prior_non_diverging_arms, opt_suggest_box_span, scrut_span, scrut_hir_id, @@ -817,12 +817,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }); let source_map = self.tcx.sess.source_map(); let mut any_multiline_arm = source_map.is_multiline(arm_span); - if prior_arms.len() <= 4 { - for sp in prior_arms { + if prior_non_diverging_arms.len() <= 4 { + for sp in prior_non_diverging_arms { any_multiline_arm |= source_map.is_multiline(*sp); err.span_label(*sp, format!("this is found to be of type `{t}`")); } - } else if let Some(sp) = prior_arms.last() { + } else if let Some(sp) = prior_non_diverging_arms.last() { any_multiline_arm |= source_map.is_multiline(*sp); err.span_label( *sp, @@ -865,7 +865,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.suggest_boxing_for_return_impl_trait( err, ret_sp, - prior_arms.iter().chain(std::iter::once(&arm_span)).copied(), + prior_non_diverging_arms + .iter() + .chain(std::iter::once(&arm_span)) + .copied(), ); } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 248e1c0fcc878..c6f6c32fe60c2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -203,10 +203,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }) } ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { - prior_arms, + prior_non_diverging_arms, .. }) => { - if let [.., arm_span] = &prior_arms[..] { + if let [.., arm_span] = &prior_non_diverging_arms[..] { Some(ConsiderAddingAwait::BothFuturesSugg { first: arm_span.shrink_to_hi(), second: exp_span.shrink_to_hi(), @@ -234,11 +234,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() }) } ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { - ref prior_arms, + ref prior_non_diverging_arms, .. }) => Some({ ConsiderAddingAwait::FutureSuggMultiple { - spans: prior_arms.iter().map(|arm| arm.shrink_to_hi()).collect(), + spans: prior_non_diverging_arms + .iter() + .map(|arm| arm.shrink_to_hi()) + .collect(), } }), _ => None, diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 8e5f026b4c27c..683610ba3b6a3 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -571,7 +571,7 @@ pub struct MatchExpressionArmCause<'tcx> { pub scrut_span: Span, pub scrut_hir_id: hir::HirId, pub source: hir::MatchSource, - pub prior_arms: Vec, + pub prior_non_diverging_arms: Vec, pub opt_suggest_box_span: Option, } diff --git a/tests/ui/match/dont-highlight-diverging-arms.rs b/tests/ui/match/dont-highlight-diverging-arms.rs new file mode 100644 index 0000000000000..dc3b4ca9caad6 --- /dev/null +++ b/tests/ui/match/dont-highlight-diverging-arms.rs @@ -0,0 +1,17 @@ +fn main() { + let m = 42u32; + + let value = 'out: { + match m { + 1 => break 'out Some(1u16), + 2 => Some(2u16), + 3 => break 'out Some(3u16), + 4 => break 'out Some(4u16), + 5 => break 'out Some(5u16), + _ => {} + //~^ ERROR `match` arms have incompatible types + } + + None + }; +} \ No newline at end of file diff --git a/tests/ui/match/dont-highlight-diverging-arms.stderr b/tests/ui/match/dont-highlight-diverging-arms.stderr new file mode 100644 index 0000000000000..886c1af13fa37 --- /dev/null +++ b/tests/ui/match/dont-highlight-diverging-arms.stderr @@ -0,0 +1,25 @@ +error[E0308]: `match` arms have incompatible types + --> $DIR/dont-highlight-diverging-arms.rs:11:18 + | +LL | / match m { +LL | | 1 => break 'out Some(1u16), +LL | | 2 => Some(2u16), + | | ---------- this is found to be of type `Option` +LL | | 3 => break 'out Some(3u16), +... | +LL | | _ => {} + | | ^^ expected `Option`, found `()` +LL | | +LL | | } + | |_________- `match` arms have incompatible types + | + = note: expected enum `Option` + found unit type `()` +help: consider using a semicolon here, but this will discard any values in the match arms + | +LL | }; + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/match/match-arm-resolving-to-never.stderr b/tests/ui/match/match-arm-resolving-to-never.stderr index 6cbdf03d4c27d..fd0c8708b8ca3 100644 --- a/tests/ui/match/match-arm-resolving-to-never.stderr +++ b/tests/ui/match/match-arm-resolving-to-never.stderr @@ -3,11 +3,14 @@ error[E0308]: `match` arms have incompatible types | LL | / match E::F { LL | | E::A => 1, + | | - this is found to be of type `{integer}` LL | | E::B => 2, + | | - this is found to be of type `{integer}` LL | | E::C => 3, + | | - this is found to be of type `{integer}` LL | | E::D => 4, + | | - this is found to be of type `{integer}` LL | | E::E => unimplemented!(""), - | | ------------------ this and all prior arms are found to be of type `{integer}` LL | | E::F => "", | | ^^ expected integer, found `&str` LL | | }; From acb201af54e15b1beebb5b8a6691f6c851afe177 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 14 Feb 2024 23:52:57 +0000 Subject: [PATCH 08/12] make better async fn kind errors --- compiler/rustc_trait_selection/messages.ftl | 12 +- compiler/rustc_trait_selection/src/errors.rs | 10 ++ .../error_reporting/type_err_ctxt_ext.rs | 123 ++++++++++++++---- tests/ui/async-await/async-closures/not-fn.rs | 15 +++ .../async-await/async-closures/not-fn.stderr | 16 +++ .../async-closures/wrong-fn-kind.rs | 3 +- .../async-closures/wrong-fn-kind.stderr | 12 +- 7 files changed, 154 insertions(+), 37 deletions(-) create mode 100644 tests/ui/async-await/async-closures/not-fn.rs create mode 100644 tests/ui/async-await/async-closures/not-fn.stderr diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 41db8059cbee3..0dcba0e05f76f 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -8,14 +8,16 @@ trait_selection_adjust_signature_remove_borrow = consider adjusting the signatur *[other] arguments } -trait_selection_closure_fn_mut_label = closure is `FnMut` because it mutates the variable `{$place}` here +trait_selection_async_closure_not_fn = async closure does not implement `{$kind}` because it captures state from its environment -trait_selection_closure_fn_once_label = closure is `FnOnce` because it moves the variable `{$place}` out of its environment +trait_selection_closure_fn_mut_label = closure is `{$trait_prefix}FnMut` because it mutates the variable `{$place}` here -trait_selection_closure_kind_mismatch = expected a closure that implements the `{$expected}` trait, but this closure only implements `{$found}` - .label = this closure implements `{$found}`, not `{$expected}` +trait_selection_closure_fn_once_label = closure is `{$trait_prefix}FnOnce` because it moves the variable `{$place}` out of its environment -trait_selection_closure_kind_requirement = the requirement to implement `{$expected}` derives from here +trait_selection_closure_kind_mismatch = expected a closure that implements the `{$trait_prefix}{$expected}` trait, but this closure only implements `{$trait_prefix}{$found}` + .label = this closure implements `{$trait_prefix}{$found}`, not `{$trait_prefix}{$expected}` + +trait_selection_closure_kind_requirement = the requirement to implement `{$trait_prefix}{$expected}` derives from here trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries} diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 20cd573f46e9b..407fff03e1588 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -135,6 +135,8 @@ pub struct ClosureKindMismatch { #[label(trait_selection_closure_kind_requirement)] pub cause_span: Span, + pub trait_prefix: &'static str, + #[subdiagnostic] pub fn_once_label: Option, @@ -157,3 +159,11 @@ pub struct ClosureFnMutLabel { pub span: Span, pub place: String, } + +#[derive(Diagnostic)] +#[diag(trait_selection_async_closure_not_fn)] +pub(crate) struct AsyncClosureNotFn { + #[primary_span] + pub span: Span, + pub kind: &'static str, +} diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 73effb3356065..68b1a0d4e61cd 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -2,7 +2,9 @@ use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _}; use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as _}; -use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch}; +use crate::errors::{ + AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, +}; use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxtExt as _; @@ -959,34 +961,102 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn emit_specialized_closure_kind_error( &self, obligation: &PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + mut trait_ref: ty::PolyTraitRef<'tcx>, ) -> Option { - let self_ty = trait_ref.self_ty().skip_binder(); - if let ty::Closure(closure_def_id, closure_args) = *self_ty.kind() - && let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id()) - && let Some(found_kind) = self.closure_kind(self_ty) + // If `AsyncFnKindHelper` is not implemented, that means that the closure kind + // doesn't extend the goal kind. This is worth reporting, but we can only do so + // if we actually know which closure this goal comes from, so look at the cause + // to see if we can extract that information. + if Some(trait_ref.def_id()) == self.tcx.lang_items().async_fn_kind_helper() + && let Some(found_kind) = trait_ref.skip_binder().args.type_at(0).to_opt_closure_kind() + && let Some(expected_kind) = + trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind() && !found_kind.extends(expected_kind) - && let sig = closure_args.as_closure().sig() - && self.can_sub( - obligation.param_env, - trait_ref, - sig.map_bound(|sig| { - ty::TraitRef::new( - self.tcx, - trait_ref.def_id(), - [trait_ref.self_ty().skip_binder(), sig.inputs()[0]], - ) - }), - ) { - let mut err = - self.report_closure_error(&obligation, closure_def_id, found_kind, expected_kind); - self.note_obligation_cause(&mut err, &obligation); - self.point_at_returns_when_relevant(&mut err, &obligation); - Some(err.emit()) - } else { - None + if let Some((_, Some(parent))) = obligation.cause.code().parent() { + // If we have a derived obligation, then the parent will be a `AsyncFn*` goal. + trait_ref = parent.to_poly_trait_ref(); + } else if let &ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = + obligation.cause.code() + && let Some(typeck_results) = &self.typeck_results + && let ty::Closure(closure_def_id, _) | ty::CoroutineClosure(closure_def_id, _) = + *typeck_results.node_type(arg_hir_id).kind() + { + // Otherwise, extract the closure kind from the obligation. + let mut err = self.report_closure_error( + &obligation, + closure_def_id, + found_kind, + expected_kind, + "async ", + ); + self.note_obligation_cause(&mut err, &obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); + return Some(err.emit()); + } + } + + let self_ty = trait_ref.self_ty().skip_binder(); + + if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id()) { + let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() { + ty::Closure(def_id, args) => { + (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None) + } + ty::CoroutineClosure(def_id, args) => ( + def_id, + args.as_coroutine_closure() + .coroutine_closure_sig() + .map_bound(|sig| sig.tupled_inputs_ty), + Some(args.as_coroutine_closure().coroutine_captures_by_ref_ty()), + ), + _ => return None, + }; + + let expected_args = trait_ref.map_bound(|trait_ref| trait_ref.args.type_at(1)); + + // Verify that the arguments are compatible. If the signature is + // mismatched, then we have a totally different error to report. + if self.enter_forall(found_args, |found_args| { + self.enter_forall(expected_args, |expected_args| { + !self.can_sub(obligation.param_env, expected_args, found_args) + }) + }) { + return None; + } + + if let Some(found_kind) = self.closure_kind(self_ty) + && !found_kind.extends(expected_kind) + { + let mut err = self.report_closure_error( + &obligation, + closure_def_id, + found_kind, + expected_kind, + "", + ); + self.note_obligation_cause(&mut err, &obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); + return Some(err.emit()); + } + + // If the closure has captures, then perhaps the reason that the trait + // is unimplemented is because async closures don't implement `Fn`/`FnMut` + // if they have captures. + if let Some(by_ref_captures) = by_ref_captures + && let ty::FnPtr(sig) = by_ref_captures.kind() + && !sig.skip_binder().output().is_unit() + { + let mut err = self.tcx.dcx().create_err(AsyncClosureNotFn { + span: self.tcx.def_span(closure_def_id), + kind: expected_kind.as_str(), + }); + self.note_obligation_cause(&mut err, &obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); + return Some(err.emit()); + } } + None } fn fn_arg_obligation( @@ -1493,6 +1563,7 @@ pub(super) trait InferCtxtPrivExt<'tcx> { closure_def_id: DefId, found_kind: ty::ClosureKind, kind: ty::ClosureKind, + trait_prefix: &'static str, ) -> DiagnosticBuilder<'tcx>; fn report_cyclic_signature_error( @@ -3376,6 +3447,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { closure_def_id: DefId, found_kind: ty::ClosureKind, kind: ty::ClosureKind, + trait_prefix: &'static str, ) -> DiagnosticBuilder<'tcx> { let closure_span = self.tcx.def_span(closure_def_id); @@ -3384,6 +3456,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { expected: kind, found: found_kind, cause_span: obligation.cause.span, + trait_prefix, fn_once_label: None, fn_mut_label: None, }; diff --git a/tests/ui/async-await/async-closures/not-fn.rs b/tests/ui/async-await/async-closures/not-fn.rs new file mode 100644 index 0000000000000..4505e6243e966 --- /dev/null +++ b/tests/ui/async-await/async-closures/not-fn.rs @@ -0,0 +1,15 @@ +// edition:2021 + +// FIXME(async_closures): This needs a better error message! + +#![feature(async_closure)] + +fn main() { + fn needs_fn(_: impl FnMut() -> T) {} + + let mut x = 1; + needs_fn(async || { + //~^ ERROR async closure does not implement `FnMut` because it captures state from its environment + x += 1; + }); +} diff --git a/tests/ui/async-await/async-closures/not-fn.stderr b/tests/ui/async-await/async-closures/not-fn.stderr new file mode 100644 index 0000000000000..9c40613599a8e --- /dev/null +++ b/tests/ui/async-await/async-closures/not-fn.stderr @@ -0,0 +1,16 @@ +error: async closure does not implement `FnMut` because it captures state from its environment + --> $DIR/not-fn.rs:11:14 + | +LL | needs_fn(async || { + | -------- ^^^^^^^^ + | | + | required by a bound introduced by this call + | +note: required by a bound in `needs_fn` + --> $DIR/not-fn.rs:8:28 + | +LL | fn needs_fn(_: impl FnMut() -> T) {} + | ^^^^^^^^^^^^ required by this bound in `needs_fn` + +error: aborting due to 1 previous error + diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.rs b/tests/ui/async-await/async-closures/wrong-fn-kind.rs index f86cee3e0709e..1e372deb984e2 100644 --- a/tests/ui/async-await/async-closures/wrong-fn-kind.rs +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.rs @@ -9,8 +9,7 @@ fn main() { let mut x = 1; needs_async_fn(async || { - //~^ ERROR i16: ops::async_function::internal_implementation_detail::AsyncFnKindHelper - // FIXME: Should say "closure is `async FnMut` but it needs `async Fn`" or sth. + //~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut` x += 1; }); } diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr index 4ef8484cc34cd..34a6b3a485a60 100644 --- a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr @@ -1,15 +1,17 @@ -error[E0277]: the trait bound `i16: ops::async_function::internal_implementation_detail::AsyncFnKindHelper` is not satisfied +error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut` --> $DIR/wrong-fn-kind.rs:11:20 | LL | needs_async_fn(async || { - | _____--------------_^ + | -------------- -^^^^^^^ + | | | + | _____|______________this closure implements `async FnMut`, not `async Fn` | | | | | required by a bound introduced by this call LL | | -LL | | // FIXME: Should say "closure is `async FnMut` but it needs `async Fn`" or sth. LL | | x += 1; + | | - closure is `async FnMut` because it mutates the variable `x` here LL | | }); - | |_____^ the trait `ops::async_function::internal_implementation_detail::AsyncFnKindHelper` is not implemented for `i16` + | |_____- the requirement to implement `async Fn` derives from here | note: required by a bound in `needs_async_fn` --> $DIR/wrong-fn-kind.rs:8:31 @@ -19,4 +21,4 @@ LL | fn needs_async_fn(_: impl async Fn()) {} error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0525`. From 6018e21d8ad072d28dbd2e991dfd8295e2de321f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 15 Feb 2024 14:38:52 +0000 Subject: [PATCH 09/12] Remove a suggestion that is redundant --- compiler/rustc_hir_typeck/src/_match.rs | 1 - .../rustc_infer/src/infer/error_reporting/mod.rs | 13 ------------- compiler/rustc_middle/src/traits/mod.rs | 1 - tests/ui/match/dont-highlight-diverging-arms.rs | 2 +- .../ui/match/dont-highlight-diverging-arms.stderr | 4 ---- tests/ui/suggestions/issue-81839.stderr | 15 ++++----------- tests/ui/wf/wf-unsafe-trait-obj-match.stderr | 4 ---- 7 files changed, 5 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 214066814221b..b0caf45b40afe 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -118,7 +118,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prior_arm_ty, prior_arm_span, scrut_span: scrut.span, - scrut_hir_id: scrut.hir_id, source: match_src, prior_non_diverging_arms: prior_non_diverging_arms.clone(), opt_suggest_box_span, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index aa92f91f24f83..104bf4a5be873 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -780,7 +780,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ref prior_non_diverging_arms, opt_suggest_box_span, scrut_span, - scrut_hir_id, .. }) => match source { hir::MatchSource::TryDesugar(scrut_hir_id) => { @@ -848,18 +847,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) { err.subdiagnostic(subdiag); } - if let hir::Node::Expr(m) = self.tcx.parent_hir_node(scrut_hir_id) - && let hir::Node::Stmt(stmt) = self.tcx.parent_hir_node(m.hir_id) - && let hir::StmtKind::Expr(_) = stmt.kind - { - err.span_suggestion_verbose( - stmt.span.shrink_to_hi(), - "consider using a semicolon here, but this will discard any values \ - in the match arms", - ";", - Applicability::MaybeIncorrect, - ); - } if let Some(ret_sp) = opt_suggest_box_span { // Get return type span and point to it. self.suggest_boxing_for_return_impl_trait( diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 683610ba3b6a3..119e0a49acf1f 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -569,7 +569,6 @@ pub struct MatchExpressionArmCause<'tcx> { pub prior_arm_ty: Ty<'tcx>, pub prior_arm_span: Span, pub scrut_span: Span, - pub scrut_hir_id: hir::HirId, pub source: hir::MatchSource, pub prior_non_diverging_arms: Vec, pub opt_suggest_box_span: Option, diff --git a/tests/ui/match/dont-highlight-diverging-arms.rs b/tests/ui/match/dont-highlight-diverging-arms.rs index dc3b4ca9caad6..0fb614fa18a6f 100644 --- a/tests/ui/match/dont-highlight-diverging-arms.rs +++ b/tests/ui/match/dont-highlight-diverging-arms.rs @@ -14,4 +14,4 @@ fn main() { None }; -} \ No newline at end of file +} diff --git a/tests/ui/match/dont-highlight-diverging-arms.stderr b/tests/ui/match/dont-highlight-diverging-arms.stderr index 886c1af13fa37..f0aaecbb7adb1 100644 --- a/tests/ui/match/dont-highlight-diverging-arms.stderr +++ b/tests/ui/match/dont-highlight-diverging-arms.stderr @@ -15,10 +15,6 @@ LL | | } | = note: expected enum `Option` found unit type `()` -help: consider using a semicolon here, but this will discard any values in the match arms - | -LL | }; - | + error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/issue-81839.stderr b/tests/ui/suggestions/issue-81839.stderr index de1ea98554bee..34ff16c653afa 100644 --- a/tests/ui/suggestions/issue-81839.stderr +++ b/tests/ui/suggestions/issue-81839.stderr @@ -4,22 +4,15 @@ error[E0308]: `match` arms have incompatible types LL | / match num { LL | | 1 => { LL | | cx.answer_str("hi"); - | | -------------------- this is found to be of type `()` + | | -------------------- + | | | | + | | | help: consider removing this semicolon + | | this is found to be of type `()` LL | | } LL | | _ => cx.answer_str("hi"), | | ^^^^^^^^^^^^^^^^^^^ expected `()`, found future LL | | } | |_____- `match` arms have incompatible types - | -help: consider removing this semicolon - | -LL - cx.answer_str("hi"); -LL + cx.answer_str("hi") - | -help: consider using a semicolon here, but this will discard any values in the match arms - | -LL | }; - | + error: aborting due to 1 previous error diff --git a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr b/tests/ui/wf/wf-unsafe-trait-obj-match.stderr index 3b53f55ffdc1d..e30cb8ff921a0 100644 --- a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr +++ b/tests/ui/wf/wf-unsafe-trait-obj-match.stderr @@ -11,10 +11,6 @@ LL | | } | = note: expected reference `&S` found reference `&R` -help: consider using a semicolon here, but this will discard any values in the match arms - | -LL | }; - | + error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/wf-unsafe-trait-obj-match.rs:26:21 From fdc56b68860a3e0fc9a9733d746a0f932f9e53cc Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Thu, 15 Feb 2024 18:38:36 +0100 Subject: [PATCH 10/12] doc: add note before panicking examples for strict_overflow_ops --- library/core/src/num/int_macros.rs | 36 +++++++++++++++++++++++++++++ library/core/src/num/uint_macros.rs | 16 +++++++++++++ 2 files changed, 52 insertions(+) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index d052dcc3e6ee6..434bcace616f2 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -472,6 +472,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).strict_add(1), ", stringify!($SelfT), "::MAX - 1);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")] @@ -552,6 +554,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_add_unsigned(2), 3);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add_unsigned(3);")] @@ -606,6 +610,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).strict_sub(1), ", stringify!($SelfT), "::MIN + 1);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub(3);")] @@ -686,6 +692,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_sub_unsigned(2), -1);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub_unsigned(3);")] @@ -740,6 +748,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.strict_mul(1), ", stringify!($SelfT), "::MAX);")] /// ``` /// + /// The following panics because of overflow: + /// /// ``` should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")] @@ -831,11 +841,15 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).strict_div(-1), ", stringify!($Max), ");")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_div(-1);")] /// ``` /// + /// The following panics because of division by zero: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div(0);")] @@ -901,11 +915,15 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).strict_div_euclid(-1), ", stringify!($Max), ");")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_div_euclid(-1);")] /// ``` /// + /// The following panics because of division by zero: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div_euclid(0);")] @@ -970,11 +988,15 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_rem(2), 1);")] /// ``` /// + /// The following panics because of division by zero: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem(0);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem(-1);")] @@ -1039,11 +1061,15 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_rem_euclid(2), 1);")] /// ``` /// + /// The following panics because of division by zero: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem_euclid(0);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem_euclid(-1);")] @@ -1121,6 +1147,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_neg(), -5);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_neg();")] @@ -1175,6 +1203,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".strict_shl(4), 0x10);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 0x1", stringify!($SelfT), ".strict_shl(129);")] @@ -1256,6 +1286,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".strict_shr(4), 0x1);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(128);")] @@ -1340,6 +1372,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!((-5", stringify!($SelfT), ").strict_abs(), 5);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_abs();")] @@ -1414,6 +1448,8 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(8", stringify!($SelfT), ".strict_pow(2), 64);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")] diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index a217c2e259d2b..5036a3b0c71cf 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -480,6 +480,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).strict_add(1), ", stringify!($SelfT), "::MAX - 1);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")] @@ -561,6 +563,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_add_signed(2), 3);")] /// ``` /// + /// The following panic because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_add_signed(-2);")] @@ -620,6 +624,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_sub(1), 0);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 0", stringify!($SelfT), ".strict_sub(1);")] @@ -700,6 +706,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_mul(1), 5);")] /// ``` /// + /// The following panics because of overflow: + /// /// ``` should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")] @@ -1172,6 +1180,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".strict_neg(), 0);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_neg();")] @@ -1226,6 +1236,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".strict_shl(4), 0x10);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shl(129);")] @@ -1307,6 +1319,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".strict_shr(4), 0x1);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(129);")] @@ -1406,6 +1420,8 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".strict_pow(5), 32);")] /// ``` /// + /// The following panics because of overflow: + /// /// ```should_panic /// #![feature(strict_overflow_ops)] #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")] From 675d092e3e69e1ca6f0abcad4b18d746e6ed558a Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Thu, 15 Feb 2024 18:41:30 +0100 Subject: [PATCH 11/12] doc: panicking division by zero examples for unsigned strict div ops --- library/core/src/num/uint_macros.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 5036a3b0c71cf..f2f29e4ad8194 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -793,6 +793,13 @@ macro_rules! uint_impl { /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_div(10), 10);")] /// ``` + /// + /// The following panics because of division by zero: + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div(0);")] + /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ @@ -848,6 +855,12 @@ macro_rules! uint_impl { /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_div_euclid(10), 10);")] /// ``` + /// The following panics because of division by zero: + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div_euclid(0);")] + /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ @@ -903,6 +916,13 @@ macro_rules! uint_impl { /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_rem(10), 0);")] /// ``` + /// + /// The following panics because of division by zero: + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem(0);")] + /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ @@ -959,6 +979,13 @@ macro_rules! uint_impl { /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_rem_euclid(10), 0);")] /// ``` + /// + /// The following panics because of division by zero: + /// + /// ```should_panic + /// #![feature(strict_overflow_ops)] + #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem_euclid(0);")] + /// ``` #[unstable(feature = "strict_overflow_ops", issue = "118260")] #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")] #[must_use = "this returns the result of the operation, \ From 954d56591cbbc057d53c233f86895658febe407d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 15 Feb 2024 13:20:33 +0000 Subject: [PATCH 12/12] Fix closure kind docs --- compiler/rustc_middle/src/ty/sty.rs | 37 ++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 66086ac87f16b..a581712526752 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2363,28 +2363,42 @@ impl<'tcx> Ty<'tcx> { } /// When we create a closure, we record its kind (i.e., what trait - /// it implements) into its `ClosureArgs` using a type + /// it implements, constrained by how it uses its borrows) into its + /// [`ty::ClosureArgs`] or [`ty::CoroutineClosureArgs`] using a type /// parameter. This is kind of a phantom type, except that the /// most convenient thing for us to are the integral types. This /// function converts such a special type into the closure - /// kind. To go the other way, use `closure_kind.to_ty(tcx)`. + /// kind. To go the other way, use [`Ty::from_closure_kind`]. /// /// Note that during type checking, we use an inference variable /// to represent the closure kind, because it has not yet been /// inferred. Once upvar inference (in `rustc_hir_analysis/src/check/upvar.rs`) - /// is complete, that type variable will be unified. + /// is complete, that type variable will be unified with one of + /// the integral types. /// - /// To be noted that you can use [`ClosureArgs::kind()`] or [`CoroutineClosureArgs::kind()`] - /// to get the same information, which you can get by calling [`GenericArgs::as_closure()`] - /// or [`GenericArgs::as_coroutine_closure()`], depending on the type of the closure. + /// ```rust,ignore (snippet of compiler code) + /// if let TyKind::Closure(def_id, args) = closure_ty.kind() + /// && let Some(closure_kind) = args.as_closure().kind_ty().to_opt_closure_kind() + /// { + /// println!("{closure_kind:?}"); + /// } else if let TyKind::CoroutineClosure(def_id, args) = closure_ty.kind() + /// && let Some(closure_kind) = args.as_coroutine_closure().kind_ty().to_opt_closure_kind() + /// { + /// println!("{closure_kind:?}"); + /// } + /// ``` /// - /// Otherwise, this method can be used as follows: + /// After upvar analysis, you should instead use [`ClosureArgs::kind()`] + /// or [`CoroutineClosureArgs::kind()`] to assert that the `ClosureKind` + /// has been constrained instead of manually calling this method. /// /// ```rust,ignore (snippet of compiler code) - /// let TyKind::Closure(def_id, [closure_fn_kind_ty, ..]) = closure_ty.kind() - /// && let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() + /// if let TyKind::Closure(def_id, args) = closure_ty.kind() + /// { + /// println!("{:?}", args.as_closure().kind()); + /// } else if let TyKind::CoroutineClosure(def_id, args) = closure_ty.kind() /// { - /// // your code + /// println!("{:?}", args.as_coroutine_closure().kind()); /// } /// ``` pub fn to_opt_closure_kind(self) -> Option { @@ -2406,7 +2420,8 @@ impl<'tcx> Ty<'tcx> { } } - /// Inverse of [`Ty::to_opt_closure_kind`]. + /// Inverse of [`Ty::to_opt_closure_kind`]. See docs on that method + /// for explanation of the relationship between `Ty` and [`ty::ClosureKind`]. pub fn from_closure_kind(tcx: TyCtxt<'tcx>, kind: ty::ClosureKind) -> Ty<'tcx> { match kind { ty::ClosureKind::Fn => tcx.types.i8,