Skip to content

Commit 95e9f68

Browse files
authored
Rollup merge of #110671 - compiler-errors:polarity, r=lcnr
Consider polarity in new solver It's kinda ugly to have a polarity check in all of the builtin impls -- I guess I could consider the polarity at the top of assemble-builtin but that would require adding a polarity fn to `GoalKind`... :shrug: putting this up just so i dont forget, since it's needed to bootstrap core during coherence (this alone does not allow core to bootstrap though, additional work is needed!) r? ``@lcnr``
2 parents 94dfb3b + bb2cb89 commit 95e9f68

File tree

4 files changed

+126
-3
lines changed

4 files changed

+126
-3
lines changed

compiler/rustc_middle/src/ty/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,11 @@ impl<'tcx> PolyTraitPredicate<'tcx> {
861861
pub fn is_const_if_const(self) -> bool {
862862
self.skip_binder().is_const_if_const()
863863
}
864+
865+
#[inline]
866+
pub fn polarity(self) -> ImplPolarity {
867+
self.skip_binder().polarity
868+
}
864869
}
865870

866871
/// `A: B`

compiler/rustc_trait_selection/src/solve/trait_goals.rs

+69-3
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
8686
) -> QueryResult<'tcx> {
8787
if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
8888
&& poly_trait_pred.def_id() == goal.predicate.def_id()
89+
&& poly_trait_pred.polarity() == goal.predicate.polarity
8990
{
90-
// FIXME: Constness and polarity
91+
// FIXME: Constness
9192
ecx.probe(|ecx| {
9293
let assumption_trait_pred =
9394
ecx.instantiate_binder_with_infer(poly_trait_pred);
@@ -111,6 +112,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
111112
) -> QueryResult<'tcx> {
112113
if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
113114
&& poly_trait_pred.def_id() == goal.predicate.def_id()
115+
&& poly_trait_pred.polarity() == goal.predicate.polarity
114116
{
115117
// FIXME: Constness and polarity
116118
ecx.probe(|ecx| {
@@ -147,6 +149,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
147149
ecx: &mut EvalCtxt<'_, 'tcx>,
148150
goal: Goal<'tcx, Self>,
149151
) -> QueryResult<'tcx> {
152+
if goal.predicate.polarity != ty::ImplPolarity::Positive {
153+
return Err(NoSolution);
154+
}
155+
150156
if let Some(result) = ecx.disqualify_auto_trait_candidate_due_to_possible_impl(goal) {
151157
return result;
152158
}
@@ -161,6 +167,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
161167
ecx: &mut EvalCtxt<'_, 'tcx>,
162168
goal: Goal<'tcx, Self>,
163169
) -> QueryResult<'tcx> {
170+
if goal.predicate.polarity != ty::ImplPolarity::Positive {
171+
return Err(NoSolution);
172+
}
173+
164174
let tcx = ecx.tcx();
165175

166176
ecx.probe(|ecx| {
@@ -176,6 +186,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
176186
ecx: &mut EvalCtxt<'_, 'tcx>,
177187
goal: Goal<'tcx, Self>,
178188
) -> QueryResult<'tcx> {
189+
if goal.predicate.polarity != ty::ImplPolarity::Positive {
190+
return Err(NoSolution);
191+
}
192+
179193
ecx.probe_and_evaluate_goal_for_constituent_tys(
180194
goal,
181195
structural_traits::instantiate_constituent_tys_for_sized_trait,
@@ -186,6 +200,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
186200
ecx: &mut EvalCtxt<'_, 'tcx>,
187201
goal: Goal<'tcx, Self>,
188202
) -> QueryResult<'tcx> {
203+
if goal.predicate.polarity != ty::ImplPolarity::Positive {
204+
return Err(NoSolution);
205+
}
206+
189207
ecx.probe_and_evaluate_goal_for_constituent_tys(
190208
goal,
191209
structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
@@ -196,6 +214,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
196214
ecx: &mut EvalCtxt<'_, 'tcx>,
197215
goal: Goal<'tcx, Self>,
198216
) -> QueryResult<'tcx> {
217+
if goal.predicate.polarity != ty::ImplPolarity::Positive {
218+
return Err(NoSolution);
219+
}
220+
199221
if goal.predicate.self_ty().has_non_region_infer() {
200222
return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
201223
}
@@ -217,6 +239,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
217239
ecx: &mut EvalCtxt<'_, 'tcx>,
218240
goal: Goal<'tcx, Self>,
219241
) -> QueryResult<'tcx> {
242+
if goal.predicate.polarity != ty::ImplPolarity::Positive {
243+
return Err(NoSolution);
244+
}
245+
220246
if let ty::FnPtr(..) = goal.predicate.self_ty().kind() {
221247
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
222248
} else {
@@ -229,6 +255,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
229255
goal: Goal<'tcx, Self>,
230256
goal_kind: ty::ClosureKind,
231257
) -> QueryResult<'tcx> {
258+
if goal.predicate.polarity != ty::ImplPolarity::Positive {
259+
return Err(NoSolution);
260+
}
261+
232262
let tcx = ecx.tcx();
233263
let tupled_inputs_and_output =
234264
match structural_traits::extract_tupled_inputs_and_output_from_callable(
@@ -259,6 +289,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
259289
ecx: &mut EvalCtxt<'_, 'tcx>,
260290
goal: Goal<'tcx, Self>,
261291
) -> QueryResult<'tcx> {
292+
if goal.predicate.polarity != ty::ImplPolarity::Positive {
293+
return Err(NoSolution);
294+
}
295+
262296
if let ty::Tuple(..) = goal.predicate.self_ty().kind() {
263297
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
264298
} else {
@@ -268,15 +302,23 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
268302

269303
fn consider_builtin_pointee_candidate(
270304
ecx: &mut EvalCtxt<'_, 'tcx>,
271-
_goal: Goal<'tcx, Self>,
305+
goal: Goal<'tcx, Self>,
272306
) -> QueryResult<'tcx> {
307+
if goal.predicate.polarity != ty::ImplPolarity::Positive {
308+
return Err(NoSolution);
309+
}
310+
273311
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
274312
}
275313

276314
fn consider_builtin_future_candidate(
277315
ecx: &mut EvalCtxt<'_, 'tcx>,
278316
goal: Goal<'tcx, Self>,
279317
) -> QueryResult<'tcx> {
318+
if goal.predicate.polarity != ty::ImplPolarity::Positive {
319+
return Err(NoSolution);
320+
}
321+
280322
let ty::Generator(def_id, _, _) = *goal.predicate.self_ty().kind() else {
281323
return Err(NoSolution);
282324
};
@@ -297,6 +339,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
297339
ecx: &mut EvalCtxt<'_, 'tcx>,
298340
goal: Goal<'tcx, Self>,
299341
) -> QueryResult<'tcx> {
342+
if goal.predicate.polarity != ty::ImplPolarity::Positive {
343+
return Err(NoSolution);
344+
}
345+
300346
let self_ty = goal.predicate.self_ty();
301347
let ty::Generator(def_id, substs, _) = *self_ty.kind() else {
302348
return Err(NoSolution);
@@ -326,6 +372,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
326372
ecx: &mut EvalCtxt<'_, 'tcx>,
327373
goal: Goal<'tcx, Self>,
328374
) -> QueryResult<'tcx> {
375+
if goal.predicate.polarity != ty::ImplPolarity::Positive {
376+
return Err(NoSolution);
377+
}
378+
329379
let tcx = ecx.tcx();
330380
let a_ty = goal.predicate.self_ty();
331381
let b_ty = goal.predicate.trait_ref.substs.type_at(1);
@@ -447,6 +497,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
447497
ecx: &mut EvalCtxt<'_, 'tcx>,
448498
goal: Goal<'tcx, Self>,
449499
) -> Vec<CanonicalResponse<'tcx>> {
500+
if goal.predicate.polarity != ty::ImplPolarity::Positive {
501+
return vec![];
502+
}
503+
450504
let tcx = ecx.tcx();
451505

452506
let a_ty = goal.predicate.self_ty();
@@ -521,8 +575,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
521575

522576
fn consider_builtin_discriminant_kind_candidate(
523577
ecx: &mut EvalCtxt<'_, 'tcx>,
524-
_goal: Goal<'tcx, Self>,
578+
goal: Goal<'tcx, Self>,
525579
) -> QueryResult<'tcx> {
580+
if goal.predicate.polarity != ty::ImplPolarity::Positive {
581+
return Err(NoSolution);
582+
}
583+
526584
// `DiscriminantKind` is automatically implemented for every type.
527585
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
528586
}
@@ -531,6 +589,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
531589
ecx: &mut EvalCtxt<'_, 'tcx>,
532590
goal: Goal<'tcx, Self>,
533591
) -> QueryResult<'tcx> {
592+
if goal.predicate.polarity != ty::ImplPolarity::Positive {
593+
return Err(NoSolution);
594+
}
595+
534596
if !goal.param_env.is_const() {
535597
// `Destruct` is automatically implemented for every type in
536598
// non-const environments.
@@ -545,6 +607,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
545607
ecx: &mut EvalCtxt<'_, 'tcx>,
546608
goal: Goal<'tcx, Self>,
547609
) -> QueryResult<'tcx> {
610+
if goal.predicate.polarity != ty::ImplPolarity::Positive {
611+
return Err(NoSolution);
612+
}
613+
548614
// `rustc_transmute` does not have support for type or const params
549615
if goal.has_non_region_placeholders() {
550616
return Err(NoSolution);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// check-pass
2+
3+
// This test verifies that negative trait predicate cannot be satisfied from a
4+
// positive param-env candidate.
5+
6+
// Negative coherence is one of the only places where we actually construct and
7+
// evaluate negative predicates. Specifically, when verifying whether the first
8+
// and second impls below overlap, we do not want to consider them disjoint,
9+
// otherwise the second impl would be missing an associated type `type Item`
10+
// which is provided by the first impl that it is specializing.
11+
12+
#![feature(specialization)]
13+
//~^ WARN the feature `specialization` is incomplete
14+
#![feature(with_negative_coherence)]
15+
16+
trait BoxIter {
17+
type Item;
18+
19+
fn last(self) -> Option<Self::Item>;
20+
}
21+
22+
impl<I: Iterator + ?Sized> BoxIter for Box<I> {
23+
type Item = I::Item;
24+
25+
default fn last(self) -> Option<I::Item> {
26+
todo!()
27+
}
28+
}
29+
30+
// When checking that this impl does/doesn't overlap the one above, we evaluate
31+
// a negative version of all of the where-clause predicates of the impl below.
32+
// For `I: !Iterator`, we should make sure that the param-env clause `I: Iterator`
33+
// from above doesn't satisfy this predicate.
34+
impl<I: Iterator> BoxIter for Box<I> {
35+
fn last(self) -> Option<I::Item> {
36+
(*self).last()
37+
}
38+
}
39+
40+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/negative-coherence-bounds.rs:12:12
3+
|
4+
LL | #![feature(specialization)]
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
8+
= help: consider using `min_specialization` instead, which is more stable and complete
9+
= note: `#[warn(incomplete_features)]` on by default
10+
11+
warning: 1 warning emitted
12+

0 commit comments

Comments
 (0)