/// See the test case `test/run-pass/coerce-expect-unsized.rs` and #20169
/// for examples of where this comes up,.
fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> {
- match fcx.tcx.struct_tail(ty).sty {
+ match fcx.tcx.struct_tail_without_normalization(ty).sty {
ty::Slice(_) | ty::Str | ty::Dynamic(..) => {
ExpectRvalueLikeUnsized(ty)
}
tcx.calculate_dtor(def_id, &mut dropck::check_drop_impl)
}
-/// If this `DefId` is a "primary tables entry", returns `Some((body_id, decl))`
-/// with information about it's body-id and fn-decl (if any). Otherwise,
+/// If this `DefId` is a "primary tables entry", returns
+/// `Some((body_id, header, decl))` with information about
+/// it's body-id, fn-header and fn-decl (if any). Otherwise,
/// returns `None`.
///
-/// If this function returns "some", then `typeck_tables(def_id)` will
+/// If this function returns `Some`, then `typeck_tables(def_id)` will
/// succeed; if it returns `None`, then `typeck_tables(def_id)` may or
/// may not succeed. In some cases where this function returns `None`
/// (notably closures), `typeck_tables(def_id)` would wind up
fn primary_body_of(
tcx: TyCtxt<'_>,
id: hir::HirId,
-) -> Option<(hir::BodyId, Option<&hir::FnDecl>)> {
+) -> Option<(hir::BodyId, Option<&hir::Ty>, Option<&hir::FnHeader>, Option<&hir::FnDecl>)> {
match tcx.hir().get(id) {
Node::Item(item) => {
match item.node {
- hir::ItemKind::Const(_, body) |
- hir::ItemKind::Static(_, _, body) =>
- Some((body, None)),
- hir::ItemKind::Fn(ref decl, .., body) =>
- Some((body, Some(decl))),
+ hir::ItemKind::Const(ref ty, body) |
+ hir::ItemKind::Static(ref ty, _, body) =>
+ Some((body, Some(ty), None, None)),
+ hir::ItemKind::Fn(ref decl, ref header, .., body) =>
+ Some((body, None, Some(header), Some(decl))),
_ =>
None,
}
}
Node::TraitItem(item) => {
match item.node {
- hir::TraitItemKind::Const(_, Some(body)) =>
- Some((body, None)),
+ hir::TraitItemKind::Const(ref ty, Some(body)) =>
+ Some((body, Some(ty), None, None)),
hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) =>
- Some((body, Some(&sig.decl))),
+ Some((body, None, Some(&sig.header), Some(&sig.decl))),
_ =>
None,
}
}
Node::ImplItem(item) => {
match item.node {
- hir::ImplItemKind::Const(_, body) =>
- Some((body, None)),
+ hir::ImplItemKind::Const(ref ty, body) =>
+ Some((body, Some(ty), None, None)),
hir::ImplItemKind::Method(ref sig, body) =>
- Some((body, Some(&sig.decl))),
+ Some((body, None, Some(&sig.header), Some(&sig.decl))),
_ =>
None,
}
}
- Node::AnonConst(constant) => Some((constant.body, None)),
+ Node::AnonConst(constant) => Some((constant.body, None, None, None)),
_ => None,
}
}
let span = tcx.hir().span(id);
// Figure out what primary body this item has.
- let (body_id, fn_decl) = primary_body_of(tcx, id).unwrap_or_else(|| {
- span_bug!(span, "can't type-check body of {:?}", def_id);
- });
+ let (body_id, body_ty, fn_header, fn_decl) = primary_body_of(tcx, id)
+ .unwrap_or_else(|| {
+ span_bug!(span, "can't type-check body of {:?}", def_id);
+ });
let body = tcx.hir().body(body_id);
let tables = Inherited::build(tcx, def_id).enter(|inh| {
let param_env = tcx.param_env(def_id);
- let fcx = if let Some(decl) = fn_decl {
- let fn_sig = tcx.fn_sig(def_id);
+ 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)
+ } else {
+ tcx.fn_sig(def_id)
+ };
check_abi(tcx, span, fn_sig.abi());
fcx
} else {
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
- let expected_type = tcx.type_of(def_id);
+ let expected_type = body_ty.and_then(|ty| match ty.node {
+ hir::TyKind::Infer => Some(AstConv::ast_ty_to_ty(&fcx, ty)),
+ _ => None
+ }).unwrap_or_else(|| tcx.type_of(def_id));
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);
check_packed(tcx, span, def_id);
}
-fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>, span: Span) {
+fn check_opaque<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+ span: Span,
+ origin: &hir::ExistTyOrigin
+) {
if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id, substs) {
- let mut err = struct_span_err!(
- tcx.sess, span, E0720,
- "opaque type expands to a recursive type",
- );
- err.span_label(span, "expands to self-referential type");
- if let ty::Opaque(..) = partially_expanded_type.sty {
- err.note("type resolves to itself");
+ if let hir::ExistTyOrigin::AsyncFn = origin {
+ struct_span_err!(
+ tcx.sess, span, E0733,
+ "recursion in an `async fn` requires boxing",
+ )
+ .span_label(span, "an `async fn` cannot invoke itself directly")
+ .note("a recursive `async fn` must be rewritten to return a boxed future.")
+ .emit();
} else {
- err.note(&format!("expanded type is `{}`", partially_expanded_type));
+ let mut err = struct_span_err!(
+ tcx.sess, span, E0720,
+ "opaque type expands to a recursive type",
+ );
+ err.span_label(span, "expands to a recursive type");
+ if let ty::Opaque(..) = partially_expanded_type.sty {
+ err.note("type resolves to itself");
+ } else {
+ err.note(&format!("expanded type is `{}`", partially_expanded_type));
+ }
+ err.emit();
}
- err.emit();
}
}
hir::ItemKind::Union(..) => {
check_union(tcx, it.hir_id, it.span);
}
- hir::ItemKind::Existential(..) => {
+ hir::ItemKind::Existential(hir::ExistTy{origin, ..}) => {
let def_id = tcx.hir().local_def_id(it.hir_id);
let substs = InternalSubsts::identity_for_item(tcx, def_id);
- check_opaque(tcx, def_id, substs, it.span);
+ check_opaque(tcx, def_id, substs, it.span, &origin);
}
hir::ItemKind::Ty(..) => {
let def_id = tcx.hir().local_def_id(it.hir_id);
return
}
- // For the wasm32 target statics with #[link_section] are placed into custom
+ // For the wasm32 target statics with `#[link_section]` are placed into custom
// sections of the final output file, but this isn't link custom sections of
// other executable formats. Namely we can only embed a list of bytes,
// nothing with pointers to anything else or relocations. If any relocation
// show up, reject them here.
+ // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
+ // the consumer's responsibility to ensure all bytes that have been read
+ // have defined values.
let instance = ty::Instance::mono(tcx, id);
let cid = GlobalId {
instance,