Skip to content

Commit 82b5205

Browse files
Check that built-in callable types validate their output type is Sized (in new solver)
1 parent 3eb5c45 commit 82b5205

File tree

5 files changed

+80
-14
lines changed

5 files changed

+80
-14
lines changed

compiler/rustc_trait_selection/src/solve/assembly.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,22 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
9696
impl_def_id: DefId,
9797
) -> QueryResult<'tcx>;
9898

99+
// Consider a predicate we know holds (`assumption`) against a goal we're trying to prove.
99100
fn consider_assumption(
100101
ecx: &mut EvalCtxt<'_, 'tcx>,
101102
goal: Goal<'tcx, Self>,
102103
assumption: ty::Predicate<'tcx>,
104+
) -> QueryResult<'tcx> {
105+
Self::consider_assumption_with_certainty(ecx, goal, assumption, Certainty::Yes)
106+
}
107+
108+
// Consider a predicate we know holds (`assumption`) against a goal, unifying with
109+
// the `assumption_certainty` if it satisfies the goal.
110+
fn consider_assumption_with_certainty(
111+
ecx: &mut EvalCtxt<'_, 'tcx>,
112+
goal: Goal<'tcx, Self>,
113+
assumption: ty::Predicate<'tcx>,
114+
assumption_certainty: Certainty,
103115
) -> QueryResult<'tcx>;
104116

105117
// A type implements an `auto trait` if its components do as well. These components

compiler/rustc_trait_selection/src/solve/project_goals.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -260,10 +260,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
260260
})
261261
}
262262

263-
fn consider_assumption(
263+
fn consider_assumption_with_certainty(
264264
ecx: &mut EvalCtxt<'_, 'tcx>,
265265
goal: Goal<'tcx, Self>,
266266
assumption: ty::Predicate<'tcx>,
267+
assumption_certainty: Certainty,
267268
) -> QueryResult<'tcx> {
268269
if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
269270
&& poly_projection_pred.projection_def_id() == goal.predicate.def_id()
@@ -280,7 +281,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
280281

281282
ecx.eq_term_and_make_canonical_response(
282283
goal,
283-
subst_certainty,
284+
subst_certainty.unify_and(assumption_certainty),
284285
assumption_projection_pred.term,
285286
)
286287
})
@@ -329,22 +330,29 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
329330
goal: Goal<'tcx, Self>,
330331
goal_kind: ty::ClosureKind,
331332
) -> QueryResult<'tcx> {
333+
let tcx = ecx.tcx();
332334
if let Some(tupled_inputs_and_output) =
333335
structural_traits::extract_tupled_inputs_and_output_from_callable(
334-
ecx.tcx(),
336+
tcx,
335337
goal.predicate.self_ty(),
336338
goal_kind,
337339
)?
338340
{
341+
// A built-in `Fn` trait needs to check that its output is `Sized`
342+
// (FIXME: technically we only need to check this if the type is a fn ptr...)
343+
let output_is_sized_pred = tupled_inputs_and_output
344+
.map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output]));
345+
let (_, output_is_sized_certainty) =
346+
ecx.evaluate_goal(goal.with(tcx, output_is_sized_pred))?;
347+
339348
let pred = tupled_inputs_and_output
340349
.map_bound(|(inputs, output)| ty::ProjectionPredicate {
341-
projection_ty: ecx
342-
.tcx()
350+
projection_ty: tcx
343351
.mk_alias_ty(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]),
344352
term: output.into(),
345353
})
346-
.to_predicate(ecx.tcx());
347-
Self::consider_assumption(ecx, goal, pred)
354+
.to_predicate(tcx);
355+
Self::consider_assumption_with_certainty(ecx, goal, pred, output_is_sized_certainty)
348356
} else {
349357
ecx.make_canonical_response(Certainty::AMBIGUOUS)
350358
}

compiler/rustc_trait_selection/src/solve/trait_goals.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use super::assembly;
66
use super::infcx_ext::InferCtxtExt;
77
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
88
use rustc_hir::def_id::DefId;
9+
use rustc_hir::LangItem;
910
use rustc_infer::infer::InferCtxt;
1011
use rustc_infer::traits::query::NoSolution;
1112
use rustc_infer::traits::util::supertraits;
@@ -61,10 +62,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
6162
})
6263
}
6364

64-
fn consider_assumption(
65+
fn consider_assumption_with_certainty(
6566
ecx: &mut EvalCtxt<'_, 'tcx>,
6667
goal: Goal<'tcx, Self>,
6768
assumption: ty::Predicate<'tcx>,
69+
assumption_certainty: Certainty,
6870
) -> QueryResult<'tcx> {
6971
if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
7072
&& poly_trait_pred.def_id() == goal.predicate.def_id()
@@ -78,7 +80,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
7880
goal.predicate.trait_ref,
7981
assumption_trait_pred.trait_ref,
8082
)?;
81-
ecx.evaluate_all_and_make_canonical_response(nested_goals)
83+
ecx.evaluate_all(nested_goals).and_then(|certainty| {
84+
ecx.make_canonical_response(certainty.unify_and(assumption_certainty))
85+
})
8286
})
8387
} else {
8488
Err(NoSolution)
@@ -173,20 +177,27 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
173177
goal: Goal<'tcx, Self>,
174178
goal_kind: ty::ClosureKind,
175179
) -> QueryResult<'tcx> {
180+
let tcx = ecx.tcx();
176181
if let Some(tupled_inputs_and_output) =
177182
structural_traits::extract_tupled_inputs_and_output_from_callable(
178-
ecx.tcx(),
183+
tcx,
179184
goal.predicate.self_ty(),
180185
goal_kind,
181186
)?
182187
{
188+
// A built-in `Fn` trait needs to check that its output is `Sized`
189+
// (FIXME: technically we only need to check this if the type is a fn ptr...)
190+
let output_is_sized_pred = tupled_inputs_and_output
191+
.map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output]));
192+
let (_, output_is_sized_certainty) =
193+
ecx.evaluate_goal(goal.with(tcx, output_is_sized_pred))?;
194+
183195
let pred = tupled_inputs_and_output
184196
.map_bound(|(inputs, _)| {
185-
ecx.tcx()
186-
.mk_trait_ref(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
197+
tcx.mk_trait_ref(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
187198
})
188-
.to_predicate(ecx.tcx());
189-
Self::consider_assumption(ecx, goal, pred)
199+
.to_predicate(tcx);
200+
Self::consider_assumption_with_certainty(ecx, goal, pred, output_is_sized_certainty)
190201
} else {
191202
ecx.make_canonical_response(Certainty::AMBIGUOUS)
192203
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// compile-flags: -Ztrait-solver=next
2+
3+
#![feature(fn_traits)]
4+
#![feature(unboxed_closures)]
5+
#![feature(tuple_trait)]
6+
7+
use std::ops::Fn;
8+
use std::marker::Tuple;
9+
10+
fn foo<F: Fn<T>, T: Tuple>(f: Option<F>, t: T) {
11+
let y = (f.unwrap()).call(t);
12+
}
13+
14+
fn main() {
15+
foo::<fn() -> str, _>(None, ());
16+
//~^ expected a `Fn<_>` closure, found `fn() -> str`
17+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0277]: expected a `Fn<_>` closure, found `fn() -> str`
2+
--> $DIR/builtin-fn-must-return-sized.rs:15:27
3+
|
4+
LL | foo::<fn() -> str, _>(None, ());
5+
| --------------------- ^^^^ expected an `Fn<_>` closure, found `fn() -> str`
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
= help: the trait `Fn<_>` is not implemented for `fn() -> str`
10+
note: required by a bound in `foo`
11+
--> $DIR/builtin-fn-must-return-sized.rs:10:11
12+
|
13+
LL | fn foo<F: Fn<T>, T: Tuple>(f: Option<F>, t: T) {
14+
| ^^^^^ required by this bound in `foo`
15+
16+
error: aborting due to previous error
17+
18+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)