@@ -18,11 +18,11 @@ use rustc_ast::Recovered;
18
18
use rustc_data_structures:: captures:: Captures ;
19
19
use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
20
20
use 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 } ;
23
22
use rustc_hir:: def:: DefKind ;
24
23
use 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} ;
26
26
use rustc_hir:: { GenericParamKind , Node } ;
27
27
use rustc_infer:: infer:: { InferCtxt , TyCtxtInferExt } ;
28
28
use rustc_infer:: traits:: ObligationCause ;
@@ -44,7 +44,7 @@ use std::ops::Bound;
44
44
45
45
use crate :: check:: intrinsic:: intrinsic_operation_unsafety;
46
46
use crate :: errors;
47
- use crate :: hir_ty_lowering:: HirTyLowerer ;
47
+ use crate :: hir_ty_lowering:: { HirTyLowerer , RegionInferReason } ;
48
48
pub use type_of:: test_opaque_hidden_types;
49
49
50
50
mod generics_of;
@@ -370,16 +370,26 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
370
370
self . tcx
371
371
}
372
372
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
375
375
}
376
376
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
+ }
383
393
}
384
394
385
395
fn ty_infer ( & self , _: Option < & ty:: GenericParamDef > , span : Span ) -> Ty < ' tcx > {
@@ -510,6 +520,89 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
510
520
fn set_tainted_by_errors ( & self , err : ErrorGuaranteed ) {
511
521
self . tainted_by_errors . set ( Some ( err) ) ;
512
522
}
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
+ }
513
606
}
514
607
515
608
/// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present.
0 commit comments