Point out when a callable is not actually callable because its return is not sized

This commit is contained in:
Michael Goulet 2022-09-03 03:46:41 +00:00
parent b44197abb0
commit 1254b32479
5 changed files with 47 additions and 19 deletions

View File

@ -24,6 +24,13 @@ pub trait InferCtxtExt<'tcx> {
span: Span,
) -> bool;
fn type_is_sized_modulo_regions(
&self,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
span: Span,
) -> bool;
fn partially_normalize_associated_types_in<T>(
&self,
cause: ObligationCause<'tcx>,
@ -74,6 +81,16 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span)
}
fn type_is_sized_modulo_regions(
&self,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
span: Span,
) -> bool {
let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item, span)
}
/// Normalizes associated types in `value`, potentially returning
/// new obligations that must further be processed.
fn partially_normalize_associated_types_in<T>(

View File

@ -1,5 +1,5 @@
use super::method::MethodCallee;
use super::{Expectation, FnCtxt, TupleArgumentsFlag};
use super::{DefIdOrName, Expectation, FnCtxt, TupleArgumentsFlag};
use crate::type_error_struct;
use rustc_errors::{struct_span_err, Applicability, Diagnostic};
@ -24,7 +24,8 @@ use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_target::spec::abi;
use rustc_trait_selection::autoderef::Autoderef;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use std::iter;
@ -471,7 +472,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
err.span_label(call_expr.span, "call expression requires function");
if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_expr, callee_ty)
&& !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
{
let descr = match maybe_def {
DefIdOrName::DefId(def_id) => self.tcx.def_kind(def_id).descr(def_id),
DefIdOrName::Name(name) => name,
};
err.span_label(
callee_expr.span,
format!("this {descr} returns an unsized value `{output_ty}`, so it cannot be called")
);
if let DefIdOrName::DefId(def_id) = maybe_def
&& let Some(def_span) = self.tcx.hir().span_if_local(def_id)
{
err.span_label(def_span, "the callable type is defined here");
}
} else {
err.span_label(call_expr.span, "call expression requires function");
}
}
if let Some(span) = self.tcx.hir().res_span(def) {

View File

@ -35,7 +35,6 @@ use crate::type_error_struct;
use hir::def_id::LOCAL_CRATE;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_middle::mir::Mutability;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::cast::{CastKind, CastTy};
@ -47,7 +46,6 @@ use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
/// Reifies a cast check to be checked once we have full type information for
@ -97,7 +95,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return Err(reported);
}
if self.type_is_known_to_be_sized_modulo_regions(t, span) {
if self.type_is_sized_modulo_regions(self.param_env, t, span) {
return Ok(Some(PointerKind::Thin));
}
@ -705,7 +703,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty);
if !fcx.type_is_known_to_be_sized_modulo_regions(self.cast_ty, self.span)
if !fcx.type_is_sized_modulo_regions(fcx.param_env, self.cast_ty, self.span)
&& !self.cast_ty.has_infer_types()
{
self.report_cast_to_unsized_type(fcx);
@ -1084,10 +1082,3 @@ impl<'a, 'tcx> CastCheck<'tcx> {
);
}
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn type_is_known_to_be_sized_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool {
let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
traits::type_known_to_meet_bound_modulo_regions(self, self.param_env, ty, lang_item, span)
}
}

View File

@ -144,7 +144,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
false
}
fn extract_callable_info(
/// Extracts information about a callable type for diagnostics. This is a
/// heuristic -- it doesn't necessarily mean that a type is always callable,
/// because the callable type must also be well-formed to be called.
pub(in super::super) fn extract_callable_info(
&self,
expr: &Expr<'_>,
found: Ty<'tcx>,
@ -1130,7 +1133,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
enum DefIdOrName {
pub enum DefIdOrName {
DefId(DefId),
Name(&'static str),
}

View File

@ -5,9 +5,7 @@ LL | fn get_function<'a>() -> &'a dyn Fn() -> dyn Trait {
| -------------------------------------------------- `get_function` defined here returns `&dyn Fn() -> (dyn Trait + 'static)`
...
LL | let t: &dyn Trait = &get_function()();
| ^^^^^^^^^^^^^^--
| |
| call expression requires function
| ^^^^^^^^^^^^^^ this trait object returns an unsized value `(dyn Trait + 'static)`, so it cannot be called
error: aborting due to previous error