From 4379a43e461f7727af2a37b12c7c83f290fc7856 Mon Sep 17 00:00:00 2001 From: Justus K Date: Thu, 8 Oct 2020 22:23:01 +0200 Subject: [PATCH] Suggest turbofish for uninferred const argument --- .../infer/error_reporting/need_type_info.rs | 32 ++++++++++++++++--- .../infer/cannot-infer-const-args.full.stderr | 5 +++ .../infer/cannot-infer-const-args.min.stderr | 5 +++ .../const-generics/infer/issue-77092.stderr | 5 +++ .../infer/method-chain.full.stderr | 5 +++ .../infer/method-chain.min.stderr | 5 +++ .../infer/one-param-uninferred.full.stderr | 14 ++++++++ .../infer/one-param-uninferred.min.stderr | 14 ++++++++ .../infer/one-param-uninferred.rs | 17 ++++++++++ .../infer/uninferred-consts.full.stderr | 7 +++- .../infer/uninferred-consts.min.stderr | 7 +++- .../const-generics/infer/uninferred-consts.rs | 2 +- 12 files changed, 110 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/const-generics/infer/one-param-uninferred.full.stderr create mode 100644 src/test/ui/const-generics/infer/one-param-uninferred.min.stderr create mode 100644 src/test/ui/const-generics/infer/one-param-uninferred.rs diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index fd8f46a6926c0..373f0a602c0ef 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -124,6 +124,11 @@ impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> { 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() { match expr.kind { ExprKind::Closure(..) => self.found_closure = Some(&expr), @@ -345,11 +350,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) -> DiagnosticBuilder<'tcx> { let arg = self.resolve_vars_if_possible(arg); 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 ty_to_string = |ty: Ty<'tcx>| -> String { @@ -618,6 +618,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .any(|span_label| span_label.label.is_some() && span_label.span == span) && 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`. err.span_label( span, diff --git a/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr index b438ed3ad6508..05bf67a5ff7c6 100644 --- a/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr +++ b/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr @@ -3,6 +3,11 @@ error[E0282]: type annotations needed | LL | foo(); | ^^^ cannot infer the value of const parameter `X` declared on the function `foo` + | +help: consider specifying the const argument + | +LL | foo::(); + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr index b438ed3ad6508..05bf67a5ff7c6 100644 --- a/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr +++ b/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr @@ -3,6 +3,11 @@ error[E0282]: type annotations needed | LL | foo(); | ^^^ cannot infer the value of const parameter `X` declared on the function `foo` + | +help: consider specifying the const argument + | +LL | foo::(); + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/issue-77092.stderr b/src/test/ui/const-generics/infer/issue-77092.stderr index 63facbf3b8c0f..99894173bc8f6 100644 --- a/src/test/ui/const-generics/infer/issue-77092.stderr +++ b/src/test/ui/const-generics/infer/issue-77092.stderr @@ -3,6 +3,11 @@ error[E0282]: type annotations needed | 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` + | +help: consider specifying the const argument + | +LL | println!("{:?}", take_array_from_mut::(&mut arr, i)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/method-chain.full.stderr b/src/test/ui/const-generics/infer/method-chain.full.stderr index 1fb0b23cf1157..7aa3bd44df844 100644 --- a/src/test/ui/const-generics/infer/method-chain.full.stderr +++ b/src/test/ui/const-generics/infer/method-chain.full.stderr @@ -3,6 +3,11 @@ error[E0282]: type annotations needed | LL | Foo.bar().bar().bar().bar().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::(); + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/method-chain.min.stderr b/src/test/ui/const-generics/infer/method-chain.min.stderr index 1fb0b23cf1157..7aa3bd44df844 100644 --- a/src/test/ui/const-generics/infer/method-chain.min.stderr +++ b/src/test/ui/const-generics/infer/method-chain.min.stderr @@ -3,6 +3,11 @@ error[E0282]: type annotations needed | LL | Foo.bar().bar().bar().bar().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::(); + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/one-param-uninferred.full.stderr b/src/test/ui/const-generics/infer/one-param-uninferred.full.stderr new file mode 100644 index 0000000000000..cc6c9a475104c --- /dev/null +++ b/src/test/ui/const-generics/infer/one-param-uninferred.full.stderr @@ -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::(); + | ^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/infer/one-param-uninferred.min.stderr b/src/test/ui/const-generics/infer/one-param-uninferred.min.stderr new file mode 100644 index 0000000000000..cc6c9a475104c --- /dev/null +++ b/src/test/ui/const-generics/infer/one-param-uninferred.min.stderr @@ -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::(); + | ^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/infer/one-param-uninferred.rs b/src/test/ui/const-generics/infer/one-param-uninferred.rs new file mode 100644 index 0000000000000..0e947131f4cdb --- /dev/null +++ b/src/test/ui/const-generics/infer/one-param-uninferred.rs @@ -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() -> [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 +} diff --git a/src/test/ui/const-generics/infer/uninferred-consts.full.stderr b/src/test/ui/const-generics/infer/uninferred-consts.full.stderr index 7a451903e9630..4be625ba90930 100644 --- a/src/test/ui/const-generics/infer/uninferred-consts.full.stderr +++ b/src/test/ui/const-generics/infer/uninferred-consts.full.stderr @@ -2,7 +2,12 @@ error[E0282]: type annotations needed --> $DIR/uninferred-consts.rs:14:9 | 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::(); + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/uninferred-consts.min.stderr b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr index 7a451903e9630..4be625ba90930 100644 --- a/src/test/ui/const-generics/infer/uninferred-consts.min.stderr +++ b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr @@ -2,7 +2,12 @@ error[E0282]: type annotations needed --> $DIR/uninferred-consts.rs:14:9 | 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::(); + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/const-generics/infer/uninferred-consts.rs b/src/test/ui/const-generics/infer/uninferred-consts.rs index ec5b3ffe5440b..00fb6eac99208 100644 --- a/src/test/ui/const-generics/infer/uninferred-consts.rs +++ b/src/test/ui/const-generics/infer/uninferred-consts.rs @@ -8,7 +8,7 @@ // taken from https://github.com/rust-lang/rust/issues/70507#issuecomment-615268893 struct Foo; impl Foo { - fn foo(self) {} + fn foo(self) {} } fn main() { Foo.foo();