@@ -34,9 +34,10 @@ use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}
34
34
35
35
use std:: iter;
36
36
use std:: mem;
37
- use std:: ops:: ControlFlow ;
38
37
use std:: slice;
39
38
39
+ use std:: ops:: ControlFlow ;
40
+
40
41
impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
41
42
pub ( in super :: super ) fn check_casts ( & mut self ) {
42
43
// 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> {
1837
1838
. into_iter ( )
1838
1839
. flatten ( )
1839
1840
{
1840
- if self . point_at_arg_if_possible (
1841
+ if self . blame_specific_arg_if_possible (
1841
1842
error,
1842
1843
def_id,
1843
1844
param,
@@ -1867,7 +1868,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1867
1868
. into_iter ( )
1868
1869
. flatten ( )
1869
1870
{
1870
- if self . point_at_arg_if_possible (
1871
+ if self . blame_specific_arg_if_possible (
1871
1872
error,
1872
1873
def_id,
1873
1874
param,
@@ -1892,16 +1893,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1892
1893
for param in
1893
1894
[ param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
1894
1895
{
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 (
1898
1898
def_id,
1899
1899
param,
1900
1900
variant_def_id,
1901
1901
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
+ }
1905
1914
}
1906
1915
}
1907
1916
}
@@ -1934,7 +1943,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1934
1943
}
1935
1944
}
1936
1945
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 (
1938
1956
& self ,
1939
1957
error : & mut traits:: FulfillmentError < ' tcx > ,
1940
1958
def_id : DefId ,
@@ -1953,13 +1971,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1953
1971
. inputs ( )
1954
1972
. iter ( )
1955
1973
. 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) )
1957
1975
. collect ( ) ;
1958
1976
// If there's one field that references the given generic, great!
1959
1977
if let [ ( idx, _) ] = args_referencing_param. as_slice ( )
1960
1978
&& let Some ( arg) = receiver
1961
1979
. map_or ( args. get ( * idx) , |rcvr| if * idx == 0 { Some ( rcvr) } else { args. get ( * idx - 1 ) } ) {
1980
+
1962
1981
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
+
1963
1988
error. obligation . cause . map_code ( |parent_code| {
1964
1989
ObligationCauseCode :: FunctionArgumentObligation {
1965
1990
arg_hir_id : arg. hir_id ,
@@ -1977,14 +2002,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1977
2002
false
1978
2003
}
1979
2004
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 (
1981
2007
& self ,
1982
- error : & mut traits:: FulfillmentError < ' tcx > ,
1983
2008
def_id : DefId ,
1984
2009
param_to_point_at : ty:: GenericArg < ' tcx > ,
1985
2010
variant_def_id : DefId ,
1986
2011
expr_fields : & [ hir:: ExprField < ' tcx > ] ,
1987
- ) -> bool {
2012
+ ) -> Option < ( & ' tcx hir :: Expr < ' tcx > , Ty < ' tcx > ) > {
1988
2013
let def = self . tcx . adt_def ( def_id) ;
1989
2014
1990
2015
let identity_substs = ty:: InternalSubsts :: identity_for_item ( self . tcx , def_id) ;
@@ -1994,7 +2019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1994
2019
. iter ( )
1995
2020
. filter ( |field| {
1996
2021
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)
1998
2023
} )
1999
2024
. collect ( ) ;
2000
2025
@@ -2004,17 +2029,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2004
2029
// same rules that check_expr_struct uses for macro hygiene.
2005
2030
if self . tcx . adjust_ident ( expr_field. ident , variant_def_id) == field. ident ( self . tcx )
2006
2031
{
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 ) ) ) ;
2013
2033
}
2014
2034
}
2015
2035
}
2016
2036
2017
- false
2037
+ None
2018
2038
}
2019
2039
2020
2040
fn point_at_path_if_possible (
@@ -2234,23 +2254,3 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2234
2254
}
2235
2255
}
2236
2256
}
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