@@ -231,54 +231,164 @@ impl<'tcx> AbstractConst<'tcx> {
231231 /// Tries to create a String of an `AbstractConst` while recursively applying substs. This
232232 /// will fail for `AbstractConst`s that contain `Leaf`s including inference variables or errors,
233233 /// 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+
235249 // try to replace substs
236250 while let abstract_const:: Node :: Leaf ( ct) = self . root ( tcx) {
237251 match AbstractConst :: from_const ( tcx, ct) {
238- Ok ( Some ( act) ) => self = act,
252+ Ok ( Some ( act) ) => {
253+ applied_subst = true ;
254+ self = act;
255+ }
239256 Ok ( None ) => break ,
240257 Err ( _) => bug ! ( "should be able to create AbstractConst here" ) ,
241258 }
242259 }
243260
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}}`.
244275 match self . root ( tcx) {
245276 abstract_const:: Node :: Leaf ( ct) => match ct. val {
246277 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+ }
248287 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+ }
250297 Err ( _) => return None ,
251298 } ,
252299 _ => return None ,
253300 } ,
254301 abstract_const:: Node :: Binop ( op, l, r) => {
255- let op = match op. try_as_string ( ) {
302+ let op_str = match op. try_as_string ( ) {
256303 Some ( o) => o,
257304 None => return None ,
258305 } ;
259306
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) ;
261312 debug ! ( ?left) ;
262313
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) ;
264315 debug ! ( ?right) ;
265316
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+ }
269360 }
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) )
271380 }
272381 }
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 ) )
277386 }
278- None => return None ,
387+ s @ Some ( PrintStyle :: NoBraces ( _) ) => s,
388+ None => None ,
279389 }
280390 }
281- _ => return None ,
391+ _ => None ,
282392 }
283393 }
284394}
@@ -551,6 +661,27 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
551661 }
552662}
553663
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+
554685/// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead.
555686pub ( super ) fn thir_abstract_const < ' tcx > (
556687 tcx : TyCtxt < ' tcx > ,
0 commit comments