Skip to content

Commit

Permalink
Auto merge of rust-lang#101359 - compiler-errors:cannot-call-trait-ob…
Browse files Browse the repository at this point in the history
…ject-with-unsized-return, r=lcnr

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

Fixes rust-lang#100755

I didn't add a UI test for that one because it's equivalent to the UI test that already exists in the suite.
  • Loading branch information
bors committed Sep 6, 2022
2 parents 6c358c6 + 1254b32 commit 098cf88
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 19 deletions.
17 changes: 17 additions & 0 deletions compiler/rustc_trait_selection/src/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down Expand Up @@ -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>(
Expand Down
25 changes: 22 additions & 3 deletions compiler/rustc_typeck/src/check/callee.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -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;

Expand Down Expand Up @@ -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) {
Expand Down
13 changes: 2 additions & 11 deletions compiler/rustc_typeck/src/check/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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
Expand Down Expand Up @@ -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));
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
}
}
7 changes: 5 additions & 2 deletions compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down Expand Up @@ -1130,7 +1133,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

enum DefIdOrName {
pub enum DefIdOrName {
DefId(DefId),
Name(&'static str),
}
4 changes: 1 addition & 3 deletions src/test/ui/issues/issue-41139.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down

0 comments on commit 098cf88

Please sign in to comment.