modules/ballerina-core/src/main/java/org/ballerinalang/util/semantics/SemanticAnalyzer.java
private BLangSymbol findBestMatchForFunctionSymbol(FunctionInvocationExpr funcIExpr,
                                                       FunctionSymbolName symbolName) {
        BLangSymbol functionSymbol = null;
        BLangSymbol pkgSymbol = null;
        if (symbolName.getPkgPath() == null) {
            pkgSymbol = (BLangPackage) getCurrentPackageScope(currentScope);
        } else {
            SymbolName pkgSymbolName = new SymbolName(symbolName.getPkgPath());
            pkgSymbol = currentScope.resolve(pkgSymbolName);
        }
        //pkgSymbol should be a instance of SymbolScope, hence doesn't do the check here
        if (pkgSymbol == null) {
            return null;
        }
        Expression[] argExprs = funcIExpr.getArgExprs();
        Expression[] updatedArgExprs = new Expression[argExprs.length];
        for (Map.Entry entry : ((SymbolScope) pkgSymbol).getSymbolMap().entrySet()) {
            if (!(entry.getKey() instanceof FunctionSymbolName)) {
                continue;
            }
            FunctionSymbolName funcSymName = (FunctionSymbolName) entry.getKey();
            if (!funcSymName.isNameAndParamCountMatch(symbolName)) {
                continue;
            }

            boolean implicitCastPossible = true;

            for (int i = 0; i < argExprs.length; i++) {
                Expression argExpr = argExprs[i];
                updatedArgExprs[i] = argExpr;
                BType lhsType;
                if (entry.getValue() instanceof NativeUnitProxy) {
                    NativeUnit nativeUnit = ((NativeUnitProxy) entry.getValue()).load();
                    SimpleTypeName simpleTypeName = nativeUnit.getArgumentTypeNames()[i];
                    lhsType = BTypes.resolveType(simpleTypeName, currentScope, funcIExpr.getNodeLocation());
                } else {
                    if (!(entry.getValue() instanceof Function)) {
                        continue;
                    }
                    lhsType = ((Function) entry.getValue()).getParameterDefs()[i].getType();
                }

                BType rhsType = argExpr.getType();
                
                // if the passed value is null, and the function parameter is a reference type,
                // then its a match
                if (rhsType instanceof BNullType && !BTypes.isValueType(lhsType)) {
                    continue;
                }
                
                if (rhsType != null && lhsType.equals(rhsType)) {
                    continue;
                }
                if (lhsType == BTypes.typeAny) { //if left hand side is any, then no need for casting
                    continue;
                }
                TypeCastExpression newExpr = checkWideningPossible(lhsType, argExpr);
                if (newExpr != null) {
                    updatedArgExprs[i] = newExpr;
                } else {
                    implicitCastPossible = false;
                    break;
                }
            }
            if (implicitCastPossible) {
                if (functionSymbol == null) {
                    functionSymbol = (BLangSymbol) entry.getValue();
                } else {
                    /**
                     * This way second ambiguous function will cause this method to throw semantic error, so in a
                     * scenario where there are more than two ambiguous functions, then this will show only the
                     * first two.
                     */
                    String ambiguousFunc1 = generateErrorMessage(funcIExpr, functionSymbol, symbolName.getPkgPath());
                    String ambiguousFunc2 = generateErrorMessage(funcIExpr, (BLangSymbol) entry.getValue(),
                                                                 symbolName.getPkgPath());
                    BLangExceptionHelper.throwSemanticError(funcIExpr, SemanticErrors.AMBIGUOUS_FUNCTIONS,
                                                            funcSymName.getFuncName(), ambiguousFunc1, ambiguousFunc2);
                    break;
                }
            }
        }
        
        for (int i = 0; i < updatedArgExprs.length; i++) {
            funcIExpr.getArgExprs()[i] = updatedArgExprs[i];
        }
        return functionSymbol;
    }
/**
     * Helper method to find the best function match when there is no direct match.
     *
     * @param symbolName
     * @return bLangSymbol
     */
Helper method to find the best function match when there is no direct match.
@param symbolName
@return bLangSymbol
Helper method to find the best function match when there is no direct match . @param symbolName @return bLangSymbol
private BLangSymbol findBestMatchForFunctionSymbol(FunctionInvocationExpr funcIExpr,
                                                       FunctionSymbolName symbolName) {
        BLangSymbol functionSymbol = null;
        BLangSymbol pkgSymbol = null;
        if (symbolName.getPkgPath() == null) {
            pkgSymbol = (BLangPackage) getCurrentPackageScope(currentScope);
        } else {
            SymbolName pkgSymbolName = new SymbolName(symbolName.getPkgPath());
            pkgSymbol = currentScope.resolve(pkgSymbolName);
        }
        if (pkgSymbol == null) {
            return null;
        }
        Expression[] argExprs = funcIExpr.getArgExprs();
        Expression[] updatedArgExprs = new Expression[argExprs.length];
        for (Map.Entry entry : ((SymbolScope) pkgSymbol).getSymbolMap().entrySet()) {
            if (!(entry.getKey() instanceof FunctionSymbolName)) {
                continue;
            }
            FunctionSymbolName funcSymName = (FunctionSymbolName) entry.getKey();
            if (!funcSymName.isNameAndParamCountMatch(symbolName)) {
                continue;
            }
            boolean implicitCastPossible = true;
            for (int i = 0; i < argExprs.length; i++) {
                Expression argExpr = argExprs[i];
                updatedArgExprs[i] = argExpr;
                BType lhsType;
                if (entry.getValue() instanceof NativeUnitProxy) {
                    NativeUnit nativeUnit = ((NativeUnitProxy) entry.getValue()).load();
                    SimpleTypeName simpleTypeName = nativeUnit.getArgumentTypeNames()[i];
                    lhsType = BTypes.resolveType(simpleTypeName, currentScope, funcIExpr.getNodeLocation());
                } else {
                    if (!(entry.getValue() instanceof Function)) {
                        continue;
                    }
                    lhsType = ((Function) entry.getValue()).getParameterDefs()[i].getType();
                }
                BType rhsType = argExpr.getType();
                if (rhsType instanceof BNullType && !BTypes.isValueType(lhsType)) {
                    continue;
                }
                if (rhsType != null && lhsType.equals(rhsType)) {
                    continue;
                }
                if (lhsType == BTypes.typeAny) { 
                    continue;
                }
                TypeCastExpression newExpr = checkWideningPossible(lhsType, argExpr);
                if (newExpr != null) {
                    updatedArgExprs[i] = newExpr;
                } else {
                    implicitCastPossible = false;
                    break;
                }
            }
            if (implicitCastPossible) {
                if (functionSymbol == null) {
                    functionSymbol = (BLangSymbol) entry.getValue();
                } else {
                    /**
                     * This way second ambiguous function will cause this method to throw semantic error, so in a
                     * scenario where there are more than two ambiguous functions, then this will show only the
                     * first two.
                     */
                    String ambiguousFunc1 = generateErrorMessage(funcIExpr, functionSymbol, symbolName.getPkgPath());
                    String ambiguousFunc2 = generateErrorMessage(funcIExpr, (BLangSymbol) entry.getValue(),
                                                                 symbolName.getPkgPath());
                    BLangExceptionHelper.throwSemanticError(funcIExpr, SemanticErrors.AMBIGUOUS_FUNCTIONS,
                                                            funcSymName.getFuncName(), ambiguousFunc1, ambiguousFunc2);
                    break;
                }
            }
        }
        for (int i = 0; i < updatedArgExprs.length; i++) {
            funcIExpr.getArgExprs()[i] = updatedArgExprs[i];
        }
        return functionSymbol;
    }
private BLangSymbol findBestMatchForFunctionSymbol ( FunctionInvocationExpr funcIExpr , FunctionSymbolName symbolName ) { BLangSymbol functionSymbol = null ; BLangSymbol pkgSymbol = null ; if ( symbolName . getPkgPath ( ) == null ) { pkgSymbol = ( BLangPackage ) getCurrentPackageScope ( currentScope ) ; } else { SymbolName pkgSymbolName = new SymbolName ( symbolName . getPkgPath ( ) ) ; pkgSymbol = currentScope . resolve ( pkgSymbolName ) ; } if ( pkgSymbol == null ) { return null ; } Expression [ ] argExprs = funcIExpr . getArgExprs ( ) ; Expression [ ] updatedArgExprs = new Expression [ argExprs . length ] ; for ( Map . Entry entry : ( ( SymbolScope ) pkgSymbol ) . getSymbolMap ( ) . entrySet ( ) ) { if ( ! ( entry . getKey ( ) instanceof FunctionSymbolName ) ) { continue ; } FunctionSymbolName funcSymName = ( FunctionSymbolName ) entry . getKey ( ) ; if ( ! funcSymName . isNameAndParamCountMatch ( symbolName ) ) { continue ; } boolean implicitCastPossible = true ; for ( int i = 0 ; i < argExprs . length ; i ++ ) { Expression argExpr = argExprs [ i ] ; updatedArgExprs [ i ] = argExpr ; BType lhsType ; if ( entry . getValue ( ) instanceof NativeUnitProxy ) { NativeUnit nativeUnit = ( ( NativeUnitProxy ) entry . getValue ( ) ) . load ( ) ; SimpleTypeName simpleTypeName = nativeUnit . getArgumentTypeNames ( ) [ i ] ; lhsType = BTypes . resolveType ( simpleTypeName , currentScope , funcIExpr . getNodeLocation ( ) ) ; } else { if ( ! ( entry . getValue ( ) instanceof Function ) ) { continue ; } lhsType = ( ( Function ) entry . getValue ( ) ) . getParameterDefs ( ) [ i ] . getType ( ) ; } BType rhsType = argExpr . getType ( ) ; if ( rhsType instanceof BNullType && ! BTypes . isValueType ( lhsType ) ) { continue ; } if ( rhsType != null && lhsType . equals ( rhsType ) ) { continue ; } if ( lhsType == BTypes . typeAny ) { continue ; } TypeCastExpression newExpr = checkWideningPossible ( lhsType , argExpr ) ; if ( newExpr != null ) { updatedArgExprs [ i ] = newExpr ; } else { implicitCastPossible = false ; break ; } } if ( implicitCastPossible ) { if ( functionSymbol == null ) { functionSymbol = ( BLangSymbol ) entry . getValue ( ) ; } else { /**
                     * This way second ambiguous function will cause this method to throw semantic error, so in a
                     * scenario where there are more than two ambiguous functions, then this will show only the
                     * first two.
                     */ String ambiguousFunc1 = generateErrorMessage ( funcIExpr , functionSymbol , symbolName . getPkgPath ( ) ) ; String ambiguousFunc2 = generateErrorMessage ( funcIExpr , ( BLangSymbol ) entry . getValue ( ) , symbolName . getPkgPath ( ) ) ; BLangExceptionHelper . throwSemanticError ( funcIExpr , SemanticErrors . AMBIGUOUS_FUNCTIONS , funcSymName . getFuncName ( ) , ambiguousFunc1 , ambiguousFunc2 ) ; break ; } } } for ( int i = 0 ; i < updatedArgExprs . length ; i ++ ) { funcIExpr . getArgExprs ( ) [ i ] = updatedArgExprs [ i ] ; } return functionSymbol ; }
Helper method to find the best function match when there is no direct match.
Helper method to find the best function match when there is no direct match .
//pkgSymbol should be a instance of SymbolScope, hence doesn't do the check here // if the passed value is null, and the function parameter is a reference type, // then its a match //if left hand side is any, then no need for casting