diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index aab29762b5..149ed5a3f3 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -21,5 +21,8 @@ jobs: with: clean: "true" - - name: setup dependencies with nix, build and test - run: nix develop -c cargo test --locked --release --no-run \ No newline at end of file + - name: setup dependencies with nix and build the tests + run: nix develop -c cargo test --locked --release --no-run + + - name: execute tests with guaranteed success + run: nix develop -c cargo test --locked --release --no-fail-fast || true # || true to return a successful exit code so that test failures can be observed diff --git a/Cargo.lock b/Cargo.lock index 0c1f479b56..57203a4c28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4141,7 +4141,6 @@ dependencies = [ "roc_module", "roc_region", "static_assertions 1.1.0", - "ven_ena", ] [[package]] @@ -5077,13 +5076,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "ven_ena" -version = "0.13.1" -dependencies = [ - "log", -] - [[package]] name = "ven_graph" version = "2.0.5-pre" diff --git a/Cargo.toml b/Cargo.toml index 9ead607540..6ec7d2b7d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,6 @@ members = [ "compiler/test_gen", "compiler/roc_target", "compiler/debug_flags", - "vendor/ena", "vendor/inkwell", "vendor/pathfinding", "vendor/pretty", diff --git a/compiler/build/src/link.rs b/compiler/build/src/link.rs index 5b3c31b019..2145d9f10f 100644 --- a/compiler/build/src/link.rs +++ b/compiler/build/src/link.rs @@ -361,11 +361,12 @@ pub fn build_swift_host_native( unimplemented!("Linking a shared library to Swift not yet implemented"); } - let mut command = Command::new("swiftc"); + let mut command = Command::new("xcrun"); // xcrun helps swiftc to find the right header files command .env_clear() .env("PATH", &env_path) .env("HOME", &env_home) + .arg("swiftc") .args(sources) .arg("-emit-object") .arg("-parse-as-library") diff --git a/compiler/can/src/def.rs b/compiler/can/src/def.rs index deebe1cbf3..af46a3204d 100644 --- a/compiler/can/src/def.rs +++ b/compiler/can/src/def.rs @@ -867,43 +867,41 @@ fn resolve_abilities<'a>( .iter() .partition(|av| av.ability == loc_ability_name.value); - let mut bad_has_clauses = false; - - if variables_bound_to_ability.is_empty() { - // There are no variables bound to the parent ability - then this member doesn't - // need to be a part of the ability. - env.problem(Problem::AbilityMemberMissingHasClause { - member: member_sym, - ability: loc_ability_name.value, - region: name_region, - }); - bad_has_clauses = true; - } - - if variables_bound_to_ability.len() > 1 { - // There is more than one variable bound to the member signature, so something like - // Eq has eq : a, b -> Bool | a has Eq, b has Eq - // We have no way of telling what type implements a particular instance of Eq in - // this case (a or b?), so disallow it. - let span_has_clauses = - Region::across_all(variables_bound_to_ability.iter().map(|v| &v.first_seen)); - let bound_var_names = variables_bound_to_ability - .iter() - .map(|v| v.name.clone()) - .collect(); - env.problem(Problem::AbilityMemberMultipleBoundVars { - member: member_sym, - ability: loc_ability_name.value, - span_has_clauses, - bound_var_names, - }); - bad_has_clauses = true; - } - - if bad_has_clauses { - // Pretend the member isn't a part of the ability - continue; - } + let var_bound_to_ability = match variables_bound_to_ability.as_slice() { + [one] => one.variable, + [] => { + // There are no variables bound to the parent ability - then this member doesn't + // need to be a part of the ability. + env.problem(Problem::AbilityMemberMissingHasClause { + member: member_sym, + ability: loc_ability_name.value, + region: name_region, + }); + // Pretend the member isn't a part of the ability + continue; + } + [..] => { + // There is more than one variable bound to the member signature, so something like + // Eq has eq : a, b -> Bool | a has Eq, b has Eq + // We have no way of telling what type implements a particular instance of Eq in + // this case (a or b?), so disallow it. + let span_has_clauses = Region::across_all( + variables_bound_to_ability.iter().map(|v| &v.first_seen), + ); + let bound_var_names = variables_bound_to_ability + .iter() + .map(|v| v.name.clone()) + .collect(); + env.problem(Problem::AbilityMemberMultipleBoundVars { + member: member_sym, + ability: loc_ability_name.value, + span_has_clauses, + bound_var_names, + }); + // Pretend the member isn't a part of the ability + continue; + } + }; // The introduced variables are good; add them to the output. output @@ -918,6 +916,13 @@ fn resolve_abilities<'a>( flex_vars: iv.collect_flex(), }; + let signature = { + let mut signature = member_annot.typ; + signature + .instantiate_lambda_sets_as_unspecialized(var_bound_to_ability, member_sym); + signature + }; + can_members.push(( member_sym, AbilityMemberData { @@ -925,7 +930,7 @@ fn resolve_abilities<'a>( region: name_region, typ: MemberTypeInfo::Local { variables, - signature: member_annot.typ, + signature, signature_var: var_store.fresh(), }, }, diff --git a/compiler/solve/src/solve.rs b/compiler/solve/src/solve.rs index 9f6ab8e66b..5493629154 100644 --- a/compiler/solve/src/solve.rs +++ b/compiler/solve/src/solve.rs @@ -1685,7 +1685,6 @@ impl LocalDefVarsVec<(Symbol, Loc)> { } } -use std::borrow::Borrow; use std::cell::RefCell; use std::ops::ControlFlow; std::thread_local! { @@ -1888,6 +1887,18 @@ fn type_to_variable<'a>( register_with_known_var(subs, destination, rank, pools, content) } + UnspecializedLambdaSet(..) => { + // TODO: instantiate properly! + let union_lambdas = + UnionLambdas::from_slices(SubsSlice::new(0, 0), SubsSlice::new(0, 0)); + + let content = Content::LambdaSet(subs::LambdaSet { + solved: union_lambdas, + recursion_var: OptVariable::NONE, + }); + + register_with_known_var(subs, destination, rank, pools, content) + } // This case is important for the rank of boolean variables Function(arguments, closure_type, ret_type) => { let new_arguments = VariableSubsSlice::reserve_into_subs(subs, arguments.len()); @@ -2379,12 +2390,12 @@ fn insert_tags_fast_path<'a>( rank: Rank, pools: &mut Pools, arena: &'_ bumpalo::Bump, - tags: &'a [(TagName, impl Borrow<[Type]>)], + tags: &'a [(TagName, Vec)], stack: &mut bumpalo::collections::Vec<'_, TypeToVar<'a>>, ) -> UnionTags { if let [(TagName(tag_name), arguments)] = tags { let variable_slice = - register_tag_arguments(subs, rank, pools, arena, stack, arguments.borrow()); + register_tag_arguments(subs, rank, pools, arena, stack, arguments.as_slice()); let new_variable_slices = SubsSlice::extend_new(&mut subs.variable_slices, [variable_slice]); @@ -2411,7 +2422,7 @@ fn insert_tags_fast_path<'a>( for (variable_slice_index, (_, arguments)) in it { subs.variable_slices[variable_slice_index] = - register_tag_arguments(subs, rank, pools, arena, stack, arguments.borrow()); + register_tag_arguments(subs, rank, pools, arena, stack, arguments.as_slice()); } UnionTags::from_slices(new_tag_names, new_variable_slices) @@ -2425,7 +2436,7 @@ fn insert_tags_fast_path<'a>( for ((variable_slice_index, tag_name_index), (tag_name, arguments)) in it { subs.variable_slices[variable_slice_index] = - register_tag_arguments(subs, rank, pools, arena, stack, arguments.borrow()); + register_tag_arguments(subs, rank, pools, arena, stack, arguments.as_slice()); subs.tag_names[tag_name_index] = tag_name.clone(); } @@ -2440,12 +2451,12 @@ fn insert_tags_slow_path<'a>( rank: Rank, pools: &mut Pools, arena: &'_ bumpalo::Bump, - tags: &'a [(TagName, impl Borrow<[Type]>)], + tags: &'a [(TagName, Vec)], mut tag_vars: bumpalo::collections::Vec<(TagName, VariableSubsSlice)>, stack: &mut bumpalo::collections::Vec<'_, TypeToVar<'a>>, ) -> UnionTags { for (tag, tag_argument_types) in tags { - let tag_argument_types: &[Type] = tag_argument_types.borrow(); + let tag_argument_types: &[Type] = tag_argument_types.as_slice(); let new_slice = VariableSubsSlice::reserve_into_subs(subs, tag_argument_types.len()); for (i, arg) in (new_slice.indices()).zip(tag_argument_types) { @@ -2466,7 +2477,7 @@ fn type_to_union_tags<'a>( rank: Rank, pools: &mut Pools, arena: &'_ bumpalo::Bump, - tags: &'a [(TagName, impl Borrow<[Type]>)], + tags: &'a [(TagName, Vec)], ext: &'a TypeExtension, stack: &mut bumpalo::collections::Vec<'_, TypeToVar<'a>>, ) -> (UnionTags, Variable) { diff --git a/compiler/solve/tests/solve_expr.rs b/compiler/solve/tests/solve_expr.rs index 486928dea1..ce8ce166c7 100644 --- a/compiler/solve/tests/solve_expr.rs +++ b/compiler/solve/tests/solve_expr.rs @@ -2504,7 +2504,7 @@ mod solve_expr { { numIdentity, x : numIdentity 42, y } "# ), - "{ numIdentity : Num a -> Num a, x : Num a, y : Float * }", + "{ numIdentity : Num a -> Num a, x : Num b, y : Float * }", ); } @@ -3395,7 +3395,7 @@ mod solve_expr { { id1, id2 } "# ), - "{ id1 : q -> q, id2 : q -> q }", + "{ id1 : q -> q, id2 : a -> a }", ); } @@ -3910,7 +3910,7 @@ mod solve_expr { { a, b } "# ), - "{ a : { x : I64, y : I64, z : Num c }, b : { blah : Str, x : I64, y : I64, z : Num c } }", + "{ a : { x : I64, y : I64, z : Num c }, b : { blah : Str, x : I64, y : I64, z : Num a } }", ); } @@ -3941,7 +3941,7 @@ mod solve_expr { { a, b } "# ), - "{ a : { x : Num a, y : Float *, z : c }, b : { blah : Str, x : Num a, y : Float *, z : c } }", + "{ a : { x : Num a, y : Float *, z : c }, b : { blah : Str, x : Num b, y : Float *, z : d } }", ); } @@ -6100,7 +6100,7 @@ mod solve_expr { hashEq = \x, y -> hash x == hash y "# ), - "a, a -> Bool | a has Hash", + "a, b -> Bool | a has Hash, b has Hash", ) } diff --git a/compiler/types/Cargo.toml b/compiler/types/Cargo.toml index a27e2ad4c9..266d118d6c 100644 --- a/compiler/types/Cargo.toml +++ b/compiler/types/Cargo.toml @@ -11,6 +11,5 @@ roc_region = { path = "../region" } roc_module = { path = "../module" } roc_error_macros = {path="../../error_macros"} roc_debug_flags = {path="../debug_flags"} -ven_ena = { path = "../../vendor/ena" } bumpalo = { version = "3.8.0", features = ["collections"] } static_assertions = "1.1.0" diff --git a/compiler/types/src/pretty_print.rs b/compiler/types/src/pretty_print.rs index 45aee3e5a8..68f50e9974 100644 --- a/compiler/types/src/pretty_print.rs +++ b/compiler/types/src/pretty_print.rs @@ -3,7 +3,7 @@ use crate::subs::{ UnionTags, Variable, }; use crate::types::{name_type_var, RecordField}; -use roc_collections::all::{MutMap, MutSet}; +use roc_collections::all::MutMap; use roc_error_macros::internal_error; use roc_module::ident::{Lowercase, TagName}; use roc_module::symbol::{Interns, ModuleId, Symbol}; @@ -58,6 +58,7 @@ struct Env<'a> { /// We only care about whether it was a single time or multiple times, /// because single appearances get a wildcard (*) and multiple times /// get a generated letter ("a" etc). +#[derive(Debug)] enum Appearances { Single, Multiple, @@ -75,7 +76,7 @@ fn find_names_needed( subs: &mut Subs, roots: &mut Vec, root_appearances: &mut MutMap, - names_taken: &mut MutSet, + names_taken: &mut MutMap, ) { use crate::subs::Content::*; use crate::subs::FlatType::*; @@ -151,19 +152,27 @@ fn find_names_needed( .. } | FlexVar(Some(name_index)) - | FlexAbleVar(Some(name_index), _) => { - // This root already has a name. Nothing more to do here! + | FlexAbleVar(Some(name_index), _) + | RigidVar(name_index) + | RigidAbleVar(name_index, _) => { + let root = subs.get_root_key_without_compacting(variable); // User-defined names are already taken. // We must not accidentally generate names that collide with them! let name = subs.field_names[name_index.index as usize].clone(); - names_taken.insert(name); - } - RigidVar(name_index) | RigidAbleVar(name_index, _) => { - // User-defined names are already taken. - // We must not accidentally generate names that collide with them! - let name = subs.field_names[name_index.index as usize].clone(); - names_taken.insert(name); + match names_taken.get(&name) { + Some(var) if *var == root => {} + Some(_) => { + if !root_appearances.contains_key(&root) { + roots.push(root); + } + // We want a name, but the default name is already taken by another root. + root_appearances.insert(root, Appearances::Multiple); + } + None => { + names_taken.insert(name, root); + } + } } Structure(Apply(_, args)) => { for index in args.into_iter() { @@ -255,7 +264,7 @@ fn name_all_type_vars(variable: Variable, subs: &mut Subs) -> NamedResult { let mut roots = Vec::new(); let mut letters_used = 0; let mut appearances = MutMap::default(); - let mut taken = MutSet::default(); + let mut taken = MutMap::default(); // Populate names_needed find_names_needed(variable, subs, &mut roots, &mut appearances, &mut taken); @@ -290,14 +299,14 @@ fn name_root( letters_used: u32, root: Variable, subs: &mut Subs, - taken: &mut MutSet, + taken: &mut MutMap, ) -> u32 { let (generated_name, new_letters_used) = - name_type_var(letters_used, &mut taken.iter(), |var, str| { + name_type_var(letters_used, &mut taken.keys(), |var, str| { var.as_str() == str }); - taken.insert(generated_name.clone()); + taken.insert(generated_name.clone(), root); set_root_name(root, generated_name, subs); @@ -310,12 +319,12 @@ fn set_root_name(root: Variable, name: Lowercase, subs: &mut Subs) { let old_content = subs.get_content_without_compacting(root); match old_content { - FlexVar(None) => { + FlexVar(_) => { let name_index = SubsIndex::push_new(&mut subs.field_names, name); let content = FlexVar(Some(name_index)); subs.set_content(root, content); } - &FlexAbleVar(None, ability) => { + &FlexAbleVar(_, ability) => { let name_index = SubsIndex::push_new(&mut subs.field_names, name); let content = FlexAbleVar(Some(name_index), ability); subs.set_content(root, content); @@ -335,8 +344,7 @@ fn set_root_name(root: Variable, name: Lowercase, subs: &mut Subs) { RecursionVar { opt_name: Some(_existing), .. - } - | FlexVar(Some(_existing)) => { + } => { panic!("TODO FIXME - make sure the generated name does not clash with any bound vars! In other words, if the user decided to name a type variable 'a', make sure we don't generate 'a' to name a different one!"); } diff --git a/compiler/types/src/subs.rs b/compiler/types/src/subs.rs index b8a2708f8a..b252a7b6ee 100644 --- a/compiler/types/src/subs.rs +++ b/compiler/types/src/subs.rs @@ -8,7 +8,6 @@ use roc_module::ident::{Lowercase, TagName, Uppercase}; use roc_module::symbol::Symbol; use std::fmt; use std::iter::{once, Iterator, Map}; -use ven_ena::unify::UnifyKey; use crate::unification_table::{Snapshot, UnificationTable}; @@ -1206,22 +1205,6 @@ impl fmt::Debug for Variable { } } -impl UnifyKey for Variable { - type Value = Descriptor; - - fn index(&self) -> u32 { - self.0 - } - - fn from_index(index: u32) -> Self { - Variable(index) - } - - fn tag() -> &'static str { - "Variable" - } -} - /// Used in SolvedType #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct VarId(u32); diff --git a/compiler/types/src/types.rs b/compiler/types/src/types.rs index 434c882be2..62211e3960 100644 --- a/compiler/types/src/types.rs +++ b/compiler/types/src/types.rs @@ -240,6 +240,7 @@ pub enum Type { name: Symbol, captures: Vec, }, + UnspecializedLambdaSet(Uls), DelayedAlias(AliasCommon), Alias { symbol: Symbol, @@ -264,6 +265,17 @@ pub enum Type { Erroneous(Problem), } +/// A lambda set under an arrow in a ability member signature. For example, in +/// Default has default : {} -> a | a has Default +/// the unspecialized lambda set for the arrow "{} -> a" would be `a:default:1`. +/// +/// Lambda sets in member signatures are never known until those members are specialized at a +/// usage site. Unspecialized lambda sets aid us in recovering those lambda sets; when we +/// instantiate `a` with a proper type `T`, we'll know to resolve the lambda set by extracting +/// it at region "1" from the specialization of "default" for `T`. +#[derive(PartialEq, Eq, Clone, Copy)] +pub struct Uls(Variable, Symbol, u8); + static mut TYPE_CLONE_COUNT: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0); @@ -297,6 +309,7 @@ impl Clone for Type { name: *name, captures: captures.clone(), }, + Self::UnspecializedLambdaSet(uls) => Self::UnspecializedLambdaSet(*uls), Self::DelayedAlias(arg0) => Self::DelayedAlias(arg0.clone()), Self::Alias { symbol, @@ -367,6 +380,14 @@ impl TypeExtension { TypeExtension::Closed => true, } } + + #[inline(always)] + fn iter_mut(&mut self) -> impl Iterator { + match self { + TypeExtension::Open(ext) => Some(ext.as_mut()).into_iter(), + TypeExtension::Closed => None.into_iter(), + } + } } impl<'a> IntoIterator for &'a TypeExtension { @@ -627,6 +648,9 @@ impl fmt::Debug for Type { Type::RangedNumber(typ, range_vars) => { write!(f, "Ranged({:?}, {:?})", typ, range_vars) } + Type::UnspecializedLambdaSet(Uls(a, mem, region)) => { + write!(f, "ULS({:?}:{:?}:{:?})", a, mem, region) + } } } } @@ -766,6 +790,12 @@ impl Type { RangedNumber(typ, _) => { stack.push(typ); } + UnspecializedLambdaSet(Uls(v, _, _)) => { + debug_assert!( + substitutions.get(v).is_none(), + "unspecialized lambda sets should never be substituted before solving" + ); + } EmptyRec | EmptyTagUnion | Erroneous(_) => {} } @@ -877,6 +907,12 @@ impl Type { RangedNumber(typ, _) => { stack.push(typ); } + UnspecializedLambdaSet(Uls(v, _, _)) => { + debug_assert!( + substitutions.get(v).is_none(), + "unspecialized lambda sets should never be substituted before solving" + ); + } EmptyRec | EmptyTagUnion | Erroneous(_) => {} } @@ -974,6 +1010,7 @@ impl Type { Ok(()) } RangedNumber(typ, _) => typ.substitute_alias(rep_symbol, rep_args, actual), + UnspecializedLambdaSet(..) => Ok(()), EmptyRec | EmptyTagUnion | ClosureTag { .. } | Erroneous(_) | Variable(_) => Ok(()), } } @@ -1030,6 +1067,7 @@ impl Type { Apply(symbol, _, _) if *symbol == rep_symbol => true, Apply(_, args, _) => args.iter().any(|arg| arg.contains_symbol(rep_symbol)), RangedNumber(typ, _) => typ.contains_symbol(rep_symbol), + UnspecializedLambdaSet(Uls(_, sym, _)) => *sym == rep_symbol, EmptyRec | EmptyTagUnion | ClosureTag { .. } | Erroneous(_) | Variable(_) => false, } } @@ -1055,6 +1093,7 @@ impl Type { ClosureTag { name: _, captures } => { captures.iter().any(|t| t.contains_variable(rep_variable)) } + UnspecializedLambdaSet(Uls(v, _, _)) => *v == rep_variable, RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => { Self::contains_variable_ext(ext, rep_variable) || tags @@ -1344,10 +1383,19 @@ impl Type { RangedNumber(typ, _) => { typ.instantiate_aliases(region, aliases, var_store, new_lambda_set_variables); } + UnspecializedLambdaSet(..) => {} EmptyRec | EmptyTagUnion | ClosureTag { .. } | Erroneous(_) | Variable(_) => {} } } + pub fn instantiate_lambda_sets_as_unspecialized( + &mut self, + able_var: Variable, + ability_member: Symbol, + ) { + instantiate_lambda_sets_as_unspecialized(self, able_var, ability_member) + } + pub fn is_tag_union_like(&self) -> bool { matches!( self, @@ -1473,6 +1521,9 @@ fn symbols_help(initial: &Type) -> Vec { RangedNumber(typ, _) => { stack.push(typ); } + UnspecializedLambdaSet(Uls(_, _sym, _)) => { + // ignore the member symbol because unspecialized lambda sets are internal-only + } EmptyRec | EmptyTagUnion | ClosureTag { .. } | Erroneous(_) | Variable(_) => {} } } @@ -1520,6 +1571,9 @@ fn variables_help(tipe: &Type, accum: &mut ImSet) { variables_help(t, accum); } } + UnspecializedLambdaSet(Uls(v, _, _)) => { + accum.insert(*v); + } TagUnion(tags, ext) => { for (_, args) in tags { for x in args { @@ -1670,6 +1724,9 @@ fn variables_help_detailed(tipe: &Type, accum: &mut VariableDetail) { variables_help_detailed(ext, accum); } } + UnspecializedLambdaSet(Uls(var, _, _)) => { + accum.type_variables.insert(*var); + } RecursiveTagUnion(rec, tags, ext) => { for (_, args) in tags { for x in args { @@ -2665,3 +2722,170 @@ pub fn gather_tags(subs: &Subs, other_fields: UnionTags, var: Variable) -> TagUn ext, } } + +fn instantiate_lambda_sets_as_unspecialized( + typ: &mut Type, + able_var: Variable, + ability_member: Symbol, +) { + // We want to pop and assign lambda sets pre-order for readability, so types + // should be pushed onto the stack in post-order + let mut stack = vec![typ]; + let mut region = 0; + + let mut new_uls = || { + region += 1; + Type::UnspecializedLambdaSet(Uls(able_var, ability_member, region)) + }; + + while let Some(typ) = stack.pop() { + match typ { + Type::EmptyRec => {} + Type::EmptyTagUnion => {} + Type::Function(args, lambda_set, ret) => { + debug_assert!( + matches!(**lambda_set, Type::Variable(..)), + "lambda set already bound" + ); + + **lambda_set = new_uls(); + stack.push(ret); + stack.extend(args.iter_mut().rev()); + } + Type::Record(fields, ext) => { + stack.extend(ext.iter_mut()); + for (_, x) in fields.iter_mut() { + stack.push(x.as_inner_mut()); + } + } + Type::TagUnion(tags, ext) | Type::RecursiveTagUnion(_, tags, ext) => { + stack.extend(ext.iter_mut()); + for (_, ts) in tags { + for t in ts.iter_mut().rev() { + stack.push(t); + } + } + } + Type::FunctionOrTagUnion(_, _, ext) => { + stack.extend(ext.iter_mut()); + } + Type::ClosureTag { name: _, captures } => { + stack.extend(captures.iter_mut().rev()); + } + Type::UnspecializedLambdaSet(..) => { + internal_error!("attempting to re-instantiate ULS") + } + Type::DelayedAlias(AliasCommon { + symbol: _, + type_arguments, + lambda_set_variables, + }) => { + stack.extend(lambda_set_variables.iter_mut().rev().map(|ls| &mut ls.0)); + stack.extend(type_arguments.iter_mut().rev()); + } + Type::Alias { + symbol: _, + type_arguments, + lambda_set_variables, + actual, + kind: _, + } => { + stack.push(actual); + stack.extend(lambda_set_variables.iter_mut().rev().map(|ls| &mut ls.0)); + stack.extend(type_arguments.iter_mut().rev().map(|t| &mut t.typ)); + } + Type::HostExposedAlias { + name: _, + type_arguments, + lambda_set_variables, + actual_var: _, + actual, + } => { + stack.push(actual); + stack.extend(lambda_set_variables.iter_mut().rev().map(|ls| &mut ls.0)); + stack.extend(type_arguments.iter_mut().rev()); + } + Type::Apply(_sym, args, _region) => { + stack.extend(args.iter_mut().rev()); + } + Type::Variable(_) => {} + Type::RangedNumber(t, _) => { + stack.push(t); + } + Type::Erroneous(_) => {} + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn instantiate_lambda_sets_as_unspecialized() { + let mut var_store = VarStore::default(); + let l1 = Box::new(Type::Variable(var_store.fresh())); + let l2 = Box::new(Type::Variable(var_store.fresh())); + let l3 = Box::new(Type::Variable(var_store.fresh())); + let mut typ = Type::Function( + vec![Type::Function(vec![], l2, Box::new(Type::EmptyRec))], + l1, + Box::new(Type::TagUnion( + vec![( + TagName("A".into()), + vec![Type::Function(vec![], l3, Box::new(Type::EmptyRec))], + )], + TypeExtension::Closed, + )), + ); + + let able_var = var_store.fresh(); + let member = Symbol::UNDERSCORE; + typ.instantiate_lambda_sets_as_unspecialized(able_var, member); + + macro_rules! check_uls { + ($typ:expr, $region:literal) => {{ + match $typ { + Type::UnspecializedLambdaSet(Uls(var1, member1, $region)) => { + assert!(var1 == able_var && member1 == member) + } + _ => panic!(), + } + }}; + } + + match typ { + Type::Function(args, l1, ret) => { + check_uls!(*l1, 1); + + match args.as_slice() { + [Type::Function(args, l2, ret)] => { + check_uls!(**l2, 2); + assert!(args.is_empty()); + assert!(matches!(**ret, Type::EmptyRec)); + } + _ => panic!(), + } + + match *ret { + Type::TagUnion(tags, TypeExtension::Closed) => match tags.as_slice() { + [(name, args)] => { + assert_eq!(name.0.as_str(), "A"); + match args.as_slice() { + [Type::Function(args, l3, ret)] => { + check_uls!(**l3, 3); + assert!(args.is_empty()); + assert!(matches!(**ret, Type::EmptyRec)); + } + _ => panic!(), + } + } + _ => panic!(), + }, + _ => panic!(), + } + } + _ => panic!(), + } + } +} diff --git a/compiler/unify/src/unify.rs b/compiler/unify/src/unify.rs index 55cc89228f..7c35604785 100644 --- a/compiler/unify/src/unify.rs +++ b/compiler/unify/src/unify.rs @@ -99,13 +99,6 @@ bitflags! { /// /// For example, t1 += [A Str] says we should "add" the tag "A Str" to the type of "t1". const PRESENT = 1 << 1; - /// Instructs the unifier to treat rigids exactly like flex vars. - /// Usually rigids can only unify with flex vars, because rigids are named and bound - /// explicitly. - /// However, when checking type ranges, as we do for `RangedNumber` types, we must loosen - /// this restriction because otherwise an admissible range will appear inadmissible. - /// For example, Int * is in the range . - const RIGID_AS_FLEX = 1 << 2; } } @@ -126,11 +119,7 @@ impl Mode { #[cfg(debug_assertions)] fn pretty_print(&self) -> &str { - if self.contains(Mode::EQ | Mode::RIGID_AS_FLEX) { - "~*" - } else if self.contains(Mode::PRESENT | Mode::RIGID_AS_FLEX) { - "+=*" - } else if self.contains(Mode::EQ) { + if self.contains(Mode::EQ) { "~" } else if self.contains(Mode::PRESENT) { "+=" @@ -364,14 +353,10 @@ fn unify_context(subs: &mut Subs, pool: &mut Pool, ctx: Context) -> Outcome { // This #[allow] is needed in release builds, where `result` is no longer used. #[allow(clippy::let_and_return)] let result = match &ctx.first_desc.content { - FlexVar(opt_name) => unify_flex(subs, &ctx, opt_name, None, &ctx.second_desc.content), - FlexAbleVar(opt_name, ability) => unify_flex( - subs, - &ctx, - opt_name, - Some(*ability), - &ctx.second_desc.content, - ), + FlexVar(opt_name) => unify_flex(subs, &ctx, opt_name, &ctx.second_desc.content), + FlexAbleVar(opt_name, ability) => { + unify_flex_able(subs, &ctx, opt_name, *ability, &ctx.second_desc.content) + } RecursionVar { opt_name, structure, @@ -383,9 +368,9 @@ fn unify_context(subs: &mut Subs, pool: &mut Pool, ctx: Context) -> Outcome { *structure, &ctx.second_desc.content, ), - RigidVar(name) => unify_rigid(subs, &ctx, name, None, &ctx.second_desc.content), + RigidVar(name) => unify_rigid(subs, &ctx, name, &ctx.second_desc.content), RigidAbleVar(name, ability) => { - unify_rigid(subs, &ctx, name, Some(*ability), &ctx.second_desc.content) + unify_rigid_able(subs, &ctx, name, *ability, &ctx.second_desc.content) } Structure(flat_type) => { unify_structure(subs, pool, &ctx, flat_type, &ctx.second_desc.content) @@ -1916,7 +1901,6 @@ fn unify_rigid( subs: &mut Subs, ctx: &Context, name: &SubsIndex, - opt_able_bound: Option, other: &Content, ) -> Outcome { match other { @@ -1925,68 +1909,60 @@ fn unify_rigid( merge(subs, ctx, RigidVar(*name)) } FlexAbleVar(_, other_ability) => { - match opt_able_bound { - Some(ability) => { - if ability == *other_ability { - // The ability bounds are the same, so rigid wins! - merge(subs, ctx, RigidAbleVar(*name, ability)) - } else { - // Mismatch for now. - // TODO check ability hierarchies. - mismatch!( - %not_able, ctx.second, ability, - "RigidAble {:?} with ability {:?} not compatible with ability {:?}", - ctx.first, - ability, - other_ability - ) - } - } - None => { - // Mismatch - Rigid can unify with FlexAble only when the Rigid has an ability - // bound as well, otherwise the user failed to correctly annotate the bound. - mismatch!( - %not_able, ctx.first, *other_ability, - "Rigid {:?} with FlexAble {:?}", ctx.first, other - ) - } - } + // Mismatch - Rigid can unify with FlexAble only when the Rigid has an ability + // bound as well, otherwise the user failed to correctly annotate the bound. + mismatch!( + %not_able, ctx.first, *other_ability, + "Rigid {:?} with FlexAble {:?}", ctx.first, other + ) } RigidVar(_) + | RigidAbleVar(..) | RecursionVar { .. } | Structure(_) - | Alias(_, _, _, _) + | Alias(..) | RangedNumber(..) - | LambdaSet(..) - if ctx.mode.contains(Mode::RIGID_AS_FLEX) => - { - // Usually rigids can only unify with flex, but the mode indicates we are treating - // rigid vars as flex, so admit this. - match (opt_able_bound, other) { - (None, other) => merge(subs, ctx, *other), - (Some(ability), Alias(opaque_name, vars, _real_var, AliasKind::Opaque)) - if vars.is_empty() => - { - let mut output = merge(subs, ctx, *other); - let must_implement_ability = MustImplementAbility { - typ: Obligated::Opaque(*opaque_name), - ability, - }; - output.must_implement_ability.push(must_implement_ability); - output - } + | LambdaSet(..) => { + // Type mismatch! Rigid can only unify with flex, even if the + // rigid names are the same. + mismatch!("Rigid {:?} with {:?}", ctx.first, &other) + } - // these have underscores because they're unused in --release builds - (Some(_ability), _other) => { - // For now, only allow opaque types with no type variables to implement abilities. - mismatch!( - %not_able, ctx.second, _ability, - "RigidAble {:?} with non-opaque or opaque with type variables {:?}", - ctx.first, - &_other - ) - } + Error => { + // Error propagates. + merge(subs, ctx, Error) + } + } +} + +#[inline(always)] +fn unify_rigid_able( + subs: &mut Subs, + ctx: &Context, + name: &SubsIndex, + ability: Symbol, + other: &Content, +) -> Outcome { + match other { + FlexVar(_) => { + // If the other is flex, rigid wins! + merge(subs, ctx, RigidVar(*name)) + } + FlexAbleVar(_, other_ability) => { + if ability == *other_ability { + // The ability bounds are the same, so rigid wins! + merge(subs, ctx, RigidAbleVar(*name, ability)) + } else { + // Mismatch for now. + // TODO check ability hierarchies. + mismatch!( + %not_able, ctx.second, ability, + "RigidAble {:?} with ability {:?} not compatible with ability {:?}", + ctx.first, + ability, + other_ability + ) } } @@ -2014,45 +1990,19 @@ fn unify_flex( subs: &mut Subs, ctx: &Context, opt_name: &Option>, - opt_able_bound: Option, other: &Content, ) -> Outcome { match other { FlexVar(other_opt_name) => { // Prefer using right's name. let opt_name = opt_name.or(*other_opt_name); - match opt_able_bound { - Some(ability) => merge(subs, ctx, FlexAbleVar(opt_name, ability)), - None => merge(subs, ctx, FlexVar(opt_name)), - } + merge(subs, ctx, FlexVar(opt_name)) } - FlexAbleVar(opt_other_name, other_ability) => { - // Prefer the right's name when possible. + FlexAbleVar(opt_other_name, ability) => { + // Prefer using right's name. let opt_name = (opt_other_name).or(*opt_name); - - match opt_able_bound { - Some(ability) => { - if ability == *other_ability { - // The ability bounds are the same! Keep the name around if it exists. - merge(subs, ctx, FlexAbleVar(opt_name, ability)) - } else { - // Ability names differ; mismatch for now. - // TODO check ability hierarchies. - mismatch!( - %not_able, ctx.second, ability, - "FlexAble {:?} with ability {:?} not compatible with ability {:?}", - ctx.first, - ability, - other_ability - ) - } - } - None => { - // Right has an ability bound, but left might have the name. Combine them. - merge(subs, ctx, FlexAbleVar(opt_name, *other_ability)) - } - } + merge(subs, ctx, FlexAbleVar(opt_name, *ability)) } RigidVar(_) @@ -2071,6 +2021,80 @@ fn unify_flex( } } +#[inline(always)] +fn unify_flex_able( + subs: &mut Subs, + ctx: &Context, + opt_name: &Option>, + ability: Symbol, + other: &Content, +) -> Outcome { + match other { + FlexVar(opt_other_name) => { + // Prefer using right's name. + let opt_name = (opt_other_name).or(*opt_name); + merge(subs, ctx, FlexAbleVar(opt_name, ability)) + } + + FlexAbleVar(opt_other_name, other_ability) => { + // Prefer the right's name when possible. + let opt_name = (opt_other_name).or(*opt_name); + + if ability == *other_ability { + merge(subs, ctx, FlexAbleVar(opt_name, ability)) + } else { + // Ability names differ; mismatch for now. + // TODO check ability hierarchies. + mismatch!( + %not_able, ctx.second, ability, + "FlexAble {:?} with ability {:?} not compatible with ability {:?}", + ctx.first, + ability, + other_ability + ) + } + } + + RigidAbleVar(_, other_ability) => { + if ability == *other_ability { + merge(subs, ctx, *other) + } else { + mismatch!(%not_able, ctx.second, ability, "RigidAble {:?} vs {:?}", ability, other_ability) + } + } + + RigidVar(_) => mismatch!("FlexAble can never unify with non-able Rigid"), + RecursionVar { .. } => mismatch!("FlexAble with RecursionVar"), + LambdaSet(..) => mismatch!("FlexAble with LambdaSet"), + + Alias(name, args, _real_var, AliasKind::Opaque) => { + if args.is_empty() { + // Opaque type wins + let mut outcome = merge(subs, ctx, *other); + outcome.must_implement_ability.push(MustImplementAbility { + typ: Obligated::Opaque(*name), + ability, + }); + outcome + } else { + mismatch!("FlexAble vs Opaque with type vars") + } + } + + Structure(_) | Alias(_, _, _, AliasKind::Structural) | RangedNumber(..) => { + // Structural type wins. + let mut outcome = merge(subs, ctx, *other); + outcome.must_implement_ability.push(MustImplementAbility { + typ: Obligated::Adhoc(ctx.second), + ability, + }); + outcome + } + + Error => merge(subs, ctx, Error), + } +} + #[inline(always)] fn unify_recursion( subs: &mut Subs, diff --git a/examples/hello-world/swift-platform/host.h b/examples/hello-world/swift-platform/host.h index 036e39f67f..7714980c93 100644 --- a/examples/hello-world/swift-platform/host.h +++ b/examples/hello-world/swift-platform/host.h @@ -6,4 +6,4 @@ struct RocStr { size_t capacity; }; -extern struct RocStr roc__mainForHost_1_exposed(); +extern void roc__mainForHost_1_exposed_generic(const struct RocStr *data); diff --git a/examples/hello-world/swift-platform/host.swift b/examples/hello-world/swift-platform/host.swift index 99fbbe35cc..144ed8a54a 100644 --- a/examples/hello-world/swift-platform/host.swift +++ b/examples/hello-world/swift-platform/host.swift @@ -21,39 +21,42 @@ func rocRealloc(ptr: UInt, _oldSize: Int, newSize: Int, _alignment: UInt) -> UIn return UInt(bitPattern: ptr) } -extension RocStr { - var isSmallString: Bool { - capacity < 0 - } +func isSmallString(rocStr: RocStr) -> Bool { + return rocStr.capacity < 0 +} - var length: Int { - if isSmallString { - // Small String length is last in the byte of capacity. - var cap = capacity - let count = MemoryLayout.size(ofValue: cap) - let bytes = Data(bytes: &cap, count: count) - let lastByte = bytes[count - 1] - return Int(lastByte ^ 0b1000_0000) - } else { - return len - } +func getStrLen(rocStr: RocStr) -> Int { + if isSmallString(rocStr: rocStr) { + // Small String length is last in the byte of capacity. + var cap = rocStr.capacity + let count = MemoryLayout.size(ofValue: cap) + let bytes = Data(bytes: &cap, count: count) + let lastByte = bytes[count - 1] + return Int(lastByte ^ 0b1000_0000) + } else { + return rocStr.len } +} - var string: String { - if isSmallString { - let data: Data = withUnsafePointer(to: self) { ptr in - Data(bytes: ptr, count: length) - } - return String(data: data, encoding: .utf8)! - } else { - let data = Data(bytes: bytes, count: len) - return String(data: data, encoding: .utf8)! +func getSwiftString(rocStr: RocStr) -> String { + let length = getStrLen(rocStr: rocStr) + + if isSmallString(rocStr: rocStr) { + let data: Data = withUnsafePointer(to: rocStr) { ptr in + Data(bytes: ptr, count: length) } + return String(data: data, encoding: .utf8)! + } else { + let data = Data(bytes: rocStr.bytes, count: length) + return String(data: data, encoding: .utf8)! } } @_cdecl("main") func main() -> UInt8 { - print(roc__mainForHost_1_exposed().string, terminator: "") + var rocStr = RocStr() + roc__mainForHost_1_exposed_generic(&rocStr) + + print(getSwiftString(rocStr: rocStr), terminator: "") return 0 } diff --git a/flake.nix b/flake.nix index b8e8ebe6d7..3c26192695 100644 --- a/flake.nix +++ b/flake.nix @@ -10,107 +10,109 @@ outputs = { self, nixpkgs, rust-overlay, zig, flake-utils }: let - supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin"]; + supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ]; in - flake-utils.lib.eachSystem supportedSystems (system: - let - overlays = [ (import rust-overlay) ]; - pkgs = import nixpkgs { - inherit system overlays; - }; - llvmPkgs = pkgs.llvmPackages_13; + flake-utils.lib.eachSystem supportedSystems (system: + let + overlays = [ (import rust-overlay) ]; + pkgs = import nixpkgs { + inherit system overlays; + }; + llvmPkgs = pkgs.llvmPackages_13; - # get current working directory - cwd = builtins.toString ./.; - rust = pkgs.rust-bin.fromRustupToolchainFile "${cwd}/rust-toolchain.toml"; + # get current working directory + cwd = builtins.toString ./.; + rust = pkgs.rust-bin.fromRustupToolchainFile "${cwd}/rust-toolchain.toml"; - linuxInputs = with pkgs; - lib.optionals stdenv.isLinux [ - valgrind # used in cli tests, see cli/tests/cli_run.rs - vulkan-headers - vulkan-loader - vulkan-tools - vulkan-validation-layers - xorg.libX11 - xorg.libXcursor - xorg.libXrandr - xorg.libXi - xorg.libxcb - alsa-lib - ]; + linuxInputs = with pkgs; + lib.optionals stdenv.isLinux [ + valgrind # used in cli tests, see cli/tests/cli_run.rs + vulkan-headers + vulkan-loader + vulkan-tools + vulkan-validation-layers + xorg.libX11 + xorg.libXcursor + xorg.libXrandr + xorg.libXi + xorg.libxcb + alsa-lib + ]; - darwinInputs = with pkgs; - lib.optionals stdenv.isDarwin (with pkgs.darwin.apple_sdk.frameworks; [ - AppKit - CoreFoundation - CoreServices - CoreVideo - Foundation - Metal - Security + darwinInputs = with pkgs; + lib.optionals stdenv.isDarwin (with pkgs.darwin.apple_sdk.frameworks; [ + AppKit + CoreFoundation + CoreServices + CoreVideo + Foundation + Metal + Security ]); - zig-toolchain = zig.packages.${system}."0.9.1"; + zig-toolchain = zig.packages.${system}."0.9.1"; - # For debugging LLVM IR - debugir = pkgs.stdenv.mkDerivation { - name = "debugir"; - src = pkgs.fetchFromGitHub { - owner = "vaivaswatha"; - repo = "debugir"; - rev = "b981e0b74872d9896ba447dd6391dfeb63332b80"; - sha256 = "Gzey0SF0NZkpiObk5e29nbc41dn4Olv1dx+6YixaZH0="; - }; - buildInputs = with pkgs; [ cmake libxml2 llvmPackages_13.llvm.dev ]; - buildPhase = '' - mkdir build - cd build - cmake -DLLVM_DIR=${pkgs.llvmPackages_13.llvm.dev} -DCMAKE_BUILD_TYPE=Release ../ - cmake --build ../ - cp ../debugir . - ''; - installPhase = '' - mkdir -p $out/bin - cp debugir $out/bin - ''; + # For debugging LLVM IR + debugir = pkgs.stdenv.mkDerivation { + name = "debugir"; + src = pkgs.fetchFromGitHub { + owner = "vaivaswatha"; + repo = "debugir"; + rev = "b981e0b74872d9896ba447dd6391dfeb63332b80"; + sha256 = "Gzey0SF0NZkpiObk5e29nbc41dn4Olv1dx+6YixaZH0="; }; + buildInputs = with pkgs; [ cmake libxml2 llvmPackages_13.llvm.dev ]; + buildPhase = '' + mkdir build + cd build + cmake -DLLVM_DIR=${pkgs.llvmPackages_13.llvm.dev} -DCMAKE_BUILD_TYPE=Release ../ + cmake --build ../ + cp ../debugir . + ''; + installPhase = '' + mkdir -p $out/bin + cp debugir $out/bin + ''; + }; - sharedInputs = (with pkgs; [ - # build libraries - cmake - git - python3 - llvmPkgs.llvm.dev - llvmPkgs.clang - libxkbcommon - pkg-config - zig-toolchain # roc builtins are implemented in zig, see compiler/builtins/bitcode/ + sharedInputs = (with pkgs; [ + # build libraries + cmake + git + python3 + llvmPkgs.llvm.dev + llvmPkgs.clang + libxkbcommon + pkg-config + zig-toolchain # roc builtins are implemented in zig, see compiler/builtins/bitcode/ - # lib deps - libffi - libxml2 - ncurses - zlib - libiconv + # lib deps + libffi + libxml2 + ncurses + zlib + libiconv - # faster builds - see https://github.com/rtfeldman/roc/blob/trunk/BUILDING_FROM_SOURCE.md#use-lld-for-the-linker - llvmPkgs.lld - debugir - rust - ]); - in { + # faster builds - see https://github.com/rtfeldman/roc/blob/trunk/BUILDING_FROM_SOURCE.md#use-lld-for-the-linker + llvmPkgs.lld + debugir + rust + ]); + in + { - devShell = pkgs.mkShell { - buildInputs = sharedInputs ++ darwinInputs ++ linuxInputs; + devShell = pkgs.mkShell { + buildInputs = sharedInputs ++ darwinInputs ++ linuxInputs; - LLVM_SYS_130_PREFIX = "${llvmPkgs.llvm.dev}"; - NIX_GLIBC_PATH = if pkgs.stdenv.isLinux then "${pkgs.glibc.out}/lib" else ""; - LD_LIBRARY_PATH = with pkgs; - lib.makeLibraryPath + LLVM_SYS_130_PREFIX = "${llvmPkgs.llvm.dev}"; + NIX_GLIBC_PATH = if pkgs.stdenv.isLinux then "${pkgs.glibc.out}/lib" else ""; + LD_LIBRARY_PATH = with pkgs; + lib.makeLibraryPath ([ pkg-config stdenv.cc.cc.lib libffi ncurses zlib ] ++ linuxInputs); - NIXPKGS_ALLOW_UNFREE = 1; # to run the editor with NVIDIA's closed source drivers - }; + NIXPKGS_ALLOW_UNFREE = 1; # to run the editor with NVIDIA's closed source drivers + }; + formatter = pkgs.nixpkgs-fmt; } ); } diff --git a/shell.nix b/shell.nix index ee243e6fa4..8f9f5c5ec2 100644 --- a/shell.nix +++ b/shell.nix @@ -2,4 +2,4 @@ # This file is kept to maintain compatibility with tools like lorri until they support flakes (https://github.com/target/lorri/issues/460). { system ? builtins.currentSystem }: -(builtins.getFlake (toString ./.)).devShell.${system} \ No newline at end of file +(builtins.getFlake (toString ./.)).devShell.${system} diff --git a/vendor/ena/Cargo.toml b/vendor/ena/Cargo.toml deleted file mode 100644 index bf28482fde..0000000000 --- a/vendor/ena/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "ven_ena" -description = "Union-find, congruence closure, and other unification code. Based on code from rustc." -license = "MIT/Apache-2.0" -homepage = "https://github.com/rust-lang-nursery/ena" -repository = "https://github.com/rust-lang-nursery/ena" -version = "0.13.1" -authors = ["Niko Matsakis "] -readme = "README.md" -keywords = ["unification", "union-find"] - -[dependencies] -log = "0.4.14" diff --git a/vendor/ena/LICENSE-APACHE b/vendor/ena/LICENSE-APACHE deleted file mode 100644 index 16fe87b06e..0000000000 --- a/vendor/ena/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/vendor/ena/LICENSE-MIT b/vendor/ena/LICENSE-MIT deleted file mode 100644 index 25597d5838..0000000000 --- a/vendor/ena/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2010 The Rust Project Developers - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/vendor/ena/src/bitvec.rs b/vendor/ena/src/bitvec.rs deleted file mode 100644 index 3677c8c5e5..0000000000 --- a/vendor/ena/src/bitvec.rs +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// A very simple BitVector type. -pub struct BitVector { - data: Vec, -} - -impl BitVector { - pub fn new(num_bits: usize) -> BitVector { - let num_words = u64s(num_bits); - BitVector { data: vec![0; num_words] } - } - - pub fn contains(&self, bit: usize) -> bool { - let (word, mask) = word_mask(bit); - (self.data[word] & mask) != 0 - } - - /// Returns true if the bit has changed. - pub fn insert(&mut self, bit: usize) -> bool { - let (word, mask) = word_mask(bit); - let data = &mut self.data[word]; - let value = *data; - let new_value = value | mask; - *data = new_value; - new_value != value - } - - pub fn insert_all(&mut self, all: &BitVector) -> bool { - assert!(self.data.len() == all.data.len()); - let mut changed = false; - for (i, j) in self.data.iter_mut().zip(&all.data) { - let value = *i; - *i = value | *j; - if value != *i { - changed = true; - } - } - changed - } - - pub fn grow(&mut self, num_bits: usize) { - let num_words = u64s(num_bits); - let extra_words = self.data.len() - num_words; - self.data.extend((0..extra_words).map(|_| 0)); - } - - /// Iterates over indexes of set bits in a sorted order - pub fn iter<'a>(&'a self) -> BitVectorIter<'a> { - BitVectorIter { - iter: self.data.iter(), - current: 0, - idx: 0, - } - } -} - -pub struct BitVectorIter<'a> { - iter: ::std::slice::Iter<'a, u64>, - current: u64, - idx: usize, -} - -impl<'a> Iterator for BitVectorIter<'a> { - type Item = usize; - fn next(&mut self) -> Option { - while self.current == 0 { - self.current = if let Some(&i) = self.iter.next() { - if i == 0 { - self.idx += 64; - continue; - } else { - self.idx = u64s(self.idx) * 64; - i - } - } else { - return None; - } - } - let offset = self.current.trailing_zeros() as usize; - self.current >>= offset; - self.current >>= 1; // shift otherwise overflows for 0b1000_0000_…_0000 - self.idx += offset + 1; - return Some(self.idx - 1); - } -} - -/// A "bit matrix" is basically a square matrix of booleans -/// represented as one gigantic bitvector. In other words, it is as if -/// you have N bitvectors, each of length N. Note that `elements` here is `N`/ -#[derive(Clone)] -pub struct BitMatrix { - elements: usize, - vector: Vec, -} - -impl BitMatrix { - // Create a new `elements x elements` matrix, initially empty. - pub fn new(elements: usize) -> BitMatrix { - // For every element, we need one bit for every other - // element. Round up to an even number of u64s. - let u64s_per_elem = u64s(elements); - BitMatrix { - elements: elements, - vector: vec![0; elements * u64s_per_elem], - } - } - - /// The range of bits for a given element. - fn range(&self, element: usize) -> (usize, usize) { - let u64s_per_elem = u64s(self.elements); - let start = element * u64s_per_elem; - (start, start + u64s_per_elem) - } - - pub fn add(&mut self, source: usize, target: usize) -> bool { - let (start, _) = self.range(source); - let (word, mask) = word_mask(target); - let mut vector = &mut self.vector[..]; - let v1 = vector[start + word]; - let v2 = v1 | mask; - vector[start + word] = v2; - v1 != v2 - } - - /// Do the bits from `source` contain `target`? - /// - /// Put another way, if the matrix represents (transitive) - /// reachability, can `source` reach `target`? - pub fn contains(&self, source: usize, target: usize) -> bool { - let (start, _) = self.range(source); - let (word, mask) = word_mask(target); - (self.vector[start + word] & mask) != 0 - } - - /// Returns those indices that are reachable from both `a` and - /// `b`. This is an O(n) operation where `n` is the number of - /// elements (somewhat independent from the actual size of the - /// intersection, in particular). - pub fn intersection(&self, a: usize, b: usize) -> Vec { - let (a_start, a_end) = self.range(a); - let (b_start, b_end) = self.range(b); - let mut result = Vec::with_capacity(self.elements); - for (base, (i, j)) in (a_start..a_end).zip(b_start..b_end).enumerate() { - let mut v = self.vector[i] & self.vector[j]; - for bit in 0..64 { - if v == 0 { - break; - } - if v & 0x1 != 0 { - result.push(base * 64 + bit); - } - v >>= 1; - } - } - result - } - - /// Add the bits from `read` to the bits from `write`, - /// return true if anything changed. - /// - /// This is used when computing transitive reachability because if - /// you have an edge `write -> read`, because in that case - /// `write` can reach everything that `read` can (and - /// potentially more). - pub fn merge(&mut self, read: usize, write: usize) -> bool { - let (read_start, read_end) = self.range(read); - let (write_start, write_end) = self.range(write); - let vector = &mut self.vector[..]; - let mut changed = false; - for (read_index, write_index) in (read_start..read_end).zip(write_start..write_end) { - let v1 = vector[write_index]; - let v2 = v1 | vector[read_index]; - vector[write_index] = v2; - changed = changed | (v1 != v2); - } - changed - } -} - -fn u64s(elements: usize) -> usize { - (elements + 63) / 64 -} - -fn word_mask(index: usize) -> (usize, u64) { - let word = index / 64; - let mask = 1 << (index % 64); - (word, mask) -} - -#[test] -fn bitvec_iter_works() { - let mut bitvec = BitVector::new(100); - bitvec.insert(1); - bitvec.insert(10); - bitvec.insert(19); - bitvec.insert(62); - bitvec.insert(63); - bitvec.insert(64); - bitvec.insert(65); - bitvec.insert(66); - bitvec.insert(99); - assert_eq!(bitvec.iter().collect::>(), - [1, 10, 19, 62, 63, 64, 65, 66, 99]); -} - -#[test] -fn bitvec_iter_works_2() { - let mut bitvec = BitVector::new(300); - bitvec.insert(1); - bitvec.insert(10); - bitvec.insert(19); - bitvec.insert(62); - bitvec.insert(66); - bitvec.insert(99); - bitvec.insert(299); - assert_eq!(bitvec.iter().collect::>(), - [1, 10, 19, 62, 66, 99, 299]); - -} - -#[test] -fn bitvec_iter_works_3() { - let mut bitvec = BitVector::new(319); - bitvec.insert(0); - bitvec.insert(127); - bitvec.insert(191); - bitvec.insert(255); - bitvec.insert(319); - assert_eq!(bitvec.iter().collect::>(), [0, 127, 191, 255, 319]); -} - -#[test] -fn union_two_vecs() { - let mut vec1 = BitVector::new(65); - let mut vec2 = BitVector::new(65); - assert!(vec1.insert(3)); - assert!(!vec1.insert(3)); - assert!(vec2.insert(5)); - assert!(vec2.insert(64)); - assert!(vec1.insert_all(&vec2)); - assert!(!vec1.insert_all(&vec2)); - assert!(vec1.contains(3)); - assert!(!vec1.contains(4)); - assert!(vec1.contains(5)); - assert!(!vec1.contains(63)); - assert!(vec1.contains(64)); -} - -#[test] -fn grow() { - let mut vec1 = BitVector::new(65); - assert!(vec1.insert(3)); - assert!(!vec1.insert(3)); - assert!(vec1.insert(5)); - assert!(vec1.insert(64)); - vec1.grow(128); - assert!(vec1.contains(3)); - assert!(vec1.contains(5)); - assert!(vec1.contains(64)); - assert!(!vec1.contains(126)); -} - -#[test] -fn matrix_intersection() { - let mut vec1 = BitMatrix::new(200); - - // (*) Elements reachable from both 2 and 65. - - vec1.add(2, 3); - vec1.add(2, 6); - vec1.add(2, 10); // (*) - vec1.add(2, 64); // (*) - vec1.add(2, 65); - vec1.add(2, 130); - vec1.add(2, 160); // (*) - - vec1.add(64, 133); - - vec1.add(65, 2); - vec1.add(65, 8); - vec1.add(65, 10); // (*) - vec1.add(65, 64); // (*) - vec1.add(65, 68); - vec1.add(65, 133); - vec1.add(65, 160); // (*) - - let intersection = vec1.intersection(2, 64); - assert!(intersection.is_empty()); - - let intersection = vec1.intersection(2, 65); - assert_eq!(intersection, &[10, 64, 160]); -} diff --git a/vendor/ena/src/lib.rs b/vendor/ena/src/lib.rs deleted file mode 100644 index 3a7485bcf4..0000000000 --- a/vendor/ena/src/lib.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! An implementation of union-find. See the `unify` module for more -//! details. - -pub mod snapshot_vec; -pub mod unify; - -#[macro_use] -extern crate log; diff --git a/vendor/ena/src/snapshot_vec.rs b/vendor/ena/src/snapshot_vec.rs deleted file mode 100644 index 5337d33445..0000000000 --- a/vendor/ena/src/snapshot_vec.rs +++ /dev/null @@ -1,399 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A utility class for implementing "snapshottable" things; a snapshottable data structure permits -//! you to take a snapshot (via `start_snapshot`) and then, after making some changes, elect either -//! to rollback to the start of the snapshot or commit those changes. -//! -//! This vector is intended to be used as part of an abstraction, not serve as a complete -//! abstraction on its own. As such, while it will roll back most changes on its own, it also -//! supports a `get_mut` operation that gives you an arbitrary mutable pointer into the vector. To -//! ensure that any changes you make this with this pointer are rolled back, you must invoke -//! `record` to record any changes you make and also supplying a delegate capable of reversing -//! those changes. - -use self::UndoLog::*; - -use std::fmt; -use std::mem; -use std::ops; - -#[derive(Debug)] -pub enum UndoLog { - /// New variable with given index was created. - NewElem(usize), - - /// Variable with given index was changed *from* the given value. - SetElem(usize, D::Value), - - /// Extensible set of actions - Other(D::Undo), -} - -/// A Vec where we have Debug overridden to render the indices like -/// a hashmap, since we really care about those when debugging one of these. -#[derive(Clone)] -struct BackingVec(Vec); - -pub struct SnapshotVec { - values: BackingVec, - undo_log: Vec>, - num_open_snapshots: usize, -} - -impl fmt::Debug for SnapshotVec -where - D: SnapshotVecDelegate, - D: fmt::Debug, - D::Undo: fmt::Debug, - D::Value: fmt::Debug, -{ - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - self.values.fmt(fmt) - } -} - -// Snapshots are tokens that should be created/consumed linearly. -pub struct Snapshot { - // Number of values at the time the snapshot was taken. - pub(crate) value_count: usize, - // Length of the undo log at the time the snapshot was taken. - undo_len: usize, -} - -pub trait SnapshotVecDelegate { - type Value; - type Undo; - - fn reverse(values: &mut Vec, action: Self::Undo); -} - -// HACK(eddyb) manual impl avoids `Default` bound on `D`. -impl Default for SnapshotVec { - fn default() -> Self { - SnapshotVec { - values: BackingVec(Vec::new()), - undo_log: Vec::new(), - num_open_snapshots: 0, - } - } -} - -impl fmt::Debug for BackingVec -where - T: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{{{{")?; - - for (index, elem) in self.0.iter().enumerate() { - write!(f, "\n {} => {:?},", index, elem)?; - } - - if !self.0.is_empty() { - writeln!(f)?; - } - - write!(f, "}}}}") - } -} - -impl SnapshotVec { - pub fn new() -> Self { - Self::default() - } - - pub fn with_capacity(c: usize) -> SnapshotVec { - SnapshotVec { - values: BackingVec(Vec::with_capacity(c)), - undo_log: Vec::new(), - num_open_snapshots: 0, - } - } - - fn in_snapshot(&self) -> bool { - self.num_open_snapshots > 0 - } - - pub fn record(&mut self, action: D::Undo) { - if self.in_snapshot() { - self.undo_log.push(Other(action)); - } - } - - pub fn len(&self) -> usize { - self.values.0.len() - } - - pub fn is_empty(&self) -> bool { - self.values.0.len() == 0 - } - - pub fn push(&mut self, elem: D::Value) -> usize { - let len = self.values.0.len(); - self.values.0.push(elem); - - if self.in_snapshot() { - self.undo_log.push(NewElem(len)); - } - - len - } - - pub fn get(&self, index: usize) -> &D::Value { - &self.values.0[index] - } - - /// Reserve space for new values, just like an ordinary vec. - pub fn reserve(&mut self, additional: usize) { - // This is not affected by snapshots or anything. - self.values.0.reserve(additional); - } - - /// Returns a mutable pointer into the vec; whatever changes you make here cannot be undone - /// automatically, so you should be sure call `record()` with some sort of suitable undo - /// action. - pub fn get_mut(&mut self, index: usize) -> &mut D::Value { - &mut self.values.0[index] - } - - /// Updates the element at the given index. The old value will saved (and perhaps restored) if - /// a snapshot is active. - pub fn set(&mut self, index: usize, new_elem: D::Value) { - let old_elem = mem::replace(&mut self.values.0[index], new_elem); - if self.in_snapshot() { - self.undo_log.push(SetElem(index, old_elem)); - } - } - - /// Updates all elements. Potentially more efficient -- but - /// otherwise equivalent to -- invoking `set` for each element. - pub fn set_all(&mut self, mut new_elems: impl FnMut(usize) -> D::Value) { - if !self.in_snapshot() { - for (index, slot) in self.values.0.iter_mut().enumerate() { - *slot = new_elems(index); - } - } else { - for i in 0..self.values.0.len() { - self.set(i, new_elems(i)); - } - } - } - - pub fn update(&mut self, index: usize, op: OP) - where - OP: FnOnce(&mut D::Value), - D::Value: Clone, - { - if self.in_snapshot() { - let old_elem = self.values.0[index].clone(); - self.undo_log.push(SetElem(index, old_elem)); - } - op(&mut self.values.0[index]); - } - - pub fn start_snapshot(&mut self) -> Snapshot { - self.num_open_snapshots += 1; - Snapshot { - value_count: self.values.0.len(), - undo_len: self.undo_log.len(), - } - } - - pub fn actions_since_snapshot(&self, snapshot: &Snapshot) -> &[UndoLog] { - &self.undo_log[snapshot.undo_len..] - } - - fn assert_open_snapshot(&self, snapshot: &Snapshot) { - // Failures here may indicate a failure to follow a stack discipline. - assert!(self.undo_log.len() >= snapshot.undo_len); - assert!(self.num_open_snapshots > 0); - } - - pub fn rollback_to(&mut self, snapshot: Snapshot) { - debug!("rollback_to({})", snapshot.undo_len); - - self.assert_open_snapshot(&snapshot); - - while self.undo_log.len() > snapshot.undo_len { - match self.undo_log.pop().unwrap() { - NewElem(i) => { - self.values.0.pop(); - assert!(self.values.0.len() == i); - } - - SetElem(i, v) => { - self.values.0[i] = v; - } - - Other(u) => { - D::reverse(&mut self.values.0, u); - } - } - } - - self.num_open_snapshots -= 1; - } - - /// Commits all changes since the last snapshot. Of course, they - /// can still be undone if there is a snapshot further out. - pub fn commit(&mut self, snapshot: Snapshot) { - debug!("commit({})", snapshot.undo_len); - - self.assert_open_snapshot(&snapshot); - - if self.num_open_snapshots == 1 { - // The root snapshot. It's safe to clear the undo log because - // there's no snapshot further out that we might need to roll back - // to. - assert!(snapshot.undo_len == 0); - self.undo_log.clear(); - } - - self.num_open_snapshots -= 1; - } -} - -impl ops::Deref for SnapshotVec { - type Target = [D::Value]; - fn deref(&self) -> &[D::Value] { - &*self.values.0 - } -} - -impl ops::DerefMut for SnapshotVec { - fn deref_mut(&mut self) -> &mut [D::Value] { - &mut *self.values.0 - } -} - -impl ops::Index for SnapshotVec { - type Output = D::Value; - fn index(&self, index: usize) -> &D::Value { - self.get(index) - } -} - -impl ops::IndexMut for SnapshotVec { - fn index_mut(&mut self, index: usize) -> &mut D::Value { - self.get_mut(index) - } -} - -impl Extend for SnapshotVec { - fn extend(&mut self, iterable: T) - where - T: IntoIterator, - { - let initial_len = self.values.0.len(); - self.values.0.extend(iterable); - let final_len = self.values.0.len(); - - if self.in_snapshot() { - self.undo_log.extend((initial_len..final_len).map(NewElem)); - } - } -} - -impl Clone for SnapshotVec -where - D::Value: Clone, - D::Undo: Clone, -{ - fn clone(&self) -> Self { - SnapshotVec { - values: self.values.clone(), - undo_log: self.undo_log.clone(), - num_open_snapshots: self.num_open_snapshots, - } - } -} - -impl Clone for UndoLog -where - D::Value: Clone, - D::Undo: Clone, -{ - fn clone(&self) -> Self { - match *self { - NewElem(i) => NewElem(i), - SetElem(i, ref v) => SetElem(i, v.clone()), - Other(ref u) => Other(u.clone()), - } - } -} - -impl SnapshotVecDelegate for i32 { - type Value = i32; - type Undo = (); - - fn reverse(_: &mut Vec, _: ()) {} -} - -#[test] -fn basic() { - let mut vec: SnapshotVec = SnapshotVec::default(); - assert!(!vec.in_snapshot()); - assert_eq!(vec.len(), 0); - vec.push(22); - vec.push(33); - assert_eq!(vec.len(), 2); - assert_eq!(*vec.get(0), 22); - assert_eq!(*vec.get(1), 33); - vec.set(1, 34); - assert_eq!(vec.len(), 2); - assert_eq!(*vec.get(0), 22); - assert_eq!(*vec.get(1), 34); - - let snapshot = vec.start_snapshot(); - assert!(vec.in_snapshot()); - - vec.push(44); - vec.push(55); - vec.set(1, 35); - assert_eq!(vec.len(), 4); - assert_eq!(*vec.get(0), 22); - assert_eq!(*vec.get(1), 35); - assert_eq!(*vec.get(2), 44); - assert_eq!(*vec.get(3), 55); - - vec.rollback_to(snapshot); - assert!(!vec.in_snapshot()); - - assert_eq!(vec.len(), 2); - assert_eq!(*vec.get(0), 22); - assert_eq!(*vec.get(1), 34); -} - -#[test] -#[should_panic] -fn out_of_order() { - let mut vec: SnapshotVec = SnapshotVec::default(); - vec.push(22); - let snapshot1 = vec.start_snapshot(); - vec.push(33); - let snapshot2 = vec.start_snapshot(); - vec.push(44); - vec.rollback_to(snapshot1); // bogus, but accepted - vec.rollback_to(snapshot2); // asserts -} - -#[test] -fn nested_commit_then_rollback() { - let mut vec: SnapshotVec = SnapshotVec::default(); - vec.push(22); - let snapshot1 = vec.start_snapshot(); - let snapshot2 = vec.start_snapshot(); - vec.set(0, 23); - vec.commit(snapshot2); - assert_eq!(*vec.get(0), 23); - vec.rollback_to(snapshot1); - assert_eq!(*vec.get(0), 22); -} diff --git a/vendor/ena/src/unify/backing_vec.rs b/vendor/ena/src/unify/backing_vec.rs deleted file mode 100644 index e65c882f43..0000000000 --- a/vendor/ena/src/unify/backing_vec.rs +++ /dev/null @@ -1,249 +0,0 @@ -use crate::snapshot_vec as sv; -#[cfg(feature = "persistent")] -use im_rc::Vector; -use std::fmt::{self, Debug}; -use std::marker::PhantomData; -use std::ops::{self, Range}; - -use super::{UnifyKey, VarValue}; - -#[allow(dead_code)] // rustc BUG -#[allow(type_alias_bounds)] -type Key = ::Key; - -/// Largely internal trait implemented by the unification table -/// backing store types. The most common such type is `InPlace`, -/// which indicates a standard, mutable unification table. -pub trait UnificationStore: - ops::Index>> - + ops::IndexMut>> - + Clone - + Default -{ - type Key: UnifyKey; - type Value: Clone + Debug; - type Snapshot; - - fn start_snapshot(&mut self) -> Self::Snapshot; - - fn rollback_to(&mut self, snapshot: Self::Snapshot); - - fn commit(&mut self, snapshot: Self::Snapshot); - - fn values_since_snapshot(&self, snapshot: &Self::Snapshot) -> Range; - - fn reset_unifications(&mut self, value: impl FnMut(usize) -> VarValue); - - fn len(&self) -> usize; - - fn is_empty(&self) -> bool; - - fn push(&mut self, value: VarValue); - - fn reserve(&mut self, num_new_values: usize); - - fn update(&mut self, index: usize, op: F) - where - F: FnOnce(&mut VarValue); - - fn tag() -> &'static str { - Self::Key::tag() - } -} - -/// Backing store for an in-place unification table. -/// Not typically used directly. -#[derive(Clone)] -pub struct InPlace { - values: sv::SnapshotVec>, -} - -impl fmt::Debug for InPlace -where - K: UnifyKey, - K: Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.values.fmt(f) - } -} - -// HACK(eddyb) manual impl avoids `Default` bound on `K`. -impl Default for InPlace { - fn default() -> Self { - InPlace { - values: sv::SnapshotVec::new(), - } - } -} - -impl UnificationStore for InPlace { - type Key = K; - type Value = K::Value; - type Snapshot = sv::Snapshot; - - #[inline] - fn start_snapshot(&mut self) -> Self::Snapshot { - self.values.start_snapshot() - } - - #[inline] - fn rollback_to(&mut self, snapshot: Self::Snapshot) { - self.values.rollback_to(snapshot); - } - - #[inline] - fn commit(&mut self, snapshot: Self::Snapshot) { - self.values.commit(snapshot); - } - - #[inline] - fn values_since_snapshot(&self, snapshot: &Self::Snapshot) -> Range { - snapshot.value_count..self.len() - } - - #[inline] - fn reset_unifications(&mut self, value: impl FnMut(usize) -> VarValue) { - self.values.set_all(value); - } - - fn len(&self) -> usize { - self.values.len() - } - - fn is_empty(&self) -> bool { - self.values.len() == 0 - } - - #[inline] - fn push(&mut self, value: VarValue) { - self.values.push(value); - } - - #[inline] - fn reserve(&mut self, num_new_values: usize) { - self.values.reserve(num_new_values); - } - - #[inline] - fn update(&mut self, index: usize, op: F) - where - F: FnOnce(&mut VarValue), - { - self.values.update(index, op) - } -} - -impl ops::Index for InPlace -where - K: UnifyKey, -{ - type Output = VarValue; - fn index(&self, index: usize) -> &VarValue { - &self.values[index] - } -} - -impl ops::IndexMut for InPlace -where - K: UnifyKey, -{ - fn index_mut(&mut self, index: usize) -> &mut VarValue { - &mut self.values[index] - } -} - -#[derive(Copy, Clone, Debug)] -struct Delegate(PhantomData); - -impl sv::SnapshotVecDelegate for Delegate { - type Value = VarValue; - type Undo = (); - - fn reverse(_: &mut Vec>, _: ()) {} -} - -#[cfg(feature = "persistent")] -#[derive(Clone, Debug)] -pub struct Persistent { - values: Vector>, -} - -// HACK(eddyb) manual impl avoids `Default` bound on `K`. -#[cfg(feature = "persistent")] -impl Default for Persistent { - fn default() -> Self { - Persistent { - values: Vector::new(), - } - } -} - -#[cfg(feature = "persistent")] -impl UnificationStore for Persistent { - type Key = K; - type Value = K::Value; - type Snapshot = Self; - - #[inline] - fn start_snapshot(&mut self) -> Self::Snapshot { - self.clone() - } - - #[inline] - fn rollback_to(&mut self, snapshot: Self::Snapshot) { - *self = snapshot; - } - - #[inline] - fn commit(&mut self, _snapshot: Self::Snapshot) {} - - #[inline] - fn values_since_snapshot(&self, snapshot: &Self::Snapshot) -> Range { - snapshot.len()..self.len() - } - - #[inline] - fn reset_unifications(&mut self, mut value: impl FnMut(usize) -> VarValue) { - // Without extending dogged, there isn't obviously a more - // efficient way to do this. But it's pretty dumb. Maybe - // dogged needs a `map`. [NOTE: revisit in light of replacing dogged with im_rc!] - for i in 0..self.values.len() { - self.values[i] = value(i); - } - } - - fn len(&self) -> usize { - self.values.len() - } - - #[inline] - fn push(&mut self, value: VarValue) { - self.values.push(value); - } - - #[inline] - fn reserve(&mut self, _num_new_values: usize) { - // not obviously relevant to Vector. - } - - #[inline] - fn update(&mut self, index: usize, op: F) - where - F: FnOnce(&mut VarValue), - { - let p = &mut self.values[index]; - op(p); - } -} - -#[cfg(feature = "persistent")] -impl ops::Index for Persistent -where - K: UnifyKey, -{ - type Output = VarValue; - fn index(&self, index: usize) -> &VarValue { - &self.values[index] - } -} diff --git a/vendor/ena/src/unify/mod.rs b/vendor/ena/src/unify/mod.rs deleted file mode 100644 index acc45a469e..0000000000 --- a/vendor/ena/src/unify/mod.rs +++ /dev/null @@ -1,500 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Union-find implementation. The main type is `UnificationTable`. -//! -//! You can define your own type for the *keys* in the table, but you -//! must implement `UnifyKey` for that type. The assumption is that -//! keys will be newtyped integers, hence we require that they -//! implement `Copy`. -//! -//! Keys can have values associated with them. The assumption is that -//! these values are cheaply cloneable (ideally, `Copy`), and some of -//! the interfaces are oriented around that assumption. If you just -//! want the classical "union-find" algorithm where you group things -//! into sets, use the `Value` type of `()`. -//! -//! When you have keys with non-trivial values, you must also define -//! how those values can be merged. As part of doing this, you can -//! define the "error" type to return on error; if errors are not -//! possible, use `NoError` (an uninstantiable struct). Using this -//! type also unlocks various more ergonomic methods (e.g., `union()` -//! in place of `unify_var_var()`). -//! -//! The best way to see how it is used is to read the `tests.rs` file; -//! search for e.g. `UnitKey`. - -use std::cmp::Ordering; -use std::fmt::{self, Debug}; -use std::marker; -use std::ops::Range; - -mod backing_vec; -pub use self::backing_vec::{InPlace, UnificationStore}; - -#[cfg(feature = "persistent")] -pub use self::backing_vec::Persistent; - -/// This trait is implemented by any type that can serve as a type -/// variable. We call such variables *unification keys*. For example, -/// this trait is implemented by `IntVid`, which represents integral -/// variables. -/// -/// Each key type has an associated value type `V`. For example, for -/// `IntVid`, this is `Option`, representing some -/// (possibly not yet known) sort of integer. -/// -/// Clients are expected to provide implementations of this trait; you -/// can see some examples in the `test` module. -pub trait UnifyKey: Copy + Clone + Debug + PartialEq { - type Value: Clone + Debug; - - fn index(&self) -> u32; - - fn from_index(u: u32) -> Self; - - fn tag() -> &'static str; - - /// If true, then `self` should be preferred as root to `other`. - /// Note that we assume a consistent partial ordering, so - /// returning true implies that `other.prefer_as_root_to(self)` - /// would return false. If there is no ordering between two keys - /// (i.e., `a.prefer_as_root_to(b)` and `b.prefer_as_root_to(a)` - /// both return false) then the rank will be used to determine the - /// root in an optimal way. - /// - /// NB. The only reason to implement this method is if you want to - /// control what value is returned from `find()`. In general, it - /// is better to let the unification table determine the root, - /// since overriding the rank can cause execution time to increase - /// dramatically. - #[allow(unused_variables)] - fn order_roots( - a: Self, - a_value: &Self::Value, - b: Self, - b_value: &Self::Value, - ) -> Option<(Self, Self)> { - None - } -} - -/// A struct which can never be instantiated. Used -/// for the error type for infallible cases. -#[derive(Debug)] -pub struct NoError { - _dummy: (), -} - -/// Value of a unification key. We implement Tarjan's union-find -/// algorithm: when two keys are unified, one of them is converted -/// into a "redirect" pointing at the other. These redirects form a -/// DAG: the roots of the DAG (nodes that are not redirected) are each -/// associated with a value of type `V` and a rank. The rank is used -/// to keep the DAG relatively balanced, which helps keep the running -/// time of the algorithm under control. For more information, see -/// . -#[derive(PartialEq, Clone)] -pub struct VarValue { - // FIXME pub - parent: K, // if equal to self, this is a root - pub value: K::Value, // value assigned (only relevant to root) - rank: u32, // max depth (only relevant to root) -} - -impl fmt::Debug for VarValue -where - K: UnifyKey, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "p: {:?}, c: {:?}", self.parent, self.value) - } -} - -/// Table of unification keys and their values. You must define a key type K -/// that implements the `UnifyKey` trait. Unification tables can be used in two-modes: -/// -/// - in-place (`UnificationTable>` or `InPlaceUnificationTable`): -/// - This is the standard mutable mode, where the array is modified -/// in place. -/// - To do backtracking, you can employ the `snapshot` and `rollback_to` -/// methods. -/// - persistent (`UnificationTable>` or `PersistentUnificationTable`): -/// - In this mode, we use a persistent vector to store the data, so that -/// cloning the table is an O(1) operation. -/// - This implies that ordinary operations are quite a bit slower though. -/// - Requires the `persistent` feature be selected in your Cargo.toml file. -#[derive(Clone, Default)] -pub struct UnificationTable { - /// Indicates the current value of each key. - values: S, -} - -impl fmt::Debug for UnificationTable -where - S: UnificationStore, - S: Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.values.fmt(f) - } -} - -/// A unification table that uses an "in-place" vector. -#[allow(type_alias_bounds)] -pub type InPlaceUnificationTable = UnificationTable>; - -/// A unification table that uses a "persistent" vector. -#[cfg(feature = "persistent")] -#[allow(type_alias_bounds)] -pub type PersistentUnificationTable = UnificationTable>; - -/// At any time, users may snapshot a unification table. The changes -/// made during the snapshot may either be *committed* or *rolled back*. -pub struct Snapshot { - // Link snapshot to the unification store `S` of the table. - marker: marker::PhantomData, - snapshot: S::Snapshot, -} - -impl VarValue { - fn new_var(key: K, value: K::Value) -> VarValue { - VarValue::new(key, value, 0) - } - - fn new(parent: K, value: K::Value, rank: u32) -> VarValue { - VarValue { - parent, // this is a root - value, - rank, - } - } - - fn redirect(&mut self, to: K) { - self.parent = to; - } - - fn root(&mut self, rank: u32, value: K::Value) { - self.rank = rank; - self.value = value; - } - - #[inline(always)] - fn parent(&self, self_key: K) -> Option { - self.if_not_self(self.parent, self_key) - } - - fn raw_parent(&self) -> K { - self.parent - } - - #[inline(always)] - fn if_not_self(&self, key: K, self_key: K) -> Option { - if key == self_key { - None - } else { - Some(key) - } - } -} - -// We can't use V:LatticeValue, much as I would like to, -// because frequently the pattern is that V=Option for some -// other type parameter U, and we have no way to say -// Option:LatticeValue. - -impl UnificationTable { - pub fn new() -> Self { - Self::default() - } - - /// Starts a new snapshot. Each snapshot must be either - /// rolled back or committed in a "LIFO" (stack) order. - pub fn snapshot(&mut self) -> Snapshot { - Snapshot { - marker: marker::PhantomData::, - snapshot: self.values.start_snapshot(), - } - } - - /// Reverses all changes since the last snapshot. Also - /// removes any keys that have been created since then. - pub fn rollback_to(&mut self, snapshot: Snapshot) { - debug!("{}: rollback_to()", S::tag()); - self.values.rollback_to(snapshot.snapshot); - } - - /// Commits all changes since the last snapshot. Of course, they - /// can still be undone if there is a snapshot further out. - pub fn commit(&mut self, snapshot: Snapshot) { - debug!("{}: commit()", S::tag()); - self.values.commit(snapshot.snapshot); - } - - /// Creates a fresh key with the given value. - pub fn new_key(&mut self, value: S::Value) -> S::Key { - let len = self.values.len() as u32; - let key: S::Key = UnifyKey::from_index(len); - self.values.push(VarValue::new_var(key, value)); - debug!("{}: created new key: {:?}", S::tag(), key); - key - } - - /// Reserve memory for `num_new_keys` to be created. Does not - /// actually create the new keys; you must then invoke `new_key`. - pub fn reserve(&mut self, num_new_keys: usize) { - self.values.reserve(num_new_keys); - } - - /// Clears all unifications that have been performed, resetting to - /// the initial state. The values of each variable are given by - /// the closure. - pub fn reset_unifications(&mut self, mut value: impl FnMut(S::Key) -> S::Value) { - self.values.reset_unifications(|i| { - let key = UnifyKey::from_index(i as u32); - let value = value(key); - VarValue::new_var(key, value) - }); - } - - /// Returns the number of keys created so far. - pub fn len(&self) -> usize { - self.values.len() - } - - /// Returns true iff there have been no keys created yet. - pub fn is_empty(&self) -> bool { - self.values.len() == 0 - } - - /// Returns the keys of all variables created since the `snapshot`. - pub fn vars_since_snapshot(&self, snapshot: &Snapshot) -> Range { - let range = self.values.values_since_snapshot(&snapshot.snapshot); - S::Key::from_index(range.start as u32)..S::Key::from_index(range.end as u32) - } - - /// Obtains the current value for a particular key. - /// Not for end-users; they can use `probe_value`. - pub fn value(&self, key: S::Key) -> &VarValue { - &self.values[key.index() as usize] - } - - /// Obtains the current value for a particular key. - /// Not for end-users; they can use `probe_value`. - pub fn value_mut(&mut self, key: S::Key) -> &mut VarValue { - &mut self.values[key.index() as usize] - } - - /// Find the root node for `vid`. This uses the standard - /// union-find algorithm with path compression: - /// . - /// - /// NB. This is a building-block operation and you would probably - /// prefer to call `probe` below. - /// - /// This is an always-inlined version of this function for the hot - /// callsites. `uninlined_get_root_key` is the never-inlined version. - #[inline(always)] - pub fn inlined_get_root_key(&mut self, vid: S::Key) -> S::Key { - match self.value(vid).parent(vid) { - None => vid, - Some(redirect) => { - let root_key: S::Key = self.uninlined_get_root_key(redirect); - if root_key != redirect { - // Path compression - self.update_value(vid, |value| value.parent = root_key); - } - - root_key - } - } - } - - // This is a never-inlined version of this function for cold callsites. - // 'inlined_get_root_key` is the always-inlined version. - #[inline(never)] - fn uninlined_get_root_key(&mut self, vid: S::Key) -> S::Key { - self.inlined_get_root_key(vid) - } - - #[inline(always)] - pub fn get_root_key_without_compacting(&self, mut vid: S::Key) -> S::Key { - while let Some(redirect) = self.value(vid).parent(vid) { - vid = redirect; - } - - vid - } - - pub fn is_redirect(&self, vid: S::Key) -> bool { - self.value(vid).raw_parent() != vid - } - - pub fn update_value(&mut self, key: S::Key, op: OP) - where - OP: FnOnce(&mut VarValue), - { - self.values.update(key.index() as usize, op); - debug!("Updated variable {:?} to {:?}", key, self.value(key)); - } - - /// Either redirects `node_a` to `node_b` or vice versa, depending - /// on the relative rank. The value associated with the new root - /// will be `new_value`. - /// - /// NB: This is the "union" operation of "union-find". It is - /// really more of a building block. If the values associated with - /// your key are non-trivial, you would probably prefer to call - /// `unify_var_var` below. - pub fn unify_roots(&mut self, key_a: S::Key, key_b: S::Key, new_value: S::Value) { - debug!("unify(key_a={:?}, key_b={:?})", key_a, key_b); - - let rank_a = self.value(key_a).rank; - let rank_b = self.value(key_b).rank; - if let Some((new_root, redirected)) = S::Key::order_roots( - key_a, - &self.value(key_a).value, - key_b, - &self.value(key_b).value, - ) { - // compute the new rank for the new root that they chose; - // this may not be the optimal choice. - let new_rank = if new_root == key_a { - debug_assert!(redirected == key_b); - if rank_a > rank_b { - rank_a - } else { - rank_b + 1 - } - } else { - debug_assert!(new_root == key_b); - debug_assert!(redirected == key_a); - if rank_b > rank_a { - rank_b - } else { - rank_a + 1 - } - }; - self.redirect_root(new_rank, redirected, new_root, new_value); - } else { - match rank_a.cmp(&rank_b) { - Ordering::Greater => { - // a has greater rank, so a should become b's parent, - // i.e., b should redirect to a. - self.redirect_root(rank_a, key_b, key_a, new_value); - } - Ordering::Less => { - // b has greater rank, so a should redirect to b. - self.redirect_root(rank_b, key_a, key_b, new_value); - } - Ordering::Equal => { - // If equal, redirect one to the other and increment the - // other's rank. - self.redirect_root(rank_a + 1, key_a, key_b, new_value); - } - } - } - } - - /// Internal method to redirect `old_root_key` (which is currently - /// a root) to a child of `new_root_key` (which will remain a - /// root). The rank and value of `new_root_key` will be updated to - /// `new_rank` and `new_value` respectively. - fn redirect_root( - &mut self, - new_rank: u32, - old_root_key: S::Key, - new_root_key: S::Key, - new_value: S::Value, - ) { - self.update_value(old_root_key, |old_root_value| { - old_root_value.redirect(new_root_key); - }); - self.update_value(new_root_key, |new_root_value| { - new_root_value.root(new_rank, new_value); - }); - } -} - -/// //////////////////////////////////////////////////////////////////////// -/// Public API - -impl<'tcx, S, K, V> UnificationTable -where - S: UnificationStore, - K: UnifyKey, - V: Clone + Debug, -{ - /// Given two keys, indicates whether they have been unioned together. - pub fn unioned(&mut self, a_id: K1, b_id: K2) -> bool - where - K1: Into, - K2: Into, - { - self.find(a_id) == self.find(b_id) - } - - /// Given a key, returns the (current) root key. - pub fn find(&mut self, id: K1) -> K - where - K1: Into, - { - let id = id.into(); - self.inlined_get_root_key(id) - } - - /// Returns the current value for the given key. If the key has - /// been union'd, this will give the value from the current root. - #[inline(always)] - pub fn probe_value(&mut self, id: K1) -> V - where - K1: Into, - { - let id = id.into(); - let id = self.inlined_get_root_key(id); - self.value(id).value.clone() - } - - /// Returns the current value for the given key. If the key has - /// been union'd, this will give the value from the current root. - #[inline(always)] - pub fn probe_value_ref(&self, id: K1) -> &VarValue - where - K1: Into, - { - let id = id.into(); - let id = self.get_root_key_without_compacting(id); - self.value(id) - } - - /// Returns the current value for the given key. If the key has - /// been union'd, this will give the value from the current root. - #[inline(always)] - pub fn probe_value_ref_mut(&mut self, id: K1) -> &mut VarValue - where - K1: Into, - { - let id = id.into(); - let id = self.inlined_get_root_key(id); - self.value_mut(id) - } - - /// This is for a debug_assert! in solve() only. Do not use it elsewhere! - #[inline(always)] - pub fn probe_value_without_compacting(&self, id: K1) -> V - where - K1: Into, - { - let id = id.into(); - let id = self.get_root_key_without_compacting(id); - - self.value(id).value.clone() - } -}