Skip to content

Commit bb8be4f

Browse files
committed
implement precedence for anon const mismatch suggestions
1 parent bf67758 commit bb8be4f

File tree

3 files changed

+174
-27
lines changed

3 files changed

+174
-27
lines changed

compiler/rustc_infer/src/infer/error_reporting/mod.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -856,11 +856,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
856856
.regions()
857857
.map(|lifetime| {
858858
let s = lifetime.to_string();
859-
if s.is_empty() {
860-
"'_".to_string()
861-
} else {
862-
s
863-
}
859+
if s.is_empty() { "'_".to_string() } else { s }
864860
})
865861
.collect::<Vec<_>>()
866862
.join(", ");
@@ -1179,11 +1175,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
11791175

11801176
fn lifetime_display(lifetime: Region<'_>) -> String {
11811177
let s = lifetime.to_string();
1182-
if s.is_empty() {
1183-
"'_".to_string()
1184-
} else {
1185-
s
1186-
}
1178+
if s.is_empty() { "'_".to_string() } else { s }
11871179
}
11881180
// At one point we'd like to elide all lifetimes here, they are irrelevant for
11891181
// all diagnostics that use this output

compiler/rustc_middle/src/mir/mod.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2352,6 +2352,30 @@ impl BinOp {
23522352
Offset => None,
23532353
}
23542354
}
2355+
2356+
pub fn get_precedence(self) -> usize {
2357+
use self::BinOp::*;
2358+
2359+
match self {
2360+
Add => 7,
2361+
Sub => 7,
2362+
Mul => 8,
2363+
Div => 8,
2364+
Rem => 8,
2365+
BitXor => 2,
2366+
BitAnd => 3,
2367+
BitOr => 1,
2368+
Shl => 6,
2369+
Shr => 6,
2370+
Eq => 4,
2371+
Lt => 5,
2372+
Le => 5,
2373+
Ne => 4,
2374+
Ge => 5,
2375+
Gt => 5,
2376+
Offset => 0,
2377+
}
2378+
}
23552379
}
23562380

23572381
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]

compiler/rustc_trait_selection/src/traits/const_evaluatable.rs

Lines changed: 148 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
555686
pub(super) fn thir_abstract_const<'tcx>(
556687
tcx: TyCtxt<'tcx>,

0 commit comments

Comments
 (0)