Skip to content

Commit

Permalink
Add ptr::Pointee trait (for all types) and ptr::metadata function
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonSapin committed Feb 15, 2021
1 parent 9503ea1 commit 696b239
Show file tree
Hide file tree
Showing 17 changed files with 349 additions and 10 deletions.
4 changes: 4 additions & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,10 @@ language_item_table! {
// The associated item of `trait DiscriminantKind`.
Discriminant, sym::discriminant_type, discriminant_type, Target::AssocTy;

PointeeTrait, sym::pointee_trait, pointee_trait, Target::Trait;
Metadata, sym::metadata_type, metadata_type, Target::AssocTy;
DynMetadata, sym::dyn_metadata, dyn_metadata, Target::Struct;

Freeze, sym::freeze, freeze_trait, Target::Trait;

Drop, sym::drop, drop_trait, Target::Trait;
Expand Down
15 changes: 13 additions & 2 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,9 @@ pub enum ImplSource<'tcx, N> {
/// ImplSource for a builtin `DeterminantKind` trait implementation.
DiscriminantKind(ImplSourceDiscriminantKindData),

/// ImplSource for a builtin `Pointee` trait implementation.
Pointee(ImplSourcePointeeData),

/// ImplSource automatically generated for a generator.
Generator(ImplSourceGeneratorData<'tcx, N>),

Expand All @@ -494,7 +497,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
ImplSource::Generator(c) => c.nested,
ImplSource::Object(d) => d.nested,
ImplSource::FnPointer(d) => d.nested,
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => Vec::new(),
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
| ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
ImplSource::TraitAlias(d) => d.nested,
}
}
Expand All @@ -509,7 +513,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
ImplSource::Generator(c) => &c.nested[..],
ImplSource::Object(d) => &d.nested[..],
ImplSource::FnPointer(d) => &d.nested[..],
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => &[],
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
| ImplSource::Pointee(ImplSourcePointeeData) => &[],
ImplSource::TraitAlias(d) => &d.nested[..],
}
}
Expand Down Expand Up @@ -554,6 +559,9 @@ impl<'tcx, N> ImplSource<'tcx, N> {
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => {
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
}
ImplSource::Pointee(ImplSourcePointeeData) => {
ImplSource::Pointee(ImplSourcePointeeData)
}
ImplSource::TraitAlias(d) => ImplSource::TraitAlias(ImplSourceTraitAliasData {
alias_def_id: d.alias_def_id,
substs: d.substs,
Expand Down Expand Up @@ -632,6 +640,9 @@ pub struct ImplSourceFnPointerData<'tcx, N> {
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
pub struct ImplSourceDiscriminantKindData;

#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
pub struct ImplSourcePointeeData;

#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
pub struct ImplSourceTraitAliasData<'tcx, N> {
pub alias_def_id: DefId,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_middle/src/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ pub enum SelectionCandidate<'tcx> {
/// Builtin implementation of `DiscriminantKind`.
DiscriminantKindCandidate,

/// Builtin implementation of `Pointee`.
PointeeCandidate,

TraitAliasCandidate(DefId),

/// Matching `dyn Trait` with a supertrait of `Trait`. The index is the
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_middle/src/traits/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {

super::ImplSource::DiscriminantKind(ref d) => write!(f, "{:?}", d),

super::ImplSource::Pointee(ref d) => write!(f, "{:?}", d),

super::ImplSource::Object(ref d) => write!(f, "{:?}", d),

super::ImplSource::Param(ref n, ct) => {
Expand Down Expand Up @@ -110,4 +112,5 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx,
TrivialTypeFoldableAndLiftImpls! {
super::IfExpressionCause,
super::ImplSourceDiscriminantKindData,
super::ImplSourcePointeeData,
}
45 changes: 45 additions & 0 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2133,6 +2133,51 @@ impl<'tcx> TyS<'tcx> {
}
}

/// Returns the type of metadata for (potentially fat) pointers to this type.
pub fn ptr_metadata_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
// FIXME: should this normalize?
let tail = tcx.struct_tail_without_normalization(self);
match tail.kind() {
// Sized types
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Uint(_)
| ty::Int(_)
| ty::Bool
| ty::Float(_)
| ty::FnDef(..)
| ty::FnPtr(_)
| ty::RawPtr(..)
| ty::Char
| ty::Ref(..)
| ty::Generator(..)
| ty::GeneratorWitness(..)
| ty::Array(..)
| ty::Closure(..)
| ty::Never
| ty::Error(_)
| ty::Foreign(..)
// If returned by `struct_tail_without_normalization` this is a unit struct
// without any fields, or not a struct, and therefore is Sized.
| ty::Adt(..)
// If returned by `struct_tail_without_normalization` this is the empty tuple,
// a.k.a. unit type, which is Sized
| ty::Tuple(..) => tcx.types.unit,

ty::Str | ty::Slice(_) => tcx.types.usize,
ty::Dynamic(..) => tcx.type_of(tcx.lang_items().dyn_metadata().unwrap()),

ty::Projection(_)
| ty::Param(_)
| ty::Opaque(..)
| ty::Infer(ty::TyVar(_))
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("`ptr_metadata_ty` applied to unexpected type: {:?}", tail)
}
}
}

/// When we create a closure, we record its kind (i.e., what trait
/// it implements) into its `ClosureSubsts` using a type
/// parameter. This is kind of a phantom type, except that the
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@ symbols! {
dropck_eyepatch,
dropck_parametricity,
dylib,
dyn_metadata,
dyn_trait,
edition_macro_pats,
eh_catch_typeinfo,
Expand Down Expand Up @@ -710,6 +711,7 @@ symbols! {
memory,
message,
meta,
metadata_type,
min_align_of,
min_align_of_val,
min_const_fn,
Expand Down Expand Up @@ -832,6 +834,7 @@ symbols! {
plugin,
plugin_registrar,
plugins,
pointee_trait,
pointer,
pointer_trait,
pointer_trait_fmt,
Expand Down
68 changes: 67 additions & 1 deletion compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use super::SelectionContext;
use super::SelectionError;
use super::{
ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData,
ImplSourceGeneratorData, ImplSourceUserDefinedData,
ImplSourceGeneratorData, ImplSourcePointeeData, ImplSourceUserDefinedData,
};
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};

Expand Down Expand Up @@ -1069,6 +1069,51 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
| ty::Error(_) => false,
}
}
super::ImplSource::Pointee(..) => {
// While `Pointee` is automatically implemented for every type,
// the concrete metadata type may not be known yet.
//
// Any type with multiple potential metadata types is therefore not eligible.
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());

// FIXME: should this normalize?
let tail = selcx.tcx().struct_tail_without_normalization(self_ty);
match tail.kind() {
ty::Bool
| ty::Char
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| 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
// If returned by `struct_tail_without_normalization` this is a unit struct
// without any fields, or not a struct, and therefore is Sized.
| ty::Adt(..)
// If returned by `struct_tail_without_normalization` this is the empty tuple.
| ty::Tuple(..)
// Integers and floats are always Sized, and so have unit type metadata.
| 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::ImplSource::Param(..) => {
// This case tell us nothing about the value of an
// associated type. Consider:
Expand Down Expand Up @@ -1169,6 +1214,7 @@ fn confirm_select_candidate<'cx, 'tcx>(
super::ImplSource::DiscriminantKind(data) => {
confirm_discriminant_kind_candidate(selcx, obligation, data)
}
super::ImplSource::Pointee(data) => confirm_pointee_candidate(selcx, obligation, data),
super::ImplSource::Object(_)
| super::ImplSource::AutoImpl(..)
| super::ImplSource::Param(..)
Expand Down Expand Up @@ -1256,6 +1302,26 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
}

fn confirm_pointee_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
_: ImplSourcePointeeData,
) -> 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 metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);

let predicate = ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy { substs, item_def_id: metadata_def_id },
ty: self_ty.ptr_metadata_ty(tcx),
};

confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate), false)
}

fn confirm_fn_pointer_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} 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.pointee_trait() == Some(def_id) {
// `Pointee` is automatically implemented for every type.
candidates.vec.push(PointeeCandidate);
} else if lang_items.sized_trait() == Some(def_id) {
// Sized is never implementable by end-users, it is
// always automatically computed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation};
use crate::traits::{
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData,
ImplSourceObjectData, ImplSourceTraitAliasData, ImplSourceUserDefinedData,
ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
ImplSourceUserDefinedData,
};
use crate::traits::{ObjectCastObligation, PredicateObligation, TraitObligation};
use crate::traits::{Obligation, ObligationCause};
Expand Down Expand Up @@ -99,6 +100,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Ok(ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData))
}

PointeeCandidate => Ok(ImplSource::Pointee(ImplSourcePointeeData)),

TraitAliasCandidate(alias_def_id) => {
let data = self.confirm_trait_alias_candidate(obligation, alias_def_id);
Ok(ImplSource::TraitAlias(data))
Expand Down
18 changes: 14 additions & 4 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1318,8 +1318,8 @@ 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.
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
// and `DiscriminantKindCandidate` to anything else.
//
// This is a fix for #53123 and prevents winnowing from accidentally extending the
// lifetime of a variable.
Expand All @@ -1332,8 +1332,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}

// (*)
(BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate, _) => true,
(_, BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate) => false,
(
BuiltinCandidate { has_nested: false }
| DiscriminantKindCandidate
| PointeeCandidate,
_,
) => true,
(
_,
BuiltinCandidate { has_nested: false }
| DiscriminantKindCandidate
| PointeeCandidate,
) => false,

(ParamCandidate(other), ParamCandidate(victim)) => {
if other.value == victim.value && victim.constness == Constness::NotConst {
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_ty_utils/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,8 @@ fn resolve_associated_item<'tcx>(
traits::ImplSource::AutoImpl(..)
| traits::ImplSource::Param(..)
| traits::ImplSource::TraitAlias(..)
| traits::ImplSource::DiscriminantKind(..) => None,
| traits::ImplSource::DiscriminantKind(..)
| traits::ImplSource::Pointee(..) => None,
})
}

Expand Down
15 changes: 14 additions & 1 deletion compiler/rustc_typeck/src/coherence/mod.rs
Original file line number Diff line number Diff line change
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 `DiscriminantKind`, `Sized` and `Unsize` for now.
// Disallow *all* explicit impls of `Pointee`, `DiscriminantKind`, `Sized` and `Unsize` for now.
if did == li.pointee_trait() {
let span = impl_header_span(tcx, impl_def_id);
struct_span_err!(
tcx.sess,
span,
E0322,
"explicit impls for the `Pointee` trait are not permitted"
)
.span_label(span, "impl of 'Pointee' not allowed")
.emit();
return;
}

if did == li.discriminant_kind_trait() {
let span = impl_header_span(tcx, impl_def_id);
struct_span_err!(
Expand Down
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
#![feature(stmt_expr_attributes)]
#![feature(str_split_as_str)]
#![feature(str_split_inclusive_as_str)]
#![feature(trait_alias)]
#![feature(transparent_unions)]
#![feature(try_blocks)]
#![feature(unboxed_closures)]
Expand Down
Loading

0 comments on commit 696b239

Please sign in to comment.