8000 Suggest type param when encountering `_` in item signatures by estebank · Pull Request #67597 · rust-lang/rust · GitHub
[go: up one dir, main page]

Skip to content

Suggest type param when encountering _ in item signatures #67597

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Dec 31, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
clean up logic
  • Loading branch information
estebank committed Dec 30, 2019
commit cfa0b07c8d7e4c63e01549b1b026bb7494a7c4f1
10 changes: 10 additions & 0 deletions src/librustc/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,16 @@ rustc_queries! {
typeck_tables.map(|tables| &*tcx.arena.alloc(tables))
}
}
query diagnostic_only_typeck_tables_of(key: DefId) -> &'tcx ty::TypeckTables<'tcx> {
cache_on_disk_if { key.is_local() }
load_cached(tcx, id) {
let typeck_tables: Option<ty::TypeckTables<'tcx>> = tcx
.queries.on_disk_cache
.try_load_query_result(tcx, id);

typeck_tables.map(|tables| &*tcx.arena.alloc(tables))
}
}
}

Other {
Expand Down
45 changes: 15 additions & 30 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2770,30 +2770,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let tcx = self.tcx();

// We proactively collect all the infered type params to emit a single error per fn def.
let mut placeholder_types = vec![];
let mut output_placeholder_types = vec![];

let input_tys = decl.inputs.iter().map(|a| {
let mut visitor = PlaceholderHirTyCollector::new();
visitor.visit_ty(&a);
if visitor.0.is_empty() || self.allow_ty_infer() {
self.ty_of_arg(a, None)
} else {
placeholder_types.extend(visitor.0);
tcx.types.err
}
});
let mut visitor = PlaceholderHirTyCollector::new();
for ty in &decl.inputs {
visitor.visit_ty(ty);
}
let input_tys = decl.inputs.iter().map(|a| self.ty_of_arg(a, None));
let output_ty = match decl.output {
hir::Return(ref output) => {
let mut visitor = PlaceholderHirTyCollector::new();
visitor.visit_ty(output);
let is_infer = if let hir::TyKind::Infer = output.kind { true } else { false };
if (is_infer || !visitor.0.is_empty()) && !self.allow_ty_infer() {
output_placeholder_types.extend(visitor.0);
tcx.types.err
} else {
self.ast_ty_to_ty(output)
}
self.ast_ty_to_ty(output)
}
hir::DefaultReturn(..) => tcx.mk_unit(),
};
Expand All @@ -2803,15 +2788,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let bare_fn_ty =
ty::Binder::bind(tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, unsafety, abi));

placeholder_types.extend(output_placeholder_types);

crate::collect::placeholder_type_error(
tcx,
ident_span.unwrap_or(DUMMY_SP),
generic_params,
placeholder_types,
ident_span.is_some(),
);
if !self.allow_ty_infer() {
crate::collect::placeholder_type_error(
tcx,
ident_span.unwrap_or(DUMMY_SP),
generic_params,
visitor.0,
ident_span.is_some(),
);
}

// Find any late-bound regions declared in return type that do
// not appear in the arguments. These are not well-formed.
Expand Down
24 changes: 22 additions & 2 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,7 @@ pub fn provide(providers: &mut Providers<'_>) {
*providers = Providers {
typeck_item_bodies,
typeck_tables_of,
diagnostic_only_typeck_tables_of,
has_typeck_tables,
adt_destructor,
used_trait_imports,
Expand Down Expand Up @@ -941,7 +942,26 @@ where
val.fold_with(&mut FixupFolder { tcx })
}

fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> {
fn typeck_tables_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &ty::TypeckTables<'tcx> {
let fallback = move || tcx.type_of(def_id);
typeck_tables_of_with_fallback(tcx, def_id, fallback)
}

/// Used only to get `TypeckTables` for type inference during error recovery.
/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
fn diagnostic_only_typeck_tables_of<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
) -> &ty::TypeckTables<'tcx> {
let fallback = move || tcx.types.err;
typeck_tables_of_with_fallback(tcx, def_id, fallback)
}

fn typeck_tables_of_with_fallback<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
fallback: impl Fn() -> Ty<'tcx> + 'tcx,
) -> &'tcx ty::TypeckTables<'tcx> {
// Closures' tables come from their outermost function,
// as they are part of the same "inference environment".
let outer_def_id = tcx.closure_base_def_id(def_id);
Expand Down Expand Up @@ -990,7 +1010,7 @@ fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> {
hir::TyKind::Infer => Some(AstConv::ast_ty_to_ty(&fcx, ty)),
_ => None,
})
.unwrap_or_else(|| tcx.type_of(def_id));
.unwrap_or_else(fallback);
let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type);
fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);

Expand Down
68 changes: 25 additions & 43 deletions src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,15 +160,7 @@ crate fn placeholder_type_error(
format!(", {}", type_name),
));
}
let mut err = struct_span_err!(
tcx.sess,
placeholder_types.clone(),
E0121,
"the type placeholder `_` is not allowed within types on item signatures",
);
for span in &placeholder_types {
err.span_label(*span, "not allowed in type signatures");
}
let mut err = bad_placeholder_type(tcx, placeholder_types);
if suggest {
err.multipart_suggestion(
"use type parameters instead",
Expand All @@ -184,14 +176,8 @@ fn reject_placeholder_type_signatures_in_item(tcx: TyCtxt<'tcx>, item: &'tcx hir
hir::ItemKind::Union(_, generics)
| hir::ItemKind::Enum(_, generics)
| hir::ItemKind::Struct(_, generics) => (&generics.params[..], true),
hir::ItemKind::Static(ty, ..) => {
if let hir::TyKind::Infer = ty.kind {
return; // We handle it elsewhere to attempt to suggest an appropriate type.
} else {
(&[][..], false)
}
}
hir::ItemKind::TyAlias(_, generics) => (&generics.params[..], false),
// hir::ItemKind::Static(ty, ..) => {
// hir::ItemKind::Fn(..) |
// hir::ItemKind::Const(..) => {} // We handle these elsewhere to suggest appropriate type.
_ => return,
Expand Down Expand Up @@ -255,15 +241,21 @@ impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
///////////////////////////////////////////////////////////////////////////
// Utility types and common code for the above passes.

fn bad_placeholder_type(tcx: TyCtxt<'tcx>, span: Span) -> errors::DiagnosticBuilder<'tcx> {
let mut diag = struct_span_err!(
fn bad_placeholder_type(
tcx: TyCtxt<'tcx>,
mut spans: Vec<Span>,
) -> errors::DiagnosticBuilder<'tcx> {
spans.sort();
let mut err = struct_span_err!(
tcx.sess,
span,
spans.clone(),
E0121,
"the type placeholder `_` is not allowed within types on item signatures",
);
diag.span_label(span, "not allowed in type signatures");
diag
for span in spans {
err.span_label(span, "not allowed in type signatures");
}
err
}

impl ItemCtxt<'tcx> {
Expand Down Expand Up @@ -298,7 +290,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
}

fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
self.tcx().sess.delay_span_bug(span, "bad placeholder type, but no error was emitted");
self.tcx().sess.delay_span_bug(span, "bad placeholder type");
self.tcx().types.err
}

Expand All @@ -308,7 +300,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
_: Option<&ty::GenericParamDef>,
span: Span,
) -> &'tcx Const<'tcx> {
bad_placeholder_type(self.tcx(), span).emit();
bad_placeholder_type(self.tcx(), vec![span]).emit();

self.tcx().consts.err
}
Expand Down Expand Up @@ -1233,7 +1225,7 @@ fn infer_placeholder_type(
span: Span,
item_ident: Ident,
) -> Ty<'_> {
let ty = tcx.typeck_tables_of(def_id).node_type(body_id.hir_id);
let ty = tcx.diagnostic_only_typeck_tables_of(def_id).node_type(body_id.hir_id);

// If this came from a free `const` or `static mut?` item,
// then the user may have written e.g. `const A = 42;`.
Expand All @@ -1253,7 +1245,7 @@ fn infer_placeholder_type(
.emit();
}
None => {
let mut diag = bad_placeholder_type(tcx, span);
let mut diag = bad_placeholder_type(tcx, vec![span]);
if ty != tcx.types.err {
diag.span_suggestion(
span,
Expand Down Expand Up @@ -1284,12 +1276,8 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
}
TraitItemKind::Const(ref ty, body_id) => body_id
.and_then(|body_id| {
if let hir::TyKind::Infer = ty.kind {
if is_infer_ty(ty) {
Some(infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident))
} else if is_infer_ty(ty) {
// Infering this would cause a cycle error.
tcx.sess.delay_span_bug(ty.span, "`_` placeholder but no error emitted");
Some(tcx.types.err)
} else {
None
}
Expand All @@ -1307,12 +1295,8 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
tcx.mk_fn_def(def_id, substs)
}
ImplItemKind::Const(ref ty, body_id) => {
if let hir::TyKind::Infer = ty.kind {
if is_infer_ty(ty) {
infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)
} else if is_infer_ty(ty) {
// Infering this would cause a cycle error.
tcx.sess.delay_span_bug(ty.span, "`_` placeholder but no error emitted");
tcx.types.err
} else {
icx.to_ty(ty)
}
Expand All @@ -1336,12 +1320,8 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
Node::Item(item) => {
match item.kind {
ItemKind::Static(ref ty, .., body_id) | ItemKind::Const(ref ty, body_id) => {
if let hir::TyKind::Infer = ty.kind {
if is_infer_ty(ty) {
infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)
} else if is_infer_ty(ty) {
// Infering this would cause a cycle error.
tcx.sess.delay_span_bug(ty.span, "`_` placeholder but no error emitted");
tcx.types.err
} else {
icx.to_ty(ty)
}
Expand Down Expand Up @@ -1818,7 +1798,7 @@ crate fn is_infer_ty(ty: &hir::Ty<'_>) -> bool {
hir::TyKind::Slice(ty) | hir::TyKind::Array(ty, _) => is_infer_ty(ty),
hir::TyKind::Tup(tys)
if !tys.is_empty()
&& tys.iter().all(|ty| match ty.kind {
&& tys.iter().any(|ty| match ty.kind {
hir::TyKind::Infer => true,
_ => false,
}) =>
Expand Down Expand Up @@ -1858,12 +1838,14 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
match get_infer_ret_ty(&sig.decl.output) {
Some(ty) => {
let fn_sig = tcx.typeck_tables_of(def_id).liberated_fn_sigs()[hir_id];
let mut diag = bad_placeholder_type(tcx, ty.span);
let mut visitor = PlaceholderHirTyCollector::new();
visitor.visit_ty(ty);
let mut diag = bad_placeholder_type(tcx, visitor.0);
let ret_ty = fn_sig.output();
if ret_ty != tcx.types.err {
diag.span_suggestion(
ty.span,
"replace this with the correct return type",
"replace with the correct return type",
ret_ty.to_string(),
Applicability::MaybeIncorrect,
);
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/error-codes/E0121.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ LL | fn foo() -> _ { 5 }
| ^
| |
| not allowed in type signatures
| help: replace this with the correct return type: `i32`
| help: replace with the correct return type: `i32`

error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/E0121.rs:3:13
Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/typeck/typeck_type_placeholder_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ fn test7(x: _) { let _x: usize = x; }

fn test8(_f: fn() -> _) { }
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
//~| ERROR the type placeholder `_` is not allowed within types on item signatures

struct Test9;

Expand Down Expand Up @@ -79,6 +80,7 @@ pub fn main() {

fn fn_test8(_f: fn() -> _) { }
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
//~| ERROR the type placeholder `_` is not allowed within types on item signatures

struct FnTest9;

Expand Down Expand Up @@ -128,4 +130,4 @@ trait T {
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
fn assoc_fn_test3() -> _;
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
}
}
Loading
0