Skip to content

Commit

Permalink
Auto merge of #75611 - JulianKnodt:cg_enum_err, r=lcnr
Browse files Browse the repository at this point in the history
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`
  • Loading branch information
bors committed Sep 11, 2020
2 parents f5b7dd8 + 96bb2c8 commit a742547
Show file tree
Hide file tree
Showing 3 changed files with 197 additions and 17 deletions.
76 changes: 59 additions & 17 deletions compiler/rustc_typeck/src/astconv/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::astconv::{
};
use crate::errors::AssocTypeBindingNotAllowed;
use rustc_ast::ast::ParamKindOrd;
use rustc_errors::{pluralize, struct_span_err, DiagnosticId, ErrorReported};
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorReported};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::{GenericArg, GenericArgs};
Expand Down Expand Up @@ -368,7 +368,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}

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

let explicit_late_bound =
Expand All @@ -393,7 +393,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}

if silent {
return Err(true);
return Err((0i32, None));
}

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

Err(true)
assert_ne!(bound, provided);
Err((bound as i32 - provided as i32, Some(err)))
};

let mut arg_count_correct = Ok(());
let mut unexpected_spans = vec![];

let mut lifetime_count_correct = Ok(());
if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes {
arg_count_correct = check_kind_count(
lifetime_count_correct = check_kind_count(
"lifetime",
param_counts.lifetimes,
param_counts.lifetimes,
arg_counts.lifetimes,
0,
&mut unexpected_spans,
explicit_late_bound == ExplicitLateBound::Yes,
)
.and(arg_count_correct);
);
}

// FIXME(const_generics:defaults)
let mut const_count_correct = Ok(());
if !infer_args || arg_counts.consts > param_counts.consts {
arg_count_correct = check_kind_count(
const_count_correct = check_kind_count(
"const",
param_counts.consts,
param_counts.consts,
arg_counts.consts,
arg_counts.lifetimes + arg_counts.types,
&mut unexpected_spans,
false,
)
.and(arg_count_correct);
);
}

// Note that type errors are currently be emitted *after* const errors.
let mut type_count_correct = Ok(());
if !infer_args || arg_counts.types > param_counts.types - defaults.types - has_self as usize
{
arg_count_correct = check_kind_count(
type_count_correct = check_kind_count(
"type",
param_counts.types - defaults.types - has_self as usize,
param_counts.types - has_self as usize,
arg_counts.types,
arg_counts.lifetimes,
&mut unexpected_spans,
false,
)
.and(arg_count_correct);
);
}

// Emit a help message if it's possible that a type could be surrounded in braces
if let Err((c_mismatch, Some(ref mut _const_err))) = const_count_correct {
if let Err((_, Some(ref mut type_err))) = type_count_correct {
let possible_matches = args.args[arg_counts.lifetimes..]
.iter()
.filter(|arg| {
matches!(
arg,
GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. })
)
})
.take(c_mismatch.max(0) as usize);
for arg in possible_matches {
let suggestions = vec![
(arg.span().shrink_to_lo(), String::from("{ ")),
(arg.span().shrink_to_hi(), String::from(" }")),
];
type_err.multipart_suggestion(
"If this generic argument was intended as a const parameter, \
try surrounding it with braces:",
suggestions,
Applicability::MaybeIncorrect,
);
}
}
}

let emit_correct =
|correct: Result<(), (_, Option<rustc_errors::DiagnosticBuilder<'_>>)>| match correct {
Ok(()) => Ok(()),
Err((_, None)) => Err(()),
Err((_, Some(mut err))) => {
err.emit();
Err(())
}
};

let arg_count_correct = emit_correct(lifetime_count_correct)
.and(emit_correct(const_count_correct))
.and(emit_correct(type_count_correct));

GenericArgCountResult {
explicit_late_bound,
correct: arg_count_correct.map_err(|reported_err| GenericArgCountMismatch {
reported: if reported_err { Some(ErrorReported) } else { None },
correct: arg_count_correct.map_err(|()| GenericArgCountMismatch {
reported: Some(ErrorReported),
invalid_args: unexpected_spans,
}),
}
Expand Down
39 changes: 39 additions & 0 deletions src/test/ui/const-generics/invalid-enum.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#![feature(const_generics)]
#![allow(incomplete_features)]

#[derive(PartialEq, Eq)]
enum CompileFlag {
A,
B,
}

pub fn test_1<const CF: CompileFlag>() {}
pub fn test_2<T, const CF: CompileFlag>(x: T) {}
pub struct Example<const CF: CompileFlag, T=u32>{
x: T,
}

impl<const CF: CompileFlag, T> Example<CF, T> {
const ASSOC_FLAG: CompileFlag = CompileFlag::A;
}

pub fn main() {
test_1::<CompileFlag::A>();
//~^ ERROR: expected type, found variant
//~| ERROR: wrong number of const arguments
//~| ERROR: wrong number of type arguments

test_2::<_, CompileFlag::A>(0);
//~^ ERROR: expected type, found variant
//~| ERROR: wrong number of const arguments
//~| ERROR: wrong number of type arguments

let _: Example<CompileFlag::A, _> = Example { x: 0 };
//~^ ERROR: expected type, found variant
//~| ERROR: wrong number of const arguments
//~| ERROR: wrong number of type arguments

let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 };
//~^ ERROR: wrong number of const arguments
//~| ERROR: wrong number of type arguments
}
99 changes: 99 additions & 0 deletions src/test/ui/const-generics/invalid-enum.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
error[E0573]: expected type, found variant `CompileFlag::A`
--> $DIR/invalid-enum.rs:21:12
|
LL | test_1::<CompileFlag::A>();
| ^^^^^^^^^^^^^^
| |
| not a type
| help: try using the variant's enum: `CompileFlag`

error[E0573]: expected type, found variant `CompileFlag::A`
--> $DIR/invalid-enum.rs:26:15
|
LL | test_2::<_, CompileFlag::A>(0);
| ^^^^^^^^^^^^^^
| |
| not a type
| help: try using the variant's enum: `CompileFlag`

error[E0573]: expected type, found variant `CompileFlag::A`
--> $DIR/invalid-enum.rs:31:18
|
LL | let _: Example<CompileFlag::A, _> = Example { x: 0 };
| ^^^^^^^^^^^^^^
| |
| not a type
| help: try using the variant's enum: `CompileFlag`

error[E0107]: wrong number of const arguments: expected 1, found 0
--> $DIR/invalid-enum.rs:31:10
|
LL | let _: Example<CompileFlag::A, _> = Example { x: 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument

error[E0107]: wrong number of type arguments: expected at most 1, found 2
--> $DIR/invalid-enum.rs:31:10
|
LL | let _: Example<CompileFlag::A, _> = Example { x: 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected at most 1 type argument
|
help: If this generic argument was intended as a const parameter, try surrounding it with braces:
|
LL | let _: Example<{ CompileFlag::A }, _> = Example { x: 0 };
| ^ ^

error[E0107]: wrong number of const arguments: expected 1, found 0
--> $DIR/invalid-enum.rs:36:10
|
LL | let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument

error[E0107]: wrong number of type arguments: expected at most 1, found 2
--> $DIR/invalid-enum.rs:36:10
|
LL | let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected at most 1 type argument
|
help: If this generic argument was intended as a const parameter, try surrounding it with braces:
|
LL | let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 };
| ^ ^

error[E0107]: wrong number of const arguments: expected 1, found 0
--> $DIR/invalid-enum.rs:21:3
|
LL | test_1::<CompileFlag::A>();
| ^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument

error[E0107]: wrong number of type arguments: expected 0, found 1
--> $DIR/invalid-enum.rs:21:12
|
LL | test_1::<CompileFlag::A>();
| ^^^^^^^^^^^^^^ unexpected type argument
|
help: If this generic argument was intended as a const parameter, try surrounding it with braces:
|
LL | test_1::<{ CompileFlag::A }>();
| ^ ^

error[E0107]: wrong number of const arguments: expected 1, found 0
--> $DIR/invalid-enum.rs:26:3
|
LL | test_2::<_, CompileFlag::A>(0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument

error[E0107]: wrong number of type arguments: expected 1, found 2
--> $DIR/invalid-enum.rs:26:15
|
LL | test_2::<_, CompileFlag::A>(0);
| ^^^^^^^^^^^^^^ unexpected type argument
|
help: If this generic argument was intended as a const parameter, try surrounding it with braces:
|
LL | test_2::<_, { CompileFlag::A }>(0);
| ^ ^

error: aborting due to 11 previous errors

Some errors have detailed explanations: E0107, E0573.
For more information about an error, try `rustc --explain E0107`.

0 comments on commit a742547

Please sign in to comment.