Rollup merge of #89317 - JulianKnodt:precise_errors, r=BoxyUwU
Move generic error message to separate branches This decomposes an error message in generic constants into more specific branches, for better readability. r? ``@lcnr``
This commit is contained in:
commit
0352a2820d
7 changed files with 113 additions and 54 deletions
|
@ -236,16 +236,27 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
||||||
self.body.exprs[self.body_id].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
|
self.tcx
|
||||||
.sess
|
.sess
|
||||||
.struct_span_err(self.root_span(), "overly complex generic constant")
|
.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")
|
.help("consider moving this anonymous constant into a `const` function")
|
||||||
.emit();
|
.emit();
|
||||||
|
|
||||||
Err(ErrorReported)
|
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(
|
fn new(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
@ -337,8 +348,8 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
||||||
Ok(match &node.kind {
|
Ok(match &node.kind {
|
||||||
// I dont know if handling of these 3 is correct
|
// I dont know if handling of these 3 is correct
|
||||||
&ExprKind::Scope { value, .. } => self.recurse_build(value)?,
|
&ExprKind::Scope { value, .. } => self.recurse_build(value)?,
|
||||||
&ExprKind::PlaceTypeAscription { source, .. } |
|
&ExprKind::PlaceTypeAscription { source, .. }
|
||||||
&ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?,
|
| &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?,
|
||||||
|
|
||||||
// subtle: associated consts are literals this arm handles
|
// subtle: associated consts are literals this arm handles
|
||||||
// `<T as Trait>::ASSOC` as well as `12`
|
// `<T as Trait>::ASSOC` as well as `12`
|
||||||
|
@ -353,7 +364,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
let new_args = self.tcx.arena.alloc_slice(&new_args);
|
let new_args = self.tcx.arena.alloc_slice(&new_args);
|
||||||
self.nodes.push(Node::FunctionCall(fun, new_args))
|
self.nodes.push(Node::FunctionCall(fun, new_args))
|
||||||
},
|
}
|
||||||
&ExprKind::Binary { op, lhs, rhs } if Self::check_binop(op) => {
|
&ExprKind::Binary { op, lhs, rhs } if Self::check_binop(op) => {
|
||||||
let lhs = self.recurse_build(lhs)?;
|
let lhs = self.recurse_build(lhs)?;
|
||||||
let rhs = self.recurse_build(rhs)?;
|
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) => {
|
&ExprKind::Unary { op, arg } if Self::check_unop(op) => {
|
||||||
let arg = self.recurse_build(arg)?;
|
let arg = self.recurse_build(arg)?;
|
||||||
self.nodes.push(Node::UnaryOp(op, arg))
|
self.nodes.push(Node::UnaryOp(op, arg))
|
||||||
},
|
}
|
||||||
// This is necessary so that the following compiles:
|
// This is necessary so that the following compiles:
|
||||||
//
|
//
|
||||||
// ```
|
// ```
|
||||||
|
@ -370,60 +381,100 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
||||||
// bar::<{ N + 1 }>();
|
// 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
|
// `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a
|
||||||
// "coercion cast" i.e. using a coercion or is a no-op.
|
// "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)
|
// This is important so that `N as usize as usize` doesnt unify with `N as usize`. (untested)
|
||||||
&ExprKind::Use { source } => {
|
&ExprKind::Use { source } => {
|
||||||
let arg = self.recurse_build(source)?;
|
let arg = self.recurse_build(source)?;
|
||||||
self.nodes.push(Node::Cast(abstract_const::CastKind::Use, arg, node.ty))
|
self.nodes.push(Node::Cast(abstract_const::CastKind::Use, arg, node.ty))
|
||||||
},
|
}
|
||||||
&ExprKind::Cast { source } => {
|
&ExprKind::Cast { source } => {
|
||||||
let arg = self.recurse_build(source)?;
|
let arg = self.recurse_build(source)?;
|
||||||
self.nodes.push(Node::Cast(abstract_const::CastKind::As, arg, node.ty))
|
self.nodes.push(Node::Cast(abstract_const::CastKind::As, arg, node.ty))
|
||||||
},
|
}
|
||||||
|
|
||||||
// FIXME(generic_const_exprs): We may want to support these.
|
// FIXME(generic_const_exprs): We may want to support these.
|
||||||
ExprKind::AddressOf { .. }
|
ExprKind::AddressOf { .. }
|
||||||
| ExprKind::Borrow { .. }
|
| ExprKind::Borrow { .. }
|
||||||
| ExprKind::Deref { .. }
|
| ExprKind::Deref { .. } => self.maybe_supported_error(
|
||||||
| ExprKind::Repeat { .. }
|
node.span,
|
||||||
| ExprKind::Array { .. }
|
"dereferencing is not supported in generic constants",
|
||||||
| 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::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 { .. }
|
ExprKind::Unary { .. } => unreachable!(),
|
||||||
// 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 { .. }
|
|
||||||
// we handle valid unary/binary ops above
|
// we handle valid unary/binary ops above
|
||||||
| ExprKind::Unary { .. }
|
ExprKind::Binary { .. } =>
|
||||||
| ExprKind::Binary { .. }
|
self.error(node.span, "unsupported binary operation in generic constants")?,
|
||||||
| ExprKind::Break { .. }
|
ExprKind::LogicalOp { .. } =>
|
||||||
| ExprKind::Continue { .. }
|
self.error(node.span, "unsupported operation in generic constants, short-circuiting operations would imply control flow")?,
|
||||||
| ExprKind::If { .. }
|
ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
|
||||||
| ExprKind::Pointer { .. } // dont know if this is correct
|
self.error(node.span, "assignment is not supported in generic constants")?
|
||||||
| ExprKind::ThreadLocalRef(_)
|
}
|
||||||
| ExprKind::LlvmInlineAsm { .. }
|
ExprKind::Closure { .. } | ExprKind::Return { .. } => self.error(
|
||||||
| ExprKind::Return { .. }
|
node.span,
|
||||||
| ExprKind::Box { .. } // allocations not allowed in constants
|
"closures and function keywords are not supported in generic constants",
|
||||||
| ExprKind::AssignOp { .. }
|
)?,
|
||||||
| ExprKind::InlineAsm { .. }
|
// let expressions imply control flow
|
||||||
| ExprKind::Yield { .. } => self.error(Some(node.span), "unsupported operation in generic constant")?,
|
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
|
--> $DIR/array-size-in-generic-struct-param.rs:19:15
|
||||||
|
|
|
|
||||||
LL | arr: [u8; CFG.arr_size],
|
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
|
= 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
|
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)()] {}
|
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
|
= 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
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,19 @@ error: overly complex generic constant
|
||||||
--> $DIR/let-bindings.rs:6:68
|
--> $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 {
|
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
|
= help: consider moving this anonymous constant into a `const` function
|
||||||
|
= note: this operation may be supported in the future
|
||||||
|
|
||||||
error: overly complex generic constant
|
error: overly complex generic constant
|
||||||
--> $DIR/let-bindings.rs:6:35
|
--> $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 {
|
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
|
= 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
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -2,25 +2,28 @@ error: overly complex generic constant
|
||||||
--> $DIR/unused_expr.rs:4:34
|
--> $DIR/unused_expr.rs:4:34
|
||||||
|
|
|
|
||||||
LL | fn add<const N: usize>() -> [u8; { N + 1; 5 }] {
|
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
|
= help: consider moving this anonymous constant into a `const` function
|
||||||
|
= note: this operation may be supported in the future
|
||||||
|
|
||||||
error: overly complex generic constant
|
error: overly complex generic constant
|
||||||
--> $DIR/unused_expr.rs:9:34
|
--> $DIR/unused_expr.rs:9:34
|
||||||
|
|
|
|
||||||
LL | fn div<const N: usize>() -> [u8; { N / 1; 5 }] {
|
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
|
= help: consider moving this anonymous constant into a `const` function
|
||||||
|
= note: this operation may be supported in the future
|
||||||
|
|
||||||
error: overly complex generic constant
|
error: overly complex generic constant
|
||||||
--> $DIR/unused_expr.rs:16:38
|
--> $DIR/unused_expr.rs:16:38
|
||||||
|
|
|
|
||||||
LL | fn fn_call<const N: usize>() -> [u8; { foo(N); 5 }] {
|
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
|
= 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
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ error: overly complex generic constant
|
||||||
LL | inner: [(); { [|_: &T| {}; 0].len() }],
|
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
|
= help: consider moving this anonymous constant into a `const` function
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,10 @@ LL | | let x: Option<Box<Self>> = None;
|
||||||
LL | |
|
LL | |
|
||||||
LL | | 0
|
LL | | 0
|
||||||
LL | | }],
|
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
|
= 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
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue