Check bindings around never patterns
This commit is contained in:
parent
b31735a401
commit
560beb1ad4
13 changed files with 110 additions and 105 deletions
|
@ -960,6 +960,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
.create_err(errs::TraitImplDuplicate { span, name, trait_item_span, old_span }),
|
||||
ResolutionError::InvalidAsmSym => self.dcx().create_err(errs::InvalidAsmSym { span }),
|
||||
ResolutionError::LowercaseSelf => self.dcx().create_err(errs::LowercaseSelf { span }),
|
||||
ResolutionError::BindingInNeverPattern => {
|
||||
self.dcx().create_err(errs::BindingInNeverPattern { span })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -486,6 +486,15 @@ pub(crate) struct LowercaseSelf {
|
|||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_binding_in_never_pattern)]
|
||||
pub(crate) struct BindingInNeverPattern {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "_", applicability = "machine-applicable", style = "short")]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_trait_impl_duplicate, code = "E0201")]
|
||||
pub(crate) struct TraitImplDuplicate {
|
||||
|
|
|
@ -65,6 +65,8 @@ enum IsRepeatExpr {
|
|||
Yes,
|
||||
}
|
||||
|
||||
struct IsNeverPattern;
|
||||
|
||||
/// Describes whether an `AnonConst` is a type level const arg or
|
||||
/// some other form of anon const (i.e. inline consts or enum discriminants)
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -3191,11 +3193,15 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
}
|
||||
|
||||
/// Build a map from pattern identifiers to binding-info's, and check the bindings are
|
||||
/// consistent when encountering or-patterns.
|
||||
/// consistent when encountering or-patterns and never patterns.
|
||||
/// This is done hygienically: this could arise for a macro that expands into an or-pattern
|
||||
/// where one 'x' was from the user and one 'x' came from the macro.
|
||||
fn compute_and_check_binding_map(&mut self, pat: &Pat) -> FxIndexMap<Ident, BindingInfo> {
|
||||
fn compute_and_check_binding_map(
|
||||
&mut self,
|
||||
pat: &Pat,
|
||||
) -> Result<FxIndexMap<Ident, BindingInfo>, IsNeverPattern> {
|
||||
let mut binding_map = FxIndexMap::default();
|
||||
let mut is_never_pat = false;
|
||||
|
||||
pat.walk(&mut |pat| {
|
||||
match pat.kind {
|
||||
|
@ -3207,17 +3213,26 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
PatKind::Or(ref ps) => {
|
||||
// Check the consistency of this or-pattern and
|
||||
// then add all bindings to the larger map.
|
||||
let bm = self.compute_and_check_or_pat_binding_map(ps);
|
||||
let (bm, np) = self.compute_and_check_or_pat_binding_map(ps);
|
||||
binding_map.extend(bm);
|
||||
is_never_pat |= np;
|
||||
return false;
|
||||
}
|
||||
PatKind::Never => is_never_pat = true,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
true
|
||||
});
|
||||
|
||||
binding_map
|
||||
if is_never_pat {
|
||||
for (_, binding) in binding_map {
|
||||
self.report_error(binding.span, ResolutionError::BindingInNeverPattern);
|
||||
}
|
||||
Err(IsNeverPattern)
|
||||
} else {
|
||||
Ok(binding_map)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_base_res_local(&self, nid: NodeId) -> bool {
|
||||
|
@ -3229,24 +3244,29 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
|
||||
/// Compute the binding map for an or-pattern. Checks that all of the arms in the or-pattern
|
||||
/// have exactly the same set of bindings, with the same binding modes for each.
|
||||
/// Returns the computed binding map.
|
||||
/// Returns the computed binding map and a boolean indicating whether the pattern is a never
|
||||
/// pattern.
|
||||
fn compute_and_check_or_pat_binding_map(
|
||||
&mut self,
|
||||
pats: &[P<Pat>],
|
||||
) -> FxIndexMap<Ident, BindingInfo> {
|
||||
) -> (FxIndexMap<Ident, BindingInfo>, bool) {
|
||||
let mut missing_vars = FxIndexMap::default();
|
||||
let mut inconsistent_vars = FxIndexMap::default();
|
||||
|
||||
// 1) Compute the binding maps of all arms.
|
||||
let maps =
|
||||
pats.iter().map(|pat| self.compute_and_check_binding_map(pat)).collect::<Vec<_>>();
|
||||
// 1) Compute the binding maps of all arms; never patterns don't participate in this.
|
||||
let not_never_pats = pats
|
||||
.iter()
|
||||
.filter_map(|pat| {
|
||||
let binding_map = self.compute_and_check_binding_map(pat).ok()?;
|
||||
Some((binding_map, pat))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// 2) Record any missing bindings or binding mode inconsistencies.
|
||||
for (map_outer, pat_outer) in maps.iter().zip(pats.iter()) {
|
||||
for (map_outer, pat_outer) in not_never_pats.iter() {
|
||||
// Check against all arms except for the same pattern which is always self-consistent.
|
||||
let inners = maps
|
||||
let inners = not_never_pats
|
||||
.iter()
|
||||
.zip(pats.iter())
|
||||
.filter(|(_, pat)| pat.id != pat_outer.id)
|
||||
.flat_map(|(map, _)| map);
|
||||
|
||||
|
@ -3294,22 +3314,17 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
}
|
||||
|
||||
// 5) Bubble up the final binding map.
|
||||
let is_never_pat = not_never_pats.is_empty();
|
||||
let mut binding_map = FxIndexMap::default();
|
||||
for bm in maps {
|
||||
for (bm, _) in not_never_pats {
|
||||
binding_map.extend(bm);
|
||||
}
|
||||
binding_map
|
||||
(binding_map, is_never_pat)
|
||||
}
|
||||
|
||||
/// Check the consistency of bindings wrt or-patterns.
|
||||
/// Check the consistency of bindings wrt or-patterns and never patterns.
|
||||
fn check_consistent_bindings(&mut self, pat: &'ast Pat) {
|
||||
pat.walk(&mut |pat| match pat.kind {
|
||||
PatKind::Or(ref ps) => {
|
||||
let _ = self.compute_and_check_or_pat_binding_map(ps);
|
||||
false
|
||||
}
|
||||
_ => true,
|
||||
})
|
||||
let _ = self.compute_and_check_binding_map(pat);
|
||||
}
|
||||
|
||||
fn resolve_arm(&mut self, arm: &'ast Arm) {
|
||||
|
|
|
@ -265,6 +265,8 @@ enum ResolutionError<'a> {
|
|||
InvalidAsmSym,
|
||||
/// `self` used instead of `Self` in a generic parameter
|
||||
LowercaseSelf,
|
||||
/// A never pattern has a binding.
|
||||
BindingInNeverPattern,
|
||||
}
|
||||
|
||||
enum VisResolutionError<'a> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue