Skip to content

Commit 9cb30f4

Browse files
committed
Move generic error message to separate branches
This decomposes an error message in generic constants into more specific branches, for better readability.
1 parent 8a12be7 commit 9cb30f4

File tree

7 files changed

+111
-52
lines changed

7 files changed

+111
-52
lines changed

compiler/rustc_trait_selection/src/traits/const_evaluatable.rs

Lines changed: 94 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -236,16 +236,27 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
236236
self.body.exprs[self.body_id].span
237237
}
238238

239-
fn error(&mut self, span: Option<Span>, msg: &str) -> Result<!, ErrorReported> {
239+
fn error(&mut self, span: Span, msg: &str) -> Result<!, ErrorReported> {
240240
self.tcx
241241
.sess
242242
.struct_span_err(self.root_span(), "overly complex generic constant")
243-
.span_label(span.unwrap_or(self.root_span()), msg)
243+
.span_label(span, msg)
244244
.help("consider moving this anonymous constant into a `const` function")
245245
.emit();
246246

247247
Err(ErrorReported)
248248
}
249+
fn maybe_supported_error(&mut self, span: Span, msg: &str) -> Result<!, ErrorReported> {
250+
self.tcx
251+
.sess
252+
.struct_span_err(self.root_span(), "overly complex generic constant")
253+
.span_label(span, msg)
254+
.help("consider moving this anonymous constant into a `const` function")
255+
.note("this operation may be supported in the future")
256+
.emit();
257+
258+
Err(ErrorReported)
259+
}
249260

250261
fn new(
251262
tcx: TyCtxt<'tcx>,
@@ -337,14 +348,14 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
337348
Ok(match &node.kind {
338349
// I dont know if handling of these 3 is correct
339350
&ExprKind::Scope { value, .. } => self.recurse_build(value)?,
340-
&ExprKind::PlaceTypeAscription { source, .. } |
341-
&ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?,
351+
&ExprKind::PlaceTypeAscription { source, .. }
352+
| &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?,
342353

343354
// subtle: associated consts are literals this arm handles
344355
// `<T as Trait>::ASSOC` as well as `12`
345356
&ExprKind::Literal { literal, .. } => self.nodes.push(Node::Leaf(literal)),
346357

347-
ExprKind::Call { fun, args, .. } => {
358+
ExprKind::Call { fun, args, .. } => {
348359
let fun = self.recurse_build(*fun)?;
349360

350361
let mut new_args = Vec::<NodeId>::with_capacity(args.len());
@@ -353,7 +364,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
353364
}
354365
let new_args = self.tcx.arena.alloc_slice(&new_args);
355366
self.nodes.push(Node::FunctionCall(fun, new_args))
356-
},
367+
}
357368
&ExprKind::Binary { op, lhs, rhs } if Self::check_binop(op) => {
358369
let lhs = self.recurse_build(lhs)?;
359370
let rhs = self.recurse_build(rhs)?;
@@ -362,68 +373,108 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
362373
&ExprKind::Unary { op, arg } if Self::check_unop(op) => {
363374
let arg = self.recurse_build(arg)?;
364375
self.nodes.push(Node::UnaryOp(op, arg))
365-
},
376+
}
366377
// This is necessary so that the following compiles:
367378
//
368379
// ```
369380
// fn foo<const N: usize>(a: [(); N + 1]) {
370381
// bar::<{ N + 1 }>();
371382
// }
372383
// ```
373-
ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. }} => self.recurse_build(*e)?,
384+
ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. } } => {
385+
self.recurse_build(*e)?
386+
}
374387
// `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a
375388
// "coercion cast" i.e. using a coercion or is a no-op.
376389
// This is important so that `N as usize as usize` doesnt unify with `N as usize`. (untested)
377390
&ExprKind::Use { source } => {
378391
let arg = self.recurse_build(source)?;
379392
self.nodes.push(Node::Cast(abstract_const::CastKind::Use, arg, node.ty))
380-
},
393+
}
381394
&ExprKind::Cast { source } => {
382395
let arg = self.recurse_build(source)?;
383396
self.nodes.push(Node::Cast(abstract_const::CastKind::As, arg, node.ty))
384-
},
397+
}
385398

386399
// FIXME(generic_const_exprs): We may want to support these.
387400
ExprKind::AddressOf { .. }
388401
| ExprKind::Borrow { .. }
389-
| ExprKind::Deref { .. }
390-
| ExprKind::Repeat { .. }
391-
| ExprKind::Array { .. }
392-
| ExprKind::Block { .. }
393-
| ExprKind::NeverToAny { .. }
394-
| ExprKind::Tuple { .. }
395-
| ExprKind::Index { .. }
396-
| ExprKind::Field { .. }
397-
| ExprKind::ConstBlock { .. }
398-
| ExprKind::Adt(_) => self.error(
399-
Some(node.span),
400-
"unsupported operation in generic constant, this may be supported in the future",
402+
| ExprKind::Deref { .. } => self.maybe_supported_error(
403+
node.span,
404+
"dereferencing is not supported in generic constants",
405+
)?,
406+
ExprKind::Repeat { .. } | ExprKind::Array { .. } => self.maybe_supported_error(
407+
node.span,
408+
"array construction is not supported in generic constants",
409+
)?,
410+
ExprKind::Block { .. } => self.maybe_supported_error(
411+
node.span,
412+
"blocks are not supported in generic constant",
413+
)?,
414+
ExprKind::NeverToAny { .. } => self.maybe_supported_error(
415+
node.span,
416+
"converting nevers to any is not supported in generic constant",
417+
)?,
418+
ExprKind::Tuple { .. } => self.maybe_supported_error(
419+
node.span,
420+
"tuple construction is not supported in generic constants",
421+
)?,
422+
ExprKind::Index { .. } => self.maybe_supported_error(
423+
node.span,
424+
"indexing is not supported in generic constant",
425+
)?,
426+
ExprKind::Field { .. } => self.maybe_supported_error(
427+
node.span,
428+
"field access is not supported in generic constant",
429+
)?,
430+
ExprKind::ConstBlock { .. } => self.maybe_supported_error(
431+
node.span,
432+
"const blocks are not supported in generic constant",
433+
)?,
434+
ExprKind::Adt(_) => self.maybe_supported_error(
435+
node.span,
436+
"struct/enum construction is not supported in generic constants",
437+
)?,
438+
// dont know if this is correct
439+
ExprKind::Pointer { .. } =>
440+
self.error(node.span, "pointer casts are not allowed in generic constants")?,
441+
ExprKind::Yield { .. } =>
442+
self.error(node.span, "generator control flow is not allowed in generic constants")?,
443+
ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::Loop { .. } => self
444+
.error(
445+
node.span,
446+
"loops and loop control flow are not supported in generic constants",
401447
)?,
448+
ExprKind::Box { .. } =>
449+
self.error(node.span, "allocations are not allowed in generic constants")?,
450+
451+
ExprKind::Unary { .. } => unreachable!(),
452+
// we handle valid unary/binary ops above
453+
ExprKind::Binary { .. } =>
454+
self.error(node.span, "unsupported binary operation in generic constants")?,
455+
ExprKind::LogicalOp { .. } =>
456+
self.error(node.span, "unsupported operation in generic constants, short-circuiting operations would imply control flow")?,
457+
ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
458+
self.error(node.span, "assignment is not supported in generic constants")?
459+
}
460+
ExprKind::Closure { .. } | ExprKind::Return { .. } => self.error(
461+
node.span,
462+
"closures and function keywords are not supported in generic constants",
463+
)?,
464+
// let expressions imply control flow
465+
ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } =>
466+
self.error(node.span, "control flow is not supported in generic constants")?,
467+
ExprKind::LlvmInlineAsm { .. } | ExprKind::InlineAsm { .. } => {
468+
self.error(node.span, "assembly is not supported in generic constants")?
469+
}
402470

403-
ExprKind::Match { .. }
404471
// we dont permit let stmts so `VarRef` and `UpvarRef` cant happen
405-
| ExprKind::VarRef { .. }
472+
ExprKind::VarRef { .. }
406473
| ExprKind::UpvarRef { .. }
407-
| ExprKind::Closure { .. }
408-
| ExprKind::Let { .. } // let expressions imply control flow
409-
| ExprKind::Loop { .. }
410-
| ExprKind::Assign { .. }
411474
| ExprKind::StaticRef { .. }
412-
| ExprKind::LogicalOp { .. }
413-
// we handle valid unary/binary ops above
414-
| ExprKind::Unary { .. }
415-
| ExprKind::Binary { .. }
416-
| ExprKind::Break { .. }
417-
| ExprKind::Continue { .. }
418-
| ExprKind::If { .. }
419-
| ExprKind::Pointer { .. } // dont know if this is correct
420-
| ExprKind::ThreadLocalRef(_)
421-
| ExprKind::LlvmInlineAsm { .. }
422-
| ExprKind::Return { .. }
423-
| ExprKind::Box { .. } // allocations not allowed in constants
424-
| ExprKind::AssignOp { .. }
425-
| ExprKind::InlineAsm { .. }
426-
| ExprKind::Yield { .. } => self.error(Some(node.span), "unsupported operation in generic constant")?,
475+
| ExprKind::ThreadLocalRef(_) => {
476+
self.error(node.span, "unsupported operation in generic constant")?
477+
}
427478
})
428479
}
429480
}

src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ error: overly complex generic constant
1010
--> $DIR/array-size-in-generic-struct-param.rs:19:15
1111
|
1212
LL | arr: [u8; CFG.arr_size],
13-
| ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
13+
| ^^^^^^^^^^^^ field access is not supported in generic constant
1414
|
1515
= help: consider moving this anonymous constant into a `const` function
16+
= note: this operation may be supported in the future
1617

1718
error: aborting due to 2 previous errors
1819

src/test/ui/const-generics/generic_const_exprs/closures.stderr

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ error: overly complex generic constant
44
LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
55
| ^^^^-------^^
66
| |
7-
| unsupported operation in generic constant, this may be supported in the future
7+
| dereferencing is not supported in generic constants
88
|
99
= help: consider moving this anonymous constant into a `const` function
10+
= note: this operation may be supported in the future
1011

1112
error: aborting due to previous error
1213

src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,19 @@ error: overly complex generic constant
22
--> $DIR/let-bindings.rs:6:68
33
|
44
LL | fn test<const N: usize>() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default {
5-
| ^^^^^^^^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
5+
| ^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constant
66
|
77
= help: consider moving this anonymous constant into a `const` function
8+
= note: this operation may be supported in the future
89

910
error: overly complex generic constant
1011
--> $DIR/let-bindings.rs:6:35
1112
|
1213
LL | fn test<const N: usize>() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default {
13-
| ^^^^^^^^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
14+
| ^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constant
1415
|
1516
= help: consider moving this anonymous constant into a `const` function
17+
= note: this operation may be supported in the future
1618

1719
error: aborting due to 2 previous errors
1820

src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,28 @@ error: overly complex generic constant
22
--> $DIR/unused_expr.rs:4:34
33
|
44
LL | fn add<const N: usize>() -> [u8; { N + 1; 5 }] {
5-
| ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
5+
| ^^^^^^^^^^^^ blocks are not supported in generic constant
66
|
77
= help: consider moving this anonymous constant into a `const` function
8+
= note: this operation may be supported in the future
89

910
error: overly complex generic constant
1011
--> $DIR/unused_expr.rs:9:34
1112
|
1213
LL | fn div<const N: usize>() -> [u8; { N / 1; 5 }] {
13-
| ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
14+
| ^^^^^^^^^^^^ blocks are not supported in generic constant
1415
|
1516
= help: consider moving this anonymous constant into a `const` function
17+
= note: this operation may be supported in the future
1618

1719
error: overly complex generic constant
1820
--> $DIR/unused_expr.rs:16:38
1921
|
2022
LL | fn fn_call<const N: usize>() -> [u8; { foo(N); 5 }] {
21-
| ^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
23+
| ^^^^^^^^^^^^^ blocks are not supported in generic constant
2224
|
2325
= help: consider moving this anonymous constant into a `const` function
26+
= note: this operation may be supported in the future
2427

2528
error: aborting due to 3 previous errors
2629

src/test/ui/const-generics/issues/issue-67375.full.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: overly complex generic constant
44
LL | inner: [(); { [|_: &T| {}; 0].len() }],
55
| ^^---------------^^^^^^^^
66
| |
7-
| unsupported operation in generic constant
7+
| pointer casts are not allowed in generic constants
88
|
99
= help: consider moving this anonymous constant into a `const` function
1010

src/test/ui/const-generics/issues/issue-67945-2.full.stderr

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ LL | | let x: Option<Box<Self>> = None;
88
LL | |
99
LL | | 0
1010
LL | | }],
11-
| |_____^ unsupported operation in generic constant, this may be supported in the future
11+
| |_____^ blocks are not supported in generic constant
1212
|
1313
= help: consider moving this anonymous constant into a `const` function
14+
= note: this operation may be supported in the future
1415

1516
error: aborting due to previous error
1617

0 commit comments

Comments
 (0)