Code review comment: In https://github.com/ballerina-platform/ballerina-lang/pull/20679, we added an entry to `expr.narrowedTypeInfo` to redefine any narrowed symbols in subsequent scopes, if the type narrowing for that symbol is reset in the current scope (L2192 - L2194).  Can't we rely on the same here? I think if `ifNode.expr.narrowedTypeInfo` doesn't have an entry for something that has an entry in `this.narrowedTypeInfo`, we could/should probably add it to `ifNode.expr.narrowedTypeInfo`.  Checked with something like ```java if (ifNode.expr.narrowedTypeInfo == null || ifNode.expr.narrowedTypeInfo.isEmpty()) {     ifNode.expr.narrowedTypeInfo = this.narrowedTypeInfo; } else {     Map<BVarSymbol, BType.NarrowedTypes> existingNarrowedTypeInfo = ifNode.expr.narrowedTypeInfo;     for (Map.Entry<BVarSymbol, BType.NarrowedTypes> entry : this.narrowedTypeInfo.entrySet()) {         BVarSymbol key = entry.getKey();         if (!existingNarrowedTypeInfo.containsKey(key)) {             existingNarrowedTypeInfo.put(key, entry.getValue());         }     } } ```  But we need to verify different combinations and make sure we aren't exposing out of scope symbols.

Code under review:
public void visit(BLangIf ifNode) {
        typeChecker.checkExpr(ifNode.expr, env, symTable.booleanType);
        BType actualType = ifNode.expr.getBType();
        if (TypeTags.TUPLE == actualType.tag) {
            dlog.error(ifNode.expr.pos, DiagnosticErrorCode.INCOMPATIBLE_TYPES, symTable.booleanType, actualType);
        }

        Map<BVarSymbol, BType.NarrowedTypes> prevNarrowedTypeInfo = this.narrowedTypeInfo;

        SymbolEnv ifEnv = typeNarrower.evaluateTruth(ifNode.expr, ifNode.body, env);
        typeNarrower.addHigherEnvTypeNarrowedSymbols(ifEnv);

        this.narrowedTypeInfo = new HashMap<>();

        analyzeStmt(ifNode.body, ifEnv);

        if (ifNode.expr.narrowedTypeInfo == null || ifNode.expr.narrowedTypeInfo.isEmpty()) {
            ifNode.expr.narrowedTypeInfo = this.narrowedTypeInfo;
        }

        if (prevNarrowedTypeInfo != null) {
            prevNarrowedTypeInfo.putAll(this.narrowedTypeInfo);
        }

        if (ifNode.elseStmt != null) {
            SymbolEnv elseEnv = typeNarrower.evaluateFalsity(ifNode.expr, ifNode.elseStmt, env);
            typeNarrower.addHigherEnvTypeNarrowedSymbols(elseEnv);
            analyzeStmt(ifNode.elseStmt, elseEnv);
        }
        this.narrowedTypeInfo = prevNarrowedTypeInfo;
    }

Line commented on: typeNarrower.addHigherEnvTypeNarrowedSymbols(ifEnv);

Revised code:
public void visit(BLangIf ifNode) {
        typeChecker.checkExpr(ifNode.expr, env, symTable.booleanType);
        BType actualType = ifNode.expr.getBType();
        if (TypeTags.TUPLE == actualType.tag) {
            dlog.error(ifNode.expr.pos, DiagnosticErrorCode.INCOMPATIBLE_TYPES, symTable.booleanType, actualType);
        }

        Map<BVarSymbol, BType.NarrowedTypes> prevNarrowedTypeInfo = this.narrowedTypeInfo;

        
        
        Map<BVarSymbol, BType.NarrowedTypes> falseTypesOfNarrowedTypes = new HashMap<>();

        SymbolEnv ifEnv = typeNarrower.evaluateTruth(ifNode.expr, ifNode.body, env);

        this.narrowedTypeInfo = new HashMap<>();

        analyzeStmt(ifNode.body, ifEnv);

        if (ifNode.expr.narrowedTypeInfo == null || ifNode.expr.narrowedTypeInfo.isEmpty()) {
            ifNode.expr.narrowedTypeInfo = this.narrowedTypeInfo;
        } else {
            Map<BVarSymbol, BType.NarrowedTypes> existingNarrowedTypeInfo = ifNode.expr.narrowedTypeInfo;
            for (Map.Entry<BVarSymbol, BType.NarrowedTypes> entry : this.narrowedTypeInfo.entrySet()) {
                BVarSymbol key = entry.getKey();
                if (!existingNarrowedTypeInfo.containsKey(key)) {
                    existingNarrowedTypeInfo.put(key, entry.getValue());
                } else {
                    BType.NarrowedTypes existingNarrowTypes = existingNarrowedTypeInfo.get(key);
                    BUnionType unionType =
                            BUnionType.create(null, existingNarrowTypes.trueType, existingNarrowTypes.falseType);
                    BType.NarrowedTypes newPair = new BType.NarrowedTypes(existingNarrowTypes.trueType, unionType);
                    falseTypesOfNarrowedTypes.put(key, newPair);
                }
            }
        }

        if (prevNarrowedTypeInfo != null) {
            prevNarrowedTypeInfo.putAll(this.narrowedTypeInfo);
        }

        if (ifNode.elseStmt != null) {
            SymbolEnv elseEnv = typeNarrower.evaluateFalsity(ifNode.expr, ifNode.elseStmt, env);
            analyzeStmt(ifNode.elseStmt, elseEnv);
        }
        this.narrowedTypeInfo = prevNarrowedTypeInfo;
        if (narrowedTypeInfo != null) {
            narrowedTypeInfo.putAll(falseTypesOfNarrowedTypes);
        }
    }