@@ -360,51 +360,102 @@ class TsExprResolver(
360360
361361 override fun visit (expr : EtsTypeOfExpr ): UExpr <out USort >? = with (ctx) {
362362 val arg = resolve(expr.arg) ? : return null
363-
364363 if (arg.sort == fp64Sort) {
365364 return mkStringConstant(" number" , scope)
366365 }
367366 if (arg.sort == boolSort) {
368367 return mkStringConstant(" boolean" , scope)
369368 }
370369 if (arg.sort == addressSort) {
371- val ref = arg.asExpr(addressSort)
372- return mkIte(
373- condition = mkHeapRefEq(ref, mkTsNullValue()),
374- trueBranch = mkStringConstant(" object" , scope),
375- falseBranch = mkIte(
376- condition = mkHeapRefEq(ref, mkUndefinedValue()),
377- trueBranch = mkStringConstant(" undefined" , scope),
370+ val resolvedArg = arg.asExpr(addressSort)
371+
372+ val processFakeFunction = { ref: UHeapRef ->
373+ check(ref.isFakeObject())
374+
375+ val fakeType = scope.calcOnState { ref.getFakeType(memory) }
376+ mkIte(
377+ fakeType.fpTypeExpr,
378+ mkStringConstant(" number" , scope),
379+ mkIte(
380+ fakeType.boolTypeExpr,
381+ mkStringConstant(" boolean" , scope),
382+ mkIte(
383+ fakeType.refTypeExpr and mkHeapRefEq(ref.extractRef(scope), mkTsNullValue()),
384+ mkStringConstant(" object" , scope),
385+ mkIte(
386+ fakeType.refTypeExpr and mkHeapRefEq(ref.extractRef(scope), mkUndefinedValue()),
387+ mkStringConstant(" undefined" , scope),
388+ mkStringConstant(" object" , scope) // TODO add string, function
389+ )
390+ )
391+ )
392+ )
393+ }
394+
395+ val regularResolve = { ref: UHeapRef ->
396+ mkIte(
397+ condition = mkHeapRefEq(ref, mkTsNullValue()),
398+ trueBranch = mkStringConstant(" object" , scope),
378399 falseBranch = mkIte(
379- condition = scope.calcOnState {
380- val unwrappedRef = ref.unwrapRefWithPathConstraint(scope)
381-
382- // TODO: adhoc: "expand" ITE
383- if (unwrappedRef is UIteExpr <* >) {
384- val trueBranch = unwrappedRef.trueBranch
385- val falseBranch = unwrappedRef.falseBranch
386- if (trueBranch.isFakeObject() || falseBranch.isFakeObject()) {
387- val unwrappedTrueExpr =
388- trueBranch.asExpr(addressSort).unwrapRefWithPathConstraint(scope)
389- val unwrappedFalseExpr =
390- falseBranch.asExpr(addressSort).unwrapRefWithPathConstraint(scope)
391- return @calcOnState mkIte(
392- condition = unwrappedRef.condition,
393- trueBranch = memory.types.evalTypeEquals(unwrappedTrueExpr, EtsStringType ),
394- falseBranch = memory.types.evalTypeEquals(unwrappedFalseExpr, EtsStringType ),
395- )
400+ condition = mkHeapRefEq(ref, mkUndefinedValue()),
401+ trueBranch = mkStringConstant(" undefined" , scope),
402+ falseBranch = mkIte(
403+ condition = scope.calcOnState {
404+ val unwrappedRef = ref.unwrapRef(scope)
405+
406+ // TODO: adhoc: "expand" ITE
407+ // TODO correst support for fake objects, including primitive branches
408+ if (unwrappedRef is UIteExpr <* >) {
409+ val trueBranch = unwrappedRef.trueBranch
410+ val falseBranch = unwrappedRef.falseBranch
411+ if (trueBranch.isFakeObject() || falseBranch.isFakeObject()) {
412+ val unwrappedTrueExpr =
413+ trueBranch.asExpr(addressSort).unwrapRef(scope)
414+ val unwrappedFalseExpr =
415+ falseBranch.asExpr(addressSort).unwrapRef(scope)
416+ return @calcOnState mkIte(
417+ condition = unwrappedRef.condition,
418+ trueBranch = memory.types.evalTypeEquals(unwrappedTrueExpr, EtsStringType ),
419+ falseBranch = memory.types.evalTypeEquals(
420+ unwrappedFalseExpr,
421+ EtsStringType
422+ ),
423+ )
424+ }
396425 }
397- }
398426
399- memory.types.evalTypeEquals(unwrappedRef, EtsStringType )
400- },
401- trueBranch = mkStringConstant(" string" , scope),
402- falseBranch = mkStringConstant(" object" , scope),
427+ memory.types.evalTypeEquals(unwrappedRef, EtsStringType )
428+ },
429+ trueBranch = mkStringConstant(" string" , scope),
430+ falseBranch = mkStringConstant(" object" , scope),
431+ )
403432 )
404433 )
405- )
406- }
407434
435+ }
436+
437+ if (resolvedArg.isFakeObject()) {
438+ return processFakeFunction(resolvedArg)
439+ }
440+
441+ if (resolvedArg is UIteExpr ) {
442+ val trueBranch = if (resolvedArg.trueBranch.isFakeObject()) {
443+ processFakeFunction(resolvedArg.trueBranch)
444+ } else {
445+ regularResolve(resolvedArg.trueBranch)
446+ }
447+
448+ val falseBranch = if (resolvedArg.falseBranch.isFakeObject()) {
449+ processFakeFunction(resolvedArg.falseBranch)
450+ } else {
451+ regularResolve(resolvedArg.falseBranch)
452+ }
453+
454+ return mkIte(resolvedArg.condition, trueBranch, falseBranch)
455+ }
456+
457+ return regularResolve(resolvedArg)
458+ }
408459 logger.error { " visit(${expr::class .simpleName} ) is not implemented yet" }
409460 error(" Not supported $expr " )
410461 }
@@ -419,6 +470,7 @@ class TsExprResolver(
419470 when (val operand = expr.arg) {
420471 is EtsInstanceFieldRef -> {
421472 val instance = resolve(operand.instance)?.asExpr(addressSort) ? : return null
473+ val unwrappedRef = instance.unwrapRefWithPathConstraint(scope)
422474
423475 // Check for null/undefined access
424476 checkUndefinedOrNullPropertyRead(instance) ? : return null
@@ -429,7 +481,8 @@ class TsExprResolver(
429481 // In such case, the "overwriting" the field value with undefined does nothing
430482 // to the actual number/boolean/string value inside the field,
431483 // [if only we read the field using that "other" sort].
432- val fieldLValue = mkFieldLValue(addressSort, instance, operand.field)
484+ // TODO use val resolvedField = resolveEtsField(operand.instance, operand.field, hierarchy) instead
485+ val fieldLValue = mkFieldLValue(addressSort, unwrappedRef, operand.field)
433486 scope.doWithState {
434487 memory.write(fieldLValue, mkUndefinedValue(), guard = trueExpr)
435488 }
@@ -1205,6 +1258,7 @@ class TsExprResolver(
12051258 return expr
12061259 }
12071260
1261+ // TODO condition for unwrapped value
12081262 fun checkUndefinedOrNullPropertyRead (instance : UHeapRef ) = with (ctx) {
12091263 val ref = instance.unwrapRef(scope)
12101264
0 commit comments