Merge remote-tracking branch 'origin/trunk' into low-level-ops

This commit is contained in:
Richard Feldman 2020-07-07 21:02:03 -04:00
commit 1cd49689c2
29 changed files with 1630 additions and 440 deletions

View file

@ -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);

View file

@ -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),
}
}

View file

@ -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)

View file

@ -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,