@@ -1014,49 +1014,33 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
1014
1014
let mut prev_ty = self . resolve_vars_if_possible (
1015
1015
typeck. expr_ty_adjusted_opt ( expr) . unwrap_or ( Ty :: new_misc_error ( self . tcx ) ) ,
1016
1016
) ;
1017
- let mut annotate_expr = |span : Span , prev_ty : Ty < ' tcx > , self_ty : Ty < ' tcx > | -> bool {
1018
- // We always look at the `E` type, because that's the only one affected by `?`. If the
1019
- // incorrect `Result<T, E>` is because of the `T`, we'll get an E0308 on the whole
1020
- // expression, after the `?` has "unwrapped" the `T`.
1017
+
1018
+ // We always look at the `E` type, because that's the only one affected by `?`. If the
1019
+ // incorrect `Result<T, E>` is because of the `T`, we'll get an E0308 on the whole
1020
+ // expression, after the `?` has "unwrapped" the `T`.
1021
+ let get_e_type = |prev_ty : Ty < ' tcx > | -> Option < Ty < ' tcx > > {
1021
1022
let ty:: Adt ( def, args) = prev_ty. kind ( ) else {
1022
- return false ;
1023
+ return None ;
1023
1024
} ;
1024
1025
let Some ( arg) = args. get ( 1 ) else {
1025
- return false ;
1026
+ return None ;
1026
1027
} ;
1027
1028
if !self . tcx . is_diagnostic_item ( sym:: Result , def. did ( ) ) {
1028
- return false ;
1029
+ return None ;
1029
1030
}
1030
- let can = if self
1031
- . infcx
1032
- . type_implements_trait (
1033
- self . tcx . get_diagnostic_item ( sym:: From ) . unwrap ( ) ,
1034
- [ self_ty. into ( ) , * arg] ,
1035
- obligation. param_env ,
1036
- )
1037
- . must_apply_modulo_regions ( )
1038
- {
1039
- "can"
1040
- } else {
1041
- "can't"
1042
- } ;
1043
- err. span_label (
1044
- span,
1045
- format ! ( "this {can} be annotated with `?` because it has type `{prev_ty}`" ) ,
1046
- ) ;
1047
- true
1031
+ Some ( arg. as_type ( ) ?)
1048
1032
} ;
1049
1033
1034
+ let mut chain = vec ! [ ] ;
1035
+
1050
1036
// The following logic is simlar to `point_at_chain`, but that's focused on associated types
1051
1037
let mut expr = expr;
1052
1038
while let hir:: ExprKind :: MethodCall ( _path_segment, rcvr_expr, _args, span) = expr. kind {
1053
1039
// Point at every method call in the chain with the `Result` type.
1054
1040
// let foo = bar.iter().map(mapper)?;
1055
1041
// ------ -----------
1056
1042
expr = rcvr_expr;
1057
- if !annotate_expr ( span, prev_ty, self_ty) {
1058
- break ;
1059
- }
1043
+ chain. push ( ( span, prev_ty) ) ;
1060
1044
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 ) ) ,
@@ -1084,7 +1068,41 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
1084
1068
prev_ty = self . resolve_vars_if_possible (
1085
1069
typeck. expr_ty_adjusted_opt ( expr) . unwrap_or ( Ty :: new_misc_error ( self . tcx ) ) ,
1086
1070
) ;
1087
- annotate_expr ( expr. span , prev_ty, self_ty) ;
1071
+ chain. push ( ( expr. span , prev_ty) ) ;
1072
+
1073
+ let mut prev = None ;
1074
+ for ( span, err_ty) in chain. into_iter ( ) . rev ( ) {
1075
+ let err_ty = get_e_type ( err_ty) ;
1076
+ let err_ty = match ( err_ty, prev) {
1077
+ ( Some ( err_ty) , Some ( prev) ) if !self . can_eq ( obligation. param_env , err_ty, prev) => {
1078
+ err_ty
1079
+ }
1080
+ ( Some ( err_ty) , None ) => err_ty,
1081
+ _ => {
1082
+ prev = err_ty;
1083
+ continue ;
1084
+ }
1085
+ } ;
1086
+ if self
1087
+ . infcx
1088
+ . type_implements_trait (
1089
+ self . tcx . get_diagnostic_item ( sym:: From ) . unwrap ( ) ,
1090
+ [ self_ty, err_ty] ,
1091
+ obligation. param_env ,
1092
+ )
1093
+ . must_apply_modulo_regions ( )
1094
+ {
1095
+ err. span_label ( span, format ! ( "this has type `Result<_, {err_ty}>`" ) ) ;
1096
+ } else {
1097
+ err. span_label (
1098
+ span,
1099
+ format ! (
1100
+ "this can't be annotated with `?` because it has type `Result<_, {err_ty}>`" ,
1101
+ ) ,
1102
+ ) ;
1103
+ }
1104
+ prev = Some ( err_ty) ;
1105
+ }
1088
1106
}
1089
1107
1090
1108
fn report_const_param_not_wf (
0 commit comments