1
Fork 0

auto implDiscriminantKind for every type

This commit is contained in:
Bastian Kauschke 2020-04-05 19:57:32 +02:00
parent 9f7c5a80a3
commit b6975bf22f
7 changed files with 140 additions and 22 deletions

View file

@ -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,

View file

@ -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,

View file

@ -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 {

View file

@ -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>,

View file

@ -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))

View file

@ -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,
})
}

View file

@ -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!(