prevent a subs lookup by reserving a Variable

This commit is contained in:
Folkert 2022-03-06 18:00:25 +01:00
parent cc5c734c20
commit 41e56519ef
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
2 changed files with 16 additions and 14 deletions

View file

@ -1928,7 +1928,8 @@ fn deep_copy_var_help(
use roc_types::subs::Content::*;
use roc_types::subs::FlatType::*;
let desc = subs.get_without_compacting(var);
let subs_len = subs.len();
let desc = subs.get_ref_mut(var);
if let Some(copy) = desc.copy.into_variable() {
return copy;
@ -1945,8 +1946,13 @@ fn deep_copy_var_help(
copy: OptVariable::NONE,
};
let content = desc.content;
let copy = subs.fresh(make_descriptor(content.clone()));
let content = desc.content.clone();
// Safety: Here we make a variable that is 1 position out of bounds.
// The reason is that we can now keep the mutable reference to `desc`
// Below, we actually push a new variable onto subs meaning the `copy`
// variable is in-bounds before it is ever used.
let copy = unsafe { Variable::from_index(subs_len as u32) };
pools.get_mut(max_rank).push(copy);
@ -1954,15 +1960,11 @@ fn deep_copy_var_help(
// avoid making multiple copies of the variable we are instantiating.
//
// Need to do this before recursively copying to avoid looping.
subs.set(
var,
Descriptor {
content: content.clone(),
rank: desc.rank,
mark: Mark::NONE,
copy: copy.into(),
},
);
desc.mark = Mark::NONE;
desc.copy = copy.into();
let actual_copy = subs.fresh(make_descriptor(content.clone()));
debug_assert_eq!(copy, actual_copy);
// Now we recursively copy the content of the variable.
// We have already marked the variable as copied, so we

View file

@ -736,8 +736,8 @@ impl Variable {
/// # Safety
///
/// This should only ever be called from tests!
pub unsafe fn unsafe_test_debug_variable(v: u32) -> Self {
/// It is not guaranteed that the variable is in bounds.
pub unsafe fn from_index(v: u32) -> Self {
debug_assert!(v >= Self::NUM_RESERVED_VARS as u32);
Variable(v)
}