chore: rename usefulness module
This commit is contained in:
parent
03efb46e6f
commit
e8a71cd63b
|
@ -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;
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue