Skip to content

Commit

Permalink
feat: Implement woobly type propagation
Browse files Browse the repository at this point in the history
  • Loading branch information
Marwes committed Apr 4, 2019
1 parent b9f0afc commit a0b8452
Show file tree
Hide file tree
Showing 34 changed files with 843 additions and 412 deletions.
8 changes: 4 additions & 4 deletions base/src/types/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ where
f.add_flags(flags);
args.add_flags(flags);
}
Type::Record(ref typ)
| Type::Variant(ref typ)
| Type::Effect(ref typ)
| Type::Forall(_, ref typ) => {
Type::Record(ref typ) | Type::Variant(ref typ) | Type::Effect(ref typ) => {
typ.add_flags(flags)
}
Type::Forall(_, ref typ) => {
*flags |= Flags::HAS_FORALL;
typ.add_flags(flags);
}
Expand Down
117 changes: 101 additions & 16 deletions base/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{
iter,
marker::PhantomData,
mem,
ops::{Deref, DerefMut},
ops::{self, Deref, DerefMut},
rc::Rc,
sync::Arc,
};
Expand Down Expand Up @@ -74,7 +74,7 @@ macro_rules! forward_eq_hash {
pub trait TypeEnv: KindEnv {
type Type;
/// Returns the type of the value bound at `id`
fn find_type(&self, id: &SymbolRef) -> Option<&Self::Type>;
fn find_type(&self, id: &SymbolRef) -> Option<ModType<&Self::Type>>;

/// Returns information about the type `id`
fn find_type_info(&self, id: &SymbolRef) -> Option<&Alias<Symbol, Self::Type>>;
Expand All @@ -83,7 +83,7 @@ pub trait TypeEnv: KindEnv {
impl<'a, T: ?Sized + TypeEnv> TypeEnv for &'a T {
type Type = T::Type;

fn find_type(&self, id: &SymbolRef) -> Option<&Self::Type> {
fn find_type(&self, id: &SymbolRef) -> Option<ModType<&Self::Type>> {
(**self).find_type(id)
}

Expand All @@ -95,7 +95,7 @@ impl<'a, T: ?Sized + TypeEnv> TypeEnv for &'a T {
impl TypeEnv for EmptyEnv<Symbol> {
type Type = ArcType;

fn find_type(&self, _id: &SymbolRef) -> Option<&ArcType> {
fn find_type(&self, _id: &SymbolRef) -> Option<ModType<&ArcType>> {
None
}

Expand Down Expand Up @@ -1427,18 +1427,6 @@ pub trait TypeExt: Deref<Target = Type<<Self as TypeExt>::Id, Self>> + Clone + S

new_typ
}
Type::Function(ArgType::Constructor, arg, ret) => match &**ret {
Type::Function(ArgType::Constructor, ..) => walk_move_type_opt(
self,
&mut InternerVisitor::control(interner, |interner, typ: &Self| {
typ.replace_generics(interner, named_variables)
}),
),

_ => arg.replace_generics(interner, named_variables).map(|arg| {
interner.function_type(ArgType::Constructor, Some(arg), ret.clone())
}),
},
_ => walk_move_type_opt(
self,
&mut InternerVisitor::control(interner, |interner, typ: &Self| {
Expand Down Expand Up @@ -3771,3 +3759,100 @@ where
Type::EmptyRow => interner.empty_row(),
}
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TypeModifier {
Wobbly,
Rigid,
}

impl Default for TypeModifier {
fn default() -> Self {
TypeModifier::Wobbly
}
}

impl ops::BitOr for TypeModifier {
type Output = Self;

fn bitor(mut self, typ: Self) -> Self {
self |= typ;
self
}
}
impl ops::BitOrAssign for TypeModifier {
fn bitor_assign(&mut self, typ: Self) {
match (*self, typ) {
(TypeModifier::Rigid, TypeModifier::Rigid) => (),
_ => *self = TypeModifier::Wobbly,
}
}
}

pub type ModTypeRef<'a> = ModType<&'a ArcType>;

#[derive(Clone, Copy, Debug)]
pub struct ModType<T = ArcType> {
pub modifier: TypeModifier,
pub concrete: T,
}

impl<T> fmt::Display for ModType<T>
where
T: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.concrete.fmt(f)
}
}

impl<T> Deref for ModType<T> {
type Target = T;

fn deref(&self) -> &Self::Target {
&self.concrete
}
}

impl<T> DerefMut for ModType<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.concrete
}
}

impl<T> ops::BitOrAssign for ModType<T> {
fn bitor_assign(&mut self, typ: Self) {
self.modifier |= typ.modifier;
self.concrete = typ.concrete;
}
}

impl<T> ModType<T> {
pub fn new(modifier: TypeModifier, typ: T) -> Self {
ModType {
modifier,
concrete: typ,
}
}

pub fn rigid(typ: T) -> Self {
Self::new(TypeModifier::Rigid, typ)
}

pub fn wobbly(typ: T) -> Self {
Self::new(TypeModifier::Wobbly, typ)
}

pub fn as_ref(&self) -> ModType<&T> {
ModType::new(self.modifier, &self.concrete)
}
}

impl<'a, T> ModType<&'a T>
where
T: Clone,
{
pub fn to_owned(&self) -> ModType<T> {
ModType::new(self.modifier, self.concrete.clone())
}
}
2 changes: 1 addition & 1 deletion base/tests/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ impl KindEnv for MockEnv {
impl TypeEnv for MockEnv {
type Type = ArcType;

fn find_type(&self, _id: &SymbolRef) -> Option<&ArcType> {
fn find_type(&self, _id: &SymbolRef) -> Option<ModTypeRef> {
None
}

Expand Down
15 changes: 11 additions & 4 deletions check/src/kindcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ pub struct KindCheck<'a> {
function1_kind: ArcKind,
/// A cached two argument kind function, `Type -> Type -> Type`
function2_kind: ArcKind,
/// A cached effect field kind, `Row -> Type -> Type`
effect_field_kind: ArcKind,
}

fn walk_move_kind<F>(kind: ArcKind, f: &mut F) -> ArcKind
Expand Down Expand Up @@ -76,8 +78,9 @@ impl<'a> KindCheck<'a> {
idents: idents,
subs: Substitution::new((), Default::default()),
function1_kind: function1_kind.clone(),
function2_kind: Kind::function(typ, function1_kind),
kind_cache: kind_cache,
function2_kind: Kind::function(typ, function1_kind.clone()),
effect_field_kind: Kind::function(kind_cache.row(), function1_kind),
kind_cache,
}
}

Expand All @@ -102,6 +105,10 @@ impl<'a> KindCheck<'a> {
self.function1_kind.clone()
}

pub fn effect_field_kind(&self) -> ArcKind {
self.effect_field_kind.clone()
}

pub fn function2_kind(&self) -> ArcKind {
self.function2_kind.clone()
}
Expand Down Expand Up @@ -291,8 +298,8 @@ impl<'a> KindCheck<'a> {
let mut iter = types::row_iter_mut(row);
for field in &mut iter {
let kind = self.kindcheck(&mut field.typ)?;
let function_kind = self.function1_kind();
self.unify(field.typ.span(), &function_kind, kind)?;
let effect_field_kind = self.effect_field_kind();
self.unify(field.typ.span(), &effect_field_kind, kind)?;
}
let kind = self.kindcheck(iter.current_type())?;
let row_kind = self.row_kind();
Expand Down
13 changes: 7 additions & 6 deletions check/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,13 @@ impl<T> TypecheckEnv for T where T: PrimitiveEnv + MetadataEnv {}
mod tests {
use super::*;

use std::cell::RefCell;
use std::rc::Rc;
use std::{cell::RefCell, rc::Rc};

use crate::base::kind::{ArcKind, KindEnv};
use crate::base::symbol::{Symbol, SymbolModule, SymbolRef, Symbols};
use crate::base::types::{Alias, TypeEnv};
use crate::base::{
kind::{ArcKind, KindEnv},
symbol::{Symbol, SymbolModule, SymbolRef, Symbols},
types::{Alias, ModTypeRef, TypeEnv},
};

pub struct MockEnv;

Expand All @@ -101,7 +102,7 @@ mod tests {

impl TypeEnv for MockEnv {
type Type = RcType;
fn find_type(&self, _id: &SymbolRef) -> Option<&RcType> {
fn find_type(&self, _id: &SymbolRef) -> Option<ModTypeRef> {
None
}
fn find_type_info(&self, _id: &SymbolRef) -> Option<&Alias<Symbol, RcType>> {
Expand Down
5 changes: 2 additions & 3 deletions check/src/substitution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,8 +458,8 @@ impl<T: Substitutable + PartialEq + Clone> Substitution<T> {
}
{
let typ = resolved_type.unwrap_or(typ);
match typ.get_id() {
Some(other_id) if variable.get_var().is_some() == typ.get_var().is_some() => {
match typ.get_var().map(|v| v.get_id()) {
Some(other_id) if variable.get_var().is_some() => {
self.union
.borrow_mut()
.union(id as usize, other_id as usize);
Expand All @@ -470,7 +470,6 @@ impl<T: Substitutable + PartialEq + Clone> Substitution<T> {
if let Some(other_id) = typ.get_id() {
self.update_level(id.get_id(), other_id);
}

self.insert(id.get_id(), typ.clone());
}
}
Expand Down
Loading

0 comments on commit a0b8452

Please sign in to comment.