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 @@ fn type_is_copy_modulo_regions(
span: Span, span: Span,
) -> bool; ) -> 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>( fn partially_normalize_associated_types_in<T>(
&self, &self,
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
@ -74,6 +81,16 @@ fn type_is_copy_modulo_regions(
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span) 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 /// Normalizes associated types in `value`, potentially returning
/// new obligations that must further be processed. /// new obligations that must further be processed.
fn partially_normalize_associated_types_in<T>( fn partially_normalize_associated_types_in<T>(

View File

@ -1,5 +1,5 @@
use super::method::MethodCallee; use super::method::MethodCallee;
use super::{Expectation, FnCtxt, TupleArgumentsFlag}; use super::{DefIdOrName, Expectation, FnCtxt, TupleArgumentsFlag};
use crate::type_error_struct; use crate::type_error_struct;
use rustc_errors::{struct_span_err, Applicability, Diagnostic}; use rustc_errors::{struct_span_err, Applicability, Diagnostic};
@ -24,7 +24,8 @@
use rustc_span::Span; use rustc_span::Span;
use rustc_target::spec::abi; use rustc_target::spec::abi;
use rustc_trait_selection::autoderef::Autoderef; 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; use std::iter;
@ -471,7 +472,25 @@ fn confirm_builtin_call(
}; };
if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) { 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) { if let Some(span) = self.tcx.hir().res_span(def) {

View File

@ -35,7 +35,6 @@
use hir::def_id::LOCAL_CRATE; use hir::def_id::LOCAL_CRATE;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_middle::mir::Mutability; use rustc_middle::mir::Mutability;
use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::cast::{CastKind, CastTy}; use rustc_middle::ty::cast::{CastKind, CastTy};
@ -47,7 +46,6 @@
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::Span; use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::error_reporting::report_object_safety_error; 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 /// Reifies a cast check to be checked once we have full type information for
@ -97,7 +95,7 @@ fn pointer_kind(
return Err(reported); 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)); return Ok(Some(PointerKind::Thin));
} }
@ -705,7 +703,7 @@ pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty); 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.cast_ty.has_infer_types()
{ {
self.report_cast_to_unsized_type(fcx); self.report_cast_to_unsized_type(fcx);
@ -1084,10 +1082,3 @@ fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, '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 @@ pub(crate) fn suggest_fn_call(
false 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, &self,
expr: &Expr<'_>, expr: &Expr<'_>,
found: Ty<'tcx>, found: Ty<'tcx>,
@ -1130,7 +1133,7 @@ pub(crate) fn consider_removing_semicolon(
} }
} }
enum DefIdOrName { pub enum DefIdOrName {
DefId(DefId), DefId(DefId),
Name(&'static str), 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)` | -------------------------------------------------- `get_function` defined here returns `&dyn Fn() -> (dyn Trait + 'static)`
... ...
LL | let t: &dyn Trait = &get_function()(); LL | let t: &dyn Trait = &get_function()();
| ^^^^^^^^^^^^^^-- | ^^^^^^^^^^^^^^ this trait object returns an unsized value `(dyn Trait + 'static)`, so it cannot be called
| |
| call expression requires function
error: aborting due to previous error error: aborting due to previous error