@@ -1049,49 +1049,33 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
1049
1049
let mut prev_ty = self . resolve_vars_if_possible (
1050
1050
typeck. expr_ty_adjusted_opt ( expr) . unwrap_or ( Ty :: new_misc_error ( self . tcx ) ) ,
1051
1051
) ;
1052
- let mut annotate_expr = |span : Span , prev_ty : Ty < ' tcx > , self_ty : Ty < ' tcx > | -> bool {
1053
- // We always look at the `E` type, because that's the only one affected by `?`. If the
1054
- // incorrect `Result<T, E>` is because of the `T`, we'll get an E0308 on the whole
1055
- // expression, after the `?` has "unwrapped" the `T`.
1052
+
1053
+ // We always look at the `E` type, because that's the only one affected by `?`. If the
1054
+ // incorrect `Result<T, E>` is because of the `T`, we'll get an E0308 on the whole
1055
+ // expression, after the `?` has "unwrapped" the `T`.
1056
+ let get_e_type = |prev_ty : Ty < ' tcx > | -> Option < Ty < ' tcx > > {
1056
1057
let ty:: Adt ( def, args) = prev_ty. kind ( ) else {
1057
- return false ;
1058
+ return None ;
1058
1059
} ;
1059
1060
let Some ( arg) = args. get ( 1 ) else {
1060
- return false ;
1061
+ return None ;
1061
1062
} ;
1062
1063
if !self . tcx . is_diagnostic_item ( sym:: Result , def. did ( ) ) {
1063
- return false ;
1064
+ return None ;
1064
1065
}
1065
- let can = if self
1066
- . infcx
1067
- . type_implements_trait (
1068
- self . tcx . get_diagnostic_item ( sym:: From ) . unwrap ( ) ,
1069
- [ self_ty. into ( ) , * arg] ,
1070
- obligation. param_env ,
1071
- )
1072
- . must_apply_modulo_regions ( )
1073
- {
1074
- "can"
1075
- } else {
1076
- "can't"
1077
- } ;
1078
- err. span_label (
1079
- span,
1080
- format ! ( "this {can} be annotated with `?` because it has type `{prev_ty}`" ) ,
1081
- ) ;
1082
- true
1066
+ Some ( arg. as_type ( ) ?)
1083
1067
} ;
1084
1068
1069
+ let mut chain = vec ! [ ] ;
1070
+
1085
1071
// The following logic is simlar to `point_at_chain`, but that's focused on associated types
1086
1072
let mut expr = expr;
1087
1073
while let hir:: ExprKind :: MethodCall ( _path_segment, rcvr_expr, _args, span) = expr. kind {
1088
1074
// Point at every method call in the chain with the `Result` type.
1089
1075
// let foo = bar.iter().map(mapper)?;
1090
1076
// ------ -----------
1091
1077
expr = rcvr_expr;
1092
- if !annotate_expr ( span, prev_ty, self_ty) {
1093
- break ;
1094
- }
1078
+ chain. push ( ( span, prev_ty) ) ;
1095
1079
1096
1080
prev_ty = self . resolve_vars_if_possible (
1097
1081
typeck. expr_ty_adjusted_opt ( expr) . unwrap_or ( Ty :: new_misc_error ( self . tcx ) ) ,
@@ -1121,7 +1105,41 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
1121
1105
prev_ty = self . resolve_vars_if_possible (
1122
1106
typeck. expr_ty_adjusted_opt ( expr) . unwrap_or ( Ty :: new_misc_error ( self . tcx ) ) ,
1123
1107
) ;
1124
- annotate_expr ( expr. span , prev_ty, self_ty) ;
1108
+ chain. push ( ( expr. span , prev_ty) ) ;
1109
+
1110
+ let mut prev = None ;
1111
+ for ( span, err_ty) in chain. into_iter ( ) . rev ( ) {
1112
+ let err_ty = get_e_type ( err_ty) ;
1113
+ let err_ty = match ( err_ty, prev) {
1114
+ ( Some ( err_ty) , Some ( prev) ) if !self . can_eq ( obligation. param_env , err_ty, prev) => {
1115
+ err_ty
1116
+ }
1117
+ ( Some ( err_ty) , None ) => err_ty,
1118
+ _ => {
1119
+ prev = err_ty;
1120
+ continue ;
1121
+ }
1122
+ } ;
1123
+ if self
1124
+ . infcx
1125
+ . type_implements_trait (
1126
+ self . tcx . get_diagnostic_item ( sym:: From ) . unwrap ( ) ,
1127
+ [ self_ty, err_ty] ,
1128
+ obligation. param_env ,
1129
+ )
1130
+ . must_apply_modulo_regions ( )
1131
+ {
1132
+ err. span_label ( span, format ! ( "this has type `Result<_, {err_ty}>`" ) ) ;
1133
+ } else {
1134
+ err. span_label (
1135
+ span,
1136
+ format ! (
1137
+ "this can't be annotated with `?` because it has type `Result<_, {err_ty}>`" ,
1138
+ ) ,
1139
+ ) ;
1140
+ }
1141
+ prev = Some ( err_ty) ;
1142
+ }
1125
1143
}
1126
1144
1127
1145
fn report_const_param_not_wf (
0 commit comments