1
1
use super :: {
2
- EvaluationResult , Obligation , ObligationCause , ObligationCauseCode , PredicateObligation ,
2
+ DefIdOrName , Obligation , ObligationCause , ObligationCauseCode , PredicateObligation ,
3
3
SelectionContext ,
4
4
} ;
5
5
6
6
use crate :: autoderef:: Autoderef ;
7
7
use crate :: infer:: InferCtxt ;
8
8
use crate :: traits:: normalize_to;
9
9
10
+ use hir:: def:: CtorOf ;
10
11
use hir:: HirId ;
11
12
use rustc_data_structures:: fx:: FxHashSet ;
12
13
use rustc_data_structures:: stack:: ensure_sufficient_stack;
@@ -22,14 +23,15 @@ use rustc_hir::lang_items::LangItem;
22
23
use rustc_hir:: { AsyncGeneratorKind , GeneratorKind , Node } ;
23
24
use rustc_infer:: infer:: error_reporting:: TypeErrCtxt ;
24
25
use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
26
+ use rustc_infer:: infer:: LateBoundRegionConversionTime ;
25
27
use rustc_middle:: hir:: map;
26
28
use rustc_middle:: ty:: {
27
29
self , suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind , DefIdTree ,
28
30
GeneratorDiagnosticData , GeneratorInteriorTypeCause , Infer , InferTy , IsSuggestable ,
29
31
ToPredicate , Ty , TyCtxt , TypeFoldable , TypeFolder , TypeSuperFoldable , TypeVisitable ,
30
32
} ;
31
33
use rustc_middle:: ty:: { TypeAndMut , TypeckResults } ;
32
- use rustc_span:: symbol:: { kw , sym, Ident , Symbol } ;
34
+ use rustc_span:: symbol:: { sym, Ident , Symbol } ;
33
35
use rustc_span:: { BytePos , DesugaringKind , ExpnKind , Span , DUMMY_SP } ;
34
36
use rustc_target:: spec:: abi;
35
37
use std:: fmt;
@@ -812,74 +814,136 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
812
814
err : & mut Diagnostic ,
813
815
trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
814
816
) -> bool {
815
- // Skipping binder here, remapping below
816
- let self_ty = trait_pred. self_ty ( ) . skip_binder ( ) ;
817
-
818
- let ( def_id, output_ty, callable) = match * self_ty. kind ( ) {
819
- ty:: Closure ( def_id, substs) => ( def_id, substs. as_closure ( ) . sig ( ) . output ( ) , "closure" ) ,
820
- ty:: FnDef ( def_id, _) => ( def_id, self_ty. fn_sig ( self . tcx ) . output ( ) , "function" ) ,
821
- _ => return false ,
822
- } ;
823
- let msg = format ! ( "use parentheses to call the {}" , callable) ;
817
+ if let ty:: PredicateKind :: Trait ( trait_pred) = obligation. predicate . kind ( ) . skip_binder ( )
818
+ && Some ( trait_pred. def_id ( ) ) == self . tcx . lang_items ( ) . sized_trait ( )
819
+ {
820
+ // Don't suggest calling to turn an unsized type into a sized type
821
+ return false ;
822
+ }
824
823
825
- // "We should really create a single list of bound vars from the combined vars
826
- // from the predicate and function, but instead we just liberate the function bound vars"
827
- let output_ty = self . tcx . liberate_late_bound_regions ( def_id, output_ty) ;
824
+ // This is duplicated from `extract_callable_info` in typeck, which
825
+ // relies on autoderef, so we can't use it here.
826
+ let found = trait_pred. self_ty ( ) . skip_binder ( ) . peel_refs ( ) ;
827
+ let Some ( ( def_id_or_name, output, inputs) ) = ( match * found. kind ( )
828
+ {
829
+ ty:: FnPtr ( fn_sig) => {
830
+ Some ( ( DefIdOrName :: Name ( "function pointer" ) , fn_sig. output ( ) , fn_sig. inputs ( ) ) )
831
+ }
832
+ ty:: FnDef ( def_id, _) => {
833
+ let fn_sig = found. fn_sig ( self . tcx ) ;
834
+ Some ( ( DefIdOrName :: DefId ( def_id) , fn_sig. output ( ) , fn_sig. inputs ( ) ) )
835
+ }
836
+ ty:: Closure ( def_id, substs) => {
837
+ let fn_sig = substs. as_closure ( ) . sig ( ) ;
838
+ Some ( (
839
+ DefIdOrName :: DefId ( def_id) ,
840
+ fn_sig. output ( ) ,
841
+ fn_sig. inputs ( ) . map_bound ( |inputs| & inputs[ 1 ..] ) ,
842
+ ) )
843
+ }
844
+ ty:: Opaque ( def_id, substs) => {
845
+ self . tcx . bound_item_bounds ( def_id) . subst ( self . tcx , substs) . iter ( ) . find_map ( |pred| {
846
+ if let ty:: PredicateKind :: Projection ( proj) = pred. kind ( ) . skip_binder ( )
847
+ && Some ( proj. projection_ty . item_def_id ) == self . tcx . lang_items ( ) . fn_once_output ( )
848
+ // args tuple will always be substs[1]
849
+ && let ty:: Tuple ( args) = proj. projection_ty . substs . type_at ( 1 ) . kind ( )
850
+ {
851
+ Some ( (
852
+ DefIdOrName :: DefId ( def_id) ,
853
+ pred. kind ( ) . rebind ( proj. term . ty ( ) . unwrap ( ) ) ,
854
+ pred. kind ( ) . rebind ( args. as_slice ( ) ) ,
855
+ ) )
856
+ } else {
857
+ None
858
+ }
859
+ } )
860
+ }
861
+ ty:: Dynamic ( data, _, ty:: Dyn ) => {
862
+ data. iter ( ) . find_map ( |pred| {
863
+ if let ty:: ExistentialPredicate :: Projection ( proj) = pred. skip_binder ( )
864
+ && Some ( proj. item_def_id ) == self . tcx . lang_items ( ) . fn_once_output ( )
865
+ // for existential projection, substs are shifted over by 1
866
+ && let ty:: Tuple ( args) = proj. substs . type_at ( 0 ) . kind ( )
867
+ {
868
+ Some ( (
869
+ DefIdOrName :: Name ( "trait object" ) ,
870
+ pred. rebind ( proj. term . ty ( ) . unwrap ( ) ) ,
871
+ pred. rebind ( args. as_slice ( ) ) ,
872
+ ) )
873
+ } else {
874
+ None
875
+ }
876
+ } )
877
+ }
878
+ ty:: Param ( _) => {
879
+ obligation. param_env . caller_bounds ( ) . iter ( ) . find_map ( |pred| {
880
+ if let ty:: PredicateKind :: Projection ( proj) = pred. kind ( ) . skip_binder ( )
881
+ && Some ( proj. projection_ty . item_def_id ) == self . tcx . lang_items ( ) . fn_once_output ( )
882
+ && proj. projection_ty . self_ty ( ) == found
883
+ // args tuple will always be substs[1]
884
+ && let ty:: Tuple ( args) = proj. projection_ty . substs . type_at ( 1 ) . kind ( )
885
+ {
886
+ Some ( (
887
+ DefIdOrName :: Name ( "type parameter" ) ,
888
+ pred. kind ( ) . rebind ( proj. term . ty ( ) . unwrap ( ) ) ,
889
+ pred. kind ( ) . rebind ( args. as_slice ( ) ) ,
890
+ ) )
891
+ } else {
892
+ None
893
+ }
894
+ } )
895
+ }
896
+ _ => None ,
897
+ } ) else { return false ; } ;
898
+ let output = self . replace_bound_vars_with_fresh_vars (
899
+ obligation. cause . span ,
900
+ LateBoundRegionConversionTime :: FnCall ,
901
+ output,
902
+ ) ;
903
+ let inputs = inputs. skip_binder ( ) . iter ( ) . map ( |ty| {
904
+ self . replace_bound_vars_with_fresh_vars (
905
+ obligation. cause . span ,
906
+ LateBoundRegionConversionTime :: FnCall ,
907
+ inputs. rebind ( * ty) ,
908
+ )
909
+ } ) ;
828
910
829
911
// Remapping bound vars here
830
- let trait_pred_and_self = trait_pred. map_bound ( |trait_pred| ( trait_pred, output_ty ) ) ;
912
+ let trait_pred_and_self = trait_pred. map_bound ( |trait_pred| ( trait_pred, output ) ) ;
831
913
832
914
let new_obligation =
833
915
self . mk_trait_obligation_with_new_self_ty ( obligation. param_env , trait_pred_and_self) ;
834
-
835
- match self . evaluate_obligation ( & new_obligation) {
836
- Ok (
837
- EvaluationResult :: EvaluatedToOk
838
- | EvaluationResult :: EvaluatedToOkModuloRegions
839
- | EvaluationResult :: EvaluatedToOkModuloOpaqueTypes
840
- | EvaluationResult :: EvaluatedToAmbig ,
841
- ) => { }
842
- _ => return false ,
916
+ if !self . predicate_must_hold_modulo_regions ( & new_obligation) {
917
+ return false ;
843
918
}
844
- let hir = self . tcx . hir ( ) ;
919
+
845
920
// Get the name of the callable and the arguments to be used in the suggestion.
846
- let ( snippet, sugg) = match hir. get_if_local ( def_id) {
847
- Some ( hir:: Node :: Expr ( hir:: Expr {
848
- kind : hir:: ExprKind :: Closure ( hir:: Closure { fn_decl, fn_decl_span, .. } ) ,
849
- ..
850
- } ) ) => {
851
- err. span_label ( * fn_decl_span, "consider calling this closure" ) ;
852
- let Some ( name) = self . get_closure_name ( def_id, err, & msg) else {
853
- return false ;
854
- } ;
855
- let args = fn_decl. inputs . iter ( ) . map ( |_| "_" ) . collect :: < Vec < _ > > ( ) . join ( ", " ) ;
856
- let sugg = format ! ( "({})" , args) ;
857
- ( format ! ( "{}{}" , name, sugg) , sugg)
858
- }
859
- Some ( hir:: Node :: Item ( hir:: Item {
860
- ident,
861
- kind : hir:: ItemKind :: Fn ( .., body_id) ,
862
- ..
863
- } ) ) => {
864
- err. span_label ( ident. span , "consider calling this function" ) ;
865
- let body = hir. body ( * body_id) ;
866
- let args = body
867
- . params
868
- . iter ( )
869
- . map ( |arg| match & arg. pat . kind {
870
- hir:: PatKind :: Binding ( _, _, ident, None )
871
- // FIXME: provide a better suggestion when encountering `SelfLower`, it
872
- // should suggest a method call.
873
- if ident. name != kw:: SelfLower => ident. to_string ( ) ,
874
- _ => "_" . to_string ( ) ,
875
- } )
876
- . collect :: < Vec < _ > > ( )
877
- . join ( ", " ) ;
878
- let sugg = format ! ( "({})" , args) ;
879
- ( format ! ( "{}{}" , ident, sugg) , sugg)
880
- }
881
- _ => return false ,
921
+ let hir = self . tcx . hir ( ) ;
922
+
923
+ let msg = match def_id_or_name {
924
+ DefIdOrName :: DefId ( def_id) => match self . tcx . def_kind ( def_id) {
925
+ DefKind :: Ctor ( CtorOf :: Struct , _) => {
926
+ "use parentheses to construct this tuple struct" . to_string ( )
927
+ }
928
+ DefKind :: Ctor ( CtorOf :: Variant , _) => {
929
+ "use parentheses to construct this tuple variant" . to_string ( )
930
+ }
931
+ kind => format ! ( "use parentheses to call this {}" , kind. descr( def_id) ) ,
932
+ } ,
933
+ DefIdOrName :: Name ( name) => format ! ( "use parentheses to call this {name}" ) ,
882
934
} ;
935
+
936
+ let args = inputs
937
+ . map ( |ty| {
938
+ if ty. is_suggestable ( self . tcx , false ) {
939
+ format ! ( "/* {ty} */" )
940
+ } else {
941
+ "/* value */" . to_string ( )
942
+ }
943
+ } )
944
+ . collect :: < Vec < _ > > ( )
945
+ . join ( ", " ) ;
946
+
883
947
if matches ! ( obligation. cause. code( ) , ObligationCauseCode :: FunctionArgumentObligation { .. } )
884
948
&& obligation. cause . span . can_be_used_for_suggestions ( )
885
949
{
@@ -890,11 +954,36 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
890
954
err. span_suggestion_verbose (
891
955
obligation. cause . span . shrink_to_hi ( ) ,
892
956
& msg,
893
- sugg ,
957
+ format ! ( "({args})" ) ,
894
958
Applicability :: HasPlaceholders ,
895
959
) ;
896
- } else {
897
- err. help ( & format ! ( "{}: `{}`" , msg, snippet) ) ;
960
+ } else if let DefIdOrName :: DefId ( def_id) = def_id_or_name {
961
+ let name = match hir. get_if_local ( def_id) {
962
+ Some ( hir:: Node :: Expr ( hir:: Expr {
963
+ kind : hir:: ExprKind :: Closure ( hir:: Closure { fn_decl_span, .. } ) ,
964
+ ..
965
+ } ) ) => {
966
+ err. span_label ( * fn_decl_span, "consider calling this closure" ) ;
967
+ let Some ( name) = self . get_closure_name ( def_id, err, & msg) else {
968
+ return false ;
969
+ } ;
970
+ name. to_string ( )
971
+ }
972
+ Some ( hir:: Node :: Item ( hir:: Item { ident, kind : hir:: ItemKind :: Fn ( ..) , .. } ) ) => {
973
+ err. span_label ( ident. span , "consider calling this function" ) ;
974
+ ident. to_string ( )
975
+ }
976
+ Some ( hir:: Node :: Ctor ( ..) ) => {
977
+ let name = self . tcx . def_path_str ( def_id) ;
978
+ err. span_label (
979
+ self . tcx . def_span ( def_id) ,
980
+ format ! ( "consider calling the constructor for `{}`" , name) ,
981
+ ) ;
982
+ name
983
+ }
984
+ _ => return false ,
985
+ } ;
986
+ err. help ( & format ! ( "{msg}: `{name}({args})`" ) ) ;
898
987
}
899
988
true
900
989
}
0 commit comments