Auto merge of #90104 - spastorino:coherence-for-negative-trait, r=nikomatsakis
Implement coherence checks for negative trait impls The main purpose of this PR is to be able to [move Error trait to core](https://github.com/rust-lang/project-error-handling/issues/3). This feature is necessary to handle the following from impl on box. ```rust impl From<&str> for Box<dyn Error> { ... } ``` Without having negative traits affect coherence moving the error trait into `core` and moving that `From` impl to `alloc` will cause the from impl to no longer compiler because of a potential future incompatibility. The compiler indicates that `&str` _could_ introduce an `Error` impl in the future, and thus prevents the `From` impl in `alloc` that would cause overlap with `From<E: Error> for Box<dyn Error>`. Adding `impl !Error for &str {}` with the negative trait coherence feature will disable this error by encoding a stability guarantee that `&str` will never implement `Error`, making the `From` impl compile. We would have this in `alloc`: ```rust impl From<&str> for Box<dyn Error> {} // A impl<E> From<E> for Box<dyn Error> where E: Error {} // B ``` and this in `core`: ```rust trait Error {} impl !Error for &str {} ``` r? `@nikomatsakis` This PR was built on top of `@yaahc` PR #85764. Language team proposal: to https://github.com/rust-lang/lang-team/issues/96
This commit is contained in:
commit
aa5740c715
38 changed files with 546 additions and 194 deletions
|
@ -94,6 +94,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
|
Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
|
||||||
trait_ref,
|
trait_ref,
|
||||||
constness: ty::BoundConstness::NotConst,
|
constness: ty::BoundConstness::NotConst,
|
||||||
|
polarity: ty::ImplPolarity::Positive,
|
||||||
}))),
|
}))),
|
||||||
locations,
|
locations,
|
||||||
category,
|
category,
|
||||||
|
|
|
@ -854,6 +854,7 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
|
||||||
Binder::dummy(TraitPredicate {
|
Binder::dummy(TraitPredicate {
|
||||||
trait_ref,
|
trait_ref,
|
||||||
constness: ty::BoundConstness::ConstIfConst,
|
constness: ty::BoundConstness::ConstIfConst,
|
||||||
|
polarity: ty::ImplPolarity::Positive,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -162,6 +162,7 @@ impl Qualif for NeedsNonConstDrop {
|
||||||
ty::Binder::dummy(ty::TraitPredicate {
|
ty::Binder::dummy(ty::TraitPredicate {
|
||||||
trait_ref,
|
trait_ref,
|
||||||
constness: ty::BoundConstness::ConstIfConst,
|
constness: ty::BoundConstness::ConstIfConst,
|
||||||
|
polarity: ty::ImplPolarity::Positive,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -556,6 +556,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)),
|
rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)),
|
||||||
rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word)),
|
rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word)),
|
||||||
rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word)),
|
rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word)),
|
||||||
|
rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word)),
|
||||||
rustc_attr!(TEST, rustc_variance, Normal, template!(Word)),
|
rustc_attr!(TEST, rustc_variance, Normal, template!(Word)),
|
||||||
rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")),
|
rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")),
|
||||||
rustc_attr!(TEST, rustc_regions, Normal, template!(Word)),
|
rustc_attr!(TEST, rustc_regions, Normal, template!(Word)),
|
||||||
|
|
|
@ -10,7 +10,7 @@ pub mod util;
|
||||||
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||||
use rustc_middle::ty::{self, Const, Ty};
|
use rustc_middle::ty::{self, Const, Ty, TyCtxt};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
pub use self::FulfillmentErrorCode::*;
|
pub use self::FulfillmentErrorCode::*;
|
||||||
|
@ -55,6 +55,20 @@ pub struct Obligation<'tcx, T> {
|
||||||
pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
|
pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
|
||||||
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
|
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
|
||||||
|
|
||||||
|
impl PredicateObligation<'tcx> {
|
||||||
|
/// Flips the polarity of the inner predicate.
|
||||||
|
///
|
||||||
|
/// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`.
|
||||||
|
pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<PredicateObligation<'tcx>> {
|
||||||
|
Some(PredicateObligation {
|
||||||
|
cause: self.cause.clone(),
|
||||||
|
param_env: self.param_env,
|
||||||
|
predicate: self.predicate.flip_polarity(tcx)?,
|
||||||
|
recursion_depth: self.recursion_depth,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
|
// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||||
static_assert_size!(PredicateObligation<'_>, 32);
|
static_assert_size!(PredicateObligation<'_>, 32);
|
||||||
|
@ -129,6 +143,10 @@ impl<'tcx> FulfillmentError<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TraitObligation<'tcx> {
|
impl<'tcx> TraitObligation<'tcx> {
|
||||||
|
pub fn polarity(&self) -> ty::ImplPolarity {
|
||||||
|
self.predicate.skip_binder().polarity
|
||||||
|
}
|
||||||
|
|
||||||
pub fn self_ty(&self) -> ty::Binder<'tcx, Ty<'tcx>> {
|
pub fn self_ty(&self) -> ty::Binder<'tcx, Ty<'tcx>> {
|
||||||
self.predicate.map_bound(|p| p.self_ty())
|
self.predicate.map_bound(|p| p.self_ty())
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,12 +12,14 @@ use rustc_hir::def_id::DefId;
|
||||||
use rustc_query_system::cache::Cache;
|
use rustc_query_system::cache::Cache;
|
||||||
|
|
||||||
pub type SelectionCache<'tcx> = Cache<
|
pub type SelectionCache<'tcx> = Cache<
|
||||||
ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>,
|
(ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>, ty::ImplPolarity),
|
||||||
SelectionResult<'tcx, SelectionCandidate<'tcx>>,
|
SelectionResult<'tcx, SelectionCandidate<'tcx>>,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
pub type EvaluationCache<'tcx> =
|
pub type EvaluationCache<'tcx> = Cache<
|
||||||
Cache<ty::ParamEnvAnd<'tcx, ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>>, EvaluationResult>;
|
(ty::ParamEnvAnd<'tcx, ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>>, ty::ImplPolarity),
|
||||||
|
EvaluationResult,
|
||||||
|
>;
|
||||||
|
|
||||||
/// The selection process begins by considering all impls, where
|
/// The selection process begins by considering all impls, where
|
||||||
/// clauses, and so forth that might resolve an obligation. Sometimes
|
/// clauses, and so forth that might resolve an obligation. Sometimes
|
||||||
|
@ -101,7 +103,7 @@ pub enum SelectionCandidate<'tcx> {
|
||||||
/// `false` if there are no *further* obligations.
|
/// `false` if there are no *further* obligations.
|
||||||
has_nested: bool,
|
has_nested: bool,
|
||||||
},
|
},
|
||||||
ParamCandidate(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>),
|
ParamCandidate((ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ty::ImplPolarity)),
|
||||||
ImplCandidate(DefId),
|
ImplCandidate(DefId),
|
||||||
AutoImplCandidate(DefId),
|
AutoImplCandidate(DefId),
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ impl<T> ExpectedFound<T> {
|
||||||
pub enum TypeError<'tcx> {
|
pub enum TypeError<'tcx> {
|
||||||
Mismatch,
|
Mismatch,
|
||||||
ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
|
ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
|
||||||
|
PolarityMismatch(ExpectedFound<ty::ImplPolarity>),
|
||||||
UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
|
UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
|
||||||
AbiMismatch(ExpectedFound<abi::Abi>),
|
AbiMismatch(ExpectedFound<abi::Abi>),
|
||||||
Mutability,
|
Mutability,
|
||||||
|
@ -104,6 +105,9 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
|
||||||
ConstnessMismatch(values) => {
|
ConstnessMismatch(values) => {
|
||||||
write!(f, "expected {} bound, found {} bound", values.expected, values.found)
|
write!(f, "expected {} bound, found {} bound", values.expected, values.found)
|
||||||
}
|
}
|
||||||
|
PolarityMismatch(values) => {
|
||||||
|
write!(f, "expected {} polarity, found {} polarity", values.expected, values.found)
|
||||||
|
}
|
||||||
UnsafetyMismatch(values) => {
|
UnsafetyMismatch(values) => {
|
||||||
write!(f, "expected {} fn, found {} fn", values.expected, values.found)
|
write!(f, "expected {} fn, found {} fn", values.expected, values.found)
|
||||||
}
|
}
|
||||||
|
@ -212,10 +216,9 @@ impl<'tcx> TypeError<'tcx> {
|
||||||
use self::TypeError::*;
|
use self::TypeError::*;
|
||||||
match self {
|
match self {
|
||||||
CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_)
|
CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_)
|
||||||
| Mismatch | AbiMismatch(_) | FixedArraySize(_) | ArgumentSorts(..) | Sorts(_)
|
| PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_)
|
||||||
| IntMismatch(_) | FloatMismatch(_) | VariadicMismatch(_) | TargetFeatureCast(_) => {
|
| ArgumentSorts(..) | Sorts(_) | IntMismatch(_) | FloatMismatch(_)
|
||||||
false
|
| VariadicMismatch(_) | TargetFeatureCast(_) => false,
|
||||||
}
|
|
||||||
|
|
||||||
Mutability
|
Mutability
|
||||||
| ArgumentMutability(_)
|
| ArgumentMutability(_)
|
||||||
|
|
|
@ -164,7 +164,18 @@ pub struct ImplHeader<'tcx> {
|
||||||
pub predicates: Vec<Predicate<'tcx>>,
|
pub predicates: Vec<Predicate<'tcx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
|
#[derive(
|
||||||
|
Copy,
|
||||||
|
Clone,
|
||||||
|
PartialEq,
|
||||||
|
Eq,
|
||||||
|
Hash,
|
||||||
|
TyEncodable,
|
||||||
|
TyDecodable,
|
||||||
|
HashStable,
|
||||||
|
Debug,
|
||||||
|
TypeFoldable
|
||||||
|
)]
|
||||||
pub enum ImplPolarity {
|
pub enum ImplPolarity {
|
||||||
/// `impl Trait for Type`
|
/// `impl Trait for Type`
|
||||||
Positive,
|
Positive,
|
||||||
|
@ -177,6 +188,27 @@ pub enum ImplPolarity {
|
||||||
Reservation,
|
Reservation,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ImplPolarity {
|
||||||
|
/// Flips polarity by turning `Positive` into `Negative` and `Negative` into `Positive`.
|
||||||
|
pub fn flip(&self) -> Option<ImplPolarity> {
|
||||||
|
match self {
|
||||||
|
ImplPolarity::Positive => Some(ImplPolarity::Negative),
|
||||||
|
ImplPolarity::Negative => Some(ImplPolarity::Positive),
|
||||||
|
ImplPolarity::Reservation => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ImplPolarity {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Positive => f.write_str("positive"),
|
||||||
|
Self::Negative => f.write_str("negative"),
|
||||||
|
Self::Reservation => f.write_str("reservation"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, TyEncodable, TyDecodable, HashStable)]
|
#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, TyEncodable, TyDecodable, HashStable)]
|
||||||
pub enum Visibility {
|
pub enum Visibility {
|
||||||
/// Visible everywhere (including in other crates).
|
/// Visible everywhere (including in other crates).
|
||||||
|
@ -459,6 +491,29 @@ impl<'tcx> Predicate<'tcx> {
|
||||||
pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> {
|
pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> {
|
||||||
self.inner.kind
|
self.inner.kind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Flips the polarity of a Predicate.
|
||||||
|
///
|
||||||
|
/// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`.
|
||||||
|
pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<Predicate<'tcx>> {
|
||||||
|
let kind = self
|
||||||
|
.inner
|
||||||
|
.kind
|
||||||
|
.map_bound(|kind| match kind {
|
||||||
|
PredicateKind::Trait(TraitPredicate { trait_ref, constness, polarity }) => {
|
||||||
|
Some(PredicateKind::Trait(TraitPredicate {
|
||||||
|
trait_ref,
|
||||||
|
constness,
|
||||||
|
polarity: polarity.flip()?,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.transpose()?;
|
||||||
|
|
||||||
|
Some(tcx.mk_predicate(kind))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
|
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
|
||||||
|
@ -654,6 +709,8 @@ pub struct TraitPredicate<'tcx> {
|
||||||
pub trait_ref: TraitRef<'tcx>,
|
pub trait_ref: TraitRef<'tcx>,
|
||||||
|
|
||||||
pub constness: BoundConstness,
|
pub constness: BoundConstness,
|
||||||
|
|
||||||
|
pub polarity: ImplPolarity,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
|
pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
|
||||||
|
@ -788,7 +845,11 @@ impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitRef<'tcx>> {
|
||||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||||
self.value
|
self.value
|
||||||
.map_bound(|trait_ref| {
|
.map_bound(|trait_ref| {
|
||||||
PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: self.constness })
|
PredicateKind::Trait(ty::TraitPredicate {
|
||||||
|
trait_ref,
|
||||||
|
constness: self.constness,
|
||||||
|
polarity: ty::ImplPolarity::Positive,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.to_predicate(tcx)
|
.to_predicate(tcx)
|
||||||
}
|
}
|
||||||
|
|
|
@ -797,6 +797,20 @@ impl<'tcx> Relate<'tcx> for GenericArg<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Relate<'tcx> for ty::ImplPolarity {
|
||||||
|
fn relate<R: TypeRelation<'tcx>>(
|
||||||
|
relation: &mut R,
|
||||||
|
a: ty::ImplPolarity,
|
||||||
|
b: ty::ImplPolarity,
|
||||||
|
) -> RelateResult<'tcx, ty::ImplPolarity> {
|
||||||
|
if a != b {
|
||||||
|
Err(TypeError::PolarityMismatch(expected_found(relation, a, b)))
|
||||||
|
} else {
|
||||||
|
Ok(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> {
|
impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> {
|
||||||
fn relate<R: TypeRelation<'tcx>>(
|
fn relate<R: TypeRelation<'tcx>>(
|
||||||
relation: &mut R,
|
relation: &mut R,
|
||||||
|
@ -806,6 +820,7 @@ impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> {
|
||||||
Ok(ty::TraitPredicate {
|
Ok(ty::TraitPredicate {
|
||||||
trait_ref: relation.relate(a.trait_ref, b.trait_ref)?,
|
trait_ref: relation.relate(a.trait_ref, b.trait_ref)?,
|
||||||
constness: relation.relate(a.constness, b.constness)?,
|
constness: relation.relate(a.constness, b.constness)?,
|
||||||
|
polarity: relation.relate(a.polarity, b.polarity)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,7 +157,7 @@ impl fmt::Debug for ty::TraitPredicate<'tcx> {
|
||||||
if let ty::BoundConstness::ConstIfConst = self.constness {
|
if let ty::BoundConstness::ConstIfConst = self.constness {
|
||||||
write!(f, "~const ")?;
|
write!(f, "~const ")?;
|
||||||
}
|
}
|
||||||
write!(f, "TraitPredicate({:?})", self.trait_ref)
|
write!(f, "TraitPredicate({:?}, polarity:{:?})", self.trait_ref, self.polarity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,8 +365,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialPredicate<'a> {
|
||||||
impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
|
impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
|
||||||
type Lifted = ty::TraitPredicate<'tcx>;
|
type Lifted = ty::TraitPredicate<'tcx>;
|
||||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::TraitPredicate<'tcx>> {
|
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::TraitPredicate<'tcx>> {
|
||||||
tcx.lift(self.trait_ref)
|
tcx.lift(self.trait_ref).map(|trait_ref| ty::TraitPredicate {
|
||||||
.map(|trait_ref| ty::TraitPredicate { trait_ref, constness: self.constness })
|
trait_ref,
|
||||||
|
constness: self.constness,
|
||||||
|
polarity: self.polarity,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -591,6 +594,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
|
||||||
Some(match self {
|
Some(match self {
|
||||||
Mismatch => Mismatch,
|
Mismatch => Mismatch,
|
||||||
ConstnessMismatch(x) => ConstnessMismatch(x),
|
ConstnessMismatch(x) => ConstnessMismatch(x),
|
||||||
|
PolarityMismatch(x) => PolarityMismatch(x),
|
||||||
UnsafetyMismatch(x) => UnsafetyMismatch(x),
|
UnsafetyMismatch(x) => UnsafetyMismatch(x),
|
||||||
AbiMismatch(x) => AbiMismatch(x),
|
AbiMismatch(x) => AbiMismatch(x),
|
||||||
Mutability => Mutability,
|
Mutability => Mutability,
|
||||||
|
|
|
@ -882,6 +882,7 @@ impl<'tcx> PolyTraitRef<'tcx> {
|
||||||
self.map_bound(|trait_ref| ty::TraitPredicate {
|
self.map_bound(|trait_ref| ty::TraitPredicate {
|
||||||
trait_ref,
|
trait_ref,
|
||||||
constness: ty::BoundConstness::NotConst,
|
constness: ty::BoundConstness::NotConst,
|
||||||
|
polarity: ty::ImplPolarity::Positive,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,9 +124,11 @@ where
|
||||||
|
|
||||||
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> {
|
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> {
|
||||||
match predicate.kind().skip_binder() {
|
match predicate.kind().skip_binder() {
|
||||||
ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: _ }) => {
|
ty::PredicateKind::Trait(ty::TraitPredicate {
|
||||||
self.visit_trait(trait_ref)
|
trait_ref,
|
||||||
}
|
constness: _,
|
||||||
|
polarity: _,
|
||||||
|
}) => self.visit_trait(trait_ref),
|
||||||
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
|
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
|
||||||
ty.visit_with(self)?;
|
ty.visit_with(self)?;
|
||||||
self.visit_projection_ty(projection_ty)
|
self.visit_projection_ty(projection_ty)
|
||||||
|
|
|
@ -1141,6 +1141,7 @@ symbols! {
|
||||||
rustc_specialization_trait,
|
rustc_specialization_trait,
|
||||||
rustc_stable,
|
rustc_stable,
|
||||||
rustc_std_internal_symbol,
|
rustc_std_internal_symbol,
|
||||||
|
rustc_strict_coherence,
|
||||||
rustc_symbol_name,
|
rustc_symbol_name,
|
||||||
rustc_synthetic,
|
rustc_synthetic,
|
||||||
rustc_test_marker,
|
rustc_test_marker,
|
||||||
|
|
|
@ -286,6 +286,8 @@ impl AutoTraitFinder<'tcx> {
|
||||||
substs: infcx.tcx.mk_substs_trait(ty, &[]),
|
substs: infcx.tcx.mk_substs_trait(ty, &[]),
|
||||||
},
|
},
|
||||||
constness: ty::BoundConstness::NotConst,
|
constness: ty::BoundConstness::NotConst,
|
||||||
|
// Auto traits are positive
|
||||||
|
polarity: ty::ImplPolarity::Positive,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let computed_preds = param_env.caller_bounds().iter();
|
let computed_preds = param_env.caller_bounds().iter();
|
||||||
|
|
|
@ -5,9 +5,12 @@
|
||||||
//! [trait-specialization]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
|
//! [trait-specialization]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
|
||||||
|
|
||||||
use crate::infer::{CombinedSnapshot, InferOk, TyCtxtInferExt};
|
use crate::infer::{CombinedSnapshot, InferOk, TyCtxtInferExt};
|
||||||
|
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||||
use crate::traits::select::IntercrateAmbiguityCause;
|
use crate::traits::select::IntercrateAmbiguityCause;
|
||||||
use crate::traits::SkipLeakCheck;
|
use crate::traits::SkipLeakCheck;
|
||||||
use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionContext};
|
use crate::traits::{
|
||||||
|
self, Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext,
|
||||||
|
};
|
||||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||||
use rustc_middle::ty::fold::TypeFoldable;
|
use rustc_middle::ty::fold::TypeFoldable;
|
||||||
use rustc_middle::ty::subst::Subst;
|
use rustc_middle::ty::subst::Subst;
|
||||||
|
@ -158,6 +161,19 @@ fn overlap_within_probe(
|
||||||
b_def_id: DefId,
|
b_def_id: DefId,
|
||||||
snapshot: &CombinedSnapshot<'_, 'tcx>,
|
snapshot: &CombinedSnapshot<'_, 'tcx>,
|
||||||
) -> Option<OverlapResult<'tcx>> {
|
) -> Option<OverlapResult<'tcx>> {
|
||||||
|
fn loose_check(selcx: &mut SelectionContext<'cx, 'tcx>, o: &PredicateObligation<'tcx>) -> bool {
|
||||||
|
!selcx.predicate_may_hold_fatal(o)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn strict_check(selcx: &SelectionContext<'cx, 'tcx>, o: &PredicateObligation<'tcx>) -> bool {
|
||||||
|
let infcx = selcx.infcx();
|
||||||
|
let tcx = infcx.tcx;
|
||||||
|
o.flip_polarity(tcx)
|
||||||
|
.as_ref()
|
||||||
|
.map(|o| selcx.infcx().predicate_must_hold_modulo_regions(o))
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
// For the purposes of this check, we don't bring any placeholder
|
// For the purposes of this check, we don't bring any placeholder
|
||||||
// types into scope; instead, we replace the generic types with
|
// types into scope; instead, we replace the generic types with
|
||||||
// fresh type variables, and hence we do our evaluations in an
|
// fresh type variables, and hence we do our evaluations in an
|
||||||
|
@ -184,8 +200,29 @@ fn overlap_within_probe(
|
||||||
|
|
||||||
debug!("overlap: unification check succeeded");
|
debug!("overlap: unification check succeeded");
|
||||||
|
|
||||||
// Are any of the obligations unsatisfiable? If so, no overlap.
|
// There's no overlap if obligations are unsatisfiable or if the obligation negated is
|
||||||
|
// satisfied.
|
||||||
|
//
|
||||||
|
// For example, given these two impl headers:
|
||||||
|
//
|
||||||
|
// `impl<'a> From<&'a str> for Box<dyn Error>`
|
||||||
|
// `impl<E> From<E> for Box<dyn Error> where E: Error`
|
||||||
|
//
|
||||||
|
// So we have:
|
||||||
|
//
|
||||||
|
// `Box<dyn Error>: From<&'?a str>`
|
||||||
|
// `Box<dyn Error>: From<?E>`
|
||||||
|
//
|
||||||
|
// After equating the two headers:
|
||||||
|
//
|
||||||
|
// `Box<dyn Error> = Box<dyn Error>`
|
||||||
|
// So, `?E = &'?a str` and then given the where clause `&'?a str: Error`.
|
||||||
|
//
|
||||||
|
// If the obligation `&'?a str: Error` holds, it means that there's overlap. If that doesn't
|
||||||
|
// hold we need to check if `&'?a str: !Error` holds, if doesn't hold there's overlap because
|
||||||
|
// at some point an impl for `&'?a str: Error` could be added.
|
||||||
let infcx = selcx.infcx();
|
let infcx = selcx.infcx();
|
||||||
|
let tcx = infcx.tcx;
|
||||||
let opt_failing_obligation = a_impl_header
|
let opt_failing_obligation = a_impl_header
|
||||||
.predicates
|
.predicates
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -199,7 +236,17 @@ fn overlap_within_probe(
|
||||||
predicate: p,
|
predicate: p,
|
||||||
})
|
})
|
||||||
.chain(obligations)
|
.chain(obligations)
|
||||||
.find(|o| !selcx.predicate_may_hold_fatal(o));
|
.find(|o| {
|
||||||
|
// if both impl headers are set to strict coherence it means that this will be accepted
|
||||||
|
// only if it's stated that T: !Trait. So only prove that the negated obligation holds.
|
||||||
|
if tcx.has_attr(a_def_id, sym::rustc_strict_coherence)
|
||||||
|
&& tcx.has_attr(b_def_id, sym::rustc_strict_coherence)
|
||||||
|
{
|
||||||
|
strict_check(selcx, o)
|
||||||
|
} else {
|
||||||
|
loose_check(selcx, o) || tcx.features().negative_impls && strict_check(selcx, o)
|
||||||
|
}
|
||||||
|
});
|
||||||
// FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported
|
// FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported
|
||||||
// to the canonical trait query form, `infcx.predicate_may_hold`, once
|
// to the canonical trait query form, `infcx.predicate_may_hold`, once
|
||||||
// the new system supports intercrate mode (which coherence needs).
|
// the new system supports intercrate mode (which coherence needs).
|
||||||
|
|
|
@ -804,6 +804,7 @@ pub fn vtable_trait_upcasting_coercion_new_vptr_slot(
|
||||||
ty::Binder::dummy(ty::TraitPredicate {
|
ty::Binder::dummy(ty::TraitPredicate {
|
||||||
trait_ref,
|
trait_ref,
|
||||||
constness: ty::BoundConstness::NotConst,
|
constness: ty::BoundConstness::NotConst,
|
||||||
|
polarity: ty::ImplPolarity::Positive,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ pub(crate) fn update<'tcx, T>(
|
||||||
ty::PredicateKind::Trait(ty::TraitPredicate {
|
ty::PredicateKind::Trait(ty::TraitPredicate {
|
||||||
trait_ref,
|
trait_ref,
|
||||||
constness: predicate.constness,
|
constness: predicate.constness,
|
||||||
|
polarity: predicate.polarity,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.to_predicate(infcx.tcx),
|
.to_predicate(infcx.tcx),
|
||||||
|
|
|
@ -121,7 +121,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut candidates = candidate_set.vec;
|
let candidates = candidate_set.vec;
|
||||||
|
|
||||||
debug!(?stack, ?candidates, "assembled {} candidates", candidates.len());
|
debug!(?stack, ?candidates, "assembled {} candidates", candidates.len());
|
||||||
|
|
||||||
|
@ -134,6 +134,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// candidate which assumes $0 == int, one that assumes `$0 ==
|
// candidate which assumes $0 == int, one that assumes `$0 ==
|
||||||
// usize`, etc. This spells an ambiguity.
|
// usize`, etc. This spells an ambiguity.
|
||||||
|
|
||||||
|
let mut candidates = self.filter_impls(candidates, stack.obligation);
|
||||||
|
|
||||||
// If there is more than one candidate, first winnow them down
|
// If there is more than one candidate, first winnow them down
|
||||||
// by considering extra conditions (nested obligations and so
|
// by considering extra conditions (nested obligations and so
|
||||||
// forth). We don't winnow if there is exactly one
|
// forth). We don't winnow if there is exactly one
|
||||||
|
@ -149,7 +151,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// Instead, we select the right impl now but report "`Bar` does
|
// Instead, we select the right impl now but report "`Bar` does
|
||||||
// not implement `Clone`".
|
// not implement `Clone`".
|
||||||
if candidates.len() == 1 {
|
if candidates.len() == 1 {
|
||||||
return self.filter_impls(candidates.pop().unwrap(), stack.obligation);
|
return self.filter_reservation_impls(candidates.pop().unwrap(), stack.obligation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Winnow, but record the exact outcome of evaluation, which
|
// Winnow, but record the exact outcome of evaluation, which
|
||||||
|
@ -223,7 +225,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just one candidate left.
|
// Just one candidate left.
|
||||||
self.filter_impls(candidates.pop().unwrap().candidate, stack.obligation)
|
self.filter_reservation_impls(candidates.pop().unwrap().candidate, stack.obligation)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self, stack), level = "debug")]
|
#[instrument(skip(self, stack), level = "debug")]
|
||||||
|
@ -254,68 +256,75 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
|
|
||||||
let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
|
let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
|
||||||
|
|
||||||
self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
|
// The only way to prove a NotImplemented(T: Foo) predicate is via a negative impl.
|
||||||
|
// There are no compiler built-in rules for this.
|
||||||
// Other bounds. Consider both in-scope bounds from fn decl
|
if obligation.polarity() == ty::ImplPolarity::Negative {
|
||||||
// and applicable impls. There is a certain set of precedence rules here.
|
self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
|
||||||
let def_id = obligation.predicate.def_id();
|
|
||||||
let lang_items = self.tcx().lang_items();
|
|
||||||
|
|
||||||
if lang_items.copy_trait() == Some(def_id) {
|
|
||||||
debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty());
|
|
||||||
|
|
||||||
// User-defined copy impls are permitted, but only for
|
|
||||||
// structs and enums.
|
|
||||||
self.assemble_candidates_from_impls(obligation, &mut candidates);
|
self.assemble_candidates_from_impls(obligation, &mut candidates);
|
||||||
|
|
||||||
// For other types, we'll use the builtin rules.
|
|
||||||
let copy_conditions = self.copy_clone_conditions(obligation);
|
|
||||||
self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates);
|
|
||||||
} else if lang_items.discriminant_kind_trait() == Some(def_id) {
|
|
||||||
// `DiscriminantKind` is automatically implemented for every type.
|
|
||||||
candidates.vec.push(DiscriminantKindCandidate);
|
|
||||||
} else if lang_items.pointee_trait() == Some(def_id) {
|
|
||||||
// `Pointee` is automatically implemented for every type.
|
|
||||||
candidates.vec.push(PointeeCandidate);
|
|
||||||
} else if lang_items.sized_trait() == Some(def_id) {
|
|
||||||
// Sized is never implementable by end-users, it is
|
|
||||||
// always automatically computed.
|
|
||||||
let sized_conditions = self.sized_conditions(obligation);
|
|
||||||
self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
|
|
||||||
} else if lang_items.unsize_trait() == Some(def_id) {
|
|
||||||
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
|
|
||||||
} else if lang_items.drop_trait() == Some(def_id)
|
|
||||||
&& obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst
|
|
||||||
{
|
|
||||||
if self.is_in_const_context {
|
|
||||||
self.assemble_const_drop_candidates(obligation, &mut candidates)?;
|
|
||||||
} else {
|
|
||||||
debug!("passing ~const Drop bound; in non-const context");
|
|
||||||
// `~const Drop` when we are not in a const context has no effect.
|
|
||||||
candidates.vec.push(ConstDropCandidate)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if lang_items.clone_trait() == Some(def_id) {
|
self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
|
||||||
// Same builtin conditions as `Copy`, i.e., every type which has builtin support
|
|
||||||
// for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone`
|
// Other bounds. Consider both in-scope bounds from fn decl
|
||||||
// types have builtin support for `Clone`.
|
// and applicable impls. There is a certain set of precedence rules here.
|
||||||
let clone_conditions = self.copy_clone_conditions(obligation);
|
let def_id = obligation.predicate.def_id();
|
||||||
self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates);
|
let lang_items = self.tcx().lang_items();
|
||||||
|
|
||||||
|
if lang_items.copy_trait() == Some(def_id) {
|
||||||
|
debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty());
|
||||||
|
|
||||||
|
// User-defined copy impls are permitted, but only for
|
||||||
|
// structs and enums.
|
||||||
|
self.assemble_candidates_from_impls(obligation, &mut candidates);
|
||||||
|
|
||||||
|
// For other types, we'll use the builtin rules.
|
||||||
|
let copy_conditions = self.copy_clone_conditions(obligation);
|
||||||
|
self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates);
|
||||||
|
} else if lang_items.discriminant_kind_trait() == Some(def_id) {
|
||||||
|
// `DiscriminantKind` is automatically implemented for every type.
|
||||||
|
candidates.vec.push(DiscriminantKindCandidate);
|
||||||
|
} else if lang_items.pointee_trait() == Some(def_id) {
|
||||||
|
// `Pointee` is automatically implemented for every type.
|
||||||
|
candidates.vec.push(PointeeCandidate);
|
||||||
|
} else if lang_items.sized_trait() == Some(def_id) {
|
||||||
|
// Sized is never implementable by end-users, it is
|
||||||
|
// always automatically computed.
|
||||||
|
let sized_conditions = self.sized_conditions(obligation);
|
||||||
|
self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
|
||||||
|
} else if lang_items.unsize_trait() == Some(def_id) {
|
||||||
|
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
|
||||||
|
} else if lang_items.drop_trait() == Some(def_id)
|
||||||
|
&& obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst
|
||||||
|
{
|
||||||
|
if self.is_in_const_context {
|
||||||
|
self.assemble_const_drop_candidates(obligation, &mut candidates)?;
|
||||||
|
} else {
|
||||||
|
debug!("passing ~const Drop bound; in non-const context");
|
||||||
|
// `~const Drop` when we are not in a const context has no effect.
|
||||||
|
candidates.vec.push(ConstDropCandidate)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if lang_items.clone_trait() == Some(def_id) {
|
||||||
|
// Same builtin conditions as `Copy`, i.e., every type which has builtin support
|
||||||
|
// for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone`
|
||||||
|
// types have builtin support for `Clone`.
|
||||||
|
let clone_conditions = self.copy_clone_conditions(obligation);
|
||||||
|
self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assemble_generator_candidates(obligation, &mut candidates);
|
||||||
|
self.assemble_closure_candidates(obligation, &mut candidates);
|
||||||
|
self.assemble_fn_pointer_candidates(obligation, &mut candidates);
|
||||||
|
self.assemble_candidates_from_impls(obligation, &mut candidates);
|
||||||
|
self.assemble_candidates_from_object_ty(obligation, &mut candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.assemble_generator_candidates(obligation, &mut candidates);
|
self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
|
||||||
self.assemble_closure_candidates(obligation, &mut candidates);
|
self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
|
||||||
self.assemble_fn_pointer_candidates(obligation, &mut candidates);
|
// Auto implementations have lower priority, so we only
|
||||||
self.assemble_candidates_from_impls(obligation, &mut candidates);
|
// consider triggering a default if there is no other impl that can apply.
|
||||||
self.assemble_candidates_from_object_ty(obligation, &mut candidates);
|
if candidates.vec.is_empty() {
|
||||||
}
|
self.assemble_candidates_from_auto_impls(obligation, &mut candidates);
|
||||||
|
}
|
||||||
self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
|
|
||||||
self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
|
|
||||||
// Auto implementations have lower priority, so we only
|
|
||||||
// consider triggering a default if there is no other impl that can apply.
|
|
||||||
if candidates.vec.is_empty() {
|
|
||||||
self.assemble_candidates_from_auto_impls(obligation, &mut candidates);
|
|
||||||
}
|
}
|
||||||
debug!("candidate list size: {}", candidates.vec.len());
|
debug!("candidate list size: {}", candidates.vec.len());
|
||||||
Ok(candidates)
|
Ok(candidates)
|
||||||
|
@ -376,7 +385,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
for bound in matching_bounds {
|
for bound in matching_bounds {
|
||||||
let wc = self.evaluate_where_clause(stack, bound.value)?;
|
let wc = self.evaluate_where_clause(stack, bound.value)?;
|
||||||
if wc.may_apply() {
|
if wc.may_apply() {
|
||||||
candidates.vec.push(ParamCandidate(bound));
|
candidates.vec.push(ParamCandidate((bound, stack.obligation.polarity())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -913,6 +922,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
substs: self.tcx().mk_substs_trait(ty, &[]),
|
substs: self.tcx().mk_substs_trait(ty, &[]),
|
||||||
},
|
},
|
||||||
constness: ty::BoundConstness::NotConst,
|
constness: ty::BoundConstness::NotConst,
|
||||||
|
polarity: ty::ImplPolarity::Positive,
|
||||||
}));
|
}));
|
||||||
copy_obligation.recursion_depth = depth + 1;
|
copy_obligation.recursion_depth = depth + 1;
|
||||||
self.assemble_candidates_from_impls(©_obligation, &mut copy_candidates);
|
self.assemble_candidates_from_impls(©_obligation, &mut copy_candidates);
|
||||||
|
|
|
@ -58,8 +58,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ParamCandidate(param) => {
|
ParamCandidate(param) => {
|
||||||
let obligations = self.confirm_param_candidate(obligation, param.value);
|
let obligations = self.confirm_param_candidate(obligation, param.0.value);
|
||||||
Ok(ImplSource::Param(obligations, param.constness))
|
Ok(ImplSource::Param(obligations, param.0.constness))
|
||||||
}
|
}
|
||||||
|
|
||||||
ImplCandidate(impl_def_id) => {
|
ImplCandidate(impl_def_id) => {
|
||||||
|
|
|
@ -20,7 +20,7 @@ use super::ObligationCauseCode;
|
||||||
use super::Selection;
|
use super::Selection;
|
||||||
use super::SelectionResult;
|
use super::SelectionResult;
|
||||||
use super::TraitQueryMode;
|
use super::TraitQueryMode;
|
||||||
use super::{ErrorReporting, Overflow, SelectionError, Unimplemented};
|
use super::{ErrorReporting, Overflow, SelectionError};
|
||||||
use super::{ObligationCause, PredicateObligation, TraitObligation};
|
use super::{ObligationCause, PredicateObligation, TraitObligation};
|
||||||
|
|
||||||
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
|
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
|
||||||
|
@ -709,7 +709,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
|
|
||||||
debug!(?fresh_trait_ref);
|
debug!(?fresh_trait_ref);
|
||||||
|
|
||||||
if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_ref) {
|
if let Some(result) = self.check_evaluation_cache(
|
||||||
|
obligation.param_env,
|
||||||
|
fresh_trait_ref,
|
||||||
|
obligation.polarity(),
|
||||||
|
) {
|
||||||
debug!(?result, "CACHE HIT");
|
debug!(?result, "CACHE HIT");
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
@ -739,12 +743,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
let reached_depth = stack.reached_depth.get();
|
let reached_depth = stack.reached_depth.get();
|
||||||
if reached_depth >= stack.depth {
|
if reached_depth >= stack.depth {
|
||||||
debug!(?result, "CACHE MISS");
|
debug!(?result, "CACHE MISS");
|
||||||
self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result);
|
self.insert_evaluation_cache(
|
||||||
|
obligation.param_env,
|
||||||
|
fresh_trait_ref,
|
||||||
|
obligation.polarity(),
|
||||||
|
dep_node,
|
||||||
|
result,
|
||||||
|
);
|
||||||
|
|
||||||
stack.cache().on_completion(stack.dfn, |fresh_trait_ref, provisional_result| {
|
stack.cache().on_completion(stack.dfn, |fresh_trait_ref, provisional_result| {
|
||||||
self.insert_evaluation_cache(
|
self.insert_evaluation_cache(
|
||||||
obligation.param_env,
|
obligation.param_env,
|
||||||
fresh_trait_ref,
|
fresh_trait_ref,
|
||||||
|
obligation.polarity(),
|
||||||
dep_node,
|
dep_node,
|
||||||
provisional_result.max(result),
|
provisional_result.max(result),
|
||||||
);
|
);
|
||||||
|
@ -855,34 +866,39 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// precise still.
|
// precise still.
|
||||||
let unbound_input_types =
|
let unbound_input_types =
|
||||||
stack.fresh_trait_ref.value.skip_binder().substs.types().any(|ty| ty.is_fresh());
|
stack.fresh_trait_ref.value.skip_binder().substs.types().any(|ty| ty.is_fresh());
|
||||||
// This check was an imperfect workaround for a bug in the old
|
|
||||||
// intercrate mode; it should be removed when that goes away.
|
if stack.obligation.polarity() != ty::ImplPolarity::Negative {
|
||||||
if unbound_input_types && self.intercrate {
|
// This check was an imperfect workaround for a bug in the old
|
||||||
debug!("evaluate_stack --> unbound argument, intercrate --> ambiguous",);
|
// intercrate mode; it should be removed when that goes away.
|
||||||
// Heuristics: show the diagnostics when there are no candidates in crate.
|
if unbound_input_types && self.intercrate {
|
||||||
if self.intercrate_ambiguity_causes.is_some() {
|
debug!("evaluate_stack --> unbound argument, intercrate --> ambiguous",);
|
||||||
debug!("evaluate_stack: intercrate_ambiguity_causes is some");
|
// Heuristics: show the diagnostics when there are no candidates in crate.
|
||||||
if let Ok(candidate_set) = self.assemble_candidates(stack) {
|
if self.intercrate_ambiguity_causes.is_some() {
|
||||||
if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
|
debug!("evaluate_stack: intercrate_ambiguity_causes is some");
|
||||||
let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
|
if let Ok(candidate_set) = self.assemble_candidates(stack) {
|
||||||
let self_ty = trait_ref.self_ty();
|
if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
|
||||||
let cause =
|
let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
|
||||||
with_no_trimmed_paths(|| IntercrateAmbiguityCause::DownstreamCrate {
|
let self_ty = trait_ref.self_ty();
|
||||||
trait_desc: trait_ref.print_only_trait_path().to_string(),
|
let cause = with_no_trimmed_paths(|| {
|
||||||
self_desc: if self_ty.has_concrete_skeleton() {
|
IntercrateAmbiguityCause::DownstreamCrate {
|
||||||
Some(self_ty.to_string())
|
trait_desc: trait_ref.print_only_trait_path().to_string(),
|
||||||
} else {
|
self_desc: if self_ty.has_concrete_skeleton() {
|
||||||
None
|
Some(self_ty.to_string())
|
||||||
},
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
debug!(?cause, "evaluate_stack: pushing cause");
|
debug!(?cause, "evaluate_stack: pushing cause");
|
||||||
self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
|
self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return Ok(EvaluatedToAmbig);
|
||||||
}
|
}
|
||||||
return Ok(EvaluatedToAmbig);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if unbound_input_types
|
if unbound_input_types
|
||||||
&& stack.iter().skip(1).any(|prev| {
|
&& stack.iter().skip(1).any(|prev| {
|
||||||
stack.obligation.param_env == prev.obligation.param_env
|
stack.obligation.param_env == prev.obligation.param_env
|
||||||
|
@ -977,6 +993,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
&self,
|
&self,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
||||||
|
polarity: ty::ImplPolarity,
|
||||||
) -> Option<EvaluationResult> {
|
) -> Option<EvaluationResult> {
|
||||||
// Neither the global nor local cache is aware of intercrate
|
// Neither the global nor local cache is aware of intercrate
|
||||||
// mode, so don't do any caching. In particular, we might
|
// mode, so don't do any caching. In particular, we might
|
||||||
|
@ -988,17 +1005,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
|
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
if self.can_use_global_caches(param_env) {
|
if self.can_use_global_caches(param_env) {
|
||||||
if let Some(res) = tcx.evaluation_cache.get(¶m_env.and(trait_ref), tcx) {
|
if let Some(res) = tcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
|
||||||
|
{
|
||||||
return Some(res);
|
return Some(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.infcx.evaluation_cache.get(¶m_env.and(trait_ref), tcx)
|
self.infcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_evaluation_cache(
|
fn insert_evaluation_cache(
|
||||||
&mut self,
|
&mut self,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
||||||
|
polarity: ty::ImplPolarity,
|
||||||
dep_node: DepNodeIndex,
|
dep_node: DepNodeIndex,
|
||||||
result: EvaluationResult,
|
result: EvaluationResult,
|
||||||
) {
|
) {
|
||||||
|
@ -1023,13 +1042,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// FIXME: Due to #50507 this overwrites the different values
|
// FIXME: Due to #50507 this overwrites the different values
|
||||||
// This should be changed to use HashMapExt::insert_same
|
// This should be changed to use HashMapExt::insert_same
|
||||||
// when that is fixed
|
// when that is fixed
|
||||||
self.tcx().evaluation_cache.insert(param_env.and(trait_ref), dep_node, result);
|
self.tcx().evaluation_cache.insert(
|
||||||
|
(param_env.and(trait_ref), polarity),
|
||||||
|
dep_node,
|
||||||
|
result,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!(?trait_ref, ?result, "insert_evaluation_cache");
|
debug!(?trait_ref, ?result, "insert_evaluation_cache");
|
||||||
self.infcx.evaluation_cache.insert(param_env.and(trait_ref), dep_node, result);
|
self.infcx.evaluation_cache.insert((param_env.and(trait_ref), polarity), dep_node, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For various reasons, it's possible for a subobligation
|
/// For various reasons, it's possible for a subobligation
|
||||||
|
@ -1094,67 +1117,89 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
(result, dep_node)
|
(result, dep_node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// filter_impls filters constant trait obligations and candidates that have a positive impl
|
||||||
|
/// for a negative goal and a negative impl for a positive goal
|
||||||
#[instrument(level = "debug", skip(self))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
fn filter_impls(
|
fn filter_impls(
|
||||||
|
&mut self,
|
||||||
|
candidates: Vec<SelectionCandidate<'tcx>>,
|
||||||
|
obligation: &TraitObligation<'tcx>,
|
||||||
|
) -> Vec<SelectionCandidate<'tcx>> {
|
||||||
|
let tcx = self.tcx();
|
||||||
|
let mut result = Vec::with_capacity(candidates.len());
|
||||||
|
|
||||||
|
for candidate in candidates {
|
||||||
|
// Respect const trait obligations
|
||||||
|
if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
|
||||||
|
match candidate {
|
||||||
|
// const impl
|
||||||
|
ImplCandidate(def_id)
|
||||||
|
if tcx.impl_constness(def_id) == hir::Constness::Const => {}
|
||||||
|
// const param
|
||||||
|
ParamCandidate((
|
||||||
|
ty::ConstnessAnd { constness: ty::BoundConstness::ConstIfConst, .. },
|
||||||
|
_,
|
||||||
|
)) => {}
|
||||||
|
// auto trait impl
|
||||||
|
AutoImplCandidate(..) => {}
|
||||||
|
// generator, this will raise error in other places
|
||||||
|
// or ignore error with const_async_blocks feature
|
||||||
|
GeneratorCandidate => {}
|
||||||
|
// FnDef where the function is const
|
||||||
|
FnPointerCandidate { is_const: true } => {}
|
||||||
|
ConstDropCandidate => {}
|
||||||
|
_ => {
|
||||||
|
// reject all other types of candidates
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let ImplCandidate(def_id) = candidate {
|
||||||
|
if ty::ImplPolarity::Reservation == tcx.impl_polarity(def_id)
|
||||||
|
|| obligation.polarity() == tcx.impl_polarity(def_id)
|
||||||
|
|| self.allow_negative_impls
|
||||||
|
{
|
||||||
|
result.push(candidate);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.push(candidate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// filter_reservation_impls filter reservation impl for any goal as ambiguous
|
||||||
|
#[instrument(level = "debug", skip(self))]
|
||||||
|
fn filter_reservation_impls(
|
||||||
&mut self,
|
&mut self,
|
||||||
candidate: SelectionCandidate<'tcx>,
|
candidate: SelectionCandidate<'tcx>,
|
||||||
obligation: &TraitObligation<'tcx>,
|
obligation: &TraitObligation<'tcx>,
|
||||||
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
|
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
// Respect const trait obligations
|
// Treat reservation impls as ambiguity.
|
||||||
if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
|
|
||||||
match candidate {
|
|
||||||
// const impl
|
|
||||||
ImplCandidate(def_id) if tcx.impl_constness(def_id) == hir::Constness::Const => {}
|
|
||||||
// const param
|
|
||||||
ParamCandidate(ty::ConstnessAnd {
|
|
||||||
constness: ty::BoundConstness::ConstIfConst,
|
|
||||||
..
|
|
||||||
}) => {}
|
|
||||||
// auto trait impl
|
|
||||||
AutoImplCandidate(..) => {}
|
|
||||||
// generator, this will raise error in other places
|
|
||||||
// or ignore error with const_async_blocks feature
|
|
||||||
GeneratorCandidate => {}
|
|
||||||
// FnDef where the function is const
|
|
||||||
FnPointerCandidate { is_const: true } => {}
|
|
||||||
ConstDropCandidate => {}
|
|
||||||
_ => {
|
|
||||||
// reject all other types of candidates
|
|
||||||
return Err(Unimplemented);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Treat negative impls as unimplemented, and reservation impls as ambiguity.
|
|
||||||
if let ImplCandidate(def_id) = candidate {
|
if let ImplCandidate(def_id) = candidate {
|
||||||
match tcx.impl_polarity(def_id) {
|
if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) {
|
||||||
ty::ImplPolarity::Negative if !self.allow_negative_impls => {
|
if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes {
|
||||||
return Err(Unimplemented);
|
let attrs = tcx.get_attrs(def_id);
|
||||||
}
|
let attr = tcx.sess.find_by_name(&attrs, sym::rustc_reservation_impl);
|
||||||
ty::ImplPolarity::Reservation => {
|
let value = attr.and_then(|a| a.value_str());
|
||||||
if let Some(intercrate_ambiguity_clauses) =
|
if let Some(value) = value {
|
||||||
&mut self.intercrate_ambiguity_causes
|
debug!(
|
||||||
{
|
"filter_reservation_impls: \
|
||||||
let attrs = tcx.get_attrs(def_id);
|
|
||||||
let attr = tcx.sess.find_by_name(&attrs, sym::rustc_reservation_impl);
|
|
||||||
let value = attr.and_then(|a| a.value_str());
|
|
||||||
if let Some(value) = value {
|
|
||||||
debug!(
|
|
||||||
"filter_impls: \
|
|
||||||
reservation impl ambiguity on {:?}",
|
reservation impl ambiguity on {:?}",
|
||||||
def_id
|
def_id
|
||||||
);
|
);
|
||||||
intercrate_ambiguity_clauses.push(
|
intercrate_ambiguity_clauses.push(
|
||||||
IntercrateAmbiguityCause::ReservationImpl {
|
IntercrateAmbiguityCause::ReservationImpl {
|
||||||
message: value.to_string(),
|
message: value.to_string(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return Ok(None);
|
|
||||||
}
|
}
|
||||||
_ => {}
|
return Ok(None);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
Ok(Some(candidate))
|
Ok(Some(candidate))
|
||||||
}
|
}
|
||||||
|
@ -1162,7 +1207,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> {
|
fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> {
|
||||||
debug!("is_knowable(intercrate={:?})", self.intercrate);
|
debug!("is_knowable(intercrate={:?})", self.intercrate);
|
||||||
|
|
||||||
if !self.intercrate {
|
if !self.intercrate || stack.obligation.polarity() == ty::ImplPolarity::Negative {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1219,14 +1264,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
if self.can_use_global_caches(param_env) {
|
if self.can_use_global_caches(param_env) {
|
||||||
if let Some(res) = tcx
|
if let Some(res) = tcx
|
||||||
.selection_cache
|
.selection_cache
|
||||||
.get(¶m_env.and(trait_ref).with_constness(pred.constness), tcx)
|
.get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
|
||||||
{
|
{
|
||||||
return Some(res);
|
return Some(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.infcx
|
self.infcx
|
||||||
.selection_cache
|
.selection_cache
|
||||||
.get(¶m_env.and(trait_ref).with_constness(pred.constness), tcx)
|
.get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines whether can we safely cache the result
|
/// Determines whether can we safely cache the result
|
||||||
|
@ -1286,7 +1331,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
debug!(?trait_ref, ?candidate, "insert_candidate_cache global");
|
debug!(?trait_ref, ?candidate, "insert_candidate_cache global");
|
||||||
// This may overwrite the cache with the same value.
|
// This may overwrite the cache with the same value.
|
||||||
tcx.selection_cache.insert(
|
tcx.selection_cache.insert(
|
||||||
param_env.and(trait_ref).with_constness(pred.constness),
|
(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
|
||||||
dep_node,
|
dep_node,
|
||||||
candidate,
|
candidate,
|
||||||
);
|
);
|
||||||
|
@ -1297,7 +1342,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
|
|
||||||
debug!(?trait_ref, ?candidate, "insert_candidate_cache local");
|
debug!(?trait_ref, ?candidate, "insert_candidate_cache local");
|
||||||
self.infcx.selection_cache.insert(
|
self.infcx.selection_cache.insert(
|
||||||
param_env.and(trait_ref).with_constness(pred.constness),
|
(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
|
||||||
dep_node,
|
dep_node,
|
||||||
candidate,
|
candidate,
|
||||||
);
|
);
|
||||||
|
@ -1523,10 +1568,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
| ConstDropCandidate,
|
| ConstDropCandidate,
|
||||||
) => false,
|
) => false,
|
||||||
|
|
||||||
(ParamCandidate(other), ParamCandidate(victim)) => {
|
(
|
||||||
|
ParamCandidate((other, other_polarity)),
|
||||||
|
ParamCandidate((victim, victim_polarity)),
|
||||||
|
) => {
|
||||||
let same_except_bound_vars = other.value.skip_binder()
|
let same_except_bound_vars = other.value.skip_binder()
|
||||||
== victim.value.skip_binder()
|
== victim.value.skip_binder()
|
||||||
&& other.constness == victim.constness
|
&& other.constness == victim.constness
|
||||||
|
&& other_polarity == victim_polarity
|
||||||
&& !other.value.skip_binder().has_escaping_bound_vars();
|
&& !other.value.skip_binder().has_escaping_bound_vars();
|
||||||
if same_except_bound_vars {
|
if same_except_bound_vars {
|
||||||
// See issue #84398. In short, we can generate multiple ParamCandidates which are
|
// See issue #84398. In short, we can generate multiple ParamCandidates which are
|
||||||
|
@ -1537,6 +1586,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
other.value.bound_vars().len() <= victim.value.bound_vars().len()
|
other.value.bound_vars().len() <= victim.value.bound_vars().len()
|
||||||
} else if other.value == victim.value
|
} else if other.value == victim.value
|
||||||
&& victim.constness == ty::BoundConstness::NotConst
|
&& victim.constness == ty::BoundConstness::NotConst
|
||||||
|
&& other_polarity == victim_polarity
|
||||||
{
|
{
|
||||||
// Drop otherwise equivalent non-const candidates in favor of const candidates.
|
// Drop otherwise equivalent non-const candidates in favor of const candidates.
|
||||||
true
|
true
|
||||||
|
@ -1566,11 +1616,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
| TraitAliasCandidate(..)
|
| TraitAliasCandidate(..)
|
||||||
| ObjectCandidate(_)
|
| ObjectCandidate(_)
|
||||||
| ProjectionCandidate(_),
|
| ProjectionCandidate(_),
|
||||||
) => !is_global(&cand.value),
|
) => !is_global(&cand.0.value),
|
||||||
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
|
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
|
||||||
// Prefer these to a global where-clause bound
|
// Prefer these to a global where-clause bound
|
||||||
// (see issue #50825).
|
// (see issue #50825).
|
||||||
is_global(&cand.value)
|
is_global(&cand.0.value)
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
ImplCandidate(_)
|
ImplCandidate(_)
|
||||||
|
@ -1586,7 +1636,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
) => {
|
) => {
|
||||||
// Prefer these to a global where-clause bound
|
// Prefer these to a global where-clause bound
|
||||||
// (see issue #50825).
|
// (see issue #50825).
|
||||||
is_global(&cand.value) && other.evaluation.must_apply_modulo_regions()
|
is_global(&cand.0.value) && other.evaluation.must_apply_modulo_regions()
|
||||||
}
|
}
|
||||||
|
|
||||||
(ProjectionCandidate(i), ProjectionCandidate(j))
|
(ProjectionCandidate(i), ProjectionCandidate(j))
|
||||||
|
|
|
@ -531,6 +531,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]),
|
substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]),
|
||||||
},
|
},
|
||||||
constness: t.constness,
|
constness: t.constness,
|
||||||
|
polarity: t.polarity,
|
||||||
}));
|
}));
|
||||||
let obl = Obligation::new(
|
let obl = Obligation::new(
|
||||||
o.cause.clone(),
|
o.cause.clone(),
|
||||||
|
|
|
@ -382,6 +382,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
|
||||||
ty::PredicateKind::Trait(ty::TraitPredicate {
|
ty::PredicateKind::Trait(ty::TraitPredicate {
|
||||||
trait_ref,
|
trait_ref,
|
||||||
constness: ty::BoundConstness::NotConst,
|
constness: ty::BoundConstness::NotConst,
|
||||||
|
polarity: _,
|
||||||
}) => {
|
}) => {
|
||||||
if !matches!(
|
if !matches!(
|
||||||
trait_predicate_kind(tcx, predicate),
|
trait_predicate_kind(tcx, predicate),
|
||||||
|
@ -413,6 +414,7 @@ fn trait_predicate_kind<'tcx>(
|
||||||
ty::PredicateKind::Trait(ty::TraitPredicate {
|
ty::PredicateKind::Trait(ty::TraitPredicate {
|
||||||
trait_ref,
|
trait_ref,
|
||||||
constness: ty::BoundConstness::NotConst,
|
constness: ty::BoundConstness::NotConst,
|
||||||
|
polarity: _,
|
||||||
}) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
|
}) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
|
||||||
ty::PredicateKind::Trait(_)
|
ty::PredicateKind::Trait(_)
|
||||||
| ty::PredicateKind::RegionOutlives(_)
|
| ty::PredicateKind::RegionOutlives(_)
|
||||||
|
|
5
src/test/ui/coherence/auxiliary/error_lib.rs
Normal file
5
src/test/ui/coherence/auxiliary/error_lib.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![feature(negative_impls)]
|
||||||
|
|
||||||
|
pub trait Error {}
|
||||||
|
impl !Error for &str {}
|
|
@ -0,0 +1,19 @@
|
||||||
|
#![feature(negative_impls)]
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
#![feature(trait_alias)]
|
||||||
|
|
||||||
|
trait A {}
|
||||||
|
trait B {}
|
||||||
|
trait AB = A + B;
|
||||||
|
|
||||||
|
impl !A for u32 {}
|
||||||
|
|
||||||
|
trait C {}
|
||||||
|
#[rustc_strict_coherence]
|
||||||
|
impl<T: AB> C for T {}
|
||||||
|
#[rustc_strict_coherence]
|
||||||
|
impl C for u32 {}
|
||||||
|
//~^ ERROR: conflicting implementations of trait `C` for type `u32` [E0119]
|
||||||
|
// FIXME this should work, we should implement an `assemble_neg_candidates` fn
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,12 @@
|
||||||
|
error[E0119]: conflicting implementations of trait `C` for type `u32`
|
||||||
|
--> $DIR/coherence-overlap-negate-alias-strict.rs:15:1
|
||||||
|
|
|
||||||
|
LL | impl<T: AB> C for T {}
|
||||||
|
| ------------------- first implementation here
|
||||||
|
LL | #[rustc_strict_coherence]
|
||||||
|
LL | impl C for u32 {}
|
||||||
|
| ^^^^^^^^^^^^^^ conflicting implementation for `u32`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0119`.
|
|
@ -0,0 +1,8 @@
|
||||||
|
use std::ops::DerefMut;
|
||||||
|
|
||||||
|
trait Foo {}
|
||||||
|
impl<T: DerefMut> Foo for T {}
|
||||||
|
impl<U> Foo for &U {}
|
||||||
|
//~^ ERROR: conflicting implementations of trait `Foo` for type `&_` [E0119]
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,11 @@
|
||||||
|
error[E0119]: conflicting implementations of trait `Foo` for type `&_`
|
||||||
|
--> $DIR/coherence-overlap-negate-not-use-feature-gate.rs:5:1
|
||||||
|
|
|
||||||
|
LL | impl<T: DerefMut> Foo for T {}
|
||||||
|
| --------------------------- first implementation here
|
||||||
|
LL | impl<U> Foo for &U {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0119`.
|
18
src/test/ui/coherence/coherence-overlap-negate-strict.rs
Normal file
18
src/test/ui/coherence/coherence-overlap-negate-strict.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(negative_impls)]
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
#![feature(trait_alias)]
|
||||||
|
|
||||||
|
trait A {}
|
||||||
|
trait B {}
|
||||||
|
|
||||||
|
impl !A for u32 {}
|
||||||
|
|
||||||
|
trait C {}
|
||||||
|
#[rustc_strict_coherence]
|
||||||
|
impl<T: A + B> C for T {}
|
||||||
|
#[rustc_strict_coherence]
|
||||||
|
impl C for u32 {}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,11 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(negative_impls)]
|
||||||
|
|
||||||
|
use std::ops::DerefMut;
|
||||||
|
|
||||||
|
trait Foo {}
|
||||||
|
impl<T: DerefMut> Foo for T {}
|
||||||
|
impl<U> Foo for &U {}
|
||||||
|
|
||||||
|
fn main() {}
|
16
src/test/ui/coherence/coherence-overlap-negative-trait.rs
Normal file
16
src/test/ui/coherence/coherence-overlap-negative-trait.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// check-pass
|
||||||
|
// aux-build:error_lib.rs
|
||||||
|
//
|
||||||
|
// Check that if we promise to not impl what would overlap it doesn't actually overlap
|
||||||
|
|
||||||
|
#![feature(negative_impls)]
|
||||||
|
|
||||||
|
extern crate error_lib as lib;
|
||||||
|
use lib::Error;
|
||||||
|
|
||||||
|
trait From<T> {}
|
||||||
|
|
||||||
|
impl From<&str> for Box<dyn Error> {}
|
||||||
|
impl<E> From<E> for Box<dyn Error> where E: Error {}
|
||||||
|
|
||||||
|
fn main() {}
|
20
src/test/ui/coherence/coherence-overlap-trait-alias.rs
Normal file
20
src/test/ui/coherence/coherence-overlap-trait-alias.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
#![feature(trait_alias)]
|
||||||
|
|
||||||
|
trait A {}
|
||||||
|
trait B {}
|
||||||
|
trait AB = A + B;
|
||||||
|
|
||||||
|
impl A for u32 {}
|
||||||
|
impl B for u32 {}
|
||||||
|
|
||||||
|
trait C {}
|
||||||
|
#[rustc_strict_coherence]
|
||||||
|
impl<T: AB> C for T {}
|
||||||
|
#[rustc_strict_coherence]
|
||||||
|
impl C for u32 {}
|
||||||
|
//~^ ERROR
|
||||||
|
// FIXME it's giving an ungreat error but unsure if we care given that it's using an internal rustc
|
||||||
|
// attribute and an artificial code path for testing purposes
|
||||||
|
|
||||||
|
fn main() {}
|
16
src/test/ui/coherence/coherence-overlap-trait-alias.stderr
Normal file
16
src/test/ui/coherence/coherence-overlap-trait-alias.stderr
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
error[E0283]: type annotations needed
|
||||||
|
--> $DIR/coherence-overlap-trait-alias.rs:15:6
|
||||||
|
|
|
||||||
|
LL | impl C for u32 {}
|
||||||
|
| ^ cannot infer type for type `u32`
|
||||||
|
|
|
||||||
|
= note: cannot satisfy `u32: C`
|
||||||
|
note: required by a bound in `C`
|
||||||
|
--> $DIR/coherence-overlap-trait-alias.rs:11:1
|
||||||
|
|
|
||||||
|
LL | trait C {}
|
||||||
|
| ^^^^^^^ required by this bound in `C`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0283`.
|
|
@ -41,5 +41,5 @@ fn test<X: ?Sized + Send>() {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
test::<A>();
|
test::<A>();
|
||||||
//~^ ERROR evaluate(Binder(TraitPredicate(<A as std::marker::Send>), [])) = Ok(EvaluatedToOk)
|
//~^ ERROR evaluate(Binder(TraitPredicate(<A as std::marker::Send>, polarity:Positive), [])) = Ok(EvaluatedToOk)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error: evaluate(Binder(TraitPredicate(<A as std::marker::Send>), [])) = Ok(EvaluatedToOk)
|
error: evaluate(Binder(TraitPredicate(<A as std::marker::Send>, polarity:Positive), [])) = Ok(EvaluatedToOk)
|
||||||
--> $DIR/cache-reached-depth-ice.rs:43:5
|
--> $DIR/cache-reached-depth-ice.rs:43:5
|
||||||
|
|
|
|
||||||
LL | fn test<X: ?Sized + Send>() {}
|
LL | fn test<X: ?Sized + Send>() {}
|
||||||
|
|
|
@ -57,10 +57,10 @@ fn main() {
|
||||||
// Key is that Vec<First> is "ok" and Third<'_, Ty> is "ok modulo regions":
|
// Key is that Vec<First> is "ok" and Third<'_, Ty> is "ok modulo regions":
|
||||||
|
|
||||||
forward();
|
forward();
|
||||||
//~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOk)
|
//~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk)
|
||||||
//~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
|
//~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
|
||||||
|
|
||||||
reverse();
|
reverse();
|
||||||
//~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOk)
|
//~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk)
|
||||||
//~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
|
//~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOk)
|
error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk)
|
||||||
--> $DIR/issue-83538-tainted-cache-after-cycle.rs:59:5
|
--> $DIR/issue-83538-tainted-cache-after-cycle.rs:59:5
|
||||||
|
|
|
|
||||||
LL | Vec<First>: Unpin,
|
LL | Vec<First>: Unpin,
|
||||||
|
@ -7,7 +7,7 @@ LL | Vec<First>: Unpin,
|
||||||
LL | forward();
|
LL | forward();
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
|
error: evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
|
||||||
--> $DIR/issue-83538-tainted-cache-after-cycle.rs:59:5
|
--> $DIR/issue-83538-tainted-cache-after-cycle.rs:59:5
|
||||||
|
|
|
|
||||||
LL | Third<'a, Ty>: Unpin,
|
LL | Third<'a, Ty>: Unpin,
|
||||||
|
@ -16,7 +16,7 @@ LL | Third<'a, Ty>: Unpin,
|
||||||
LL | forward();
|
LL | forward();
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
|
error: evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
|
||||||
--> $DIR/issue-83538-tainted-cache-after-cycle.rs:63:5
|
--> $DIR/issue-83538-tainted-cache-after-cycle.rs:63:5
|
||||||
|
|
|
|
||||||
LL | Third<'a, Ty>: Unpin,
|
LL | Third<'a, Ty>: Unpin,
|
||||||
|
@ -25,7 +25,7 @@ LL | Third<'a, Ty>: Unpin,
|
||||||
LL | reverse();
|
LL | reverse();
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOk)
|
error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk)
|
||||||
--> $DIR/issue-83538-tainted-cache-after-cycle.rs:63:5
|
--> $DIR/issue-83538-tainted-cache-after-cycle.rs:63:5
|
||||||
|
|
|
|
||||||
LL | Vec<First>: Unpin,
|
LL | Vec<First>: Unpin,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
#![feature(negative_impls)]
|
#![feature(negative_impls)]
|
||||||
|
|
||||||
// aux-build: foreign_trait.rs
|
// aux-build: foreign_trait.rs
|
||||||
|
@ -16,6 +18,6 @@ use foreign_trait::ForeignTrait;
|
||||||
|
|
||||||
trait LocalTrait { }
|
trait LocalTrait { }
|
||||||
impl<T: ForeignTrait> LocalTrait for T { }
|
impl<T: ForeignTrait> LocalTrait for T { }
|
||||||
impl LocalTrait for String { } //~ ERROR conflicting implementations
|
impl LocalTrait for String { }
|
||||||
|
|
||||||
fn main() { }
|
fn main() { }
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
error[E0119]: conflicting implementations of trait `LocalTrait` for type `std::string::String`
|
|
||||||
--> $DIR/rely-on-negative-impl-in-coherence.rs:19:1
|
|
||||||
|
|
|
||||||
LL | impl<T: ForeignTrait> LocalTrait for T { }
|
|
||||||
| -------------------------------------- first implementation here
|
|
||||||
LL | impl LocalTrait for String { }
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `std::string::String`
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0119`.
|
|
Loading…
Add table
Add a link
Reference in a new issue