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:
Manish Goregaokar 2021-10-05 12:52:44 -07:00 committed by GitHub
commit 0352a2820d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 113 additions and 54 deletions

View file

@ -236,16 +236,27 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
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 @@ 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
// `<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 @@ 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::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")?
}
})
}
}