Rollup merge of #136922 - oli-obk:pattern-types-option-ends, r=BoxyUwU
Pattern types: Avoid having to handle an Option for range ends in the type system or the HIR Instead, 1. during hir_ty_lowering, we now generate constants for the min/max when the range doesn't have a start/end specified. 2. in a later commit we generate those constants during ast lowering, simplifying everything further by not having to handle the range end inclusivity anymore in the type system (and thus avoiding any issues of `0..5` being different from `0..=4` I think it makes all the type system code simpler, and the cost of the extra `ConstKind::Value` processing seems negligible. r? `@BoxyUwU` cc `@joshtriplett` `@scottmcm`
This commit is contained in:
commit
6ac714d526
39 changed files with 467 additions and 281 deletions
|
@ -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]>,
|
||||
|
@ -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 {
|
||||
|
@ -1365,7 +1367,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")
|
||||
|
|
|
@ -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,
|
||||
|
@ -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 })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
@ -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),
|
||||
|
|
|
@ -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(_) => (),
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
use rustc_macros::Diagnostic;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::Span;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_invalid_base_type)]
|
||||
pub(crate) struct InvalidBaseType<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
#[primary_span]
|
||||
pub ty_span: Span,
|
||||
pub pat: &'static str,
|
||||
#[note]
|
||||
pub pat_span: Span,
|
||||
}
|
|
@ -55,9 +55,7 @@ use tracing::{debug, instrument};
|
|||
|
||||
use self::errors::assoc_kind_str;
|
||||
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;
|
||||
|
@ -2692,28 +2690,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),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1943,17 +1943,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();
|
||||
|
|
|
@ -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)?;
|
||||
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)?;
|
||||
|
||||
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,
|
||||
}
|
||||
// This also works for negative numbers, as we just need
|
||||
// to ensure we aren't wrapping over zero.
|
||||
start > 0 && end >= start
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,18 +26,30 @@ impl<'tcx> fmt::Debug for Pattern<'tcx> {
|
|||
impl<'tcx> fmt::Debug for PatternKind<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
PatternKind::Range { start, end, include_end } => {
|
||||
if let Some(start) = start {
|
||||
write!(f, "{start}")?;
|
||||
PatternKind::Range { start, end } => {
|
||||
write!(f, "{start}")?;
|
||||
|
||||
if let Some(c) = end.try_to_value() {
|
||||
let end = c.valtree.unwrap_leaf();
|
||||
let size = end.size();
|
||||
let max = match c.ty.kind() {
|
||||
ty::Int(_) => {
|
||||
Some(ty::ScalarInt::truncate_from_int(size.signed_int_max(), size))
|
||||
}
|
||||
ty::Uint(_) => {
|
||||
Some(ty::ScalarInt::truncate_from_uint(size.unsigned_int_max(), size))
|
||||
}
|
||||
ty::Char => Some(ty::ScalarInt::truncate_from_uint(char::MAX, size)),
|
||||
_ => None,
|
||||
};
|
||||
if let Some((max, _)) = max
|
||||
&& end == max
|
||||
{
|
||||
return write!(f, "..");
|
||||
}
|
||||
}
|
||||
write!(f, "..")?;
|
||||
if include_end {
|
||||
write!(f, "=")?;
|
||||
}
|
||||
if let Some(end) = end {
|
||||
write!(f, "{end}")?;
|
||||
}
|
||||
Ok(())
|
||||
|
||||
write!(f, "..={end}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,5 +58,5 @@ impl<'tcx> fmt::Debug for PatternKind<'tcx> {
|
|||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
|
||||
pub enum PatternKind<'tcx> {
|
||||
Range { start: Option<ty::Const<'tcx>>, end: Option<ty::Const<'tcx>>, include_end: bool },
|
||||
Range { start: ty::Const<'tcx>, end: ty::Const<'tcx> },
|
||||
}
|
||||
|
|
|
@ -51,22 +51,12 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Pattern<'tcx> {
|
|||
) -> RelateResult<'tcx, Self> {
|
||||
match (&*a, &*b) {
|
||||
(
|
||||
&ty::PatternKind::Range { start: start_a, end: end_a, include_end: inc_a },
|
||||
&ty::PatternKind::Range { start: start_b, end: end_b, include_end: inc_b },
|
||||
&ty::PatternKind::Range { start: start_a, end: end_a },
|
||||
&ty::PatternKind::Range { start: start_b, end: end_b },
|
||||
) => {
|
||||
// FIXME(pattern_types): make equal patterns equal (`0..=` is the same as `..=`).
|
||||
let mut relate_opt_const = |a, b| match (a, b) {
|
||||
(None, None) => Ok(None),
|
||||
(Some(a), Some(b)) => relation.relate(a, b).map(Some),
|
||||
// FIXME(pattern_types): report a better error
|
||||
_ => Err(TypeError::Mismatch),
|
||||
};
|
||||
let start = relate_opt_const(start_a, start_b)?;
|
||||
let end = relate_opt_const(end_a, end_b)?;
|
||||
if inc_a != inc_b {
|
||||
todo!()
|
||||
}
|
||||
Ok(relation.cx().mk_pat(ty::PatternKind::Range { start, end, include_end: inc_a }))
|
||||
let start = relation.relate(start_a, start_b)?;
|
||||
let end = relation.relate(end_a, end_b)?;
|
||||
Ok(relation.cx().mk_pat(ty::PatternKind::Range { start, end }))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -284,6 +284,7 @@ TrivialTypeTraversalImpls! {
|
|||
rustc_hir::def_id::LocalDefId,
|
||||
rustc_hir::HirId,
|
||||
rustc_hir::MatchSource,
|
||||
rustc_hir::RangeEnd,
|
||||
rustc_span::Ident,
|
||||
rustc_span::Span,
|
||||
rustc_span::Symbol,
|
||||
|
|
|
@ -137,9 +137,9 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
|
|||
|
||||
ty::Pat(ty, pat) => {
|
||||
match *pat {
|
||||
ty::PatternKind::Range { start, end, include_end: _ } => {
|
||||
stack.extend(end.map(Into::into));
|
||||
stack.extend(start.map(Into::into));
|
||||
ty::PatternKind::Range { start, end } => {
|
||||
stack.push(end.into());
|
||||
stack.push(start.into());
|
||||
}
|
||||
}
|
||||
stack.push(ty.into());
|
||||
|
|
|
@ -88,10 +88,9 @@ impl RustcInternal for Pattern {
|
|||
type T<'tcx> = rustc_ty::Pattern<'tcx>;
|
||||
fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
|
||||
tcx.mk_pat(match self {
|
||||
Pattern::Range { start, end, include_end } => rustc_ty::PatternKind::Range {
|
||||
start: start.as_ref().map(|c| c.internal(tables, tcx)),
|
||||
end: end.as_ref().map(|c| c.internal(tables, tcx)),
|
||||
include_end: *include_end,
|
||||
Pattern::Range { start, end, include_end: _ } => rustc_ty::PatternKind::Range {
|
||||
start: start.as_ref().unwrap().internal(tables, tcx),
|
||||
end: end.as_ref().unwrap().internal(tables, tcx),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -405,10 +405,11 @@ impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> {
|
|||
|
||||
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
||||
match **self {
|
||||
ty::PatternKind::Range { start, end, include_end } => stable_mir::ty::Pattern::Range {
|
||||
start: start.stable(tables),
|
||||
end: end.stable(tables),
|
||||
include_end,
|
||||
ty::PatternKind::Range { start, end } => stable_mir::ty::Pattern::Range {
|
||||
// FIXME(SMIR): update data structures to not have an Option here anymore
|
||||
start: Some(start.stable(tables)),
|
||||
end: Some(end.stable(tables)),
|
||||
include_end: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1173,6 +1173,8 @@ pub enum DesugaringKind {
|
|||
BoundModifier,
|
||||
/// Calls to contract checks (`#[requires]` to precond, `#[ensures]` to postcond)
|
||||
Contract,
|
||||
/// A pattern type range start/end
|
||||
PatTyRange,
|
||||
}
|
||||
|
||||
impl DesugaringKind {
|
||||
|
@ -1190,6 +1192,7 @@ impl DesugaringKind {
|
|||
DesugaringKind::WhileLoop => "`while` loop",
|
||||
DesugaringKind::BoundModifier => "trait bound modifier",
|
||||
DesugaringKind::Contract => "contract check",
|
||||
DesugaringKind::PatTyRange => "pattern type",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -308,6 +308,9 @@ symbols! {
|
|||
RangeFull,
|
||||
RangeInclusive,
|
||||
RangeInclusiveCopy,
|
||||
RangeMax,
|
||||
RangeMin,
|
||||
RangeSub,
|
||||
RangeTo,
|
||||
RangeToInclusive,
|
||||
Rc,
|
||||
|
@ -1522,6 +1525,7 @@ symbols! {
|
|||
pattern_complexity_limit,
|
||||
pattern_parentheses,
|
||||
pattern_type,
|
||||
pattern_type_range_trait,
|
||||
pattern_types,
|
||||
permissions_from_mode,
|
||||
phantom_data,
|
||||
|
|
|
@ -413,12 +413,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
|
|||
}
|
||||
|
||||
ty::Pat(ty, pat) => match *pat {
|
||||
ty::PatternKind::Range { start, end, include_end } => {
|
||||
let consts = [
|
||||
start.unwrap_or(self.tcx.consts.unit),
|
||||
end.unwrap_or(self.tcx.consts.unit),
|
||||
ty::Const::from_bool(self.tcx, include_end),
|
||||
];
|
||||
ty::PatternKind::Range { start, end } => {
|
||||
let consts = [start, end];
|
||||
// HACK: Represent as tuple until we have something better.
|
||||
// HACK: constants are used in arrays, even if the types don't match.
|
||||
self.push("T");
|
||||
|
|
|
@ -708,7 +708,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
|
|||
ty::Pat(subty, pat) => {
|
||||
self.require_sized(subty, ObligationCauseCode::Misc);
|
||||
match *pat {
|
||||
ty::PatternKind::Range { start, end, include_end: _ } => {
|
||||
ty::PatternKind::Range { start, end } => {
|
||||
let mut check = |c| {
|
||||
let cause = self.cause(ObligationCauseCode::Misc);
|
||||
self.out.push(traits::Obligation::with_depth(
|
||||
|
@ -738,12 +738,8 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
};
|
||||
if let Some(start) = start {
|
||||
check(start)
|
||||
}
|
||||
if let Some(end) = end {
|
||||
check(end)
|
||||
}
|
||||
check(start);
|
||||
check(end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -205,24 +205,17 @@ fn layout_of_uncached<'tcx>(
|
|||
let layout = cx.layout_of(ty)?.layout;
|
||||
let mut layout = LayoutData::clone(&layout.0);
|
||||
match *pat {
|
||||
ty::PatternKind::Range { start, end, include_end } => {
|
||||
ty::PatternKind::Range { start, end } => {
|
||||
if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) =
|
||||
&mut layout.backend_repr
|
||||
{
|
||||
if let Some(start) = start {
|
||||
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)))?;
|
||||
}
|
||||
if let Some(end) = end {
|
||||
let mut end = extract_const_value(cx, ty, end)?
|
||||
.try_to_bits(tcx, cx.typing_env)
|
||||
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
|
||||
if !include_end {
|
||||
end = end.wrapping_sub(1);
|
||||
}
|
||||
scalar.valid_range_mut().end = end;
|
||||
}
|
||||
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)))?;
|
||||
|
||||
scalar.valid_range_mut().end = extract_const_value(cx, ty, end)?
|
||||
.try_to_bits(tcx, cx.typing_env)
|
||||
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
|
||||
|
||||
let niche = Niche {
|
||||
offset: Size::ZERO,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue