Skip to main content

Model

Trait Model 

Source
pub trait Model {
    type Ty: Clone;

    // Required methods
    fn signature(&self, ty: &Self::Ty) -> Signature<Self::Ty>;
    fn fields(&self, ty: &Self::Ty, variant: u32, out: &mut Vec<Self::Ty>);

    // Provided methods
    fn is_empty(&self, ty: &Self::Ty) -> bool { ... }
    fn variant_name(&self, ty: &Self::Ty, variant: u32) -> Option<&str> { ... }
}
Expand description

A language’s constructor model.

The checker never sees the language’s types directly. It asks the model two questions about a type: what its Signature is (which constructors build its values), and what the field types of a constructor are. That is enough to decide exhaustiveness and usefulness for every type the signatures can describe: sums, products, booleans, bounded and unbounded integers, characters, opaque literals, arrays, and slices.

The model must answer consistently: the same type must get the same signature and fields every time during one check. A model that changes its answers mid-check is reported as Error::Model, never a panic.

Ty is whatever names a type in the language: an interned id is ideal, since the checker clones types as it descends into fields.

§Examples

A model for bool and Option<T>:

use match_lang::{Model, Signature};

#[derive(Clone)]
enum Ty {
    Bool,
    Option(Box<Ty>),
}

struct Lang;

impl Model for Lang {
    type Ty = Ty;

    fn signature(&self, ty: &Ty) -> Signature<Ty> {
        match ty {
            Ty::Bool => Signature::Bool,
            Ty::Option(_) => Signature::Sum { count: 2 },
        }
    }

    fn fields(&self, ty: &Ty, variant: u32, out: &mut Vec<Ty>) {
        // `None` (variant 0) has no fields; `Some` (variant 1) has one.
        if let (Ty::Option(inner), 1) = (ty, variant) {
            out.push((**inner).clone());
        }
    }

    fn variant_name(&self, ty: &Ty, variant: u32) -> Option<&str> {
        match (ty, variant) {
            (Ty::Option(_), 0) => Some("None"),
            (Ty::Option(_), 1) => Some("Some"),
            _ => None,
        }
    }
}

let mut fields = Vec::new();
Lang.fields(&Ty::Option(Box::new(Ty::Bool)), 1, &mut fields);
assert!(matches!(fields[..], [Ty::Bool]));

Required Associated Types§

Source

type Ty: Clone

A type of the language.

Required Methods§

Source

fn signature(&self, ty: &Self::Ty) -> Signature<Self::Ty>

The constructors that build values of ty.

§Examples
use match_lang::{Model, Signature};

struct Bytes;

impl Model for Bytes {
    type Ty = ();
    fn signature(&self, _: &()) -> Signature<()> {
        Signature::Int { min: 0, max: 255 }
    }
    fn fields(&self, _: &(), _: u32, _: &mut Vec<()>) {}
}

assert_eq!(Bytes.signature(&()), Signature::Int { min: 0, max: 255 });
Source

fn fields(&self, ty: &Self::Ty, variant: u32, out: &mut Vec<Self::Ty>)

Pushes onto out the field types of a constructor of ty, in field order: variant variant of a Sum, or the single constructor of a Product (variant is then 0). out is empty when called. It is not called for other signatures: booleans, integers, characters, and opaque literals have no fields, and arrays and slices name their element type in the signature.

§Examples
use match_lang::{Model, Signature};

// A model of `(bool, bool)`: the unit type `()` stands for `bool`
// inside, and `None` for the pair.
struct Pair;

impl Model for Pair {
    type Ty = Option<()>;
    fn signature(&self, ty: &Option<()>) -> Signature<Option<()>> {
        match ty {
            None => Signature::Product,
            Some(()) => Signature::Bool,
        }
    }
    fn fields(&self, _: &Option<()>, _: u32, out: &mut Vec<Option<()>>) {
        out.extend([Some(()), Some(())]);
    }
}

let mut out = Vec::new();
Pair.fields(&None, 0, &mut out);
assert_eq!(out.len(), 2);

Provided Methods§

Source

fn is_empty(&self, ty: &Self::Ty) -> bool

Whether ty has no values at all, like ! or an enum with no variants.

The checker treats a constructor as impossible when one of its fields is empty, so Err(_) is not required, and is reported unreachable, for a Result<T, !>. For that to be exact the answer should be deep: a tuple or struct with an empty field is itself empty. The default recognizes only Sum { count: 0 }.

§Examples
use match_lang::{Model, Signature};

struct Never;

impl Model for Never {
    type Ty = ();
    fn signature(&self, _: &()) -> Signature<()> {
        Signature::Sum { count: 0 }
    }
    fn fields(&self, _: &(), _: u32, _: &mut Vec<()>) {}
}

assert!(Never.is_empty(&()));
Source

fn variant_name(&self, ty: &Self::Ty, variant: u32) -> Option<&str>

A name for variant variant of ty (or, with variant 0, for a product type), used only when printing witnesses with Witness::display. Without a name a variant prints as #index and a product as a tuple.

§Examples
use match_lang::{Model, Signature};

struct Unit;

impl Model for Unit {
    type Ty = ();
    fn signature(&self, _: &()) -> Signature<()> {
        Signature::Product
    }
    fn fields(&self, _: &(), _: u32, _: &mut Vec<()>) {}
}

assert_eq!(Unit.variant_name(&(), 0), None);

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§