mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-21 15:59:20 +03:00
fix bad test examples using unbound type alias variables
This commit is contained in:
parent
1ac66a8fee
commit
48f392f372
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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`?
|
||||
|
||||
|
@ -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)));
|
||||
|
@ -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))
|
||||
"#
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user