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