From 218caa410aa38c29984be31a5229b9fa717560ee Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:19:13 +0200 Subject: Merging upstream version 1.68.2+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_infer/src/errors/mod.rs | 427 ++++++++++++++++++++- compiler/rustc_infer/src/infer/at.rs | 18 +- .../src/infer/canonical/canonicalizer.rs | 20 +- .../src/infer/canonical/query_response.rs | 15 +- compiler/rustc_infer/src/infer/combine.rs | 6 +- compiler/rustc_infer/src/infer/equate.rs | 15 +- .../rustc_infer/src/infer/error_reporting/mod.rs | 185 ++++++--- .../src/infer/error_reporting/need_type_info.rs | 113 ++++-- .../nice_region_error/find_anon_type.rs | 4 +- .../infer/error_reporting/nice_region_error/mod.rs | 2 +- .../nice_region_error/named_anon_conflict.rs | 43 +-- .../nice_region_error/placeholder_error.rs | 323 ++++++++-------- .../nice_region_error/placeholder_relation.rs | 14 +- .../nice_region_error/static_impl_trait.rs | 400 ++++++++++--------- .../nice_region_error/trait_impl_difference.rs | 76 ++-- .../rustc_infer/src/infer/error_reporting/note.rs | 195 ++++------ .../src/infer/error_reporting/note_region.rs | 427 --------------------- .../src/infer/error_reporting/suggest.rs | 85 ++-- compiler/rustc_infer/src/infer/freshen.rs | 5 +- compiler/rustc_infer/src/infer/glb.rs | 5 + compiler/rustc_infer/src/infer/lattice.rs | 14 +- .../src/infer/lexical_region_resolve/mod.rs | 55 +-- compiler/rustc_infer/src/infer/lub.rs | 5 + compiler/rustc_infer/src/infer/mod.rs | 111 ++++-- compiler/rustc_infer/src/infer/nll_relate/mod.rs | 48 ++- compiler/rustc_infer/src/infer/note.rs | 203 ---------- compiler/rustc_infer/src/infer/opaque_types.rs | 58 +-- .../rustc_infer/src/infer/opaque_types/table.rs | 5 - .../rustc_infer/src/infer/outlives/components.rs | 32 +- compiler/rustc_infer/src/infer/outlives/env.rs | 8 +- .../rustc_infer/src/infer/outlives/obligations.rs | 124 +----- compiler/rustc_infer/src/infer/outlives/verify.rs | 73 ++-- compiler/rustc_infer/src/infer/projection.rs | 4 +- .../src/infer/region_constraints/leak_check.rs | 10 +- .../src/infer/region_constraints/mod.rs | 18 +- compiler/rustc_infer/src/infer/resolve.rs | 4 +- compiler/rustc_infer/src/infer/sub.rs | 15 +- compiler/rustc_infer/src/infer/type_variable.rs | 2 +- compiler/rustc_infer/src/infer/undo_log.rs | 8 +- compiler/rustc_infer/src/traits/project.rs | 6 +- compiler/rustc_infer/src/traits/util.rs | 35 +- 41 files changed, 1503 insertions(+), 1713 deletions(-) delete mode 100644 compiler/rustc_infer/src/infer/error_reporting/note_region.rs delete mode 100644 compiler/rustc_infer/src/infer/note.rs (limited to 'compiler/rustc_infer/src') diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 74c4c65cc..033a1842e 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1,15 +1,18 @@ use hir::GenericParamKind; use rustc_errors::{ fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString, - MultiSpan, SubdiagnosticMessage, + IntoDiagnosticArg, MultiSpan, SubdiagnosticMessage, }; use rustc_hir as hir; -use rustc_hir::{FnRetTy, Ty}; +use rustc_hir::FnRetTy; use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_middle::ty::{Region, TyCtxt}; +use rustc_middle::ty::print::TraitRefPrintOnlyTraitPath; +use rustc_middle::ty::{Binder, FnSig, Region, Ty, TyCtxt}; use rustc_span::symbol::kw; +use rustc_span::Symbol; use rustc_span::{symbol::Ident, BytePos, Span}; +use crate::infer::error_reporting::nice_region_error::placeholder_error::Highlighted; use crate::infer::error_reporting::{ need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind}, ObligationCauseAsDiagArg, @@ -357,8 +360,8 @@ impl AddToDiagnostic for LifetimeMismatchLabels { pub struct AddLifetimeParamsSuggestion<'a> { pub tcx: TyCtxt<'a>, pub sub: Region<'a>, - pub ty_sup: &'a Ty<'a>, - pub ty_sub: &'a Ty<'a>, + pub ty_sup: &'a hir::Ty<'a>, + pub ty_sub: &'a hir::Ty<'a>, pub add_note: bool, } @@ -369,8 +372,8 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> { { let mut mk_suggestion = || { let ( - hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. }, - hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. }, + hir::Ty { kind: hir::TyKind::Ref(lifetime_sub, _), .. }, + hir::Ty { kind: hir::TyKind::Ref(lifetime_sup, _), .. }, ) = (self.ty_sub, self.ty_sup) else { return false; }; @@ -517,6 +520,414 @@ pub struct MismatchedStaticLifetime<'a> { pub expl: Option>, #[subdiagnostic] pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl, - #[subdiagnostic(eager)] + #[subdiagnostic] pub implicit_static_lifetimes: Vec, } + +#[derive(Diagnostic)] +pub enum ExplicitLifetimeRequired<'a> { + #[diag(infer_explicit_lifetime_required_with_ident, code = "E0621")] + WithIdent { + #[primary_span] + #[label] + span: Span, + simple_ident: Ident, + named: String, + #[suggestion( + infer_explicit_lifetime_required_sugg_with_ident, + code = "{new_ty}", + applicability = "unspecified" + )] + new_ty_span: Span, + #[skip_arg] + new_ty: Ty<'a>, + }, + #[diag(infer_explicit_lifetime_required_with_param_type, code = "E0621")] + WithParamType { + #[primary_span] + #[label] + span: Span, + named: String, + #[suggestion( + infer_explicit_lifetime_required_sugg_with_param_type, + code = "{new_ty}", + applicability = "unspecified" + )] + new_ty_span: Span, + #[skip_arg] + new_ty: Ty<'a>, + }, +} + +pub enum TyOrSig<'tcx> { + Ty(Highlighted<'tcx, Ty<'tcx>>), + ClosureSig(Highlighted<'tcx, Binder<'tcx, FnSig<'tcx>>>), +} + +impl IntoDiagnosticArg for TyOrSig<'_> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + match self { + TyOrSig::Ty(ty) => ty.into_diagnostic_arg(), + TyOrSig::ClosureSig(sig) => sig.into_diagnostic_arg(), + } + } +} + +#[derive(Subdiagnostic)] +pub enum ActualImplExplNotes<'tcx> { + #[note(infer_actual_impl_expl_expected_signature_two)] + ExpectedSignatureTwo { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + lifetime_2: usize, + }, + #[note(infer_actual_impl_expl_expected_signature_any)] + ExpectedSignatureAny { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + }, + #[note(infer_actual_impl_expl_expected_signature_some)] + ExpectedSignatureSome { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + }, + #[note(infer_actual_impl_expl_expected_signature_nothing)] + ExpectedSignatureNothing { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + }, + #[note(infer_actual_impl_expl_expected_passive_two)] + ExpectedPassiveTwo { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + lifetime_2: usize, + }, + #[note(infer_actual_impl_expl_expected_passive_any)] + ExpectedPassiveAny { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + }, + #[note(infer_actual_impl_expl_expected_passive_some)] + ExpectedPassiveSome { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + }, + #[note(infer_actual_impl_expl_expected_passive_nothing)] + ExpectedPassiveNothing { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + }, + #[note(infer_actual_impl_expl_expected_other_two)] + ExpectedOtherTwo { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + lifetime_2: usize, + }, + #[note(infer_actual_impl_expl_expected_other_any)] + ExpectedOtherAny { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + }, + #[note(infer_actual_impl_expl_expected_other_some)] + ExpectedOtherSome { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + }, + #[note(infer_actual_impl_expl_expected_other_nothing)] + ExpectedOtherNothing { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + }, + #[note(infer_actual_impl_expl_but_actually_implements_trait)] + ButActuallyImplementsTrait { + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + has_lifetime: bool, + lifetime: usize, + }, + #[note(infer_actual_impl_expl_but_actually_implemented_for_ty)] + ButActuallyImplementedForTy { + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + has_lifetime: bool, + lifetime: usize, + ty: String, + }, + #[note(infer_actual_impl_expl_but_actually_ty_implements)] + ButActuallyTyImplements { + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + has_lifetime: bool, + lifetime: usize, + ty: String, + }, +} + +pub enum ActualImplExpectedKind { + Signature, + Passive, + Other, +} + +pub enum ActualImplExpectedLifetimeKind { + Two, + Any, + Some, + Nothing, +} + +impl<'tcx> ActualImplExplNotes<'tcx> { + pub fn new_expected( + kind: ActualImplExpectedKind, + lt_kind: ActualImplExpectedLifetimeKind, + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + lifetime_2: usize, + ) -> Self { + match (kind, lt_kind) { + (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Two) => { + Self::ExpectedSignatureTwo { + leading_ellipsis, + ty_or_sig, + trait_path, + lifetime_1, + lifetime_2, + } + } + (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Any) => { + Self::ExpectedSignatureAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Some) => { + Self::ExpectedSignatureSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Nothing) => { + Self::ExpectedSignatureNothing { leading_ellipsis, ty_or_sig, trait_path } + } + (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Two) => { + Self::ExpectedPassiveTwo { + leading_ellipsis, + ty_or_sig, + trait_path, + lifetime_1, + lifetime_2, + } + } + (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Any) => { + Self::ExpectedPassiveAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Some) => { + Self::ExpectedPassiveSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Nothing) => { + Self::ExpectedPassiveNothing { leading_ellipsis, ty_or_sig, trait_path } + } + (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Two) => { + Self::ExpectedOtherTwo { + leading_ellipsis, + ty_or_sig, + trait_path, + lifetime_1, + lifetime_2, + } + } + (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Any) => { + Self::ExpectedOtherAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Some) => { + Self::ExpectedOtherSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Nothing) => { + Self::ExpectedOtherNothing { leading_ellipsis, ty_or_sig, trait_path } + } + } + } +} + +#[derive(Diagnostic)] +#[diag(infer_trait_placeholder_mismatch)] +pub struct TraitPlaceholderMismatch<'tcx> { + #[primary_span] + pub span: Span, + #[label(label_satisfy)] + pub satisfy_span: Option, + #[label(label_where)] + pub where_span: Option, + #[label(label_dup)] + pub dup_span: Option, + pub def_id: String, + pub trait_def_id: String, + + #[subdiagnostic] + pub actual_impl_expl_notes: Vec>, +} + +pub struct ConsiderBorrowingParamHelp { + pub spans: Vec, +} + +impl AddToDiagnostic for ConsiderBorrowingParamHelp { + fn add_to_diagnostic_with(self, diag: &mut Diagnostic, f: F) + where + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, + { + let mut type_param_span: MultiSpan = self.spans.clone().into(); + for &span in &self.spans { + // Seems like we can't call f() here as Into is required + type_param_span.push_span_label(span, fluent::infer_tid_consider_borrowing); + } + let msg = f(diag, fluent::infer_tid_param_help.into()); + diag.span_help(type_param_span, msg); + } +} + +#[derive(Subdiagnostic)] +#[help(infer_tid_rel_help)] +pub struct RelationshipHelp; + +#[derive(Diagnostic)] +#[diag(infer_trait_impl_diff)] +pub struct TraitImplDiff { + #[primary_span] + #[label(found)] + pub sp: Span, + #[label(expected)] + pub trait_sp: Span, + #[note(expected_found)] + pub note: (), + #[subdiagnostic] + pub param_help: ConsiderBorrowingParamHelp, + #[subdiagnostic] + // Seems like subdiagnostics are always pushed to the end, so this one + // also has to be a subdiagnostic to maintain order. + pub rel_help: Option, + pub expected: String, + pub found: String, +} + +pub struct DynTraitConstraintSuggestion { + pub span: Span, + pub ident: Ident, +} + +impl AddToDiagnostic for DynTraitConstraintSuggestion { + fn add_to_diagnostic_with(self, diag: &mut Diagnostic, f: F) + where + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, + { + let mut multi_span: MultiSpan = vec![self.span].into(); + multi_span.push_span_label(self.span, fluent::infer_dtcs_has_lifetime_req_label); + multi_span.push_span_label(self.ident.span, fluent::infer_dtcs_introduces_requirement); + let msg = f(diag, fluent::infer_dtcs_has_req_note.into()); + diag.span_note(multi_span, msg); + let msg = f(diag, fluent::infer_dtcs_suggestion.into()); + diag.span_suggestion_verbose( + self.span.shrink_to_hi(), + msg, + " + '_", + Applicability::MaybeIncorrect, + ); + } +} + +#[derive(Diagnostic)] +#[diag(infer_but_calling_introduces, code = "E0772")] +pub struct ButCallingIntroduces { + #[label(label1)] + pub param_ty_span: Span, + #[primary_span] + #[label(label2)] + pub cause_span: Span, + + pub has_param_name: bool, + pub param_name: String, + pub has_lifetime: bool, + pub lifetime: String, + pub assoc_item: Symbol, + pub has_impl_path: bool, + pub impl_path: String, +} + +pub struct ReqIntroducedLocations { + pub span: MultiSpan, + pub spans: Vec, + pub fn_decl_span: Span, + pub cause_span: Span, + pub add_label: bool, +} + +impl AddToDiagnostic for ReqIntroducedLocations { + fn add_to_diagnostic_with(mut self, diag: &mut Diagnostic, f: F) + where + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, + { + for sp in self.spans { + self.span.push_span_label(sp, fluent::infer_ril_introduced_here); + } + + if self.add_label { + self.span.push_span_label(self.fn_decl_span, fluent::infer_ril_introduced_by); + } + self.span.push_span_label(self.cause_span, fluent::infer_ril_because_of); + let msg = f(diag, fluent::infer_ril_static_introduced_by.into()); + diag.span_note(self.span, msg); + } +} + +pub struct MoreTargeted { + pub ident: Symbol, +} + +impl AddToDiagnostic for MoreTargeted { + fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _f: F) + where + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, + { + diag.code(rustc_errors::error_code!(E0772)); + diag.set_primary_message(fluent::infer_more_targeted); + diag.set_arg("ident", self.ident); + } +} + +#[derive(Diagnostic)] +#[diag(infer_but_needs_to_satisfy, code = "E0759")] +pub struct ButNeedsToSatisfy { + #[primary_span] + pub sp: Span, + #[label(influencer)] + pub influencer_point: Span, + #[label(used_here)] + pub spans: Vec, + #[label(require)] + pub require_span_as_label: Option, + #[note(require)] + pub require_span_as_note: Option, + #[note(introduced_by_bound)] + pub bound: Option, + + #[subdiagnostic] + pub req_introduces_loc: Option, + + pub spans_empty: bool, + pub has_lifetime: bool, + pub lifetime: String, +} diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 4429e4f43..d816a9ed3 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -411,7 +411,7 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> { } } -impl<'tcx> ToTrace<'tcx> for ty::ProjectionTy<'tcx> { +impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> { fn to_trace( tcx: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, @@ -419,11 +419,23 @@ impl<'tcx> ToTrace<'tcx> for ty::ProjectionTy<'tcx> { a: Self, b: Self, ) -> TypeTrace<'tcx> { - let a_ty = tcx.mk_projection(a.item_def_id, a.substs); - let b_ty = tcx.mk_projection(b.item_def_id, b.substs); + let a_ty = tcx.mk_projection(a.def_id, a.substs); + let b_ty = tcx.mk_projection(b.def_id, b.substs); TypeTrace { cause: cause.clone(), values: Terms(ExpectedFound::new(a_is_expected, a_ty.into(), b_ty.into())), } } } + +impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> { + fn to_trace( + _: TyCtxt<'tcx>, + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self, + ) -> TypeTrace<'tcx> { + TypeTrace { cause: cause.clone(), values: Sigs(ExpectedFound::new(a_is_expected, a, b)) } + } +} diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 3dc0d60b1..091635e6c 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -6,8 +6,7 @@ //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html use crate::infer::canonical::{ - Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Canonicalized, - OriginalQueryValues, + Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, OriginalQueryValues, }; use crate::infer::InferCtxt; use rustc_middle::ty::flags::FlagComputation; @@ -40,7 +39,7 @@ impl<'tcx> InferCtxt<'tcx> { &self, value: V, query_state: &mut OriginalQueryValues<'tcx>, - ) -> Canonicalized<'tcx, V> + ) -> Canonical<'tcx, V> where V: TypeFoldable<'tcx>, { @@ -59,7 +58,7 @@ impl<'tcx> InferCtxt<'tcx> { &self, value: V, query_state: &mut OriginalQueryValues<'tcx>, - ) -> Canonicalized<'tcx, V> + ) -> Canonical<'tcx, V> where V: TypeFoldable<'tcx>, { @@ -99,7 +98,7 @@ impl<'tcx> InferCtxt<'tcx> { /// out the [chapter in the rustc dev guide][c]. /// /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query-result - pub fn canonicalize_response(&self, value: V) -> Canonicalized<'tcx, V> + pub fn canonicalize_response(&self, value: V) -> Canonical<'tcx, V> where V: TypeFoldable<'tcx>, { @@ -113,7 +112,7 @@ impl<'tcx> InferCtxt<'tcx> { ) } - pub fn canonicalize_user_type_annotation(&self, value: V) -> Canonicalized<'tcx, V> + pub fn canonicalize_user_type_annotation(&self, value: V) -> Canonical<'tcx, V> where V: TypeFoldable<'tcx>, { @@ -135,7 +134,7 @@ impl<'tcx> InferCtxt<'tcx> { &self, value: V, query_state: &mut OriginalQueryValues<'tcx>, - ) -> Canonicalized<'tcx, V> + ) -> Canonical<'tcx, V> where V: TypeFoldable<'tcx>, { @@ -453,10 +452,9 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { | ty::Dynamic(..) | ty::Never | ty::Tuple(..) - | ty::Projection(..) + | ty::Alias(..) | ty::Foreign(..) - | ty::Param(..) - | ty::Opaque(..) => { + | ty::Param(..) => { if t.flags().intersects(self.needs_canonical_flags) { t.super_fold_with(self) } else { @@ -525,7 +523,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { tcx: TyCtxt<'tcx>, canonicalize_region_mode: &dyn CanonicalizeMode, query_state: &mut OriginalQueryValues<'tcx>, - ) -> Canonicalized<'tcx, V> + ) -> Canonical<'tcx, V> where V: TypeFoldable<'tcx>, { diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 996b1c40e..3d49182f0 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -9,7 +9,7 @@ use crate::infer::canonical::substitute::{substitute_value, CanonicalExt}; use crate::infer::canonical::{ - Canonical, CanonicalVarValues, CanonicalizedQueryResponse, Certainty, OriginalQueryValues, + Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues, QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse, }; use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; @@ -57,7 +57,7 @@ impl<'tcx> InferCtxt<'tcx> { inference_vars: CanonicalVarValues<'tcx>, answer: T, fulfill_cx: &mut dyn TraitEngine<'tcx>, - ) -> Fallible> + ) -> Fallible> where T: Debug + TypeFoldable<'tcx>, Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>, @@ -151,11 +151,12 @@ impl<'tcx> InferCtxt<'tcx> { }) } - fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> { - self.inner - .borrow_mut() - .opaque_type_storage - .take_opaque_types() + /// FIXME: This method should only be used for canonical queries and therefore be private. + /// + /// As the new solver does canonicalization slightly differently, this is also used there + /// for now. This should hopefully change fairly soon. + pub fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> { + std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types) .into_iter() .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)) .collect() diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index cf895ed0d..72676b718 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -219,7 +219,7 @@ impl<'tcx> InferCtxt<'tcx> { /// /// As `3 + 4` contains `N` in its substs, this must not succeed. /// - /// See `src/test/ui/const-generics/occurs-check/` for more examples where this is relevant. + /// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant. #[instrument(level = "debug", skip(self))] fn unify_const_variable( &self, @@ -331,7 +331,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown()); // Generalize type of `a_ty` appropriately depending on the - // direction. As an example, assume: + // direction. As an example, assume: // // - `a_ty == &'x ?1`, where `'x` is some free region and `?1` is an // inference variable, @@ -675,7 +675,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { // relatable. Ok(t) } - ty::Opaque(def_id, substs) => { + ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { let s = self.relate(substs, substs)?; Ok(if s == substs { t } else { self.infcx.tcx.mk_opaque(def_id, s) }) } diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index 8682f4d3b..46e7813d9 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -100,11 +100,15 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?; } - (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => { + ( + &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), + &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), + ) if a_def_id == b_def_id => { self.fields.infcx.super_combine_tys(self, a, b)?; } - (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) - if self.fields.define_opaque_types && did.is_local() => + (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) + | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) + if self.fields.define_opaque_types && def_id.is_local() => { self.fields.obligations.extend( infcx @@ -178,6 +182,11 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { where T: Relate<'tcx>, { + // A binder is equal to itself if it's structually equal to itself + if a == b { + return Ok(a); + } + if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() { self.fields.higher_ranked_sub(a, b, self.a_is_expected)?; self.fields.higher_ranked_sub(b, a, self.a_is_expected)?; diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 987559d7e..28fd03b87 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1,4 +1,3 @@ -// ignore-tidy-filelength //! Error Reporting Code for the inference engine //! //! Because of the way inference, and in particular region inference, @@ -56,6 +55,7 @@ use crate::infer::ExpectedFound; use crate::traits::error_reporting::report_object_safety_error; use crate::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, + PredicateObligation, }; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; @@ -92,8 +92,12 @@ pub mod nice_region_error; pub struct TypeErrCtxt<'a, 'tcx> { pub infcx: &'a InferCtxt<'tcx>, pub typeck_results: Option>>, - pub normalize_fn_sig: Box) -> ty::PolyFnSig<'tcx> + 'a>, pub fallback_has_occurred: bool, + + pub normalize_fn_sig: Box) -> ty::PolyFnSig<'tcx> + 'a>, + + pub autoderef_steps: + Box) -> Vec<(Ty<'tcx>, Vec>)> + 'a>, } impl TypeErrCtxt<'_, '_> { @@ -184,7 +188,7 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>( let text = if br.has_name() { format!("the lifetime `{}` as defined here", br.name) } else { - format!("the anonymous lifetime as defined here") + "the anonymous lifetime as defined here".to_string() }; (text, sp) } @@ -203,7 +207,7 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>( sp = param.span; } let text = if name == kw::UnderscoreLifetime { - format!("the anonymous lifetime as defined here") + "the anonymous lifetime as defined here".to_string() } else { format!("the lifetime `{}` as defined here", name) }; @@ -303,6 +307,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( None, format!("captures `{}`", hidden_region), None, + Some(reg_info.def_id), ) } } @@ -310,7 +315,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( // Ugh. This is a painful case: the hidden region is not one // that we can easily summarize or explain. This can happen // in a case like - // `src/test/ui/multiple-lifetimes/ordinary-bounds-unsuited.rs`: + // `tests/ui/multiple-lifetimes/ordinary-bounds-unsuited.rs`: // // ``` // fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> { @@ -339,11 +344,13 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( impl<'tcx> InferCtxt<'tcx> { pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option> { let (def_id, substs) = match *ty.kind() { - ty::Opaque(def_id, substs) => (def_id, substs), - ty::Projection(data) - if self.tcx.def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder => + ty::Alias(_, ty::AliasTy { def_id, substs, .. }) + if matches!( + self.tcx.def_kind(def_id), + DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder + ) => { - (data.item_def_id, data.substs) + (def_id, substs) } _ => return None, }; @@ -357,7 +364,7 @@ impl<'tcx> InferCtxt<'tcx> { .kind() .map_bound(|kind| match kind { ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate)) - if projection_predicate.projection_ty.item_def_id == item_def_id => + if projection_predicate.projection_ty.def_id == item_def_id => { projection_predicate.term.ty() } @@ -727,7 +734,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { format!("this and all prior arms are found to be of type `{}`", t), ); } - let outer_error_span = if any_multiline_arm { + let outer = if any_multiline_arm || !source_map.is_multiline(cause.span) { // Cover just `match` and the scrutinee expression, not // the entire match body, to reduce diagram noise. cause.span.shrink_to_lo().to(scrut_span) @@ -735,7 +742,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { cause.span }; let msg = "`match` arms have incompatible types"; - err.span_label(outer_error_span, msg); + err.span_label(outer, msg); self.suggest_remove_semi_or_return_binding( err, prior_arm_block_id, @@ -1393,7 +1400,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { /// `swap_secondary_and_primary` is used to make projection errors in particular nicer by using /// the message in `secondary_span` as the primary label, and apply the message that would /// otherwise be used for the primary label on the `secondary_span` `Span`. This applies on - /// E0271, like `src/test/ui/issues/issue-39970.stderr`. + /// E0271, like `tests/ui/issues/issue-39970.stderr`. #[instrument( level = "debug", skip(self, diag, secondary_span, swap_secondary_and_primary, prefer_label) @@ -1426,8 +1433,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { impl<'tcx> OpaqueTypesVisitor<'tcx> { fn visit_expected_found( tcx: TyCtxt<'tcx>, - expected: Ty<'tcx>, - found: Ty<'tcx>, + expected: impl TypeVisitable<'tcx>, + found: impl TypeVisitable<'tcx>, ignore_span: Span, ) -> Self { let mut types_visitor = OpaqueTypesVisitor { @@ -1567,6 +1574,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { _ => (false, Mismatch::Fixed("type")), } } + ValuePairs::Sigs(infer::ExpectedFound { expected, found }) => { + OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span) + .report(diag); + (false, Mismatch::Fixed("signature")) + } ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => { (false, Mismatch::Fixed("trait")) } @@ -1730,7 +1742,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let extra = expected == found; let sort_string = |ty: Ty<'tcx>, path: Option| { let mut s = match (extra, ty.kind()) { - (true, ty::Opaque(def_id, _)) => { + (true, ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) => { let sm = self.tcx.sess.source_map(); let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo()); format!( @@ -1740,12 +1752,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { pos.col.to_usize() + 1, ) } - (true, ty::Projection(proj)) - if self.tcx.def_kind(proj.item_def_id) + (true, ty::Alias(ty::Projection, proj)) + if self.tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder => { let sm = self.tcx.sess.source_map(); - let pos = sm.lookup_char_pos(self.tcx.def_span(proj.item_def_id).lo()); + let pos = sm.lookup_char_pos(self.tcx.def_span(proj.def_id).lo()); format!( " (trait associated opaque type at <{}:{}:{}>)", sm.filename_for_diagnostics(&pos.file.name), @@ -1770,9 +1782,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // like when you have two references but one is `usize` and the other // is `f32`. In those cases we still want to show the `note`. If the // value from `ef` is `Infer(_)`, then we ignore it. - if !ef.expected.is_ty_infer() { + if !ef.expected.is_ty_or_numeric_infer() { ef.expected != values.expected - } else if !ef.found.is_ty_infer() { + } else if !ef.found.is_ty_or_numeric_infer() { ef.found != values.found } else { false @@ -1834,7 +1846,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // In some (most?) cases cause.body_id points to actual body, but in some cases // it's an actual definition. According to the comments (e.g. in - // rustc_hir_analysis/check/compare_method.rs:compare_predicate_entailment) the latter + // rustc_hir_analysis/check/compare_impl_item.rs:compare_predicate_entailment) the latter // is relied upon by some other code. This might (or might not) need cleanup. let body_owner_def_id = self.tcx.hir().opt_local_def_id(cause.body_id).unwrap_or_else(|| { @@ -1911,6 +1923,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (ty::Tuple(fields), _) => { self.emit_tuple_wrap_err(&mut err, span, found, fields) } + // If a byte was expected and the found expression is a char literal + // containing a single ASCII character, perhaps the user meant to write `b'c'` to + // specify a byte literal + (ty::Uint(ty::UintTy::U8), ty::Char) => { + if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) + && let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) + && code.chars().next().map_or(false, |c| c.is_ascii()) + { + err.span_suggestion( + span, + "if you meant to write a byte literal, prefix with `b`", + format!("b'{}'", escape_literal(code)), + Applicability::MachineApplicable, + ); + } + } // If a character was expected and the found expression is a string literal // containing a single character, perhaps the user meant to write `'c'` to // specify a character literal (issue #92479) @@ -2038,6 +2066,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ret => ret, } } + infer::Sigs(exp_found) => { + let exp_found = self.resolve_vars_if_possible(exp_found); + if exp_found.references_error() { + return None; + } + let (exp, fnd) = self.cmp_fn_sig( + &ty::Binder::dummy(exp_found.expected), + &ty::Binder::dummy(exp_found.found), + ); + Some((exp, fnd, None, None)) + } } } @@ -2126,18 +2165,21 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // suggest adding an explicit lifetime bound to it. let generics = self.tcx.generics_of(generic_param_scope); // type_param_span is (span, has_bounds) + let mut is_synthetic = false; + let mut ast_generics = None; let type_param_span = match bound_kind { GenericKind::Param(ref param) => { // Account for the case where `param` corresponds to `Self`, // which doesn't have the expected type argument. if !(generics.has_self && param.index == 0) { let type_param = generics.type_param(param, self.tcx); + is_synthetic = type_param.kind.is_synthetic(); type_param.def_id.as_local().map(|def_id| { // Get the `hir::Param` to verify whether it already has any bounds. // We do this to avoid suggesting code that ends up as `T: 'a'b`, // instead we suggest `T: 'a + 'b` in that case. let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); - let ast_generics = self.tcx.hir().get_generics(hir_id.owner.def_id); + ast_generics = self.tcx.hir().get_generics(hir_id.owner.def_id); let bounds = ast_generics.and_then(|g| g.bounds_span_for_suggestions(def_id)); // `sp` only covers `T`, change it so that it covers @@ -2169,18 +2211,71 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .unwrap_or("'lt".to_string()) }; - let add_lt_sugg = generics - .params - .first() - .and_then(|param| param.def_id.as_local()) - .map(|def_id| (self.tcx.def_span(def_id).shrink_to_lo(), format!("{}, ", new_lt))); + let mut add_lt_suggs: Vec> = vec![]; + if is_synthetic { + if let Some(ast_generics) = ast_generics { + let named_lifetime_param_exist = ast_generics.params.iter().any(|p| { + matches!( + p.kind, + hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } + ) + }); + if named_lifetime_param_exist && let [param, ..] = ast_generics.params + { + add_lt_suggs.push(Some(( + self.tcx.def_span(param.def_id).shrink_to_lo(), + format!("{new_lt}, "), + ))); + } else { + add_lt_suggs + .push(Some((ast_generics.span.shrink_to_hi(), format!("<{new_lt}>")))); + } + } + } else { + if let [param, ..] = &generics.params[..] && let Some(def_id) = param.def_id.as_local() + { + add_lt_suggs + .push(Some((self.tcx.def_span(def_id).shrink_to_lo(), format!("{new_lt}, ")))); + } + } + + if let Some(ast_generics) = ast_generics { + for p in ast_generics.params { + if p.is_elided_lifetime() { + if self + .tcx + .sess + .source_map() + .span_to_prev_source(p.span.shrink_to_hi()) + .ok() + .map_or(false, |s| *s.as_bytes().last().unwrap() == b'&') + { + add_lt_suggs + .push(Some( + ( + p.span.shrink_to_hi(), + if let Ok(snip) = self.tcx.sess.source_map().span_to_next_source(p.span) + && snip.starts_with(' ') + { + format!("{new_lt}") + } else { + format!("{new_lt} ") + } + ) + )); + } else { + add_lt_suggs.push(Some((p.span.shrink_to_hi(), format!("<{new_lt}>")))); + } + } + } + } let labeled_user_string = match bound_kind { GenericKind::Param(ref p) => format!("the parameter type `{}`", p), - GenericKind::Projection(ref p) => format!("the associated type `{}`", p), - GenericKind::Opaque(def_id, substs) => { - format!("the opaque type `{}`", self.tcx.def_path_str_with_substs(def_id, substs)) - } + GenericKind::Alias(ref p) => match p.kind(self.tcx) { + ty::AliasKind::Projection => format!("the associated type `{}`", p), + ty::AliasKind::Opaque => format!("the opaque type `{}`", p), + }, }; if let Some(SubregionOrigin::CompareImplItemObligation { @@ -2202,15 +2297,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { type_param_span: Option<(Span, bool)>, bound_kind: GenericKind<'tcx>, sub: S, - add_lt_sugg: Option<(Span, String)>, + add_lt_suggs: Vec>, ) { let msg = "consider adding an explicit lifetime bound"; if let Some((sp, has_lifetimes)) = type_param_span { let suggestion = if has_lifetimes { format!(" + {}", sub) } else { format!(": {}", sub) }; let mut suggestions = vec![(sp, suggestion)]; - if let Some(add_lt_sugg) = add_lt_sugg { - suggestions.push(add_lt_sugg); + for add_lt_sugg in add_lt_suggs { + if let Some(add_lt_sugg) = add_lt_sugg { + suggestions.push(add_lt_sugg); + } } err.multipart_suggestion_verbose( format!("{msg}..."), @@ -2234,9 +2331,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; let mut sugg = vec![(sp, suggestion), (span.shrink_to_hi(), format!(" + {}", new_lt))]; - if let Some(lt) = add_lt_sugg.clone() { - sugg.push(lt); - sugg.rotate_right(1); + for add_lt_sugg in add_lt_suggs.clone() { + if let Some(lt) = add_lt_sugg { + sugg.push(lt); + sugg.rotate_right(1); + } } // `MaybeIncorrect` due to issue #41966. err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect); @@ -2340,7 +2439,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // for the bound is not suitable for suggestions when `-Zverbose` is set because it // uses `Debug` output, so we handle it specially here so that suggestions are // always correct. - binding_suggestion(&mut err, type_param_span, bound_kind, name, None); + binding_suggestion(&mut err, type_param_span, bound_kind, name, vec![]); err } @@ -2353,7 +2452,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { "{} may not live long enough", labeled_user_string ); - binding_suggestion(&mut err, type_param_span, bound_kind, "'static", None); + binding_suggestion(&mut err, type_param_span, bound_kind, "'static", vec![]); err } @@ -2383,7 +2482,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // fn get_later(g: G, dest: &mut T) -> impl FnOnce() + '_ // suggest: // fn get_later<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a - ty::Closure(_, _substs) | ty::Opaque(_, _substs) if return_impl_trait => { + ty::Closure(..) | ty::Alias(ty::Opaque, ..) if return_impl_trait => { new_binding_suggestion(&mut err, type_param_span); } _ => { @@ -2392,7 +2491,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { type_param_span, bound_kind, new_lt, - add_lt_sugg, + add_lt_suggs, ); } } @@ -2765,7 +2864,7 @@ impl TyCategory { pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> { match *ty.kind() { ty::Closure(def_id, _) => Some((Self::Closure, def_id)), - ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)), + ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => Some((Self::Opaque, def_id)), ty::Generator(def_id, ..) => { Some((Self::Generator(tcx.generator_kind(def_id).unwrap()), def_id)) } diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 8ff1639a3..b8c843a8a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -20,7 +20,7 @@ use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer}; use rustc_middle::ty::{self, DefIdTree, InferConst}; use rustc_middle::ty::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults}; -use rustc_span::symbol::{kw, Ident}; +use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{BytePos, Span}; use std::borrow::Cow; use std::iter; @@ -78,8 +78,8 @@ impl InferenceDiagnosticsData { } fn where_x_is_kind(&self, in_type: Ty<'_>) -> &'static str { - if in_type.is_ty_infer() { - "empty" + if in_type.is_ty_or_numeric_infer() { + "" } else if self.name == "_" { // FIXME: Consider specializing this message if there is a single `_` // in the type. @@ -183,13 +183,24 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte printer } -fn ty_to_string<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String { +fn ty_to_string<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, + called_method_def_id: Option, +) -> String { let printer = fmt_printer(infcx, Namespace::TypeNS); let ty = infcx.resolve_vars_if_possible(ty); - match ty.kind() { + match (ty.kind(), called_method_def_id) { // We don't want the regular output for `fn`s because it includes its path in // invalid pseudo-syntax, we want the `fn`-pointer output instead. - ty::FnDef(..) => ty.fn_sig(infcx.tcx).print(printer).unwrap().into_buffer(), + (ty::FnDef(..), _) => ty.fn_sig(infcx.tcx).print(printer).unwrap().into_buffer(), + (_, Some(def_id)) + if ty.is_ty_or_numeric_infer() + && infcx.tcx.get_diagnostic_item(sym::iterator_collect_fn) == Some(def_id) => + { + "Vec<_>".to_string() + } + _ if ty.is_ty_or_numeric_infer() => "/* Type */".to_string(), // FIXME: The same thing for closures, but this only works when the closure // does not capture anything. // @@ -213,7 +224,7 @@ fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String { .map(|args| { args.tuple_fields() .iter() - .map(|arg| ty_to_string(infcx, arg)) + .map(|arg| ty_to_string(infcx, arg, None)) .collect::>() .join(", ") }) @@ -221,7 +232,7 @@ fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String { let ret = if fn_sig.output().skip_binder().is_unit() { String::new() } else { - format!(" -> {}", ty_to_string(infcx, fn_sig.output().skip_binder())) + format!(" -> {}", ty_to_string(infcx, fn_sig.output().skip_binder(), None)) }; format!("fn({}){}", args, ret) } @@ -368,6 +379,7 @@ impl<'tcx> InferCtxt<'tcx> { } impl<'tcx> TypeErrCtxt<'_, 'tcx> { + #[instrument(level = "debug", skip(self, error_code))] pub fn emit_inference_failure_err( &self, body_id: Option, @@ -406,7 +418,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let mut infer_subdiags = Vec::new(); let mut multi_suggestions = Vec::new(); match kind { - InferSourceKind::LetBinding { insert_span, pattern_name, ty } => { + InferSourceKind::LetBinding { insert_span, pattern_name, ty, def_id } => { infer_subdiags.push(SourceKindSubdiag::LetLike { span: insert_span, name: pattern_name.map(|name| name.to_string()).unwrap_or_else(String::new), @@ -415,7 +427,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { prefix: arg_data.kind.try_get_prefix().unwrap_or_default(), arg_name: arg_data.name, kind: if pattern_name.is_some() { "with_pattern" } else { "other" }, - type_name: ty_to_string(self, ty), + type_name: ty_to_string(self, ty, def_id), }); } InferSourceKind::ClosureArg { insert_span, ty } => { @@ -427,7 +439,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { prefix: arg_data.kind.try_get_prefix().unwrap_or_default(), arg_name: arg_data.name, kind: "closure", - type_name: ty_to_string(self, ty), + type_name: ty_to_string(self, ty, None), }); } InferSourceKind::GenericArg { @@ -456,33 +468,39 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { parent_name, }); - let args = fmt_printer(self, Namespace::TypeNS) - .comma_sep(generic_args.iter().copied().map(|arg| { - if arg.is_suggestable(self.tcx, true) { - return arg; - } + let args = if self.infcx.tcx.get_diagnostic_item(sym::iterator_collect_fn) + == Some(generics_def_id) + { + "Vec<_>".to_string() + } else { + fmt_printer(self, Namespace::TypeNS) + .comma_sep(generic_args.iter().copied().map(|arg| { + if arg.is_suggestable(self.tcx, true) { + return arg; + } - match arg.unpack() { - GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), - GenericArgKind::Type(_) => self - .next_ty_var(TypeVariableOrigin { - span: rustc_span::DUMMY_SP, - kind: TypeVariableOriginKind::MiscVariable, - }) - .into(), - GenericArgKind::Const(arg) => self - .next_const_var( - arg.ty(), - ConstVariableOrigin { + match arg.unpack() { + GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), + GenericArgKind::Type(_) => self + .next_ty_var(TypeVariableOrigin { span: rustc_span::DUMMY_SP, - kind: ConstVariableOriginKind::MiscVariable, - }, - ) - .into(), - } - })) - .unwrap() - .into_buffer(); + kind: TypeVariableOriginKind::MiscVariable, + }) + .into(), + GenericArgKind::Const(arg) => self + .next_const_var( + arg.ty(), + ConstVariableOrigin { + span: rustc_span::DUMMY_SP, + kind: ConstVariableOriginKind::MiscVariable, + }, + ) + .into(), + } + })) + .unwrap() + .into_buffer() + }; if !have_turbofish { infer_subdiags.push(SourceKindSubdiag::GenericSuggestion { @@ -520,7 +538,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { )); } InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => { - let ty_info = ty_to_string(self, ty); + let ty_info = ty_to_string(self, ty, None); multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return( ty_info, data, @@ -608,6 +626,7 @@ enum InferSourceKind<'tcx> { insert_span: Span, pattern_name: Option, ty: Ty<'tcx>, + def_id: Option, }, ClosureArg { insert_span: Span, @@ -661,8 +680,8 @@ impl<'tcx> InferSourceKind<'tcx> { | InferSourceKind::ClosureReturn { ty, .. } => { if ty.is_closure() { ("closure", closure_as_fn_str(infcx, ty)) - } else if !ty.is_ty_infer() { - ("normal", ty_to_string(infcx, ty)) + } else if !ty.is_ty_or_numeric_infer() { + ("normal", ty_to_string(infcx, ty, None)) } else { ("other", String::new()) } @@ -788,10 +807,18 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { /// Uses `fn source_cost` to determine whether this inference source is preferable to /// previous sources. We generally prefer earlier sources. #[instrument(level = "debug", skip(self))] - fn update_infer_source(&mut self, new_source: InferSource<'tcx>) { + fn update_infer_source(&mut self, mut new_source: InferSource<'tcx>) { let cost = self.source_cost(&new_source) + self.attempt; debug!(?cost); self.attempt += 1; + if let Some(InferSource { kind: InferSourceKind::GenericArg { def_id: did, ..}, .. }) = self.infer_source + && let InferSourceKind::LetBinding { ref ty, ref mut def_id, ..} = new_source.kind + && ty.is_ty_or_numeric_infer() + { + // Customize the output so we talk about `let x: Vec<_> = iter.collect();` instead of + // `let x: _ = iter.collect();`, as this is a very common case. + *def_id = Some(did); + } if cost < self.infer_source_cost { self.infer_source_cost = cost; self.infer_source = Some(new_source); @@ -852,7 +879,10 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { match inner.unpack() { GenericArgKind::Lifetime(_) => {} GenericArgKind::Type(ty) => { - if matches!(ty.kind(), ty::Opaque(..) | ty::Closure(..) | ty::Generator(..)) { + if matches!( + ty.kind(), + ty::Alias(ty::Opaque, ..) | ty::Closure(..) | ty::Generator(..) + ) { // Opaque types can't be named by the user right now. // // Both the generic arguments of closures and generators can @@ -1089,6 +1119,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { insert_span: local.pat.span.shrink_to_hi(), pattern_name: local.pat.simple_ident(), ty, + def_id: None, }, }) } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs index d8f540b74..39f4d5022 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -96,8 +96,8 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { } } - hir::TyKind::Rptr(ref lifetime, _) => { - // the lifetime of the TyRptr + hir::TyKind::Ref(ref lifetime, _) => { + // the lifetime of the Ref let hir_id = lifetime.hir_id; match (self.tcx.named_region(hir_id), self.bound_region) { // Find the index of the named region that was part of the diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs index 8a0e332f9..59fb74eb5 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs @@ -9,7 +9,7 @@ mod different_lifetimes; pub mod find_anon_type; mod mismatched_static_lifetime; mod named_anon_conflict; -mod placeholder_error; +pub(crate) mod placeholder_error; mod placeholder_relation; mod static_impl_trait; mod trait_impl_difference; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 3fe7c1598..4e13ec902 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -1,8 +1,11 @@ //! Error Reporting for Anonymous Region Lifetime Errors //! where one region is named and the other is anonymous. -use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type; use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; +use crate::{ + errors::ExplicitLifetimeRequired, + infer::error_reporting::nice_region_error::find_anon_type::find_anon_type, +}; +use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; use rustc_middle::ty; use rustc_span::symbol::kw; @@ -86,31 +89,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { { return None; } - - let (error_var, span_label_var) = match param.pat.simple_ident() { - Some(simple_ident) => ( - format!("the type of `{}`", simple_ident), - format!("the type of `{}`", simple_ident), - ), - None => ("parameter type".to_owned(), "type".to_owned()), + let named = named.to_string(); + let err = match param.pat.simple_ident() { + Some(simple_ident) => ExplicitLifetimeRequired::WithIdent { + span, + simple_ident, + named, + new_ty_span, + new_ty, + }, + None => ExplicitLifetimeRequired::WithParamType { span, named, new_ty_span, new_ty }, }; - - let mut diag = struct_span_err!( - self.tcx().sess, - span, - E0621, - "explicit lifetime required in {}", - error_var - ); - - diag.span_label(span, format!("lifetime `{}` required", named)); - diag.span_suggestion( - new_ty_span, - &format!("add explicit lifetime `{}` to {}", named, span_label_var), - new_ty, - Applicability::Unspecified, - ); - - Some(diag) + Some(self.tcx().sess.parse_sess.create_err(err)) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index 1f554c81e..99431567e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -1,10 +1,14 @@ +use crate::errors::{ + ActualImplExpectedKind, ActualImplExpectedLifetimeKind, ActualImplExplNotes, + TraitPlaceholderMismatch, TyOrSig, +}; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::ValuePairs; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::intern::Interned; -use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg}; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; use rustc_middle::ty::error::ExpectedFound; @@ -12,7 +16,43 @@ use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt}; -use std::fmt::{self, Write}; +use std::fmt; + +// HACK(eddyb) maybe move this in a more central location. +#[derive(Copy, Clone)] +pub struct Highlighted<'tcx, T> { + tcx: TyCtxt<'tcx>, + highlight: RegionHighlightMode<'tcx>, + value: T, +} + +impl<'tcx, T> IntoDiagnosticArg for Highlighted<'tcx, T> +where + T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>, +{ + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + rustc_errors::DiagnosticArgValue::Str(self.to_string().into()) + } +} + +impl<'tcx, T> Highlighted<'tcx, T> { + fn map(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> { + Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) } + } +} + +impl<'tcx, T> fmt::Display for Highlighted<'tcx, T> +where + T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS); + printer.region_highlight_mode = self.highlight; + + let s = self.value.print(printer)?.into_buffer(); + f.write_str(&s) + } +} impl<'tcx> NiceRegionError<'_, 'tcx> { /// When given a `ConcreteFailure` for a function with arguments containing a named region and @@ -205,34 +245,27 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { actual_substs: SubstsRef<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let span = cause.span(); - let msg = format!( - "implementation of `{}` is not general enough", - self.tcx().def_path_str(trait_def_id), - ); - let mut err = self.tcx().sess.struct_span_err(span, &msg); - - let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) - | ObligationCauseCode::ExprItemObligation(def_id, ..) = - *cause.code() - { - err.span_label(span, "doesn't satisfy where-clause"); - err.span_label( - self.tcx().def_span(def_id), - &format!("due to a where-clause on `{}`...", self.tcx().def_path_str(def_id)), - ); - true - } else { - err.span_label(span, &msg); - false - }; - let expected_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef { - def_id: trait_def_id, - substs: expected_substs, - }); - let actual_trait_ref = self + let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) = + if let ObligationCauseCode::ItemObligation(def_id) + | ObligationCauseCode::ExprItemObligation(def_id, ..) = *cause.code() + { + ( + true, + Some(span), + Some(self.tcx().def_span(def_id)), + None, + self.tcx().def_path_str(def_id), + ) + } else { + (false, None, None, Some(span), String::new()) + }; + + let expected_trait_ref = self .cx - .resolve_vars_if_possible(ty::TraitRef { def_id: trait_def_id, substs: actual_substs }); + .resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, expected_substs)); + let actual_trait_ref = + self.cx.resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, actual_substs)); // Search the expected and actual trait references to see (a) // whether the sub/sup placeholders appear in them (sometimes @@ -286,8 +319,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { ?expected_self_ty_has_vid, ); - self.explain_actual_impl_that_was_found( - &mut err, + let actual_impl_expl_notes = self.explain_actual_impl_that_was_found( sub_placeholder, sup_placeholder, has_sub, @@ -301,7 +333,15 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { leading_ellipsis, ); - err + self.tcx().sess.create_err(TraitPlaceholderMismatch { + span, + satisfy_span, + where_span, + dup_span, + def_id, + trait_def_id: self.tcx().def_path_str(trait_def_id), + actual_impl_expl_notes, + }) } /// Add notes with details about the expected and actual trait refs, with attention to cases @@ -311,7 +351,6 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { /// due to the number of combinations we have to deal with. fn explain_actual_impl_that_was_found( &self, - err: &mut Diagnostic, sub_placeholder: Option>, sup_placeholder: Option>, has_sub: Option, @@ -323,39 +362,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { actual_has_vid: Option, any_self_ty_has_vid: bool, leading_ellipsis: bool, - ) { - // HACK(eddyb) maybe move this in a more central location. - #[derive(Copy, Clone)] - struct Highlighted<'tcx, T> { - tcx: TyCtxt<'tcx>, - highlight: RegionHighlightMode<'tcx>, - value: T, - } - - impl<'tcx, T> Highlighted<'tcx, T> { - fn map(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> { - Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) } - } - } - - impl<'tcx, T> fmt::Display for Highlighted<'tcx, T> - where - T: for<'a> Print< - 'tcx, - FmtPrinter<'a, 'tcx>, - Error = fmt::Error, - Output = FmtPrinter<'a, 'tcx>, - >, - { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS); - printer.region_highlight_mode = self.highlight; - - let s = self.value.print(printer)?.into_buffer(); - f.write_str(&s) - } - } - + ) -> Vec> { // The weird thing here with the `maybe_highlighting_region` calls and the // the match inside is meant to be like this: // @@ -363,7 +370,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { // in the types are about to print // - Meanwhile, the `maybe_highlighting_region` calls set up // highlights so that, if they do appear, we will replace - // them `'0` and whatever. (This replacement takes place + // them `'0` and whatever. (This replacement takes place // inside the closure given to `maybe_highlighting_region`.) // // There is some duplication between the calls -- i.e., the @@ -382,120 +389,110 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref); expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub); expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup); - err.note(&{ - let passive_voice = match (has_sub, has_sup) { - (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid, - (None, None) => { - expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid); - match expected_has_vid { - Some(_) => true, - None => any_self_ty_has_vid, - } - } - }; - let mut note = if same_self_type { - let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty()); - self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid); - - if self_ty.value.is_closure() - && self.tcx().is_fn_trait(expected_trait_ref.value.def_id) - { - let closure_sig = self_ty.map(|closure| { - if let ty::Closure(_, substs) = closure.kind() { - self.tcx().signature_unclosure( - substs.as_closure().sig(), - rustc_hir::Unsafety::Normal, - ) - } else { - bug!("type is not longer closure"); - } - }); - - format!( - "{}closure with signature `{}` must implement `{}`", - if leading_ellipsis { "..." } else { "" }, - closure_sig, - expected_trait_ref.map(|tr| tr.print_only_trait_path()), - ) - } else { - format!( - "{}`{}` must implement `{}`", - if leading_ellipsis { "..." } else { "" }, - self_ty, - expected_trait_ref.map(|tr| tr.print_only_trait_path()), - ) + let passive_voice = match (has_sub, has_sup) { + (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid, + (None, None) => { + expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid); + match expected_has_vid { + Some(_) => true, + None => any_self_ty_has_vid, } - } else if passive_voice { - format!( - "{}`{}` would have to be implemented for the type `{}`", - if leading_ellipsis { "..." } else { "" }, + } + }; + + let (kind, ty_or_sig, trait_path) = if same_self_type { + let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty()); + self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid); + + if self_ty.value.is_closure() && self.tcx().is_fn_trait(expected_trait_ref.value.def_id) + { + let closure_sig = self_ty.map(|closure| { + if let ty::Closure(_, substs) = closure.kind() { + self.tcx().signature_unclosure( + substs.as_closure().sig(), + rustc_hir::Unsafety::Normal, + ) + } else { + bug!("type is not longer closure"); + } + }); + ( + ActualImplExpectedKind::Signature, + TyOrSig::ClosureSig(closure_sig), expected_trait_ref.map(|tr| tr.print_only_trait_path()), - expected_trait_ref.map(|tr| tr.self_ty()), ) } else { - format!( - "{}`{}` must implement `{}`", - if leading_ellipsis { "..." } else { "" }, - expected_trait_ref.map(|tr| tr.self_ty()), + ( + ActualImplExpectedKind::Other, + TyOrSig::Ty(self_ty), expected_trait_ref.map(|tr| tr.print_only_trait_path()), ) - }; + } + } else if passive_voice { + ( + ActualImplExpectedKind::Passive, + TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())), + expected_trait_ref.map(|tr| tr.print_only_trait_path()), + ) + } else { + ( + ActualImplExpectedKind::Other, + TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())), + expected_trait_ref.map(|tr| tr.print_only_trait_path()), + ) + }; - match (has_sub, has_sup) { - (Some(n1), Some(n2)) => { - let _ = write!( - note, - ", for any two lifetimes `'{}` and `'{}`...", - std::cmp::min(n1, n2), - std::cmp::max(n1, n2), - ); - } - (Some(n), _) | (_, Some(n)) => { - let _ = write!(note, ", for any lifetime `'{}`...", n,); - } - (None, None) => { - if let Some(n) = expected_has_vid { - let _ = write!(note, ", for some specific lifetime `'{}`...", n,); - } + let (lt_kind, lifetime_1, lifetime_2) = match (has_sub, has_sup) { + (Some(n1), Some(n2)) => { + (ActualImplExpectedLifetimeKind::Two, std::cmp::min(n1, n2), std::cmp::max(n1, n2)) + } + (Some(n), _) | (_, Some(n)) => (ActualImplExpectedLifetimeKind::Any, n, 0), + (None, None) => { + if let Some(n) = expected_has_vid { + (ActualImplExpectedLifetimeKind::Some, n, 0) + } else { + (ActualImplExpectedLifetimeKind::Nothing, 0, 0) } } + }; - note - }); + let note_1 = ActualImplExplNotes::new_expected( + kind, + lt_kind, + leading_ellipsis, + ty_or_sig, + trait_path, + lifetime_1, + lifetime_2, + ); let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref); actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid); - err.note(&{ - let passive_voice = match actual_has_vid { - Some(_) => any_self_ty_has_vid, - None => true, - }; - let mut note = if same_self_type { - format!( - "...but it actually implements `{}`", - actual_trait_ref.map(|tr| tr.print_only_trait_path()), - ) - } else if passive_voice { - format!( - "...but `{}` is actually implemented for the type `{}`", - actual_trait_ref.map(|tr| tr.print_only_trait_path()), - actual_trait_ref.map(|tr| tr.self_ty()), - ) - } else { - format!( - "...but `{}` actually implements `{}`", - actual_trait_ref.map(|tr| tr.self_ty()), - actual_trait_ref.map(|tr| tr.print_only_trait_path()), - ) - }; + let passive_voice = match actual_has_vid { + Some(_) => any_self_ty_has_vid, + None => true, + }; - if let Some(n) = actual_has_vid { - let _ = write!(note, ", for some specific lifetime `'{}`", n); + let trait_path = actual_trait_ref.map(|tr| tr.print_only_trait_path()); + let ty = actual_trait_ref.map(|tr| tr.self_ty()).to_string(); + let has_lifetime = actual_has_vid.is_some(); + let lifetime = actual_has_vid.unwrap_or_default(); + + let note_2 = if same_self_type { + ActualImplExplNotes::ButActuallyImplementsTrait { trait_path, has_lifetime, lifetime } + } else if passive_voice { + ActualImplExplNotes::ButActuallyImplementedForTy { + trait_path, + ty, + has_lifetime, + lifetime, } + } else { + ActualImplExplNotes::ButActuallyTyImplements { trait_path, ty, has_lifetime, lifetime } + }; - note - }); + vec![note_1, note_2] } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs index c42240f21..9534bce54 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs @@ -44,7 +44,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { ); } (Some(sub_span), Some(sup_span), _, Some(sup_symbol)) => { - err.span_note(sub_span, format!("the lifetime defined here...")); + err.span_note(sub_span, "the lifetime defined here..."); err.span_note( sup_span, format!("...must outlive the lifetime `{sup_symbol}` defined here"), @@ -55,17 +55,11 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { sub_span, format!("the lifetime `{sub_symbol}` defined here..."), ); - err.span_note( - sup_span, - format!("...must outlive the lifetime defined here"), - ); + err.span_note(sup_span, "...must outlive the lifetime defined here"); } (Some(sub_span), Some(sup_span), _, _) => { - err.span_note(sub_span, format!("the lifetime defined here...")); - err.span_note( - sup_span, - format!("...must outlive the lifetime defined here"), - ); + err.span_note(sub_span, "the lifetime defined here..."); + err.span_note(sup_span, "...must outlive the lifetime defined here"); } _ => {} } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 09f9aa3c8..49ad3ce50 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -1,20 +1,28 @@ //! Error Reporting for static impl Traits. +use crate::errors::{ + ButCallingIntroduces, ButNeedsToSatisfy, DynTraitConstraintSuggestion, MoreTargeted, + ReqIntroducedLocations, +}; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_ty, Visitor}; -use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind}; +use rustc_hir::{ + self as hir, GenericBound, GenericParamKind, Item, ItemKind, Lifetime, LifetimeName, Node, + TyKind, +}; use rustc_middle::ty::{ self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, }; use rustc_span::symbol::Ident; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; use std::ops::ControlFlow; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { @@ -49,46 +57,32 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } let param = self.find_param_with_region(*sup_r, *sub_r)?; - let lifetime = if sup_r.has_name() { - format!("lifetime `{}`", sup_r) - } else { - "an anonymous lifetime `'_`".to_string() + let simple_ident = param.param.pat.simple_ident(); + + let (has_impl_path, impl_path) = match ctxt.assoc_item.container { + AssocItemContainer::TraitContainer => { + let id = ctxt.assoc_item.container_id(tcx); + (true, tcx.def_path_str(id)) + } + AssocItemContainer::ImplContainer => (false, String::new()), }; - let mut err = struct_span_err!( - tcx.sess, - cause.span, - E0772, - "{} has {} but calling `{}` introduces an implicit `'static` lifetime \ - requirement", - param - .param - .pat - .simple_ident() - .map(|s| format!("`{}`", s)) - .unwrap_or_else(|| "`fn` parameter".to_string()), - lifetime, - ctxt.assoc_item.name, - ); - err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime)); - err.span_label( - cause.span, - &format!( - "...is used and required to live as long as `'static` here \ - because of an implicit lifetime bound on the {}", - match ctxt.assoc_item.container { - AssocItemContainer::TraitContainer => { - let id = ctxt.assoc_item.container_id(tcx); - format!("`impl` of `{}`", tcx.def_path_str(id)) - } - AssocItemContainer::ImplContainer => "inherent `impl`".to_string(), - }, - ), - ); + + let mut err = self.tcx().sess.create_err(ButCallingIntroduces { + param_ty_span: param.param_ty_span, + cause_span: cause.span, + has_param_name: simple_ident.is_some(), + param_name: simple_ident.map(|x| x.to_string()).unwrap_or_default(), + has_lifetime: sup_r.has_name(), + lifetime: sup_r.to_string(), + assoc_item: ctxt.assoc_item.name, + has_impl_path, + impl_path, + }); if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) { let reported = err.emit(); return Some(reported); } else { - err.cancel(); + err.cancel() } } return None; @@ -104,25 +98,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let sp = var_origin.span(); let return_sp = sub_origin.span(); let param = self.find_param_with_region(*sup_r, *sub_r)?; - let (lifetime_name, lifetime) = if sup_r.has_name() { - (sup_r.to_string(), format!("lifetime `{}`", sup_r)) - } else { - ("'_".to_owned(), "an anonymous lifetime `'_`".to_string()) - }; - let param_name = param - .param - .pat - .simple_ident() - .map(|s| format!("`{}`", s)) - .unwrap_or_else(|| "`fn` parameter".to_string()); - let mut err = struct_span_err!( - tcx.sess, - sp, - E0759, - "{} has {} but it needs to satisfy a `'static` lifetime requirement", - param_name, - lifetime, - ); + let lifetime_name = if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() }; let (mention_influencer, influencer_point) = if sup_origin.span().overlaps(param.param_ty_span) { @@ -141,7 +117,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } else { (!sup_origin.span().overlaps(return_sp), param.param_ty_span) }; - err.span_label(influencer_point, &format!("this data with {}...", lifetime)); debug!("try_report_static_impl_trait: param_info={:?}", param); @@ -155,31 +130,19 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { spans.dedup_by_key(|span| (span.lo(), span.hi())); // We try to make the output have fewer overlapping spans if possible. - let require_msg = if spans.is_empty() { - "...is used and required to live as long as `'static` here" - } else { - "...and is required to live as long as `'static` here" - }; let require_span = if sup_origin.span().overlaps(return_sp) { sup_origin.span() } else { return_sp }; - for span in &spans { - err.span_label(*span, "...is used here..."); - } - - if spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp) { - // If any of the "captured here" labels appears on the same line or after - // `require_span`, we put it on a note to ensure the text flows by appearing - // always at the end. - err.span_note(require_span, require_msg); + let spans_empty = spans.is_empty(); + let require_as_note = spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp); + let bound = if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin { + Some(*bound) } else { - // We don't need a note, it's already at the end, it can be shown as a `span_label`. - err.span_label(require_span, require_msg); - } + None + }; + + let mut subdiag = None; - if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin { - err.span_note(*bound, "`'static` lifetime requirement introduced by this bound"); - } if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin { if let ObligationCauseCode::ReturnValue(hir_id) | ObligationCauseCode::BlockTailExpression(hir_id) = cause.code() @@ -187,33 +150,50 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let parent_id = tcx.hir().get_parent_item(*hir_id); if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) { let mut span: MultiSpan = fn_decl.output.span().into(); + let mut spans = Vec::new(); let mut add_label = true; if let hir::FnRetTy::Return(ty) = fn_decl.output { let mut v = StaticLifetimeVisitor(vec![], tcx.hir()); v.visit_ty(ty); if !v.0.is_empty() { span = v.0.clone().into(); - for sp in v.0 { - span.push_span_label(sp, "`'static` requirement introduced here"); - } + spans = v.0; add_label = false; } } - if add_label { - span.push_span_label( - fn_decl.output.span(), - "requirement introduced by this return type", - ); - } - span.push_span_label(cause.span, "because of this returned expression"); - err.span_note( + let fn_decl_span = fn_decl.output.span(); + + subdiag = Some(ReqIntroducedLocations { span, - "`'static` lifetime requirement introduced by the return type", - ); + spans, + fn_decl_span, + cause_span: cause.span, + add_label, + }); } } } + let diag = ButNeedsToSatisfy { + sp, + influencer_point, + spans: spans.clone(), + // If any of the "captured here" labels appears on the same line or after + // `require_span`, we put it on a note to ensure the text flows by appearing + // always at the end. + require_span_as_note: require_as_note.then_some(require_span), + // We don't need a note, it's already at the end, it can be shown as a `span_label`. + require_span_as_label: (!require_as_note).then_some(require_span), + req_introduces_loc: subdiag, + + has_lifetime: sup_r.has_name(), + lifetime: sup_r.to_string(), + spans_empty, + bound, + }; + + let mut err = self.tcx().sess.create_err(diag); + let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); let mut override_error_code = None; @@ -239,7 +219,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let mut v = TraitObjectVisitor(FxIndexSet::default()); v.visit_ty(param.param_ty); if let Some((ident, self_ty)) = - self.get_impl_ident_and_self_ty_from_trait(item_def_id, &v.0) + NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, item_def_id, &v.0) && self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0, ident, self_ty) { override_error_code = Some(ident.name); @@ -247,12 +227,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) { // Provide a more targeted error code and description. - err.code(rustc_errors::error_code!(E0772)); - err.set_primary_message(&format!( - "{} has {} but calling `{}` introduces an implicit `'static` lifetime \ - requirement", - param_name, lifetime, ident, - )); + let retarget_subdiag = MoreTargeted { ident }; + retarget_subdiag.add_to_diagnostic(&mut err); } let arg = match param.param.pat.simple_ident() { @@ -268,6 +244,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { Some(arg), captures, Some((param.param_ty_span, param.param_ty.to_string())), + Some(anon_reg_sup.def_id), ); let reported = err.emit(); @@ -283,6 +260,7 @@ pub fn suggest_new_region_bound( arg: Option, captures: String, param: Option<(Span, String)>, + scope_def_id: Option, ) { debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns); // FIXME: account for the need of parens in `&(dyn Trait + '_)` @@ -309,19 +287,12 @@ pub fn suggest_new_region_bound( let did = item_id.owner_id.to_def_id(); let ty = tcx.mk_opaque(did, ty::InternalSubsts::identity_for_item(tcx, did)); - if let Some(span) = opaque - .bounds - .iter() - .filter_map(|arg| match arg { - GenericBound::Outlives(Lifetime { - res: LifetimeName::Static, - ident, - .. - }) => Some(ident.span), - _ => None, - }) - .next() - { + if let Some(span) = opaque.bounds.iter().find_map(|arg| match arg { + GenericBound::Outlives(Lifetime { + res: LifetimeName::Static, ident, .. + }) => Some(ident.span), + _ => None, + }) { if let Some(explicit_static) = &explicit_static { err.span_suggestion_verbose( span, @@ -330,7 +301,7 @@ pub fn suggest_new_region_bound( Applicability::MaybeIncorrect, ); } - if let Some((param_span, param_ty)) = param.clone() { + if let Some((param_span, ref param_ty)) = param { err.span_suggestion_verbose( param_span, add_static_bound, @@ -338,27 +309,78 @@ pub fn suggest_new_region_bound( Applicability::MaybeIncorrect, ); } - } else if opaque - .bounds - .iter() - .filter_map(|arg| match arg { - GenericBound::Outlives(Lifetime { ident, .. }) - if ident.name.to_string() == lifetime_name => - { - Some(ident.span) - } - _ => None, - }) - .next() - .is_some() - { + } else if opaque.bounds.iter().any(|arg| match arg { + GenericBound::Outlives(Lifetime { ident, .. }) + if ident.name.to_string() == lifetime_name => + { + true + } + _ => false, + }) { } else { - err.span_suggestion_verbose( - fn_return.span.shrink_to_hi(), - &format!("{declare} `{ty}` {captures}, {explicit}",), - &plus_lt, - Applicability::MaybeIncorrect, - ); + // get a lifetime name of existing named lifetimes if any + let existing_lt_name = if let Some(id) = scope_def_id + && let Some(generics) = tcx.hir().get_generics(id) + && let named_lifetimes = generics + .params + .iter() + .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit })) + .map(|p| { if let hir::ParamName::Plain(name) = p.name {Some(name.to_string())} else {None}}) + .filter(|n| ! matches!(n, None)) + .collect::>() + && named_lifetimes.len() > 0 { + named_lifetimes[0].clone() + } else { + None + }; + let name = if let Some(name) = &existing_lt_name { + format!("{}", name) + } else { + format!("'a") + }; + // if there are more than one elided lifetimes in inputs, the explicit `'_` lifetime cannot be used. + // introducing a new lifetime `'a` or making use of one from existing named lifetimes if any + if let Some(id) = scope_def_id + && let Some(generics) = tcx.hir().get_generics(id) + && let mut spans_suggs = generics + .params + .iter() + .filter(|p| p.is_elided_lifetime()) + .map(|p| + if p.span.hi() - p.span.lo() == rustc_span::BytePos(1) { // Ampersand (elided without '_) + (p.span.shrink_to_hi(),format!("{name} ")) + } else { // Underscore (elided with '_) + (p.span, format!("{name}")) + } + ) + .collect::>() + && spans_suggs.len() > 1 + { + let use_lt = + if existing_lt_name == None { + spans_suggs.push((generics.span.shrink_to_hi(), format!("<{name}>"))); + format!("you can introduce a named lifetime parameter `{name}`") + } else { + // make use the existing named lifetime + format!("you can use the named lifetime parameter `{name}`") + }; + spans_suggs + .push((fn_return.span.shrink_to_hi(), format!(" + {name} "))); + err.multipart_suggestion_verbose( + &format!( + "{declare} `{ty}` {captures}, {use_lt}", + ), + spans_suggs, + Applicability::MaybeIncorrect, + ); + } else { + err.span_suggestion_verbose( + fn_return.span.shrink_to_hi(), + &format!("{declare} `{ty}` {captures}, {explicit}",), + &plus_lt, + Applicability::MaybeIncorrect, + ); + } } } TyKind::TraitObject(_, lt, _) => { @@ -403,66 +425,54 @@ pub fn suggest_new_region_bound( } impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { - fn get_impl_ident_and_self_ty_from_trait( - &self, + pub fn get_impl_ident_and_self_ty_from_trait( + tcx: TyCtxt<'tcx>, def_id: DefId, trait_objects: &FxIndexSet, ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> { - let tcx = self.tcx(); - match tcx.hir().get_if_local(def_id) { - Some(Node::ImplItem(impl_item)) => { - match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id) + match tcx.hir().get_if_local(def_id)? { + Node::ImplItem(impl_item) => { + let impl_did = tcx.hir().get_parent_item(impl_item.hir_id()); + if let hir::OwnerNode::Item(Item { + kind: ItemKind::Impl(hir::Impl { self_ty, .. }), + .. + }) = tcx.hir().owner(impl_did) { - Some(Node::Item(Item { - kind: ItemKind::Impl(hir::Impl { self_ty, .. }), - .. - })) => Some((impl_item.ident, self_ty)), - _ => None, + Some((impl_item.ident, self_ty)) + } else { + None } } - Some(Node::TraitItem(trait_item)) => { - let trait_did = tcx.hir().get_parent_item(trait_item.hir_id()); - match tcx.hir().find_by_def_id(trait_did.def_id) { - Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => { - // The method being called is defined in the `trait`, but the `'static` - // obligation comes from the `impl`. Find that `impl` so that we can point - // at it in the suggestion. - let trait_did = trait_did.to_def_id(); - match tcx - .hir() - .trait_impls(trait_did) - .iter() - .filter_map(|&impl_did| { - match tcx.hir().get_if_local(impl_did.to_def_id()) { - Some(Node::Item(Item { - kind: ItemKind::Impl(hir::Impl { self_ty, .. }), - .. - })) if trait_objects.iter().all(|did| { - // FIXME: we should check `self_ty` against the receiver - // type in the `UnifyReceiver` context, but for now, use - // this imperfect proxy. This will fail if there are - // multiple `impl`s for the same trait like - // `impl Foo for Box` and `impl Foo for dyn Bar`. - // In that case, only the first one will get suggestions. - let mut traits = vec![]; - let mut hir_v = HirTraitObjectVisitor(&mut traits, *did); - hir_v.visit_ty(self_ty); - !traits.is_empty() - }) => - { - Some(self_ty) - } - _ => None, - } - }) - .next() - { - Some(self_ty) => Some((trait_item.ident, self_ty)), - _ => None, - } + Node::TraitItem(trait_item) => { + let trait_id = tcx.hir().get_parent_item(trait_item.hir_id()); + debug_assert_eq!(tcx.def_kind(trait_id.def_id), hir::def::DefKind::Trait); + // The method being called is defined in the `trait`, but the `'static` + // obligation comes from the `impl`. Find that `impl` so that we can point + // at it in the suggestion. + let trait_did = trait_id.to_def_id(); + tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| { + if let Node::Item(Item { + kind: ItemKind::Impl(hir::Impl { self_ty, .. }), + .. + }) = tcx.hir().find_by_def_id(impl_did)? + && trait_objects.iter().all(|did| { + // FIXME: we should check `self_ty` against the receiver + // type in the `UnifyReceiver` context, but for now, use + // this imperfect proxy. This will fail if there are + // multiple `impl`s for the same trait like + // `impl Foo for Box` and `impl Foo for dyn Bar`. + // In that case, only the first one will get suggestions. + let mut traits = vec![]; + let mut hir_v = HirTraitObjectVisitor(&mut traits, *did); + hir_v.visit_ty(self_ty); + !traits.is_empty() + }) + { + Some((trait_item.ident, *self_ty)) + } else { + None } - _ => None, - } + }) } _ => None, } @@ -493,7 +503,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // Get the `Ident` of the method being called and the corresponding `impl` (to point at // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called). - let Some((ident, self_ty)) = self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &v.0) else { + let Some((ident, self_ty)) = NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, instance.def_id(), &v.0) else { return false; }; @@ -513,21 +523,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let mut traits = vec![]; let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did); hir_v.visit_ty(&self_ty); - for span in &traits { - let mut multi_span: MultiSpan = vec![*span].into(); - multi_span - .push_span_label(*span, "this has an implicit `'static` lifetime requirement"); - multi_span.push_span_label( - ident.span, - "calling this method introduces the `impl`'s 'static` requirement", - ); - err.span_note(multi_span, "the used `impl` has a `'static` requirement"); - err.span_suggestion_verbose( - span.shrink_to_hi(), - "consider relaxing the implicit `'static` requirement", - " + '_", - Applicability::MaybeIncorrect, - ); + for &span in &traits { + let subdiag = DynTraitConstraintSuggestion { span, ident }; + subdiag.add_to_diagnostic(err); suggested = true; } } @@ -545,7 +543,7 @@ impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor { if let Some(def_id) = preds.principal_def_id() { self.0.insert(def_id); } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => t.super_visit_with(self), } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 5d536e982..40c0c806e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -1,15 +1,17 @@ //! Error Reporting for `impl` items that do not match the obligations from their `trait`. +use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff}; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; -use crate::infer::Subtype; +use crate::infer::{Subtype, ValuePairs}; use crate::traits::ObligationCauseCode::CompareImplItemObligation; -use rustc_errors::{ErrorGuaranteed, MultiSpan}; +use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; +use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::print::RegionHighlightMode; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_span::Span; @@ -22,22 +24,27 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let error = self.error.as_ref()?; debug!("try_report_impl_not_conforming_to_trait {:?}", error); if let RegionResolutionError::SubSupConflict( - _, - var_origin, - sub_origin, - _sub, - sup_origin, - _sup, - _, - ) = error.clone() + _, + var_origin, + sub_origin, + _sub, + sup_origin, + _sup, + _, + ) = error.clone() && let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin) - && let sub_expected_found @ Some((sub_expected, sub_found)) = sub_trace.values.ty() - && let sup_expected_found @ Some(_) = sup_trace.values.ty() && let CompareImplItemObligation { trait_item_def_id, .. } = sub_trace.cause.code() - && sup_expected_found == sub_expected_found + && sub_trace.values == sup_trace.values + && let ValuePairs::Sigs(ExpectedFound { expected, found }) = sub_trace.values { - let guar = - self.emit_err(var_origin.span(), sub_expected, sub_found, *trait_item_def_id); + // FIXME(compiler-errors): Don't like that this needs `Ty`s, but + // all of the region highlighting machinery only deals with those. + let guar = self.emit_err( + var_origin.span(), + self.cx.tcx.mk_fn_ptr(ty::Binder::dummy(expected)), + self.cx.tcx.mk_fn_ptr(ty::Binder::dummy(found)), + *trait_item_def_id, + ); return Some(guar); } None @@ -51,10 +58,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { trait_def_id: DefId, ) -> ErrorGuaranteed { let trait_sp = self.tcx().def_span(trait_def_id); - let mut err = self - .tcx() - .sess - .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature"); // Mark all unnamed regions in the type with a number. // This diagnostic is called in response to lifetime errors, so be informative. @@ -91,9 +94,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let found = self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name; - err.span_label(sp, &format!("found `{}`", found)); - err.span_label(trait_sp, &format!("expected `{}`", expected)); - // Get the span of all the used type parameters in the method. let assoc_item = self.tcx().associated_item(trait_def_id); let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] }; @@ -110,26 +110,18 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } _ => {} } - let mut type_param_span: MultiSpan = visitor.types.to_vec().into(); - for &span in &visitor.types { - type_param_span - .push_span_label(span, "consider borrowing this type parameter in the trait"); - } - err.note(&format!("expected `{}`\n found `{}`", expected, found)); - - err.span_help( - type_param_span, - "the lifetime requirements from the `impl` do not correspond to the requirements in \ - the `trait`", - ); - if visitor.types.is_empty() { - err.help( - "verify the lifetime relationships in the `trait` and `impl` between the `self` \ - argument, the other inputs and its output", - ); - } - err.emit() + let diag = TraitImplDiff { + sp, + trait_sp, + note: (), + param_help: ConsiderBorrowingParamHelp { spans: visitor.types.to_vec() }, + rel_help: visitor.types.is_empty().then_some(RelationshipHelp), + expected, + found, + }; + + self.tcx().sess.emit_err(diag) } } @@ -147,7 +139,7 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { match arg.kind { - hir::TyKind::Rptr(_, ref mut_ty) => { + hir::TyKind::Ref(_, ref mut_ty) => { // We don't want to suggest looking into borrowing `&T` or `&Self`. hir::intravisit::walk_ty(self, mut_ty.ty); return; diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index d2dffa4a0..b18cbd404 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -2,11 +2,14 @@ use crate::errors::RegionOriginNote; use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt}; use crate::infer::{self, SubregionOrigin}; use rustc_errors::{ - fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, + fluent, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, + ErrorGuaranteed, }; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::{self, Region}; +use rustc_middle::ty::{self, IsSuggestable, Region}; +use rustc_span::symbol::kw; use super::ObligationCauseAsDiagArg; @@ -22,29 +25,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer::Reborrow(span) => { RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err) } - infer::ReborrowUpvar(span, ref upvar_id) => { - let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); - RegionOriginNote::WithName { - span, - msg: fluent::infer_reborrow, - name: &var_name.to_string(), - continues: false, - } - .add_to_diagnostic(err); - } infer::RelateObjectBound(span) => { RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound } .add_to_diagnostic(err); } - infer::DataBorrowed(ty, span) => { - RegionOriginNote::WithName { - span, - msg: fluent::infer_data_borrowed, - name: &self.ty_to_string(ty), - continues: false, - } - .add_to_diagnostic(err); - } infer::ReferenceOutlivesReferent(ty, span) => { RegionOriginNote::WithName { span, @@ -159,33 +143,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); err } - infer::ReborrowUpvar(span, ref upvar_id) => { - let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0313, - "lifetime of borrowed pointer outlives lifetime of captured variable `{}`...", - var_name - ); - note_and_explain_region( - self.tcx, - &mut err, - "...the borrowed pointer is valid for ", - sub, - "...", - None, - ); - note_and_explain_region( - self.tcx, - &mut err, - &format!("...but `{}` is only valid for ", var_name), - sup, - "", - None, - ); - err - } infer::RelateObjectBound(span) => { let mut err = struct_span_err!( self.tcx.sess, @@ -261,32 +218,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); err } - infer::DataBorrowed(ty, span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0490, - "a value of type `{}` is borrowed for too long", - self.ty_to_string(ty) - ); - note_and_explain_region( - self.tcx, - &mut err, - "the type is valid for ", - sub, - "", - None, - ); - note_and_explain_region( - self.tcx, - &mut err, - "but the borrow lasts for ", - sup, - "", - None, - ); - err - } infer::ReferenceOutlivesReferent(ty, span) => { let mut err = struct_span_err!( self.tcx.sess, @@ -313,55 +244,38 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); err } - infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self - .report_extra_impl_obligation( + infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => { + let mut err = self.report_extra_impl_obligation( span, impl_item_def_id, trait_item_def_id, &format!("`{}: {}`", sup, sub), - ), + ); + // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause + if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) + && generics.where_clause_span.contains(span) + { + self.suggest_copy_trait_method_bounds( + trait_item_def_id, + impl_item_def_id, + &mut err, + ); + } + err + } infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => { let mut err = self.report_concrete_failure(*parent, sub, sup); - let trait_item_span = self.tcx.def_span(trait_item_def_id); let item_name = self.tcx.item_name(impl_item_def_id.to_def_id()); err.span_label( trait_item_span, format!("definition of `{}` from trait", item_name), ); - - let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id); - let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id); - - let impl_predicates: rustc_data_structures::fx::FxHashSet<_> = - impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect(); - let clauses: Vec<_> = trait_predicates - .predicates - .into_iter() - .filter(|&(pred, _)| !impl_predicates.contains(pred)) - .map(|(pred, _)| format!("{}", pred)) - .collect(); - - if !clauses.is_empty() { - let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap(); - let where_clause_span = generics.tail_span_for_predicate_suggestion(); - - let suggestion = format!( - "{} {}", - generics.add_where_or_trailing_comma(), - clauses.join(", "), - ); - err.span_suggestion( - where_clause_span, - &format!( - "try copying {} from the trait", - if clauses.len() > 1 { "these clauses" } else { "this clause" } - ), - suggestion, - rustc_errors::Applicability::MaybeIncorrect, - ); - } - + self.suggest_copy_trait_method_bounds( + trait_item_def_id, + impl_item_def_id, + &mut err, + ); err } infer::AscribeUserTypeProvePredicate(span) => { @@ -388,6 +302,65 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } + pub fn suggest_copy_trait_method_bounds( + &self, + trait_item_def_id: DefId, + impl_item_def_id: LocalDefId, + err: &mut Diagnostic, + ) { + // FIXME(compiler-errors): Right now this is only being used for region + // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches, + // but right now it's not really very smart when it comes to implicit `Sized` + // predicates and bounds on the trait itself. + + let Some(impl_def_id) = + self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx) else { return; }; + let Some(trait_ref) = self + .tcx + .impl_trait_ref(impl_def_id) + else { return; }; + let trait_substs = trait_ref + .subst_identity() + // Replace the explicit self type with `Self` for better suggestion rendering + .with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper)) + .substs; + let trait_item_substs = + ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id.to_def_id()) + .rebase_onto(self.tcx, impl_def_id, trait_substs); + + let Ok(trait_predicates) = self + .tcx + .explicit_predicates_of(trait_item_def_id) + .instantiate_own(self.tcx, trait_item_substs) + .map(|(pred, _)| { + if pred.is_suggestable(self.tcx, false) { + Ok(pred.to_string()) + } else { + Err(()) + } + }) + .collect::, ()>>() else { return; }; + + let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else { return; }; + + if trait_predicates.is_empty() { + err.span_suggestion_verbose( + generics.where_clause_span, + "remove the `where` clause", + String::new(), + Applicability::MachineApplicable, + ); + } else { + let space = if generics.where_clause_span.is_empty() { " " } else { "" }; + err.span_suggestion_verbose( + generics.where_clause_span, + "copy the `where` clause predicates from the trait", + format!("{space}where {}", trait_predicates.join(", ")), + Applicability::MachineApplicable, + ); + } + } + pub(super) fn report_placeholder_failure( &self, placeholder_origin: SubregionOrigin<'tcx>, diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_region.rs b/compiler/rustc_infer/src/infer/error_reporting/note_region.rs deleted file mode 100644 index 41b115f33..000000000 --- a/compiler/rustc_infer/src/infer/error_reporting/note_region.rs +++ /dev/null @@ -1,427 +0,0 @@ -use crate::errors::RegionOriginNote; -use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt}; -use crate::infer::{self, SubregionOrigin}; -use rustc_errors::{ - fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, -}; -use rustc_middle::traits::ObligationCauseCode; -use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::{self, Region}; - -use super::ObligationCauseAsDiagArg; - -impl<'tcx> TypeErrCtxt<'_, 'tcx> { - pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) { - match *origin { - infer::Subtype(ref trace) => RegionOriginNote::WithRequirement { - span: trace.cause.span, - requirement: ObligationCauseAsDiagArg(trace.cause.clone()), - expected_found: self.values_str(trace.values), - } - .add_to_diagnostic(err), - infer::Reborrow(span) => { - RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err) - } - infer::ReborrowUpvar(span, ref upvar_id) => { - let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); - RegionOriginNote::WithName { - span, - msg: fluent::infer_reborrow, - name: &var_name.to_string(), - continues: false, - } - .add_to_diagnostic(err); - } - infer::RelateObjectBound(span) => { - RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound } - .add_to_diagnostic(err); - } - infer::DataBorrowed(ty, span) => { - RegionOriginNote::WithName { - span, - msg: fluent::infer_data_borrowed, - name: &self.ty_to_string(ty), - continues: false, - } - .add_to_diagnostic(err); - } - infer::ReferenceOutlivesReferent(ty, span) => { - RegionOriginNote::WithName { - span, - msg: fluent::infer_reference_outlives_referent, - name: &self.ty_to_string(ty), - continues: false, - } - .add_to_diagnostic(err); - } - infer::RelateParamBound(span, ty, opt_span) => { - RegionOriginNote::WithName { - span, - msg: fluent::infer_relate_param_bound, - name: &self.ty_to_string(ty), - continues: opt_span.is_some(), - } - .add_to_diagnostic(err); - if let Some(span) = opt_span { - RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 } - .add_to_diagnostic(err); - } - } - infer::RelateRegionParamBound(span) => { - RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound } - .add_to_diagnostic(err); - } - infer::CompareImplItemObligation { span, .. } => { - RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation } - .add_to_diagnostic(err); - } - infer::CheckAssociatedTypeBounds { ref parent, .. } => { - self.note_region_origin(err, &parent); - } - infer::AscribeUserTypeProvePredicate(span) => { - RegionOriginNote::Plain { - span, - msg: fluent::infer_ascribe_user_type_prove_predicate, - } - .add_to_diagnostic(err); - } - } - } - - pub(super) fn report_concrete_failure( - &self, - origin: SubregionOrigin<'tcx>, - sub: Region<'tcx>, - sup: Region<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - match origin { - infer::Subtype(box trace) => { - let terr = TypeError::RegionsDoesNotOutlive(sup, sub); - let mut err = self.report_and_explain_type_error(trace, terr); - match (*sub, *sup) { - (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {} - (ty::RePlaceholder(_), _) => { - note_and_explain_region( - self.tcx, - &mut err, - "", - sup, - " doesn't meet the lifetime requirements", - None, - ); - } - (_, ty::RePlaceholder(_)) => { - note_and_explain_region( - self.tcx, - &mut err, - "the required lifetime does not necessarily outlive ", - sub, - "", - None, - ); - } - _ => { - note_and_explain_region(self.tcx, &mut err, "", sup, "...", None); - note_and_explain_region( - self.tcx, - &mut err, - "...does not necessarily outlive ", - sub, - "", - None, - ); - } - } - err - } - infer::Reborrow(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0312, - "lifetime of reference outlives lifetime of borrowed content..." - ); - note_and_explain_region( - self.tcx, - &mut err, - "...the reference is valid for ", - sub, - "...", - None, - ); - note_and_explain_region( - self.tcx, - &mut err, - "...but the borrowed content is only valid for ", - sup, - "", - None, - ); - err - } - infer::ReborrowUpvar(span, ref upvar_id) => { - let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0313, - "lifetime of borrowed pointer outlives lifetime of captured variable `{}`...", - var_name - ); - note_and_explain_region( - self.tcx, - &mut err, - "...the borrowed pointer is valid for ", - sub, - "...", - None, - ); - note_and_explain_region( - self.tcx, - &mut err, - &format!("...but `{}` is only valid for ", var_name), - sup, - "", - None, - ); - err - } - infer::RelateObjectBound(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0476, - "lifetime of the source pointer does not outlive lifetime bound of the \ - object type" - ); - note_and_explain_region( - self.tcx, - &mut err, - "object type is valid for ", - sub, - "", - None, - ); - note_and_explain_region( - self.tcx, - &mut err, - "source pointer is only valid for ", - sup, - "", - None, - ); - err - } - infer::RelateParamBound(span, ty, opt_span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0477, - "the type `{}` does not fulfill the required lifetime", - self.ty_to_string(ty) - ); - match *sub { - ty::ReStatic => note_and_explain_region( - self.tcx, - &mut err, - "type must satisfy ", - sub, - if opt_span.is_some() { " as required by this binding" } else { "" }, - opt_span, - ), - _ => note_and_explain_region( - self.tcx, - &mut err, - "type must outlive ", - sub, - if opt_span.is_some() { " as required by this binding" } else { "" }, - opt_span, - ), - } - err - } - infer::RelateRegionParamBound(span) => { - let mut err = - struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied"); - note_and_explain_region( - self.tcx, - &mut err, - "lifetime parameter instantiated with ", - sup, - "", - None, - ); - note_and_explain_region( - self.tcx, - &mut err, - "but lifetime parameter must outlive ", - sub, - "", - None, - ); - err - } - infer::DataBorrowed(ty, span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0490, - "a value of type `{}` is borrowed for too long", - self.ty_to_string(ty) - ); - note_and_explain_region( - self.tcx, - &mut err, - "the type is valid for ", - sub, - "", - None, - ); - note_and_explain_region( - self.tcx, - &mut err, - "but the borrow lasts for ", - sup, - "", - None, - ); - err - } - infer::ReferenceOutlivesReferent(ty, span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0491, - "in type `{}`, reference has a longer lifetime than the data it references", - self.ty_to_string(ty) - ); - note_and_explain_region( - self.tcx, - &mut err, - "the pointer is valid for ", - sub, - "", - None, - ); - note_and_explain_region( - self.tcx, - &mut err, - "but the referenced data is only valid for ", - sup, - "", - None, - ); - err - } - infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self - .report_extra_impl_obligation( - span, - impl_item_def_id, - trait_item_def_id, - &format!("`{}: {}`", sup, sub), - ), - infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => { - let mut err = self.report_concrete_failure(*parent, sub, sup); - - let trait_item_span = self.tcx.def_span(trait_item_def_id); - let item_name = self.tcx.item_name(impl_item_def_id.to_def_id()); - err.span_label( - trait_item_span, - format!("definition of `{}` from trait", item_name), - ); - - let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id); - let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id); - - let impl_predicates: rustc_data_structures::fx::FxHashSet<_> = - impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect(); - let clauses: Vec<_> = trait_predicates - .predicates - .into_iter() - .filter(|&(pred, _)| !impl_predicates.contains(pred)) - .map(|(pred, _)| format!("{}", pred)) - .collect(); - - if !clauses.is_empty() { - let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap(); - let where_clause_span = generics.tail_span_for_predicate_suggestion(); - - let suggestion = format!( - "{} {}", - generics.add_where_or_trailing_comma(), - clauses.join(", "), - ); - err.span_suggestion( - where_clause_span, - &format!( - "try copying {} from the trait", - if clauses.len() > 1 { "these clauses" } else { "this clause" } - ), - suggestion, - rustc_errors::Applicability::MaybeIncorrect, - ); - } - - err - } - infer::AscribeUserTypeProvePredicate(span) => { - let mut err = - struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied"); - note_and_explain_region( - self.tcx, - &mut err, - "lifetime instantiated with ", - sup, - "", - None, - ); - note_and_explain_region( - self.tcx, - &mut err, - "but lifetime must outlive ", - sub, - "", - None, - ); - err - } - } - } - - pub(super) fn report_placeholder_failure( - &self, - placeholder_origin: SubregionOrigin<'tcx>, - sub: Region<'tcx>, - sup: Region<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - // I can't think how to do better than this right now. -nikomatsakis - debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure"); - match placeholder_origin { - infer::Subtype(box ref trace) - if matches!( - &trace.cause.code().peel_derives(), - ObligationCauseCode::BindingObligation(..) - | ObligationCauseCode::ExprBindingObligation(..) - ) => - { - // Hack to get around the borrow checker because trace.cause has an `Rc`. - if let ObligationCauseCode::BindingObligation(_, span) - | ObligationCauseCode::ExprBindingObligation(_, span, ..) = - &trace.cause.code().peel_derives() - { - let span = *span; - let mut err = self.report_concrete_failure(placeholder_origin, sub, sup); - err.span_note(span, "the lifetime requirement is introduced here"); - err - } else { - unreachable!() - } - } - infer::Subtype(box trace) => { - let terr = TypeError::RegionsPlaceholderMismatch; - return self.report_and_explain_type_error(trace, terr); - } - _ => return self.report_concrete_failure(placeholder_origin, sub, sup), - } - } -} diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 73b5a2cc4..5b02956a1 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -411,7 +411,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span: Span, ) { let hir = self.tcx.hir(); - let fn_hir_id = hir.get_parent_node(cause.body_id); + let fn_hir_id = hir.parent_id(cause.body_id); if let Some(node) = self.tcx.hir().find(fn_hir_id) && let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_sig, _, body_id), .. @@ -486,12 +486,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { _ if self.same_type_modulo_infer(last_expr_ty, expected_ty) => { StatementAsExpression::CorrectType } - (ty::Opaque(last_def_id, _), ty::Opaque(exp_def_id, _)) - if last_def_id == exp_def_id => - { - StatementAsExpression::CorrectType - } - (ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => { + ( + ty::Alias(ty::Opaque, ty::AliasTy { def_id: last_def_id, .. }), + ty::Alias(ty::Opaque, ty::AliasTy { def_id: exp_def_id, .. }), + ) if last_def_id == exp_def_id => StatementAsExpression::CorrectType, + ( + ty::Alias(ty::Opaque, ty::AliasTy { def_id: last_def_id, substs: last_bounds, .. }), + ty::Alias(ty::Opaque, ty::AliasTy { def_id: exp_def_id, substs: exp_bounds, .. }), + ) => { debug!( "both opaque, likely future {:?} {:?} {:?} {:?}", last_def_id, last_bounds, exp_def_id, exp_bounds @@ -583,45 +585,42 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let hir::StmtKind::Local(local) = &stmt.kind else { continue; }; local.pat.walk(&mut find_compatible_candidates); } - match hir.find(hir.get_parent_node(blk.hir_id)) { - Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => { - match hir.find(hir.get_parent_node(*hir_id)) { - Some(hir::Node::Arm(hir::Arm { pat, .. })) => { - pat.walk(&mut find_compatible_candidates); - } - Some( - hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. }) - | hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Fn(_, body), - .. - }) - | hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)), - .. - }) - | hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(hir::Closure { body, .. }), - .. - }), - ) => { - for param in hir.body(*body).params { - param.pat.walk(&mut find_compatible_candidates); - } - } - Some(hir::Node::Expr(hir::Expr { - kind: - hir::ExprKind::If( - hir::Expr { kind: hir::ExprKind::Let(let_), .. }, - then_block, - _, - ), + match hir.find_parent(blk.hir_id) { + Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => match hir.find_parent(*hir_id) { + Some(hir::Node::Arm(hir::Arm { pat, .. })) => { + pat.walk(&mut find_compatible_candidates); + } + Some( + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. }) + | hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Fn(_, body), .. + }) + | hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)), .. - })) if then_block.hir_id == *hir_id => { - let_.pat.walk(&mut find_compatible_candidates); + }) + | hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(hir::Closure { body, .. }), + .. + }), + ) => { + for param in hir.body(*body).params { + param.pat.walk(&mut find_compatible_candidates); } - _ => {} } - } + Some(hir::Node::Expr(hir::Expr { + kind: + hir::ExprKind::If( + hir::Expr { kind: hir::ExprKind::Let(let_), .. }, + then_block, + _, + ), + .. + })) if then_block.hir_id == *hir_id => { + let_.pat.walk(&mut find_compatible_candidates); + } + _ => {} + }, _ => {} } diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index f6946929b..8f53b1ccd 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -205,12 +205,11 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { | ty::Dynamic(..) | ty::Never | ty::Tuple(..) - | ty::Projection(..) + | ty::Alias(..) | ty::Foreign(..) | ty::Param(..) | ty::Closure(..) - | ty::GeneratorWitness(..) - | ty::Opaque(..) => t.super_fold_with(self), + | ty::GeneratorWitness(..) => t.super_fold_with(self), ty::Placeholder(..) | ty::Bound(..) => bug!("unexpected type {:?}", t), } diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs index 7f27b35a5..21b68ce99 100644 --- a/compiler/rustc_infer/src/infer/glb.rs +++ b/compiler/rustc_infer/src/infer/glb.rs @@ -103,6 +103,11 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { where T: Relate<'tcx>, { + // GLB of a binder and itself is just itself + if a == b { + return Ok(a); + } + debug!("binders(a={:?}, b={:?})", a, b); if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() { // When higher-ranked types are involved, computing the GLB is diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs index eba65361a..4dbb4b4d7 100644 --- a/compiler/rustc_infer/src/infer/lattice.rs +++ b/compiler/rustc_infer/src/infer/lattice.rs @@ -78,7 +78,7 @@ where // // Example: if the LHS is a type variable, and RHS is // `Box`, then we current compare `v` to the RHS first, - // which will instantiate `v` with `Box`. Then when `v` + // which will instantiate `v` with `Box`. Then when `v` // is compared to the LHS, we instantiate LHS with `Box`. // But if we did in reverse order, we would create a `v <: // LHS` (or vice versa) constraint and then instantiate @@ -105,11 +105,13 @@ where Ok(v) } - (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => { - infcx.super_combine_tys(this, a, b) - } - (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) - if this.define_opaque_types() && did.is_local() => + ( + &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), + &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), + ) if a_def_id == b_def_id => infcx.super_combine_tys(this, a, b), + (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) + | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) + if this.define_opaque_types() && def_id.is_local() => { this.add_obligations( infcx diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index ba990acfe..ce8aec804 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -52,7 +52,7 @@ pub struct LexicalRegionResolutions<'tcx> { #[derive(Copy, Clone, Debug)] pub(crate) enum VarValue<'tcx> { - /// Empty lifetime is for data that is never accessed. We tag the + /// Empty lifetime is for data that is never accessed. We tag the /// empty lifetime with a universe -- the idea is that we don't /// want `exists<'a> { forall<'b> { 'b: 'a } }` to be satisfiable. /// Therefore, the `'empty` in a universe `U` is less than all @@ -251,7 +251,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { VarValue::Empty(a_universe) => { let b_data = var_values.value_mut(b_vid); - let changed = (|| match *b_data { + let changed = match *b_data { VarValue::Empty(b_universe) => { // Empty regions are ordered according to the universe // they are associated with. @@ -280,20 +280,20 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { }; if lub == cur_region { - return false; + false + } else { + debug!( + "Expanding value of {:?} from {:?} to {:?}", + b_vid, cur_region, lub + ); + + *b_data = VarValue::Value(lub); + true } - - debug!( - "Expanding value of {:?} from {:?} to {:?}", - b_vid, cur_region, lub - ); - - *b_data = VarValue::Value(lub); - true } VarValue::ErrorValue => false, - })(); + }; if changed { changes.push(b_vid); @@ -488,7 +488,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // If this empty region is from a universe that can // name the placeholder, then the placeholder is // larger; otherwise, the only ancestor is `'static`. - if a_ui.can_name(placeholder.universe) { true } else { false } + return a_ui.can_name(placeholder.universe); } } } @@ -510,7 +510,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } // If both `a` and `b` are free, consult the declared - // relationships. Note that this can be more precise than the + // relationships. Note that this can be more precise than the // `lub` relationship defined below, since sometimes the "lub" // is actually the `postdom_upper_bound` (see // `TransitiveRelation` for more details). @@ -665,7 +665,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // conflicting regions to report to the user. As we walk, we // trip the flags from false to true, and if we find that // we've already reported an error involving any particular - // node we just stop and don't report the current error. The + // node we just stop and don't report the current error. The // idea is to report errors that derive from independent // regions of the graph, but not those that derive from // overlapping locations. @@ -702,26 +702,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // Obtain the spans for all the places that can // influence the constraints on this value for // richer diagnostics in `static_impl_trait`. - let influences: Vec = self - .data - .constraints - .iter() - .filter_map(|(constraint, origin)| match (constraint, origin) { - ( - Constraint::VarSubVar(_, sup), - SubregionOrigin::DataBorrowed(_, sp), - ) if sup == &node_vid => Some(*sp), - _ => None, - }) - .collect(); - - self.collect_error_for_expanding_node( - graph, - &mut dup_vec, - node_vid, - errors, - influences, - ); + + self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors); } } } @@ -775,7 +757,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { dup_vec: &mut IndexVec>, node_idx: RegionVid, errors: &mut Vec>, - influences: Vec, ) { // Errors in expanding nodes result from a lower-bound that is // not contained by an upper-bound. @@ -830,7 +811,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { lower_bound.region, upper_bound.origin.clone(), upper_bound.region, - influences, + vec![], )); return; } diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs index 97ed4729b..c07ac1d3a 100644 --- a/compiler/rustc_infer/src/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/lub.rs @@ -103,6 +103,11 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { where T: Relate<'tcx>, { + // LUB of a binder and itself is just itself + if a == b { + return Ok(a); + } + debug!("binders(a={:?}, b={:?})", a, b); if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() { // When higher-ranked types are involved, computing the LUB is diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 706cd4124..f0e42c1fc 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -361,6 +361,7 @@ pub enum ValuePairs<'tcx> { Terms(ExpectedFound>), TraitRefs(ExpectedFound>), PolyTraitRefs(ExpectedFound>), + Sigs(ExpectedFound>), } impl<'tcx> ValuePairs<'tcx> { @@ -409,12 +410,6 @@ pub enum SubregionOrigin<'tcx> { /// Creating a pointer `b` to contents of another reference Reborrow(Span), - /// Creating a pointer `b` to contents of an upvar - ReborrowUpvar(Span, ty::UpvarId), - - /// Data with type `Ty<'tcx>` was borrowed - DataBorrowed(Ty<'tcx>, Span), - /// (&'a &'b T) where a >= b ReferenceOutlivesReferent(Ty<'tcx>, Span), @@ -690,6 +685,10 @@ impl<'tcx> InferCtxt<'tcx> { typeck_results: None, fallback_has_occurred: false, normalize_fn_sig: Box::new(|fn_sig| fn_sig), + autoderef_steps: Box::new(|ty| { + debug_assert!(false, "shouldn't be using autoderef_steps outside of typeck"); + vec![(ty, vec![])] + }), } } @@ -1106,7 +1105,7 @@ impl<'tcx> InferCtxt<'tcx> { self.tcx.mk_region(ty::ReVar(region_var)) } - /// Return the universe that the region `r` was created in. For + /// Return the universe that the region `r` was created in. For /// most regions (e.g., `'static`, named regions from the user, /// etc) this is the root universe U0. For inference variables or /// placeholders, however, it will return the universe which they @@ -1340,6 +1339,12 @@ impl<'tcx> InferCtxt<'tcx> { var_infos } + #[instrument(level = "debug", skip(self), ret)] + pub fn take_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> { + debug_assert_ne!(self.defining_use_anchor, DefiningAnchor::Error); + std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types) + } + pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { self.resolve_vars_if_possible(t).to_string() } @@ -1356,7 +1361,7 @@ impl<'tcx> InferCtxt<'tcx> { } /// Resolve any type variables found in `value` -- but only one - /// level. So, if the variable `?X` is bound to some type + /// level. So, if the variable `?X` is bound to some type /// `Foo`, then this would return `Foo` (but `?Y` may /// itself be bound to a type). /// @@ -1681,33 +1686,54 @@ impl<'tcx> InferCtxt<'tcx> { } impl<'tcx> TypeErrCtxt<'_, 'tcx> { + /// Processes registered region obliations and resolves regions, reporting + /// any errors if any were raised. Prefer using this function over manually + /// calling `resolve_regions_and_report_errors`. + pub fn check_region_obligations_and_report_errors( + &self, + generic_param_scope: LocalDefId, + outlives_env: &OutlivesEnvironment<'tcx>, + ) -> Result<(), ErrorGuaranteed> { + self.process_registered_region_obligations( + outlives_env.region_bound_pairs(), + outlives_env.param_env, + ); + + self.resolve_regions_and_report_errors(generic_param_scope, outlives_env) + } + /// Process the region constraints and report any errors that /// result. After this, no more unification operations should be /// done -- or the compiler will panic -- but it is legal to use /// `resolve_vars_if_possible` as well as `fully_resolve`. /// /// Make sure to call [`InferCtxt::process_registered_region_obligations`] - /// first, or preferably use [`InferCtxt::check_region_obligations_and_report_errors`] + /// first, or preferably use [`TypeErrCtxt::check_region_obligations_and_report_errors`] /// to do both of these operations together. pub fn resolve_regions_and_report_errors( &self, generic_param_scope: LocalDefId, outlives_env: &OutlivesEnvironment<'tcx>, - ) -> Option { + ) -> Result<(), ErrorGuaranteed> { let errors = self.resolve_regions(outlives_env); if let None = self.tainted_by_errors() { // As a heuristic, just skip reporting region errors // altogether if other errors have been reported while - // this infcx was in use. This is totally hokey but + // this infcx was in use. This is totally hokey but // otherwise we have a hard time separating legit region // errors from silly ones. self.report_region_errors(generic_param_scope, &errors); } - (!errors.is_empty()).then(|| { - self.tcx.sess.delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted") - }) + if errors.is_empty() { + Ok(()) + } else { + Err(self + .tcx + .sess + .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted")) + } } // [Note-Type-error-reporting] @@ -1924,7 +1950,7 @@ impl<'tcx> TypeTrace<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b)), } } @@ -1949,8 +1975,6 @@ impl<'tcx> SubregionOrigin<'tcx> { RelateParamBound(a, ..) => a, RelateRegionParamBound(a) => a, Reborrow(a) => a, - ReborrowUpvar(a, _) => a, - DataBorrowed(_, a) => a, ReferenceOutlivesReferent(_, a) => a, CompareImplItemObligation { span, .. } => span, AscribeUserTypeProvePredicate(span) => span, @@ -2018,31 +2042,54 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>( tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, ) -> SubstsRef<'tcx> { - tcx.mk_substs(substs.iter().enumerate().map(|(idx, arg)| { - match arg.unpack() { - GenericArgKind::Type(_) if arg.has_non_region_param() || arg.has_non_region_infer() => { - tcx.mk_ty(ty::Placeholder(ty::PlaceholderType { + struct ReplaceParamAndInferWithPlaceholder<'tcx> { + tcx: TyCtxt<'tcx>, + idx: usize, + } + + impl<'tcx> TypeFolder<'tcx> for ReplaceParamAndInferWithPlaceholder<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if let ty::Infer(_) = t.kind() { + self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::ROOT, - name: ty::BoundVar::from_usize(idx), + name: ty::BoundVar::from_usize({ + let idx = self.idx; + self.idx += 1; + idx + }), })) - .into() + } else { + t.super_fold_with(self) } - GenericArgKind::Const(ct) if ct.has_non_region_infer() || ct.has_non_region_param() => { - let ty = ct.ty(); - // If the type references param or infer, replace that too... + } + + fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { + if let ty::ConstKind::Infer(_) = c.kind() { + let ty = c.ty(); + // If the type references param or infer then ICE ICE ICE if ty.has_non_region_param() || ty.has_non_region_infer() { - bug!("const `{ct}`'s type should not reference params or types"); + bug!("const `{c}`'s type should not reference params or types"); } - tcx.mk_const( + self.tcx.mk_const( ty::PlaceholderConst { universe: ty::UniverseIndex::ROOT, - name: ty::BoundVar::from_usize(idx), + name: ty::BoundVar::from_usize({ + let idx = self.idx; + self.idx += 1; + idx + }), }, ty, ) - .into() + } else { + c.super_fold_with(self) } - _ => arg, } - })) + } + + substs.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 }) } diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index f6bc4db0d..f235cb5ab 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -275,13 +275,13 @@ where /// `ProjectionEq(projection = ?U)`, `ProjectionEq(other_projection = ?U)`. fn relate_projection_ty( &mut self, - projection_ty: ty::ProjectionTy<'tcx>, + projection_ty: ty::AliasTy<'tcx>, value_ty: Ty<'tcx>, ) -> Ty<'tcx> { use rustc_span::DUMMY_SP; match *value_ty.kind() { - ty::Projection(other_projection_ty) => { + ty::Alias(ty::Projection, other_projection_ty) => { let var = self.infcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span: DUMMY_SP, @@ -335,7 +335,9 @@ where return Ok(value_ty); } - ty::Projection(projection_ty) if D::normalization() == NormalizationStrategy::Lazy => { + ty::Alias(ty::Projection, projection_ty) + if D::normalization() == NormalizationStrategy::Lazy => + { return Ok(self.relate_projection_ty(projection_ty, self.infcx.tcx.mk_ty_var(vid))); } @@ -406,8 +408,8 @@ where } }; let (a, b) = match (a.kind(), b.kind()) { - (&ty::Opaque(..), _) => (a, generalize(b, false)?), - (_, &ty::Opaque(..)) => (generalize(a, true)?, b), + (&ty::Alias(ty::Opaque, ..), _) => (a, generalize(b, false)?), + (_, &ty::Alias(ty::Opaque, ..)) => (generalize(a, true)?, b), _ => unreachable!(), }; let cause = ObligationCause::dummy_with_span(self.delegate.span()); @@ -437,7 +439,7 @@ trait VidValuePair<'tcx>: Debug { fn value_ty(&self) -> Ty<'tcx>; /// Extract the scopes that apply to whichever side of the tuple - /// the vid was found on. See the comment where this is called + /// the vid was found on. See the comment where this is called /// for more details on why we want them. fn vid_scopes<'r, D: TypeRelatingDelegate<'tcx>>( &self, @@ -608,26 +610,30 @@ where (&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)), - (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => { - infcx.super_combine_tys(self, a, b).or_else(|err| { - self.tcx().sess.delay_span_bug( - self.delegate.span(), - "failure to relate an opaque to itself should result in an error later on", - ); - if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) } - }) - } - (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) if did.is_local() => { + ( + &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), + &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), + ) if a_def_id == b_def_id => infcx.super_combine_tys(self, a, b).or_else(|err| { + self.tcx().sess.delay_span_bug( + self.delegate.span(), + "failure to relate an opaque to itself should result in an error later on", + ); + if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) } + }), + (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) + | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) + if def_id.is_local() => + { self.relate_opaques(a, b) } - (&ty::Projection(projection_ty), _) + (&ty::Alias(ty::Projection, projection_ty), _) if D::normalization() == NormalizationStrategy::Lazy => { Ok(self.relate_projection_ty(projection_ty, b)) } - (_, &ty::Projection(projection_ty)) + (_, &ty::Alias(ty::Projection, projection_ty)) if D::normalization() == NormalizationStrategy::Lazy => { Ok(self.relate_projection_ty(projection_ty, a)) @@ -825,7 +831,7 @@ where /// (these are not explicitly present in the ty representation right /// now). This visitor handles that: it descends the type, tracking /// binder depth, and finds late-bound regions targeting the -/// `for<..`>. For each of those, it creates an entry in +/// `for<..`>. For each of those, it creates an entry in /// `bound_region_scope`. struct ScopeInstantiator<'me, 'tcx> { next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>, @@ -843,7 +849,7 @@ impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { t.super_visit_with(self); self.target_index.shift_out(1); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { @@ -857,7 +863,7 @@ impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { _ => {} } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_infer/src/infer/note.rs b/compiler/rustc_infer/src/infer/note.rs deleted file mode 100644 index 2ccbd164f..000000000 --- a/compiler/rustc_infer/src/infer/note.rs +++ /dev/null @@ -1,203 +0,0 @@ -impl<'tcx> TypeErrCtxt<'_, 'tcx> { - fn note_error_origin( - &self, - err: &mut Diagnostic, - cause: &ObligationCause<'tcx>, - exp_found: Option>>, - terr: TypeError<'tcx>, - ) { - match *cause.code() { - ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => { - let ty = self.resolve_vars_if_possible(root_ty); - if !matches!(ty.kind(), ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_))) - { - // don't show type `_` - if span.desugaring_kind() == Some(DesugaringKind::ForLoop) - && let ty::Adt(def, substs) = ty.kind() - && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option) - { - err.span_label(span, format!("this is an iterator with items of type `{}`", substs.type_at(0))); - } else { - err.span_label(span, format!("this expression has type `{}`", ty)); - } - } - if let Some(ty::error::ExpectedFound { found, .. }) = exp_found - && ty.is_box() && ty.boxed_ty() == found - && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) - { - err.span_suggestion( - span, - "consider dereferencing the boxed value", - format!("*{}", snippet), - Applicability::MachineApplicable, - ); - } - } - ObligationCauseCode::Pattern { origin_expr: false, span: Some(span), .. } => { - err.span_label(span, "expected due to this"); - } - ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { - arm_block_id, - arm_span, - arm_ty, - prior_arm_block_id, - prior_arm_span, - prior_arm_ty, - source, - ref prior_arms, - scrut_hir_id, - opt_suggest_box_span, - scrut_span, - .. - }) => match source { - hir::MatchSource::TryDesugar => { - if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found { - let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id); - let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind { - let arg_expr = args.first().expect("try desugaring call w/out arg"); - self.typeck_results.as_ref().and_then(|typeck_results| { - typeck_results.expr_ty_opt(arg_expr) - }) - } else { - bug!("try desugaring w/out call expr as scrutinee"); - }; - - match scrut_ty { - Some(ty) if expected == ty => { - let source_map = self.tcx.sess.source_map(); - err.span_suggestion( - source_map.end_point(cause.span), - "try removing this `?`", - "", - Applicability::MachineApplicable, - ); - } - _ => {} - } - } - } - _ => { - // `prior_arm_ty` can be `!`, `expected` will have better info when present. - let t = self.resolve_vars_if_possible(match exp_found { - Some(ty::error::ExpectedFound { expected, .. }) => expected, - _ => prior_arm_ty, - }); - let source_map = self.tcx.sess.source_map(); - let mut any_multiline_arm = source_map.is_multiline(arm_span); - if prior_arms.len() <= 4 { - for sp in prior_arms { - any_multiline_arm |= source_map.is_multiline(*sp); - err.span_label(*sp, format!("this is found to be of type `{}`", t)); - } - } else if let Some(sp) = prior_arms.last() { - any_multiline_arm |= source_map.is_multiline(*sp); - err.span_label( - *sp, - format!("this and all prior arms are found to be of type `{}`", t), - ); - } - let outer_error_span = if any_multiline_arm { - // Cover just `match` and the scrutinee expression, not - // the entire match body, to reduce diagram noise. - cause.span.shrink_to_lo().to(scrut_span) - } else { - cause.span - }; - let msg = "`match` arms have incompatible types"; - err.span_label(outer_error_span, msg); - self.suggest_remove_semi_or_return_binding( - err, - prior_arm_block_id, - prior_arm_ty, - prior_arm_span, - arm_block_id, - arm_ty, - arm_span, - ); - if let Some(ret_sp) = opt_suggest_box_span { - // Get return type span and point to it. - self.suggest_boxing_for_return_impl_trait( - err, - ret_sp, - prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s), - ); - } - } - }, - ObligationCauseCode::IfExpression(box IfExpressionCause { - then_id, - else_id, - then_ty, - else_ty, - outer_span, - opt_suggest_box_span, - }) => { - let then_span = self.find_block_span_from_hir_id(then_id); - let else_span = self.find_block_span_from_hir_id(else_id); - err.span_label(then_span, "expected because of this"); - if let Some(sp) = outer_span { - err.span_label(sp, "`if` and `else` have incompatible types"); - } - self.suggest_remove_semi_or_return_binding( - err, - Some(then_id), - then_ty, - then_span, - Some(else_id), - else_ty, - else_span, - ); - if let Some(ret_sp) = opt_suggest_box_span { - self.suggest_boxing_for_return_impl_trait( - err, - ret_sp, - [then_span, else_span].into_iter(), - ); - } - } - ObligationCauseCode::LetElse => { - err.help("try adding a diverging expression, such as `return` or `panic!(..)`"); - err.help("...or use `match` instead of `let...else`"); - } - _ => { - if let ObligationCauseCode::BindingObligation(_, span) - | ObligationCauseCode::ExprBindingObligation(_, span, ..) - = cause.code().peel_derives() - && let TypeError::RegionsPlaceholderMismatch = terr - { - err.span_note( * span, - "the lifetime requirement is introduced here"); - } - } - } - } -} - -impl<'tcx> InferCtxt<'tcx> { - /// Given a [`hir::Block`], get the span of its last expression or - /// statement, peeling off any inner blocks. - pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span { - let block = block.innermost_block(); - if let Some(expr) = &block.expr { - expr.span - } else if let Some(stmt) = block.stmts.last() { - // possibly incorrect trailing `;` in the else arm - stmt.span - } else { - // empty block; point at its entirety - block.span - } - } - - /// Given a [`hir::HirId`] for a block, get the span of its last expression - /// or statement, peeling off any inner blocks. - pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span { - match self.tcx.hir().get(hir_id) { - hir::Node::Block(blk) => self.find_block_span(blk), - // The parser was in a weird state if either of these happen, but - // it's better not to panic. - hir::Node::Expr(e) => e.span, - _ => rustc_span::DUMMY_SP, - } - } -} diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 524f7a39e..c54c66eab 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -61,12 +61,14 @@ impl<'tcx> InferCtxt<'tcx> { .as_local() .map_or(false, |def_id| self.opaque_type_origin(def_id, span).is_some()) }; - let value = value.fold_with(&mut ty::fold::BottomUpFolder { + let value = value.fold_with(&mut BottomUpFolder { tcx: self.tcx, lt_op: |lt| lt, ct_op: |ct| ct, ty_op: |ty| match *ty.kind() { - ty::Opaque(def_id, _substs) if replace_opaque_type(def_id) => { + ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) + if replace_opaque_type(def_id) => + { let def_span = self.tcx.def_span(def_id); let span = if span.contains(def_span) { def_span } else { span }; let code = traits::ObligationCauseCode::OpaqueReturnType(None); @@ -104,13 +106,13 @@ impl<'tcx> InferCtxt<'tcx> { } let (a, b) = if a_is_expected { (a, b) } else { (b, a) }; let process = |a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected| match *a.kind() { - ty::Opaque(def_id, substs) if def_id.is_local() => { + ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) if def_id.is_local() => { let def_id = def_id.expect_local(); let origin = match self.defining_use_anchor { DefiningAnchor::Bind(_) => { // Check that this is `impl Trait` type is // declared by `parent_def_id` -- i.e., one whose - // value we are inferring. At present, this is + // value we are inferring. At present, this is // always true during the first phase of // type-check, but not always true later on during // NLL. Once we support named opaque types more fully, @@ -147,18 +149,19 @@ impl<'tcx> InferCtxt<'tcx> { DefiningAnchor::Bubble => self.opaque_ty_origin_unchecked(def_id, cause.span), DefiningAnchor::Error => return None, }; - if let ty::Opaque(did2, _) = *b.kind() { + if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() { // We could accept this, but there are various ways to handle this situation, and we don't // want to make a decision on it right now. Likely this case is so super rare anyway, that // no one encounters it in practice. // It does occur however in `fn fut() -> impl Future { async { 42 } }`, // where it is of no concern, so we only check for TAITs. - if let Some(OpaqueTyOrigin::TyAlias) = - did2.as_local().and_then(|did2| self.opaque_type_origin(did2, cause.span)) + if let Some(OpaqueTyOrigin::TyAlias) = b_def_id + .as_local() + .and_then(|b_def_id| self.opaque_type_origin(b_def_id, cause.span)) { self.tcx.sess.emit_err(OpaqueHiddenTypeDiag { span: cause.span, - hidden_type: self.tcx.def_span(did2), + hidden_type: self.tcx.def_span(b_def_id), opaque_type: self.tcx.def_span(def_id), }); } @@ -377,7 +380,7 @@ impl<'tcx> InferCtxt<'tcx> { }; let item_kind = &self.tcx.hir().expect_item(def_id).kind; - let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else { + let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else { span_bug!( span, "weird opaque type: {:#?}, {:#?}", @@ -437,16 +440,16 @@ where t: &ty::Binder<'tcx, T>, ) -> ControlFlow { t.super_visit_with(self); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { match *r { // ignore bound regions, keep visiting - ty::ReLateBound(_, _) => ControlFlow::CONTINUE, + ty::ReLateBound(_, _) => ControlFlow::Continue(()), _ => { (self.op)(r); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -454,7 +457,7 @@ where fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { // We're only interested in types involving regions if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } match ty.kind() { @@ -475,8 +478,8 @@ where substs.as_generator().resume_ty().visit_with(self); } - ty::Opaque(def_id, ref substs) => { - // Skip lifetime paramters that are not captures. + ty::Alias(ty::Opaque, ty::AliasTy { def_id, ref substs, .. }) => { + // Skip lifetime parameters that are not captures. let variances = self.tcx.variances_of(*def_id); for (v, s) in std::iter::zip(variances, substs.iter()) { @@ -486,11 +489,11 @@ where } } - ty::Projection(proj) - if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder => + ty::Alias(ty::Projection, proj) + if self.tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder => { - // Skip lifetime paramters that are not captures. - let variances = self.tcx.variances_of(proj.item_def_id); + // Skip lifetime parameters that are not captures. + let variances = self.tcx.variances_of(proj.def_id); for (v, s) in std::iter::zip(variances, proj.substs.iter()) { if *v != ty::Variance::Bivariant { @@ -504,7 +507,7 @@ where } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -563,9 +566,9 @@ impl<'tcx> InferCtxt<'tcx> { // We can't normalize associated types from `rustc_infer`, // but we can eagerly register inference variables for them. // FIXME(RPITIT): Don't replace RPITITs with inference vars. - ty::Projection(projection_ty) + ty::Alias(ty::Projection, projection_ty) if !projection_ty.has_escaping_bound_vars() - && tcx.def_kind(projection_ty.item_def_id) + && tcx.def_kind(projection_ty.def_id) != DefKind::ImplTraitPlaceholder => { self.infer_projection( @@ -578,17 +581,16 @@ impl<'tcx> InferCtxt<'tcx> { } // Replace all other mentions of the same opaque type with the hidden type, // as the bounds must hold on the hidden type after all. - ty::Opaque(def_id2, substs2) + ty::Alias(ty::Opaque, ty::AliasTy { def_id: def_id2, substs: substs2, .. }) if def_id.to_def_id() == def_id2 && substs == substs2 => { hidden_ty } // FIXME(RPITIT): This can go away when we move to associated types - ty::Projection(proj) - if def_id.to_def_id() == proj.item_def_id && substs == proj.substs => - { - hidden_ty - } + ty::Alias( + ty::Projection, + ty::AliasTy { def_id: def_id2, substs: substs2, .. }, + ) if def_id.to_def_id() == def_id2 && substs == substs2 => hidden_ty, _ => ty, }, lt_op: |lt| lt, diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index c146902d5..ae4b85c87 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -29,11 +29,6 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { } } - #[instrument(level = "debug", ret)] - pub fn take_opaque_types(&mut self) -> OpaqueTypeMap<'tcx> { - std::mem::take(&mut self.opaque_types) - } - #[inline] pub(crate) fn with_log<'a>( &'a mut self, diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index 14ee9f051..3d86279b0 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -3,9 +3,8 @@ // RFC for reference. use rustc_data_structures::sso::SsoHashSet; -use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, SubstsRef, Ty, TyCtxt, TypeVisitable}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; use smallvec::{smallvec, SmallVec}; #[derive(Debug)] @@ -23,7 +22,7 @@ pub enum Component<'tcx> { // is not in a position to judge which is the best technique, so // we just product the projection as a component and leave it to // the consumer to decide (but see `EscapingProjection` below). - Projection(ty::ProjectionTy<'tcx>), + Alias(ty::AliasTy<'tcx>), // In the case where a projection has escaping regions -- meaning // regions bound within the type itself -- we always use @@ -45,9 +44,7 @@ pub enum Component<'tcx> { // projection, so that implied bounds code can avoid relying on // them. This gives us room to improve the regionck reasoning in // the future without breaking backwards compat. - EscapingProjection(Vec>), - - Opaque(DefId, SubstsRef<'tcx>), + EscapingAlias(Vec>), } /// Push onto `out` all the things that must outlive `'a` for the condition @@ -123,17 +120,6 @@ fn compute_components<'tcx>( out.push(Component::Param(p)); } - // Ignore lifetimes found in opaque types. Opaque types can - // have lifetimes in their substs which their hidden type doesn't - // actually use. If we inferred that an opaque type is outlived by - // its parameter lifetimes, then we could prove that any lifetime - // outlives any other lifetime, which is unsound. - // See https://github.com/rust-lang/rust/issues/84305 for - // more details. - ty::Opaque(def_id, substs) => { - out.push(Component::Opaque(def_id, substs)); - }, - // For projections, we prefer to generate an obligation like // `>::Foo: 'a`, because this gives the // regionck more ways to prove that it holds. However, @@ -142,23 +128,23 @@ fn compute_components<'tcx>( // trait-ref. Therefore, if we see any higher-ranked regions, // we simply fallback to the most restrictive rule, which // requires that `Pi: 'a` for all `i`. - ty::Projection(ref data) => { - if !data.has_escaping_bound_vars() { + ty::Alias(_, alias_ty) => { + if !alias_ty.has_escaping_bound_vars() { // best case: no escaping regions, so push the // projection and skip the subtree (thus generating no // constraints for Pi). This defers the choice between // the rules OutlivesProjectionEnv, // OutlivesProjectionTraitDef, and // OutlivesProjectionComponents to regionck. - out.push(Component::Projection(*data)); + out.push(Component::Alias(alias_ty)); } else { // fallback case: hard code - // OutlivesProjectionComponents. Continue walking + // OutlivesProjectionComponents. Continue walking // through and constrain Pi. let mut subcomponents = smallvec![]; let mut subvisited = SsoHashSet::new(); compute_components_recursive(tcx, ty.into(), &mut subcomponents, &mut subvisited); - out.push(Component::EscapingProjection(subcomponents.into_iter().collect())); + out.push(Component::EscapingAlias(subcomponents.into_iter().collect())); } } @@ -195,7 +181,7 @@ fn compute_components<'tcx>( ty::Error(_) => { // (*) Function pointers and trait objects are both binders. // In the RFC, this means we would add the bound regions to - // the "bound regions list". In our representation, no such + // the "bound regions list". In our representation, no such // list is maintained explicitly, because bound regions // themselves can be readily identified. compute_components_recursive(tcx, ty.into(), out, visited); diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 33543135d..24e3c34dd 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -138,13 +138,9 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> { self.region_bound_pairs .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a)); } - OutlivesBound::RegionSubProjection(r_a, projection_b) => { + OutlivesBound::RegionSubAlias(r_a, alias_b) => { self.region_bound_pairs - .insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a)); - } - OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => { - self.region_bound_pairs - .insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a)); + .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a)); } OutlivesBound::RegionSubRegion(r_a, r_b) => { if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) { diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index abb46ce3b..0194549a8 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -60,7 +60,6 @@ //! imply that `'b: 'a`. use crate::infer::outlives::components::{push_outlives_components, Component}; -use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::outlives::verify::VerifyBoundCx; use crate::infer::{ @@ -68,9 +67,6 @@ use crate::infer::{ }; use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::undo_log::UndoLogs; -use rustc_errors::ErrorGuaranteed; -use rustc_hir::def_id::DefId; -use rustc_hir::def_id::LocalDefId; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitable}; @@ -116,7 +112,7 @@ impl<'tcx> InferCtxt<'tcx> { std::mem::take(&mut self.inner.borrow_mut().region_obligations) } - /// NOTE: Prefer using [`InferCtxt::check_region_obligations_and_report_errors`] + /// NOTE: Prefer using `TypeErrCtxt::check_region_obligations_and_report_errors` /// instead of calling this directly. /// /// Process the region obligations that must be proven (during @@ -170,22 +166,6 @@ impl<'tcx> InferCtxt<'tcx> { outlives.type_must_outlive(origin, sup_type, sub_region, category); } } - - /// Processes registered region obliations and resolves regions, reporting - /// any errors if any were raised. Prefer using this function over manually - /// calling `resolve_regions_and_report_errors`. - pub fn check_region_obligations_and_report_errors( - &self, - generic_param_scope: LocalDefId, - outlives_env: &OutlivesEnvironment<'tcx>, - ) -> Option { - self.process_registered_region_obligations( - outlives_env.region_bound_pairs(), - outlives_env.param_env, - ); - - self.err_ctxt().resolve_regions_and_report_errors(generic_param_scope, outlives_env) - } } /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` @@ -285,13 +265,8 @@ where Component::Param(param_ty) => { self.param_ty_must_outlive(origin, region, *param_ty); } - Component::Opaque(def_id, substs) => { - self.opaque_must_outlive(*def_id, substs, origin, region) - } - Component::Projection(projection_ty) => { - self.projection_must_outlive(origin, region, *projection_ty); - } - Component::EscapingProjection(subcomponents) => { + Component::Alias(alias_ty) => self.alias_ty_must_outlive(origin, region, *alias_ty), + Component::EscapingAlias(subcomponents) => { self.components_must_outlive(origin, &subcomponents, region, category); } Component::UnresolvedInferenceVariable(v) => { @@ -307,78 +282,26 @@ where } } + #[instrument(level = "debug", skip(self))] fn param_ty_must_outlive( &mut self, origin: infer::SubregionOrigin<'tcx>, region: ty::Region<'tcx>, param_ty: ty::ParamTy, ) { - debug!( - "param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})", - region, param_ty, origin - ); - - let generic = GenericKind::Param(param_ty); let verify_bound = self.verify_bound.param_bound(param_ty); - self.delegate.push_verify(origin, generic, region, verify_bound); + self.delegate.push_verify(origin, GenericKind::Param(param_ty), region, verify_bound); } #[instrument(level = "debug", skip(self))] - fn opaque_must_outlive( + fn alias_ty_must_outlive( &mut self, - def_id: DefId, - substs: SubstsRef<'tcx>, origin: infer::SubregionOrigin<'tcx>, region: ty::Region<'tcx>, - ) { - self.generic_must_outlive( - origin, - region, - GenericKind::Opaque(def_id, substs), - def_id, - substs, - true, - |ty| match *ty.kind() { - ty::Opaque(def_id, substs) => (def_id, substs), - _ => bug!("expected only projection types from env, not {:?}", ty), - }, - ); - } - - #[instrument(level = "debug", skip(self))] - fn projection_must_outlive( - &mut self, - origin: infer::SubregionOrigin<'tcx>, - region: ty::Region<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - ) { - self.generic_must_outlive( - origin, - region, - GenericKind::Projection(projection_ty), - projection_ty.item_def_id, - projection_ty.substs, - false, - |ty| match ty.kind() { - ty::Projection(projection_ty) => (projection_ty.item_def_id, projection_ty.substs), - _ => bug!("expected only projection types from env, not {:?}", ty), - }, - ); - } - - #[instrument(level = "debug", skip(self, filter))] - fn generic_must_outlive( - &mut self, - origin: infer::SubregionOrigin<'tcx>, - region: ty::Region<'tcx>, - generic: GenericKind<'tcx>, - def_id: DefId, - substs: SubstsRef<'tcx>, - is_opaque: bool, - filter: impl Fn(Ty<'tcx>) -> (DefId, SubstsRef<'tcx>), + alias_ty: ty::AliasTy<'tcx>, ) { // An optimization for a common case with opaque types. - if substs.is_empty() { + if alias_ty.substs.is_empty() { return; } @@ -388,7 +311,7 @@ where // particular). :) First off, we have to choose between using the // OutlivesProjectionEnv, OutlivesProjectionTraitDef, and // OutlivesProjectionComponent rules, any one of which is - // sufficient. If there are no inference variables involved, it's + // sufficient. If there are no inference variables involved, it's // not hard to pick the right rule, but if there are, we're in a // bit of a catch 22: if we picked which rule we were going to // use, we could add constraints to the region inference graph @@ -400,14 +323,14 @@ where // These are guaranteed to apply, no matter the inference // results. let trait_bounds: Vec<_> = - self.verify_bound.declared_region_bounds(def_id, substs).collect(); + self.verify_bound.declared_bounds_from_definition(alias_ty).collect(); debug!(?trait_bounds); // Compute the bounds we can derive from the environment. This // is an "approximate" match -- in some cases, these bounds // may not apply. - let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(generic); + let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(alias_ty); debug!(?approx_env_bounds); // Remove outlives bounds that we get from the environment but @@ -422,8 +345,8 @@ where // If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait` // will be invoked with `['b => ^1]` and so we will get `^1` returned. let bound = bound_outlives.skip_binder(); - let (def_id, substs) = filter(bound.0); - self.verify_bound.declared_region_bounds(def_id, substs).all(|r| r != bound.1) + let ty::Alias(_, alias_ty) = bound.0.kind() else { bug!("expected AliasTy") }; + self.verify_bound.declared_bounds_from_definition(*alias_ty).all(|r| r != bound.1) }); // If declared bounds list is empty, the only applicable rule is @@ -440,12 +363,12 @@ where // the problem is to add `T: 'r`, which isn't true. So, if there are no // inference variables, we use a verify constraint instead of adding // edges, which winds up enforcing the same condition. - let needs_infer = substs.needs_infer(); - if approx_env_bounds.is_empty() && trait_bounds.is_empty() && (needs_infer || is_opaque) { + if approx_env_bounds.is_empty() + && trait_bounds.is_empty() + && (alias_ty.needs_infer() || alias_ty.kind(self.tcx) == ty::Opaque) + { debug!("no declared bounds"); - - self.substs_must_outlive(substs, origin, region); - + self.substs_must_outlive(alias_ty.substs, origin, region); return; } @@ -486,14 +409,9 @@ where // projection outlive; in some cases, this may add insufficient // edges into the inference graph, leading to inference failures // even though a satisfactory solution exists. - let verify_bound = self.verify_bound.projection_opaque_bounds( - generic, - def_id, - substs, - &mut Default::default(), - ); - debug!("projection_must_outlive: pushing {:?}", verify_bound); - self.delegate.push_verify(origin, generic, region, verify_bound); + let verify_bound = self.verify_bound.alias_bound(alias_ty, &mut Default::default()); + debug!("alias_must_outlive: pushing {:?}", verify_bound); + self.delegate.push_verify(origin, GenericKind::Alias(alias_ty), region, verify_bound); } fn substs_must_outlive( diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index f470b2eb8..94de9bc2d 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -1,11 +1,10 @@ use crate::infer::outlives::components::{compute_components_recursive, Component}; use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::region_constraints::VerifyIfEq; -use crate::infer::{GenericKind, VerifyBound}; +use crate::infer::VerifyBound; use rustc_data_structures::sso::SsoHashSet; -use rustc_hir::def_id::DefId; use rustc_middle::ty::GenericArg; -use rustc_middle::ty::{self, EarlyBinder, OutlivesPredicate, SubstsRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt}; use smallvec::smallvec; @@ -94,29 +93,26 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// this list. pub fn approx_declared_bounds_from_env( &self, - generic: GenericKind<'tcx>, + alias_ty: ty::AliasTy<'tcx>, ) -> Vec, ty::Region<'tcx>>>> { - let projection_ty = generic.to_ty(self.tcx); - let erased_projection_ty = self.tcx.erase_regions(projection_ty); - self.declared_generic_bounds_from_env_for_erased_ty(erased_projection_ty) + let erased_alias_ty = self.tcx.erase_regions(alias_ty.to_ty(self.tcx)); + self.declared_generic_bounds_from_env_for_erased_ty(erased_alias_ty) } #[instrument(level = "debug", skip(self, visited))] - pub fn projection_opaque_bounds( + pub fn alias_bound( &self, - generic: GenericKind<'tcx>, - def_id: DefId, - substs: SubstsRef<'tcx>, + alias_ty: ty::AliasTy<'tcx>, visited: &mut SsoHashSet>, ) -> VerifyBound<'tcx> { - let generic_ty = generic.to_ty(self.tcx); + let alias_ty_as_ty = alias_ty.to_ty(self.tcx); // Search the env for where clauses like `P: 'a`. - let projection_opaque_bounds = self - .approx_declared_bounds_from_env(generic) + let env_bounds = self + .approx_declared_bounds_from_env(alias_ty) .into_iter() .map(|binder| { - if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == generic_ty { + if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == alias_ty_as_ty { // Micro-optimize if this is an exact match (this // occurs often when there are no region variables // involved). @@ -126,19 +122,19 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { VerifyBound::IfEq(verify_if_eq_b) } }); - // Extend with bounds that we can find from the trait. - let trait_bounds = - self.declared_region_bounds(def_id, substs).map(|r| VerifyBound::OutlivedBy(r)); + + // Extend with bounds that we can find from the definition. + let definition_bounds = + self.declared_bounds_from_definition(alias_ty).map(|r| VerifyBound::OutlivedBy(r)); // see the extensive comment in projection_must_outlive let recursive_bound = { let mut components = smallvec![]; - compute_components_recursive(self.tcx, generic_ty.into(), &mut components, visited); + compute_components_recursive(self.tcx, alias_ty_as_ty.into(), &mut components, visited); self.bound_from_components(&components, visited) }; - VerifyBound::AnyBound(projection_opaque_bounds.chain(trait_bounds).collect()) - .or(recursive_bound) + VerifyBound::AnyBound(env_bounds.chain(definition_bounds).collect()).or(recursive_bound) } fn bound_from_components( @@ -149,10 +145,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { let mut bounds = components .iter() .map(|component| self.bound_from_single_component(component, visited)) - .filter(|bound| { - // Remove bounds that must hold, since they are not interesting. - !bound.must_hold() - }); + // Remove bounds that must hold, since they are not interesting. + .filter(|bound| !bound.must_hold()); match (bounds.next(), bounds.next()) { (Some(first), None) => first, @@ -170,19 +164,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { match *component { Component::Region(lt) => VerifyBound::OutlivedBy(lt), Component::Param(param_ty) => self.param_bound(param_ty), - Component::Opaque(did, substs) => self.projection_opaque_bounds( - GenericKind::Opaque(did, substs), - did, - substs, - visited, - ), - Component::Projection(projection_ty) => self.projection_opaque_bounds( - GenericKind::Projection(projection_ty), - projection_ty.item_def_id, - projection_ty.substs, - visited, - ), - Component::EscapingProjection(ref components) => { + Component::Alias(alias_ty) => self.alias_bound(alias_ty, visited), + Component::EscapingAlias(ref components) => { self.bound_from_components(components, visited) } Component::UnresolvedInferenceVariable(v) => { @@ -298,20 +281,18 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// /// This is for simplicity, and because we are not really smart /// enough to cope with such bounds anywhere. - pub fn declared_region_bounds( + pub fn declared_bounds_from_definition( &self, - def_id: DefId, - substs: SubstsRef<'tcx>, + alias_ty: ty::AliasTy<'tcx>, ) -> impl Iterator> { let tcx = self.tcx; - let bounds = tcx.item_bounds(def_id); - trace!("{:#?}", bounds); + let bounds = tcx.item_bounds(alias_ty.def_id); + trace!("{:#?}", bounds.0); bounds - .into_iter() + .subst_iter(tcx, alias_ty.substs) .filter_map(|p| p.to_opt_type_outlives()) .filter_map(|p| p.no_bound_vars()) - .map(|b| b.1) - .map(move |r| EarlyBinder(r).subst(tcx, substs)) + .map(|OutlivesPredicate(_, r)| r) } /// Searches through a predicate list for a predicate `T: 'a`. diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs index eb6deee29..4667d99ff 100644 --- a/compiler/rustc_infer/src/infer/projection.rs +++ b/compiler/rustc_infer/src/infer/projection.rs @@ -16,12 +16,12 @@ impl<'tcx> InferCtxt<'tcx> { pub fn infer_projection( &self, param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, + projection_ty: ty::AliasTy<'tcx>, cause: ObligationCause<'tcx>, recursion_depth: usize, obligations: &mut Vec>, ) -> Ty<'tcx> { - let def_id = projection_ty.item_def_id; + let def_id = projection_ty.def_id; let ty_var = self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::NormalizeProjectionType, span: self.tcx.def_span(def_id), diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 22b4bbb17..c46edc33f 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -357,15 +357,13 @@ impl<'tcx> SccUniverse<'tcx> { } rustc_index::newtype_index! { - struct LeakCheckNode { - DEBUG_FORMAT = "LeakCheckNode({})" - } + #[debug_format = "LeakCheckNode({})"] + struct LeakCheckNode {} } rustc_index::newtype_index! { - struct LeakCheckScc { - DEBUG_FORMAT = "LeakCheckScc({})" - } + #[debug_format = "LeakCheckScc({})"] + struct LeakCheckScc {} } /// Represents the graph of constraints. For each `R1: R2` constraint we create diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 985c5d360..0428481b7 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -12,10 +12,8 @@ use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::unify as ut; -use rustc_hir::def_id::DefId; use rustc_index::vec::IndexVec; use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion}; -use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::ReStatic; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ReLateBound, ReVar}; @@ -169,8 +167,7 @@ pub struct Verify<'tcx> { #[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)] pub enum GenericKind<'tcx> { Param(ty::ParamTy), - Projection(ty::ProjectionTy<'tcx>), - Opaque(DefId, SubstsRef<'tcx>), + Alias(ty::AliasTy<'tcx>), } /// Describes the things that some `GenericKind` value `G` is known to @@ -749,10 +746,7 @@ impl<'tcx> fmt::Debug for GenericKind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { GenericKind::Param(ref p) => write!(f, "{:?}", p), - GenericKind::Projection(ref p) => write!(f, "{:?}", p), - GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| { - write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap())) - }), + GenericKind::Alias(ref p) => write!(f, "{:?}", p), } } } @@ -761,10 +755,7 @@ impl<'tcx> fmt::Display for GenericKind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { GenericKind::Param(ref p) => write!(f, "{}", p), - GenericKind::Projection(ref p) => write!(f, "{}", p), - GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| { - write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap())) - }), + GenericKind::Alias(ref p) => write!(f, "{}", p), } } } @@ -773,8 +764,7 @@ impl<'tcx> GenericKind<'tcx> { pub fn to_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match *self { GenericKind::Param(ref p) => p.to_ty(tcx), - GenericKind::Projection(ref p) => tcx.mk_projection(p.item_def_id, p.substs), - GenericKind::Opaque(def_id, substs) => tcx.mk_opaque(def_id, substs), + GenericKind::Alias(ref p) => p.to_ty(tcx), } } } diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 8671f8d45..65b90aa3d 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -147,7 +147,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeOrConstFinder<'a, 'tcx> { } else if !t.has_non_region_infer() { // All const/type variables in inference types must already be resolved, // no need to visit the contents. - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { // Otherwise, keep visiting. t.super_visit_with(self) @@ -178,7 +178,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeOrConstFinder<'a, 'tcx> { } else if !ct.has_non_region_infer() { // All const/type variables in inference types must already be resolved, // no need to visit the contents. - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { // Otherwise, keep visiting. ct.super_visit_with(self) diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 2c6987cc3..bd38b52ba 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -130,12 +130,16 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { Ok(self.tcx().ty_error_with_guaranteed(e)) } - (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => { + ( + &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), + &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), + ) if a_def_id == b_def_id => { self.fields.infcx.super_combine_tys(self, a, b)?; Ok(a) } - (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) - if self.fields.define_opaque_types && did.is_local() => + (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) + | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) + if self.fields.define_opaque_types && def_id.is_local() => { self.fields.obligations.extend( infcx @@ -213,6 +217,11 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { where T: Relate<'tcx>, { + // A binder is always a subtype of itself if it's structually equal to itself + if a == b { + return Ok(a); + } + self.fields.higher_ranked_sub(a, b, self.a_is_expected)?; Ok(a) } diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 7ff086452..263c6a47d 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -433,7 +433,7 @@ impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> { fn unify_values(value1: &Self, value2: &Self) -> Result { match (value1, value2) { // We never equate two type variables, both of which - // have known types. Instead, we recursively equate + // have known types. Instead, we recursively equate // those types. (&TypeVariableValue::Known { .. }, &TypeVariableValue::Known { .. }) => { bug!("equating two type variables, both of which have known types") diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs index 611961ab1..955c54e85 100644 --- a/compiler/rustc_infer/src/infer/undo_log.rs +++ b/compiler/rustc_infer/src/infer/undo_log.rs @@ -87,18 +87,12 @@ impl<'tcx> Rollback> for InferCtxtInner<'tcx> { /// The combined undo log for all the various unification tables. For each change to the storage /// for any kind of inference variable, we record an UndoLog entry in the vector here. -#[derive(Clone)] +#[derive(Clone, Default)] pub(crate) struct InferCtxtUndoLogs<'tcx> { logs: Vec>, num_open_snapshots: usize, } -impl Default for InferCtxtUndoLogs<'_> { - fn default() -> Self { - Self { logs: Default::default(), num_open_snapshots: Default::default() } - } -} - /// The UndoLogs trait defines how we undo a particular kind of action (of type T). We can undo any /// action that is convertible into an UndoLog (per the From impls above). impl<'tcx, T> UndoLogs for InferCtxtUndoLogs<'tcx> diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs index 5d22f9f97..ac455055b 100644 --- a/compiler/rustc_infer/src/traits/project.rs +++ b/compiler/rustc_infer/src/traits/project.rs @@ -77,11 +77,11 @@ pub struct ProjectionCacheStorage<'tcx> { #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct ProjectionCacheKey<'tcx> { - ty: ty::ProjectionTy<'tcx>, + ty: ty::AliasTy<'tcx>, } impl<'tcx> ProjectionCacheKey<'tcx> { - pub fn new(ty: ty::ProjectionTy<'tcx>) -> Self { + pub fn new(ty: ty::AliasTy<'tcx>) -> Self { Self { ty } } } @@ -200,7 +200,7 @@ impl<'tcx> ProjectionCache<'_, 'tcx> { pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>, result: EvaluationResult) { let mut map = self.map(); match map.get(&key) { - Some(&ProjectionCacheEntry::NormalizedTy { ref ty, complete: _ }) => { + Some(ProjectionCacheEntry::NormalizedTy { ty, complete: _ }) => { info!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty); let mut ty = ty.clone(); if result.must_apply_considering_regions() { diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 512e6079f..cd5bde2a7 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -1,7 +1,7 @@ use smallvec::smallvec; use crate::infer::outlives::components::{push_outlives_components, Component}; -use crate::traits::{Obligation, ObligationCause, PredicateObligation}; +use crate::traits::{self, Obligation, ObligationCause, PredicateObligation}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_middle::ty::{self, ToPredicate, TyCtxt}; use rustc_span::symbol::Ident; @@ -145,16 +145,28 @@ impl<'tcx> Elaborator<'tcx> { // Get predicates declared on the trait. let predicates = tcx.super_predicates_of(data.def_id()); - let obligations = predicates.predicates.iter().map(|&(mut pred, _)| { + let obligations = predicates.predicates.iter().map(|&(mut pred, span)| { // when parent predicate is non-const, elaborate it to non-const predicates. if data.constness == ty::BoundConstness::NotConst { pred = pred.without_const(tcx); } + let cause = obligation.cause.clone().derived_cause( + bound_predicate.rebind(data), + |derived| { + traits::ImplDerivedObligation(Box::new( + traits::ImplDerivedObligationCause { + derived, + impl_def_id: data.def_id(), + span, + }, + )) + }, + ); predicate_obligation( pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)), obligation.param_env, - obligation.cause.clone(), + cause, ) }); debug!(?data, ?obligations, "super_predicates"); @@ -249,24 +261,15 @@ impl<'tcx> Elaborator<'tcx> { Component::UnresolvedInferenceVariable(_) => None, - Component::Opaque(def_id, substs) => { - let ty = tcx.mk_opaque(def_id, substs); - Some(ty::PredicateKind::Clause(ty::Clause::TypeOutlives( - ty::OutlivesPredicate(ty, r_min), - ))) - } - - Component::Projection(projection) => { + Component::Alias(alias_ty) => { // We might end up here if we have `Foo<::Assoc>: 'a`. // With this, we can deduce that `::Assoc: 'a`. - let ty = - tcx.mk_projection(projection.item_def_id, projection.substs); Some(ty::PredicateKind::Clause(ty::Clause::TypeOutlives( - ty::OutlivesPredicate(ty, r_min), + ty::OutlivesPredicate(alias_ty.to_ty(tcx), r_min), ))) } - Component::EscapingProjection(_) => { + Component::EscapingAlias(_) => { // We might be able to do more here, but we don't // want to deal with escaping vars right now. None @@ -334,7 +337,7 @@ pub fn transitive_bounds<'tcx>( /// A specialized variant of `elaborate_trait_refs` that only elaborates trait references that may /// define the given associated type `assoc_name`. It uses the /// `super_predicates_that_define_assoc_type` query to avoid enumerating super-predicates that -/// aren't related to `assoc_item`. This is used when resolving types like `Self::Item` or +/// aren't related to `assoc_item`. This is used when resolving types like `Self::Item` or /// `T::Item` and helps to avoid cycle errors (see e.g. #35237). pub fn transitive_bounds_that_define_assoc_type<'tcx>( tcx: TyCtxt<'tcx>, -- cgit v1.2.3