Skip to content

Commit

Permalink
Actually create ranged int types in the type system.
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed Apr 8, 2024
1 parent 6b24a9c commit 84acfe8
Show file tree
Hide file tree
Showing 97 changed files with 1,208 additions and 77 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_ast_lowering/src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,4 +381,8 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
ArrayLen::Body(..) => intravisit::walk_array_len(self, len),
}
}

fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) {
self.visit_pat(p)
}
}
2 changes: 2 additions & 0 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1606,6 +1606,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::FnDef(_, _)
| ty::FnPtr(_)
Expand Down Expand Up @@ -1648,6 +1649,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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$<");
Expand Down
16 changes: 14 additions & 2 deletions compiler/rustc_const_eval/src/const_eval/valtrees.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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`).
Expand Down Expand Up @@ -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
Expand All @@ -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)
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_const_eval/src/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1060,6 +1060,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {

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,

Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
| ty::Str
| ty::Dynamic(..)
| ty::Closure(..)
| ty::Pat(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..) => Ok(false),
// Some types only occur during typechecking, they have no layout.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/util/type_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
| ty::Uint(_)
| ty::Float(_)
| ty::Str
| ty::Pat(_, _)
| ty::Array(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>),
}

Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,11 @@ pub trait Visitor<'v>: Sized {
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)
}
Expand Down Expand Up @@ -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()
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
8 changes: 7 additions & 1 deletion compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,12 @@ impl<'tcx> InherentCollect<'tcx> {
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),
Expand All @@ -154,6 +159,7 @@ impl<'tcx> InherentCollect<'tcx> {
ty::Dynamic(..) => {
Err(self.tcx.dcx().emit_err(errors::InherentDyn { span: item_span }))
}
ty::Pat(_, _) => unreachable!(),
ty::Bool
| ty::Char
| ty::Int(_)
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_hir_analysis/src/coherence/orphan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,11 @@ pub(crate) fn orphan_check_impl(
(LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther)
}

ty::Pat(..) => (
LocalImpl::Disallow { problematic_kind: "pattern type" },
NonlocalImpl::DisallowOther,
),

ty::Bool
| ty::Char
| ty::Int(..)
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
68 changes: 59 additions & 9 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use rustc_hir::{GenericArg, GenericArgs};
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,
Expand Down Expand Up @@ -2195,15 +2196,64 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// 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),
};

Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_hir_analysis/src/variance/constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,20 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
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);
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| ty::CoroutineWitness(..)
| ty::RawPtr(_, _)
| ty::Ref(..)
| ty::Pat(..)
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::Closure(..)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
| ty::Tuple(..)
| ty::Alias(..)
| ty::Foreign(..)
| ty::Pat(..)
| ty::Param(..) => {
if t.flags().intersects(self.needs_canonical_flags) {
t.super_fold_with(self)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_infer/src/infer/outlives/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_lint/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1379,6 +1379,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
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 }
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_middle/src/ty/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,12 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Const<'tcx> {
}
}

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)
Expand Down Expand Up @@ -364,6 +370,12 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Const<'tcx> {
}
}

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
Expand Down
Loading

0 comments on commit 84acfe8

Please sign in to comment.