Merge pull request #817 from rtfeldman/editor-ast-def

Editor ast def
This commit is contained in:
Richard Feldman 2020-12-21 23:48:36 -05:00 committed by GitHub
commit 4d692af639
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 656 additions and 35 deletions

1
Cargo.lock generated
View File

@ -2674,6 +2674,7 @@ dependencies = [
"roc_unify",
"roc_uniq",
"target-lexicon",
"ven_graph",
"wgpu",
"wgpu_glyph",
"winit",

View File

@ -27,6 +27,7 @@ roc_fmt = { path = "../compiler/fmt" }
roc_reporting = { path = "../compiler/reporting" }
# TODO switch to clap 3.0.0 once it's out. Tried adding clap = "~3.0.0-beta.1" and cargo wouldn't accept it
ven_graph = { path = "../vendor/pathfinding" }
im = "14" # im and im-rc should always have the same version!
im-rc = "14" # im and im-rc should always have the same version!
bumpalo = { version = "3.2", features = ["collections"] }

View File

@ -1,5 +1,5 @@
use crate::pattern::{Pattern2, PatternId};
use crate::pool::{NodeId, PoolStr, PoolVec};
use crate::pool::{NodeId, PoolStr, PoolVec, ShallowClone};
use crate::types::{Type2, TypeId};
use arraystring::{typenum::U30, ArrayString};
use roc_can::expr::Recursive;
@ -204,9 +204,22 @@ pub enum Expr2 {
#[derive(Debug)]
pub struct ValueDef {
pattern: PatternId, // 4B
expr_type: Option<(Type2, Rigids)>, // ?
expr_var: Variable, // 4B
pattern: PatternId, // 4B
expr_type: Option<(TypeId, Rigids)>, // ?
expr_var: Variable, // 4B
}
impl ShallowClone for ValueDef {
fn shallow_clone(&self) -> Self {
Self {
pattern: self.pattern,
expr_type: match &self.expr_type {
Some((id, rigids)) => Some((*id, rigids.shallow_clone())),
None => None,
},
expr_var: self.expr_var,
}
}
}
#[derive(Debug)]
@ -224,10 +237,38 @@ pub enum FunctionDef {
},
}
impl ShallowClone for FunctionDef {
fn shallow_clone(&self) -> Self {
match self {
Self::WithAnnotation {
name,
arguments,
rigids,
return_type,
} => Self::WithAnnotation {
name: *name,
arguments: arguments.shallow_clone(),
rigids: *rigids,
return_type: *return_type,
},
Self::NoAnnotation {
name,
arguments,
return_var,
} => Self::NoAnnotation {
name: *name,
arguments: arguments.shallow_clone(),
return_var: *return_var,
},
}
}
}
#[derive(Debug)]
pub struct Rigids {
named: PoolVec<(PoolStr, Variable)>, // 8B
unnamed: PoolVec<Variable>, // 8B
pub named: PoolVec<(PoolStr, Variable)>, // 8B
pub unnamed: PoolVec<Variable>, // 8B
}
/// This is overflow data from a Closure variant, which needs to store
@ -253,3 +294,12 @@ pub type ExprId = NodeId<Expr2>;
fn size_of_expr() {
assert_eq!(std::mem::size_of::<Expr2>(), crate::pool::NODE_BYTES);
}
impl ShallowClone for Rigids {
fn shallow_clone(&self) -> Self {
Self {
named: self.named.shallow_clone(),
unnamed: self.unnamed.shallow_clone(),
}
}
}

430
editor/src/def.rs Normal file
View File

@ -0,0 +1,430 @@
#![allow(clippy::all)]
#![allow(dead_code)]
#![allow(unused_imports)]
#![allow(unused_variables)]
// use crate::annotation::canonicalize_annotation;
// use crate::annotation::IntroducedVariables;
// use crate::env::Env;
// use crate::expr::Expr::{self, *};
// use crate::expr::{
// canonicalize_expr, local_successors, references_from_call, references_from_local, Output,
// Recursive,
// };
// use crate::pattern::{bindings_from_patterns, canonicalize_pattern, Pattern};
// use crate::procedure::References;
use crate::ast::{FunctionDef, Rigids, ValueDef};
use crate::expr::Env;
use crate::pattern::{
symbols_and_variables_from_pattern, symbols_from_pattern, to_pattern_id, Pattern2, PatternId,
};
use crate::pool::{NodeId, Pool, PoolStr, PoolVec, ShallowClone};
use crate::scope::Scope;
use crate::types::{to_annotation2, Alias, Annotation2, References, Signature, Type2, TypeId};
use roc_can::expr::Output;
use roc_collections::all::{default_hasher, ImMap, ImSet, MutMap, MutSet, SendMap};
use roc_module::ident::Lowercase;
use roc_module::symbol::Symbol;
use roc_parse::ast;
use roc_parse::pattern::PatternType;
use roc_problem::can::{Problem, RuntimeError};
use roc_region::all::{Located, Region};
use roc_types::subs::{VarStore, Variable};
use std::collections::HashMap;
use std::fmt::Debug;
use ven_graph::{strongly_connected_components, topological_sort_into_groups};
#[derive(Debug)]
enum Def {
AnnotationOnly {
rigids: crate::ast::Rigids,
annotation: TypeId,
},
Value(ValueDef),
Function(FunctionDef),
}
impl ShallowClone for Def {
fn shallow_clone(&self) -> Self {
match self {
Self::AnnotationOnly { rigids, annotation } => Self::AnnotationOnly {
rigids: rigids.shallow_clone(),
annotation: *annotation,
},
Self::Value(def) => Self::Value(def.shallow_clone()),
Self::Function(def) => Self::Function(def.shallow_clone()),
}
}
}
/// A Def that has had patterns and type annnotations canonicalized,
/// but no Expr canonicalization has happened yet. Also, it has had spaces
/// and nesting resolved, and knows whether annotations are standalone or not.
#[derive(Debug)]
enum PendingDef<'a> {
/// A standalone annotation with no body
AnnotationOnly(
&'a Located<ast::Pattern<'a>>,
PatternId,
&'a Located<ast::TypeAnnotation<'a>>,
),
/// A body with no type annotation
Body(
&'a Located<ast::Pattern<'a>>,
PatternId,
&'a Located<ast::Expr<'a>>,
),
/// A body with a type annotation
TypedBody(
&'a Located<ast::Pattern<'a>>,
PatternId,
&'a Located<ast::TypeAnnotation<'a>>,
&'a Located<ast::Expr<'a>>,
),
/// A type alias, e.g. `Ints : List Int`
Alias {
name: Located<Symbol>,
vars: Vec<Located<Lowercase>>,
ann: &'a Located<ast::TypeAnnotation<'a>>,
},
/// An invalid alias, that is ignored in the rest of the pipeline
/// e.g. a shadowed alias, or a definition like `MyAlias 1 : Int`
/// with an incorrect pattern
InvalidAlias,
}
fn to_pending_def<'a>(
env: &mut Env<'a>,
def: &'a ast::Def<'a>,
scope: &mut Scope,
pattern_type: PatternType,
) -> Option<(Output, PendingDef<'a>)> {
use roc_parse::ast::Def::*;
match def {
Annotation(loc_pattern, loc_ann) => {
// This takes care of checking for shadowing and adding idents to scope.
let (output, loc_can_pattern) = crate::pattern::to_pattern_id(
env,
scope,
pattern_type,
&loc_pattern.value,
loc_pattern.region,
);
Some((
output,
PendingDef::AnnotationOnly(loc_pattern, loc_can_pattern, loc_ann),
))
}
Body(loc_pattern, loc_expr) => {
// This takes care of checking for shadowing and adding idents to scope.
let (output, loc_can_pattern) = crate::pattern::to_pattern_id(
env,
scope,
pattern_type,
&loc_pattern.value,
loc_pattern.region,
);
Some((
output,
PendingDef::Body(loc_pattern, loc_can_pattern, loc_expr),
))
}
AnnotatedBody {
ann_pattern,
ann_type,
comment: _,
body_pattern,
body_expr,
} => {
if ann_pattern.value.equivalent(&body_pattern.value) {
// NOTE: Pick the body pattern, picking the annotation one is
// incorrect in the presence of optional record fields!
//
// { x, y } : { x : Int, y ? Bool }*
// { x, y ? False } = rec
Some(pending_typed_body(
env,
body_pattern,
ann_type,
body_expr,
scope,
pattern_type,
))
} else {
// the pattern of the annotation does not match the pattern of the body direc
env.problem(Problem::SignatureDefMismatch {
annotation_pattern: ann_pattern.region,
def_pattern: body_pattern.region,
});
// TODO: Should we instead build some PendingDef::InvalidAnnotatedBody ? This would
// remove the `Option` on this function (and be probably more reliable for further
// problem/error reporting)
None
}
}
roc_parse::ast::Def::Alias { name, vars, ann } => {
let region = Region::span_across(&name.region, &ann.region);
match scope.introduce(
name.value.into(),
&env.exposed_ident_ids,
&mut env.ident_ids,
region,
) {
Ok(symbol) => {
let mut can_rigids: Vec<Located<Lowercase>> = Vec::with_capacity(vars.len());
for loc_var in vars.iter() {
match loc_var.value {
ast::Pattern::Identifier(name)
if name.chars().next().unwrap().is_lowercase() =>
{
let lowercase = Lowercase::from(name);
can_rigids.push(Located {
value: lowercase,
region: loc_var.region,
});
}
_ => {
// any other pattern in this position is a syntax error.
env.problem(Problem::InvalidAliasRigid {
alias_name: symbol,
region: loc_var.region,
});
return Some((Output::default(), PendingDef::InvalidAlias));
}
}
}
Some((
Output::default(),
PendingDef::Alias {
name: Located {
region: name.region,
value: symbol,
},
vars: can_rigids,
ann,
},
))
}
Err((original_region, loc_shadowed_symbol)) => {
env.problem(Problem::ShadowingInAnnotation {
original_region,
shadow: loc_shadowed_symbol,
});
Some((Output::default(), PendingDef::InvalidAlias))
}
}
}
SpaceBefore(sub_def, _) | SpaceAfter(sub_def, _) | Nested(sub_def) => {
to_pending_def(env, sub_def, scope, pattern_type)
}
NotYetImplemented(s) => todo!("{}", s),
}
}
fn pending_typed_body<'a>(
env: &mut Env<'a>,
loc_pattern: &'a Located<ast::Pattern<'a>>,
loc_ann: &'a Located<ast::TypeAnnotation<'a>>,
loc_expr: &'a Located<ast::Expr<'a>>,
scope: &mut Scope,
pattern_type: PatternType,
) -> (Output, PendingDef<'a>) {
// This takes care of checking for shadowing and adding idents to scope.
let (output, loc_can_pattern) = to_pattern_id(
env,
scope,
pattern_type,
&loc_pattern.value,
loc_pattern.region,
);
(
output,
PendingDef::TypedBody(loc_pattern, loc_can_pattern, loc_ann, loc_expr),
)
}
// TODO trim down these arguments!
#[allow(clippy::too_many_arguments)]
#[allow(clippy::cognitive_complexity)]
fn canonicalize_pending_def<'a>(
env: &mut Env<'a>,
pending_def: PendingDef<'a>,
mut output: Output,
scope: &mut Scope,
can_defs_by_symbol: &mut MutMap<Symbol, Def>,
refs_by_symbol: &mut MutMap<Symbol, (Region, References)>,
aliases: &mut SendMap<Symbol, Alias>,
) -> Output {
use PendingDef::*;
// Make types for the body expr, even if we won't end up having a body.
let expr_var = env.var_store.fresh();
match pending_def {
AnnotationOnly(_, loc_can_pattern, loc_ann) => {
// annotation sans body cannot introduce new rigids that are visible in other annotations
// but the rigids can show up in type error messages, so still register them
match to_annotation2(env, scope, &loc_ann.value, loc_ann.region) {
Annotation2::Erroneous(_) => todo!(),
Annotation2::Annotation {
named_rigids,
unnamed_rigids,
symbols,
signature,
} => {
// Record all the annotation's references in output.references.lookups
for symbol in symbols {
output.references.lookups.insert(symbol);
output.references.referenced_aliases.insert(symbol);
}
let rigids = {
let named = PoolVec::with_capacity(named_rigids.len() as u32, env.pool);
let unnamed = PoolVec::with_capacity(unnamed_rigids.len() as u32, env.pool);
for (node_id, (name, variable)) in named.iter_node_ids().zip(named_rigids) {
let poolstr = PoolStr::new(name, env.pool);
env.pool[node_id] = (poolstr, variable);
}
for (node_id, rigid) in unnamed.iter_node_ids().zip(unnamed_rigids) {
env.pool[node_id] = rigid;
}
Rigids { named, unnamed }
};
let annotation = match signature {
Signature::Value { annotation } => annotation,
Signature::Function {
arguments,
closure_type_id,
return_type_id,
} => Type2::Function(arguments, closure_type_id, return_type_id),
Signature::FunctionWithAliases { annotation, .. } => annotation,
};
let annotation = env.add(annotation, loc_ann.region);
let def = Def::AnnotationOnly { rigids, annotation };
for symbol in symbols_from_pattern(env.pool, env.pool.get(loc_can_pattern)) {
can_defs_by_symbol.insert(symbol, def.shallow_clone());
}
output
}
}
}
PendingDef::Alias { name, ann, vars } => {
let symbol = name.value;
match to_annotation2(env, scope, &ann.value, ann.region) {
Annotation2::Erroneous(_) => todo!(),
Annotation2::Annotation {
named_rigids,
unnamed_rigids,
symbols,
signature,
} => {
// Record all the annotation's references in output.references.lookups
for symbol in symbols {
output.references.lookups.insert(symbol);
output.references.referenced_aliases.insert(symbol);
}
for loc_lowercase in vars {
if !named_rigids.contains_key(loc_lowercase.value.as_str()) {
env.problem(Problem::PhantomTypeArgument {
alias: symbol,
variable_region: loc_lowercase.region,
variable_name: loc_lowercase.value.clone(),
});
}
}
let named = PoolVec::with_capacity(named_rigids.len() as u32, env.pool);
let unnamed = PoolVec::with_capacity(unnamed_rigids.len() as u32, env.pool);
for (node_id, (name, variable)) in named.iter_node_ids().zip(named_rigids) {
let poolstr = PoolStr::new(name, env.pool);
env.pool[node_id] = (poolstr, variable);
}
for (node_id, rigid) in unnamed.iter_node_ids().zip(unnamed_rigids) {
env.pool[node_id] = rigid;
}
let rigids = Rigids {
named: named.shallow_clone(),
unnamed,
};
let annotation = match signature {
Signature::Value { annotation } => annotation,
Signature::Function {
arguments,
closure_type_id,
return_type_id,
} => Type2::Function(arguments, closure_type_id, return_type_id),
Signature::FunctionWithAliases { annotation, .. } => annotation,
};
if annotation.contains_symbol(env.pool, symbol) {
// the alias is recursive. If it's a tag union, we attempt to fix this
if let Type2::TagUnion(tags, ext) = annotation {
// re-canonicalize the alias with the alias already in scope
let rec_var = env.var_store.fresh();
let rec_type_union = Type2::RecursiveTagUnion(rec_var, tags, ext);
// NOTE this only looks at the symbol, and just assumes that the
// recursion is not polymorphic
rec_type_union.substitute_alias(
env.pool,
symbol,
Type2::Variable(rec_var),
);
let annotation_id = env.add(rec_type_union, ann.region);
scope.add_alias(env.pool, symbol, named, annotation_id);
} else {
env.problem(Problem::CyclicAlias(symbol, name.region, vec![]));
return output;
}
} else {
let annotation_id = env.add(annotation, ann.region);
scope.add_alias(env.pool, symbol, named, annotation_id);
}
output
}
}
}
InvalidAlias => {
// invalid aliases (shadowed, incorrect patterns )
todo!()
}
_ => todo!(),
}
}

View File

@ -4,6 +4,7 @@
use crate::ast::{Expr2, ExprId, FloatVal, IntStyle, IntVal};
use crate::pattern::to_pattern2;
use crate::pool::{NodeId, Pool, PoolStr, PoolVec};
use crate::scope::Scope;
use crate::types::{Type2, TypeId};
use bumpalo::Bump;
use inlinable_string::InlinableString;
@ -11,7 +12,6 @@ use roc_can::expr::Output;
use roc_can::expr::Recursive;
use roc_can::num::{finish_parsing_base, finish_parsing_float, finish_parsing_int};
use roc_can::procedure::References;
use roc_can::scope::Scope;
use roc_collections::all::{MutMap, MutSet};
use roc_module::low_level::LowLevel;
use roc_module::operator::CalledVia;
@ -511,7 +511,7 @@ pub fn to_expr2<'a>(
// Shadow `scope` to make sure we don't accidentally use the original one for the
// rest of this block, but keep the original around for later diffing.
let original_scope = scope;
let mut scope = original_scope.clone();
let mut scope = original_scope.duplicate();
let can_args = PoolVec::with_capacity(loc_arg_patterns.len() as u32, env.pool);
let mut output = Output::default();
@ -569,16 +569,16 @@ pub fn to_expr2<'a>(
// Now that we've collected all the references, check to see if any of the args we defined
// went unreferenced. If any did, report them as unused arguments.
for (sub_symbol, region) in scope.symbols() {
if !original_scope.contains_symbol(*sub_symbol) {
if !output.references.has_lookup(*sub_symbol) {
if !original_scope.contains_symbol(sub_symbol) {
if !output.references.has_lookup(sub_symbol) {
// The body never referenced this argument we declared. It's an unused argument!
env.problem(Problem::UnusedArgument(symbol, *sub_symbol, *region));
env.problem(Problem::UnusedArgument(symbol, sub_symbol, region));
}
// We shouldn't ultimately count arguments as referenced locals. Otherwise,
// we end up with weird conclusions like the expression (\x -> x + 1)
// references the (nonexistant) local variable x!
output.references.lookups.remove(sub_symbol);
output.references.lookups.remove(&sub_symbol);
}
}
@ -1049,7 +1049,7 @@ fn canonicalize_when_branch<'a>(
let patterns = PoolVec::with_capacity(branch.patterns.len() as u32, env.pool);
let original_scope = scope;
let mut scope = original_scope.clone();
let mut scope = original_scope.duplicate();
// TODO report symbols not bound in all patterns
for (node_id, loc_pattern) in patterns.iter_node_ids().zip(branch.patterns.iter()) {
@ -1089,13 +1089,13 @@ fn canonicalize_when_branch<'a>(
// Now that we've collected all the references for this branch, check to see if
// any of the new idents it defined were unused. If any were, report it.
for (symbol, region) in scope.symbols() {
let symbol = *symbol;
let symbol = symbol;
if !output.references.has_lookup(symbol)
&& !branch_output.references.has_lookup(symbol)
&& !original_scope.contains_symbol(symbol)
{
env.problem(Problem::UnusedDef(symbol, *region));
env.problem(Problem::UnusedDef(symbol, region));
}
}

View File

@ -21,6 +21,7 @@ use winit::event_loop::ControlFlow;
pub mod ast;
mod buffer;
mod def;
pub mod expr;
pub mod file;
mod keyboard_input;

View File

@ -4,9 +4,9 @@
use crate::ast::{ExprId, FloatVal, IntVal};
use crate::expr::{to_expr_id, Env};
use crate::pool::{NodeId, Pool, PoolStr, PoolVec};
use crate::scope::Scope;
use roc_can::expr::{unescape_char, Output};
use roc_can::num::{finish_parsing_base, finish_parsing_float, finish_parsing_int};
use roc_can::scope::Scope;
use roc_module::symbol::Symbol;
use roc_parse::ast::{StrLiteral, StrSegment};
use roc_parse::pattern::PatternType;
@ -455,6 +455,54 @@ pub fn symbols_from_pattern(pool: &Pool, initial: &Pattern2) -> Vec<Symbol> {
symbols
}
pub fn symbols_and_variables_from_pattern(
pool: &Pool,
initial: &Pattern2,
initial_var: Variable,
) -> Vec<(Symbol, Variable)> {
use Pattern2::*;
let mut symbols = Vec::new();
let mut stack = vec![(initial_var, initial)];
while let Some((variable, pattern)) = stack.pop() {
match pattern {
Identifier(symbol) => {
symbols.push((*symbol, variable));
}
GlobalTag { arguments, .. } | PrivateTag { arguments, .. } => {
for (var, pat) in arguments.iter(pool) {
stack.push((*var, pat));
}
}
RecordDestructure { destructs, .. } => {
for destruct in destructs.iter(pool) {
let destruct_type = pool.get(destruct.typ);
if let DestructType::Guard(_, subpattern_id) = &destruct_type {
let subpattern = pool.get(*subpattern_id);
stack.push((destruct.var, subpattern));
} else {
symbols.push((destruct.symbol, destruct.var));
}
}
}
NumLiteral(_, _)
| IntLiteral(_)
| FloatLiteral(_)
| StrLiteral(_)
| Underscore
| MalformedPattern(_, _)
| Shadowed { .. }
| UnsupportedPattern(_) => {}
}
}
symbols
}
/// When we detect an unsupported pattern type (e.g. 5 = 1 + 2 is unsupported because you can't
/// assign to Int patterns), report it to Env and return an UnsupportedPattern runtime error pattern.
fn unsupported_pattern<'a>(

View File

@ -244,8 +244,10 @@ impl PoolStr {
}
}
}
}
pub fn duplicate(&self) -> Self {
impl ShallowClone for PoolStr {
fn shallow_clone(&self) -> Self {
// Question: should this fully clone, or is a shallow copy
// (and the aliasing it entails) OK?
Self {
@ -365,15 +367,6 @@ impl<'a, T: 'a + Sized> PoolVec<T> {
}
}
pub fn duplicate(&self) -> Self {
// Question: should this fully clone, or is a shallow copy
// (and the aliasing it entails) OK?
Self {
first_node_id: self.first_node_id,
len: self.len,
}
}
pub fn free<S>(self, pool: &'a mut Pool) {
// zero out the memory
unsafe {
@ -388,6 +381,17 @@ impl<'a, T: 'a + Sized> PoolVec<T> {
}
}
impl<T> ShallowClone for PoolVec<T> {
fn shallow_clone(&self) -> Self {
// Question: should this fully clone, or is a shallow copy
// (and the aliasing it entails) OK?
Self {
first_node_id: self.first_node_id,
len: self.len,
}
}
}
struct PoolVecIter<'a, T> {
pool: &'a Pool,
current_node_id: NodeId<T>,
@ -551,3 +555,8 @@ impl<T> Iterator for PoolVecIterNodeIds<T> {
}
}
}
/// Clones the outer node, but does not clone any nodeids
pub trait ShallowClone {
fn shallow_clone(&self) -> Self;
}

View File

@ -1,7 +1,7 @@
#![allow(clippy::all)]
#![allow(dead_code)]
#![allow(unused_imports)]
use crate::pool::{Pool, PoolStr, PoolVec};
use crate::pool::{Pool, PoolStr, PoolVec, ShallowClone};
use crate::types::{Alias, TypeId};
use roc_collections::all::{MutMap, MutSet};
use roc_module::ident::{Ident, Lowercase};
@ -25,7 +25,6 @@ pub struct Scope {
symbols: MutMap<Symbol, Region>,
/// The type aliases currently in scope
/// Uses BTreeMap because HashMap requires elements are Clone
aliases: MutMap<Symbol, Alias>,
/// The current module being processed. This will be used to turn
@ -34,6 +33,19 @@ pub struct Scope {
}
impl Scope {
pub fn duplicate(&self) -> Self {
Self {
idents: self.idents.clone(),
symbols: self.symbols.clone(),
aliases: self
.aliases
.iter()
.map(|(s, a)| (*s, a.shallow_clone()))
.collect(),
home: self.home,
}
}
pub fn new(home: ModuleId, pool: &mut Pool, _var_store: &mut VarStore) -> Scope {
use roc_types::solved_types::{BuiltinAlias, FreeVars};
let solved_aliases = roc_types::builtin_aliases::aliases();

View File

@ -2,7 +2,7 @@
#![allow(dead_code)]
#![allow(unused_imports)]
use crate::expr::Env;
use crate::pool::{NodeId, Pool, PoolStr, PoolVec};
use crate::pool::{NodeId, Pool, PoolStr, PoolVec, ShallowClone};
use crate::scope::Scope;
// use roc_can::expr::Output;
use roc_collections::all::{MutMap, MutSet};
@ -45,7 +45,66 @@ impl Type2 {
fn substitute(_pool: &mut Pool, _subs: &MutMap<Variable, TypeId>, _type_id: TypeId) {
todo!()
}
pub fn variables(&self, _pool: &mut Pool) -> MutSet<Variable> {
pub fn variables(&self, pool: &mut Pool) -> MutSet<Variable> {
use Type2::*;
let mut stack = vec![self];
let mut result = MutSet::default();
while let Some(this) = stack.pop() {
match this {
Variable(v) => {
result.insert(*v);
}
Alias(_, _, actual) | AsAlias(_, _, actual) => {
stack.push(pool.get(*actual));
}
HostExposedAlias {
actual_var, actual, ..
} => {
result.insert(*actual_var);
stack.push(pool.get(*actual));
}
EmptyTagUnion | EmptyRec | Erroneous(_) => {}
TagUnion(tags, ext) => {
for (_, args) in tags.iter(pool) {
stack.extend(args.iter(pool));
}
stack.push(pool.get(*ext));
}
RecursiveTagUnion(rec, tags, ext) => {
for (_, args) in tags.iter(pool) {
stack.extend(args.iter(pool));
}
stack.push(pool.get(*ext));
result.insert(*rec);
}
Record(fields, ext) => {
for (_, field) in fields.iter(pool) {
stack.push(field.as_inner());
}
stack.push(pool.get(*ext));
}
Function(args, closure, result) => {
stack.extend(args.iter(pool));
stack.push(pool.get(*closure));
stack.push(pool.get(*result));
}
Apply(_, args) => {
stack.extend(args.iter(pool));
}
}
}
result
}
pub fn contains_symbol(&self, _pool: &mut Pool, _needle: Symbol) -> bool {
todo!()
}
pub fn substitute_alias(&self, _pool: &mut Pool, _needle: Symbol, _actual: Self) {
todo!()
}
}
@ -163,7 +222,7 @@ fn shallow_dealias<'a>(
}
Type2::Function(arguments, closure_type_id, return_type_id) => {
let signature = Signature::FunctionWithAliases {
arguments: arguments.duplicate(),
arguments: arguments.shallow_clone(),
closure_type_id: *closure_type_id,
return_type_id: *return_type_id,
annotation,
@ -370,7 +429,7 @@ pub fn to_type2<'a>(
let poolstr = PoolStr::new(var_name, env.pool);
let type_id = env.pool.add(Type2::Variable(*var));
env.pool[var_id] = (poolstr.duplicate(), type_id);
env.pool[var_id] = (poolstr.shallow_clone(), type_id);
env.pool[named_id] = (poolstr, *var);
env.set_region(named_id, loc_var.region);
@ -381,7 +440,7 @@ pub fn to_type2<'a>(
let poolstr = PoolStr::new(var_name, env.pool);
let type_id = env.pool.add(Type2::Variable(var));
env.pool[var_id] = (poolstr.duplicate(), type_id);
env.pool[var_id] = (poolstr.shallow_clone(), type_id);
env.pool[named_id] = (poolstr, var);
env.set_region(named_id, loc_var.region);
@ -700,7 +759,7 @@ fn to_type_apply<'a>(
for (node_id, (type_id, loc_var_id)) in it {
let loc_var = &env.pool[loc_var_id];
let name = loc_var.0.duplicate();
let name = loc_var.0.shallow_clone();
let var = loc_var.1;
env.pool[node_id] = (name, type_id);
@ -715,7 +774,7 @@ fn to_type_apply<'a>(
if let Type2::RecursiveTagUnion(rvar, ref tags, ext) = &mut env.pool[actual] {
substitutions.insert(*rvar, fresh);
env.pool[actual] = Type2::RecursiveTagUnion(new, tags.duplicate(), *ext);
env.pool[actual] = Type2::RecursiveTagUnion(new, tags.shallow_clone(), *ext);
}
// make sure hidden variables are freshly instantiated
@ -742,3 +801,13 @@ pub struct Alias {
/// hidden type variables, like the closure variable in `a -> b`
pub hidden_variables: PoolVec<Variable>,
}
impl ShallowClone for Alias {
fn shallow_clone(&self) -> Self {
Self {
targs: self.targs.shallow_clone(),
hidden_variables: self.hidden_variables.shallow_clone(),
actual: self.actual,
}
}
}