Skip to content

Commit

Permalink
If old name is interchangeable, use instead
Browse files Browse the repository at this point in the history
This means that old unions are preserved.
However, this doesn't quite explain to me why
we get rid of the unnecessary unions.
One would expect that we instead get even more
unnecessary unions.
As of now I can't quite yet explain this change
in behaviour, but should be documented once I
understand the change in behaviour.
  • Loading branch information
JSAbrahams committed Dec 30, 2022
1 parent 337760a commit a63c40a
Show file tree
Hide file tree
Showing 12 changed files with 47 additions and 27 deletions.
13 changes: 8 additions & 5 deletions src/check/constrain/unify/finished.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::check::ast::pos_name::PosNameMap;
use crate::check::name::{Any, Name, Union};
use crate::check::name::{Name, Union};
use crate::common::position::Position;

#[derive(Debug, Clone)]
Expand All @@ -18,12 +18,15 @@ impl Finished {
/// [Name].
/// Ignores [Any] type, and trims from union.
pub fn push_ty(&mut self, pos: Position, name: &Name) {
if *name == Name::any() {
return;
}
let name = name.trim_any();

let name = self.pos_to_name.get(&pos).map_or(name.clone(), |s_name| s_name.union(&name));
let name = self.pos_to_name.get(&pos)
.map_or(name.clone(), |old_name| if old_name.is_interchangeable {
old_name.clone()
} else {
old_name.union(&name)
});

if self.pos_to_name.insert(pos, name.clone()).is_none() {
trace!("{:width$}type at {}: {}", "", pos, name, width = 0);
}
Expand Down
2 changes: 1 addition & 1 deletion src/check/constrain/unify/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ fn unify_fun_arg(
let name = names
.iter()
.fold(Name::empty(), |name, f_name| name.union(f_name))
.as_any();
.is_interchangeable();
let ctx_arg_ty = Expected::new(expected.pos, &Type { name });
constr.push("function argument", &ctx_arg_ty, expected);
added += 1;
Expand Down
6 changes: 3 additions & 3 deletions src/check/constrain/unify/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::check::constrain::unify::expression::substitute::substitute;
use crate::check::constrain::unify::finished::Finished;
use crate::check::constrain::unify::link::unify_link;
use crate::check::context::{Context, LookupClass};
use crate::check::name::{Any, ColType, IsSuperSet, Name, Union};
use crate::check::name::{Any, ColType, IsSuperSet, Name};
use crate::check::name::name_variant::NameVariant;
use crate::check::result::{TypeErr, TypeResult};
use crate::common::position::Position;
Expand Down Expand Up @@ -42,8 +42,8 @@ pub fn unify_type(
ctx.class(l_ty, left.pos)?;
ctx.class(r_ty, right.pos)?;

finished.push_ty(left.pos, &l_ty.union(r_ty));
finished.push_ty(right.pos, &l_ty.union(r_ty));
finished.push_ty(left.pos, &l_ty);
finished.push_ty(right.pos, &r_ty);
unify_link(constraints, finished, ctx, total)
} else if constraint.superset == ConstrVariant::Left {
let msg = format!("Unifying two types within {}: Expected {left}, was {right}", constraint.msg);
Expand Down
2 changes: 1 addition & 1 deletion src/check/name/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ impl TryFrom<&AST> for Name {
} else {
vec![TrueName::try_from(ast)?].into_iter().collect::<HashSet<_>>()
};
Ok(Name { names, any: false })
Ok(Name { names, is_interchangeable: false })
}
}

Expand Down
22 changes: 11 additions & 11 deletions src/check/name/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub trait ColType {
#[derive(Debug, Clone, Eq)]
pub struct Name {
pub names: HashSet<TrueName>,
pub any: bool,
pub is_interchangeable: bool,
}

impl Any for Name {
Expand Down Expand Up @@ -173,7 +173,7 @@ impl Union<Name> for Name {
names
};

Name { names, any: self.any || name.any }
Name { names, is_interchangeable: self.is_interchangeable || name.is_interchangeable }
}
}

Expand Down Expand Up @@ -241,7 +241,7 @@ impl Display for Name {
impl From<&TrueName> for Name {
fn from(name: &TrueName) -> Self {
let names: HashSet<TrueName> = HashSet::from_iter(vec![name.clone()]);
Name { names, any: false }
Name { names, is_interchangeable: false }
}
}

Expand All @@ -262,9 +262,9 @@ impl IsSuperSet<Name> for Name {
let any_superset: Vec<bool> =
self.names.iter().map(is_superset).collect::<Result<_, _>>()?;

if !any_superset.clone().iter().any(|b| *b) && !other.any {
if !any_superset.clone().iter().any(|b| *b) && !other.is_interchangeable {
return Ok(false);
} else if any_superset.clone().iter().any(|b| *b) && other.any {
} else if any_superset.clone().iter().any(|b| *b) && other.is_interchangeable {
return Ok(true);
}
}
Expand Down Expand Up @@ -293,15 +293,15 @@ impl Empty for Name {
}

fn empty() -> Name {
Name { names: HashSet::new(), any: false }
Name { names: HashSet::new(), is_interchangeable: false }
}
}

impl Substitute for Name {
fn substitute(&self, generics: &HashMap<Name, Name>, pos: Position) -> TypeResult<Name> {
let names =
self.names.iter().map(|n| n.substitute(generics, pos)).collect::<Result<_, _>>()?;
Ok(Name { names, any: self.any })
Ok(Name { names, is_interchangeable: self.is_interchangeable })
}
}

Expand All @@ -317,8 +317,8 @@ impl Name {

/// Any means that if one check if another [is_superset_of] self, then it will be true if it is
/// just a superset of one.
pub fn as_any(&self) -> Self {
Name { any: true, ..self.clone() }
pub fn is_interchangeable(&self) -> Self {
Name { is_interchangeable: true, ..self.clone() }
}

pub fn contains(&self, item: &TrueName) -> bool {
Expand Down Expand Up @@ -397,7 +397,7 @@ mod tests {

#[test]
fn is_superset_any_only_one() {
let union_1 = Name::from(&vec![TrueName::from(BOOL), TrueName::from(INT)]).as_any();
let union_1 = Name::from(&vec![TrueName::from(BOOL), TrueName::from(INT)]).is_interchangeable();
let union_2 = Name::from(BOOL);

let ctx = Context::default().into_with_primitives().unwrap();
Expand All @@ -406,7 +406,7 @@ mod tests {

#[test]
fn is_superset_any_no_one() {
let union_1 = Name::from(&vec![TrueName::from(BOOL), TrueName::from(INT)]).as_any();
let union_1 = Name::from(&vec![TrueName::from(BOOL), TrueName::from(INT)]).is_interchangeable();
let union_2 = Name::from(FLOAT);

let ctx = Context::default().into_with_primitives().unwrap();
Expand Down
2 changes: 1 addition & 1 deletion src/check/name/string_name/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ impl IsSuperSet<StringName> for StringName {

impl From<&StringName> for Name {
fn from(name: &StringName) -> Self {
Name { names: HashSet::from_iter(vec![TrueName::from(name)]), any: false }
Name { names: HashSet::from_iter(vec![TrueName::from(name)]), is_interchangeable: false }
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/check/name/true_name/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ impl From<&TrueName> for StringName {
impl From<&Vec<TrueName>> for Name {
fn from(names: &Vec<TrueName>) -> Self {
let names: HashSet<TrueName> = HashSet::from_iter(names.iter().cloned());
Name { names, any: false }
Name { names, is_interchangeable: false }
}
}

Expand Down
7 changes: 7 additions & 0 deletions tests/resource/valid/call/input.mamba
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
def num := input("Compute factorial: ")

if num.is_digit() then
def result := Int(num)
print("Factorial {num} is: {result}.")
else
print("Input was not an integer.")
7 changes: 7 additions & 0 deletions tests/resource/valid/call/input_check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
num: str = input("Compute factorial: ")

if num.is_digit():
result: int = int(num)
print(f"Factorial {num} is: {result}.")
else:
print("Input was not an integer.")
3 changes: 1 addition & 2 deletions tests/resource/valid/operation/arithmetic_check.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import math
from typing import Union

a: Union[float, int] = 10
a: int = 10
b: int = 20

c: int = a + b
Expand Down
3 changes: 1 addition & 2 deletions tests/resource/valid/readme_example/factorial_check.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from typing import Union
def factorial(x: int) -> int:
match x:
case 0:
return 1
case n:
return n * factorial(n - 1)

num: Union[flot, int, str] = input("Compute factorial: ")
num: str = input("Compute factorial: ")

if num.is_digit():
result = factorial(int(num))
Expand Down
5 changes: 5 additions & 0 deletions tests/system/valid/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@ use crate::system::{OutTestRet, test_directory};
fn call_with_class_child() -> OutTestRet {
test_directory(true, &["call"], &["call", "target"], "call_with_class_child")
}

#[test]
fn input() -> OutTestRet {
test_directory(true, &["call"], &["call", "target"], "input")
}

0 comments on commit a63c40a

Please sign in to comment.