@@ -61,9 +61,13 @@ impl ValueType {
61
61
/// Evaluate the expression and attempt to determine which ValueType it could resolve to.
62
62
/// This function ignores the cases that throws an error, e.g. `foo * 0` can throw an error when `foo` is a bigint.
63
63
/// To detect those cases, use [`crate::side_effects::MayHaveSideEffects`].
64
- pub trait DetermineValueType : IsGlobalReference {
65
- fn expression_value_type ( & self , expr : & Expression < ' _ > ) -> ValueType {
66
- match expr {
64
+ pub trait DetermineValueType {
65
+ fn value_type ( & self , is_global_reference : & impl IsGlobalReference ) -> ValueType ;
66
+ }
67
+
68
+ impl DetermineValueType for Expression < ' _ > {
69
+ fn value_type ( & self , is_global_reference : & impl IsGlobalReference ) -> ValueType {
70
+ match self {
67
71
Expression :: BigIntLiteral ( _) => ValueType :: BigInt ,
68
72
Expression :: BooleanLiteral ( _) | Expression :: PrivateInExpression ( _) => {
69
73
ValueType :: Boolean
@@ -84,7 +88,7 @@ pub trait DetermineValueType: IsGlobalReference {
84
88
}
85
89
}
86
90
Expression :: Identifier ( ident) => {
87
- if self . is_global_reference ( ident) == Some ( true ) {
91
+ if is_global_reference . is_global_reference ( ident) == Some ( true ) {
88
92
match ident. name . as_str ( ) {
89
93
"undefined" => ValueType :: Undefined ,
90
94
"NaN" | "Infinity" => ValueType :: Number ,
@@ -97,7 +101,7 @@ pub trait DetermineValueType: IsGlobalReference {
97
101
Expression :: UnaryExpression ( unary_expr) => match unary_expr. operator {
98
102
UnaryOperator :: Void => ValueType :: Undefined ,
99
103
UnaryOperator :: UnaryNegation | UnaryOperator :: BitwiseNot => {
100
- let argument_ty = self . expression_value_type ( & unary_expr. argument ) ;
104
+ let argument_ty = unary_expr. argument . value_type ( is_global_reference ) ;
101
105
match argument_ty {
102
106
ValueType :: BigInt => ValueType :: BigInt ,
103
107
// non-object values other than BigInt are converted to number by `ToNumber`
@@ -113,24 +117,26 @@ pub trait DetermineValueType: IsGlobalReference {
113
117
UnaryOperator :: LogicalNot | UnaryOperator :: Delete => ValueType :: Boolean ,
114
118
UnaryOperator :: Typeof => ValueType :: String ,
115
119
} ,
116
- Expression :: BinaryExpression ( e) => self . binary_expression_value_type ( e ) ,
120
+ Expression :: BinaryExpression ( e) => e . value_type ( is_global_reference ) ,
117
121
Expression :: SequenceExpression ( e) => e
118
122
. expressions
119
123
. last ( )
120
- . map_or ( ValueType :: Undetermined , |e| self . expression_value_type ( e ) ) ,
121
- Expression :: AssignmentExpression ( e) => self . assignment_expression_value_type ( e ) ,
122
- Expression :: ConditionalExpression ( e) => self . conditional_expression_value_type ( e ) ,
123
- Expression :: LogicalExpression ( e) => self . logical_expression_value_type ( e ) ,
124
- Expression :: ParenthesizedExpression ( e) => self . expression_value_type ( & e. expression ) ,
124
+ . map_or ( ValueType :: Undetermined , |e| e . value_type ( is_global_reference ) ) ,
125
+ Expression :: AssignmentExpression ( e) => e . value_type ( is_global_reference ) ,
126
+ Expression :: ConditionalExpression ( e) => e . value_type ( is_global_reference ) ,
127
+ Expression :: LogicalExpression ( e) => e . value_type ( is_global_reference ) ,
128
+ Expression :: ParenthesizedExpression ( e) => e. expression . value_type ( is_global_reference ) ,
125
129
_ => ValueType :: Undetermined ,
126
130
}
127
131
}
132
+ }
128
133
129
- fn binary_expression_value_type ( & self , e : & BinaryExpression < ' _ > ) -> ValueType {
130
- match e. operator {
134
+ impl DetermineValueType for BinaryExpression < ' _ > {
135
+ fn value_type ( & self , is_global_reference : & impl IsGlobalReference ) -> ValueType {
136
+ match self . operator {
131
137
BinaryOperator :: Addition => {
132
- let left = self . expression_value_type ( & e . left ) ;
133
- let right = self . expression_value_type ( & e . right ) ;
138
+ let left = self . left . value_type ( is_global_reference ) ;
139
+ let right = self . right . value_type ( is_global_reference ) ;
134
140
if left == ValueType :: Boolean
135
141
&& matches ! ( right, ValueType :: Undefined | ValueType :: Null | ValueType :: Number )
136
142
{
@@ -157,8 +163,8 @@ pub trait DetermineValueType: IsGlobalReference {
157
163
| BinaryOperator :: BitwiseXOR
158
164
| BinaryOperator :: BitwiseAnd
159
165
| BinaryOperator :: Exponential => {
160
- let left = self . expression_value_type ( & e . left ) ;
161
- let right = self . expression_value_type ( & e . right ) ;
166
+ let left = self . left . value_type ( is_global_reference ) ;
167
+ let right = self . right . value_type ( is_global_reference ) ;
162
168
if left. is_bigint ( ) || right. is_bigint ( ) {
163
169
ValueType :: BigInt
164
170
} else if !( left. is_object ( ) || left. is_undetermined ( ) )
@@ -180,17 +186,19 @@ pub trait DetermineValueType: IsGlobalReference {
180
186
| BinaryOperator :: StrictEquality
181
187
| BinaryOperator :: StrictInequality
182
188
| BinaryOperator :: LessThan
183
- | BinaryOperator :: LessEqualThan
184
189
| BinaryOperator :: GreaterThan
190
+ | BinaryOperator :: LessEqualThan
185
191
| BinaryOperator :: GreaterEqualThan => ValueType :: Boolean ,
186
192
}
187
193
}
194
+ }
188
195
189
- fn assignment_expression_value_type ( & self , e : & AssignmentExpression < ' _ > ) -> ValueType {
190
- match e. operator {
191
- AssignmentOperator :: Assign => self . expression_value_type ( & e. right ) ,
196
+ impl DetermineValueType for AssignmentExpression < ' _ > {
197
+ fn value_type ( & self , is_global_reference : & impl IsGlobalReference ) -> ValueType {
198
+ match self . operator {
199
+ AssignmentOperator :: Assign => self . right . value_type ( is_global_reference) ,
192
200
AssignmentOperator :: Addition => {
193
- let right = self . expression_value_type ( & e . right ) ;
201
+ let right = self . right . value_type ( is_global_reference ) ;
194
202
if right. is_string ( ) {
195
203
ValueType :: String
196
204
} else {
@@ -207,7 +215,7 @@ pub trait DetermineValueType: IsGlobalReference {
207
215
| AssignmentOperator :: BitwiseXOR
208
216
| AssignmentOperator :: BitwiseAnd
209
217
| AssignmentOperator :: Exponential => {
210
- let right = self . expression_value_type ( & e . right ) ;
218
+ let right = self . right . value_type ( is_global_reference ) ;
211
219
if right. is_bigint ( ) {
212
220
ValueType :: BigInt
213
221
} else if !( right. is_object ( ) || right. is_undetermined ( ) ) {
@@ -222,25 +230,29 @@ pub trait DetermineValueType: IsGlobalReference {
222
230
| AssignmentOperator :: LogicalNullish => ValueType :: Undetermined ,
223
231
}
224
232
}
233
+ }
225
234
226
- fn conditional_expression_value_type ( & self , e : & ConditionalExpression < ' _ > ) -> ValueType {
227
- let left = self . expression_value_type ( & e. consequent ) ;
235
+ impl DetermineValueType for ConditionalExpression < ' _ > {
236
+ fn value_type ( & self , is_global_reference : & impl IsGlobalReference ) -> ValueType {
237
+ let left = self . consequent . value_type ( is_global_reference) ;
228
238
if left. is_undetermined ( ) {
229
239
return ValueType :: Undetermined ;
230
240
}
231
- let right = self . expression_value_type ( & e . alternate ) ;
241
+ let right = self . alternate . value_type ( is_global_reference ) ;
232
242
if left == right {
233
243
return left;
234
244
}
235
245
ValueType :: Undetermined
236
246
}
247
+ }
237
248
238
- fn logical_expression_value_type ( & self , e : & LogicalExpression < ' _ > ) -> ValueType {
239
- let left = self . expression_value_type ( & e. left ) ;
249
+ impl DetermineValueType for LogicalExpression < ' _ > {
250
+ fn value_type ( & self , is_global_reference : & impl IsGlobalReference ) -> ValueType {
251
+ let left = self . left . value_type ( is_global_reference) ;
240
252
if !left. is_boolean ( ) {
241
253
return ValueType :: Undetermined ;
242
254
}
243
- let right = self . expression_value_type ( & e . right ) ;
255
+ let right = self . right . value_type ( is_global_reference ) ;
244
256
if left == right {
245
257
return left;
246
258
}
0 commit comments