Skip to content

Fix next solver handling of shallow trait impl check #138594

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 18 additions & 12 deletions compiler/rustc_trait_selection/src/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down Expand Up @@ -122,30 +122,36 @@ 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,
ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Option<Vec<traits::FulfillmentError<'tcx>>> {
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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment pls, this is a clever way to handle this in both solvers, but it took me a bit to think through it

r=me afterwards

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)
})
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
//@ 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<u32, HashSet<Day>>
days: BTreeMap<u32, HashSet<Day>>,
}

impl Class {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Day> = v.clone();
| ------------ ^^^^^^^^^ expected `HashSet<Day>`, found `&HashSet<Day>`
Expand All @@ -9,7 +9,7 @@ LL | let mut x: HashSet<Day> = v.clone();
= note: expected struct `HashSet<_>`
found reference `&HashSet<_>`
note: `HashSet<Day>` does not implement `Clone`, so `&HashSet<Day>` 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<Day> = v.clone();
| ^
Expand Down
Original file line number Diff line number Diff line change
@@ -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<u32, HashSet<Day>>,
}

impl Class {
fn do_stuff(&self) {
for (_, v) in &self.days {
let mut x: HashSet<Day> = v.clone(); //~ ERROR
let y: Vec<Day> = x.drain().collect();
println!("{:?}", x);
}
}
}

fn fail() {
let c = Class { days: BTreeMap::new() };
c.do_stuff();
}
fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
error[E0308]: mismatched types
--> $DIR/assignment-of-clone-call-on-ref-due-to-missing-bound.rs:19:39
|
LL | let mut x: HashSet<Day> = v.clone();
| ------------ ^^^^^^^^^ expected `HashSet<Day>`, found `&HashSet<Day>`
| |
| expected due to this
|
= note: expected struct `HashSet<_>`
found reference `&HashSet<_>`
note: `HashSet<Day>` does not implement `Clone`, so `&HashSet<Day>` was cloned instead
--> $DIR/assignment-of-clone-call-on-ref-due-to-missing-bound.rs:19:39
|
LL | let mut x: HashSet<Day> = 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

For more information about this error, try `rustc --explain E0308`.
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
//@ 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<u32, HashSet<Day>>
days: BTreeMap<u32, HashSet<Day>>,
}

impl Class {
Expand Down
Loading