llr: Store a GlobalIndex in the EvaluationContext instead of a reference

So that the CompilationUnit is only borrowed once and can be made
mutable
This commit is contained in:
Olivier Goffart 2025-01-25 15:42:48 +01:00
parent 3e586edd1a
commit 1aeeba7d6b
6 changed files with 50 additions and 37 deletions

View file

@ -794,11 +794,11 @@ pub fn generate(
}),
));
for glob in &llr.globals {
for (idx, glob) in llr.globals.iter().enumerate() {
let ty = if glob.is_builtin {
format_smolstr!("slint::cbindgen_private::{}", glob.name)
} else if glob.must_generate() {
generate_global(&mut file, &conditional_includes, glob, &llr);
generate_global(&mut file, &conditional_includes, idx, glob, &llr);
file.definitions.extend(glob.aliases.iter().map(|name| {
Declaration::TypeAlias(TypeAlias {
old_name: ident(&glob.name),
@ -2555,6 +2555,7 @@ fn generate_repeated_component(
fn generate_global(
file: &mut File,
conditional_includes: &ConditionalIncludes,
global_idx: llr::GlobalIndex,
global: &llr::GlobalComponent,
root: &llr::CompilationUnit,
) {
@ -2587,7 +2588,7 @@ fn generate_global(
let mut init = vec!["(void)this->globals;".into()];
let ctx = EvaluationContext::new_global(
root,
global,
global_idx,
CppGeneratorContext { global_access: "this->globals".into(), conditional_includes },
);
@ -2918,7 +2919,7 @@ fn access_member(reference: &llr::PropertyReference, ctx: &EvaluationContext) ->
);
let property_name = ident(&sub_component.properties[*property_index].name);
format!("self->{}{}", compo_path, property_name)
} else if let Some(current_global) = ctx.current_global {
} else if let Some(current_global) = ctx.current_global() {
format!("this->{}", ident(&current_global.properties[*property_index].name))
} else {
unreachable!()
@ -2933,7 +2934,7 @@ fn access_member(reference: &llr::PropertyReference, ctx: &EvaluationContext) ->
);
let name = ident(&sub_component.functions[*function_index].name);
format!("self->{compo_path}fn_{name}")
} else if let Some(current_global) = ctx.current_global {
} else if let Some(current_global) = ctx.current_global() {
format!("this->fn_{}", ident(&current_global.functions[*function_index].name))
} else {
unreachable!()

View file

@ -199,8 +199,9 @@ pub fn generate(
let globals = llr
.globals
.iter()
.filter(|glob| glob.must_generate())
.map(|glob| generate_global(glob, &llr));
.enumerate()
.filter(|(_, glob)| glob.must_generate())
.map(|(idx, glob)| generate_global(idx, glob, &llr));
let shared_globals = generate_shared_globals(&llr, &compiler_config);
let globals_ids = llr.globals.iter().filter(|glob| glob.exported).flat_map(|glob| {
std::iter::once(ident(&glob.name)).chain(glob.aliases.iter().map(|x| ident(x)))
@ -1327,7 +1328,11 @@ fn generate_functions(functions: &[llr::Function], ctx: &EvaluationContext) -> V
.collect()
}
fn generate_global(global: &llr::GlobalComponent, root: &llr::CompilationUnit) -> TokenStream {
fn generate_global(
global_idx: llr::GlobalIndex,
global: &llr::GlobalComponent,
root: &llr::CompilationUnit,
) -> TokenStream {
let mut declared_property_vars = vec![];
let mut declared_property_types = vec![];
let mut declared_callbacks = vec![];
@ -1361,7 +1366,7 @@ fn generate_global(global: &llr::GlobalComponent, root: &llr::CompilationUnit) -
let ctx = EvaluationContext::new_global(
root,
global,
global_idx,
RustGeneratorContext {
global_access: quote!(_self.globals.get().unwrap().upgrade().unwrap()),
},
@ -1918,7 +1923,7 @@ fn access_member(reference: &llr::PropertyReference, ctx: &EvaluationContext) ->
let property_name = ident(&sub_component.properties[*property_index].name);
let property_field = access_component_field_offset(&component_id, &property_name);
MemberAccess::Direct(quote!((#compo_path #property_field).apply_pin(_self)))
} else if let Some(current_global) = ctx.current_global {
} else if let Some(current_global) = ctx.current_global() {
let global_name = global_inner_name(current_global);
let property_name = ident(&current_global.properties[*property_index].name);
let property_field = quote!({ *&#global_name::FIELD_OFFSETS.#property_name });
@ -2018,7 +2023,7 @@ fn access_member(reference: &llr::PropertyReference, ctx: &EvaluationContext) ->
}
let fn_id = ident(&format!("fn_{}", sub_component.functions[*function_index].name));
MemberAccess::Direct(quote!(#compo_path.#fn_id))
} else if let Some(current_global) = ctx.current_global {
} else if let Some(current_global) = ctx.current_global() {
let fn_id =
ident(&format!("fn_{}", current_global.functions[*function_index].name));
MemberAccess::Direct(quote!(_self.#fn_id))

View file

@ -1,7 +1,7 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
use super::{PropertyReference, SubComponentIndex};
use super::{GlobalIndex, PropertyReference, SubComponentIndex};
use crate::expression_tree::{BuiltinFunction, MinMaxOp, OperatorClass};
use crate::langtype::Type;
use crate::layout::Orientation;
@ -482,7 +482,7 @@ impl<'a, T> ParentCtx<'a, T> {
pub struct EvaluationContext<'a, T = ()> {
pub compilation_unit: &'a super::CompilationUnit,
pub current_sub_component: Option<SubComponentIndex>,
pub current_global: Option<&'a super::GlobalComponent>,
pub current_global: Option<GlobalIndex>,
pub generator_state: T,
/// The repeater parent
pub parent: Option<ParentCtx<'a, T>>,
@ -510,7 +510,7 @@ impl<'a, T> EvaluationContext<'a, T> {
pub fn new_global(
compilation_unit: &'a super::CompilationUnit,
global: &'a super::GlobalComponent,
global: GlobalIndex,
generator_state: T,
) -> Self {
Self {
@ -604,7 +604,7 @@ impl<'a, T> EvaluationContext<'a, T> {
match prop {
PropertyReference::Local { property_index, .. } => {
if let Some(g) = self.current_global {
if let Some(g) = self.current_global() {
return PropertyInfoResult {
analysis: Some(&g.prop_analysis[*property_index]),
binding: g.init_values[*property_index]
@ -674,6 +674,10 @@ impl<'a, T> EvaluationContext<'a, T> {
pub fn current_sub_component(&self) -> Option<&super::SubComponent> {
self.current_sub_component.and_then(|i| self.compilation_unit.sub_components.get(i))
}
pub fn current_global(&self) -> Option<&super::GlobalComponent> {
self.current_global.and_then(|i| self.compilation_unit.globals.get(i))
}
}
impl<'a, T> TypeResolutionContext for EvaluationContext<'a, T> {
@ -686,7 +690,7 @@ impl<'a, T> TypeResolutionContext for EvaluationContext<'a, T> {
[sub_component.sub_components[*i].ty];
}
&sub_component.properties[*property_index].ty
} else if let Some(current_global) = self.current_global {
} else if let Some(current_global) = self.current_global() {
&current_global.properties[*property_index].ty
} else {
unreachable!()
@ -723,7 +727,7 @@ impl<'a, T> TypeResolutionContext for EvaluationContext<'a, T> {
[sub_component.sub_components[*i].ty];
}
&sub_component.functions[*function_index].ret_ty
} else if let Some(current_global) = self.current_global {
} else if let Some(current_global) = self.current_global() {
&current_global.functions[*function_index].ret_ty
} else {
unreachable!()
@ -755,7 +759,7 @@ pub(crate) struct PropertyInfoResult<'a> {
pub(crate) enum ContextMap {
Identity,
InSubElement { path: Vec<usize>, parent: usize },
InGlobal(usize),
InGlobal(GlobalIndex),
}
impl ContextMap {
@ -861,11 +865,7 @@ impl ContextMap {
EvaluationContext::new_sub_component(ctx.compilation_unit, e, (), None)
}
}
ContextMap::InGlobal(g) => EvaluationContext::new_global(
ctx.compilation_unit,
&ctx.compilation_unit.globals[*g],
(),
),
ContextMap::InGlobal(g) => EvaluationContext::new_global(ctx.compilation_unit, *g, ()),
}
}
}

View file

@ -13,6 +13,8 @@ use std::rc::Rc;
pub type PropertyIndex = usize;
// Index in CompilationUint::sub_components
pub type SubComponentIndex = usize;
// Index in CompilationUnit::globas
pub type GlobalIndex = usize;
#[derive(Debug, Clone, derive_more::Deref)]
pub struct MutExpression(RefCell<Expression>);
@ -94,12 +96,12 @@ pub enum PropertyReference {
/// The properties is a property relative to a parent ItemTree (`level` level deep)
InParent { level: NonZeroUsize, parent_reference: Box<PropertyReference> },
/// The property within a GlobalComponent
Global { global_index: usize, property_index: usize },
Global { global_index: GlobalIndex, property_index: usize },
/// A function in a sub component.
Function { sub_component_path: Vec<usize>, function_index: usize },
/// A function in a global.
GlobalFunction { global_index: usize, function_index: usize },
GlobalFunction { global_index: GlobalIndex, function_index: usize },
}
#[derive(Debug, Default)]
@ -437,8 +439,8 @@ impl CompilationUnit {
visitor(e, ctx);
}
});
for g in &self.globals {
let ctx = EvaluationContext::new_global(self, g, ());
for (idx, g) in self.globals.iter().enumerate() {
let ctx = EvaluationContext::new_global(self, idx, ());
for e in g.init_values.iter().filter_map(|x| x.as_ref()) {
visitor(&e.expression, &ctx)
}

View file

@ -24,8 +24,8 @@ pub fn count_property_use(root: &CompilationUnit) {
visit_property(&p.prop, &root_ctx);
}
}
for g in root.globals.iter().filter(|g| g.exported) {
let ctx = EvaluationContext::new_global(root, g, ());
for (idx, g) in root.globals.iter().enumerate().filter(|(_, g)| g.exported) {
let ctx = EvaluationContext::new_global(root, idx, ());
for p in g.public_properties.iter().filter(|p| {
!matches!(
p.prop,
@ -136,8 +136,8 @@ pub fn count_property_use(root: &CompilationUnit) {
});
// TODO: only visit used function
for g in root.globals.iter() {
let ctx = EvaluationContext::new_global(root, g, ());
for (idx, g) in root.globals.iter().enumerate() {
let ctx = EvaluationContext::new_global(root, idx, ());
for f in &g.functions {
f.code.visit_property_references(&ctx, &mut visit_property);
}

View file

@ -22,9 +22,9 @@ struct PrettyPrinter<'a> {
impl<'a> PrettyPrinter<'a> {
fn print_root(&mut self, root: &CompilationUnit) -> Result {
for g in &root.globals {
for (idx, g) in root.globals.iter().enumerate() {
if !g.is_builtin {
self.print_global(root, g)?;
self.print_global(root, idx, g)?;
}
}
for c in 0..root.sub_components.len() {
@ -116,8 +116,13 @@ impl<'a> PrettyPrinter<'a> {
writeln!(self.writer, "}}")
}
fn print_global(&mut self, root: &CompilationUnit, global: &super::GlobalComponent) -> Result {
let ctx = EvaluationContext::new_global(root, global, ());
fn print_global(
&mut self,
root: &CompilationUnit,
idx: super::GlobalIndex,
global: &super::GlobalComponent,
) -> Result {
let ctx = EvaluationContext::new_global(root, idx, ());
if global.exported {
write!(self.writer, "export ")?;
}
@ -184,7 +189,7 @@ impl<T> Display for DisplayPropertyRef<'_, T> {
let mut ctx = self.1;
match &self.0 {
PropertyReference::Local { sub_component_path, property_index } => {
if let Some(g) = ctx.current_global {
if let Some(g) = ctx.current_global() {
write!(f, "{}.{}", g.name, g.properties[*property_index].name)
} else {
let mut sc = ctx.current_sub_component().unwrap();
@ -215,7 +220,7 @@ impl<T> Display for DisplayPropertyRef<'_, T> {
write!(f, "{}.{}", g.name, g.properties[*property_index].name)
}
PropertyReference::Function { sub_component_path, function_index } => {
if let Some(g) = ctx.current_global {
if let Some(g) = ctx.current_global() {
write!(f, "{}.{}", g.name, g.functions[*function_index].name)
} else {
let mut sc = ctx.current_sub_component().unwrap();