Skip to content

Commit 2848b87

Browse files
committed
fix: to_number and array deps
1 parent c9cd8fa commit 2848b87

File tree

5 files changed

+69
-78
lines changed

5 files changed

+69
-78
lines changed

crates/jsshaker/src/analyzer/operations.rs

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,7 @@ impl<'a> Analyzer<'a> {
129129
let rhs = rhs.to_number();
130130
match (lhs, rhs) {
131131
(None, _) | (_, None) => None,
132-
(Some(None), _) | (_, Some(None)) => Some(false),
133-
(Some(Some(l)), Some(Some(r))) => Some(if eq { l.0 <= r.0 } else { l.0 < r.0 }),
132+
(Some(l), Some(r)) => Some(if eq { l.0 <= r.0 } else { l.0 < r.0 }),
134133
}
135134
}
136135
}
@@ -215,15 +214,10 @@ impl<'a> Analyzer<'a> {
215214
if maybe_number {
216215
// Possibly number
217216
match (lhs_lit.and_then(|v| v.to_number()), rhs_lit.and_then(|v| v.to_number())) {
218-
(Some(l), Some(r)) => match (l, r) {
219-
(Some(l), Some(r)) => {
220-
let val = l.0 + r.0;
221-
values.push(self.factory.number(val));
222-
}
223-
_ => {
224-
values.push(self.factory.nan);
225-
}
226-
},
217+
(Some(l), Some(r)) => {
218+
let val = l.0 + r.0;
219+
values.push(self.factory.number(val));
220+
}
227221
_ => {
228222
values.push(self.factory.unknown_number);
229223
}
@@ -279,21 +273,12 @@ impl<'a> Analyzer<'a> {
279273
}
280274

281275
pub fn op_update(&self, input: Entity<'a>, operator: UpdateOperator) -> Entity<'a> {
282-
let apply_update = |v: f64| {
283-
self.factory.number(match operator {
284-
UpdateOperator::Increment => v + 1.0,
285-
UpdateOperator::Decrement => v - 1.0,
286-
})
287-
};
288-
289276
if let Some(num) = input.get_literal(self).and_then(|lit| lit.to_number()) {
290-
return self.factory.computed(
291-
match num {
292-
Some(num) => apply_update(num.0),
293-
None => self.factory.nan,
294-
},
295-
input,
296-
);
277+
let updated = self.factory.number(match operator {
278+
UpdateOperator::Increment => num.0 + 1.0,
279+
UpdateOperator::Decrement => num.0 - 1.0,
280+
});
281+
return self.factory.computed(updated, input);
297282
}
298283

299284
let input_t = input.test_typeof();

crates/jsshaker/src/nodes/expr/unary_expression.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,7 @@ impl<'a> Analyzer<'a> {
4949
UnaryOperator::UnaryNegation => {
5050
self.factory.computed(
5151
if let Some(num) = argument.get_literal(self).and_then(|lit| lit.to_number()) {
52-
if let Some(num) = num {
53-
let num = -num.0;
54-
self.factory.number(num)
55-
} else {
56-
self.factory.nan
57-
}
52+
self.factory.number(-num.0)
5853
} else {
5954
// Maybe number or bigint
6055
self.factory.unknown_primitive

crates/jsshaker/src/value/array.rs

Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::{
2020
#[derive(Debug)]
2121
pub struct ArrayValue<'a> {
2222
pub included: Cell<bool>,
23+
pub trackable: Cell<bool>,
2324
pub deps: RefCell<DepCollector<'a>>,
2425
pub cf_scope: CfScopeId,
2526
pub elements: RefCell<allocator::Vec<'a, Entity<'a>>>,
@@ -34,6 +35,7 @@ impl<'a> ValueTrait<'a> for ArrayValue<'a> {
3435
fn include(&'a self, analyzer: &mut Analyzer<'a>) {
3536
use_included_flag!(self);
3637

38+
self.trackable.set(false);
3739
self.deps.borrow().include_all(analyzer);
3840
self.elements.borrow().include(analyzer);
3941
self.rest.borrow().include(analyzer);
@@ -55,6 +57,7 @@ impl<'a> ValueTrait<'a> for ArrayValue<'a> {
5557
return escaped::unknown_mutate(analyzer, dep);
5658
}
5759

60+
self.trackable.set(false);
5861
self.deps.borrow_mut().push(analyzer.dep((exec_deps, dep)));
5962
}
6063

@@ -70,11 +73,11 @@ impl<'a> ValueTrait<'a> for ArrayValue<'a> {
7073

7174
analyzer.track_read(self.cf_scope, ReadWriteTarget::Array(self.array_id()), None);
7275

73-
if !self.deps.borrow().is_empty() {
76+
if !self.trackable.get() {
7477
return analyzer.factory.computed_unknown((self, dep, key));
7578
}
7679

77-
let dep = analyzer.dep((dep, key));
80+
let dep = analyzer.dep((dep, key, self.deps(analyzer)));
7881
if let Some(key_literals) = key.get_literals(analyzer) {
7982
let mut result = analyzer.factory.vec();
8083
let mut rest_added = false;
@@ -132,9 +135,9 @@ impl<'a> ValueTrait<'a> for ArrayValue<'a> {
132135
return escaped::set_property(analyzer, dep, key, value);
133136
}
134137

135-
let mut has_effect = false;
138+
let deps = analyzer.dep((exec_deps, key));
136139
'known: {
137-
if !self.deps.borrow().is_empty() {
140+
if !self.trackable.get() {
138141
break 'known;
139142
}
140143

@@ -143,44 +146,47 @@ impl<'a> ValueTrait<'a> for ArrayValue<'a> {
143146
};
144147

145148
let definite = !non_det && key_literals.len() == 1;
149+
let mut has_effect = false;
146150
let mut rest_added = false;
147151
for &key_literal in &key_literals {
148152
match key_literal {
149153
LiteralValue::String(key_str, _) => {
150154
if let Ok(index) = key_str.parse::<usize>() {
151-
has_effect = true;
155+
let value = analyzer.factory.computed(value, deps);
152156
if let Some(element) = self.elements.borrow_mut().get_mut(index) {
153157
*element = if definite { value } else { analyzer.factory.union((*element, value)) };
154158
} else if !rest_added {
155159
rest_added = true;
156160
self.rest.borrow_mut().push(value);
157161
}
158162
} else if key_str == "length" {
159-
if let Some(length) = value.get_literal(analyzer).and_then(|lit| lit.to_number()) {
160-
if let Some(length) = length.map(|l| l.0.trunc()) {
161-
let length = length as usize;
162-
if length > 1024 {
163-
break 'known;
164-
}
163+
if let Some(literal) = value.get_literal(analyzer)
164+
&& let Some(length) = literal.to_number()
165+
{
166+
if length.0.is_nan() || length.0 < 0.0 {
167+
break 'known;
168+
}
169+
let length = length.0.trunc() as usize;
170+
if length > 1024 {
171+
break 'known;
172+
}
165173

166-
let mut elements = self.elements.borrow_mut();
167-
let mut rest = self.rest.borrow_mut();
168-
if elements.len() > length {
169-
has_effect = true;
170-
elements.truncate(length);
171-
rest.clear();
172-
} else if !rest.is_empty() {
173-
has_effect = true;
174-
rest.push(analyzer.factory.undefined);
175-
} else if elements.len() < length {
176-
has_effect = true;
177-
for _ in elements.len()..length {
178-
elements.push(analyzer.factory.undefined);
179-
}
174+
self.deps.borrow_mut().push(analyzer.dep(value));
175+
176+
let mut elements = self.elements.borrow_mut();
177+
let mut rest = self.rest.borrow_mut();
178+
if elements.len() > length {
179+
has_effect = true;
180+
elements.truncate(length);
181+
rest.clear();
182+
} else if !rest.is_empty() {
183+
has_effect = true;
184+
rest.push(analyzer.factory.undefined);
185+
} else if elements.len() < length {
186+
has_effect = true;
187+
for _ in elements.len()..length {
188+
elements.push(analyzer.factory.undefined);
180189
}
181-
} else {
182-
analyzer.throw_builtin_error("Invalid array length");
183-
has_effect = analyzer.config.preserve_exceptions;
184190
}
185191
} else {
186192
has_effect = true;
@@ -194,15 +200,14 @@ impl<'a> ValueTrait<'a> for ArrayValue<'a> {
194200
}
195201
}
196202
if has_effect {
197-
let mut deps = self.deps.borrow_mut();
198-
deps.push(analyzer.dep((exec_deps, key)));
203+
self.deps.borrow_mut().push(deps);
199204
}
200205
return;
201206
}
202207

203208
// Unknown
204-
let mut deps = self.deps.borrow_mut();
205-
deps.push(analyzer.dep((exec_deps, key, value)));
209+
self.deps.borrow_mut().push(analyzer.dep((deps, value)));
210+
self.trackable.set(false);
206211
}
207212

208213
fn enumerate_properties(
@@ -216,7 +221,7 @@ impl<'a> ValueTrait<'a> for ArrayValue<'a> {
216221

217222
analyzer.track_read(self.cf_scope, ReadWriteTarget::Array(self.array_id()), None);
218223

219-
if !self.deps.borrow().is_empty() {
224+
if !self.trackable.get() {
220225
return EnumeratedProperties {
221226
known: Default::default(),
222227
unknown: Some(analyzer.factory.unknown),
@@ -237,11 +242,7 @@ impl<'a> ValueTrait<'a> for ArrayValue<'a> {
237242
analyzer.factory.union(allocator::Vec::from_iter_in(rest.iter().copied(), analyzer.allocator))
238243
});
239244

240-
EnumeratedProperties {
241-
known,
242-
unknown,
243-
dep: analyzer.dep((self.deps.borrow_mut().collect(analyzer.factory), dep)),
244-
}
245+
EnumeratedProperties { known, unknown, dep: analyzer.dep((self.deps(analyzer), dep)) }
245246
}
246247

247248
fn delete_property(&'a self, analyzer: &mut Analyzer<'a>, dep: Dep<'a>, key: Entity<'a>) {
@@ -258,6 +259,7 @@ impl<'a> ValueTrait<'a> for ArrayValue<'a> {
258259

259260
let mut deps = self.deps.borrow_mut();
260261
deps.push(analyzer.dep((exec_deps, key)));
262+
self.trackable.set(false);
261263
}
262264

263265
fn call(
@@ -297,7 +299,7 @@ impl<'a> ValueTrait<'a> for ArrayValue<'a> {
297299

298300
analyzer.track_read(self.cf_scope, ReadWriteTarget::Array(self.array_id()), None);
299301

300-
if !self.deps.borrow().is_empty() {
302+
if !self.trackable.get() {
301303
return (vec![], Some(analyzer.factory.unknown), analyzer.dep((self, dep)));
302304
}
303305

@@ -307,7 +309,7 @@ impl<'a> ValueTrait<'a> for ArrayValue<'a> {
307309
self.rest.borrow().iter().copied(),
308310
analyzer.allocator,
309311
)),
310-
dep,
312+
analyzer.dep((self.deps(analyzer), dep)),
311313
)
312314
}
313315

@@ -398,13 +400,18 @@ impl<'a> ArrayValue<'a> {
398400

399401
(is_exhaustive, non_det, exec_deps)
400402
}
403+
404+
fn deps(&self, analyzer: &Analyzer<'a>) -> Option<Dep<'a>> {
405+
self.deps.borrow_mut().collect(analyzer.factory)
406+
}
401407
}
402408

403409
impl<'a> Analyzer<'a> {
404410
pub fn new_empty_array(&mut self) -> &'a mut ArrayValue<'a> {
405411
let cf_scope = self.scoping.cf.current_id();
406412
self.factory.alloc(ArrayValue {
407413
included: Cell::new(false),
414+
trackable: Cell::new(true),
408415
deps: RefCell::new(DepCollector::new(self.factory.vec())),
409416
cf_scope,
410417
elements: RefCell::new(self.factory.vec()),

crates/jsshaker/src/value/literal/mod.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -367,25 +367,25 @@ impl<'a> LiteralValue<'a> {
367367
}
368368
}
369369

370-
// `None` for unresolvable, `Some(None)` for NaN, `Some(Some(value))` for number
371-
pub fn to_number(self) -> Option<Option<F64WithEq>> {
370+
// `None` for unresolvable
371+
pub fn to_number(self) -> Option<F64WithEq> {
372372
match self {
373-
LiteralValue::Number(value) => Some(Some(value)),
373+
LiteralValue::Number(value) => Some(value),
374374
LiteralValue::BigInt(_value) => {
375375
// TODO: warn: TypeError: Cannot convert a BigInt value to a number
376376
None
377377
}
378-
LiteralValue::Boolean(value) => Some(Some(if value { 1.0 } else { 0.0 }.into())),
378+
LiteralValue::Boolean(value) => Some(if value { 1.0 } else { 0.0 }.into()),
379379
LiteralValue::String(value, _) => {
380380
let val = value.trim().string_to_number();
381-
Some(if val.is_nan() { None } else { Some(val.into()) })
381+
Some(val.into())
382382
}
383-
LiteralValue::Null => Some(Some(0.0.into())),
383+
LiteralValue::Null => Some(0.0.into()),
384384
LiteralValue::Symbol(_, _) => {
385385
// TODO: warn: TypeError: Cannot convert a Symbol value to a number
386386
None
387387
}
388-
LiteralValue::Undefined => Some(None),
388+
LiteralValue::Undefined => Some(f64::NAN.into()),
389389
}
390390
}
391391

tasks/test262/ignored2.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,3 +1023,7 @@ built-ins/Array/prototype/map/create-proto-from-ctor-realm-array.js | 修改了
10231023
built-ins/Array/prototype/splice/create-proto-from-ctor-realm-array.js | 修改了内置对象
10241024
built-ins/Array/prototype/filter/create-proto-from-ctor-realm-array.js | 修改了内置对象
10251025
staging/sm/RegExp/split-trace.js | 修改了内置对象
1026+
built-ins/Array/prototype/toLocaleString/S15.4.4.3_A3_T1.js | 修改了内置对象
1027+
built-ins/Array/prototype/concat/S15.4.4.4_A3_T2.js | 修改了内置对象
1028+
built-ins/Array/prototype/concat/S15.4.4.4_A3_T3.js | 修改了内置对象
1029+
built-ins/Array/S15.4.5.1_A1.2_T2.js | 修改了内置对象

0 commit comments

Comments
 (0)