mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 11:07:42 +00:00
Only shown relevant type params in E0283 label
When we point at a binding to suggest giving it a type, erase all the type for ADTs that have been resolved, leaving only the ones that could not be inferred. For small shallow types this is not a problem, but for big nested types with lots of params, this can otherwise cause a lot of unnecessary visual output.
This commit is contained in:
parent
0fb1c371d4
commit
78e88f46d6
@ -11,7 +11,7 @@ use rustc_middle::hir::map::Map;
|
|||||||
use rustc_middle::infer::unify_key::ConstVariableOriginKind;
|
use rustc_middle::infer::unify_key::ConstVariableOriginKind;
|
||||||
use rustc_middle::ty::print::Print;
|
use rustc_middle::ty::print::Print;
|
||||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
|
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
|
||||||
use rustc_middle::ty::{self, DefIdTree, InferConst, Ty, TyCtxt};
|
use rustc_middle::ty::{self, DefIdTree, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder};
|
||||||
use rustc_span::symbol::kw;
|
use rustc_span::symbol::kw;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
@ -629,6 +629,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
format!("the explicit type `{}`, with the type parameters specified", ty)
|
format!("the explicit type `{}`, with the type parameters specified", ty)
|
||||||
}
|
}
|
||||||
Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => {
|
Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => {
|
||||||
|
let ty = ResolvedTypeParamEraser::new(self.tcx).fold_ty(ty);
|
||||||
|
let ty = ErrTypeParamEraser(self.tcx).fold_ty(ty);
|
||||||
let ty = ty_to_string(ty);
|
let ty = ty_to_string(ty);
|
||||||
format!(
|
format!(
|
||||||
"the explicit type `{}`, where the type parameter `{}` is specified",
|
"the explicit type `{}`, where the type parameter `{}` is specified",
|
||||||
@ -908,3 +910,99 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
err
|
err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Turn resolved type params into `[type error]` to signal we don't want to display them.
|
||||||
|
struct ResolvedTypeParamEraser<'tcx> {
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
level: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> ResolvedTypeParamEraser<'tcx> {
|
||||||
|
fn new(tcx: TyCtxt<'tcx>) -> Self {
|
||||||
|
ResolvedTypeParamEraser { tcx, level: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'tcx> TypeFolder<'tcx> for ResolvedTypeParamEraser<'tcx> {
|
||||||
|
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
|
||||||
|
self.tcx
|
||||||
|
}
|
||||||
|
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
|
self.level += 1;
|
||||||
|
let t = match t.kind() {
|
||||||
|
// We'll hide this type only if all its type params are hidden as well.
|
||||||
|
ty::Adt(def, substs) => {
|
||||||
|
let generics = self.tcx().generics_of(def.did);
|
||||||
|
// Account for params with default values, like `Vec`, where we
|
||||||
|
// want to show `Vec<T>`, not `Vec<T, _>`. If we replaced that
|
||||||
|
// subst, then we'd get the incorrect output, so we passthrough.
|
||||||
|
let substs: Vec<_> = substs
|
||||||
|
.iter()
|
||||||
|
.zip(generics.params.iter())
|
||||||
|
.map(|(subst, param)| match ¶m.kind {
|
||||||
|
ty::GenericParamDefKind::Type { has_default: true, .. } => subst,
|
||||||
|
_ => subst.super_fold_with(self),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
if self.level == 1
|
||||||
|
|| substs.iter().any(|subst| match subst.unpack() {
|
||||||
|
ty::subst::GenericArgKind::Type(t) => match t.kind() {
|
||||||
|
ty::Error(_) => false,
|
||||||
|
_ => true,
|
||||||
|
},
|
||||||
|
// Account for `const` params here, otherwise `doesnt_infer.rs`
|
||||||
|
// shows `_` instead of `Foo<{ _: u32 }>`
|
||||||
|
ty::subst::GenericArgKind::Const(_) => true,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
{
|
||||||
|
let substs = self.tcx().intern_substs(&substs[..]);
|
||||||
|
self.tcx().mk_ty(ty::Adt(def, substs))
|
||||||
|
} else {
|
||||||
|
self.tcx().ty_error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ty::Ref(_, ty, _) => {
|
||||||
|
let ty = self.fold_ty(ty);
|
||||||
|
match ty.kind() {
|
||||||
|
// Avoid `&_`, these can be safely presented as `_`.
|
||||||
|
ty::Error(_) => self.tcx().ty_error(),
|
||||||
|
_ => t.super_fold_with(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We could account for `()` if we wanted to replace it, but it's assured to be short.
|
||||||
|
ty::Tuple(_)
|
||||||
|
| ty::Slice(_)
|
||||||
|
| ty::RawPtr(_)
|
||||||
|
| ty::FnDef(..)
|
||||||
|
| ty::FnPtr(_)
|
||||||
|
| ty::Opaque(..)
|
||||||
|
| ty::Projection(_)
|
||||||
|
| ty::Never
|
||||||
|
| ty::Array(..) => t.super_fold_with(self),
|
||||||
|
// We don't want to hide type params that haven't been resolved yet.
|
||||||
|
// This would be the type that will be written out with the type param
|
||||||
|
// name in the output.
|
||||||
|
ty::Infer(_) => t,
|
||||||
|
// We don't want to hide the outermost type, only its type params.
|
||||||
|
_ if self.level == 1 => t.super_fold_with(self),
|
||||||
|
// Hide this type
|
||||||
|
_ => self.tcx().ty_error(),
|
||||||
|
};
|
||||||
|
self.level -= 1;
|
||||||
|
t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replace `[type error]` with `ty::Infer(ty::Var)` to display `_`.
|
||||||
|
struct ErrTypeParamEraser<'tcx>(TyCtxt<'tcx>);
|
||||||
|
impl<'tcx> TypeFolder<'tcx> for ErrTypeParamEraser<'tcx> {
|
||||||
|
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
|
match t.kind() {
|
||||||
|
ty::Error(_) => self.tcx().mk_ty_var(ty::TyVid::from_u32(0)),
|
||||||
|
_ => t.super_fold_with(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,7 +4,7 @@ error[E0282]: type annotations needed for `Foo<{_: u32}>`
|
|||||||
LL | let foo = Foo::foo();
|
LL | let foo = Foo::foo();
|
||||||
| --- ^^^^^^^^ cannot infer the value of const parameter `N`
|
| --- ^^^^^^^^ cannot infer the value of const parameter `N`
|
||||||
| |
|
| |
|
||||||
| consider giving `foo` the explicit type `Foo<{_: u32}>`, where the type parameter `N` is specified
|
| consider giving `foo` the explicit type `Foo<{_: _}>`, where the type parameter `N` is specified
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
13
src/test/ui/inference/erase-type-params-in-label.rs
Normal file
13
src/test/ui/inference/erase-type-params-in-label.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
fn main() {
|
||||||
|
let foo = new(1, ""); //~ ERROR E0283
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Bar<T, K, N: Default> {
|
||||||
|
t: T,
|
||||||
|
k: K,
|
||||||
|
n: N,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new<T, K, Z: Default>(t: T, k: K) -> Bar<T, K, Z> {
|
||||||
|
Bar { t, k, n: Default::default() }
|
||||||
|
}
|
22
src/test/ui/inference/erase-type-params-in-label.stderr
Normal file
22
src/test/ui/inference/erase-type-params-in-label.stderr
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
error[E0283]: type annotations needed for `Bar<i32, &str, Z>`
|
||||||
|
--> $DIR/erase-type-params-in-label.rs:2:15
|
||||||
|
|
|
||||||
|
LL | let foo = new(1, "");
|
||||||
|
| --- ^^^ cannot infer type for type parameter `Z` declared on the function `new`
|
||||||
|
| |
|
||||||
|
| consider giving `foo` the explicit type `Bar<_, _, Z>`, where the type parameter `Z` is specified
|
||||||
|
|
|
||||||
|
= note: cannot satisfy `_: Default`
|
||||||
|
note: required by a bound in `new`
|
||||||
|
--> $DIR/erase-type-params-in-label.rs:11:17
|
||||||
|
|
|
||||||
|
LL | fn new<T, K, Z: Default>(t: T, k: K) -> Bar<T, K, Z> {
|
||||||
|
| ^^^^^^^ required by this bound in `new`
|
||||||
|
help: consider specifying the type arguments in the function call
|
||||||
|
|
|
||||||
|
LL | let foo = new::<T, K, Z>(1, "");
|
||||||
|
| +++++++++++
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0283`.
|
@ -4,7 +4,7 @@ error[E0282]: type annotations needed for `[usize; _]`
|
|||||||
LL | let _ = foo("foo"); //<- Do not suggest `foo::<N>("foo");`!
|
LL | let _ = foo("foo"); //<- Do not suggest `foo::<N>("foo");`!
|
||||||
| - ^^^ cannot infer the value of const parameter `N` declared on the function `foo`
|
| - ^^^ cannot infer the value of const parameter `N` declared on the function `foo`
|
||||||
| |
|
| |
|
||||||
| consider giving this pattern the explicit type `[usize; _]`, where the type parameter `N` is specified
|
| consider giving this pattern the explicit type `[_; _]`, where the type parameter `N` is specified
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user