@@ -991,49 +991,33 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
991
991
let mut prev_ty = self . resolve_vars_if_possible (
992
992
typeck. expr_ty_adjusted_opt ( expr) . unwrap_or ( Ty :: new_misc_error ( self . tcx ) ) ,
993
993
) ;
994
- let mut annotate_expr = |span : Span , prev_ty : Ty < ' tcx > , self_ty : Ty < ' tcx > | -> bool {
995
- // We always look at the `E` type, because that's the only one affected by `?`. If the
996
- // incorrect `Result<T, E>` is because of the `T`, we'll get an E0308 on the whole
997
- // expression, after the `?` has "unwrapped" the `T`.
994
+
995
+ // We always look at the `E` type, because that's the only one affected by `?`. If the
996
+ // incorrect `Result<T, E>` is because of the `T`, we'll get an E0308 on the whole
997
+ // expression, after the `?` has "unwrapped" the `T`.
998
+ let get_e_type = |prev_ty : Ty < ' tcx > | -> Option < Ty < ' tcx > > {
998
999
let ty:: Adt ( def, args) = prev_ty. kind ( ) else {
999
- return false ;
1000
+ return None ;
1000
1001
} ;
1001
1002
let Some ( arg) = args. get ( 1 ) else {
1002
- return false ;
1003
+ return None ;
1003
1004
} ;
1004
1005
if !self . tcx . is_diagnostic_item ( sym:: Result , def. did ( ) ) {
1005
- return false ;
1006
+ return None ;
1006
1007
}
1007
- let can = if self
1008
- . infcx
1009
- . type_implements_trait (
1010
- self . tcx . get_diagnostic_item ( sym:: From ) . unwrap ( ) ,
1011
- [ self_ty. into ( ) , * arg] ,
1012
- obligation. param_env ,
1013
- )
1014
- . must_apply_modulo_regions ( )
1015
- {
1016
- "can"
1017
- } else {
1018
- "can't"
1019
- } ;
1020
- err. span_label (
1021
- span,
1022
- format ! ( "this {can} be annotated with `?` because it has type `{prev_ty}`" ) ,
1023
- ) ;
1024
- true
1008
+ Some ( arg. as_type ( ) ?)
1025
1009
} ;
1026
1010
1011
+ let mut chain = vec ! [ ] ;
1012
+
1027
1013
// The following logic is simlar to `point_at_chain`, but that's focused on associated types
1028
1014
let mut expr = expr;
1029
1015
while let hir:: ExprKind :: MethodCall ( _path_segment, rcvr_expr, _args, span) = expr. kind {
1030
1016
// Point at every method call in the chain with the `Result` type.
1031
1017
// let foo = bar.iter().map(mapper)?;
1032
1018
// ------ -----------
1033
1019
expr = rcvr_expr;
1034
- if !annotate_expr ( span, prev_ty, self_ty) {
1035
- break ;
1036
- }
1020
+ chain. push ( ( span, prev_ty) ) ;
1037
1021
1038
1022
prev_ty = self . resolve_vars_if_possible (
1039
1023
typeck. expr_ty_adjusted_opt ( expr) . unwrap_or ( Ty :: new_misc_error ( self . tcx ) ) ,
@@ -1061,7 +1045,41 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
1061
1045
prev_ty = self . resolve_vars_if_possible (
1062
1046
typeck. expr_ty_adjusted_opt ( expr) . unwrap_or ( Ty :: new_misc_error ( self . tcx ) ) ,
1063
1047
) ;
1064
- annotate_expr ( expr. span , prev_ty, self_ty) ;
1048
+ chain. push ( ( expr. span , prev_ty) ) ;
1049
+
1050
+ let mut prev = None ;
1051
+ for ( span, err_ty) in chain. into_iter ( ) . rev ( ) {
1052
+ let err_ty = get_e_type ( err_ty) ;
1053
+ let err_ty = match ( err_ty, prev) {
1054
+ ( Some ( err_ty) , Some ( prev) ) if !self . can_eq ( obligation. param_env , err_ty, prev) => {
1055
+ err_ty
1056
+ }
1057
+ ( Some ( err_ty) , None ) => err_ty,
1058
+ _ => {
1059
+ prev = err_ty;
1060
+ continue ;
1061
+ }
1062
+ } ;
1063
+ if self
1064
+ . infcx
1065
+ . type_implements_trait (
1066
+ self . tcx . get_diagnostic_item ( sym:: From ) . unwrap ( ) ,
1067
+ [ self_ty, err_ty] ,
1068
+ obligation. param_env ,
1069
+ )
1070
+ . must_apply_modulo_regions ( )
1071
+ {
1072
+ err. span_label ( span, format ! ( "this has type `Result<_, {err_ty}>`" ) ) ;
1073
+ } else {
1074
+ err. span_label (
1075
+ span,
1076
+ format ! (
1077
+ "this can't be annotated with `?` because it has type `Result<_, {err_ty}>`" ,
1078
+ ) ,
1079
+ ) ;
1080
+ }
1081
+ prev = Some ( err_ty) ;
1082
+ }
1065
1083
}
1066
1084
1067
1085
fn report_const_param_not_wf (
0 commit comments