diff options
| author | David Wood <david@davidtw.co> | 2019-10-14 18:55:32 +0100 |
|---|---|---|
| committer | David Wood <david@davidtw.co> | 2019-10-23 22:10:58 +0100 |
| commit | 7ffbd62445b9706325d01ec8be8e70c41404fe0d (patch) | |
| tree | d968523abcb2a40c5dc6cc34f694d3bd999316c7 /src/librustc_mir | |
| parent | 4a8c5b20c7772bc5342b83d4b0696ea216ef75a7 (diff) | |
| download | rust-7ffbd62445b9706325d01ec8be8e70c41404fe0d.tar.gz rust-7ffbd62445b9706325d01ec8be8e70c41404fe0d.zip | |
ignore uninhabited non-exhaustive variant fields
This commit modifies the uninhabitedness checking so that the fields of a non-exhaustive variant (which is not local) are ignored if they are uninhabited. This is an improvement over the previous behaviour which considered all non-local non-exhaustive variants useful because unreachable patterns are now detected. Signed-off-by: David Wood <david@davidtw.co>
Diffstat (limited to 'src/librustc_mir')
| -rw-r--r-- | src/librustc_mir/hair/pattern/_match.rs | 88 |
1 files changed, 39 insertions, 49 deletions
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index dc6d4b27886..907c84b6f8c 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -394,16 +394,6 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } } - fn is_non_exhaustive_variant<'p>(&self, pattern: &'p Pat<'tcx>) -> bool { - match *pattern.kind { - PatKind::Variant { adt_def, variant_index, .. } => { - let ref variant = adt_def.variants[variant_index]; - variant.is_field_list_non_exhaustive() - } - _ => false, - } - } - fn is_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool { match ty.kind { ty::Adt(adt_def, ..) => adt_def.is_variant_list_non_exhaustive(), @@ -1252,19 +1242,12 @@ pub fn is_useful<'p, 'a, 'tcx>( debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]); if let Some(constructors) = pat_constructors(cx, v[0], pcx) { - let is_declared_nonexhaustive = cx.is_non_exhaustive_variant(v[0]) && !cx.is_local(pcx.ty); - debug!("is_useful - expanding constructors: {:#?}, is_declared_nonexhaustive: {:?}", - constructors, is_declared_nonexhaustive); - - if is_declared_nonexhaustive { - Useful - } else { - split_grouped_constructors( - cx.tcx, cx.param_env, constructors, matrix, pcx.ty, pcx.span, Some(hir_id), - ).into_iter().map(|c| - is_useful_specialized(cx, matrix, v, c, pcx.ty, witness, hir_id) - ).find(|result| result.is_useful()).unwrap_or(NotUseful) - } + debug!("is_useful - expanding constructors: {:#?}", constructors); + split_grouped_constructors( + cx.tcx, cx.param_env, constructors, matrix, pcx.ty, pcx.span, Some(hir_id), + ).into_iter().map(|c| + is_useful_specialized(cx, matrix, v, c, pcx.ty, witness, hir_id) + ).find(|result| result.is_useful()).unwrap_or(NotUseful) } else { debug!("is_useful - expanding wildcard"); @@ -1548,27 +1531,30 @@ fn constructor_sub_pattern_tys<'a, 'tcx>( // Use T as the sub pattern type of Box<T>. vec![substs.type_at(0)] } else { - adt.variants[ctor.variant_index_for_adt(cx, adt)].fields.iter().map(|field| { + let variant = &adt.variants[ctor.variant_index_for_adt(cx, adt)]; + let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !cx.is_local(ty); + variant.fields.iter().map(|field| { let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); - if is_visible { - let ty = field.ty(cx.tcx, substs); - match ty.kind { - // If the field type returned is an array of an unknown - // size return an TyErr. - ty::Array(_, len) - if len.try_eval_usize(cx.tcx, cx.param_env).is_none() => - cx.tcx.types.err, - _ => ty, - } - } else { - // Treat all non-visible fields as TyErr. They - // can't appear in any other pattern from - // this match (because they are private), - // so their type does not matter - but - // we don't want to know they are - // uninhabited. - cx.tcx.types.err + let is_uninhabited = cx.is_uninhabited(field.ty(cx.tcx, substs)); + match (is_visible, is_non_exhaustive, is_uninhabited) { + // Treat all uninhabited types in non-exhaustive variants as `TyErr`. + (_, true, true) => cx.tcx.types.err, + // Treat all non-visible fields as `TyErr`. They can't appear in any + // other pattern from this match (because they are private), so their + // type does not matter - but we don't want to know they are uninhabited. + (false, ..) => cx.tcx.types.err, + (true, ..) => { + let ty = field.ty(cx.tcx, substs); + match ty.kind { + // If the field type returned is an array of an unknown + // size return an TyErr. + ty::Array(_, len) + if len.try_eval_usize(cx.tcx, cx.param_env).is_none() => + cx.tcx.types.err, + _ => ty, + } + }, } }).collect() } @@ -1874,15 +1860,18 @@ fn constructor_covered_by_range<'tcx>( } } -fn patterns_for_variant<'p, 'tcx>( +fn patterns_for_variant<'p, 'a: 'p, 'tcx>( + cx: &mut MatchCheckCtxt<'a, 'tcx>, subpatterns: &'p [FieldPat<'tcx>], - wild_patterns: &[&'p Pat<'tcx>]) - -> SmallVec<[&'p Pat<'tcx>; 2]> -{ + wild_patterns: &[&'p Pat<'tcx>], + is_non_exhaustive: bool, +) -> SmallVec<[&'p Pat<'tcx>; 2]> { let mut result = SmallVec::from_slice(wild_patterns); for subpat in subpatterns { - result[subpat.field.index()] = &subpat.pattern; + if !is_non_exhaustive || !cx.is_uninhabited(subpat.pattern.ty) { + result[subpat.field.index()] = &subpat.pattern; + } } debug!("patterns_for_variant({:#?}, {:#?}) = {:#?}", subpatterns, wild_patterns, result); @@ -1916,13 +1905,14 @@ fn specialize<'p, 'a: 'p, 'tcx>( PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { let ref variant = adt_def.variants[variant_index]; + let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !cx.is_local(pat.ty); Some(Variant(variant.def_id)) .filter(|variant_constructor| variant_constructor == constructor) - .map(|_| patterns_for_variant(subpatterns, wild_patterns)) + .map(|_| patterns_for_variant(cx, subpatterns, wild_patterns, is_non_exhaustive)) } PatKind::Leaf { ref subpatterns } => { - Some(patterns_for_variant(subpatterns, wild_patterns)) + Some(patterns_for_variant(cx, subpatterns, wild_patterns, false)) } PatKind::Deref { ref subpattern } => { |
