Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exhaustiveness checking: work around type normalization issues #72506

Merged
merged 4 commits into from
May 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 30 additions & 19 deletions src/librustc_mir_build/hair/pattern/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1025,11 +1025,11 @@ enum Fields<'p, 'tcx> {
/// have not measured if it really made a difference.
Slice(&'p [Pat<'tcx>]),
Vec(SmallVec<[&'p Pat<'tcx>; 2]>),
/// Patterns where some of the fields need to be hidden. `len` caches the number of non-hidden
/// fields.
/// Patterns where some of the fields need to be hidden. `kept_count` caches the number of
/// non-hidden fields.
Filtered {
fields: SmallVec<[FilteredField<'p, 'tcx>; 2]>,
len: usize,
kept_count: usize,
},
}

Expand Down Expand Up @@ -1066,10 +1066,9 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
constructor: &Constructor<'tcx>,
ty: Ty<'tcx>,
) -> Self {
debug!("Fields::wildcards({:#?}, {:?})", constructor, ty);
let wildcard_from_ty = |ty| &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty));

match constructor {
let ret = match constructor {
Single | Variant(_) => match ty.kind {
ty::Tuple(ref fs) => {
Fields::wildcards_from_tys(cx, fs.into_iter().map(|ty| ty.expect_ty()))
Expand All @@ -1093,7 +1092,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
if has_no_hidden_fields {
Fields::wildcards_from_tys(cx, field_tys)
} else {
let mut len = 0;
let mut kept_count = 0;
let fields = variant
.fields
.iter()
Expand All @@ -1110,12 +1109,12 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
if is_uninhabited && (!is_visible || is_non_exhaustive) {
FilteredField::Hidden(ty)
} else {
len += 1;
kept_count += 1;
FilteredField::Kept(wildcard_from_ty(ty))
}
})
.collect();
Fields::Filtered { fields, len }
Fields::Filtered { fields, kept_count }
}
}
}
Expand All @@ -1129,14 +1128,19 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
_ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
},
ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => Fields::empty(),
}
};
debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
ret
}

/// Returns the number of patterns from the viewpoint of match-checking, i.e. excluding hidden
/// fields. This is what we want in most cases in this file, the only exception being
/// conversion to/from `Pat`.
fn len(&self) -> usize {
match self {
Fields::Slice(pats) => pats.len(),
Fields::Vec(pats) => pats.len(),
Fields::Filtered { len, .. } => *len,
Fields::Filtered { kept_count, .. } => *kept_count,
}
}

Expand Down Expand Up @@ -1206,7 +1210,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
let pats: &[_] = cx.pattern_arena.alloc_from_iter(pats);

match self {
Fields::Filtered { fields, len } => {
Fields::Filtered { fields, kept_count } => {
let mut pats = pats.iter();
let mut fields = fields.clone();
for f in &mut fields {
Expand All @@ -1215,7 +1219,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
*p = pats.next().unwrap();
}
}
Fields::Filtered { fields, len: *len }
Fields::Filtered { fields, kept_count: *kept_count }
}
_ => Fields::Slice(pats),
}
Expand Down Expand Up @@ -1866,11 +1870,13 @@ crate fn is_useful<'p, 'tcx>(
return if any_is_useful { Useful(unreachable_pats) } else { NotUseful };
}

let pcx = PatCtxt { ty: v.head().ty, span: v.head().span };
// FIXME(Nadrieril): Hack to work around type normalization issues (see #72476).
let ty = matrix.heads().next().map(|r| r.ty).unwrap_or(v.head().ty);
let pcx = PatCtxt { ty, span: v.head().span };

debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v.head());

if let Some(constructor) = pat_constructor(cx.tcx, cx.param_env, v.head()) {
let ret = if let Some(constructor) = pat_constructor(cx.tcx, cx.param_env, v.head()) {
debug!("is_useful - expanding constructor: {:#?}", constructor);
split_grouped_constructors(
cx.tcx,
Expand Down Expand Up @@ -1901,11 +1907,11 @@ crate fn is_useful<'p, 'tcx>(

let used_ctors: Vec<Constructor<'_>> =
matrix.heads().filter_map(|p| pat_constructor(cx.tcx, cx.param_env, p)).collect();
debug!("used_ctors = {:#?}", used_ctors);
debug!("is_useful_used_ctors = {:#?}", used_ctors);
// `all_ctors` are all the constructors for the given type, which
// should all be represented (or caught with the wild pattern `_`).
let all_ctors = all_constructors(cx, pcx);
debug!("all_ctors = {:#?}", all_ctors);
debug!("is_useful_all_ctors = {:#?}", all_ctors);

// `missing_ctors` is the set of constructors from the same type as the
// first column of `matrix` that are matched only by wildcard patterns
Expand All @@ -1920,7 +1926,7 @@ crate fn is_useful<'p, 'tcx>(
// can be big.
let missing_ctors = MissingConstructors::new(all_ctors, used_ctors);

debug!("missing_ctors.empty()={:#?}", missing_ctors.is_empty(),);
debug!("is_useful_missing_ctors.empty()={:#?}", missing_ctors.is_empty(),);

if missing_ctors.is_empty() {
let (all_ctors, _) = missing_ctors.into_inner();
Expand Down Expand Up @@ -1988,7 +1994,9 @@ crate fn is_useful<'p, 'tcx>(
usefulness.apply_missing_ctors(cx, pcx.ty, &missing_ctors)
}
}
}
};
debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret);
ret
}

/// A shorthand for the `U(S(c, P), S(c, q))` operation from the paper. I.e., `is_useful` applied
Expand Down Expand Up @@ -2647,7 +2655,10 @@ fn specialize_one_pattern<'p, 'tcx>(

PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
};
debug!("specialize({:#?}, {:#?}) = {:#?}", pat, ctor_wild_subpatterns, result);
debug!(
"specialize({:#?}, {:#?}, {:#?}) = {:#?}",
pat, constructor, ctor_wild_subpatterns, result
);

result
}
22 changes: 22 additions & 0 deletions src/test/ui/pattern/usefulness/issue-72476-associated-type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// check-pass

// From https://github.com/rust-lang/rust/issues/72476

trait A {
type Projection;
}

impl A for () {
type Projection = bool;
}

struct Next<T: A>(T::Projection);

fn f(item: Next<()>) {
match item {
Next(true) => {}
Next(false) => {}
}
}

fn main() {}