Check that built-in callable types validate their output type is Sized
(in new solver)
This commit is contained in:
parent
3eb5c4581a
commit
82b52056fe
5 changed files with 80 additions and 14 deletions
|
@ -96,10 +96,22 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
|
||||||
impl_def_id: DefId,
|
impl_def_id: DefId,
|
||||||
) -> QueryResult<'tcx>;
|
) -> QueryResult<'tcx>;
|
||||||
|
|
||||||
|
// Consider a predicate we know holds (`assumption`) against a goal we're trying to prove.
|
||||||
fn consider_assumption(
|
fn consider_assumption(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
assumption: ty::Predicate<'tcx>,
|
assumption: ty::Predicate<'tcx>,
|
||||||
|
) -> QueryResult<'tcx> {
|
||||||
|
Self::consider_assumption_with_certainty(ecx, goal, assumption, Certainty::Yes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consider a predicate we know holds (`assumption`) against a goal, unifying with
|
||||||
|
// the `assumption_certainty` if it satisfies the goal.
|
||||||
|
fn consider_assumption_with_certainty(
|
||||||
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
|
goal: Goal<'tcx, Self>,
|
||||||
|
assumption: ty::Predicate<'tcx>,
|
||||||
|
assumption_certainty: Certainty,
|
||||||
) -> QueryResult<'tcx>;
|
) -> QueryResult<'tcx>;
|
||||||
|
|
||||||
// A type implements an `auto trait` if its components do as well. These components
|
// A type implements an `auto trait` if its components do as well. These components
|
||||||
|
|
|
@ -260,10 +260,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_assumption(
|
fn consider_assumption_with_certainty(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
assumption: ty::Predicate<'tcx>,
|
assumption: ty::Predicate<'tcx>,
|
||||||
|
assumption_certainty: Certainty,
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
|
if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
|
||||||
&& poly_projection_pred.projection_def_id() == goal.predicate.def_id()
|
&& poly_projection_pred.projection_def_id() == goal.predicate.def_id()
|
||||||
|
@ -280,7 +281,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||||
|
|
||||||
ecx.eq_term_and_make_canonical_response(
|
ecx.eq_term_and_make_canonical_response(
|
||||||
goal,
|
goal,
|
||||||
subst_certainty,
|
subst_certainty.unify_and(assumption_certainty),
|
||||||
assumption_projection_pred.term,
|
assumption_projection_pred.term,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -329,22 +330,29 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
goal_kind: ty::ClosureKind,
|
goal_kind: ty::ClosureKind,
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
|
let tcx = ecx.tcx();
|
||||||
if let Some(tupled_inputs_and_output) =
|
if let Some(tupled_inputs_and_output) =
|
||||||
structural_traits::extract_tupled_inputs_and_output_from_callable(
|
structural_traits::extract_tupled_inputs_and_output_from_callable(
|
||||||
ecx.tcx(),
|
tcx,
|
||||||
goal.predicate.self_ty(),
|
goal.predicate.self_ty(),
|
||||||
goal_kind,
|
goal_kind,
|
||||||
)?
|
)?
|
||||||
{
|
{
|
||||||
|
// A built-in `Fn` trait needs to check that its output is `Sized`
|
||||||
|
// (FIXME: technically we only need to check this if the type is a fn ptr...)
|
||||||
|
let output_is_sized_pred = tupled_inputs_and_output
|
||||||
|
.map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output]));
|
||||||
|
let (_, output_is_sized_certainty) =
|
||||||
|
ecx.evaluate_goal(goal.with(tcx, output_is_sized_pred))?;
|
||||||
|
|
||||||
let pred = tupled_inputs_and_output
|
let pred = tupled_inputs_and_output
|
||||||
.map_bound(|(inputs, output)| ty::ProjectionPredicate {
|
.map_bound(|(inputs, output)| ty::ProjectionPredicate {
|
||||||
projection_ty: ecx
|
projection_ty: tcx
|
||||||
.tcx()
|
|
||||||
.mk_alias_ty(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]),
|
.mk_alias_ty(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]),
|
||||||
term: output.into(),
|
term: output.into(),
|
||||||
})
|
})
|
||||||
.to_predicate(ecx.tcx());
|
.to_predicate(tcx);
|
||||||
Self::consider_assumption(ecx, goal, pred)
|
Self::consider_assumption_with_certainty(ecx, goal, pred, output_is_sized_certainty)
|
||||||
} else {
|
} else {
|
||||||
ecx.make_canonical_response(Certainty::AMBIGUOUS)
|
ecx.make_canonical_response(Certainty::AMBIGUOUS)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ use super::assembly;
|
||||||
use super::infcx_ext::InferCtxtExt;
|
use super::infcx_ext::InferCtxtExt;
|
||||||
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
|
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
use rustc_hir::LangItem;
|
||||||
use rustc_infer::infer::InferCtxt;
|
use rustc_infer::infer::InferCtxt;
|
||||||
use rustc_infer::traits::query::NoSolution;
|
use rustc_infer::traits::query::NoSolution;
|
||||||
use rustc_infer::traits::util::supertraits;
|
use rustc_infer::traits::util::supertraits;
|
||||||
|
@ -61,10 +62,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_assumption(
|
fn consider_assumption_with_certainty(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
assumption: ty::Predicate<'tcx>,
|
assumption: ty::Predicate<'tcx>,
|
||||||
|
assumption_certainty: Certainty,
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
|
if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
|
||||||
&& poly_trait_pred.def_id() == goal.predicate.def_id()
|
&& poly_trait_pred.def_id() == goal.predicate.def_id()
|
||||||
|
@ -78,7 +80,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||||
goal.predicate.trait_ref,
|
goal.predicate.trait_ref,
|
||||||
assumption_trait_pred.trait_ref,
|
assumption_trait_pred.trait_ref,
|
||||||
)?;
|
)?;
|
||||||
ecx.evaluate_all_and_make_canonical_response(nested_goals)
|
ecx.evaluate_all(nested_goals).and_then(|certainty| {
|
||||||
|
ecx.make_canonical_response(certainty.unify_and(assumption_certainty))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
|
@ -173,20 +177,27 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
goal_kind: ty::ClosureKind,
|
goal_kind: ty::ClosureKind,
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
|
let tcx = ecx.tcx();
|
||||||
if let Some(tupled_inputs_and_output) =
|
if let Some(tupled_inputs_and_output) =
|
||||||
structural_traits::extract_tupled_inputs_and_output_from_callable(
|
structural_traits::extract_tupled_inputs_and_output_from_callable(
|
||||||
ecx.tcx(),
|
tcx,
|
||||||
goal.predicate.self_ty(),
|
goal.predicate.self_ty(),
|
||||||
goal_kind,
|
goal_kind,
|
||||||
)?
|
)?
|
||||||
{
|
{
|
||||||
|
// A built-in `Fn` trait needs to check that its output is `Sized`
|
||||||
|
// (FIXME: technically we only need to check this if the type is a fn ptr...)
|
||||||
|
let output_is_sized_pred = tupled_inputs_and_output
|
||||||
|
.map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output]));
|
||||||
|
let (_, output_is_sized_certainty) =
|
||||||
|
ecx.evaluate_goal(goal.with(tcx, output_is_sized_pred))?;
|
||||||
|
|
||||||
let pred = tupled_inputs_and_output
|
let pred = tupled_inputs_and_output
|
||||||
.map_bound(|(inputs, _)| {
|
.map_bound(|(inputs, _)| {
|
||||||
ecx.tcx()
|
tcx.mk_trait_ref(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
|
||||||
.mk_trait_ref(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
|
|
||||||
})
|
})
|
||||||
.to_predicate(ecx.tcx());
|
.to_predicate(tcx);
|
||||||
Self::consider_assumption(ecx, goal, pred)
|
Self::consider_assumption_with_certainty(ecx, goal, pred, output_is_sized_certainty)
|
||||||
} else {
|
} else {
|
||||||
ecx.make_canonical_response(Certainty::AMBIGUOUS)
|
ecx.make_canonical_response(Certainty::AMBIGUOUS)
|
||||||
}
|
}
|
||||||
|
|
17
tests/ui/traits/new-solver/builtin-fn-must-return-sized.rs
Normal file
17
tests/ui/traits/new-solver/builtin-fn-must-return-sized.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// compile-flags: -Ztrait-solver=next
|
||||||
|
|
||||||
|
#![feature(fn_traits)]
|
||||||
|
#![feature(unboxed_closures)]
|
||||||
|
#![feature(tuple_trait)]
|
||||||
|
|
||||||
|
use std::ops::Fn;
|
||||||
|
use std::marker::Tuple;
|
||||||
|
|
||||||
|
fn foo<F: Fn<T>, T: Tuple>(f: Option<F>, t: T) {
|
||||||
|
let y = (f.unwrap()).call(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
foo::<fn() -> str, _>(None, ());
|
||||||
|
//~^ expected a `Fn<_>` closure, found `fn() -> str`
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
error[E0277]: expected a `Fn<_>` closure, found `fn() -> str`
|
||||||
|
--> $DIR/builtin-fn-must-return-sized.rs:15:27
|
||||||
|
|
|
||||||
|
LL | foo::<fn() -> str, _>(None, ());
|
||||||
|
| --------------------- ^^^^ expected an `Fn<_>` closure, found `fn() -> str`
|
||||||
|
| |
|
||||||
|
| required by a bound introduced by this call
|
||||||
|
|
|
||||||
|
= help: the trait `Fn<_>` is not implemented for `fn() -> str`
|
||||||
|
note: required by a bound in `foo`
|
||||||
|
--> $DIR/builtin-fn-must-return-sized.rs:10:11
|
||||||
|
|
|
||||||
|
LL | fn foo<F: Fn<T>, T: Tuple>(f: Option<F>, t: T) {
|
||||||
|
| ^^^^^ required by this bound in `foo`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Add table
Add a link
Reference in a new issue