mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Consider principal trait ref's auto-trait super-traits in dyn upcasting
This commit is contained in:
parent
fa9f77ff35
commit
ec8e898193
@ -1,7 +1,10 @@
|
|||||||
//! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
|
//! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
|
||||||
|
|
||||||
|
use crate::traits::supertrait_def_ids;
|
||||||
|
|
||||||
use super::assembly::{self, structural_traits, Candidate};
|
use super::assembly::{self, structural_traits, Candidate};
|
||||||
use super::{EvalCtxt, GoalSource, SolverMode};
|
use super::{EvalCtxt, GoalSource, SolverMode};
|
||||||
|
use rustc_data_structures::fx::FxIndexSet;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::{LangItem, Movability};
|
use rustc_hir::{LangItem, Movability};
|
||||||
use rustc_infer::traits::query::NoSolution;
|
use rustc_infer::traits::query::NoSolution;
|
||||||
@ -663,13 +666,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let Goal { predicate: (a_ty, _b_ty), .. } = goal;
|
let Goal { predicate: (a_ty, _b_ty), .. } = goal;
|
||||||
|
|
||||||
// All of a's auto traits need to be in b's auto traits.
|
|
||||||
let auto_traits_compatible =
|
|
||||||
b_data.auto_traits().all(|b| a_data.auto_traits().any(|a| a == b));
|
|
||||||
if !auto_traits_compatible {
|
|
||||||
return vec![];
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut responses = vec![];
|
let mut responses = vec![];
|
||||||
// If the principal def ids match (or are both none), then we're not doing
|
// If the principal def ids match (or are both none), then we're not doing
|
||||||
// trait upcasting. We're just removing auto traits (or shortening the lifetime).
|
// trait upcasting. We're just removing auto traits (or shortening the lifetime).
|
||||||
@ -757,6 +753,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
let param_env = goal.param_env;
|
let param_env = goal.param_env;
|
||||||
|
|
||||||
|
// We may upcast to auto traits that are either explicitly listed in
|
||||||
|
// the object type's bounds, or implied by the principal trait ref's
|
||||||
|
// supertraits.
|
||||||
|
let a_auto_traits: FxIndexSet<DefId> = a_data
|
||||||
|
.auto_traits()
|
||||||
|
.chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| {
|
||||||
|
supertrait_def_ids(self.tcx(), principal_def_id)
|
||||||
|
.filter(|def_id| self.tcx().trait_is_auto(*def_id))
|
||||||
|
}))
|
||||||
|
.collect();
|
||||||
|
|
||||||
// More than one projection in a_ty's bounds may match the projection
|
// More than one projection in a_ty's bounds may match the projection
|
||||||
// in b_ty's bound. Use this to first determine *which* apply without
|
// in b_ty's bound. Use this to first determine *which* apply without
|
||||||
// having any inference side-effects. We process obligations because
|
// having any inference side-effects. We process obligations because
|
||||||
@ -806,7 +813,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
// Check that b_ty's auto traits are present in a_ty's bounds.
|
// Check that b_ty's auto traits are present in a_ty's bounds.
|
||||||
ty::ExistentialPredicate::AutoTrait(def_id) => {
|
ty::ExistentialPredicate::AutoTrait(def_id) => {
|
||||||
if !a_data.auto_traits().any(|source_def_id| source_def_id == def_id) {
|
if !a_auto_traits.contains(&def_id) {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ use std::ops::ControlFlow;
|
|||||||
|
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use hir::LangItem;
|
use hir::LangItem;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_infer::traits::ObligationCause;
|
use rustc_infer::traits::ObligationCause;
|
||||||
use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError};
|
use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError};
|
||||||
@ -968,52 +968,61 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
//
|
//
|
||||||
// We always perform upcasting coercions when we can because of reason
|
// We always perform upcasting coercions when we can because of reason
|
||||||
// #2 (region bounds).
|
// #2 (region bounds).
|
||||||
let auto_traits_compatible = b_data
|
let principal_def_id_a = a_data.principal_def_id();
|
||||||
.auto_traits()
|
let principal_def_id_b = b_data.principal_def_id();
|
||||||
// All of a's auto traits need to be in b's auto traits.
|
if principal_def_id_a == principal_def_id_b {
|
||||||
.all(|b| a_data.auto_traits().any(|a| a == b));
|
// We may upcast to auto traits that are either explicitly listed in
|
||||||
if auto_traits_compatible {
|
// the object type's bounds, or implied by the principal trait ref's
|
||||||
let principal_def_id_a = a_data.principal_def_id();
|
// supertraits.
|
||||||
let principal_def_id_b = b_data.principal_def_id();
|
let a_auto_traits: FxIndexSet<DefId> = a_data
|
||||||
if principal_def_id_a == principal_def_id_b {
|
.auto_traits()
|
||||||
// no cyclic
|
.chain(principal_def_id_a.into_iter().flat_map(|principal_def_id| {
|
||||||
|
util::supertrait_def_ids(self.tcx(), principal_def_id)
|
||||||
|
.filter(|def_id| self.tcx().trait_is_auto(*def_id))
|
||||||
|
}))
|
||||||
|
.collect();
|
||||||
|
let auto_traits_compatible = b_data
|
||||||
|
.auto_traits()
|
||||||
|
// All of a's auto traits need to be in b's auto traits.
|
||||||
|
.all(|b| a_auto_traits.contains(&b));
|
||||||
|
if auto_traits_compatible {
|
||||||
candidates.vec.push(BuiltinUnsizeCandidate);
|
candidates.vec.push(BuiltinUnsizeCandidate);
|
||||||
} else if principal_def_id_a.is_some() && principal_def_id_b.is_some() {
|
}
|
||||||
// not casual unsizing, now check whether this is trait upcasting coercion.
|
} else if principal_def_id_a.is_some() && principal_def_id_b.is_some() {
|
||||||
let principal_a = a_data.principal().unwrap();
|
// not casual unsizing, now check whether this is trait upcasting coercion.
|
||||||
let target_trait_did = principal_def_id_b.unwrap();
|
let principal_a = a_data.principal().unwrap();
|
||||||
let source_trait_ref = principal_a.with_self_ty(self.tcx(), source);
|
let target_trait_did = principal_def_id_b.unwrap();
|
||||||
if let Some(deref_trait_ref) = self.need_migrate_deref_output_trait_object(
|
let source_trait_ref = principal_a.with_self_ty(self.tcx(), source);
|
||||||
source,
|
if let Some(deref_trait_ref) = self.need_migrate_deref_output_trait_object(
|
||||||
obligation.param_env,
|
source,
|
||||||
&obligation.cause,
|
obligation.param_env,
|
||||||
) {
|
&obligation.cause,
|
||||||
if deref_trait_ref.def_id() == target_trait_did {
|
) {
|
||||||
return;
|
if deref_trait_ref.def_id() == target_trait_did {
|
||||||
}
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (idx, upcast_trait_ref) in
|
for (idx, upcast_trait_ref) in
|
||||||
util::supertraits(self.tcx(), source_trait_ref).enumerate()
|
util::supertraits(self.tcx(), source_trait_ref).enumerate()
|
||||||
{
|
{
|
||||||
self.infcx.probe(|_| {
|
self.infcx.probe(|_| {
|
||||||
if upcast_trait_ref.def_id() == target_trait_did
|
if upcast_trait_ref.def_id() == target_trait_did
|
||||||
&& let Ok(nested) = self.match_upcast_principal(
|
&& let Ok(nested) = self.match_upcast_principal(
|
||||||
obligation,
|
obligation,
|
||||||
upcast_trait_ref,
|
upcast_trait_ref,
|
||||||
a_data,
|
a_data,
|
||||||
b_data,
|
b_data,
|
||||||
a_region,
|
a_region,
|
||||||
b_region,
|
b_region,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if nested.is_none() {
|
if nested.is_none() {
|
||||||
candidates.ambiguous = true;
|
candidates.ambiguous = true;
|
||||||
}
|
|
||||||
candidates.vec.push(TraitUpcastingUnsizeCandidate(idx));
|
|
||||||
}
|
}
|
||||||
})
|
candidates.vec.push(TraitUpcastingUnsizeCandidate(idx));
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2526,6 +2526,17 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let mut nested = vec![];
|
let mut nested = vec![];
|
||||||
|
|
||||||
|
// We may upcast to auto traits that are either explicitly listed in
|
||||||
|
// the object type's bounds, or implied by the principal trait ref's
|
||||||
|
// supertraits.
|
||||||
|
let a_auto_traits: FxIndexSet<DefId> = a_data
|
||||||
|
.auto_traits()
|
||||||
|
.chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| {
|
||||||
|
util::supertrait_def_ids(tcx, principal_def_id)
|
||||||
|
.filter(|def_id| tcx.trait_is_auto(*def_id))
|
||||||
|
}))
|
||||||
|
.collect();
|
||||||
|
|
||||||
let upcast_principal = normalize_with_depth_to(
|
let upcast_principal = normalize_with_depth_to(
|
||||||
self,
|
self,
|
||||||
obligation.param_env,
|
obligation.param_env,
|
||||||
@ -2588,7 +2599,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
// Check that b_ty's auto traits are present in a_ty's bounds.
|
// Check that b_ty's auto traits are present in a_ty's bounds.
|
||||||
ty::ExistentialPredicate::AutoTrait(def_id) => {
|
ty::ExistentialPredicate::AutoTrait(def_id) => {
|
||||||
if !a_data.auto_traits().any(|source_def_id| source_def_id == def_id) {
|
if !a_auto_traits.contains(&def_id) {
|
||||||
return Err(SelectionError::Unimplemented);
|
return Err(SelectionError::Unimplemented);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
// check-pass
|
||||||
|
// revisions: current next
|
||||||
|
//[next] compile-flags: -Znext-solver
|
||||||
|
|
||||||
|
#![feature(trait_upcasting)]
|
||||||
|
|
||||||
|
trait Target {}
|
||||||
|
trait Source: Send + Target {}
|
||||||
|
|
||||||
|
fn upcast(x: &dyn Source) -> &(dyn Target + Send) { x }
|
||||||
|
|
||||||
|
fn same(x: &dyn Source) -> &(dyn Source + Send) { x }
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Reference in New Issue
Block a user