@@ -18,11 +18,11 @@ use rustc_ast::Recovered;
1818use rustc_data_structures:: captures:: Captures ;
1919use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
2020use rustc_data_structures:: unord:: UnordMap ;
21- use rustc_errors:: { Applicability , Diag , ErrorGuaranteed , StashKey } ;
22- use rustc_hir as hir;
21+ use rustc_errors:: { struct_span_code_err, Applicability , Diag , ErrorGuaranteed , StashKey , E0228 } ;
2322use rustc_hir:: def:: DefKind ;
2423use rustc_hir:: def_id:: { DefId , LocalDefId } ;
25- use rustc_hir:: intravisit:: { self , Visitor } ;
24+ use rustc_hir:: intravisit:: { self , walk_generics, Visitor } ;
25+ use rustc_hir:: { self as hir} ;
2626use rustc_hir:: { GenericParamKind , Node } ;
2727use rustc_infer:: infer:: { InferCtxt , TyCtxtInferExt } ;
2828use rustc_infer:: traits:: ObligationCause ;
@@ -44,7 +44,7 @@ use std::ops::Bound;
4444
4545use crate :: check:: intrinsic:: intrinsic_operation_unsafety;
4646use crate :: errors;
47- use crate :: hir_ty_lowering:: HirTyLowerer ;
47+ use crate :: hir_ty_lowering:: { HirTyLowerer , RegionInferReason } ;
4848pub use type_of:: test_opaque_hidden_types;
4949
5050mod generics_of;
@@ -370,16 +370,26 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
370370 self . tcx
371371 }
372372
373- fn item_def_id ( & self ) -> DefId {
374- self . item_def_id . to_def_id ( )
373+ fn item_def_id ( & self ) -> LocalDefId {
374+ self . item_def_id
375375 }
376376
377- fn allow_infer ( & self ) -> bool {
378- false
379- }
380-
381- fn re_infer ( & self , _: Option < & ty:: GenericParamDef > , _: Span ) -> Option < ty:: Region < ' tcx > > {
382- None
377+ fn re_infer ( & self , span : Span , reason : RegionInferReason < ' _ > ) -> ty:: Region < ' tcx > {
378+ if let RegionInferReason :: BorrowedObjectLifetimeDefault = reason {
379+ let e = struct_span_code_err ! (
380+ self . tcx( ) . dcx( ) ,
381+ span,
382+ E0228 ,
383+ "the lifetime bound for this object type cannot be deduced \
384+ from context; please supply an explicit bound"
385+ )
386+ . emit ( ) ;
387+ self . set_tainted_by_errors ( e) ;
388+ ty:: Region :: new_error ( self . tcx ( ) , e)
389+ } else {
390+ // This indicates an illegal lifetime in a non-assoc-trait position
391+ ty:: Region :: new_error_with_message ( self . tcx ( ) , span, "unelided lifetime in signature" )
392+ }
383393 }
384394
385395 fn ty_infer ( & self , _: Option < & ty:: GenericParamDef > , span : Span ) -> Ty < ' tcx > {
@@ -510,6 +520,89 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
510520 fn set_tainted_by_errors ( & self , err : ErrorGuaranteed ) {
511521 self . tainted_by_errors . set ( Some ( err) ) ;
512522 }
523+
524+ fn lower_fn_sig (
525+ & self ,
526+ decl : & hir:: FnDecl < ' tcx > ,
527+ generics : Option < & hir:: Generics < ' _ > > ,
528+ hir_id : rustc_hir:: HirId ,
529+ hir_ty : Option < & hir:: Ty < ' _ > > ,
530+ ) -> ( Vec < Ty < ' tcx > > , Ty < ' tcx > ) {
531+ let tcx = self . tcx ( ) ;
532+ // We proactively collect all the inferred type params to emit a single error per fn def.
533+ let mut visitor = HirPlaceholderCollector :: default ( ) ;
534+ let mut infer_replacements = vec ! [ ] ;
535+
536+ if let Some ( generics) = generics {
537+ walk_generics ( & mut visitor, generics) ;
538+ }
539+
540+ let input_tys = decl
541+ . inputs
542+ . iter ( )
543+ . enumerate ( )
544+ . map ( |( i, a) | {
545+ if let hir:: TyKind :: Infer = a. kind {
546+ if let Some ( suggested_ty) =
547+ self . lowerer ( ) . suggest_trait_fn_ty_for_impl_fn_infer ( hir_id, Some ( i) )
548+ {
549+ infer_replacements. push ( ( a. span , suggested_ty. to_string ( ) ) ) ;
550+ return Ty :: new_error_with_message ( tcx, a. span , suggested_ty. to_string ( ) ) ;
551+ }
552+ }
553+
554+ // Only visit the type looking for `_` if we didn't fix the type above
555+ visitor. visit_ty ( a) ;
556+ self . lowerer ( ) . lower_arg_ty ( a, None )
557+ } )
558+ . collect ( ) ;
559+
560+ let output_ty = match decl. output {
561+ hir:: FnRetTy :: Return ( output) => {
562+ if let hir:: TyKind :: Infer = output. kind
563+ && let Some ( suggested_ty) =
564+ self . lowerer ( ) . suggest_trait_fn_ty_for_impl_fn_infer ( hir_id, None )
565+ {
566+ infer_replacements. push ( ( output. span , suggested_ty. to_string ( ) ) ) ;
567+ Ty :: new_error_with_message ( tcx, output. span , suggested_ty. to_string ( ) )
568+ } else {
569+ visitor. visit_ty ( output) ;
570+ self . lower_ty ( output)
571+ }
572+ }
573+ hir:: FnRetTy :: DefaultReturn ( ..) => tcx. types . unit ,
574+ } ;
575+
576+ if !( visitor. 0 . is_empty ( ) && infer_replacements. is_empty ( ) ) {
577+ // We check for the presence of
578+ // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
579+
580+ let mut diag = crate :: collect:: placeholder_type_error_diag (
581+ tcx,
582+ generics,
583+ visitor. 0 ,
584+ infer_replacements. iter ( ) . map ( |( s, _) | * s) . collect ( ) ,
585+ true ,
586+ hir_ty,
587+ "function" ,
588+ ) ;
589+
590+ if !infer_replacements. is_empty ( ) {
591+ diag. multipart_suggestion (
592+ format ! (
593+ "try replacing `_` with the type{} in the corresponding trait method signature" ,
594+ rustc_errors:: pluralize!( infer_replacements. len( ) ) ,
595+ ) ,
596+ infer_replacements,
597+ Applicability :: MachineApplicable ,
598+ ) ;
599+ }
600+
601+ self . set_tainted_by_errors ( diag. emit ( ) ) ;
602+ }
603+
604+ ( input_tys, output_ty)
605+ }
513606}
514607
515608/// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present.
0 commit comments