1
1
use crate :: infer:: type_variable:: TypeVariableOriginKind ;
2
- use crate :: infer:: InferCtxt ;
2
+ use crate :: infer:: { InferCtxt , Symbol } ;
3
3
use rustc_errors:: { pluralize, struct_span_err, Applicability , DiagnosticBuilder } ;
4
4
use rustc_hir as hir;
5
5
use rustc_hir:: def:: { DefKind , Namespace } ;
@@ -10,7 +10,7 @@ use rustc_middle::hir::map::Map;
10
10
use rustc_middle:: infer:: unify_key:: ConstVariableOriginKind ;
11
11
use rustc_middle:: ty:: print:: Print ;
12
12
use 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 } ;
14
14
use rustc_span:: symbol:: kw;
15
15
use rustc_span:: Span ;
16
16
use std:: borrow:: Cow ;
@@ -305,6 +305,15 @@ pub enum UnderspecifiedArgKind {
305
305
Const { is_parameter : bool } ,
306
306
}
307
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
+
308
317
impl InferenceDiagnosticsData {
309
318
/// Generate a label for a generic argument which can't be inferred. When not
310
319
/// much is known about the argument, `use_diag` may be used to describe the
@@ -548,6 +557,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
548
557
}
549
558
}
550
559
560
+ let param_type = arg_data. kind . descr ( ) ;
551
561
let suffix = match local_visitor. found_node_ty {
552
562
Some ( ty) if ty. is_closure ( ) => {
553
563
let substs =
@@ -586,13 +596,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
586
596
}
587
597
Some ( ty) if is_named_and_not_impl_trait ( ty) && arg_data. name == "_" => {
588
598
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 )
590
600
}
591
601
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) ;
592
604
let ty = ty_to_string ( ty) ;
593
605
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,
596
608
)
597
609
}
598
610
_ => "a type" . to_string ( ) ,
@@ -868,3 +880,117 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
868
880
err
869
881
}
870
882
}
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