Skip to content
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

Suggest type param when encountering _ in item signatures #67597

Merged
merged 8 commits into from
Dec 31, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
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
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
34 changes: 31 additions & 3 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
//! The main routine here is `ast_ty_to_ty()`; each use is parameterized by an
//! instance of `AstConv`.

use crate::collect::PlaceholderHirTyCollector;
use crate::hir::def::{CtorOf, DefKind, Res};
use crate::hir::def_id::DefId;
use crate::hir::intravisit::Visitor;
use crate::hir::print;
use crate::hir::ptr::P;
use crate::hir::{self, ExprKind, GenericArg, GenericArgs, HirVec};
Expand Down Expand Up @@ -66,6 +68,9 @@ pub trait AstConv<'tcx> {
/// Returns the type to use when a type is omitted.
fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>;

/// Returns `true` if `_` is allowed in type signatures in the current context.
fn allow_ty_infer(&self) -> bool;
estebank marked this conversation as resolved.
Show resolved Hide resolved

/// Returns the const to use when a const is omitted.
fn ct_infer(
&self,
Expand Down Expand Up @@ -2593,7 +2598,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
hir::TyKind::BareFn(ref bf) => {
require_c_abi_if_c_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
tcx.mk_fn_ptr(self.ty_of_fn(bf.unsafety, bf.abi, &bf.decl))
tcx.mk_fn_ptr(self.ty_of_fn(bf.unsafety, bf.abi, &bf.decl, &[], None))
}
hir::TyKind::TraitObject(ref bounds, ref lifetime) => {
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime)
Expand Down Expand Up @@ -2758,14 +2763,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
unsafety: hir::Unsafety,
abi: abi::Abi,
decl: &hir::FnDecl<'_>,
generic_params: &[hir::GenericParam<'_>],
ident_span: Option<Span>,
) -> ty::PolyFnSig<'tcx> {
debug!("ty_of_fn");

let tcx = self.tcx();
let input_tys = decl.inputs.iter().map(|a| self.ty_of_arg(a, None));

// We proactively collect all the infered type params to emit a single error per fn def.
let mut visitor = PlaceholderHirTyCollector::default();
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) => self.ast_ty_to_ty(output),
hir::Return(ref output) => {
visitor.visit_ty(output);
self.ast_ty_to_ty(output)
}
hir::DefaultReturn(..) => tcx.mk_unit(),
};

Expand All @@ -2774,6 +2789,19 @@ 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));

if !self.allow_ty_infer() {
estebank marked this conversation as resolved.
Show resolved Hide resolved
// We always collect the spans for placeholder types when evaluating `fn`s, but we
// only want to emit an error complaining about them if infer types (`_`) are not
// allowed. `allow_ty_infer` gates this behavior.
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
36 changes: 33 additions & 3 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,31 @@ 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> {
assert!(def_id.is_local());
let fallback = move || {
let span = tcx.hir().span(tcx.hir().as_local_hir_id(def_id).unwrap());
tcx.sess.delay_span_bug(span, "diagnostic only typeck table used");
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 All @@ -963,7 +988,7 @@ fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> {
let fcx = if let (Some(header), Some(decl)) = (fn_header, fn_decl) {
let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
AstConv::ty_of_fn(&fcx, header.unsafety, header.abi, decl)
AstConv::ty_of_fn(&fcx, header.unsafety, header.abi, decl, &[], None)
} else {
tcx.fn_sig(def_id)
};
Expand All @@ -990,7 +1015,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 Expand Up @@ -1069,6 +1094,7 @@ fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> {
let ty = fcx.normalize_ty(span, ty);
fcx.require_type_is_sized(ty, span, code);
}

fcx.select_all_obligations_or_error();

if fn_decl.is_some() {
Expand Down Expand Up @@ -2563,6 +2589,10 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
Some(self.next_region_var(v))
}

fn allow_ty_infer(&self) -> bool {
true
}

fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
if let Some(param) = param {
if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() {
Expand Down
Loading