use syn::{self, visit};
use crate::interp;
use crate::util;
pub trait IsUninhabited {
fn is_uninhabited(&self) -> bool;
}
impl IsUninhabited for syn::DataEnum {
fn is_uninhabited(&self) -> bool {
self.variants.is_uninhabited()
}
}
impl<P> IsUninhabited for syn::punctuated::Punctuated<syn::Variant, P> {
fn is_uninhabited(&self) -> bool {
self.iter().all(IsUninhabited::is_uninhabited)
}
}
impl<'a> IsUninhabited for &'a [syn::Variant] {
fn is_uninhabited(&self) -> bool {
self.iter().all(IsUninhabited::is_uninhabited)
}
}
impl IsUninhabited for syn::Variant {
fn is_uninhabited(&self) -> bool {
self.fields.is_uninhabited()
}
}
impl IsUninhabited for syn::Fields {
fn is_uninhabited(&self) -> bool {
self.iter().any(syn::Field::is_uninhabited)
}
}
impl<'a> IsUninhabited for &'a [syn::Field] {
fn is_uninhabited(&self) -> bool {
self.iter().any(syn::Field::is_uninhabited)
}
}
impl IsUninhabited for syn::Field {
fn is_uninhabited(&self) -> bool {
self.ty.is_uninhabited()
}
}
impl IsUninhabited for syn::Type {
fn is_uninhabited(&self) -> bool {
let mut uninhabited = Uninhabited(false);
visit::visit_type(&mut uninhabited, &self);
uninhabited.0
}
}
struct Uninhabited(bool);
impl Uninhabited {
fn set(&mut self) {
self.0 = true;
}
}
impl<'ast> visit::Visit<'ast> for Uninhabited {
fn visit_type_never(&mut self, _: &'ast syn::TypeNever) {
self.set();
}
fn visit_type_path(&mut self, type_path: &'ast syn::TypePath) {
const KNOWN_UNINHABITED: &[&str] =
&["std::string::ParseError", "::std::string::ParseError"];
if type_path.qself.is_none()
&& util::match_pathsegs(&type_path.path, KNOWN_UNINHABITED)
{
self.set();
}
}
fn visit_type_array(&mut self, arr: &'ast syn::TypeArray) {
if let Some(len) = interp::eval_expr(&arr.len) {
if len > 0 {
self.visit_type(&arr.elem);
}
}
}
fn visit_type_bare_fn(&mut self, _: &'ast syn::TypeBareFn) {}
fn visit_macro(&mut self, _: &'ast syn::Macro) {}
fn visit_type_impl_trait(&mut self, _: &'ast syn::TypeImplTrait) {}
fn visit_type_trait_object(&mut self, _: &'ast syn::TypeTraitObject) {}
}