Skip to content

Commit

Permalink
auto implDiscriminantKind for every type
Browse files Browse the repository at this point in the history
  • Loading branch information
lcnr committed May 19, 2020
1 parent 9f7c5a8 commit b6975bf
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 22 deletions.
12 changes: 12 additions & 0 deletions src/librustc_middle/traits/mod.rs
Expand Up @@ -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>),

Expand All @@ -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,
}
}
Expand All @@ -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[..],
}
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions src/librustc_middle/traits/select.rs
Expand Up @@ -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,
Expand Down
5 changes: 5 additions & 0 deletions src/librustc_middle/traits/structural_impls.rs
Expand Up @@ -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),
Expand Down Expand Up @@ -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 {
Expand Down
85 changes: 81 additions & 4 deletions src/librustc_trait_selection/traits/project.rs
Expand Up @@ -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};
Expand All @@ -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;
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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 `{:?}`",
Expand Down Expand Up @@ -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>,
Expand Down
37 changes: 21 additions & 16 deletions src/librustc_trait_selection/traits/select.rs
Expand Up @@ -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};
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -1995,22 +1999,23 @@ 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!(
"default implementations shouldn't be recorded \
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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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))
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_ty/instance.rs
Expand Up @@ -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,
})
}

Expand Down
15 changes: 14 additions & 1 deletion src/librustc_typeck/coherence/mod.rs
Expand Up @@ -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!(
Expand Down

0 comments on commit b6975bf

Please sign in to comment.