From ba27e22f671f6b2a56519e61a75fe070b0e96bf9 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 9 Jan 2024 15:49:31 +0000 Subject: [PATCH 1/3] Use a ty::Error instead of patching up a type after erroring --- compiler/rustc_hir_analysis/src/collect/type_of.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 55720e6d2aa4f..18401726817a3 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -603,6 +603,8 @@ fn infer_placeholder_type<'a>( } err.emit(); + // diagnostic stashing loses the information of whether something is a hard error. + Ty::new_error_with_message(tcx, span, "ItemNoType is a hard error") } None => { let mut diag = bad_placeholder(tcx, vec![span], kind); @@ -623,15 +625,9 @@ fn infer_placeholder_type<'a>( } } - diag.emit(); + Ty::new_error(tcx, diag.emit()) } } - - // Typeck doesn't expect erased regions to be returned from `type_of`. - tcx.fold_regions(ty, |r, _| match *r { - ty::ReErased => tcx.lifetimes.re_static, - _ => r, - }) } fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) { From 972c95a6e2a86c0e35fcfa4133facff31c34994e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 9 Jan 2024 18:12:56 +0000 Subject: [PATCH 2/3] Turn some free functions into methods --- compiler/rustc_hir/src/hir.rs | 44 +++++++++++++++- compiler/rustc_hir_analysis/src/collect.rs | 50 ++----------------- .../rustc_hir_analysis/src/collect/type_of.rs | 10 ++-- compiler/rustc_hir_typeck/src/lib.rs | 2 +- 4 files changed, 53 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 082658a3a3b06..58ac9668da5e9 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2405,6 +2405,39 @@ impl<'hir> Ty<'hir> { my_visitor.visit_ty(self); my_visitor.0 } + + /// Whether `ty` is a type with `_` placeholders that can be inferred. Used in diagnostics only to + /// use inference to provide suggestions for the appropriate type if possible. + pub fn is_suggestable_infer_ty(&self) -> bool { + fn are_suggestable_generic_args(generic_args: &[GenericArg<'_>]) -> bool { + generic_args.iter().any(|arg| match arg { + GenericArg::Type(ty) => ty.is_suggestable_infer_ty(), + GenericArg::Infer(_) => true, + _ => false, + }) + } + debug!(?self); + match &self.kind { + TyKind::Infer => true, + TyKind::Slice(ty) => ty.is_suggestable_infer_ty(), + TyKind::Array(ty, length) => { + ty.is_suggestable_infer_ty() || matches!(length, ArrayLen::Infer(_, _)) + } + TyKind::Tup(tys) => tys.iter().any(Self::is_suggestable_infer_ty), + TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => mut_ty.ty.is_suggestable_infer_ty(), + TyKind::OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args), + TyKind::Path(QPath::TypeRelative(ty, segment)) => { + ty.is_suggestable_infer_ty() || are_suggestable_generic_args(segment.args().args) + } + TyKind::Path(QPath::Resolved(ty_opt, Path { segments, .. })) => { + ty_opt.is_some_and(Self::is_suggestable_infer_ty) + || segments + .iter() + .any(|segment| are_suggestable_generic_args(segment.args().args)) + } + _ => false, + } + } } /// Not represented directly in the AST; referred to by name through a `ty_path`. @@ -2735,7 +2768,7 @@ pub enum FnRetTy<'hir> { Return(&'hir Ty<'hir>), } -impl FnRetTy<'_> { +impl<'hir> FnRetTy<'hir> { #[inline] pub fn span(&self) -> Span { match *self { @@ -2743,6 +2776,15 @@ impl FnRetTy<'_> { Self::Return(ref ty) => ty.span, } } + + pub fn get_infer_ret_ty(&self) -> Option<&'hir Ty<'hir>> { + if let Self::Return(ty) = self { + if ty.is_suggestable_infer_ty() { + return Some(*ty); + } + } + None + } } /// Represents `for<...>` binder before a closure diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 0a13949a68821..c9f89a0c3ef32 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -642,7 +642,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { tcx.ensure().generics_of(def_id); tcx.ensure().type_of(def_id); tcx.ensure().predicates_of(def_id); - if !is_suggestable_infer_ty(ty) { + if !ty.is_suggestable_infer_ty() { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_item(it); placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr()); @@ -674,7 +674,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { hir::TraitItemKind::Const(ty, body_id) => { tcx.ensure().type_of(def_id); if !tcx.dcx().has_stashed_diagnostic(ty.span, StashKey::ItemNoType) - && !(is_suggestable_infer_ty(ty) && body_id.is_some()) + && !(ty.is_suggestable_infer_ty() && body_id.is_some()) { // Account for `const C: _;`. let mut visitor = HirPlaceholderCollector::default(); @@ -726,7 +726,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { } hir::ImplItemKind::Const(ty, _) => { // Account for `const T: _ = ..;` - if !is_suggestable_infer_ty(ty) { + if !ty.is_suggestable_infer_ty() { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_impl_item(impl_item); placeholder_type_error(tcx, None, visitor.0, false, None, "associated constant"); @@ -1054,48 +1054,6 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { } } -fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool { - generic_args.iter().any(|arg| match arg { - hir::GenericArg::Type(ty) => is_suggestable_infer_ty(ty), - hir::GenericArg::Infer(_) => true, - _ => false, - }) -} - -/// Whether `ty` is a type with `_` placeholders that can be inferred. Used in diagnostics only to -/// use inference to provide suggestions for the appropriate type if possible. -fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool { - debug!(?ty); - use hir::TyKind::*; - match &ty.kind { - Infer => true, - Slice(ty) => is_suggestable_infer_ty(ty), - Array(ty, length) => { - is_suggestable_infer_ty(ty) || matches!(length, hir::ArrayLen::Infer(_, _)) - } - Tup(tys) => tys.iter().any(is_suggestable_infer_ty), - Ptr(mut_ty) | Ref(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty), - OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args), - Path(hir::QPath::TypeRelative(ty, segment)) => { - is_suggestable_infer_ty(ty) || are_suggestable_generic_args(segment.args().args) - } - Path(hir::QPath::Resolved(ty_opt, hir::Path { segments, .. })) => { - ty_opt.is_some_and(is_suggestable_infer_ty) - || segments.iter().any(|segment| are_suggestable_generic_args(segment.args().args)) - } - _ => false, - } -} - -pub fn get_infer_ret_ty<'hir>(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir hir::Ty<'hir>> { - if let hir::FnRetTy::Return(ty) = output { - if is_suggestable_infer_ty(ty) { - return Some(*ty); - } - } - None -} - #[instrument(level = "debug", skip(tcx))] fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder> { use rustc_hir::Node::*; @@ -1188,7 +1146,7 @@ fn infer_return_ty_for_fn_sig<'tcx>( ) -> ty::PolyFnSig<'tcx> { let hir_id = tcx.local_def_id_to_hir_id(def_id); - match get_infer_ret_ty(&sig.decl.output) { + match sig.decl.output.get_infer_ret_ty() { Some(ty) => { let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id]; // Typeck doesn't expect erased regions to be returned from `type_of`. diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 18401726817a3..3ceea3dc7ae3f 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -9,8 +9,8 @@ use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, Ty use rustc_span::symbol::Ident; use rustc_span::{Span, DUMMY_SP}; +use super::bad_placeholder; use super::ItemCtxt; -use super::{bad_placeholder, is_suggestable_infer_ty}; pub use opaque::test_opaque_hidden_types; mod opaque; @@ -368,7 +368,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder body_id .and_then(|body_id| { - is_suggestable_infer_ty(ty).then(|| { + ty.is_suggestable_infer_ty().then(|| { infer_placeholder_type( tcx, def_id, @@ -392,7 +392,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder { - if is_suggestable_infer_ty(ty) { + if ty.is_suggestable_infer_ty() { infer_placeholder_type( tcx, def_id, @@ -416,7 +416,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder match item.kind { ItemKind::Static(ty, .., body_id) => { - if is_suggestable_infer_ty(ty) { + if ty.is_suggestable_infer_ty() { infer_placeholder_type( tcx, def_id, @@ -430,7 +430,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder { - if is_suggestable_infer_ty(ty) { + if ty.is_suggestable_infer_ty() { infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant") } else { icx.to_ty(ty) diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index ffae08d0f27cc..db3fc375e3492 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -181,7 +181,7 @@ fn typeck_with_fallback<'tcx>( let mut fcx = FnCtxt::new(&inh, param_env, def_id); if let Some(hir::FnSig { header, decl, .. }) = fn_sig { - let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() { + let fn_sig = if decl.output.get_infer_ret_ty().is_some() { fcx.astconv().ty_of_fn(id, header.unsafety, header.abi, decl, None, None) } else { tcx.fn_sig(def_id).instantiate_identity() From 0e82aaeb6799041991c54fb9ff37b5c20a5c6146 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 9 Jan 2024 18:13:19 +0000 Subject: [PATCH 3/3] Avoid follow up errors --- .../src/collect/type_of/opaque.rs | 15 +++++++++++ tests/ui/type-alias-impl-trait/issue-77179.rs | 2 -- .../type-alias-impl-trait/issue-77179.stderr | 26 ++----------------- 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index da7279967dac1..1f7ca48234a24 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -134,6 +134,21 @@ impl TaitConstraintLocator<'_> { debug!("no constraint: no typeck results"); return; } + + if let Some(hir_sig) = self.tcx.hir_node_by_def_id(item_def_id).fn_decl() { + if hir_sig.output.get_infer_ret_ty().is_some() { + let guar = self.tcx.dcx().span_delayed_bug( + hir_sig.output.span(), + "inferring return types and opaque types do not mix well", + ); + self.found = Some(ty::OpaqueHiddenType { + span: DUMMY_SP, + ty: Ty::new_error(self.tcx, guar), + }); + return; + } + } + // Calling `mir_borrowck` can lead to cycle errors through // const-checking, avoid calling it if we don't have to. // ```rust diff --git a/tests/ui/type-alias-impl-trait/issue-77179.rs b/tests/ui/type-alias-impl-trait/issue-77179.rs index 6e2ce76632fdc..093aeb4b27911 100644 --- a/tests/ui/type-alias-impl-trait/issue-77179.rs +++ b/tests/ui/type-alias-impl-trait/issue-77179.rs @@ -6,9 +6,7 @@ type Pointer = impl std::ops::Deref; fn test() -> Pointer<_> { //~^ ERROR: the placeholder `_` is not allowed within types - //~| ERROR: non-defining opaque type use in defining scope Box::new(1) - //~^ ERROR expected generic type parameter, found `i32` } fn main() { diff --git a/tests/ui/type-alias-impl-trait/issue-77179.stderr b/tests/ui/type-alias-impl-trait/issue-77179.stderr index c5b7c4178e473..68dd6570d00c0 100644 --- a/tests/ui/type-alias-impl-trait/issue-77179.stderr +++ b/tests/ui/type-alias-impl-trait/issue-77179.stderr @@ -7,28 +7,6 @@ LL | fn test() -> Pointer<_> { | | not allowed in type signatures | help: replace with the correct return type: `Pointer` -error[E0792]: non-defining opaque type use in defining scope - --> $DIR/issue-77179.rs:7:14 - | -LL | fn test() -> Pointer<_> { - | ^^^^^^^^^^ argument `i32` is not a generic parameter - | -note: for this opaque type - --> $DIR/issue-77179.rs:5:19 - | -LL | type Pointer = impl std::ops::Deref; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0792]: expected generic type parameter, found `i32` - --> $DIR/issue-77179.rs:10:5 - | -LL | type Pointer = impl std::ops::Deref; - | - this generic parameter must be used with a generic type parameter -... -LL | Box::new(1) - | ^^^^^^^^^^^ - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0121, E0792. -For more information about an error, try `rustc --explain E0121`. +For more information about this error, try `rustc --explain E0121`.