1
Fork 0

Rollup merge of #79287 - jonas-schievink:const-trait-impl, r=oli-obk

Allow using generic trait methods in `const fn`

Next step for https://github.com/rust-lang/rust/issues/67792, this now also allows code like the following:

```rust
struct S;

impl const PartialEq for S {
    fn eq(&self, _: &S) -> bool {
        true
    }
}

const fn equals_self<T: PartialEq>(t: &T) -> bool {
    *t == *t
}

pub const EQ: bool = equals_self(&S);
```

This works by threading const-ness of trait predicates through trait selection, in particular through `ParamCandidate`, and exposing it in the resulting `ImplSource`.

Since this change makes two bounds `T: Trait` and `T: ?const Trait` that only differ in their const-ness be treated like different bounds, candidate winnowing has been changed to drop the `?const` candidate in favor of the const candidate, to avoid ambiguities when both a const and a non-const bound is present.
This commit is contained in:
Jonas Schievink 2020-11-23 15:25:44 +01:00 committed by GitHub
commit c7a67209c8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 230 additions and 33 deletions

View file

@ -16,6 +16,7 @@ use crate::ty::{self, AdtKind, Ty, TyCtxt};
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::Constness;
use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP};
use smallvec::SmallVec;
@ -457,7 +458,7 @@ pub enum ImplSource<'tcx, N> {
/// for some type parameter. The `Vec<N>` represents the
/// obligations incurred from normalizing the where-clause (if
/// any).
Param(Vec<N>),
Param(Vec<N>, Constness),
/// Virtual calls through an object.
Object(ImplSourceObjectData<'tcx, N>),
@ -487,7 +488,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
pub fn nested_obligations(self) -> Vec<N> {
match self {
ImplSource::UserDefined(i) => i.nested,
ImplSource::Param(n) => n,
ImplSource::Param(n, _) => n,
ImplSource::Builtin(i) => i.nested,
ImplSource::AutoImpl(d) => d.nested,
ImplSource::Closure(c) => c.nested,
@ -502,7 +503,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
pub fn borrow_nested_obligations(&self) -> &[N] {
match &self {
ImplSource::UserDefined(i) => &i.nested[..],
ImplSource::Param(n) => &n[..],
ImplSource::Param(n, _) => &n[..],
ImplSource::Builtin(i) => &i.nested[..],
ImplSource::AutoImpl(d) => &d.nested[..],
ImplSource::Closure(c) => &c.nested[..],
@ -524,7 +525,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
substs: i.substs,
nested: i.nested.into_iter().map(f).collect(),
}),
ImplSource::Param(n) => ImplSource::Param(n.into_iter().map(f).collect()),
ImplSource::Param(n, ct) => ImplSource::Param(n.into_iter().map(f).collect(), ct),
ImplSource::Builtin(i) => ImplSource::Builtin(ImplSourceBuiltinData {
nested: i.nested.into_iter().map(f).collect(),
}),

View file

@ -101,7 +101,7 @@ pub enum SelectionCandidate<'tcx> {
/// `false` if there are no *further* obligations.
has_nested: bool,
},
ParamCandidate(ty::PolyTraitRef<'tcx>),
ParamCandidate(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>),
ImplCandidate(DefId),
AutoImplCandidate(DefId),

View file

@ -21,7 +21,9 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
super::ImplSource::Object(ref d) => write!(f, "{:?}", d),
super::ImplSource::Param(ref n) => write!(f, "ImplSourceParamData({:?})", n),
super::ImplSource::Param(ref n, ct) => {
write!(f, "ImplSourceParamData({:?}, {:?})", n, ct)
}
super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d),

View file

@ -42,7 +42,9 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
use rustc_hir::definitions::{DefPathHash, Definitions};
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{HirId, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet, Node, TraitCandidate};
use rustc_hir::{
Constness, HirId, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet, Node, TraitCandidate,
};
use rustc_index::vec::{Idx, IndexVec};
use rustc_macros::HashStable;
use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames};
@ -1635,6 +1637,8 @@ nop_list_lift! {projs; ProjectionKind => ProjectionKind}
// This is the impl for `&'a InternalSubsts<'a>`.
nop_list_lift! {substs; GenericArg<'a> => GenericArg<'tcx>}
CloneLiftImpls! { for<'tcx> { Constness, } }
pub mod tls {
use super::{ptr_eq, GlobalCtxt, TyCtxt};

View file

@ -1503,9 +1503,11 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
}
impl<'tcx> Predicate<'tcx> {
pub fn to_opt_poly_trait_ref(self) -> Option<PolyTraitRef<'tcx>> {
pub fn to_opt_poly_trait_ref(self) -> Option<ConstnessAnd<PolyTraitRef<'tcx>>> {
match self.skip_binders() {
PredicateAtom::Trait(t, _) => Some(ty::Binder::bind(t.trait_ref)),
PredicateAtom::Trait(t, constness) => {
Some(ConstnessAnd { constness, value: ty::Binder::bind(t.trait_ref) })
}
PredicateAtom::Projection(..)
| PredicateAtom::Subtype(..)
| PredicateAtom::RegionOutlives(..)
@ -1947,7 +1949,7 @@ impl<'tcx> ParamEnv<'tcx> {
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)]
pub struct ConstnessAnd<T> {
pub constness: Constness,
pub value: T,