Skip to content

Commit 69d7172

Browse files
authored
Rollup merge of #110207 - compiler-errors:new-solver-unpin, r=lcnr
Assemble `Unpin` candidates specially for generators in new solver Fixes compiler-errors/next-solver-hir-issues#16 r? ``@lcnr``
2 parents 44db7c3 + 319c790 commit 69d7172

File tree

6 files changed

+130
-65
lines changed

6 files changed

+130
-65
lines changed

compiler/rustc_trait_selection/src/solve/assembly/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
348348
) {
349349
let lang_items = self.tcx().lang_items();
350350
let trait_def_id = goal.predicate.trait_def_id(self.tcx());
351+
352+
// N.B. When assembling built-in candidates for lang items that are also
353+
// `auto` traits, then the auto trait candidate that is assembled in
354+
// `consider_auto_trait_candidate` MUST be disqualified to remain sound.
355+
//
356+
// Instead of adding the logic here, it's a better idea to add it in
357+
// `EvalCtxt::disqualify_auto_trait_candidate_due_to_possible_impl` in
358+
// `solve::trait_goals` instead.
351359
let result = if self.tcx().trait_is_auto(trait_def_id) {
352360
G::consider_auto_trait_candidate(self, goal)
353361
} else if self.tcx().trait_is_alias(trait_def_id) {

compiler/rustc_trait_selection/src/solve/trait_goals.rs

+94-61
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use super::assembly::{self, structural_traits};
44
use super::{EvalCtxt, SolverMode};
55
use rustc_hir::def_id::DefId;
6-
use rustc_hir::LangItem;
6+
use rustc_hir::{LangItem, Movability};
77
use rustc_infer::traits::query::NoSolution;
88
use rustc_infer::traits::util::supertraits;
99
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
@@ -147,66 +147,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
147147
ecx: &mut EvalCtxt<'_, 'tcx>,
148148
goal: Goal<'tcx, Self>,
149149
) -> QueryResult<'tcx> {
150-
let self_ty = goal.predicate.self_ty();
151-
match *self_ty.kind() {
152-
// Stall int and float vars until they are resolved to a concrete
153-
// numerical type. That's because the check for impls below treats
154-
// int vars as matching any impl. Even if we filtered such impls,
155-
// we probably don't want to treat an `impl !AutoTrait for i32` as
156-
// disqualifying the built-in auto impl for `i64: AutoTrait` either.
157-
ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
158-
return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
159-
}
160-
161-
// These types cannot be structurally decomposed into constitutent
162-
// types, and therefore have no builtin impl.
163-
ty::Dynamic(..)
164-
| ty::Param(..)
165-
| ty::Foreign(..)
166-
| ty::Alias(ty::Projection, ..)
167-
| ty::Placeholder(..) => return Err(NoSolution),
168-
169-
ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"),
170-
171-
// For rigid types, we only register a builtin auto implementation
172-
// if there is no implementation that could ever apply to the self
173-
// type.
174-
//
175-
// This differs from the current stable behavior and fixes #84857.
176-
// Due to breakage found via crater, we currently instead lint
177-
// patterns which can be used to exploit this unsoundness on stable,
178-
// see #93367 for more details.
179-
ty::Bool
180-
| ty::Char
181-
| ty::Int(_)
182-
| ty::Uint(_)
183-
| ty::Float(_)
184-
| ty::Str
185-
| ty::Array(_, _)
186-
| ty::Slice(_)
187-
| ty::RawPtr(_)
188-
| ty::Ref(_, _, _)
189-
| ty::FnDef(_, _)
190-
| ty::FnPtr(_)
191-
| ty::Closure(_, _)
192-
| ty::Generator(_, _, _)
193-
| ty::GeneratorWitness(_)
194-
| ty::GeneratorWitnessMIR(_, _)
195-
| ty::Never
196-
| ty::Tuple(_)
197-
| ty::Error(_)
198-
| ty::Adt(_, _)
199-
| ty::Alias(ty::Opaque, _) => {
200-
if let Some(def_id) = ecx.tcx().find_map_relevant_impl(
201-
goal.predicate.def_id(),
202-
goal.predicate.self_ty(),
203-
TreatProjections::NextSolverLookup,
204-
Some,
205-
) {
206-
debug!(?def_id, ?goal, "disqualified auto-trait implementation");
207-
return Err(NoSolution);
208-
}
209-
}
150+
if let Some(result) = ecx.disqualify_auto_trait_candidate_due_to_possible_impl(goal) {
151+
return result;
210152
}
211153

212154
ecx.probe_and_evaluate_goal_for_constituent_tys(
@@ -630,6 +572,97 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
630572
}
631573

632574
impl<'tcx> EvalCtxt<'_, 'tcx> {
575+
// Return `Some` if there is an impl (built-in or user provided) that may
576+
// hold for the self type of the goal, which for coherence and soundness
577+
// purposes must disqualify the built-in auto impl assembled by considering
578+
// the type's constituent types.
579+
fn disqualify_auto_trait_candidate_due_to_possible_impl(
580+
&mut self,
581+
goal: Goal<'tcx, TraitPredicate<'tcx>>,
582+
) -> Option<QueryResult<'tcx>> {
583+
let self_ty = goal.predicate.self_ty();
584+
match *self_ty.kind() {
585+
// Stall int and float vars until they are resolved to a concrete
586+
// numerical type. That's because the check for impls below treats
587+
// int vars as matching any impl. Even if we filtered such impls,
588+
// we probably don't want to treat an `impl !AutoTrait for i32` as
589+
// disqualifying the built-in auto impl for `i64: AutoTrait` either.
590+
ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
591+
Some(self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS))
592+
}
593+
594+
// These types cannot be structurally decomposed into constitutent
595+
// types, and therefore have no built-in auto impl.
596+
ty::Dynamic(..)
597+
| ty::Param(..)
598+
| ty::Foreign(..)
599+
| ty::Alias(ty::Projection, ..)
600+
| ty::Placeholder(..) => Some(Err(NoSolution)),
601+
602+
ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"),
603+
604+
// Generators have one special built-in candidate, `Unpin`, which
605+
// takes precedence over the structural auto trait candidate being
606+
// assembled.
607+
ty::Generator(_, _, movability)
608+
if Some(goal.predicate.def_id()) == self.tcx().lang_items().unpin_trait() =>
609+
{
610+
match movability {
611+
Movability::Static => Some(Err(NoSolution)),
612+
Movability::Movable => {
613+
Some(self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
614+
}
615+
}
616+
}
617+
618+
// For rigid types, any possible implementation that could apply to
619+
// the type (even if after unification and processing nested goals
620+
// it does not hold) will disqualify the built-in auto impl.
621+
//
622+
// This differs from the current stable behavior and fixes #84857.
623+
// Due to breakage found via crater, we currently instead lint
624+
// patterns which can be used to exploit this unsoundness on stable,
625+
// see #93367 for more details.
626+
ty::Bool
627+
| ty::Char
628+
| ty::Int(_)
629+
| ty::Uint(_)
630+
| ty::Float(_)
631+
| ty::Str
632+
| ty::Array(_, _)
633+
| ty::Slice(_)
634+
| ty::RawPtr(_)
635+
| ty::Ref(_, _, _)
636+
| ty::FnDef(_, _)
637+
| ty::FnPtr(_)
638+
| ty::Closure(_, _)
639+
| ty::Generator(_, _, _)
640+
| ty::GeneratorWitness(_)
641+
| ty::GeneratorWitnessMIR(_, _)
642+
| ty::Never
643+
| ty::Tuple(_)
644+
| ty::Adt(_, _)
645+
// FIXME: Handling opaques here is kinda sus. Especially because we
646+
// simplify them to PlaceholderSimplifiedType.
647+
| ty::Alias(ty::Opaque, _) => {
648+
if let Some(def_id) = self.tcx().find_map_relevant_impl(
649+
goal.predicate.def_id(),
650+
goal.predicate.self_ty(),
651+
TreatProjections::NextSolverLookup,
652+
Some,
653+
) {
654+
debug!(?def_id, ?goal, "disqualified auto-trait implementation");
655+
// No need to actually consider the candidate here,
656+
// since we do that in `consider_impl_candidate`.
657+
return Some(Err(NoSolution));
658+
} else {
659+
None
660+
}
661+
}
662+
ty::Error(_) => None,
663+
}
664+
}
665+
633666
/// Convenience function for traits that are structural, i.e. that only
634667
/// have nested subgoals that only change the self type. Unlike other
635668
/// evaluate-like helpers, this does a probe, so it doesn't need to be

tests/ui/generator/non-static-is-unpin.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// revisions: current next
2+
//[next] compile-flags: -Ztrait-solver=next
13
// run-pass
24

35
#![feature(generators, generator_trait)]

tests/ui/generator/static-not-unpin.stderr renamed to tests/ui/generator/static-not-unpin.current.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 11:34]` cannot be unpinned
2-
--> $DIR/static-not-unpin.rs:14:18
1+
error[E0277]: `[static generator@$DIR/static-not-unpin.rs:14:25: 14:34]` cannot be unpinned
2+
--> $DIR/static-not-unpin.rs:17:18
33
|
44
LL | assert_unpin(generator);
5-
| ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 11:34]`
5+
| ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:14:25: 14:34]`
66
| |
77
| required by a bound introduced by this call
88
|
99
= note: consider using the `pin!` macro
1010
consider using `Box::pin` if you need to access the pinned value outside of the current scope
1111
note: required by a bound in `assert_unpin`
12-
--> $DIR/static-not-unpin.rs:7:20
12+
--> $DIR/static-not-unpin.rs:10:20
1313
|
1414
LL | fn assert_unpin<T: Unpin>(_: T) {
1515
| ^^^^^ required by this bound in `assert_unpin`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0277]: `[static generator@$DIR/static-not-unpin.rs:14:25: 14:34]` cannot be unpinned
2+
--> $DIR/static-not-unpin.rs:17:18
3+
|
4+
LL | assert_unpin(generator);
5+
| ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:14:25: 14:34]`
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
= note: consider using the `pin!` macro
10+
consider using `Box::pin` if you need to access the pinned value outside of the current scope
11+
note: required by a bound in `assert_unpin`
12+
--> $DIR/static-not-unpin.rs:10:20
13+
|
14+
LL | fn assert_unpin<T: Unpin>(_: T) {
15+
| ^^^^^ required by this bound in `assert_unpin`
16+
17+
error: aborting due to previous error
18+
19+
For more information about this error, try `rustc --explain E0277`.

tests/ui/generator/static-not-unpin.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// revisions: current next
2+
//[next] compile-flags: -Ztrait-solver=next
3+
14
#![feature(generators)]
25

36
// normalize-stderr-test "std::pin::Unpin" -> "std::marker::Unpin"

0 commit comments

Comments
 (0)