Skip to content

Commit

Permalink
Auto merge of #67597 - estebank:placeholder-type, r=oli-obk
Browse files Browse the repository at this point in the history
Suggest type param when encountering `_` in item signatures

Fix #27435.
  • Loading branch information
bors committed Dec 31, 2019
2 parents bf2d145 + 261b606 commit 71bb0ff
Show file tree
Hide file tree
Showing 9 changed files with 516 additions and 119 deletions.
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::{self, ExprKind, GenericArg, GenericArgs};
use crate::lint;
Expand Down Expand Up @@ -65,6 +67,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;

/// Returns the const to use when a const is omitted.
fn ct_infer(
&self,
Expand Down Expand Up @@ -2591,7 +2596,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 @@ -2756,14 +2761,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 @@ -2772,6 +2787,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() {
// 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

0 comments on commit 71bb0ff

Please sign in to comment.