Skip to content

Add NonNull pattern types #142339

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2632,6 +2632,9 @@ pub enum TyPatKind {
/// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`).
Range(Option<P<AnonConst>>, Option<P<AnonConst>>, Spanned<RangeEnd>),

/// A `!null` pattern for raw pointers.
NotNull,

Or(ThinVec<P<TyPat>>),

/// Placeholder for a pattern that wasn't syntactically well formed in some way.
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_ast_lowering/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,9 @@ impl<'a, 'hir> LoweringContext<'a, '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),
}
};
Expand Down Expand Up @@ -460,6 +462,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
)
}),
),
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)),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1234,6 +1234,7 @@ impl<'a> State<'a> {
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 {
Expand Down
24 changes: 15 additions & 9 deletions compiler/rustc_builtin_macros/src/pattern_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,21 @@ fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P
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()?;
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1259,9 +1259,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
// 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
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1830,6 +1830,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>]),

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,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()
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2593,6 +2593,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.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| {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_analysis/src/variance/constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
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)
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1883,6 +1883,10 @@ impl<'a> State<'a> {
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;
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_lint/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,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))
}
Expand Down Expand Up @@ -1065,7 +1066,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..] {
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_middle/src/ty/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ impl<'tcx> Flags for Pattern<'tcx> {
}
flags
}
ty::PatternKind::NotNull => rustc_type_ir::TypeFlags::empty(),
}
}

Expand All @@ -45,6 +46,7 @@ impl<'tcx> Flags for Pattern<'tcx> {
}
idx
}
ty::PatternKind::NotNull => rustc_type_ir::INNERMOST,
}
}
}
Expand Down Expand Up @@ -91,6 +93,7 @@ impl<'tcx> IrPrint<PatternKind<'tcx>> for TyCtxt<'tcx> {

write!(f, "..={end}")
}
PatternKind::NotNull => write!(f, "!null"),
PatternKind::Or(patterns) => {
write!(f, "(")?;
let mut first = true;
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_middle/src/ty/relate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Pattern<'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);
Expand All @@ -67,7 +68,10 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Pattern<'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),
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_parse/src/parser/token_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ pub enum TokenType {
SymNomem,
SymNoreturn,
SymNostack,
SymNull,
SymOptions,
SymOut,
SymPreservesFlags,
Expand Down Expand Up @@ -273,6 +274,7 @@ impl TokenType {
SymNomem,
SymNoreturn,
SymNostack,
SymNull,
SymOptions,
SymOut,
SymPreservesFlags,
Expand Down Expand Up @@ -348,6 +350,7 @@ impl TokenType {
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),
Expand Down Expand Up @@ -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) };
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_public/src/unstable/convert/stable/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> {
end: Some(end.stable(tables, cx)),
include_end: true,
},
ty::PatternKind::NotNull => todo!(),
ty::PatternKind::Or(_) => todo!(),
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -976,7 +976,7 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc
self.visit_ty_pat(pat)
}
}
TyPatKind::Err(_) => {}
TyPatKind::NotNull | TyPatKind::Err(_) => {}
}
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1512,6 +1512,7 @@ symbols! {
not,
notable_trait,
note,
null,
object_safe_for_dispatch,
of,
off,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_symbol_mangling/src/v0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,9 @@ impl<'tcx> SymbolMangler<'tcx> {
Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct).print(self)?;
}
}
ty::PatternKind::NotNull => {
self.tcx.types.unit.print(self)?;
}
ty::PatternKind::Or(patterns) => {
for pat in patterns {
self.print_pat(pat)?;
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_trait_selection/src/traits/wf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,7 @@ impl<'a, 'tcx> WfPredicates<'a, '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)
Expand Down
26 changes: 22 additions & 4 deletions compiler/rustc_ty_utils/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,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)))?;
Expand Down Expand Up @@ -263,6 +261,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, _) =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this ScalarPair(scalar, _) for wide pointers, where we assume the data pointer is the first scalar?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

&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 {
Expand All @@ -279,7 +296,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")
}
})
Expand Down Expand Up @@ -344,6 +361,7 @@ 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"),
},
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_type_ir/src/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ use crate::Interner;
pub enum PatternKind<I: Interner> {
Range { start: I::Const, end: I::Const },
Or(I::PatList),
NotNull,
}
1 change: 1 addition & 0 deletions compiler/rustc_type_ir/src/walk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {}
}
}
2 changes: 1 addition & 1 deletion src/tools/clippy/clippy_utils/src/hir_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
self.hash_ty_pat(variant);
}
},
TyPatKind::Err(_) => {},
TyPatKind::NotNull | TyPatKind::Err(_) => {},
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/tools/rustfmt/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1100,7 +1100,7 @@ impl Rewrite for ast::TyPat {
}
Ok(s)
}
ast::TyPatKind::Err(_) => Err(RewriteError::Unknown),
ast::TyPatKind::NotNull | ast::TyPatKind::Err(_) => Err(RewriteError::Unknown),
}
}
}
Expand Down
11 changes: 11 additions & 0 deletions tests/ui/type/pattern_types/bad_pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,15 @@ type Positive2 = pattern_type!(i32 is 0..=);
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() {}
20 changes: 19 additions & 1 deletion tests/ui/type/pattern_types/bad_pat.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Loading