Skip to content
Open
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
147 changes: 138 additions & 9 deletions compiler/rustc_next_trait_solver/src/canonical/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@
//! [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html

use std::iter;
use std::marker::PhantomData;

use canonicalizer::Canonicalizer;
use rustc_index::IndexVec;
use rustc_type_ir::inherent::*;
use rustc_type_ir::relate::solver_relating::RelateExt;
use rustc_type_ir::{
self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner,
TypeFoldable, TypingMode, TypingModeEqWrapper,
TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingMode, TypingModeEqWrapper,
};
use tracing::instrument;

Expand Down Expand Up @@ -144,12 +145,29 @@ where
// FIXME: Longterm canonical queries should deal with all placeholders
// created inside of the query directly instead of returning them to the
// caller.
let prev_universe = delegate.universe();
let universes_created_in_query = response.max_universe.index();
for _ in 0..universes_created_in_query {
delegate.create_next_universe();
}
let prev_universe = create_universes_for_response(delegate, response);

compute_query_response_instantiation_values_in_universe(
delegate,
original_values,
response,
span,
prev_universe,
)
}

fn compute_query_response_instantiation_values_in_universe<D, I, T>(
delegate: &D,
original_values: &[I::GenericArg],
response: &Canonical<I, T>,
span: I::Span,
prev_universe: ty::UniverseIndex,
) -> CanonicalVarValues<I>
where
D: SolverDelegate<Interner = I>,
I: Interner,
T: ResponseT<I>,
{
let var_values = response.value.var_values();
assert_eq!(original_values.len(), var_values.len());

Expand Down Expand Up @@ -233,6 +251,109 @@ where
})
}

fn create_universes_for_response<D, I, T>(
delegate: &D,
response: &Canonical<I, T>,
) -> ty::UniverseIndex
where
D: SolverDelegate<Interner = I>,
I: Interner,
{
let prev_universe = delegate.universe();
let universes_created_in_query = response.max_universe.index();
for _ in 0..universes_created_in_query {
delegate.create_next_universe();
}
prev_universe
}

fn max_input_universe_for_replay<D, I>(
delegate: &D,
orig_values: &[I::GenericArg],
) -> ty::UniverseIndex
where
D: SolverDelegate<Interner = I>,
I: Interner,
{
struct MaxUniverseVisitor<'a, D, I> {
delegate: &'a D,
max_universe: ty::UniverseIndex,
_interner: PhantomData<I>,
}

impl<D, I> TypeVisitor<I> for MaxUniverseVisitor<'_, D, I>
where
D: SolverDelegate<Interner = I>,
I: Interner,
{
type Result = ();

fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
match t.kind() {
ty::Placeholder(placeholder) => {
self.max_universe = self.max_universe.max(placeholder.universe());
}
ty::Infer(ty::TyVar(vid)) => {
if let Some(universe) = self.delegate.universe_of_ty(vid) {
self.max_universe = self.max_universe.max(universe);
}
}
_ => {}
}
t.super_visit_with(self)
}

fn visit_region(&mut self, r: I::Region) -> Self::Result {
match r.kind() {
ty::RePlaceholder(placeholder) => {
self.max_universe = self.max_universe.max(placeholder.universe());
}
ty::ReVar(vid) => {
if let Some(universe) = self.delegate.universe_of_lt(vid) {
self.max_universe = self.max_universe.max(universe);
}
}
_ => {}
}
}

fn visit_const(&mut self, c: I::Const) -> Self::Result {
match c.kind() {
ty::ConstKind::Placeholder(placeholder) => {
self.max_universe = self.max_universe.max(placeholder.universe());
}
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
if let Some(universe) = self.delegate.universe_of_ct(vid) {
self.max_universe = self.max_universe.max(universe);
}
}
_ => {}
}
c.super_visit_with(self)
}
}

let mut visitor = MaxUniverseVisitor {
delegate,
max_universe: ty::UniverseIndex::ROOT,
_interner: PhantomData,
};
for value in orig_values {
value.visit_with(&mut visitor);
}
visitor.max_universe
}

fn ensure_universes_through<D, I>(delegate: &D, max_universe: ty::UniverseIndex)
where
D: SolverDelegate<Interner = I>,
I: Interner,
{
while delegate.universe() < max_universe {
delegate.create_next_universe();
}
}

/// Unify the `original_values` with the `var_values` returned by the canonical query..
///
/// This assumes that this unification will always succeed. This is the case when
Expand Down Expand Up @@ -347,14 +468,22 @@ where
{
// In case any fresh inference variables have been created between `state`
// and the previous instantiation, extend `orig_values` for it.
let prev_universe = max_input_universe_for_replay(delegate, orig_values);
let max_universe = prev_universe + state.max_universe.index();
ensure_universes_through(delegate, max_universe);
orig_values.extend(
state.value.var_values.var_values.as_slice()[orig_values.len()..]
.iter()
.map(|&arg| delegate.fresh_var_for_kind_with_span(arg, span)),
.map(|&arg| delegate.fresh_var_for_kind_in_universe(arg, span, max_universe)),
);

let instantiation =
compute_query_response_instantiation_values(delegate, orig_values, &state, span);
let instantiation = compute_query_response_instantiation_values_in_universe(
delegate,
orig_values,
&state,
span,
prev_universe,
);

let inspect::State { var_values, data } = delegate.instantiate_canonical(state, instantiation);

Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_next_trait_solver/src/delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
span: <Self::Interner as Interner>::Span,
) -> Option<Certainty>;

fn fresh_var_for_kind_with_span(
fn fresh_var_for_kind_in_universe(
&self,
arg: <Self::Interner as Interner>::GenericArg,
span: <Self::Interner as Interner>::Span,
universe: ty::UniverseIndex,
) -> <Self::Interner as Interner>::GenericArg;

// FIXME: Uplift the leak check into this crate.
Expand Down
9 changes: 5 additions & 4 deletions compiler/rustc_trait_selection/src/solve/delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,17 +166,18 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
}
}

fn fresh_var_for_kind_with_span(
fn fresh_var_for_kind_in_universe(
&self,
arg: ty::GenericArg<'tcx>,
span: Span,
universe: ty::UniverseIndex,
) -> ty::GenericArg<'tcx> {
match arg.kind() {
ty::GenericArgKind::Lifetime(_) => {
self.next_region_var(RegionVariableOrigin::Misc(span)).into()
self.next_region_var_in_universe(RegionVariableOrigin::Misc(span), universe).into()
}
ty::GenericArgKind::Type(_) => self.next_ty_var(span).into(),
ty::GenericArgKind::Const(_) => self.next_const_var(span).into(),
ty::GenericArgKind::Type(_) => self.next_ty_var_in_universe(span, universe).into(),
ty::GenericArgKind::Const(_) => self.next_const_var_in_universe(span, universe).into(),
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//@ compile-flags: -Znext-solver=globally

#![allow(incomplete_features)]
#![feature(non_lifetime_binders)]

fn auto_trait()
where
for<T> T: PartialEq + PartialOrd,
{}

fn main() {
auto_trait();
//~^ ERROR can't compare `T` with `T`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error[E0277]: can't compare `T` with `T`
--> $DIR/foreach-partial-eq-next-solver.rs:12:5
|
LL | auto_trait();
| ^^^^^^^^^^^^ no implementation for `T < T` and `T > T`
|
= help: the trait `PartialOrd` is not implemented for `T`
note: required by a bound in `auto_trait`
--> $DIR/foreach-partial-eq-next-solver.rs:8:27
|
LL | fn auto_trait()
| ---------- required by a bound in this function
LL | where
LL | for<T> T: PartialEq + PartialOrd,
| ^^^^^^^^^^ required by this bound in `auto_trait`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.
Loading