Move generic error message to separate branches

This decomposes an error message in generic constants into more specific branches, for better
readability.
This commit is contained in:
kadmin 2021-09-28 04:10:33 +00:00
parent 8a12be7412
commit 9cb30f465e
7 changed files with 113 additions and 54 deletions

View File

@ -236,16 +236,27 @@ fn root_span(&self) -> Span {
self.body.exprs[self.body_id].span
}
fn error(&mut self, span: Option<Span>, msg: &str) -> Result<!, ErrorReported> {
fn error(&mut self, span: Span, msg: &str) -> Result<!, ErrorReported> {
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<!, ErrorReported> {
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 @@ fn recurse_build(&mut self, node: thir::ExprId) -> Result<NodeId, ErrorReported>
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
// `<T as Trait>::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::<NodeId>::with_capacity(args.len());
@ -353,7 +364,7 @@ fn recurse_build(&mut self, node: thir::ExprId) -> Result<NodeId, ErrorReported>
}
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 @@ fn recurse_build(&mut self, node: thir::ExprId) -> Result<NodeId, ErrorReported>
&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 @@ fn recurse_build(&mut self, node: thir::ExprId) -> Result<NodeId, ErrorReported>
// 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::Match { .. }
// we dont permit let stmts so `VarRef` and `UpvarRef` cant happen
| ExprKind::VarRef { .. }
| ExprKind::UpvarRef { .. }
| ExprKind::Closure { .. }
| ExprKind::Let { .. } // let expressions imply control flow
| ExprKind::Loop { .. }
| ExprKind::Assign { .. }
| ExprKind::StaticRef { .. }
| ExprKind::LogicalOp { .. }
ExprKind::Unary { .. } => unreachable!(),
// 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::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")?
}
// we dont permit let stmts so `VarRef` and `UpvarRef` cant happen
ExprKind::VarRef { .. }
| ExprKind::UpvarRef { .. }
| ExprKind::StaticRef { .. }
| ExprKind::ThreadLocalRef(_) => {
self.error(node.span, "unsupported operation in generic constant")?
}
})
}
}

View File

@ -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

View File

@ -4,9 +4,10 @@ error: overly complex generic constant
LL | fn test<const N: usize>() -> [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

View File

@ -2,17 +2,19 @@ error: overly complex generic constant
--> $DIR/let-bindings.rs:6:68
|
LL | fn test<const N: usize>() -> [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<const N: usize>() -> [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

View File

@ -2,25 +2,28 @@ error: overly complex generic constant
--> $DIR/unused_expr.rs:4:34
|
LL | fn add<const N: usize>() -> [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<const N: usize>() -> [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<const N: usize>() -> [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

View File

@ -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

View File

@ -8,9 +8,10 @@ LL | | let x: Option<Box<Self>> = 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