1
1
use crate :: infer:: type_variable:: TypeVariableOriginKind ;
2
- use crate :: infer:: InferCtxt ;
3
- use crate :: rustc_middle:: ty:: TypeFoldable ;
2
+ use crate :: infer:: { InferCtxt , Symbol } ;
4
3
use rustc_errors:: { pluralize, struct_span_err, Applicability , DiagnosticBuilder } ;
5
4
use rustc_hir as hir;
6
5
use rustc_hir:: def:: { DefKind , Namespace } ;
@@ -11,7 +10,7 @@ use rustc_middle::hir::map::Map;
11
10
use rustc_middle:: infer:: unify_key:: ConstVariableOriginKind ;
12
11
use rustc_middle:: ty:: print:: Print ;
13
12
use 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 } ;
15
14
use rustc_span:: symbol:: kw;
16
15
use rustc_span:: Span ;
17
16
use std:: borrow:: Cow ;
@@ -306,6 +305,15 @@ pub enum UnderspecifiedArgKind {
306
305
Const { is_parameter : bool } ,
307
306
}
308
307
308
+ impl UnderspecifiedArgKind {
309
+ fn descr ( & self ) -> & ' static str {
310
+ match self {
311
+ Self :: Type { .. } => "type" ,
312
+ Self :: Const { .. } => "const" ,
313
+ }
314
+ }
315
+ }
316
+
309
317
impl InferenceDiagnosticsData {
310
318
/// Generate a label for a generic argument which can't be inferred. When not
311
319
/// much is known about the argument, `use_diag` may be used to describe the
@@ -588,6 +596,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
588
596
}
589
597
}
590
598
599
+ let param_type = arg_data. kind . descr ( ) ;
591
600
let suffix = match local_visitor. found_node_ty {
592
601
Some ( ty) if ty. is_closure ( ) => {
593
602
let substs =
@@ -626,13 +635,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
626
635
}
627
636
Some ( ty) if is_named_and_not_impl_trait ( ty) && arg_data. name == "_" => {
628
637
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 )
630
639
}
631
640
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) ;
632
643
let ty = ty_to_string ( ty) ;
633
644
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,
636
647
)
637
648
}
638
649
_ => "a type" . to_string ( ) ,
@@ -908,3 +919,117 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
908
919
err
909
920
}
910
921
}
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