Don't suggest unnameable generic arguments
This commit is contained in:
parent
af7ab34470
commit
c98399f5eb
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 rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
|
@ -8,12 +8,12 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
|
||||
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::print::{FmtPrinter, PrettyPrinter, Print, Printer};
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
|
||||
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::{BytePos, Span};
|
||||
use std::borrow::Cow;
|
||||
|
@ -407,11 +407,40 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
|
||||
err.span_label(span, cannot_infer_msg);
|
||||
|
||||
let printer = fmt_printer(self, Namespace::TypeNS);
|
||||
let args = printer.comma_sep(generic_args.iter().copied()).unwrap().into_buffer();
|
||||
let args = 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 {
|
||||
span: rustc_span::DUMMY_SP,
|
||||
kind: ConstVariableOriginKind::MiscVariable,
|
||||
},
|
||||
)
|
||||
.into(),
|
||||
}
|
||||
}))
|
||||
.unwrap()
|
||||
.into_buffer();
|
||||
|
||||
err.span_suggestion_verbose(
|
||||
insert_span,
|
||||
&format!("consider specifying the generic argument{}", pluralize!(args.len()),),
|
||||
&format!(
|
||||
"consider specifying the generic argument{}",
|
||||
pluralize!(generic_args.len()),
|
||||
),
|
||||
format!("::<{}>", args),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
use crate::ty::{
|
||||
visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy,
|
||||
visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferConst, InferTy,
|
||||
PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
|
||||
};
|
||||
|
||||
|
@ -82,15 +82,18 @@ pub trait IsSuggestable<'tcx> {
|
|||
/// meaningful rendered suggestions when pretty-printed. We leave some
|
||||
/// nonsense, such as region vars, since those render as `'_` and are
|
||||
/// 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
|
||||
where
|
||||
T: TypeVisitable<'tcx>,
|
||||
{
|
||||
fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool {
|
||||
self.visit_with(&mut IsSuggestableVisitor { tcx }).is_continue()
|
||||
fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool {
|
||||
self.visit_with(&mut IsSuggestableVisitor { tcx, infer_suggestable }).is_continue()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,7 +103,7 @@ pub fn suggest_arbitrary_trait_bound<'tcx>(
|
|||
err: &mut Diagnostic,
|
||||
trait_pred: PolyTraitPredicate<'tcx>,
|
||||
) -> bool {
|
||||
if !trait_pred.is_suggestable(tcx) {
|
||||
if !trait_pred.is_suggestable(tcx, false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -419,6 +422,7 @@ impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
|
|||
|
||||
pub struct IsSuggestableVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
infer_suggestable: bool,
|
||||
}
|
||||
|
||||
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> {
|
||||
match t.kind() {
|
||||
Infer(InferTy::TyVar(_)) if self.infer_suggestable => {}
|
||||
|
||||
FnDef(..)
|
||||
| Closure(..)
|
||||
| Infer(..)
|
||||
|
@ -479,6 +485,8 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
|
|||
|
||||
fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
match c.kind() {
|
||||
ConstKind::Infer(InferConst::Var(_)) if self.infer_suggestable => {}
|
||||
|
||||
ConstKind::Infer(..)
|
||||
| ConstKind::Bound(..)
|
||||
| ConstKind::Placeholder(..)
|
||||
|
|
|
@ -378,7 +378,7 @@ fn suggest_restriction<'tcx>(
|
|||
replace_ty: ty::ParamTy::new(generics.count() as u32, Symbol::intern(&type_param_name))
|
||||
.to_ty(tcx),
|
||||
});
|
||||
if !trait_pred.is_suggestable(tcx) {
|
||||
if !trait_pred.is_suggestable(tcx, false) {
|
||||
return;
|
||||
}
|
||||
// We know we have an `impl Trait` that doesn't satisfy a required projection.
|
||||
|
@ -417,7 +417,7 @@ fn suggest_restriction<'tcx>(
|
|||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
if !trait_pred.is_suggestable(tcx) {
|
||||
if !trait_pred.is_suggestable(tcx, false) {
|
||||
return;
|
||||
}
|
||||
// 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.
|
||||
if !trait_pred.skip_binder().trait_ref.substs[1..]
|
||||
.iter()
|
||||
.all(|g| g.is_suggestable(self.tcx))
|
||||
.all(|g| g.is_suggestable(self.tcx, false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
let param_type = tcx.infer_ctxt().enter(|infcx| {
|
||||
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(
|
||||
tcx.def_span(src_def_id),
|
||||
"consider changing this type parameter to be a `const` generic",
|
||||
|
|
|
@ -2676,7 +2676,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
span,
|
||||
ty,
|
||||
opt_sugg: Some((span, Applicability::MachineApplicable))
|
||||
.filter(|_| ty.is_suggestable(tcx)),
|
||||
.filter(|_| ty.is_suggestable(tcx, false)),
|
||||
});
|
||||
|
||||
ty
|
||||
|
|
|
@ -1070,7 +1070,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let (_, expected_ty) = formal_and_expected_inputs[expected_idx];
|
||||
if expected_ty.is_unit() {
|
||||
"()".to_string()
|
||||
} else if expected_ty.is_suggestable(tcx) {
|
||||
} else if expected_ty.is_suggestable(tcx, false) {
|
||||
format!("/* {} */", expected_ty)
|
||||
} else {
|
||||
"/* value */".to_string()
|
||||
|
|
|
@ -507,7 +507,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
|
||||
// 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).
|
||||
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) => {
|
||||
err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found });
|
||||
true
|
||||
|
|
|
@ -1929,7 +1929,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
|
|||
visitor.visit_ty(ty);
|
||||
let mut diag = bad_placeholder(tcx, visitor.0, "return type");
|
||||
let ret_ty = fn_sig.skip_binder().output();
|
||||
if ret_ty.is_suggestable(tcx) {
|
||||
if ret_ty.is_suggestable(tcx, false) {
|
||||
diag.span_suggestion(
|
||||
ty.span,
|
||||
"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(..)) {
|
||||
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(
|
||||
ty.span,
|
||||
"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(_)->_>();
|
||||
| ^^^^^^^^^^^^ 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(_) -> _>();
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
|
|
@ -4,7 +4,7 @@ error[E0282]: type annotations needed
|
|||
LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))};
|
||||
| ^^^^^^^^^^^^^^ 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))};
|
||||
| ~~~~~~~~~~
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue