11use super :: {
2- EvaluationResult , Obligation , ObligationCause , ObligationCauseCode , PredicateObligation ,
2+ DefIdOrName , Obligation , ObligationCause , ObligationCauseCode , PredicateObligation ,
33 SelectionContext ,
44} ;
55
66use crate :: autoderef:: Autoderef ;
77use crate :: infer:: InferCtxt ;
88use crate :: traits:: normalize_to;
99
10+ use hir:: def:: CtorOf ;
1011use hir:: HirId ;
1112use rustc_data_structures:: fx:: FxHashSet ;
1213use rustc_data_structures:: stack:: ensure_sufficient_stack;
@@ -22,14 +23,15 @@ use rustc_hir::lang_items::LangItem;
2223use rustc_hir:: { AsyncGeneratorKind , GeneratorKind , Node } ;
2324use rustc_infer:: infer:: error_reporting:: TypeErrCtxt ;
2425use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
26+ use rustc_infer:: infer:: LateBoundRegionConversionTime ;
2527use rustc_middle:: hir:: map;
2628use rustc_middle:: ty:: {
2729 self , suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind , DefIdTree ,
2830 GeneratorDiagnosticData , GeneratorInteriorTypeCause , Infer , InferTy , IsSuggestable ,
2931 ToPredicate , Ty , TyCtxt , TypeFoldable , TypeFolder , TypeSuperFoldable , TypeVisitable ,
3032} ;
3133use rustc_middle:: ty:: { TypeAndMut , TypeckResults } ;
32- use rustc_span:: symbol:: { kw , sym, Ident , Symbol } ;
34+ use rustc_span:: symbol:: { sym, Ident , Symbol } ;
3335use rustc_span:: { BytePos , DesugaringKind , ExpnKind , Span , DUMMY_SP } ;
3436use rustc_target:: spec:: abi;
3537use std:: fmt;
@@ -812,74 +814,136 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
812814 err : & mut Diagnostic ,
813815 trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
814816 ) -> 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+ }
824823
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+ } ) ;
828910
829911 // 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 ) ) ;
831913
832914 let new_obligation =
833915 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 ;
843918 }
844- let hir = self . tcx . hir ( ) ;
919+
845920 // 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}" ) ,
882934 } ;
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+
883947 if matches ! ( obligation. cause. code( ) , ObligationCauseCode :: FunctionArgumentObligation { .. } )
884948 && obligation. cause . span . can_be_used_for_suggestions ( )
885949 {
@@ -890,11 +954,36 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
890954 err. span_suggestion_verbose (
891955 obligation. cause . span . shrink_to_hi ( ) ,
892956 & msg,
893- sugg ,
957+ format ! ( "({args})" ) ,
894958 Applicability :: HasPlaceholders ,
895959 ) ;
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})`" ) ) ;
898987 }
899988 true
900989 }
0 commit comments