Skip to content

Commit

Permalink
support pattern as const parents in type_of
Browse files Browse the repository at this point in the history
  • Loading branch information
lcnr committed Dec 31, 2020
1 parent e226704 commit 2aef46b
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 11 deletions.
10 changes: 5 additions & 5 deletions compiler/rustc_hir/src/hir.rs
Expand Up @@ -760,9 +760,9 @@ pub struct Pat<'hir> {
pub default_binding_modes: bool,
}

impl Pat<'_> {
impl<'hir> Pat<'hir> {
// FIXME(#19596) this is a workaround, but there should be a better way
fn walk_short_(&self, it: &mut impl FnMut(&Pat<'_>) -> bool) -> bool {
fn walk_short_(&self, it: &mut impl FnMut(&Pat<'hir>) -> bool) -> bool {
if !it(self) {
return false;
}
Expand All @@ -785,12 +785,12 @@ impl Pat<'_> {
/// Note that when visiting e.g. `Tuple(ps)`,
/// if visiting `ps[0]` returns `false`,
/// then `ps[1]` will not be visited.
pub fn walk_short(&self, mut it: impl FnMut(&Pat<'_>) -> bool) -> bool {
pub fn walk_short(&self, mut it: impl FnMut(&Pat<'hir>) -> bool) -> bool {
self.walk_short_(&mut it)
}

// FIXME(#19596) this is a workaround, but there should be a better way
fn walk_(&self, it: &mut impl FnMut(&Pat<'_>) -> bool) {
fn walk_(&self, it: &mut impl FnMut(&Pat<'hir>) -> bool) {
if !it(self) {
return;
}
Expand All @@ -810,7 +810,7 @@ impl Pat<'_> {
/// Walk the pattern in left-to-right order.
///
/// If `it(pat)` returns `false`, the children are not visited.
pub fn walk(&self, mut it: impl FnMut(&Pat<'_>) -> bool) {
pub fn walk(&self, mut it: impl FnMut(&Pat<'hir>) -> bool) {
self.walk_(&mut it)
}

Expand Down
52 changes: 46 additions & 6 deletions compiler/rustc_typeck/src/collect/type_of.rs
Expand Up @@ -6,7 +6,7 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit;
use rustc_hir::intravisit::Visitor;
use rustc_hir::Node;
use rustc_hir::{HirId, Node};
use rustc_middle::hir::map::Map;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::util::IntTypeExt;
Expand All @@ -22,7 +22,6 @@ use super::{bad_placeholder_type, is_suggestable_infer_ty};
/// This should be called using the query `tcx.opt_const_param_of`.
pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> {
use hir::*;

let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);

if let Node::AnonConst(_) = tcx.hir().get(hir_id) {
Expand Down Expand Up @@ -62,9 +61,9 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
}

Node::Ty(&Ty { kind: TyKind::Path(_), .. })
| Node::Expr(&Expr { kind: ExprKind::Struct(..), .. })
| Node::Expr(&Expr { kind: ExprKind::Path(_), .. })
| Node::TraitRef(..) => {
| Node::Expr(&Expr { kind: ExprKind::Path(_) | ExprKind::Struct(..), .. })
| Node::TraitRef(..)
| Node::Pat(_) => {
let path = match parent_node {
Node::Ty(&Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. })
| Node::TraitRef(&TraitRef { path, .. }) => &*path,
Expand All @@ -79,6 +78,20 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
let _tables = tcx.typeck(body_owner);
&*path
}
Node::Pat(pat) => {
if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) {
path
} else {
tcx.sess.delay_span_bug(
tcx.def_span(def_id),
&format!(
"unable to find const parent for {} in pat {:?}",
hir_id, pat
),
);
return None;
}
}
_ => {
tcx.sess.delay_span_bug(
tcx.def_span(def_id),
Expand All @@ -91,7 +104,6 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
// We've encountered an `AnonConst` in some path, so we need to
// figure out which generic parameter it corresponds to and return
// the relevant type.

let (arg_index, segment) = path
.segments
.iter()
Expand Down Expand Up @@ -144,6 +156,34 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
}
}

fn get_path_containing_arg_in_pat<'hir>(
pat: &'hir hir::Pat<'hir>,
arg_id: HirId,
) -> Option<&'hir hir::Path<'hir>> {
use hir::*;

let is_arg_in_path = |p: &hir::Path<'_>| {
p.segments
.iter()
.filter_map(|seg| seg.args)
.flat_map(|args| args.args)
.any(|arg| arg.id() == arg_id)
};
let mut arg_path = None;
pat.walk(|pat| match pat.kind {
PatKind::Struct(QPath::Resolved(_, path), _, _)
| PatKind::TupleStruct(QPath::Resolved(_, path), _, _)
| PatKind::Path(QPath::Resolved(_, path))
if is_arg_in_path(path) =>
{
arg_path = Some(path);
false
}
_ => true,
});
arg_path
}

pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
let def_id = def_id.expect_local();
use rustc_hir::*;
Expand Down
23 changes: 23 additions & 0 deletions src/test/ui/const-generics/arg-in-pat-1.rs
@@ -0,0 +1,23 @@
// check-pass
enum ConstGenericEnum<const N: usize> {
Foo([i32; N]),
Bar,
}

fn foo<const N: usize>(val: &ConstGenericEnum<N>) {
if let ConstGenericEnum::<N>::Foo(field, ..) = val {}
}

fn bar<const N: usize>(val: &ConstGenericEnum<N>) {
match val {
ConstGenericEnum::<N>::Foo(field, ..) => (),
ConstGenericEnum::<N>::Bar => (),
}
}

fn main() {
match ConstGenericEnum::Bar {
ConstGenericEnum::<3>::Foo(field, ..) => (),
ConstGenericEnum::<3>::Bar => (),
}
}
10 changes: 10 additions & 0 deletions src/test/ui/const-generics/arg-in-pat-2.rs
@@ -0,0 +1,10 @@
// check-pass
enum Generic<const N: usize> {
Variant,
}

fn main() {
match todo!() {
Generic::<0usize>::Variant => todo!()
}
}
43 changes: 43 additions & 0 deletions src/test/ui/const-generics/arg-in-pat-3.rs
@@ -0,0 +1,43 @@
// check-pass
struct Foo<const N: usize>;

fn bindingp() {
match Foo {
mut x @ Foo::<3> => {
let ref mut _x @ Foo::<3> = x;
}
}
}

struct Bar<const N: usize> {
field: Foo<N>,
}

fn structp() {
match todo!() {
Bar::<3> {
field: Foo::<3>,
} => (),
}
}

struct Baz<const N: usize>(Foo<N>);

fn tuplestructp() {
match Baz(Foo) {
Baz::<3>(Foo::<3>) => (),
}
}

impl<const N: usize> Baz<N> {
const ASSOC: usize = 3;
}

fn pathp() {
match 3 {
Baz::<3>::ASSOC => (),
_ => (),
}
}

fn main() {}

0 comments on commit 2aef46b

Please sign in to comment.