Skip to content

Commit a742547

Browse files
committed
Auto merge of #75611 - JulianKnodt:cg_enum_err, r=lcnr
Add help note when using type in place of const This adds a small help note when it might be possible that wrapping a parameter in braces might resolve the issue of having a type where a const was expected. Currently, I am displaying the `HirId`, and I'm not particularly sure where to get the currently displayed path(?). r? `@lcnr`
2 parents f5b7dd8 + 96bb2c8 commit a742547

File tree

3 files changed

+197
-17
lines changed

3 files changed

+197
-17
lines changed

compiler/rustc_typeck/src/astconv/generics.rs

+59-17
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::astconv::{
33
};
44
use crate::errors::AssocTypeBindingNotAllowed;
55
use rustc_ast::ast::ParamKindOrd;
6-
use rustc_errors::{pluralize, struct_span_err, DiagnosticId, ErrorReported};
6+
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorReported};
77
use rustc_hir as hir;
88
use rustc_hir::def_id::DefId;
99
use rustc_hir::{GenericArg, GenericArgs};
@@ -368,7 +368,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
368368
}
369369

370370
if position != GenericArgPosition::Type && !args.bindings.is_empty() {
371-
Self::prohibit_assoc_ty_binding(tcx, args.bindings[0].span);
371+
AstConv::prohibit_assoc_ty_binding(tcx, args.bindings[0].span);
372372
}
373373

374374
let explicit_late_bound =
@@ -393,7 +393,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
393393
}
394394

395395
if silent {
396-
return Err(true);
396+
return Err((0i32, None));
397397
}
398398

399399
// Unfortunately lifetime and type parameter mismatches are typically styled
@@ -442,58 +442,100 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
442442
for span in spans {
443443
err.span_label(span, label.as_str());
444444
}
445-
err.emit();
446445

447-
Err(true)
446+
assert_ne!(bound, provided);
447+
Err((bound as i32 - provided as i32, Some(err)))
448448
};
449449

450-
let mut arg_count_correct = Ok(());
451450
let mut unexpected_spans = vec![];
452451

452+
let mut lifetime_count_correct = Ok(());
453453
if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes {
454-
arg_count_correct = check_kind_count(
454+
lifetime_count_correct = check_kind_count(
455455
"lifetime",
456456
param_counts.lifetimes,
457457
param_counts.lifetimes,
458458
arg_counts.lifetimes,
459459
0,
460460
&mut unexpected_spans,
461461
explicit_late_bound == ExplicitLateBound::Yes,
462-
)
463-
.and(arg_count_correct);
462+
);
464463
}
464+
465465
// FIXME(const_generics:defaults)
466+
let mut const_count_correct = Ok(());
466467
if !infer_args || arg_counts.consts > param_counts.consts {
467-
arg_count_correct = check_kind_count(
468+
const_count_correct = check_kind_count(
468469
"const",
469470
param_counts.consts,
470471
param_counts.consts,
471472
arg_counts.consts,
472473
arg_counts.lifetimes + arg_counts.types,
473474
&mut unexpected_spans,
474475
false,
475-
)
476-
.and(arg_count_correct);
476+
);
477477
}
478+
478479
// Note that type errors are currently be emitted *after* const errors.
480+
let mut type_count_correct = Ok(());
479481
if !infer_args || arg_counts.types > param_counts.types - defaults.types - has_self as usize
480482
{
481-
arg_count_correct = check_kind_count(
483+
type_count_correct = check_kind_count(
482484
"type",
483485
param_counts.types - defaults.types - has_self as usize,
484486
param_counts.types - has_self as usize,
485487
arg_counts.types,
486488
arg_counts.lifetimes,
487489
&mut unexpected_spans,
488490
false,
489-
)
490-
.and(arg_count_correct);
491+
);
491492
}
492493

494+
// Emit a help message if it's possible that a type could be surrounded in braces
495+
if let Err((c_mismatch, Some(ref mut _const_err))) = const_count_correct {
496+
if let Err((_, Some(ref mut type_err))) = type_count_correct {
497+
let possible_matches = args.args[arg_counts.lifetimes..]
498+
.iter()
499+
.filter(|arg| {
500+
matches!(
501+
arg,
502+
GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. })
503+
)
504+
})
505+
.take(c_mismatch.max(0) as usize);
506+
for arg in possible_matches {
507+
let suggestions = vec![
508+
(arg.span().shrink_to_lo(), String::from("{ ")),
509+
(arg.span().shrink_to_hi(), String::from(" }")),
510+
];
511+
type_err.multipart_suggestion(
512+
"If this generic argument was intended as a const parameter, \
513+
try surrounding it with braces:",
514+
suggestions,
515+
Applicability::MaybeIncorrect,
516+
);
517+
}
518+
}
519+
}
520+
521+
let emit_correct =
522+
|correct: Result<(), (_, Option<rustc_errors::DiagnosticBuilder<'_>>)>| match correct {
523+
Ok(()) => Ok(()),
524+
Err((_, None)) => Err(()),
525+
Err((_, Some(mut err))) => {
526+
err.emit();
527+
Err(())
528+
}
529+
};
530+
531+
let arg_count_correct = emit_correct(lifetime_count_correct)
532+
.and(emit_correct(const_count_correct))
533+
.and(emit_correct(type_count_correct));
534+
493535
GenericArgCountResult {
494536
explicit_late_bound,
495-
correct: arg_count_correct.map_err(|reported_err| GenericArgCountMismatch {
496-
reported: if reported_err { Some(ErrorReported) } else { None },
537+
correct: arg_count_correct.map_err(|()| GenericArgCountMismatch {
538+
reported: Some(ErrorReported),
497539
invalid_args: unexpected_spans,
498540
}),
499541
}
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#![feature(const_generics)]
2+
#![allow(incomplete_features)]
3+
4+
#[derive(PartialEq, Eq)]
5+
enum CompileFlag {
6+
A,
7+
B,
8+
}
9+
10+
pub fn test_1<const CF: CompileFlag>() {}
11+
pub fn test_2<T, const CF: CompileFlag>(x: T) {}
12+
pub struct Example<const CF: CompileFlag, T=u32>{
13+
x: T,
14+
}
15+
16+
impl<const CF: CompileFlag, T> Example<CF, T> {
17+
const ASSOC_FLAG: CompileFlag = CompileFlag::A;
18+
}
19+
20+
pub fn main() {
21+
test_1::<CompileFlag::A>();
22+
//~^ ERROR: expected type, found variant
23+
//~| ERROR: wrong number of const arguments
24+
//~| ERROR: wrong number of type arguments
25+
26+
test_2::<_, CompileFlag::A>(0);
27+
//~^ ERROR: expected type, found variant
28+
//~| ERROR: wrong number of const arguments
29+
//~| ERROR: wrong number of type arguments
30+
31+
let _: Example<CompileFlag::A, _> = Example { x: 0 };
32+
//~^ ERROR: expected type, found variant
33+
//~| ERROR: wrong number of const arguments
34+
//~| ERROR: wrong number of type arguments
35+
36+
let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 };
37+
//~^ ERROR: wrong number of const arguments
38+
//~| ERROR: wrong number of type arguments
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
error[E0573]: expected type, found variant `CompileFlag::A`
2+
--> $DIR/invalid-enum.rs:21:12
3+
|
4+
LL | test_1::<CompileFlag::A>();
5+
| ^^^^^^^^^^^^^^
6+
| |
7+
| not a type
8+
| help: try using the variant's enum: `CompileFlag`
9+
10+
error[E0573]: expected type, found variant `CompileFlag::A`
11+
--> $DIR/invalid-enum.rs:26:15
12+
|
13+
LL | test_2::<_, CompileFlag::A>(0);
14+
| ^^^^^^^^^^^^^^
15+
| |
16+
| not a type
17+
| help: try using the variant's enum: `CompileFlag`
18+
19+
error[E0573]: expected type, found variant `CompileFlag::A`
20+
--> $DIR/invalid-enum.rs:31:18
21+
|
22+
LL | let _: Example<CompileFlag::A, _> = Example { x: 0 };
23+
| ^^^^^^^^^^^^^^
24+
| |
25+
| not a type
26+
| help: try using the variant's enum: `CompileFlag`
27+
28+
error[E0107]: wrong number of const arguments: expected 1, found 0
29+
--> $DIR/invalid-enum.rs:31:10
30+
|
31+
LL | let _: Example<CompileFlag::A, _> = Example { x: 0 };
32+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument
33+
34+
error[E0107]: wrong number of type arguments: expected at most 1, found 2
35+
--> $DIR/invalid-enum.rs:31:10
36+
|
37+
LL | let _: Example<CompileFlag::A, _> = Example { x: 0 };
38+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected at most 1 type argument
39+
|
40+
help: If this generic argument was intended as a const parameter, try surrounding it with braces:
41+
|
42+
LL | let _: Example<{ CompileFlag::A }, _> = Example { x: 0 };
43+
| ^ ^
44+
45+
error[E0107]: wrong number of const arguments: expected 1, found 0
46+
--> $DIR/invalid-enum.rs:36:10
47+
|
48+
LL | let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 };
49+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument
50+
51+
error[E0107]: wrong number of type arguments: expected at most 1, found 2
52+
--> $DIR/invalid-enum.rs:36:10
53+
|
54+
LL | let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 };
55+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected at most 1 type argument
56+
|
57+
help: If this generic argument was intended as a const parameter, try surrounding it with braces:
58+
|
59+
LL | let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 };
60+
| ^ ^
61+
62+
error[E0107]: wrong number of const arguments: expected 1, found 0
63+
--> $DIR/invalid-enum.rs:21:3
64+
|
65+
LL | test_1::<CompileFlag::A>();
66+
| ^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument
67+
68+
error[E0107]: wrong number of type arguments: expected 0, found 1
69+
--> $DIR/invalid-enum.rs:21:12
70+
|
71+
LL | test_1::<CompileFlag::A>();
72+
| ^^^^^^^^^^^^^^ unexpected type argument
73+
|
74+
help: If this generic argument was intended as a const parameter, try surrounding it with braces:
75+
|
76+
LL | test_1::<{ CompileFlag::A }>();
77+
| ^ ^
78+
79+
error[E0107]: wrong number of const arguments: expected 1, found 0
80+
--> $DIR/invalid-enum.rs:26:3
81+
|
82+
LL | test_2::<_, CompileFlag::A>(0);
83+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument
84+
85+
error[E0107]: wrong number of type arguments: expected 1, found 2
86+
--> $DIR/invalid-enum.rs:26:15
87+
|
88+
LL | test_2::<_, CompileFlag::A>(0);
89+
| ^^^^^^^^^^^^^^ unexpected type argument
90+
|
91+
help: If this generic argument was intended as a const parameter, try surrounding it with braces:
92+
|
93+
LL | test_2::<_, { CompileFlag::A }>(0);
94+
| ^ ^
95+
96+
error: aborting due to 11 previous errors
97+
98+
Some errors have detailed explanations: E0107, E0573.
99+
For more information about an error, try `rustc --explain E0107`.

0 commit comments

Comments
 (0)