Repository: rokucommunity/brighterscript
Pull request #474 (2022-01-05 13:09:09)

Null coalescing <uninitialized> fix
Fixes an issue in the transpiled output of the null coalescing operator where plain variable references are not properly passed into the function. 


Patch:
diff --git a/docs/null-coalescing-operator.md b/docs/null-coalescing-operator.md
index 6f4b097c..0759e3da 100644
--- a/docs/null-coalescing-operator.md
+++ b/docs/null-coalescing-operator.md
@@ -55,14 +55,14 @@ user = getUser(userId ?? globalSettings.defaultUserId) ?? getDefaultUser()
 transpiles to:
 ```brightscript
 user = (function(getDefaultUser, getUser, globalSettings, userId)
-        __bsConsequent = getUser((function(globalSettings)
+        __bsConsequent = getUser((function(globalSettings, userId)
                 __bsConsequent = userId
                 if __bsConsequent <> invalid then
                     return __bsConsequent
                 else
                     return globalSettings.defaultUserId
                 end if
-            end function)(globalSettings))
+            end function)(globalSettings, userId))
         if __bsConsequent <> invalid then
             return __bsConsequent
         else
diff --git a/src/util.ts b/src/util.ts
index 8f9d30c4..2c6c07a4 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -1043,9 +1043,7 @@ export class Util {
         const variableExpressions = [] as VariableExpression[];
         const uniqueVarNames = new Set<string>();
 
-        // Collect all expressions. Most of these expressions are fairly small so this should be quick!
-        // This should only be called during transpile time and only when we actually need it.
-        expression?.walk((expression) => {
+        function expressionWalker(expression) {
             if (isExpression(expression)) {
                 expressions.push(expression);
             }
@@ -1053,9 +1051,17 @@ export class Util {
                 variableExpressions.push(expression);
                 uniqueVarNames.add(expression.name.text);
             }
-        }, {
+        }
+
+        // Collect all expressions. Most of these expressions are fairly small so this should be quick!
+        // This should only be called during transpile time and only when we actually need it.
+        expression?.walk(expressionWalker, {
             walkMode: WalkMode.visitExpressions
         });
+
+        //handle the expression itself (for situations when expression is a VariableExpression)
+        expressionWalker(expression);
+
         return { expressions: expressions, varExpressions: variableExpressions, uniqueVarNames: [...uniqueVarNames] };
     }
 


Test patch:
diff --git a/src/parser/tests/expression/NullCoalescenceExpression.spec.ts b/src/parser/tests/expression/NullCoalescenceExpression.spec.ts
index e54b0114..aeb2005f 100644
--- a/src/parser/tests/expression/NullCoalescenceExpression.spec.ts
+++ b/src/parser/tests/expression/NullCoalescenceExpression.spec.ts
@@ -216,16 +216,29 @@ describe('NullCoalescingExpression', () => {
             `);
         });
 
+        it('transpiles null coalesence assignment for variable alternate- complex consequent', () => {
+            testTranspile(`a = obj.link ?? fallback`, `
+                a = (function(fallback, obj)
+                        __bsConsequent = obj.link
+                        if __bsConsequent <> invalid then
+                            return __bsConsequent
+                        else
+                            return fallback
+                        end if
+                    end function)(fallback, obj)
+            `);
+        });
+
         it('properly transpiles null coalesence assignments - complex alternate', () => {
             testTranspile(`a = user ?? m.defaults.getAccount(settings.name)`, `
-                a = (function(m, settings)
+                a = (function(m, settings, user)
                         __bsConsequent = user
                         if __bsConsequent <> invalid then
                             return __bsConsequent
                         else
                             return m.defaults.getAccount(settings.name)
                         end if
-                    end function)(m, settings)
+                    end function)(m, settings, user)
             `);
         });
     });