mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Rollup merge of #142339 - oli-obk:not-null-pattern-types, r=BoxyUwU
Add NonNull pattern types These are the final piece missing for * https://github.com/rust-lang/rust/pull/136006 We cannot use the previous scheme of using an integer range for raw pointers, as we're not just changing the layout of raw pointers anymore, but also the type representation. And we can't represent "any provenance or NonZero<usize>" natively as patterns. So I created a new `!null` pattern. Since this is all unstable representation stuff for replacing rustc_layout_scalar_range_start with pattern types, the divergence from normal patterns is fine, especially since T-lang seems interested in exploring general negation patterns r? `@BoxyUwU`
This commit is contained in:
@@ -2579,6 +2579,9 @@ pub enum TyPatKind {
|
||||
/// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`).
|
||||
Range(Option<Box<AnonConst>>, Option<Box<AnonConst>>, Spanned<RangeEnd>),
|
||||
|
||||
/// A `!null` pattern for raw pointers.
|
||||
NotNull,
|
||||
|
||||
Or(ThinVec<TyPat>),
|
||||
|
||||
/// Placeholder for a pattern that wasn't syntactically well formed in some way.
|
||||
|
||||
@@ -143,7 +143,9 @@ fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> {
|
||||
}
|
||||
// return inner to be processed in next loop
|
||||
PatKind::Paren(inner) => pattern = inner,
|
||||
PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span),
|
||||
PatKind::MacCall(_) => {
|
||||
panic!("{pattern:#?} shouldn't exist here")
|
||||
}
|
||||
PatKind::Err(guar) => break hir::PatKind::Err(*guar),
|
||||
}
|
||||
};
|
||||
@@ -460,6 +462,7 @@ fn lower_ty_pat_mut(&mut self, pattern: &TyPat, base_type: Span) -> hir::TyPat<'
|
||||
)
|
||||
}),
|
||||
),
|
||||
TyPatKind::NotNull => hir::TyPatKind::NotNull,
|
||||
TyPatKind::Or(variants) => {
|
||||
hir::TyPatKind::Or(self.arena.alloc_from_iter(
|
||||
variants.iter().map(|pat| self.lower_ty_pat_mut(pat, base_type)),
|
||||
|
||||
@@ -1232,6 +1232,7 @@ pub fn print_ty_pat(&mut self, pat: &ast::TyPat) {
|
||||
self.print_expr_anon_const(end, &[]);
|
||||
}
|
||||
}
|
||||
rustc_ast::TyPatKind::NotNull => self.word("!null"),
|
||||
rustc_ast::TyPatKind::Or(variants) => {
|
||||
let mut first = true;
|
||||
for pat in variants {
|
||||
|
||||
@@ -30,15 +30,21 @@ fn parse_pat_ty<'a>(
|
||||
let ty = parser.parse_ty()?;
|
||||
parser.expect_keyword(exp!(Is))?;
|
||||
|
||||
let pat = pat_to_ty_pat(
|
||||
cx,
|
||||
parser.parse_pat_no_top_guard(
|
||||
None,
|
||||
RecoverComma::No,
|
||||
RecoverColon::No,
|
||||
CommaRecoveryMode::EitherTupleOrPipe,
|
||||
)?,
|
||||
);
|
||||
let start = parser.token.span;
|
||||
let pat = if parser.eat(exp!(Bang)) {
|
||||
parser.expect_keyword(exp!(Null))?;
|
||||
ty_pat(TyPatKind::NotNull, start.to(parser.token.span))
|
||||
} else {
|
||||
pat_to_ty_pat(
|
||||
cx,
|
||||
parser.parse_pat_no_top_guard(
|
||||
None,
|
||||
RecoverComma::No,
|
||||
RecoverColon::No,
|
||||
CommaRecoveryMode::EitherTupleOrPipe,
|
||||
)?,
|
||||
)
|
||||
};
|
||||
|
||||
if parser.token != token::Eof {
|
||||
parser.unexpected()?;
|
||||
|
||||
@@ -131,6 +131,11 @@ pub(crate) fn coerce_unsized_into<'tcx>(
|
||||
dst.write_cvalue(fx, CValue::by_val_pair(base, info, dst.layout()));
|
||||
};
|
||||
match (&src_ty.kind(), &dst_ty.kind()) {
|
||||
(ty::Pat(a, _), ty::Pat(b, _)) => {
|
||||
let src = src.cast_pat_ty_to_base(fx.layout_of(*a));
|
||||
let dst = dst.place_transmute_type(fx, *b);
|
||||
return coerce_unsized_into(fx, src, dst);
|
||||
}
|
||||
(&ty::Ref(..), &ty::Ref(..))
|
||||
| (&ty::Ref(..), &ty::RawPtr(..))
|
||||
| (&ty::RawPtr(..), &ty::RawPtr(..)) => coerce_ptr(),
|
||||
|
||||
@@ -342,6 +342,14 @@ pub(crate) fn cast_pointer_to(self, layout: TyAndLayout<'tcx>) -> Self {
|
||||
assert_eq!(self.layout().backend_repr, layout.backend_repr);
|
||||
CValue(self.0, layout)
|
||||
}
|
||||
|
||||
pub(crate) fn cast_pat_ty_to_base(self, layout: TyAndLayout<'tcx>) -> Self {
|
||||
let ty::Pat(base, _) = *self.layout().ty.kind() else {
|
||||
panic!("not a pattern type: {:#?}", self.layout())
|
||||
};
|
||||
assert_eq!(layout.ty, base);
|
||||
CValue(self.0, layout)
|
||||
}
|
||||
}
|
||||
|
||||
/// A place where you can write a value to or read a value from
|
||||
|
||||
@@ -228,6 +228,7 @@ pub(crate) fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
) -> (Bx::Value, Bx::Value) {
|
||||
debug!("unsize_ptr: {:?} => {:?}", src_ty, dst_ty);
|
||||
match (src_ty.kind(), dst_ty.kind()) {
|
||||
(&ty::Pat(a, _), &ty::Pat(b, _)) => unsize_ptr(bx, src, a, b, old_info),
|
||||
(&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _))
|
||||
| (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => {
|
||||
assert_eq!(bx.cx().type_is_sized(a), old_info.is_none());
|
||||
|
||||
@@ -466,6 +466,12 @@ pub fn unsize_into(
|
||||
) -> InterpResult<'tcx> {
|
||||
trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty);
|
||||
match (src.layout.ty.kind(), cast_ty.ty.kind()) {
|
||||
(&ty::Pat(_, s_pat), &ty::Pat(cast_ty, c_pat)) if s_pat == c_pat => {
|
||||
let src = self.project_field(src, FieldIdx::ZERO)?;
|
||||
let dest = self.project_field(dest, FieldIdx::ZERO)?;
|
||||
let cast_ty = self.layout_of(cast_ty)?;
|
||||
self.unsize_into(&src, cast_ty, &dest)
|
||||
}
|
||||
(&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(c, _))
|
||||
| (&ty::RawPtr(s, _), &ty::RawPtr(c, _)) => self.unsize_into_ptr(src, dest, s, c),
|
||||
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
|
||||
|
||||
@@ -1261,9 +1261,10 @@ fn visit_value(&mut self, val: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'t
|
||||
// When you extend this match, make sure to also add tests to
|
||||
// tests/ui/type/pattern_types/validity.rs((
|
||||
match **pat {
|
||||
// Range patterns are precisely reflected into `valid_range` and thus
|
||||
// Range and non-null patterns are precisely reflected into `valid_range` and thus
|
||||
// handled fully by `visit_scalar` (called below).
|
||||
ty::PatternKind::Range { .. } => {},
|
||||
ty::PatternKind::NotNull => {},
|
||||
|
||||
// FIXME(pattern_types): check that the value is covered by one of the variants.
|
||||
// For now, we rely on layout computation setting the scalar's `valid_range` to
|
||||
|
||||
@@ -1854,6 +1854,9 @@ pub enum TyPatKind<'hir> {
|
||||
/// A range pattern (e.g., `1..=2` or `1..2`).
|
||||
Range(&'hir ConstArg<'hir>, &'hir ConstArg<'hir>),
|
||||
|
||||
/// A pattern that excludes null pointers
|
||||
NotNull,
|
||||
|
||||
/// A list of patterns where only one needs to be satisfied
|
||||
Or(&'hir [TyPat<'hir>]),
|
||||
|
||||
|
||||
@@ -725,7 +725,7 @@ pub fn walk_ty_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v TyPat<'v>)
|
||||
try_visit!(visitor.visit_const_arg_unambig(upper_bound));
|
||||
}
|
||||
TyPatKind::Or(patterns) => walk_list!(visitor, visit_pattern_type_pattern, patterns),
|
||||
TyPatKind::Err(_) => (),
|
||||
TyPatKind::NotNull | TyPatKind::Err(_) => (),
|
||||
}
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
@@ -103,6 +103,8 @@ hir_analysis_coerce_pointee_not_struct = `derive(CoercePointee)` is only applica
|
||||
|
||||
hir_analysis_coerce_pointee_not_transparent = `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout
|
||||
|
||||
hir_analysis_coerce_same_pat_kind = only pattern types with the same pattern can be coerced between each other
|
||||
|
||||
hir_analysis_coerce_unsized_field_validity = for `{$ty}` to have a valid implementation of `{$trait_name}`, it must be possible to coerce the field of type `{$field_ty}`
|
||||
.label = `{$field_ty}` must be a pointer, reference, or smart pointer that is allowed to be unsized
|
||||
|
||||
|
||||
@@ -243,6 +243,18 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
|
||||
// in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent)
|
||||
// even if they do not carry that attribute.
|
||||
match (source.kind(), target.kind()) {
|
||||
(&ty::Pat(_, pat_a), &ty::Pat(_, pat_b)) => {
|
||||
if pat_a != pat_b {
|
||||
return Err(tcx.dcx().emit_err(errors::CoerceSamePatKind {
|
||||
span,
|
||||
trait_name,
|
||||
pat_a: pat_a.to_string(),
|
||||
pat_b: pat_b.to_string(),
|
||||
}));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
(&ty::Ref(r_a, _, mutbl_a), ty::Ref(r_b, _, mutbl_b))
|
||||
if r_a == *r_b && mutbl_a == *mutbl_b =>
|
||||
{
|
||||
@@ -408,6 +420,18 @@ pub(crate) fn coerce_unsized_info<'tcx>(
|
||||
(mt_a.ty, mt_b.ty, unsize_trait, None, span)
|
||||
};
|
||||
let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) {
|
||||
(&ty::Pat(ty_a, pat_a), &ty::Pat(ty_b, pat_b)) => {
|
||||
if pat_a != pat_b {
|
||||
return Err(tcx.dcx().emit_err(errors::CoerceSamePatKind {
|
||||
span,
|
||||
trait_name,
|
||||
pat_a: pat_a.to_string(),
|
||||
pat_b: pat_b.to_string(),
|
||||
}));
|
||||
}
|
||||
(ty_a, ty_b, coerce_unsized_trait, None, span)
|
||||
}
|
||||
|
||||
(&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
|
||||
infcx.sub_regions(SubregionOrigin::RelateObjectBound(span), r_b, r_a);
|
||||
let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
|
||||
|
||||
@@ -206,12 +206,8 @@ enum NonlocalImpl {
|
||||
(LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther)
|
||||
}
|
||||
|
||||
ty::Pat(..) => (
|
||||
LocalImpl::Disallow { problematic_kind: "pattern type" },
|
||||
NonlocalImpl::DisallowOther,
|
||||
),
|
||||
|
||||
ty::Bool
|
||||
| ty::Pat(..)
|
||||
| ty::Char
|
||||
| ty::Int(..)
|
||||
| ty::Uint(..)
|
||||
|
||||
@@ -1258,6 +1258,16 @@ pub(crate) struct CoerceUnsizedNonStruct {
|
||||
pub trait_name: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_coerce_same_pat_kind)]
|
||||
pub(crate) struct CoerceSamePatKind {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub trait_name: &'static str,
|
||||
pub pat_a: String,
|
||||
pub pat_b: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_coerce_unsized_may, code = E0377)]
|
||||
pub(crate) struct CoerceSameStruct {
|
||||
|
||||
@@ -2611,6 +2611,7 @@ fn lower_pat_ty_pat(
|
||||
.span_delayed_bug(ty_span, "invalid base type for range pattern")),
|
||||
}
|
||||
}
|
||||
hir::TyPatKind::NotNull => Ok(ty::PatternKind::NotNull),
|
||||
hir::TyPatKind::Or(patterns) => {
|
||||
self.tcx()
|
||||
.mk_patterns_from_iter(patterns.iter().map(|pat| {
|
||||
|
||||
@@ -340,6 +340,7 @@ fn add_constraints_from_pat(
|
||||
self.add_constraints_from_const(current, start, variance);
|
||||
self.add_constraints_from_const(current, end, variance);
|
||||
}
|
||||
ty::PatternKind::NotNull => {}
|
||||
ty::PatternKind::Or(patterns) => {
|
||||
for pat in patterns {
|
||||
self.add_constraints_from_pat(current, variance, pat)
|
||||
|
||||
@@ -1888,6 +1888,10 @@ fn print_ty_pat(&mut self, pat: &hir::TyPat<'_>) {
|
||||
self.word("..=");
|
||||
self.print_const_arg(end);
|
||||
}
|
||||
TyPatKind::NotNull => {
|
||||
self.word_space("not");
|
||||
self.word("null");
|
||||
}
|
||||
TyPatKind::Or(patterns) => {
|
||||
self.popen();
|
||||
let mut first = true;
|
||||
|
||||
@@ -758,6 +758,7 @@ fn pat_ty_is_known_nonnull<'tcx>(
|
||||
// to ensure we aren't wrapping over zero.
|
||||
start > 0 && end >= start
|
||||
}
|
||||
ty::PatternKind::NotNull => true,
|
||||
ty::PatternKind::Or(patterns) => {
|
||||
patterns.iter().all(|pat| pat_ty_is_known_nonnull(tcx, typing_env, pat))
|
||||
}
|
||||
@@ -918,7 +919,9 @@ fn get_nullable_type_from_pat<'tcx>(
|
||||
pat: ty::Pattern<'tcx>,
|
||||
) -> Option<Ty<'tcx>> {
|
||||
match *pat {
|
||||
ty::PatternKind::Range { .. } => get_nullable_type(tcx, typing_env, base),
|
||||
ty::PatternKind::NotNull | ty::PatternKind::Range { .. } => {
|
||||
get_nullable_type(tcx, typing_env, base)
|
||||
}
|
||||
ty::PatternKind::Or(patterns) => {
|
||||
let first = get_nullable_type_from_pat(tcx, typing_env, base, patterns[0])?;
|
||||
for &pat in &patterns[1..] {
|
||||
|
||||
@@ -160,6 +160,9 @@ pub enum SelectionCandidate<'tcx> {
|
||||
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
|
||||
FnPointerCandidate,
|
||||
|
||||
/// Builtin impl of the `PointerLike` trait.
|
||||
PointerLikeCandidate,
|
||||
|
||||
TraitAliasCandidate,
|
||||
|
||||
/// Matching `dyn Trait` with a supertrait of `Trait`. The index is the
|
||||
|
||||
@@ -839,11 +839,15 @@ fn field_ty_or_layout<'tcx>(
|
||||
| ty::FnDef(..)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Foreign(..)
|
||||
| ty::Pat(_, _)
|
||||
| ty::Dynamic(_, _) => {
|
||||
bug!("TyAndLayout::field({:?}): not applicable", this)
|
||||
}
|
||||
|
||||
ty::Pat(base, _) => {
|
||||
assert_eq!(i, 0);
|
||||
TyMaybeWithLayout::Ty(base)
|
||||
}
|
||||
|
||||
ty::UnsafeBinder(bound_ty) => {
|
||||
let ty = tcx.instantiate_bound_regions_with_erased(bound_ty.into());
|
||||
field_ty_or_layout(TyAndLayout { ty, ..this }, cx, i)
|
||||
|
||||
@@ -30,6 +30,7 @@ fn flags(&self) -> rustc_type_ir::TypeFlags {
|
||||
}
|
||||
flags
|
||||
}
|
||||
ty::PatternKind::NotNull => rustc_type_ir::TypeFlags::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +46,7 @@ fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex {
|
||||
}
|
||||
idx
|
||||
}
|
||||
ty::PatternKind::NotNull => rustc_type_ir::INNERMOST,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,6 +93,7 @@ fn print(t: &PatternKind<'tcx>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
||||
write!(f, "..={end}")
|
||||
}
|
||||
PatternKind::NotNull => write!(f, "!null"),
|
||||
PatternKind::Or(patterns) => {
|
||||
write!(f, "(")?;
|
||||
let mut first = true;
|
||||
|
||||
@@ -35,6 +35,7 @@ fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
|
||||
let end = relation.relate(end_a, end_b)?;
|
||||
Ok(tcx.mk_pat(ty::PatternKind::Range { start, end }))
|
||||
}
|
||||
(ty::PatternKind::NotNull, ty::PatternKind::NotNull) => Ok(a),
|
||||
(&ty::PatternKind::Or(a), &ty::PatternKind::Or(b)) => {
|
||||
if a.len() != b.len() {
|
||||
return Err(TypeError::Mismatch);
|
||||
@@ -43,7 +44,10 @@ fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
|
||||
let patterns = tcx.mk_patterns_from_iter(v)?;
|
||||
Ok(tcx.mk_pat(ty::PatternKind::Or(patterns)))
|
||||
}
|
||||
(ty::PatternKind::Range { .. } | ty::PatternKind::Or(_), _) => Err(TypeError::Mismatch),
|
||||
(
|
||||
ty::PatternKind::NotNull | ty::PatternKind::Range { .. } | ty::PatternKind::Or(_),
|
||||
_,
|
||||
) => Err(TypeError::Mismatch),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -695,6 +695,8 @@ fn visit_projection_elem(
|
||||
};
|
||||
check_equal(self, location, *f_ty);
|
||||
}
|
||||
// Debug info is allowed to project into pattern types
|
||||
ty::Pat(base, _) => check_equal(self, location, *base),
|
||||
ty::Adt(adt_def, args) => {
|
||||
// see <https://github.com/rust-lang/rust/blob/7601adcc764d42c9f2984082b49948af652df986/compiler/rustc_middle/src/ty/layout.rs#L861-L864>
|
||||
if self.tcx.is_lang_item(adt_def.did(), LangItem::DynMetadata) {
|
||||
|
||||
@@ -1145,6 +1145,7 @@ fn find_tails_for_unsizing<'tcx>(
|
||||
debug_assert!(!target_ty.has_param(), "{target_ty} should be fully monomorphic");
|
||||
|
||||
match (source_ty.kind(), target_ty.kind()) {
|
||||
(&ty::Pat(source, _), &ty::Pat(target, _)) => find_tails_for_unsizing(tcx, source, target),
|
||||
(
|
||||
&ty::Ref(_, source_pointee, _),
|
||||
&ty::Ref(_, target_pointee, _) | &ty::RawPtr(target_pointee, _),
|
||||
|
||||
@@ -139,6 +139,7 @@ pub enum TokenType {
|
||||
SymNomem,
|
||||
SymNoreturn,
|
||||
SymNostack,
|
||||
SymNull,
|
||||
SymOptions,
|
||||
SymOut,
|
||||
SymPreservesFlags,
|
||||
@@ -273,6 +274,7 @@ fn from_u32(val: u32) -> TokenType {
|
||||
SymNomem,
|
||||
SymNoreturn,
|
||||
SymNostack,
|
||||
SymNull,
|
||||
SymOptions,
|
||||
SymOut,
|
||||
SymPreservesFlags,
|
||||
@@ -348,6 +350,7 @@ pub(super) fn is_keyword(&self) -> Option<Symbol> {
|
||||
TokenType::SymNomem => Some(sym::nomem),
|
||||
TokenType::SymNoreturn => Some(sym::noreturn),
|
||||
TokenType::SymNostack => Some(sym::nostack),
|
||||
TokenType::SymNull => Some(sym::null),
|
||||
TokenType::SymOptions => Some(sym::options),
|
||||
TokenType::SymOut => Some(sym::out),
|
||||
TokenType::SymPreservesFlags => Some(sym::preserves_flags),
|
||||
@@ -562,6 +565,7 @@ macro_rules! exp {
|
||||
(Nomem) => { exp!(@sym, nomem, SymNomem) };
|
||||
(Noreturn) => { exp!(@sym, noreturn, SymNoreturn) };
|
||||
(Nostack) => { exp!(@sym, nostack, SymNostack) };
|
||||
(Null) => { exp!(@sym, null, SymNull) };
|
||||
(Options) => { exp!(@sym, options, SymOptions) };
|
||||
(Out) => { exp!(@sym, out, SymOut) };
|
||||
(PreservesFlags) => { exp!(@sym, preserves_flags, SymPreservesFlags) };
|
||||
|
||||
@@ -485,6 +485,7 @@ fn stable<'cx>(
|
||||
end: Some(end.stable(tables, cx)),
|
||||
include_end: true,
|
||||
},
|
||||
ty::PatternKind::NotNull => todo!(),
|
||||
ty::PatternKind::Or(_) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -968,7 +968,7 @@ fn visit_ty_pat(&mut self, t: &'ast TyPat) -> Self::Result {
|
||||
self.visit_ty_pat(pat)
|
||||
}
|
||||
}
|
||||
TyPatKind::Err(_) => {}
|
||||
TyPatKind::NotNull | TyPatKind::Err(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1554,6 +1554,7 @@
|
||||
not,
|
||||
notable_trait,
|
||||
note,
|
||||
null,
|
||||
nvptx_target_feature,
|
||||
object_safe_for_dispatch,
|
||||
of,
|
||||
|
||||
@@ -266,6 +266,9 @@ fn print_pat(&mut self, pat: ty::Pattern<'tcx>) -> Result<(), std::fmt::Error> {
|
||||
self.print_const(start)?;
|
||||
self.print_const(end)?;
|
||||
}
|
||||
ty::PatternKind::NotNull => {
|
||||
self.tcx.types.unit.print(self)?;
|
||||
}
|
||||
ty::PatternKind::Or(patterns) => {
|
||||
self.push("O");
|
||||
for pat in patterns {
|
||||
|
||||
@@ -115,6 +115,11 @@ pub(super) fn confirm_candidate(
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
||||
}
|
||||
|
||||
PointerLikeCandidate => {
|
||||
let data = self.confirm_pointer_like_candidate(obligation);
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
||||
}
|
||||
|
||||
TraitAliasCandidate => {
|
||||
let data = self.confirm_trait_alias_candidate(obligation);
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
||||
@@ -631,6 +636,25 @@ fn confirm_fn_pointer_candidate(
|
||||
Ok(nested)
|
||||
}
|
||||
|
||||
fn confirm_pointer_like_candidate(
|
||||
&mut self,
|
||||
obligation: &PolyTraitObligation<'tcx>,
|
||||
) -> PredicateObligations<'tcx> {
|
||||
debug!(?obligation, "confirm_pointer_like_candidate");
|
||||
let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
|
||||
let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
|
||||
let ty::Pat(base, _) = *self_ty.kind() else { bug!() };
|
||||
let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
|
||||
|
||||
self.collect_predicates_for_types(
|
||||
obligation.param_env,
|
||||
cause,
|
||||
obligation.recursion_depth + 1,
|
||||
placeholder_predicate.def_id(),
|
||||
vec![base],
|
||||
)
|
||||
}
|
||||
|
||||
fn confirm_trait_alias_candidate(
|
||||
&mut self,
|
||||
obligation: &PolyTraitObligation<'tcx>,
|
||||
|
||||
@@ -2036,6 +2036,7 @@ fn winnow_candidates(
|
||||
| TraitUpcastingUnsizeCandidate(_)
|
||||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| PointerLikeCandidate
|
||||
| BikeshedGuaranteedNoDropCandidate => false,
|
||||
// Non-global param candidates have already been handled, global
|
||||
// where-bounds get ignored.
|
||||
|
||||
@@ -705,6 +705,7 @@ fn add_wf_preds_for_pat_ty(&mut self, base_ty: Ty<'tcx>, pat: ty::Pattern<'tcx>)
|
||||
check(start);
|
||||
check(end);
|
||||
}
|
||||
ty::PatternKind::NotNull => {}
|
||||
ty::PatternKind::Or(patterns) => {
|
||||
for pat in patterns {
|
||||
self.add_wf_preds_for_pat_ty(base_ty, pat)
|
||||
|
||||
@@ -216,9 +216,7 @@ fn layout_of_uncached<'tcx>(
|
||||
let mut layout = LayoutData::clone(&layout.0);
|
||||
match *pat {
|
||||
ty::PatternKind::Range { start, end } => {
|
||||
if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) =
|
||||
&mut layout.backend_repr
|
||||
{
|
||||
if let BackendRepr::Scalar(scalar) = &mut layout.backend_repr {
|
||||
scalar.valid_range_mut().start = extract_const_value(cx, ty, start)?
|
||||
.try_to_bits(tcx, cx.typing_env)
|
||||
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
|
||||
@@ -266,6 +264,25 @@ fn layout_of_uncached<'tcx>(
|
||||
bug!("pattern type with range but not scalar layout: {ty:?}, {layout:?}")
|
||||
}
|
||||
}
|
||||
ty::PatternKind::NotNull => {
|
||||
if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) =
|
||||
&mut layout.backend_repr
|
||||
{
|
||||
scalar.valid_range_mut().start = 1;
|
||||
let niche = Niche {
|
||||
offset: Size::ZERO,
|
||||
value: scalar.primitive(),
|
||||
valid_range: scalar.valid_range(cx),
|
||||
};
|
||||
|
||||
layout.largest_niche = Some(niche);
|
||||
} else {
|
||||
bug!(
|
||||
"pattern type with `!null` pattern but not scalar/pair layout: {ty:?}, {layout:?}"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ty::PatternKind::Or(variants) => match *variants[0] {
|
||||
ty::PatternKind::Range { .. } => {
|
||||
if let BackendRepr::Scalar(scalar) = &mut layout.backend_repr {
|
||||
@@ -282,7 +299,7 @@ fn layout_of_uncached<'tcx>(
|
||||
.try_to_bits(tcx, cx.typing_env)
|
||||
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?,
|
||||
)),
|
||||
ty::PatternKind::Or(_) => {
|
||||
ty::PatternKind::NotNull | ty::PatternKind::Or(_) => {
|
||||
unreachable!("mixed or patterns are not allowed")
|
||||
}
|
||||
})
|
||||
@@ -347,9 +364,18 @@ fn layout_of_uncached<'tcx>(
|
||||
)
|
||||
}
|
||||
}
|
||||
ty::PatternKind::NotNull => bug!("or patterns can't contain `!null` patterns"),
|
||||
ty::PatternKind::Or(..) => bug!("patterns cannot have nested or patterns"),
|
||||
},
|
||||
}
|
||||
// Pattern types contain their base as their sole field.
|
||||
// This allows the rest of the compiler to process pattern types just like
|
||||
// single field transparent Adts, and only the parts of the compiler that
|
||||
// specifically care about pattern types will have to handle it.
|
||||
layout.fields = FieldsShape::Arbitrary {
|
||||
offsets: [Size::ZERO].into_iter().collect(),
|
||||
memory_index: [0].into_iter().collect(),
|
||||
};
|
||||
tcx.mk_layout(layout)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
pub enum PatternKind<I: Interner> {
|
||||
Range { start: I::Const, end: I::Const },
|
||||
Or(I::PatList),
|
||||
NotNull,
|
||||
}
|
||||
|
||||
impl<I: Interner> Eq for PatternKind<I> {}
|
||||
|
||||
@@ -178,5 +178,6 @@ fn push_ty_pat<I: Interner>(stack: &mut TypeWalkerStack<I>, pat: I::Pat) {
|
||||
push_ty_pat::<I>(stack, pat)
|
||||
}
|
||||
}
|
||||
ty::PatternKind::NotNull => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,6 +116,7 @@
|
||||
#![feature(link_cfg)]
|
||||
#![feature(offset_of_enum)]
|
||||
#![feature(panic_internals)]
|
||||
#![feature(pattern_type_macro)]
|
||||
#![feature(ptr_alignment_type)]
|
||||
#![feature(ptr_metadata)]
|
||||
#![feature(set_ptr_value)]
|
||||
@@ -171,6 +172,7 @@
|
||||
#![feature(never_type)]
|
||||
#![feature(no_core)]
|
||||
#![feature(optimize_attribute)]
|
||||
#![feature(pattern_types)]
|
||||
#![feature(prelude_import)]
|
||||
#![feature(reborrow)]
|
||||
#![feature(repr_simd)]
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
//! Helper module for exporting the `pattern_type` macro
|
||||
|
||||
use crate::marker::{Freeze, PointeeSized, Unsize};
|
||||
use crate::ops::{CoerceUnsized, DispatchFromDyn};
|
||||
|
||||
/// Creates a pattern type.
|
||||
/// ```ignore (cannot test this from within core yet)
|
||||
/// type Positive = std::pat::pattern_type!(i32 is 1..);
|
||||
@@ -73,3 +76,16 @@ fn sub_one(self) -> Self {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<pattern_type!(*const U is !null)> for pattern_type!(*const T is !null) where
|
||||
T: Unsize<U>
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<pattern_type!(U is !null)> for pattern_type!(T is !null) {}
|
||||
|
||||
impl<T: PointeeSized> Unpin for pattern_type!(*const T is !null) {}
|
||||
|
||||
unsafe impl<T: PointeeSized> Freeze for pattern_type!(*const T is !null) {}
|
||||
|
||||
unsafe impl<T: PointeeSized> Freeze for pattern_type!(*mut T is !null) {}
|
||||
|
||||
@@ -1123,7 +1123,7 @@ pub fn hash_ty_pat(&mut self, pat: &TyPat<'_>) {
|
||||
self.hash_ty_pat(variant);
|
||||
}
|
||||
},
|
||||
TyPatKind::Err(_) => {},
|
||||
TyPatKind::NotNull | TyPatKind::Err(_) => {},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#![feature(pattern_types, pattern_type_macro, sized_hierarchy)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::marker::PointeeSized;
|
||||
use std::mem::transmute;
|
||||
|
||||
pub struct NonNull<T: PointeeSized> {
|
||||
pointer: std::pat::pattern_type!(*const T is !null),
|
||||
}
|
||||
|
||||
trait Trait {}
|
||||
impl Trait for () {}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let _: NonNull<dyn Trait> = NonNull { pointer: transmute(&mut () as *mut dyn Trait) };
|
||||
}
|
||||
}
|
||||
@@ -1099,7 +1099,7 @@ fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteR
|
||||
}
|
||||
Ok(s)
|
||||
}
|
||||
ast::TyPatKind::Err(_) => Err(RewriteError::Unknown),
|
||||
ast::TyPatKind::NotNull | ast::TyPatKind::Err(_) => Err(RewriteError::Unknown),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,4 +10,15 @@
|
||||
type Wild = pattern_type!(() is _);
|
||||
//~^ ERROR: pattern not supported in pattern types
|
||||
|
||||
// FIXME: confusing diagnostic because `not` can be a binding
|
||||
type NonNull = pattern_type!(*const () is not null);
|
||||
//~^ ERROR: expected one of `@` or `|`, found `null`
|
||||
//~| ERROR: pattern not supported in pattern types
|
||||
|
||||
type NonNull2 = pattern_type!(*const () is !nil);
|
||||
//~^ ERROR: expected `null`, found `nil`
|
||||
|
||||
// FIXME: reject with a type mismatch
|
||||
type Mismatch2 = pattern_type!(() is !null);
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -30,6 +30,24 @@ error: pattern not supported in pattern types
|
||||
LL | type Wild = pattern_type!(() is _);
|
||||
| ^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: pattern not supported in pattern types
|
||||
--> $DIR/bad_pat.rs:14:43
|
||||
|
|
||||
LL | type NonNull = pattern_type!(*const () is not null);
|
||||
| ^^^
|
||||
|
||||
error: expected one of `@` or `|`, found `null`
|
||||
--> $DIR/bad_pat.rs:14:47
|
||||
|
|
||||
LL | type NonNull = pattern_type!(*const () is not null);
|
||||
| ^^^^ expected one of `@` or `|`
|
||||
|
||||
error: expected `null`, found `nil`
|
||||
--> $DIR/bad_pat.rs:18:45
|
||||
|
|
||||
LL | type NonNull2 = pattern_type!(*const () is !nil);
|
||||
| ^^^ expected `null`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0586`.
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
//! Show that pattern-types non-null is the same as libstd's
|
||||
|
||||
//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED"
|
||||
//@ only-64bit
|
||||
|
||||
#![feature(pattern_type_macro, pattern_types, rustc_attrs)]
|
||||
|
||||
use std::pat::pattern_type;
|
||||
|
||||
#[rustc_layout(debug)]
|
||||
type NonNull<T> = pattern_type!(*const T is !null); //~ ERROR layout_of
|
||||
|
||||
#[rustc_layout(debug)]
|
||||
type Test = Option<NonNull<()>>; //~ ERROR layout_of
|
||||
|
||||
#[rustc_layout(debug)]
|
||||
type Wide = pattern_type!(*const [u8] is !null); //~ ERROR layout_of
|
||||
|
||||
const _: () = assert!(size_of::<NonNull<()>>() == size_of::<Option<NonNull<()>>>());
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,218 @@
|
||||
error: layout_of((*const T) is !null) = Layout {
|
||||
size: Size(8 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(8 bytes),
|
||||
},
|
||||
backend_repr: Scalar(
|
||||
Initialized {
|
||||
value: Pointer(
|
||||
AddressSpace(
|
||||
0,
|
||||
),
|
||||
),
|
||||
valid_range: 1..=18446744073709551615,
|
||||
},
|
||||
),
|
||||
fields: Arbitrary {
|
||||
offsets: [
|
||||
Size(0 bytes),
|
||||
],
|
||||
memory_index: [
|
||||
0,
|
||||
],
|
||||
},
|
||||
largest_niche: Some(
|
||||
Niche {
|
||||
offset: Size(0 bytes),
|
||||
value: Pointer(
|
||||
AddressSpace(
|
||||
0,
|
||||
),
|
||||
),
|
||||
valid_range: 1..=18446744073709551615,
|
||||
},
|
||||
),
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 0,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(8 bytes),
|
||||
randomization_seed: $SEED,
|
||||
}
|
||||
--> $DIR/non_null.rs:11:1
|
||||
|
|
||||
LL | type NonNull<T> = pattern_type!(*const T is !null);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: layout_of(Option<(*const ()) is !null>) = Layout {
|
||||
size: Size(8 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(8 bytes),
|
||||
},
|
||||
backend_repr: Scalar(
|
||||
Initialized {
|
||||
value: Pointer(
|
||||
AddressSpace(
|
||||
0,
|
||||
),
|
||||
),
|
||||
valid_range: (..=0) | (1..),
|
||||
},
|
||||
),
|
||||
fields: Arbitrary {
|
||||
offsets: [
|
||||
Size(0 bytes),
|
||||
],
|
||||
memory_index: [
|
||||
0,
|
||||
],
|
||||
},
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
variants: Multiple {
|
||||
tag: Initialized {
|
||||
value: Pointer(
|
||||
AddressSpace(
|
||||
0,
|
||||
),
|
||||
),
|
||||
valid_range: (..=0) | (1..),
|
||||
},
|
||||
tag_encoding: Niche {
|
||||
untagged_variant: 1,
|
||||
niche_variants: 0..=0,
|
||||
niche_start: 0,
|
||||
},
|
||||
tag_field: 0,
|
||||
variants: [
|
||||
Layout {
|
||||
size: Size(0 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(1 bytes),
|
||||
},
|
||||
backend_repr: Memory {
|
||||
sized: true,
|
||||
},
|
||||
fields: Arbitrary {
|
||||
offsets: [],
|
||||
memory_index: [],
|
||||
},
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 0,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(1 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
Layout {
|
||||
size: Size(8 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(8 bytes),
|
||||
},
|
||||
backend_repr: Scalar(
|
||||
Initialized {
|
||||
value: Pointer(
|
||||
AddressSpace(
|
||||
0,
|
||||
),
|
||||
),
|
||||
valid_range: 1..=18446744073709551615,
|
||||
},
|
||||
),
|
||||
fields: Arbitrary {
|
||||
offsets: [
|
||||
Size(0 bytes),
|
||||
],
|
||||
memory_index: [
|
||||
0,
|
||||
],
|
||||
},
|
||||
largest_niche: Some(
|
||||
Niche {
|
||||
offset: Size(0 bytes),
|
||||
value: Pointer(
|
||||
AddressSpace(
|
||||
0,
|
||||
),
|
||||
),
|
||||
valid_range: 1..=18446744073709551615,
|
||||
},
|
||||
),
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 1,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(8 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
],
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(8 bytes),
|
||||
randomization_seed: $SEED,
|
||||
}
|
||||
--> $DIR/non_null.rs:14:1
|
||||
|
|
||||
LL | type Test = Option<NonNull<()>>;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: layout_of((*const [u8]) is !null) = Layout {
|
||||
size: Size(16 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(8 bytes),
|
||||
},
|
||||
backend_repr: ScalarPair(
|
||||
Initialized {
|
||||
value: Pointer(
|
||||
AddressSpace(
|
||||
0,
|
||||
),
|
||||
),
|
||||
valid_range: 1..=18446744073709551615,
|
||||
},
|
||||
Initialized {
|
||||
value: Int(
|
||||
I64,
|
||||
false,
|
||||
),
|
||||
valid_range: 0..=18446744073709551615,
|
||||
},
|
||||
),
|
||||
fields: Arbitrary {
|
||||
offsets: [
|
||||
Size(0 bytes),
|
||||
],
|
||||
memory_index: [
|
||||
0,
|
||||
],
|
||||
},
|
||||
largest_niche: Some(
|
||||
Niche {
|
||||
offset: Size(0 bytes),
|
||||
value: Pointer(
|
||||
AddressSpace(
|
||||
0,
|
||||
),
|
||||
),
|
||||
valid_range: 1..=18446744073709551615,
|
||||
},
|
||||
),
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 0,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(8 bytes),
|
||||
randomization_seed: $SEED,
|
||||
}
|
||||
--> $DIR/non_null.rs:17:1
|
||||
|
|
||||
LL | type Wide = pattern_type!(*const [u8] is !null);
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
@@ -53,7 +53,14 @@ error: layout_of((i8) is (i8::MIN..=-1 | 1..)) = Layout {
|
||||
valid_range: 1..=255,
|
||||
},
|
||||
),
|
||||
fields: Primitive,
|
||||
fields: Arbitrary {
|
||||
offsets: [
|
||||
Size(0 bytes),
|
||||
],
|
||||
memory_index: [
|
||||
0,
|
||||
],
|
||||
},
|
||||
largest_niche: Some(
|
||||
Niche {
|
||||
offset: Size(0 bytes),
|
||||
@@ -91,7 +98,14 @@ error: layout_of((i8) is (i8::MIN..=-2 | 0..)) = Layout {
|
||||
valid_range: 0..=254,
|
||||
},
|
||||
),
|
||||
fields: Primitive,
|
||||
fields: Arbitrary {
|
||||
offsets: [
|
||||
Size(0 bytes),
|
||||
],
|
||||
memory_index: [
|
||||
0,
|
||||
],
|
||||
},
|
||||
largest_niche: Some(
|
||||
Niche {
|
||||
offset: Size(0 bytes),
|
||||
|
||||
@@ -57,7 +57,14 @@ error: layout_of((u32) is 1..) = Layout {
|
||||
valid_range: 1..=4294967295,
|
||||
},
|
||||
),
|
||||
fields: Primitive,
|
||||
fields: Arbitrary {
|
||||
offsets: [
|
||||
Size(0 bytes),
|
||||
],
|
||||
memory_index: [
|
||||
0,
|
||||
],
|
||||
},
|
||||
largest_niche: Some(
|
||||
Niche {
|
||||
offset: Size(0 bytes),
|
||||
@@ -390,7 +397,14 @@ error: layout_of((i8) is -10..=10) = Layout {
|
||||
valid_range: (..=10) | (246..),
|
||||
},
|
||||
),
|
||||
fields: Primitive,
|
||||
fields: Arbitrary {
|
||||
offsets: [
|
||||
Size(0 bytes),
|
||||
],
|
||||
memory_index: [
|
||||
0,
|
||||
],
|
||||
},
|
||||
largest_niche: Some(
|
||||
Niche {
|
||||
offset: Size(0 bytes),
|
||||
@@ -428,7 +442,14 @@ error: layout_of((i8) is i8::MIN..=0) = Layout {
|
||||
valid_range: (..=0) | (128..),
|
||||
},
|
||||
),
|
||||
fields: Primitive,
|
||||
fields: Arbitrary {
|
||||
offsets: [
|
||||
Size(0 bytes),
|
||||
],
|
||||
memory_index: [
|
||||
0,
|
||||
],
|
||||
},
|
||||
largest_niche: Some(
|
||||
Niche {
|
||||
offset: Size(0 bytes),
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
//! Show that pattern-types with pointer base types can be part of unsizing coercions
|
||||
|
||||
//@ check-pass
|
||||
|
||||
#![feature(pattern_type_macro, pattern_types)]
|
||||
|
||||
use std::pat::pattern_type;
|
||||
|
||||
type NonNull<T> = pattern_type!(*const T is !null);
|
||||
|
||||
trait Trait {}
|
||||
impl Trait for u32 {}
|
||||
impl Trait for i32 {}
|
||||
|
||||
fn main() {
|
||||
let x: NonNull<u32> = unsafe { std::mem::transmute(std::ptr::dangling::<u32>()) };
|
||||
let x: NonNull<dyn Trait> = x;
|
||||
}
|
||||
Reference in New Issue
Block a user