Upgrading Weak failing from arena

I've finalized the semantic system of a language compiler codebase and I had the plans of using an arena of shared pointers, however, when I upgrade from std::rc::Weak to std::rc::Rc I get a None.

#[test]
fn f() {
    let host = SymbolHost::new();
    let p = host.factory().create_package(["com", "nintendo", "supermariomaker"]);
    println!("{}", p.fully_qualified_name());
}

I get a panic here:

/// Indicates subpackages of a package from their unqualified name to their `Package` symbol.
pub fn subpackages(&self) -> SharedMap<String, Symbol> {
    let symbol = self.0.upgrade().unwrap();
    match symbol.as_ref() {
        SymbolKind::Package(data) => data.subpackages.clone(),
        _ => panic!(),
    }
}

The subpackages() field is accessed from these factory functions:

/// Creates an interned package from a fully qualified name.
///
/// # Example
///
/// ```ignore
/// assert_eq!(host.factory.create_package(["q", "b", "w"]).fully_qualified_name(), "q.b.w");
/// ```
pub fn create_package<'b>(&self, name: impl IntoIterator<Item = &'b str>) -> Symbol {
    self.create_package_1(&name.into_iter().collect())
}

fn create_package_1(&self, name: &Vec<&str>) -> Symbol {
    let mut result: Symbol = self.host.top_level_package.clone();
    for name_1 in name {
        let name_1 = (*name_1).to_owned();
        let result_1 = result.subpackages().get(&name_1);
        if let Some(result_1) = result_1 {
            result = result_1;
        } else {
            let result_1 = Symbol(self.host.arena.allocate(SymbolKind::Package(Rc::new(PackageData {
                name: name_1.clone(),
                parent_definition: RefCell::new(Some(result.clone())),
                properties: SharedMap::new(),
                redirect_packages: SharedArray::new(),
                subpackages: SharedMap::new(),
                jetdoc: RefCell::new(None),
            }))));
            result.subpackages().set(name_1, result_1.clone());
            result = result_1;
        }
    }
    result
}

The arena code is just that little piece:

use std::{cell::RefCell, rc::{Rc, Weak}};

pub struct Arena<T> {
    data: RefCell<Vec<Rc<T>>>,
}

impl<T> Arena<T> {
    pub fn new() -> Self {
        Self {
            data: RefCell::new(vec![]),
        }
    }

    pub fn allocate(&self, value: T) -> Weak<T> {
        let obj = Rc::new(value);
        self.data.borrow_mut().push(Rc::clone(&obj));
        Rc::downgrade(&obj)
    }
}

Full source code:

I heard that this trick of using Weak from an arena's shared pointer would work in here. Am I doing something wrong?

I've ran even println!(arena.data.borrow().len()) in the allocate() function and it incremented successfully.

Will I've to give up on the arena and leak memory and therefore leaving SymbolHosts accumulating data? I don't think this would be a considerable problem given that only one SymbolHost is to be expected to be created and will last the compiler execution in most use cases. (I don't see any use case for creating more hosts yet...)

On these lines, you call Arena::new() twice, creating two separate arenas:

The first of these (the local variable arena) is dropped at the end of the function, so anything allocated in that arena becomes a dangling pointer.

1 Like

Thanks for the pointer! I modified the SymbolHost constructor a little and it works now apparently:

pub fn new() -> Self {
    let arena = Arena::new();
    let unresolved = Symbol(arena.allocate(SymbolKind::Unresolved));
    let any_type = Symbol(arena.allocate(SymbolKind::Type(TypeKind::AnyType)));
    let void_type = Symbol(arena.allocate(SymbolKind::Type(TypeKind::VoidType)));
    let import_meta = Symbol(arena.allocate(SymbolKind::ImportMeta));
    let import_meta_env = Symbol(arena.allocate(SymbolKind::ImportMetaEnv));
    let top_level_package = Symbol(arena.allocate(SymbolKind::Package(Rc::new(PackageData {
        name: String::new(),
        parent_definition: RefCell::new(None),
        properties: SharedMap::new(),
        redirect_packages: SharedArray::new(),
        subpackages: SharedMap::new(),
        jetdoc: RefCell::new(None),
    }))));

    Self {
        arena,
        unresolved,
        any_type,
        void_type,
        import_meta,
        import_meta_env,

        env_cache: RefCell::new(None),

        function_types: RefCell::new(HashMap::new()),
        tuple_types: RefCell::new(HashMap::new()),
        nullable_types: RefCell::new(HashMap::new()),
        taets: RefCell::new(HashMap::new()),
        vapaits: RefCell::new(HashMap::new()),
        vipaits: RefCell::new(HashMap::new()),
        faeoits: RefCell::new(HashMap::new()),

        top_level_package,

        jet_lang_package: RefCell::new(None),

        object_type: RefCell::new(None),
        boolean_type: RefCell::new(None),
        string_type: RefCell::new(None),
        char_type: RefCell::new(None),
        char_index_type: RefCell::new(None),
        number_type: RefCell::new(None),
        single_type: RefCell::new(None),
        byte_type: RefCell::new(None),
        short_type: RefCell::new(None),
        int_type: RefCell::new(None),
        long_type: RefCell::new(None),
        unsigned_byte_type: RefCell::new(None),
        unsigned_short_type: RefCell::new(None),
        unsigned_int_type: RefCell::new(None),
        unsigned_long_type: RefCell::new(None),
        big_int_type: RefCell::new(None),
        function_type: RefCell::new(None),
        xml_type: RefCell::new(None),
        xml_list_type: RefCell::new(None),
        class_type: RefCell::new(None),
        array_type: RefCell::new(None),

        infinity_constant: RefCell::new(None),
        nan_constant: RefCell::new(None),

        root_scope: RefCell::new(None),
    }
}