Rollup merge of #77758 - Stupremee:turbofish-help-for-const, r=varkor

suggest turbofish syntax for uninferred const arguments

When not providing a const generic value, and it can not be inferred, the following suggestion is suggested:
![image](https://user-images.githubusercontent.com/39732259/95616180-af127b80-0a69-11eb-8877-551c815f9627.png)

Resolves #76737

r? ``@varkor``
This commit is contained in:
Jonas Schievink 2020-11-26 13:39:00 +01:00 committed by GitHub
commit 9b2117d1f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 110 additions and 8 deletions

View File

@ -124,6 +124,11 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
return; return;
} }
} }
// FIXME(const_generics): Currently, any uninferred `const` generics arguments
// are handled specially, but instead they should be handled in `annotate_method_call`,
// which currently doesn't work because this evaluates to `false` for const arguments.
// See https://github.com/rust-lang/rust/pull/77758 for more details.
if self.node_ty_contains_target(expr.hir_id).is_some() { if self.node_ty_contains_target(expr.hir_id).is_some() {
match expr.kind { match expr.kind {
ExprKind::Closure(..) => self.found_closure = Some(&expr), ExprKind::Closure(..) => self.found_closure = Some(&expr),
@ -345,11 +350,6 @@ pub fn emit_inference_failure_err(
) -> DiagnosticBuilder<'tcx> { ) -> DiagnosticBuilder<'tcx> {
let arg = self.resolve_vars_if_possible(arg); let arg = self.resolve_vars_if_possible(arg);
let arg_data = self.extract_inference_diagnostics_data(arg, None); let arg_data = self.extract_inference_diagnostics_data(arg, None);
let kind_str = match arg.unpack() {
GenericArgKind::Type(_) => "type",
GenericArgKind::Const(_) => "the value",
GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
};
let mut local_visitor = FindHirNodeVisitor::new(&self, arg, span); let mut local_visitor = FindHirNodeVisitor::new(&self, arg, span);
let ty_to_string = |ty: Ty<'tcx>| -> String { let ty_to_string = |ty: Ty<'tcx>| -> String {
@ -618,6 +618,28 @@ pub fn emit_inference_failure_err(
.any(|span_label| span_label.label.is_some() && span_label.span == span) .any(|span_label| span_label.label.is_some() && span_label.span == span)
&& local_visitor.found_arg_pattern.is_none() && local_visitor.found_arg_pattern.is_none()
{ {
let (kind_str, const_value) = match arg.unpack() {
GenericArgKind::Type(_) => ("type", None),
GenericArgKind::Const(_) => ("the value", Some(())),
GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
};
// FIXME(const_generics): we would like to handle const arguments
// as part of the normal diagnostics flow below, but there appear to
// be subtleties in doing so, so for now we special-case const args
// here.
if let Some(suggestion) = const_value
.and_then(|_| arg_data.parent_name.as_ref())
.map(|parent| format!("{}::<{}>", parent, arg_data.name))
{
err.span_suggestion_verbose(
span,
"consider specifying the const argument",
suggestion,
Applicability::MaybeIncorrect,
);
}
// Avoid multiple labels pointing at `span`. // Avoid multiple labels pointing at `span`.
err.span_label( err.span_label(
span, span,

View File

@ -3,6 +3,11 @@ error[E0282]: type annotations needed
| |
LL | foo(); LL | foo();
| ^^^ cannot infer the value of const parameter `X` declared on the function `foo` | ^^^ cannot infer the value of const parameter `X` declared on the function `foo`
|
help: consider specifying the const argument
|
LL | foo::<X>();
| ^^^^^^^^
error: aborting due to previous error error: aborting due to previous error

View File

@ -3,6 +3,11 @@ error[E0282]: type annotations needed
| |
LL | foo(); LL | foo();
| ^^^ cannot infer the value of const parameter `X` declared on the function `foo` | ^^^ cannot infer the value of const parameter `X` declared on the function `foo`
|
help: consider specifying the const argument
|
LL | foo::<X>();
| ^^^^^^^^
error: aborting due to previous error error: aborting due to previous error

View File

@ -3,6 +3,11 @@ error[E0282]: type annotations needed
| |
LL | println!("{:?}", take_array_from_mut(&mut arr, i)); LL | println!("{:?}", take_array_from_mut(&mut arr, i));
| ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `take_array_from_mut` | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `take_array_from_mut`
|
help: consider specifying the const argument
|
LL | println!("{:?}", take_array_from_mut::<N>(&mut arr, i));
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error error: aborting due to previous error

View File

@ -3,6 +3,11 @@ error[E0282]: type annotations needed
| |
LL | Foo.bar().bar().bar().bar().baz(); LL | Foo.bar().bar().bar().bar().baz();
| ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz` | ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz`
|
help: consider specifying the const argument
|
LL | Foo.bar().bar().bar().bar().baz::<N>();
| ^^^^^^^^
error: aborting due to previous error error: aborting due to previous error

View File

@ -3,6 +3,11 @@ error[E0282]: type annotations needed
| |
LL | Foo.bar().bar().bar().bar().baz(); LL | Foo.bar().bar().bar().bar().baz();
| ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz` | ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz`
|
help: consider specifying the const argument
|
LL | Foo.bar().bar().bar().bar().baz::<N>();
| ^^^^^^^^
error: aborting due to previous error error: aborting due to previous error

View File

@ -0,0 +1,14 @@
error[E0282]: type annotations needed
--> $DIR/one-param-uninferred.rs:15:23
|
LL | let _: [u8; 17] = foo();
| ^^^ cannot infer the value of const parameter `M` declared on the function `foo`
|
help: consider specifying the const argument
|
LL | let _: [u8; 17] = foo::<M>();
| ^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0282`.

View File

@ -0,0 +1,14 @@
error[E0282]: type annotations needed
--> $DIR/one-param-uninferred.rs:15:23
|
LL | let _: [u8; 17] = foo();
| ^^^ cannot infer the value of const parameter `M` declared on the function `foo`
|
help: consider specifying the const argument
|
LL | let _: [u8; 17] = foo::<M>();
| ^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0282`.

View File

@ -0,0 +1,17 @@
// Test that we emit an error if we cannot properly infer a constant.
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
#![cfg_attr(min, feature(min_const_generics))]
fn foo<const N: usize, const M: usize>() -> [u8; N] {
todo!()
}
fn main() {
// FIXME(const_generics): Currently this only suggests one const parameter,
// but instead it should suggest to provide all parameters.
let _: [u8; 17] = foo();
//~^ ERROR type annotations needed
}

View File

@ -2,7 +2,12 @@ error[E0282]: type annotations needed
--> $DIR/uninferred-consts.rs:14:9 --> $DIR/uninferred-consts.rs:14:9
| |
LL | Foo.foo(); LL | Foo.foo();
| ^^^ cannot infer the value of const parameter `N` declared on the associated function `foo` | ^^^ cannot infer the value of const parameter `A` declared on the associated function `foo`
|
help: consider specifying the const argument
|
LL | Foo.foo::<A>();
| ^^^^^^^^
error: aborting due to previous error error: aborting due to previous error

View File

@ -2,7 +2,12 @@ error[E0282]: type annotations needed
--> $DIR/uninferred-consts.rs:14:9 --> $DIR/uninferred-consts.rs:14:9
| |
LL | Foo.foo(); LL | Foo.foo();
| ^^^ cannot infer the value of const parameter `N` declared on the associated function `foo` | ^^^ cannot infer the value of const parameter `A` declared on the associated function `foo`
|
help: consider specifying the const argument
|
LL | Foo.foo::<A>();
| ^^^^^^^^
error: aborting due to previous error error: aborting due to previous error

View File

@ -8,7 +8,7 @@
// taken from https://github.com/rust-lang/rust/issues/70507#issuecomment-615268893 // taken from https://github.com/rust-lang/rust/issues/70507#issuecomment-615268893
struct Foo; struct Foo;
impl Foo { impl Foo {
fn foo<const N: usize>(self) {} fn foo<const A: usize, const B: usize>(self) {}
} }
fn main() { fn main() {
Foo.foo(); Foo.foo();