@@ -135,6 +135,7 @@ use syntax::util::parser::ExprPrecedence;
135135
136136use rustc_error_codes:: * ;
137137
138+ use std:: borrow:: Cow ;
138139use std:: cell:: { Cell , Ref , RefCell , RefMut } ;
139140use std:: cmp;
140141use std:: collections:: hash_map:: Entry ;
@@ -254,6 +255,8 @@ pub struct Inherited<'a, 'tcx> {
254255 /// not clear.
255256 implicit_region_bound : Option < ty:: Region < ' tcx > > ,
256257
258+ inferred_paths : RefCell < FxHashMap < hir:: HirId , InferredPath < ' tcx > > > ,
259+
257260 body_id : Option < hir:: BodyId > ,
258261}
259262
@@ -619,6 +622,13 @@ pub struct FnCtxt<'a, 'tcx> {
619622 inh : & ' a Inherited < ' a , ' tcx > ,
620623}
621624
625+ #[ derive( Clone , Debug ) ]
626+ struct InferredPath < ' tcx > {
627+ span : Span ,
628+ ty : Option < Ty < ' tcx > > ,
629+ args : Option < Cow < ' tcx , [ Ty < ' tcx > ] > > ,
630+ }
631+
622632impl < ' a , ' tcx > Deref for FnCtxt < ' a , ' tcx > {
623633 type Target = Inherited < ' a , ' tcx > ;
624634 fn deref ( & self ) -> & Self :: Target {
@@ -685,6 +695,7 @@ impl Inherited<'a, 'tcx> {
685695 opaque_types : RefCell :: new ( Default :: default ( ) ) ,
686696 opaque_types_vars : RefCell :: new ( Default :: default ( ) ) ,
687697 implicit_region_bound,
698+ inferred_paths : RefCell :: new ( Default :: default ( ) ) ,
688699 body_id,
689700 }
690701 }
@@ -1053,6 +1064,32 @@ fn typeck_tables_of_with_fallback<'tcx>(
10531064 // All type checking constraints were added, try to fallback unsolved variables.
10541065 fcx. select_obligations_where_possible ( false , |_| { } ) ;
10551066 let mut fallback_has_occurred = false ;
1067+ let unresolved_paths: FxHashMap < hir:: HirId , InferredPath < ' tcx > > = fcx
1068+ . inferred_paths
1069+ . borrow ( )
1070+ . iter ( )
1071+ . map ( |( id, path) | ( * id, path. clone ( ) ) )
1072+ . filter ( |( hir_id, path) | {
1073+ debug ! (
1074+ "typeck_tables_of_with_fallback: inspecting path ({:?}, {:?})" ,
1075+ hir_id, path
1076+ ) ;
1077+ let debug_resolved = fcx. infcx . resolve_vars_if_possible ( & path. ty ) ;
1078+ if fcx. infcx . unresolved_type_vars ( & path. ty ) . is_some ( ) {
1079+ debug ! (
1080+ "typeck_tables_of_with_fallback: unresolved vars in ty: {:?}" ,
1081+ debug_resolved
1082+ ) ;
1083+ true
1084+ } else {
1085+ debug ! (
1086+ "typeck_tables_of_with_fallback: all vars resolved in ty: {:?}" ,
1087+ debug_resolved
1088+ ) ;
1089+ false
1090+ }
1091+ } )
1092+ . collect ( ) ;
10561093
10571094 // We do fallback in two passes, to try to generate
10581095 // better error messages.
@@ -1095,6 +1132,42 @@ fn typeck_tables_of_with_fallback<'tcx>(
10951132 // See if we can make any more progress.
10961133 fcx. select_obligations_where_possible ( fallback_has_occurred, |_| { } ) ;
10971134
1135+ for ( call_id, path) in unresolved_paths {
1136+ debug ! (
1137+ "Resolved ty: {:?} at span {:?} : expr={:?} parent={:?} path={:?}" ,
1138+ path. span,
1139+ path. ty,
1140+ tcx. hir( ) . get( call_id) ,
1141+ tcx. hir( ) . get( tcx. hir( ) . get_parent_node( call_id) ) ,
1142+ path
1143+ ) ;
1144+
1145+ let ty = fcx. infcx . resolve_vars_if_possible ( & path. ty ) ;
1146+ debug ! ( "Fully resolved ty: {:?}" , ty) ;
1147+
1148+ let ty = ty. unwrap_or_else ( || bug ! ( "Missing ty in path: {:?}" , path) ) ;
1149+
1150+ if let ty:: FnDef ( _, substs) = ty. kind {
1151+ debug ! ( "Got substs: {:?}" , substs) ;
1152+ let mut inhabited = true ;
1153+ for arg in & * path. args . unwrap ( ) {
1154+ let resolved_arg = fcx. infcx . resolve_vars_if_possible ( arg) ;
1155+
1156+ if resolved_arg. conservative_is_privately_uninhabited ( tcx) {
1157+ debug ! ( "Arg is uninhabited: {:?}" , resolved_arg) ;
1158+ inhabited = false ;
1159+ break ;
1160+ } else {
1161+ debug ! ( "Arg is inhabited: {:?}" , resolved_arg) ;
1162+ }
1163+ }
1164+
1165+ if inhabited {
1166+ debug ! ( "All arguments are inhabited!" ) ;
1167+ }
1168+ }
1169+ }
1170+
10981171 // Even though coercion casts provide type hints, we check casts after fallback for
10991172 // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
11001173 fcx. check_casts ( ) ;
@@ -3624,7 +3697,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
36243697 self . check_argument_types (
36253698 sp,
36263699 expr,
3627- & err_inputs[ .. ] ,
3700+ err_inputs,
36283701 & [ ] ,
36293702 args_no_rcvr,
36303703 false ,
@@ -3732,13 +3805,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
37323805 & self ,
37333806 sp : Span ,
37343807 expr : & ' tcx hir:: Expr < ' tcx > ,
3735- fn_inputs : & [ Ty < ' tcx > ] ,
3808+ fn_inputs : impl Into < Cow < ' tcx , [ Ty < ' tcx > ] > > ,
37363809 expected_arg_tys : & [ Ty < ' tcx > ] ,
37373810 args : & ' tcx [ hir:: Expr < ' tcx > ] ,
37383811 c_variadic : bool ,
37393812 tuple_arguments : TupleArgumentsFlag ,
37403813 def_span : Option < Span > ,
37413814 ) {
3815+ let fn_inputs = fn_inputs. into ( ) ;
3816+ debug ! ( "check_argument_types: storing arguments for expr {:?}" , expr) ;
3817+ match self . inferred_paths . borrow_mut ( ) . entry ( expr. hir_id ) {
3818+ Entry :: Vacant ( e) => {
3819+ debug ! ( "check_argument_types: making new entry for types {:?}" , fn_inputs) ;
3820+ e. insert ( InferredPath { span : sp, ty : None , args : Some ( fn_inputs. clone ( ) ) } ) ;
3821+ }
3822+ Entry :: Occupied ( mut e) => {
3823+ debug ! (
3824+ "check_argument_types: modifiying exsting entry {:?} with types {:?}" ,
3825+ e. get( ) ,
3826+ fn_inputs
3827+ ) ;
3828+ e. get_mut ( ) . args = Some ( fn_inputs. clone ( ) ) ;
3829+ }
3830+ }
3831+
37423832 let tcx = self . tcx ;
37433833 // Grab the argument types, supplying fresh type variables
37443834 // if the wrong number of arguments were supplied
@@ -5425,6 +5515,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
54255515 // the referenced item.
54265516 let ty_substituted = self . instantiate_type_scheme ( span, & substs, & ty) ;
54275517
5518+ if ty_substituted. has_infer_types ( ) {
5519+ debug ! (
5520+ "instantiate_value_path: saving path with infer: ({:?}, {:?})" ,
5521+ span, ty_substituted
5522+ ) ;
5523+ let parent_id = tcx. hir ( ) . get_parent_node ( hir_id) ;
5524+ let parent = tcx. hir ( ) . get ( parent_id) ;
5525+ match parent {
5526+ Node :: Expr ( hir:: Expr { span : p_span, kind : ExprKind :: Call ( ..) , .. } )
5527+ | Node :: Expr ( hir:: Expr { span : p_span, kind : ExprKind :: MethodCall ( ..) , .. } ) => {
5528+ match self . inferred_paths . borrow_mut ( ) . entry ( parent_id) {
5529+ Entry :: Vacant ( e) => {
5530+ debug ! ( "instantiate_value_path: inserting new path" ) ;
5531+ e. insert ( InferredPath {
5532+ span : * p_span,
5533+ ty : Some ( ty_substituted) ,
5534+ args : None ,
5535+ } ) ;
5536+ }
5537+ Entry :: Occupied ( mut e) => {
5538+ debug ! ( "instantiate_value_path: updating existing path {:?}" , e. get( ) ) ;
5539+ e. get_mut ( ) . ty = Some ( ty_substituted) ;
5540+ }
5541+ }
5542+ }
5543+ _ => { }
5544+ }
5545+ }
5546+
54285547 if let Some ( UserSelfTy { impl_def_id, self_ty } ) = user_self_ty {
54295548 // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
54305549 // is inherent, there is no `Self` parameter; instead, the impl needs
0 commit comments