From 055d31c7a5aa2ef642d3d390665ba52e36a7895c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 17 Mar 2025 08:58:08 +0000 Subject: [PATCH 1/2] Demonstrate next-solver missing diagnostic --- ...on-ref-due-to-missing-bound.current.fixed} | 11 ++++++----- ...n-ref-due-to-missing-bound.current.stderr} | 4 ++-- ...ll-on-ref-due-to-missing-bound.next.stderr | 19 +++++++++++++++++++ ...-clone-call-on-ref-due-to-missing-bound.rs | 11 ++++++----- 4 files changed, 33 insertions(+), 12 deletions(-) rename tests/ui/moves/{assignment-of-clone-call-on-ref-due-to-missing-bound.fixed => assignment-of-clone-call-on-ref-due-to-missing-bound.current.fixed} (66%) rename tests/ui/moves/{assignment-of-clone-call-on-ref-due-to-missing-bound.stderr => assignment-of-clone-call-on-ref-due-to-missing-bound.current.stderr} (98%) create mode 100644 tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.next.stderr diff --git a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.fixed b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.current.fixed similarity index 66% rename from tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.fixed rename to tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.current.fixed index 85b1853c23b82..4a27c66b89e45 100644 --- a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.fixed +++ b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.current.fixed @@ -1,16 +1,17 @@ -//@ run-rustfix +//@[current] run-rustfix +//@ revisions: current next +//@[next] compile-flags: -Znext-solver #![allow(unused_variables, dead_code)] -use std::collections::BTreeMap; -use std::collections::HashSet; +use std::collections::{BTreeMap, HashSet}; -#[derive(Debug,Eq,PartialEq,Hash)] +#[derive(Debug, Eq, PartialEq, Hash)] #[derive(Clone)] enum Day { Mon, } struct Class { - days: BTreeMap> + days: BTreeMap>, } impl Class { diff --git a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.stderr b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.current.stderr similarity index 98% rename from tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.stderr rename to tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.current.stderr index 6a9d76f7998c9..301f3c3a458de 100644 --- a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.stderr +++ b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.current.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/assignment-of-clone-call-on-ref-due-to-missing-bound.rs:18:39 + --> $DIR/assignment-of-clone-call-on-ref-due-to-missing-bound.rs:19:39 | LL | let mut x: HashSet = v.clone(); | ------------ ^^^^^^^^^ expected `HashSet`, found `&HashSet` @@ -9,7 +9,7 @@ LL | let mut x: HashSet = v.clone(); = note: expected struct `HashSet<_>` found reference `&HashSet<_>` note: `HashSet` does not implement `Clone`, so `&HashSet` was cloned instead - --> $DIR/assignment-of-clone-call-on-ref-due-to-missing-bound.rs:18:39 + --> $DIR/assignment-of-clone-call-on-ref-due-to-missing-bound.rs:19:39 | LL | let mut x: HashSet = v.clone(); | ^ diff --git a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.next.stderr b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.next.stderr new file mode 100644 index 0000000000000..4e71c57ea1af0 --- /dev/null +++ b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.next.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/assignment-of-clone-call-on-ref-due-to-missing-bound.rs:19:39 + | +LL | let mut x: HashSet = v.clone(); + | ------------ ^^^^^^^^^ expected `HashSet`, found `&HashSet` + | | + | expected due to this + | + = note: expected struct `HashSet<_>` + found reference `&HashSet<_>` +note: `HashSet` does not implement `Clone`, so `&HashSet` was cloned instead + --> $DIR/assignment-of-clone-call-on-ref-due-to-missing-bound.rs:19:39 + | +LL | let mut x: HashSet = v.clone(); + | ^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.rs b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.rs index 740cda470d913..7fadbce2b98b0 100644 --- a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.rs +++ b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.rs @@ -1,15 +1,16 @@ -//@ run-rustfix +//@[current] run-rustfix +//@ revisions: current next +//@[next] compile-flags: -Znext-solver #![allow(unused_variables, dead_code)] -use std::collections::BTreeMap; -use std::collections::HashSet; +use std::collections::{BTreeMap, HashSet}; -#[derive(Debug,Eq,PartialEq,Hash)] +#[derive(Debug, Eq, PartialEq, Hash)] enum Day { Mon, } struct Class { - days: BTreeMap> + days: BTreeMap>, } impl Class { From 14cd467001aa5324fb3b067c80debfffda12c527 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 17 Mar 2025 08:16:52 +0000 Subject: [PATCH 2/2] Fix next solver handling of shallow trait impl check --- compiler/rustc_trait_selection/src/infer.rs | 30 +++++++++++------- ...-on-ref-due-to-missing-bound.current.fixed | 2 +- ...all-on-ref-due-to-missing-bound.next.fixed | 31 +++++++++++++++++++ ...ll-on-ref-due-to-missing-bound.next.stderr | 6 ++++ ...-clone-call-on-ref-due-to-missing-bound.rs | 2 +- 5 files changed, 57 insertions(+), 14 deletions(-) create mode 100644 tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.next.fixed diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 5cf0600ade8b4..84ac229b743d9 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -15,7 +15,7 @@ use tracing::instrument; use crate::infer::at::ToTrace; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; -use crate::traits::{self, Obligation, ObligationCause, ObligationCtxt, SelectionContext}; +use crate::traits::{self, Obligation, ObligationCause, ObligationCtxt}; #[extension(pub trait InferCtxtExt<'tcx>)] impl<'tcx> InferCtxt<'tcx> { @@ -122,9 +122,6 @@ impl<'tcx> InferCtxt<'tcx> { /// - If this returns `Some([errors..])`, then the trait has an impl for /// the self type, but some nested obligations do not hold. /// - If this returns `None`, no implementation that applies could be found. - /// - /// FIXME(-Znext-solver): Due to the recursive nature of the new solver, - /// this will probably only ever return `Some([])` or `None`. fn type_implements_trait_shallow( &self, trait_def_id: DefId, @@ -132,20 +129,29 @@ impl<'tcx> InferCtxt<'tcx> { param_env: ty::ParamEnv<'tcx>, ) -> Option>> { self.probe(|_snapshot| { - let mut selcx = SelectionContext::new(self); - match selcx.select(&Obligation::new( + let ocx = ObligationCtxt::new_with_diagnostics(self); + ocx.register_obligation(Obligation::new( self.tcx, ObligationCause::dummy(), param_env, ty::TraitRef::new(self.tcx, trait_def_id, [ty]), - )) { - Ok(Some(selection)) => { - let ocx = ObligationCtxt::new_with_diagnostics(self); - ocx.register_obligations(selection.nested_obligations()); - Some(ocx.select_all_or_error()) + )); + let errors = ocx.select_where_possible(); + // Find the original predicate in the list of predicates that could definitely not be fulfilled. + // If it is in that list, then we know this doesn't even shallowly implement the trait. + // If it is not in that list, it was fulfilled, but there may be nested obligations, which we don't care about here. + for error in &errors { + let Some(trait_clause) = error.obligation.predicate.as_trait_clause() else { + continue; + }; + let Some(bound_ty) = trait_clause.self_ty().no_bound_vars() else { continue }; + if trait_clause.def_id() == trait_def_id + && ocx.eq(&ObligationCause::dummy(), param_env, bound_ty, ty).is_ok() + { + return None; } - Ok(None) | Err(_) => None, } + Some(errors) }) } } diff --git a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.current.fixed b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.current.fixed index 4a27c66b89e45..922c883f4f71f 100644 --- a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.current.fixed +++ b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.current.fixed @@ -1,4 +1,4 @@ -//@[current] run-rustfix +//@ run-rustfix //@ revisions: current next //@[next] compile-flags: -Znext-solver #![allow(unused_variables, dead_code)] diff --git a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.next.fixed b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.next.fixed new file mode 100644 index 0000000000000..922c883f4f71f --- /dev/null +++ b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.next.fixed @@ -0,0 +1,31 @@ +//@ run-rustfix +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +#![allow(unused_variables, dead_code)] +use std::collections::{BTreeMap, HashSet}; + +#[derive(Debug, Eq, PartialEq, Hash)] +#[derive(Clone)] +enum Day { + Mon, +} + +struct Class { + days: BTreeMap>, +} + +impl Class { + fn do_stuff(&self) { + for (_, v) in &self.days { + let mut x: HashSet = v.clone(); //~ ERROR + let y: Vec = x.drain().collect(); + println!("{:?}", x); + } + } +} + +fn fail() { + let c = Class { days: BTreeMap::new() }; + c.do_stuff(); +} +fn main() {} diff --git a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.next.stderr b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.next.stderr index 4e71c57ea1af0..301f3c3a458de 100644 --- a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.next.stderr +++ b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.next.stderr @@ -13,6 +13,12 @@ note: `HashSet` does not implement `Clone`, so `&HashSet` was cloned i | LL | let mut x: HashSet = v.clone(); | ^ + = help: `Clone` is not implemented because the trait bound `Day: Clone` is not satisfied +help: consider annotating `Day` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | enum Day { + | error: aborting due to 1 previous error diff --git a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.rs b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.rs index 7fadbce2b98b0..6f7b55be8bd28 100644 --- a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.rs +++ b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.rs @@ -1,4 +1,4 @@ -//@[current] run-rustfix +//@ run-rustfix //@ revisions: current next //@[next] compile-flags: -Znext-solver #![allow(unused_variables, dead_code)]