add guard patterns to HIR and implement lowering
This commit is contained in:
parent
d117b7f211
commit
b579c36224
11 changed files with 40 additions and 7 deletions
|
@ -120,8 +120,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
self.lower_range_end(end, e2.is_some()),
|
self.lower_range_end(end, e2.is_some()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// FIXME(guard_patterns): lower pattern guards to HIR
|
PatKind::Guard(inner, cond) => {
|
||||||
PatKind::Guard(inner, _) => pattern = inner,
|
break hir::PatKind::Guard(self.lower_pat(inner), self.lower_expr(cond));
|
||||||
|
}
|
||||||
PatKind::Slice(pats) => break self.lower_pat_slice(pats),
|
PatKind::Slice(pats) => break self.lower_pat_slice(pats),
|
||||||
PatKind::Rest => {
|
PatKind::Rest => {
|
||||||
// If we reach here the `..` pattern is not semantically allowed.
|
// If we reach here the `..` pattern is not semantically allowed.
|
||||||
|
|
|
@ -1385,7 +1385,7 @@ impl<'hir> Pat<'hir> {
|
||||||
use PatKind::*;
|
use PatKind::*;
|
||||||
match self.kind {
|
match self.kind {
|
||||||
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true,
|
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true,
|
||||||
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it),
|
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it),
|
||||||
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
|
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
|
||||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
|
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
|
||||||
Slice(before, slice, after) => {
|
Slice(before, slice, after) => {
|
||||||
|
@ -1412,7 +1412,7 @@ impl<'hir> Pat<'hir> {
|
||||||
use PatKind::*;
|
use PatKind::*;
|
||||||
match self.kind {
|
match self.kind {
|
||||||
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {}
|
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {}
|
||||||
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it),
|
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it),
|
||||||
Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
|
Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
|
||||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
|
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
|
||||||
Slice(before, slice, after) => {
|
Slice(before, slice, after) => {
|
||||||
|
@ -1564,6 +1564,9 @@ pub enum PatKind<'hir> {
|
||||||
/// A literal.
|
/// A literal.
|
||||||
Lit(&'hir Expr<'hir>),
|
Lit(&'hir Expr<'hir>),
|
||||||
|
|
||||||
|
/// A guard pattern (e.g., `x if guard(x)`).
|
||||||
|
Guard(&'hir Pat<'hir>, &'hir Expr<'hir>),
|
||||||
|
|
||||||
/// A range pattern (e.g., `1..=2` or `1..2`).
|
/// A range pattern (e.g., `1..=2` or `1..2`).
|
||||||
Range(Option<&'hir Expr<'hir>>, Option<&'hir Expr<'hir>>, RangeEnd),
|
Range(Option<&'hir Expr<'hir>>, Option<&'hir Expr<'hir>>, RangeEnd),
|
||||||
|
|
||||||
|
|
|
@ -696,6 +696,10 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
|
||||||
visit_opt!(visitor, visit_pat, slice_pattern);
|
visit_opt!(visitor, visit_pat, slice_pattern);
|
||||||
walk_list!(visitor, visit_pat, postpatterns);
|
walk_list!(visitor, visit_pat, postpatterns);
|
||||||
}
|
}
|
||||||
|
PatKind::Guard(subpat, condition) => {
|
||||||
|
try_visit!(visitor.visit_pat(subpat));
|
||||||
|
try_visit!(visitor.visit_expr(condition));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
V::Result::output()
|
V::Result::output()
|
||||||
}
|
}
|
||||||
|
|
|
@ -654,6 +654,7 @@ fn resolve_local<'tcx>(
|
||||||
/// | ( ..., P&, ... )
|
/// | ( ..., P&, ... )
|
||||||
/// | ... "|" P& "|" ...
|
/// | ... "|" P& "|" ...
|
||||||
/// | box P&
|
/// | box P&
|
||||||
|
/// | P& if ...
|
||||||
/// ```
|
/// ```
|
||||||
fn is_binding_pat(pat: &hir::Pat<'_>) -> bool {
|
fn is_binding_pat(pat: &hir::Pat<'_>) -> bool {
|
||||||
// Note that the code below looks for *explicit* refs only, that is, it won't
|
// Note that the code below looks for *explicit* refs only, that is, it won't
|
||||||
|
@ -694,7 +695,9 @@ fn resolve_local<'tcx>(
|
||||||
| PatKind::TupleStruct(_, subpats, _)
|
| PatKind::TupleStruct(_, subpats, _)
|
||||||
| PatKind::Tuple(subpats, _) => subpats.iter().any(|p| is_binding_pat(p)),
|
| PatKind::Tuple(subpats, _) => subpats.iter().any(|p| is_binding_pat(p)),
|
||||||
|
|
||||||
PatKind::Box(subpat) | PatKind::Deref(subpat) => is_binding_pat(subpat),
|
PatKind::Box(subpat) | PatKind::Deref(subpat) | PatKind::Guard(subpat, _) => {
|
||||||
|
is_binding_pat(subpat)
|
||||||
|
}
|
||||||
|
|
||||||
PatKind::Ref(_, _)
|
PatKind::Ref(_, _)
|
||||||
| PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..)
|
| PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..)
|
||||||
|
|
|
@ -1999,6 +1999,12 @@ impl<'a> State<'a> {
|
||||||
self.commasep(Inconsistent, after, |s, p| s.print_pat(p));
|
self.commasep(Inconsistent, after, |s, p| s.print_pat(p));
|
||||||
self.word("]");
|
self.word("]");
|
||||||
}
|
}
|
||||||
|
PatKind::Guard(inner, cond) => {
|
||||||
|
self.print_pat(inner);
|
||||||
|
self.space();
|
||||||
|
self.word_space("if");
|
||||||
|
self.print_expr(cond);
|
||||||
|
}
|
||||||
PatKind::Err(_) => {
|
PatKind::Err(_) => {
|
||||||
self.popen();
|
self.popen();
|
||||||
self.word("/*ERROR*/");
|
self.word("/*ERROR*/");
|
||||||
|
|
|
@ -457,6 +457,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// Does not constitute a read.
|
// Does not constitute a read.
|
||||||
hir::PatKind::Wild => false,
|
hir::PatKind::Wild => false,
|
||||||
|
|
||||||
|
// Might not constitute a read, since the condition might be false.
|
||||||
|
hir::PatKind::Guard(_, _) => true,
|
||||||
|
|
||||||
// This is unnecessarily restrictive when the pattern that doesn't
|
// This is unnecessarily restrictive when the pattern that doesn't
|
||||||
// constitute a read is unreachable.
|
// constitute a read is unreachable.
|
||||||
//
|
//
|
||||||
|
|
|
@ -615,6 +615,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
||||||
| PatKind::Box(_)
|
| PatKind::Box(_)
|
||||||
| PatKind::Deref(_)
|
| PatKind::Deref(_)
|
||||||
| PatKind::Ref(..)
|
| PatKind::Ref(..)
|
||||||
|
| PatKind::Guard(..)
|
||||||
| PatKind::Wild
|
| PatKind::Wild
|
||||||
| PatKind::Err(_) => {
|
| PatKind::Err(_) => {
|
||||||
// If the PatKind is Or, Box, or Ref, the decision is made later
|
// If the PatKind is Or, Box, or Ref, the decision is made later
|
||||||
|
@ -1737,7 +1738,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::Binding(.., Some(subpat)) => {
|
PatKind::Binding(.., Some(subpat)) | PatKind::Guard(subpat, _) => {
|
||||||
self.cat_pattern(place_with_id, subpat, op)?;
|
self.cat_pattern(place_with_id, subpat, op)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -284,6 +284,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
PatKind::Struct(ref qpath, fields, has_rest_pat) => {
|
PatKind::Struct(ref qpath, fields, has_rest_pat) => {
|
||||||
self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info)
|
self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info)
|
||||||
}
|
}
|
||||||
|
PatKind::Guard(pat, _) => {
|
||||||
|
self.check_pat(pat, expected, pat_info);
|
||||||
|
expected
|
||||||
|
}
|
||||||
PatKind::Or(pats) => {
|
PatKind::Or(pats) => {
|
||||||
for pat in pats {
|
for pat in pats {
|
||||||
self.check_pat(pat, expected, pat_info);
|
self.check_pat(pat, expected, pat_info);
|
||||||
|
@ -422,7 +426,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// An OR-pattern just propagates to each individual alternative.
|
// An OR-pattern just propagates to each individual alternative.
|
||||||
// This is maximally flexible, allowing e.g., `Some(mut x) | &Some(mut x)`.
|
// This is maximally flexible, allowing e.g., `Some(mut x) | &Some(mut x)`.
|
||||||
// In that example, `Some(mut x)` results in `Peel` whereas `&Some(mut x)` in `Reset`.
|
// In that example, `Some(mut x)` results in `Peel` whereas `&Some(mut x)` in `Reset`.
|
||||||
| PatKind::Or(_) => AdjustMode::Pass,
|
| PatKind::Or(_)
|
||||||
|
// Like or-patterns, guard patterns just propogate to their subpatterns.
|
||||||
|
| PatKind::Guard(..) => AdjustMode::Pass,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -901,6 +907,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
PatKind::Struct(..)
|
PatKind::Struct(..)
|
||||||
| PatKind::TupleStruct(..)
|
| PatKind::TupleStruct(..)
|
||||||
| PatKind::Or(..)
|
| PatKind::Or(..)
|
||||||
|
| PatKind::Guard(..)
|
||||||
| PatKind::Tuple(..)
|
| PatKind::Tuple(..)
|
||||||
| PatKind::Slice(..) => "binding",
|
| PatKind::Slice(..) => "binding",
|
||||||
|
|
||||||
|
|
|
@ -435,6 +435,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) },
|
hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) },
|
||||||
|
|
||||||
|
// FIXME(guard_patterns): implement guard pattern lowering
|
||||||
|
hir::PatKind::Guard(pat, _) => self.lower_pattern(pat).kind,
|
||||||
|
|
||||||
hir::PatKind::Err(guar) => PatKind::Error(guar),
|
hir::PatKind::Err(guar) => PatKind::Error(guar),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -305,6 +305,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
||||||
Deref,
|
Deref,
|
||||||
Ref,
|
Ref,
|
||||||
Lit,
|
Lit,
|
||||||
|
Guard,
|
||||||
Range,
|
Range,
|
||||||
Slice,
|
Slice,
|
||||||
Err
|
Err
|
||||||
|
|
|
@ -320,6 +320,7 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
|
||||||
);
|
);
|
||||||
return Symbol::intern("()");
|
return Symbol::intern("()");
|
||||||
}
|
}
|
||||||
|
PatKind::Guard(p, _) => return name_from_pat(&*p),
|
||||||
PatKind::Range(..) => return kw::Underscore,
|
PatKind::Range(..) => return kw::Underscore,
|
||||||
PatKind::Slice(begin, ref mid, end) => {
|
PatKind::Slice(begin, ref mid, end) => {
|
||||||
let begin = begin.iter().map(|p| name_from_pat(p).to_string());
|
let begin = begin.iter().map(|p| name_from_pat(p).to_string());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue