From 9cb30f465ed07debfdb95bf2457423d1445e737d Mon Sep 17 00:00:00 2001 From: kadmin Date: Tue, 28 Sep 2021 04:10:33 +0000 Subject: [PATCH] Move generic error message to separate branches This decomposes an error message in generic constants into more specific branches, for better readability. --- .../src/traits/const_evaluatable.rs | 137 ++++++++++++------ ...y-size-in-generic-struct-param.full.stderr | 3 +- .../generic_const_exprs/closures.stderr | 3 +- .../generic_const_exprs/let-bindings.stderr | 6 +- .../generic_const_exprs/unused_expr.stderr | 9 +- .../issues/issue-67375.full.stderr | 2 +- .../issues/issue-67945-2.full.stderr | 3 +- 7 files changed, 111 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 24fa5007f1ecd..25ec9682d8407 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -236,16 +236,27 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { self.body.exprs[self.body_id].span } - fn error(&mut self, span: Option, msg: &str) -> Result { + fn error(&mut self, span: Span, msg: &str) -> Result { self.tcx .sess .struct_span_err(self.root_span(), "overly complex generic constant") - .span_label(span.unwrap_or(self.root_span()), msg) + .span_label(span, msg) .help("consider moving this anonymous constant into a `const` function") .emit(); Err(ErrorReported) } + fn maybe_supported_error(&mut self, span: Span, msg: &str) -> Result { + self.tcx + .sess + .struct_span_err(self.root_span(), "overly complex generic constant") + .span_label(span, msg) + .help("consider moving this anonymous constant into a `const` function") + .note("this operation may be supported in the future") + .emit(); + + Err(ErrorReported) + } fn new( tcx: TyCtxt<'tcx>, @@ -337,14 +348,14 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { Ok(match &node.kind { // I dont know if handling of these 3 is correct &ExprKind::Scope { value, .. } => self.recurse_build(value)?, - &ExprKind::PlaceTypeAscription { source, .. } | - &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?, + &ExprKind::PlaceTypeAscription { source, .. } + | &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?, // subtle: associated consts are literals this arm handles // `::ASSOC` as well as `12` &ExprKind::Literal { literal, .. } => self.nodes.push(Node::Leaf(literal)), - ExprKind::Call { fun, args, .. } => { + ExprKind::Call { fun, args, .. } => { let fun = self.recurse_build(*fun)?; let mut new_args = Vec::::with_capacity(args.len()); @@ -353,7 +364,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } let new_args = self.tcx.arena.alloc_slice(&new_args); self.nodes.push(Node::FunctionCall(fun, new_args)) - }, + } &ExprKind::Binary { op, lhs, rhs } if Self::check_binop(op) => { let lhs = self.recurse_build(lhs)?; let rhs = self.recurse_build(rhs)?; @@ -362,7 +373,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { &ExprKind::Unary { op, arg } if Self::check_unop(op) => { let arg = self.recurse_build(arg)?; self.nodes.push(Node::UnaryOp(op, arg)) - }, + } // This is necessary so that the following compiles: // // ``` @@ -370,60 +381,100 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { // bar::<{ N + 1 }>(); // } // ``` - ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. }} => self.recurse_build(*e)?, + ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. } } => { + self.recurse_build(*e)? + } // `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a // "coercion cast" i.e. using a coercion or is a no-op. // This is important so that `N as usize as usize` doesnt unify with `N as usize`. (untested) &ExprKind::Use { source } => { let arg = self.recurse_build(source)?; self.nodes.push(Node::Cast(abstract_const::CastKind::Use, arg, node.ty)) - }, + } &ExprKind::Cast { source } => { let arg = self.recurse_build(source)?; self.nodes.push(Node::Cast(abstract_const::CastKind::As, arg, node.ty)) - }, + } // FIXME(generic_const_exprs): We may want to support these. ExprKind::AddressOf { .. } | ExprKind::Borrow { .. } - | ExprKind::Deref { .. } - | ExprKind::Repeat { .. } - | ExprKind::Array { .. } - | ExprKind::Block { .. } - | ExprKind::NeverToAny { .. } - | ExprKind::Tuple { .. } - | ExprKind::Index { .. } - | ExprKind::Field { .. } - | ExprKind::ConstBlock { .. } - | ExprKind::Adt(_) => self.error( - Some(node.span), - "unsupported operation in generic constant, this may be supported in the future", + | ExprKind::Deref { .. } => self.maybe_supported_error( + node.span, + "dereferencing is not supported in generic constants", + )?, + ExprKind::Repeat { .. } | ExprKind::Array { .. } => self.maybe_supported_error( + node.span, + "array construction is not supported in generic constants", + )?, + ExprKind::Block { .. } => self.maybe_supported_error( + node.span, + "blocks are not supported in generic constant", + )?, + ExprKind::NeverToAny { .. } => self.maybe_supported_error( + node.span, + "converting nevers to any is not supported in generic constant", + )?, + ExprKind::Tuple { .. } => self.maybe_supported_error( + node.span, + "tuple construction is not supported in generic constants", + )?, + ExprKind::Index { .. } => self.maybe_supported_error( + node.span, + "indexing is not supported in generic constant", + )?, + ExprKind::Field { .. } => self.maybe_supported_error( + node.span, + "field access is not supported in generic constant", + )?, + ExprKind::ConstBlock { .. } => self.maybe_supported_error( + node.span, + "const blocks are not supported in generic constant", + )?, + ExprKind::Adt(_) => self.maybe_supported_error( + node.span, + "struct/enum construction is not supported in generic constants", + )?, + // dont know if this is correct + ExprKind::Pointer { .. } => + self.error(node.span, "pointer casts are not allowed in generic constants")?, + ExprKind::Yield { .. } => + self.error(node.span, "generator control flow is not allowed in generic constants")?, + ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::Loop { .. } => self + .error( + node.span, + "loops and loop control flow are not supported in generic constants", )?, + ExprKind::Box { .. } => + self.error(node.span, "allocations are not allowed in generic constants")?, + + ExprKind::Unary { .. } => unreachable!(), + // we handle valid unary/binary ops above + ExprKind::Binary { .. } => + self.error(node.span, "unsupported binary operation in generic constants")?, + ExprKind::LogicalOp { .. } => + self.error(node.span, "unsupported operation in generic constants, short-circuiting operations would imply control flow")?, + ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { + self.error(node.span, "assignment is not supported in generic constants")? + } + ExprKind::Closure { .. } | ExprKind::Return { .. } => self.error( + node.span, + "closures and function keywords are not supported in generic constants", + )?, + // let expressions imply control flow + ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } => + self.error(node.span, "control flow is not supported in generic constants")?, + ExprKind::LlvmInlineAsm { .. } | ExprKind::InlineAsm { .. } => { + self.error(node.span, "assembly is not supported in generic constants")? + } - ExprKind::Match { .. } // we dont permit let stmts so `VarRef` and `UpvarRef` cant happen - | ExprKind::VarRef { .. } + ExprKind::VarRef { .. } | ExprKind::UpvarRef { .. } - | ExprKind::Closure { .. } - | ExprKind::Let { .. } // let expressions imply control flow - | ExprKind::Loop { .. } - | ExprKind::Assign { .. } | ExprKind::StaticRef { .. } - | ExprKind::LogicalOp { .. } - // we handle valid unary/binary ops above - | ExprKind::Unary { .. } - | ExprKind::Binary { .. } - | ExprKind::Break { .. } - | ExprKind::Continue { .. } - | ExprKind::If { .. } - | ExprKind::Pointer { .. } // dont know if this is correct - | ExprKind::ThreadLocalRef(_) - | ExprKind::LlvmInlineAsm { .. } - | ExprKind::Return { .. } - | ExprKind::Box { .. } // allocations not allowed in constants - | ExprKind::AssignOp { .. } - | ExprKind::InlineAsm { .. } - | ExprKind::Yield { .. } => self.error(Some(node.span), "unsupported operation in generic constant")?, + | ExprKind::ThreadLocalRef(_) => { + self.error(node.span, "unsupported operation in generic constant")? + } }) } } diff --git a/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr b/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr index 9b3c32a939779..041232e869079 100644 --- a/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr @@ -10,9 +10,10 @@ error: overly complex generic constant --> $DIR/array-size-in-generic-struct-param.rs:19:15 | LL | arr: [u8; CFG.arr_size], - | ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future + | ^^^^^^^^^^^^ field access is not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/generic_const_exprs/closures.stderr b/src/test/ui/const-generics/generic_const_exprs/closures.stderr index 95dae4ecc0431..0dfd804be41b4 100644 --- a/src/test/ui/const-generics/generic_const_exprs/closures.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/closures.stderr @@ -4,9 +4,10 @@ error: overly complex generic constant LL | fn test() -> [u8; N + (|| 42)()] {} | ^^^^-------^^ | | - | unsupported operation in generic constant, this may be supported in the future + | dereferencing is not supported in generic constants | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: aborting due to previous error diff --git a/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr b/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr index c9f847995223a..5ebb4c3999c36 100644 --- a/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr @@ -2,17 +2,19 @@ error: overly complex generic constant --> $DIR/let-bindings.rs:6:68 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^^^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future + | ^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: overly complex generic constant --> $DIR/let-bindings.rs:6:35 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^^^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future + | ^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr b/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr index 3da91b19a5ed9..df73acf53de65 100644 --- a/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr @@ -2,25 +2,28 @@ error: overly complex generic constant --> $DIR/unused_expr.rs:4:34 | LL | fn add() -> [u8; { N + 1; 5 }] { - | ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future + | ^^^^^^^^^^^^ blocks are not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: overly complex generic constant --> $DIR/unused_expr.rs:9:34 | LL | fn div() -> [u8; { N / 1; 5 }] { - | ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future + | ^^^^^^^^^^^^ blocks are not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: overly complex generic constant --> $DIR/unused_expr.rs:16:38 | LL | fn fn_call() -> [u8; { foo(N); 5 }] { - | ^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future + | ^^^^^^^^^^^^^ blocks are not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: aborting due to 3 previous errors diff --git a/src/test/ui/const-generics/issues/issue-67375.full.stderr b/src/test/ui/const-generics/issues/issue-67375.full.stderr index d7b52063dc4db..2ee5b6a587040 100644 --- a/src/test/ui/const-generics/issues/issue-67375.full.stderr +++ b/src/test/ui/const-generics/issues/issue-67375.full.stderr @@ -4,7 +4,7 @@ error: overly complex generic constant LL | inner: [(); { [|_: &T| {}; 0].len() }], | ^^---------------^^^^^^^^ | | - | unsupported operation in generic constant + | pointer casts are not allowed in generic constants | = help: consider moving this anonymous constant into a `const` function diff --git a/src/test/ui/const-generics/issues/issue-67945-2.full.stderr b/src/test/ui/const-generics/issues/issue-67945-2.full.stderr index fe0351a829220..cce85772aa4da 100644 --- a/src/test/ui/const-generics/issues/issue-67945-2.full.stderr +++ b/src/test/ui/const-generics/issues/issue-67945-2.full.stderr @@ -8,9 +8,10 @@ LL | | let x: Option> = None; LL | | LL | | 0 LL | | }], - | |_____^ unsupported operation in generic constant, this may be supported in the future + | |_____^ blocks are not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: aborting due to previous error