Skip to content

Commit

Permalink
Rollup merge of rust-lang#119803 - oli-obk:even_more_follow_up_errors…
Browse files Browse the repository at this point in the history
…, r=compiler-errors

Silence some follow-up errors [1/x]

this is one piece of the requested cleanups from rust-lang#117449

When we use `-> impl SomeTrait<_>` as a return type, we are both using the "infer return type suggestion" code path, and the infer opaque type code path within the same function. That can lead to confusing diagnostics, so silence all opaque type diagnostics in that case.
  • Loading branch information
matthiaskrgr authored Jan 11, 2024
2 parents d93df41 + 0e82aae commit d37de53
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 86 deletions.
44 changes: 43 additions & 1 deletion compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down Expand Up @@ -2735,14 +2768,23 @@ pub enum FnRetTy<'hir> {
Return(&'hir Ty<'hir>),
}

impl FnRetTy<'_> {
impl<'hir> FnRetTy<'hir> {
#[inline]
pub fn span(&self) -> Span {
match *self {
Self::DefaultReturn(span) => span,
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
Expand Down
50 changes: 4 additions & 46 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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<ty::PolyFnSig<'_>> {
use rustc_hir::Node::*;
Expand Down Expand Up @@ -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`.
Expand Down
20 changes: 8 additions & 12 deletions compiler/rustc_hir_analysis/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -368,7 +368,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
}
TraitItemKind::Const(ty, body_id) => body_id
.and_then(|body_id| {
is_suggestable_infer_ty(ty).then(|| {
ty.is_suggestable_infer_ty().then(|| {
infer_placeholder_type(
tcx,
def_id,
Expand All @@ -392,7 +392,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
Ty::new_fn_def(tcx, def_id.to_def_id(), args)
}
ImplItemKind::Const(ty, body_id) => {
if is_suggestable_infer_ty(ty) {
if ty.is_suggestable_infer_ty() {
infer_placeholder_type(
tcx,
def_id,
Expand All @@ -416,7 +416,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty

Node::Item(item) => 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,
Expand All @@ -430,7 +430,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
}
}
ItemKind::Const(ty, _, body_id) => {
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)
Expand Down Expand Up @@ -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);
Expand All @@ -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) {
Expand Down
15 changes: 15 additions & 0 deletions compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
2 changes: 0 additions & 2 deletions tests/ui/type-alias-impl-trait/issue-77179.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ type Pointer<T> = impl std::ops::Deref<Target = T>;

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() {
Expand Down
26 changes: 2 additions & 24 deletions tests/ui/type-alias-impl-trait/issue-77179.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,6 @@ LL | fn test() -> Pointer<_> {
| | not allowed in type signatures
| help: replace with the correct return type: `Pointer<i32>`

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<T> = impl std::ops::Deref<Target = T>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0792]: expected generic type parameter, found `i32`
--> $DIR/issue-77179.rs:10:5
|
LL | type Pointer<T> = impl std::ops::Deref<Target = T>;
| - 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`.

0 comments on commit d37de53

Please sign in to comment.