Skip to content
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

Stop using translate_args in the new solver #125776

Merged
merged 1 commit into from
May 31, 2024
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
11 changes: 0 additions & 11 deletions compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use rustc_middle::bug;
use rustc_middle::traits::solve::{
inspect, CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaquesData, QueryResult,
};
use rustc_middle::traits::specialization_graph;
use rustc_middle::ty::AliasRelationDirection;
use rustc_middle::ty::TypeFolder;
use rustc_middle::ty::{
Expand Down Expand Up @@ -900,16 +899,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
args
}

pub(super) fn translate_args(
&self,
param_env: ty::ParamEnv<'tcx>,
source_impl: DefId,
source_args: ty::GenericArgsRef<'tcx>,
target_node: specialization_graph::Node,
) -> ty::GenericArgsRef<'tcx> {
crate::traits::translate_args(self.infcx, param_env, source_impl, source_args, target_node)
}

pub(super) fn register_ty_outlives(&self, ty: Ty<'tcx>, lt: ty::Region<'tcx>) {
self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy());
}
Expand Down
125 changes: 79 additions & 46 deletions compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::traits::specialization_graph;
use crate::traits::specialization_graph::{self, LeafDef, Node};

use super::assembly::structural_traits::AsyncCallableRelevantTypes;
use super::assembly::{self, structural_traits, Candidate};
Expand All @@ -9,7 +9,6 @@ use rustc_infer::infer::InferCtxt;
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::solve::inspect::ProbeKind;
use rustc_infer::traits::solve::MaybeCause;
use rustc_infer::traits::specialization_graph::LeafDef;
use rustc_infer::traits::Reveal;
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult};
use rustc_middle::traits::BuiltinImplSource;
Expand Down Expand Up @@ -189,8 +188,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
// In case the associated item is hidden due to specialization, we have to
// return ambiguity this would otherwise be incomplete, resulting in
// unsoundness during coherence (#105782).
let Some(assoc_def) = fetch_eligible_assoc_item_def(
ecx,
let Some(assoc_def) = ecx.fetch_eligible_assoc_item_def(
goal.param_env,
goal_trait_ref,
goal.predicate.def_id(),
Expand Down Expand Up @@ -235,16 +233,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
//
// And then map these args to the args of the defining impl of `Assoc`, going
// from `[u32, u64]` to `[u32, i32, u64]`.
let impl_args_with_gat =
goal.predicate.alias.args.rebase_onto(tcx, goal_trait_ref.def_id, impl_args);
let args = ecx.translate_args(
goal.param_env,
impl_def_id,
impl_args_with_gat,
assoc_def.defining_node,
);
let associated_item_args =
ecx.translate_args(&assoc_def, goal, impl_def_id, impl_args, impl_trait_ref)?;

if !tcx.check_args_compatible(assoc_def.item.def_id, args) {
if !tcx.check_args_compatible(assoc_def.item.def_id, associated_item_args) {
return error_response(
ecx,
"associated item has mismatched generic item arguments",
Expand Down Expand Up @@ -272,7 +264,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
ty::AssocKind::Fn => unreachable!("we should never project to a fn"),
};

ecx.instantiate_normalizes_to_term(goal, term.instantiate(tcx, args));
ecx.instantiate_normalizes_to_term(goal, term.instantiate(tcx, associated_item_args));
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
}
Expand Down Expand Up @@ -889,38 +881,79 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
}
}

/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
///
/// FIXME: We should merge these 3 implementations as it's likely that they otherwise
/// diverge.
#[instrument(level = "trace", skip(ecx, param_env), ret)]
fn fetch_eligible_assoc_item_def<'tcx>(
ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
goal_trait_ref: ty::TraitRef<'tcx>,
trait_assoc_def_id: DefId,
impl_def_id: DefId,
) -> Result<Option<LeafDef>, NoSolution> {
let node_item =
specialization_graph::assoc_def(ecx.interner(), impl_def_id, trait_assoc_def_id)
.map_err(|ErrorGuaranteed { .. }| NoSolution)?;

let eligible = if node_item.is_final() {
// Non-specializable items are always projectable.
true
} else {
// Only reveal a specializable default if we're past type-checking
// and the obligation is monomorphic, otherwise passes such as
// transmute checking and polymorphic MIR optimizations could
// get a result which isn't correct for all monomorphizations.
if param_env.reveal() == Reveal::All {
let poly_trait_ref = ecx.resolve_vars_if_possible(goal_trait_ref);
!poly_trait_ref.still_further_specializable()
impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
fn translate_args(
&mut self,
assoc_def: &LeafDef,
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
impl_def_id: DefId,
impl_args: ty::GenericArgsRef<'tcx>,
impl_trait_ref: rustc_type_ir::TraitRef<TyCtxt<'tcx>>,
) -> Result<ty::GenericArgsRef<'tcx>, NoSolution> {
let tcx = self.interner();
Ok(match assoc_def.defining_node {
Node::Trait(_) => goal.predicate.alias.args,
Node::Impl(target_impl_def_id) => {
if target_impl_def_id == impl_def_id {
// Same impl, no need to fully translate, just a rebase from
// the trait is sufficient.
goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, impl_args)
} else {
let target_args = self.fresh_args_for_item(target_impl_def_id);
let target_trait_ref = tcx
.impl_trait_ref(target_impl_def_id)
.unwrap()
.instantiate(tcx, target_args);
// Relate source impl to target impl by equating trait refs.
self.eq(goal.param_env, impl_trait_ref, target_trait_ref)?;
// Also add predicates since they may be needed to constrain the
// target impl's params.
self.add_goals(
GoalSource::Misc,
tcx.predicates_of(target_impl_def_id)
.instantiate(tcx, target_args)
.into_iter()
.map(|(pred, _)| goal.with(tcx, pred)),
);
goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, target_args)
}
}
})
}

/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
///
/// FIXME: We should merge these 3 implementations as it's likely that they otherwise
/// diverge.
#[instrument(level = "trace", skip(self, param_env), ret)]
fn fetch_eligible_assoc_item_def(
&self,
param_env: ty::ParamEnv<'tcx>,
goal_trait_ref: ty::TraitRef<'tcx>,
trait_assoc_def_id: DefId,
impl_def_id: DefId,
) -> Result<Option<LeafDef>, NoSolution> {
let node_item =
specialization_graph::assoc_def(self.interner(), impl_def_id, trait_assoc_def_id)
.map_err(|ErrorGuaranteed { .. }| NoSolution)?;

let eligible = if node_item.is_final() {
// Non-specializable items are always projectable.
true
} else {
trace!(?node_item.item.def_id, "not eligible due to default");
false
}
};
// Only reveal a specializable default if we're past type-checking
// and the obligation is monomorphic, otherwise passes such as
// transmute checking and polymorphic MIR optimizations could
// get a result which isn't correct for all monomorphizations.
if param_env.reveal() == Reveal::All {
let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
!poly_trait_ref.still_further_specializable()
} else {
trace!(?node_item.item.def_id, "not eligible due to default");
false
}
};

if eligible { Ok(Some(node_item)) } else { Ok(None) }
if eligible { Ok(Some(node_item)) } else { Ok(None) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/source-impl-requires-constraining-predicates-ambig.rs:14:12
|
LL | #![feature(specialization)]
| ^^^^^^^^^^^^^^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: consider using `min_specialization` instead, which is more stable and complete
= note: `#[warn(incomplete_features)]` on by default

warning: 1 warning emitted

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
//@[next] check-pass
//@[current] known-bug: unknown
//@[current] failure-status: 101
//@[current] dont-check-compiler-stderr

// Tests that rebasing from the concrete impl to the default impl also processes the
// `[u32; 0]: IntoIterator<Item = ?U>` predicate to constrain the `?U` impl arg.
// This test also makes sure that we don't do anything weird when rebasing the args
// is ambiguous.

#![feature(specialization)]
//[next]~^ WARN the feature `specialization` is incomplete

trait Spec {
type Assoc;
}

default impl<T, U> Spec for T where T: IntoIterator<Item = U> {
type Assoc = U;
}

impl<T> Spec for [T; 0] {}

fn main() {
let x: <[_; 0] as Spec>::Assoc = 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/source-impl-requires-constraining-predicates.rs:9:12
|
LL | #![feature(specialization)]
| ^^^^^^^^^^^^^^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: consider using `min_specialization` instead, which is more stable and complete
= note: `#[warn(incomplete_features)]` on by default

warning: 1 warning emitted

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/source-impl-requires-constraining-predicates.rs:9:12
|
LL | #![feature(specialization)]
| ^^^^^^^^^^^^^^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: consider using `min_specialization` instead, which is more stable and complete
= note: `#[warn(incomplete_features)]` on by default

warning: 1 warning emitted

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//@ check-pass
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver

// Tests that rebasing from the concrete impl to the default impl also processes the
// `[u32; 0]: IntoIterator<Item = ?U>` predicate to constrain the `?U` impl arg.

#![feature(specialization)]
//~^ WARN the feature `specialization` is incomplete

trait Spec {
type Assoc;
}

default impl<T, U> Spec for T where T: IntoIterator<Item = U> {
type Assoc = U;
}

impl<T> Spec for [T; 0] {}

fn main() {
let x: <[u32; 0] as Spec>::Assoc = 1;
Copy link
Contributor

Choose a reason for hiding this comment

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

you're not testing the [_; 0] ice?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, because it's not fixed in the old solver. Could add one for the new solver if you want?

Copy link
Member Author

Choose a reason for hiding this comment

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

Added a test for the ambiguity case, and known-bug:unknown in the old solver

}
Loading