Actually create ranged int types in the type system.

This commit is contained in:
Oli Scherer 2023-02-02 13:57:36 +00:00
parent 6b24a9cf70
commit 84acfe86de
97 changed files with 1208 additions and 77 deletions

View file

@ -2152,7 +2152,7 @@ pub enum TyKind {
MacCall(P<MacCall>),
/// Placeholder for a `va_list`.
CVarArgs,
/// Pattern types like `u32 as 1..=`, which is the same as `NonZeroU32`,
/// Pattern types like `pattern_type!(u32 is 1..=)`, which is the same as `NonZeroU32`,
/// just as part of the type system.
Pat(P<Ty>, P<Pat>),
/// Sometimes we need a dummy value when no error has occurred.

View file

@ -381,4 +381,8 @@ fn visit_array_length(&mut self, len: &'hir ArrayLen) {
ArrayLen::Body(..) => intravisit::walk_array_len(self, len),
}
}
fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) {
self.visit_pat(p)
}
}

View file

@ -1606,6 +1606,7 @@ fn check_movable_place(&mut self, location: Location, place: Place<'tcx>) {
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::FnDef(_, _)
| ty::FnPtr(_)
@ -1648,6 +1649,7 @@ fn check_movable_place(&mut self, location: Location, place: Place<'tcx>) {
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)

View file

@ -202,6 +202,16 @@ fn push_debuginfo_type_name<'tcx>(
}
}
}
ty::Pat(inner_type, pat) => {
if cpp_like_debuginfo {
output.push_str("pat$<");
push_debuginfo_type_name(tcx, inner_type, true, output, visited);
// FIXME(wg-debugging): implement CPP like printing for patterns.
write!(output, ",{:?}>", pat).unwrap();
} else {
write!(output, "{:?}", t).unwrap();
}
}
ty::Slice(inner_type) => {
if cpp_like_debuginfo {
output.push_str("slice2$<");

View file

@ -1,3 +1,4 @@
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
@ -98,6 +99,16 @@ fn const_to_valtree_inner<'tcx>(
Ok(ty::ValTree::Leaf(val.assert_int()))
}
ty::Pat(base, ..) => {
let mut place = place.clone();
// The valtree of the base type is the same as the valtree of the pattern type.
// Since the returned valtree does not contain the type or layout, we can just
// switch to the base type.
place.layout = ecx.layout_of(*base).unwrap();
ensure_sufficient_stack(|| const_to_valtree_inner(ecx, &place, num_nodes))
},
ty::RawPtr(_, _) => {
// Not all raw pointers are allowed, as we cannot properly test them for
// equality at compile-time (see `ptr_guaranteed_cmp`).
@ -273,7 +284,7 @@ pub fn valtree_to_const_value<'tcx>(
let (param_env, ty) = param_env_ty.into_parts();
match ty.kind() {
match *ty.kind() {
ty::FnDef(..) => {
assert!(valtree.unwrap_branch().is_empty());
mir::ConstValue::ZeroSized
@ -286,10 +297,11 @@ pub fn valtree_to_const_value<'tcx>(
),
}
}
ty::Pat(ty, _) => valtree_to_const_value(tcx, param_env.and(ty), valtree),
ty::Ref(_, inner_ty, _) => {
let mut ecx =
mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No);
let imm = valtree_to_ref(&mut ecx, valtree, *inner_ty);
let imm = valtree_to_ref(&mut ecx, valtree, inner_ty);
let imm = ImmTy::from_immediate(imm, tcx.layout_of(param_env_ty).unwrap());
op_to_const(&ecx, &imm.into(), /* for diagnostics */ false)
}

View file

@ -1060,6 +1060,8 @@ fn is_very_trivially_sized(ty: Ty<'_>) -> bool {
ty::Tuple(tys) => tys.last().iter().all(|ty| is_very_trivially_sized(**ty)),
ty::Pat(ty, ..) => is_very_trivially_sized(*ty),
// We don't want to do any queries, so there is not much we can do with ADTs.
ty::Adt(..) => false,

View file

@ -69,6 +69,10 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => {
throw_inval!(TooGeneric)
}
ty::Pat(_, pat) => match **pat {
ty::PatternKind::Range { .. } => ConstValue::from_target_usize(0u64, &tcx),
// Future pattern kinds may have more variants
},
ty::Bound(_, _) => bug!("bound ty during ctfe"),
ty::Bool
| ty::Char

View file

@ -640,6 +640,7 @@ fn try_visit_primitive(
| ty::Str
| ty::Dynamic(..)
| ty::Closure(..)
| ty::Pat(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..) => Ok(false),
// Some types only occur during typechecking, they have no layout.

View file

@ -31,6 +31,7 @@ fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
| ty::Uint(_)
| ty::Float(_)
| ty::Str
| ty::Pat(_, _)
| ty::Array(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)

View file

@ -2624,7 +2624,7 @@ pub enum TyKind<'hir> {
Infer,
/// Placeholder for a type that has failed to be defined.
Err(rustc_span::ErrorGuaranteed),
/// Pattern types (`u32 as 1..`)
/// Pattern types (`pattern_type!(u32 is 1..)`)
Pat(&'hir Ty<'hir>, &'hir Pat<'hir>),
}

View file

@ -356,6 +356,11 @@ fn visit_expr_field(&mut self, field: &'v ExprField<'v>) -> Self::Result {
fn visit_ty(&mut self, t: &'v Ty<'v>) -> Self::Result {
walk_ty(self, t)
}
fn visit_pattern_type_pattern(&mut self, _p: &'v Pat<'v>) {
// Do nothing. Only a few visitors need to know the details of the pattern type,
// and they opt into it. All other visitors will just choke on our fake patterns
// because they aren't in a body.
}
fn visit_generic_param(&mut self, p: &'v GenericParam<'v>) -> Self::Result {
walk_generic_param(self, p)
}
@ -884,7 +889,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
}
TyKind::Pat(ty, pat) => {
try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_pat(pat));
try_visit!(visitor.visit_pattern_type_pattern(pat));
}
}
V::Result::output()

View file

@ -349,6 +349,7 @@ hir_analysis_pass_to_variadic_function = can't pass `{$ty}` to variadic function
.suggestion = cast the value to `{$cast_ty}`
.help = cast the value to `{$cast_ty}`
hir_analysis_pattern_type_non_const_range = "range patterns must have constant range start and end"
hir_analysis_pattern_type_wild_pat = "wildcard patterns are not permitted for pattern types"
.label = "this type is the same as the inner type without a pattern"
hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}

View file

@ -144,7 +144,12 @@ fn check_item(&mut self, id: hir::ItemId) -> Result<(), ErrorGuaranteed> {
let id = id.owner_id.def_id;
let item_span = self.tcx.def_span(id);
let self_ty = self.tcx.type_of(id).instantiate_identity();
let self_ty = self.tcx.peel_off_weak_alias_tys(self_ty);
let mut self_ty = self.tcx.peel_off_weak_alias_tys(self_ty);
// We allow impls on pattern types exactly when we allow impls on the base type.
// FIXME(pattern_types): Figure out the exact coherence rules we want here.
while let ty::Pat(base, _) = *self_ty.kind() {
self_ty = base;
}
match *self_ty.kind() {
ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()),
ty::Foreign(did) => self.check_def_id(id, self_ty, did),
@ -154,6 +159,7 @@ fn check_item(&mut self, id: hir::ItemId) -> Result<(), ErrorGuaranteed> {
ty::Dynamic(..) => {
Err(self.tcx.dcx().emit_err(errors::InherentDyn { span: item_span }))
}
ty::Pat(_, _) => unreachable!(),
ty::Bool
| ty::Char
| ty::Int(_)

View file

@ -206,6 +206,11 @@ enum NonlocalImpl {
(LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther)
}
ty::Pat(..) => (
LocalImpl::Disallow { problematic_kind: "pattern type" },
NonlocalImpl::DisallowOther,
),
ty::Bool
| ty::Char
| ty::Int(..)

View file

@ -1631,3 +1631,10 @@ pub struct OpaqueCapturesHigherRankedLifetime {
pub decl_span: Span,
pub bad_place: &'static str,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_pattern_type_non_const_range)]
pub struct NonConstRange {
#[primary_span]
pub span: Span,
}

View file

@ -39,6 +39,7 @@
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause;
use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
use rustc_middle::ty::{
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
TypeVisitableExt,
@ -2195,15 +2196,64 @@ fn lower_ty_common(&self, hir_ty: &hir::Ty<'tcx>, borrowed: bool, in_path: bool)
// handled specially and will not descend into this routine.
self.ty_infer(None, hir_ty.span)
}
hir::TyKind::Pat(_ty, pat) => match pat.kind {
hir::PatKind::Wild => {
let err = tcx.dcx().emit_err(WildPatTy { span: pat.span });
Ty::new_error(tcx, err)
}
hir::PatKind::Range(_, _, _) => Ty::new_misc_error(tcx),
hir::PatKind::Err(e) => Ty::new_error(tcx, e),
_ => span_bug!(pat.span, "unsupported pattern for pattern type: {pat:#?}"),
},
hir::TyKind::Pat(ty, pat) => {
let ty = self.lower_ty(ty);
let pat_ty = match pat.kind {
hir::PatKind::Wild => {
let err = tcx.dcx().emit_err(WildPatTy { span: pat.span });
Ty::new_error(tcx, err)
}
hir::PatKind::Range(start, end, include_end) => {
let expr_to_const = |expr: &'tcx hir::Expr<'tcx>| -> ty::Const<'tcx> {
let (expr, neg) = match expr.kind {
hir::ExprKind::Unary(hir::UnOp::Neg, negated) => {
(negated, Some((expr.hir_id, expr.span)))
}
_ => (expr, None),
};
let c = match &expr.kind {
hir::ExprKind::Lit(lit) => {
let lit_input =
LitToConstInput { lit: &lit.node, ty, neg: neg.is_some() };
match tcx.lit_to_const(lit_input) {
Ok(c) => c,
Err(LitToConstError::Reported(err)) => {
ty::Const::new_error(tcx, err, ty)
}
Err(LitToConstError::TypeError) => todo!(),
}
}
_ => {
let err = tcx
.dcx()
.emit_err(crate::errors::NonConstRange { span: expr.span });
ty::Const::new_error(tcx, err, ty)
}
};
self.record_ty(expr.hir_id, c.ty(), expr.span);
if let Some((id, span)) = neg {
self.record_ty(id, c.ty(), span);
}
c
};
let start = start.map(expr_to_const);
let end = end.map(expr_to_const);
let include_end = match include_end {
hir::RangeEnd::Included => true,
hir::RangeEnd::Excluded => false,
};
let pat = tcx.mk_pat(ty::PatternKind::Range { start, end, include_end });
Ty::new_pat(tcx, ty, pat)
}
hir::PatKind::Err(e) => Ty::new_error(tcx, e),
_ => span_bug!(pat.span, "unsupported pattern for pattern type: {pat:#?}"),
};
self.record_ty(pat.hir_id, ty, pat.span);
pat_ty
}
hir::TyKind::Err(guar) => Ty::new_error(tcx, *guar),
};

View file

@ -249,6 +249,20 @@ fn add_constraints_from_ty(
self.add_constraints_from_ty(current, typ, variance);
}
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);
}
}
}
self.add_constraints_from_ty(current, typ, variance);
}
ty::Slice(typ) => {
self.add_constraints_from_ty(current, typ, variance);
}

View file

@ -130,6 +130,7 @@ fn pointer_kind(
| ty::CoroutineWitness(..)
| ty::RawPtr(_, _)
| ty::Ref(..)
| ty::Pat(..)
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::Closure(..)

View file

@ -440,6 +440,7 @@ fn fold_ty(&mut self, mut t: Ty<'tcx>) -> Ty<'tcx> {
| ty::Tuple(..)
| ty::Alias(..)
| ty::Foreign(..)
| ty::Pat(..)
| ty::Param(..) => {
if t.flags().intersects(self.needs_canonical_flags) {
t.super_fold_with(self)

View file

@ -93,6 +93,7 @@ fn compute_components<'tcx>(
}
}
ty::Pat(element, _) |
ty::Array(element, _) => {
// Don't look into the len const as it doesn't affect regions
compute_components(tcx, element, out, visited);

View file

@ -299,6 +299,9 @@ lint_improper_ctypes_only_phantomdata = composed only of `PhantomData`
lint_improper_ctypes_opaque = opaque types have no C equivalent
lint_improper_ctypes_pat_help = consider using the base type instead
lint_improper_ctypes_pat_reason = pattern types have no C equivalent
lint_improper_ctypes_slice_help = consider using a raw pointer instead
lint_improper_ctypes_slice_reason = slices have no C equivalent

View file

@ -1379,6 +1379,12 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
help: Some(fluent::lint_improper_ctypes_char_help),
},
ty::Pat(..) => FfiUnsafe {
ty,
reason: fluent::lint_improper_ctypes_pat_reason,
help: Some(fluent::lint_improper_ctypes_pat_help),
},
ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => {
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_128bit, help: None }
}

View file

@ -90,6 +90,7 @@ macro_rules! arena_types {
[decode] attribute: rustc_ast::Attribute,
[] name_set: rustc_data_structures::unord::UnordSet<rustc_span::symbol::Symbol>,
[] ordered_name_set: rustc_data_structures::fx::FxIndexSet<rustc_span::symbol::Symbol>,
[] pats: rustc_middle::ty::PatternKind<'tcx>,
// Note that this deliberately duplicates items in the `rustc_hir::arena`,
// since we need to allocate this type on both the `rustc_hir` arena

View file

@ -148,6 +148,12 @@ fn encode(&self, e: &mut E) {
}
}
impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Pattern<'tcx> {
fn encode(&self, e: &mut E) {
self.0.0.encode(e);
}
}
impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ConstAllocation<'tcx> {
fn encode(&self, e: &mut E) {
self.inner().encode(e)
@ -364,6 +370,12 @@ fn decode(decoder: &mut D) -> Self {
}
}
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Pattern<'tcx> {
fn decode(decoder: &mut D) -> Self {
decoder.interner().mk_pat(Decodable::decode(decoder))
}
}
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] {
fn decode(decoder: &mut D) -> &'tcx Self {
decoder

View file

@ -26,9 +26,10 @@
};
use crate::ty::{
self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, ConstData,
GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy,
PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity, Region,
RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, TypeVisitable, Visibility,
GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy, Pattern,
PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity,
Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, TypeVisitable,
Visibility,
};
use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
use rustc_ast::{self as ast, attr};
@ -95,6 +96,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
type CanonicalVars = CanonicalVarInfos<'tcx>;
type Ty = Ty<'tcx>;
type Pat = Pattern<'tcx>;
type Tys = &'tcx List<Ty<'tcx>>;
type AliasTy = ty::AliasTy<'tcx>;
type ParamTy = ParamTy;
@ -157,6 +159,7 @@ pub struct CtxtInterners<'tcx> {
projs: InternedSet<'tcx, List<ProjectionKind>>,
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
const_: InternedSet<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>,
pat: InternedSet<'tcx, PatternKind<'tcx>>,
const_allocation: InternedSet<'tcx, Allocation>,
bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
layout: InternedSet<'tcx, LayoutS<FieldIdx, VariantIdx>>,
@ -184,6 +187,7 @@ fn new(arena: &'tcx WorkerLocal<Arena<'tcx>>) -> CtxtInterners<'tcx> {
projs: Default::default(),
place_elems: Default::default(),
const_: Default::default(),
pat: Default::default(),
const_allocation: Default::default(),
bound_variable_kinds: Default::default(),
layout: Default::default(),
@ -1578,6 +1582,7 @@ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
nop_lift! {type_; Ty<'a> => Ty<'tcx>}
nop_lift! {region; Region<'a> => Region<'tcx>}
nop_lift! {const_; Const<'a> => Const<'tcx>}
nop_lift! {pat; Pattern<'a> => Pattern<'tcx>}
nop_lift! {const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx>}
nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>}
nop_lift! {predicate; Clause<'a> => Clause<'tcx>}
@ -1715,6 +1720,7 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Param,
Infer,
Alias,
Pat,
Foreign
)?;
@ -1866,6 +1872,7 @@ impl<'tcx> TyCtxt<'tcx> {
// crate only, and have a corresponding `mk_` function.
direct_interners! {
region: pub(crate) intern_region(RegionKind<'tcx>): Region -> Region<'tcx>,
pat: pub mk_pat(PatternKind<'tcx>): Pattern -> Pattern<'tcx>,
const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
layout: pub mk_layout(LayoutS<FieldIdx, VariantIdx>): Layout -> Layout<'tcx>,
adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>,

View file

@ -285,6 +285,7 @@ pub fn prefix_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
ty::Adt(def, _) => def.descr().into(),
ty::Foreign(_) => "extern type".into(),
ty::Array(..) => "array".into(),
ty::Pat(..) => "pattern type".into(),
ty::Slice(_) => "slice".into(),
ty::RawPtr(_, _) => "raw pointer".into(),
ty::Ref(.., mutbl) => match mutbl {

View file

@ -120,6 +120,7 @@ pub fn simplify_type<'tcx>(
ty::Str => Some(SimplifiedType::Str),
ty::Array(..) => Some(SimplifiedType::Array),
ty::Slice(..) => Some(SimplifiedType::Slice),
ty::Pat(ty, ..) => simplify_type(tcx, ty, treat_params),
ty::RawPtr(_, mutbl) => Some(SimplifiedType::Ptr(mutbl)),
ty::Dynamic(trait_info, ..) => match trait_info.principal_def_id() {
Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => {
@ -231,6 +232,7 @@ pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -
| ty::Slice(..)
| ty::RawPtr(..)
| ty::Dynamic(..)
| ty::Pat(..)
| ty::Ref(..)
| ty::Never
| ty::Tuple(..)
@ -269,6 +271,10 @@ pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -
}
_ => false,
},
ty::Pat(obl_ty, _) => {
// FIXME(pattern_types): take pattern into account
matches!(k, &ty::Pat(impl_ty, _) if self.types_may_unify(obl_ty, impl_ty))
}
ty::Slice(obl_ty) => {
matches!(k, &ty::Slice(impl_ty) if self.types_may_unify(obl_ty, impl_ty))
}

View file

@ -218,6 +218,20 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
self.add_const(len);
}
&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::Slice(tt) => self.add_ty(tt),
&ty::RawPtr(ty, _) => {

View file

@ -316,11 +316,11 @@ pub fn has_impl_trait(&'tcx self) -> bool {
/// of this item, excluding `Self`.
///
/// **This should only be used for diagnostics purposes.**
pub fn own_args_no_defaults(
pub fn own_args_no_defaults<'a>(
&'tcx self,
tcx: TyCtxt<'tcx>,
args: &'tcx [ty::GenericArg<'tcx>],
) -> &'tcx [ty::GenericArg<'tcx>] {
args: &'a [ty::GenericArg<'tcx>],
) -> &'a [ty::GenericArg<'tcx>] {
let mut own_params = self.parent_count..self.count();
if self.has_self && self.parent.is_none() {
own_params.start = 1;

View file

@ -742,6 +742,7 @@ fn field_ty_or_layout<'tcx>(
| ty::FnDef(..)
| ty::CoroutineWitness(..)
| ty::Foreign(..)
| ty::Pat(_, _)
| ty::Dynamic(_, _, ty::Dyn) => {
bug!("TyAndLayout::field({:?}): not applicable", this)
}

View file

@ -91,6 +91,7 @@
pub use self::instance::{Instance, InstanceDef, ReifyReason, ShortInstance, UnusedGenericParams};
pub use self::list::{List, ListWithCachedTypeInfo};
pub use self::parameterized::ParameterizedOverTcx;
pub use self::pattern::{Pattern, PatternKind};
pub use self::predicate::{
Clause, ClauseKind, CoercePredicate, ExistentialPredicate, ExistentialProjection,
ExistentialTraitRef, NormalizesTo, OutlivesPredicate, PolyCoercePredicate,
@ -130,6 +131,7 @@
pub mod inhabitedness;
pub mod layout;
pub mod normalize_erasing_regions;
pub mod pattern;
pub mod print;
pub mod relate;
pub mod trait_def;

View file

@ -0,0 +1,48 @@
use std::fmt;
use crate::ty;
use rustc_data_structures::intern::Interned;
#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)]
#[rustc_pass_by_value]
pub struct Pattern<'tcx>(pub Interned<'tcx, PatternKind<'tcx>>);
impl<'tcx> std::ops::Deref for Pattern<'tcx> {
type Target = PatternKind<'tcx>;
fn deref(&self) -> &Self::Target {
&*self.0
}
}
impl<'tcx> fmt::Debug for Pattern<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", **self)
}
}
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}")?;
}
write!(f, "..")?;
if include_end {
write!(f, "=")?;
}
if let Some(end) = end {
write!(f, "{end}")?;
}
Ok(())
}
}
}
}
#[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 },
}

View file

@ -259,7 +259,7 @@ fn characteristic_def_id_of_type_cached<'a>(
ty::Dynamic(data, ..) => data.principal_def_id(),
ty::Array(subty, _) | ty::Slice(subty) => {
ty::Pat(subty, _) | ty::Array(subty, _) | ty::Slice(subty) => {
characteristic_def_id_of_type_cached(subty, visited)
}

View file

@ -667,6 +667,9 @@ fn pretty_print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
ty::Int(t) => p!(write("{}", t.name_str())),
ty::Uint(t) => p!(write("{}", t.name_str())),
ty::Float(t) => p!(write("{}", t.name_str())),
ty::Pat(ty, pat) => {
p!("(", print(ty), ") is ", write("{pat:?}"))
}
ty::RawPtr(ty, mutbl) => {
p!(write(
"*{} ",

View file

@ -13,6 +13,8 @@
use rustc_target::spec::abi;
use std::iter;
use super::Pattern;
pub type RelateResult<'tcx, T> = Result<T, TypeError<'tcx>>;
pub trait TypeRelation<'tcx>: Sized {
@ -351,6 +353,36 @@ fn relate<R: TypeRelation<'tcx>>(
}
}
impl<'tcx> Relate<'tcx> for Pattern<'tcx> {
#[inline]
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
a: Self,
b: Self,
) -> 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 },
) => {
// 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.tcx().mk_pat(ty::PatternKind::Range { start, end, include_end: inc_a }))
}
}
}
}
/// Relates `a` and `b` structurally, calling the relation for all nested values.
/// Any semantic equality, e.g. of projections, and inference variables have to be
/// handled by the caller.
@ -533,6 +565,12 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
Ok(Ty::new_alias(tcx, a_kind, alias_ty))
}
(&ty::Pat(a_ty, a_pat), &ty::Pat(b_ty, b_pat)) => {
let ty = relation.relate(a_ty, b_ty)?;
let pat = relation.relate(a_pat, b_pat)?;
Ok(Ty::new_pat(tcx, ty, pat))
}
_ => Err(TypeError::Sorts(expected_found(a, b))),
}
}

View file

@ -20,6 +20,8 @@
use super::print::PrettyPrinter;
use super::{GenericArg, GenericArgKind, Region};
use super::Pattern;
impl fmt::Debug for ty::TraitDef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
ty::tls::with(|tcx| {
@ -210,6 +212,22 @@ fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
}
}
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Pattern<'tcx> {
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
match &**this.data {
ty::PatternKind::Range { start, end, include_end } => f
.debug_struct("Pattern::Range")
.field("start", start)
.field("end", end)
.field("include_end", include_end)
.finish(),
}
}
}
impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
WithInfcx::with_no_infcx(self).fmt(f)
@ -541,6 +559,22 @@ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
}
}
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for Pattern<'tcx> {
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
self,
folder: &mut F,
) -> Result<Self, F::Error> {
let pat = (*self).clone().try_fold_with(folder)?;
Ok(if pat == *self { self } else { folder.interner().mk_pat(pat) })
}
}
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for Pattern<'tcx> {
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
(**self).visit_with(visitor)
}
}
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
self,
@ -586,6 +620,7 @@ fn try_super_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
ty::CoroutineClosure(did, args.try_fold_with(folder)?)
}
ty::Alias(kind, data) => ty::Alias(kind, data.try_fold_with(folder)?),
ty::Pat(ty, pat) => ty::Pat(ty.try_fold_with(folder)?, pat.try_fold_with(folder)?),
ty::Bool
| ty::Char
@ -633,6 +668,11 @@ fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::
ty::CoroutineClosure(_did, ref args) => args.visit_with(visitor),
ty::Alias(_, ref data) => data.visit_with(visitor),
ty::Pat(ty, pat) => {
try_visit!(ty.visit_with(visitor));
pat.visit_with(visitor)
}
ty::Bool
| ty::Char
| ty::Str

View file

@ -1522,6 +1522,11 @@ pub fn new_alias(
Ty::new(tcx, Alias(kind, alias_ty))
}
#[inline]
pub fn new_pat(tcx: TyCtxt<'tcx>, base: Ty<'tcx>, pat: ty::Pattern<'tcx>) -> Ty<'tcx> {
Ty::new(tcx, Pat(base, pat))
}
#[inline]
pub fn new_opaque(tcx: TyCtxt<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>) -> Ty<'tcx> {
Ty::new_alias(tcx, ty::Opaque, AliasTy::new(tcx, def_id, args))
@ -2278,6 +2283,8 @@ pub fn discriminant_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
Ty::new_projection(tcx, assoc_items[0], tcx.mk_args(&[self.into()]))
}
ty::Pat(ty, _) => ty.discriminant_ty(tcx),
ty::Bool
| ty::Char
| ty::Int(_)
@ -2359,6 +2366,7 @@ pub fn ptr_metadata_ty_or_tail(
ty::Param(_) | ty::Alias(..) => Err(tail),
ty::Infer(ty::TyVar(_))
| ty::Pat(..)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(
@ -2495,6 +2503,7 @@ pub fn is_trivially_sized(self, tcx: TyCtxt<'tcx>) -> bool {
| ty::Coroutine(..)
| ty::CoroutineWitness(..)
| ty::Array(..)
| ty::Pat(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Never
@ -2549,6 +2558,8 @@ pub fn is_trivially_pure_clone_copy(self) -> bool {
field_tys.len() <= 3 && field_tys.iter().all(Self::is_trivially_pure_clone_copy)
}
ty::Pat(ty, _) => ty.is_trivially_pure_clone_copy(),
// Sometimes traits aren't implemented for every ABI or arity,
// because we can't be generic over everything yet.
ty::FnPtr(..) => false,
@ -2630,6 +2641,7 @@ pub fn is_known_rigid(self) -> bool {
| Foreign(_)
| Str
| Array(_, _)
| Pat(_, _)
| Slice(_)
| RawPtr(_, _)
| Ref(_, _, _)

View file

@ -245,6 +245,11 @@ pub fn struct_tail_with_normalize(
ty::Tuple(_) => break,
ty::Pat(inner, _) => {
f();
ty = inner;
}
ty::Alias(..) => {
let normalized = normalize(ty);
if ty == normalized {
@ -1242,7 +1247,7 @@ fn is_trivially_freeze(self) -> bool {
| ty::Error(_)
| ty::FnPtr(_) => true,
ty::Tuple(fields) => fields.iter().all(Self::is_trivially_freeze),
ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_freeze(),
ty::Pat(ty, _) | ty::Slice(ty) | ty::Array(ty, _) => ty.is_trivially_freeze(),
ty::Adt(..)
| ty::Bound(..)
| ty::Closure(..)
@ -1282,7 +1287,7 @@ fn is_trivially_unpin(self) -> bool {
| ty::Error(_)
| ty::FnPtr(_) => true,
ty::Tuple(fields) => fields.iter().all(Self::is_trivially_unpin),
ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_unpin(),
ty::Pat(ty, _) | ty::Slice(ty) | ty::Array(ty, _) => ty.is_trivially_unpin(),
ty::Adt(..)
| ty::Bound(..)
| ty::Closure(..)
@ -1398,7 +1403,7 @@ pub fn is_structural_eq_shallow(self, tcx: TyCtxt<'tcx>) -> bool {
//
// Because this function is "shallow", we return `true` for these composites regardless
// of the type(s) contained within.
ty::Ref(..) | ty::Array(..) | ty::Slice(_) | ty::Tuple(..) => true,
ty::Pat(..) | ty::Ref(..) | ty::Array(..) | ty::Slice(_) | ty::Tuple(..) => true,
// Raw pointers use bitwise comparison.
ty::RawPtr(_, _) | ty::FnPtr(_) => true,
@ -1528,7 +1533,7 @@ pub fn needs_drop_components<'tcx>(
ty::Dynamic(..) | ty::Error(_) => Err(AlwaysRequiresDrop),
ty::Slice(ty) => needs_drop_components(tcx, ty),
ty::Pat(ty, _) | ty::Slice(ty) => needs_drop_components(tcx, ty),
ty::Array(elem_ty, size) => {
match needs_drop_components(tcx, elem_ty) {
Ok(v) if v.is_empty() => Ok(v),
@ -1597,7 +1602,7 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool {
| ty::CoroutineWitness(..)
| ty::Adt(..) => false,
ty::Array(ty, _) | ty::Slice(ty) => is_trivially_const_drop(ty),
ty::Array(ty, _) | ty::Slice(ty) | ty::Pat(ty, _) => is_trivially_const_drop(ty),
ty::Tuple(tys) => tys.iter().all(|ty| is_trivially_const_drop(ty)),
}

View file

@ -151,6 +151,15 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
| ty::Bound(..)
| ty::Foreign(..) => {}
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));
}
}
stack.push(ty.into());
}
ty::Array(ty, len) => {
stack.push(len.into());
stack.push(ty.into());

View file

@ -457,7 +457,7 @@ fn recur(
PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }
}
}
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => {
ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => {
// The raw pointers we see here have been "vetted" by valtree construction to be
// just integers, so we simply allow them.
PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }

View file

@ -153,6 +153,7 @@ fn move_path_for(&mut self, place: Place<'tcx>) -> MovePathResult {
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::FnDef(_, _)
| ty::FnPtr(_)
@ -193,6 +194,7 @@ fn move_path_for(&mut self, place: Place<'tcx>) -> MovePathResult {
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)

View file

@ -684,6 +684,7 @@ fn try_write_constant<'tcx>(
// Unsupported for now.
ty::Array(_, _)
| ty::Pat(_, _)
// Do not attempt to support indirection in constants.
| ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) | ty::Str | ty::Slice(_)

View file

@ -349,6 +349,7 @@ fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
| ty::Pat(_, _)
| ty::FnDef(_, _)
| ty::FnPtr(_)
| ty::Dynamic(_, _, _)

View file

@ -161,4 +161,8 @@ fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) {
let mut inner_visitor = self.new_visitor(self.tcx);
inner_visitor.check(i.owner_id, |this| intravisit::walk_impl_item(this, i));
}
fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) {
self.visit_pat(p)
}
}

View file

@ -399,6 +399,7 @@ pub fn ctors_for_ty(
| ty::RawPtr(_, _)
| ty::FnDef(_, _)
| ty::FnPtr(_)
| ty::Pat(_, _)
| ty::Dynamic(_, _, _)
| ty::Closure(..)
| ty::CoroutineClosure(..)

View file

@ -276,6 +276,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
| ty::Tuple(..)
| ty::RawPtr(..)
| ty::Ref(..)
| ty::Pat(..)
| ty::FnPtr(..)
| ty::Param(..)
| ty::Bound(..)

View file

@ -14,8 +14,8 @@
use stable_mir::ty::{
Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const,
DynKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig,
GenericArgKind, GenericArgs, IndexedVal, IntTy, Movability, Region, RigidTy, Span, TermKind,
TraitRef, Ty, UintTy, VariantDef, VariantIdx,
GenericArgKind, GenericArgs, IndexedVal, IntTy, Movability, Pattern, Region, RigidTy, Span,
TermKind, TraitRef, Ty, UintTy, VariantDef, VariantIdx,
};
use stable_mir::{CrateItem, CrateNum, DefId};
@ -76,6 +76,19 @@ fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<
}
}
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| ty_const(c, tables, tcx)),
end: end.as_ref().map(|c| ty_const(c, tables, tcx)),
include_end: *include_end,
},
})
}
}
impl RustcInternal for RigidTy {
type T<'tcx> = rustc_ty::TyKind<'tcx>;
@ -90,6 +103,9 @@ fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<
RigidTy::Array(ty, cnst) => {
rustc_ty::TyKind::Array(ty.internal(tables, tcx), ty_const(cnst, tables, tcx))
}
RigidTy::Pat(ty, pat) => {
rustc_ty::TyKind::Pat(ty.internal(tables, tcx), pat.internal(tables, tcx))
}
RigidTy::Adt(def, args) => {
rustc_ty::TyKind::Adt(def.internal(tables, tcx), args.internal(tables, tcx))
}

View file

@ -330,6 +330,9 @@ fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
ty::Array(ty, constant) => {
TyKind::RigidTy(RigidTy::Array(ty.stable(tables), constant.stable(tables)))
}
ty::Pat(ty, pat) => {
TyKind::RigidTy(RigidTy::Pat(ty.stable(tables), pat.stable(tables)))
}
ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(ty.stable(tables))),
ty::RawPtr(ty, mutbl) => {
TyKind::RigidTy(RigidTy::RawPtr(ty.stable(tables), mutbl.stable(tables)))
@ -385,6 +388,20 @@ fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
}
}
impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> {
type T = stable_mir::ty::Pattern;
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,
},
}
}
}
impl<'tcx> Stable<'tcx> for ty::Const<'tcx> {
type T = stable_mir::ty::Const;

View file

@ -533,6 +533,16 @@ fn encode_ty<'tcx>(
typeid.push_str(&s);
}
ty::Pat(ty0, pat) => {
// u3patI<element-type><pattern>E as vendor extended type
let mut s = String::from("u3patI");
s.push_str(&encode_ty(tcx, *ty0, dict, options));
write!(s, "{:?}", **pat).unwrap();
s.push('E');
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
typeid.push_str(&s);
}
ty::Slice(ty0) => {
// u5sliceI<element-type>E as vendor extended type
let mut s = String::from("u5sliceI");
@ -782,6 +792,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
| ty::Foreign(..)
| ty::Never
| ty::Slice(..)
| ty::Pat(..)
| ty::Str
| ty::Tuple(..) => t.super_fold_with(self),

View file

@ -371,6 +371,25 @@ fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
ty.print(self)?;
}
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).into(),
];
// 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");
ty.print(self)?;
for ct in consts {
Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct)
.print(self)?;
}
self.push("E");
}
},
ty::Array(ty, len) => {
self.push("A");
ty.print(self)?;

View file

@ -363,6 +363,7 @@ fn assemble_non_blanket_impl_candidates<G: GoalKind<'tcx>>(
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
@ -596,6 +597,7 @@ fn assemble_alias_bound_candidates_recur<G: GoalKind<'tcx>>(
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
@ -684,6 +686,7 @@ fn assemble_object_bound_candidates<G: GoalKind<'tcx>>(
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)

View file

@ -50,7 +50,9 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
Ok(vec![ty::Binder::dummy(element_ty)])
}
ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![ty::Binder::dummy(element_ty)]),
ty::Pat(element_ty, _) | ty::Array(element_ty, _) | ty::Slice(element_ty) => {
Ok(vec![ty::Binder::dummy(element_ty)])
}
ty::Tuple(tys) => {
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
@ -114,6 +116,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
| ty::Coroutine(..)
| ty::CoroutineWitness(..)
| ty::Array(..)
| ty::Pat(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Never
@ -177,6 +180,10 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
| ty::Ref(_, _, Mutability::Not)
| ty::Array(..) => Err(NoSolution),
// Cannot implement in core, as we can't be generic over patterns yet,
// so we'd have to list all patterns and type combinations.
ty::Pat(ty, ..) => Ok(vec![ty::Binder::dummy(ty)]),
ty::Dynamic(..)
| ty::Str
| ty::Slice(_)
@ -347,6 +354,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
| ty::CoroutineWitness(..)
| ty::Never
| ty::Tuple(_)
| ty::Pat(_, _)
| ty::Alias(_, _)
| ty::Param(_)
| ty::Placeholder(..)
@ -526,6 +534,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)

View file

@ -533,6 +533,7 @@ fn consider_builtin_pointee_candidate(
| ty::Uint(..)
| ty::Float(..)
| ty::Array(..)
| ty::Pat(..)
| ty::RawPtr(..)
| ty::Ref(..)
| ty::FnDef(..)
@ -768,6 +769,7 @@ fn consider_builtin_discriminant_kind_candidate(
| ty::Uint(..)
| ty::Float(..)
| ty::Array(..)
| ty::Pat(..)
| ty::RawPtr(..)
| ty::Ref(..)
| ty::FnDef(..)

View file

@ -1051,6 +1051,7 @@ fn disqualify_auto_trait_candidate_due_to_possible_impl(
| ty::Float(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)

View file

@ -883,6 +883,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
| ty::Float(..)
| ty::Str
| ty::FnDef(..)
| ty::Pat(..)
| ty::FnPtr(_)
| ty::Array(..)
| ty::Slice(..)

View file

@ -1804,6 +1804,7 @@ fn type_category(tcx: TyCtxt<'_>, t: Ty<'_>) -> Option<u32> {
ty::Foreign(..) => Some(19),
ty::CoroutineWitness(..) => Some(20),
ty::CoroutineClosure(..) => Some(21),
ty::Pat(..) => Some(22),
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
}
}

View file

@ -1048,6 +1048,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
| ty::Foreign(_)
| ty::Str
| ty::Array(..)
| ty::Pat(..)
| ty::Slice(_)
| ty::RawPtr(..)
| ty::Ref(..)
@ -1099,6 +1100,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
| ty::Float(_)
| ty::Str
| ty::Array(..)
| ty::Pat(..)
| ty::Slice(_)
| ty::RawPtr(..)
| ty::Ref(..)

View file

@ -42,8 +42,8 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
| ty::Foreign(..)
| ty::Error(_) => true,
// [T; N] and [T] have same properties as T.
ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty),
// `T is PAT`, `[T; N]`, and `[T]` have same properties as T.
ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty),
// (T1..Tn) and closures have same properties as T1..Tn --
// check if *all* of them are trivial.
@ -222,7 +222,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
// these types never have a destructor
}
ty::Array(ety, _) | ty::Slice(ety) => {
ty::Pat(ety, _) | ty::Array(ety, _) | ty::Slice(ety) => {
// single-element containers, behave like their element
rustc_data_structures::stack::ensure_sufficient_stack(|| {
dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, *ety, constraints)

View file

@ -670,6 +670,7 @@ fn reject_fn_ptr_impls(
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
@ -803,6 +804,7 @@ fn assemble_candidates_from_auto_impls(
| ty::Float(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::Adt(..)
| ty::RawPtr(_, _)
@ -1193,6 +1195,7 @@ fn assemble_const_destruct_candidates(
| ty::Never
| ty::Foreign(_)
| ty::Array(..)
| ty::Pat(..)
| ty::Slice(_)
| ty::Closure(..)
| ty::CoroutineClosure(..)
@ -1270,6 +1273,7 @@ fn assemble_candidate_for_tuple(
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
| ty::FnDef(_, _)
| ty::Pat(_, _)
| ty::FnPtr(_)
| ty::Dynamic(_, _, _)
| ty::Closure(..)
@ -1329,6 +1333,7 @@ fn assemble_candidates_for_fn_ptr_trait(
| ty::Foreign(..)
| ty::Str
| ty::Array(..)
| ty::Pat(..)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(..)

View file

@ -1417,7 +1417,7 @@ fn confirm_const_destruct_candidate(
// These types are built-in, so we can fast-track by registering
// nested predicates for their constituent type(s)
ty::Array(ty, _) | ty::Slice(ty) => {
ty::Array(ty, _) | ty::Slice(ty) | ty::Pat(ty, _) => {
stack.push(ty);
}
ty::Tuple(tys) => {
@ -1469,7 +1469,15 @@ fn confirm_const_destruct_candidate(
// If we have any other type (e.g. an ADT), just register a nested obligation
// since it's either not `const Drop` (and we raise an error during selection),
// or it's an ADT (and we need to check for a custom impl during selection)
_ => {
ty::Error(_)
| ty::Dynamic(..)
| ty::CoroutineClosure(..)
| ty::Param(_)
| ty::Bound(..)
| ty::Adt(..)
| ty::Alias(ty::Opaque | ty::Weak, _)
| ty::Infer(_)
| ty::Placeholder(_) => {
let predicate = self_ty.rebind(ty::TraitPredicate {
trait_ref: ty::TraitRef::from_lang_item(
self.tcx(),

View file

@ -2142,6 +2142,8 @@ fn sized_conditions(
obligation.predicate.rebind(tys.last().map_or_else(Vec::new, |&last| vec![last])),
),
ty::Pat(ty, _) => Where(obligation.predicate.rebind(vec![*ty])),
ty::Adt(def, args) => {
if let Some(sized_crit) = def.sized_constraint(self.tcx()) {
// (*) binder moved here
@ -2202,6 +2204,11 @@ fn copy_clone_conditions(
Where(obligation.predicate.rebind(tys.iter().collect()))
}
ty::Pat(ty, _) => {
// (*) binder moved here
Where(obligation.predicate.rebind(vec![ty]))
}
ty::Coroutine(coroutine_def_id, args) => {
match self.tcx().coroutine_movability(coroutine_def_id) {
hir::Movability::Static => None,
@ -2340,7 +2347,7 @@ fn constituent_types_for_ty(
ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => t.rebind(vec![element_ty]),
ty::Array(element_ty, _) | ty::Slice(element_ty) => t.rebind(vec![element_ty]),
ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => t.rebind(vec![ty]),
ty::Tuple(tys) => {
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet

View file

@ -126,7 +126,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
return ControlFlow::Continue(());
}
ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
ty::Pat(..) | ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
// First check all contained types and then tell the caller to continue searching.
return ty.super_visit_with(self);
}

View file

@ -681,6 +681,10 @@ fn visit_ty(&mut self, t: <TyCtxt<'tcx> as ty::Interner>::Ty) -> Self::Result {
// Note that we handle the len is implicitly checked while walking `arg`.
}
ty::Pat(subty, _) => {
self.require_sized(subty, traits::MiscObligation);
}
ty::Tuple(tys) => {
if let Some((_last, rest)) = tys.split_last() {
for &elem in rest {

View file

@ -126,6 +126,39 @@ fn layout_of_uncached<'tcx>(
debug_assert!(!ty.has_non_region_infer());
Ok(match *ty.kind() {
ty::Pat(ty, pat) => {
let layout = cx.layout_of(ty)?.layout;
let mut layout = LayoutS::clone(&layout.0);
match *pat {
ty::PatternKind::Range { start, end, include_end } => {
if let Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) = &mut layout.abi {
if let Some(start) = start {
scalar.valid_range_mut().start = start.eval_bits(tcx, param_env);
}
if let Some(end) = end {
let mut end = end.eval_bits(tcx, param_env);
if !include_end {
end = end.wrapping_sub(1);
}
scalar.valid_range_mut().end = end;
}
let niche = Niche {
offset: Size::ZERO,
value: scalar.primitive(),
valid_range: scalar.valid_range(cx),
};
layout.largest_niche = Some(niche);
tcx.mk_layout(layout)
} else {
bug!("pattern type with range but not scalar layout: {ty:?}, {layout:?}")
}
}
}
}
// Basic scalars.
ty::Bool => tcx.mk_layout(LayoutS::scalar(
cx,

View file

@ -221,6 +221,7 @@ fn next(&mut self) -> Option<NeedsDropResult<Ty<'tcx>>> {
| ty::Ref(..)
| ty::RawPtr(..)
| ty::FnDef(..)
| ty::Pat(..)
| ty::FnPtr(..)
| ty::Tuple(_)
| ty::Bound(..)

View file

@ -36,6 +36,8 @@ fn sized_constraint_for_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'
// these are never sized
Str | Slice(..) | Dynamic(_, _, ty::Dyn) | Foreign(..) => Some(ty),
Pat(ty, _) => sized_constraint_for_ty(tcx, *ty),
Tuple(tys) => tys.last().and_then(|&ty| sized_constraint_for_ty(tcx, ty)),
// recursive case

View file

@ -49,6 +49,7 @@ pub trait Interner: Sized + Copy {
type BoundExistentialPredicates: Copy + DebugWithInfcx<Self> + Hash + Eq;
type PolyFnSig: Copy + DebugWithInfcx<Self> + Hash + Eq;
type AllocId: Copy + Debug + Hash + Eq;
type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx<Self>;
// Kinds of consts
type Const: Copy

View file

@ -100,6 +100,13 @@ pub enum TyKind<I: Interner> {
/// An array with the given length. Written as `[T; N]`.
Array(I::Ty, I::Const),
/// A pattern newtype. Takes any type and restricts its valid values to its pattern.
/// This will also change the layout to take advantage of this restriction.
/// Only `Copy` and `Clone` will automatically get implemented for pattern types.
/// Auto-traits treat this as if it were an aggregate with a single nested type.
/// Only supports integer range patterns for now.
Pat(I::Ty, I::Pat),
/// The pointee of an array slice. Written as `[T]`.
Slice(I::Ty),
@ -273,12 +280,13 @@ const fn tykind_discriminant<I: Interner>(value: &TyKind<I>) -> usize {
CoroutineWitness(_, _) => 18,
Never => 19,
Tuple(_) => 20,
Alias(_, _) => 21,
Param(_) => 22,
Bound(_, _) => 23,
Placeholder(_) => 24,
Infer(_) => 25,
Error(_) => 26,
Pat(_, _) => 21,
Alias(_, _) => 22,
Param(_) => 23,
Bound(_, _) => 24,
Placeholder(_) => 25,
Infer(_) => 26,
Error(_) => 27,
}
}
@ -299,6 +307,7 @@ fn eq(&self, other: &TyKind<I>) -> bool {
(Adt(a_d, a_s), Adt(b_d, b_s)) => a_d == b_d && a_s == b_s,
(Foreign(a_d), Foreign(b_d)) => a_d == b_d,
(Array(a_t, a_c), Array(b_t, b_c)) => a_t == b_t && a_c == b_c,
(Pat(a_t, a_c), Pat(b_t, b_c)) => a_t == b_t && a_c == b_c,
(Slice(a_t), Slice(b_t)) => a_t == b_t,
(RawPtr(a_t, a_m), RawPtr(b_t, b_m)) => a_t == b_t && a_m == b_m,
(Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => a_r == b_r && a_t == b_t && a_m == b_m,
@ -322,7 +331,7 @@ fn eq(&self, other: &TyKind<I>) -> bool {
_ => {
debug_assert!(
tykind_discriminant(self) != tykind_discriminant(other),
"This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}"
"This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}"
);
false
}
@ -362,6 +371,7 @@ fn fmt<Infcx: InferCtxtLike<Interner = I>>(
Foreign(d) => f.debug_tuple("Foreign").field(d).finish(),
Str => write!(f, "str"),
Array(t, c) => write!(f, "[{:?}; {:?}]", &this.wrap(t), &this.wrap(c)),
Pat(t, p) => write!(f, "pattern_type!({:?} is {:?})", &this.wrap(t), &this.wrap(p)),
Slice(t) => write!(f, "[{:?}]", &this.wrap(t)),
RawPtr(ty, mutbl) => {
match mutbl {

View file

@ -99,6 +99,12 @@ pub fn kind(&self) -> TyKind {
}
}
/// Represents a pattern in the type system
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Pattern {
Range { start: Option<Const>, end: Option<Const>, include_end: bool },
}
/// Represents a constant in MIR or from the Type system.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Const {
@ -481,6 +487,7 @@ pub enum RigidTy {
Foreign(ForeignDef),
Str,
Array(Ty, Const),
Pat(Ty, Pattern),
Slice(Ty),
RawPtr(Ty, Mutability),
Ref(Region, Ty, Mutability),

View file

@ -139,6 +139,7 @@ fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
t.visit(visitor)?;
c.visit(visitor)
}
RigidTy::Pat(t, _p) => t.visit(visitor),
RigidTy::Slice(inner) => inner.visit(visitor),
RigidTy::RawPtr(ty, _) => ty.visit(visitor),
RigidTy::Ref(reg, ty, _) => {

View file

@ -2009,6 +2009,10 @@ pub(crate) fn clean_middle_ty<'tcx>(
ty::Float(float_ty) => Primitive(float_ty.into()),
ty::Str => Primitive(PrimitiveType::Str),
ty::Slice(ty) => Slice(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None))),
ty::Pat(ty, pat) => Type::Pat(
Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)),
format!("{pat:?}").into_boxed_str(),
),
ty::Array(ty, mut n) => {
n = n.normalize(cx.tcx, ty::ParamEnv::reveal_all());
let n = print_const(cx, n);

View file

@ -573,9 +573,10 @@ fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
Tuple(t) => Type::Tuple(t.into_tcx(tcx)),
Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))),
Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s.to_string() },
clean::Type::Pat(t, p) => {
Type::Pat { type_: Box::new((*t).into_tcx(tcx)), pat: p.to_string() }
}
clean::Type::Pat(t, p) => Type::Pat {
type_: Box::new((*t).into_tcx(tcx)),
__pat_unstable_do_not_use: p.to_string(),
},
ImplTrait(g) => Type::ImplTrait(g.into_tcx(tcx)),
Infer => Type::Infer,
RawPointer(mutability, type_) => Type::RawPointer {

View file

@ -491,6 +491,7 @@ fn def_id_to_res(&self, ty_id: DefId) -> Option<Res> {
ty::Str => Res::Primitive(Str),
ty::Tuple(tys) if tys.is_empty() => Res::Primitive(Unit),
ty::Tuple(_) => Res::Primitive(Tuple),
ty::Pat(..) => Res::Primitive(Pat),
ty::Array(..) => Res::Primitive(Array),
ty::Slice(_) => Res::Primitive(Slice),
ty::RawPtr(_, _) => Res::Primitive(RawPointer),

View file

@ -566,7 +566,7 @@ pub enum Type {
Pat {
#[serde(rename = "type")]
type_: Box<Type>,
pat: String,
__pat_unstable_do_not_use: String,
},
/// `impl TraitA + TraitB + ...`
ImplTrait(Vec<GenericBound>),

View file

@ -870,6 +870,7 @@ fn for_mir_ty<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>,
| ty::Int(_)
| ty::Uint(_)
| ty::Array(..)
| ty::Pat(..)
| ty::Float(_)
| ty::RawPtr(..)
| ty::FnPtr(_)

View file

@ -262,6 +262,7 @@ fn check_type(&mut self, x: &'a Type) {
Type::DynTrait(dyn_trait) => self.check_dyn_trait(dyn_trait),
Type::Generic(_) => {}
Type::Primitive(_) => {}
Type::Pat { type_, pat: _ } => self.check_type(type_),
Type::FunctionPointer(fp) => self.check_function_pointer(&**fp),
Type::Tuple(tys) => tys.iter().for_each(|ty| self.check_type(ty)),
Type::Slice(inner) => self.check_type(&**inner),

View file

@ -0,0 +1,23 @@
//! Check that symbol names with pattern types in them are
//! different from the same symbol with the base type
//@ compile-flags: -Csymbol-mangling-version=v0 -Copt-level=0 --crate-type=lib
#![feature(pattern_types)]
#![feature(core_pattern_types)]
#![feature(core_pattern_type)]
use std::pat::pattern_type;
type NanoU32 = crate::pattern_type!(u32 is 0..=999_999_999);
fn foo<T>() {}
pub fn bar() {
// CHECK: call pattern_type_symbols::foo::<u32>
// CHECK: call void @_RINvCs3QvG2ESzx2Q_20pattern_type_symbols3foomEB2_
foo::<u32>();
// CHECK: call pattern_type_symbols::foo::<(u32, [(); 0], [(); 999999999], [(); true])>
// CHECK: call void @_RINvCs3QvG2ESzx2Q_20pattern_type_symbols3fooTmAum0_Aum3b9ac9ff_Aub1_EEB2_
foo::<NanoU32>();
}

View file

@ -22,6 +22,7 @@ fn main() {
TyKind::Foreign(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Str => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Array(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Pat(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Slice(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::RawPtr(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Ref(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`

View file

@ -67,119 +67,125 @@ LL | TyKind::Array(..) => (),
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:25:9
|
LL | TyKind::Slice(..) => (),
LL | TyKind::Pat(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:26:9
|
LL | TyKind::RawPtr(..) => (),
LL | TyKind::Slice(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:27:9
|
LL | TyKind::Ref(..) => (),
LL | TyKind::RawPtr(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:28:9
|
LL | TyKind::FnDef(..) => (),
LL | TyKind::Ref(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:29:9
|
LL | TyKind::FnPtr(..) => (),
LL | TyKind::FnDef(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:30:9
|
LL | TyKind::Dynamic(..) => (),
LL | TyKind::FnPtr(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:31:9
|
LL | TyKind::Closure(..) => (),
LL | TyKind::Dynamic(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:32:9
|
LL | TyKind::CoroutineClosure(..) => (),
LL | TyKind::Closure(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:33:9
|
LL | TyKind::Coroutine(..) => (),
LL | TyKind::CoroutineClosure(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:34:9
|
LL | TyKind::CoroutineWitness(..) => (),
LL | TyKind::Coroutine(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:35:9
|
LL | TyKind::Never => (),
LL | TyKind::CoroutineWitness(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:36:9
|
LL | TyKind::Tuple(..) => (),
LL | TyKind::Never => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:37:9
|
LL | TyKind::Alias(..) => (),
LL | TyKind::Tuple(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:38:9
|
LL | TyKind::Param(..) => (),
LL | TyKind::Alias(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:39:9
|
LL | TyKind::Bound(..) => (),
LL | TyKind::Param(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:40:9
|
LL | TyKind::Placeholder(..) => (),
LL | TyKind::Bound(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:41:9
|
LL | TyKind::Infer(..) => (),
LL | TyKind::Placeholder(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:42:9
|
LL | TyKind::Infer(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:43:9
|
LL | TyKind::Error(_) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:47:12
--> $DIR/ty_tykind_usage.rs:48:12
|
LL | if let TyKind::Int(int_ty) = kind {}
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind`
--> $DIR/ty_tykind_usage.rs:49:24
--> $DIR/ty_tykind_usage.rs:50:24
|
LL | fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {}
| ^^^^^^^^^^
@ -187,7 +193,7 @@ LL | fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {}
= help: try using `Ty` instead
error: usage of `ty::TyKind`
--> $DIR/ty_tykind_usage.rs:51:37
--> $DIR/ty_tykind_usage.rs:52:37
|
LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
| ^^^^^^^^^^^
@ -195,7 +201,7 @@ LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
= help: try using `Ty` instead
error: usage of `ty::TyKind`
--> $DIR/ty_tykind_usage.rs:51:53
--> $DIR/ty_tykind_usage.rs:52:53
|
LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
| ^^^^^^^^^^^
@ -203,12 +209,12 @@ LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
= help: try using `Ty` instead
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:54:9
--> $DIR/ty_tykind_usage.rs:55:9
|
LL | IrTyKind::Bool
| --------^^^^^^
| |
| help: try using `ty::<kind>` directly: `ty`
error: aborting due to 33 previous errors
error: aborting due to 34 previous errors

View file

@ -1,10 +1,10 @@
error: symbol-name(_ZN5basic4main17h6fc0c8d27b1a289fE)
error: symbol-name(_ZN5basic4main17had874e876c8b1028E)
--> $DIR/basic.rs:8:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling(basic::main::h6fc0c8d27b1a289f)
error: demangling(basic::main::had874e876c8b1028)
--> $DIR/basic.rs:8:1
|
LL | #[rustc_symbol_name]

View file

@ -1,10 +1,10 @@
error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17hab58a402db4ebf3aE)
error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17haf0d0ad2255e29c6E)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::hab58a402db4ebf3a)
error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::haf0d0ad2255e29c6)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_symbol_name]

View file

@ -0,0 +1,14 @@
error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999`
--> $DIR/derives.rs:14:20
|
LL | #[derive(Clone, Copy, PartialEq)]
| --------- in this derive macro expansion
LL | #[repr(transparent)]
LL | struct Nanoseconds(NanoI32);
| ^^^^^^^
|
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0369`.

View file

@ -0,0 +1,20 @@
//! Check that pattern types don't implement traits of their base automatically
#![feature(pattern_types)]
#![feature(core_pattern_types)]
#![feature(core_pattern_type)]
use std::pat::pattern_type;
#[derive(Clone, Copy, PartialEq)]
#[repr(transparent)]
struct Nanoseconds(NanoI32);
//~^ ERROR: binary operation `==` cannot be applied to type `(i32) is 0..=999999999`
type NanoI32 = crate::pattern_type!(i32 is 0..=999_999_999);
fn main() {
let x = Nanoseconds(unsafe { std::mem::transmute(42) });
let y = x.clone();
if y == x {}
}

View file

@ -0,0 +1,14 @@
error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999`
--> $DIR/derives.rs:11:20
|
LL | #[derive(Clone, Copy, PartialEq)]
| --------- in this derive macro expansion
LL | #[repr(transparent)]
LL | struct Nanoseconds(NanoI32);
| ^^^^^^^
|
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0369`.

View file

@ -4,7 +4,7 @@
#![allow(incomplete_features)]
// Check that pattern types do not affect existing macros.
// They don't, because `is` was never legal after `ty` fragments.
// They don't, because pattern types don't have surface syntax.
macro_rules! foo {
($t:ty is $p:pat) => {}; //~ ERROR `$t:ty` is followed by `is`, which is not allowed for `ty` fragments

View file

@ -0,0 +1,21 @@
#![feature(pattern_types, rustc_attrs)]
#![feature(core_pattern_type)]
#![feature(core_pattern_types)]
#![allow(incomplete_features)]
use std::pat::pattern_type;
#[rustc_layout(debug)]
type X = std::num::NonZeroU32; //~ ERROR layout_of
#[rustc_layout(debug)]
type Y = pattern_type!(u32 is 1..); //~ ERROR layout_of
#[rustc_layout(debug)]
type Z = Option<pattern_type!(u32 is 1..)>; //~ ERROR layout_of
#[rustc_layout(debug)]
type A = Option<std::num::NonZeroU32>; //~ ERROR layout_of
#[rustc_layout(debug)]
struct NonZeroU32New(pattern_type!(u32 is 1..)); //~ ERROR layout_of
fn main() {
let x: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(42_u32) };
}

View file

@ -0,0 +1,343 @@
error: layout_of(NonZero<u32>) = Layout {
size: Size(4 bytes),
align: AbiAndPrefAlign {
abi: Align(4 bytes),
pref: Align(8 bytes),
},
abi: Scalar(
Initialized {
value: Int(
I32,
false,
),
valid_range: 1..=4294967295,
},
),
fields: Arbitrary {
offsets: [
Size(0 bytes),
],
memory_index: [
0,
],
},
largest_niche: Some(
Niche {
offset: Size(0 bytes),
value: Int(
I32,
false,
),
valid_range: 1..=4294967295,
},
),
variants: Single {
index: 0,
},
max_repr_align: None,
unadjusted_abi_align: Align(4 bytes),
}
--> $DIR/range_patterns.rs:9:1
|
LL | type X = std::num::NonZeroU32;
| ^^^^^^
error: layout_of((u32) is 1..=) = Layout {
size: Size(4 bytes),
align: AbiAndPrefAlign {
abi: Align(4 bytes),
pref: Align(4 bytes),
},
abi: Scalar(
Initialized {
value: Int(
I32,
false,
),
valid_range: 1..=4294967295,
},
),
fields: Primitive,
largest_niche: Some(
Niche {
offset: Size(0 bytes),
value: Int(
I32,
false,
),
valid_range: 1..=4294967295,
},
),
variants: Single {
index: 0,
},
max_repr_align: None,
unadjusted_abi_align: Align(4 bytes),
}
--> $DIR/range_patterns.rs:11:1
|
LL | type Y = pattern_type!(u32 is 1..);
| ^^^^^^
error: layout_of(Option<(u32) is 1..=>) = Layout {
size: Size(4 bytes),
align: AbiAndPrefAlign {
abi: Align(4 bytes),
pref: Align(8 bytes),
},
abi: Scalar(
Initialized {
value: Int(
I32,
false,
),
valid_range: (..=0) | (1..),
},
),
fields: Arbitrary {
offsets: [
Size(0 bytes),
],
memory_index: [
0,
],
},
largest_niche: None,
variants: Multiple {
tag: Initialized {
value: Int(
I32,
false,
),
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: AbiAndPrefAlign {
abi: Align(1 bytes),
pref: Align(8 bytes),
},
abi: Aggregate {
sized: true,
},
fields: Arbitrary {
offsets: [],
memory_index: [],
},
largest_niche: None,
variants: Single {
index: 0,
},
max_repr_align: None,
unadjusted_abi_align: Align(1 bytes),
},
Layout {
size: Size(4 bytes),
align: AbiAndPrefAlign {
abi: Align(4 bytes),
pref: Align(8 bytes),
},
abi: Scalar(
Initialized {
value: Int(
I32,
false,
),
valid_range: 1..=4294967295,
},
),
fields: Arbitrary {
offsets: [
Size(0 bytes),
],
memory_index: [
0,
],
},
largest_niche: Some(
Niche {
offset: Size(0 bytes),
value: Int(
I32,
false,
),
valid_range: 1..=4294967295,
},
),
variants: Single {
index: 1,
},
max_repr_align: None,
unadjusted_abi_align: Align(4 bytes),
},
],
},
max_repr_align: None,
unadjusted_abi_align: Align(4 bytes),
}
--> $DIR/range_patterns.rs:13:1
|
LL | type Z = Option<pattern_type!(u32 is 1..)>;
| ^^^^^^
error: layout_of(Option<NonZero<u32>>) = Layout {
size: Size(4 bytes),
align: AbiAndPrefAlign {
abi: Align(4 bytes),
pref: Align(8 bytes),
},
abi: Scalar(
Initialized {
value: Int(
I32,
false,
),
valid_range: (..=0) | (1..),
},
),
fields: Arbitrary {
offsets: [
Size(0 bytes),
],
memory_index: [
0,
],
},
largest_niche: None,
variants: Multiple {
tag: Initialized {
value: Int(
I32,
false,
),
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: AbiAndPrefAlign {
abi: Align(1 bytes),
pref: Align(8 bytes),
},
abi: Aggregate {
sized: true,
},
fields: Arbitrary {
offsets: [],
memory_index: [],
},
largest_niche: None,
variants: Single {
index: 0,
},
max_repr_align: None,
unadjusted_abi_align: Align(1 bytes),
},
Layout {
size: Size(4 bytes),
align: AbiAndPrefAlign {
abi: Align(4 bytes),
pref: Align(8 bytes),
},
abi: Scalar(
Initialized {
value: Int(
I32,
false,
),
valid_range: 1..=4294967295,
},
),
fields: Arbitrary {
offsets: [
Size(0 bytes),
],
memory_index: [
0,
],
},
largest_niche: Some(
Niche {
offset: Size(0 bytes),
value: Int(
I32,
false,
),
valid_range: 1..=4294967295,
},
),
variants: Single {
index: 1,
},
max_repr_align: None,
unadjusted_abi_align: Align(4 bytes),
},
],
},
max_repr_align: None,
unadjusted_abi_align: Align(4 bytes),
}
--> $DIR/range_patterns.rs:15:1
|
LL | type A = Option<std::num::NonZeroU32>;
| ^^^^^^
error: layout_of(NonZeroU32New) = Layout {
size: Size(4 bytes),
align: AbiAndPrefAlign {
abi: Align(4 bytes),
pref: Align(8 bytes),
},
abi: Scalar(
Initialized {
value: Int(
I32,
false,
),
valid_range: 1..=4294967295,
},
),
fields: Arbitrary {
offsets: [
Size(0 bytes),
],
memory_index: [
0,
],
},
largest_niche: Some(
Niche {
offset: Size(0 bytes),
value: Int(
I32,
false,
),
valid_range: 1..=4294967295,
},
),
variants: Single {
index: 0,
},
max_repr_align: None,
unadjusted_abi_align: Align(4 bytes),
}
--> $DIR/range_patterns.rs:17:1
|
LL | struct NonZeroU32New(pattern_type!(u32 is 1..));
| ^^^^^^^^^^^^^^^^^^^^
error: aborting due to 5 previous errors

View file

@ -0,0 +1,30 @@
#![feature(pattern_types, rustc_attrs)]
#![feature(core_pattern_type)]
#![feature(core_pattern_types)]
#![allow(incomplete_features)]
//! check that pattern types can have traits implemented for them if
//! their base type is a local type.
use std::pat::pattern_type;
type Y = pattern_type!(u32 is 1..);
impl Y {
//~^ ERROR cannot define inherent `impl`
fn foo() {}
}
struct MyStruct<T>(T);
impl MyStruct<Y> {
fn foo() {}
}
struct Wrapper(Y);
impl Wrapper {
fn foo() {}
}
fn main() {}

View file

@ -0,0 +1,16 @@
error[E0390]: cannot define inherent `impl` for primitive types outside of `core`
--> $DIR/range_patterns_inherent_impls.rs:13:1
|
LL | impl Y {
| ^^^^^^
|
= help: consider moving this inherent impl into `core` if possible
help: alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
--> $DIR/range_patterns_inherent_impls.rs:15:5
|
LL | fn foo() {}
| ^^^^^^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0390`.

View file

@ -0,0 +1,19 @@
#![feature(pattern_types, rustc_attrs)]
#![feature(core_pattern_type)]
#![feature(core_pattern_types)]
#![allow(incomplete_features)]
//! check that pattern types can have local traits
//! implemented for them.
//@ check-pass
use std::pat::pattern_type;
type Y = pattern_type!(u32 is 1..);
trait Trait {}
impl Trait for Y {}
fn main() {}

View file

@ -0,0 +1,16 @@
#![feature(pattern_types, rustc_attrs)]
#![feature(core_pattern_type)]
#![feature(core_pattern_types)]
#![allow(incomplete_features)]
//! check that pattern types can have local traits
//! implemented for them.
use std::pat::pattern_type;
type Y = pattern_type!(u32 is 1..);
impl Eq for Y {}
//~^ ERROR: only traits defined in the current crate can be implemented for arbitrary types
fn main() {}

View file

@ -0,0 +1,14 @@
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/range_patterns_trait_impls2.rs:13:1
|
LL | impl Eq for Y {}
| ^^^^^^^^^^^^-
| | |
| | `(u32) is 1..=` is not defined in the current crate
| impl doesn't use only types from inside the current crate
|
= note: define and implement a trait or new type instead
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0117`.

View file

@ -0,0 +1,15 @@
#![feature(pattern_types, rustc_attrs)]
#![feature(core_pattern_type)]
#![feature(core_pattern_types)]
#![allow(incomplete_features)]
//! Some practical niche checks.
use std::pat::pattern_type;
type Z = Option<pattern_type!(u32 is 1..)>;
fn main() {
let z: Z = Some(unsafe { std::mem::transmute(42_u32) });
let _: Option<u32> = unsafe { std::mem::transmute(z) }; //~ ERROR: different sizes
}

View file

@ -0,0 +1,12 @@
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/range_patterns_unusable.rs:14:35
|
LL | let _: Option<u32> = unsafe { std::mem::transmute(z) };
| ^^^^^^^^^^^^^^^^^^^
|
= note: source type: `Option<(u32) is 1..=>` (32 bits)
= note: target type: `Option<u32>` (64 bits)
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0512`.

View file

@ -0,0 +1,16 @@
#![feature(pattern_types, rustc_attrs)]
#![feature(core_pattern_type)]
#![feature(core_pattern_types)]
#![allow(incomplete_features)]
//! check that pattern types don't have an `Add` impl.
use std::pat::pattern_type;
type Y = pattern_type!(u32 is 1..);
type Z = Option<pattern_type!(u32 is 1..)>;
fn main() {
let x: Y = unsafe { std::mem::transmute(42_u32) };
let x = x + 1_u32; //~ ERROR cannot add `u32` to `(u32) is 1..=`
}

View file

@ -0,0 +1,11 @@
error[E0369]: cannot add `u32` to `(u32) is 1..=`
--> $DIR/range_patterns_unusable_math.rs:15:15
|
LL | let x = x + 1_u32;
| - ^ ----- u32
| |
| (u32) is 1..=
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0369`.

View file

@ -0,0 +1,26 @@
#![feature(pattern_types, rustc_attrs)]
#![feature(core_pattern_type)]
#![feature(core_pattern_types)]
#![allow(incomplete_features)]
//@ check-pass
//! check that pattern types can actually be part of code that compiles successfully.
use std::pat::pattern_type;
type X = std::num::NonZeroU32;
type Y = pattern_type!(u32 is 1..);
type Z = Option<pattern_type!(u32 is 1..)>;
struct NonZeroU32New(pattern_type!(u32 is 1..));
fn main() {
let x: Y = unsafe { std::mem::transmute(42_u32) };
let z: Z = Some(unsafe { std::mem::transmute(42_u32) });
match z {
Some(y) => {
let _: Y = y;
}
None => {}
}
let x: X = unsafe { std::mem::transmute(x) };
}