Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
SasinduDilshara committed Aug 18, 2022
2 parents 6e28d27 + 2d730a6 commit ae2be1b
Show file tree
Hide file tree
Showing 16 changed files with 799 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#the following will interpreted as: invalid type 'typName'
invalid.type = invalid type ''{0}''
incompatible.types = incompatible types: expected ''{0}'', found ''{1}''
incompatible.arguments = arguments of incompatible types: expected argument(s) of types ''{0}'', found ''{1}''
incompatible.arguments = arguments of incompatible types: argument list ''{0}'' cannot be passed to function expecting parameter list ''{1}''
redeclared.symbol = redeclared symbol ''{0}''
incompatible.types.cannot.convert = incompatible types: ''{0}'' cannot be converted to ''{1}''
cannot.convert.with.suggestion = incompatible types: ''{0}'' cannot be converted to ''{1}'', try casting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1619,9 +1619,10 @@ public BType readType(int cpI) throws IOException {
ignoreAttachedFunc();
}
int funcCount = inputStream.readInt();
boolean isImmutable = isImmutable(objectSymbol.flags);
for (int i = 0; i < funcCount; i++) {
//populate intersection type object functions
if (isImmutable(objectSymbol.flags) && Symbols.isFlagOn(flags, Flags.ANONYMOUS)) {
if (isImmutable) {
populateIntersectionTypeReferencedFunctions(inputStream, objectSymbol);
} else {
ignoreAttachedFunc();
Expand Down Expand Up @@ -1752,33 +1753,30 @@ private void populateIntersectionTypeReferencedFunctions(DataInputStream inputSt
String attachedFuncName = getStringCPEntryValue(inputStream);
String attachedFuncOrigName = getStringCPEntryValue(inputStream);
var attachedFuncFlags = inputStream.readLong();
if (Symbols.isFlagOn(attachedFuncFlags, Flags.INTERFACE) &&
Symbols.isFlagOn(attachedFuncFlags, Flags.ATTACHED)) {
BInvokableType attachedFuncType = (BInvokableType) readTypeFromCp();
Name funcName = names.fromString(Symbols.getAttachedFuncSymbolName(
objectSymbol.name.value, attachedFuncName));
Name funcOrigName = names.fromString(attachedFuncOrigName);
BInvokableSymbol attachedFuncSymbol =
Symbols.createFunctionSymbol(attachedFuncFlags, funcName, funcOrigName,
env.pkgSymbol.pkgID, attachedFuncType,
env.pkgSymbol, false, symTable.builtinPos,
COMPILED_SOURCE);
BAttachedFunction attachedFunction = new BAttachedFunction(names.fromString(attachedFuncName),
attachedFuncSymbol, attachedFuncType, symTable.builtinPos);

setInvokableTypeSymbol(attachedFuncType);

if (!Symbols.isFlagOn(attachedFuncType.flags, Flags.ANY_FUNCTION)) {
BInvokableTypeSymbol tsymbol = (BInvokableTypeSymbol) attachedFuncType.tsymbol;
attachedFuncSymbol.params = tsymbol.params;
attachedFuncSymbol.restParam = tsymbol.restParam;
attachedFuncSymbol.retType = tsymbol.returnType;
}

objectSymbol.referencedFunctions.add(attachedFunction);
objectSymbol.attachedFuncs.add(attachedFunction);
objectSymbol.scope.define(funcName, attachedFuncSymbol);
BInvokableType attachedFuncType = (BInvokableType) readTypeFromCp();
Name funcName = Names.fromString(Symbols.getAttachedFuncSymbolName(
objectSymbol.name.value, attachedFuncName));
Name funcOrigName = Names.fromString(attachedFuncOrigName);
BInvokableSymbol attachedFuncSymbol =
Symbols.createFunctionSymbol(attachedFuncFlags, funcName, funcOrigName,
env.pkgSymbol.pkgID, attachedFuncType,
env.pkgSymbol, false, symTable.builtinPos,
COMPILED_SOURCE);
BAttachedFunction attachedFunction = new BAttachedFunction(Names.fromString(attachedFuncName),
attachedFuncSymbol, attachedFuncType, symTable.builtinPos);

setInvokableTypeSymbol(attachedFuncType);

if (!Symbols.isFlagOn(attachedFuncType.flags, Flags.ANY_FUNCTION)) {
BInvokableTypeSymbol tsymbol = (BInvokableTypeSymbol) attachedFuncType.tsymbol;
attachedFuncSymbol.params = tsymbol.params;
attachedFuncSymbol.restParam = tsymbol.restParam;
attachedFuncSymbol.retType = tsymbol.returnType;
}

objectSymbol.referencedFunctions.add(attachedFunction);
objectSymbol.attachedFuncs.add(attachedFunction);
objectSymbol.scope.define(funcName, attachedFuncSymbol);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2110,7 +2110,7 @@ private BLangInvokableNode getWorkerEnclosedFunctionInvokable() {
SymbolEnv env = this.env;
while (env != null) {
BLangNode node = env.node;
if (node != null && node.getKind() == NodeKind.FUNCTION &&
if (node != null && (node.getKind() == NodeKind.FUNCTION || node.getKind() == NodeKind.RESOURCE_FUNC) &&
!isWorkerLambda((BLangFunction) node)) {
return env.enclInvokable;
}
Expand Down Expand Up @@ -3213,7 +3213,7 @@ private boolean isEnclosedLockWithinSameFunction(BLangNode parent, BLangLock pot
return true;
}

if (parent == null || parent.getKind() == NodeKind.FUNCTION) {
if (parent == null || parent.getKind() == NodeKind.FUNCTION || parent.getKind() == NodeKind.RESOURCE_FUNC) {
return false;
}

Expand Down Expand Up @@ -3292,8 +3292,10 @@ private void markDependsOnIsolationNonInferableConstructs() {
enclInvokableSymbol = this.arrowFunctionTempSymbolMap.get((BLangArrowFunction) env.enclEnv.node);
} else {
enclInvokableSymbol = enclInvokable.symbol;
NodeKind enclInvokableKind = enclInvokable.getKind();

if (enclInvokable.getKind() == NodeKind.FUNCTION && ((BLangFunction) enclInvokable).attachedFunction) {
if (enclInvokableKind == NodeKind.RESOURCE_FUNC || (enclInvokableKind == NodeKind.FUNCTION &&
((BLangFunction) enclInvokable).attachedFunction)) {
BSymbol owner = enclInvokableSymbol.owner;

if (this.isolationInferenceInfoMap.containsKey(owner)) {
Expand Down
2 changes: 1 addition & 1 deletion docs/language-server/WritingExtendedServices.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ public class CustomServiceClientCapabilitySetter
```

__Note:__
> It is important to note that the `nameOfService` which has been used in four places above, should be the same string value since the particular string value is used to correlate the capabilites with the services.
> It is important to note that the `nameOfService` which has been used in four places above, should be the same string value since the particular string value is used to correlate the capabilities with the services.
<a name="Checklist"></a>
# Developer Checklist
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ public static Object call(BFunctionPointer<Object, Object> func, Object... args)
throw ErrorCreator.createError(
getModulePrefixedReason(FUNCTION_LANG_LIB, INCOMPATIBLE_ARGUMENTS),
BLangExceptionHelper.getErrorDetails(RuntimeErrors.INCOMPATIBLE_ARGUMENTS,
new BTupleType(paramTypes, restType, 0, false), new BTupleType(argTypes)));
removeBracketsFromStringFormatOfTuple(new BTupleType(argTypes)),
removeBracketsFromStringFormatOfTuple(new BTupleType(paramTypes, restType, 0, false))));
}

return func.asyncCall(argsList.toArray(), METADATA);
Expand Down Expand Up @@ -130,4 +131,9 @@ private static boolean checkIsValidRestArgs(Object[] args, List<Object> argsList
}
return errored;
}

private static String removeBracketsFromStringFormatOfTuple(BTupleType tupleType) {
String stringValue = tupleType.toString();
return "(" + stringValue.substring(1, stringValue.length() - 1) + ")";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ function testCallFunctionWithRequiredParameters() {
assertEquality(function:call(value1, 20, 20, 10), 50);
assertEquality(function:call(value1, 10, 10), 35);
assertEquality(function:call(value2, 10, 20, 30), 60);
assertEquality(function:call(test21), 10);
}

function value3(int a = 10, int b = 15, int c = 20) returns int {
Expand All @@ -64,6 +65,10 @@ function testCallFunctionWithDefaultParameters() {
assertEquality(function:call(value3, a, b), 45);
assertEquality(function:call(value3, 10, 10, 10), 30);
assertEquality(function:call(value3, a, b, c), 55);
assertEquality(function:call(test22), 10);
assertEquality(function:call(test22, 15), 15);
assertEquality(function:call(test23), 25);
assertEquality(function:call(test23, 15), 30);
}

function value4(int a, int b, int... c) returns int {
Expand Down Expand Up @@ -177,6 +182,22 @@ function func3() returns function(string a, string b) returns string {
};
}

function test20(string... details) returns string {
return details[0];
}

function test21() returns int {
return 10;
}

function test22(int k = 10) returns int {
return k;
}

function test23(int k = 10, int l = 15) returns int {
return k + l;
}

function testCallFunctionWithFunctionPointers() {
assertEquality(test16(), 3);
assertEquality(test17(), "sum is 3");
Expand All @@ -188,22 +209,32 @@ function testCallFunctionWithInvalidArguments() {
any|error a1 = trap function:call(value1, 10);
assertEquality(true, a1 is error);
assertEquality("{ballerina/lang.function}IncompatibleArguments", (<error> a1).message());
assertEquality("arguments of incompatible types: expected argument(s) of types '[int,int,int]', found '[int]'", (<error> a1).detail()["message"]);
assertEquality("arguments of incompatible types: argument list '(int)' cannot be passed to function expecting parameter list '(int,int,int)'", (<error> a1).detail()["message"]);

a1 = trap function:call(value1);
assertEquality(true, a1 is error);
assertEquality("{ballerina/lang.function}IncompatibleArguments", (<error> a1).message());
assertEquality("arguments of incompatible types: argument list '()' cannot be passed to function expecting parameter list '(int,int,int)'", (<error> a1).detail()["message"]);

a1 = trap function:call(value1, 10, "10");
assertEquality(true, a1 is error);
assertEquality("{ballerina/lang.function}IncompatibleArguments", (<error> a1).message());
assertEquality("arguments of incompatible types: expected argument(s) of types '[int,int,int]', found '[int,string]'", (<error> a1).detail()["message"]);
assertEquality("arguments of incompatible types: argument list '(int,string)' cannot be passed to function expecting parameter list '(int,int,int)'", (<error> a1).detail()["message"]);

a1 = trap function:call(value2, 10, 10, 10, 10);
assertEquality(true, a1 is error);
assertEquality("{ballerina/lang.function}IncompatibleArguments", (<error> a1).message());
assertEquality("arguments of incompatible types: expected argument(s) of types '[int,int,int]', found '[int,int,int,int]'", (<error> a1).detail()["message"]);
assertEquality("arguments of incompatible types: argument list '(int,int,int,int)' cannot be passed to function expecting parameter list '(int,int,int)'", (<error> a1).detail()["message"]);

a1 = trap function:call(value2, 10, 10);
assertEquality(true, a1 is error);
assertEquality("{ballerina/lang.function}IncompatibleArguments", (<error> a1).message());
assertEquality("arguments of incompatible types: expected argument(s) of types '[int,int,int]', found '[int,int]'", (<error> a1).detail()["message"]);
assertEquality("arguments of incompatible types: argument list '(int,int)' cannot be passed to function expecting parameter list '(int,int,int)'", (<error> a1).detail()["message"]);

a1 = trap function:call(value2);
assertEquality(true, a1 is error);
assertEquality("{ballerina/lang.function}IncompatibleArguments", (<error> a1).message());
assertEquality("arguments of incompatible types: argument list '()' cannot be passed to function expecting parameter list '(int,int,int)'", (<error> a1).detail()["message"]);

a1 = trap function:call(value4, 10, 10);
assertEquality(true, a1 is error);
Expand All @@ -228,28 +259,48 @@ function testCallFunctionWithInvalidArguments() {
a1 = trap function:call(value8, "");
assertEquality(true, a1 is error);
assertEquality("{ballerina/lang.function}IncompatibleArguments", (<error> a1).message());
assertEquality("arguments of incompatible types: expected argument(s) of types '[int...]', found '[string]'", (<error> a1).detail()["message"]);
assertEquality("arguments of incompatible types: argument list '(string)' cannot be passed to function expecting parameter list '(int...)'", (<error> a1).detail()["message"]);

a1 = trap function:call(value8, "", "");
assertEquality(true, a1 is error);
assertEquality("{ballerina/lang.function}IncompatibleArguments", (<error> a1).message());
assertEquality("arguments of incompatible types: expected argument(s) of types '[int...]', found '[string,string]'", (<error> a1).detail()["message"]);
assertEquality("arguments of incompatible types: argument list '(string,string)' cannot be passed to function expecting parameter list '(int...)'", (<error> a1).detail()["message"]);

a1 = trap function:call(value1, 10);
assertEquality(true, a1 is error);
assertEquality("{ballerina/lang.function}IncompatibleArguments", (<error> a1).message());
assertEquality("arguments of incompatible types: expected argument(s) of types '[int,int,int]', found '[int]'", (<error> a1).detail()["message"]);
assertEquality("arguments of incompatible types: argument list '(int)' cannot be passed to function expecting parameter list '(int,int,int)'", (<error> a1).detail()["message"]);

NewPerson person = {firstName: "chiran", secondName: "sachintha"};
a1 = trap function:call(test10, person);
assertEquality(true, a1 is error);
assertEquality("{ballerina/lang.function}IncompatibleArguments", (<error> a1).message());
assertEquality("arguments of incompatible types: expected argument(s) of types '[string,NewPerson]', found '[NewPerson]'", (<error> a1).detail()["message"]);
assertEquality("arguments of incompatible types: argument list '(NewPerson)' cannot be passed to function expecting parameter list '(string,NewPerson)'", (<error> a1).detail()["message"]);

a1 = trap function:call(test11, {});
assertEquality(true, a1 is error);
assertEquality("{ballerina/lang.function}IncompatibleArguments", (<error> a1).message());
assertEquality("arguments of incompatible types: expected argument(s) of types '[NewStudent]', found '[map<(any|error)>]'", (<error> a1).detail()["message"]);
assertEquality("arguments of incompatible types: argument list '(map<(any|error)>)' cannot be passed to function expecting parameter list '(NewStudent)'", (<error> a1).detail()["message"]);

a1 = trap function:call(test20, 10);
assertEquality(true, a1 is error);
assertEquality("{ballerina/lang.function}IncompatibleArguments", (<error> a1).message());
assertEquality("arguments of incompatible types: argument list '(int)' cannot be passed to function expecting parameter list '(string...)'", (<error> a1).detail()["message"]);

a1 = trap function:call(test21, 10);
assertEquality(true, a1 is error);
assertEquality("{ballerina/lang.function}IncompatibleArguments", (<error> a1).message());
assertEquality("arguments of incompatible types: argument list '(int)' cannot be passed to function expecting parameter list '()'", (<error> a1).detail()["message"]);

a1 = trap function:call(test21, 10, 10);
assertEquality(true, a1 is error);
assertEquality("{ballerina/lang.function}IncompatibleArguments", (<error> a1).message());
assertEquality("arguments of incompatible types: argument list '(int,int)' cannot be passed to function expecting parameter list '()'", (<error> a1).detail()["message"]);

a1 = trap function:call(test22, "10");
assertEquality(true, a1 is error);
assertEquality("{ballerina/lang.function}IncompatibleArguments", (<error> a1).message());
assertEquality("arguments of incompatible types: argument list '(string)' cannot be passed to function expecting parameter list '(int)'", (<error> a1).detail()["message"]);
}

function assertEquality(any|error expected, any|error actual) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@

package org.ballerinalang.test.bala.record;

import org.ballerinalang.test.BAssertUtil;
import org.ballerinalang.test.BCompileUtil;
import org.ballerinalang.test.BRunUtil;
import org.ballerinalang.test.CompileResult;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

Expand All @@ -45,6 +47,17 @@ public void testRestFieldTypeDefAfterRecordDef() {
BRunUtil.invoke(result, "testCRRestFieldInCR");
}

@Test
public void negativeTests() {
CompileResult result = BCompileUtil.compile("test-src/record/record_negative_bala.bal");
int count = 0;
BAssertUtil.validateError(result, count++, "incompatible types: expected 'testorg/foo.records:1.0.0:" +
"(testorg/foo.records:1:Interceptor & readonly)', found 'PersonInterceptor'", 26, 40);
BAssertUtil.validateError(result, count++, "incompatible types: expected 'testorg/foo.records:1.0.0:Foo'" +
", found '[Bar]'", 26, 71);
Assert.assertEquals(result.getErrorCount(), count);
}

@Test
public void testComplexCyclicRecordTypeResolution() {
CompileResult typeResolution =
Expand Down
Loading

0 comments on commit ae2be1b

Please sign in to comment.