From 6f3f8783517f939c1646eecc705872b7f18fe353 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 27 Jun 2023 16:56:58 +0000 Subject: [PATCH] Normalize types when applying uninhabited predicate. --- .../ty/inhabitedness/inhabited_predicate.rs | 13 +++++++- tests/ui/uninhabited/projection.rs | 32 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 tests/ui/uninhabited/projection.rs diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs index d48672b2baaee..018fa22715403 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -62,7 +62,18 @@ impl<'tcx> InhabitedPredicate<'tcx> { Some(1..) => Ok(false), }, Self::NotInModule(id) => in_module(id).map(|in_mod| !in_mod), - Self::GenericType(_) => Ok(true), + // `t` may be a projection, for which `inhabited_predicate` returns a `GenericType`. As + // we have a param_env available, we can do better. + Self::GenericType(t) => { + let normalized_pred = tcx + .try_normalize_erasing_regions(param_env, t) + .map_or(self, |t| t.inhabited_predicate(tcx)); + match normalized_pred { + // We don't have more information than we started with, so consider inhabited. + Self::GenericType(_) => Ok(true), + pred => pred.apply_inner(tcx, param_env, in_module), + } + } Self::And([a, b]) => try_and(a, b, |x| x.apply_inner(tcx, param_env, in_module)), Self::Or([a, b]) => try_or(a, b, |x| x.apply_inner(tcx, param_env, in_module)), } diff --git a/tests/ui/uninhabited/projection.rs b/tests/ui/uninhabited/projection.rs new file mode 100644 index 0000000000000..be0d3ff7da78f --- /dev/null +++ b/tests/ui/uninhabited/projection.rs @@ -0,0 +1,32 @@ +// check-pass + +#![feature(never_type, exhaustive_patterns)] + +trait Tag { + type TagType; +} + +enum Keep {} +enum Erase {} + +impl Tag for Keep { + type TagType = (); +} + +impl Tag for Erase { + type TagType = !; +} + +enum TagInt { + Untagged(i32), + Tagged(T::TagType, i32) +} + +fn test(keep: TagInt, erase: TagInt) { + match erase { + TagInt::Untagged(_) => (), + TagInt::Tagged(_, _) => () + }; +} + +fn main() {}