mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
Merge remote-tracking branch 'origin/trunk' into low-level-ops
This commit is contained in:
commit
1cd49689c2
29 changed files with 1630 additions and 440 deletions
|
@ -140,6 +140,11 @@ fn find_names_needed(
|
|||
// We must not accidentally generate names that collide with them!
|
||||
names_taken.insert(name);
|
||||
}
|
||||
Structure(Apply(Symbol::ATTR_ATTR, args)) => {
|
||||
// assign uniqueness var names based on when they occur in the base type
|
||||
find_names_needed(args[1], subs, roots, root_appearances, names_taken);
|
||||
find_names_needed(args[0], subs, roots, root_appearances, names_taken);
|
||||
}
|
||||
Structure(Apply(_, args)) => {
|
||||
for var in args {
|
||||
find_names_needed(var, subs, roots, root_appearances, names_taken);
|
||||
|
@ -153,21 +158,30 @@ fn find_names_needed(
|
|||
find_names_needed(ret_var, subs, roots, root_appearances, names_taken);
|
||||
}
|
||||
Structure(Record(fields, ext_var)) => {
|
||||
for (_, var) in fields {
|
||||
find_names_needed(var, subs, roots, root_appearances, names_taken);
|
||||
let mut sorted_fields: Vec<_> = fields.iter().collect();
|
||||
sorted_fields.sort();
|
||||
|
||||
for (_, var) in sorted_fields {
|
||||
find_names_needed(*var, subs, roots, root_appearances, names_taken);
|
||||
}
|
||||
|
||||
find_names_needed(ext_var, subs, roots, root_appearances, names_taken);
|
||||
}
|
||||
Structure(TagUnion(tags, ext_var)) => {
|
||||
for var in tags.values().flatten() {
|
||||
let mut sorted_tags: Vec<_> = tags.iter().collect();
|
||||
sorted_tags.sort();
|
||||
|
||||
for var in sorted_tags.into_iter().map(|(_, v)| v).flatten() {
|
||||
find_names_needed(*var, subs, roots, root_appearances, names_taken);
|
||||
}
|
||||
|
||||
find_names_needed(ext_var, subs, roots, root_appearances, names_taken);
|
||||
}
|
||||
Structure(RecursiveTagUnion(rec_var, tags, ext_var)) => {
|
||||
for var in tags.values().flatten() {
|
||||
let mut sorted_tags: Vec<_> = tags.iter().collect();
|
||||
sorted_tags.sort();
|
||||
|
||||
for var in sorted_tags.into_iter().map(|(_, v)| v).flatten() {
|
||||
find_names_needed(*var, subs, roots, root_appearances, names_taken);
|
||||
}
|
||||
|
||||
|
@ -178,6 +192,7 @@ fn find_names_needed(
|
|||
Bool::Shared => {}
|
||||
Bool::Container(cvar, mvars) => {
|
||||
find_names_needed(cvar, subs, roots, root_appearances, names_taken);
|
||||
|
||||
for var in mvars {
|
||||
find_names_needed(var, subs, roots, root_appearances, names_taken);
|
||||
}
|
||||
|
@ -188,10 +203,11 @@ fn find_names_needed(
|
|||
find_names_needed(args[0].1, subs, roots, root_appearances, names_taken);
|
||||
find_names_needed(args[1].1, subs, roots, root_appearances, names_taken);
|
||||
} else {
|
||||
// TODO should we also look in the actual variable?
|
||||
for (_, var) in args {
|
||||
find_names_needed(var, subs, roots, root_appearances, names_taken);
|
||||
}
|
||||
// TODO should we also look in the actual variable?
|
||||
// find_names_needed(_actual, subs, roots, root_appearances, names_taken);
|
||||
}
|
||||
}
|
||||
Error | Structure(Erroneous(_)) | Structure(EmptyRecord) | Structure(EmptyTagUnion) => {
|
||||
|
@ -211,7 +227,7 @@ pub fn name_all_type_vars(variable: Variable, subs: &mut Subs) {
|
|||
|
||||
for root in roots {
|
||||
// show the type variable number instead of `*`. useful for debugging
|
||||
// set_root_name(root, &(format!("<{:?}>", root).into()), subs);
|
||||
// set_root_name(root, (format!("<{:?}>", root).into()), subs);
|
||||
if let Some(Appearances::Multiple) = appearances.get(&root) {
|
||||
letters_used = name_root(letters_used, root, subs, &mut taken);
|
||||
}
|
||||
|
@ -226,21 +242,19 @@ fn name_root(
|
|||
) -> u32 {
|
||||
let (generated_name, new_letters_used) = name_type_var(letters_used, taken);
|
||||
|
||||
set_root_name(root, &generated_name, subs);
|
||||
set_root_name(root, generated_name, subs);
|
||||
|
||||
new_letters_used
|
||||
}
|
||||
|
||||
fn set_root_name(root: Variable, name: &Lowercase, subs: &mut Subs) {
|
||||
fn set_root_name(root: Variable, name: Lowercase, subs: &mut Subs) {
|
||||
use crate::subs::Content::*;
|
||||
|
||||
let mut descriptor = subs.get_without_compacting(root);
|
||||
|
||||
match descriptor.content {
|
||||
FlexVar(None) => {
|
||||
descriptor.content = FlexVar(Some(name.clone()));
|
||||
|
||||
// TODO is this necessary, or was mutating descriptor in place sufficient?
|
||||
descriptor.content = FlexVar(Some(name));
|
||||
subs.set(root, descriptor);
|
||||
}
|
||||
FlexVar(Some(_existing)) => {
|
||||
|
@ -334,8 +348,7 @@ fn write_content(env: &Env, content: Content, subs: &Subs, buf: &mut String, par
|
|||
}
|
||||
|
||||
// useful for debugging
|
||||
let write_out_alias = false;
|
||||
if write_out_alias {
|
||||
if false {
|
||||
buf.push_str("[[ but really ");
|
||||
let content = subs.get_without_compacting(_actual).content;
|
||||
write_content(env, content, subs, buf, parens);
|
||||
|
|
|
@ -62,16 +62,25 @@ pub enum SolvedBool {
|
|||
}
|
||||
|
||||
impl SolvedBool {
|
||||
pub fn from_bool(boolean: &boolean_algebra::Bool) -> Self {
|
||||
pub fn from_bool(boolean: &boolean_algebra::Bool, subs: &Subs) -> Self {
|
||||
use boolean_algebra::Bool;
|
||||
|
||||
// NOTE we blindly trust that `cvar` is a root and has a FlexVar as content
|
||||
match boolean {
|
||||
Bool::Shared => SolvedBool::SolvedShared,
|
||||
Bool::Container(cvar, mvars) => SolvedBool::SolvedContainer(
|
||||
VarId::from_var(*cvar),
|
||||
mvars.iter().map(|mvar| VarId::from_var(*mvar)).collect(),
|
||||
),
|
||||
Bool::Container(cvar, mvars) => {
|
||||
debug_assert!(matches!(
|
||||
subs.get_without_compacting(*cvar).content,
|
||||
crate::subs::Content::FlexVar(_)
|
||||
));
|
||||
|
||||
SolvedBool::SolvedContainer(
|
||||
VarId::from_var(*cvar, subs),
|
||||
mvars
|
||||
.iter()
|
||||
.map(|mvar| VarId::from_var(*mvar, subs))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +164,7 @@ impl SolvedType {
|
|||
}
|
||||
|
||||
SolvedType::RecursiveTagUnion(
|
||||
VarId::from_var(rec_var),
|
||||
VarId::from_var(rec_var, solved_subs.inner()),
|
||||
solved_tags,
|
||||
Box::new(solved_ext),
|
||||
)
|
||||
|
@ -171,7 +180,7 @@ impl SolvedType {
|
|||
|
||||
SolvedType::Alias(symbol, solved_args, Box::new(solved_type))
|
||||
}
|
||||
Boolean(val) => SolvedType::Boolean(SolvedBool::from_bool(&val)),
|
||||
Boolean(val) => SolvedType::Boolean(SolvedBool::from_bool(&val, solved_subs.inner())),
|
||||
Variable(var) => Self::from_var(solved_subs.inner(), var),
|
||||
}
|
||||
}
|
||||
|
@ -180,7 +189,7 @@ impl SolvedType {
|
|||
use crate::subs::Content::*;
|
||||
|
||||
match subs.get_without_compacting(var).content {
|
||||
FlexVar(_) => SolvedType::Flex(VarId::from_var(var)),
|
||||
FlexVar(_) => SolvedType::Flex(VarId::from_var(var, subs)),
|
||||
RigidVar(name) => SolvedType::Rigid(name),
|
||||
Structure(flat_type) => Self::from_flat_type(subs, flat_type),
|
||||
Alias(symbol, args, actual_var) => {
|
||||
|
@ -270,11 +279,15 @@ impl SolvedType {
|
|||
|
||||
let ext = Self::from_var(subs, ext_var);
|
||||
|
||||
SolvedType::RecursiveTagUnion(VarId::from_var(rec_var), new_tags, Box::new(ext))
|
||||
SolvedType::RecursiveTagUnion(
|
||||
VarId::from_var(rec_var, subs),
|
||||
new_tags,
|
||||
Box::new(ext),
|
||||
)
|
||||
}
|
||||
EmptyRecord => SolvedType::EmptyRecord,
|
||||
EmptyTagUnion => SolvedType::EmptyTagUnion,
|
||||
Boolean(val) => SolvedType::Boolean(SolvedBool::from_bool(&val)),
|
||||
Boolean(val) => SolvedType::Boolean(SolvedBool::from_bool(&val, subs)),
|
||||
Erroneous(problem) => SolvedType::Erroneous(problem),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -199,7 +199,8 @@ impl UnifyKey for Variable {
|
|||
pub struct VarId(u32);
|
||||
|
||||
impl VarId {
|
||||
pub fn from_var(var: Variable) -> Self {
|
||||
pub fn from_var(var: Variable, subs: &Subs) -> Self {
|
||||
let var = subs.get_root_key_without_compacting(var);
|
||||
let Variable(n) = var;
|
||||
|
||||
VarId(n)
|
||||
|
|
|
@ -9,6 +9,10 @@ use roc_module::symbol::{Interns, ModuleId, Symbol};
|
|||
use roc_region::all::{Located, Region};
|
||||
use std::fmt;
|
||||
|
||||
pub const TYPE_NUM: &str = "Num";
|
||||
pub const TYPE_INTEGER: &str = "Integer";
|
||||
pub const TYPE_FLOATINGPOINT: &str = "FloatingPoint";
|
||||
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
pub enum Type {
|
||||
EmptyRec,
|
||||
|
@ -455,31 +459,32 @@ impl Type {
|
|||
Apply(Symbol::ATTR_ATTR, attr_args) => {
|
||||
use boolean_algebra::Bool;
|
||||
|
||||
let mut substitution = ImMap::default();
|
||||
debug_assert_eq!(attr_args.len(), 2);
|
||||
let mut it = attr_args.iter_mut();
|
||||
let uniqueness_type = it.next().unwrap();
|
||||
let base_type = it.next().unwrap();
|
||||
|
||||
if let Apply(symbol, _) = attr_args[1] {
|
||||
if let Some(alias) = aliases.get(&symbol) {
|
||||
if let Some(Bool::Container(unbound_cvar, mvars1)) =
|
||||
alias.uniqueness.clone()
|
||||
// instantiate the rest
|
||||
base_type.instantiate_aliases(region, aliases, var_store, introduced);
|
||||
|
||||
// correct uniqueness type
|
||||
// if this attr contains an alias of a recursive tag union, then the uniqueness
|
||||
// attribute on the recursion variable must match the uniqueness of the whole tag
|
||||
// union. We enforce that here.
|
||||
|
||||
if let Some(rec_uvar) = find_rec_var_uniqueness(base_type, aliases) {
|
||||
if let Bool::Container(unbound_cvar, mvars1) = rec_uvar {
|
||||
if let Type::Boolean(Bool::Container(bound_cvar, mvars2)) = uniqueness_type
|
||||
{
|
||||
debug_assert!(mvars1.is_empty());
|
||||
debug_assert!(mvars2.is_empty());
|
||||
|
||||
if let Type::Boolean(Bool::Container(bound_cvar, mvars2)) =
|
||||
&attr_args[0]
|
||||
{
|
||||
debug_assert!(mvars2.is_empty());
|
||||
substitution.insert(unbound_cvar, Type::Variable(*bound_cvar));
|
||||
}
|
||||
let mut substitution = ImMap::default();
|
||||
substitution.insert(unbound_cvar, Type::Variable(*bound_cvar));
|
||||
base_type.substitute(&substitution);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for x in attr_args {
|
||||
x.instantiate_aliases(region, aliases, var_store, introduced);
|
||||
if !substitution.is_empty() {
|
||||
x.substitute(&substitution);
|
||||
}
|
||||
}
|
||||
}
|
||||
Apply(symbol, args) => {
|
||||
if let Some(alias) = aliases.get(symbol) {
|
||||
|
@ -686,6 +691,34 @@ fn variables_help(tipe: &Type, accum: &mut ImSet<Variable>) {
|
|||
}
|
||||
}
|
||||
|
||||
/// We're looking for an alias whose actual type is a recursive tag union
|
||||
/// if `base_type` is one, return the uniqueness variable of the alias.
|
||||
fn find_rec_var_uniqueness(
|
||||
base_type: &Type,
|
||||
aliases: &ImMap<Symbol, Alias>,
|
||||
) -> Option<boolean_algebra::Bool> {
|
||||
use Type::*;
|
||||
|
||||
if let Alias(symbol, _, actual) = base_type {
|
||||
match **actual {
|
||||
Alias(_, _, _) => find_rec_var_uniqueness(actual, aliases),
|
||||
RecursiveTagUnion(_, _, _) => {
|
||||
if let Some(alias) = aliases.get(symbol) {
|
||||
// alias with a recursive tag union must have its uniqueness set
|
||||
debug_assert!(alias.uniqueness.is_some());
|
||||
|
||||
alias.uniqueness.clone()
|
||||
} else {
|
||||
unreachable!("aliases must be defined in the set of aliases!")
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RecordStructure {
|
||||
pub fields: MutMap<Lowercase, Variable>,
|
||||
pub ext: Variable,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue