Skip to content

Commit

Permalink
chore: rename usefulness module
Browse files Browse the repository at this point in the history
  • Loading branch information
rvcas committed Jul 25, 2023
1 parent 9fc7389 commit 836206f
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 114 deletions.
1 change: 1 addition & 0 deletions crates/aiken-lang/src/tipo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use uplc::{ast::Type as UplcType, builtins::DefaultFunction};

mod environment;
pub mod error;
mod exhaustive;
mod expr;
pub mod fields;
mod hydrator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,53 +6,69 @@ use crate::{
};

#[derive(Debug, Clone)]
pub(crate) struct PatternStack {
pub(crate) patterns: Vec<Pattern>,
}
pub(crate) struct PatternStack(Vec<Pattern>);

impl From<Pattern> for PatternStack {
fn from(value: Pattern) -> Self {
Self {
patterns: vec![value],
}
Self(vec![value])
}
}

impl From<Vec<Pattern>> for PatternStack {
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 {
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 {
&self.patterns[0]
&self.0[0]
}

fn tail(&self) -> PatternStack {
PatternStack {
patterns: self.patterns.iter().skip(1).cloned().collect(),
}
self.0
.iter()
.skip(1)
.cloned()
.collect::<Vec<Pattern>>()
.into()
}

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 {
PatternStack {
patterns: front.chain(self.iter().skip(1)).cloned().collect(),
}
front
.chain(self.iter().skip(1))
.cloned()
.collect::<Vec<Pattern>>()
.into()
}

fn chain_tail_into_iter(&self, front: impl Iterator<Item = Pattern>) -> PatternStack {
PatternStack {
patterns: front.chain(self.iter().skip(1).cloned()).collect(),
}
front
.chain(
self.iter()
.skip(1)
.cloned()
)
.collect::<Vec<Pattern>>()
.into()
}

// INVARIANT: (length row == N) ==> (length result == arity + N - 1)
Expand Down Expand Up @@ -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)]
pub(super) struct Matrix {
pub patterns: Vec<PatternStack>,
}
pub(super) struct Matrix(Vec<PatternStack>);

impl Matrix {
fn new() -> Self {
Matrix { patterns: vec![] }
Matrix(vec![])
}

pub(crate) fn is_empty(&self) -> bool {
self.patterns.is_empty()
self.0.is_empty()
}

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
pub(super) fn iter(&self) -> impl Iterator<Item = &PatternStack> {
self.patterns.iter()
self.0.iter()
}

/// Iterate over the first component of each row, mutably
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 {
let mut patterns = self.patterns;
patterns.extend(other.patterns);
Matrix { patterns }
let mut patterns = self.0;
patterns.extend(other.0);
Matrix(patterns)
}

pub(crate) fn is_complete(&self) -> Complete {
Expand Down Expand Up @@ -188,6 +212,70 @@ impl Matrix {
.filter_map(|p_stack| p_stack.specialize_row_by_literal(literal))
.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)]
Expand Down Expand Up @@ -300,9 +388,7 @@ fn simplify(environment: &mut Environment, value: &ast::TypedPattern) -> Result<

impl iter::FromIterator<PatternStack> for Matrix {
fn from_iter<T: IntoIterator<Item = PatternStack>>(iter: T) -> Self {
Matrix {
patterns: iter.into_iter().collect(),
}
Matrix(iter.into_iter().collect())
}
}

Expand All @@ -316,9 +402,10 @@ pub(crate) fn compute_match_usefulness(
let pattern = simplify(environment, unchecked_pattern)?;
let pattern_stack = PatternStack::from(pattern);

if is_useful(&matrix, &pattern_stack) {
if matrix.is_useful(&pattern_stack) {
matrix.push(pattern_stack);
} else {
dbg!(&pattern_stack);
todo!("redudant")
}
}
Expand All @@ -343,11 +430,7 @@ pub(crate) fn compute_match_usefulness(
//
fn is_exhaustive(matrix: Matrix, n: usize) -> Matrix {
if matrix.is_empty() {
return Matrix {
patterns: vec![PatternStack {
patterns: vec![Pattern::Wildcard; n],
}],
};
return Matrix(vec![vec![Pattern::Wildcard; n].into()]);
}

if n == 0 {
Expand All @@ -366,7 +449,7 @@ fn is_exhaustive(matrix: Matrix, n: usize) -> Matrix {
.iter()
.map(|p_stack| {
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
})
.collect::<Matrix>();
Expand All @@ -388,7 +471,7 @@ fn is_exhaustive(matrix: Matrix, n: usize) -> Matrix {
for p_stack in new_matrix.into_iter() {
for p in prefix.clone() {
let mut p_stack = p_stack.clone();
p_stack.patterns.insert(0, p);
p_stack.insert(0, p);
m.push(p_stack);
}
}
Expand Down Expand Up @@ -436,15 +519,11 @@ fn recover_ctor(
arity: usize,
patterns: PatternStack,
) -> PatternStack {
let mut rest = patterns.patterns;

let mut args = rest.split_off(arity);
let (args, mut rest) = patterns.split_at(arity);

std::mem::swap(&mut rest, &mut args);
rest.insert(0, Pattern::Constructor(name.to_string(), alts, args.into()));

rest.insert(0, Pattern::Constructor(name.to_string(), alts, args));

rest.into()
rest
}

fn is_missing(
Expand All @@ -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)
}
}
}
5 changes: 1 addition & 4 deletions crates/aiken-lang/src/tipo/expr.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use std::{cmp::Ordering, collections::HashMap, sync::Arc};
use vec1::Vec1;

mod usefulness;

use crate::{
ast::{
Annotation, Arg, ArgName, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg,
Expand All @@ -17,11 +15,10 @@ use crate::{
tipo::fields::FieldMap,
};

use self::usefulness::compute_match_usefulness;

use super::{
environment::{assert_no_labeled_arguments, collapse_links, EntityKind, Environment},
error::{Error, Warning},
exhaustive::compute_match_usefulness,
hydrator::Hydrator,
pattern::PatternTyper,
pipe::PipeTyper,
Expand Down

0 comments on commit 836206f

Please sign in to comment.