Skip to content

Commit

Permalink
Auto merge of rust-lang#86215 - FabianWolff:unnameable-types, r=jackh726
Browse files Browse the repository at this point in the history
Do not suggest to add type annotations for unnameable types

Consider this example:
```rust
const A = || 42;

struct S<T> { t: T }
const B: _ = S { t: || 42 };
```
This currently produces the following output:
```
error: missing type for `const` item
 --> src/lib.rs:1:7
  |
1 | const A = || 42;
  |       ^ help: provide a type for the item: `A: [closure@src/lib.rs:1:11: 1:16]`

error[E0121]: the type placeholder `_` is not allowed within types on item signatures
 --> src/lib.rs:4:10
  |
4 | const B: _ = S { t: || 42 };
  |          ^
  |          |
  |          not allowed in type signatures
  |          help: replace `_` with the correct type: `S<[closure@src/lib.rs:4:21: 4:26]>`

error: aborting due to 2 previous errors
```
However, these suggestions are obviously useless, because the suggested types cannot be written down. With my changes, the suggestion is replaced with a note, because there is no simple fix:
```
error: missing type for `const` item
 --> test.rs:1:7
  |
1 | const A = || 42;
  |       ^
  |
note: however, the inferred type `[closure@test.rs:1:11: 1:16]` cannot be named
 --> test.rs:1:11
  |
1 | const A = || 42;
  |           ^^^^^

error[E0121]: the type placeholder `_` is not allowed within types on item signatures
 --> test.rs:4:10
  |
4 | const B: _ = S { t: || 42 };
  |          ^ not allowed in type signatures
  |
note: however, the inferred type `S<[closure@test.rs:4:21: 4:26]>` cannot be named
 --> test.rs:4:14
  |
4 | const B: _ = S { t: || 42 };
  |              ^^^^^^^^^^^^^^

error: aborting due to 2 previous errors
```
  • Loading branch information
bors committed Jun 12, 2021
2 parents d59b80d + 79dc9a7 commit 60f1a2f
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 14 deletions.
85 changes: 71 additions & 14 deletions compiler/rustc_typeck/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rustc_hir::{HirId, Node};
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};

Expand Down Expand Up @@ -749,6 +749,40 @@ fn infer_placeholder_type(
span: Span,
item_ident: Ident,
) -> Ty<'_> {
// 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),
}
}
}

let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id);

// If this came from a free `const` or `static mut?` item,
Expand All @@ -760,24 +794,47 @@ fn infer_placeholder_type(
// The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
// We are typeck and have the real type, so remove that and suggest the actual type.
err.suggestions.clear();
err.span_suggestion(
span,
"provide a type for the item",
format!("{}: {}", item_ident, ty),
Applicability::MachineApplicable,
)
.emit_unless(ty.references_error());

// Suggesting unnameable types won't help.
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, sugg_ty),
Applicability::MachineApplicable,
);
} else {
err.span_note(
tcx.hir().body(body_id).value.span,
&format!("however, the inferred type `{}` cannot be named", ty.to_string()),
);
}

err.emit_unless(ty.references_error());
}
None => {
let mut diag = bad_placeholder_type(tcx, vec![span]);

if !ty.references_error() {
diag.span_suggestion(
span,
"replace with the correct type",
ty.to_string(),
Applicability::MaybeIncorrect,
);
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",
sugg_ty.to_string(),
Applicability::MaybeIncorrect,
);
} else {
diag.span_note(
tcx.hir().body(body_id).value.span,
&format!("however, the inferred type `{}` cannot be named", ty.to_string()),
);
}
}

diag.emit();
Expand Down
39 changes: 39 additions & 0 deletions src/test/ui/suggestions/unnamable-types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Test that we do not suggest to add type annotations for unnamable types.

#![crate_type="lib"]
#![feature(generators)]

const A = 5;
//~^ ERROR: missing type for `const` item
//~| HELP: provide a type for the item

static B: _ = "abc";
//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures
//~| NOTE: not allowed in type signatures
//~| 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: { let i = 0; move || -> i32 { i } } };
//~^ ERROR: missing type for `const` item
//~| NOTE: however, the inferred type


fn foo() -> i32 { 42 }
const E = foo;
//~^ ERROR: missing type for `const` item
//~| 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 G = || -> i32 { yield 0; return 1; };
//~^ ERROR: missing type for `const` item
//~| NOTE: however, the inferred type
66 changes: 66 additions & 0 deletions src/test/ui/suggestions/unnamable-types.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
error: missing type for `const` item
--> $DIR/unnamable-types.rs:6:7
|
LL | const A = 5;
| ^ help: provide a type for the item: `A: i32`

error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/unnamable-types.rs:10:11
|
LL | static B: _ = "abc";
| ^
| |
| not allowed in type signatures
| help: replace with the correct type: `&str`

error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $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: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:23:7
|
LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
| ^
|
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: { let i = 0; move || -> i32 { i } } };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: missing type for `const` item
--> $DIR/unnamable-types.rs:29:7
|
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 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:37:7
|
LL | const G = || -> i32 { yield 0; return 1; };
| ^
|
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 G = || -> i32 { yield 0; return 1; };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 7 previous errors

For more information about this error, try `rustc --explain E0121`.

0 comments on commit 60f1a2f

Please sign in to comment.