From e6b135aa82b0b548c469fb47086bc03552a83172 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 19 Oct 2023 19:00:18 +0000 Subject: [PATCH 01/29] Add lifetime_capture_rules_2024 --- compiler/rustc_ast_lowering/src/lib.rs | 6 +++-- compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_span/src/symbol.rs | 1 + ...eature-gate-lifetime-capture-rules-2024.rs | 6 +++++ ...re-gate-lifetime-capture-rules-2024.stderr | 18 +++++++++++++ tests/ui/impl-trait/variance.new.stderr | 26 +++++++++++++++++++ .../{variance.stderr => variance.old.stderr} | 8 +++--- tests/ui/impl-trait/variance.rs | 12 +++++++-- 8 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-lifetime-capture-rules-2024.rs create mode 100644 tests/ui/feature-gates/feature-gate-lifetime-capture-rules-2024.stderr create mode 100644 tests/ui/impl-trait/variance.new.stderr rename tests/ui/impl-trait/{variance.stderr => variance.old.stderr} (83%) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a88493acf982f..70b4be9da825f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1542,8 +1542,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { Vec::new() } hir::OpaqueTyOrigin::FnReturn(..) => { - if let FnDeclKind::Impl | FnDeclKind::Trait = - fn_kind.expect("expected RPITs to be lowered with a FnKind") + if matches!( + fn_kind.expect("expected RPITs to be lowered with a FnKind"), + FnDeclKind::Impl | FnDeclKind::Trait + ) || self.tcx.features().lifetime_capture_rules_2024 { // return-position impl trait in trait was decided to capture all // in-scope lifetimes, which we collect for all opaques during resolution. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 64b5a7d2921a6..394dadbfb45df 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -187,6 +187,8 @@ declare_features! ( (internal, intrinsics, "1.0.0", None, None), /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. (internal, lang_items, "1.0.0", None, None), + /// Changes `impl Trait` to capture all lifetimes in scope. + (unstable, lifetime_capture_rules_2024, "CURRENT_RUSTC_VERSION", None, None), /// Allows `#[link(..., cfg(..))]`; perma-unstable per #37406 (unstable, link_cfg, "1.14.0", None, None), /// Allows the `multiple_supertrait_upcastable` lint. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f287862cc23c5..41e2c28ca5e0e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -941,6 +941,7 @@ symbols! { lib, libc, lifetime, + lifetime_capture_rules_2024, lifetimes, likely, line, diff --git a/tests/ui/feature-gates/feature-gate-lifetime-capture-rules-2024.rs b/tests/ui/feature-gates/feature-gate-lifetime-capture-rules-2024.rs new file mode 100644 index 0000000000000..c06107e66a76c --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-lifetime-capture-rules-2024.rs @@ -0,0 +1,6 @@ +fn foo(x: &Vec) -> impl Sized { + x + //~^ ERROR hidden type for `impl Sized` captures lifetime that does not appear in bounds +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-lifetime-capture-rules-2024.stderr b/tests/ui/feature-gates/feature-gate-lifetime-capture-rules-2024.stderr new file mode 100644 index 0000000000000..ddf9a3b305d3a --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-lifetime-capture-rules-2024.stderr @@ -0,0 +1,18 @@ +error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds + --> $DIR/feature-gate-lifetime-capture-rules-2024.rs:2:5 + | +LL | fn foo(x: &Vec) -> impl Sized { + | --------- ---------- opaque type defined here + | | + | hidden type `&Vec` captures the anonymous lifetime defined here +LL | x + | ^ + | +help: to declare that `impl Sized` captures `'_`, you can add an explicit `'_` lifetime bound + | +LL | fn foo(x: &Vec) -> impl Sized + '_ { + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/impl-trait/variance.new.stderr b/tests/ui/impl-trait/variance.new.stderr new file mode 100644 index 0000000000000..abf4b1ac2104e --- /dev/null +++ b/tests/ui/impl-trait/variance.new.stderr @@ -0,0 +1,26 @@ +error: [*, o] + --> $DIR/variance.rs:12:36 + | +LL | fn not_captured_early<'a: 'a>() -> impl Sized {} + | ^^^^^^^^^^ + +error: [*, o] + --> $DIR/variance.rs:16:32 + | +LL | fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: [o] + --> $DIR/variance.rs:18:40 + | +LL | fn not_captured_late<'a>(_: &'a ()) -> impl Sized {} + | ^^^^^^^^^^ + +error: [o] + --> $DIR/variance.rs:22:36 + | +LL | fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/impl-trait/variance.stderr b/tests/ui/impl-trait/variance.old.stderr similarity index 83% rename from tests/ui/impl-trait/variance.stderr rename to tests/ui/impl-trait/variance.old.stderr index 6447367541097..8b4d6314359e0 100644 --- a/tests/ui/impl-trait/variance.stderr +++ b/tests/ui/impl-trait/variance.old.stderr @@ -1,23 +1,23 @@ error: [*] - --> $DIR/variance.rs:8:36 + --> $DIR/variance.rs:12:36 | LL | fn not_captured_early<'a: 'a>() -> impl Sized {} | ^^^^^^^^^^ error: [*, o] - --> $DIR/variance.rs:10:32 + --> $DIR/variance.rs:16:32 | LL | fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: [] - --> $DIR/variance.rs:12:40 + --> $DIR/variance.rs:18:40 | LL | fn not_captured_late<'a>(_: &'a ()) -> impl Sized {} | ^^^^^^^^^^ error: [o] - --> $DIR/variance.rs:14:36 + --> $DIR/variance.rs:22:36 | LL | fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/impl-trait/variance.rs b/tests/ui/impl-trait/variance.rs index d6212f8f39372..e111d37761f4b 100644 --- a/tests/ui/impl-trait/variance.rs +++ b/tests/ui/impl-trait/variance.rs @@ -1,3 +1,7 @@ +// revisions: old new + +#![cfg_attr(new, feature(lifetime_capture_rules_2024))] + #![feature(rustc_attrs)] #![allow(internal_features)] #![rustc_variance_of_opaques] @@ -5,11 +9,15 @@ trait Captures<'a> {} impl Captures<'_> for T {} -fn not_captured_early<'a: 'a>() -> impl Sized {} //~ [*] +fn not_captured_early<'a: 'a>() -> impl Sized {} +//[old]~^ [*] +//[new]~^^ [*, o] fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {} //~ [*, o] -fn not_captured_late<'a>(_: &'a ()) -> impl Sized {} //~ [] +fn not_captured_late<'a>(_: &'a ()) -> impl Sized {} +//[old]~^ [] +//[new]~^^ [o] fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} //~ [o] From 52143ffcb3087665b2a2aabf3ce6c2a5940bbfe6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 19 Oct 2023 19:01:59 +0000 Subject: [PATCH 02/29] Add test for implicitly capturing late-bound var with new capture rules --- tests/ui/impl-trait/implicit-capture-late.rs | 14 ++++++++++++++ tests/ui/impl-trait/implicit-capture-late.stderr | 9 +++++++++ 2 files changed, 23 insertions(+) create mode 100644 tests/ui/impl-trait/implicit-capture-late.rs create mode 100644 tests/ui/impl-trait/implicit-capture-late.stderr diff --git a/tests/ui/impl-trait/implicit-capture-late.rs b/tests/ui/impl-trait/implicit-capture-late.rs new file mode 100644 index 0000000000000..8bfb16760c918 --- /dev/null +++ b/tests/ui/impl-trait/implicit-capture-late.rs @@ -0,0 +1,14 @@ +// known-bug: #117647 + +#![feature(lifetime_capture_rules_2024)] +#![feature(rustc_attrs)] +#![allow(internal_features)] +#![rustc_variance_of_opaques] + +use std::ops::Deref; + +fn foo(x: Vec) -> Box Deref> { + Box::new(x) +} + +fn main() {} diff --git a/tests/ui/impl-trait/implicit-capture-late.stderr b/tests/ui/impl-trait/implicit-capture-late.stderr new file mode 100644 index 0000000000000..4d760d69513bf --- /dev/null +++ b/tests/ui/impl-trait/implicit-capture-late.stderr @@ -0,0 +1,9 @@ +error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level + --> $DIR/implicit-capture-late.rs:10:36 + | +LL | fn foo(x: Vec) -> Box Deref> { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0657`. From 2faaea98f813827ca0f91266652039d2d859989d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 6 Oct 2023 19:07:05 +0000 Subject: [PATCH 03/29] Provide context when `?` can't be called because of `Result<_, E>` When a method chain ending in `?` causes an E0277 because the expression's `Result::Err` variant doesn't have a type that can be converted to the `Result<_, E>` type parameter in the return type, provide additional context of which parts of the chain can and can't support the `?` operator. ``` error[E0277]: `?` couldn't convert the error to `String` --> $DIR/question-mark-result-err-mismatch.rs:28:25 | LL | fn bar() -> Result<(), String> { | ------------------ expected `String` because of this LL | let x = foo(); | ----- this can be annotated with `?` because it has type `Result` LL | let one = x LL | .map(|s| ()) | ----------- this can be annotated with `?` because it has type `Result<(), String>` LL | .map_err(|_| ())?; | ---------------^ the trait `From<()>` is not implemented for `String` | | | this can't be annotated with `?` because it has type `Result<(), ()>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: > >> >> > > > = note: required for `Result<(), String>` to implement `FromResidual>` ``` Fix #72124. --- .../src/traits/error_reporting/suggestions.rs | 18 ++- .../error_reporting/type_err_ctxt_ext.rs | 142 +++++++++++++++++- .../question-mark-result-err-mismatch.rs | 59 ++++++++ .../question-mark-result-err-mismatch.stderr | 83 ++++++++++ tests/ui/try-block/try-block-bad-type.stderr | 4 +- tests/ui/try-trait/bad-interconversion.stderr | 4 +- tests/ui/try-trait/issue-32709.stderr | 4 +- 7 files changed, 302 insertions(+), 12 deletions(-) create mode 100644 tests/ui/traits/question-mark-result-err-mismatch.rs create mode 100644 tests/ui/traits/question-mark-result-err-mismatch.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 9bd1030ac74fa..939c06a1191fd 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -3640,14 +3640,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { && let Some(failed_pred) = failed_pred.to_opt_poly_projection_pred() && let Some(found) = failed_pred.skip_binder().term.ty() { - type_diffs = vec![Sorts(ty::error::ExpectedFound { - expected: Ty::new_alias( - self.tcx, - ty::Projection, - where_pred.skip_binder().projection_ty, - ), - found, - })]; + type_diffs = vec![ + Sorts(ty::error::ExpectedFound { + expected: Ty::new_alias( + self.tcx, + ty::Projection, + where_pred.skip_binder().projection_ty, + ), + found, + }), + ]; } } if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind 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 78c9ac157c0ad..faa806d54a57b 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 @@ -3,6 +3,7 @@ use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch}; use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use crate::infer::InferCtxtExt as _; use crate::infer::{self, InferCtxt}; use crate::traits::error_reporting::infer_ctxt_ext::InferCtxtExt; use crate::traits::error_reporting::{ambiguity, ambiguity::Ambiguity::*}; @@ -40,7 +41,7 @@ use rustc_session::config::{DumpSolverProofTree, TraitSolver}; use rustc_session::Limit; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::symbol::sym; -use rustc_span::{ExpnKind, Span, DUMMY_SP}; +use rustc_span::{BytePos, ExpnKind, Span, DUMMY_SP}; use std::borrow::Cow; use std::fmt; use std::iter; @@ -100,6 +101,13 @@ pub trait TypeErrCtxtExt<'tcx> { fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool; + fn try_conversion_context( + &self, + obligation: &PredicateObligation<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + err: &mut Diagnostic, + ); + fn report_const_param_not_wf( &self, ty: Ty<'tcx>, @@ -499,6 +507,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut err = struct_span_err!(self.tcx.sess, span, E0277, "{}", err_msg); + if is_try_conversion { + self.try_conversion_context(&obligation, trait_ref.skip_binder(), &mut err); + } + if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) { err.span_label( ret_span, @@ -945,6 +957,134 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { false } + /// When the `E` of the resulting `Result` in an expression `foo().bar().baz()?`, + /// identify thoe method chain sub-expressions that could or could not have been annotated + /// with `?`. + fn try_conversion_context( + &self, + obligation: &PredicateObligation<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + err: &mut Diagnostic, + ) { + let span = obligation.cause.span; + struct V<'v> { + search_span: Span, + found: Option<&'v hir::Expr<'v>>, + } + impl<'v> Visitor<'v> for V<'v> { + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + if let hir::ExprKind::Match(expr, _arms, hir::MatchSource::TryDesugar(_)) = ex.kind + { + if ex.span.with_lo(ex.span.hi() - BytePos(1)).source_equal(self.search_span) { + if let hir::ExprKind::Call(_, [expr, ..]) = expr.kind { + self.found = Some(expr); + return; + } + } + } + hir::intravisit::walk_expr(self, ex); + } + } + let hir_id = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id); + let body_id = match self.tcx.hir().find(hir_id) { + Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) => { + body_id + } + _ => return, + }; + let mut v = V { search_span: span, found: None }; + v.visit_body(self.tcx.hir().body(*body_id)); + let Some(expr) = v.found else { + return; + }; + let Some(typeck) = &self.typeck_results else { + return; + }; + let Some((ObligationCauseCode::QuestionMark, Some(y))) = obligation.cause.code().parent() + else { + return; + }; + if !self.tcx.is_diagnostic_item(sym::FromResidual, y.def_id()) { + return; + } + let self_ty = trait_ref.self_ty(); + + let mut prev_ty = self.resolve_vars_if_possible( + typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), + ); + let mut annotate_expr = |span: Span, prev_ty: Ty<'tcx>, self_ty: Ty<'tcx>| -> bool { + // We always look at the `E` type, because that's the only one affected by `?`. If the + // incorrect `Result` is because of the `T`, we'll get an E0308 on the whole + // expression, after the `?` has "unwrapped" the `T`. + let ty::Adt(def, args) = prev_ty.kind() else { + return false; + }; + let Some(arg) = args.get(1) else { + return false; + }; + if !self.tcx.is_diagnostic_item(sym::Result, def.did()) { + return false; + } + let can = if self + .infcx + .type_implements_trait( + self.tcx.get_diagnostic_item(sym::From).unwrap(), + [self_ty.into(), *arg], + obligation.param_env, + ) + .must_apply_modulo_regions() + { + "can" + } else { + "can't" + }; + err.span_label( + span, + format!("this {can} be annotated with `?` because it has type `{prev_ty}`"), + ); + true + }; + + // The following logic is simlar to `point_at_chain`, but that's focused on associated types + let mut expr = expr; + while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, span) = expr.kind { + // Point at every method call in the chain with the `Result` type. + // let foo = bar.iter().map(mapper)?; + // ------ ----------- + expr = rcvr_expr; + if !annotate_expr(span, prev_ty, self_ty) { + break; + } + + prev_ty = self.resolve_vars_if_possible( + typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), + ); + + if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind + && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path + && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id) + && let Some(parent) = self.tcx.hir().find_parent(binding.hir_id) + { + // We've reached the root of the method call chain... + if let hir::Node::Local(local) = parent && let Some(binding_expr) = local.init { + // ...and it is a binding. Get the binding creation and continue the chain. + expr = binding_expr; + } + if let hir::Node::Param(_param) = parent { + // ...and it is a an fn argument. + break; + } + } + } + // `expr` is now the "root" expression of the method call chain, which can be any + // expression kind, like a method call or a path. If this expression is `Result` as + // well, then we also point at it. + prev_ty = self.resolve_vars_if_possible( + typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), + ); + annotate_expr(expr.span, prev_ty, self_ty); + } + fn report_const_param_not_wf( &self, ty: Ty<'tcx>, diff --git a/tests/ui/traits/question-mark-result-err-mismatch.rs b/tests/ui/traits/question-mark-result-err-mismatch.rs new file mode 100644 index 0000000000000..7b364580858be --- /dev/null +++ b/tests/ui/traits/question-mark-result-err-mismatch.rs @@ -0,0 +1,59 @@ +fn foo() -> Result { //~ NOTE expected `String` because of this + let test = String::from("one,two"); + let x = test + .split_whitespace() + .next() + .ok_or_else(|| { //~ NOTE this can be annotated with `?` because it has type `Result<&str, &str>` + "Couldn't split the test string" + }); + let one = x + .map(|s| ()) //~ NOTE this can be annotated with `?` because it has type `Result<(), &str>` + .map_err(|_| ()) //~ NOTE this can't be annotated with `?` because it has type `Result<(), ()>` + .map(|()| "")?; //~ ERROR `?` couldn't convert the error to `String` + //~^ NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE this can't be annotated with `?` because it has type `Result<&str, ()>` + //~| NOTE the trait `From<()>` is not implemented for `String` + //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + //~| NOTE required for `Result` to implement `FromResidual>` + Ok(one.to_string()) +} + +fn bar() -> Result<(), String> { //~ NOTE expected `String` because of this + let x = foo(); //~ NOTE this can be annotated with `?` because it has type `Result` + let one = x + .map(|s| ()) //~ NOTE this can be annotated with `?` because it has type `Result<(), String>` + .map_err(|_| ())?; //~ ERROR `?` couldn't convert the error to `String` + //~^ NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE this can't be annotated with `?` because it has type `Result<(), ()>` + //~| NOTE the trait `From<()>` is not implemented for `String` + //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + //~| NOTE required for `Result<(), String>` to implement `FromResidual>` + Ok(one) +} + +fn baz() -> Result { //~ NOTE expected `String` because of this + let test = String::from("one,two"); + let one = test + .split_whitespace() + .next() + .ok_or_else(|| { //~ NOTE this can't be annotated with `?` because it has type `Result<&str, ()>` + "Couldn't split the test string"; + })?; + //~^ ERROR `?` couldn't convert the error to `String` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE the trait `From<()>` is not implemented for `String` + //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + //~| NOTE required for `Result` to implement `FromResidual>` + Ok(one.to_string()) +} + +fn main() {} diff --git a/tests/ui/traits/question-mark-result-err-mismatch.stderr b/tests/ui/traits/question-mark-result-err-mismatch.stderr new file mode 100644 index 0000000000000..f6acbc6dd0785 --- /dev/null +++ b/tests/ui/traits/question-mark-result-err-mismatch.stderr @@ -0,0 +1,83 @@ +error[E0277]: `?` couldn't convert the error to `String` + --> $DIR/question-mark-result-err-mismatch.rs:12:22 + | +LL | fn foo() -> Result { + | ---------------------- expected `String` because of this +... +LL | .ok_or_else(|| { + | __________- +LL | | "Couldn't split the test string" +LL | | }); + | |__________- this can be annotated with `?` because it has type `Result<&str, &str>` +LL | let one = x +LL | .map(|s| ()) + | ----------- this can be annotated with `?` because it has type `Result<(), &str>` +LL | .map_err(|_| ()) + | --------------- this can't be annotated with `?` because it has type `Result<(), ()>` +LL | .map(|()| "")?; + | ------------^ the trait `From<()>` is not implemented for `String` + | | + | this can't be annotated with `?` because it has type `Result<&str, ()>` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + = help: the following other types implement trait `From`: + > + >> + >> + > + > + > + = note: required for `Result` to implement `FromResidual>` + +error[E0277]: `?` couldn't convert the error to `String` + --> $DIR/question-mark-result-err-mismatch.rs:28:25 + | +LL | fn bar() -> Result<(), String> { + | ------------------ expected `String` because of this +LL | let x = foo(); + | ----- this can be annotated with `?` because it has type `Result` +LL | let one = x +LL | .map(|s| ()) + | ----------- this can be annotated with `?` because it has type `Result<(), String>` +LL | .map_err(|_| ())?; + | ---------------^ the trait `From<()>` is not implemented for `String` + | | + | this can't be annotated with `?` because it has type `Result<(), ()>` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + = help: the following other types implement trait `From`: + > + >> + >> + > + > + > + = note: required for `Result<(), String>` to implement `FromResidual>` + +error[E0277]: `?` couldn't convert the error to `String` + --> $DIR/question-mark-result-err-mismatch.rs:47:11 + | +LL | fn baz() -> Result { + | ---------------------- expected `String` because of this +... +LL | .ok_or_else(|| { + | __________- +LL | | "Couldn't split the test string"; +LL | | })?; + | | -^ the trait `From<()>` is not implemented for `String` + | |__________| + | this can't be annotated with `?` because it has type `Result<&str, ()>` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + = help: the following other types implement trait `From`: + > + >> + >> + > + > + > + = note: required for `Result` to implement `FromResidual>` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/try-block/try-block-bad-type.stderr b/tests/ui/try-block/try-block-bad-type.stderr index b41bf86d3d911..d58a011ff5501 100644 --- a/tests/ui/try-block/try-block-bad-type.stderr +++ b/tests/ui/try-block/try-block-bad-type.stderr @@ -2,7 +2,9 @@ error[E0277]: `?` couldn't convert the error to `TryFromSliceError` --> $DIR/try-block-bad-type.rs:7:16 | LL | Err("")?; - | ^ the trait `From<&str>` is not implemented for `TryFromSliceError` + | -------^ the trait `From<&str>` is not implemented for `TryFromSliceError` + | | + | this can't be annotated with `?` because it has type `Result<_, &str>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the trait `From` is implemented for `TryFromSliceError` diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index d8b9431becc6b..97fbbdbf8f8a8 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -4,7 +4,9 @@ error[E0277]: `?` couldn't convert the error to `u8` LL | fn result_to_result() -> Result { | --------------- expected `u8` because of this LL | Ok(Err(123_i32)?) - | ^ the trait `From` is not implemented for `u8` + | ------------^ the trait `From` is not implemented for `u8` + | | + | this can't be annotated with `?` because it has type `Result<_, i32>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: diff --git a/tests/ui/try-trait/issue-32709.stderr b/tests/ui/try-trait/issue-32709.stderr index 94e8f9295fdd5..6e0f464d16152 100644 --- a/tests/ui/try-trait/issue-32709.stderr +++ b/tests/ui/try-trait/issue-32709.stderr @@ -4,7 +4,9 @@ error[E0277]: `?` couldn't convert the error to `()` LL | fn a() -> Result { | --------------- expected `()` because of this LL | Err(5)?; - | ^ the trait `From<{integer}>` is not implemented for `()` + | ------^ the trait `From<{integer}>` is not implemented for `()` + | | + | this can't be annotated with `?` because it has type `Result<_, {integer}>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: From 276b74d1fff0c688ffb51bcce04d7cca65cdd3af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 7 Oct 2023 01:14:43 +0000 Subject: [PATCH 04/29] Point at fewer methods in the chain, only those that change the E type --- .../error_reporting/type_err_ctxt_ext.rs | 76 ++++++++++++------- .../question-mark-result-err-mismatch.rs | 15 ++-- .../question-mark-result-err-mismatch.stderr | 26 +++---- 3 files changed, 64 insertions(+), 53 deletions(-) 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 faa806d54a57b..875cb71f3ace9 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 @@ -1012,39 +1012,25 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut prev_ty = self.resolve_vars_if_possible( typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), ); - let mut annotate_expr = |span: Span, prev_ty: Ty<'tcx>, self_ty: Ty<'tcx>| -> bool { - // We always look at the `E` type, because that's the only one affected by `?`. If the - // incorrect `Result` is because of the `T`, we'll get an E0308 on the whole - // expression, after the `?` has "unwrapped" the `T`. + + // We always look at the `E` type, because that's the only one affected by `?`. If the + // incorrect `Result` is because of the `T`, we'll get an E0308 on the whole + // expression, after the `?` has "unwrapped" the `T`. + let get_e_type = |prev_ty: Ty<'tcx>| -> Option> { let ty::Adt(def, args) = prev_ty.kind() else { - return false; + return None; }; let Some(arg) = args.get(1) else { - return false; + return None; }; if !self.tcx.is_diagnostic_item(sym::Result, def.did()) { - return false; + return None; } - let can = if self - .infcx - .type_implements_trait( - self.tcx.get_diagnostic_item(sym::From).unwrap(), - [self_ty.into(), *arg], - obligation.param_env, - ) - .must_apply_modulo_regions() - { - "can" - } else { - "can't" - }; - err.span_label( - span, - format!("this {can} be annotated with `?` because it has type `{prev_ty}`"), - ); - true + Some(arg.as_type()?) }; + let mut chain = vec![]; + // The following logic is simlar to `point_at_chain`, but that's focused on associated types let mut expr = expr; while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, span) = expr.kind { @@ -1052,9 +1038,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // let foo = bar.iter().map(mapper)?; // ------ ----------- expr = rcvr_expr; - if !annotate_expr(span, prev_ty, self_ty) { - break; - } + chain.push((span, prev_ty)); prev_ty = self.resolve_vars_if_possible( typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), @@ -1082,7 +1066,41 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { prev_ty = self.resolve_vars_if_possible( typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), ); - annotate_expr(expr.span, prev_ty, self_ty); + chain.push((expr.span, prev_ty)); + + let mut prev = None; + for (span, err_ty) in chain.into_iter().rev() { + let err_ty = get_e_type(err_ty); + let err_ty = match (err_ty, prev) { + (Some(err_ty), Some(prev)) if !self.can_eq(obligation.param_env, err_ty, prev) => { + err_ty + } + (Some(err_ty), None) => err_ty, + _ => { + prev = err_ty; + continue; + } + }; + if self + .infcx + .type_implements_trait( + self.tcx.get_diagnostic_item(sym::From).unwrap(), + [self_ty, err_ty], + obligation.param_env, + ) + .must_apply_modulo_regions() + { + err.span_label(span, format!("this has type `Result<_, {err_ty}>`")); + } else { + err.span_label( + span, + format!( + "this can't be annotated with `?` because it has type `Result<_, {err_ty}>`", + ), + ); + } + prev = Some(err_ty); + } } fn report_const_param_not_wf( diff --git a/tests/ui/traits/question-mark-result-err-mismatch.rs b/tests/ui/traits/question-mark-result-err-mismatch.rs index 7b364580858be..e5ccca2e5f7c7 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.rs +++ b/tests/ui/traits/question-mark-result-err-mismatch.rs @@ -3,18 +3,17 @@ fn foo() -> Result { //~ NOTE expected `String` because of this let x = test .split_whitespace() .next() - .ok_or_else(|| { //~ NOTE this can be annotated with `?` because it has type `Result<&str, &str>` + .ok_or_else(|| { //~ NOTE this has type `Result<_, &str>` "Couldn't split the test string" }); let one = x - .map(|s| ()) //~ NOTE this can be annotated with `?` because it has type `Result<(), &str>` - .map_err(|_| ()) //~ NOTE this can't be annotated with `?` because it has type `Result<(), ()>` + .map(|s| ()) + .map_err(|_| ()) //~ NOTE this can't be annotated with `?` because it has type `Result<_, ()>` .map(|()| "")?; //~ ERROR `?` couldn't convert the error to `String` //~^ NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE this can't be annotated with `?` because it has type `Result<&str, ()>` //~| NOTE the trait `From<()>` is not implemented for `String` //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait //~| NOTE required for `Result` to implement `FromResidual>` @@ -22,15 +21,15 @@ fn foo() -> Result { //~ NOTE expected `String` because of this } fn bar() -> Result<(), String> { //~ NOTE expected `String` because of this - let x = foo(); //~ NOTE this can be annotated with `?` because it has type `Result` + let x = foo(); //~ NOTE this has type `Result<_, String>` let one = x - .map(|s| ()) //~ NOTE this can be annotated with `?` because it has type `Result<(), String>` + .map(|s| ()) .map_err(|_| ())?; //~ ERROR `?` couldn't convert the error to `String` //~^ NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE this can't be annotated with `?` because it has type `Result<(), ()>` + //~| NOTE this can't be annotated with `?` because it has type `Result<_, ()>` //~| NOTE the trait `From<()>` is not implemented for `String` //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait //~| NOTE required for `Result<(), String>` to implement `FromResidual>` @@ -42,7 +41,7 @@ fn baz() -> Result { //~ NOTE expected `String` because of this let one = test .split_whitespace() .next() - .ok_or_else(|| { //~ NOTE this can't be annotated with `?` because it has type `Result<&str, ()>` + .ok_or_else(|| { //~ NOTE this can't be annotated with `?` because it has type `Result<_, ()>` "Couldn't split the test string"; })?; //~^ ERROR `?` couldn't convert the error to `String` diff --git a/tests/ui/traits/question-mark-result-err-mismatch.stderr b/tests/ui/traits/question-mark-result-err-mismatch.stderr index f6acbc6dd0785..fc3b2e6b46b38 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.stderr +++ b/tests/ui/traits/question-mark-result-err-mismatch.stderr @@ -8,16 +8,12 @@ LL | .ok_or_else(|| { | __________- LL | | "Couldn't split the test string" LL | | }); - | |__________- this can be annotated with `?` because it has type `Result<&str, &str>` -LL | let one = x -LL | .map(|s| ()) - | ----------- this can be annotated with `?` because it has type `Result<(), &str>` + | |__________- this has type `Result<_, &str>` +... LL | .map_err(|_| ()) - | --------------- this can't be annotated with `?` because it has type `Result<(), ()>` + | --------------- this can't be annotated with `?` because it has type `Result<_, ()>` LL | .map(|()| "")?; - | ------------^ the trait `From<()>` is not implemented for `String` - | | - | this can't be annotated with `?` because it has type `Result<&str, ()>` + | ^ the trait `From<()>` is not implemented for `String` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: @@ -30,19 +26,17 @@ LL | .map(|()| "")?; = note: required for `Result` to implement `FromResidual>` error[E0277]: `?` couldn't convert the error to `String` - --> $DIR/question-mark-result-err-mismatch.rs:28:25 + --> $DIR/question-mark-result-err-mismatch.rs:27:25 | LL | fn bar() -> Result<(), String> { | ------------------ expected `String` because of this LL | let x = foo(); - | ----- this can be annotated with `?` because it has type `Result` -LL | let one = x -LL | .map(|s| ()) - | ----------- this can be annotated with `?` because it has type `Result<(), String>` + | ----- this has type `Result<_, String>` +... LL | .map_err(|_| ())?; | ---------------^ the trait `From<()>` is not implemented for `String` | | - | this can't be annotated with `?` because it has type `Result<(), ()>` + | this can't be annotated with `?` because it has type `Result<_, ()>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: @@ -55,7 +49,7 @@ LL | .map_err(|_| ())?; = note: required for `Result<(), String>` to implement `FromResidual>` error[E0277]: `?` couldn't convert the error to `String` - --> $DIR/question-mark-result-err-mismatch.rs:47:11 + --> $DIR/question-mark-result-err-mismatch.rs:46:11 | LL | fn baz() -> Result { | ---------------------- expected `String` because of this @@ -66,7 +60,7 @@ LL | | "Couldn't split the test string"; LL | | })?; | | -^ the trait `From<()>` is not implemented for `String` | |__________| - | this can't be annotated with `?` because it has type `Result<&str, ()>` + | this can't be annotated with `?` because it has type `Result<_, ()>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: From e6887429a25d4b1bd7a44033a1681bdc42f7069a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 7 Oct 2023 03:47:02 +0000 Subject: [PATCH 05/29] Detect incorrect `;` in `Option::ok_or_else` and `Result::map_err` Fix #72124. --- compiler/rustc_span/src/symbol.rs | 2 + .../error_reporting/type_err_ctxt_ext.rs | 66 ++++++++++++++++++- .../question-mark-result-err-mismatch.rs | 9 ++- .../question-mark-result-err-mismatch.stderr | 15 +++-- 4 files changed, 82 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 302be85a429f4..1e1fa6778f04a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -988,6 +988,7 @@ symbols! { managed_boxes, manually_drop, map, + map_err, marker, marker_trait_attr, masked, @@ -1152,6 +1153,7 @@ symbols! { offset, offset_of, offset_of_enum, + ok_or_else, omit_gdb_pretty_printer_section, on, on_unimplemented, 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 875cb71f3ace9..d9a2fd1810545 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 @@ -41,7 +41,7 @@ use rustc_session::config::{DumpSolverProofTree, TraitSolver}; use rustc_session::Limit; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::symbol::sym; -use rustc_span::{BytePos, ExpnKind, Span, DUMMY_SP}; +use rustc_span::{BytePos, ExpnKind, Span, Symbol, DUMMY_SP}; use std::borrow::Cow; use std::fmt; use std::iter; @@ -1008,6 +1008,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { return; } let self_ty = trait_ref.self_ty(); + let found_ty = trait_ref.args.get(1).and_then(|a| a.as_type()); let mut prev_ty = self.resolve_vars_if_possible( typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), @@ -1033,17 +1034,76 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // The following logic is simlar to `point_at_chain`, but that's focused on associated types let mut expr = expr; - while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, span) = expr.kind { + while let hir::ExprKind::MethodCall(path_segment, rcvr_expr, args, span) = expr.kind { // Point at every method call in the chain with the `Result` type. // let foo = bar.iter().map(mapper)?; // ------ ----------- expr = rcvr_expr; chain.push((span, prev_ty)); - prev_ty = self.resolve_vars_if_possible( + let next_ty = self.resolve_vars_if_possible( typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), ); + let is_diagnostic_item = |symbol: Symbol, ty: Ty<'tcx>| { + let ty::Adt(def, _) = ty.kind() else { + return false; + }; + self.tcx.is_diagnostic_item(symbol, def.did()) + }; + // For each method in the chain, see if this is `Result::map_err` or + // `Option::ok_or_else` and if it is, see if the closure passed to it has an incorrect + // trailing `;`. + // Ideally we would instead use `FnCtxt::lookup_method_for_diagnostic` for 100% + // accurate check, but we are in the wrong stage to do that and looking for + // `Result::map_err` by checking the Self type and the path segment is enough. + // sym::ok_or_else + if let Some(ty) = get_e_type(prev_ty) + && let Some(found_ty) = found_ty + && ( + ( + path_segment.ident.name == sym::map_err + && is_diagnostic_item(sym::Result, next_ty) + ) || ( + path_segment.ident.name == sym::ok_or_else + && is_diagnostic_item(sym::Option, next_ty) + ) + ) + && [sym::map_err, sym::ok_or_else].contains(&path_segment.ident.name) + && let ty::Tuple(tys) = found_ty.kind() + && tys.is_empty() + && self.can_eq(obligation.param_env, ty, found_ty) + && args.len() == 1 + && let Some(arg) = args.get(0) + && let hir::ExprKind::Closure(closure) = arg.kind + && let body = self.tcx.hir().body(closure.body) + && let hir::ExprKind::Block(block, _) = body.value.kind + && let None = block.expr + && let [.., stmt] = block.stmts + && let hir::StmtKind::Semi(expr) = stmt.kind + && let expr_ty = self.resolve_vars_if_possible( + typeck.expr_ty_adjusted_opt(expr) + .unwrap_or(Ty::new_misc_error(self.tcx)), + ) + && self + .infcx + .type_implements_trait( + self.tcx.get_diagnostic_item(sym::From).unwrap(), + [self_ty, expr_ty], + obligation.param_env, + ) + .must_apply_modulo_regions() + { + err.span_suggestion_short( + stmt.span.with_lo(expr.span.hi()), + "remove this semicolon", + String::new(), + Applicability::MachineApplicable, + ); + } + + prev_ty = next_ty; + if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id) diff --git a/tests/ui/traits/question-mark-result-err-mismatch.rs b/tests/ui/traits/question-mark-result-err-mismatch.rs index e5ccca2e5f7c7..317029e004613 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.rs +++ b/tests/ui/traits/question-mark-result-err-mismatch.rs @@ -8,7 +8,9 @@ fn foo() -> Result { //~ NOTE expected `String` because of this }); let one = x .map(|s| ()) - .map_err(|_| ()) //~ NOTE this can't be annotated with `?` because it has type `Result<_, ()>` + .map_err(|e| { //~ NOTE this can't be annotated with `?` because it has type `Result<_, ()>` + e; //~ HELP remove this semicolon + }) .map(|()| "")?; //~ ERROR `?` couldn't convert the error to `String` //~^ NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` @@ -17,6 +19,7 @@ fn foo() -> Result { //~ NOTE expected `String` because of this //~| NOTE the trait `From<()>` is not implemented for `String` //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait //~| NOTE required for `Result` to implement `FromResidual>` + //~| HELP the following other types implement trait `From`: Ok(one.to_string()) } @@ -33,6 +36,7 @@ fn bar() -> Result<(), String> { //~ NOTE expected `String` because of this //~| NOTE the trait `From<()>` is not implemented for `String` //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait //~| NOTE required for `Result<(), String>` to implement `FromResidual>` + //~| HELP the following other types implement trait `From`: Ok(one) } @@ -42,7 +46,7 @@ fn baz() -> Result { //~ NOTE expected `String` because of this .split_whitespace() .next() .ok_or_else(|| { //~ NOTE this can't be annotated with `?` because it has type `Result<_, ()>` - "Couldn't split the test string"; + "Couldn't split the test string"; //~ HELP remove this semicolon })?; //~^ ERROR `?` couldn't convert the error to `String` //~| NOTE in this expansion of desugaring of operator `?` @@ -52,6 +56,7 @@ fn baz() -> Result { //~ NOTE expected `String` because of this //~| NOTE the trait `From<()>` is not implemented for `String` //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait //~| NOTE required for `Result` to implement `FromResidual>` + //~| HELP the following other types implement trait `From`: Ok(one.to_string()) } diff --git a/tests/ui/traits/question-mark-result-err-mismatch.stderr b/tests/ui/traits/question-mark-result-err-mismatch.stderr index fc3b2e6b46b38..1f9495a505ac3 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.stderr +++ b/tests/ui/traits/question-mark-result-err-mismatch.stderr @@ -1,5 +1,5 @@ error[E0277]: `?` couldn't convert the error to `String` - --> $DIR/question-mark-result-err-mismatch.rs:12:22 + --> $DIR/question-mark-result-err-mismatch.rs:14:22 | LL | fn foo() -> Result { | ---------------------- expected `String` because of this @@ -10,8 +10,12 @@ LL | | "Couldn't split the test string" LL | | }); | |__________- this has type `Result<_, &str>` ... -LL | .map_err(|_| ()) - | --------------- this can't be annotated with `?` because it has type `Result<_, ()>` +LL | .map_err(|e| { + | __________- +LL | | e; + | | - help: remove this semicolon +LL | | }) + | |__________- this can't be annotated with `?` because it has type `Result<_, ()>` LL | .map(|()| "")?; | ^ the trait `From<()>` is not implemented for `String` | @@ -26,7 +30,7 @@ LL | .map(|()| "")?; = note: required for `Result` to implement `FromResidual>` error[E0277]: `?` couldn't convert the error to `String` - --> $DIR/question-mark-result-err-mismatch.rs:27:25 + --> $DIR/question-mark-result-err-mismatch.rs:30:25 | LL | fn bar() -> Result<(), String> { | ------------------ expected `String` because of this @@ -49,7 +53,7 @@ LL | .map_err(|_| ())?; = note: required for `Result<(), String>` to implement `FromResidual>` error[E0277]: `?` couldn't convert the error to `String` - --> $DIR/question-mark-result-err-mismatch.rs:46:11 + --> $DIR/question-mark-result-err-mismatch.rs:50:11 | LL | fn baz() -> Result { | ---------------------- expected `String` because of this @@ -57,6 +61,7 @@ LL | fn baz() -> Result { LL | .ok_or_else(|| { | __________- LL | | "Couldn't split the test string"; + | | - help: remove this semicolon LL | | })?; | | -^ the trait `From<()>` is not implemented for `String` | |__________| From cc49398f9724d3357b2f6128ad0b2b5918f05c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 7 Oct 2023 03:58:45 +0000 Subject: [PATCH 06/29] Reduce verbosity of error --- .../error_reporting/type_err_ctxt_ext.rs | 37 +++++++++++-------- .../question-mark-result-err-mismatch.rs | 6 +-- .../question-mark-result-err-mismatch.stderr | 24 +----------- 3 files changed, 24 insertions(+), 43 deletions(-) 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 d9a2fd1810545..89fee338a8b05 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 @@ -106,7 +106,7 @@ pub trait TypeErrCtxtExt<'tcx> { obligation: &PredicateObligation<'tcx>, trait_ref: ty::TraitRef<'tcx>, err: &mut Diagnostic, - ); + ) -> bool; fn report_const_param_not_wf( &self, @@ -507,8 +507,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut err = struct_span_err!(self.tcx.sess, span, E0277, "{}", err_msg); + let mut suggested = false; if is_try_conversion { - self.try_conversion_context(&obligation, trait_ref.skip_binder(), &mut err); + suggested = self.try_conversion_context(&obligation, trait_ref.skip_binder(), &mut err); } if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) { @@ -611,8 +612,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref); self.suggest_dereferencing_index(&obligation, &mut err, trait_predicate); - let mut suggested = - self.suggest_dereferences(&obligation, &mut err, trait_predicate); + suggested |= self.suggest_dereferences(&obligation, &mut err, trait_predicate); suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate); let impl_candidates = self.find_similar_impl_candidates(trait_predicate); suggested = if let &[cand] = &impl_candidates[..] { @@ -965,7 +965,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { obligation: &PredicateObligation<'tcx>, trait_ref: ty::TraitRef<'tcx>, err: &mut Diagnostic, - ) { + ) -> bool { let span = obligation.cause.span; struct V<'v> { search_span: Span, @@ -990,22 +990,22 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) => { body_id } - _ => return, + _ => return false, }; let mut v = V { search_span: span, found: None }; v.visit_body(self.tcx.hir().body(*body_id)); let Some(expr) = v.found else { - return; + return false; }; let Some(typeck) = &self.typeck_results else { - return; + return false; }; let Some((ObligationCauseCode::QuestionMark, Some(y))) = obligation.cause.code().parent() else { - return; + return false; }; if !self.tcx.is_diagnostic_item(sym::FromResidual, y.def_id()) { - return; + return false; } let self_ty = trait_ref.self_ty(); let found_ty = trait_ref.args.get(1).and_then(|a| a.as_type()); @@ -1030,6 +1030,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { Some(arg.as_type()?) }; + let mut suggested = false; let mut chain = vec![]; // The following logic is simlar to `point_at_chain`, but that's focused on associated types @@ -1094,6 +1095,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) .must_apply_modulo_regions() { + suggested = true; err.span_suggestion_short( stmt.span.with_lo(expr.span.hi()), "remove this semicolon", @@ -1150,17 +1152,20 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) .must_apply_modulo_regions() { - err.span_label(span, format!("this has type `Result<_, {err_ty}>`")); + if !suggested { + err.span_label(span, format!("this has type `Result<_, {err_ty}>`")); + } } else { err.span_label( - span, - format!( - "this can't be annotated with `?` because it has type `Result<_, {err_ty}>`", - ), - ); + span, + format!( + "this can't be annotated with `?` because it has type `Result<_, {err_ty}>`", + ), + ); } prev = Some(err_ty); } + suggested } fn report_const_param_not_wf( diff --git a/tests/ui/traits/question-mark-result-err-mismatch.rs b/tests/ui/traits/question-mark-result-err-mismatch.rs index 317029e004613..0ca18b5b0ddce 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.rs +++ b/tests/ui/traits/question-mark-result-err-mismatch.rs @@ -3,7 +3,7 @@ fn foo() -> Result { //~ NOTE expected `String` because of this let x = test .split_whitespace() .next() - .ok_or_else(|| { //~ NOTE this has type `Result<_, &str>` + .ok_or_else(|| { "Couldn't split the test string" }); let one = x @@ -15,11 +15,9 @@ fn foo() -> Result { //~ NOTE expected `String` because of this //~^ NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE the trait `From<()>` is not implemented for `String` //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait //~| NOTE required for `Result` to implement `FromResidual>` - //~| HELP the following other types implement trait `From`: Ok(one.to_string()) } @@ -52,11 +50,9 @@ fn baz() -> Result { //~ NOTE expected `String` because of this //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE the trait `From<()>` is not implemented for `String` //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait //~| NOTE required for `Result` to implement `FromResidual>` - //~| HELP the following other types implement trait `From`: Ok(one.to_string()) } diff --git a/tests/ui/traits/question-mark-result-err-mismatch.stderr b/tests/ui/traits/question-mark-result-err-mismatch.stderr index 1f9495a505ac3..3059e0beca3e4 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.stderr +++ b/tests/ui/traits/question-mark-result-err-mismatch.stderr @@ -4,12 +4,6 @@ error[E0277]: `?` couldn't convert the error to `String` LL | fn foo() -> Result { | ---------------------- expected `String` because of this ... -LL | .ok_or_else(|| { - | __________- -LL | | "Couldn't split the test string" -LL | | }); - | |__________- this has type `Result<_, &str>` -... LL | .map_err(|e| { | __________- LL | | e; @@ -20,17 +14,10 @@ LL | .map(|()| "")?; | ^ the trait `From<()>` is not implemented for `String` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = help: the following other types implement trait `From`: - > - >> - >> - > - > - > = note: required for `Result` to implement `FromResidual>` error[E0277]: `?` couldn't convert the error to `String` - --> $DIR/question-mark-result-err-mismatch.rs:30:25 + --> $DIR/question-mark-result-err-mismatch.rs:28:25 | LL | fn bar() -> Result<(), String> { | ------------------ expected `String` because of this @@ -53,7 +40,7 @@ LL | .map_err(|_| ())?; = note: required for `Result<(), String>` to implement `FromResidual>` error[E0277]: `?` couldn't convert the error to `String` - --> $DIR/question-mark-result-err-mismatch.rs:50:11 + --> $DIR/question-mark-result-err-mismatch.rs:48:11 | LL | fn baz() -> Result { | ---------------------- expected `String` because of this @@ -68,13 +55,6 @@ LL | | })?; | this can't be annotated with `?` because it has type `Result<_, ()>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = help: the following other types implement trait `From`: - > - >> - >> - > - > - > = note: required for `Result` to implement `FromResidual>` error: aborting due to 3 previous errors From d92c2b5ec16e4e77052c3c815f0331cff5635641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 7 Oct 2023 04:55:20 +0000 Subject: [PATCH 07/29] add comments --- .../error_reporting/type_err_ctxt_ext.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) 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 89fee338a8b05..abe589b5ab210 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 @@ -1055,31 +1055,35 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // For each method in the chain, see if this is `Result::map_err` or // `Option::ok_or_else` and if it is, see if the closure passed to it has an incorrect // trailing `;`. - // Ideally we would instead use `FnCtxt::lookup_method_for_diagnostic` for 100% - // accurate check, but we are in the wrong stage to do that and looking for - // `Result::map_err` by checking the Self type and the path segment is enough. - // sym::ok_or_else if let Some(ty) = get_e_type(prev_ty) && let Some(found_ty) = found_ty + // Ideally we would instead use `FnCtxt::lookup_method_for_diagnostic` for 100% + // accurate check, but we are in the wrong stage to do that and looking for + // `Result::map_err` by checking the Self type and the path segment is enough. + // sym::ok_or_else && ( - ( + ( // Result::map_err path_segment.ident.name == sym::map_err && is_diagnostic_item(sym::Result, next_ty) - ) || ( + ) || ( // Option::ok_or_else path_segment.ident.name == sym::ok_or_else && is_diagnostic_item(sym::Option, next_ty) ) ) - && [sym::map_err, sym::ok_or_else].contains(&path_segment.ident.name) + // Found `Result<_, ()>?` && let ty::Tuple(tys) = found_ty.kind() && tys.is_empty() + // The current method call returns `Result<_, ()>` && self.can_eq(obligation.param_env, ty, found_ty) + // There's a single argument in the method call and it is a closure && args.len() == 1 && let Some(arg) = args.get(0) && let hir::ExprKind::Closure(closure) = arg.kind + // The closure has a block for its body with no tail expression && let body = self.tcx.hir().body(closure.body) && let hir::ExprKind::Block(block, _) = body.value.kind && let None = block.expr + // The last statement is of a type that can be converted to the return error type && let [.., stmt] = block.stmts && let hir::StmtKind::Semi(expr) = stmt.kind && let expr_ty = self.resolve_vars_if_possible( From cce82d862cc422707073f9ed80e7695f9c44ff8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 16 Nov 2023 17:01:21 +0000 Subject: [PATCH 08/29] let-chain fmt --- .../src/traits/error_reporting/suggestions.rs | 18 ++++++++---------- .../error_reporting/type_err_ctxt_ext.rs | 4 +++- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 939c06a1191fd..9bd1030ac74fa 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -3640,16 +3640,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { && let Some(failed_pred) = failed_pred.to_opt_poly_projection_pred() && let Some(found) = failed_pred.skip_binder().term.ty() { - type_diffs = vec![ - Sorts(ty::error::ExpectedFound { - expected: Ty::new_alias( - self.tcx, - ty::Projection, - where_pred.skip_binder().projection_ty, - ), - found, - }), - ]; + type_diffs = vec![Sorts(ty::error::ExpectedFound { + expected: Ty::new_alias( + self.tcx, + ty::Projection, + where_pred.skip_binder().projection_ty, + ), + found, + })]; } } if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind 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 abe589b5ab210..cfc9d32498e87 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 @@ -1116,7 +1116,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { && let Some(parent) = self.tcx.hir().find_parent(binding.hir_id) { // We've reached the root of the method call chain... - if let hir::Node::Local(local) = parent && let Some(binding_expr) = local.init { + if let hir::Node::Local(local) = parent + && let Some(binding_expr) = local.init + { // ...and it is a binding. Get the binding creation and continue the chain. expr = binding_expr; } From d1583eba66bf1ccb65c3aeaa5de30bcc90ae208c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 21 Nov 2023 08:00:26 +0100 Subject: [PATCH 09/29] lib features ending in '_internals?' are internal --- compiler/rustc_feature/src/unstable.rs | 18 ++++++++++++------ tests/ui/lint/internal_features.rs | 11 +++++++++++ tests/ui/lint/internal_features.stderr | 23 +++++++++++++++++++++++ 3 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 tests/ui/lint/internal_features.rs create mode 100644 tests/ui/lint/internal_features.stderr diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index b11b190bdedad..40611102250b2 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -54,8 +54,10 @@ macro_rules! declare_features { #[derive(Clone, Default, Debug)] pub struct Features { /// `#![feature]` attrs for language features, for error reporting. + /// "declared" here means that the feature is actually enabled in the current crate. pub declared_lang_features: Vec<(Symbol, Span, Option)>, /// `#![feature]` attrs for non-language (library) features. + /// "declared" here means that the feature is actually enabled in the current crate. pub declared_lib_features: Vec<(Symbol, Span)>, /// `declared_lang_features` + `declared_lib_features`. pub declared_features: FxHashSet, @@ -125,9 +127,16 @@ macro_rules! declare_features { $( sym::$feature => status_to_enum!($status) == FeatureStatus::Internal, )* - // Accepted/removed features aren't in this file but are never internal - // (a removed feature might have been internal, but that's now irrelevant). - _ if self.declared_features.contains(&feature) => false, + _ if self.declared_features.contains(&feature) => { + // This could be accepted/removed, or a libs feature. + // Accepted/removed features aren't in this file but are never internal + // (a removed feature might have been internal, but that's now irrelevant). + // Libs features are internal if they end in `_internal` or `_internals`. + // We just always test the name; it's not a big deal if we accidentally hit + // an accepted/removed lang feature that way. + let name = feature.as_str(); + name.ends_with("_internal") || name.ends_with("_internals") + } _ => panic!("`{}` was not listed in `declare_features`", feature), } } @@ -207,9 +216,6 @@ declare_features! ( (internal, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)), /// Added for testing unstable lints; perma-unstable. (internal, test_unstable_lint, "1.60.0", None, None), - /// Allows non-`unsafe` —and thus, unsound— access to `Pin` constructions. - /// Marked `internal` since perma-unstable and unsound. - (internal, unsafe_pin_internals, "1.60.0", None, None), /// Use for stable + negative coherence and strict coherence depending on trait's /// rustc_strict_coherence value. (unstable, with_negative_coherence, "1.60.0", None, None), diff --git a/tests/ui/lint/internal_features.rs b/tests/ui/lint/internal_features.rs new file mode 100644 index 0000000000000..32ce9540cb364 --- /dev/null +++ b/tests/ui/lint/internal_features.rs @@ -0,0 +1,11 @@ +#![forbid(internal_features)] +// A lang feature and a lib feature. +#![feature(intrinsics, panic_internals)] +//~^ ERROR: internal +//~| ERROR: internal + +extern "rust-intrinsic" { + fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); +} + +fn main() {} diff --git a/tests/ui/lint/internal_features.stderr b/tests/ui/lint/internal_features.stderr new file mode 100644 index 0000000000000..8b52bef8f033b --- /dev/null +++ b/tests/ui/lint/internal_features.stderr @@ -0,0 +1,23 @@ +error: the feature `intrinsics` is internal to the compiler or standard library + --> $DIR/internal_features.rs:3:12 + | +LL | #![feature(intrinsics, panic_internals)] + | ^^^^^^^^^^ + | + = note: using it is strongly discouraged +note: the lint level is defined here + --> $DIR/internal_features.rs:1:11 + | +LL | #![forbid(internal_features)] + | ^^^^^^^^^^^^^^^^^ + +error: the feature `panic_internals` is internal to the compiler or standard library + --> $DIR/internal_features.rs:3:24 + | +LL | #![feature(intrinsics, panic_internals)] + | ^^^^^^^^^^^^^^^ + | + = note: using it is strongly discouraged + +error: aborting due to 2 previous errors + From 74834a9d74ce2a26bf0ee609ce2790299226f742 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 22 Nov 2023 07:30:09 +0100 Subject: [PATCH 10/29] also make 'core_intrinsics' internal --- compiler/rustc_feature/src/unstable.rs | 4 +++- compiler/rustc_query_system/src/lib.rs | 2 +- library/alloc/tests/lib.rs | 1 + library/core/src/intrinsics.rs | 7 +++++++ library/core/tests/lib.rs | 1 + src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs | 2 +- 6 files changed, 14 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 40611102250b2..b4a7ea203fda6 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -132,10 +132,12 @@ macro_rules! declare_features { // Accepted/removed features aren't in this file but are never internal // (a removed feature might have been internal, but that's now irrelevant). // Libs features are internal if they end in `_internal` or `_internals`. + // As a special exception we also consider `core_intrinsics` internal; + // renaming that age-old feature is just not worth the hassle. // We just always test the name; it's not a big deal if we accidentally hit // an accepted/removed lang feature that way. let name = feature.as_str(); - name.ends_with("_internal") || name.ends_with("_internals") + name == "core_intrinsics" || name.ends_with("_internal") || name.ends_with("_internals") } _ => panic!("`{}` was not listed in `declare_features`", feature), } diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 2ed420f356439..1e317f9ce3336 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -3,7 +3,7 @@ #![feature(hash_raw_entry)] #![feature(min_specialization)] #![feature(let_chains)] -#![allow(rustc::potential_query_instability)] +#![allow(rustc::potential_query_instability, internal_features)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 6d5c17ef02303..af825e40bafbb 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -40,6 +40,7 @@ #![feature(thin_box)] #![feature(strict_provenance)] #![feature(drain_keep_rest)] +#![allow(internal_features)] #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index f25ca9e2b1866..43e316c662b05 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1900,6 +1900,7 @@ extern "rust-intrinsic" { /// /// ``` /// #![feature(core_intrinsics)] + /// # #![allow(internal_features)] /// /// use std::intrinsics::ctlz; /// @@ -1912,6 +1913,7 @@ extern "rust-intrinsic" { /// /// ``` /// #![feature(core_intrinsics)] + /// # #![allow(internal_features)] /// /// use std::intrinsics::ctlz; /// @@ -1933,6 +1935,7 @@ extern "rust-intrinsic" { /// /// ``` /// #![feature(core_intrinsics)] + /// # #![allow(internal_features)] /// /// use std::intrinsics::ctlz_nonzero; /// @@ -1959,6 +1962,7 @@ extern "rust-intrinsic" { /// /// ``` /// #![feature(core_intrinsics)] + /// # #![allow(internal_features)] /// /// use std::intrinsics::cttz; /// @@ -1971,6 +1975,7 @@ extern "rust-intrinsic" { /// /// ``` /// #![feature(core_intrinsics)] + /// # #![allow(internal_features)] /// /// use std::intrinsics::cttz; /// @@ -1992,6 +1997,7 @@ extern "rust-intrinsic" { /// /// ``` /// #![feature(core_intrinsics)] + /// # #![allow(internal_features)] /// /// use std::intrinsics::cttz_nonzero; /// @@ -2453,6 +2459,7 @@ extern "rust-intrinsic" { /// ```no_run /// #![feature(const_eval_select)] /// #![feature(core_intrinsics)] + /// # #![allow(internal_features)] /// use std::hint::unreachable_unchecked; /// use std::intrinsics::const_eval_select; /// diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index c167240ba2439..0f8583c443563 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -116,6 +116,7 @@ #![feature(get_many_mut)] #![feature(offset_of)] #![feature(iter_map_windows)] +#![allow(internal_features)] #![deny(unsafe_op_in_unsafe_fn)] #![deny(fuzzy_provenance_casts)] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 84bd15efb8bee..58833cb7e9264 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -13,7 +13,7 @@ #![cfg(feature = "sysroot-abi")] #![feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span)] #![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] -#![allow(unreachable_pub)] +#![allow(unreachable_pub, internal_features)] extern crate proc_macro; From 114380d215931bef6037e2c9b16397a3071a1800 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 1 Dec 2023 14:08:10 +1100 Subject: [PATCH 11/29] Give `Handler::fatal` and `Session::fatal` the same return type. Currently, `Handler::fatal` returns `FatalError`. But `Session::fatal` returns `!`, because it calls `Handler::fatal` and then calls `raise` on the result. This inconsistency is unfortunate. This commit changes `Handler::fatal` to do the `raise` itself, changing its return type to `!`. This is safe because there are only two calls to `Handler::fatal`, one in `rustc_session` and one in `rustc_codegen_cranelift`, and they both call `raise` on the result. `HandlerInner::fatal` still returns `FatalError`, so I renamed it `fatal_no_raise` to emphasise the return type difference. --- .../src/concurrency_limiter.rs | 2 +- compiler/rustc_errors/src/lib.rs | 13 +++++++------ compiler/rustc_session/src/session.rs | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs index 20f2ee4c76a57..978891f2b0db5 100644 --- a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs +++ b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs @@ -64,7 +64,7 @@ impl ConcurrencyLimiter { // Make sure to drop the mutex guard first to prevent poisoning the mutex. drop(state); if let Some(err) = err { - handler.fatal(err).raise(); + handler.fatal(err); } else { // The error was already emitted, but compilation continued. Raise a silent // fatal error. diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 5966fd80f979b..383bec2fa8fc9 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1034,10 +1034,9 @@ impl Handler { db } - // NOTE: intentionally doesn't raise an error so rustc_codegen_ssa only reports fatal errors in the main thread #[rustc_lint_diagnostics] - pub fn fatal(&self, msg: impl Into) -> FatalError { - self.inner.borrow_mut().fatal(msg) + pub fn fatal(&self, msg: impl Into) -> ! { + self.inner.borrow_mut().fatal_no_raise(msg).raise() } #[rustc_lint_diagnostics] @@ -1469,10 +1468,10 @@ impl HandlerInner { DiagnosticMessage::Str(warnings), )), (_, 0) => { - let _ = self.fatal(errors); + let _ = self.fatal_no_raise(errors); } (_, _) => { - let _ = self.fatal(format!("{errors}; {warnings}")); + let _ = self.fatal_no_raise(format!("{errors}; {warnings}")); } } @@ -1631,7 +1630,9 @@ impl HandlerInner { self.emit_diagnostic(&mut Diagnostic::new(FailureNote, msg)); } - fn fatal(&mut self, msg: impl Into) -> FatalError { + // Note: unlike `Handler::fatal`, this doesn't return `!`, because that is + // inappropriate for some of its call sites. + fn fatal_no_raise(&mut self, msg: impl Into) -> FatalError { self.emit(Fatal, msg); FatalError } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index c6f435a8f9204..a53160a5ab4a0 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -461,7 +461,7 @@ impl Session { } #[rustc_lint_diagnostics] pub fn fatal(&self, msg: impl Into) -> ! { - self.diagnostic().fatal(msg).raise() + self.diagnostic().fatal(msg) } #[rustc_lint_diagnostics] #[track_caller] From d4933aaf1fe182e32058928354b86b92f539c19b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 3 Dec 2023 22:01:57 +1100 Subject: [PATCH 12/29] Inline and remove `DiagnosticBuilder::new_diagnostic_*` functions. They each have a single call site. --- .../rustc_errors/src/diagnostic_builder.rs | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 3823a1707ec77..df40dda7f8994 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -254,13 +254,6 @@ impl<'a> DiagnosticBuilder<'a, Noted> { /// `struct_*` methods on [`Handler`]. pub(crate) fn new_note(handler: &'a Handler, message: impl Into) -> Self { let diagnostic = Diagnostic::new_with_code(Level::Note, None, message); - Self::new_diagnostic_note(handler, diagnostic) - } - - /// Creates a new `DiagnosticBuilder` with an already constructed - /// diagnostic. - pub(crate) fn new_diagnostic_note(handler: &'a Handler, diagnostic: Diagnostic) -> Self { - debug!("Created new diagnostic"); Self { inner: DiagnosticBuilderInner { state: DiagnosticBuilderState::Emittable(handler), @@ -305,13 +298,6 @@ impl<'a> DiagnosticBuilder<'a, Bug> { #[track_caller] pub(crate) fn new_bug(handler: &'a Handler, message: impl Into) -> Self { let diagnostic = Diagnostic::new_with_code(Level::Bug, None, message); - Self::new_diagnostic_bug(handler, diagnostic) - } - - /// Creates a new `DiagnosticBuilder` with an already constructed - /// diagnostic. - pub(crate) fn new_diagnostic_bug(handler: &'a Handler, diagnostic: Diagnostic) -> Self { - debug!("Created new diagnostic bug"); Self { inner: DiagnosticBuilderInner { state: DiagnosticBuilderState::Emittable(handler), @@ -394,16 +380,6 @@ impl<'a> DiagnosticBuilder<'a, rustc_span::fatal_error::FatalError> { message: impl Into, ) -> Self { let diagnostic = Diagnostic::new_with_code(Level::Fatal, None, message); - Self::new_diagnostic_almost_fatal(handler, diagnostic) - } - - /// Creates a new `DiagnosticBuilder` with an already constructed - /// diagnostic. - pub(crate) fn new_diagnostic_almost_fatal( - handler: &'a Handler, - diagnostic: Diagnostic, - ) -> Self { - debug!("Created new diagnostic"); Self { inner: DiagnosticBuilderInner { state: DiagnosticBuilderState::Emittable(handler), From ab640ca86b5915703b6adb75710dd57d3144def5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 3 Dec 2023 22:26:34 +1100 Subject: [PATCH 13/29] Inline and remove more `DiagnosticBuilder::new_diagnostic_*` functions. They each have a single call site. Note: the `make_diagnostic_builder` calls in `lib.rs` will be replaced in a subsequent commit. --- .../rustc_errors/src/diagnostic_builder.rs | 105 +++++------------- compiler/rustc_errors/src/lib.rs | 6 +- 2 files changed, 28 insertions(+), 83 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index df40dda7f8994..5e0d8c8b89340 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -116,26 +116,6 @@ pub trait EmissionGuarantee: Sized { } impl<'a> DiagnosticBuilder<'a, ErrorGuaranteed> { - /// Convenience function for internal use, clients should use one of the - /// `struct_*` methods on [`Handler`]. - #[track_caller] - pub(crate) fn new_guaranteeing_error>( - handler: &'a Handler, - message: M, - ) -> Self { - Self { - inner: DiagnosticBuilderInner { - state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(Diagnostic::new_with_code( - Level::Error { lint: false }, - None, - message, - )), - }, - _marker: PhantomData, - } - } - /// Discard the guarantee `.emit()` would return, in favor of having the /// type `DiagnosticBuilder<'a, ()>`. This may be necessary whenever there /// is a common codepath handling both errors and warnings. @@ -189,7 +169,13 @@ impl EmissionGuarantee for ErrorGuaranteed { handler: &Handler, msg: impl Into, ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder::new_guaranteeing_error(handler, msg) + DiagnosticBuilder { + inner: DiagnosticBuilderInner { + state: DiagnosticBuilderState::Emittable(handler), + diagnostic: Box::new(Diagnostic::new(Level::Error { lint: false }, msg)), + }, + _marker: PhantomData, + } } } @@ -249,21 +235,6 @@ impl EmissionGuarantee for () { #[derive(Copy, Clone)] pub struct Noted; -impl<'a> DiagnosticBuilder<'a, Noted> { - /// Convenience function for internal use, clients should use one of the - /// `struct_*` methods on [`Handler`]. - pub(crate) fn new_note(handler: &'a Handler, message: impl Into) -> Self { - let diagnostic = Diagnostic::new_with_code(Level::Note, None, message); - Self { - inner: DiagnosticBuilderInner { - state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(diagnostic), - }, - _marker: PhantomData, - } - } -} - impl EmissionGuarantee for Noted { fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self { match db.inner.state { @@ -283,31 +254,21 @@ impl EmissionGuarantee for Noted { handler: &Handler, msg: impl Into, ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder::new_note(handler, msg) - } -} - -/// Marker type which enables implementation of `create_bug` and `emit_bug` functions for -/// bug struct diagnostics. -#[derive(Copy, Clone)] -pub struct Bug; - -impl<'a> DiagnosticBuilder<'a, Bug> { - /// Convenience function for internal use, clients should use one of the - /// `struct_*` methods on [`Handler`]. - #[track_caller] - pub(crate) fn new_bug(handler: &'a Handler, message: impl Into) -> Self { - let diagnostic = Diagnostic::new_with_code(Level::Bug, None, message); - Self { + DiagnosticBuilder { inner: DiagnosticBuilderInner { state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(diagnostic), + diagnostic: Box::new(Diagnostic::new_with_code(Level::Note, None, msg)), }, _marker: PhantomData, } } } +/// Marker type which enables implementation of `create_bug` and `emit_bug` functions for +/// bug struct diagnostics. +#[derive(Copy, Clone)] +pub struct Bug; + impl EmissionGuarantee for Bug { fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self { match db.inner.state { @@ -328,19 +289,10 @@ impl EmissionGuarantee for Bug { handler: &Handler, msg: impl Into, ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder::new_bug(handler, msg) - } -} - -impl<'a> DiagnosticBuilder<'a, !> { - /// Convenience function for internal use, clients should use one of the - /// `struct_*` methods on [`Handler`]. - #[track_caller] - pub(crate) fn new_fatal(handler: &'a Handler, message: impl Into) -> Self { - Self { + DiagnosticBuilder { inner: DiagnosticBuilderInner { state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(Diagnostic::new_with_code(Level::Fatal, None, message)), + diagnostic: Box::new(Diagnostic::new_with_code(Level::Bug, None, msg)), }, _marker: PhantomData, } @@ -367,23 +319,10 @@ impl EmissionGuarantee for ! { handler: &Handler, msg: impl Into, ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder::new_fatal(handler, msg) - } -} - -impl<'a> DiagnosticBuilder<'a, rustc_span::fatal_error::FatalError> { - /// Convenience function for internal use, clients should use one of the - /// `struct_*` methods on [`Handler`]. - #[track_caller] - pub(crate) fn new_almost_fatal( - handler: &'a Handler, - message: impl Into, - ) -> Self { - let diagnostic = Diagnostic::new_with_code(Level::Fatal, None, message); - Self { + DiagnosticBuilder { inner: DiagnosticBuilderInner { state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(diagnostic), + diagnostic: Box::new(Diagnostic::new_with_code(Level::Fatal, None, msg)), }, _marker: PhantomData, } @@ -410,7 +349,13 @@ impl EmissionGuarantee for rustc_span::fatal_error::FatalError { handler: &Handler, msg: impl Into, ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder::new_almost_fatal(handler, msg) + DiagnosticBuilder { + inner: DiagnosticBuilderInner { + state: DiagnosticBuilderState::Emittable(handler), + diagnostic: Box::new(Diagnostic::new_with_code(Level::Fatal, None, msg)), + }, + _marker: PhantomData, + } } } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 383bec2fa8fc9..d9baadc68d77d 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -776,7 +776,7 @@ impl Handler { #[rustc_lint_diagnostics] #[track_caller] pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { - DiagnosticBuilder::new(self, Level::Warning(None), msg) + <()>::make_diagnostic_builder(self, msg) } /// Construct a builder at the `Warning` level with the `msg`. The `id` is used for @@ -847,7 +847,7 @@ impl Handler { &self, msg: impl Into, ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - DiagnosticBuilder::new_guaranteeing_error(self, msg) + ErrorGuaranteed::make_diagnostic_builder(self, msg) } /// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors. @@ -914,7 +914,7 @@ impl Handler { #[rustc_lint_diagnostics] #[track_caller] pub fn struct_fatal(&self, msg: impl Into) -> DiagnosticBuilder<'_, !> { - DiagnosticBuilder::new_fatal(self, msg) + ::make_diagnostic_builder(self, msg) } /// Construct a builder at the `Help` level with the `msg`. From 6a95dee395b65ecf68712a987df1a2d60debd597 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 4 Dec 2023 08:43:18 +1100 Subject: [PATCH 14/29] Rename some arguments. `sess` is a terribly misleading name for a `Handler`! This confused me for a bit. --- compiler/rustc_codegen_gcc/src/errors.rs | 4 ++-- compiler/rustc_codegen_llvm/src/errors.rs | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index 4bf3b71f503d6..5fc4b12d7e699 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs @@ -111,8 +111,8 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> { pub(crate) struct MissingFeatures; impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> { - fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = sess.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable); + fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = handler.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable); if let Some(span) = self.span { diag.set_span(span); }; diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 10ca5ad802a05..e5407ba4dd12e 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -102,12 +102,12 @@ pub(crate) struct DynamicLinkingWithLTO; pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>); impl IntoDiagnostic<'_, EM> for ParseTargetMachineConfig<'_> { - fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, EM> { - let diag: DiagnosticBuilder<'_, EM> = self.0.into_diagnostic(sess); + fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, EM> { + let diag: DiagnosticBuilder<'_, EM> = self.0.into_diagnostic(handler); let (message, _) = diag.styled_message().first().expect("`LlvmError` with no message"); - let message = sess.eagerly_translate_to_string(message.clone(), diag.args()); + let message = handler.eagerly_translate_to_string(message.clone(), diag.args()); - let mut diag = sess.struct_diagnostic(fluent::codegen_llvm_parse_target_machine_config); + let mut diag = handler.struct_diagnostic(fluent::codegen_llvm_parse_target_machine_config); diag.set_arg("error", message); diag } @@ -124,8 +124,8 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> { pub(crate) struct MissingFeatures; impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> { - fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = sess.struct_err(fluent::codegen_llvm_target_feature_disable_or_enable); + fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = handler.struct_err(fluent::codegen_llvm_target_feature_disable_or_enable); if let Some(span) = self.span { diag.set_span(span); }; @@ -184,7 +184,7 @@ pub enum LlvmError<'a> { pub(crate) struct WithLlvmError<'a>(pub LlvmError<'a>, pub String); impl IntoDiagnostic<'_, EM> for WithLlvmError<'_> { - fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, EM> { + fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, EM> { use LlvmError::*; let msg_with_llvm_err = match &self.0 { WriteOutput { .. } => fluent::codegen_llvm_write_output_with_llvm_err, @@ -201,7 +201,7 @@ impl IntoDiagnostic<'_, EM> for WithLlvmError<'_> { PrepareThinLtoModule => fluent::codegen_llvm_prepare_thin_lto_module_with_llvm_err, ParseBitcode => fluent::codegen_llvm_parse_bitcode_with_llvm_err, }; - let mut diag = self.0.into_diagnostic(sess); + let mut diag = self.0.into_diagnostic(handler); diag.set_primary_message(msg_with_llvm_err); diag.set_arg("llvm_err", self.1); diag From ed95f397cf83a3ca52a66818963e3fd20d6705c3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 4 Dec 2023 08:46:50 +1100 Subject: [PATCH 15/29] Always use `G` for `EmissionGuarantee` type variables. That's what is mostly used. This commit changes a few `EM` and `E` and `T` type variables to `G`. --- compiler/rustc_codegen_llvm/src/errors.rs | 10 +++++----- compiler/rustc_errors/src/diagnostic_builder.rs | 12 ++++++------ compiler/rustc_session/src/errors.rs | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index e5407ba4dd12e..2ba337a8edf78 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -101,9 +101,9 @@ pub(crate) struct DynamicLinkingWithLTO; pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>); -impl IntoDiagnostic<'_, EM> for ParseTargetMachineConfig<'_> { - fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, EM> { - let diag: DiagnosticBuilder<'_, EM> = self.0.into_diagnostic(handler); +impl IntoDiagnostic<'_, G> for ParseTargetMachineConfig<'_> { + fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, G> { + let diag: DiagnosticBuilder<'_, G> = self.0.into_diagnostic(handler); let (message, _) = diag.styled_message().first().expect("`LlvmError` with no message"); let message = handler.eagerly_translate_to_string(message.clone(), diag.args()); @@ -183,8 +183,8 @@ pub enum LlvmError<'a> { pub(crate) struct WithLlvmError<'a>(pub LlvmError<'a>, pub String); -impl IntoDiagnostic<'_, EM> for WithLlvmError<'_> { - fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, EM> { +impl IntoDiagnostic<'_, G> for WithLlvmError<'_> { + fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, G> { use LlvmError::*; let msg_with_llvm_err = match &self.0 { WriteOutput { .. } => fluent::codegen_llvm_write_output_with_llvm_err, diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 5e0d8c8b89340..1366ef52261e1 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -18,18 +18,18 @@ use std::thread::panicking; /// Trait implemented by error types. This should not be implemented manually. Instead, use /// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic]. #[rustc_diagnostic_item = "IntoDiagnostic"] -pub trait IntoDiagnostic<'a, T: EmissionGuarantee = ErrorGuaranteed> { +pub trait IntoDiagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> { /// Write out as a diagnostic out of `Handler`. #[must_use] - fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, T>; + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G>; } -impl<'a, T, E> IntoDiagnostic<'a, E> for Spanned +impl<'a, T, G> IntoDiagnostic<'a, G> for Spanned where - T: IntoDiagnostic<'a, E>, - E: EmissionGuarantee, + T: IntoDiagnostic<'a, G>, + G: EmissionGuarantee, { - fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, E> { + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> { let mut diag = self.node.into_diagnostic(handler); diag.set_span(self.span); diag diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 70ee46ea902dc..f7934ce163d15 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -13,12 +13,12 @@ pub struct FeatureGateError { pub explain: DiagnosticMessage, } -impl<'a, T: EmissionGuarantee> IntoDiagnostic<'a, T> for FeatureGateError { +impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for FeatureGateError { #[track_caller] fn into_diagnostic( self, handler: &'a rustc_errors::Handler, - ) -> rustc_errors::DiagnosticBuilder<'a, T> { + ) -> rustc_errors::DiagnosticBuilder<'a, G> { let mut diag = handler.struct_diagnostic(self.explain); diag.set_span(self.span); diag.code(error_code!(E0658)); From 32dc78ede8c3e96475d2fbe818d25bb01faec3ad Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 4 Dec 2023 08:49:18 +1100 Subject: [PATCH 16/29] Avoid `Diagnostic::new_with_code(..., None, ...)`. `Diagnostic::new` can be used instead. --- compiler/rustc_errors/src/diagnostic_builder.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 1366ef52261e1..354fe1da2c998 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -188,7 +188,7 @@ impl<'a> DiagnosticBuilder<'a, ()> { level: Level, message: M, ) -> Self { - let diagnostic = Diagnostic::new_with_code(level, None, message); + let diagnostic = Diagnostic::new(level, message); Self::new_diagnostic(handler, diagnostic) } @@ -257,7 +257,7 @@ impl EmissionGuarantee for Noted { DiagnosticBuilder { inner: DiagnosticBuilderInner { state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(Diagnostic::new_with_code(Level::Note, None, msg)), + diagnostic: Box::new(Diagnostic::new(Level::Note, msg)), }, _marker: PhantomData, } @@ -292,7 +292,7 @@ impl EmissionGuarantee for Bug { DiagnosticBuilder { inner: DiagnosticBuilderInner { state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(Diagnostic::new_with_code(Level::Bug, None, msg)), + diagnostic: Box::new(Diagnostic::new(Level::Bug, msg)), }, _marker: PhantomData, } @@ -322,7 +322,7 @@ impl EmissionGuarantee for ! { DiagnosticBuilder { inner: DiagnosticBuilderInner { state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(Diagnostic::new_with_code(Level::Fatal, None, msg)), + diagnostic: Box::new(Diagnostic::new(Level::Fatal, msg)), }, _marker: PhantomData, } @@ -352,7 +352,7 @@ impl EmissionGuarantee for rustc_span::fatal_error::FatalError { DiagnosticBuilder { inner: DiagnosticBuilderInner { state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(Diagnostic::new_with_code(Level::Fatal, None, msg)), + diagnostic: Box::new(Diagnostic::new(Level::Fatal, msg)), }, _marker: PhantomData, } From d51b3dbfc61c2746ea8495a83d50c79f7e759359 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 4 Dec 2023 09:35:50 +1100 Subject: [PATCH 17/29] Remove some unused code, and downgrade some `pub`s. --- compiler/rustc_errors/src/diagnostic.rs | 43 +++---------------- .../rustc_errors/src/diagnostic_builder.rs | 7 --- compiler/rustc_expand/src/base.rs | 5 --- 3 files changed, 6 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 0aaa8ae69e16f..6aaf4a0f5cff2 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -239,7 +239,7 @@ impl Diagnostic { } #[track_caller] - pub fn new_with_code>( + pub(crate) fn new_with_code>( level: Level, code: Option, message: M, @@ -281,7 +281,7 @@ impl Diagnostic { } } - pub fn update_unstable_expectation_id( + pub(crate) fn update_unstable_expectation_id( &mut self, unstable_to_stable: &FxHashMap, ) { @@ -307,14 +307,14 @@ impl Diagnostic { } /// Indicates whether this diagnostic should show up in cargo's future breakage report. - pub fn has_future_breakage(&self) -> bool { + pub(crate) fn has_future_breakage(&self) -> bool { match self.code { Some(DiagnosticId::Lint { has_future_breakage, .. }) => has_future_breakage, _ => false, } } - pub fn is_force_warn(&self) -> bool { + pub(crate) fn is_force_warn(&self) -> bool { match self.code { Some(DiagnosticId::Lint { is_force_warn, .. }) => is_force_warn, _ => false, @@ -391,29 +391,6 @@ impl Diagnostic { self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"") } - pub fn note_unsuccessful_coercion( - &mut self, - expected: DiagnosticStyledString, - found: DiagnosticStyledString, - ) -> &mut Self { - let mut msg: Vec<_> = - vec![(Cow::from("required when trying to coerce from type `"), Style::NoStyle)]; - msg.extend(expected.0.iter().map(|x| match *x { - StringPart::Normal(ref s) => (Cow::from(s.clone()), Style::NoStyle), - StringPart::Highlighted(ref s) => (Cow::from(s.clone()), Style::Highlight), - })); - msg.push((Cow::from("` to type '"), Style::NoStyle)); - msg.extend(found.0.iter().map(|x| match *x { - StringPart::Normal(ref s) => (Cow::from(s.clone()), Style::NoStyle), - StringPart::Highlighted(ref s) => (Cow::from(s.clone()), Style::Highlight), - })); - msg.push((Cow::from("`"), Style::NoStyle)); - - // For now, just attach these as notes - self.highlighted_note(msg); - self - } - pub fn note_expected_found_extra( &mut self, expected_label: &dyn fmt::Display, @@ -475,7 +452,7 @@ impl Diagnostic { self } - pub fn highlighted_note>( + fn highlighted_note>( &mut self, msg: Vec<(M, Style)>, ) -> &mut Self { @@ -572,14 +549,6 @@ impl Diagnostic { self } - /// Clear any existing suggestions. - pub fn clear_suggestions(&mut self) -> &mut Self { - if let Ok(suggestions) = &mut self.suggestions { - suggestions.clear(); - } - self - } - /// Helper for pushing to `self.suggestions`, if available (not disable). fn push_suggestion(&mut self, suggestion: CodeSuggestion) { if let Ok(suggestions) = &mut self.suggestions { @@ -992,7 +961,7 @@ impl Diagnostic { /// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by /// combining it with the primary message of the diagnostic (if translatable, otherwise it just /// passes the user's string along). - pub(crate) fn subdiagnostic_message_to_diagnostic_message( + fn subdiagnostic_message_to_diagnostic_message( &self, attr: impl Into, ) -> DiagnosticMessage { diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 354fe1da2c998..fefff8d152744 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -547,12 +547,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { found_extra: &dyn fmt::Display, ) -> &mut Self); - forward!(pub fn note_unsuccessful_coercion( - &mut self, - expected: DiagnosticStyledString, - found: DiagnosticStyledString, - ) -> &mut Self); - forward!(pub fn note(&mut self, msg: impl Into) -> &mut Self); forward!(pub fn note_once(&mut self, msg: impl Into) -> &mut Self); forward!(pub fn span_note( @@ -581,7 +575,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { forward!(pub fn set_is_lint(&mut self,) -> &mut Self); forward!(pub fn disable_suggestions(&mut self,) -> &mut Self); - forward!(pub fn clear_suggestions(&mut self,) -> &mut Self); forward!(pub fn multipart_suggestion( &mut self, diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 91f3ca1d1156e..74f46efb365b2 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1145,11 +1145,6 @@ impl<'a> ExtCtxt<'a> { pub fn span_err>(&self, sp: S, msg: impl Into) { self.sess.diagnostic().span_err(sp, msg); } - #[rustc_lint_diagnostics] - #[track_caller] - pub fn span_warn>(&self, sp: S, msg: impl Into) { - self.sess.diagnostic().span_warn(sp, msg); - } pub fn span_bug>(&self, sp: S, msg: impl Into) -> ! { self.sess.diagnostic().span_bug(sp, msg); } From b7e18cabd2af625c2582ab0ce0fecc9b5437a512 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 4 Dec 2023 10:11:39 +1100 Subject: [PATCH 18/29] De-genericize some `IntoDiagnostic` impls. These impls are all needed for just a single `IntoDiagnostic` type, not a family of them. Note that `ErrorGuaranteed` is the default type parameter for `IntoDiagnostic`. --- compiler/rustc_builtin_macros/src/errors.rs | 10 +++++----- compiler/rustc_codegen_llvm/src/errors.rs | 8 ++++---- compiler/rustc_mir_transform/src/errors.rs | 6 +++--- compiler/rustc_parse/src/errors.rs | 10 +++++----- compiler/rustc_session/src/errors.rs | 6 +++--- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index fde4270334b67..0a3af2c2e1330 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1,5 +1,5 @@ use rustc_errors::{ - AddToDiagnostic, DiagnosticBuilder, EmissionGuarantee, Handler, IntoDiagnostic, MultiSpan, + AddToDiagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, MultiSpan, SingleLabelManySpans, }; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -446,9 +446,9 @@ pub(crate) struct EnvNotDefinedWithUserMessage { } // Hand-written implementation to support custom user messages. -impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefinedWithUserMessage { +impl<'a> IntoDiagnostic<'a> for EnvNotDefinedWithUserMessage { #[track_caller] - fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> { + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> { #[expect( rustc::untranslatable_diagnostic, reason = "cannot translate user-provided messages" @@ -801,8 +801,8 @@ pub(crate) struct AsmClobberNoReg { pub(crate) clobbers: Vec, } -impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for AsmClobberNoReg { - fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> { +impl<'a> IntoDiagnostic<'a> for AsmClobberNoReg { + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> { let mut diag = handler.struct_diagnostic(crate::fluent_generated::builtin_macros_asm_clobber_no_reg); diag.set_span(self.spans.clone()); diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 2ba337a8edf78..57ea13ddcd6a8 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -5,7 +5,7 @@ use std::path::Path; use crate::fluent_generated as fluent; use rustc_data_structures::small_c_str::SmallCStr; use rustc_errors::{ - DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed, Handler, IntoDiagnostic, + DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed, FatalError, Handler, IntoDiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; @@ -101,9 +101,9 @@ pub(crate) struct DynamicLinkingWithLTO; pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>); -impl IntoDiagnostic<'_, G> for ParseTargetMachineConfig<'_> { - fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, G> { - let diag: DiagnosticBuilder<'_, G> = self.0.into_diagnostic(handler); +impl IntoDiagnostic<'_, FatalError> for ParseTargetMachineConfig<'_> { + fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, FatalError> { + let diag: DiagnosticBuilder<'_, FatalError> = self.0.into_diagnostic(handler); let (message, _) = diag.styled_message().first().expect("`LlvmError` with no message"); let message = handler.eagerly_translate_to_string(message.clone(), diag.args()); diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 3a5270f105ae4..2358661738a55 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use rustc_errors::{ Applicability, DecorateLint, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, - EmissionGuarantee, Handler, IntoDiagnostic, + EmissionGuarantee, ErrorGuaranteed, Handler, IntoDiagnostic, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails}; @@ -62,9 +62,9 @@ pub(crate) struct RequiresUnsafe { // so we need to eagerly translate the label here, which isn't supported by the derive API // We could also exhaustively list out the primary messages for all unsafe violations, // but this would result in a lot of duplication. -impl<'sess, G: EmissionGuarantee> IntoDiagnostic<'sess, G> for RequiresUnsafe { +impl<'sess> IntoDiagnostic<'sess> for RequiresUnsafe { #[track_caller] - fn into_diagnostic(self, handler: &'sess Handler) -> DiagnosticBuilder<'sess, G> { + fn into_diagnostic(self, handler: &'sess Handler) -> DiagnosticBuilder<'sess, ErrorGuaranteed> { let mut diag = handler.struct_diagnostic(fluent::mir_transform_requires_unsafe); diag.code(rustc_errors::DiagnosticId::Error("E0133".to_string())); diag.set_span(self.span); diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 03e047b297dc5..b6369a8036fe7 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use rustc_ast::token::Token; use rustc_ast::{Path, Visibility}; -use rustc_errors::{AddToDiagnostic, Applicability, EmissionGuarantee, IntoDiagnostic}; +use rustc_errors::{AddToDiagnostic, Applicability, ErrorGuaranteed, IntoDiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::edition::{Edition, LATEST_STABLE_EDITION}; @@ -1038,12 +1038,12 @@ pub(crate) struct ExpectedIdentifier { pub help_cannot_start_number: Option, } -impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier { +impl<'a> IntoDiagnostic<'a> for ExpectedIdentifier { #[track_caller] fn into_diagnostic( self, handler: &'a rustc_errors::Handler, - ) -> rustc_errors::DiagnosticBuilder<'a, G> { + ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> { let token_descr = TokenDescription::from_token(&self.token); let mut diag = handler.struct_diagnostic(match token_descr { @@ -1095,12 +1095,12 @@ pub(crate) struct ExpectedSemi { pub sugg: ExpectedSemiSugg, } -impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedSemi { +impl<'a> IntoDiagnostic<'a> for ExpectedSemi { #[track_caller] fn into_diagnostic( self, handler: &'a rustc_errors::Handler, - ) -> rustc_errors::DiagnosticBuilder<'a, G> { + ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> { let token_descr = TokenDescription::from_token(&self.token); let mut diag = handler.struct_diagnostic(match token_descr { diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index f7934ce163d15..72c013eb54916 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -3,7 +3,7 @@ use std::num::NonZeroU32; use crate::parse::ParseSess; use rustc_ast::token; use rustc_ast::util::literal::LitError; -use rustc_errors::{error_code, DiagnosticMessage, EmissionGuarantee, IntoDiagnostic, MultiSpan}; +use rustc_errors::{error_code, DiagnosticMessage, ErrorGuaranteed, IntoDiagnostic, MultiSpan}; use rustc_macros::Diagnostic; use rustc_span::{BytePos, Span, Symbol}; use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple}; @@ -13,12 +13,12 @@ pub struct FeatureGateError { pub explain: DiagnosticMessage, } -impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for FeatureGateError { +impl<'a> IntoDiagnostic<'a> for FeatureGateError { #[track_caller] fn into_diagnostic( self, handler: &'a rustc_errors::Handler, - ) -> rustc_errors::DiagnosticBuilder<'a, G> { + ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> { let mut diag = handler.struct_diagnostic(self.explain); diag.set_span(self.span); diag.code(error_code!(E0658)); From 8c20ad6a08702a44a4557a12b5bf7de1a0909461 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 4 Dec 2023 10:44:57 +1100 Subject: [PATCH 19/29] Use `DiagnosticBuilder::new` more. By making it generic, instead of only for `EmissionGuarantee = ()`, we can use it everywhere. --- .../rustc_errors/src/diagnostic_builder.rs | 94 ++++++------------- compiler/rustc_errors/src/lib.rs | 10 +- 2 files changed, 36 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index fefff8d152744..b8bd86a72e4df 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -169,41 +169,7 @@ impl EmissionGuarantee for ErrorGuaranteed { handler: &Handler, msg: impl Into, ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder { - inner: DiagnosticBuilderInner { - state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(Diagnostic::new(Level::Error { lint: false }, msg)), - }, - _marker: PhantomData, - } - } -} - -impl<'a> DiagnosticBuilder<'a, ()> { - /// Convenience function for internal use, clients should use one of the - /// `struct_*` methods on [`Handler`]. - #[track_caller] - pub(crate) fn new>( - handler: &'a Handler, - level: Level, - message: M, - ) -> Self { - let diagnostic = Diagnostic::new(level, message); - Self::new_diagnostic(handler, diagnostic) - } - - /// Creates a new `DiagnosticBuilder` with an already constructed - /// diagnostic. - #[track_caller] - pub(crate) fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> Self { - debug!("Created new diagnostic"); - Self { - inner: DiagnosticBuilderInner { - state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(diagnostic), - }, - _marker: PhantomData, - } + DiagnosticBuilder::new(handler, Level::Error { lint: false }, msg) } } @@ -254,13 +220,7 @@ impl EmissionGuarantee for Noted { handler: &Handler, msg: impl Into, ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder { - inner: DiagnosticBuilderInner { - state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(Diagnostic::new(Level::Note, msg)), - }, - _marker: PhantomData, - } + DiagnosticBuilder::new(handler, Level::Note, msg) } } @@ -289,13 +249,7 @@ impl EmissionGuarantee for Bug { handler: &Handler, msg: impl Into, ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder { - inner: DiagnosticBuilderInner { - state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(Diagnostic::new(Level::Bug, msg)), - }, - _marker: PhantomData, - } + DiagnosticBuilder::new(handler, Level::Bug, msg) } } @@ -319,13 +273,7 @@ impl EmissionGuarantee for ! { handler: &Handler, msg: impl Into, ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder { - inner: DiagnosticBuilderInner { - state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(Diagnostic::new(Level::Fatal, msg)), - }, - _marker: PhantomData, - } + DiagnosticBuilder::new(handler, Level::Fatal, msg) } } @@ -349,13 +297,7 @@ impl EmissionGuarantee for rustc_span::fatal_error::FatalError { handler: &Handler, msg: impl Into, ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder { - inner: DiagnosticBuilderInner { - state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(Diagnostic::new(Level::Fatal, msg)), - }, - _marker: PhantomData, - } + DiagnosticBuilder::new(handler, Level::Fatal, msg) } } @@ -397,6 +339,32 @@ impl DerefMut for DiagnosticBuilder<'_, G> { } impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { + /// Convenience function for internal use, clients should use one of the + /// `struct_*` methods on [`Handler`]. + #[track_caller] + pub(crate) fn new>( + handler: &'a Handler, + level: Level, + message: M, + ) -> Self { + let diagnostic = Diagnostic::new(level, message); + Self::new_diagnostic(handler, diagnostic) + } + + /// Creates a new `DiagnosticBuilder` with an already constructed + /// diagnostic. + #[track_caller] + pub(crate) fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> Self { + debug!("Created new diagnostic"); + Self { + inner: DiagnosticBuilderInner { + state: DiagnosticBuilderState::Emittable(handler), + diagnostic: Box::new(diagnostic), + }, + _marker: PhantomData, + } + } + /// Emit the diagnostic. #[track_caller] pub fn emit(&mut self) -> G { diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index d9baadc68d77d..cfd730eb4ab2d 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -776,7 +776,7 @@ impl Handler { #[rustc_lint_diagnostics] #[track_caller] pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { - <()>::make_diagnostic_builder(self, msg) + DiagnosticBuilder::new(self, Level::Warning(None), msg) } /// Construct a builder at the `Warning` level with the `msg`. The `id` is used for @@ -847,7 +847,7 @@ impl Handler { &self, msg: impl Into, ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - ErrorGuaranteed::make_diagnostic_builder(self, msg) + DiagnosticBuilder::new(self, Level::Error { lint: false }, msg) } /// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors. @@ -914,7 +914,7 @@ impl Handler { #[rustc_lint_diagnostics] #[track_caller] pub fn struct_fatal(&self, msg: impl Into) -> DiagnosticBuilder<'_, !> { - ::make_diagnostic_builder(self, msg) + DiagnosticBuilder::new(self, Level::Fatal, msg) } /// Construct a builder at the `Help` level with the `msg`. @@ -1046,12 +1046,12 @@ impl Handler { #[rustc_lint_diagnostics] pub fn warn(&self, msg: impl Into) { - DiagnosticBuilder::new(self, Warning(None), msg).emit(); + DiagnosticBuilder::<()>::new(self, Warning(None), msg).emit(); } #[rustc_lint_diagnostics] pub fn note(&self, msg: impl Into) { - DiagnosticBuilder::new(self, Note, msg).emit(); + DiagnosticBuilder::<()>::new(self, Note, msg).emit(); } pub fn bug(&self, msg: impl Into) -> ! { From a8ff867d5c3f88224cfec66f36b697cac0c6f75e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 4 Dec 2023 14:06:28 +1100 Subject: [PATCH 20/29] Move some `HandlerInner` functions to `Handler`. `Handler` is a wrapper around `HanderInner`. Some functions on on `Handler` just forward to the samed-named functions on `HandlerInner`. This commit removes as many of those as possible, implementing functions on `Handler` where possible, to avoid the boilerplate required for forwarding. The commit is moderately large but it's very mechanical. --- compiler/rustc_errors/src/lib.rs | 376 ++++++++++++++----------------- 1 file changed, 164 insertions(+), 212 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index cfd730eb4ab2d..5ff99f065256d 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -554,7 +554,8 @@ impl Drop for HandlerInner { // instead of "require some error happened". Sadly that isn't ideal, as // lints can be `#[allow]`'d, potentially leading to this triggering. // Also, "good path" should be replaced with a better naming. - if !self.has_any_message() && !self.suppressed_expected_diag && !std::thread::panicking() { + let has_any_message = self.err_count > 0 || self.lint_err_count > 0 || self.warn_count > 0; + if !has_any_message && !self.suppressed_expected_diag && !std::thread::panicking() { let bugs = std::mem::replace(&mut self.good_path_delayed_bugs, Vec::new()); self.flush_delayed( bugs, @@ -675,15 +676,46 @@ impl Handler { /// Stash a given diagnostic with the given `Span` and [`StashKey`] as the key. /// Retrieve a stashed diagnostic with `steal_diagnostic`. pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) { - self.inner.borrow_mut().stash((span.with_parent(None), key), diag); + let mut inner = self.inner.borrow_mut(); + + let key = (span.with_parent(None), key); + + if diag.is_error() { + if matches!(diag.level, Level::Error { lint: true }) { + inner.lint_err_count += 1; + } else { + inner.err_count += 1; + } + } else { + // Warnings are only automatically flushed if they're forced. + if diag.is_force_warn() { + inner.warn_count += 1; + } + } + + // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic + // if/when we have a more robust macro-friendly replacement for `(span, key)` as a key. + // See the PR for a discussion. + inner.stashed_diagnostics.insert(key, diag); } /// Steal a previously stashed diagnostic with the given `Span` and [`StashKey`] as the key. pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option> { - self.inner - .borrow_mut() - .steal((span.with_parent(None), key)) - .map(|diag| DiagnosticBuilder::new_diagnostic(self, diag)) + let mut inner = self.inner.borrow_mut(); + let key = (span.with_parent(None), key); + let diag = inner.stashed_diagnostics.remove(&key)?; + if diag.is_error() { + if matches!(diag.level, Level::Error { lint: true }) { + inner.lint_err_count -= 1; + } else { + inner.err_count -= 1; + } + } else { + if diag.is_force_warn() { + inner.warn_count -= 1; + } + } + Some(DiagnosticBuilder::new_diagnostic(self, diag)) } pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool { @@ -996,19 +1028,42 @@ impl Handler { } /// For documentation on this, see `Session::span_delayed_bug`. + /// + /// Note: this function used to be called `delay_span_bug`. It was renamed + /// to match similar functions like `span_bug`, `span_err`, etc. #[track_caller] pub fn span_delayed_bug( &self, - span: impl Into, + sp: impl Into, msg: impl Into, ) -> ErrorGuaranteed { - self.inner.borrow_mut().span_delayed_bug(span, msg) + let mut inner = self.inner.borrow_mut(); + + // This is technically `self.treat_err_as_bug()` but `span_delayed_bug` is called before + // incrementing `err_count` by one, so we need to +1 the comparing. + // FIXME: Would be nice to increment err_count in a more coherent way. + if inner.flags.treat_err_as_bug.is_some_and(|c| { + inner.err_count + inner.lint_err_count + inner.delayed_bug_count() + 1 >= c.get() + }) { + // FIXME: don't abort here if report_delayed_bugs is off + inner.span_bug(sp, msg.into()); + } + let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg.into()); + diagnostic.set_span(sp.into()); + inner.emit_diagnostic(&mut diagnostic).unwrap() } // FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's // where the explanation of what "good path" is (also, it should be renamed). pub fn good_path_delayed_bug(&self, msg: impl Into) { - self.inner.borrow_mut().good_path_delayed_bug(msg) + let mut inner = self.inner.borrow_mut(); + + let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg); + if inner.flags.report_delayed_bugs { + inner.emit_diagnostic(&mut diagnostic); + } + let backtrace = std::backtrace::Backtrace::capture(); + inner.good_path_delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); } #[track_caller] @@ -1041,7 +1096,7 @@ impl Handler { #[rustc_lint_diagnostics] pub fn err(&self, msg: impl Into) -> ErrorGuaranteed { - self.inner.borrow_mut().err(msg) + self.inner.borrow_mut().emit(Error { lint: false }, msg) } #[rustc_lint_diagnostics] @@ -1060,7 +1115,7 @@ impl Handler { #[inline] pub fn err_count(&self) -> usize { - self.inner.borrow().err_count() + self.inner.borrow().err_count } pub fn has_errors(&self) -> Option { @@ -1071,26 +1126,103 @@ impl Handler { } pub fn has_errors_or_lint_errors(&self) -> Option { - self.inner.borrow().has_errors_or_lint_errors().then(|| { + let inner = self.inner.borrow(); + let has_errors_or_lint_errors = inner.has_errors() || inner.lint_err_count > 0; + has_errors_or_lint_errors.then(|| { #[allow(deprecated)] ErrorGuaranteed::unchecked_claim_error_was_emitted() }) } + pub fn has_errors_or_span_delayed_bugs(&self) -> Option { - self.inner.borrow().has_errors_or_span_delayed_bugs().then(|| { + let inner = self.inner.borrow(); + let has_errors_or_span_delayed_bugs = + inner.has_errors() || !inner.span_delayed_bugs.is_empty(); + has_errors_or_span_delayed_bugs.then(|| { #[allow(deprecated)] ErrorGuaranteed::unchecked_claim_error_was_emitted() }) } + pub fn is_compilation_going_to_fail(&self) -> Option { - self.inner.borrow().is_compilation_going_to_fail().then(|| { + let inner = self.inner.borrow(); + let will_fail = + inner.has_errors() || inner.lint_err_count > 0 || !inner.span_delayed_bugs.is_empty(); + will_fail.then(|| { #[allow(deprecated)] ErrorGuaranteed::unchecked_claim_error_was_emitted() }) } pub fn print_error_count(&self, registry: &Registry) { - self.inner.borrow_mut().print_error_count(registry) + let mut inner = self.inner.borrow_mut(); + + inner.emit_stashed_diagnostics(); + + let warnings = match inner.deduplicated_warn_count { + 0 => Cow::from(""), + 1 => Cow::from("1 warning emitted"), + count => Cow::from(format!("{count} warnings emitted")), + }; + let errors = match inner.deduplicated_err_count { + 0 => Cow::from(""), + 1 => Cow::from("aborting due to 1 previous error"), + count => Cow::from(format!("aborting due to {count} previous errors")), + }; + if inner.treat_err_as_bug() { + return; + } + + match (errors.len(), warnings.len()) { + (0, 0) => return, + (0, _) => inner.emitter.emit_diagnostic(&Diagnostic::new( + Level::Warning(None), + DiagnosticMessage::Str(warnings), + )), + (_, 0) => { + let _ = inner.fatal_no_raise(errors); + } + (_, _) => { + let _ = inner.fatal_no_raise(format!("{errors}; {warnings}")); + } + } + + let can_show_explain = inner.emitter.should_show_explain(); + let are_there_diagnostics = !inner.emitted_diagnostic_codes.is_empty(); + if can_show_explain && are_there_diagnostics { + let mut error_codes = inner + .emitted_diagnostic_codes + .iter() + .filter_map(|x| match &x { + DiagnosticId::Error(s) if registry.try_find_description(s).is_ok() => { + Some(s.clone()) + } + _ => None, + }) + .collect::>(); + if !error_codes.is_empty() { + error_codes.sort(); + if error_codes.len() > 1 { + let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() }; + inner.failure_note(format!( + "Some errors have detailed explanations: {}{}", + error_codes[..limit].join(", "), + if error_codes.len() > 9 { "..." } else { "." } + )); + inner.failure_note(format!( + "For more information about an error, try \ + `rustc --explain {}`.", + &error_codes[0] + )); + } else { + inner.failure_note(format!( + "For more information about this error, try \ + `rustc --explain {}`.", + &error_codes[0] + )); + } + } + } } pub fn take_future_breakage_diagnostics(&self) -> Vec { @@ -1098,7 +1230,11 @@ impl Handler { } pub fn abort_if_errors(&self) { - self.inner.borrow_mut().abort_if_errors() + let mut inner = self.inner.borrow_mut(); + inner.emit_stashed_diagnostics(); + if inner.has_errors() { + FatalError.raise(); + } } /// `true` if we haven't taught a diagnostic with this code already. @@ -1107,11 +1243,11 @@ impl Handler { /// Used to suppress emitting the same error multiple times with extended explanation when /// calling `-Zteach`. pub fn must_teach(&self, code: &DiagnosticId) -> bool { - self.inner.borrow_mut().must_teach(code) + self.inner.borrow_mut().taught_diagnostics.insert(code.clone()) } pub fn force_print_diagnostic(&self, db: Diagnostic) { - self.inner.borrow_mut().force_print_diagnostic(db) + self.inner.borrow_mut().emitter.emit_diagnostic(&db); } pub fn emit_diagnostic(&self, diagnostic: &mut Diagnostic) -> Option { @@ -1195,11 +1331,11 @@ impl Handler { mut diag: Diagnostic, sp: impl Into, ) -> Option { - self.inner.borrow_mut().emit_diagnostic(diag.set_span(sp)) + self.emit_diagnostic(diag.set_span(sp)) } pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) { - self.inner.borrow_mut().emit_artifact_notification(path, artifact_type) + self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type); } pub fn emit_future_breakage_report(&self, diags: Vec) { @@ -1218,7 +1354,7 @@ impl Handler { inner.bump_err_count(); } - inner.emit_unused_externs(lint_level, unused_externs) + inner.emitter.emit_unused_externs(lint_level, unused_externs) } pub fn update_unstable_expectation_id( @@ -1269,15 +1405,11 @@ impl Handler { } } +// Note: we prefer implementing operations on `Handler`, rather than +// `HandlerInner`, whenever possible. This minimizes functions where +// `Handler::foo()` just borrows `inner` and forwards a call to +// `HanderInner::foo`. impl HandlerInner { - fn must_teach(&mut self, code: &DiagnosticId) -> bool { - self.taught_diagnostics.insert(code.clone()) - } - - fn force_print_diagnostic(&mut self, db: Diagnostic) { - self.emitter.emit_diagnostic(&db); - } - /// Emit all stashed diagnostics. fn emit_stashed_diagnostics(&mut self) -> Option { let has_errors = self.has_errors(); @@ -1426,17 +1558,9 @@ impl HandlerInner { guaranteed } - fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) { - self.emitter.emit_artifact_notification(path, artifact_type); - } - - fn emit_unused_externs(&mut self, lint_level: rustc_lint_defs::Level, unused_externs: &[&str]) { - self.emitter.emit_unused_externs(lint_level, unused_externs); - } - fn treat_err_as_bug(&self) -> bool { self.flags.treat_err_as_bug.is_some_and(|c| { - self.err_count() + self.lint_err_count + self.delayed_bug_count() >= c.get() + self.err_count + self.lint_err_count + self.delayed_bug_count() >= c.get() }) } @@ -1444,141 +1568,8 @@ impl HandlerInner { self.span_delayed_bugs.len() + self.good_path_delayed_bugs.len() } - fn print_error_count(&mut self, registry: &Registry) { - self.emit_stashed_diagnostics(); - - let warnings = match self.deduplicated_warn_count { - 0 => Cow::from(""), - 1 => Cow::from("1 warning emitted"), - count => Cow::from(format!("{count} warnings emitted")), - }; - let errors = match self.deduplicated_err_count { - 0 => Cow::from(""), - 1 => Cow::from("aborting due to 1 previous error"), - count => Cow::from(format!("aborting due to {count} previous errors")), - }; - if self.treat_err_as_bug() { - return; - } - - match (errors.len(), warnings.len()) { - (0, 0) => return, - (0, _) => self.emitter.emit_diagnostic(&Diagnostic::new( - Level::Warning(None), - DiagnosticMessage::Str(warnings), - )), - (_, 0) => { - let _ = self.fatal_no_raise(errors); - } - (_, _) => { - let _ = self.fatal_no_raise(format!("{errors}; {warnings}")); - } - } - - let can_show_explain = self.emitter.should_show_explain(); - let are_there_diagnostics = !self.emitted_diagnostic_codes.is_empty(); - if can_show_explain && are_there_diagnostics { - let mut error_codes = self - .emitted_diagnostic_codes - .iter() - .filter_map(|x| match &x { - DiagnosticId::Error(s) if registry.try_find_description(s).is_ok() => { - Some(s.clone()) - } - _ => None, - }) - .collect::>(); - if !error_codes.is_empty() { - error_codes.sort(); - if error_codes.len() > 1 { - let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() }; - self.failure_note(format!( - "Some errors have detailed explanations: {}{}", - error_codes[..limit].join(", "), - if error_codes.len() > 9 { "..." } else { "." } - )); - self.failure_note(format!( - "For more information about an error, try \ - `rustc --explain {}`.", - &error_codes[0] - )); - } else { - self.failure_note(format!( - "For more information about this error, try \ - `rustc --explain {}`.", - &error_codes[0] - )); - } - } - } - } - - fn stash(&mut self, key: (Span, StashKey), diagnostic: Diagnostic) { - // Track the diagnostic for counts, but don't panic-if-treat-err-as-bug - // yet; that happens when we actually emit the diagnostic. - if diagnostic.is_error() { - if matches!(diagnostic.level, Level::Error { lint: true }) { - self.lint_err_count += 1; - } else { - self.err_count += 1; - } - } else { - // Warnings are only automatically flushed if they're forced. - if diagnostic.is_force_warn() { - self.warn_count += 1; - } - } - - // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic - // if/when we have a more robust macro-friendly replacement for `(span, key)` as a key. - // See the PR for a discussion. - self.stashed_diagnostics.insert(key, diagnostic); - } - - fn steal(&mut self, key: (Span, StashKey)) -> Option { - let diagnostic = self.stashed_diagnostics.remove(&key)?; - if diagnostic.is_error() { - if matches!(diagnostic.level, Level::Error { lint: true }) { - self.lint_err_count -= 1; - } else { - self.err_count -= 1; - } - } else { - if diagnostic.is_force_warn() { - self.warn_count -= 1; - } - } - Some(diagnostic) - } - - #[inline] - fn err_count(&self) -> usize { - self.err_count - } - fn has_errors(&self) -> bool { - self.err_count() > 0 - } - fn has_errors_or_lint_errors(&self) -> bool { - self.has_errors() || self.lint_err_count > 0 - } - fn has_errors_or_span_delayed_bugs(&self) -> bool { - self.has_errors() || !self.span_delayed_bugs.is_empty() - } - fn has_any_message(&self) -> bool { - self.err_count() > 0 || self.lint_err_count > 0 || self.warn_count > 0 - } - - fn is_compilation_going_to_fail(&self) -> bool { - self.has_errors() || self.lint_err_count > 0 || !self.span_delayed_bugs.is_empty() - } - - fn abort_if_errors(&mut self) { - self.emit_stashed_diagnostics(); - - if self.has_errors() { - FatalError.raise(); - } + self.err_count > 0 } #[track_caller] @@ -1591,41 +1582,6 @@ impl HandlerInner { self.emit_diagnostic(diag.set_span(sp)); } - /// For documentation on this, see `Session::span_delayed_bug`. - /// - /// Note: this function used to be called `delay_span_bug`. It was renamed - /// to match similar functions like `span_bug`, `span_err`, etc. - #[track_caller] - fn span_delayed_bug( - &mut self, - sp: impl Into, - msg: impl Into, - ) -> ErrorGuaranteed { - // This is technically `self.treat_err_as_bug()` but `span_delayed_bug` is called before - // incrementing `err_count` by one, so we need to +1 the comparing. - // FIXME: Would be nice to increment err_count in a more coherent way. - if self.flags.treat_err_as_bug.is_some_and(|c| { - self.err_count() + self.lint_err_count + self.delayed_bug_count() + 1 >= c.get() - }) { - // FIXME: don't abort here if report_delayed_bugs is off - self.span_bug(sp, msg.into()); - } - let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg.into()); - diagnostic.set_span(sp.into()); - self.emit_diagnostic(&mut diagnostic).unwrap() - } - - // FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's - // where the explanation of what "good path" is (also, it should be renamed). - fn good_path_delayed_bug(&mut self, msg: impl Into) { - let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg); - if self.flags.report_delayed_bugs { - self.emit_diagnostic(&mut diagnostic); - } - let backtrace = std::backtrace::Backtrace::capture(); - self.good_path_delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); - } - fn failure_note(&mut self, msg: impl Into) { self.emit_diagnostic(&mut Diagnostic::new(FailureNote, msg)); } @@ -1637,10 +1593,6 @@ impl HandlerInner { FatalError } - fn err(&mut self, msg: impl Into) -> ErrorGuaranteed { - self.emit(Error { lint: false }, msg) - } - /// Emit an error; level should be `Error` or `Fatal`. fn emit(&mut self, level: Level, msg: impl Into) -> ErrorGuaranteed { if self.treat_err_as_bug() { @@ -1724,7 +1676,7 @@ impl HandlerInner { fn panic_if_treat_err_as_bug(&self) { if self.treat_err_as_bug() { match ( - self.err_count() + self.lint_err_count, + self.err_count + self.lint_err_count, self.delayed_bug_count(), self.flags.treat_err_as_bug.map(|c| c.get()).unwrap(), ) { From 883bdb7fda9b2eda5e3c1846ed653e7edf4936c4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 4 Dec 2023 14:27:43 +1100 Subject: [PATCH 21/29] Remove `HandlerInner::emit`. This is weird: `HandlerInner::emit` calls `HandlerInner::emit_diagnostic`, but only after doing a `treat-err-as-bug` check. Which is fine, *except* that there are multiple others paths for an `Error` or `Fatal` diagnostic to be passed to `HandlerInner::emit_diagnostic` without going through `HandlerInner::emit`, e.g. `Handler::span_err` call `Handler::emit_diag_at_span`, which calls `emit_diagnostic`. So that suggests that the coverage for `treat-err-as-bug` is incomplete. This commit removes `HandlerInner::emit` and moves the `treat-err-as-bug` check to `HandlerInner::emit_diagnostic`, so it cannot by bypassed. --- compiler/rustc_errors/src/lib.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 5ff99f065256d..11ac5239445c7 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1096,7 +1096,10 @@ impl Handler { #[rustc_lint_diagnostics] pub fn err(&self, msg: impl Into) -> ErrorGuaranteed { - self.inner.borrow_mut().emit(Error { lint: false }, msg) + self.inner + .borrow_mut() + .emit_diagnostic(&mut Diagnostic::new(Error { lint: false }, msg)) + .unwrap() } #[rustc_lint_diagnostics] @@ -1126,7 +1129,7 @@ impl Handler { } pub fn has_errors_or_lint_errors(&self) -> Option { - let inner = self.inner.borrow(); + let inner = self.inner.borrow(); let has_errors_or_lint_errors = inner.has_errors() || inner.lint_err_count > 0; has_errors_or_lint_errors.then(|| { #[allow(deprecated)] @@ -1135,7 +1138,7 @@ impl Handler { } pub fn has_errors_or_span_delayed_bugs(&self) -> Option { - let inner = self.inner.borrow(); + let inner = self.inner.borrow(); let has_errors_or_span_delayed_bugs = inner.has_errors() || !inner.span_delayed_bugs.is_empty(); has_errors_or_span_delayed_bugs.then(|| { @@ -1443,6 +1446,11 @@ impl HandlerInner { // FIXME(eddyb) this should ideally take `diagnostic` by value. fn emit_diagnostic(&mut self, diagnostic: &mut Diagnostic) -> Option { + if matches!(diagnostic.level, Level::Error { .. } | Level::Fatal) && self.treat_err_as_bug() + { + diagnostic.level = Level::Bug; + } + // The `LintExpectationId` can be stable or unstable depending on when it was created. // Diagnostics created before the definition of `HirId`s are unstable and can not yet // be stored. Instead, they are buffered until the `LintExpectationId` is replaced by @@ -1589,18 +1597,10 @@ impl HandlerInner { // Note: unlike `Handler::fatal`, this doesn't return `!`, because that is // inappropriate for some of its call sites. fn fatal_no_raise(&mut self, msg: impl Into) -> FatalError { - self.emit(Fatal, msg); + self.emit_diagnostic(&mut Diagnostic::new(Fatal, msg)); FatalError } - /// Emit an error; level should be `Error` or `Fatal`. - fn emit(&mut self, level: Level, msg: impl Into) -> ErrorGuaranteed { - if self.treat_err_as_bug() { - self.bug(msg); - } - self.emit_diagnostic(&mut Diagnostic::new(level, msg)).unwrap() - } - fn bug(&mut self, msg: impl Into) -> ! { self.emit_diagnostic(&mut Diagnostic::new(Bug, msg)); panic::panic_any(ExplicitBug); From 3ab05caa4d196340dd61ce10543f64cb56878676 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 4 Dec 2023 14:48:11 +1100 Subject: [PATCH 22/29] Make `Handler::{err,bug}` more like `Handler::{warn,note}`. --- compiler/rustc_errors/src/lib.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 11ac5239445c7..e6faefa612f3d 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1096,10 +1096,7 @@ impl Handler { #[rustc_lint_diagnostics] pub fn err(&self, msg: impl Into) -> ErrorGuaranteed { - self.inner - .borrow_mut() - .emit_diagnostic(&mut Diagnostic::new(Error { lint: false }, msg)) - .unwrap() + DiagnosticBuilder::::new(self, Error { lint: false }, msg).emit() } #[rustc_lint_diagnostics] @@ -1113,7 +1110,8 @@ impl Handler { } pub fn bug(&self, msg: impl Into) -> ! { - self.inner.borrow_mut().bug(msg) + DiagnosticBuilder::::new(self, Bug, msg).emit(); + panic::panic_any(ExplicitBug); } #[inline] @@ -1601,11 +1599,6 @@ impl HandlerInner { FatalError } - fn bug(&mut self, msg: impl Into) -> ! { - self.emit_diagnostic(&mut Diagnostic::new(Bug, msg)); - panic::panic_any(ExplicitBug); - } - fn flush_delayed( &mut self, bugs: impl IntoIterator, From 7811c976d1a6b014bff0fdada7aaaa1774d31b82 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 4 Dec 2023 15:36:46 +1100 Subject: [PATCH 23/29] Inline and remove `fatal_no_raise`. This makes `Handler::fatal` more like `Handler::{err,warn,bug,note}`. --- compiler/rustc_errors/src/lib.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index e6faefa612f3d..daa8a7706eb47 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1091,7 +1091,7 @@ impl Handler { #[rustc_lint_diagnostics] pub fn fatal(&self, msg: impl Into) -> ! { - self.inner.borrow_mut().fatal_no_raise(msg).raise() + DiagnosticBuilder::::new(self, Fatal, msg).emit().raise() } #[rustc_lint_diagnostics] @@ -1181,10 +1181,10 @@ impl Handler { DiagnosticMessage::Str(warnings), )), (_, 0) => { - let _ = inner.fatal_no_raise(errors); + inner.emit_diagnostic(&mut Diagnostic::new(Fatal, errors)); } (_, _) => { - let _ = inner.fatal_no_raise(format!("{errors}; {warnings}")); + inner.emit_diagnostic(&mut Diagnostic::new(Fatal, format!("{errors}; {warnings}"))); } } @@ -1592,13 +1592,6 @@ impl HandlerInner { self.emit_diagnostic(&mut Diagnostic::new(FailureNote, msg)); } - // Note: unlike `Handler::fatal`, this doesn't return `!`, because that is - // inappropriate for some of its call sites. - fn fatal_no_raise(&mut self, msg: impl Into) -> FatalError { - self.emit_diagnostic(&mut Diagnostic::new(Fatal, msg)); - FatalError - } - fn flush_delayed( &mut self, bugs: impl IntoIterator, From d627e2a4e8317fc11ccd69832d482b9ae591084a Mon Sep 17 00:00:00 2001 From: sjwang05 <63834813+sjwang05@users.noreply.github.com> Date: Sun, 3 Dec 2023 20:43:31 -0800 Subject: [PATCH 24/29] Fix parser ICE when recovering `dyn`/`impl` after `for<...>` --- compiler/rustc_parse/src/parser/ty.rs | 22 ++++++++++--------- .../parser/recover-hrtb-before-dyn-impl-kw.rs | 4 ++++ .../recover-hrtb-before-dyn-impl-kw.stderr | 8 ++++++- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index b1a57c3dfd97c..90e4a2aac8367 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -304,23 +304,25 @@ impl<'a> Parser<'a> { if self.may_recover() && (self.eat_keyword_noexpect(kw::Impl) || self.eat_keyword_noexpect(kw::Dyn)) { - let kw = self.prev_token.ident().unwrap().0.name; + let kw = self.prev_token.ident().unwrap().0; + let removal_span = kw.span.with_hi(self.token.span.lo()); + let path = self.parse_path(PathStyle::Type)?; + let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); + let kind = + self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?; let mut err = self.sess.create_err(errors::TransposeDynOrImpl { - span: self.prev_token.span, - kw: kw.as_str(), + span: kw.span, + kw: kw.name.as_str(), sugg: errors::TransposeDynOrImplSugg { - removal_span: self.prev_token.span.with_hi(self.token.span.lo()), + removal_span, insertion_span: for_span.shrink_to_lo(), - kw: kw.as_str(), + kw: kw.name.as_str(), }, }); - let path = self.parse_path(PathStyle::Type)?; - let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); - let kind = - self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?; + // Take the parsed bare trait object and turn it either // into a `dyn` object or an `impl Trait`. - let kind = match (kind, kw) { + let kind = match (kind, kw.name) { (TyKind::TraitObject(bounds, _), kw::Dyn) => { TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn) } diff --git a/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.rs b/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.rs index fe363a6887f58..b9e3c5783ebd7 100644 --- a/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.rs +++ b/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.rs @@ -6,4 +6,8 @@ fn test(_: &for<'a> dyn Trait) {} fn test2(_: for<'a> impl Trait) {} //~^ ERROR `for<...>` expected after `impl`, not before +// Issue #118564 +type A2 = dyn dyn>; +//~^ ERROR expected identifier, found `>` + fn main() {} diff --git a/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.stderr b/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.stderr index 6fc1259b91061..a012220e8c7c9 100644 --- a/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.stderr +++ b/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.stderr @@ -22,5 +22,11 @@ LL - fn test2(_: for<'a> impl Trait) {} LL + fn test2(_: impl for<'a> Trait) {} | -error: aborting due to 2 previous errors +error: expected identifier, found `>` + --> $DIR/recover-hrtb-before-dyn-impl-kw.rs:10:24 + | +LL | type A2 = dyn dyn>; + | ^ expected identifier + +error: aborting due to 3 previous errors From a0ba895f2d6bf94da9a083eb4afce7bf6fb730a4 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Tue, 5 Dec 2023 12:11:29 +0100 Subject: [PATCH 25/29] bootstrap(builder.rs): Don't explicitly warn against `semicolon_in_expressions_from_macros` This already wasn't passed in bootstrap.py and the lint itself already warns-by-default for 2 years now and has already been added to the future-incompat group in Rust 1.68. See https://github.com/rust-lang/rust/issues/79813 for the tracking issue. --- src/bootstrap/src/core/builder.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 65af2aed6de37..80dc5439b3bb3 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1872,7 +1872,6 @@ impl<'a> Builder<'a> { // some code doesn't go through this `rustc` wrapper. lint_flags.push("-Wrust_2018_idioms"); lint_flags.push("-Wunused_lifetimes"); - lint_flags.push("-Wsemicolon_in_expressions_from_macros"); if self.config.deny_warnings { lint_flags.push("-Dwarnings"); From 334577f0910f64f3865f3803d124b299bf0f3fe5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 27 Nov 2023 03:20:45 +0000 Subject: [PATCH 26/29] Add deeply_normalize_for_diagnostics, use it in coherence --- .../rustc_trait_selection/src/solve/mod.rs | 4 +++- .../src/solve/normalize.rs | 16 +++++++++++++- .../src/traits/coherence.rs | 14 ++++++++++-- .../normalize-for-errors.current.stderr | 14 ++++++++++++ .../normalize-for-errors.next.stderr | 14 ++++++++++++ tests/ui/coherence/normalize-for-errors.rs | 22 +++++++++++++++++++ 6 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 tests/ui/coherence/normalize-for-errors.current.stderr create mode 100644 tests/ui/coherence/normalize-for-errors.next.stderr create mode 100644 tests/ui/coherence/normalize-for-errors.rs diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index b9e256236e940..bf3b72caeb4db 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -41,7 +41,9 @@ mod trait_goals; pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt}; pub use fulfill::FulfillmentCtxt; -pub(crate) use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; +pub(crate) use normalize::{ + deeply_normalize, deeply_normalize_for_diagnostics, deeply_normalize_with_skipped_universes, +}; #[derive(Debug, Clone, Copy)] enum SolverMode { diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index b0a348985708d..af522799db820 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -4,10 +4,11 @@ use crate::traits::{needs_normalization, BoundVarReplacer, PlaceholderReplacer}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::at::At; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::InferCtxt; use rustc_infer::traits::TraitEngineExt; use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::traits::Reveal; +use rustc_middle::traits::{ObligationCause, Reveal}; use rustc_middle::ty::{self, AliasTy, Ty, TyCtxt, UniverseIndex}; use rustc_middle::ty::{FallibleTypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{TypeFoldable, TypeVisitableExt}; @@ -41,6 +42,19 @@ pub(crate) fn deeply_normalize_with_skipped_universes<'tcx, T: TypeFoldable>>( + infcx: &InferCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + t: T, +) -> T { + infcx + .commit_if_ok(|_| { + deeply_normalize(infcx.at(&ObligationCause::dummy(), param_env), t.clone()) + }) + .unwrap_or(t) +} + struct NormalizationFolder<'me, 'tcx> { at: At<'me, 'tcx>, fulfill_cx: FulfillmentCtxt<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 8e97333ad0f3e..9f2e1df8ef8fd 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -6,8 +6,8 @@ use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::InferOk; -use crate::solve::inspect; use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor}; +use crate::solve::{deeply_normalize_for_diagnostics, inspect}; use crate::traits::engine::TraitEngineExt; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs}; @@ -308,7 +308,13 @@ fn overlap<'tcx>( .iter() .any(|c| c.0.involves_placeholders()); - let impl_header = selcx.infcx.resolve_vars_if_possible(impl1_header); + let mut impl_header = infcx.resolve_vars_if_possible(impl1_header); + + // Deeply normalize the impl header for diagnostics, ignoring any errors if this fails. + if infcx.next_trait_solver() { + impl_header = deeply_normalize_for_diagnostics(&infcx, param_env, impl_header); + } + Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) } @@ -1084,6 +1090,10 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> { Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"), Ok(Err(conflict)) => { if !trait_ref.references_error() { + // Normalize the trait ref for diagnostics, ignoring any errors if this fails. + let trait_ref = + deeply_normalize_for_diagnostics(infcx, param_env, trait_ref); + let self_ty = trait_ref.self_ty(); let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty); ambiguity_cause = Some(match conflict { diff --git a/tests/ui/coherence/normalize-for-errors.current.stderr b/tests/ui/coherence/normalize-for-errors.current.stderr new file mode 100644 index 0000000000000..df71d80e7fbed --- /dev/null +++ b/tests/ui/coherence/normalize-for-errors.current.stderr @@ -0,0 +1,14 @@ +error[E0119]: conflicting implementations of trait `MyTrait` for type `Box<(MyType,)>` + --> $DIR/normalize-for-errors.rs:17:1 + | +LL | impl MyTrait for T {} + | --------------------------- first implementation here +LL | +LL | impl MyTrait for Box<<(MyType,) as Mirror>::Assoc> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<(MyType,)>` + | + = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/normalize-for-errors.next.stderr b/tests/ui/coherence/normalize-for-errors.next.stderr new file mode 100644 index 0000000000000..df71d80e7fbed --- /dev/null +++ b/tests/ui/coherence/normalize-for-errors.next.stderr @@ -0,0 +1,14 @@ +error[E0119]: conflicting implementations of trait `MyTrait` for type `Box<(MyType,)>` + --> $DIR/normalize-for-errors.rs:17:1 + | +LL | impl MyTrait for T {} + | --------------------------- first implementation here +LL | +LL | impl MyTrait for Box<<(MyType,) as Mirror>::Assoc> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<(MyType,)>` + | + = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/normalize-for-errors.rs b/tests/ui/coherence/normalize-for-errors.rs new file mode 100644 index 0000000000000..f488ad3d46862 --- /dev/null +++ b/tests/ui/coherence/normalize-for-errors.rs @@ -0,0 +1,22 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + +struct MyType; +trait MyTrait { +} + +trait Mirror { + type Assoc; +} +impl Mirror for T { + type Assoc = T; +} + +impl MyTrait for T {} +//~^ NOTE first implementation here +impl MyTrait for Box<<(MyType,) as Mirror>::Assoc> {} +//~^ ERROR conflicting implementations of trait `MyTrait` for type `Box<(MyType,)>` +//~| NOTE conflicting implementation for `Box<(MyType,)> +//~| NOTE upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions + +fn main() {} From 3448284f8df0f136835500d220addc1326ab98d6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 28 Nov 2023 21:45:37 +0000 Subject: [PATCH 27/29] Continue folding if deep normalizer fails --- .../src/solve/normalize.rs | 54 ++++++++++++++----- .../normalize-for-errors.current.stderr | 12 ++--- .../normalize-for-errors.next.stderr | 12 ++--- tests/ui/coherence/normalize-for-errors.rs | 11 ++-- 4 files changed, 57 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index af522799db820..ea512ba5fa777 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -10,7 +10,7 @@ use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::traits::{ObligationCause, Reveal}; use rustc_middle::ty::{self, AliasTy, Ty, TyCtxt, UniverseIndex}; -use rustc_middle::ty::{FallibleTypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{TypeFoldable, TypeVisitableExt}; use super::FulfillmentCtxt; @@ -42,19 +42,6 @@ pub(crate) fn deeply_normalize_with_skipped_universes<'tcx, T: TypeFoldable>>( - infcx: &InferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - t: T, -) -> T { - infcx - .commit_if_ok(|_| { - deeply_normalize(infcx.at(&ObligationCause::dummy(), param_env), t.clone()) - }) - .unwrap_or(t) -} - struct NormalizationFolder<'me, 'tcx> { at: At<'me, 'tcx>, fulfill_cx: FulfillmentCtxt<'tcx>, @@ -244,3 +231,42 @@ impl<'tcx> FallibleTypeFolder> for NormalizationFolder<'_, 'tcx> { } } } + +// Deeply normalize a value and return it +pub(crate) fn deeply_normalize_for_diagnostics<'tcx, T: TypeFoldable>>( + infcx: &InferCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + t: T, +) -> T { + t.fold_with(&mut DeeplyNormalizeForDiagnosticsFolder { + at: infcx.at(&ObligationCause::dummy(), param_env), + }) +} + +struct DeeplyNormalizeForDiagnosticsFolder<'a, 'tcx> { + at: At<'a, 'tcx>, +} + +impl<'tcx> TypeFolder> for DeeplyNormalizeForDiagnosticsFolder<'_, 'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.at.infcx.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + deeply_normalize_with_skipped_universes( + self.at, + ty, + vec![None; ty.outer_exclusive_binder().as_usize()], + ) + .unwrap_or_else(|_| ty.super_fold_with(self)) + } + + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + deeply_normalize_with_skipped_universes( + self.at, + ct, + vec![None; ct.outer_exclusive_binder().as_usize()], + ) + .unwrap_or_else(|_| ct.super_fold_with(self)) + } +} diff --git a/tests/ui/coherence/normalize-for-errors.current.stderr b/tests/ui/coherence/normalize-for-errors.current.stderr index df71d80e7fbed..0e48aaed87991 100644 --- a/tests/ui/coherence/normalize-for-errors.current.stderr +++ b/tests/ui/coherence/normalize-for-errors.current.stderr @@ -1,11 +1,11 @@ -error[E0119]: conflicting implementations of trait `MyTrait` for type `Box<(MyType,)>` - --> $DIR/normalize-for-errors.rs:17:1 +error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, _)` + --> $DIR/normalize-for-errors.rs:16:1 | -LL | impl MyTrait for T {} - | --------------------------- first implementation here +LL | impl MyTrait for (T, S::Item) {} + | ------------------------------------------------------ first implementation here LL | -LL | impl MyTrait for Box<<(MyType,) as Mirror>::Assoc> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<(MyType,)>` +LL | impl MyTrait for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, _)` | = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions diff --git a/tests/ui/coherence/normalize-for-errors.next.stderr b/tests/ui/coherence/normalize-for-errors.next.stderr index df71d80e7fbed..a8a7d437b32d3 100644 --- a/tests/ui/coherence/normalize-for-errors.next.stderr +++ b/tests/ui/coherence/normalize-for-errors.next.stderr @@ -1,11 +1,11 @@ -error[E0119]: conflicting implementations of trait `MyTrait` for type `Box<(MyType,)>` - --> $DIR/normalize-for-errors.rs:17:1 +error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, <_ as Iterator>::Item)` + --> $DIR/normalize-for-errors.rs:16:1 | -LL | impl MyTrait for T {} - | --------------------------- first implementation here +LL | impl MyTrait for (T, S::Item) {} + | ------------------------------------------------------ first implementation here LL | -LL | impl MyTrait for Box<<(MyType,) as Mirror>::Assoc> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<(MyType,)>` +LL | impl MyTrait for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, <_ as Iterator>::Item)` | = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions diff --git a/tests/ui/coherence/normalize-for-errors.rs b/tests/ui/coherence/normalize-for-errors.rs index f488ad3d46862..367d34251ae30 100644 --- a/tests/ui/coherence/normalize-for-errors.rs +++ b/tests/ui/coherence/normalize-for-errors.rs @@ -2,8 +2,7 @@ //[next] compile-flags: -Ztrait-solver=next struct MyType; -trait MyTrait { -} +trait MyTrait {} trait Mirror { type Assoc; @@ -12,11 +11,11 @@ impl Mirror for T { type Assoc = T; } -impl MyTrait for T {} +impl MyTrait for (T, S::Item) {} //~^ NOTE first implementation here -impl MyTrait for Box<<(MyType,) as Mirror>::Assoc> {} -//~^ ERROR conflicting implementations of trait `MyTrait` for type `Box<(MyType,)>` -//~| NOTE conflicting implementation for `Box<(MyType,)> +impl MyTrait for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {} +//~^ ERROR conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, +//~| NOTE conflicting implementation for `(Box<(MyType,)>, //~| NOTE upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions fn main() {} From b97ff8eb16c4b07dc8d24cf784b7c12bd3903e29 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 24 Nov 2023 22:09:59 +0000 Subject: [PATCH 28/29] Add print_trait_sugared --- .../rustc_hir_analysis/src/astconv/mod.rs | 5 +- .../src/astconv/object_safety.rs | 1 + .../rustc_hir_typeck/src/method/suggest.rs | 2 +- .../src/infer/error_reporting/mod.rs | 4 +- compiler/rustc_middle/src/ty/print/pretty.rs | 46 ++++++++++++++++++- .../error_reporting/on_unimplemented.rs | 9 +--- .../error_reporting/type_err_ctxt_ext.rs | 6 +-- tests/ui/error-codes/E0401.stderr | 2 +- .../normalize-under-binder/issue-71955.stderr | 16 +++---- tests/ui/lifetimes/issue-105675.stderr | 16 +++---- tests/ui/lifetimes/issue-79187-2.stderr | 4 +- tests/ui/lifetimes/issue-79187.stderr | 4 +- .../lifetime-errors/issue_74400.stderr | 4 +- .../mismatched_types/closure-mismatch.stderr | 8 ++-- ...missing-universe-cause-issue-114907.stderr | 8 ++-- .../ui/rfcs/rfc-1623-static/rfc1623-2.stderr | 8 ++-- tests/ui/traits/issue-85735.stderr | 4 +- 17 files changed, 91 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index fd3e6bd44e794..0f06407f44559 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1182,10 +1182,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if let Some(bound_span) = bound_span { err.span_label( bound_span, - format!( - "ambiguous `{assoc_name}` from `{}`", - bound.print_only_trait_path(), - ), + format!("ambiguous `{assoc_name}` from `{}`", bound.print_trait_sugared(),), ); if let Some(constraint) = &is_equality { where_bounds.push(format!( diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs index 6cb38c741b755..ce5426b51427f 100644 --- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs @@ -106,6 +106,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait here instead: `trait NewTrait: {} {{}}`", regular_traits .iter() + // FIXME: This should `print_sugared`, but also needs to integrate projection bounds... .map(|t| t.trait_ref().print_only_trait_path().to_string()) .collect::>() .join(" + "), diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 858385246dd70..37b1d6e0fcf7c 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2288,7 +2288,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Adt(def, _) if def.did().is_local() => { spans.push_span_label( self.tcx.def_span(def.did()), - format!("must implement `{}`", pred.trait_ref.print_only_trait_path()), + format!("must implement `{}`", pred.trait_ref.print_trait_sugared()), ); } _ => {} diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 9cdf78484d47d..ecaf9f4e16937 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2219,8 +2219,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer::ExistentialProjection(exp_found) => self.expected_found_str(exp_found), infer::PolyTraitRefs(exp_found) => { let pretty_exp_found = ty::error::ExpectedFound { - expected: exp_found.expected.print_only_trait_path(), - found: exp_found.found.print_only_trait_path(), + expected: exp_found.expected.print_trait_sugared(), + found: exp_found.found.print_trait_sugared(), }; match self.expected_found_str(pretty_exp_found) { Some((expected, found, _, _)) if expected == found => { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 25423348638a9..63b706e6b3d1d 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2640,6 +2640,23 @@ impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> { } } +/// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only +/// the trait path, and additionally tries to "sugar" `Fn(...)` trait bounds. +#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)] +pub struct TraitRefPrintSugared<'tcx>(ty::TraitRef<'tcx>); + +impl<'tcx> rustc_errors::IntoDiagnosticArg for TraitRefPrintSugared<'tcx> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + +impl<'tcx> fmt::Debug for TraitRefPrintSugared<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + /// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only /// the trait name. That is, it will print `Trait` instead of /// `>`. @@ -2657,6 +2674,10 @@ impl<'tcx> ty::TraitRef<'tcx> { TraitRefPrintOnlyTraitPath(self) } + pub fn print_trait_sugared(self) -> TraitRefPrintSugared<'tcx> { + TraitRefPrintSugared(self) + } + pub fn print_only_trait_name(self) -> TraitRefPrintOnlyTraitName<'tcx> { TraitRefPrintOnlyTraitName(self) } @@ -2666,6 +2687,10 @@ impl<'tcx> ty::Binder<'tcx, ty::TraitRef<'tcx>> { pub fn print_only_trait_path(self) -> ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>> { self.map_bound(|tr| tr.print_only_trait_path()) } + + pub fn print_trait_sugared(self) -> ty::Binder<'tcx, TraitRefPrintSugared<'tcx>> { + self.map_bound(|tr| tr.print_trait_sugared()) + } } #[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)] @@ -2745,6 +2770,7 @@ forward_display_to_print! { ty::PolyExistentialTraitRef<'tcx>, ty::Binder<'tcx, ty::TraitRef<'tcx>>, ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + ty::Binder<'tcx, TraitRefPrintSugared<'tcx>>, ty::Binder<'tcx, ty::FnSig<'tcx>>, ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>, @@ -2844,6 +2870,24 @@ define_print_and_forward_display! { p!(print_def_path(self.0.def_id, self.0.args)); } + TraitRefPrintSugared<'tcx> { + if !with_no_queries() + && let Some(kind) = cx.tcx().fn_trait_kind_from_def_id(self.0.def_id) + && let ty::Tuple(args) = self.0.args.type_at(1).kind() + { + p!(write("{}", kind.as_str()), "("); + for (i, arg) in args.iter().enumerate() { + if i > 0 { + p!(", "); + } + p!(print(arg)); + } + p!(")"); + } else { + p!(print_def_path(self.0.def_id, self.0.args)); + } + } + TraitRefPrintOnlyTraitName<'tcx> { p!(print_def_path(self.0.def_id, &[])); } @@ -2892,7 +2936,7 @@ define_print_and_forward_display! { if let ty::ImplPolarity::Negative = self.polarity { p!("!"); } - p!(print(self.trait_ref.print_only_trait_path())) + p!(print(self.trait_ref.print_trait_sugared())) } ty::ProjectionPredicate<'tcx> { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index fbe6e2bd5b892..c07db12b25b25 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -184,14 +184,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { flags.push((sym::cause, Some("MainFunctionType".to_string()))); } - if let Some(kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id) - && let ty::Tuple(args) = trait_ref.args.type_at(1).kind() - { - let args = args.iter().map(|ty| ty.to_string()).collect::>().join(", "); - flags.push((sym::Trait, Some(format!("{}({args})", kind.as_str())))); - } else { - flags.push((sym::Trait, Some(trait_ref.print_only_trait_path().to_string()))); - } + flags.push((sym::Trait, Some(trait_ref.print_trait_sugared().to_string()))); // Add all types without trimmed paths or visible paths, ensuring they end up with // their "canonical" def path. 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 b3910a2770b3a..0c36cba35482a 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 @@ -622,7 +622,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span.shrink_to_hi(), format!( "the trait `{}` is implemented for fn pointer `{}`, try casting using `as`", - cand.print_only_trait_path(), + cand.print_trait_sugared(), cand.self_ty(), ), format!(" as {}", cand.self_ty()), @@ -1785,7 +1785,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()), }); err.highlighted_help(vec![ - (format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle), + (format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle), ("is".to_string(), Style::Highlight), (" implemented for `".to_string(), Style::NoStyle), (cand.self_ty().to_string(), Style::Highlight), @@ -1821,7 +1821,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { _ => (" implemented for `", ""), }; err.highlighted_help(vec![ - (format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle), + (format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle), ("is".to_string(), Style::Highlight), (desc.to_string(), Style::NoStyle), (cand.self_ty().to_string(), Style::Highlight), diff --git a/tests/ui/error-codes/E0401.stderr b/tests/ui/error-codes/E0401.stderr index 0a069e8d35063..d27fade487fe2 100644 --- a/tests/ui/error-codes/E0401.stderr +++ b/tests/ui/error-codes/E0401.stderr @@ -55,7 +55,7 @@ error[E0283]: type annotations needed LL | bfnr(x); | ^^^^ cannot infer type of the type parameter `W` declared on the function `bfnr` | - = note: multiple `impl`s satisfying `_: Fn<()>` found in the following crates: `alloc`, `core`: + = note: multiple `impl`s satisfying `_: Fn()` found in the following crates: `alloc`, `core`: - impl Fn for &F where A: Tuple, F: Fn, F: ?Sized; - impl Fn for Box diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr index 4ef96cd954106..1cf364aa9f6a1 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | foo(bar, "string", |s| s.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a &'b str,)>` - found trait `for<'a> FnOnce<(&'a &str,)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a &'b str)` + found trait `for<'a> FnOnce(&'a &str)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:45:24 | @@ -23,8 +23,8 @@ error[E0308]: mismatched types LL | foo(bar, "string", |s| s.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a &'b str,)>` - found trait `for<'a> FnOnce<(&'a &str,)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a &'b str)` + found trait `for<'a> FnOnce(&'a &str)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:45:24 | @@ -42,8 +42,8 @@ error[E0308]: mismatched types LL | foo(baz, "string", |s| s.0.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a Wrapper<'b>,)>` - found trait `for<'a> FnOnce<(&'a Wrapper<'_>,)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a Wrapper<'b>)` + found trait `for<'a> FnOnce(&'a Wrapper<'_>)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:48:24 | @@ -61,8 +61,8 @@ error[E0308]: mismatched types LL | foo(baz, "string", |s| s.0.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a Wrapper<'b>,)>` - found trait `for<'a> FnOnce<(&'a Wrapper<'_>,)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a Wrapper<'b>)` + found trait `for<'a> FnOnce(&'a Wrapper<'_>)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:48:24 | diff --git a/tests/ui/lifetimes/issue-105675.stderr b/tests/ui/lifetimes/issue-105675.stderr index 54ecd35ed6acd..f1fa5a5986060 100644 --- a/tests/ui/lifetimes/issue-105675.stderr +++ b/tests/ui/lifetimes/issue-105675.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` - found trait `for<'a> FnOnce<(&u32, &'a u32, u32)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)` + found trait `for<'a> FnOnce(&u32, &'a u32, u32)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-105675.rs:4:13 | @@ -27,8 +27,8 @@ error[E0308]: mismatched types LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` - found trait `for<'a> FnOnce<(&u32, &'a u32, u32)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)` + found trait `for<'a> FnOnce(&u32, &'a u32, u32)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-105675.rs:4:13 | @@ -46,8 +46,8 @@ error[E0308]: mismatched types LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` - found trait `FnOnce<(&u32, &u32, u32)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)` + found trait `FnOnce(&u32, &u32, u32)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-105675.rs:8:13 | @@ -69,8 +69,8 @@ error[E0308]: mismatched types LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` - found trait `FnOnce<(&u32, &u32, u32)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)` + found trait `FnOnce(&u32, &u32, u32)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-105675.rs:8:13 | diff --git a/tests/ui/lifetimes/issue-79187-2.stderr b/tests/ui/lifetimes/issue-79187-2.stderr index 75fd87b3fe9b3..86a4ac4132e44 100644 --- a/tests/ui/lifetimes/issue-79187-2.stderr +++ b/tests/ui/lifetimes/issue-79187-2.stderr @@ -31,8 +31,8 @@ error[E0308]: mismatched types LL | take_foo(|a| a); | ^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> Fn<(&'a i32,)>` - found trait `Fn<(&i32,)>` + = note: expected trait `for<'a> Fn(&'a i32)` + found trait `Fn(&i32)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-79187-2.rs:8:14 | diff --git a/tests/ui/lifetimes/issue-79187.stderr b/tests/ui/lifetimes/issue-79187.stderr index 209f2b7b7398a..14bdfe75c08be 100644 --- a/tests/ui/lifetimes/issue-79187.stderr +++ b/tests/ui/lifetimes/issue-79187.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> FnOnce<(&'a u32,)>` - found trait `FnOnce<(&u32,)>` + = note: expected trait `for<'a> FnOnce(&'a u32)` + found trait `FnOnce(&u32)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-79187.rs:4:13 | diff --git a/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr b/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr index dbc587dd004a4..677f918fe932e 100644 --- a/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr +++ b/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr @@ -18,8 +18,8 @@ error[E0308]: mismatched types LL | f(data, identity) | ^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> Fn<(&'a T,)>` - found trait `Fn<(&T,)>` + = note: expected trait `for<'a> Fn(&'a T)` + found trait `Fn(&T)` note: the lifetime requirement is introduced here --> $DIR/issue_74400.rs:8:34 | diff --git a/tests/ui/mismatched_types/closure-mismatch.stderr b/tests/ui/mismatched_types/closure-mismatch.stderr index c5b8270ba84d5..74033c1857377 100644 --- a/tests/ui/mismatched_types/closure-mismatch.stderr +++ b/tests/ui/mismatched_types/closure-mismatch.stderr @@ -13,8 +13,8 @@ error[E0308]: mismatched types LL | baz(|_| ()); | ^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> Fn<(&'a (),)>` - found trait `Fn<(&(),)>` + = note: expected trait `for<'a> Fn(&'a ())` + found trait `Fn(&())` note: this closure does not fulfill the lifetime requirements --> $DIR/closure-mismatch.rs:8:9 | @@ -45,8 +45,8 @@ error[E0308]: mismatched types LL | baz(|x| ()); | ^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> Fn<(&'a (),)>` - found trait `Fn<(&(),)>` + = note: expected trait `for<'a> Fn(&'a ())` + found trait `Fn(&())` note: this closure does not fulfill the lifetime requirements --> $DIR/closure-mismatch.rs:11:9 | diff --git a/tests/ui/nll/missing-universe-cause-issue-114907.stderr b/tests/ui/nll/missing-universe-cause-issue-114907.stderr index 988eee61027bc..a616d29c4fea6 100644 --- a/tests/ui/nll/missing-universe-cause-issue-114907.stderr +++ b/tests/ui/nll/missing-universe-cause-issue-114907.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | accept(callback); | ^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> FnOnce<(&'a (),)>` - found trait `FnOnce<(&(),)>` + = note: expected trait `for<'a> FnOnce(&'a ())` + found trait `FnOnce(&())` note: this closure does not fulfill the lifetime requirements --> $DIR/missing-universe-cause-issue-114907.rs:32:20 | @@ -46,8 +46,8 @@ error[E0308]: mismatched types LL | accept(callback); | ^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> FnOnce<(&'a (),)>` - found trait `FnOnce<(&(),)>` + = note: expected trait `for<'a> FnOnce(&'a ())` + found trait `FnOnce(&())` note: this closure does not fulfill the lifetime requirements --> $DIR/missing-universe-cause-issue-114907.rs:32:20 | diff --git a/tests/ui/rfcs/rfc-1623-static/rfc1623-2.stderr b/tests/ui/rfcs/rfc-1623-static/rfc1623-2.stderr index 5f8c5dbe61938..52c700c326e30 100644 --- a/tests/ui/rfcs/rfc-1623-static/rfc1623-2.stderr +++ b/tests/ui/rfcs/rfc-1623-static/rfc1623-2.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | f: &id, | ^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> Fn<(&'a Foo<'b>,)>` - found trait `Fn<(&Foo<'_>,)>` + = note: expected trait `for<'a, 'b> Fn(&'a Foo<'b>)` + found trait `Fn(&Foo<'_>)` error[E0308]: mismatched types --> $DIR/rfc1623-2.rs:28:8 @@ -13,8 +13,8 @@ error[E0308]: mismatched types LL | f: &id, | ^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> Fn<(&'a Foo<'b>,)>` - found trait `Fn<(&Foo<'_>,)>` + = note: expected trait `for<'a, 'b> Fn(&'a Foo<'b>)` + found trait `Fn(&Foo<'_>)` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `FnOnce` is not general enough diff --git a/tests/ui/traits/issue-85735.stderr b/tests/ui/traits/issue-85735.stderr index 1aba418334848..0980c5c33bdb4 100644 --- a/tests/ui/traits/issue-85735.stderr +++ b/tests/ui/traits/issue-85735.stderr @@ -1,10 +1,10 @@ -error[E0283]: type annotations needed: cannot satisfy `T: FnMut<(&'a (),)>` +error[E0283]: type annotations needed: cannot satisfy `T: FnMut(&'a ())` --> $DIR/issue-85735.rs:7:8 | LL | T: FnMut(&'a ()), | ^^^^^^^^^^^^^ | -note: multiple `impl`s or `where` clauses satisfying `T: FnMut<(&'a (),)>` found +note: multiple `impl`s or `where` clauses satisfying `T: FnMut(&'a ())` found --> $DIR/issue-85735.rs:7:8 | LL | T: FnMut(&'a ()), From f6c30b3a54630ce4fa49ad2333a82afe1a0e8453 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 24 Nov 2023 22:36:25 +0000 Subject: [PATCH 29/29] Add more --- compiler/rustc_hir_analysis/src/coherence/unsafety.rs | 8 ++++---- compiler/rustc_hir_typeck/src/method/suggest.rs | 2 +- compiler/rustc_trait_selection/src/traits/coherence.rs | 2 +- .../src/traits/error_reporting/type_err_ctxt_ext.rs | 2 +- compiler/rustc_trait_selection/src/traits/select/mod.rs | 4 ++-- .../rustc_trait_selection/src/traits/specialize/mod.rs | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index 42e2818b63f39..8a02bab92aaf7 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -23,7 +23,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { tcx.def_span(def_id), E0199, "implementing the trait `{}` is not unsafe", - trait_ref.print_only_trait_path() + trait_ref.print_trait_sugared() ) .span_suggestion_verbose( item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)), @@ -40,13 +40,13 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { tcx.def_span(def_id), E0200, "the trait `{}` requires an `unsafe impl` declaration", - trait_ref.print_only_trait_path() + trait_ref.print_trait_sugared() ) .note(format!( "the trait `{}` enforces invariants that the compiler can't check. \ Review the trait documentation and make sure this implementation \ upholds those invariants before adding the `unsafe` keyword", - trait_ref.print_only_trait_path() + trait_ref.print_trait_sugared() )) .span_suggestion_verbose( item.span.shrink_to_lo(), @@ -69,7 +69,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { "the trait `{}` enforces invariants that the compiler can't check. \ Review the trait documentation and make sure this implementation \ upholds those invariants before adding the `unsafe` keyword", - trait_ref.print_only_trait_path() + trait_ref.print_trait_sugared() )) .span_suggestion_verbose( item.span.shrink_to_lo(), diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 37b1d6e0fcf7c..143454c71e1c4 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2299,7 +2299,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let msg = if preds.len() == 1 { format!( "an implementation of `{}` might be missing for `{}`", - preds[0].trait_ref.print_only_trait_path(), + preds[0].trait_ref.print_trait_sugared(), preds[0].self_ty() ) } else { diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 8e97333ad0f3e..8e2ec2e46b24a 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -245,7 +245,7 @@ fn overlap<'tcx>( let trait_ref = infcx.resolve_vars_if_possible(trait_ref); format!( "of `{}` for `{}`", - trait_ref.print_only_trait_path(), + trait_ref.print_trait_sugared(), trait_ref.self_ty() ) } 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 0c36cba35482a..857740130628f 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 @@ -1854,7 +1854,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let end = if candidates.len() <= 9 { candidates.len() } else { 8 }; err.help(format!( "the following {other}types implement trait `{}`:{}{}", - trait_ref.print_only_trait_path(), + trait_ref.print_trait_sugared(), candidates[..end].join(""), if candidates.len() > 9 { format!("\nand {} others", candidates.len() - 8) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index b26c781100a09..8e4f7d5d9655d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -78,7 +78,7 @@ impl<'tcx> IntercrateAmbiguityCause<'tcx> { IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty } => { format!( "downstream crates may implement trait `{trait_desc}`{self_desc}", - trait_desc = trait_ref.print_only_trait_path(), + trait_desc = trait_ref.print_trait_sugared(), self_desc = if let Some(self_ty) = self_ty { format!(" for type `{self_ty}`") } else { @@ -90,7 +90,7 @@ impl<'tcx> IntercrateAmbiguityCause<'tcx> { format!( "upstream crates may add a new impl of trait `{trait_desc}`{self_desc} \ in future versions", - trait_desc = trait_ref.print_only_trait_path(), + trait_desc = trait_ref.print_trait_sugared(), self_desc = if let Some(self_ty) = self_ty { format!(" for type `{self_ty}`") } else { diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 56f5057608f6e..39f5ff52eba69 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -412,7 +412,7 @@ fn report_conflicting_impls<'tcx>( let msg = DelayDm(|| { format!( "conflicting implementations of trait `{}`{}{}", - overlap.trait_ref.print_only_trait_path(), + overlap.trait_ref.print_trait_sugared(), overlap.self_ty.map_or_else(String::new, |ty| format!(" for type `{ty}`")), match used_to_be_allowed { Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)",