11use crate :: infer:: type_variable:: TypeVariableOriginKind ;
2- use crate :: infer:: InferCtxt ;
3- use crate :: rustc_middle:: ty:: TypeFoldable ;
2+ use crate :: infer:: { InferCtxt , Symbol } ;
43use rustc_errors:: { pluralize, struct_span_err, Applicability , DiagnosticBuilder } ;
54use rustc_hir as hir;
65use rustc_hir:: def:: { DefKind , Namespace } ;
@@ -11,7 +10,7 @@ use rustc_middle::hir::map::Map;
1110use rustc_middle:: infer:: unify_key:: ConstVariableOriginKind ;
1211use rustc_middle:: ty:: print:: Print ;
1312use rustc_middle:: ty:: subst:: { GenericArg , GenericArgKind } ;
14- use rustc_middle:: ty:: { self , DefIdTree , InferConst , Ty , TyCtxt } ;
13+ use rustc_middle:: ty:: { self , Const , DefIdTree , InferConst , Ty , TyCtxt , TypeFoldable , TypeFolder } ;
1514use rustc_span:: symbol:: kw;
1615use rustc_span:: Span ;
1716use std:: borrow:: Cow ;
@@ -306,6 +305,15 @@ pub enum UnderspecifiedArgKind {
306305 Const { is_parameter : bool } ,
307306}
308307
308+ impl UnderspecifiedArgKind {
309+ fn descr ( & self ) -> & ' static str {
310+ match self {
311+ Self :: Type { .. } => "type" ,
312+ Self :: Const { .. } => "const" ,
313+ }
314+ }
315+ }
316+
309317impl InferenceDiagnosticsData {
310318 /// Generate a label for a generic argument which can't be inferred. When not
311319 /// much is known about the argument, `use_diag` may be used to describe the
@@ -588,6 +596,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
588596 }
589597 }
590598
599+ let param_type = arg_data. kind . descr ( ) ;
591600 let suffix = match local_visitor. found_node_ty {
592601 Some ( ty) if ty. is_closure ( ) => {
593602 let substs =
@@ -626,13 +635,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
626635 }
627636 Some ( ty) if is_named_and_not_impl_trait ( ty) && arg_data. name == "_" => {
628637 let ty = ty_to_string ( ty) ;
629- format ! ( "the explicit type `{}`, with the type parameters specified" , ty)
638+ format ! ( "the explicit type `{}`, with the {} parameters specified" , ty, param_type )
630639 }
631640 Some ( ty) if is_named_and_not_impl_trait ( ty) && ty. to_string ( ) != arg_data. name => {
641+ let ty = ResolvedTypeParamEraser :: new ( self . tcx ) . fold_ty ( ty) ;
642+ let ty = ErrTypeParamEraser ( self . tcx ) . fold_ty ( ty) ;
632643 let ty = ty_to_string ( ty) ;
633644 format ! (
634- "the explicit type `{}`, where the type parameter `{}` is specified" ,
635- ty, arg_data. name,
645+ "the explicit type `{}`, where the {} parameter `{}` is specified" ,
646+ ty, param_type , arg_data. name,
636647 )
637648 }
638649 _ => "a type" . to_string ( ) ,
@@ -908,3 +919,117 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
908919 err
909920 }
910921}
922+
923+ /// Turn *resolved* type params into `[type error]` to signal we don't want to display them. After
924+ /// performing that replacement, we'll turn all remaining infer type params to use their name from
925+ /// their definition, and replace all the `[type error]`s back to being infer so they display in
926+ /// the output as `_`. If we didn't go through `[type error]`, we would either show all type params
927+ /// by their name *or* `_`, neither of which is desireable: we want to show all types that we could
928+ /// infer as `_` to reduce verbosity and avoid telling the user about unnecessary type annotations.
929+ struct ResolvedTypeParamEraser < ' tcx > {
930+ tcx : TyCtxt < ' tcx > ,
931+ level : usize ,
932+ }
933+
934+ impl < ' tcx > ResolvedTypeParamEraser < ' tcx > {
935+ fn new ( tcx : TyCtxt < ' tcx > ) -> Self {
936+ ResolvedTypeParamEraser { tcx, level : 0 }
937+ }
938+
939+ /// Replace not yet inferred const params with their def name.
940+ fn replace_infers ( & self , c : & ' tcx Const < ' tcx > , index : u32 , name : Symbol ) -> & ' tcx Const < ' tcx > {
941+ match c. val {
942+ ty:: ConstKind :: Infer ( ..) => self . tcx ( ) . mk_const_param ( index, name, c. ty ) ,
943+ _ => c,
944+ }
945+ }
946+ }
947+
948+ impl < ' tcx > TypeFolder < ' tcx > for ResolvedTypeParamEraser < ' tcx > {
949+ fn tcx < ' a > ( & ' a self ) -> TyCtxt < ' tcx > {
950+ self . tcx
951+ }
952+ fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
953+ self . level += 1 ;
954+ let t = match t. kind ( ) {
955+ // We'll hide this type only if all its type params are hidden as well.
956+ ty:: Adt ( def, substs) => {
957+ let generics = self . tcx ( ) . generics_of ( def. did ) ;
958+ // Account for params with default values, like `Vec`, where we
959+ // want to show `Vec<T>`, not `Vec<T, _>`. If we replaced that
960+ // subst, then we'd get the incorrect output, so we passthrough.
961+ let substs: Vec < _ > = substs
962+ . iter ( )
963+ . zip ( generics. params . iter ( ) )
964+ . map ( |( subst, param) | match & ( subst. unpack ( ) , & param. kind ) {
965+ ( _, ty:: GenericParamDefKind :: Type { has_default : true , .. } ) => subst,
966+ ( crate :: infer:: GenericArgKind :: Const ( c) , _) => {
967+ self . replace_infers ( c, param. index , param. name ) . into ( )
968+ }
969+ _ => subst. super_fold_with ( self ) ,
970+ } )
971+ . collect ( ) ;
972+ let should_keep = |subst : & GenericArg < ' _ > | match subst. unpack ( ) {
973+ ty:: subst:: GenericArgKind :: Type ( t) => match t. kind ( ) {
974+ ty:: Error ( _) => false ,
975+ _ => true ,
976+ } ,
977+ // Account for `const` params here, otherwise `doesnt_infer.rs`
978+ // shows `_` instead of `Foo<{ _: u32 }>`
979+ ty:: subst:: GenericArgKind :: Const ( _) => true ,
980+ _ => false ,
981+ } ;
982+ if self . level == 1 || substs. iter ( ) . any ( should_keep) {
983+ let substs = self . tcx ( ) . intern_substs ( & substs[ ..] ) ;
984+ self . tcx ( ) . mk_ty ( ty:: Adt ( def, substs) )
985+ } else {
986+ self . tcx ( ) . ty_error ( )
987+ }
988+ }
989+ ty:: Ref ( _, ty, _) => {
990+ let ty = self . fold_ty ( ty) ;
991+ match ty. kind ( ) {
992+ // Avoid `&_`, these can be safely presented as `_`.
993+ ty:: Error ( _) => self . tcx ( ) . ty_error ( ) ,
994+ _ => t. super_fold_with ( self ) ,
995+ }
996+ }
997+ // We could account for `()` if we wanted to replace it, but it's assured to be short.
998+ ty:: Tuple ( _)
999+ | ty:: Slice ( _)
1000+ | ty:: RawPtr ( _)
1001+ | ty:: FnDef ( ..)
1002+ | ty:: FnPtr ( _)
1003+ | ty:: Opaque ( ..)
1004+ | ty:: Projection ( _)
1005+ | ty:: Never => t. super_fold_with ( self ) ,
1006+ ty:: Array ( ty, c) => self
1007+ . tcx ( )
1008+ . mk_ty ( ty:: Array ( self . fold_ty ( ty) , self . replace_infers ( c, 0 , Symbol :: intern ( "N" ) ) ) ) ,
1009+ // We don't want to hide type params that haven't been resolved yet.
1010+ // This would be the type that will be written out with the type param
1011+ // name in the output.
1012+ ty:: Infer ( _) => t,
1013+ // We don't want to hide the outermost type, only its type params.
1014+ _ if self . level == 1 => t. super_fold_with ( self ) ,
1015+ // Hide this type
1016+ _ => self . tcx ( ) . ty_error ( ) ,
1017+ } ;
1018+ self . level -= 1 ;
1019+ t
1020+ }
1021+ }
1022+
1023+ /// Replace `[type error]` with `ty::Infer(ty::Var)` to display `_`.
1024+ struct ErrTypeParamEraser < ' tcx > ( TyCtxt < ' tcx > ) ;
1025+ impl < ' tcx > TypeFolder < ' tcx > for ErrTypeParamEraser < ' tcx > {
1026+ fn tcx < ' a > ( & ' a self ) -> TyCtxt < ' tcx > {
1027+ self . 0
1028+ }
1029+ fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
1030+ match t. kind ( ) {
1031+ ty:: Error ( _) => self . tcx ( ) . mk_ty_var ( ty:: TyVid :: from_u32 ( 0 ) ) ,
1032+ _ => t. super_fold_with ( self ) ,
1033+ }
1034+ }
1035+ }
0 commit comments