Skip to content

Commit 3552e00

Browse files
committed
Fix wrong value or panic in the interpreter when converting struct of struct
The "tmpobj" variable was overwriten because the interpreter (contrary to rust and C++) don't have scopes for the local variables, and local variable of the same name would conflict. (I think this could in theory be a problem in C++ and rust although i haven't reproduced it) Other uses of StoreLocalVariable also make the number unique with a counter Fixes #6721
1 parent 14adc2a commit 3552e00

File tree

3 files changed

+91
-10
lines changed

3 files changed

+91
-10
lines changed

internal/compiler/expression_tree.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::lookup::LookupCtx;
88
use crate::object_tree::*;
99
use crate::parser::{NodeOrToken, SyntaxNode};
1010
use core::cell::RefCell;
11-
use smol_str::SmolStr;
11+
use smol_str::{format_smolstr, SmolStr};
1212
use std::cell::Cell;
1313
use std::collections::HashMap;
1414
use std::rc::{Rc, Weak};
@@ -1119,13 +1119,18 @@ impl Expression {
11191119
}
11201120
return Expression::Struct { values: new_values, ty: target_type };
11211121
}
1122-
let var_name = "tmpobj";
1122+
static COUNT: std::sync::atomic::AtomicUsize =
1123+
std::sync::atomic::AtomicUsize::new(0);
1124+
let var_name = format_smolstr!(
1125+
"tmpobj_conv_{}",
1126+
COUNT.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
1127+
);
11231128
let mut new_values = HashMap::new();
11241129
for (key, ty) in &right.fields {
11251130
let expression = if left.fields.contains_key(key) {
11261131
Expression::StructFieldAccess {
11271132
base: Box::new(Expression::ReadLocalVariable {
1128-
name: var_name.into(),
1133+
name: var_name.clone(),
11291134
ty: from_ty.clone(),
11301135
}),
11311136
name: key.clone(),
@@ -1137,10 +1142,7 @@ impl Expression {
11371142
new_values.insert(key.clone(), expression);
11381143
}
11391144
return Expression::CodeBlock(vec![
1140-
Expression::StoreLocalVariable {
1141-
name: var_name.into(),
1142-
value: Box::new(self),
1143-
},
1145+
Expression::StoreLocalVariable { name: var_name, value: Box::new(self) },
11441146
Expression::Struct { values: new_values, ty: target_type },
11451147
]);
11461148
}

internal/compiler/passes/remove_return.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,11 @@ fn convert_struct(from: Expression, to: Type) -> Expression {
460460
}
461461
return Expression::Struct { values: new_values, ty: to };
462462
}
463-
let var_name = "tmpobj";
463+
static COUNT: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
464+
let var_name = format_smolstr!(
465+
"tmpobj_ret_conv_{}",
466+
COUNT.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
467+
);
464468
let from_ty = from.ty();
465469
let mut new_values = HashMap::new();
466470
let Type::Struct(from_s) = &from_ty else {
@@ -471,7 +475,7 @@ fn convert_struct(from: Expression, to: Type) -> Expression {
471475
let expression = if from_s.fields.contains_key(key) {
472476
Expression::StructFieldAccess {
473477
base: Box::new(Expression::ReadLocalVariable {
474-
name: var_name.into(),
478+
name: var_name.clone(),
475479
ty: from_ty.clone(),
476480
}),
477481
name: key.clone(),
@@ -482,7 +486,7 @@ fn convert_struct(from: Expression, to: Type) -> Expression {
482486
new_values.insert(key.clone(), expression);
483487
}
484488
Expression::CodeBlock(vec![
485-
Expression::StoreLocalVariable { name: var_name.into(), value: Box::new(from) },
489+
Expression::StoreLocalVariable { name: var_name, value: Box::new(from) },
486490
Expression::Struct { values: new_values, ty: to },
487491
])
488492
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright © SixtyFPS GmbH <[email protected]>
2+
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3+
4+
5+
export struct SA {
6+
is-set: bool,
7+
zoom-range: float,
8+
}
9+
export struct SB {
10+
is-set: bool,
11+
}
12+
13+
export struct Model {
14+
fov: SA,
15+
tilt-speed: SB,
16+
}
17+
18+
19+
export struct EvenMoreComplex {
20+
m1: Model,
21+
m2: Model,
22+
xx: bool,
23+
}
24+
25+
export component TestCase inherits Window{
26+
27+
preferred-width: 600px;
28+
preferred-height: 320px;
29+
30+
in-out property <Model> local: {
31+
{
32+
fov: {
33+
is-set: false,
34+
},
35+
tilt-speed: {
36+
is-set: true,
37+
},
38+
}
39+
};
40+
41+
in-out property <EvenMoreComplex> p2: {
42+
{
43+
m1: { fov: { zoom-range: 5 }, tilt-speed: { is-set: true } },
44+
m2: { tilt-speed: local.tilt-speed, fov: { is-set: local.fov.is-set } },
45+
}
46+
}
47+
48+
init => {
49+
debug(p2);
50+
local.fov = { is-set: true }
51+
}
52+
out property <bool> test: p2.m2.fov.is-set && p2.m1.fov.zoom-range == 5 && !p2.m1.fov.is-set;
53+
}
54+
55+
56+
/*
57+
```cpp
58+
auto handle = TestCase::create();
59+
const TestCase &instance = *handle;
60+
assert(instance.get_test());
61+
```
62+
63+
```rust
64+
let instance = TestCase::new().unwrap();
65+
assert!(instance.get_test());
66+
```
67+
68+
```js
69+
var instance = new slint.TestCase({});
70+
assert(instance.test);
71+
```
72+
*/
73+
74+
75+

0 commit comments

Comments
 (0)