]> git.lizzy.rs Git - rust.git/commitdiff
Suggest a FnPtr type if a FnDef type is found
authorFabian Wolff <fabian.wolff@alumni.ethz.ch>
Fri, 11 Jun 2021 18:12:40 +0000 (20:12 +0200)
committerFabian Wolff <fabian.wolff@alumni.ethz.ch>
Fri, 11 Jun 2021 21:05:17 +0000 (23:05 +0200)
compiler/rustc_typeck/src/collect/type_of.rs
src/test/ui/suggestions/unnamable-types.rs
src/test/ui/suggestions/unnamable-types.stderr

index 38678cc76e0deadf03b343ac86fa6868bec5638e..abe5d69a3b3c1b313c71f02a28084f38167d5fb8 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
 use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder};
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 
@@ -749,15 +749,38 @@ fn infer_placeholder_type(
     span: Span,
     item_ident: Ident,
 ) -> Ty<'_> {
-    fn contains_anonymous(ty: Ty<'_>) -> bool {
-        for gen_arg in ty.walk() {
-            if let ty::subst::GenericArgKind::Type(inner_ty) = gen_arg.unpack() {
-                if let ty::FnDef(..) | ty::Closure(..) | ty::Generator(..) = inner_ty.kind() {
-                    return true;
+    // Attempts to make the type nameable by turning FnDefs into FnPtrs.
+    struct MakeNameable<'tcx> {
+        success: bool,
+        tcx: TyCtxt<'tcx>,
+    }
+
+    impl<'tcx> MakeNameable<'tcx> {
+        fn new(tcx: TyCtxt<'tcx>) -> Self {
+            MakeNameable { success: true, tcx }
+        }
+    }
+
+    impl TypeFolder<'tcx> for MakeNameable<'tcx> {
+        fn tcx(&self) -> TyCtxt<'tcx> {
+            self.tcx
+        }
+
+        fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+            if !self.success {
+                return ty;
+            }
+
+            match ty.kind() {
+                ty::FnDef(def_id, _) => self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id)),
+                // FIXME: non-capturing closures should also suggest a function pointer
+                ty::Closure(..) | ty::Generator(..) => {
+                    self.success = false;
+                    ty
                 }
+                _ => ty.super_fold_with(self),
             }
         }
-        false
     }
 
     let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id);
@@ -773,11 +796,14 @@ fn contains_anonymous(ty: Ty<'_>) -> bool {
             err.suggestions.clear();
 
             // Suggesting unnameable types won't help.
-            if !contains_anonymous(ty) {
+            let mut mk_nameable = MakeNameable::new(tcx);
+            let ty = mk_nameable.fold_ty(ty);
+            let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
+            if let Some(sugg_ty) = sugg_ty {
                 err.span_suggestion(
                     span,
                     "provide a type for the item",
-                    format!("{}: {}", item_ident, ty),
+                    format!("{}: {}", item_ident, sugg_ty),
                     Applicability::MachineApplicable,
                 );
             } else {
@@ -793,11 +819,14 @@ fn contains_anonymous(ty: Ty<'_>) -> bool {
             let mut diag = bad_placeholder_type(tcx, vec![span]);
 
             if !ty.references_error() {
-                if !contains_anonymous(ty) {
+                let mut mk_nameable = MakeNameable::new(tcx);
+                let ty = mk_nameable.fold_ty(ty);
+                let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
+                if let Some(sugg_ty) = sugg_ty {
                     diag.span_suggestion(
                         span,
                         "replace with the correct type",
-                        ty.to_string(),
+                        sugg_ty.to_string(),
                         Applicability::MaybeIncorrect,
                     );
                 } else {
index ed70bcf5484c1ed9ca567efe033615bce4b21a8b..5d0616443e5ac872252c6f47dd9ac4d4690b486d 100644 (file)
 //~| HELP: replace with the correct type
 
 
+// FIXME: this should also suggest a function pointer, as the closure is non-capturing
 const C: _ = || 42;
 //~^ ERROR: the type placeholder `_` is not allowed within types on item signatures
 //~| NOTE: not allowed in type signatures
 //~| NOTE: however, the inferred type
 
 struct S<T> { t: T }
-const D = S { t: || -> i32 { 42 } };
+const D = S { t: { let i = 0; move || -> i32 { i } } };
 //~^ ERROR: missing type for `const` item
 //~| NOTE: however, the inferred type
 
+
 fn foo() -> i32 { 42 }
-const E = S { t: foo };
+const E = foo;
 //~^ ERROR: missing type for `const` item
-//~| NOTE: however, the inferred type
+//~| HELP: provide a type for the item
+const F = S { t: foo };
+//~^ ERROR: missing type for `const` item
+//~| HELP: provide a type for the item
+
 
-const F = || -> i32 { yield 0; return 1; };
+const G = || -> i32 { yield 0; return 1; };
 //~^ ERROR: missing type for `const` item
 //~| NOTE: however, the inferred type
index 8082707fd3c2a2786e3fb8a12aae6f2c71300d7f..2c8166781bfdc68aeae06f8a3485c01a85906e60 100644 (file)
@@ -14,53 +14,53 @@ LL | static B: _ = "abc";
    |           help: replace with the correct type: `&str`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/unnamable-types.rs:16:10
+  --> $DIR/unnamable-types.rs:17:10
    |
 LL | const C: _ = || 42;
    |          ^ not allowed in type signatures
    |
-note: however, the inferred type `[closure@$DIR/unnamable-types.rs:16:14: 16:19]` cannot be named
-  --> $DIR/unnamable-types.rs:16:14
+note: however, the inferred type `[closure@$DIR/unnamable-types.rs:17:14: 17:19]` cannot be named
+  --> $DIR/unnamable-types.rs:17:14
    |
 LL | const C: _ = || 42;
    |              ^^^^^
 
 error: missing type for `const` item
-  --> $DIR/unnamable-types.rs:22:7
+  --> $DIR/unnamable-types.rs:23:7
    |
-LL | const D = S { t: || -> i32 { 42 } };
+LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
    |       ^
    |
-note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:22:18: 22:34]>` cannot be named
-  --> $DIR/unnamable-types.rs:22:11
+note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:23:31: 23:51]>` cannot be named
+  --> $DIR/unnamable-types.rs:23:11
    |
-LL | const D = S { t: || -> i32 { 42 } };
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing type for `const` item
-  --> $DIR/unnamable-types.rs:27:7
+  --> $DIR/unnamable-types.rs:29:7
    |
-LL | const E = S { t: foo };
-   |       ^
-   |
-note: however, the inferred type `S<fn() -> i32 {foo}>` cannot be named
-  --> $DIR/unnamable-types.rs:27:11
+LL | const E = foo;
+   |       ^ help: provide a type for the item: `E: fn() -> i32`
+
+error: missing type for `const` item
+  --> $DIR/unnamable-types.rs:32:7
    |
-LL | const E = S { t: foo };
-   |           ^^^^^^^^^^^^
+LL | const F = S { t: foo };
+   |       ^ help: provide a type for the item: `F: S<fn() -> i32>`
 
 error: missing type for `const` item
-  --> $DIR/unnamable-types.rs:31:7
+  --> $DIR/unnamable-types.rs:37:7
    |
-LL | const F = || -> i32 { yield 0; return 1; };
+LL | const G = || -> i32 { yield 0; return 1; };
    |       ^
    |
-note: however, the inferred type `[generator@$DIR/unnamable-types.rs:31:11: 31:43 {i32, ()}]` cannot be named
-  --> $DIR/unnamable-types.rs:31:11
+note: however, the inferred type `[generator@$DIR/unnamable-types.rs:37:11: 37:43 {i32, ()}]` cannot be named
+  --> $DIR/unnamable-types.rs:37:11
    |
-LL | const F = || -> i32 { yield 0; return 1; };
+LL | const G = || -> i32 { yield 0; return 1; };
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0121`.