@@ -11,26 +11,56 @@ use rustc_trait_selection::traits;
11
11
12
12
use crate :: FnCtxt ;
13
13
14
+ enum ClauseFlavor {
15
+ /// Predicate comes from `predicates_of`.
16
+ Where ,
17
+ /// Predicate comes from `const_conditions`.
18
+ Const ,
19
+ }
20
+
14
21
impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
15
22
pub ( crate ) fn adjust_fulfillment_error_for_expr_obligation (
16
23
& self ,
17
24
error : & mut traits:: FulfillmentError < ' tcx > ,
18
25
) -> bool {
19
- let ObligationCauseCode :: WhereClauseInExpr ( def_id, _, hir_id, idx) =
20
- * error. obligation . cause . code ( ) . peel_derives ( )
21
- else {
22
- return false ;
26
+ let ( def_id, hir_id, idx, flavor) = match * error. obligation . cause . code ( ) . peel_derives ( ) {
27
+ ObligationCauseCode :: WhereClauseInExpr ( def_id, _, hir_id, idx) => {
28
+ ( def_id, hir_id, idx, ClauseFlavor :: Where )
29
+ }
30
+ ObligationCauseCode :: HostEffectInExpr ( def_id, _, hir_id, idx) => {
31
+ ( def_id, hir_id, idx, ClauseFlavor :: Const )
32
+ }
33
+ _ => return false ,
23
34
} ;
24
35
25
- let Some ( uninstantiated_pred) = self
26
- . tcx
27
- . predicates_of ( def_id)
28
- . instantiate_identity ( self . tcx )
29
- . predicates
30
- . into_iter ( )
31
- . nth ( idx)
32
- else {
33
- return false ;
36
+ let uninstantiated_pred = match flavor {
37
+ ClauseFlavor :: Where => {
38
+ if let Some ( pred) = self
39
+ . tcx
40
+ . predicates_of ( def_id)
41
+ . instantiate_identity ( self . tcx )
42
+ . predicates
43
+ . into_iter ( )
44
+ . nth ( idx)
45
+ {
46
+ pred
47
+ } else {
48
+ return false ;
49
+ }
50
+ }
51
+ ClauseFlavor :: Const => {
52
+ if let Some ( ( pred, _) ) = self
53
+ . tcx
54
+ . const_conditions ( def_id)
55
+ . instantiate_identity ( self . tcx )
56
+ . into_iter ( )
57
+ . nth ( idx)
58
+ {
59
+ pred. to_host_effect_clause ( self . tcx , ty:: BoundConstness :: Maybe )
60
+ } else {
61
+ return false ;
62
+ }
63
+ }
34
64
} ;
35
65
36
66
let generics = self . tcx . generics_of ( def_id) ;
@@ -39,6 +69,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
39
69
ty:: ClauseKind :: Trait ( pred) => {
40
70
( pred. trait_ref . args . to_vec ( ) , Some ( pred. self_ty ( ) . into ( ) ) )
41
71
}
72
+ ty:: ClauseKind :: HostEffect ( pred) => {
73
+ ( pred. trait_ref . args . to_vec ( ) , Some ( pred. self_ty ( ) . into ( ) ) )
74
+ }
42
75
ty:: ClauseKind :: Projection ( pred) => ( pred. projection_term . args . to_vec ( ) , None ) ,
43
76
ty:: ClauseKind :: ConstArgHasType ( arg, ty) => ( vec ! [ ty. into( ) , arg. into( ) ] , None ) ,
44
77
ty:: ClauseKind :: ConstEvaluatable ( e) => ( vec ! [ e. into( ) ] , None ) ,
@@ -94,39 +127,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
94
127
self . find_ambiguous_parameter_in ( def_id, error. root_obligation . predicate ) ;
95
128
}
96
129
97
- let ( expr, qpath) = match self . tcx . hir_node ( hir_id) {
98
- hir:: Node :: Expr ( expr) => {
99
- if self . closure_span_overlaps_error ( error, expr. span ) {
100
- return false ;
130
+ match self . tcx . hir_node ( hir_id) {
131
+ hir:: Node :: Expr ( expr) => self . point_at_expr_if_possible (
132
+ error,
133
+ def_id,
134
+ expr,
135
+ predicate_self_type_to_point_at,
136
+ param_to_point_at,
137
+ fallback_param_to_point_at,
138
+ self_param_to_point_at,
139
+ ) ,
140
+
141
+ hir:: Node :: Ty ( hir:: Ty { kind : hir:: TyKind :: Path ( qpath) , .. } ) => {
142
+ for param in [
143
+ predicate_self_type_to_point_at,
144
+ param_to_point_at,
145
+ fallback_param_to_point_at,
146
+ self_param_to_point_at,
147
+ ]
148
+ . into_iter ( )
149
+ . flatten ( )
150
+ {
151
+ if self . point_at_path_if_possible ( error, def_id, param, & qpath) {
152
+ return true ;
153
+ }
101
154
}
102
- let qpath =
103
- if let hir:: ExprKind :: Path ( qpath) = expr. kind { Some ( qpath) } else { None } ;
104
155
105
- ( Some ( & expr . kind ) , qpath )
156
+ false
106
157
}
107
- hir:: Node :: Ty ( hir:: Ty { kind : hir:: TyKind :: Path ( qpath) , .. } ) => ( None , Some ( * qpath) ) ,
108
- _ => return false ,
109
- } ;
110
158
111
- if let Some ( qpath) = qpath {
112
- // Prefer pointing at the turbofished arg that corresponds to the
113
- // self type of the failing predicate over anything else.
114
- if let Some ( param) = predicate_self_type_to_point_at
115
- && self . point_at_path_if_possible ( error, def_id, param, & qpath)
116
- {
117
- return true ;
118
- }
159
+ _ => false ,
160
+ }
161
+ }
119
162
120
- if let hir:: Node :: Expr ( hir:: Expr {
121
- kind : hir:: ExprKind :: Call ( callee, args) ,
122
- hir_id : call_hir_id,
123
- span : call_span,
124
- ..
125
- } ) = self . tcx . parent_hir_node ( hir_id)
126
- && callee. hir_id == hir_id
127
- {
128
- if self . closure_span_overlaps_error ( error, * call_span) {
129
- return false ;
163
+ fn point_at_expr_if_possible (
164
+ & self ,
165
+ error : & mut traits:: FulfillmentError < ' tcx > ,
166
+ callee_def_id : DefId ,
167
+ expr : & ' tcx hir:: Expr < ' tcx > ,
168
+ predicate_self_type_to_point_at : Option < ty:: GenericArg < ' tcx > > ,
169
+ param_to_point_at : Option < ty:: GenericArg < ' tcx > > ,
170
+ fallback_param_to_point_at : Option < ty:: GenericArg < ' tcx > > ,
171
+ self_param_to_point_at : Option < ty:: GenericArg < ' tcx > > ,
172
+ ) -> bool {
173
+ if self . closure_span_overlaps_error ( error, expr. span ) {
174
+ return false ;
175
+ }
176
+
177
+ match expr. kind {
178
+ hir:: ExprKind :: Call (
179
+ hir:: Expr { kind : hir:: ExprKind :: Path ( qpath) , span : callee_span, .. } ,
180
+ args,
181
+ ) => {
182
+ if let Some ( param) = predicate_self_type_to_point_at
183
+ && self . point_at_path_if_possible ( error, callee_def_id, param, & qpath)
184
+ {
185
+ return true ;
130
186
}
131
187
132
188
for param in [ param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
@@ -135,32 +191,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
135
191
{
136
192
if self . blame_specific_arg_if_possible (
137
193
error,
138
- def_id ,
194
+ callee_def_id ,
139
195
param,
140
- * call_hir_id ,
141
- callee . span ,
196
+ expr . hir_id ,
197
+ * callee_span ,
142
198
None ,
143
199
args,
144
200
) {
145
201
return true ;
146
202
}
147
203
}
204
+
205
+ for param in [ param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
206
+ . into_iter ( )
207
+ . flatten ( )
208
+ {
209
+ if self . point_at_path_if_possible ( error, callee_def_id, param, & qpath) {
210
+ return true ;
211
+ }
212
+ }
148
213
}
214
+ hir:: ExprKind :: Path ( qpath) => {
215
+ // If the parent is an call, then process this as a call.
216
+ //
217
+ // This is because the `WhereClauseInExpr` obligations come from
218
+ // the well-formedness of the *path* expression, but we care to
219
+ // point at the call expression (namely, its args).
220
+ if let hir:: Node :: Expr (
221
+ call_expr @ hir:: Expr { kind : hir:: ExprKind :: Call ( callee, ..) , .. } ,
222
+ ) = self . tcx . parent_hir_node ( expr. hir_id )
223
+ && callee. hir_id == expr. hir_id
224
+ {
225
+ return self . point_at_expr_if_possible (
226
+ error,
227
+ callee_def_id,
228
+ call_expr,
229
+ predicate_self_type_to_point_at,
230
+ param_to_point_at,
231
+ fallback_param_to_point_at,
232
+ self_param_to_point_at,
233
+ ) ;
234
+ }
149
235
150
- for param in [ param_to_point_at , fallback_param_to_point_at , self_param_to_point_at ]
151
- . into_iter ( )
152
- . flatten ( )
153
- {
154
- if self . point_at_path_if_possible ( error , def_id , param , & qpath ) {
236
+ // Otherwise, just try to point at path components.
237
+
238
+ if let Some ( param ) = predicate_self_type_to_point_at
239
+ && self . point_at_path_if_possible ( error , callee_def_id , param , & qpath )
240
+ {
155
241
return true ;
156
242
}
157
- }
158
- }
159
243
160
- match expr {
161
- Some ( hir:: ExprKind :: MethodCall ( segment, receiver, args, ..) ) => {
244
+ for param in [ param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
245
+ . into_iter ( )
246
+ . flatten ( )
247
+ {
248
+ if self . point_at_path_if_possible ( error, callee_def_id, param, & qpath) {
249
+ return true ;
250
+ }
251
+ }
252
+ }
253
+ hir:: ExprKind :: MethodCall ( segment, receiver, args, ..) => {
162
254
if let Some ( param) = predicate_self_type_to_point_at
163
- && self . point_at_generic_if_possible ( error, def_id , param, segment)
255
+ && self . point_at_generic_if_possible ( error, callee_def_id , param, segment)
164
256
{
165
257
// HACK: This is not correct, since `predicate_self_type_to_point_at` might
166
258
// not actually correspond to the receiver of the method call. But we
@@ -170,7 +262,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
170
262
error. obligation . cause . map_code ( |parent_code| {
171
263
ObligationCauseCode :: FunctionArg {
172
264
arg_hir_id : receiver. hir_id ,
173
- call_hir_id : hir_id,
265
+ call_hir_id : expr . hir_id ,
174
266
parent_code,
175
267
}
176
268
} ) ;
@@ -183,9 +275,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
183
275
{
184
276
if self . blame_specific_arg_if_possible (
185
277
error,
186
- def_id ,
278
+ callee_def_id ,
187
279
param,
188
- hir_id,
280
+ expr . hir_id ,
189
281
segment. ident . span ,
190
282
Some ( receiver) ,
191
283
args,
@@ -194,7 +286,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
194
286
}
195
287
}
196
288
if let Some ( param_to_point_at) = param_to_point_at
197
- && self . point_at_generic_if_possible ( error, def_id, param_to_point_at, segment)
289
+ && self . point_at_generic_if_possible (
290
+ error,
291
+ callee_def_id,
292
+ param_to_point_at,
293
+ segment,
294
+ )
198
295
{
199
296
return true ;
200
297
}
@@ -208,17 +305,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
208
305
return true ;
209
306
}
210
307
}
211
- Some ( hir:: ExprKind :: Struct ( qpath, fields, ..) ) => {
308
+ hir:: ExprKind :: Struct ( qpath, fields, ..) => {
212
309
if let Res :: Def ( DefKind :: Struct | DefKind :: Variant , variant_def_id) =
213
- self . typeck_results . borrow ( ) . qpath_res ( qpath, hir_id)
310
+ self . typeck_results . borrow ( ) . qpath_res ( qpath, expr . hir_id )
214
311
{
215
312
for param in
216
313
[ param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
217
314
. into_iter ( )
218
315
. flatten ( )
219
316
{
220
- let refined_expr =
221
- self . point_at_field_if_possible ( def_id, param, variant_def_id, fields) ;
317
+ let refined_expr = self . point_at_field_if_possible (
318
+ callee_def_id,
319
+ param,
320
+ variant_def_id,
321
+ fields,
322
+ ) ;
222
323
223
324
match refined_expr {
224
325
None => { }
@@ -242,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
242
343
. into_iter ( )
243
344
. flatten ( )
244
345
{
245
- if self . point_at_path_if_possible ( error, def_id , param, qpath) {
346
+ if self . point_at_path_if_possible ( error, callee_def_id , param, qpath) {
246
347
return true ;
247
348
}
248
349
}
@@ -525,7 +626,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
525
626
expr : & ' tcx hir:: Expr < ' tcx > ,
526
627
) -> Result < & ' tcx hir:: Expr < ' tcx > , & ' tcx hir:: Expr < ' tcx > > {
527
628
match obligation_cause_code {
528
- traits:: ObligationCauseCode :: WhereClauseInExpr ( _, _, _, _) => {
629
+ traits:: ObligationCauseCode :: WhereClauseInExpr ( _, _, _, _)
630
+ | ObligationCauseCode :: HostEffectInExpr ( ..) => {
529
631
// This is the "root"; we assume that the `expr` is already pointing here.
530
632
// Therefore, we return `Ok` so that this `expr` can be refined further.
531
633
Ok ( expr)
0 commit comments