fix bad test examples using unbound type alias variables

This commit is contained in:
Folkert 2021-05-05 19:54:10 +02:00
parent 1ac66a8fee
commit 48f392f372
9 changed files with 162 additions and 41 deletions

View File

@ -201,17 +201,17 @@ fn can_annotation_help(
let mut substitutions = ImMap::default();
let mut vars = Vec::new();
if alias.vars.len() != args.len() {
if alias.type_variables.len() != args.len() {
let error = Type::Erroneous(Problem::BadTypeArguments {
symbol,
region,
alias_needs: alias.vars.len() as u8,
alias_needs: alias.type_variables.len() as u8,
type_got: args.len() as u8,
});
return error;
}
for (loc_var, arg_ann) in alias.vars.iter().zip(args.into_iter()) {
for (loc_var, arg_ann) in alias.type_variables.iter().zip(args.into_iter()) {
let name = loc_var.value.0.clone();
let var = loc_var.value.1;
@ -227,8 +227,8 @@ fn can_annotation_help(
}
// make sure hidden variables are freshly instantiated
for var in alias.hidden_variables.iter() {
substitutions.insert(*var, Type::Variable(var_store.fresh()));
for var in alias.lambda_set_variables.iter() {
substitutions.insert(var.into_inner(), Type::Variable(var_store.fresh()));
}
// instantiate variables

View File

@ -61,7 +61,7 @@ where
let num_deps = dep_idents.len();
for (name, alias) in aliases.into_iter() {
scope.add_alias(name, alias.region, alias.vars, alias.typ);
scope.add_alias(name, alias.region, alias.type_variables, alias.typ);
}
// Desugar operators (convert them to Apply calls, taking into account

View File

@ -47,8 +47,9 @@ impl Scope {
let alias = Alias {
region,
typ,
hidden_variables: MutSet::default(),
vars: variables,
lambda_set_variables: MutSet::default(),
recursion_variables: MutSet::default(),
type_variables: variables,
};
aliases.insert(symbol, alias);
@ -174,17 +175,34 @@ impl Scope {
vars: Vec<Located<(Lowercase, Variable)>>,
typ: Type,
) {
let mut hidden_variables = MutSet::default();
hidden_variables.extend(typ.variables());
let roc_types::types::VariableDetail {
type_variables,
lambda_set_variables,
recursion_variables,
} = typ.variables_detail();
for loc_var in vars.iter() {
hidden_variables.remove(&loc_var.value.1);
}
debug_assert!({
let mut hidden = type_variables;
for loc_var in vars.iter() {
hidden.remove(&loc_var.value.1);
}
if !hidden.is_empty() {
panic!(
"Found unbound type variables {:?} \n in type alias {:?} {:?} : {:?}",
hidden, name, &vars, &typ
)
}
true
});
let alias = Alias {
region,
vars,
hidden_variables,
type_variables: vars,
lambda_set_variables,
recursion_variables,
typ,
};

View File

@ -524,7 +524,7 @@ mod test_can {
fn annotation_followed_with_unrelated_affectation() {
let src = indoc!(
r#"
F : Int *
F : Str
x = 1
@ -545,9 +545,9 @@ mod test_can {
fn two_annotations_followed_with_unrelated_affectation() {
let src = indoc!(
r#"
G : Int *
G : Str
F : Int *
F : {}
x = 1

View File

@ -2663,9 +2663,9 @@ mod test_reporting {
report_problem_as(
indoc!(
r#"
Foo : { x : Int * }
Foo a : { x : Int a }
f : Foo -> Int *
f : Foo a -> Int a
f = \r -> r.x
f { y: 3.14 }
@ -2687,7 +2687,7 @@ mod test_reporting {
But `f` needs the 1st argument to be:
{ x : Int * }
{ x : Int a }
Tip: Seems like a record field typo. Maybe `y` should be `x`?

View File

@ -50,9 +50,9 @@ pub fn make_solved_types(
let mut solved_types = MutMap::default();
for (symbol, alias) in solved_env.aliases.iter() {
let mut args = Vec::with_capacity(alias.vars.len());
let mut args = Vec::with_capacity(alias.type_variables.len());
for loc_named_var in alias.vars.iter() {
for loc_named_var in alias.type_variables.iter() {
let (name, var) = &loc_named_var.value;
args.push((name.clone(), SolvedType::new(&solved_subs, *var)));

View File

@ -1241,9 +1241,9 @@ fn recursive_functon_with_rigid() {
r#"
app "test" provides [ main ] to "./platform"
State a : { count : Int *, x : a }
State a : { count : I64, x : a }
foo : State a -> Int *
foo : State a -> Int *
foo = \state ->
if state.count == 0 then
0
@ -1632,15 +1632,15 @@ fn binary_tree_double_pattern_match() {
r#"
app "test" provides [ main ] to "./platform"
BTree : [ Node BTree BTree, Leaf (Int *) ]
BTree : [ Node BTree BTree, Leaf I64 ]
foo : BTree -> Int *
foo : BTree -> I64
foo = \btree ->
when btree is
Node (Node (Leaf x) _) _ -> x
_ -> 0
main : Int *
main : I64
main =
foo (Node (Node (Leaf 32) (Leaf 0)) (Leaf 0))
"#

View File

@ -96,12 +96,6 @@ impl VarStore {
}
}
// impl From<VarStore> for Variable {
// fn from(store: VarStore) -> Self {
// Variable(store.next)
// }
// }
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct OptVariable(u32);
@ -220,6 +214,18 @@ impl fmt::Debug for LambdaSet {
}
}
impl LambdaSet {
pub fn into_inner(self) -> Variable {
self.0
}
}
impl From<Variable> for LambdaSet {
fn from(variable: Variable) -> Self {
LambdaSet(variable)
}
}
/// Used in SolvedType
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct VarId(u32);

View File

@ -1,5 +1,5 @@
use crate::pretty_print::Parens;
use crate::subs::{Subs, VarStore, Variable};
use crate::subs::{LambdaSet, Subs, VarStore, Variable};
use inlinable_string::InlinableString;
use roc_collections::all::{union, ImMap, ImSet, Index, MutMap, MutSet, SendMap};
use roc_module::ident::{ForeignSymbol, Ident, Lowercase, TagName};
@ -373,6 +373,13 @@ impl Type {
result
}
pub fn variables_detail(&self) -> VariableDetail {
let mut result = Default::default();
variables_help_detailed(self, &mut result);
result
}
pub fn substitute(&mut self, substitutions: &ImMap<Variable, Type>) {
use Type::*;
@ -617,12 +624,12 @@ impl Type {
}
Apply(symbol, args) => {
if let Some(alias) = aliases.get(symbol) {
if args.len() != alias.vars.len() {
if args.len() != alias.type_variables.len() {
*self = Type::Erroneous(Problem::BadTypeArguments {
symbol: *symbol,
region,
type_got: args.len() as u8,
alias_needs: alias.vars.len() as u8,
alias_needs: alias.type_variables.len() as u8,
});
return;
}
@ -639,7 +646,7 @@ impl Type {
..
},
filler,
) in alias.vars.iter().zip(args.iter())
) in alias.type_variables.iter().zip(args.iter())
{
let mut filler = filler.clone();
filler.instantiate_aliases(region, aliases, var_store, introduced);
@ -836,6 +843,93 @@ fn variables_help(tipe: &Type, accum: &mut ImSet<Variable>) {
}
}
#[derive(Default)]
pub struct VariableDetail {
pub type_variables: MutSet<Variable>,
pub lambda_set_variables: MutSet<LambdaSet>,
pub recursion_variables: MutSet<Variable>,
}
fn variables_help_detailed(tipe: &Type, accum: &mut VariableDetail) {
use Type::*;
match tipe {
EmptyRec | EmptyTagUnion | Erroneous(_) => (),
Variable(v) => {
accum.type_variables.insert(*v);
}
Function(args, closure, ret) => {
for arg in args {
variables_help_detailed(arg, accum);
}
if let Type::Variable(v) = **closure {
accum.lambda_set_variables.insert(LambdaSet::from(v));
} else {
variables_help_detailed(closure, accum);
}
variables_help_detailed(ret, accum);
}
Record(fields, ext) => {
use RecordField::*;
for (_, field) in fields {
match field {
Optional(x) => variables_help_detailed(x, accum),
Required(x) => variables_help_detailed(x, accum),
Demanded(x) => variables_help_detailed(x, accum),
};
}
variables_help_detailed(ext, accum);
}
TagUnion(tags, ext) => {
for (_, args) in tags {
for x in args {
variables_help_detailed(x, accum);
}
}
variables_help_detailed(ext, accum);
}
RecursiveTagUnion(rec, tags, ext) => {
for (_, args) in tags {
for x in args {
variables_help_detailed(x, accum);
}
}
variables_help_detailed(ext, accum);
// just check that this is actually a recursive type
debug_assert!(accum.type_variables.contains(rec));
// this rec var doesn't need to be in flex_vars or rigid_vars
accum.type_variables.remove(rec);
accum.recursion_variables.insert(*rec);
}
Alias(_, args, actual) => {
for (_, arg) in args {
variables_help_detailed(arg, accum);
}
variables_help_detailed(actual, accum);
}
HostExposedAlias {
arguments, actual, ..
} => {
for (_, arg) in arguments {
variables_help_detailed(arg, accum);
}
variables_help_detailed(actual, accum);
}
Apply(_, args) => {
for x in args {
variables_help_detailed(x, accum);
}
}
}
}
pub struct RecordStructure {
pub fields: MutMap<Lowercase, RecordField<Variable>>,
pub ext: Variable,
@ -959,10 +1053,13 @@ pub enum PatternCategory {
#[derive(Clone, Debug, PartialEq)]
pub struct Alias {
pub region: Region,
pub vars: Vec<Located<(Lowercase, Variable)>>,
pub type_variables: Vec<Located<(Lowercase, Variable)>>,
/// hidden type variables, like the closure variable in `a -> b`
pub hidden_variables: MutSet<Variable>,
/// lambda set variables, e.g. the one annotating the arrow in
/// a |c|-> b
pub lambda_set_variables: MutSet<LambdaSet>,
pub recursion_variables: MutSet<Variable>,
pub typ: Type,
}