| author | bors <bors@rust-lang.org> 2026-05-08 14:56:56 UTC |
| committer | bors <bors@rust-lang.org> 2026-05-08 14:56:56 UTC |
| log | 8068e2fc9afa8c888336b12db01987be768785f9 |
| tree | 32d63ab35a6b7818f9e08e2cc5c21ac5c5d38d25 |
| parent | f2b291d902bfde7d7f209fc3a64908134bcef201 |
| parent | 01cccf92dca30d28746597f6f06e6af2f832ba92 |
Rollup of 4 pull requests
Successful merges:
- rust-lang/rust#156246 (Introduce a `RerunNonErased` error type mirroring `NoSolution`, to better track when we're bailing)
- rust-lang/rust#156038 (turn `compute_goal_fast_path` into a single match)
- rust-lang/rust#156291 (Treat MSVC "performing full link" message as informational)
- rust-lang/rust#156301 (Avoid ICE when suggesting as_ref for ill-typed closure receivers)28 files changed, 879 insertions(+), 518 deletions(-)
compiler/rustc_ast_ir/src/visit.rs+23| ... | ... | @@ -41,6 +41,29 @@ impl<T> VisitorResult for ControlFlow<T> { |
| 41 | 41 | } |
| 42 | 42 | } |
| 43 | 43 | |
| 44 | impl<E> VisitorResult for Result<(), E> { | |
| 45 | type Residual = E; | |
| 46 | ||
| 47 | fn output() -> Self { | |
| 48 | Ok(()) | |
| 49 | } | |
| 50 | fn from_residual(residual: Self::Residual) -> Self { | |
| 51 | Err(residual) | |
| 52 | } | |
| 53 | fn from_branch(b: ControlFlow<Self::Residual>) -> Self { | |
| 54 | match b { | |
| 55 | ControlFlow::Continue(()) => Ok(()), | |
| 56 | ControlFlow::Break(e) => Err(e), | |
| 57 | } | |
| 58 | } | |
| 59 | fn branch(self) -> ControlFlow<Self::Residual> { | |
| 60 | match self { | |
| 61 | Ok(()) => ControlFlow::Continue(()), | |
| 62 | Err(e) => ControlFlow::Break(e), | |
| 63 | } | |
| 64 | } | |
| 65 | } | |
| 66 | ||
| 44 | 67 | #[macro_export] |
| 45 | 68 | macro_rules! try_visit { |
| 46 | 69 | ($e:expr) => { |
compiler/rustc_codegen_ssa/src/back/link.rs+5| ... | ... | @@ -754,10 +754,15 @@ fn report_linker_output(sess: &Session, levels: CodegenLintLevels, stdout: &[u8] |
| 754 | 754 | escaped_stdout = for_each(&stdout, |line, output| { |
| 755 | 755 | // Hide some progress messages from link.exe that we don't care about. |
| 756 | 756 | // See https://github.com/chromium/chromium/blob/bfa41e41145ffc85f041384280caf2949bb7bd72/build/toolchain/win/tool_wrapper.py#L144-L146 |
| 757 | // When incremental linking is enabled and an .ilk exists, but its associated .exe is | |
| 758 | // missing, link.exe prints the path of the missing .exe followed by: | |
| 759 | let ilk_but_no_exe = | |
| 760 | "not found or not built by the last incremental link; performing full link"; | |
| 757 | 761 | let trimmed = line.trim_start(); |
| 758 | 762 | if trimmed.starts_with("Creating library") |
| 759 | 763 | || trimmed.starts_with("Generating code") |
| 760 | 764 | || trimmed.starts_with("Finished generating code") |
| 765 | || trimmed.ends_with(ilk_but_no_exe) | |
| 761 | 766 | { |
| 762 | 767 | linker_info += line; |
| 763 | 768 | linker_info += "\r\n"; |
compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs+1-1| ... | ... | @@ -2787,7 +2787,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 2787 | 2787 | return None; |
| 2788 | 2788 | }; |
| 2789 | 2789 | |
| 2790 | let self_ty = self.typeck_results.borrow().expr_ty(receiver); | |
| 2790 | let self_ty = self.typeck_results.borrow().expr_ty_opt(receiver)?; | |
| 2791 | 2791 | let name = method_path.ident.name; |
| 2792 | 2792 | let is_as_ref_able = match self_ty.peel_refs().kind() { |
| 2793 | 2793 | ty::Adt(def, _) => { |
compiler/rustc_middle/src/ty/context/impl_interner.rs+33-10| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | //! Implementation of [`rustc_type_ir::Interner`] for [`TyCtxt`]. |
| 2 | 2 | |
| 3 | use std::ops::ControlFlow; | |
| 3 | 4 | use std::{debug_assert_matches, fmt}; |
| 4 | 5 | |
| 5 | 6 | use rustc_errors::ErrorGuaranteed; |
| ... | ... | @@ -9,7 +10,9 @@ use rustc_hir::def_id::{DefId, LocalDefId}; |
| 9 | 10 | use rustc_hir::lang_items::LangItem; |
| 10 | 11 | use rustc_span::{DUMMY_SP, Span, Symbol}; |
| 11 | 12 | use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverProjectionLangItem, SolverTraitLangItem}; |
| 12 | use rustc_type_ir::{CollectAndApply, Interner, TypeFoldable, Unnormalized, search_graph}; | |
| 13 | use rustc_type_ir::{ | |
| 14 | CollectAndApply, Interner, TypeFoldable, Unnormalized, VisitorResult, search_graph, | |
| 15 | }; | |
| 13 | 16 | |
| 14 | 17 | use crate::dep_graph::{DepKind, DepNodeIndex}; |
| 15 | 18 | use crate::infer::canonical::CanonicalVarKinds; |
| ... | ... | @@ -522,20 +525,31 @@ impl<'tcx> Interner for TyCtxt<'tcx> { |
| 522 | 525 | // This implementation is a bit different from `TyCtxt::for_each_relevant_impl`, |
| 523 | 526 | // since we want to skip over blanket impls for non-rigid aliases, and also we |
| 524 | 527 | // only want to consider types that *actually* unify with float/int vars. |
| 525 | fn for_each_relevant_impl( | |
| 528 | fn for_each_relevant_impl<R: VisitorResult>( | |
| 526 | 529 | self, |
| 527 | 530 | trait_def_id: DefId, |
| 528 | 531 | self_ty: Ty<'tcx>, |
| 529 | mut f: impl FnMut(DefId), | |
| 530 | ) { | |
| 532 | mut f: impl FnMut(DefId) -> R, | |
| 533 | ) -> R { | |
| 534 | macro_rules! ret { | |
| 535 | ($e: expr) => { | |
| 536 | match $e.branch() { | |
| 537 | ControlFlow::Break(b) => return R::from_residual(b), | |
| 538 | ControlFlow::Continue(()) => {} | |
| 539 | } | |
| 540 | }; | |
| 541 | } | |
| 542 | ||
| 531 | 543 | let tcx = self; |
| 532 | 544 | let trait_impls = tcx.trait_impls_of(trait_def_id); |
| 533 | 545 | let mut consider_impls_for_simplified_type = |simp| { |
| 534 | 546 | if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) { |
| 535 | 547 | for &impl_def_id in impls_for_type { |
| 536 | f(impl_def_id); | |
| 548 | ret!(f(impl_def_id)) | |
| 537 | 549 | } |
| 538 | 550 | } |
| 551 | ||
| 552 | R::output() | |
| 539 | 553 | }; |
| 540 | 554 | |
| 541 | 555 | match self_ty.kind() { |
| ... | ... | @@ -566,7 +580,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { |
| 566 | 580 | self_ty, |
| 567 | 581 | ty::fast_reject::TreatParams::AsRigid, |
| 568 | 582 | ) { |
| 569 | consider_impls_for_simplified_type(simp); | |
| 583 | ret!(consider_impls_for_simplified_type(simp)); | |
| 570 | 584 | } |
| 571 | 585 | } |
| 572 | 586 | |
| ... | ... | @@ -595,7 +609,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { |
| 595 | 609 | ty::SimplifiedType::Uint(Usize), |
| 596 | 610 | ]; |
| 597 | 611 | for simp in possible_integers { |
| 598 | consider_impls_for_simplified_type(simp); | |
| 612 | ret!(consider_impls_for_simplified_type(simp)); | |
| 599 | 613 | } |
| 600 | 614 | } |
| 601 | 615 | |
| ... | ... | @@ -610,7 +624,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { |
| 610 | 624 | ]; |
| 611 | 625 | |
| 612 | 626 | for simp in possible_floats { |
| 613 | consider_impls_for_simplified_type(simp); | |
| 627 | ret!(consider_impls_for_simplified_type(simp)); | |
| 614 | 628 | } |
| 615 | 629 | } |
| 616 | 630 | |
| ... | ... | @@ -634,11 +648,20 @@ impl<'tcx> Interner for TyCtxt<'tcx> { |
| 634 | 648 | #[allow(rustc::usage_of_type_ir_traits)] |
| 635 | 649 | self.for_each_blanket_impl(trait_def_id, f) |
| 636 | 650 | } |
| 637 | fn for_each_blanket_impl(self, trait_def_id: DefId, mut f: impl FnMut(DefId)) { | |
| 651 | fn for_each_blanket_impl<R: VisitorResult>( | |
| 652 | self, | |
| 653 | trait_def_id: DefId, | |
| 654 | mut f: impl FnMut(DefId) -> R, | |
| 655 | ) -> R { | |
| 638 | 656 | let trait_impls = self.trait_impls_of(trait_def_id); |
| 639 | 657 | for &impl_def_id in trait_impls.blanket_impls() { |
| 640 | f(impl_def_id); | |
| 658 | match f(impl_def_id).branch() { | |
| 659 | ControlFlow::Break(b) => return R::from_residual(b), | |
| 660 | ControlFlow::Continue(()) => {} | |
| 661 | } | |
| 641 | 662 | } |
| 663 | ||
| 664 | R::output() | |
| 642 | 665 | } |
| 643 | 666 | |
| 644 | 667 | fn has_item_definition(self, def_id: DefId) -> bool { |
compiler/rustc_next_trait_solver/src/solve/alias_relate.rs+3-3| ... | ... | @@ -16,12 +16,12 @@ |
| 16 | 16 | //! relate them structurally. |
| 17 | 17 | |
| 18 | 18 | use rustc_type_ir::inherent::*; |
| 19 | use rustc_type_ir::solve::GoalSource; | |
| 19 | use rustc_type_ir::solve::{GoalSource, QueryResultOrRerunNonErased}; | |
| 20 | 20 | use rustc_type_ir::{self as ty, Interner}; |
| 21 | 21 | use tracing::{instrument, trace}; |
| 22 | 22 | |
| 23 | 23 | use crate::delegate::SolverDelegate; |
| 24 | use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult}; | |
| 24 | use crate::solve::{Certainty, EvalCtxt, Goal}; | |
| 25 | 25 | |
| 26 | 26 | impl<D, I> EvalCtxt<'_, D> |
| 27 | 27 | where |
| ... | ... | @@ -32,7 +32,7 @@ where |
| 32 | 32 | pub(super) fn compute_alias_relate_goal( |
| 33 | 33 | &mut self, |
| 34 | 34 | goal: Goal<I, (I::Term, I::Term, ty::AliasRelationDirection)>, |
| 35 | ) -> QueryResult<I> { | |
| 35 | ) -> QueryResultOrRerunNonErased<I> { | |
| 36 | 36 | let cx = self.cx(); |
| 37 | 37 | let Goal { param_env, predicate: (lhs, rhs, direction) } = goal; |
| 38 | 38 |
compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs+123-92| ... | ... | @@ -10,8 +10,8 @@ use rustc_type_ir::inherent::*; |
| 10 | 10 | use rustc_type_ir::lang_items::SolverTraitLangItem; |
| 11 | 11 | use rustc_type_ir::search_graph::CandidateHeadUsages; |
| 12 | 12 | use rustc_type_ir::solve::{ |
| 13 | AliasBoundKind, MaybeInfo, NoSolutionOrOpaquesAccessed, RerunReason, SizedTraitKind, | |
| 14 | StalledOnCoroutines, | |
| 13 | AliasBoundKind, MaybeInfo, NoSolutionOrRerunNonErased, QueryResultOrRerunNonErased, | |
| 14 | RerunNonErased, RerunReason, RerunResultExt, SizedTraitKind, StalledOnCoroutines, | |
| 15 | 15 | }; |
| 16 | 16 | use rustc_type_ir::{ |
| 17 | 17 | self as ty, AliasTy, Interner, MayBeErased, TypeFlags, TypeFoldable, TypeFolder, |
| ... | ... | @@ -65,7 +65,7 @@ where |
| 65 | 65 | goal: Goal<I, Self>, |
| 66 | 66 | assumption: I::Clause, |
| 67 | 67 | requirements: impl IntoIterator<Item = (GoalSource, Goal<I, I::Predicate>)>, |
| 68 | ) -> Result<Candidate<I>, NoSolution> { | |
| 68 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 69 | 69 | Self::probe_and_match_goal_against_assumption(ecx, parent_source, goal, assumption, |ecx| { |
| 70 | 70 | for (nested_source, goal) in requirements { |
| 71 | 71 | ecx.add_goal(nested_source, goal); |
| ... | ... | @@ -84,7 +84,7 @@ where |
| 84 | 84 | source: CandidateSource<I>, |
| 85 | 85 | goal: Goal<I, Self>, |
| 86 | 86 | assumption: I::Clause, |
| 87 | ) -> Result<Candidate<I>, NoSolution> { | |
| 87 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 88 | 88 | Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| { |
| 89 | 89 | let cx = ecx.cx(); |
| 90 | 90 | let ty::Dynamic(bounds, _) = goal.predicate.self_ty().kind() else { |
| ... | ... | @@ -136,10 +136,10 @@ where |
| 136 | 136 | ecx: &mut EvalCtxt<'_, D>, |
| 137 | 137 | goal: Goal<I, Self>, |
| 138 | 138 | assumption: I::Clause, |
| 139 | ) -> Result<Candidate<I>, CandidateHeadUsages> { | |
| 139 | ) -> Result<Result<Candidate<I>, CandidateHeadUsages>, RerunNonErased> { | |
| 140 | 140 | match Self::fast_reject_assumption(ecx, goal, assumption) { |
| 141 | 141 | Ok(()) => {} |
| 142 | Err(NoSolution) => return Err(CandidateHeadUsages::default()), | |
| 142 | Err(NoSolution) => return Ok(Err(CandidateHeadUsages::default())), | |
| 143 | 143 | } |
| 144 | 144 | |
| 145 | 145 | // Dealing with `ParamEnv` candidates is a bit of a mess as we need to lazily |
| ... | ... | @@ -155,19 +155,25 @@ where |
| 155 | 155 | result: *result, |
| 156 | 156 | }) |
| 157 | 157 | .enter_single_candidate(|ecx| { |
| 158 | Self::match_assumption(ecx, goal, assumption, |ecx| { | |
| 159 | ecx.try_evaluate_added_goals()?; | |
| 160 | let (src, certainty) = | |
| 161 | ecx.characterize_param_env_assumption(goal.param_env, assumption)?; | |
| 162 | source.set(src); | |
| 163 | ecx.evaluate_added_goals_and_make_canonical_response(certainty) | |
| 164 | }) | |
| 158 | Self::match_assumption( | |
| 159 | ecx, | |
| 160 | goal, | |
| 161 | assumption, | |
| 162 | |ecx| -> Result<_, NoSolutionOrRerunNonErased> { | |
| 163 | ecx.try_evaluate_added_goals()?; | |
| 164 | let (src, certainty) = | |
| 165 | ecx.characterize_param_env_assumption(goal.param_env, assumption)?; | |
| 166 | source.set(src); | |
| 167 | ecx.evaluate_added_goals_and_make_canonical_response(certainty) | |
| 168 | }, | |
| 169 | ) | |
| 170 | .map_err(Into::into) | |
| 165 | 171 | }); |
| 166 | 172 | |
| 167 | match result.map_err(Into::into) { | |
| 173 | Ok(match result.map_err_to_rerun()? { | |
| 168 | 174 | Ok(result) => Ok(Candidate { source: source.get(), result, head_usages }), |
| 169 | 175 | Err(NoSolution) => Err(head_usages), |
| 170 | } | |
| 176 | }) | |
| 171 | 177 | } |
| 172 | 178 | |
| 173 | 179 | /// Try equating an assumption predicate against a goal's predicate. If it |
| ... | ... | @@ -179,8 +185,8 @@ where |
| 179 | 185 | source: CandidateSource<I>, |
| 180 | 186 | goal: Goal<I, Self>, |
| 181 | 187 | assumption: I::Clause, |
| 182 | then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>, | |
| 183 | ) -> Result<Candidate<I>, NoSolution> { | |
| 188 | then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResultOrRerunNonErased<I>, | |
| 189 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 184 | 190 | Self::fast_reject_assumption(ecx, goal, assumption)?; |
| 185 | 191 | |
| 186 | 192 | ecx.probe_trait_candidate(source) |
| ... | ... | @@ -200,15 +206,15 @@ where |
| 200 | 206 | ecx: &mut EvalCtxt<'_, D>, |
| 201 | 207 | goal: Goal<I, Self>, |
| 202 | 208 | assumption: I::Clause, |
| 203 | then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>, | |
| 204 | ) -> QueryResult<I>; | |
| 209 | then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResultOrRerunNonErased<I>, | |
| 210 | ) -> QueryResultOrRerunNonErased<I>; | |
| 205 | 211 | |
| 206 | 212 | fn consider_impl_candidate( |
| 207 | 213 | ecx: &mut EvalCtxt<'_, D>, |
| 208 | 214 | goal: Goal<I, Self>, |
| 209 | 215 | impl_def_id: I::ImplId, |
| 210 | then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>, | |
| 211 | ) -> Result<Candidate<I>, NoSolution>; | |
| 216 | then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResultOrRerunNonErased<I>, | |
| 217 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 212 | 218 | |
| 213 | 219 | /// If the predicate contained an error, we want to avoid emitting unnecessary trait |
| 214 | 220 | /// errors but still want to emit errors for other trait goals. We have some special |
| ... | ... | @@ -219,7 +225,7 @@ where |
| 219 | 225 | fn consider_error_guaranteed_candidate( |
| 220 | 226 | ecx: &mut EvalCtxt<'_, D>, |
| 221 | 227 | guar: I::ErrorGuaranteed, |
| 222 | ) -> Result<Candidate<I>, NoSolution>; | |
| 228 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 223 | 229 | |
| 224 | 230 | /// A type implements an `auto trait` if its components do as well. |
| 225 | 231 | /// |
| ... | ... | @@ -228,13 +234,13 @@ where |
| 228 | 234 | fn consider_auto_trait_candidate( |
| 229 | 235 | ecx: &mut EvalCtxt<'_, D>, |
| 230 | 236 | goal: Goal<I, Self>, |
| 231 | ) -> Result<Candidate<I>, NoSolution>; | |
| 237 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 232 | 238 | |
| 233 | 239 | /// A trait alias holds if the RHS traits and `where` clauses hold. |
| 234 | 240 | fn consider_trait_alias_candidate( |
| 235 | 241 | ecx: &mut EvalCtxt<'_, D>, |
| 236 | 242 | goal: Goal<I, Self>, |
| 237 | ) -> Result<Candidate<I>, NoSolution>; | |
| 243 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 238 | 244 | |
| 239 | 245 | /// A type is `Sized` if its tail component is `Sized` and a type is `MetaSized` if its tail |
| 240 | 246 | /// component is `MetaSized`. |
| ... | ... | @@ -245,7 +251,7 @@ where |
| 245 | 251 | ecx: &mut EvalCtxt<'_, D>, |
| 246 | 252 | goal: Goal<I, Self>, |
| 247 | 253 | sizedness: SizedTraitKind, |
| 248 | ) -> Result<Candidate<I>, NoSolution>; | |
| 254 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 249 | 255 | |
| 250 | 256 | /// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`. |
| 251 | 257 | /// |
| ... | ... | @@ -254,13 +260,13 @@ where |
| 254 | 260 | fn consider_builtin_copy_clone_candidate( |
| 255 | 261 | ecx: &mut EvalCtxt<'_, D>, |
| 256 | 262 | goal: Goal<I, Self>, |
| 257 | ) -> Result<Candidate<I>, NoSolution>; | |
| 263 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 258 | 264 | |
| 259 | 265 | /// A type is a `FnPtr` if it is of `FnPtr` type. |
| 260 | 266 | fn consider_builtin_fn_ptr_trait_candidate( |
| 261 | 267 | ecx: &mut EvalCtxt<'_, D>, |
| 262 | 268 | goal: Goal<I, Self>, |
| 263 | ) -> Result<Candidate<I>, NoSolution>; | |
| 269 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 264 | 270 | |
| 265 | 271 | /// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>` |
| 266 | 272 | /// family of traits where `A` is given by the signature of the type. |
| ... | ... | @@ -268,7 +274,7 @@ where |
| 268 | 274 | ecx: &mut EvalCtxt<'_, D>, |
| 269 | 275 | goal: Goal<I, Self>, |
| 270 | 276 | kind: ty::ClosureKind, |
| 271 | ) -> Result<Candidate<I>, NoSolution>; | |
| 277 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 272 | 278 | |
| 273 | 279 | /// An async closure is known to implement the `AsyncFn<A>` family of traits |
| 274 | 280 | /// where `A` is given by the signature of the type. |
| ... | ... | @@ -276,7 +282,7 @@ where |
| 276 | 282 | ecx: &mut EvalCtxt<'_, D>, |
| 277 | 283 | goal: Goal<I, Self>, |
| 278 | 284 | kind: ty::ClosureKind, |
| 279 | ) -> Result<Candidate<I>, NoSolution>; | |
| 285 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 280 | 286 | |
| 281 | 287 | /// Compute the built-in logic of the `AsyncFnKindHelper` helper trait, which |
| 282 | 288 | /// is used internally to delay computation for async closures until after |
| ... | ... | @@ -284,13 +290,13 @@ where |
| 284 | 290 | fn consider_builtin_async_fn_kind_helper_candidate( |
| 285 | 291 | ecx: &mut EvalCtxt<'_, D>, |
| 286 | 292 | goal: Goal<I, Self>, |
| 287 | ) -> Result<Candidate<I>, NoSolution>; | |
| 293 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 288 | 294 | |
| 289 | 295 | /// `Tuple` is implemented if the `Self` type is a tuple. |
| 290 | 296 | fn consider_builtin_tuple_candidate( |
| 291 | 297 | ecx: &mut EvalCtxt<'_, D>, |
| 292 | 298 | goal: Goal<I, Self>, |
| 293 | ) -> Result<Candidate<I>, NoSolution>; | |
| 299 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 294 | 300 | |
| 295 | 301 | /// `Pointee` is always implemented. |
| 296 | 302 | /// |
| ... | ... | @@ -300,7 +306,7 @@ where |
| 300 | 306 | fn consider_builtin_pointee_candidate( |
| 301 | 307 | ecx: &mut EvalCtxt<'_, D>, |
| 302 | 308 | goal: Goal<I, Self>, |
| 303 | ) -> Result<Candidate<I>, NoSolution>; | |
| 309 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 304 | 310 | |
| 305 | 311 | /// A coroutine (that comes from an `async` desugaring) is known to implement |
| 306 | 312 | /// `Future<Output = O>`, where `O` is given by the coroutine's return type |
| ... | ... | @@ -308,7 +314,7 @@ where |
| 308 | 314 | fn consider_builtin_future_candidate( |
| 309 | 315 | ecx: &mut EvalCtxt<'_, D>, |
| 310 | 316 | goal: Goal<I, Self>, |
| 311 | ) -> Result<Candidate<I>, NoSolution>; | |
| 317 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 312 | 318 | |
| 313 | 319 | /// A coroutine (that comes from a `gen` desugaring) is known to implement |
| 314 | 320 | /// `Iterator<Item = O>`, where `O` is given by the generator's yield type |
| ... | ... | @@ -316,19 +322,19 @@ where |
| 316 | 322 | fn consider_builtin_iterator_candidate( |
| 317 | 323 | ecx: &mut EvalCtxt<'_, D>, |
| 318 | 324 | goal: Goal<I, Self>, |
| 319 | ) -> Result<Candidate<I>, NoSolution>; | |
| 325 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 320 | 326 | |
| 321 | 327 | /// A coroutine (that comes from a `gen` desugaring) is known to implement |
| 322 | 328 | /// `FusedIterator` |
| 323 | 329 | fn consider_builtin_fused_iterator_candidate( |
| 324 | 330 | ecx: &mut EvalCtxt<'_, D>, |
| 325 | 331 | goal: Goal<I, Self>, |
| 326 | ) -> Result<Candidate<I>, NoSolution>; | |
| 332 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 327 | 333 | |
| 328 | 334 | fn consider_builtin_async_iterator_candidate( |
| 329 | 335 | ecx: &mut EvalCtxt<'_, D>, |
| 330 | 336 | goal: Goal<I, Self>, |
| 331 | ) -> Result<Candidate<I>, NoSolution>; | |
| 337 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 332 | 338 | |
| 333 | 339 | /// A coroutine (that doesn't come from an `async` or `gen` desugaring) is known to |
| 334 | 340 | /// implement `Coroutine<R, Yield = Y, Return = O>`, given the resume, yield, |
| ... | ... | @@ -336,27 +342,27 @@ where |
| 336 | 342 | fn consider_builtin_coroutine_candidate( |
| 337 | 343 | ecx: &mut EvalCtxt<'_, D>, |
| 338 | 344 | goal: Goal<I, Self>, |
| 339 | ) -> Result<Candidate<I>, NoSolution>; | |
| 345 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 340 | 346 | |
| 341 | 347 | fn consider_builtin_discriminant_kind_candidate( |
| 342 | 348 | ecx: &mut EvalCtxt<'_, D>, |
| 343 | 349 | goal: Goal<I, Self>, |
| 344 | ) -> Result<Candidate<I>, NoSolution>; | |
| 350 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 345 | 351 | |
| 346 | 352 | fn consider_builtin_destruct_candidate( |
| 347 | 353 | ecx: &mut EvalCtxt<'_, D>, |
| 348 | 354 | goal: Goal<I, Self>, |
| 349 | ) -> Result<Candidate<I>, NoSolution>; | |
| 355 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 350 | 356 | |
| 351 | 357 | fn consider_builtin_transmute_candidate( |
| 352 | 358 | ecx: &mut EvalCtxt<'_, D>, |
| 353 | 359 | goal: Goal<I, Self>, |
| 354 | ) -> Result<Candidate<I>, NoSolution>; | |
| 360 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 355 | 361 | |
| 356 | 362 | fn consider_builtin_bikeshed_guaranteed_no_drop_candidate( |
| 357 | 363 | ecx: &mut EvalCtxt<'_, D>, |
| 358 | 364 | goal: Goal<I, Self>, |
| 359 | ) -> Result<Candidate<I>, NoSolution>; | |
| 365 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 360 | 366 | |
| 361 | 367 | /// Consider (possibly several) candidates to upcast or unsize a type to another |
| 362 | 368 | /// type, excluding the coercion of a sized type into a `dyn Trait`. |
| ... | ... | @@ -368,12 +374,12 @@ where |
| 368 | 374 | fn consider_structural_builtin_unsize_candidates( |
| 369 | 375 | ecx: &mut EvalCtxt<'_, D>, |
| 370 | 376 | goal: Goal<I, Self>, |
| 371 | ) -> Vec<Candidate<I>>; | |
| 377 | ) -> Result<Vec<Candidate<I>>, RerunNonErased>; | |
| 372 | 378 | |
| 373 | 379 | fn consider_builtin_field_candidate( |
| 374 | 380 | ecx: &mut EvalCtxt<'_, D>, |
| 375 | 381 | goal: Goal<I, Self>, |
| 376 | ) -> Result<Candidate<I>, NoSolution>; | |
| 382 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>; | |
| 377 | 383 | } |
| 378 | 384 | |
| 379 | 385 | /// Allows callers of `assemble_and_evaluate_candidates` to choose whether to limit |
| ... | ... | @@ -425,14 +431,14 @@ where |
| 425 | 431 | &mut self, |
| 426 | 432 | goal: Goal<I, G>, |
| 427 | 433 | assemble_from: AssembleCandidatesFrom, |
| 428 | ) -> (Vec<Candidate<I>>, FailedCandidateInfo) { | |
| 434 | ) -> Result<(Vec<Candidate<I>>, FailedCandidateInfo), RerunNonErased> { | |
| 429 | 435 | let mut candidates = vec![]; |
| 430 | 436 | let mut failed_candidate_info = |
| 431 | 437 | FailedCandidateInfo { param_env_head_usages: CandidateHeadUsages::default() }; |
| 432 | 438 | let Ok(normalized_self_ty) = |
| 433 | 439 | self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty()) |
| 434 | 440 | else { |
| 435 | return (candidates, failed_candidate_info); | |
| 441 | return Ok((candidates, failed_candidate_info)); | |
| 436 | 442 | }; |
| 437 | 443 | |
| 438 | 444 | let goal: Goal<I, G> = goal |
| ... | ... | @@ -440,8 +446,8 @@ where |
| 440 | 446 | |
| 441 | 447 | if normalized_self_ty.is_ty_var() { |
| 442 | 448 | debug!("self type has been normalized to infer"); |
| 443 | self.try_assemble_bounds_via_registered_opaques(goal, assemble_from, &mut candidates); | |
| 444 | return (candidates, failed_candidate_info); | |
| 449 | self.try_assemble_bounds_via_registered_opaques(goal, assemble_from, &mut candidates)?; | |
| 450 | return Ok((candidates, failed_candidate_info)); | |
| 445 | 451 | } |
| 446 | 452 | |
| 447 | 453 | // Vars that show up in the rest of the goal substs may have been constrained by |
| ... | ... | @@ -452,15 +458,15 @@ where |
| 452 | 458 | && let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) |
| 453 | 459 | { |
| 454 | 460 | candidates.push(candidate); |
| 455 | return (candidates, failed_candidate_info); | |
| 461 | return Ok((candidates, failed_candidate_info)); | |
| 456 | 462 | } |
| 457 | 463 | |
| 458 | self.assemble_alias_bound_candidates(goal, &mut candidates); | |
| 459 | self.assemble_param_env_candidates(goal, &mut candidates, &mut failed_candidate_info); | |
| 464 | self.assemble_alias_bound_candidates(goal, &mut candidates)?; | |
| 465 | self.assemble_param_env_candidates(goal, &mut candidates, &mut failed_candidate_info)?; | |
| 460 | 466 | |
| 461 | 467 | match assemble_from { |
| 462 | 468 | AssembleCandidatesFrom::All => { |
| 463 | self.assemble_builtin_impl_candidates(goal, &mut candidates); | |
| 469 | self.assemble_builtin_impl_candidates(goal, &mut candidates)?; | |
| 464 | 470 | // For performance we only assemble impls if there are no candidates |
| 465 | 471 | // which would shadow them. This is necessary to avoid hangs in rayon, |
| 466 | 472 | // see trait-system-refactor-initiative#109 for more details. |
| ... | ... | @@ -487,7 +493,7 @@ where |
| 487 | 493 | }), |
| 488 | 494 | }; |
| 489 | 495 | if assemble_impls { |
| 490 | self.assemble_impl_candidates(goal, &mut candidates); | |
| 496 | self.assemble_impl_candidates(goal, &mut candidates)?; | |
| 491 | 497 | self.assemble_object_bound_candidates(goal, &mut candidates); |
| 492 | 498 | } |
| 493 | 499 | } |
| ... | ... | @@ -503,13 +509,13 @@ where |
| 503 | 509 | } |
| 504 | 510 | } |
| 505 | 511 | |
| 506 | (candidates, failed_candidate_info) | |
| 512 | Ok((candidates, failed_candidate_info)) | |
| 507 | 513 | } |
| 508 | 514 | |
| 509 | 515 | pub(super) fn forced_ambiguity( |
| 510 | 516 | &mut self, |
| 511 | 517 | maybe: MaybeInfo, |
| 512 | ) -> Result<Candidate<I>, NoSolution> { | |
| 518 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 513 | 519 | // This may fail if `try_evaluate_added_goals` overflows because it |
| 514 | 520 | // fails to reach a fixpoint but ends up getting an error after |
| 515 | 521 | // running for some additional step. |
| ... | ... | @@ -529,26 +535,30 @@ where |
| 529 | 535 | &mut self, |
| 530 | 536 | goal: Goal<I, G>, |
| 531 | 537 | candidates: &mut Vec<Candidate<I>>, |
| 532 | ) { | |
| 538 | ) -> Result<(), RerunNonErased> { | |
| 533 | 539 | let cx = self.cx(); |
| 534 | 540 | cx.for_each_relevant_impl( |
| 535 | 541 | goal.predicate.trait_def_id(cx), |
| 536 | 542 | goal.predicate.self_ty(), |
| 537 | |impl_def_id| { | |
| 543 | |impl_def_id| -> Result<_, _> { | |
| 538 | 544 | // For every `default impl`, there's always a non-default `impl` |
| 539 | 545 | // that will *also* apply. There's no reason to register a candidate |
| 540 | 546 | // for this impl, since it is *not* proof that the trait goal holds. |
| 541 | 547 | if cx.impl_is_default(impl_def_id) { |
| 542 | return; | |
| 548 | return Ok(()); | |
| 543 | 549 | } |
| 544 | 550 | match G::consider_impl_candidate(self, goal, impl_def_id, |ecx, certainty| { |
| 545 | 551 | ecx.evaluate_added_goals_and_make_canonical_response(certainty) |
| 546 | }) { | |
| 552 | }) | |
| 553 | .map_err_to_rerun()? | |
| 554 | { | |
| 547 | 555 | Ok(candidate) => candidates.push(candidate), |
| 548 | Err(NoSolution) => (), | |
| 556 | Err(NoSolution) => {} | |
| 549 | 557 | } |
| 558 | ||
| 559 | Ok(()) | |
| 550 | 560 | }, |
| 551 | ); | |
| 561 | ) | |
| 552 | 562 | } |
| 553 | 563 | |
| 554 | 564 | #[instrument(level = "trace", skip_all)] |
| ... | ... | @@ -556,7 +566,7 @@ where |
| 556 | 566 | &mut self, |
| 557 | 567 | goal: Goal<I, G>, |
| 558 | 568 | candidates: &mut Vec<Candidate<I>>, |
| 559 | ) { | |
| 569 | ) -> Result<(), RerunNonErased> { | |
| 560 | 570 | let cx = self.cx(); |
| 561 | 571 | let trait_def_id = goal.predicate.trait_def_id(cx); |
| 562 | 572 | |
| ... | ... | @@ -653,7 +663,7 @@ where |
| 653 | 663 | G::consider_builtin_bikeshed_guaranteed_no_drop_candidate(self, goal) |
| 654 | 664 | } |
| 655 | 665 | Some(SolverTraitLangItem::Field) => G::consider_builtin_field_candidate(self, goal), |
| 656 | _ => Err(NoSolution), | |
| 666 | _ => Err(NoSolution.into()), | |
| 657 | 667 | } |
| 658 | 668 | }; |
| 659 | 669 | |
| ... | ... | @@ -662,8 +672,10 @@ where |
| 662 | 672 | // There may be multiple unsize candidates for a trait with several supertraits: |
| 663 | 673 | // `trait Foo: Bar<A> + Bar<B>` and `dyn Foo: Unsize<dyn Bar<_>>` |
| 664 | 674 | if cx.is_trait_lang_item(trait_def_id, SolverTraitLangItem::Unsize) { |
| 665 | candidates.extend(G::consider_structural_builtin_unsize_candidates(self, goal)); | |
| 675 | candidates.extend(G::consider_structural_builtin_unsize_candidates(self, goal)?); | |
| 666 | 676 | } |
| 677 | ||
| 678 | Ok(()) | |
| 667 | 679 | } |
| 668 | 680 | |
| 669 | 681 | #[instrument(level = "trace", skip_all)] |
| ... | ... | @@ -672,15 +684,17 @@ where |
| 672 | 684 | goal: Goal<I, G>, |
| 673 | 685 | candidates: &mut Vec<Candidate<I>>, |
| 674 | 686 | failed_candidate_info: &mut FailedCandidateInfo, |
| 675 | ) { | |
| 687 | ) -> Result<(), RerunNonErased> { | |
| 676 | 688 | for assumption in goal.param_env.caller_bounds().iter() { |
| 677 | match G::probe_and_consider_param_env_candidate(self, goal, assumption) { | |
| 689 | match G::probe_and_consider_param_env_candidate(self, goal, assumption)? { | |
| 678 | 690 | Ok(candidate) => candidates.push(candidate), |
| 679 | 691 | Err(head_usages) => { |
| 680 | 692 | failed_candidate_info.param_env_head_usages.merge_usages(head_usages) |
| 681 | 693 | } |
| 682 | 694 | } |
| 683 | 695 | } |
| 696 | ||
| 697 | Ok(()) | |
| 684 | 698 | } |
| 685 | 699 | |
| 686 | 700 | #[instrument(level = "trace", skip_all)] |
| ... | ... | @@ -688,21 +702,22 @@ where |
| 688 | 702 | &mut self, |
| 689 | 703 | goal: Goal<I, G>, |
| 690 | 704 | candidates: &mut Vec<Candidate<I>>, |
| 691 | ) { | |
| 705 | ) -> Result<(), RerunNonErased> { | |
| 692 | 706 | let res = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| { |
| 693 | 707 | ecx.assemble_alias_bound_candidates_recur( |
| 694 | 708 | goal.predicate.self_ty(), |
| 695 | 709 | goal, |
| 696 | 710 | candidates, |
| 697 | 711 | AliasBoundKind::SelfBounds, |
| 698 | ); | |
| 712 | )?; | |
| 699 | 713 | Ok(()) |
| 700 | 714 | }); |
| 701 | 715 | |
| 702 | 716 | // always returns Ok |
| 703 | 717 | match res { |
| 704 | Ok(_) | Err(NoSolutionOrOpaquesAccessed::OpaquesAccessed) => {} | |
| 705 | Err(NoSolutionOrOpaquesAccessed::NoSolution(NoSolution)) => { | |
| 718 | Ok(_) => Ok(()), | |
| 719 | Err(NoSolutionOrRerunNonErased::RerunNonErased(e)) => Err(e), | |
| 720 | Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution)) => { | |
| 706 | 721 | unreachable!() |
| 707 | 722 | } |
| 708 | 723 | } |
| ... | ... | @@ -723,7 +738,7 @@ where |
| 723 | 738 | goal: Goal<I, G>, |
| 724 | 739 | candidates: &mut Vec<Candidate<I>>, |
| 725 | 740 | consider_self_bounds: AliasBoundKind, |
| 726 | ) { | |
| 741 | ) -> Result<(), RerunNonErased> { | |
| 727 | 742 | let alias_ty = match self_ty.kind() { |
| 728 | 743 | ty::Bool |
| 729 | 744 | | ty::Char |
| ... | ... | @@ -751,7 +766,7 @@ where |
| 751 | 766 | | ty::Param(_) |
| 752 | 767 | | ty::Placeholder(..) |
| 753 | 768 | | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) |
| 754 | | ty::Error(_) => return, | |
| 769 | | ty::Error(_) => return Ok(()), | |
| 755 | 770 | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => { |
| 756 | 771 | panic!("unexpected self type for `{goal:?}`") |
| 757 | 772 | } |
| ... | ... | @@ -769,7 +784,7 @@ where |
| 769 | 784 | head_usages: CandidateHeadUsages::default(), |
| 770 | 785 | }); |
| 771 | 786 | } |
| 772 | return; | |
| 787 | return Ok(()); | |
| 773 | 788 | } |
| 774 | 789 | |
| 775 | 790 | ty::Alias( |
| ... | ... | @@ -777,7 +792,7 @@ where |
| 777 | 792 | ) => alias_ty, |
| 778 | 793 | ty::Alias(AliasTy { kind: ty::Inherent { .. } | ty::Free { .. }, .. }) => { |
| 779 | 794 | self.cx().delay_bug(format!("could not normalize {self_ty:?}, it is not WF")); |
| 780 | return; | |
| 795 | return Ok(()); | |
| 781 | 796 | } |
| 782 | 797 | }; |
| 783 | 798 | |
| ... | ... | @@ -819,7 +834,7 @@ where |
| 819 | 834 | candidates.extend(G::consider_additional_alias_assumptions(self, goal, alias_ty)); |
| 820 | 835 | |
| 821 | 836 | if !matches!(alias_ty.kind, ty::Projection { .. }) { |
| 822 | return; | |
| 837 | return Ok(()); | |
| 823 | 838 | } |
| 824 | 839 | |
| 825 | 840 | // Recurse on the self type of the projection. |
| ... | ... | @@ -830,7 +845,8 @@ where |
| 830 | 845 | candidates, |
| 831 | 846 | AliasBoundKind::NonSelfBounds, |
| 832 | 847 | ), |
| 833 | Err(NoSolution) => {} | |
| 848 | Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution)) => Ok(()), | |
| 849 | Err(NoSolutionOrRerunNonErased::RerunNonErased(e)) => Err(e), | |
| 834 | 850 | } |
| 835 | 851 | } |
| 836 | 852 | |
| ... | ... | @@ -932,12 +948,12 @@ where |
| 932 | 948 | fn consider_coherence_unknowable_candidate<G: GoalKind<D>>( |
| 933 | 949 | &mut self, |
| 934 | 950 | goal: Goal<I, G>, |
| 935 | ) -> Result<Candidate<I>, NoSolution> { | |
| 951 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 936 | 952 | self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(|ecx| { |
| 937 | 953 | let cx = ecx.cx(); |
| 938 | 954 | let trait_ref = goal.predicate.trait_ref(cx); |
| 939 | 955 | if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? { |
| 940 | Err(NoSolution) | |
| 956 | Err(NoSolution.into()) | |
| 941 | 957 | } else { |
| 942 | 958 | // While the trait bound itself may be unknowable, we may be able to |
| 943 | 959 | // prove that a super trait is not implemented. For this, we recursively |
| ... | ... | @@ -1032,7 +1048,7 @@ where |
| 1032 | 1048 | goal: Goal<I, G>, |
| 1033 | 1049 | assemble_from: AssembleCandidatesFrom, |
| 1034 | 1050 | candidates: &mut Vec<Candidate<I>>, |
| 1035 | ) { | |
| 1051 | ) -> Result<(), RerunNonErased> { | |
| 1036 | 1052 | let self_ty = goal.predicate.self_ty(); |
| 1037 | 1053 | // We only use this hack during HIR typeck. |
| 1038 | 1054 | let opaque_types = match self.typing_mode() { |
| ... | ... | @@ -1043,14 +1059,14 @@ where |
| 1043 | 1059 | | TypingMode::PostAnalysis => vec![], |
| 1044 | 1060 | TypingMode::ErasedNotCoherence(MayBeErased) => { |
| 1045 | 1061 | self.opaque_accesses |
| 1046 | .rerun_if_any_opaque_has_infer_as_hidden_type(RerunReason::SelfTyInfer); | |
| 1062 | .rerun_if_any_opaque_has_infer_as_hidden_type(RerunReason::SelfTyInfer)?; | |
| 1047 | 1063 | Vec::new() |
| 1048 | 1064 | } |
| 1049 | 1065 | }; |
| 1050 | 1066 | |
| 1051 | 1067 | if opaque_types.is_empty() { |
| 1052 | 1068 | candidates.extend(self.forced_ambiguity(MaybeInfo::AMBIGUOUS)); |
| 1053 | return; | |
| 1069 | return Ok(()); | |
| 1054 | 1070 | } |
| 1055 | 1071 | |
| 1056 | 1072 | for &alias_ty in &opaque_types { |
| ... | ... | @@ -1115,7 +1131,7 @@ where |
| 1115 | 1131 | // that will *also* apply. There's no reason to register a candidate |
| 1116 | 1132 | // for this impl, since it is *not* proof that the trait goal holds. |
| 1117 | 1133 | if cx.impl_is_default(impl_def_id) { |
| 1118 | return; | |
| 1134 | return Ok(()); | |
| 1119 | 1135 | } |
| 1120 | 1136 | |
| 1121 | 1137 | match G::consider_impl_candidate(self, goal, impl_def_id, |ecx, certainty| { |
| ... | ... | @@ -1129,13 +1145,17 @@ where |
| 1129 | 1145 | // FIXME(trait-system-refactor-initiative#229): This isn't |
| 1130 | 1146 | // perfect yet as it still allows us to incorrectly constrain |
| 1131 | 1147 | // other inference variables. |
| 1132 | Err(NoSolution) | |
| 1148 | Err(NoSolution.into()) | |
| 1133 | 1149 | } |
| 1134 | }) { | |
| 1150 | }) | |
| 1151 | .map_err_to_rerun()? | |
| 1152 | { | |
| 1135 | 1153 | Ok(candidate) => candidates.push(candidate), |
| 1136 | Err(NoSolution) => (), | |
| 1154 | Err(NoSolution) => {} | |
| 1137 | 1155 | } |
| 1138 | }); | |
| 1156 | ||
| 1157 | Ok(()) | |
| 1158 | })?; | |
| 1139 | 1159 | } |
| 1140 | 1160 | |
| 1141 | 1161 | if candidates.is_empty() { |
| ... | ... | @@ -1150,6 +1170,8 @@ where |
| 1150 | 1170 | this.evaluate_added_goals_and_make_canonical_response(certainty) |
| 1151 | 1171 | })); |
| 1152 | 1172 | } |
| 1173 | ||
| 1174 | Ok(()) | |
| 1153 | 1175 | } |
| 1154 | 1176 | |
| 1155 | 1177 | /// Assemble and merge candidates for goals which are related to an underlying trait |
| ... | ... | @@ -1187,9 +1209,18 @@ where |
| 1187 | 1209 | &mut self, |
| 1188 | 1210 | proven_via: Option<TraitGoalProvenVia>, |
| 1189 | 1211 | goal: Goal<I, G>, |
| 1190 | inject_forced_ambiguity_candidate: impl FnOnce(&mut EvalCtxt<'_, D>) -> Option<QueryResult<I>>, | |
| 1191 | inject_normalize_to_rigid_candidate: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>, | |
| 1192 | ) -> QueryResult<I> { | |
| 1212 | inject_forced_ambiguity_candidate: impl FnOnce( | |
| 1213 | &mut EvalCtxt<'_, D>, | |
| 1214 | ) -> Option< | |
| 1215 | Result<CanonicalResponse<I>, NoSolutionOrRerunNonErased>, | |
| 1216 | >, | |
| 1217 | inject_normalize_to_rigid_candidate: impl FnOnce( | |
| 1218 | &mut EvalCtxt<'_, D>, | |
| 1219 | ) -> Result< | |
| 1220 | CanonicalResponse<I>, | |
| 1221 | NoSolutionOrRerunNonErased, | |
| 1222 | >, | |
| 1223 | ) -> QueryResultOrRerunNonErased<I> { | |
| 1193 | 1224 | let Some(proven_via) = proven_via else { |
| 1194 | 1225 | // We don't care about overflow. If proving the trait goal overflowed, then |
| 1195 | 1226 | // it's enough to report an overflow error for that, we don't also have to |
| ... | ... | @@ -1206,7 +1237,7 @@ where |
| 1206 | 1237 | // still need to consider alias-bounds for normalization, see |
| 1207 | 1238 | // `tests/ui/next-solver/alias-bound-shadowed-by-env.rs`. |
| 1208 | 1239 | let (mut candidates, _) = self |
| 1209 | .assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::EnvAndBounds); | |
| 1240 | .assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::EnvAndBounds)?; | |
| 1210 | 1241 | debug!(?candidates); |
| 1211 | 1242 | |
| 1212 | 1243 | // If the trait goal has been proven by using the environment, we want to treat |
| ... | ... | @@ -1230,12 +1261,12 @@ where |
| 1230 | 1261 | if let Some((response, _)) = self.try_merge_candidates(&candidates) { |
| 1231 | 1262 | Ok(response) |
| 1232 | 1263 | } else { |
| 1233 | self.flounder(&candidates) | |
| 1264 | self.flounder(&candidates).map_err(Into::into) | |
| 1234 | 1265 | } |
| 1235 | 1266 | } |
| 1236 | 1267 | TraitGoalProvenVia::Misc => { |
| 1237 | 1268 | let (mut candidates, _) = |
| 1238 | self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All); | |
| 1269 | self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All)?; | |
| 1239 | 1270 | |
| 1240 | 1271 | // Prefer "orphaned" param-env normalization predicates, which are used |
| 1241 | 1272 | // (for example, and ideally only) when proving item bounds for an impl. |
| ... | ... | @@ -1252,7 +1283,7 @@ where |
| 1252 | 1283 | if let Some((response, _)) = self.try_merge_candidates(&candidates) { |
| 1253 | 1284 | Ok(response) |
| 1254 | 1285 | } else { |
| 1255 | self.flounder(&candidates) | |
| 1286 | self.flounder(&candidates).map_err(Into::into) | |
| 1256 | 1287 | } |
| 1257 | 1288 | } |
| 1258 | 1289 | } |
compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs+1-1| ... | ... | @@ -970,7 +970,7 @@ where |
| 970 | 970 | && self |
| 971 | 971 | .ecx |
| 972 | 972 | .probe(|_| ProbeKind::ProjectionCompatibility) |
| 973 | .enter_without_propagated_nested_goals(|ecx| -> Result<_, NoSolution> { | |
| 973 | .enter_without_propagated_nested_goals(|ecx| { | |
| 974 | 974 | let source_projection = ecx.instantiate_binder_with_infer(source_projection); |
| 975 | 975 | ecx.eq(self.param_env, source_projection.projection_term, target_projection)?; |
| 976 | 976 | ecx.try_evaluate_added_goals() |
compiler/rustc_next_trait_solver/src/solve/effect_goals.rs+45-37| ... | ... | @@ -5,15 +5,17 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt; |
| 5 | 5 | use rustc_type_ir::inherent::*; |
| 6 | 6 | use rustc_type_ir::lang_items::SolverTraitLangItem; |
| 7 | 7 | use rustc_type_ir::solve::inspect::ProbeKind; |
| 8 | use rustc_type_ir::solve::{AliasBoundKind, SizedTraitKind}; | |
| 8 | use rustc_type_ir::solve::{ | |
| 9 | AliasBoundKind, NoSolutionOrRerunNonErased, QueryResultOrRerunNonErased, RerunNonErased, | |
| 10 | SizedTraitKind, | |
| 11 | }; | |
| 9 | 12 | use rustc_type_ir::{self as ty, Interner, Unnormalized, elaborate}; |
| 10 | 13 | use tracing::instrument; |
| 11 | 14 | |
| 12 | 15 | use super::assembly::{Candidate, structural_traits}; |
| 13 | 16 | use crate::delegate::SolverDelegate; |
| 14 | 17 | use crate::solve::{ |
| 15 | BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, NoSolution, | |
| 16 | QueryResult, assembly, | |
| 18 | BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, NoSolution, assembly, | |
| 17 | 19 | }; |
| 18 | 20 | |
| 19 | 21 | impl<D, I> assembly::GoalKind<D> for ty::HostEffectPredicate<I> |
| ... | ... | @@ -60,8 +62,8 @@ where |
| 60 | 62 | ecx: &mut EvalCtxt<'_, D>, |
| 61 | 63 | goal: Goal<I, Self>, |
| 62 | 64 | assumption: I::Clause, |
| 63 | then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>, | |
| 64 | ) -> QueryResult<I> { | |
| 65 | then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResultOrRerunNonErased<I>, | |
| 66 | ) -> QueryResultOrRerunNonErased<I> { | |
| 65 | 67 | let host_clause = assumption.as_host_effect_clause().unwrap(); |
| 66 | 68 | |
| 67 | 69 | let assumption_trait_pred = ecx.instantiate_binder_with_infer(host_clause); |
| ... | ... | @@ -128,32 +130,32 @@ where |
| 128 | 130 | ecx: &mut EvalCtxt<'_, D>, |
| 129 | 131 | goal: Goal<I, Self>, |
| 130 | 132 | impl_def_id: I::ImplId, |
| 131 | then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>, | |
| 132 | ) -> Result<Candidate<I>, NoSolution> { | |
| 133 | then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResultOrRerunNonErased<I>, | |
| 134 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 133 | 135 | let cx = ecx.cx(); |
| 134 | 136 | |
| 135 | 137 | let impl_trait_ref = cx.impl_trait_ref(impl_def_id); |
| 136 | 138 | if !DeepRejectCtxt::relate_rigid_infer(ecx.cx()) |
| 137 | 139 | .args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args) |
| 138 | 140 | { |
| 139 | return Err(NoSolution); | |
| 141 | return Err(NoSolution.into()); | |
| 140 | 142 | } |
| 141 | 143 | |
| 142 | 144 | let impl_polarity = cx.impl_polarity(impl_def_id); |
| 143 | 145 | let certainty = match impl_polarity { |
| 144 | ty::ImplPolarity::Negative => return Err(NoSolution), | |
| 146 | ty::ImplPolarity::Negative => return Err(NoSolution.into()), | |
| 145 | 147 | ty::ImplPolarity::Reservation => { |
| 146 | 148 | if ecx.typing_mode().is_coherence() { |
| 147 | 149 | Certainty::AMBIGUOUS |
| 148 | 150 | } else { |
| 149 | return Err(NoSolution); | |
| 151 | return Err(NoSolution.into()); | |
| 150 | 152 | } |
| 151 | 153 | } |
| 152 | 154 | ty::ImplPolarity::Positive => Certainty::Yes, |
| 153 | 155 | }; |
| 154 | 156 | |
| 155 | 157 | if !cx.impl_is_const(impl_def_id) { |
| 156 | return Err(NoSolution); | |
| 158 | return Err(NoSolution.into()); | |
| 157 | 159 | } |
| 158 | 160 | |
| 159 | 161 | ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| { |
| ... | ... | @@ -190,7 +192,7 @@ where |
| 190 | 192 | fn consider_error_guaranteed_candidate( |
| 191 | 193 | ecx: &mut EvalCtxt<'_, D>, |
| 192 | 194 | _guar: I::ErrorGuaranteed, |
| 193 | ) -> Result<Candidate<I>, NoSolution> { | |
| 195 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 194 | 196 | ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) |
| 195 | 197 | .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) |
| 196 | 198 | } |
| ... | ... | @@ -198,15 +200,15 @@ where |
| 198 | 200 | fn consider_auto_trait_candidate( |
| 199 | 201 | ecx: &mut EvalCtxt<'_, D>, |
| 200 | 202 | _goal: Goal<I, Self>, |
| 201 | ) -> Result<Candidate<I>, NoSolution> { | |
| 203 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 202 | 204 | ecx.cx().delay_bug("auto traits are never const"); |
| 203 | Err(NoSolution) | |
| 205 | Err(NoSolution.into()) | |
| 204 | 206 | } |
| 205 | 207 | |
| 206 | 208 | fn consider_trait_alias_candidate( |
| 207 | 209 | ecx: &mut EvalCtxt<'_, D>, |
| 208 | 210 | goal: Goal<I, Self>, |
| 209 | ) -> Result<Candidate<I>, NoSolution> { | |
| 211 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 210 | 212 | let cx = ecx.cx(); |
| 211 | 213 | |
| 212 | 214 | ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { |
| ... | ... | @@ -242,14 +244,14 @@ where |
| 242 | 244 | _ecx: &mut EvalCtxt<'_, D>, |
| 243 | 245 | _goal: Goal<I, Self>, |
| 244 | 246 | _sizedness: SizedTraitKind, |
| 245 | ) -> Result<Candidate<I>, NoSolution> { | |
| 247 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 246 | 248 | unreachable!("Sized/MetaSized is never const") |
| 247 | 249 | } |
| 248 | 250 | |
| 249 | 251 | fn consider_builtin_copy_clone_candidate( |
| 250 | 252 | ecx: &mut EvalCtxt<'_, D>, |
| 251 | 253 | goal: Goal<I, Self>, |
| 252 | ) -> Result<Candidate<I>, NoSolution> { | |
| 254 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 253 | 255 | let cx = ecx.cx(); |
| 254 | 256 | |
| 255 | 257 | let self_ty = goal.predicate.self_ty(); |
| ... | ... | @@ -278,7 +280,7 @@ where |
| 278 | 280 | fn consider_builtin_fn_ptr_trait_candidate( |
| 279 | 281 | _ecx: &mut EvalCtxt<'_, D>, |
| 280 | 282 | _goal: Goal<I, Self>, |
| 281 | ) -> Result<Candidate<I>, NoSolution> { | |
| 283 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 282 | 284 | todo!("Fn* are not yet const") |
| 283 | 285 | } |
| 284 | 286 | |
| ... | ... | @@ -287,7 +289,7 @@ where |
| 287 | 289 | ecx: &mut EvalCtxt<'_, D>, |
| 288 | 290 | goal: Goal<I, Self>, |
| 289 | 291 | _kind: rustc_type_ir::ClosureKind, |
| 290 | ) -> Result<Candidate<I>, NoSolution> { | |
| 292 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 291 | 293 | let cx = ecx.cx(); |
| 292 | 294 | |
| 293 | 295 | let self_ty = goal.predicate.self_ty(); |
| ... | ... | @@ -329,83 +331,84 @@ where |
| 329 | 331 | pred, |
| 330 | 332 | requirements, |
| 331 | 333 | ) |
| 334 | .map_err(Into::into) | |
| 332 | 335 | } |
| 333 | 336 | |
| 334 | 337 | fn consider_builtin_async_fn_trait_candidates( |
| 335 | 338 | _ecx: &mut EvalCtxt<'_, D>, |
| 336 | 339 | _goal: Goal<I, Self>, |
| 337 | 340 | _kind: rustc_type_ir::ClosureKind, |
| 338 | ) -> Result<Candidate<I>, NoSolution> { | |
| 341 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 339 | 342 | todo!("AsyncFn* are not yet const") |
| 340 | 343 | } |
| 341 | 344 | |
| 342 | 345 | fn consider_builtin_async_fn_kind_helper_candidate( |
| 343 | 346 | _ecx: &mut EvalCtxt<'_, D>, |
| 344 | 347 | _goal: Goal<I, Self>, |
| 345 | ) -> Result<Candidate<I>, NoSolution> { | |
| 348 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 346 | 349 | unreachable!("AsyncFnKindHelper is not const") |
| 347 | 350 | } |
| 348 | 351 | |
| 349 | 352 | fn consider_builtin_tuple_candidate( |
| 350 | 353 | _ecx: &mut EvalCtxt<'_, D>, |
| 351 | 354 | _goal: Goal<I, Self>, |
| 352 | ) -> Result<Candidate<I>, NoSolution> { | |
| 355 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 353 | 356 | unreachable!("Tuple trait is not const") |
| 354 | 357 | } |
| 355 | 358 | |
| 356 | 359 | fn consider_builtin_pointee_candidate( |
| 357 | 360 | _ecx: &mut EvalCtxt<'_, D>, |
| 358 | 361 | _goal: Goal<I, Self>, |
| 359 | ) -> Result<Candidate<I>, NoSolution> { | |
| 362 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 360 | 363 | unreachable!("Pointee is not const") |
| 361 | 364 | } |
| 362 | 365 | |
| 363 | 366 | fn consider_builtin_future_candidate( |
| 364 | 367 | _ecx: &mut EvalCtxt<'_, D>, |
| 365 | 368 | _goal: Goal<I, Self>, |
| 366 | ) -> Result<Candidate<I>, NoSolution> { | |
| 369 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 367 | 370 | unreachable!("Future is not const") |
| 368 | 371 | } |
| 369 | 372 | |
| 370 | 373 | fn consider_builtin_iterator_candidate( |
| 371 | 374 | _ecx: &mut EvalCtxt<'_, D>, |
| 372 | 375 | _goal: Goal<I, Self>, |
| 373 | ) -> Result<Candidate<I>, NoSolution> { | |
| 376 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 374 | 377 | todo!("Iterator is not yet const") |
| 375 | 378 | } |
| 376 | 379 | |
| 377 | 380 | fn consider_builtin_fused_iterator_candidate( |
| 378 | 381 | _ecx: &mut EvalCtxt<'_, D>, |
| 379 | 382 | _goal: Goal<I, Self>, |
| 380 | ) -> Result<Candidate<I>, NoSolution> { | |
| 383 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 381 | 384 | unreachable!("FusedIterator is not const") |
| 382 | 385 | } |
| 383 | 386 | |
| 384 | 387 | fn consider_builtin_async_iterator_candidate( |
| 385 | 388 | _ecx: &mut EvalCtxt<'_, D>, |
| 386 | 389 | _goal: Goal<I, Self>, |
| 387 | ) -> Result<Candidate<I>, NoSolution> { | |
| 390 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 388 | 391 | unreachable!("AsyncIterator is not const") |
| 389 | 392 | } |
| 390 | 393 | |
| 391 | 394 | fn consider_builtin_coroutine_candidate( |
| 392 | 395 | _ecx: &mut EvalCtxt<'_, D>, |
| 393 | 396 | _goal: Goal<I, Self>, |
| 394 | ) -> Result<Candidate<I>, NoSolution> { | |
| 397 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 395 | 398 | unreachable!("Coroutine is not const") |
| 396 | 399 | } |
| 397 | 400 | |
| 398 | 401 | fn consider_builtin_discriminant_kind_candidate( |
| 399 | 402 | _ecx: &mut EvalCtxt<'_, D>, |
| 400 | 403 | _goal: Goal<I, Self>, |
| 401 | ) -> Result<Candidate<I>, NoSolution> { | |
| 404 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 402 | 405 | unreachable!("DiscriminantKind is not const") |
| 403 | 406 | } |
| 404 | 407 | |
| 405 | 408 | fn consider_builtin_destruct_candidate( |
| 406 | 409 | ecx: &mut EvalCtxt<'_, D>, |
| 407 | 410 | goal: Goal<I, Self>, |
| 408 | ) -> Result<Candidate<I>, NoSolution> { | |
| 411 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 409 | 412 | let cx = ecx.cx(); |
| 410 | 413 | |
| 411 | 414 | let self_ty = goal.predicate.self_ty(); |
| ... | ... | @@ -429,28 +432,28 @@ where |
| 429 | 432 | fn consider_builtin_transmute_candidate( |
| 430 | 433 | _ecx: &mut EvalCtxt<'_, D>, |
| 431 | 434 | _goal: Goal<I, Self>, |
| 432 | ) -> Result<Candidate<I>, NoSolution> { | |
| 435 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 433 | 436 | unreachable!("TransmuteFrom is not const") |
| 434 | 437 | } |
| 435 | 438 | |
| 436 | 439 | fn consider_builtin_bikeshed_guaranteed_no_drop_candidate( |
| 437 | 440 | _ecx: &mut EvalCtxt<'_, D>, |
| 438 | 441 | _goal: Goal<I, Self>, |
| 439 | ) -> Result<Candidate<I>, NoSolution> { | |
| 442 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 440 | 443 | unreachable!("BikeshedGuaranteedNoDrop is not const"); |
| 441 | 444 | } |
| 442 | 445 | |
| 443 | 446 | fn consider_structural_builtin_unsize_candidates( |
| 444 | 447 | _ecx: &mut EvalCtxt<'_, D>, |
| 445 | 448 | _goal: Goal<I, Self>, |
| 446 | ) -> Vec<Candidate<I>> { | |
| 449 | ) -> Result<Vec<Candidate<I>>, RerunNonErased> { | |
| 447 | 450 | unreachable!("Unsize is not const") |
| 448 | 451 | } |
| 449 | 452 | |
| 450 | 453 | fn consider_builtin_field_candidate( |
| 451 | 454 | _ecx: &mut EvalCtxt<'_, D>, |
| 452 | 455 | _goal: Goal<<D as SolverDelegate>::Interner, Self>, |
| 453 | ) -> Result<Candidate<<D as SolverDelegate>::Interner>, NoSolution> { | |
| 456 | ) -> Result<Candidate<<D as SolverDelegate>::Interner>, NoSolutionOrRerunNonErased> { | |
| 454 | 457 | unreachable!("Field is not const") |
| 455 | 458 | } |
| 456 | 459 | } |
| ... | ... | @@ -464,12 +467,17 @@ where |
| 464 | 467 | pub(super) fn compute_host_effect_goal( |
| 465 | 468 | &mut self, |
| 466 | 469 | goal: Goal<I, ty::HostEffectPredicate<I>>, |
| 467 | ) -> QueryResult<I> { | |
| 470 | ) -> QueryResultOrRerunNonErased<I> { | |
| 468 | 471 | let (_, proven_via) = self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| { |
| 469 | 472 | let trait_goal: Goal<I, ty::TraitPredicate<I>> = |
| 470 | 473 | goal.with(ecx.cx(), goal.predicate.trait_ref); |
| 471 | ecx.compute_trait_goal(trait_goal) | |
| 474 | ecx.compute_trait_goal(trait_goal).map_err(Into::into) | |
| 472 | 475 | })?; |
| 473 | self.assemble_and_merge_candidates(proven_via, goal, |_ecx| None, |_ecx| Err(NoSolution)) | |
| 476 | self.assemble_and_merge_candidates( | |
| 477 | proven_via, | |
| 478 | goal, | |
| 479 | |_ecx| None, | |
| 480 | |_ecx| Err(NoSolution.into()), | |
| 481 | ) | |
| 474 | 482 | } |
| 475 | 483 | } |
compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs+119-79| ... | ... | @@ -9,8 +9,9 @@ use rustc_type_ir::relate::Relate; |
| 9 | 9 | use rustc_type_ir::relate::solver_relating::RelateExt; |
| 10 | 10 | use rustc_type_ir::search_graph::{CandidateHeadUsages, PathKind}; |
| 11 | 11 | use rustc_type_ir::solve::{ |
| 12 | AccessedOpaques, FetchEligibleAssocItemResponse, MaybeInfo, OpaqueTypesJank, RerunCondition, | |
| 13 | RerunReason, SmallCopyList, | |
| 12 | AccessedOpaques, FetchEligibleAssocItemResponse, MaybeInfo, NoSolutionOrRerunNonErased, | |
| 13 | OpaqueTypesJank, QueryResultOrRerunNonErased, RerunCondition, RerunNonErased, RerunReason, | |
| 14 | RerunResultExt, SmallCopyList, | |
| 14 | 15 | }; |
| 15 | 16 | use rustc_type_ir::{ |
| 16 | 17 | self as ty, CanonicalVarValues, ClauseKind, InferCtxtLike, Interner, MayBeErased, |
| ... | ... | @@ -214,9 +215,17 @@ where |
| 214 | 215 | span: I::Span, |
| 215 | 216 | stalled_on: Option<GoalStalledOn<I>>, |
| 216 | 217 | ) -> Result<GoalEvaluation<I>, NoSolution> { |
| 217 | EvalCtxt::enter_root(self, self.cx().recursion_limit(), span, |ecx| { | |
| 218 | let result = EvalCtxt::enter_root(self, self.cx().recursion_limit(), span, |ecx| { | |
| 218 | 219 | ecx.evaluate_goal(GoalSource::Misc, goal, stalled_on) |
| 219 | }) | |
| 220 | }); | |
| 221 | ||
| 222 | match result { | |
| 223 | Ok(i) => Ok(i), | |
| 224 | Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution)) => Err(NoSolution), | |
| 225 | Err(NoSolutionOrRerunNonErased::RerunNonErased(_)) => { | |
| 226 | unreachable!("this never happens at the root, we're never in erased mode here"); | |
| 227 | } | |
| 228 | } | |
| 220 | 229 | } |
| 221 | 230 | |
| 222 | 231 | #[instrument(level = "debug", skip(self), ret)] |
| ... | ... | @@ -371,7 +380,10 @@ where |
| 371 | 380 | search_graph: &'a mut SearchGraph<D>, |
| 372 | 381 | canonical_input: CanonicalInput<I>, |
| 373 | 382 | proof_tree_builder: &mut inspect::ProofTreeBuilder<D>, |
| 374 | f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal<I, I::Predicate>) -> Result<T, NoSolution>, | |
| 383 | f: impl FnOnce( | |
| 384 | &mut EvalCtxt<'_, D>, | |
| 385 | Goal<I, I::Predicate>, | |
| 386 | ) -> Result<T, NoSolutionOrRerunNonErased>, | |
| 375 | 387 | ) -> (Result<T, NoSolution>, AccessedOpaques<I>) { |
| 376 | 388 | let (ref delegate, input, var_values) = D::build_with_canonical(cx, &canonical_input); |
| 377 | 389 | for (key, ty) in input.predefined_opaques_in_body.iter() { |
| ... | ... | @@ -427,7 +439,19 @@ where |
| 427 | 439 | // FIXME: Could we make `build_with_canonical` into `enter_with_canonical` and call this at the end? |
| 428 | 440 | delegate.reset_opaque_types(); |
| 429 | 441 | |
| 430 | (result, ecx.opaque_accesses) | |
| 442 | let opaque_accesses = ecx.opaque_accesses; | |
| 443 | ( | |
| 444 | match result { | |
| 445 | Ok(i) => Ok(i), | |
| 446 | Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution)) => Err(NoSolution), | |
| 447 | Err(NoSolutionOrRerunNonErased::RerunNonErased(_)) => { | |
| 448 | // check th t the opaque_accesses state mirrors the result we got. | |
| 449 | assert!(opaque_accesses.should_bail().is_err()); | |
| 450 | Err(NoSolution) | |
| 451 | } | |
| 452 | }, | |
| 453 | opaque_accesses, | |
| 454 | ) | |
| 431 | 455 | } |
| 432 | 456 | |
| 433 | 457 | pub(super) fn ignore_candidate_head_usages(&mut self, usages: CandidateHeadUsages) { |
| ... | ... | @@ -441,7 +465,7 @@ where |
| 441 | 465 | source: GoalSource, |
| 442 | 466 | goal: Goal<I, I::Predicate>, |
| 443 | 467 | stalled_on: Option<GoalStalledOn<I>>, |
| 444 | ) -> Result<GoalEvaluation<I>, NoSolution> { | |
| 468 | ) -> Result<GoalEvaluation<I>, NoSolutionOrRerunNonErased> { | |
| 445 | 469 | let (normalization_nested_goals, goal_evaluation) = |
| 446 | 470 | self.evaluate_goal_raw(source, goal, stalled_on)?; |
| 447 | 471 | assert!(normalization_nested_goals.is_empty()); |
| ... | ... | @@ -460,7 +484,7 @@ where |
| 460 | 484 | source: GoalSource, |
| 461 | 485 | goal: Goal<I, I::Predicate>, |
| 462 | 486 | stalled_on: Option<GoalStalledOn<I>>, |
| 463 | ) -> Result<(NestedNormalizationGoals<I>, GoalEvaluation<I>), NoSolution> { | |
| 487 | ) -> Result<(NestedNormalizationGoals<I>, GoalEvaluation<I>), NoSolutionOrRerunNonErased> { | |
| 464 | 488 | // If we have run this goal before, and it was stalled, check that any of the goal's |
| 465 | 489 | // args have changed. Otherwise, we don't need to re-run the goal because it'll remain |
| 466 | 490 | // stalled, since it'll canonicalize the same way and evaluation is pure. |
| ... | ... | @@ -532,9 +556,7 @@ where |
| 532 | 556 | |
| 533 | 557 | if skip_erased_attempt { |
| 534 | 558 | if typing_mode.is_erased_not_coherence() { |
| 535 | self.opaque_accesses.rerun_always(RerunReason::SkipErasedAttempt); | |
| 536 | // FIXME(#155443): We should differentiate between `NoSolution` and force rerun here. | |
| 537 | return Err(NoSolution); | |
| 559 | match self.opaque_accesses.rerun_always(RerunReason::SkipErasedAttempt)? {} | |
| 538 | 560 | } else { |
| 539 | 561 | debug!("running in original typing mode"); |
| 540 | 562 | } |
| ... | ... | @@ -566,7 +588,7 @@ where |
| 566 | 588 | break 'retry_canonicalize (canonical_result, orig_values, canonical_goal); |
| 567 | 589 | } |
| 568 | 590 | RerunDecision::EagerlyPropagateToParent => { |
| 569 | self.opaque_accesses.update(accessed_opaques); | |
| 591 | self.opaque_accesses.update(accessed_opaques)?; | |
| 570 | 592 | break 'retry_canonicalize (canonical_result, orig_values, canonical_goal); |
| 571 | 593 | } |
| 572 | 594 | } |
| ... | ... | @@ -590,7 +612,16 @@ where |
| 590 | 612 | }; |
| 591 | 613 | |
| 592 | 614 | debug!(?result); |
| 593 | let response = result?; | |
| 615 | let response = match result { | |
| 616 | Ok(response) => { | |
| 617 | debug!("success"); | |
| 618 | response | |
| 619 | } | |
| 620 | Err(NoSolution) => { | |
| 621 | debug!("normal failure"); | |
| 622 | return Err(NoSolution.into()); | |
| 623 | } | |
| 624 | }; | |
| 594 | 625 | |
| 595 | 626 | drop(tracing_span); |
| 596 | 627 | |
| ... | ... | @@ -786,72 +817,81 @@ where |
| 786 | 817 | res |
| 787 | 818 | } |
| 788 | 819 | |
| 789 | pub(super) fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> { | |
| 820 | pub(super) fn compute_goal( | |
| 821 | &mut self, | |
| 822 | goal: Goal<I, I::Predicate>, | |
| 823 | ) -> QueryResultOrRerunNonErased<I> { | |
| 790 | 824 | let Goal { param_env, predicate } = goal; |
| 791 | 825 | let kind = predicate.kind(); |
| 792 | self.enter_forall(kind, |ecx, kind| match kind { | |
| 793 | ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { | |
| 794 | ecx.compute_trait_goal(Goal { param_env, predicate }).map(|(r, _via)| r) | |
| 795 | } | |
| 796 | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => { | |
| 797 | ecx.compute_host_effect_goal(Goal { param_env, predicate }) | |
| 798 | } | |
| 799 | ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => { | |
| 800 | ecx.compute_projection_goal(Goal { param_env, predicate }) | |
| 801 | } | |
| 802 | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => { | |
| 803 | ecx.compute_type_outlives_goal(Goal { param_env, predicate }) | |
| 804 | } | |
| 805 | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => { | |
| 806 | ecx.compute_region_outlives_goal(Goal { param_env, predicate }) | |
| 807 | } | |
| 808 | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { | |
| 809 | ecx.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) }) | |
| 810 | } | |
| 811 | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { | |
| 812 | ecx.compute_unstable_feature_goal(param_env, symbol) | |
| 813 | } | |
| 814 | ty::PredicateKind::Subtype(predicate) => { | |
| 815 | ecx.compute_subtype_goal(Goal { param_env, predicate }) | |
| 816 | } | |
| 817 | ty::PredicateKind::Coerce(predicate) => { | |
| 818 | ecx.compute_coerce_goal(Goal { param_env, predicate }) | |
| 819 | } | |
| 820 | ty::PredicateKind::DynCompatible(trait_def_id) => { | |
| 821 | ecx.compute_dyn_compatible_goal(trait_def_id) | |
| 822 | } | |
| 823 | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => { | |
| 824 | ecx.compute_well_formed_goal(Goal { param_env, predicate: term }) | |
| 825 | } | |
| 826 | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => { | |
| 827 | ecx.compute_const_evaluatable_goal(Goal { param_env, predicate: ct }) | |
| 828 | } | |
| 829 | ty::PredicateKind::ConstEquate(_, _) => { | |
| 830 | panic!("ConstEquate should not be emitted when `-Znext-solver` is active") | |
| 831 | } | |
| 832 | ty::PredicateKind::NormalizesTo(predicate) => { | |
| 833 | ecx.compute_normalizes_to_goal(Goal { param_env, predicate }) | |
| 834 | } | |
| 835 | ty::PredicateKind::AliasRelate(lhs, rhs, direction) => { | |
| 836 | ecx.compute_alias_relate_goal(Goal { param_env, predicate: (lhs, rhs, direction) }) | |
| 837 | } | |
| 838 | ty::PredicateKind::Ambiguous => { | |
| 839 | ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) | |
| 840 | } | |
| 826 | self.enter_forall(kind, |ecx, kind| { | |
| 827 | Ok(match kind { | |
| 828 | ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { | |
| 829 | ecx.compute_trait_goal(Goal { param_env, predicate }).map(|(r, _via)| r)? | |
| 830 | } | |
| 831 | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => { | |
| 832 | ecx.compute_host_effect_goal(Goal { param_env, predicate })? | |
| 833 | } | |
| 834 | ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => { | |
| 835 | ecx.compute_projection_goal(Goal { param_env, predicate })? | |
| 836 | } | |
| 837 | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => { | |
| 838 | ecx.compute_type_outlives_goal(Goal { param_env, predicate })? | |
| 839 | } | |
| 840 | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => { | |
| 841 | ecx.compute_region_outlives_goal(Goal { param_env, predicate })? | |
| 842 | } | |
| 843 | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { | |
| 844 | ecx.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) })? | |
| 845 | } | |
| 846 | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { | |
| 847 | ecx.compute_unstable_feature_goal(param_env, symbol)? | |
| 848 | } | |
| 849 | ty::PredicateKind::Subtype(predicate) => { | |
| 850 | ecx.compute_subtype_goal(Goal { param_env, predicate })? | |
| 851 | } | |
| 852 | ty::PredicateKind::Coerce(predicate) => { | |
| 853 | ecx.compute_coerce_goal(Goal { param_env, predicate })? | |
| 854 | } | |
| 855 | ty::PredicateKind::DynCompatible(trait_def_id) => { | |
| 856 | ecx.compute_dyn_compatible_goal(trait_def_id)? | |
| 857 | } | |
| 858 | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => { | |
| 859 | ecx.compute_well_formed_goal(Goal { param_env, predicate: term })? | |
| 860 | } | |
| 861 | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => { | |
| 862 | ecx.compute_const_evaluatable_goal(Goal { param_env, predicate: ct })? | |
| 863 | } | |
| 864 | ty::PredicateKind::ConstEquate(_, _) => { | |
| 865 | panic!("ConstEquate should not be emitted when `-Znext-solver` is active") | |
| 866 | } | |
| 867 | ty::PredicateKind::NormalizesTo(predicate) => { | |
| 868 | ecx.compute_normalizes_to_goal(Goal { param_env, predicate })? | |
| 869 | } | |
| 870 | ty::PredicateKind::AliasRelate(lhs, rhs, direction) => ecx | |
| 871 | .compute_alias_relate_goal(Goal { | |
| 872 | param_env, | |
| 873 | predicate: (lhs, rhs, direction), | |
| 874 | })?, | |
| 875 | ty::PredicateKind::Ambiguous => { | |
| 876 | ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)? | |
| 877 | } | |
| 878 | }) | |
| 841 | 879 | }) |
| 842 | 880 | } |
| 843 | 881 | |
| 844 | 882 | // Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning |
| 845 | 883 | // the certainty of all the goals. |
| 846 | 884 | #[instrument(level = "trace", skip(self))] |
| 847 | pub(super) fn try_evaluate_added_goals(&mut self) -> Result<Certainty, NoSolution> { | |
| 885 | pub(super) fn try_evaluate_added_goals( | |
| 886 | &mut self, | |
| 887 | ) -> Result<Certainty, NoSolutionOrRerunNonErased> { | |
| 848 | 888 | for _ in 0..FIXPOINT_STEP_LIMIT { |
| 849 | match self.evaluate_added_goals_step() { | |
| 889 | match self.evaluate_added_goals_step().map_err_to_rerun()? { | |
| 850 | 890 | Ok(None) => {} |
| 851 | 891 | Ok(Some(cert)) => return Ok(cert), |
| 852 | 892 | Err(NoSolution) => { |
| 853 | 893 | self.tainted = Err(NoSolution); |
| 854 | return Err(NoSolution); | |
| 894 | return Err(NoSolution.into()); | |
| 855 | 895 | } |
| 856 | 896 | } |
| 857 | 897 | } |
| ... | ... | @@ -863,7 +903,9 @@ where |
| 863 | 903 | /// Iterate over all added goals: returning `Ok(Some(_))` in case we can stop rerunning. |
| 864 | 904 | /// |
| 865 | 905 | /// Goals for the next step get directly added to the nested goals of the `EvalCtxt`. |
| 866 | fn evaluate_added_goals_step(&mut self) -> Result<Option<Certainty>, NoSolution> { | |
| 906 | fn evaluate_added_goals_step( | |
| 907 | &mut self, | |
| 908 | ) -> Result<Option<Certainty>, NoSolutionOrRerunNonErased> { | |
| 867 | 909 | let cx = self.cx(); |
| 868 | 910 | // If this loop did not result in any progress, what's our final certainty. |
| 869 | 911 | let mut unchanged_certainty = Some(Certainty::Yes); |
| ... | ... | @@ -1347,7 +1389,7 @@ where |
| 1347 | 1389 | &mut self, |
| 1348 | 1390 | param_env: I::ParamEnv, |
| 1349 | 1391 | trait_ref: ty::TraitRef<I>, |
| 1350 | ) -> Result<bool, NoSolution> { | |
| 1392 | ) -> Result<bool, NoSolutionOrRerunNonErased> { | |
| 1351 | 1393 | let delegate = self.delegate; |
| 1352 | 1394 | let lazily_normalize_ty = |ty| self.structurally_normalize_ty(param_env, ty); |
| 1353 | 1395 | coherence::trait_ref_is_knowable(&**delegate, trait_ref, lazily_normalize_ty) |
| ... | ... | @@ -1397,21 +1439,20 @@ where |
| 1397 | 1439 | &mut self, |
| 1398 | 1440 | param_env: I::ParamEnv, |
| 1399 | 1441 | uv: ty::UnevaluatedConst<I>, |
| 1400 | ) -> Option<I::Const> { | |
| 1442 | ) -> Result<Option<I::Const>, RerunNonErased> { | |
| 1401 | 1443 | if self.typing_mode().is_erased_not_coherence() { |
| 1402 | self.opaque_accesses.rerun_always(RerunReason::EvaluateConst); | |
| 1403 | return None; | |
| 1444 | self.opaque_accesses.rerun_always(RerunReason::EvaluateConst)?; | |
| 1404 | 1445 | } |
| 1405 | 1446 | |
| 1406 | self.delegate.evaluate_const(param_env, uv) | |
| 1447 | Ok(self.delegate.evaluate_const(param_env, uv)) | |
| 1407 | 1448 | } |
| 1408 | 1449 | |
| 1409 | 1450 | pub(super) fn evaluate_const_and_instantiate_normalizes_to_term( |
| 1410 | 1451 | &mut self, |
| 1411 | 1452 | goal: Goal<I, ty::NormalizesTo<I>>, |
| 1412 | 1453 | uv: ty::UnevaluatedConst<I>, |
| 1413 | ) -> QueryResult<I> { | |
| 1414 | match self.evaluate_const(goal.param_env, uv) { | |
| 1454 | ) -> QueryResultOrRerunNonErased<I> { | |
| 1455 | match self.evaluate_const(goal.param_env, uv)? { | |
| 1415 | 1456 | Some(evaluated) => { |
| 1416 | 1457 | self.instantiate_normalizes_to_term(goal, evaluated.into()); |
| 1417 | 1458 | self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| ... | ... | @@ -1465,13 +1506,12 @@ where |
| 1465 | 1506 | &mut self, |
| 1466 | 1507 | param_env: I::ParamEnv, |
| 1467 | 1508 | symbol: I::Symbol, |
| 1468 | ) -> bool { | |
| 1509 | ) -> Result<bool, RerunNonErased> { | |
| 1469 | 1510 | if self.typing_mode().is_erased_not_coherence() { |
| 1470 | self.opaque_accesses.rerun_always(RerunReason::MayUseUnstableFeature); | |
| 1471 | return false; | |
| 1511 | self.opaque_accesses.rerun_always(RerunReason::MayUseUnstableFeature)?; | |
| 1472 | 1512 | } |
| 1473 | 1513 | |
| 1474 | may_use_unstable_feature(&**self.delegate, param_env, symbol) | |
| 1514 | Ok(may_use_unstable_feature(&**self.delegate, param_env, symbol)) | |
| 1475 | 1515 | } |
| 1476 | 1516 | |
| 1477 | 1517 | pub(crate) fn opaques_with_sub_unified_hidden_type( |
| ... | ... | @@ -1502,7 +1542,7 @@ where |
| 1502 | 1542 | pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response( |
| 1503 | 1543 | &mut self, |
| 1504 | 1544 | shallow_certainty: Certainty, |
| 1505 | ) -> QueryResult<I> { | |
| 1545 | ) -> QueryResultOrRerunNonErased<I> { | |
| 1506 | 1546 | self.inspect.make_canonical_response(shallow_certainty); |
| 1507 | 1547 | |
| 1508 | 1548 | let goals_certainty = self.try_evaluate_added_goals()?; |
compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs+24-18| ... | ... | @@ -1,7 +1,9 @@ |
| 1 | 1 | use std::marker::PhantomData; |
| 2 | 2 | |
| 3 | 3 | use rustc_type_ir::search_graph::CandidateHeadUsages; |
| 4 | use rustc_type_ir::solve::{AccessedOpaques, CanonicalResponse, NoSolutionOrOpaquesAccessed}; | |
| 4 | use rustc_type_ir::solve::{ | |
| 5 | AccessedOpaques, CanonicalResponse, NoSolutionOrRerunNonErased, RerunResultExt, | |
| 6 | }; | |
| 5 | 7 | use rustc_type_ir::{InferCtxtLike, Interner}; |
| 6 | 8 | use tracing::{instrument, warn}; |
| 7 | 9 | |
| ... | ... | @@ -30,12 +32,12 @@ where |
| 30 | 32 | { |
| 31 | 33 | pub(in crate::solve) fn enter_single_candidate( |
| 32 | 34 | self, |
| 33 | f: impl FnOnce(&mut EvalCtxt<'_, D>) -> Result<T, NoSolution>, | |
| 34 | ) -> (Result<T, NoSolutionOrOpaquesAccessed>, CandidateHeadUsages) { | |
| 35 | f: impl FnOnce(&mut EvalCtxt<'_, D>) -> Result<T, NoSolutionOrRerunNonErased>, | |
| 36 | ) -> (Result<T, NoSolutionOrRerunNonErased>, CandidateHeadUsages) { | |
| 35 | 37 | let mut candidate_usages = CandidateHeadUsages::default(); |
| 36 | 38 | |
| 37 | if self.ecx.opaque_accesses.should_bail() { | |
| 38 | return (Err(NoSolutionOrOpaquesAccessed::OpaquesAccessed), candidate_usages); | |
| 39 | if let Err(e) = self.ecx.opaque_accesses.should_bail() { | |
| 40 | return (Err(e.into()), candidate_usages); | |
| 39 | 41 | } |
| 40 | 42 | |
| 41 | 43 | self.ecx.search_graph.enter_single_candidate(); |
| ... | ... | @@ -49,29 +51,27 @@ where |
| 49 | 51 | |
| 50 | 52 | pub(in crate::solve) fn enter( |
| 51 | 53 | self, |
| 52 | f: impl FnOnce(&mut EvalCtxt<'_, D>) -> Result<T, NoSolution>, | |
| 53 | ) -> Result<T, NoSolutionOrOpaquesAccessed> { | |
| 54 | f: impl FnOnce(&mut EvalCtxt<'_, D>) -> Result<T, NoSolutionOrRerunNonErased>, | |
| 55 | ) -> Result<T, NoSolutionOrRerunNonErased> { | |
| 54 | 56 | let nested_goals = self.ecx.nested_goals.clone(); |
| 55 | 57 | self.enter_inner(f, nested_goals) |
| 56 | 58 | } |
| 57 | 59 | |
| 58 | 60 | pub(in crate::solve) fn enter_without_propagated_nested_goals( |
| 59 | 61 | self, |
| 60 | f: impl FnOnce(&mut EvalCtxt<'_, D>) -> Result<T, NoSolution>, | |
| 61 | ) -> Result<T, NoSolutionOrOpaquesAccessed> { | |
| 62 | f: impl FnOnce(&mut EvalCtxt<'_, D>) -> Result<T, NoSolutionOrRerunNonErased>, | |
| 63 | ) -> Result<T, NoSolutionOrRerunNonErased> { | |
| 62 | 64 | self.enter_inner(f, Default::default()) |
| 63 | 65 | } |
| 64 | 66 | |
| 65 | 67 | pub(in crate::solve) fn enter_inner( |
| 66 | 68 | self, |
| 67 | f: impl FnOnce(&mut EvalCtxt<'_, D>) -> Result<T, NoSolution>, | |
| 69 | f: impl FnOnce(&mut EvalCtxt<'_, D>) -> Result<T, NoSolutionOrRerunNonErased>, | |
| 68 | 70 | propagated_nested_goals: Vec<(GoalSource, Goal<I, I::Predicate>, Option<GoalStalledOn<I>>)>, |
| 69 | ) -> Result<T, NoSolutionOrOpaquesAccessed> { | |
| 71 | ) -> Result<T, NoSolutionOrRerunNonErased> { | |
| 70 | 72 | let ProbeCtxt { ecx: outer, probe_kind, _result } = self; |
| 71 | 73 | |
| 72 | if outer.opaque_accesses.should_bail() { | |
| 73 | return Err(NoSolutionOrOpaquesAccessed::OpaquesAccessed); | |
| 74 | } | |
| 74 | outer.opaque_accesses.should_bail()?; | |
| 75 | 75 | |
| 76 | 76 | let delegate = outer.delegate; |
| 77 | 77 | let max_input_universe = outer.max_input_universe; |
| ... | ... | @@ -95,14 +95,20 @@ where |
| 95 | 95 | nested.inspect.probe_final_state(delegate, max_input_universe); |
| 96 | 96 | r |
| 97 | 97 | }); |
| 98 | ||
| 99 | outer.opaque_accesses.update(nested.opaque_accesses)?; | |
| 100 | ||
| 101 | let r = match r.map_err_to_rerun()? { | |
| 102 | Ok(i) => Ok(i), | |
| 103 | Err(NoSolution) => Err(NoSolution), | |
| 104 | }; | |
| 105 | ||
| 98 | 106 | if !nested.inspect.is_noop() { |
| 99 | 107 | let probe_kind = probe_kind(&r); |
| 100 | 108 | nested.inspect.probe_kind(probe_kind); |
| 101 | 109 | outer.inspect = nested.inspect.finish_probe(); |
| 102 | 110 | } |
| 103 | 111 | |
| 104 | outer.opaque_accesses.update(nested.opaque_accesses); | |
| 105 | ||
| 106 | 112 | r.map_err(Into::into) |
| 107 | 113 | } |
| 108 | 114 | } |
| ... | ... | @@ -125,8 +131,8 @@ where |
| 125 | 131 | #[instrument(level = "debug", skip_all, fields(source = ?self.source))] |
| 126 | 132 | pub(in crate::solve) fn enter( |
| 127 | 133 | self, |
| 128 | f: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>, | |
| 129 | ) -> Result<Candidate<I>, NoSolution> { | |
| 134 | f: impl FnOnce(&mut EvalCtxt<'_, D>) -> Result<CanonicalResponse<I>, NoSolutionOrRerunNonErased>, | |
| 135 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 130 | 136 | let (result, head_usages) = self.cx.enter_single_candidate(f); |
| 131 | 137 | Ok(Candidate { source: self.source, result: result?, head_usages }) |
| 132 | 138 | } |
compiler/rustc_next_trait_solver/src/solve/mod.rs+34-18| ... | ... | @@ -89,7 +89,7 @@ where |
| 89 | 89 | fn compute_type_outlives_goal( |
| 90 | 90 | &mut self, |
| 91 | 91 | goal: Goal<I, ty::OutlivesPredicate<I, I::Ty>>, |
| 92 | ) -> QueryResult<I> { | |
| 92 | ) -> QueryResultOrRerunNonErased<I> { | |
| 93 | 93 | let ty::OutlivesPredicate(ty, lt) = goal.predicate; |
| 94 | 94 | self.register_ty_outlives(ty, lt); |
| 95 | 95 | self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| ... | ... | @@ -99,14 +99,17 @@ where |
| 99 | 99 | fn compute_region_outlives_goal( |
| 100 | 100 | &mut self, |
| 101 | 101 | goal: Goal<I, ty::OutlivesPredicate<I, I::Region>>, |
| 102 | ) -> QueryResult<I> { | |
| 102 | ) -> QueryResultOrRerunNonErased<I> { | |
| 103 | 103 | let ty::OutlivesPredicate(a, b) = goal.predicate; |
| 104 | 104 | self.register_region_outlives(a, b, VisibleForLeakCheck::Yes); |
| 105 | 105 | self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| 106 | 106 | } |
| 107 | 107 | |
| 108 | 108 | #[instrument(level = "trace", skip(self))] |
| 109 | fn compute_coerce_goal(&mut self, goal: Goal<I, ty::CoercePredicate<I>>) -> QueryResult<I> { | |
| 109 | fn compute_coerce_goal( | |
| 110 | &mut self, | |
| 111 | goal: Goal<I, ty::CoercePredicate<I>>, | |
| 112 | ) -> QueryResultOrRerunNonErased<I> { | |
| 110 | 113 | self.compute_subtype_goal(Goal { |
| 111 | 114 | param_env: goal.param_env, |
| 112 | 115 | predicate: ty::SubtypePredicate { |
| ... | ... | @@ -118,7 +121,10 @@ where |
| 118 | 121 | } |
| 119 | 122 | |
| 120 | 123 | #[instrument(level = "trace", skip(self))] |
| 121 | fn compute_subtype_goal(&mut self, goal: Goal<I, ty::SubtypePredicate<I>>) -> QueryResult<I> { | |
| 124 | fn compute_subtype_goal( | |
| 125 | &mut self, | |
| 126 | goal: Goal<I, ty::SubtypePredicate<I>>, | |
| 127 | ) -> QueryResultOrRerunNonErased<I> { | |
| 122 | 128 | match (goal.predicate.a.kind(), goal.predicate.b.kind()) { |
| 123 | 129 | (ty::Infer(ty::TyVar(a_vid)), ty::Infer(ty::TyVar(b_vid))) => { |
| 124 | 130 | self.sub_unify_ty_vids_raw(a_vid, b_vid); |
| ... | ... | @@ -131,16 +137,22 @@ where |
| 131 | 137 | } |
| 132 | 138 | } |
| 133 | 139 | |
| 134 | fn compute_dyn_compatible_goal(&mut self, trait_def_id: I::TraitId) -> QueryResult<I> { | |
| 140 | fn compute_dyn_compatible_goal( | |
| 141 | &mut self, | |
| 142 | trait_def_id: I::TraitId, | |
| 143 | ) -> QueryResultOrRerunNonErased<I> { | |
| 135 | 144 | if self.cx().trait_is_dyn_compatible(trait_def_id) { |
| 136 | 145 | self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| 137 | 146 | } else { |
| 138 | Err(NoSolution) | |
| 147 | Err(NoSolution.into()) | |
| 139 | 148 | } |
| 140 | 149 | } |
| 141 | 150 | |
| 142 | 151 | #[instrument(level = "trace", skip(self))] |
| 143 | fn compute_well_formed_goal(&mut self, goal: Goal<I, I::Term>) -> QueryResult<I> { | |
| 152 | fn compute_well_formed_goal( | |
| 153 | &mut self, | |
| 154 | goal: Goal<I, I::Term>, | |
| 155 | ) -> QueryResultOrRerunNonErased<I> { | |
| 144 | 156 | match self.well_formed_goals(goal.param_env, goal.predicate) { |
| 145 | 157 | Some(goals) => { |
| 146 | 158 | self.add_goals(GoalSource::Misc, goals); |
| ... | ... | @@ -154,8 +166,8 @@ where |
| 154 | 166 | &mut self, |
| 155 | 167 | param_env: <I as Interner>::ParamEnv, |
| 156 | 168 | symbol: <I as Interner>::Symbol, |
| 157 | ) -> QueryResult<I> { | |
| 158 | if self.may_use_unstable_feature(param_env, symbol) { | |
| 169 | ) -> QueryResultOrRerunNonErased<I> { | |
| 170 | if self.may_use_unstable_feature(param_env, symbol)? { | |
| 159 | 171 | self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| 160 | 172 | } else { |
| 161 | 173 | self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) |
| ... | ... | @@ -166,7 +178,7 @@ where |
| 166 | 178 | fn compute_const_evaluatable_goal( |
| 167 | 179 | &mut self, |
| 168 | 180 | Goal { param_env, predicate: ct }: Goal<I, I::Const>, |
| 169 | ) -> QueryResult<I> { | |
| 181 | ) -> QueryResultOrRerunNonErased<I> { | |
| 170 | 182 | match ct.kind() { |
| 171 | 183 | ty::ConstKind::Unevaluated(uv) => { |
| 172 | 184 | // We never return `NoSolution` here as `evaluate_const` emits an |
| ... | ... | @@ -177,7 +189,7 @@ where |
| 177 | 189 | |
| 178 | 190 | // FIXME(generic_const_exprs): Implement handling for generic |
| 179 | 191 | // const expressions here. |
| 180 | if let Some(_normalized) = self.evaluate_const(param_env, uv) { | |
| 192 | if let Some(_normalized) = self.evaluate_const(param_env, uv)? { | |
| 181 | 193 | self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| 182 | 194 | } else { |
| 183 | 195 | self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) |
| ... | ... | @@ -203,16 +215,20 @@ where |
| 203 | 215 | fn compute_const_arg_has_type_goal( |
| 204 | 216 | &mut self, |
| 205 | 217 | goal: Goal<I, (I::Const, I::Ty)>, |
| 206 | ) -> QueryResult<I> { | |
| 218 | ) -> QueryResultOrRerunNonErased<I> { | |
| 207 | 219 | let (ct, ty) = goal.predicate; |
| 208 | 220 | let ct = self.structurally_normalize_const(goal.param_env, ct)?; |
| 209 | 221 | |
| 210 | 222 | let ct_ty = match ct.kind() { |
| 211 | 223 | ty::ConstKind::Infer(_) => { |
| 212 | return self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); | |
| 224 | return self | |
| 225 | .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) | |
| 226 | .map_err(Into::into); | |
| 213 | 227 | } |
| 214 | 228 | ty::ConstKind::Error(_) => { |
| 215 | return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); | |
| 229 | return self | |
| 230 | .evaluate_added_goals_and_make_canonical_response(Certainty::Yes) | |
| 231 | .map_err(Into::into); | |
| 216 | 232 | } |
| 217 | 233 | ty::ConstKind::Unevaluated(uv) => { |
| 218 | 234 | self.cx().type_of(uv.def.into()).instantiate(self.cx(), uv.args).skip_norm_wip() |
| ... | ... | @@ -231,7 +247,7 @@ where |
| 231 | 247 | }; |
| 232 | 248 | |
| 233 | 249 | self.eq(goal.param_env, ct_ty, ty)?; |
| 234 | self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) | |
| 250 | self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes).map_err(Into::into) | |
| 235 | 251 | } |
| 236 | 252 | } |
| 237 | 253 | |
| ... | ... | @@ -308,7 +324,7 @@ where |
| 308 | 324 | &mut self, |
| 309 | 325 | param_env: I::ParamEnv, |
| 310 | 326 | ty: I::Ty, |
| 311 | ) -> Result<I::Ty, NoSolution> { | |
| 327 | ) -> Result<I::Ty, NoSolutionOrRerunNonErased> { | |
| 312 | 328 | self.structurally_normalize_term(param_env, ty.into()).map(|term| term.expect_ty()) |
| 313 | 329 | } |
| 314 | 330 | |
| ... | ... | @@ -323,7 +339,7 @@ where |
| 323 | 339 | &mut self, |
| 324 | 340 | param_env: I::ParamEnv, |
| 325 | 341 | ct: I::Const, |
| 326 | ) -> Result<I::Const, NoSolution> { | |
| 342 | ) -> Result<I::Const, NoSolutionOrRerunNonErased> { | |
| 327 | 343 | self.structurally_normalize_term(param_env, ct.into()).map(|term| term.expect_const()) |
| 328 | 344 | } |
| 329 | 345 | |
| ... | ... | @@ -335,7 +351,7 @@ where |
| 335 | 351 | &mut self, |
| 336 | 352 | param_env: I::ParamEnv, |
| 337 | 353 | term: I::Term, |
| 338 | ) -> Result<I::Term, NoSolution> { | |
| 354 | ) -> Result<I::Term, NoSolutionOrRerunNonErased> { | |
| 339 | 355 | if let Some(_) = term.to_alias_term(self.cx()) { |
| 340 | 356 | let normalized_term = self.next_term_infer_of_kind(term); |
| 341 | 357 | let alias_relate_goal = Goal::new( |
compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs+3-2| ... | ... | @@ -1,8 +1,9 @@ |
| 1 | use rustc_type_ir::solve::QueryResultOrRerunNonErased; | |
| 1 | 2 | use rustc_type_ir::{self as ty, Interner}; |
| 2 | 3 | use tracing::instrument; |
| 3 | 4 | |
| 4 | 5 | use crate::delegate::SolverDelegate; |
| 5 | use crate::solve::{EvalCtxt, Goal, QueryResult}; | |
| 6 | use crate::solve::{EvalCtxt, Goal}; | |
| 6 | 7 | |
| 7 | 8 | impl<D, I> EvalCtxt<'_, D> |
| 8 | 9 | where |
| ... | ... | @@ -14,7 +15,7 @@ where |
| 14 | 15 | &mut self, |
| 15 | 16 | goal: Goal<I, ty::NormalizesTo<I>>, |
| 16 | 17 | def_id: I::UnevaluatedConstId, |
| 17 | ) -> QueryResult<I> { | |
| 18 | ) -> QueryResultOrRerunNonErased<I> { | |
| 18 | 19 | let uv = goal.predicate.alias.expect_ct(self.cx()); |
| 19 | 20 | self.evaluate_const_and_instantiate_normalizes_to_term(goal, uv) |
| 20 | 21 | } |
compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs+3-2| ... | ... | @@ -4,10 +4,11 @@ |
| 4 | 4 | //! Since a free alias is never ambiguous, this just computes the `type_of` of |
| 5 | 5 | //! the alias and registers the where-clauses of the type alias. |
| 6 | 6 | |
| 7 | use rustc_type_ir::solve::QueryResultOrRerunNonErased; | |
| 7 | 8 | use rustc_type_ir::{self as ty, Interner, Unnormalized}; |
| 8 | 9 | |
| 9 | 10 | use crate::delegate::SolverDelegate; |
| 10 | use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult}; | |
| 11 | use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource}; | |
| 11 | 12 | |
| 12 | 13 | impl<D, I> EvalCtxt<'_, D> |
| 13 | 14 | where |
| ... | ... | @@ -17,7 +18,7 @@ where |
| 17 | 18 | pub(super) fn normalize_free_alias( |
| 18 | 19 | &mut self, |
| 19 | 20 | goal: Goal<I, ty::NormalizesTo<I>>, |
| 20 | ) -> QueryResult<I> { | |
| 21 | ) -> QueryResultOrRerunNonErased<I> { | |
| 21 | 22 | let cx = self.cx(); |
| 22 | 23 | let free_alias = goal.predicate.alias; |
| 23 | 24 |
compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs+3-2| ... | ... | @@ -5,10 +5,11 @@ |
| 5 | 5 | //! 2. equate the self type, and |
| 6 | 6 | //! 3. instantiate and register where clauses. |
| 7 | 7 | |
| 8 | use rustc_type_ir::solve::QueryResultOrRerunNonErased; | |
| 8 | 9 | use rustc_type_ir::{self as ty, Interner, Unnormalized}; |
| 9 | 10 | |
| 10 | 11 | use crate::delegate::SolverDelegate; |
| 11 | use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult}; | |
| 12 | use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource}; | |
| 12 | 13 | |
| 13 | 14 | impl<D, I> EvalCtxt<'_, D> |
| 14 | 15 | where |
| ... | ... | @@ -19,7 +20,7 @@ where |
| 19 | 20 | &mut self, |
| 20 | 21 | goal: Goal<I, ty::NormalizesTo<I>>, |
| 21 | 22 | def_id: I::InherentAssocTermId, |
| 22 | ) -> QueryResult<I> { | |
| 23 | ) -> QueryResultOrRerunNonErased<I> { | |
| 23 | 24 | let cx = self.cx(); |
| 24 | 25 | let inherent = goal.predicate.alias; |
| 25 | 26 |
compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs+79-58| ... | ... | @@ -6,7 +6,10 @@ mod opaque_types; |
| 6 | 6 | use rustc_type_ir::fast_reject::DeepRejectCtxt; |
| 7 | 7 | use rustc_type_ir::inherent::*; |
| 8 | 8 | use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverProjectionLangItem, SolverTraitLangItem}; |
| 9 | use rustc_type_ir::solve::{FetchEligibleAssocItemResponse, RerunReason}; | |
| 9 | use rustc_type_ir::solve::{ | |
| 10 | FetchEligibleAssocItemResponse, NoSolutionOrRerunNonErased, QueryResultOrRerunNonErased, | |
| 11 | RerunNonErased, RerunReason, RerunResultExt, | |
| 12 | }; | |
| 10 | 13 | use rustc_type_ir::{ |
| 11 | 14 | self as ty, FieldInfo, Interner, NormalizesTo, PredicateKind, Unnormalized, Upcast as _, |
| 12 | 15 | }; |
| ... | ... | @@ -18,7 +21,7 @@ use crate::solve::assembly::{self, Candidate}; |
| 18 | 21 | use crate::solve::inspect::ProbeKind; |
| 19 | 22 | use crate::solve::{ |
| 20 | 23 | BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeInfo, |
| 21 | NoSolution, QueryResult, SizedTraitKind, | |
| 24 | NoSolution, SizedTraitKind, | |
| 22 | 25 | }; |
| 23 | 26 | |
| 24 | 27 | impl<D, I> EvalCtxt<'_, D> |
| ... | ... | @@ -30,7 +33,7 @@ where |
| 30 | 33 | pub(super) fn compute_normalizes_to_goal( |
| 31 | 34 | &mut self, |
| 32 | 35 | goal: Goal<I, NormalizesTo<I>>, |
| 33 | ) -> QueryResult<I> { | |
| 36 | ) -> QueryResultOrRerunNonErased<I> { | |
| 34 | 37 | debug_assert!(self.term_is_fully_unconstrained(goal)); |
| 35 | 38 | match goal.predicate.alias.kind { |
| 36 | 39 | ty::AliasTermKind::ProjectionTy { .. } | ty::AliasTermKind::ProjectionConst { .. } => { |
| ... | ... | @@ -44,15 +47,18 @@ where |
| 44 | 47 | } |
| 45 | 48 | ty::AliasTermKind::OpaqueTy { def_id } => self.normalize_opaque_type(goal, def_id), |
| 46 | 49 | ty::AliasTermKind::FreeTy { .. } | ty::AliasTermKind::FreeConst { .. } => { |
| 47 | self.normalize_free_alias(goal) | |
| 50 | self.normalize_free_alias(goal).map_err(Into::into) | |
| 48 | 51 | } |
| 49 | 52 | ty::AliasTermKind::UnevaluatedConst { def_id } => { |
| 50 | self.normalize_anon_const(goal, def_id) | |
| 53 | self.normalize_anon_const(goal, def_id).map_err(Into::into) | |
| 51 | 54 | } |
| 52 | 55 | } |
| 53 | 56 | } |
| 54 | 57 | |
| 55 | fn normalize_associated_term(&mut self, goal: Goal<I, NormalizesTo<I>>) -> QueryResult<I> { | |
| 58 | fn normalize_associated_term( | |
| 59 | &mut self, | |
| 60 | goal: Goal<I, NormalizesTo<I>>, | |
| 61 | ) -> QueryResultOrRerunNonErased<I> { | |
| 56 | 62 | let cx = self.cx(); |
| 57 | 63 | |
| 58 | 64 | let trait_ref = goal.predicate.alias.trait_ref(cx); |
| ... | ... | @@ -85,7 +91,12 @@ where |
| 85 | 91 | )); |
| 86 | 92 | } |
| 87 | 93 | } |
| 88 | Err(NoSolution) => return Some(Err(NoSolution)), | |
| 94 | Err( | |
| 95 | e @ (NoSolutionOrRerunNonErased::NoSolution(NoSolution) | |
| 96 | | NoSolutionOrRerunNonErased::RerunNonErased(_)), | |
| 97 | ) => { | |
| 98 | return Some(Err(e)); | |
| 99 | } | |
| 89 | 100 | } |
| 90 | 101 | } |
| 91 | 102 | |
| ... | ... | @@ -174,8 +185,8 @@ where |
| 174 | 185 | ecx: &mut EvalCtxt<'_, D>, |
| 175 | 186 | goal: Goal<I, Self>, |
| 176 | 187 | assumption: I::Clause, |
| 177 | then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>, | |
| 178 | ) -> QueryResult<I> { | |
| 188 | then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResultOrRerunNonErased<I>, | |
| 189 | ) -> QueryResultOrRerunNonErased<I> { | |
| 179 | 190 | let cx = ecx.cx(); |
| 180 | 191 | let projection_pred = assumption.as_projection_clause().unwrap(); |
| 181 | 192 | let assumption_projection_pred = ecx.instantiate_binder_with_infer(projection_pred); |
| ... | ... | @@ -204,7 +215,7 @@ where |
| 204 | 215 | source: CandidateSource<I>, |
| 205 | 216 | goal: Goal<I, Self>, |
| 206 | 217 | assumption: I::Clause, |
| 207 | ) -> Result<Candidate<I>, NoSolution> { | |
| 218 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 208 | 219 | Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| { |
| 209 | 220 | ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| 210 | 221 | }) |
| ... | ... | @@ -222,8 +233,8 @@ where |
| 222 | 233 | ecx: &mut EvalCtxt<'_, D>, |
| 223 | 234 | goal: Goal<I, NormalizesTo<I>>, |
| 224 | 235 | impl_def_id: I::ImplId, |
| 225 | then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>, | |
| 226 | ) -> Result<Candidate<I>, NoSolution> { | |
| 236 | then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResultOrRerunNonErased<I>, | |
| 237 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 227 | 238 | let cx = ecx.cx(); |
| 228 | 239 | |
| 229 | 240 | let goal_trait_ref = goal.predicate.alias.trait_ref(cx); |
| ... | ... | @@ -232,13 +243,13 @@ where |
| 232 | 243 | goal.predicate.alias.trait_ref(cx).args, |
| 233 | 244 | impl_trait_ref.skip_binder().args, |
| 234 | 245 | ) { |
| 235 | return Err(NoSolution); | |
| 246 | return Err(NoSolution.into()); | |
| 236 | 247 | } |
| 237 | 248 | |
| 238 | 249 | // We have to ignore negative impls when projecting. |
| 239 | 250 | let impl_polarity = cx.impl_polarity(impl_def_id); |
| 240 | 251 | match impl_polarity { |
| 241 | ty::ImplPolarity::Negative => return Err(NoSolution), | |
| 252 | ty::ImplPolarity::Negative => return Err(NoSolution.into()), | |
| 242 | 253 | ty::ImplPolarity::Reservation => { |
| 243 | 254 | unimplemented!("reservation impl for trait with assoc item: {:?}", goal) |
| 244 | 255 | } |
| ... | ... | @@ -307,7 +318,8 @@ where |
| 307 | 318 | ty::TypingMode::Coherence => { |
| 308 | 319 | ecx.add_goal(GoalSource::Misc, goal.with(cx, PredicateKind::Ambiguous)); |
| 309 | 320 | return ecx |
| 310 | .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); | |
| 321 | .evaluate_added_goals_and_make_canonical_response(Certainty::Yes) | |
| 322 | .map_err(Into::into); | |
| 311 | 323 | } |
| 312 | 324 | // Outside of coherence, we treat the associated item as rigid instead. |
| 313 | 325 | ty::TypingMode::Analysis { .. } |
| ... | ... | @@ -319,14 +331,15 @@ where |
| 319 | 331 | goal.predicate.alias, |
| 320 | 332 | ); |
| 321 | 333 | return ecx |
| 322 | .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); | |
| 334 | .evaluate_added_goals_and_make_canonical_response(Certainty::Yes) | |
| 335 | .map_err(Into::into); | |
| 323 | 336 | } |
| 324 | 337 | }; |
| 325 | 338 | } |
| 326 | 339 | FetchEligibleAssocItemResponse::Err(guar) => return error_response(ecx, guar), |
| 327 | 340 | FetchEligibleAssocItemResponse::NotFoundBecauseErased => { |
| 328 | ecx.opaque_accesses.rerun_always(RerunReason::FetchEligibleAssocItem); | |
| 329 | return Err(NoSolution); | |
| 341 | ecx.opaque_accesses.rerun_always(RerunReason::FetchEligibleAssocItem)?; | |
| 342 | return Err(NoSolution.into()); | |
| 330 | 343 | } |
| 331 | 344 | }; |
| 332 | 345 | |
| ... | ... | @@ -349,10 +362,10 @@ where |
| 349 | 362 | // This is not the case here and we only prefer adding an ambiguous |
| 350 | 363 | // nested goal for consistency. |
| 351 | 364 | ecx.add_goal(GoalSource::Misc, goal.with(cx, PredicateKind::Ambiguous)); |
| 352 | return then(ecx, Certainty::Yes); | |
| 365 | return then(ecx, Certainty::Yes).map_err(Into::into); | |
| 353 | 366 | } else { |
| 354 | 367 | ecx.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias); |
| 355 | return then(ecx, Certainty::Yes); | |
| 368 | return then(ecx, Certainty::Yes).map_err(Into::into); | |
| 356 | 369 | } |
| 357 | 370 | } else { |
| 358 | 371 | return error_response(ecx, cx.delay_bug("missing item")); |
| ... | ... | @@ -412,7 +425,7 @@ where |
| 412 | 425 | }; |
| 413 | 426 | |
| 414 | 427 | ecx.instantiate_normalizes_to_term(goal, term); |
| 415 | ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) | |
| 428 | ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes).map_err(Into::into) | |
| 416 | 429 | }) |
| 417 | 430 | } |
| 418 | 431 | |
| ... | ... | @@ -421,22 +434,22 @@ where |
| 421 | 434 | fn consider_error_guaranteed_candidate( |
| 422 | 435 | _ecx: &mut EvalCtxt<'_, D>, |
| 423 | 436 | _guar: I::ErrorGuaranteed, |
| 424 | ) -> Result<Candidate<I>, NoSolution> { | |
| 425 | Err(NoSolution) | |
| 437 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 438 | Err(NoSolution.into()) | |
| 426 | 439 | } |
| 427 | 440 | |
| 428 | 441 | fn consider_auto_trait_candidate( |
| 429 | 442 | ecx: &mut EvalCtxt<'_, D>, |
| 430 | 443 | _goal: Goal<I, Self>, |
| 431 | ) -> Result<Candidate<I>, NoSolution> { | |
| 444 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 432 | 445 | ecx.cx().delay_bug("associated types not allowed on auto traits"); |
| 433 | Err(NoSolution) | |
| 446 | Err(NoSolution.into()) | |
| 434 | 447 | } |
| 435 | 448 | |
| 436 | 449 | fn consider_trait_alias_candidate( |
| 437 | 450 | _ecx: &mut EvalCtxt<'_, D>, |
| 438 | 451 | goal: Goal<I, Self>, |
| 439 | ) -> Result<Candidate<I>, NoSolution> { | |
| 452 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 440 | 453 | panic!("trait aliases do not have associated types: {:?}", goal); |
| 441 | 454 | } |
| 442 | 455 | |
| ... | ... | @@ -444,21 +457,21 @@ where |
| 444 | 457 | _ecx: &mut EvalCtxt<'_, D>, |
| 445 | 458 | goal: Goal<I, Self>, |
| 446 | 459 | _sizedness: SizedTraitKind, |
| 447 | ) -> Result<Candidate<I>, NoSolution> { | |
| 460 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 448 | 461 | panic!("`Sized`/`MetaSized` does not have an associated type: {:?}", goal); |
| 449 | 462 | } |
| 450 | 463 | |
| 451 | 464 | fn consider_builtin_copy_clone_candidate( |
| 452 | 465 | _ecx: &mut EvalCtxt<'_, D>, |
| 453 | 466 | goal: Goal<I, Self>, |
| 454 | ) -> Result<Candidate<I>, NoSolution> { | |
| 467 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 455 | 468 | panic!("`Copy`/`Clone` does not have an associated type: {:?}", goal); |
| 456 | 469 | } |
| 457 | 470 | |
| 458 | 471 | fn consider_builtin_fn_ptr_trait_candidate( |
| 459 | 472 | _ecx: &mut EvalCtxt<'_, D>, |
| 460 | 473 | goal: Goal<I, Self>, |
| 461 | ) -> Result<Candidate<I>, NoSolution> { | |
| 474 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 462 | 475 | panic!("`FnPtr` does not have an associated type: {:?}", goal); |
| 463 | 476 | } |
| 464 | 477 | |
| ... | ... | @@ -466,7 +479,7 @@ where |
| 466 | 479 | ecx: &mut EvalCtxt<'_, D>, |
| 467 | 480 | goal: Goal<I, Self>, |
| 468 | 481 | goal_kind: ty::ClosureKind, |
| 469 | ) -> Result<Candidate<I>, NoSolution> { | |
| 482 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 470 | 483 | let cx = ecx.cx(); |
| 471 | 484 | let Some(tupled_inputs_and_output) = |
| 472 | 485 | structural_traits::extract_tupled_inputs_and_output_from_callable( |
| ... | ... | @@ -501,13 +514,14 @@ where |
| 501 | 514 | pred, |
| 502 | 515 | [(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))], |
| 503 | 516 | ) |
| 517 | .map_err(Into::into) | |
| 504 | 518 | } |
| 505 | 519 | |
| 506 | 520 | fn consider_builtin_async_fn_trait_candidates( |
| 507 | 521 | ecx: &mut EvalCtxt<'_, D>, |
| 508 | 522 | goal: Goal<I, Self>, |
| 509 | 523 | goal_kind: ty::ClosureKind, |
| 510 | ) -> Result<Candidate<I>, NoSolution> { | |
| 524 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 511 | 525 | let cx = ecx.cx(); |
| 512 | 526 | let def_id = goal.predicate.def_id().try_into().unwrap(); |
| 513 | 527 | |
| ... | ... | @@ -590,7 +604,7 @@ where |
| 590 | 604 | fn consider_builtin_async_fn_kind_helper_candidate( |
| 591 | 605 | ecx: &mut EvalCtxt<'_, D>, |
| 592 | 606 | goal: Goal<I, Self>, |
| 593 | ) -> Result<Candidate<I>, NoSolution> { | |
| 607 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 594 | 608 | let [ |
| 595 | 609 | closure_fn_kind_ty, |
| 596 | 610 | goal_kind_ty, |
| ... | ... | @@ -610,13 +624,13 @@ where |
| 610 | 624 | |
| 611 | 625 | let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else { |
| 612 | 626 | // We don't need to worry about the self type being an infer var. |
| 613 | return Err(NoSolution); | |
| 627 | return Err(NoSolution.into()); | |
| 614 | 628 | }; |
| 615 | 629 | let Some(goal_kind) = goal_kind_ty.expect_ty().to_opt_closure_kind() else { |
| 616 | return Err(NoSolution); | |
| 630 | return Err(NoSolution.into()); | |
| 617 | 631 | }; |
| 618 | 632 | if !closure_kind.extends(goal_kind) { |
| 619 | return Err(NoSolution); | |
| 633 | return Err(NoSolution.into()); | |
| 620 | 634 | } |
| 621 | 635 | |
| 622 | 636 | let upvars_ty = ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind( |
| ... | ... | @@ -637,14 +651,14 @@ where |
| 637 | 651 | fn consider_builtin_tuple_candidate( |
| 638 | 652 | _ecx: &mut EvalCtxt<'_, D>, |
| 639 | 653 | goal: Goal<I, Self>, |
| 640 | ) -> Result<Candidate<I>, NoSolution> { | |
| 654 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 641 | 655 | panic!("`Tuple` does not have an associated type: {:?}", goal); |
| 642 | 656 | } |
| 643 | 657 | |
| 644 | 658 | fn consider_builtin_pointee_candidate( |
| 645 | 659 | ecx: &mut EvalCtxt<'_, D>, |
| 646 | 660 | goal: Goal<I, Self>, |
| 647 | ) -> Result<Candidate<I>, NoSolution> { | |
| 661 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 648 | 662 | let cx = ecx.cx(); |
| 649 | 663 | let metadata_def_id = cx.require_projection_lang_item(SolverProjectionLangItem::Metadata); |
| 650 | 664 | assert_eq!(Into::<I::DefId>::into(metadata_def_id), goal.predicate.def_id()); |
| ... | ... | @@ -695,6 +709,12 @@ where |
| 695 | 709 | ecx.instantiate_normalizes_to_term(goal, Ty::new_unit(cx).into()); |
| 696 | 710 | ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| 697 | 711 | }); |
| 712 | ||
| 713 | let alias_bound_result = match alias_bound_result.map_err_to_rerun()? { | |
| 714 | Ok(i) => Ok(i), | |
| 715 | Err(NoSolution) => Err(NoSolution), | |
| 716 | }; | |
| 717 | ||
| 698 | 718 | // In case the dummy alias-bound candidate does not apply, we instead treat this projection |
| 699 | 719 | // as rigid. |
| 700 | 720 | return alias_bound_result.or_else(|NoSolution| { |
| ... | ... | @@ -744,16 +764,16 @@ where |
| 744 | 764 | fn consider_builtin_future_candidate( |
| 745 | 765 | ecx: &mut EvalCtxt<'_, D>, |
| 746 | 766 | goal: Goal<I, Self>, |
| 747 | ) -> Result<Candidate<I>, NoSolution> { | |
| 767 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 748 | 768 | let self_ty = goal.predicate.self_ty(); |
| 749 | 769 | let ty::Coroutine(def_id, args) = self_ty.kind() else { |
| 750 | return Err(NoSolution); | |
| 770 | return Err(NoSolution.into()); | |
| 751 | 771 | }; |
| 752 | 772 | |
| 753 | 773 | // Coroutines are not futures unless they come from `async` desugaring |
| 754 | 774 | let cx = ecx.cx(); |
| 755 | 775 | if !cx.coroutine_is_async(def_id) { |
| 756 | return Err(NoSolution); | |
| 776 | return Err(NoSolution.into()); | |
| 757 | 777 | } |
| 758 | 778 | |
| 759 | 779 | let term = args.as_coroutine().return_ty().into(); |
| ... | ... | @@ -780,16 +800,16 @@ where |
| 780 | 800 | fn consider_builtin_iterator_candidate( |
| 781 | 801 | ecx: &mut EvalCtxt<'_, D>, |
| 782 | 802 | goal: Goal<I, Self>, |
| 783 | ) -> Result<Candidate<I>, NoSolution> { | |
| 803 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 784 | 804 | let self_ty = goal.predicate.self_ty(); |
| 785 | 805 | let ty::Coroutine(def_id, args) = self_ty.kind() else { |
| 786 | return Err(NoSolution); | |
| 806 | return Err(NoSolution.into()); | |
| 787 | 807 | }; |
| 788 | 808 | |
| 789 | 809 | // Coroutines are not Iterators unless they come from `gen` desugaring |
| 790 | 810 | let cx = ecx.cx(); |
| 791 | 811 | if !cx.coroutine_is_gen(def_id) { |
| 792 | return Err(NoSolution); | |
| 812 | return Err(NoSolution.into()); | |
| 793 | 813 | } |
| 794 | 814 | |
| 795 | 815 | let term = args.as_coroutine().yield_ty().into(); |
| ... | ... | @@ -811,28 +831,29 @@ where |
| 811 | 831 | // but that's already proven by the generator being WF. |
| 812 | 832 | [], |
| 813 | 833 | ) |
| 834 | .map_err(Into::into) | |
| 814 | 835 | } |
| 815 | 836 | |
| 816 | 837 | fn consider_builtin_fused_iterator_candidate( |
| 817 | 838 | _ecx: &mut EvalCtxt<'_, D>, |
| 818 | 839 | goal: Goal<I, Self>, |
| 819 | ) -> Result<Candidate<I>, NoSolution> { | |
| 840 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 820 | 841 | panic!("`FusedIterator` does not have an associated type: {:?}", goal); |
| 821 | 842 | } |
| 822 | 843 | |
| 823 | 844 | fn consider_builtin_async_iterator_candidate( |
| 824 | 845 | ecx: &mut EvalCtxt<'_, D>, |
| 825 | 846 | goal: Goal<I, Self>, |
| 826 | ) -> Result<Candidate<I>, NoSolution> { | |
| 847 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 827 | 848 | let self_ty = goal.predicate.self_ty(); |
| 828 | 849 | let ty::Coroutine(def_id, args) = self_ty.kind() else { |
| 829 | return Err(NoSolution); | |
| 850 | return Err(NoSolution.into()); | |
| 830 | 851 | }; |
| 831 | 852 | |
| 832 | 853 | // Coroutines are not AsyncIterators unless they come from `gen` desugaring |
| 833 | 854 | let cx = ecx.cx(); |
| 834 | 855 | if !cx.coroutine_is_async_gen(def_id) { |
| 835 | return Err(NoSolution); | |
| 856 | return Err(NoSolution.into()); | |
| 836 | 857 | } |
| 837 | 858 | |
| 838 | 859 | ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { |
| ... | ... | @@ -859,16 +880,16 @@ where |
| 859 | 880 | fn consider_builtin_coroutine_candidate( |
| 860 | 881 | ecx: &mut EvalCtxt<'_, D>, |
| 861 | 882 | goal: Goal<I, Self>, |
| 862 | ) -> Result<Candidate<I>, NoSolution> { | |
| 883 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 863 | 884 | let self_ty = goal.predicate.self_ty(); |
| 864 | 885 | let ty::Coroutine(def_id, args) = self_ty.kind() else { |
| 865 | return Err(NoSolution); | |
| 886 | return Err(NoSolution.into()); | |
| 866 | 887 | }; |
| 867 | 888 | |
| 868 | 889 | // `async`-desugared coroutines do not implement the coroutine trait |
| 869 | 890 | let cx = ecx.cx(); |
| 870 | 891 | if !cx.is_general_coroutine(def_id) { |
| 871 | return Err(NoSolution); | |
| 892 | return Err(NoSolution.into()); | |
| 872 | 893 | } |
| 873 | 894 | |
| 874 | 895 | let coroutine = args.as_coroutine(); |
| ... | ... | @@ -905,14 +926,14 @@ where |
| 905 | 926 | fn consider_structural_builtin_unsize_candidates( |
| 906 | 927 | _ecx: &mut EvalCtxt<'_, D>, |
| 907 | 928 | goal: Goal<I, Self>, |
| 908 | ) -> Vec<Candidate<I>> { | |
| 929 | ) -> Result<Vec<Candidate<I>>, RerunNonErased> { | |
| 909 | 930 | panic!("`Unsize` does not have an associated type: {:?}", goal); |
| 910 | 931 | } |
| 911 | 932 | |
| 912 | 933 | fn consider_builtin_discriminant_kind_candidate( |
| 913 | 934 | ecx: &mut EvalCtxt<'_, D>, |
| 914 | 935 | goal: Goal<I, Self>, |
| 915 | ) -> Result<Candidate<I>, NoSolution> { | |
| 936 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 916 | 937 | let self_ty = goal.predicate.self_ty(); |
| 917 | 938 | let discriminant_ty = match self_ty.kind() { |
| 918 | 939 | ty::Bool |
| ... | ... | @@ -971,35 +992,35 @@ where |
| 971 | 992 | fn consider_builtin_destruct_candidate( |
| 972 | 993 | _ecx: &mut EvalCtxt<'_, D>, |
| 973 | 994 | goal: Goal<I, Self>, |
| 974 | ) -> Result<Candidate<I>, NoSolution> { | |
| 995 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 975 | 996 | panic!("`Destruct` does not have an associated type: {:?}", goal); |
| 976 | 997 | } |
| 977 | 998 | |
| 978 | 999 | fn consider_builtin_transmute_candidate( |
| 979 | 1000 | _ecx: &mut EvalCtxt<'_, D>, |
| 980 | 1001 | goal: Goal<I, Self>, |
| 981 | ) -> Result<Candidate<I>, NoSolution> { | |
| 1002 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 982 | 1003 | panic!("`TransmuteFrom` does not have an associated type: {:?}", goal) |
| 983 | 1004 | } |
| 984 | 1005 | |
| 985 | 1006 | fn consider_builtin_bikeshed_guaranteed_no_drop_candidate( |
| 986 | 1007 | _ecx: &mut EvalCtxt<'_, D>, |
| 987 | 1008 | goal: Goal<I, Self>, |
| 988 | ) -> Result<Candidate<I>, NoSolution> { | |
| 1009 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 989 | 1010 | unreachable!("`BikeshedGuaranteedNoDrop` does not have an associated type: {:?}", goal) |
| 990 | 1011 | } |
| 991 | 1012 | |
| 992 | 1013 | fn consider_builtin_field_candidate( |
| 993 | 1014 | ecx: &mut EvalCtxt<'_, D>, |
| 994 | 1015 | goal: Goal<I, Self>, |
| 995 | ) -> Result<Candidate<I>, NoSolution> { | |
| 1016 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 996 | 1017 | let self_ty = goal.predicate.self_ty(); |
| 997 | 1018 | let ty::Adt(def, args) = self_ty.kind() else { |
| 998 | return Err(NoSolution); | |
| 1019 | return Err(NoSolution.into()); | |
| 999 | 1020 | }; |
| 1000 | 1021 | let Some(FieldInfo { base, ty, .. }) = def.field_representing_type_info(ecx.cx(), args) |
| 1001 | 1022 | else { |
| 1002 | return Err(NoSolution); | |
| 1023 | return Err(NoSolution.into()); | |
| 1003 | 1024 | }; |
| 1004 | 1025 | let ty = match ecx.cx().as_projection_lang_item(goal.predicate.def_id().try_into().unwrap()) |
| 1005 | 1026 | { |
compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs+16-12| ... | ... | @@ -2,11 +2,11 @@ |
| 2 | 2 | //! behaves differently depending on the current `TypingMode`. |
| 3 | 3 | |
| 4 | 4 | use rustc_type_ir::inherent::*; |
| 5 | use rustc_type_ir::solve::{GoalSource, NoSolution, RerunReason}; | |
| 5 | use rustc_type_ir::solve::{GoalSource, QueryResultOrRerunNonErased, RerunReason}; | |
| 6 | 6 | use rustc_type_ir::{self as ty, Interner, MayBeErased, TypingMode, fold_regions}; |
| 7 | 7 | |
| 8 | 8 | use crate::delegate::SolverDelegate; |
| 9 | use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult}; | |
| 9 | use crate::solve::{Certainty, EvalCtxt, Goal}; | |
| 10 | 10 | |
| 11 | 11 | impl<D, I> EvalCtxt<'_, D> |
| 12 | 12 | where |
| ... | ... | @@ -18,7 +18,7 @@ where |
| 18 | 18 | &mut self, |
| 19 | 19 | goal: Goal<I, ty::NormalizesTo<I>>, |
| 20 | 20 | def_id: I::OpaqueTyId, |
| 21 | ) -> QueryResult<I> { | |
| 21 | ) -> QueryResultOrRerunNonErased<I> { | |
| 22 | 22 | let cx = self.cx(); |
| 23 | 23 | let opaque_ty = goal.predicate.alias; |
| 24 | 24 | let expected = goal.predicate.term.as_type().expect("no such thing as an opaque const"); |
| ... | ... | @@ -39,6 +39,7 @@ where |
| 39 | 39 | // This can then allow nested goals to fail after we've constrained the `term`. |
| 40 | 40 | self.add_goal(GoalSource::Misc, goal.with(cx, ty::PredicateKind::Ambiguous)); |
| 41 | 41 | self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| 42 | .map_err(Into::into) | |
| 42 | 43 | } |
| 43 | 44 | TypingMode::Analysis { |
| 44 | 45 | defining_opaque_types_and_generators: defining_opaque_types, |
| ... | ... | @@ -50,7 +51,9 @@ where |
| 50 | 51 | else { |
| 51 | 52 | // If we're not in the defining scope, treat the alias as rigid. |
| 52 | 53 | self.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias); |
| 53 | return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); | |
| 54 | return self | |
| 55 | .evaluate_added_goals_and_make_canonical_response(Certainty::Yes) | |
| 56 | .map_err(Into::into); | |
| 54 | 57 | }; |
| 55 | 58 | |
| 56 | 59 | // We structurally normalize the args so that we're able to detect defining uses |
| ... | ... | @@ -108,6 +111,7 @@ where |
| 108 | 111 | expected, |
| 109 | 112 | ); |
| 110 | 113 | self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| 114 | .map_err(Into::into) | |
| 111 | 115 | } |
| 112 | 116 | TypingMode::PostBorrowckAnalysis { defined_opaque_types } => { |
| 113 | 117 | let Some(def_id) = opaque_ty |
| ... | ... | @@ -116,7 +120,9 @@ where |
| 116 | 120 | .filter(|&def_id| defined_opaque_types.contains(&def_id)) |
| 117 | 121 | else { |
| 118 | 122 | self.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias); |
| 119 | return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); | |
| 123 | return self | |
| 124 | .evaluate_added_goals_and_make_canonical_response(Certainty::Yes) | |
| 125 | .map_err(Into::into); | |
| 120 | 126 | }; |
| 121 | 127 | |
| 122 | 128 | let actual = |
| ... | ... | @@ -130,6 +136,7 @@ where |
| 130 | 136 | }); |
| 131 | 137 | self.eq(goal.param_env, expected, actual)?; |
| 132 | 138 | self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| 139 | .map_err(Into::into) | |
| 133 | 140 | } |
| 134 | 141 | TypingMode::PostAnalysis => { |
| 135 | 142 | // FIXME: Add an assertion that opaque type storage is empty. |
| ... | ... | @@ -137,6 +144,7 @@ where |
| 137 | 144 | cx.type_of(def_id.into()).instantiate(cx, opaque_ty.args).skip_norm_wip(); |
| 138 | 145 | self.eq(goal.param_env, expected, actual)?; |
| 139 | 146 | self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| 147 | .map_err(Into::into) | |
| 140 | 148 | } |
| 141 | 149 | TypingMode::ErasedNotCoherence(MayBeErased) => { |
| 142 | 150 | let def_id = opaque_ty.def_id().as_local(); |
| ... | ... | @@ -151,20 +159,16 @@ where |
| 151 | 159 | self.opaque_accesses.rerun_if_opaque_in_opaque_type_storage( |
| 152 | 160 | RerunReason::NormalizeOpaqueType, |
| 153 | 161 | def_id, |
| 154 | ); | |
| 162 | )?; | |
| 155 | 163 | } else { |
| 156 | 164 | self.opaque_accesses |
| 157 | .rerun_if_in_post_analysis(RerunReason::NormalizeOpaqueTypeRemoteCrate); | |
| 158 | } | |
| 159 | if self.opaque_accesses.should_bail() { | |
| 160 | // If we already accessed opaque types once, bail. | |
| 161 | // We can't make it more precise | |
| 162 | return Err(NoSolution); | |
| 165 | .rerun_if_in_post_analysis(RerunReason::NormalizeOpaqueTypeRemoteCrate)?; | |
| 163 | 166 | } |
| 164 | 167 | |
| 165 | 168 | // Always treat the opaque type as rigid. |
| 166 | 169 | self.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias); |
| 167 | 170 | self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| 171 | .map_err(Into::into) | |
| 168 | 172 | } |
| 169 | 173 | } |
| 170 | 174 | } |
compiler/rustc_next_trait_solver/src/solve/project_goals.rs+3-2| ... | ... | @@ -1,8 +1,9 @@ |
| 1 | use rustc_type_ir::solve::QueryResultOrRerunNonErased; | |
| 1 | 2 | use rustc_type_ir::{self as ty, Interner, ProjectionPredicate}; |
| 2 | 3 | use tracing::instrument; |
| 3 | 4 | |
| 4 | 5 | use crate::delegate::SolverDelegate; |
| 5 | use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult}; | |
| 6 | use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource}; | |
| 6 | 7 | |
| 7 | 8 | impl<D, I> EvalCtxt<'_, D> |
| 8 | 9 | where |
| ... | ... | @@ -13,7 +14,7 @@ where |
| 13 | 14 | pub(super) fn compute_projection_goal( |
| 14 | 15 | &mut self, |
| 15 | 16 | goal: Goal<I, ProjectionPredicate<I>>, |
| 16 | ) -> QueryResult<I> { | |
| 17 | ) -> QueryResultOrRerunNonErased<I> { | |
| 17 | 18 | let cx = self.cx(); |
| 18 | 19 | let projection_term = goal.predicate.projection_term.to_term(cx); |
| 19 | 20 | let goal = goal.with( |
compiler/rustc_next_trait_solver/src/solve/search_graph.rs+15-2| ... | ... | @@ -3,7 +3,9 @@ use std::marker::PhantomData; |
| 3 | 3 | |
| 4 | 4 | use rustc_type_ir::data_structures::ensure_sufficient_stack; |
| 5 | 5 | use rustc_type_ir::search_graph::{self, PathKind}; |
| 6 | use rustc_type_ir::solve::{AccessedOpaques, CanonicalInput, Certainty, NoSolution, QueryResult}; | |
| 6 | use rustc_type_ir::solve::{ | |
| 7 | AccessedOpaques, CanonicalInput, Certainty, NoSolution, NoSolutionOrRerunNonErased, QueryResult, | |
| 8 | }; | |
| 7 | 9 | use rustc_type_ir::{Interner, MayBeErased, TypingMode}; |
| 8 | 10 | |
| 9 | 11 | use crate::canonical::response_no_constraints_raw; |
| ... | ... | @@ -139,8 +141,19 @@ where |
| 139 | 141 | ensure_sufficient_stack(|| { |
| 140 | 142 | EvalCtxt::enter_canonical(cx, search_graph, input, inspect, |ecx, goal| { |
| 141 | 143 | let result = ecx.compute_goal(goal); |
| 144 | ||
| 145 | // if we're in `RerunNonErased`, don't even bother with inspect, | |
| 146 | // and immediately return | |
| 147 | let result = match result { | |
| 148 | Ok(i) => Ok(i), | |
| 149 | Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution)) => Err(NoSolution), | |
| 150 | Err(NoSolutionOrRerunNonErased::RerunNonErased(e)) => { | |
| 151 | return Err(e.into()); | |
| 152 | } | |
| 153 | }; | |
| 154 | ||
| 142 | 155 | ecx.inspect.query_result(result); |
| 143 | result | |
| 156 | result.map_err(Into::into) | |
| 144 | 157 | }) |
| 145 | 158 | }) |
| 146 | 159 | } |
compiler/rustc_next_trait_solver/src/solve/trait_goals.rs+129-113| ... | ... | @@ -5,8 +5,9 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt; |
| 5 | 5 | use rustc_type_ir::inherent::*; |
| 6 | 6 | use rustc_type_ir::lang_items::SolverTraitLangItem; |
| 7 | 7 | use rustc_type_ir::solve::{ |
| 8 | AliasBoundKind, CandidatePreferenceMode, CanonicalResponse, MaybeInfo, OpaqueTypesJank, | |
| 9 | RerunReason, SizedTraitKind, | |
| 8 | AliasBoundKind, CandidatePreferenceMode, CanonicalResponse, MaybeInfo, | |
| 9 | NoSolutionOrRerunNonErased, OpaqueTypesJank, QueryResultOrRerunNonErased, RerunNonErased, | |
| 10 | RerunReason, RerunResultExt, SizedTraitKind, | |
| 10 | 11 | }; |
| 11 | 12 | use rustc_type_ir::{ |
| 12 | 13 | self as ty, FieldInfo, Interner, MayBeErased, Movability, PredicatePolarity, TraitPredicate, |
| ... | ... | @@ -22,7 +23,7 @@ use crate::solve::assembly::{ |
| 22 | 23 | use crate::solve::inspect::ProbeKind; |
| 23 | 24 | use crate::solve::{ |
| 24 | 25 | BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause, |
| 25 | MergeCandidateInfo, NoSolution, ParamEnvSource, QueryResult, StalledOnCoroutines, | |
| 26 | MergeCandidateInfo, NoSolution, ParamEnvSource, StalledOnCoroutines, | |
| 26 | 27 | has_only_region_constraints, |
| 27 | 28 | }; |
| 28 | 29 | |
| ... | ... | @@ -59,15 +60,15 @@ where |
| 59 | 60 | ecx: &mut EvalCtxt<'_, D>, |
| 60 | 61 | goal: Goal<I, TraitPredicate<I>>, |
| 61 | 62 | impl_def_id: I::ImplId, |
| 62 | then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>, | |
| 63 | ) -> Result<Candidate<I>, NoSolution> { | |
| 63 | then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResultOrRerunNonErased<I>, | |
| 64 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 64 | 65 | let cx = ecx.cx(); |
| 65 | 66 | |
| 66 | 67 | let impl_trait_ref = cx.impl_trait_ref(impl_def_id); |
| 67 | 68 | if !DeepRejectCtxt::relate_rigid_infer(ecx.cx()) |
| 68 | 69 | .args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args) |
| 69 | 70 | { |
| 70 | return Err(NoSolution); | |
| 71 | return Err(NoSolution.into()); | |
| 71 | 72 | } |
| 72 | 73 | |
| 73 | 74 | // An upper bound of the certainty of this goal, used to lower the certainty |
| ... | ... | @@ -79,7 +80,7 @@ where |
| 79 | 80 | if ecx.typing_mode().is_coherence() { |
| 80 | 81 | Certainty::AMBIGUOUS |
| 81 | 82 | } else { |
| 82 | return Err(NoSolution); | |
| 83 | return Err(NoSolution.into()); | |
| 83 | 84 | } |
| 84 | 85 | } |
| 85 | 86 | |
| ... | ... | @@ -90,7 +91,7 @@ where |
| 90 | 91 | // Impl doesn't match polarity |
| 91 | 92 | (ty::ImplPolarity::Positive, ty::PredicatePolarity::Negative) |
| 92 | 93 | | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Positive) => { |
| 93 | return Err(NoSolution); | |
| 94 | return Err(NoSolution.into()); | |
| 94 | 95 | } |
| 95 | 96 | }; |
| 96 | 97 | |
| ... | ... | @@ -118,14 +119,14 @@ where |
| 118 | 119 | .map(|pred| goal.with(cx, pred)), |
| 119 | 120 | ); |
| 120 | 121 | |
| 121 | then(ecx, maximal_certainty) | |
| 122 | then(ecx, maximal_certainty).map_err(Into::into) | |
| 122 | 123 | }) |
| 123 | 124 | } |
| 124 | 125 | |
| 125 | 126 | fn consider_error_guaranteed_candidate( |
| 126 | 127 | ecx: &mut EvalCtxt<'_, D>, |
| 127 | 128 | _guar: I::ErrorGuaranteed, |
| 128 | ) -> Result<Candidate<I>, NoSolution> { | |
| 129 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 129 | 130 | ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) |
| 130 | 131 | .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) |
| 131 | 132 | } |
| ... | ... | @@ -174,8 +175,8 @@ where |
| 174 | 175 | ecx: &mut EvalCtxt<'_, D>, |
| 175 | 176 | goal: Goal<I, Self>, |
| 176 | 177 | assumption: I::Clause, |
| 177 | then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>, | |
| 178 | ) -> QueryResult<I> { | |
| 178 | then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResultOrRerunNonErased<I>, | |
| 179 | ) -> QueryResultOrRerunNonErased<I> { | |
| 179 | 180 | let trait_clause = assumption.as_trait_clause().unwrap(); |
| 180 | 181 | |
| 181 | 182 | // PERF(sized-hierarchy): Sizedness supertraits aren't elaborated to improve perf, so |
| ... | ... | @@ -200,10 +201,10 @@ where |
| 200 | 201 | fn consider_auto_trait_candidate( |
| 201 | 202 | ecx: &mut EvalCtxt<'_, D>, |
| 202 | 203 | goal: Goal<I, Self>, |
| 203 | ) -> Result<Candidate<I>, NoSolution> { | |
| 204 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 204 | 205 | let cx = ecx.cx(); |
| 205 | 206 | if goal.predicate.polarity != ty::PredicatePolarity::Positive { |
| 206 | return Err(NoSolution); | |
| 207 | return Err(NoSolution.into()); | |
| 207 | 208 | } |
| 208 | 209 | |
| 209 | 210 | if let Some(result) = ecx.disqualify_auto_trait_candidate_due_to_possible_impl(goal) { |
| ... | ... | @@ -215,7 +216,7 @@ where |
| 215 | 216 | if cx.trait_is_unsafe(goal.predicate.def_id()) |
| 216 | 217 | && goal.predicate.self_ty().has_unsafe_fields() |
| 217 | 218 | { |
| 218 | return Err(NoSolution); | |
| 219 | return Err(NoSolution.into()); | |
| 219 | 220 | } |
| 220 | 221 | |
| 221 | 222 | // We leak the implemented auto traits of opaques outside of their defining scope. |
| ... | ... | @@ -237,8 +238,8 @@ where |
| 237 | 238 | goal.predicate.self_ty().kind() |
| 238 | 239 | { |
| 239 | 240 | if ecx.opaque_accesses.might_rerun() { |
| 240 | ecx.opaque_accesses.rerun_always(RerunReason::AutoTraitLeakage); | |
| 241 | return Err(NoSolution); | |
| 241 | ecx.opaque_accesses.rerun_always(RerunReason::AutoTraitLeakage)?; | |
| 242 | return Err(NoSolution.into()); | |
| 242 | 243 | } |
| 243 | 244 | |
| 244 | 245 | debug_assert!(ecx.opaque_type_is_rigid(def_id)); |
| ... | ... | @@ -247,7 +248,7 @@ where |
| 247 | 248 | .as_trait_clause() |
| 248 | 249 | .is_some_and(|b| b.def_id() == goal.predicate.def_id()) |
| 249 | 250 | { |
| 250 | return Err(NoSolution); | |
| 251 | return Err(NoSolution.into()); | |
| 251 | 252 | } |
| 252 | 253 | } |
| 253 | 254 | } |
| ... | ... | @@ -267,9 +268,9 @@ where |
| 267 | 268 | fn consider_trait_alias_candidate( |
| 268 | 269 | ecx: &mut EvalCtxt<'_, D>, |
| 269 | 270 | goal: Goal<I, Self>, |
| 270 | ) -> Result<Candidate<I>, NoSolution> { | |
| 271 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 271 | 272 | if goal.predicate.polarity != ty::PredicatePolarity::Positive { |
| 272 | return Err(NoSolution); | |
| 273 | return Err(NoSolution.into()); | |
| 273 | 274 | } |
| 274 | 275 | |
| 275 | 276 | let cx = ecx.cx(); |
| ... | ... | @@ -294,9 +295,9 @@ where |
| 294 | 295 | ecx: &mut EvalCtxt<'_, D>, |
| 295 | 296 | goal: Goal<I, Self>, |
| 296 | 297 | sizedness: SizedTraitKind, |
| 297 | ) -> Result<Candidate<I>, NoSolution> { | |
| 298 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 298 | 299 | if goal.predicate.polarity != ty::PredicatePolarity::Positive { |
| 299 | return Err(NoSolution); | |
| 300 | return Err(NoSolution.into()); | |
| 300 | 301 | } |
| 301 | 302 | |
| 302 | 303 | ecx.probe_and_evaluate_goal_for_constituent_tys( |
| ... | ... | @@ -313,9 +314,9 @@ where |
| 313 | 314 | fn consider_builtin_copy_clone_candidate( |
| 314 | 315 | ecx: &mut EvalCtxt<'_, D>, |
| 315 | 316 | goal: Goal<I, Self>, |
| 316 | ) -> Result<Candidate<I>, NoSolution> { | |
| 317 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 317 | 318 | if goal.predicate.polarity != ty::PredicatePolarity::Positive { |
| 318 | return Err(NoSolution); | |
| 319 | return Err(NoSolution.into()); | |
| 319 | 320 | } |
| 320 | 321 | |
| 321 | 322 | // We need to make sure to stall any coroutines we are inferring to avoid query cycles. |
| ... | ... | @@ -333,7 +334,7 @@ where |
| 333 | 334 | fn consider_builtin_fn_ptr_trait_candidate( |
| 334 | 335 | ecx: &mut EvalCtxt<'_, D>, |
| 335 | 336 | goal: Goal<I, Self>, |
| 336 | ) -> Result<Candidate<I>, NoSolution> { | |
| 337 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 337 | 338 | let self_ty = goal.predicate.self_ty(); |
| 338 | 339 | match goal.predicate.polarity { |
| 339 | 340 | // impl FnPtr for FnPtr {} |
| ... | ... | @@ -343,7 +344,7 @@ where |
| 343 | 344 | ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| 344 | 345 | }) |
| 345 | 346 | } else { |
| 346 | Err(NoSolution) | |
| 347 | Err(NoSolution.into()) | |
| 347 | 348 | } |
| 348 | 349 | } |
| 349 | 350 | // impl !FnPtr for T where T != FnPtr && T is rigid {} |
| ... | ... | @@ -355,7 +356,7 @@ where |
| 355 | 356 | ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| 356 | 357 | }) |
| 357 | 358 | } else { |
| 358 | Err(NoSolution) | |
| 359 | Err(NoSolution.into()) | |
| 359 | 360 | } |
| 360 | 361 | } |
| 361 | 362 | } |
| ... | ... | @@ -365,9 +366,9 @@ where |
| 365 | 366 | ecx: &mut EvalCtxt<'_, D>, |
| 366 | 367 | goal: Goal<I, Self>, |
| 367 | 368 | goal_kind: ty::ClosureKind, |
| 368 | ) -> Result<Candidate<I>, NoSolution> { | |
| 369 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 369 | 370 | if goal.predicate.polarity != ty::PredicatePolarity::Positive { |
| 370 | return Err(NoSolution); | |
| 371 | return Err(NoSolution.into()); | |
| 371 | 372 | } |
| 372 | 373 | |
| 373 | 374 | let cx = ecx.cx(); |
| ... | ... | @@ -397,15 +398,16 @@ where |
| 397 | 398 | pred, |
| 398 | 399 | [(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))], |
| 399 | 400 | ) |
| 401 | .map_err(Into::into) | |
| 400 | 402 | } |
| 401 | 403 | |
| 402 | 404 | fn consider_builtin_async_fn_trait_candidates( |
| 403 | 405 | ecx: &mut EvalCtxt<'_, D>, |
| 404 | 406 | goal: Goal<I, Self>, |
| 405 | 407 | goal_kind: ty::ClosureKind, |
| 406 | ) -> Result<Candidate<I>, NoSolution> { | |
| 408 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 407 | 409 | if goal.predicate.polarity != ty::PredicatePolarity::Positive { |
| 408 | return Err(NoSolution); | |
| 410 | return Err(NoSolution.into()); | |
| 409 | 411 | } |
| 410 | 412 | |
| 411 | 413 | let cx = ecx.cx(); |
| ... | ... | @@ -447,26 +449,27 @@ where |
| 447 | 449 | .chain(nested_preds.into_iter().map(|pred| goal.with(cx, pred))) |
| 448 | 450 | .map(|goal| (GoalSource::ImplWhereBound, goal)), |
| 449 | 451 | ) |
| 452 | .map_err(Into::into) | |
| 450 | 453 | } |
| 451 | 454 | |
| 452 | 455 | fn consider_builtin_async_fn_kind_helper_candidate( |
| 453 | 456 | ecx: &mut EvalCtxt<'_, D>, |
| 454 | 457 | goal: Goal<I, Self>, |
| 455 | ) -> Result<Candidate<I>, NoSolution> { | |
| 458 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 456 | 459 | let [closure_fn_kind_ty, goal_kind_ty] = *goal.predicate.trait_ref.args.as_slice() else { |
| 457 | 460 | panic!(); |
| 458 | 461 | }; |
| 459 | 462 | |
| 460 | 463 | let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else { |
| 461 | 464 | // We don't need to worry about the self type being an infer var. |
| 462 | return Err(NoSolution); | |
| 465 | return Err(NoSolution.into()); | |
| 463 | 466 | }; |
| 464 | 467 | let goal_kind = goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap(); |
| 465 | 468 | if closure_kind.extends(goal_kind) { |
| 466 | 469 | ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) |
| 467 | 470 | .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) |
| 468 | 471 | } else { |
| 469 | Err(NoSolution) | |
| 472 | Err(NoSolution.into()) | |
| 470 | 473 | } |
| 471 | 474 | } |
| 472 | 475 | |
| ... | ... | @@ -479,25 +482,25 @@ where |
| 479 | 482 | fn consider_builtin_tuple_candidate( |
| 480 | 483 | ecx: &mut EvalCtxt<'_, D>, |
| 481 | 484 | goal: Goal<I, Self>, |
| 482 | ) -> Result<Candidate<I>, NoSolution> { | |
| 485 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 483 | 486 | if goal.predicate.polarity != ty::PredicatePolarity::Positive { |
| 484 | return Err(NoSolution); | |
| 487 | return Err(NoSolution.into()); | |
| 485 | 488 | } |
| 486 | 489 | |
| 487 | 490 | if let ty::Tuple(..) = goal.predicate.self_ty().kind() { |
| 488 | 491 | ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) |
| 489 | 492 | .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) |
| 490 | 493 | } else { |
| 491 | Err(NoSolution) | |
| 494 | Err(NoSolution.into()) | |
| 492 | 495 | } |
| 493 | 496 | } |
| 494 | 497 | |
| 495 | 498 | fn consider_builtin_pointee_candidate( |
| 496 | 499 | ecx: &mut EvalCtxt<'_, D>, |
| 497 | 500 | goal: Goal<I, Self>, |
| 498 | ) -> Result<Candidate<I>, NoSolution> { | |
| 501 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 499 | 502 | if goal.predicate.polarity != ty::PredicatePolarity::Positive { |
| 500 | return Err(NoSolution); | |
| 503 | return Err(NoSolution.into()); | |
| 501 | 504 | } |
| 502 | 505 | |
| 503 | 506 | ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) |
| ... | ... | @@ -507,19 +510,19 @@ where |
| 507 | 510 | fn consider_builtin_future_candidate( |
| 508 | 511 | ecx: &mut EvalCtxt<'_, D>, |
| 509 | 512 | goal: Goal<I, Self>, |
| 510 | ) -> Result<Candidate<I>, NoSolution> { | |
| 513 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 511 | 514 | if goal.predicate.polarity != ty::PredicatePolarity::Positive { |
| 512 | return Err(NoSolution); | |
| 515 | return Err(NoSolution.into()); | |
| 513 | 516 | } |
| 514 | 517 | |
| 515 | 518 | let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else { |
| 516 | return Err(NoSolution); | |
| 519 | return Err(NoSolution.into()); | |
| 517 | 520 | }; |
| 518 | 521 | |
| 519 | 522 | // Coroutines are not futures unless they come from `async` desugaring |
| 520 | 523 | let cx = ecx.cx(); |
| 521 | 524 | if !cx.coroutine_is_async(def_id) { |
| 522 | return Err(NoSolution); | |
| 525 | return Err(NoSolution.into()); | |
| 523 | 526 | } |
| 524 | 527 | |
| 525 | 528 | // Async coroutine unconditionally implement `Future` |
| ... | ... | @@ -532,19 +535,19 @@ where |
| 532 | 535 | fn consider_builtin_iterator_candidate( |
| 533 | 536 | ecx: &mut EvalCtxt<'_, D>, |
| 534 | 537 | goal: Goal<I, Self>, |
| 535 | ) -> Result<Candidate<I>, NoSolution> { | |
| 538 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 536 | 539 | if goal.predicate.polarity != ty::PredicatePolarity::Positive { |
| 537 | return Err(NoSolution); | |
| 540 | return Err(NoSolution.into()); | |
| 538 | 541 | } |
| 539 | 542 | |
| 540 | 543 | let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else { |
| 541 | return Err(NoSolution); | |
| 544 | return Err(NoSolution.into()); | |
| 542 | 545 | }; |
| 543 | 546 | |
| 544 | 547 | // Coroutines are not iterators unless they come from `gen` desugaring |
| 545 | 548 | let cx = ecx.cx(); |
| 546 | 549 | if !cx.coroutine_is_gen(def_id) { |
| 547 | return Err(NoSolution); | |
| 550 | return Err(NoSolution.into()); | |
| 548 | 551 | } |
| 549 | 552 | |
| 550 | 553 | // Gen coroutines unconditionally implement `Iterator` |
| ... | ... | @@ -557,19 +560,19 @@ where |
| 557 | 560 | fn consider_builtin_fused_iterator_candidate( |
| 558 | 561 | ecx: &mut EvalCtxt<'_, D>, |
| 559 | 562 | goal: Goal<I, Self>, |
| 560 | ) -> Result<Candidate<I>, NoSolution> { | |
| 563 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 561 | 564 | if goal.predicate.polarity != ty::PredicatePolarity::Positive { |
| 562 | return Err(NoSolution); | |
| 565 | return Err(NoSolution.into()); | |
| 563 | 566 | } |
| 564 | 567 | |
| 565 | 568 | let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else { |
| 566 | return Err(NoSolution); | |
| 569 | return Err(NoSolution.into()); | |
| 567 | 570 | }; |
| 568 | 571 | |
| 569 | 572 | // Coroutines are not iterators unless they come from `gen` desugaring |
| 570 | 573 | let cx = ecx.cx(); |
| 571 | 574 | if !cx.coroutine_is_gen(def_id) { |
| 572 | return Err(NoSolution); | |
| 575 | return Err(NoSolution.into()); | |
| 573 | 576 | } |
| 574 | 577 | |
| 575 | 578 | // Gen coroutines unconditionally implement `FusedIterator`. |
| ... | ... | @@ -580,19 +583,19 @@ where |
| 580 | 583 | fn consider_builtin_async_iterator_candidate( |
| 581 | 584 | ecx: &mut EvalCtxt<'_, D>, |
| 582 | 585 | goal: Goal<I, Self>, |
| 583 | ) -> Result<Candidate<I>, NoSolution> { | |
| 586 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 584 | 587 | if goal.predicate.polarity != ty::PredicatePolarity::Positive { |
| 585 | return Err(NoSolution); | |
| 588 | return Err(NoSolution.into()); | |
| 586 | 589 | } |
| 587 | 590 | |
| 588 | 591 | let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else { |
| 589 | return Err(NoSolution); | |
| 592 | return Err(NoSolution.into()); | |
| 590 | 593 | }; |
| 591 | 594 | |
| 592 | 595 | // Coroutines are not iterators unless they come from `gen` desugaring |
| 593 | 596 | let cx = ecx.cx(); |
| 594 | 597 | if !cx.coroutine_is_async_gen(def_id) { |
| 595 | return Err(NoSolution); | |
| 598 | return Err(NoSolution.into()); | |
| 596 | 599 | } |
| 597 | 600 | |
| 598 | 601 | // Gen coroutines unconditionally implement `Iterator` |
| ... | ... | @@ -605,20 +608,20 @@ where |
| 605 | 608 | fn consider_builtin_coroutine_candidate( |
| 606 | 609 | ecx: &mut EvalCtxt<'_, D>, |
| 607 | 610 | goal: Goal<I, Self>, |
| 608 | ) -> Result<Candidate<I>, NoSolution> { | |
| 611 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 609 | 612 | if goal.predicate.polarity != ty::PredicatePolarity::Positive { |
| 610 | return Err(NoSolution); | |
| 613 | return Err(NoSolution.into()); | |
| 611 | 614 | } |
| 612 | 615 | |
| 613 | 616 | let self_ty = goal.predicate.self_ty(); |
| 614 | 617 | let ty::Coroutine(def_id, args) = self_ty.kind() else { |
| 615 | return Err(NoSolution); | |
| 618 | return Err(NoSolution.into()); | |
| 616 | 619 | }; |
| 617 | 620 | |
| 618 | 621 | // `async`-desugared coroutines do not implement the coroutine trait |
| 619 | 622 | let cx = ecx.cx(); |
| 620 | 623 | if !cx.is_general_coroutine(def_id) { |
| 621 | return Err(NoSolution); | |
| 624 | return Err(NoSolution.into()); | |
| 622 | 625 | } |
| 623 | 626 | |
| 624 | 627 | let coroutine = args.as_coroutine(); |
| ... | ... | @@ -637,9 +640,9 @@ where |
| 637 | 640 | fn consider_builtin_discriminant_kind_candidate( |
| 638 | 641 | ecx: &mut EvalCtxt<'_, D>, |
| 639 | 642 | goal: Goal<I, Self>, |
| 640 | ) -> Result<Candidate<I>, NoSolution> { | |
| 643 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 641 | 644 | if goal.predicate.polarity != ty::PredicatePolarity::Positive { |
| 642 | return Err(NoSolution); | |
| 645 | return Err(NoSolution.into()); | |
| 643 | 646 | } |
| 644 | 647 | |
| 645 | 648 | // `DiscriminantKind` is automatically implemented for every type. |
| ... | ... | @@ -650,9 +653,9 @@ where |
| 650 | 653 | fn consider_builtin_destruct_candidate( |
| 651 | 654 | ecx: &mut EvalCtxt<'_, D>, |
| 652 | 655 | goal: Goal<I, Self>, |
| 653 | ) -> Result<Candidate<I>, NoSolution> { | |
| 656 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 654 | 657 | if goal.predicate.polarity != ty::PredicatePolarity::Positive { |
| 655 | return Err(NoSolution); | |
| 658 | return Err(NoSolution.into()); | |
| 656 | 659 | } |
| 657 | 660 | |
| 658 | 661 | // `Destruct` is automatically implemented for every type in |
| ... | ... | @@ -664,14 +667,14 @@ where |
| 664 | 667 | fn consider_builtin_transmute_candidate( |
| 665 | 668 | ecx: &mut EvalCtxt<'_, D>, |
| 666 | 669 | goal: Goal<I, Self>, |
| 667 | ) -> Result<Candidate<I>, NoSolution> { | |
| 670 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 668 | 671 | if goal.predicate.polarity != ty::PredicatePolarity::Positive { |
| 669 | return Err(NoSolution); | |
| 672 | return Err(NoSolution.into()); | |
| 670 | 673 | } |
| 671 | 674 | |
| 672 | 675 | // `rustc_transmute` does not have support for type or const params |
| 673 | 676 | if goal.predicate.has_non_region_placeholders() { |
| 674 | return Err(NoSolution); | |
| 677 | return Err(NoSolution.into()); | |
| 675 | 678 | } |
| 676 | 679 | |
| 677 | 680 | // Match the old solver by treating unresolved inference variables as |
| ... | ... | @@ -680,19 +683,21 @@ where |
| 680 | 683 | return ecx.forced_ambiguity(MaybeInfo::AMBIGUOUS); |
| 681 | 684 | } |
| 682 | 685 | |
| 683 | ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { | |
| 684 | let assume = ecx.structurally_normalize_const( | |
| 685 | goal.param_env, | |
| 686 | goal.predicate.trait_ref.args.const_at(2), | |
| 687 | )?; | |
| 686 | ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter( | |
| 687 | |ecx| -> Result<_, NoSolutionOrRerunNonErased> { | |
| 688 | let assume = ecx.structurally_normalize_const( | |
| 689 | goal.param_env, | |
| 690 | goal.predicate.trait_ref.args.const_at(2), | |
| 691 | )?; | |
| 688 | 692 | |
| 689 | let certainty = ecx.is_transmutable( | |
| 690 | goal.predicate.trait_ref.args.type_at(0), | |
| 691 | goal.predicate.trait_ref.args.type_at(1), | |
| 692 | assume, | |
| 693 | )?; | |
| 694 | ecx.evaluate_added_goals_and_make_canonical_response(certainty) | |
| 695 | }) | |
| 693 | let certainty = ecx.is_transmutable( | |
| 694 | goal.predicate.trait_ref.args.type_at(0), | |
| 695 | goal.predicate.trait_ref.args.type_at(1), | |
| 696 | assume, | |
| 697 | )?; | |
| 698 | ecx.evaluate_added_goals_and_make_canonical_response(certainty).map_err(Into::into) | |
| 699 | }, | |
| 700 | ) | |
| 696 | 701 | } |
| 697 | 702 | |
| 698 | 703 | /// NOTE: This is implemented as a built-in goal and not a set of impls like: |
| ... | ... | @@ -710,9 +715,9 @@ where |
| 710 | 715 | fn consider_builtin_bikeshed_guaranteed_no_drop_candidate( |
| 711 | 716 | ecx: &mut EvalCtxt<'_, D>, |
| 712 | 717 | goal: Goal<I, Self>, |
| 713 | ) -> Result<Candidate<I>, NoSolution> { | |
| 718 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 714 | 719 | if goal.predicate.polarity != ty::PredicatePolarity::Positive { |
| 715 | return Err(NoSolution); | |
| 720 | return Err(NoSolution.into()); | |
| 716 | 721 | } |
| 717 | 722 | |
| 718 | 723 | let cx = ecx.cx(); |
| ... | ... | @@ -803,13 +808,13 @@ where |
| 803 | 808 | fn consider_structural_builtin_unsize_candidates( |
| 804 | 809 | ecx: &mut EvalCtxt<'_, D>, |
| 805 | 810 | goal: Goal<I, Self>, |
| 806 | ) -> Vec<Candidate<I>> { | |
| 811 | ) -> Result<Vec<Candidate<I>>, RerunNonErased> { | |
| 807 | 812 | if goal.predicate.polarity != ty::PredicatePolarity::Positive { |
| 808 | return vec![]; | |
| 813 | return Ok(vec![]); | |
| 809 | 814 | } |
| 810 | 815 | |
| 811 | 816 | let result = ecx.probe(|_| ProbeKind::UnsizeAssembly).enter( |
| 812 | |ecx| -> Result<Vec<Candidate<I>>, NoSolution> { | |
| 817 | |ecx| -> Result<Vec<Candidate<I>>, NoSolutionOrRerunNonErased> { | |
| 813 | 818 | let a_ty = goal.predicate.self_ty(); |
| 814 | 819 | // We need to normalize the b_ty since it's matched structurally |
| 815 | 820 | // in the other functions below. |
| ... | ... | @@ -849,23 +854,23 @@ where |
| 849 | 854 | Ok(vec![ecx.consider_builtin_struct_unsize(goal, a_def, a_args, b_args)?]) |
| 850 | 855 | } |
| 851 | 856 | |
| 852 | _ => Err(NoSolution), | |
| 857 | _ => Err(NoSolution.into()), | |
| 853 | 858 | } |
| 854 | 859 | }, |
| 855 | 860 | ); |
| 856 | 861 | |
| 857 | match result.map_err(Into::into) { | |
| 858 | Ok(resp) => resp, | |
| 859 | Err(NoSolution) => vec![], | |
| 862 | match result.map_err_to_rerun()? { | |
| 863 | Ok(resp) => Ok(resp), | |
| 864 | Err(NoSolution) => Ok(vec![]), | |
| 860 | 865 | } |
| 861 | 866 | } |
| 862 | 867 | |
| 863 | 868 | fn consider_builtin_field_candidate( |
| 864 | 869 | ecx: &mut EvalCtxt<'_, D>, |
| 865 | 870 | goal: Goal<I, Self>, |
| 866 | ) -> Result<Candidate<I>, NoSolution> { | |
| 871 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 867 | 872 | if goal.predicate.polarity != ty::PredicatePolarity::Positive { |
| 868 | return Err(NoSolution); | |
| 873 | return Err(NoSolution.into()); | |
| 869 | 874 | } |
| 870 | 875 | if let ty::Adt(def, args) = goal.predicate.self_ty().kind() |
| 871 | 876 | && let Some(FieldInfo { base, ty, .. }) = |
| ... | ... | @@ -904,7 +909,7 @@ where |
| 904 | 909 | ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) |
| 905 | 910 | .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) |
| 906 | 911 | } else { |
| 907 | Err(NoSolution) | |
| 912 | Err(NoSolution.into()) | |
| 908 | 913 | } |
| 909 | 914 | } |
| 910 | 915 | } |
| ... | ... | @@ -995,13 +1000,13 @@ where |
| 995 | 1000 | goal: Goal<I, (I::Ty, I::Ty)>, |
| 996 | 1001 | b_data: I::BoundExistentialPredicates, |
| 997 | 1002 | b_region: I::Region, |
| 998 | ) -> Result<Candidate<I>, NoSolution> { | |
| 1003 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 999 | 1004 | let cx = self.cx(); |
| 1000 | 1005 | let Goal { predicate: (a_ty, _), .. } = goal; |
| 1001 | 1006 | |
| 1002 | 1007 | // Can only unsize to an dyn-compatible trait. |
| 1003 | 1008 | if b_data.principal_def_id().is_some_and(|def_id| !cx.trait_is_dyn_compatible(def_id)) { |
| 1004 | return Err(NoSolution); | |
| 1009 | return Err(NoSolution.into()); | |
| 1005 | 1010 | } |
| 1006 | 1011 | |
| 1007 | 1012 | self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { |
| ... | ... | @@ -1040,7 +1045,7 @@ where |
| 1040 | 1045 | b_data: I::BoundExistentialPredicates, |
| 1041 | 1046 | b_region: I::Region, |
| 1042 | 1047 | upcast_principal: Option<ty::Binder<I, ty::ExistentialTraitRef<I>>>, |
| 1043 | ) -> Result<Candidate<I>, NoSolution> { | |
| 1048 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 1044 | 1049 | let param_env = goal.param_env; |
| 1045 | 1050 | |
| 1046 | 1051 | // We may upcast to auto traits that are either explicitly listed in |
| ... | ... | @@ -1066,13 +1071,14 @@ where |
| 1066 | 1071 | source_projection.item_def_id() == target_projection.item_def_id() |
| 1067 | 1072 | && ecx |
| 1068 | 1073 | .probe(|_| ProbeKind::ProjectionCompatibility) |
| 1069 | .enter(|ecx| -> Result<_, NoSolution> { | |
| 1074 | .enter(|ecx| { | |
| 1070 | 1075 | ecx.enter_forall(target_projection, |ecx, target_projection| { |
| 1071 | 1076 | let source_projection = |
| 1072 | 1077 | ecx.instantiate_binder_with_infer(source_projection); |
| 1073 | 1078 | ecx.eq(param_env, source_projection, target_projection)?; |
| 1074 | 1079 | ecx.try_evaluate_added_goals() |
| 1075 | 1080 | }) |
| 1081 | .map_err(Into::into) | |
| 1076 | 1082 | }) |
| 1077 | 1083 | .is_ok() |
| 1078 | 1084 | }; |
| ... | ... | @@ -1104,12 +1110,14 @@ where |
| 1104 | 1110 | projection_may_match(ecx, *source_projection, target_projection) |
| 1105 | 1111 | }); |
| 1106 | 1112 | let Some(source_projection) = matching_projections.next() else { |
| 1107 | return Err(NoSolution); | |
| 1113 | return Err(NoSolution.into()); | |
| 1108 | 1114 | }; |
| 1109 | 1115 | if matching_projections.next().is_some() { |
| 1110 | return ecx.evaluate_added_goals_and_make_canonical_response( | |
| 1111 | Certainty::AMBIGUOUS, | |
| 1112 | ); | |
| 1116 | return ecx | |
| 1117 | .evaluate_added_goals_and_make_canonical_response( | |
| 1118 | Certainty::AMBIGUOUS, | |
| 1119 | ) | |
| 1120 | .map_err(Into::into); | |
| 1113 | 1121 | } |
| 1114 | 1122 | ecx.enter_forall(target_projection, |ecx, target_projection| { |
| 1115 | 1123 | let source_projection = |
| ... | ... | @@ -1121,7 +1129,7 @@ where |
| 1121 | 1129 | // Check that b_ty's auto traits are present in a_ty's bounds. |
| 1122 | 1130 | ty::ExistentialPredicate::AutoTrait(def_id) => { |
| 1123 | 1131 | if !a_auto_traits.contains(&def_id) { |
| 1124 | return Err(NoSolution); | |
| 1132 | return Err(NoSolution.into()); | |
| 1125 | 1133 | } |
| 1126 | 1134 | } |
| 1127 | 1135 | } |
| ... | ... | @@ -1133,7 +1141,7 @@ where |
| 1133 | 1141 | Goal::new(ecx.cx(), param_env, ty::OutlivesPredicate(a_region, b_region)), |
| 1134 | 1142 | ); |
| 1135 | 1143 | |
| 1136 | ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) | |
| 1144 | ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes).map_err(Into::into) | |
| 1137 | 1145 | }) |
| 1138 | 1146 | } |
| 1139 | 1147 | |
| ... | ... | @@ -1150,7 +1158,7 @@ where |
| 1150 | 1158 | goal: Goal<I, (I::Ty, I::Ty)>, |
| 1151 | 1159 | a_elem_ty: I::Ty, |
| 1152 | 1160 | b_elem_ty: I::Ty, |
| 1153 | ) -> Result<Candidate<I>, NoSolution> { | |
| 1161 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 1154 | 1162 | self.eq(goal.param_env, a_elem_ty, b_elem_ty)?; |
| 1155 | 1163 | self.probe_builtin_trait_candidate(BuiltinImplSource::Misc) |
| 1156 | 1164 | .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) |
| ... | ... | @@ -1175,7 +1183,7 @@ where |
| 1175 | 1183 | def: I::AdtDef, |
| 1176 | 1184 | a_args: I::GenericArgs, |
| 1177 | 1185 | b_args: I::GenericArgs, |
| 1178 | ) -> Result<Candidate<I>, NoSolution> { | |
| 1186 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 1179 | 1187 | let cx = self.cx(); |
| 1180 | 1188 | let Goal { predicate: (_a_ty, b_ty), .. } = goal; |
| 1181 | 1189 | |
| ... | ... | @@ -1183,7 +1191,7 @@ where |
| 1183 | 1191 | // We must be unsizing some type parameters. This also implies |
| 1184 | 1192 | // that the struct has a tail field. |
| 1185 | 1193 | if unsizing_params.is_empty() { |
| 1186 | return Err(NoSolution); | |
| 1194 | return Err(NoSolution.into()); | |
| 1187 | 1195 | } |
| 1188 | 1196 | |
| 1189 | 1197 | let tail_field_ty = def.struct_tail_ty(cx).unwrap(); |
| ... | ... | @@ -1224,7 +1232,7 @@ where |
| 1224 | 1232 | fn disqualify_auto_trait_candidate_due_to_possible_impl( |
| 1225 | 1233 | &mut self, |
| 1226 | 1234 | goal: Goal<I, TraitPredicate<I>>, |
| 1227 | ) -> Option<Result<Candidate<I>, NoSolution>> { | |
| 1235 | ) -> Option<Result<Candidate<I>, NoSolutionOrRerunNonErased>> { | |
| 1228 | 1236 | let self_ty = goal.predicate.self_ty(); |
| 1229 | 1237 | let check_impls = || { |
| 1230 | 1238 | let mut disqualifying_impl = None; |
| ... | ... | @@ -1239,7 +1247,7 @@ where |
| 1239 | 1247 | trace!(?def_id, ?goal, "disqualified auto-trait implementation"); |
| 1240 | 1248 | // No need to actually consider the candidate here, |
| 1241 | 1249 | // since we do that in `consider_impl_candidate`. |
| 1242 | return Some(Err(NoSolution)); | |
| 1250 | return Some(Err(NoSolution.into())); | |
| 1243 | 1251 | } else { |
| 1244 | 1252 | None |
| 1245 | 1253 | } |
| ... | ... | @@ -1268,7 +1276,7 @@ where |
| 1268 | 1276 | kind: ty::Projection { .. } | ty::Free { .. } | ty::Inherent { .. }, |
| 1269 | 1277 | .. |
| 1270 | 1278 | }) |
| 1271 | | ty::Placeholder(..) => Some(Err(NoSolution)), | |
| 1279 | | ty::Placeholder(..) => Some(Err(NoSolution.into())), | |
| 1272 | 1280 | |
| 1273 | 1281 | ty::Infer(_) | ty::Bound(_, _) => panic!("unexpected type `{self_ty:?}`"), |
| 1274 | 1282 | |
| ... | ... | @@ -1281,7 +1289,7 @@ where |
| 1281 | 1289 | .is_trait_lang_item(goal.predicate.def_id(), SolverTraitLangItem::Unpin) => |
| 1282 | 1290 | { |
| 1283 | 1291 | match self.cx().coroutine_movability(def_id) { |
| 1284 | Movability::Static => Some(Err(NoSolution)), | |
| 1292 | Movability::Static => Some(Err(NoSolution.into())), | |
| 1285 | 1293 | Movability::Movable => Some( |
| 1286 | 1294 | self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { |
| 1287 | 1295 | ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| ... | ... | @@ -1339,7 +1347,7 @@ where |
| 1339 | 1347 | &EvalCtxt<'_, D>, |
| 1340 | 1348 | I::Ty, |
| 1341 | 1349 | ) -> Result<ty::Binder<I, Vec<I::Ty>>, NoSolution>, |
| 1342 | ) -> Result<Candidate<I>, NoSolution> { | |
| 1350 | ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> { | |
| 1343 | 1351 | self.probe_trait_candidate(source).enter(|ecx| { |
| 1344 | 1352 | let goals = |
| 1345 | 1353 | ecx.enter_forall(constituent_tys(ecx, goal.predicate.self_ty())?, |ecx, tys| { |
| ... | ... | @@ -1548,15 +1556,20 @@ where |
| 1548 | 1556 | pub(super) fn compute_trait_goal( |
| 1549 | 1557 | &mut self, |
| 1550 | 1558 | goal: Goal<I, TraitPredicate<I>>, |
| 1551 | ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> { | |
| 1559 | ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolutionOrRerunNonErased> | |
| 1560 | { | |
| 1552 | 1561 | let (candidates, failed_candidate_info) = |
| 1553 | self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All); | |
| 1562 | self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All)?; | |
| 1554 | 1563 | let candidate_preference_mode = |
| 1555 | 1564 | CandidatePreferenceMode::compute(self.cx(), goal.predicate.def_id()); |
| 1556 | 1565 | self.merge_trait_candidates(candidate_preference_mode, candidates, failed_candidate_info) |
| 1566 | .map_err(Into::into) | |
| 1557 | 1567 | } |
| 1558 | 1568 | |
| 1559 | fn try_stall_coroutine(&mut self, self_ty: I::Ty) -> Option<Result<Candidate<I>, NoSolution>> { | |
| 1569 | fn try_stall_coroutine( | |
| 1570 | &mut self, | |
| 1571 | self_ty: I::Ty, | |
| 1572 | ) -> Option<Result<Candidate<I>, NoSolutionOrRerunNonErased>> { | |
| 1560 | 1573 | if let ty::Coroutine(def_id, _) = self_ty.kind() { |
| 1561 | 1574 | match self.typing_mode() { |
| 1562 | 1575 | TypingMode::Analysis { |
| ... | ... | @@ -1573,8 +1586,11 @@ where |
| 1573 | 1586 | } |
| 1574 | 1587 | TypingMode::ErasedNotCoherence(MayBeErased) => { |
| 1575 | 1588 | // Trying to continue here isn't worth it. |
| 1576 | self.opaque_accesses.rerun_always(RerunReason::TryStallCoroutine); | |
| 1577 | return Some(Err(NoSolution)); | |
| 1589 | return Some( | |
| 1590 | match self.opaque_accesses.rerun_always(RerunReason::TryStallCoroutine) { | |
| 1591 | Err(e) => Err(e.into()), | |
| 1592 | }, | |
| 1593 | ); | |
| 1578 | 1594 | } |
| 1579 | 1595 | TypingMode::Coherence |
| 1580 | 1596 | | TypingMode::PostAnalysis |
compiler/rustc_trait_selection/src/solve/delegate.rs+57-32| ... | ... | @@ -13,7 +13,7 @@ use rustc_infer::traits::solve::{FetchEligibleAssocItemResponse, Goal}; |
| 13 | 13 | use rustc_middle::traits::query::NoSolution; |
| 14 | 14 | use rustc_middle::traits::solve::Certainty; |
| 15 | 15 | use rustc_middle::ty::{ |
| 16 | self, MayBeErased, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitableExt as _, TypingMode, | |
| 16 | self, MayBeErased, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitableExt, TypingMode, | |
| 17 | 17 | }; |
| 18 | 18 | use rustc_span::{DUMMY_SP, Span}; |
| 19 | 19 | |
| ... | ... | @@ -73,51 +73,60 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< |
| 73 | 73 | goal: Goal<'tcx, ty::Predicate<'tcx>>, |
| 74 | 74 | span: Span, |
| 75 | 75 | ) -> Option<Certainty> { |
| 76 | if let Some(trait_pred) = goal.predicate.as_trait_clause() { | |
| 77 | if self.shallow_resolve(trait_pred.self_ty().skip_binder()).is_ty_var() | |
| 76 | let pred = goal.predicate.kind(); | |
| 77 | match pred.skip_binder() { | |
| 78 | ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => { | |
| 79 | let trait_pred = pred.rebind(trait_pred); | |
| 80 | ||
| 81 | if self.shallow_resolve(trait_pred.self_ty().skip_binder()).is_ty_var() | |
| 78 | 82 | // We don't do this fast path when opaques are defined since we may |
| 79 | 83 | // eventually use opaques to incompletely guide inference via ty var |
| 80 | 84 | // self types. |
| 81 | 85 | // FIXME: Properly consider opaques here. |
| 82 | 86 | && self.known_no_opaque_types_in_storage() |
| 83 | { | |
| 84 | return Some(Certainty::AMBIGUOUS); | |
| 85 | } | |
| 86 | ||
| 87 | if trait_pred.polarity() == ty::PredicatePolarity::Positive { | |
| 88 | match self.0.tcx.as_lang_item(trait_pred.def_id()) { | |
| 89 | Some(LangItem::Sized) | Some(LangItem::MetaSized) => { | |
| 90 | let predicate = self.resolve_vars_if_possible(goal.predicate); | |
| 91 | if sizedness_fast_path(self.tcx, predicate, goal.param_env) { | |
| 92 | return Some(Certainty::Yes); | |
| 87 | { | |
| 88 | Some(Certainty::AMBIGUOUS) | |
| 89 | } else if trait_pred.polarity() == ty::PredicatePolarity::Positive { | |
| 90 | match self.0.tcx.as_lang_item(trait_pred.def_id()) { | |
| 91 | Some(LangItem::Sized) | Some(LangItem::MetaSized) => { | |
| 92 | let predicate = self.resolve_vars_if_possible(goal.predicate); | |
| 93 | if sizedness_fast_path(self.tcx, predicate, goal.param_env) { | |
| 94 | return Some(Certainty::Yes); | |
| 95 | } else { | |
| 96 | None | |
| 97 | } | |
| 93 | 98 | } |
| 94 | } | |
| 95 | Some(LangItem::Copy | LangItem::Clone) => { | |
| 96 | let self_ty = | |
| 97 | self.resolve_vars_if_possible(trait_pred.self_ty().skip_binder()); | |
| 98 | // Unlike `Sized` traits, which always prefer the built-in impl, | |
| 99 | // `Copy`/`Clone` may be shadowed by a param-env candidate which | |
| 100 | // could force a lifetime error or guide inference. While that's | |
| 101 | // not generally desirable, it is observable, so for now let's | |
| 102 | // ignore this fast path for types that have regions or infer. | |
| 103 | if !self_ty | |
| 104 | .has_type_flags(TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_INFER) | |
| 105 | && self_ty.is_trivially_pure_clone_copy() | |
| 106 | { | |
| 107 | return Some(Certainty::Yes); | |
| 99 | Some(LangItem::Copy | LangItem::Clone) => { | |
| 100 | let self_ty = | |
| 101 | self.resolve_vars_if_possible(trait_pred.self_ty().skip_binder()); | |
| 102 | // Unlike `Sized` traits, which always prefer the built-in impl, | |
| 103 | // `Copy`/`Clone` may be shadowed by a param-env candidate which | |
| 104 | // could force a lifetime error or guide inference. While that's | |
| 105 | // not generally desirable, it is observable, so for now let's | |
| 106 | // ignore this fast path for types that have regions or infer. | |
| 107 | if !self_ty | |
| 108 | .has_type_flags(TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_INFER) | |
| 109 | && self_ty.is_trivially_pure_clone_copy() | |
| 110 | { | |
| 111 | return Some(Certainty::Yes); | |
| 112 | } else { | |
| 113 | None | |
| 114 | } | |
| 108 | 115 | } |
| 116 | _ => None, | |
| 109 | 117 | } |
| 110 | _ => {} | |
| 118 | } else { | |
| 119 | None | |
| 111 | 120 | } |
| 112 | 121 | } |
| 113 | } | |
| 114 | ||
| 115 | let pred = goal.predicate.kind(); | |
| 116 | match pred.no_bound_vars()? { | |
| 117 | 122 | ty::PredicateKind::DynCompatible(def_id) if self.0.tcx.is_dyn_compatible(def_id) => { |
| 118 | 123 | Some(Certainty::Yes) |
| 119 | 124 | } |
| 120 | 125 | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(outlives)) => { |
| 126 | if outlives.has_escaping_bound_vars() { | |
| 127 | return None; | |
| 128 | } | |
| 129 | ||
| 121 | 130 | self.0.sub_regions( |
| 122 | 131 | SubregionOrigin::RelateRegionParamBound(span, None), |
| 123 | 132 | outlives.1, |
| ... | ... | @@ -127,6 +136,10 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< |
| 127 | 136 | Some(Certainty::Yes) |
| 128 | 137 | } |
| 129 | 138 | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => { |
| 139 | if outlives.has_escaping_bound_vars() { | |
| 140 | return None; | |
| 141 | } | |
| 142 | ||
| 130 | 143 | self.0.register_type_outlives_constraint( |
| 131 | 144 | outlives.0, |
| 132 | 145 | outlives.1, |
| ... | ... | @@ -137,6 +150,10 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< |
| 137 | 150 | } |
| 138 | 151 | ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, .. }) |
| 139 | 152 | | ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => { |
| 153 | if a.has_escaping_bound_vars() || b.has_escaping_bound_vars() { | |
| 154 | return None; | |
| 155 | } | |
| 156 | ||
| 140 | 157 | match (self.shallow_resolve(a).kind(), self.shallow_resolve(b).kind()) { |
| 141 | 158 | (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => { |
| 142 | 159 | self.sub_unify_ty_vids_raw(a_vid, b_vid); |
| ... | ... | @@ -146,6 +163,10 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< |
| 146 | 163 | } |
| 147 | 164 | } |
| 148 | 165 | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _)) => { |
| 166 | if ct.has_escaping_bound_vars() { | |
| 167 | return None; | |
| 168 | } | |
| 169 | ||
| 149 | 170 | if self.shallow_resolve_const(ct).is_ct_infer() { |
| 150 | 171 | Some(Certainty::AMBIGUOUS) |
| 151 | 172 | } else { |
| ... | ... | @@ -153,6 +174,10 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< |
| 153 | 174 | } |
| 154 | 175 | } |
| 155 | 176 | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { |
| 177 | if arg.has_escaping_bound_vars() { | |
| 178 | return None; | |
| 179 | } | |
| 180 | ||
| 156 | 181 | let arg = self.shallow_resolve_term(arg); |
| 157 | 182 | if arg.is_trivially_wf(self.tcx) { |
| 158 | 183 | Some(Certainty::Yes) |
compiler/rustc_type_ir/src/interner.rs+9-4| ... | ... | @@ -4,6 +4,7 @@ use std::hash::Hash; |
| 4 | 4 | use std::ops::Deref; |
| 5 | 5 | |
| 6 | 6 | use rustc_ast_ir::Movability; |
| 7 | use rustc_ast_ir::visit::VisitorResult; | |
| 7 | 8 | use rustc_index::bit_set::DenseBitSet; |
| 8 | 9 | |
| 9 | 10 | use crate::fold::TypeFoldable; |
| ... | ... | @@ -401,13 +402,17 @@ pub trait Interner: |
| 401 | 402 | def_id: Self::TraitId, |
| 402 | 403 | ) -> impl IntoIterator<Item = Self::DefId>; |
| 403 | 404 | |
| 404 | fn for_each_relevant_impl( | |
| 405 | fn for_each_relevant_impl<R: VisitorResult>( | |
| 405 | 406 | self, |
| 406 | 407 | trait_def_id: Self::TraitId, |
| 407 | 408 | self_ty: Self::Ty, |
| 408 | f: impl FnMut(Self::ImplId), | |
| 409 | ); | |
| 410 | fn for_each_blanket_impl(self, trait_def_id: Self::TraitId, f: impl FnMut(Self::ImplId)); | |
| 409 | f: impl FnMut(Self::ImplId) -> R, | |
| 410 | ) -> R; | |
| 411 | fn for_each_blanket_impl<R: VisitorResult>( | |
| 412 | self, | |
| 413 | trait_def_id: Self::TraitId, | |
| 414 | f: impl FnMut(Self::ImplId) -> R, | |
| 415 | ) -> R; | |
| 411 | 416 | |
| 412 | 417 | fn has_item_definition(self, def_id: Self::ImplOrTraitAssocTermId) -> bool; |
| 413 | 418 |
compiler/rustc_type_ir/src/solve/mod.rs+56-30| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | pub mod inspect; |
| 2 | 2 | |
| 3 | use std::convert::Infallible; | |
| 3 | 4 | use std::fmt::Debug; |
| 4 | 5 | use std::hash::Hash; |
| 5 | 6 | |
| ... | ... | @@ -27,38 +28,55 @@ pub type CanonicalResponse<I> = Canonical<I, Response<I>>; |
| 27 | 28 | /// having to worry about changes to currently used code. Once we've made progress on this |
| 28 | 29 | /// solver, merge the two responses again. |
| 29 | 30 | pub type QueryResult<I> = Result<CanonicalResponse<I>, NoSolution>; |
| 31 | pub type QueryResultOrRerunNonErased<I> = Result<CanonicalResponse<I>, NoSolutionOrRerunNonErased>; | |
| 30 | 32 | |
| 31 | 33 | #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] |
| 32 | 34 | #[cfg_attr(feature = "nightly", derive(StableHash))] |
| 33 | 35 | pub struct NoSolution; |
| 34 | 36 | |
| 35 | pub enum NoSolutionOrOpaquesAccessed { | |
| 36 | NoSolution(NoSolution), | |
| 37 | /// A bit like [`NoSolution`], but for functions that normally cannot fail *unless* they accessed | |
| 38 | /// opaues. (See [`TypingMode::ErasedNotCoherence`]). Getting `OpaquesAccessed` doesn't mean there | |
| 39 | /// truly is no solution. It just means that we want to bail out of the current query as fast as | |
| 40 | /// possible, possibly by returning `NoSolution` if that's fastest. This is okay because when you get | |
| 41 | /// `OpaquesAccessed` we're guaranteed that we're going to retry this query in the original typing | |
| 42 | /// mode to get the correct answer. | |
| 43 | OpaquesAccessed, | |
| 37 | pub trait RerunResultExt<T> { | |
| 38 | fn map_err_to_rerun(self) -> Result<Result<T, NoSolution>, RerunNonErased>; | |
| 44 | 39 | } |
| 45 | 40 | |
| 46 | /// This conversion is sound, because even in we're in `OpaquesAccessed`, | |
| 47 | /// we're going to retry so `NoSolution` is a valid response to give.. | |
| 48 | impl From<NoSolutionOrOpaquesAccessed> for NoSolution { | |
| 49 | fn from( | |
| 50 | (NoSolutionOrOpaquesAccessed::NoSolution(_) | NoSolutionOrOpaquesAccessed::OpaquesAccessed): NoSolutionOrOpaquesAccessed, | |
| 51 | ) -> Self { | |
| 52 | NoSolution | |
| 41 | impl<T> RerunResultExt<T> for Result<T, NoSolutionOrRerunNonErased> { | |
| 42 | fn map_err_to_rerun(self) -> Result<Result<T, NoSolution>, RerunNonErased> { | |
| 43 | match self { | |
| 44 | Ok(i) => Ok(Ok(i)), | |
| 45 | Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution)) => Ok(Err(NoSolution)), | |
| 46 | Err(NoSolutionOrRerunNonErased::RerunNonErased(e)) => Err(e), | |
| 47 | } | |
| 53 | 48 | } |
| 54 | 49 | } |
| 55 | 50 | |
| 56 | impl From<NoSolution> for NoSolutionOrOpaquesAccessed { | |
| 51 | /// A bit like [`NoSolution`], but for functions that normally cannot fail *unless* they accessed | |
| 52 | /// opaues. (See [`TypingMode::ErasedNotCoherence`]). Getting `OpaquesAccessed` doesn't mean there | |
| 53 | /// truly is no solution. It just means that we want to bail out of the current query as fast as | |
| 54 | /// possible, possibly by returning `NoSolution` if that's fastest. This is okay because when you get | |
| 55 | /// `OpaquesAccessed` we're guaranteed that we're going to retry this query in the original typing | |
| 56 | /// mode to get the correct answer. | |
| 57 | #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] | |
| 58 | #[cfg_attr(feature = "nightly", derive(StableHash))] | |
| 59 | pub struct RerunNonErased(()); | |
| 60 | ||
| 61 | #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] | |
| 62 | #[cfg_attr(feature = "nightly", derive(StableHash))] | |
| 63 | pub enum NoSolutionOrRerunNonErased { | |
| 64 | NoSolution(NoSolution), | |
| 65 | RerunNonErased(RerunNonErased), | |
| 66 | } | |
| 67 | ||
| 68 | impl From<NoSolution> for NoSolutionOrRerunNonErased { | |
| 57 | 69 | fn from(value: NoSolution) -> Self { |
| 58 | 70 | Self::NoSolution(value) |
| 59 | 71 | } |
| 60 | 72 | } |
| 61 | 73 | |
| 74 | impl From<RerunNonErased> for NoSolutionOrRerunNonErased { | |
| 75 | fn from(value: RerunNonErased) -> Self { | |
| 76 | Self::RerunNonErased(value) | |
| 77 | } | |
| 78 | } | |
| 79 | ||
| 62 | 80 | #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] |
| 63 | 81 | #[derive(TypeVisitable_Generic, TypeFoldable_Generic, GenericTypeVisitable)] |
| 64 | 82 | #[cfg_attr(feature = "nightly", derive(StableHash_NoContext))] |
| ... | ... | @@ -216,13 +234,13 @@ impl<I: Interner> RerunCondition<I> { |
| 216 | 234 | } |
| 217 | 235 | |
| 218 | 236 | #[must_use] |
| 219 | fn should_bail(&self) -> bool { | |
| 237 | fn should_bail(&self) -> Result<(), RerunNonErased> { | |
| 220 | 238 | match self { |
| 221 | Self::Always => true, | |
| 239 | Self::Always => Err(RerunNonErased(())), | |
| 222 | 240 | Self::Never |
| 223 | 241 | | Self::OpaqueInStorage(_) |
| 224 | 242 | | Self::OpaqueInStorageOrAnyOpaqueHasInferAsHidden(_) |
| 225 | | Self::AnyOpaqueHasInferAsHidden => false, | |
| 243 | | Self::AnyOpaqueHasInferAsHidden => Ok(()), | |
| 226 | 244 | } |
| 227 | 245 | } |
| 228 | 246 | |
| ... | ... | @@ -274,13 +292,15 @@ impl<I: Interner> Default for AccessedOpaques<I> { |
| 274 | 292 | } |
| 275 | 293 | |
| 276 | 294 | impl<I: Interner> AccessedOpaques<I> { |
| 277 | pub fn update(&mut self, other: Self) { | |
| 295 | pub fn update(&mut self, other: Self) -> Result<(), RerunNonErased> { | |
| 278 | 296 | *self = Self { |
| 279 | 297 | // prefer the newest reason |
| 280 | 298 | reason: other.reason.or(self.reason), |
| 281 | 299 | // merging accessed states can only result in MultipleOrUnknown |
| 282 | 300 | rerun: self.rerun.merge(other.rerun), |
| 283 | 301 | }; |
| 302 | ||
| 303 | self.should_bail() | |
| 284 | 304 | } |
| 285 | 305 | |
| 286 | 306 | #[must_use] |
| ... | ... | @@ -289,41 +309,47 @@ impl<I: Interner> AccessedOpaques<I> { |
| 289 | 309 | } |
| 290 | 310 | |
| 291 | 311 | #[must_use] |
| 292 | pub fn should_bail(&self) -> bool { | |
| 312 | pub fn should_bail(&self) -> Result<(), RerunNonErased> { | |
| 293 | 313 | self.rerun.should_bail() |
| 294 | 314 | } |
| 295 | 315 | |
| 296 | pub fn rerun_always(&mut self, reason: RerunReason) { | |
| 316 | pub fn rerun_always(&mut self, reason: RerunReason) -> Result<Infallible, RerunNonErased> { | |
| 297 | 317 | debug!("set rerun always"); |
| 298 | self.update(AccessedOpaques { reason: Some(reason), rerun: RerunCondition::Always }); | |
| 318 | match self.update(AccessedOpaques { reason: Some(reason), rerun: RerunCondition::Always }) { | |
| 319 | Ok(_) => unreachable!(), | |
| 320 | Err(e) => Err(e), | |
| 321 | } | |
| 299 | 322 | } |
| 300 | 323 | |
| 301 | pub fn rerun_if_in_post_analysis(&mut self, reason: RerunReason) { | |
| 324 | pub fn rerun_if_in_post_analysis(&mut self, reason: RerunReason) -> Result<(), RerunNonErased> { | |
| 302 | 325 | debug!("set rerun if post analysis"); |
| 303 | 326 | self.update(AccessedOpaques { |
| 304 | 327 | reason: Some(reason), |
| 305 | 328 | rerun: RerunCondition::OpaqueInStorage(SmallCopyList::empty()), |
| 306 | }); | |
| 329 | }) | |
| 307 | 330 | } |
| 308 | 331 | |
| 309 | 332 | pub fn rerun_if_opaque_in_opaque_type_storage( |
| 310 | 333 | &mut self, |
| 311 | 334 | reason: RerunReason, |
| 312 | 335 | defid: I::LocalDefId, |
| 313 | ) { | |
| 336 | ) -> Result<(), RerunNonErased> { | |
| 314 | 337 | debug!("set rerun if opaque type {defid:?} in storage"); |
| 315 | 338 | self.update(AccessedOpaques { |
| 316 | 339 | reason: Some(reason), |
| 317 | 340 | rerun: RerunCondition::OpaqueInStorage(SmallCopyList::new(defid)), |
| 318 | }); | |
| 341 | }) | |
| 319 | 342 | } |
| 320 | 343 | |
| 321 | pub fn rerun_if_any_opaque_has_infer_as_hidden_type(&mut self, reason: RerunReason) { | |
| 344 | pub fn rerun_if_any_opaque_has_infer_as_hidden_type( | |
| 345 | &mut self, | |
| 346 | reason: RerunReason, | |
| 347 | ) -> Result<(), RerunNonErased> { | |
| 322 | 348 | debug!("set rerun if any opaque in the storage has a hidden type that is an infer var"); |
| 323 | 349 | self.update(AccessedOpaques { |
| 324 | 350 | reason: Some(reason), |
| 325 | 351 | rerun: RerunCondition::AnyOpaqueHasInferAsHidden, |
| 326 | }); | |
| 352 | }) | |
| 327 | 353 | } |
| 328 | 354 | } |
| 329 | 355 |
tests/run-make/msvc-incremental-full-link-info/main.rs created+1| ... | ... | @@ -0,0 +1 @@ |
| 1 | fn main() {} |
tests/run-make/msvc-incremental-full-link-info/rmake.rs created+47| ... | ... | @@ -0,0 +1,47 @@ |
| 1 | //@ only-msvc | |
| 2 | //! Tests that the MSVC incremental linker's "performing full link" message is classified as | |
| 3 | //! `linker_info`, not `linker_messages`. | |
| 4 | //! | |
| 5 | //! The MSVC incremental linker prints this message to stdout when it finds a `.ilk` file for | |
| 6 | //! incremental linking but its associated `.exe` file is missing: | |
| 7 | //! | |
| 8 | //! ``` | |
| 9 | //! LINK : ...\main.exe not found or not built by the last incremental link; performing full link | |
| 10 | //! ``` | |
| 11 | ||
| 12 | use std::fs; | |
| 13 | ||
| 14 | use run_make_support::bare_rustc; | |
| 15 | ||
| 16 | fn incremental_rustc() -> run_make_support::Rustc { | |
| 17 | let mut r = bare_rustc(); | |
| 18 | r.input("main.rs") | |
| 19 | // Overrides `rust.lld=true` on CI. | |
| 20 | .arg("-Clinker=link.exe") | |
| 21 | .arg("-Clinker-flavor=msvc") | |
| 22 | // Without this, Rust passes /OPT:REF to link.exe, which | |
| 23 | // disables incremental linking entirely and suppresses the message. | |
| 24 | .arg("-Clink-dead-code") | |
| 25 | // /DEBUG is required: it implies /INCREMENTAL, which is what makes | |
| 26 | // link.exe create the .ilk file and later emit the message. | |
| 27 | .arg("-Cdebuginfo=2"); | |
| 28 | r | |
| 29 | } | |
| 30 | ||
| 31 | fn main() { | |
| 32 | // First link: produces main.exe and main.ilk. | |
| 33 | incremental_rustc().run(); | |
| 34 | ||
| 35 | // Delete the .exe but leave the .ilk. | |
| 36 | fs::remove_file("main.exe").unwrap(); | |
| 37 | ||
| 38 | // Second link: link.exe finds the .ilk but not the .exe and emits the | |
| 39 | // "performing full link" message on stdout. | |
| 40 | let output = incremental_rustc() | |
| 41 | .arg("-Dlinker_messages") // Fail if the message is misclassified. | |
| 42 | .arg("-Wlinker_info") | |
| 43 | .run(); | |
| 44 | ||
| 45 | // Verify the message was actually emitted and routed to linker_info. | |
| 46 | output.assert_stderr_contains("performing full link"); | |
| 47 | } |
tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr+3| ... | ... | @@ -16,6 +16,9 @@ help: the following other types implement trait `VisitorResult` |
| 16 | 16 | ::: /rustc-dev/xyz/compiler/rustc_ast_ir/src/visit.rs:LL:COL |
| 17 | 17 | | |
| 18 | 18 | = note: `ControlFlow<T>` |
| 19 | ::: /rustc-dev/xyz/compiler/rustc_ast_ir/src/visit.rs:LL:COL | |
| 20 | | | |
| 21 | = note: `Result<(), E>` | |
| 19 | 22 | note: required by a bound in `rustc_ast::visit::Visitor::Result` |
| 20 | 23 | --> /rustc-dev/xyz/compiler/rustc_ast/src/visit.rs:LL:COL |
| 21 | 24 | ::: /rustc-dev/xyz/compiler/rustc_ast/src/visit.rs:LL:COL |
tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr+3| ... | ... | @@ -17,6 +17,9 @@ LL | impl VisitorResult for () { |
| 17 | 17 | ... |
| 18 | 18 | LL | impl<T> VisitorResult for ControlFlow<T> { |
| 19 | 19 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ControlFlow<T>` |
| 20 | ... | |
| 21 | LL | impl<E> VisitorResult for Result<(), E> { | |
| 22 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Result<(), E>` | |
| 20 | 23 | note: required by a bound in `rustc_ast::visit::Visitor::Result` |
| 21 | 24 | --> $COMPILER_DIR_REAL/rustc_ast/src/visit.rs:LL:COL |
| 22 | 25 | | |
tests/ui/closures/closure-arg-type-mismatch-method-receiver.rs created+13| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | // Regression test for https://github.com/rust-lang/rust/issues/156299. | |
| 2 | ||
| 3 | struct A; | |
| 4 | ||
| 5 | fn foo(_: &A) {} | |
| 6 | ||
| 7 | fn test_foo() { | |
| 8 | (|a: A| foo(a)).bar(); | |
| 9 | //~^ ERROR mismatched types | |
| 10 | //~| ERROR no method named `bar` found | |
| 11 | } | |
| 12 | ||
| 13 | fn main() {} |
tests/ui/closures/closure-arg-type-mismatch-method-receiver.stderr created+28| ... | ... | @@ -0,0 +1,28 @@ |
| 1 | error[E0308]: mismatched types | |
| 2 | --> $DIR/closure-arg-type-mismatch-method-receiver.rs:8:17 | |
| 3 | | | |
| 4 | LL | (|a: A| foo(a)).bar(); | |
| 5 | | --- ^ expected `&A`, found `A` | |
| 6 | | | | |
| 7 | | arguments to this function are incorrect | |
| 8 | | | |
| 9 | note: function defined here | |
| 10 | --> $DIR/closure-arg-type-mismatch-method-receiver.rs:5:4 | |
| 11 | | | |
| 12 | LL | fn foo(_: &A) {} | |
| 13 | | ^^^ ----- | |
| 14 | help: consider borrowing here | |
| 15 | | | |
| 16 | LL | (|a: A| foo(&a)).bar(); | |
| 17 | | + | |
| 18 | ||
| 19 | error[E0599]: no method named `bar` found for closure `{closure@$DIR/closure-arg-type-mismatch-method-receiver.rs:8:6: 8:12}` in the current scope | |
| 20 | --> $DIR/closure-arg-type-mismatch-method-receiver.rs:8:21 | |
| 21 | | | |
| 22 | LL | (|a: A| foo(a)).bar(); | |
| 23 | | ^^^ method not found in `{closure@$DIR/closure-arg-type-mismatch-method-receiver.rs:8:6: 8:12}` | |
| 24 | ||
| 25 | error: aborting due to 2 previous errors | |
| 26 | ||
| 27 | Some errors have detailed explanations: E0308, E0599. | |
| 28 | For more information about an error, try `rustc --explain E0308`. |