Stop using translate_args in the new solver
This commit is contained in:
parent
99cb42c296
commit
20699fe6b2
@ -12,7 +12,6 @@
|
||||
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::{
|
||||
@ -900,16 +899,6 @@ pub(super) fn fresh_args_for_item(&mut self, def_id: DefId) -> ty::GenericArgsRe
|
||||
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());
|
||||
}
|
||||
|
@ -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};
|
||||
@ -9,7 +9,6 @@
|
||||
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;
|
||||
@ -189,8 +188,7 @@ fn consider_impl_candidate(
|
||||
// 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(),
|
||||
@ -235,16 +233,10 @@ fn consider_impl_candidate(
|
||||
//
|
||||
// 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",
|
||||
@ -272,7 +264,7 @@ fn consider_impl_candidate(
|
||||
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)
|
||||
})
|
||||
}
|
||||
@ -889,38 +881,79 @@ fn consider_builtin_transmute_candidate(
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)?;
|
||||
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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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()
|
||||
/// 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) }
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user