From 147bb17f51b521269929f348b4b2a27afad8a273 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 24 Aug 2024 14:55:31 -0400 Subject: [PATCH 1/2] Rework how we emit errors for unresolved object lifetimes --- compiler/rustc_hir_analysis/src/collect.rs | 2 +- .../src/hir_ty_lowering/mod.rs | 7 ++-- .../src/hir_ty_lowering/object_safety.rs | 32 ++++++++++++------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f75954c9edf..9e6c431a6e6 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -392,7 +392,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { } fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> { - if let RegionInferReason::BorrowedObjectLifetimeDefault = reason { + if let RegionInferReason::ObjectLifetimeDefault = reason { let e = struct_span_code_err!( self.dcx(), span, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 5c8ecf254a5..73baa05bce6 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -85,10 +85,9 @@ pub enum PredicateFilter { #[derive(Debug)] pub enum RegionInferReason<'a> { - /// Lifetime on a trait object behind a reference. - /// This allows inferring information from the reference. - BorrowedObjectLifetimeDefault, - /// A trait object's lifetime. + /// Lifetime on a trait object that is spelled explicitly, e.g. `+ 'a` or `+ '_`. + ExplicitObjectLifetime, + /// A trait object's lifetime when it is elided, e.g. `dyn Any`. ObjectLifetimeDefault, /// Generic lifetime parameter Param(&'a ty::GenericParamDef), diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs index 31d1750f33d..082fbb2c418 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs @@ -30,7 +30,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir_id: hir::HirId, hir_trait_bounds: &[(hir::PolyTraitRef<'tcx>, hir::TraitBoundModifier)], lifetime: &hir::Lifetime, - borrowed: bool, + _borrowed: bool, representation: DynKind, ) -> Ty<'tcx> { let tcx = self.tcx(); @@ -325,22 +325,32 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { v.dedup(); let existential_predicates = tcx.mk_poly_existential_predicates(&v); - // Use explicitly-specified region bound. + // Use explicitly-specified region bound, unless the bound is missing. let region_bound = if !lifetime.is_elided() { - self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault) + self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime) } else { self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { + // Curiously, we prefer object lifetime default for `+ '_`... if tcx.named_bound_var(lifetime.hir_id).is_some() { - self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault) + self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime) } else { - self.re_infer( - span, - if borrowed { - RegionInferReason::ObjectLifetimeDefault + let reason = + if let hir::LifetimeName::ImplicitObjectLifetimeDefault = lifetime.res { + if let hir::Node::Ty(hir::Ty { + kind: hir::TyKind::Ref(parent_lifetime, _), + .. + }) = tcx.parent_hir_node(hir_id) + && tcx.named_bound_var(parent_lifetime.hir_id).is_none() + { + // Parent lifetime must have failed to resolve. Don't emit a redundant error. + RegionInferReason::ExplicitObjectLifetime + } else { + RegionInferReason::ObjectLifetimeDefault + } } else { - RegionInferReason::BorrowedObjectLifetimeDefault - }, - ) + RegionInferReason::ExplicitObjectLifetime + }; + self.re_infer(span, reason) } }) }; From ecd2d115736581726ee9b77432561ea9480b3241 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 24 Aug 2024 15:03:51 -0400 Subject: [PATCH 2/2] Remove redundant flags that can be inferred from the HIR --- .../src/hir_ty_lowering/lint.rs | 21 +++++++++++---- .../src/hir_ty_lowering/mod.rs | 27 ++++--------------- .../src/hir_ty_lowering/object_safety.rs | 1 - .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 2 +- .../suggest-dyn-on-bare-trait-in-pat.rs | 14 ++++++++++ .../suggest-dyn-on-bare-trait-in-pat.stderr | 14 ++++++++++ 6 files changed, 50 insertions(+), 29 deletions(-) create mode 100644 tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.rs create mode 100644 tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index 6aff518390f..7be45463f15 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -15,11 +15,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// /// *Bare* trait object types are ones that aren't preceded by the keyword `dyn`. /// In edition 2021 and onward we emit a hard error for them. - pub(super) fn prohibit_or_lint_bare_trait_object_ty( - &self, - self_ty: &hir::Ty<'_>, - in_path: bool, - ) { + pub(super) fn prohibit_or_lint_bare_trait_object_ty(&self, self_ty: &hir::Ty<'_>) { let tcx = self.tcx(); let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) = @@ -28,6 +24,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return; }; + let in_path = match tcx.parent_hir_node(self_ty.hir_id) { + hir::Node::Ty(hir::Ty { + kind: hir::TyKind::Path(hir::QPath::TypeRelative(qself, _)), + .. + }) + | hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Path(hir::QPath::TypeRelative(qself, _)), + .. + }) + | hir::Node::Pat(hir::Pat { + kind: hir::PatKind::Path(hir::QPath::TypeRelative(qself, _)), + .. + }) if qself.hir_id == self_ty.hir_id => true, + _ => false, + }; let needs_bracket = in_path && !tcx .sess diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 73baa05bce6..010d58bfb67 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1998,16 +1998,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - /// Lower a type from the HIR to our internal notion of a type. - pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { - self.lower_ty_common(hir_ty, false, false) - } - - /// Lower a type inside of a path from the HIR to our internal notion of a type. - pub fn lower_ty_in_path(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { - self.lower_ty_common(hir_ty, false, true) - } - fn lower_delegation_ty(&self, idx: hir::InferDelegationKind) -> Ty<'tcx> { let delegation_sig = self.tcx().inherit_sig_for_delegation_item(self.item_def_id()); match idx { @@ -2025,7 +2015,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// 2. `in_path`: Whether the type appears inside of a path. /// Used to provide correct diagnostics for bare trait object types. #[instrument(level = "debug", skip(self), ret)] - fn lower_ty_common(&self, hir_ty: &hir::Ty<'tcx>, borrowed: bool, in_path: bool) -> Ty<'tcx> { + pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { let tcx = self.tcx(); let result_ty = match &hir_ty.kind { @@ -2035,7 +2025,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::TyKind::Ref(region, mt) => { let r = self.lower_lifetime(region, RegionInferReason::Reference); debug!(?r); - let t = self.lower_ty_common(mt.ty, true, false); + let t = self.lower_ty(mt.ty); Ty::new_ref(tcx, r, t, mt.mutbl) } hir::TyKind::Never => tcx.types.never, @@ -2064,20 +2054,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) } hir::TyKind::TraitObject(bounds, lifetime, repr) => { - self.prohibit_or_lint_bare_trait_object_ty(hir_ty, in_path); + self.prohibit_or_lint_bare_trait_object_ty(hir_ty); let repr = match repr { TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn, TraitObjectSyntax::DynStar => ty::DynStar, }; - self.lower_trait_object_ty( - hir_ty.span, - hir_ty.hir_id, - bounds, - lifetime, - borrowed, - repr, - ) + self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, repr) } hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { debug!(?maybe_qself, ?path); @@ -2105,7 +2088,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => { debug!(?qself, ?segment); - let ty = self.lower_ty_common(qself, false, true); + let ty = self.lower_ty(qself); self.lower_assoc_path(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false) .map(|(ty, _, _)| ty) .unwrap_or_else(|guar| Ty::new_error(tcx, guar)) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs index 082fbb2c418..52e167379b5 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs @@ -30,7 +30,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir_id: hir::HirId, hir_trait_bounds: &[(hir::PolyTraitRef<'tcx>, hir::TraitBoundModifier)], lifetime: &hir::Lifetime, - _borrowed: bool, representation: DynKind, ) -> Ty<'tcx> { let tcx = self.tcx(); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index b169f75796b..21e6ac9332c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -798,7 +798,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // to be object-safe. // We manually call `register_wf_obligation` in the success path // below. - let ty = self.lowerer().lower_ty_in_path(qself); + let ty = self.lowerer().lower_ty(qself); (LoweredTy::from_raw(self, span, ty), qself, segment) } QPath::LangItem(..) => { diff --git a/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.rs b/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.rs new file mode 100644 index 00000000000..19b5edb620f --- /dev/null +++ b/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.rs @@ -0,0 +1,14 @@ +//@ edition: 2021 + +trait Trait {} + +impl dyn Trait { + const CONST: () = (); +} + +fn main() { + match () { + Trait::CONST => {} + //~^ ERROR trait objects must include the `dyn` keyword + } +} diff --git a/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.stderr b/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.stderr new file mode 100644 index 00000000000..4446a89b63b --- /dev/null +++ b/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.stderr @@ -0,0 +1,14 @@ +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/suggest-dyn-on-bare-trait-in-pat.rs:11:9 + | +LL | Trait::CONST => {} + | ^^^^^ + | +help: add `dyn` keyword before this trait + | +LL | ::CONST => {} + | ++++ + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0782`.