chore: rename usefulness module

This commit is contained in:
rvcas 2023-07-24 22:21:18 -04:00 committed by Lucas
parent 03efb46e6f
commit e8a71cd63b
3 changed files with 129 additions and 114 deletions

View File

@ -8,6 +8,7 @@ use uplc::{ast::Type as UplcType, builtins::DefaultFunction};
mod environment; mod environment;
pub mod error; pub mod error;
mod exhaustive;
mod expr; mod expr;
pub mod fields; pub mod fields;
mod hydrator; mod hydrator;

View File

@ -6,53 +6,69 @@ use crate::{
}; };
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct PatternStack { pub(crate) struct PatternStack(Vec<Pattern>);
pub(crate) patterns: Vec<Pattern>,
}
impl From<Pattern> for PatternStack { impl From<Pattern> for PatternStack {
fn from(value: Pattern) -> Self { fn from(value: Pattern) -> Self {
Self { Self(vec![value])
patterns: vec![value],
}
} }
} }
impl From<Vec<Pattern>> for PatternStack { impl From<Vec<Pattern>> for PatternStack {
fn from(value: Vec<Pattern>) -> Self { fn from(value: Vec<Pattern>) -> Self {
Self { patterns: value } Self(value)
}
}
impl From<PatternStack> for Vec<Pattern> {
fn from(value: PatternStack) -> Self {
value.0
} }
} }
impl PatternStack { impl PatternStack {
fn is_empty(&self) -> bool { fn is_empty(&self) -> bool {
self.patterns.is_empty() self.0.is_empty()
}
fn insert(&mut self, index: usize, element: Pattern) {
self.0.insert(index, element);
} }
fn head(&self) -> &Pattern { fn head(&self) -> &Pattern {
&self.patterns[0] &self.0[0]
} }
fn tail(&self) -> PatternStack { fn tail(&self) -> PatternStack {
PatternStack { self.0
patterns: self.patterns.iter().skip(1).cloned().collect(), .iter()
} .skip(1)
.cloned()
.collect::<Vec<Pattern>>()
.into()
} }
fn iter(&self) -> impl Iterator<Item = &Pattern> { fn iter(&self) -> impl Iterator<Item = &Pattern> {
self.patterns.iter() self.0.iter()
} }
fn chain_tail_to_iter<'a>(&'a self, front: impl Iterator<Item = &'a Pattern>) -> PatternStack { fn chain_tail_to_iter<'a>(&'a self, front: impl Iterator<Item = &'a Pattern>) -> PatternStack {
PatternStack { front
patterns: front.chain(self.iter().skip(1)).cloned().collect(), .chain(self.iter().skip(1))
} .cloned()
.collect::<Vec<Pattern>>()
.into()
} }
fn chain_tail_into_iter(&self, front: impl Iterator<Item = Pattern>) -> PatternStack { fn chain_tail_into_iter(&self, front: impl Iterator<Item = Pattern>) -> PatternStack {
PatternStack { front
patterns: front.chain(self.iter().skip(1).cloned()).collect(), .chain(
} self.iter()
.skip(1)
.cloned()
)
.collect::<Vec<Pattern>>()
.into()
} }
// INVARIANT: (length row == N) ==> (length result == arity + N - 1) // INVARIANT: (length row == N) ==> (length result == arity + N - 1)
@ -103,40 +119,48 @@ impl PatternStack {
), ),
} }
} }
fn split_at(self, arity: usize) -> (PatternStack, PatternStack) {
let mut rest = self.0;
let mut args = rest.split_off(arity);
std::mem::swap(&mut rest, &mut args);
(args.into(), rest.into())
}
} }
#[derive(Debug)] #[derive(Debug)]
pub(super) struct Matrix { pub(super) struct Matrix(Vec<PatternStack>);
pub patterns: Vec<PatternStack>,
}
impl Matrix { impl Matrix {
fn new() -> Self { fn new() -> Self {
Matrix { patterns: vec![] } Matrix(vec![])
} }
pub(crate) fn is_empty(&self) -> bool { pub(crate) fn is_empty(&self) -> bool {
self.patterns.is_empty() self.0.is_empty()
} }
pub(crate) fn push(&mut self, pattern_stack: PatternStack) { pub(crate) fn push(&mut self, pattern_stack: PatternStack) {
self.patterns.push(pattern_stack); self.0.push(pattern_stack);
} }
/// Iterate over the first component of each row /// Iterate over the first component of each row
pub(super) fn iter(&self) -> impl Iterator<Item = &PatternStack> { pub(super) fn iter(&self) -> impl Iterator<Item = &PatternStack> {
self.patterns.iter() self.0.iter()
} }
/// Iterate over the first component of each row, mutably /// Iterate over the first component of each row, mutably
pub(super) fn into_iter(self) -> impl Iterator<Item = PatternStack> { pub(super) fn into_iter(self) -> impl Iterator<Item = PatternStack> {
self.patterns.into_iter() self.0.into_iter()
} }
pub(super) fn concat(self, other: Matrix) -> Matrix { pub(super) fn concat(self, other: Matrix) -> Matrix {
let mut patterns = self.patterns; let mut patterns = self.0;
patterns.extend(other.patterns); patterns.extend(other.0);
Matrix { patterns } Matrix(patterns)
} }
pub(crate) fn is_complete(&self) -> Complete { pub(crate) fn is_complete(&self) -> Complete {
@ -188,6 +212,70 @@ impl Matrix {
.filter_map(|p_stack| p_stack.specialize_row_by_literal(literal)) .filter_map(|p_stack| p_stack.specialize_row_by_literal(literal))
.collect() .collect()
} }
fn is_useful(&self, vector: &PatternStack) -> bool {
// No rows are the same as the new vector! The vector is useful!
if self.is_empty() {
return true;
}
// There is nothing left in the new vector, but we still have
// rows that match the same things. This is not a useful vector!
if vector.is_empty() {
return false;
}
let first_pattern = vector.head();
match first_pattern {
Pattern::Constructor(name, _, args) => {
let arity = args.len();
let new_matrix = self.specialize_rows_by_ctor(name, arity);
let new_vector: PatternStack = vector.chain_tail_to_iter(args.iter());
new_matrix.is_useful(&new_vector)
}
Pattern::Wildcard => {
// check if all alts appear in matrix
match self.is_complete() {
Complete::No => {
// This Wildcard is useful because some Ctors are missing.
// But what if a previous row has a Wildcard?
// If so, this one is not useful.
let new_matrix = self.specialize_rows_by_wildcard();
let new_vector = vector.tail();
new_matrix.is_useful( &new_vector)
}
Complete::Yes(alts) => alts.into_iter().any(|alt| {
let tipo::ValueConstructor { variant, .. } = alt;
let tipo::ValueConstructorVariant::Record {
name,
arity,
..
} = variant else {unreachable!("variant should be a ValueConstructorVariant")};
let new_matrix = self.specialize_rows_by_ctor(&name, arity);
let new_vector =
vector.chain_tail_into_iter(vec![Pattern::Wildcard; arity].into_iter());
new_matrix.is_useful(&new_vector)
}),
}
}
Pattern::Literal(literal) => {
let new_matrix: Matrix = self.specialize_rows_by_literal(literal);
let new_vector = vector.tail();
new_matrix.is_useful(&new_vector)
}
}
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -300,9 +388,7 @@ fn simplify(environment: &mut Environment, value: &ast::TypedPattern) -> Result<
impl iter::FromIterator<PatternStack> for Matrix { impl iter::FromIterator<PatternStack> for Matrix {
fn from_iter<T: IntoIterator<Item = PatternStack>>(iter: T) -> Self { fn from_iter<T: IntoIterator<Item = PatternStack>>(iter: T) -> Self {
Matrix { Matrix(iter.into_iter().collect())
patterns: iter.into_iter().collect(),
}
} }
} }
@ -316,9 +402,10 @@ pub(crate) fn compute_match_usefulness(
let pattern = simplify(environment, unchecked_pattern)?; let pattern = simplify(environment, unchecked_pattern)?;
let pattern_stack = PatternStack::from(pattern); let pattern_stack = PatternStack::from(pattern);
if is_useful(&matrix, &pattern_stack) { if matrix.is_useful(&pattern_stack) {
matrix.push(pattern_stack); matrix.push(pattern_stack);
} else { } else {
dbg!(&pattern_stack);
todo!("redudant") todo!("redudant")
} }
} }
@ -343,11 +430,7 @@ pub(crate) fn compute_match_usefulness(
// //
fn is_exhaustive(matrix: Matrix, n: usize) -> Matrix { fn is_exhaustive(matrix: Matrix, n: usize) -> Matrix {
if matrix.is_empty() { if matrix.is_empty() {
return Matrix { return Matrix(vec![vec![Pattern::Wildcard; n].into()]);
patterns: vec![PatternStack {
patterns: vec![Pattern::Wildcard; n],
}],
};
} }
if n == 0 { if n == 0 {
@ -366,7 +449,7 @@ fn is_exhaustive(matrix: Matrix, n: usize) -> Matrix {
.iter() .iter()
.map(|p_stack| { .map(|p_stack| {
let mut new_p_stack = p_stack.clone(); let mut new_p_stack = p_stack.clone();
new_p_stack.patterns.insert(0, Pattern::Wildcard); new_p_stack.insert(0, Pattern::Wildcard);
new_p_stack new_p_stack
}) })
.collect::<Matrix>(); .collect::<Matrix>();
@ -388,7 +471,7 @@ fn is_exhaustive(matrix: Matrix, n: usize) -> Matrix {
for p_stack in new_matrix.into_iter() { for p_stack in new_matrix.into_iter() {
for p in prefix.clone() { for p in prefix.clone() {
let mut p_stack = p_stack.clone(); let mut p_stack = p_stack.clone();
p_stack.patterns.insert(0, p); p_stack.insert(0, p);
m.push(p_stack); m.push(p_stack);
} }
} }
@ -436,15 +519,11 @@ fn recover_ctor(
arity: usize, arity: usize,
patterns: PatternStack, patterns: PatternStack,
) -> PatternStack { ) -> PatternStack {
let mut rest = patterns.patterns; let (args, mut rest) = patterns.split_at(arity);
let mut args = rest.split_off(arity); rest.insert(0, Pattern::Constructor(name.to_string(), alts, args.into()));
std::mem::swap(&mut rest, &mut args); rest
rest.insert(0, Pattern::Constructor(name.to_string(), alts, args));
rest.into()
} }
fn is_missing( fn is_missing(
@ -470,66 +549,4 @@ fn is_missing(
} }
} }
fn is_useful(matrix: &Matrix, vector: &PatternStack) -> bool {
// No rows are the same as the new vector! The vector is useful!
if matrix.is_empty() {
return true;
}
// There is nothing left in the new vector, but we still have
// rows that match the same things. This is not a useful vector!
if vector.is_empty() {
return false;
}
let first_pattern = vector.head();
match first_pattern {
Pattern::Constructor(name, _, args) => {
let arity = args.len();
let new_matrix = matrix.specialize_rows_by_ctor(name, arity);
let new_vector: PatternStack = vector.chain_tail_to_iter(args.iter());
is_useful(&new_matrix, &new_vector)
}
Pattern::Wildcard => {
// check if all alts appear in matrix
match matrix.is_complete() {
Complete::No => {
// This Wildcard is useful because some Ctors are missing.
// But what if a previous row has a Wildcard?
// If so, this one is not useful.
let new_matrix = matrix.specialize_rows_by_wildcard();
let new_vector = vector.tail();
is_useful(&new_matrix, &new_vector)
}
Complete::Yes(alts) => alts.into_iter().any(|alt| {
let tipo::ValueConstructor { variant, .. } = alt;
let tipo::ValueConstructorVariant::Record {
name,
arity,
..
} = variant else {unreachable!("variant should be a ValueConstructorVariant")};
let new_matrix = matrix.specialize_rows_by_ctor(&name, arity);
let new_vector =
vector.chain_tail_into_iter(vec![Pattern::Wildcard; arity].into_iter());
is_useful(&new_matrix, &new_vector)
}),
}
}
Pattern::Literal(literal) => {
let new_matrix: Matrix = matrix.specialize_rows_by_literal(literal);
let new_vector = vector.tail();
is_useful(&new_matrix, &new_vector)
}
}
}

View File

@ -1,8 +1,6 @@
use std::{cmp::Ordering, collections::HashMap, sync::Arc}; use std::{cmp::Ordering, collections::HashMap, sync::Arc};
use vec1::Vec1; use vec1::Vec1;
mod usefulness;
use crate::{ use crate::{
ast::{ ast::{
Annotation, Arg, ArgName, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg, Annotation, Arg, ArgName, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg,
@ -17,11 +15,10 @@ use crate::{
tipo::fields::FieldMap, tipo::fields::FieldMap,
}; };
use self::usefulness::compute_match_usefulness;
use super::{ use super::{
environment::{assert_no_labeled_arguments, collapse_links, EntityKind, Environment}, environment::{assert_no_labeled_arguments, collapse_links, EntityKind, Environment},
error::{Error, Warning}, error::{Error, Warning},
exhaustive::compute_match_usefulness,
hydrator::Hydrator, hydrator::Hydrator,
pattern::PatternTyper, pattern::PatternTyper,
pipe::PipeTyper, pipe::PipeTyper,