Skip to content
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

Pattern types: Avoid having to handle an Option for range ends in the type system or the HIR #136922

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 3 additions & 1 deletion compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ struct LoweringContext<'a, 'hir> {

allow_try_trait: Arc<[Symbol]>,
allow_gen_future: Arc<[Symbol]>,
allow_pattern_type: Arc<[Symbol]>,
allow_async_iterator: Arc<[Symbol]>,
allow_for_await: Arc<[Symbol]>,
allow_async_fn_traits: Arc<[Symbol]>,
Expand Down Expand Up @@ -176,6 +177,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
impl_trait_defs: Vec::new(),
impl_trait_bounds: Vec::new(),
allow_try_trait: [sym::try_trait_v2, sym::yeet_desugar_details].into(),
allow_pattern_type: [sym::pattern_types, sym::pattern_type_range_trait].into(),
allow_gen_future: if tcx.features().async_fn_track_caller() {
[sym::gen_future, sym::closure_track_caller].into()
} else {
Expand Down Expand Up @@ -1357,7 +1359,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}
TyKind::Pat(ty, pat) => {
hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_ty_pat(pat))
hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_ty_pat(pat, ty.span))
}
TyKind::MacCall(_) => {
span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now")
Expand Down
122 changes: 112 additions & 10 deletions compiler/rustc_ast_lowering/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ use std::sync::Arc;
use rustc_ast::ptr::P;
use rustc_ast::*;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{self as hir, LangItem};
use rustc_middle::span_bug;
use rustc_span::source_map::{Spanned, respan};
use rustc_span::{Ident, Span};
use rustc_span::{DesugaringKind, Ident, Span, kw};

use super::errors::{
ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding,
Expand Down Expand Up @@ -430,22 +430,124 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.arena.alloc(hir::PatExpr { hir_id: self.lower_node_id(expr.id), span, kind })
}

pub(crate) fn lower_ty_pat(&mut self, pattern: &TyPat) -> &'hir hir::TyPat<'hir> {
self.arena.alloc(self.lower_ty_pat_mut(pattern))
pub(crate) fn lower_ty_pat(
&mut self,
pattern: &TyPat,
base_type: Span,
) -> &'hir hir::TyPat<'hir> {
self.arena.alloc(self.lower_ty_pat_mut(pattern, base_type))
}

fn lower_ty_pat_mut(&mut self, pattern: &TyPat) -> hir::TyPat<'hir> {
fn lower_ty_pat_mut(&mut self, pattern: &TyPat, base_type: Span) -> hir::TyPat<'hir> {
// loop here to avoid recursion
let pat_hir_id = self.lower_node_id(pattern.id);
let node = match &pattern.kind {
TyPatKind::Range(e1, e2, Spanned { node: end, .. }) => hir::TyPatKind::Range(
e1.as_deref().map(|e| self.lower_anon_const_to_const_arg(e)),
e2.as_deref().map(|e| self.lower_anon_const_to_const_arg(e)),
self.lower_range_end(end, e2.is_some()),
TyPatKind::Range(e1, e2, Spanned { node: end, span }) => hir::TyPatKind::Range(
e1.as_deref().map(|e| self.lower_anon_const_to_const_arg(e)).unwrap_or_else(|| {
self.lower_ty_pat_range_end(
hir::LangItem::RangeMin,
span.shrink_to_lo(),
base_type,
)
}),
e2.as_deref()
.map(|e| match end {
RangeEnd::Included(..) => self.lower_anon_const_to_const_arg(e),
RangeEnd::Excluded => self.lower_excluded_range_end(e),
})
.unwrap_or_else(|| {
self.lower_ty_pat_range_end(
hir::LangItem::RangeMax,
span.shrink_to_hi(),
base_type,
)
}),
),
TyPatKind::Err(guar) => hir::TyPatKind::Err(*guar),
};

hir::TyPat { hir_id: pat_hir_id, kind: node, span: self.lower_span(pattern.span) }
}

/// Lowers the range end of an exclusive range (`2..5`) to an inclusive range 2..=(5 - 1).
/// This way the type system doesn't have to handle the distinction between inclusive/exclusive ranges.
fn lower_excluded_range_end(&mut self, e: &AnonConst) -> &'hir hir::ConstArg<'hir> {
let span = self.lower_span(e.value.span);
let unstable_span = self.mark_span_with_reason(
DesugaringKind::PatTyRange,
span,
Some(Arc::clone(&self.allow_pattern_type)),
);
let anon_const = self.with_new_scopes(span, |this| {
let def_id = this.local_def_id(e.id);
let hir_id = this.lower_node_id(e.id);
let body = this.lower_body(|this| {
// Need to use a custom function as we can't just subtract `1` from a `char`.
let kind = hir::ExprKind::Path(this.make_lang_item_qpath(
hir::LangItem::RangeSub,
unstable_span,
None,
));
let fn_def = this.arena.alloc(hir::Expr { hir_id: this.next_id(), kind, span });
let args = this.arena.alloc([this.lower_expr_mut(&e.value)]);
(
&[],
hir::Expr {
hir_id: this.next_id(),
kind: hir::ExprKind::Call(fn_def, args),
span,
},
)
});
hir::AnonConst { def_id, hir_id, body, span }
});
self.arena.alloc(hir::ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Anon(self.arena.alloc(anon_const)),
})
}

/// When a range has no end specified (`1..` or `1..=`) or no start specified (`..5` or `..=5`),
/// we instead use a constant of the MAX/MIN of the type.
/// This way the type system does not have to handle the lack of a start/end.
fn lower_ty_pat_range_end(
&mut self,
lang_item: LangItem,
span: Span,
base_type: Span,
) -> &'hir hir::ConstArg<'hir> {
let parent_def_id = self.current_hir_id_owner.def_id;
let node_id = self.next_node_id();

// Add a definition for the in-band const def.
// We're generating a range end that didn't exist in the AST,
// so the def collector didn't create the def ahead of time. That's why we have to do
// it here.
let def_id = self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span);
let hir_id = self.lower_node_id(node_id);

let unstable_span = self.mark_span_with_reason(
DesugaringKind::PatTyRange,
self.lower_span(span),
Some(Arc::clone(&self.allow_pattern_type)),
);
let span = self.lower_span(base_type);

let path_expr = hir::Expr {
hir_id: self.next_id(),
kind: hir::ExprKind::Path(self.make_lang_item_qpath(lang_item, unstable_span, None)),
span,
};

let ct = self.with_new_scopes(span, |this| {
self.arena.alloc(hir::AnonConst {
def_id,
hir_id,
body: this.lower_body(|_this| (&[], path_expr)),
span,
})
});
let hir_id = self.next_id();
self.arena.alloc(hir::ConstArg { kind: hir::ConstArgKind::Anon(ct), hir_id })
}
}
4 changes: 2 additions & 2 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1600,7 +1600,7 @@ pub struct PatField<'hir> {
pub span: Span,
}

#[derive(Copy, Clone, PartialEq, Debug, HashStable_Generic)]
#[derive(Copy, Clone, PartialEq, Debug, HashStable_Generic, Hash, Eq, Encodable, Decodable)]
pub enum RangeEnd {
Included,
Excluded,
Expand Down Expand Up @@ -1668,7 +1668,7 @@ pub enum PatExprKind<'hir> {
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum TyPatKind<'hir> {
/// A range pattern (e.g., `1..=2` or `1..2`).
Range(Option<&'hir ConstArg<'hir>>, Option<&'hir ConstArg<'hir>>, RangeEnd),
Range(&'hir ConstArg<'hir>, &'hir ConstArg<'hir>),

/// A placeholder for a pattern that wasn't well formed in some way.
Err(ErrorGuaranteed),
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -708,9 +708,9 @@ pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) -> V::Res
pub fn walk_ty_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v TyPat<'v>) -> V::Result {
try_visit!(visitor.visit_id(pattern.hir_id));
match pattern.kind {
TyPatKind::Range(lower_bound, upper_bound, _) => {
visit_opt!(visitor, visit_const_arg_unambig, lower_bound);
visit_opt!(visitor, visit_const_arg_unambig, upper_bound);
TyPatKind::Range(lower_bound, upper_bound) => {
try_visit!(visitor.visit_const_arg_unambig(lower_bound));
try_visit!(visitor.visit_const_arg_unambig(upper_bound));
}
TyPatKind::Err(_) => (),
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,9 @@ language_item_table! {
Range, sym::Range, range_struct, Target::Struct, GenericRequirement::None;
RangeToInclusive, sym::RangeToInclusive, range_to_inclusive_struct, Target::Struct, GenericRequirement::None;
RangeTo, sym::RangeTo, range_to_struct, Target::Struct, GenericRequirement::None;
RangeMax, sym::RangeMax, range_max, Target::AssocConst, GenericRequirement::Exact(0);
RangeMin, sym::RangeMin, range_min, Target::AssocConst, GenericRequirement::Exact(0);
RangeSub, sym::RangeSub, range_sub, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::Exact(0);

// `new_range` types that are `Copy + IntoIterator`
RangeFromCopy, sym::RangeFromCopy, range_from_copy_struct, Target::Struct, GenericRequirement::None;
Expand Down
3 changes: 0 additions & 3 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,6 @@ hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a
.help = consider moving this inherent impl into the crate defining the type if possible
.span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
hir_analysis_invalid_base_type = `{$ty}` is not a valid base type for range patterns
.note = range patterns only support integers
hir_analysis_invalid_generic_receiver_ty = invalid generic `self` parameter type: `{$receiver_ty}`
.note = type of `self` must not be a method generic parameter type
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ use rustc_middle::ty::Ty;
use rustc_span::{Ident, Span, Symbol};

use crate::fluent_generated as fluent;
mod pattern_types;
pub(crate) use pattern_types::*;
pub(crate) mod wrong_number_of_generic_args;

mod precise_captures;
Expand Down
14 changes: 0 additions & 14 deletions compiler/rustc_hir_analysis/src/errors/pattern_types.rs

This file was deleted.

40 changes: 18 additions & 22 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,7 @@ use rustc_type_ir::Upcast;
use tracing::{debug, instrument};

use crate::check::check_abi_fn_ptr;
use crate::errors::{
AmbiguousLifetimeBound, BadReturnTypeNotation, InvalidBaseType, NoVariantNamed,
};
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoVariantNamed};
use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
use crate::middle::resolve_bound_vars as rbv;
Expand Down Expand Up @@ -2452,28 +2450,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let ty_span = ty.span;
let ty = self.lower_ty(ty);
let pat_ty = match pat.kind {
hir::TyPatKind::Range(start, end, include_end) => {
let ty = match ty.kind() {
ty::Int(_) | ty::Uint(_) | ty::Char => ty,
_ => Ty::new_error(
tcx,
self.dcx().emit_err(InvalidBaseType {
ty,
pat: "range",
hir::TyPatKind::Range(start, end) => {
let (ty, start, end) = match ty.kind() {
// Keep this list of types in sync with the list of types that
// the `RangePattern` trait is implemented for.
ty::Int(_) | ty::Uint(_) | ty::Char => {
let start = self.lower_const_arg(start, FeedConstTy::No);
let end = self.lower_const_arg(end, FeedConstTy::No);
(ty, start, end)
}
_ => {
let guar = self.dcx().span_delayed_bug(
ty_span,
pat_span: pat.span,
}),
),
};
let start = start.map(|expr| self.lower_const_arg(expr, FeedConstTy::No));
let end = end.map(|expr| self.lower_const_arg(expr, FeedConstTy::No));

let include_end = match include_end {
hir::RangeEnd::Included => true,
hir::RangeEnd::Excluded => false,
"invalid base type for range pattern",
);
let errc = ty::Const::new_error(tcx, guar);
(Ty::new_error(tcx, guar), errc, errc)
}
};

let pat = tcx.mk_pat(ty::PatternKind::Range { start, end, include_end });
let pat = tcx.mk_pat(ty::PatternKind::Range { start, end });
Ty::new_pat(tcx, ty, pat)
}
hir::TyPatKind::Err(e) => Ty::new_error(tcx, e),
Expand Down
10 changes: 3 additions & 7 deletions compiler/rustc_hir_analysis/src/variance/constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,13 +252,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {

ty::Pat(typ, pat) => {
match *pat {
ty::PatternKind::Range { start, end, include_end: _ } => {
if let Some(start) = start {
self.add_constraints_from_const(current, start, variance);
}
if let Some(end) = end {
self.add_constraints_from_const(current, end, variance);
}
ty::PatternKind::Range { start, end } => {
self.add_constraints_from_const(current, start, variance);
self.add_constraints_from_const(current, end, variance);
}
}
self.add_constraints_from_ty(current, typ, variance);
Expand Down
15 changes: 4 additions & 11 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1869,17 +1869,10 @@ impl<'a> State<'a> {
// Pat isn't normalized, but the beauty of it
// is that it doesn't matter
match pat.kind {
TyPatKind::Range(begin, end, end_kind) => {
if let Some(expr) = begin {
self.print_const_arg(expr);
}
match end_kind {
RangeEnd::Included => self.word("..."),
RangeEnd::Excluded => self.word(".."),
}
if let Some(expr) = end {
self.print_const_arg(expr);
}
TyPatKind::Range(begin, end) => {
self.print_const_arg(begin);
self.word("..=");
self.print_const_arg(end);
}
TyPatKind::Err(_) => {
self.popen();
Expand Down
28 changes: 7 additions & 21 deletions compiler/rustc_lint/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -882,27 +882,13 @@ fn ty_is_known_nonnull<'tcx>(
|| Option::unwrap_or_default(
try {
match **pat {
ty::PatternKind::Range { start, end, include_end } => {
match (start, end) {
(Some(start), None) => {
start.try_to_value()?.try_to_bits(tcx, typing_env)? > 0
}
(Some(start), Some(end)) => {
let start =
start.try_to_value()?.try_to_bits(tcx, typing_env)?;
let end =
end.try_to_value()?.try_to_bits(tcx, typing_env)?;

if include_end {
// This also works for negative numbers, as we just need
// to ensure we aren't wrapping over zero.
start > 0 && end >= start
} else {
start > 0 && end > start
}
}
_ => false,
}
ty::PatternKind::Range { start, end } => {
let start = start.try_to_value()?.try_to_bits(tcx, typing_env)?;
let end = end.try_to_value()?.try_to_bits(tcx, typing_env)?;

// This also works for negative numbers, as we just need
// to ensure we aren't wrapping over zero.
start > 0 && end >= start
}
}
},
Expand Down
10 changes: 3 additions & 7 deletions compiler/rustc_middle/src/ty/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,13 +220,9 @@ impl FlagComputation {
&ty::Pat(ty, pat) => {
self.add_ty(ty);
match *pat {
ty::PatternKind::Range { start, end, include_end: _ } => {
if let Some(start) = start {
self.add_const(start)
}
if let Some(end) = end {
self.add_const(end)
}
ty::PatternKind::Range { start, end } => {
self.add_const(start);
self.add_const(end);
}
}
}
Expand Down
Loading
Loading