Skip to content

Commit

Permalink
Remove unneeded parenthesis (#203)
Browse files Browse the repository at this point in the history
* Remove parenthesis from type application

e.g. `(Int a)` to `Int a`

* Remove unneeded parentheses from fun, app and forall type expr

* Add priority of pair type

* Passing cache to resolve TypeVariableId

* Fix: avoid parenthesis for primitive int and float

* Fix unit tests

* Fix: polymorphic and concrete numeral types are now distinguished

before:
> foo : (Foo String Int a)
> add_one : forall a. (Maybe I32 -> Maybe I32 can a)

after:
> foo : (Foo String (Int a))
> add_one : forall a. (Maybe I32 -> Maybe I32 can a) -- No change for concrete types

refs: #203 (comment)

* Fix the test named_constructor.an

* Update src/types/mod.rs

---------

Co-authored-by: jfecher <[email protected]>
  • Loading branch information
eldesh and jfecher authored Nov 11, 2024
1 parent 91f0d34 commit b2aae73
Show file tree
Hide file tree
Showing 19 changed files with 176 additions and 89 deletions.
6 changes: 3 additions & 3 deletions examples/regressions/129_int_defaulting_generalization.an
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ second b + 2i64

// args: --check --show-types
// expected stdout:
// a : (U64, I64)
// b : (U64, I64)
// c : (U64, I64)
// a : U64, I64
// b : U64, I64
// c : U64, I64

// Expected results with the function block uncommented:
// f : (forall a. (Unit -> (U64, I64) can a))
Expand Down
8 changes: 4 additions & 4 deletions examples/typechecking/bind.an
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ add_one x =

// args: --check --show-types
// expected stdout:
// add_one : (forall a. ((Maybe I32) -> (Maybe I32) can a))
// bind : (forall a b c d. ((Maybe c) - (c => (Maybe b) can d) -> (Maybe b) can d))
// ret : (forall a b. (a -> (Maybe a) can b))
// x : (Maybe I32)
// add_one : forall a. (Maybe I32 -> Maybe I32 can a)
// bind : forall a b c d. (Maybe c - (c => Maybe b can d) -> Maybe b can d)
// ret : forall a b. (a -> Maybe a can b)
// x : Maybe I32
2 changes: 1 addition & 1 deletion examples/typechecking/completeness_checking.an
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,5 @@ match (1, 2, 3, 4)
// completeness_checking.an:20:1 error: Missing case (false, false)
// match (true, true)
//
// completeness_checking.an:25:4 error: This pattern of type ((Int a), (Int b)) does not match the type ((Int a), ((Int b), ((Int c), (Int d)))) that is being matched on
// completeness_checking.an:25:4 error: This pattern of type Int a, Int b does not match the type Int a, Int b, Int c, Int d that is being matched on
// | (1, 2) -> 1
12 changes: 6 additions & 6 deletions examples/typechecking/effects.an
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ does_use x =

// args: --check --show-types
// expected stdout:
// does_use : (forall a b. (a -> Unit can (Use a, b)))
// does_use : forall a b. (a -> Unit can (Use a, b))
// given Add a
// get : (forall a b. (Unit -> a can (Use a, b)))
// handle_basic : (forall a. (Unit -> Unit can (Use String, a)))
// log : (forall a. (String -> Unit can (Log, a)))
// set : (forall a b. (a -> Unit can (Use a, b)))
// use_resume : (forall a. (Unit -> Unit can a))
// get : forall a b. (Unit -> a can (Use a, b))
// handle_basic : forall a. (Unit -> Unit can (Use String, a))
// log : forall a. (String -> Unit can (Log, a))
// set : forall a b. (a -> Unit can (Use a, b))
// use_resume : forall a. (Unit -> Unit can a)
8 changes: 4 additions & 4 deletions examples/typechecking/extern.an
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ exit2 0

// args: --check --show-types
// expected stdout:
// add : (forall a. (I32 - I32 -> I32 can a))
// exit2 : (forall a b. (I32 -> a can b))
// foo : (forall a b c. (a -> b can c))
// puts2 : (forall a. (String -> Unit can a))
// add : forall a. (I32 - I32 -> I32 can a)
// exit2 : forall a b. (I32 -> a can b)
// foo : forall a b c. (a -> b can c)
// puts2 : forall a. (String -> Unit can a)
6 changes: 3 additions & 3 deletions examples/typechecking/functor_and_monad.an
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ impl Monad Maybe with

// args: --check --show-types
// expected stdout:
// bind : (forall a b c d e. ((a b) - (b -> (a c) can d) -> (a c) can e))
// bind : forall a b c d e. (a b - (b -> a c can d) -> a c can e)
// given Monad a
// map : (forall a b c d e. ((a b) - (b -> c can d) -> (a c) can e))
// map : forall a b c d e. (a b - (b -> c can d) -> a c can e)
// given Functor a
// wrap : (forall a b c. (b -> (a b) can c))
// wrap : forall a b c. (b -> a b can c)
// given Monad a
2 changes: 1 addition & 1 deletion examples/typechecking/generalization.an
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ foo x =

// args: --check --show-types
// expected stdout:
// foo : (forall a b c d. (a -> (b => a can c) can d))
// foo : forall a b c d. (a -> b => a can c can d)
2 changes: 1 addition & 1 deletion examples/typechecking/impl.an
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ c = foo "one" "two"
// a : I32
// b : F64
// c : String
// foo : (forall a b. (a - a -> a can b))
// foo : forall a b. (a - a -> a can b)
// given Foo a
10 changes: 5 additions & 5 deletions examples/typechecking/instantiation.an
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ id x = x

// args: --check --show-types
// expected stdout:
// add : (forall a b c d e f g h i. ((a - c => e can g) - (a - b => c can g) -> (a => (b => e can g) can h) can i))
// id : (forall a b. (a -> a can b))
// one : (forall a b c d. ((a => b can d) - a -> b can d))
// two1 : (forall a b c. ((b => b can c) - b -> b can c))
// two2 : ((a => a can c) => (a => a can c) can d)
// add : forall a b c d e f g h i. ((a - c => e can g) - (a - b => c can g) -> a => b => e can g can h can i)
// id : forall a b. (a -> a can b)
// one : forall a b c d. ((a => b can d) - a -> b can d)
// two1 : forall a b c. ((b => b can c) - b -> b can c)
// two2 : (a => a can c) => a => a can c can d
10 changes: 5 additions & 5 deletions examples/typechecking/member_access.an
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ foo_and_bar foo bar
//

// expected stdout:
// Bar : (forall a. (Char -> Bar can a))
// Foo : (forall a. (F64 -> Foo can a))
// FooBar : (forall a. (I32 - String -> FooBar can a))
// Bar : forall a. (Char -> Bar can a)
// Foo : forall a. (F64 -> Foo can a)
// FooBar : forall a. (I32 - String -> FooBar can a)
// bar : Bar
// foo : Foo
// foo_and_bar : (forall a b c d. ({ foo: a, ..b } - { bar: String, ..c } -> String can d))
// foo_and_bar : forall a b c d. ({ foo: a, ..b } - { bar: String, ..c } -> String can d)
// foobar : FooBar
// stringify : (forall a. (String -> String can a))
// stringify : forall a. (String -> String can a)
8 changes: 4 additions & 4 deletions examples/typechecking/mutual_recursion.an
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ is_even 4
// TODO: is_odd here uses `forall a c.` instead of `forall a b.`

// expected stdout:
// is_even : (forall a b. ((Int a) -> Bool can b))
// given Eq (Int a), Print (Int a), Sub (Int a)
// is_odd : (forall a c. ((Int a) -> Bool can c))
// given Eq (Int a), Print (Int a), Sub (Int a)
// is_even : forall a b. (Int a -> Bool can b)
// given Eq Int a, Print Int a, Sub Int a
// is_odd : forall a c. (Int a -> Bool can c)
// given Eq Int a, Print Int a, Sub Int a
6 changes: 3 additions & 3 deletions examples/typechecking/named_constructor.an
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ foo = hello_foo 42

// args: --check --show-types
// expected stdout:
// Foo : (forall a b c. (a - b -> (Foo a b) can c))
// foo : (Foo String (Int a))
// hello_foo : (forall a b. (a -> (Foo String a) can b))
// Foo : forall a b c. (a - b -> Foo a b can c)
// foo : Foo String (Int a)
// hello_foo : forall a b. (a -> Foo String a can b)
2 changes: 1 addition & 1 deletion examples/typechecking/repeated_traits.an
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ foo a =
// Make sure output is not "... given Print a, Print a"
// args: --check --show-types
// expected stdout:
// foo : (forall a b. (a -> Unit can b))
// foo : forall a b. (a -> Unit can b)
// given Print a
2 changes: 1 addition & 1 deletion examples/typechecking/trait_fundep_result.an
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ str = foo 0i32

// args: --check --show-types
// expected stdout:
// foo : (forall a b c. (a -> b can c))
// foo : forall a b c. (a -> b can c)
// given Foo a b
// str : String
2 changes: 1 addition & 1 deletion examples/typechecking/trait_generalization.an
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
a = "test".c_string

// args: --check --show-types
// expected stdout: a : (Ptr Char)
// expected stdout: a : Ptr Char
6 changes: 3 additions & 3 deletions examples/typechecking/trait_propagation.an
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ foo () = baz bar
//
// args: --check --show-types
// expected stdout:
// bar : (forall a. a)
// baz : (forall a b. (a -> Unit can b))
// bar : forall a. a
// baz : forall a b. (a -> Unit can b)
// given Baz a
// foo : (forall a. (Unit -> Unit can a))
// foo : forall a. (Unit -> Unit can a)

// expected stderr:
// trait_propagation.an:6:10 error: No impl found for Baz a
Expand Down
10 changes: 5 additions & 5 deletions examples/typechecking/type_annotations.an
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ puts2
//

// expected stdout:
// bar : (forall a. (I32 - I32 -> I32 can a))
// baz : (forall a b. (Usz -> (Ptr a) can b))
// exit2 : (forall a b. (I32 -> a can b))
// foo : (forall a. (I32 - String -> Char can a))
// puts2 : (forall a. ((Ptr Char) -> I32 can a))
// bar : forall a. (I32 - I32 -> I32 can a)
// baz : forall a b. (Usz -> Ptr a can b)
// exit2 : forall a b. (I32 -> a can b)
// foo : forall a. (I32 - String -> Char can a)
// puts2 : forall a. (Ptr Char -> I32 can a)
67 changes: 64 additions & 3 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use std::collections::BTreeMap;
use crate::cache::{DefinitionInfoId, ModuleCache};
use crate::error::location::{Locatable, Location};
use crate::lexer::token::{FloatKind, IntegerKind};
use crate::util::fmap;
use crate::util;
use crate::util::fmap;

use self::typeprinter::TypePrinter;
use crate::types::effects::EffectSet;
Expand All @@ -27,6 +27,30 @@ pub mod typeprinter;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct TypeVariableId(pub usize);

/// Priority of operator on Types
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct TypePriority(u8);

impl From<u8> for TypePriority {
fn from(priority: u8) -> Self {
Self(priority)
}
}

impl std::fmt::Display for TypePriority {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "priority {}", self.0)
}
}

impl TypePriority {
pub const MAX: TypePriority = TypePriority(u8::MAX);
pub const APP: TypePriority = TypePriority(4);
pub const FORALL: TypePriority = TypePriority(3);
pub const PAIR: TypePriority = TypePriority(2);
pub const FUN: TypePriority = TypePriority(1);
}

/// Primitive types are the easy cases when unifying types.
/// They're equal simply if the other type is also the same PrimitiveType variant,
/// there is no recursion needed like with other Types. If the `Type`
Expand Down Expand Up @@ -217,6 +241,36 @@ impl Type {
}
}

pub fn priority(&self, cache: &ModuleCache<'_>) -> TypePriority {
use Type::*;
match self {
Primitive(_) | UserDefined(_) | Struct(_, _) | Tag(_) => TypePriority::MAX,
TypeVariable(id) => match &cache.type_bindings[id.0] {
TypeBinding::Bound(typ) => typ.priority(cache),
TypeBinding::Unbound(..) => TypePriority::MAX,
},
Function(_) => TypePriority::FUN,
TypeApplication(ctor, args) if ctor.is_polymorphic_int_type() || ctor.is_polymorphic_float_type() => {
if matches!(cache.follow_typebindings_shallow(&args[0]), Type::TypeVariable(_)) {
// type variable is unbound variable
TypePriority::APP
} else {
// type variable is bound (polymorphic int)
TypePriority::MAX
}
},
TypeApplication(ctor, _) => {
if ctor.is_pair_type() {
TypePriority::PAIR
} else {
TypePriority::APP
}
},
Ref { .. } => TypePriority::APP,
Effects(_) => unimplemented!("Type::priority for Effects"),
}
}

/// Pretty-print each type with each typevar substituted for a, b, c, etc.
pub fn display<'a, 'b>(&self, cache: &'a ModuleCache<'b>) -> typeprinter::TypePrinter<'a, 'b> {
let typ = GeneralizedType::MonoType(self.clone());
Expand Down Expand Up @@ -257,7 +311,7 @@ impl Type {
sharedness.traverse_rec(cache, f);
mutability.traverse_rec(cache, f);
lifetime.traverse_rec(cache, f);
}
},
Type::TypeApplication(constructor, args) => {
constructor.traverse_rec(cache, f);
for arg in args {
Expand Down Expand Up @@ -356,7 +410,7 @@ impl Type {
let mutable = mutability.approx_to_string();
let lifetime = lifetime.approx_to_string();
format!("{}{} '{}", mutable, shared, lifetime)
}
},
Type::Struct(fields, id) => {
let fields = fmap(fields, |(name, typ)| format!("{}: {}", name, typ.approx_to_string()));
format!("{{ {}, ..tv{} }}", fields.join(", "), id.0)
Expand Down Expand Up @@ -440,6 +494,13 @@ impl GeneralizedType {
GeneralizedType::PolyType(_, _) => unreachable!(),
}
}

pub fn priority(&self, cache: &ModuleCache<'_>) -> TypePriority {
match self {
GeneralizedType::MonoType(typ) => typ.priority(cache),
GeneralizedType::PolyType(..) => TypePriority::FORALL,
}
}
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
Expand Down
Loading

0 comments on commit b2aae73

Please sign in to comment.