@@ -231,54 +231,164 @@ impl<'tcx> AbstractConst<'tcx> {
231
231
/// Tries to create a String of an `AbstractConst` while recursively applying substs. This
232
232
/// will fail for `AbstractConst`s that contain `Leaf`s including inference variables or errors,
233
233
/// and any non-Leaf `Node`s other than `BinOp` and `UnOp`.
234
- pub ( crate ) fn try_print_with_replacing_substs ( mut self , tcx : TyCtxt < ' tcx > ) -> Option < String > {
234
+ pub ( crate ) fn try_print_with_replacing_substs ( self , tcx : TyCtxt < ' tcx > ) -> Option < String > {
235
+ self . recursive_try_print_with_replacing_substs ( tcx) . map ( |s| s. to_string ( ) )
236
+ }
237
+
238
+ // Recursively applies substs to leaves. Also ensures that the strings corresponding
239
+ // to nodes in the `AbstractConst` tree are wrapped in curly braces after a substitution
240
+ // was applied. E.g in `{ 3 * M}` where we have substs `{ N + 2 }` for M, we want to
241
+ // make sure that the node corresponding to `M` is wrapped in curly braces: `{ 3 * { N +2 }}`
242
+ #[ instrument( skip( tcx) , level = "debug" ) ]
243
+ fn recursive_try_print_with_replacing_substs (
244
+ mut self ,
245
+ tcx : TyCtxt < ' tcx > ,
246
+ ) -> Option < PrintStyle > {
247
+ let mut applied_subst = false ;
248
+
235
249
// try to replace substs
236
250
while let abstract_const:: Node :: Leaf ( ct) = self . root ( tcx) {
237
251
match AbstractConst :: from_const ( tcx, ct) {
238
- Ok ( Some ( act) ) => self = act,
252
+ Ok ( Some ( act) ) => {
253
+ applied_subst = true ;
254
+ self = act;
255
+ }
239
256
Ok ( None ) => break ,
240
257
Err ( _) => bug ! ( "should be able to create AbstractConst here" ) ,
241
258
}
242
259
}
243
260
261
+ debug ! ( "after applying substs: {:#?}" , self ) ;
262
+ debug ! ( "root: {:?}" , self . root( tcx) ) ;
263
+ debug ! ( ?applied_subst) ;
264
+
265
+ // How we infer precedence of operations:
266
+ // We use `PrintStyle::Braces(op_precedence, str)` to indicate that resulting
267
+ // string of recursive call may need to be wrapped in curly braces. If the
268
+ // precedence of the op of a node is larger than `op_precedence` of the returned
269
+ // subnode we need to use curly braces.
270
+ // If the precedence isn't larger we still send `PrintStyle::Braces` upwards
271
+ // since the string that includes the node which requires precedence might
272
+ // still require a higher-level node string to be wrapped in curly braces, e.g
273
+ // in `{ 3 + {M + K}}` where `M` is substituted by `N + 2` we want the result string
274
+ // to be `{ M + { N + 2 + K}}`.
244
275
match self . root ( tcx) {
245
276
abstract_const:: Node :: Leaf ( ct) => match ct. val {
246
277
ty:: ConstKind :: Error ( _) | ty:: ConstKind :: Infer ( _) => return None ,
247
- ty:: ConstKind :: Param ( c) => return Some ( format ! ( "{}" , c) ) ,
278
+ ty:: ConstKind :: Param ( c) => {
279
+ let s = format ! ( "{}" , c) ;
280
+
281
+ if applied_subst {
282
+ return Some ( PrintStyle :: Braces ( None , s) ) ;
283
+ } else {
284
+ return Some ( PrintStyle :: NoBraces ( s) ) ;
285
+ }
286
+ }
248
287
ty:: ConstKind :: Value ( ConstValue :: Scalar ( scalar) ) => match scalar. to_i64 ( ) {
249
- Ok ( s) => return Some ( format ! ( "{}" , s) ) ,
288
+ Ok ( s) => {
289
+ let s = format ! ( "{}" , s) ;
290
+
291
+ if applied_subst {
292
+ return Some ( PrintStyle :: Braces ( None , s) ) ;
293
+ } else {
294
+ return Some ( PrintStyle :: NoBraces ( s) ) ;
295
+ }
296
+ }
250
297
Err ( _) => return None ,
251
298
} ,
252
299
_ => return None ,
253
300
} ,
254
301
abstract_const:: Node :: Binop ( op, l, r) => {
255
- let op = match op. try_as_string ( ) {
302
+ let op_str = match op. try_as_string ( ) {
256
303
Some ( o) => o,
257
304
None => return None ,
258
305
} ;
259
306
260
- let left = self . subtree ( l) . try_print_with_replacing_substs ( tcx) ;
307
+ // To decide whether we need to propagate PrintStyle::CurlyBraces upwards
308
+ // due to substitutions in subnodes of Binop
309
+ let mut use_curly_braces_due_to_subnodes = false ;
310
+
311
+ let left = self . subtree ( l) . recursive_try_print_with_replacing_substs ( tcx) ;
261
312
debug ! ( ?left) ;
262
313
263
- let right = self . subtree ( r) . try_print_with_replacing_substs ( tcx) ;
314
+ let right = self . subtree ( r) . recursive_try_print_with_replacing_substs ( tcx) ;
264
315
debug ! ( ?right) ;
265
316
266
- match ( left, right) {
267
- ( Some ( l) , Some ( r) ) => {
268
- return Some ( format ! ( "{} {} {}" , l, op, r) ) ;
317
+ let left_str = match left {
318
+ Some ( PrintStyle :: Braces ( opt_l_prec, l_str) ) => {
319
+ use_curly_braces_due_to_subnodes = true ;
320
+
321
+ if let Some ( l_prec) = opt_l_prec {
322
+ if op. get_precedence ( ) > l_prec {
323
+ // Already applied curly braces for subnode, no need to
324
+ // propagate PrintStyle::CurlyBraces upwards anymore
325
+ // for this node
326
+ use_curly_braces_due_to_subnodes = false ;
327
+
328
+ // Include curly braces for l_str
329
+ format ! ( "{{ {} }}" , l_str)
330
+ } else {
331
+ l_str
332
+ }
333
+ } else {
334
+ l_str
335
+ }
336
+ }
337
+ Some ( PrintStyle :: NoBraces ( l_str) ) => l_str,
338
+ None => return None ,
339
+ } ;
340
+
341
+ let right_str = match right {
342
+ Some ( PrintStyle :: Braces ( opt_r_prec, r_str) ) => {
343
+ use_curly_braces_due_to_subnodes = true ;
344
+
345
+ if let Some ( r_prec) = opt_r_prec {
346
+ if op. get_precedence ( ) > r_prec {
347
+ // Already applied curly braces for subnode, no need to
348
+ // propagate PrintStyle::CurlyBraces upwards anymore
349
+ // for this node
350
+ use_curly_braces_due_to_subnodes = false ;
351
+
352
+ // Include curly braces for l_str
353
+ format ! ( "{{ {} }}" , r_str)
354
+ } else {
355
+ r_str
356
+ }
357
+ } else {
358
+ r_str
359
+ }
269
360
}
270
- _ => return None ,
361
+ Some ( PrintStyle :: NoBraces ( r_str) ) => r_str,
362
+ None => return None ,
363
+ } ;
364
+
365
+ let binop_str = format ! ( "{} {} {}" , left_str, op_str, right_str) ;
366
+
367
+ // We propagate the need for curly braces upwards in the following cases:
368
+ // 1. We applied a substitution for current root
369
+ // 2. We applied a substitution in a subnode and did not apply curly braces
370
+ // to that subnode string
371
+ let current_op_prec = op. get_precedence ( ) ;
372
+ debug ! ( ?current_op_prec) ;
373
+ debug ! ( ?applied_subst) ;
374
+ debug ! ( ?use_curly_braces_due_to_subnodes) ;
375
+
376
+ if applied_subst || use_curly_braces_due_to_subnodes {
377
+ Some ( PrintStyle :: Braces ( Some ( current_op_prec) , binop_str) )
378
+ } else {
379
+ Some ( PrintStyle :: NoBraces ( binop_str) )
271
380
}
272
381
}
273
- abstract_const:: Node :: UnaryOp ( op , v) => {
274
- match self . subtree ( v) . try_print_with_replacing_substs ( tcx) {
275
- Some ( operand ) => {
276
- return Some ( format ! ( "{}{}" , op , operand ) ) ;
382
+ abstract_const:: Node :: UnaryOp ( _ , v) => {
383
+ match self . subtree ( v) . recursive_try_print_with_replacing_substs ( tcx) {
384
+ Some ( PrintStyle :: Braces ( opt_prec , operand_str ) ) => {
385
+ Some ( PrintStyle :: Braces ( opt_prec , operand_str ) )
277
386
}
278
- None => return None ,
387
+ s @ Some ( PrintStyle :: NoBraces ( _) ) => s,
388
+ None => None ,
279
389
}
280
390
}
281
- _ => return None ,
391
+ _ => None ,
282
392
}
283
393
}
284
394
}
@@ -551,6 +661,27 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
551
661
}
552
662
}
553
663
664
+ /// Used in diagnostics for creating const mismatch suggestions. Indicates precedence
665
+ /// that needs to be applied to nodes
666
+ #[ derive( Debug ) ]
667
+ enum PrintStyle {
668
+ /// String needs to possibly be wrapped in curly braces if precedence of operation
669
+ /// requires it
670
+ Braces ( Option < usize > , String ) ,
671
+
672
+ /// String does not need to be wrapped in curly braces
673
+ NoBraces ( String ) ,
674
+ }
675
+
676
+ impl PrintStyle {
677
+ pub ( crate ) fn to_string ( self ) -> String {
678
+ match self {
679
+ Self :: Braces ( _, s) => s,
680
+ Self :: NoBraces ( s) => s,
681
+ }
682
+ }
683
+ }
684
+
554
685
/// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead.
555
686
pub ( super ) fn thir_abstract_const < ' tcx > (
556
687
tcx : TyCtxt < ' tcx > ,
0 commit comments