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:
parent
8a12be7412
commit
9cb30f465e
@ -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")?
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user