Auto merge of #124811 - matthiaskrgr:rollup-4zpov13, r=matthiaskrgr
Rollup of 4 pull requests
Successful merges:
- #124520 (Document that `create_dir_all` calls `mkdir`/`CreateDirW` multiple times)
- #124724 (Prefer lower vtable candidates in select in new solver)
- #124771 (Don't consider candidates with no failing where clauses when refining obligation causes in new solver)
- #124808 (Use `super_fold` in `RegionsToStatic` visitor)
r? `@ghost`
`@rustbot` modify labels: rollup
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index 6600b92..c437ded 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -455,7 +455,7 @@
I::Binder<T>: TypeSuperFoldable<I>,
{
self.binder.shift_in(1);
- let t = t.fold_with(self);
+ let t = t.super_fold_with(self);
self.binder.shift_out(1);
t
}
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
index 16fe045..4d474b8 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
@@ -58,6 +58,12 @@
)));
}
+ // Don't winnow until `Certainty::Yes` -- we don't need to winnow until
+ // codegen, and only on the good path.
+ if matches!(goal.result().unwrap(), Certainty::Maybe(..)) {
+ return ControlFlow::Break(Ok(None));
+ }
+
// We need to winnow. See comments on `candidate_should_be_dropped_in_favor_of`.
let mut i = 0;
while i < candidates.len() {
@@ -86,7 +92,7 @@
other: &inspect::InspectCandidate<'_, 'tcx>,
) -> bool {
// Don't winnow until `Certainty::Yes` -- we don't need to winnow until
- // codegen, technically.
+ // codegen, and only on the good path.
if matches!(other.result().unwrap(), Certainty::Maybe(..)) {
return false;
}
@@ -105,13 +111,15 @@
bug!("should not have assembled a CoherenceUnknowable candidate")
}
+ // In the old trait solver, we arbitrarily choose lower vtable candidates
+ // over higher ones.
+ (
+ CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base: a }),
+ CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base: b }),
+ ) => a >= b,
// Prefer dyn candidates over non-dyn candidates. This is necessary to
// handle the unsoundness between `impl<T: ?Sized> Any for T` and `dyn Any: Any`.
(
- CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
- CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
- ) => false,
- (
CandidateSource::Impl(_) | CandidateSource::ParamEnv(_) | CandidateSource::AliasBound,
CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
) => true,
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index fd4b580..39d2ec4 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -14,7 +14,7 @@
use rustc_span::symbol::sym;
use super::eval_ctxt::GenerateProofTree;
-use super::inspect::{ProofTreeInferCtxtExt, ProofTreeVisitor};
+use super::inspect::{InspectCandidate, InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
use super::{Certainty, InferCtxtEvalExt};
/// A trait engine using the new trait solver.
@@ -304,6 +304,46 @@
self.obligation = old_obligation;
res
}
+
+ /// Filter out the candidates that aren't either error or ambiguous (depending
+ /// on what we are looking for), and also throw out candidates that have no
+ /// failing WC (or higher-ranked obligations, for which there should only be
+ /// one candidate anyways -- but I digress). This most likely means that the
+ /// goal just didn't unify at all, e.g. a param candidate with an alias in it.
+ fn non_trivial_candidates<'a>(
+ &self,
+ goal: &'a InspectGoal<'a, 'tcx>,
+ ) -> Vec<InspectCandidate<'a, 'tcx>> {
+ let mut candidates = goal
+ .candidates()
+ .into_iter()
+ .filter(|candidate| match self.consider_ambiguities {
+ true => matches!(candidate.result(), Ok(Certainty::Maybe(_))),
+ false => matches!(candidate.result(), Err(_)),
+ })
+ .collect::<Vec<_>>();
+
+ // If we have >1 candidate, one may still be due to "boring" reasons, like
+ // an alias-relate that failed to hold when deeply evaluated. We really
+ // don't care about reasons like this.
+ if candidates.len() > 1 {
+ candidates.retain(|candidate| {
+ goal.infcx().probe(|_| {
+ candidate.instantiate_nested_goals(self.span()).iter().any(|nested_goal| {
+ matches!(
+ nested_goal.source(),
+ GoalSource::ImplWhereBound | GoalSource::InstantiateHigherRanked
+ ) && match self.consider_ambiguities {
+ true => matches!(nested_goal.result(), Ok(Certainty::Maybe(_))),
+ false => matches!(nested_goal.result(), Err(_)),
+ }
+ })
+ })
+ });
+ }
+
+ candidates
+ }
}
impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
@@ -314,11 +354,7 @@
}
fn visit_goal(&mut self, goal: &super::inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
- // FIXME: Throw out candidates that have no failing WC and >0 failing misc goal.
- // This most likely means that the goal just didn't unify at all, e.g. a param
- // candidate with an alias in it.
- let candidates = goal.candidates();
-
+ let candidates = self.non_trivial_candidates(goal);
let [candidate] = candidates.as_slice() else {
return ControlFlow::Break(self.obligation.clone());
};
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 409ead0..a59faf5 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -2258,7 +2258,7 @@
/// # Platform-specific behavior
///
/// This function currently corresponds to the `mkdir` function on Unix
-/// and the `CreateDirectory` function on Windows.
+/// and the `CreateDirectoryW` function on Windows.
/// Note that, this [may change in the future][changes].
///
/// [changes]: io#platform-specific-behavior
@@ -2298,10 +2298,14 @@
/// Recursively create a directory and all of its parent components if they
/// are missing.
///
+/// If this function returns an error, some of the parent components might have
+/// been created already.
+///
/// # Platform-specific behavior
///
-/// This function currently corresponds to the `mkdir` function on Unix
-/// and the `CreateDirectory` function on Windows.
+/// This function currently corresponds to multiple calls to the `mkdir`
+/// function on Unix and the `CreateDirectoryW` function on Windows.
+///
/// Note that, this [may change in the future][changes].
///
/// [changes]: io#platform-specific-behavior
diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.rs b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.rs
new file mode 100644
index 0000000..33a6d7a
--- /dev/null
+++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.rs
@@ -0,0 +1,8 @@
+//@ compile-flags: -Znext-solver=coherence
+
+#[derive(Debug)]
+struct X<const FN: fn() = { || {} }>;
+//~^ ERROR using function pointers as const generic parameters is forbidden
+//~| ERROR using function pointers as const generic parameters is forbidden
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
new file mode 100644
index 0000000..4eef8c0
--- /dev/null
+++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
@@ -0,0 +1,19 @@
+error: using function pointers as const generic parameters is forbidden
+ --> $DIR/const-region-infer-to-static-in-binder.rs:4:20
+ |
+LL | struct X<const FN: fn() = { || {} }>;
+ | ^^^^
+ |
+ = note: the only supported types are integers, `bool` and `char`
+
+error: using function pointers as const generic parameters is forbidden
+ --> $DIR/const-region-infer-to-static-in-binder.rs:4:20
+ |
+LL | struct X<const FN: fn() = { || {} }>;
+ | ^^^^
+ |
+ = note: the only supported types are integers, `bool` and `char`
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/traits/next-solver/canonicalize-effect-var.rs b/tests/ui/traits/next-solver/canonical/effect-var.rs
similarity index 100%
rename from tests/ui/traits/next-solver/canonicalize-effect-var.rs
rename to tests/ui/traits/next-solver/canonical/effect-var.rs
diff --git a/tests/ui/traits/next-solver/canonical-int-var-eq-in-response.rs b/tests/ui/traits/next-solver/canonical/int-var-eq-in-response.rs
similarity index 100%
rename from tests/ui/traits/next-solver/canonical-int-var-eq-in-response.rs
rename to tests/ui/traits/next-solver/canonical/int-var-eq-in-response.rs
diff --git a/tests/ui/traits/next-solver/canonical-ty-var-eq-in-response.rs b/tests/ui/traits/next-solver/canonical/ty-var-eq-in-response.rs
similarity index 100%
rename from tests/ui/traits/next-solver/canonical-ty-var-eq-in-response.rs
rename to tests/ui/traits/next-solver/canonical/ty-var-eq-in-response.rs
diff --git a/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.rs b/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.rs
new file mode 100644
index 0000000..4737546
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.rs
@@ -0,0 +1,22 @@
+trait Foo {}
+trait Bar {}
+
+impl<T> Foo for T where T: Bar {}
+fn needs_foo(_: impl Foo) {}
+
+trait Mirror {
+ type Mirror;
+}
+impl<T> Mirror for T {
+ type Mirror = T;
+}
+
+// Make sure the `Alias: Foo` bound doesn't "shadow" the impl, since the
+// impl is really the only candidate we care about here for the purpose
+// of error reporting.
+fn hello<T>() where <T as Mirror>::Mirror: Foo {
+ needs_foo(());
+ //~^ ERROR the trait bound `(): Foo` is not satisfied
+}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr b/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr
new file mode 100644
index 0000000..77a0cc4
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr
@@ -0,0 +1,22 @@
+error[E0277]: the trait bound `(): Foo` is not satisfied
+ --> $DIR/where-clause-doesnt-apply.rs:18:15
+ |
+LL | needs_foo(());
+ | --------- ^^ the trait `Bar` is not implemented for `()`, which is required by `(): Foo`
+ | |
+ | required by a bound introduced by this call
+ |
+note: required for `()` to implement `Foo`
+ --> $DIR/where-clause-doesnt-apply.rs:4:9
+ |
+LL | impl<T> Foo for T where T: Bar {}
+ | ^^^ ^ --- unsatisfied trait bound introduced here
+note: required by a bound in `needs_foo`
+ --> $DIR/where-clause-doesnt-apply.rs:5:22
+ |
+LL | fn needs_foo(_: impl Foo) {}
+ | ^^^ required by this bound in `needs_foo`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/normalize-supertrait.rs b/tests/ui/traits/normalize-supertrait.rs
index 1ab2b8e..3ba4a8b 100644
--- a/tests/ui/traits/normalize-supertrait.rs
+++ b/tests/ui/traits/normalize-supertrait.rs
@@ -4,6 +4,9 @@
// comparing the supertrait `Derived<()>` to the expected trait.
//@ build-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
trait Proj {
type S;