Skip to content

Commit 20699fe

Browse files
Stop using translate_args in the new solver
1 parent 99cb42c commit 20699fe

7 files changed

+168
-57
lines changed

compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs

-11
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use rustc_middle::bug;
1212
use rustc_middle::traits::solve::{
1313
inspect, CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaquesData, QueryResult,
1414
};
15-
use rustc_middle::traits::specialization_graph;
1615
use rustc_middle::ty::AliasRelationDirection;
1716
use rustc_middle::ty::TypeFolder;
1817
use rustc_middle::ty::{
@@ -900,16 +899,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
900899
args
901900
}
902901

903-
pub(super) fn translate_args(
904-
&self,
905-
param_env: ty::ParamEnv<'tcx>,
906-
source_impl: DefId,
907-
source_args: ty::GenericArgsRef<'tcx>,
908-
target_node: specialization_graph::Node,
909-
) -> ty::GenericArgsRef<'tcx> {
910-
crate::traits::translate_args(self.infcx, param_env, source_impl, source_args, target_node)
911-
}
912-
913902
pub(super) fn register_ty_outlives(&self, ty: Ty<'tcx>, lt: ty::Region<'tcx>) {
914903
self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy());
915904
}

compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs

+79-46
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::traits::specialization_graph;
1+
use crate::traits::specialization_graph::{self, LeafDef, Node};
22

33
use super::assembly::structural_traits::AsyncCallableRelevantTypes;
44
use super::assembly::{self, structural_traits, Candidate};
@@ -9,7 +9,6 @@ use rustc_infer::infer::InferCtxt;
99
use rustc_infer::traits::query::NoSolution;
1010
use rustc_infer::traits::solve::inspect::ProbeKind;
1111
use rustc_infer::traits::solve::MaybeCause;
12-
use rustc_infer::traits::specialization_graph::LeafDef;
1312
use rustc_infer::traits::Reveal;
1413
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult};
1514
use rustc_middle::traits::BuiltinImplSource;
@@ -189,8 +188,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
189188
// In case the associated item is hidden due to specialization, we have to
190189
// return ambiguity this would otherwise be incomplete, resulting in
191190
// unsoundness during coherence (#105782).
192-
let Some(assoc_def) = fetch_eligible_assoc_item_def(
193-
ecx,
191+
let Some(assoc_def) = ecx.fetch_eligible_assoc_item_def(
194192
goal.param_env,
195193
goal_trait_ref,
196194
goal.predicate.def_id(),
@@ -235,16 +233,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
235233
//
236234
// And then map these args to the args of the defining impl of `Assoc`, going
237235
// from `[u32, u64]` to `[u32, i32, u64]`.
238-
let impl_args_with_gat =
239-
goal.predicate.alias.args.rebase_onto(tcx, goal_trait_ref.def_id, impl_args);
240-
let args = ecx.translate_args(
241-
goal.param_env,
242-
impl_def_id,
243-
impl_args_with_gat,
244-
assoc_def.defining_node,
245-
);
236+
let associated_item_args =
237+
ecx.translate_args(&assoc_def, goal, impl_def_id, impl_args, impl_trait_ref)?;
246238

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

275-
ecx.instantiate_normalizes_to_term(goal, term.instantiate(tcx, args));
267+
ecx.instantiate_normalizes_to_term(goal, term.instantiate(tcx, associated_item_args));
276268
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
277269
})
278270
}
@@ -889,38 +881,79 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
889881
}
890882
}
891883

892-
/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
893-
///
894-
/// FIXME: We should merge these 3 implementations as it's likely that they otherwise
895-
/// diverge.
896-
#[instrument(level = "trace", skip(ecx, param_env), ret)]
897-
fn fetch_eligible_assoc_item_def<'tcx>(
898-
ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
899-
param_env: ty::ParamEnv<'tcx>,
900-
goal_trait_ref: ty::TraitRef<'tcx>,
901-
trait_assoc_def_id: DefId,
902-
impl_def_id: DefId,
903-
) -> Result<Option<LeafDef>, NoSolution> {
904-
let node_item =
905-
specialization_graph::assoc_def(ecx.interner(), impl_def_id, trait_assoc_def_id)
906-
.map_err(|ErrorGuaranteed { .. }| NoSolution)?;
907-
908-
let eligible = if node_item.is_final() {
909-
// Non-specializable items are always projectable.
910-
true
911-
} else {
912-
// Only reveal a specializable default if we're past type-checking
913-
// and the obligation is monomorphic, otherwise passes such as
914-
// transmute checking and polymorphic MIR optimizations could
915-
// get a result which isn't correct for all monomorphizations.
916-
if param_env.reveal() == Reveal::All {
917-
let poly_trait_ref = ecx.resolve_vars_if_possible(goal_trait_ref);
918-
!poly_trait_ref.still_further_specializable()
884+
impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
885+
fn translate_args(
886+
&mut self,
887+
assoc_def: &LeafDef,
888+
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
889+
impl_def_id: DefId,
890+
impl_args: ty::GenericArgsRef<'tcx>,
891+
impl_trait_ref: rustc_type_ir::TraitRef<TyCtxt<'tcx>>,
892+
) -> Result<ty::GenericArgsRef<'tcx>, NoSolution> {
893+
let tcx = self.interner();
894+
Ok(match assoc_def.defining_node {
895+
Node::Trait(_) => goal.predicate.alias.args,
896+
Node::Impl(target_impl_def_id) => {
897+
if target_impl_def_id == impl_def_id {
898+
// Same impl, no need to fully translate, just a rebase from
899+
// the trait is sufficient.
900+
goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, impl_args)
901+
} else {
902+
let target_args = self.fresh_args_for_item(target_impl_def_id);
903+
let target_trait_ref = tcx
904+
.impl_trait_ref(target_impl_def_id)
905+
.unwrap()
906+
.instantiate(tcx, target_args);
907+
// Relate source impl to target impl by equating trait refs.
908+
self.eq(goal.param_env, impl_trait_ref, target_trait_ref)?;
909+
// Also add predicates since they may be needed to constrain the
910+
// target impl's params.
911+
self.add_goals(
912+
GoalSource::Misc,
913+
tcx.predicates_of(target_impl_def_id)
914+
.instantiate(tcx, target_args)
915+
.into_iter()
916+
.map(|(pred, _)| goal.with(tcx, pred)),
917+
);
918+
goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, target_args)
919+
}
920+
}
921+
})
922+
}
923+
924+
/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
925+
///
926+
/// FIXME: We should merge these 3 implementations as it's likely that they otherwise
927+
/// diverge.
928+
#[instrument(level = "trace", skip(self, param_env), ret)]
929+
fn fetch_eligible_assoc_item_def(
930+
&self,
931+
param_env: ty::ParamEnv<'tcx>,
932+
goal_trait_ref: ty::TraitRef<'tcx>,
933+
trait_assoc_def_id: DefId,
934+
impl_def_id: DefId,
935+
) -> Result<Option<LeafDef>, NoSolution> {
936+
let node_item =
937+
specialization_graph::assoc_def(self.interner(), impl_def_id, trait_assoc_def_id)
938+
.map_err(|ErrorGuaranteed { .. }| NoSolution)?;
939+
940+
let eligible = if node_item.is_final() {
941+
// Non-specializable items are always projectable.
942+
true
919943
} else {
920-
trace!(?node_item.item.def_id, "not eligible due to default");
921-
false
922-
}
923-
};
944+
// Only reveal a specializable default if we're past type-checking
945+
// and the obligation is monomorphic, otherwise passes such as
946+
// transmute checking and polymorphic MIR optimizations could
947+
// get a result which isn't correct for all monomorphizations.
948+
if param_env.reveal() == Reveal::All {
949+
let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
950+
!poly_trait_ref.still_further_specializable()
951+
} else {
952+
trace!(?node_item.item.def_id, "not eligible due to default");
953+
false
954+
}
955+
};
924956

925-
if eligible { Ok(Some(node_item)) } else { Ok(None) }
957+
if eligible { Ok(Some(node_item)) } else { Ok(None) }
958+
}
926959
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/source-impl-requires-constraining-predicates-ambig.rs:14:12
3+
|
4+
LL | #![feature(specialization)]
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
8+
= help: consider using `min_specialization` instead, which is more stable and complete
9+
= note: `#[warn(incomplete_features)]` on by default
10+
11+
warning: 1 warning emitted
12+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//@ revisions: current next
2+
//@ ignore-compare-mode-next-solver (explicit revisions)
3+
//@[next] compile-flags: -Znext-solver
4+
//@[next] check-pass
5+
//@[current] known-bug: unknown
6+
//@[current] failure-status: 101
7+
//@[current] dont-check-compiler-stderr
8+
9+
// Tests that rebasing from the concrete impl to the default impl also processes the
10+
// `[u32; 0]: IntoIterator<Item = ?U>` predicate to constrain the `?U` impl arg.
11+
// This test also makes sure that we don't do anything weird when rebasing the args
12+
// is ambiguous.
13+
14+
#![feature(specialization)]
15+
//[next]~^ WARN the feature `specialization` is incomplete
16+
17+
trait Spec {
18+
type Assoc;
19+
}
20+
21+
default impl<T, U> Spec for T where T: IntoIterator<Item = U> {
22+
type Assoc = U;
23+
}
24+
25+
impl<T> Spec for [T; 0] {}
26+
27+
fn main() {
28+
let x: <[_; 0] as Spec>::Assoc = 1;
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/source-impl-requires-constraining-predicates.rs:9:12
3+
|
4+
LL | #![feature(specialization)]
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
8+
= help: consider using `min_specialization` instead, which is more stable and complete
9+
= note: `#[warn(incomplete_features)]` on by default
10+
11+
warning: 1 warning emitted
12+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/source-impl-requires-constraining-predicates.rs:9:12
3+
|
4+
LL | #![feature(specialization)]
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
8+
= help: consider using `min_specialization` instead, which is more stable and complete
9+
= note: `#[warn(incomplete_features)]` on by default
10+
11+
warning: 1 warning emitted
12+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//@ check-pass
2+
//@ revisions: current next
3+
//@ ignore-compare-mode-next-solver (explicit revisions)
4+
//@[next] compile-flags: -Znext-solver
5+
6+
// Tests that rebasing from the concrete impl to the default impl also processes the
7+
// `[u32; 0]: IntoIterator<Item = ?U>` predicate to constrain the `?U` impl arg.
8+
9+
#![feature(specialization)]
10+
//~^ WARN the feature `specialization` is incomplete
11+
12+
trait Spec {
13+
type Assoc;
14+
}
15+
16+
default impl<T, U> Spec for T where T: IntoIterator<Item = U> {
17+
type Assoc = U;
18+
}
19+
20+
impl<T> Spec for [T; 0] {}
21+
22+
fn main() {
23+
let x: <[u32; 0] as Spec>::Assoc = 1;
24+
}

0 commit comments

Comments
 (0)