@@ -34,9 +34,10 @@ use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}
3434
3535use std:: iter;
3636use std:: mem;
37- use std:: ops:: ControlFlow ;
3837use std:: slice;
3938
39+ use std:: ops:: ControlFlow ;
40+
4041impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
4142 pub ( in super :: super ) fn check_casts ( & mut self ) {
4243 // don't hold the borrow to deferred_cast_checks while checking to avoid borrow checker errors
@@ -1837,7 +1838,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18371838 . into_iter ( )
18381839 . flatten ( )
18391840 {
1840- if self . point_at_arg_if_possible (
1841+ if self . blame_specific_arg_if_possible (
18411842 error,
18421843 def_id,
18431844 param,
@@ -1867,7 +1868,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18671868 . into_iter ( )
18681869 . flatten ( )
18691870 {
1870- if self . point_at_arg_if_possible (
1871+ if self . blame_specific_arg_if_possible (
18711872 error,
18721873 def_id,
18731874 param,
@@ -1892,16 +1893,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18921893 for param in
18931894 [ param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
18941895 {
1895- if let Some ( param) = param
1896- && self . point_at_field_if_possible (
1897- error,
1896+ if let Some ( param) = param {
1897+ let refined_expr = self . point_at_field_if_possible (
18981898 def_id,
18991899 param,
19001900 variant_def_id,
19011901 fields,
1902- )
1903- {
1904- return true ;
1902+ ) ;
1903+
1904+ match refined_expr {
1905+ None => { }
1906+ Some ( ( refined_expr, _) ) => {
1907+ error. obligation . cause . span = refined_expr
1908+ . span
1909+ . find_ancestor_in_same_ctxt ( error. obligation . cause . span )
1910+ . unwrap_or ( refined_expr. span ) ;
1911+ return true ;
1912+ }
1913+ }
19051914 }
19061915 }
19071916 }
@@ -1934,7 +1943,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
19341943 }
19351944 }
19361945
1937- fn point_at_arg_if_possible (
1946+ /// - `blame_specific_*` means that the function will recursively traverse the expression,
1947+ /// looking for the most-specific-possible span to blame.
1948+ ///
1949+ /// - `point_at_*` means that the function will only go "one level", pointing at the specific
1950+ /// expression mentioned.
1951+ ///
1952+ /// `blame_specific_arg_if_possible` will find the most-specific expression anywhere inside
1953+ /// the provided function call expression, and mark it as responsible for the fullfillment
1954+ /// error.
1955+ fn blame_specific_arg_if_possible (
19381956 & self ,
19391957 error : & mut traits:: FulfillmentError < ' tcx > ,
19401958 def_id : DefId ,
@@ -1953,13 +1971,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
19531971 . inputs ( )
19541972 . iter ( )
19551973 . enumerate ( )
1956- . filter ( |( _, ty) | find_param_in_ty ( * * ty, param_to_point_at) )
1974+ . filter ( |( _, ty) | Self :: find_param_in_ty ( ( * * ty) . into ( ) , param_to_point_at) )
19571975 . collect ( ) ;
19581976 // If there's one field that references the given generic, great!
19591977 if let [ ( idx, _) ] = args_referencing_param. as_slice ( )
19601978 && let Some ( arg) = receiver
19611979 . map_or ( args. get ( * idx) , |rcvr| if * idx == 0 { Some ( rcvr) } else { args. get ( * idx - 1 ) } ) {
1980+
19621981 error. obligation . cause . span = arg. span . find_ancestor_in_same_ctxt ( error. obligation . cause . span ) . unwrap_or ( arg. span ) ;
1982+
1983+ if let hir:: Node :: Expr ( arg_expr) = self . tcx . hir ( ) . get ( arg. hir_id ) {
1984+ // This is more specific than pointing at the entire argument.
1985+ self . blame_specific_expr_if_possible ( error, arg_expr)
1986+ }
1987+
19631988 error. obligation . cause . map_code ( |parent_code| {
19641989 ObligationCauseCode :: FunctionArgumentObligation {
19651990 arg_hir_id : arg. hir_id ,
@@ -1977,14 +2002,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
19772002 false
19782003 }
19792004
1980- fn point_at_field_if_possible (
2005+ // FIXME: Make this private and move to mod adjust_fulfillment_errors
2006+ pub fn point_at_field_if_possible (
19812007 & self ,
1982- error : & mut traits:: FulfillmentError < ' tcx > ,
19832008 def_id : DefId ,
19842009 param_to_point_at : ty:: GenericArg < ' tcx > ,
19852010 variant_def_id : DefId ,
19862011 expr_fields : & [ hir:: ExprField < ' tcx > ] ,
1987- ) -> bool {
2012+ ) -> Option < ( & ' tcx hir :: Expr < ' tcx > , Ty < ' tcx > ) > {
19882013 let def = self . tcx . adt_def ( def_id) ;
19892014
19902015 let identity_substs = ty:: InternalSubsts :: identity_for_item ( self . tcx , def_id) ;
@@ -1994,7 +2019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
19942019 . iter ( )
19952020 . filter ( |field| {
19962021 let field_ty = field. ty ( self . tcx , identity_substs) ;
1997- find_param_in_ty ( field_ty, param_to_point_at)
2022+ Self :: find_param_in_ty ( field_ty. into ( ) , param_to_point_at)
19982023 } )
19992024 . collect ( ) ;
20002025
@@ -2004,17 +2029,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20042029 // same rules that check_expr_struct uses for macro hygiene.
20052030 if self . tcx . adjust_ident ( expr_field. ident , variant_def_id) == field. ident ( self . tcx )
20062031 {
2007- error. obligation . cause . span = expr_field
2008- . expr
2009- . span
2010- . find_ancestor_in_same_ctxt ( error. obligation . cause . span )
2011- . unwrap_or ( expr_field. span ) ;
2012- return true ;
2032+ return Some ( ( expr_field. expr , self . tcx . type_of ( field. did ) ) ) ;
20132033 }
20142034 }
20152035 }
20162036
2017- false
2037+ None
20182038 }
20192039
20202040 fn point_at_path_if_possible (
@@ -2234,23 +2254,3 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22342254 }
22352255 }
22362256}
2237-
2238- fn find_param_in_ty < ' tcx > ( ty : Ty < ' tcx > , param_to_point_at : ty:: GenericArg < ' tcx > ) -> bool {
2239- let mut walk = ty. walk ( ) ;
2240- while let Some ( arg) = walk. next ( ) {
2241- if arg == param_to_point_at {
2242- return true ;
2243- } else if let ty:: GenericArgKind :: Type ( ty) = arg. unpack ( )
2244- && let ty:: Alias ( ty:: Projection , ..) = ty. kind ( )
2245- {
2246- // This logic may seem a bit strange, but typically when
2247- // we have a projection type in a function signature, the
2248- // argument that's being passed into that signature is
2249- // not actually constraining that projection's substs in
2250- // a meaningful way. So we skip it, and see improvements
2251- // in some UI tests.
2252- walk. skip_current_subtree ( ) ;
2253- }
2254- }
2255- false
2256- }
0 commit comments