Rollup merge of #99580 - fmease:fix-issue-99565, r=estebank
Don't suggest unnameable generic arguments Fixes #99565. `@rustbot` label T-compiler A-diagnostics r? `@rust-lang/wg-diagnostics`
This commit is contained in:
commit
b6d6f100a1
12 changed files with 90 additions and 22 deletions
|
@ -1,4 +1,4 @@
|
||||||
use crate::infer::type_variable::TypeVariableOriginKind;
|
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use crate::infer::InferCtxt;
|
use crate::infer::InferCtxt;
|
||||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
|
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
@ -8,12 +8,12 @@ use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
|
use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
use rustc_middle::infer::unify_key::ConstVariableOriginKind;
|
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
|
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
|
||||||
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
|
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
|
||||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
|
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
|
||||||
use rustc_middle::ty::{self, DefIdTree, InferConst};
|
use rustc_middle::ty::{self, DefIdTree, InferConst};
|
||||||
use rustc_middle::ty::{Ty, TyCtxt, TypeckResults};
|
use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults};
|
||||||
use rustc_span::symbol::{kw, Ident};
|
use rustc_span::symbol::{kw, Ident};
|
||||||
use rustc_span::{BytePos, Span};
|
use rustc_span::{BytePos, Span};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
@ -407,11 +407,40 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
err.span_label(span, cannot_infer_msg);
|
err.span_label(span, cannot_infer_msg);
|
||||||
|
|
||||||
let printer = fmt_printer(self, Namespace::TypeNS);
|
let args = fmt_printer(self, Namespace::TypeNS)
|
||||||
let args = printer.comma_sep(generic_args.iter().copied()).unwrap().into_buffer();
|
.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 {
|
||||||
|
span: rustc_span::DUMMY_SP,
|
||||||
|
kind: ConstVariableOriginKind::MiscVariable,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.unwrap()
|
||||||
|
.into_buffer();
|
||||||
|
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
insert_span,
|
insert_span,
|
||||||
&format!("consider specifying the generic argument{}", pluralize!(args.len()),),
|
&format!(
|
||||||
|
"consider specifying the generic argument{}",
|
||||||
|
pluralize!(generic_args.len()),
|
||||||
|
),
|
||||||
format!("::<{}>", args),
|
format!("::<{}>", args),
|
||||||
Applicability::HasPlaceholders,
|
Applicability::HasPlaceholders,
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use crate::ty::{
|
use crate::ty::{
|
||||||
visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy,
|
visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferConst, InferTy,
|
||||||
PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
|
PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -82,15 +82,18 @@ pub trait IsSuggestable<'tcx> {
|
||||||
/// meaningful rendered suggestions when pretty-printed. We leave some
|
/// meaningful rendered suggestions when pretty-printed. We leave some
|
||||||
/// nonsense, such as region vars, since those render as `'_` and are
|
/// nonsense, such as region vars, since those render as `'_` and are
|
||||||
/// usually okay to reinterpret as elided lifetimes.
|
/// usually okay to reinterpret as elided lifetimes.
|
||||||
fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool;
|
///
|
||||||
|
/// Only if `infer_suggestable` is true, we consider type and const
|
||||||
|
/// inference variables to be suggestable.
|
||||||
|
fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, T> IsSuggestable<'tcx> for T
|
impl<'tcx, T> IsSuggestable<'tcx> for T
|
||||||
where
|
where
|
||||||
T: TypeVisitable<'tcx>,
|
T: TypeVisitable<'tcx>,
|
||||||
{
|
{
|
||||||
fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool {
|
fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool {
|
||||||
self.visit_with(&mut IsSuggestableVisitor { tcx }).is_continue()
|
self.visit_with(&mut IsSuggestableVisitor { tcx, infer_suggestable }).is_continue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +103,7 @@ pub fn suggest_arbitrary_trait_bound<'tcx>(
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
trait_pred: PolyTraitPredicate<'tcx>,
|
trait_pred: PolyTraitPredicate<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if !trait_pred.is_suggestable(tcx) {
|
if !trait_pred.is_suggestable(tcx, false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,6 +422,7 @@ impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
|
||||||
|
|
||||||
pub struct IsSuggestableVisitor<'tcx> {
|
pub struct IsSuggestableVisitor<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
infer_suggestable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
|
impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
|
||||||
|
@ -426,6 +430,8 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
|
||||||
|
|
||||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
match t.kind() {
|
match t.kind() {
|
||||||
|
Infer(InferTy::TyVar(_)) if self.infer_suggestable => {}
|
||||||
|
|
||||||
FnDef(..)
|
FnDef(..)
|
||||||
| Closure(..)
|
| Closure(..)
|
||||||
| Infer(..)
|
| Infer(..)
|
||||||
|
@ -479,6 +485,8 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
|
||||||
|
|
||||||
fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
match c.kind() {
|
match c.kind() {
|
||||||
|
ConstKind::Infer(InferConst::Var(_)) if self.infer_suggestable => {}
|
||||||
|
|
||||||
ConstKind::Infer(..)
|
ConstKind::Infer(..)
|
||||||
| ConstKind::Bound(..)
|
| ConstKind::Bound(..)
|
||||||
| ConstKind::Placeholder(..)
|
| ConstKind::Placeholder(..)
|
||||||
|
|
|
@ -378,7 +378,7 @@ fn suggest_restriction<'tcx>(
|
||||||
replace_ty: ty::ParamTy::new(generics.count() as u32, Symbol::intern(&type_param_name))
|
replace_ty: ty::ParamTy::new(generics.count() as u32, Symbol::intern(&type_param_name))
|
||||||
.to_ty(tcx),
|
.to_ty(tcx),
|
||||||
});
|
});
|
||||||
if !trait_pred.is_suggestable(tcx) {
|
if !trait_pred.is_suggestable(tcx, false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// We know we have an `impl Trait` that doesn't satisfy a required projection.
|
// We know we have an `impl Trait` that doesn't satisfy a required projection.
|
||||||
|
@ -417,7 +417,7 @@ fn suggest_restriction<'tcx>(
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
if !trait_pred.is_suggestable(tcx) {
|
if !trait_pred.is_suggestable(tcx, false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Trivial case: `T` needs an extra bound: `T: Bound`.
|
// Trivial case: `T` needs an extra bound: `T: Bound`.
|
||||||
|
@ -586,7 +586,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
// else in the predicate.
|
// else in the predicate.
|
||||||
if !trait_pred.skip_binder().trait_ref.substs[1..]
|
if !trait_pred.skip_binder().trait_ref.substs[1..]
|
||||||
.iter()
|
.iter()
|
||||||
.all(|g| g.is_suggestable(self.tcx))
|
.all(|g| g.is_suggestable(self.tcx, false))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
let param_type = tcx.infer_ctxt().enter(|infcx| {
|
let param_type = tcx.infer_ctxt().enter(|infcx| {
|
||||||
infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id))
|
infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id))
|
||||||
});
|
});
|
||||||
if param_type.is_suggestable(tcx) {
|
if param_type.is_suggestable(tcx, false) {
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
tcx.def_span(src_def_id),
|
tcx.def_span(src_def_id),
|
||||||
"consider changing this type parameter to be a `const` generic",
|
"consider changing this type parameter to be a `const` generic",
|
||||||
|
|
|
@ -2676,7 +2676,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
span,
|
span,
|
||||||
ty,
|
ty,
|
||||||
opt_sugg: Some((span, Applicability::MachineApplicable))
|
opt_sugg: Some((span, Applicability::MachineApplicable))
|
||||||
.filter(|_| ty.is_suggestable(tcx)),
|
.filter(|_| ty.is_suggestable(tcx, false)),
|
||||||
});
|
});
|
||||||
|
|
||||||
ty
|
ty
|
||||||
|
|
|
@ -1070,7 +1070,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let (_, expected_ty) = formal_and_expected_inputs[expected_idx];
|
let (_, expected_ty) = formal_and_expected_inputs[expected_idx];
|
||||||
if expected_ty.is_unit() {
|
if expected_ty.is_unit() {
|
||||||
"()".to_string()
|
"()".to_string()
|
||||||
} else if expected_ty.is_suggestable(tcx) {
|
} else if expected_ty.is_suggestable(tcx, false) {
|
||||||
format!("/* {} */", expected_ty)
|
format!("/* {} */", expected_ty)
|
||||||
} else {
|
} else {
|
||||||
"/* value */".to_string()
|
"/* value */".to_string()
|
||||||
|
|
|
@ -506,7 +506,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
|
self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
|
||||||
// Only suggest changing the return type for methods that
|
// Only suggest changing the return type for methods that
|
||||||
// haven't set a return type at all (and aren't `fn main()` or an impl).
|
// haven't set a return type at all (and aren't `fn main()` or an impl).
|
||||||
match (&fn_decl.output, found.is_suggestable(self.tcx), can_suggest, expected.is_unit()) {
|
match (
|
||||||
|
&fn_decl.output,
|
||||||
|
found.is_suggestable(self.tcx, false),
|
||||||
|
can_suggest,
|
||||||
|
expected.is_unit(),
|
||||||
|
) {
|
||||||
(&hir::FnRetTy::DefaultReturn(span), true, true, true) => {
|
(&hir::FnRetTy::DefaultReturn(span), true, true, true) => {
|
||||||
err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found });
|
err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found });
|
||||||
true
|
true
|
||||||
|
|
|
@ -1929,7 +1929,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
|
||||||
visitor.visit_ty(ty);
|
visitor.visit_ty(ty);
|
||||||
let mut diag = bad_placeholder(tcx, visitor.0, "return type");
|
let mut diag = bad_placeholder(tcx, visitor.0, "return type");
|
||||||
let ret_ty = fn_sig.skip_binder().output();
|
let ret_ty = fn_sig.skip_binder().output();
|
||||||
if ret_ty.is_suggestable(tcx) {
|
if ret_ty.is_suggestable(tcx, false) {
|
||||||
diag.span_suggestion(
|
diag.span_suggestion(
|
||||||
ty.span,
|
ty.span,
|
||||||
"replace with the correct return type",
|
"replace with the correct return type",
|
||||||
|
@ -1938,7 +1938,12 @@ fn infer_return_ty_for_fn_sig<'tcx>(
|
||||||
);
|
);
|
||||||
} else if matches!(ret_ty.kind(), ty::FnDef(..)) {
|
} else if matches!(ret_ty.kind(), ty::FnDef(..)) {
|
||||||
let fn_sig = ret_ty.fn_sig(tcx);
|
let fn_sig = ret_ty.fn_sig(tcx);
|
||||||
if fn_sig.skip_binder().inputs_and_output.iter().all(|t| t.is_suggestable(tcx)) {
|
if fn_sig
|
||||||
|
.skip_binder()
|
||||||
|
.inputs_and_output
|
||||||
|
.iter()
|
||||||
|
.all(|t| t.is_suggestable(tcx, false))
|
||||||
|
{
|
||||||
diag.span_suggestion(
|
diag.span_suggestion(
|
||||||
ty.span,
|
ty.span,
|
||||||
"replace with the correct return type",
|
"replace with the correct return type",
|
||||||
|
|
7
src/test/ui/closures/issue-99565.rs
Normal file
7
src/test/ui/closures/issue-99565.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
fn foo<T, U>(_: U) {}
|
||||||
|
|
||||||
|
fn bar() {
|
||||||
|
foo(|| {}); //~ ERROR type annotations needed
|
||||||
|
}
|
14
src/test/ui/closures/issue-99565.stderr
Normal file
14
src/test/ui/closures/issue-99565.stderr
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
error[E0282]: type annotations needed
|
||||||
|
--> $DIR/issue-99565.rs:6:5
|
||||||
|
|
|
||||||
|
LL | foo(|| {});
|
||||||
|
| ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
|
||||||
|
|
|
||||||
|
help: consider specifying the generic arguments
|
||||||
|
|
|
||||||
|
LL | foo::<T, _>(|| {});
|
||||||
|
| ++++++++
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0282`.
|
|
@ -4,7 +4,7 @@ error[E0282]: type annotations needed
|
||||||
LL | b.downcast_ref::<fn(_)->_>();
|
LL | b.downcast_ref::<fn(_)->_>();
|
||||||
| ^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `downcast_ref`
|
| ^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `downcast_ref`
|
||||||
|
|
|
|
||||||
help: consider specifying the generic arguments
|
help: consider specifying the generic argument
|
||||||
|
|
|
|
||||||
LL | b.downcast_ref::<fn(_) -> _>();
|
LL | b.downcast_ref::<fn(_) -> _>();
|
||||||
| ~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -4,7 +4,7 @@ error[E0282]: type annotations needed
|
||||||
LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))};
|
LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))};
|
||||||
| ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `swap`
|
| ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `swap`
|
||||||
|
|
|
|
||||||
help: consider specifying the generic arguments
|
help: consider specifying the generic argument
|
||||||
|
|
|
|
||||||
LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))};
|
LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))};
|
||||||
| ~~~~~~~~~~
|
| ~~~~~~~~~~
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue