Skip to content

Commit

Permalink
fix(check): Distionguish forall in the top of aliases
Browse files Browse the repository at this point in the history
These should be distinct but weren't due to weird quirk of how types
were encoded
```
type Test a = | Test a
type Test = forall a . | Test a
```
  • Loading branch information
Marwes committed Nov 26, 2018
1 parent 7e472ab commit aee2389
Show file tree
Hide file tree
Showing 15 changed files with 192 additions and 148 deletions.
10 changes: 1 addition & 9 deletions base/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use ordered_float::NotNan;
use pos::{self, BytePos, HasSpan, Span, Spanned};
use resolve::remove_aliases_cow;
use symbol::Symbol;
use types::{self, Alias, AliasData, ArcType, ArgType, Generic, Type, TypeEnv};
use types::{self, Alias, AliasData, ArcType, ArgType, Type, TypeEnv};

pub trait DisplayEnv {
type Ident;
Expand Down Expand Up @@ -148,14 +148,6 @@ impl<Id> AstType<Id> {
self._typ.typ.value
}

pub fn params_mut(&mut self) -> &mut [Generic<Id>] {
match self._typ.typ.value {
Type::Forall(ref mut params, _, _) => params,
Type::App(ref mut id, _) => id.params_mut(),
_ => &mut [],
}
}

pub fn remove_single_forall(&mut self) -> &mut AstType<Id> {
match self._typ.typ.value {
Type::Forall(_, ref mut typ, _) => typ,
Expand Down
50 changes: 44 additions & 6 deletions base/src/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use symbol::Symbol;
use types::{AliasRef, ArcType, Type, TypeEnv};

quick_error! {
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub enum Error {
UndefinedType(id: Symbol) {
description("undefined type")
Expand Down Expand Up @@ -40,6 +40,40 @@ impl AliasRemover {
self.reduced_aliases.truncate(to)
}

pub fn canonical_alias<'t, F>(
&mut self,
env: &TypeEnv,
typ: &'t ArcType,
mut canonical: F,
) -> Result<Cow<'t, ArcType>, Error>
where
F: FnMut(&AliasRef<Symbol, ArcType>) -> bool,
{
Ok(match peek_alias(env, typ) {
Ok(Some(alias)) => {
if self.reduced_aliases.contains(&alias.name) {
return Err(Error::SelfRecursiveAlias(alias.name.clone()));
}
self.reduced_aliases.push(alias.name.clone());

if canonical(alias) {
Cow::Borrowed(typ)
} else {
match alias
.typ()
.apply_args(alias.params(), &typ.unapplied_args())
{
Some(typ) => {
Cow::Owned(self.canonical_alias(env, &typ, canonical)?.into_owned())
}
None => Cow::Borrowed(typ),
}
}
}
_ => Cow::Borrowed(typ),
})
}

pub fn remove_aliases(&mut self, env: &TypeEnv, mut typ: ArcType) -> Result<ArcType, Error> {
loop {
typ = match self.remove_alias(env, &typ)? {
Expand All @@ -58,10 +92,12 @@ impl AliasRemover {
}
self.reduced_aliases.push(alias.name.clone());
// Opaque types should only exist as the alias itself
if **alias.unresolved_type().remove_forall() == Type::Opaque {
if **alias.unresolved_type() == Type::Opaque {
return Ok(None);
}
Ok(alias.typ().apply_args(&typ.unapplied_args()))
Ok(alias
.typ()
.apply_args(alias.params(), &typ.unapplied_args()))
}
None => Ok(None),
}
Expand Down Expand Up @@ -96,7 +132,7 @@ where
} else {
alias
.typ()
.apply_args(&typ.unapplied_args())
.apply_args(alias.params(), &typ.unapplied_args())
.map(|typ| Cow::Owned(canonical_alias(env, &typ, canonical).into_owned()))
.unwrap_or_else(|| Cow::Borrowed(typ))
}
Expand All @@ -111,10 +147,12 @@ pub fn remove_alias(env: &TypeEnv, typ: &ArcType) -> Result<Option<ArcType>, Err
let typ = typ.skolemize(&mut FnvMap::default());
Ok(peek_alias(env, &typ)?.and_then(|alias| {
// Opaque types should only exist as the alias itself
if **alias.unresolved_type().remove_forall() == Type::Opaque {
if **alias.unresolved_type() == Type::Opaque {
return None;
}
alias.typ().apply_args(&typ.unapplied_args())
alias
.typ()
.apply_args(alias.params(), &typ.unapplied_args())
}))
}

Expand Down
54 changes: 19 additions & 35 deletions base/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ where
{
fn from(data: AliasData<Id, T>) -> Alias<Id, T> {
Alias {
_typ: Type::alias(data.name, data.typ),
_typ: Type::alias(data.name, data.args, data.typ),
_marker: PhantomData,
}
}
Expand All @@ -346,9 +346,9 @@ impl<Id, T> Alias<Id, T>
where
T: From<Type<Id, T>>,
{
pub fn new(name: Id, typ: T) -> Alias<Id, T> {
pub fn new(name: Id, args: Vec<Generic<Id>>, typ: T) -> Alias<Id, T> {
Alias {
_typ: Type::alias(name, typ),
_typ: Type::alias(name, args, typ),
_marker: PhantomData,
}
}
Expand Down Expand Up @@ -496,6 +496,8 @@ where
pub struct AliasData<Id, T> {
#[cfg_attr(feature = "serde_derive", serde(state))]
pub name: Id,
#[cfg_attr(feature = "serde_derive", serde(state))]
args: Vec<Generic<Id>>,
/// The type that is being aliased
#[cfg_attr(feature = "serde_derive", serde(state))]
typ: T,
Expand All @@ -518,10 +520,7 @@ where
T: From<Type<Id, T>>,
{
pub fn new(name: Id, args: Vec<Generic<Id>>, typ: T) -> AliasData<Id, T> {
AliasData {
name,
typ: Type::forall(args, typ),
}
AliasData { name, args, typ }
}
}

Expand All @@ -530,14 +529,15 @@ where
T: Deref<Target = Type<Id, T>>,
{
pub fn params(&self) -> &[Generic<Id>] {
self.typ.params()
&self.args
}

pub fn params_mut(&mut self) -> &mut [Generic<Id>] {
&mut self.args
}

pub fn aliased_type(&self) -> &T {
match *self.typ {
Type::Forall(_, ref typ, _) => typ,
_ => &self.typ,
}
&self.typ
}
}

Expand Down Expand Up @@ -862,10 +862,10 @@ where
T::from(Type::Variable(typ))
}

pub fn alias(name: Id, typ: T) -> T {
pub fn alias(name: Id, args: Vec<Generic<Id>>, typ: T) -> T {
T::from(Type::Alias(AliasRef {
index: 0,
group: Arc::new(vec![AliasData { name, typ }]),
group: Arc::new(vec![AliasData { name, args, typ }]),
}))
}

Expand Down Expand Up @@ -1363,22 +1363,6 @@ impl<'a, Id> Iterator for ForallScopeIter<'a, Id> {
}

impl ArcType {
pub fn params_mut(&mut self) -> &mut [Generic<Symbol>] {
use std::sync::Arc;

match *Arc::make_mut(&mut self.typ) {
/*
// TODO
Type::Alias(ref mut alias) => {
Arc::make_mut(alias.unresolved_type_mut().typ).params_mut()
}
*/
Type::Forall(ref mut params, _, _) => params,
Type::App(ref mut id, _) => id.params_mut(),
_ => &mut [],
}
}

/// Applies a list of arguments to a parameterised type, returning `Some`
/// if the substitution was successful.
///
Expand All @@ -1389,9 +1373,8 @@ impl ArcType {
/// args = [Error, Option a]
/// result = | Err Error | Ok (Option a)
/// ```
pub fn apply_args(&self, args: &[ArcType]) -> Option<ArcType> {
let params = self.params();
let typ = self.remove_forall().clone();
pub fn apply_args(&self, params: &[Generic<Symbol>], args: &[ArcType]) -> Option<ArcType> {
let typ = self.clone();

// It is ok to take the type only if it is fully applied or if it
// the missing argument only appears in order at the end, i.e:
Expand Down Expand Up @@ -1424,7 +1407,7 @@ impl ArcType {
return None;
};

Some(walk_move_type(typ.remove_forall().clone(), &mut |typ| {
Some(walk_move_type(typ.clone(), &mut |typ| {
match **typ {
Type::Generic(ref generic) => {
// Replace the generic variable with the type from the list
Expand Down Expand Up @@ -2101,7 +2084,7 @@ where
if filter == Filter::RetainKey {
arena.text("...")
} else {
top(remove_forall(&field.typ.typ)).pretty(printer)
top(&field.typ.typ).pretty(printer)
},
if i + 1 != types.len() || print_any_field {
arena.text(",")
Expand Down Expand Up @@ -2551,6 +2534,7 @@ where
{
AliasData {
name: alias.name.clone(),
args: alias.args.clone(),
typ: translate(&alias.typ),
}
}
Expand Down
28 changes: 10 additions & 18 deletions base/tests/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,7 @@ fn show_record_singleton_polymorphic() {
let typ = Type::record(
vec![Field::new(
"Test",
Alias::new(
"Test",
Type::forall(vec![Generic::new("a", Kind::typ())], fun.clone()),
),
Alias::new("Test", vec![Generic::new("a", Kind::typ())], fun.clone()),
)],
vec![],
);
Expand All @@ -93,10 +90,7 @@ fn show_record_multifield() {
let typ = Type::record(
vec![Field::new(
"Test",
Alias::new(
"Test",
Type::forall(vec![Generic::new("a", Kind::typ())], fun.clone()),
),
Alias::new("Test", vec![Generic::new("a", Kind::typ())], fun.clone()),
)],
vec![Field::new("x", Type::int())],
);
Expand Down Expand Up @@ -145,7 +139,10 @@ fn show_record_filtered() {
let data = |s, a| ArcType::from(type_con(s, a));
let test = data("Test", vec![data("a", vec![])]);
let record = Type::record(
vec![Field::new("Test", Alias::new("Test", Type::int()))],
vec![Field::new(
"Test",
Alias::new("Test", Vec::new(), Type::int()),
)],
vec![
Field::new("x", Type::int()),
Field::new("y", Type::int()),
Expand Down Expand Up @@ -198,10 +195,7 @@ fn show_record_multi_line_nested() {
let inner_record = Type::record(
vec![Field::new(
"Test",
Alias::new(
"Test",
Type::forall(vec![Generic::new("a", Kind::typ())], fun.clone()),
),
Alias::new("Test", vec![Generic::new("a", Kind::typ())], fun.clone()),
)],
vec![
Field::new("x", Type::int()),
Expand All @@ -215,10 +209,7 @@ fn show_record_multi_line_nested() {
let record = Type::record(
vec![Field::new(
"Test",
Alias::new(
"Test",
Type::forall(vec![Generic::new("a", Kind::typ())], fun.clone()),
),
Alias::new("Test", vec![Generic::new("a", Kind::typ())], fun.clone()),
)],
vec![
Field::new("x", Type::int()),
Expand Down Expand Up @@ -292,7 +283,8 @@ fn show_polymorphic_record_associated_type() {
"Test",
Alias::new(
"Test",
Type::forall(vec![Generic::new("a", Kind::typ())], Type::ident("a")),
vec![Generic::new("a", Kind::typ())],
Type::ident("a"),
),
)];
let typ: ArcType<&str> = Type::poly_record(type_fields, vec![], Type::ident("r"));
Expand Down
Loading

0 comments on commit aee2389

Please sign in to comment.