auto implDiscriminantKind
for every type
This commit is contained in:
parent
9f7c5a80a3
commit
b6975bf22f
7 changed files with 140 additions and 22 deletions
|
@ -409,6 +409,9 @@ pub enum Vtable<'tcx, N> {
|
|||
/// Same as above, but for a function pointer type with the given signature.
|
||||
VtableFnPointer(VtableFnPointerData<'tcx, N>),
|
||||
|
||||
/// Vtable for a builtin `DeterminantKind` trait implementation.
|
||||
VtableDiscriminantKind(VtableDiscriminantKindData),
|
||||
|
||||
/// Vtable automatically generated for a generator.
|
||||
VtableGenerator(VtableGeneratorData<'tcx, N>),
|
||||
|
||||
|
@ -427,6 +430,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
|
|||
VtableGenerator(c) => c.nested,
|
||||
VtableObject(d) => d.nested,
|
||||
VtableFnPointer(d) => d.nested,
|
||||
VtableDiscriminantKind(VtableDiscriminantKindData) => Vec::new(),
|
||||
VtableTraitAlias(d) => d.nested,
|
||||
}
|
||||
}
|
||||
|
@ -441,6 +445,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
|
|||
VtableGenerator(c) => &c.nested[..],
|
||||
VtableObject(d) => &d.nested[..],
|
||||
VtableFnPointer(d) => &d.nested[..],
|
||||
VtableDiscriminantKind(VtableDiscriminantKindData) => &[],
|
||||
VtableTraitAlias(d) => &d.nested[..],
|
||||
}
|
||||
}
|
||||
|
@ -482,6 +487,9 @@ impl<'tcx, N> Vtable<'tcx, N> {
|
|||
fn_ty: p.fn_ty,
|
||||
nested: p.nested.into_iter().map(f).collect(),
|
||||
}),
|
||||
VtableDiscriminantKind(VtableDiscriminantKindData) => {
|
||||
VtableDiscriminantKind(VtableDiscriminantKindData)
|
||||
}
|
||||
VtableTraitAlias(d) => VtableTraitAlias(VtableTraitAliasData {
|
||||
alias_def_id: d.alias_def_id,
|
||||
substs: d.substs,
|
||||
|
@ -558,6 +566,10 @@ pub struct VtableFnPointerData<'tcx, N> {
|
|||
pub nested: Vec<N>,
|
||||
}
|
||||
|
||||
// FIXME(@lcnr): This should be refactored and merged with other builtin vtables.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
|
||||
pub struct VtableDiscriminantKindData;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
|
||||
pub struct VtableTraitAliasData<'tcx, N> {
|
||||
pub alias_def_id: DefId,
|
||||
|
|
|
@ -132,6 +132,9 @@ pub enum SelectionCandidate<'tcx> {
|
|||
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
|
||||
FnPointerCandidate,
|
||||
|
||||
/// Builtin implementation of `DiscriminantKind`.
|
||||
DiscriminantKindCandidate,
|
||||
|
||||
TraitAliasCandidate(DefId),
|
||||
|
||||
ObjectCandidate,
|
||||
|
|
|
@ -19,6 +19,8 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> {
|
|||
|
||||
super::VtableFnPointer(ref d) => write!(f, "VtableFnPointer({:?})", d),
|
||||
|
||||
super::VtableDiscriminantKind(ref d) => write!(f, "{:?}", d),
|
||||
|
||||
super::VtableObject(ref d) => write!(f, "{:?}", d),
|
||||
|
||||
super::VtableParam(ref n) => write!(f, "VtableParam({:?})", n),
|
||||
|
@ -273,6 +275,9 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
|
|||
traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested })
|
||||
})
|
||||
}
|
||||
traits::VtableDiscriminantKind(traits::VtableDiscriminantKindData) => {
|
||||
Some(traits::VtableDiscriminantKind(traits::VtableDiscriminantKindData))
|
||||
}
|
||||
traits::VtableParam(n) => Some(traits::VtableParam(n)),
|
||||
traits::VtableBuiltin(n) => Some(traits::VtableBuiltin(n)),
|
||||
traits::VtableObject(traits::VtableObjectData {
|
||||
|
|
|
@ -12,7 +12,10 @@ use super::Selection;
|
|||
use super::SelectionContext;
|
||||
use super::SelectionError;
|
||||
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
|
||||
use super::{VtableClosureData, VtableFnPointerData, VtableGeneratorData, VtableImplData};
|
||||
use super::{
|
||||
VtableClosureData, VtableDiscriminantKindData, VtableFnPointerData, VtableGeneratorData,
|
||||
VtableImplData,
|
||||
};
|
||||
|
||||
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
||||
|
@ -23,6 +26,7 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_hir::lang_items::{FnOnceTraitLangItem, GeneratorTraitLangItem};
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
||||
use rustc_middle::ty::subst::{InternalSubsts, Subst};
|
||||
use rustc_middle::ty::util::IntTypeExt;
|
||||
use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
@ -1043,6 +1047,46 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
|||
}
|
||||
}
|
||||
}
|
||||
super::VtableDiscriminantKind(..) => {
|
||||
// While `DiscriminantKind` is automatically implemented for every type,
|
||||
// the concrete discriminant may not be known yet.
|
||||
//
|
||||
// Any type with multiple potential discriminant types is therefore not eligible.
|
||||
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
|
||||
|
||||
match self_ty.kind {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| ty::Adt(..)
|
||||
| ty::Foreign(_)
|
||||
| ty::Str
|
||||
| ty::Array(..)
|
||||
| ty::Slice(_)
|
||||
| ty::RawPtr(..)
|
||||
| ty::Ref(..)
|
||||
| ty::FnDef(..)
|
||||
| ty::FnPtr(..)
|
||||
| ty::Dynamic(..)
|
||||
| ty::Closure(..)
|
||||
| ty::Generator(..)
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::Never
|
||||
| ty::Tuple(..)
|
||||
// Integers and floats always have `u8` as their discriminant.
|
||||
| ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
|
||||
|
||||
ty::Projection(..)
|
||||
| ty::Opaque(..)
|
||||
| ty::Param(..)
|
||||
| ty::Bound(..)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Infer(..)
|
||||
| ty::Error => false,
|
||||
}
|
||||
}
|
||||
super::VtableParam(..) => {
|
||||
// This case tell us nothing about the value of an
|
||||
// associated type. Consider:
|
||||
|
@ -1124,13 +1168,15 @@ fn confirm_select_candidate<'cx, 'tcx>(
|
|||
super::VtableGenerator(data) => confirm_generator_candidate(selcx, obligation, data),
|
||||
super::VtableClosure(data) => confirm_closure_candidate(selcx, obligation, data),
|
||||
super::VtableFnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data),
|
||||
super::VtableDiscriminantKind(data) => {
|
||||
confirm_discriminant_kind_candidate(selcx, obligation, data)
|
||||
}
|
||||
super::VtableObject(_) => confirm_object_candidate(selcx, obligation, obligation_trait_ref),
|
||||
super::VtableAutoImpl(..)
|
||||
| super::VtableParam(..)
|
||||
| super::VtableBuiltin(..)
|
||||
| super::VtableTraitAlias(..) =>
|
||||
// we don't create Select candidates with this kind of resolution
|
||||
{
|
||||
| super::VtableTraitAlias(..) => {
|
||||
// we don't create Select candidates with this kind of resolution
|
||||
span_bug!(
|
||||
obligation.cause.span,
|
||||
"Cannot project an associated type from `{:?}`",
|
||||
|
@ -1259,6 +1305,37 @@ fn confirm_generator_candidate<'cx, 'tcx>(
|
|||
.with_addl_obligations(obligations)
|
||||
}
|
||||
|
||||
fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
_: VtableDiscriminantKindData,
|
||||
) -> Progress<'tcx> {
|
||||
let tcx = selcx.tcx();
|
||||
|
||||
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
|
||||
let substs = tcx.mk_substs([self_ty.into()].iter());
|
||||
|
||||
let assoc_items = tcx.associated_items(tcx.lang_items().discriminant_kind_trait().unwrap());
|
||||
// FIXME: emit an error if the trait definition is wrong
|
||||
let discriminant_def_id = assoc_items.in_definition_order().next().unwrap().def_id;
|
||||
|
||||
let discriminant_ty = match self_ty.kind {
|
||||
// Use the discriminant type for enums.
|
||||
ty::Adt(adt, _) if adt.is_enum() => adt.repr.discr_type().to_ty(tcx),
|
||||
// Default to `i32` for generators.
|
||||
ty::Generator(..) => tcx.types.i32,
|
||||
// Use `u8` for all other types.
|
||||
_ => tcx.types.u8,
|
||||
};
|
||||
|
||||
let predicate = ty::ProjectionPredicate {
|
||||
projection_ty: ty::ProjectionTy { substs, item_def_id: discriminant_def_id },
|
||||
ty: discriminant_ty,
|
||||
};
|
||||
|
||||
confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate))
|
||||
}
|
||||
|
||||
fn confirm_fn_pointer_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
|
|
|
@ -24,12 +24,13 @@ use super::{ObjectCastObligation, Obligation};
|
|||
use super::{ObligationCause, PredicateObligation, TraitObligation};
|
||||
use super::{OutputTypeParameterMismatch, Overflow, SelectionError, Unimplemented};
|
||||
use super::{
|
||||
VtableAutoImpl, VtableBuiltin, VtableClosure, VtableFnPointer, VtableGenerator, VtableImpl,
|
||||
VtableObject, VtableParam, VtableTraitAlias,
|
||||
VtableAutoImpl, VtableBuiltin, VtableClosure, VtableDiscriminantKind, VtableFnPointer,
|
||||
VtableGenerator, VtableImpl, VtableObject, VtableParam, VtableTraitAlias,
|
||||
};
|
||||
use super::{
|
||||
VtableAutoImplData, VtableBuiltinData, VtableClosureData, VtableFnPointerData,
|
||||
VtableGeneratorData, VtableImplData, VtableObjectData, VtableTraitAliasData,
|
||||
VtableAutoImplData, VtableBuiltinData, VtableClosureData, VtableDiscriminantKindData,
|
||||
VtableFnPointerData, VtableGeneratorData, VtableImplData, VtableObjectData,
|
||||
VtableTraitAliasData,
|
||||
};
|
||||
|
||||
use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener};
|
||||
|
@ -1382,6 +1383,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// 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.sized_trait() == Some(def_id) {
|
||||
// Sized is never implementable by end-users, it is
|
||||
// always automatically computed.
|
||||
|
@ -1995,11 +1999,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
let is_global =
|
||||
|cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions();
|
||||
|
||||
// (*) Prefer `BuiltinCandidate { has_nested: false }` and `DiscriminantKindCandidate`
|
||||
// to anything else.
|
||||
//
|
||||
// This is a fix for #53123 and prevents winnowing from accidentally extending the
|
||||
// lifetime of a variable.
|
||||
match other.candidate {
|
||||
// Prefer `BuiltinCandidate { has_nested: false }` to anything else.
|
||||
// This is a fix for #53123 and prevents winnowing from accidentally extending the
|
||||
// lifetime of a variable.
|
||||
BuiltinCandidate { has_nested: false } => true,
|
||||
// (*)
|
||||
BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => true,
|
||||
ParamCandidate(ref cand) => match victim.candidate {
|
||||
AutoImplCandidate(..) => {
|
||||
bug!(
|
||||
|
@ -2007,10 +2014,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
when there are other valid candidates"
|
||||
);
|
||||
}
|
||||
// Prefer `BuiltinCandidate { has_nested: false }` to anything else.
|
||||
// This is a fix for #53123 and prevents winnowing from accidentally extending the
|
||||
// lifetime of a variable.
|
||||
BuiltinCandidate { has_nested: false } => false,
|
||||
// (*)
|
||||
BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => false,
|
||||
ImplCandidate(..)
|
||||
| ClosureCandidate
|
||||
| GeneratorCandidate
|
||||
|
@ -2038,10 +2043,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
when there are other valid candidates"
|
||||
);
|
||||
}
|
||||
// Prefer `BuiltinCandidate { has_nested: false }` to anything else.
|
||||
// This is a fix for #53123 and prevents winnowing from accidentally extending the
|
||||
// lifetime of a variable.
|
||||
BuiltinCandidate { has_nested: false } => false,
|
||||
// (*)
|
||||
BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => false,
|
||||
ImplCandidate(..)
|
||||
| ClosureCandidate
|
||||
| GeneratorCandidate
|
||||
|
@ -2486,6 +2489,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
Ok(VtableFnPointer(data))
|
||||
}
|
||||
|
||||
DiscriminantKindCandidate => Ok(VtableDiscriminantKind(VtableDiscriminantKindData)),
|
||||
|
||||
TraitAliasCandidate(alias_def_id) => {
|
||||
let data = self.confirm_trait_alias_candidate(obligation, alias_def_id);
|
||||
Ok(VtableTraitAlias(data))
|
||||
|
|
|
@ -236,7 +236,10 @@ fn resolve_associated_item<'tcx>(
|
|||
None
|
||||
}
|
||||
}
|
||||
traits::VtableAutoImpl(..) | traits::VtableParam(..) | traits::VtableTraitAlias(..) => None,
|
||||
traits::VtableAutoImpl(..)
|
||||
| traits::VtableParam(..)
|
||||
| traits::VtableTraitAlias(..)
|
||||
| traits::VtableDiscriminantKind(..) => None,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,20 @@ fn enforce_trait_manually_implementable(
|
|||
let did = Some(trait_def_id);
|
||||
let li = tcx.lang_items();
|
||||
|
||||
// Disallow *all* explicit impls of `Sized` and `Unsize` for now.
|
||||
// Disallow *all* explicit impls of `DiscriminantKind`, `Sized` and `Unsize` for now.
|
||||
if did == li.discriminant_kind_trait() {
|
||||
let span = impl_header_span(tcx, impl_def_id);
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0322,
|
||||
"explicit impls for the `DiscriminantKind` trait are not permitted"
|
||||
)
|
||||
.span_label(span, "impl of 'DiscriminantKind' not allowed")
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
if did == li.sized_trait() {
|
||||
let span = impl_header_span(tcx, impl_def_id);
|
||||
struct_span_err!(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue