Skip to content

Commit b6975bf

Browse files
committed
auto implDiscriminantKind for every type
1 parent 9f7c5a8 commit b6975bf

File tree

7 files changed

+140
-22
lines changed

7 files changed

+140
-22
lines changed

src/librustc_middle/traits/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,9 @@ pub enum Vtable<'tcx, N> {
409409
/// Same as above, but for a function pointer type with the given signature.
410410
VtableFnPointer(VtableFnPointerData<'tcx, N>),
411411

412+
/// Vtable for a builtin `DeterminantKind` trait implementation.
413+
VtableDiscriminantKind(VtableDiscriminantKindData),
414+
412415
/// Vtable automatically generated for a generator.
413416
VtableGenerator(VtableGeneratorData<'tcx, N>),
414417

@@ -427,6 +430,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
427430
VtableGenerator(c) => c.nested,
428431
VtableObject(d) => d.nested,
429432
VtableFnPointer(d) => d.nested,
433+
VtableDiscriminantKind(VtableDiscriminantKindData) => Vec::new(),
430434
VtableTraitAlias(d) => d.nested,
431435
}
432436
}
@@ -441,6 +445,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
441445
VtableGenerator(c) => &c.nested[..],
442446
VtableObject(d) => &d.nested[..],
443447
VtableFnPointer(d) => &d.nested[..],
448+
VtableDiscriminantKind(VtableDiscriminantKindData) => &[],
444449
VtableTraitAlias(d) => &d.nested[..],
445450
}
446451
}
@@ -482,6 +487,9 @@ impl<'tcx, N> Vtable<'tcx, N> {
482487
fn_ty: p.fn_ty,
483488
nested: p.nested.into_iter().map(f).collect(),
484489
}),
490+
VtableDiscriminantKind(VtableDiscriminantKindData) => {
491+
VtableDiscriminantKind(VtableDiscriminantKindData)
492+
}
485493
VtableTraitAlias(d) => VtableTraitAlias(VtableTraitAliasData {
486494
alias_def_id: d.alias_def_id,
487495
substs: d.substs,
@@ -558,6 +566,10 @@ pub struct VtableFnPointerData<'tcx, N> {
558566
pub nested: Vec<N>,
559567
}
560568

569+
// FIXME(@lcnr): This should be refactored and merged with other builtin vtables.
570+
#[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
571+
pub struct VtableDiscriminantKindData;
572+
561573
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
562574
pub struct VtableTraitAliasData<'tcx, N> {
563575
pub alias_def_id: DefId,

src/librustc_middle/traits/select.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ pub enum SelectionCandidate<'tcx> {
132132
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
133133
FnPointerCandidate,
134134

135+
/// Builtin implementation of `DiscriminantKind`.
136+
DiscriminantKindCandidate,
137+
135138
TraitAliasCandidate(DefId),
136139

137140
ObjectCandidate,

src/librustc_middle/traits/structural_impls.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> {
1919

2020
super::VtableFnPointer(ref d) => write!(f, "VtableFnPointer({:?})", d),
2121

22+
super::VtableDiscriminantKind(ref d) => write!(f, "{:?}", d),
23+
2224
super::VtableObject(ref d) => write!(f, "{:?}", d),
2325

2426
super::VtableParam(ref n) => write!(f, "VtableParam({:?})", n),
@@ -273,6 +275,9 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
273275
traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested })
274276
})
275277
}
278+
traits::VtableDiscriminantKind(traits::VtableDiscriminantKindData) => {
279+
Some(traits::VtableDiscriminantKind(traits::VtableDiscriminantKindData))
280+
}
276281
traits::VtableParam(n) => Some(traits::VtableParam(n)),
277282
traits::VtableBuiltin(n) => Some(traits::VtableBuiltin(n)),
278283
traits::VtableObject(traits::VtableObjectData {

src/librustc_trait_selection/traits/project.rs

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ use super::Selection;
1212
use super::SelectionContext;
1313
use super::SelectionError;
1414
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
15-
use super::{VtableClosureData, VtableFnPointerData, VtableGeneratorData, VtableImplData};
15+
use super::{
16+
VtableClosureData, VtableDiscriminantKindData, VtableFnPointerData, VtableGeneratorData,
17+
VtableImplData,
18+
};
1619

1720
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
1821
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
@@ -23,6 +26,7 @@ use rustc_hir::def_id::DefId;
2326
use rustc_hir::lang_items::{FnOnceTraitLangItem, GeneratorTraitLangItem};
2427
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
2528
use rustc_middle::ty::subst::{InternalSubsts, Subst};
29+
use rustc_middle::ty::util::IntTypeExt;
2630
use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
2731
use rustc_span::symbol::{sym, Ident};
2832
use rustc_span::DUMMY_SP;
@@ -1043,6 +1047,46 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
10431047
}
10441048
}
10451049
}
1050+
super::VtableDiscriminantKind(..) => {
1051+
// While `DiscriminantKind` is automatically implemented for every type,
1052+
// the concrete discriminant may not be known yet.
1053+
//
1054+
// Any type with multiple potential discriminant types is therefore not eligible.
1055+
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
1056+
1057+
match self_ty.kind {
1058+
ty::Bool
1059+
| ty::Char
1060+
| ty::Int(_)
1061+
| ty::Uint(_)
1062+
| ty::Float(_)
1063+
| ty::Adt(..)
1064+
| ty::Foreign(_)
1065+
| ty::Str
1066+
| ty::Array(..)
1067+
| ty::Slice(_)
1068+
| ty::RawPtr(..)
1069+
| ty::Ref(..)
1070+
| ty::FnDef(..)
1071+
| ty::FnPtr(..)
1072+
| ty::Dynamic(..)
1073+
| ty::Closure(..)
1074+
| ty::Generator(..)
1075+
| ty::GeneratorWitness(..)
1076+
| ty::Never
1077+
| ty::Tuple(..)
1078+
// Integers and floats always have `u8` as their discriminant.
1079+
| ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
1080+
1081+
ty::Projection(..)
1082+
| ty::Opaque(..)
1083+
| ty::Param(..)
1084+
| ty::Bound(..)
1085+
| ty::Placeholder(..)
1086+
| ty::Infer(..)
1087+
| ty::Error => false,
1088+
}
1089+
}
10461090
super::VtableParam(..) => {
10471091
// This case tell us nothing about the value of an
10481092
// associated type. Consider:
@@ -1124,13 +1168,15 @@ fn confirm_select_candidate<'cx, 'tcx>(
11241168
super::VtableGenerator(data) => confirm_generator_candidate(selcx, obligation, data),
11251169
super::VtableClosure(data) => confirm_closure_candidate(selcx, obligation, data),
11261170
super::VtableFnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data),
1171+
super::VtableDiscriminantKind(data) => {
1172+
confirm_discriminant_kind_candidate(selcx, obligation, data)
1173+
}
11271174
super::VtableObject(_) => confirm_object_candidate(selcx, obligation, obligation_trait_ref),
11281175
super::VtableAutoImpl(..)
11291176
| super::VtableParam(..)
11301177
| super::VtableBuiltin(..)
1131-
| super::VtableTraitAlias(..) =>
1132-
// we don't create Select candidates with this kind of resolution
1133-
{
1178+
| super::VtableTraitAlias(..) => {
1179+
// we don't create Select candidates with this kind of resolution
11341180
span_bug!(
11351181
obligation.cause.span,
11361182
"Cannot project an associated type from `{:?}`",
@@ -1259,6 +1305,37 @@ fn confirm_generator_candidate<'cx, 'tcx>(
12591305
.with_addl_obligations(obligations)
12601306
}
12611307

1308+
fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
1309+
selcx: &mut SelectionContext<'cx, 'tcx>,
1310+
obligation: &ProjectionTyObligation<'tcx>,
1311+
_: VtableDiscriminantKindData,
1312+
) -> Progress<'tcx> {
1313+
let tcx = selcx.tcx();
1314+
1315+
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
1316+
let substs = tcx.mk_substs([self_ty.into()].iter());
1317+
1318+
let assoc_items = tcx.associated_items(tcx.lang_items().discriminant_kind_trait().unwrap());
1319+
// FIXME: emit an error if the trait definition is wrong
1320+
let discriminant_def_id = assoc_items.in_definition_order().next().unwrap().def_id;
1321+
1322+
let discriminant_ty = match self_ty.kind {
1323+
// Use the discriminant type for enums.
1324+
ty::Adt(adt, _) if adt.is_enum() => adt.repr.discr_type().to_ty(tcx),
1325+
// Default to `i32` for generators.
1326+
ty::Generator(..) => tcx.types.i32,
1327+
// Use `u8` for all other types.
1328+
_ => tcx.types.u8,
1329+
};
1330+
1331+
let predicate = ty::ProjectionPredicate {
1332+
projection_ty: ty::ProjectionTy { substs, item_def_id: discriminant_def_id },
1333+
ty: discriminant_ty,
1334+
};
1335+
1336+
confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate))
1337+
}
1338+
12621339
fn confirm_fn_pointer_candidate<'cx, 'tcx>(
12631340
selcx: &mut SelectionContext<'cx, 'tcx>,
12641341
obligation: &ProjectionTyObligation<'tcx>,

src/librustc_trait_selection/traits/select.rs

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,13 @@ use super::{ObjectCastObligation, Obligation};
2424
use super::{ObligationCause, PredicateObligation, TraitObligation};
2525
use super::{OutputTypeParameterMismatch, Overflow, SelectionError, Unimplemented};
2626
use super::{
27-
VtableAutoImpl, VtableBuiltin, VtableClosure, VtableFnPointer, VtableGenerator, VtableImpl,
28-
VtableObject, VtableParam, VtableTraitAlias,
27+
VtableAutoImpl, VtableBuiltin, VtableClosure, VtableDiscriminantKind, VtableFnPointer,
28+
VtableGenerator, VtableImpl, VtableObject, VtableParam, VtableTraitAlias,
2929
};
3030
use super::{
31-
VtableAutoImplData, VtableBuiltinData, VtableClosureData, VtableFnPointerData,
32-
VtableGeneratorData, VtableImplData, VtableObjectData, VtableTraitAliasData,
31+
VtableAutoImplData, VtableBuiltinData, VtableClosureData, VtableDiscriminantKindData,
32+
VtableFnPointerData, VtableGeneratorData, VtableImplData, VtableObjectData,
33+
VtableTraitAliasData,
3334
};
3435

3536
use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener};
@@ -1382,6 +1383,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
13821383
// For other types, we'll use the builtin rules.
13831384
let copy_conditions = self.copy_clone_conditions(obligation);
13841385
self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?;
1386+
} else if lang_items.discriminant_kind_trait() == Some(def_id) {
1387+
// `DiscriminantKind` is automatically implemented for every type.
1388+
candidates.vec.push(DiscriminantKindCandidate);
13851389
} else if lang_items.sized_trait() == Some(def_id) {
13861390
// Sized is never implementable by end-users, it is
13871391
// always automatically computed.
@@ -1995,22 +1999,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
19951999
let is_global =
19962000
|cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions();
19972001

2002+
// (*) Prefer `BuiltinCandidate { has_nested: false }` and `DiscriminantKindCandidate`
2003+
// to anything else.
2004+
//
2005+
// This is a fix for #53123 and prevents winnowing from accidentally extending the
2006+
// lifetime of a variable.
19982007
match other.candidate {
1999-
// Prefer `BuiltinCandidate { has_nested: false }` to anything else.
2000-
// This is a fix for #53123 and prevents winnowing from accidentally extending the
2001-
// lifetime of a variable.
2002-
BuiltinCandidate { has_nested: false } => true,
2008+
// (*)
2009+
BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => true,
20032010
ParamCandidate(ref cand) => match victim.candidate {
20042011
AutoImplCandidate(..) => {
20052012
bug!(
20062013
"default implementations shouldn't be recorded \
20072014
when there are other valid candidates"
20082015
);
20092016
}
2010-
// Prefer `BuiltinCandidate { has_nested: false }` to anything else.
2011-
// This is a fix for #53123 and prevents winnowing from accidentally extending the
2012-
// lifetime of a variable.
2013-
BuiltinCandidate { has_nested: false } => false,
2017+
// (*)
2018+
BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => false,
20142019
ImplCandidate(..)
20152020
| ClosureCandidate
20162021
| GeneratorCandidate
@@ -2038,10 +2043,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
20382043
when there are other valid candidates"
20392044
);
20402045
}
2041-
// Prefer `BuiltinCandidate { has_nested: false }` to anything else.
2042-
// This is a fix for #53123 and prevents winnowing from accidentally extending the
2043-
// lifetime of a variable.
2044-
BuiltinCandidate { has_nested: false } => false,
2046+
// (*)
2047+
BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => false,
20452048
ImplCandidate(..)
20462049
| ClosureCandidate
20472050
| GeneratorCandidate
@@ -2486,6 +2489,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
24862489
Ok(VtableFnPointer(data))
24872490
}
24882491

2492+
DiscriminantKindCandidate => Ok(VtableDiscriminantKind(VtableDiscriminantKindData)),
2493+
24892494
TraitAliasCandidate(alias_def_id) => {
24902495
let data = self.confirm_trait_alias_candidate(obligation, alias_def_id);
24912496
Ok(VtableTraitAlias(data))

src/librustc_ty/instance.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,10 @@ fn resolve_associated_item<'tcx>(
236236
None
237237
}
238238
}
239-
traits::VtableAutoImpl(..) | traits::VtableParam(..) | traits::VtableTraitAlias(..) => None,
239+
traits::VtableAutoImpl(..)
240+
| traits::VtableParam(..)
241+
| traits::VtableTraitAlias(..)
242+
| traits::VtableDiscriminantKind(..) => None,
240243
})
241244
}
242245

src/librustc_typeck/coherence/mod.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,20 @@ fn enforce_trait_manually_implementable(
4848
let did = Some(trait_def_id);
4949
let li = tcx.lang_items();
5050

51-
// Disallow *all* explicit impls of `Sized` and `Unsize` for now.
51+
// Disallow *all* explicit impls of `DiscriminantKind`, `Sized` and `Unsize` for now.
52+
if did == li.discriminant_kind_trait() {
53+
let span = impl_header_span(tcx, impl_def_id);
54+
struct_span_err!(
55+
tcx.sess,
56+
span,
57+
E0322,
58+
"explicit impls for the `DiscriminantKind` trait are not permitted"
59+
)
60+
.span_label(span, "impl of 'DiscriminantKind' not allowed")
61+
.emit();
62+
return;
63+
}
64+
5265
if did == li.sized_trait() {
5366
let span = impl_header_span(tcx, impl_def_id);
5467
struct_span_err!(

0 commit comments

Comments
 (0)