diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 0b3d50ff2199f..8b17d0e69797c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -663,6 +663,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !result.is_empty() { mutate_fulfillment_errors(&mut result); self.adjust_fulfillment_errors_for_expr_obligation(&mut result); + result.retain(|error| !self.add_error(&error.obligation.cause)); + self.err_ctxt().report_fulfillment_errors(result); } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 36abd7c85550f..7b206e64a1794 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -403,14 +403,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // that are not closures, then we type-check the closures. This is so // that we have more information about the types of arguments when we // type-check the functions. This isn't really the right way to do this. + self.select_obligations_where_possible(|_| {}); for check_closures in [false, true] { // More awful hacks: before we check argument types, try to do // an "opportunistic" trait resolution of any trait bounds on // the call. This helps coercions. if check_closures { - self.select_obligations_where_possible(|_| {}) + self.select_obligations_where_possible(|_| {}); } - // Check each argument, to satisfy the input it was provided for // Visually, we're traveling down the diagonal of the compatibility matrix for (idx, arg) in provided_args.iter().enumerate() { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 0c6226ce71e78..0aaddf41a2080 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -9,6 +9,7 @@ use std::cell::{Cell, RefCell}; use std::ops::Deref; use hir::def_id::CRATE_DEF_ID; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::DiagCtxtHandle; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, HirId, ItemLocalMap}; @@ -16,7 +17,7 @@ use rustc_hir_analysis::hir_ty_lowering::{ HirTyLowerer, InherentAssocCandidate, RegionInferReason, }; use rustc_infer::infer::{self, RegionVariableOrigin}; -use rustc_infer::traits::{DynCompatibilityViolation, Obligation}; +use rustc_infer::traits::{DynCompatibilityViolation, Obligation, ObligationCauseCodeHandle}; use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::Session; use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span, sym}; @@ -126,6 +127,8 @@ pub(crate) struct FnCtxt<'a, 'tcx> { /// These are stored here so we may collect them when canonicalizing user /// type ascriptions later. pub(super) trait_ascriptions: RefCell>>>, + + error_causes: RefCell>>>, } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -154,6 +157,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { diverging_fallback_behavior, diverging_block_behavior, trait_ascriptions: Default::default(), + error_causes: Default::default(), + } + } + + pub(crate) fn add_error(&self, error: &ObligationCause<'tcx>) -> bool { + let mut error_causes = self.error_causes.borrow_mut(); + let body_id = &error.body_id; + let code = error.code_handle(); + + if let Some(s) = error_causes.get_mut(body_id) { + if s.contains(code) { + true + } else { + s.insert(code.clone()); + false + } + } else { + let mut s = FxHashSet::default(); + s.insert(code.clone()); + error_causes.insert(body_id.clone(), s); + false } } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 5bdde3a514e48..a7607a92e95af 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -95,6 +95,11 @@ impl<'tcx> ObligationCause<'tcx> { &self.code } + #[inline] + pub fn code_handle(&self) -> &ObligationCauseCodeHandle<'tcx> { + &self.code + } + pub fn map_code( &mut self, f: impl FnOnce(ObligationCauseCodeHandle<'tcx>) -> ObligationCauseCode<'tcx>, @@ -145,7 +150,7 @@ impl<'tcx> ObligationCause<'tcx> { } /// A compact form of `ObligationCauseCode`. -#[derive(Clone, PartialEq, Eq, Default, HashStable)] +#[derive(Clone, PartialEq, Eq, Default, HashStable, Hash)] #[derive(TypeVisitable, TypeFoldable, TyEncodable, TyDecodable)] pub struct ObligationCauseCodeHandle<'tcx> { /// `None` for `ObligationCauseCode::Misc` (a common case, occurs ~60% of @@ -177,7 +182,7 @@ impl<'tcx> std::ops::Deref for ObligationCauseCodeHandle<'tcx> { } } -#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable, Hash)] #[derive(TypeVisitable, TypeFoldable)] pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from the span. @@ -420,7 +425,7 @@ pub enum ObligationCauseCode<'tcx> { /// Whether a value can be extracted into a const. /// Used for diagnostics around array repeat expressions. -#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, Hash, TyEncodable, TyDecodable)] pub enum IsConstable { No, /// Call to a const fn @@ -516,7 +521,7 @@ impl<'tcx> ObligationCauseCode<'tcx> { #[cfg(target_pointer_width = "64")] rustc_data_structures::static_assert_size!(ObligationCauseCode<'_>, 48); -#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, HashStable, Hash, TyEncodable, TyDecodable)] #[derive(TypeVisitable, TypeFoldable)] pub struct MatchExpressionArmCause<'tcx> { pub arm_block_id: Option, @@ -543,7 +548,7 @@ pub struct MatchExpressionArmCause<'tcx> { /// Fields here refer to the scrutinee of a pattern. /// If the scrutinee isn't given in the diagnostic, then this won't exist. #[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[derive(TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeFoldable, TypeVisitable, HashStable, Hash, TyEncodable, TyDecodable)] pub struct PatternOriginExpr { /// A span representing the scrutinee expression, with all leading references /// peeled from the expression. @@ -558,7 +563,7 @@ pub struct PatternOriginExpr { pub peeled_prefix_suggestion_parentheses: bool, } -#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, HashStable, Hash, TyEncodable, TyDecodable)] #[derive(TypeVisitable, TypeFoldable)] pub struct DerivedCause<'tcx> { /// The trait predicate of the parent obligation that led to the @@ -571,7 +576,7 @@ pub struct DerivedCause<'tcx> { pub parent_code: ObligationCauseCodeHandle<'tcx>, } -#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, HashStable, Hash, TyEncodable, TyDecodable)] #[derive(TypeVisitable, TypeFoldable)] pub struct ImplDerivedCause<'tcx> { pub derived: DerivedCause<'tcx>, @@ -585,7 +590,7 @@ pub struct ImplDerivedCause<'tcx> { pub span: Span, } -#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, HashStable, Hash, TyEncodable, TyDecodable)] #[derive(TypeVisitable, TypeFoldable)] pub struct DerivedHostCause<'tcx> { /// The trait predicate of the parent obligation that led to the @@ -598,7 +603,7 @@ pub struct DerivedHostCause<'tcx> { pub parent_code: ObligationCauseCodeHandle<'tcx>, } -#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] #[derive(TypeVisitable, TypeFoldable)] pub struct ImplDerivedHostCause<'tcx> { pub derived: DerivedHostCause<'tcx>, diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index df82c7a826be9..a04b90ec0ea78 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -249,7 +249,7 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef> for AdtDef<'tcx> { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable, Hash, TyEncodable, TyDecodable)] pub enum AdtKind { Struct, Union, diff --git a/tests/ui/suggestions/duplcate-diagnostics-issue-144074.rs b/tests/ui/suggestions/duplcate-diagnostics-issue-144074.rs new file mode 100644 index 0000000000000..e7467cdd3e5d0 --- /dev/null +++ b/tests/ui/suggestions/duplcate-diagnostics-issue-144074.rs @@ -0,0 +1,10 @@ +struct Struct(T); +fn assert_sized(_x: impl Sized) {} +fn f() { + assert_sized(Struct(*"")); //~ ERROR: the size for values of type `str` cannot be known at compilation time + //~^ ERROR: the size for values of type `str` cannot be known at compilation time +} + +fn main() { + f(); +} diff --git a/tests/ui/suggestions/duplcate-diagnostics-issue-144074.stderr b/tests/ui/suggestions/duplcate-diagnostics-issue-144074.stderr new file mode 100644 index 0000000000000..9edaaae0b4e48 --- /dev/null +++ b/tests/ui/suggestions/duplcate-diagnostics-issue-144074.stderr @@ -0,0 +1,43 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/duplcate-diagnostics-issue-144074.rs:4:25 + | +LL | assert_sized(Struct(*"")); + | ------ ^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `str` +note: required by a bound in `Struct` + --> $DIR/duplcate-diagnostics-issue-144074.rs:1:15 + | +LL | struct Struct(T); + | ^ required by this bound in `Struct` +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - assert_sized(Struct(*"")); +LL + assert_sized(Struct("")); + | + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/duplcate-diagnostics-issue-144074.rs:4:18 + | +LL | assert_sized(Struct(*"")); + | ^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` +note: required by an implicit `Sized` bound in `Struct` + --> $DIR/duplcate-diagnostics-issue-144074.rs:1:15 + | +LL | struct Struct(T); + | ^ required by the implicit `Sized` requirement on this type parameter in `Struct` +help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` + --> $DIR/duplcate-diagnostics-issue-144074.rs:1:15 + | +LL | struct Struct(T); + | ^ - ...if indirection were used here: `Box` + | | + | this could be changed to `T: ?Sized`... + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`.