11use crate :: infer:: type_variable:: TypeVariableOriginKind ;
2- use crate :: infer:: InferCtxt ;
2+ use crate :: infer:: { InferCtxt , Symbol } ;
33use rustc_errors:: { pluralize, struct_span_err, Applicability , DiagnosticBuilder } ;
44use rustc_hir as hir;
55use rustc_hir:: def:: { DefKind , Namespace } ;
@@ -10,7 +10,7 @@ use rustc_middle::hir::map::Map;
1010use rustc_middle:: infer:: unify_key:: ConstVariableOriginKind ;
1111use rustc_middle:: ty:: print:: Print ;
1212use rustc_middle:: ty:: subst:: { GenericArg , GenericArgKind } ;
13- use rustc_middle:: ty:: { self , DefIdTree , InferConst , Ty , TyCtxt } ;
13+ use rustc_middle:: ty:: { self , Const , DefIdTree , InferConst , Ty , TyCtxt , TypeFoldable , TypeFolder } ;
1414use rustc_span:: symbol:: kw;
1515use rustc_span:: Span ;
1616use std:: borrow:: Cow ;
@@ -305,6 +305,15 @@ pub enum UnderspecifiedArgKind {
305305 Const { is_parameter : bool } ,
306306}
307307
308+ impl UnderspecifiedArgKind {
309+ fn descr ( & self ) -> & ' static str {
310+ match self {
311+ Self :: Type { .. } => "type" ,
312+ Self :: Const { .. } => "const" ,
313+ }
314+ }
315+ }
316+
308317impl InferenceDiagnosticsData {
309318 /// Generate a label for a generic argument which can't be inferred. When not
310319 /// much is known about the argument, `use_diag` may be used to describe the
@@ -548,6 +557,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
548557 }
549558 }
550559
560+ let param_type = arg_data. kind . descr ( ) ;
551561 let suffix = match local_visitor. found_node_ty {
552562 Some ( ty) if ty. is_closure ( ) => {
553563 let substs =
@@ -586,13 +596,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
586596 }
587597 Some ( ty) if is_named_and_not_impl_trait ( ty) && arg_data. name == "_" => {
588598 let ty = ty_to_string ( ty) ;
589- format ! ( "the explicit type `{}`, with the type parameters specified" , ty)
599+ format ! ( "the explicit type `{}`, with the {} parameters specified" , ty, param_type )
590600 }
591601 Some ( ty) if is_named_and_not_impl_trait ( ty) && ty. to_string ( ) != arg_data. name => {
602+ let ty = ResolvedTypeParamEraser :: new ( self . tcx ) . fold_ty ( ty) ;
603+ let ty = ErrTypeParamEraser ( self . tcx ) . fold_ty ( ty) ;
592604 let ty = ty_to_string ( ty) ;
593605 format ! (
594- "the explicit type `{}`, where the type parameter `{}` is specified" ,
595- ty, arg_data. name,
606+ "the explicit type `{}`, where the {} parameter `{}` is specified" ,
607+ ty, param_type , arg_data. name,
596608 )
597609 }
598610 _ => "a type" . to_string ( ) ,
@@ -868,3 +880,117 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
868880 err
869881 }
870882}
883+
884+ /// Turn *resolved* type params into `[type error]` to signal we don't want to display them. After
885+ /// performing that replacement, we'll turn all remaining infer type params to use their name from
886+ /// their definition, and replace all the `[type error]`s back to being infer so they display in
887+ /// the output as `_`. If we didn't go through `[type error]`, we would either show all type params
888+ /// by their name *or* `_`, neither of which is desireable: we want to show all types that we could
889+ /// infer as `_` to reduce verbosity and avoid telling the user about unnecessary type annotations.
890+ struct ResolvedTypeParamEraser < ' tcx > {
891+ tcx : TyCtxt < ' tcx > ,
892+ level : usize ,
893+ }
894+
895+ impl < ' tcx > ResolvedTypeParamEraser < ' tcx > {
896+ fn new ( tcx : TyCtxt < ' tcx > ) -> Self {
897+ ResolvedTypeParamEraser { tcx, level : 0 }
898+ }
899+
900+ /// Replace not yet inferred const params with their def name.
901+ fn replace_infers ( & self , c : & ' tcx Const < ' tcx > , index : u32 , name : Symbol ) -> & ' tcx Const < ' tcx > {
902+ match c. val {
903+ ty:: ConstKind :: Infer ( ..) => self . tcx ( ) . mk_const_param ( index, name, c. ty ) ,
904+ _ => c,
905+ }
906+ }
907+ }
908+
909+ impl < ' tcx > TypeFolder < ' tcx > for ResolvedTypeParamEraser < ' tcx > {
910+ fn tcx < ' a > ( & ' a self ) -> TyCtxt < ' tcx > {
911+ self . tcx
912+ }
913+ fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
914+ self . level += 1 ;
915+ let t = match t. kind ( ) {
916+ // We'll hide this type only if all its type params are hidden as well.
917+ ty:: Adt ( def, substs) => {
918+ let generics = self . tcx ( ) . generics_of ( def. did ) ;
919+ // Account for params with default values, like `Vec`, where we
920+ // want to show `Vec<T>`, not `Vec<T, _>`. If we replaced that
921+ // subst, then we'd get the incorrect output, so we passthrough.
922+ let substs: Vec < _ > = substs
923+ . iter ( )
924+ . zip ( generics. params . iter ( ) )
925+ . map ( |( subst, param) | match & ( subst. unpack ( ) , & param. kind ) {
926+ ( _, ty:: GenericParamDefKind :: Type { has_default : true , .. } ) => subst,
927+ ( crate :: infer:: GenericArgKind :: Const ( c) , _) => {
928+ self . replace_infers ( c, param. index , param. name ) . into ( )
929+ }
930+ _ => subst. super_fold_with ( self ) ,
931+ } )
932+ . collect ( ) ;
933+ let should_keep = |subst : & GenericArg < ' _ > | match subst. unpack ( ) {
934+ ty:: subst:: GenericArgKind :: Type ( t) => match t. kind ( ) {
935+ ty:: Error ( _) => false ,
936+ _ => true ,
937+ } ,
938+ // Account for `const` params here, otherwise `doesnt_infer.rs`
939+ // shows `_` instead of `Foo<{ _: u32 }>`
940+ ty:: subst:: GenericArgKind :: Const ( _) => true ,
941+ _ => false ,
942+ } ;
943+ if self . level == 1 || substs. iter ( ) . any ( should_keep) {
944+ let substs = self . tcx ( ) . intern_substs ( & substs[ ..] ) ;
945+ self . tcx ( ) . mk_ty ( ty:: Adt ( def, substs) )
946+ } else {
947+ self . tcx ( ) . ty_error ( )
948+ }
949+ }
950+ ty:: Ref ( _, ty, _) => {
951+ let ty = self . fold_ty ( ty) ;
952+ match ty. kind ( ) {
953+ // Avoid `&_`, these can be safely presented as `_`.
954+ ty:: Error ( _) => self . tcx ( ) . ty_error ( ) ,
955+ _ => t. super_fold_with ( self ) ,
956+ }
957+ }
958+ // We could account for `()` if we wanted to replace it, but it's assured to be short.
959+ ty:: Tuple ( _)
960+ | ty:: Slice ( _)
961+ | ty:: RawPtr ( _)
962+ | ty:: FnDef ( ..)
963+ | ty:: FnPtr ( _)
964+ | ty:: Opaque ( ..)
965+ | ty:: Projection ( _)
966+ | ty:: Never => t. super_fold_with ( self ) ,
967+ ty:: Array ( ty, c) => self
968+ . tcx ( )
969+ . mk_ty ( ty:: Array ( self . fold_ty ( ty) , self . replace_infers ( c, 0 , Symbol :: intern ( "N" ) ) ) ) ,
970+ // We don't want to hide type params that haven't been resolved yet.
971+ // This would be the type that will be written out with the type param
972+ // name in the output.
973+ ty:: Infer ( _) => t,
974+ // We don't want to hide the outermost type, only its type params.
975+ _ if self . level == 1 => t. super_fold_with ( self ) ,
976+ // Hide this type
977+ _ => self . tcx ( ) . ty_error ( ) ,
978+ } ;
979+ self . level -= 1 ;
980+ t
981+ }
982+ }
983+
984+ /// Replace `[type error]` with `ty::Infer(ty::Var)` to display `_`.
985+ struct ErrTypeParamEraser < ' tcx > ( TyCtxt < ' tcx > ) ;
986+ impl < ' tcx > TypeFolder < ' tcx > for ErrTypeParamEraser < ' tcx > {
987+ fn tcx < ' a > ( & ' a self ) -> TyCtxt < ' tcx > {
988+ self . 0
989+ }
990+ fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
991+ match t. kind ( ) {
992+ ty:: Error ( _) => self . tcx ( ) . mk_ty_var ( ty:: TyVid :: from_u32 ( 0 ) ) ,
993+ _ => t. super_fold_with ( self ) ,
994+ }
995+ }
996+ }
0 commit comments