1
Fork 0

Recompute MissingConstructors when needed

This only happens in a slow (diagnostics) path, so the code clarity gain
is worth it.
This commit is contained in:
Nadrieril 2020-10-26 18:41:31 +00:00
parent b49f90760d
commit c96bd28ab3

View file

@ -1285,7 +1285,9 @@ impl<'tcx> Constructor<'tcx> {
IntRange(range) => return range.to_pat(pcx.cx.tcx), IntRange(range) => return range.to_pat(pcx.cx.tcx),
NonExhaustive => PatKind::Wild, NonExhaustive => PatKind::Wild,
Opaque => bug!("we should not try to apply an opaque constructor"), Opaque => bug!("we should not try to apply an opaque constructor"),
Wildcard => bug!("we should not try to apply a wildcard constructor"), Wildcard => bug!(
"trying to apply a wildcard constructor; this should have been done in `apply_constructors`"
),
}; };
Pat { ty: pcx.ty, span: DUMMY_SP, kind: Box::new(pat) } Pat { ty: pcx.ty, span: DUMMY_SP, kind: Box::new(pat) }
@ -1610,27 +1612,13 @@ impl<'tcx> Usefulness<'tcx> {
pcx: PatCtxt<'_, 'p, 'tcx>, pcx: PatCtxt<'_, 'p, 'tcx>,
ctor: &Constructor<'tcx>, ctor: &Constructor<'tcx>,
ctor_wild_subpatterns: &Fields<'p, 'tcx>, ctor_wild_subpatterns: &Fields<'p, 'tcx>,
) -> Self { is_top_level: bool,
match self {
UsefulWithWitness(witnesses) => UsefulWithWitness(
witnesses
.into_iter()
.map(|witness| witness.apply_constructor(pcx, &ctor, ctor_wild_subpatterns))
.collect(),
),
x => x,
}
}
fn apply_wildcard<'p>(
self,
pcx: PatCtxt<'_, 'p, 'tcx>,
missing_ctors: MissingConstructors<'tcx>,
) -> Self { ) -> Self {
match self { match self {
UsefulWithWitness(witnesses) => { UsefulWithWitness(witnesses) => {
let new_witnesses = if ctor.is_wildcard() {
let missing_ctors = MissingConstructors::new(pcx, is_top_level);
let new_patterns = missing_ctors.report_patterns(pcx); let new_patterns = missing_ctors.report_patterns(pcx);
UsefulWithWitness(
witnesses witnesses
.into_iter() .into_iter()
.flat_map(|witness| { .flat_map(|witness| {
@ -1640,8 +1628,14 @@ impl<'tcx> Usefulness<'tcx> {
witness witness
}) })
}) })
.collect(), .collect()
) } else {
witnesses
.into_iter()
.map(|witness| witness.apply_constructor(pcx, &ctor, ctor_wild_subpatterns))
.collect()
};
UsefulWithWitness(new_witnesses)
} }
x => x, x => x,
} }
@ -2419,7 +2413,17 @@ crate fn is_useful<'p, 'tcx>(
constructor constructor
.split(pcx, Some(hir_id)) .split(pcx, Some(hir_id))
.into_iter() .into_iter()
.map(|c| is_useful_specialized(pcx, v, c, witness_preference, hir_id, is_under_guard)) .map(|c| {
is_useful_specialized(
pcx,
v,
&c,
witness_preference,
hir_id,
is_under_guard,
is_top_level,
)
})
.find(|result| result.is_useful()) .find(|result| result.is_useful())
.unwrap_or(NotUseful) .unwrap_or(NotUseful)
} else { } else {
@ -2446,20 +2450,31 @@ crate fn is_useful<'p, 'tcx>(
.into_iter() .into_iter()
.flat_map(|ctor| ctor.split(pcx, None)) .flat_map(|ctor| ctor.split(pcx, None))
.map(|c| { .map(|c| {
is_useful_specialized(pcx, v, c, witness_preference, hir_id, is_under_guard) is_useful_specialized(
pcx,
v,
&c,
witness_preference,
hir_id,
is_under_guard,
is_top_level,
)
}) })
.find(|result| result.is_useful()) .find(|result| result.is_useful())
.unwrap_or(NotUseful) .unwrap_or(NotUseful)
} else { } else {
let ctor_wild_subpatterns = Fields::empty(); // Some constructors are missing, thus we can specialize with the wildcard constructor,
let matrix = matrix.specialize_constructor(pcx, &constructor, &ctor_wild_subpatterns); // which will stand for those constructors that are missing, and behaves like any of
// Unwrap is ok: v can always be specialized with its own constructor. // them.
let v = is_useful_specialized(
v.specialize_constructor(pcx, &constructor, &ctor_wild_subpatterns, true).unwrap(); pcx,
let usefulness = v,
is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); constructor,
witness_preference,
usefulness.apply_wildcard(pcx, missing_ctors) hir_id,
is_under_guard,
is_top_level,
)
} }
}; };
debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret); debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret);
@ -2471,20 +2486,22 @@ crate fn is_useful<'p, 'tcx>(
fn is_useful_specialized<'p, 'tcx>( fn is_useful_specialized<'p, 'tcx>(
pcx: PatCtxt<'_, 'p, 'tcx>, pcx: PatCtxt<'_, 'p, 'tcx>,
v: &PatStack<'p, 'tcx>, v: &PatStack<'p, 'tcx>,
ctor: Constructor<'tcx>, ctor: &Constructor<'tcx>,
witness_preference: WitnessPreference, witness_preference: WitnessPreference,
hir_id: HirId, hir_id: HirId,
is_under_guard: bool, is_under_guard: bool,
is_top_level: bool,
) -> Usefulness<'tcx> { ) -> Usefulness<'tcx> {
debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, pcx.ty); debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, pcx.ty);
// We cache the result of `Fields::wildcards` because it is used a lot. // We cache the result of `Fields::wildcards` because it is used a lot.
let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor); let ctor_wild_subpatterns = Fields::wildcards(pcx, ctor);
let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns); let matrix = pcx.matrix.specialize_constructor(pcx, ctor, &ctor_wild_subpatterns);
v.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns, true) // Unwrap is ok: v can always be specialized with its own constructor.
.map(|v| is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false)) let v = v.specialize_constructor(pcx, ctor, &ctor_wild_subpatterns, true).unwrap();
.map(|u| u.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns)) let usefulness =
.unwrap_or(NotUseful) is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
usefulness.apply_constructor(pcx, ctor, &ctor_wild_subpatterns, is_top_level)
} }
/// Determines the constructor that the given pattern can be specialized to. /// Determines the constructor that the given pattern can be specialized to.