ballerina-lang
ballerina-lang copied to clipboard
[Bug]: records fields are set to null when there should be a default value assigned
Description
When a record is created using a predefined type where several nullable fields with default values, these fields are set to null instead of having the default value. This happens in the repository, client.config
Steps to Reproduce
When debugging the following code, the values of the returned client is set to null instead of having default parameters(defaultTokenExpTime, clockSkew, credentialBearer).
import ballerinax/'client.config;
import ballerina/http;
configurable string refreshToken = "";
configurable string clientId = "";
configurable string clientSecret = "";
configurable string spreadsheetId = "";
ConnectionConfig spreadsheetConfig = {
auth: {
clientId: clientId,
clientSecret: clientSecret,
refreshToken: refreshToken,
refreshUrl:"https://www.googleapis.com/oauth2/v3/token"
}
};
public type ConnectionConfig record {|
*config:ConnectionConfig;
# Configurations related to client authentication
http:BearerTokenConfig|config:OAuth2RefreshTokenGrantConfig auth;
# The HTTP version understood by the client
http:HttpVersion httpVersion = http:HTTP_1_1;
|};
public function main() returns error? {
http:ClientConfiguration|error httpClientConfig = config:constructHTTPClientConfig(spreadsheetConfig);
}
Affected Version(s)
2201.9.0
OS, DB, other environment details and versions
No response
Related area
-> Runtime
Related issue(s) (optional)
https://github.com/ballerina-platform/ballerina-library/issues/6023
Suggested label(s) (optional)
No response
Suggested assignee(s) (optional)
No response
The issue happens when we rewrite the default value closure function calls when compiling. Reproducible with the following code.
import ballerina/http;
import ballerina/io;
public function main() returns error? {
OAuth2RefreshTokenGrantConfig config = {
clientId: "",
clientSecret: "",
refreshToken: "",
refreshUrl: ""
};
http:OAuth2RefreshTokenGrantConfig auth = {...config};
io:println(auth);
//{"refreshUrl":"","refreshToken":"","clientId":"","clientSecret":"",
//"defaultTokenExpTime":null,"clockSkew":null,
//"credentialBearer":"AUTH_HEADER_BEARER","clientConfig":{"httpVersion":"HTTP_1_1"}}
io:println(typeof auth); // http:OAuth2RefreshTokenGrantConfig
}
public type OAuth2RefreshTokenGrantConfig record {|
string refreshUrl;
string refreshToken;
string clientId;
string clientSecret;
string[] scopes?;
decimal defaultTokenExpTime?;
decimal clockSkew?;
|};
Here, the map value creation at http:OAuth2RefreshTokenGrantConfig auth = {...config} will be desugared into multiple function pointer calls to populate the default field values. But, in the above case, there were only 2 such calls for credentialBearer and clientConfig fields. The calls for defaultTokenExpTime and clockSkew fields are missing.
The BIR of the above function is given below.
public main function() -> error|() {
%0(RETURN) error|();
%1(LOCAL) OAuth2RefreshTokenGrantConfig;
%2(TEMP) typeDesc<any|error>;
%4(TEMP) string;
%5(TEMP) string;
%6(TEMP) string;
%7(TEMP) string;
%8(TEMP) string;
%9(TEMP) string;
%10(TEMP) string;
%11(TEMP) string;
%12(LOCAL) ballerina/http:2.10.12:OAuth2RefreshTokenGrantConfig;
%17(TEMP) function() -> [POST_BODY_BEARER]|[AUTH_HEADER_BEARER];
%18(TEMP) [POST_BODY_BEARER]|[AUTH_HEADER_BEARER];
%20(TEMP) function() -> ballerina/oauth2:2.10.0:ClientConfiguration;
%21(TEMP) ballerina/oauth2:2.10.0:ClientConfiguration;
%22(TEMP) typeRefDesc<>[];
%23(TEMP) int;
%24(TEMP) typeRefDesc<>;
%26(TEMP) ();
%29(TEMP) ballerina/io:1.6.0:Printable;
%31(TEMP) typeDesc<ballerina/http:2.10.12:OAuth2RefreshTokenGrantConfig>;
%32(TEMP) ();
bb0 {
%2 = newType OAuth2RefreshTokenGrantConfig;
%4 = ConstLoad clientId;
%5 = ConstLoad ;
%6 = ConstLoad clientSecret;
%7 = ConstLoad ;
%8 = ConstLoad refreshToken;
%9 = ConstLoad ;
%10 = ConstLoad refreshUrl;
%11 = ConstLoad ;
%1 = NewMap %2{%4:%5,%6:%7,%8:%9,%10:%11};
%2 = newType ballerina/http:2.10.12:OAuth2RefreshTokenGrantConfig;
%4 = ConstLoad credentialBearer;
%17 = fp ballerina/oauth2:2.10.0::$RefreshTokenGrantConfig_$rec$RefreshTokenGrantConfig$rec$credentialBearer;
%18 = FPCall %17() -> bb1;
}
bb1 {
%5 = ConstLoad clientConfig;
%20 = fp ballerina/oauth2:2.10.0::$RefreshTokenGrantConfig_$rec$RefreshTokenGrantConfig$rec$clientConfig;
%21 = FPCall %20() -> bb2;
}
bb2 {
%12 = NewMap %2{%1,%4:%18,%5:%21};
%23 = ConstLoad -1;
%24 = <typeRefDesc<>> %12;
%22 = newArray typeRefDesc<>[][%23]{%24};
%26 = println(%22) -> bb3;
}
bb3 {
%23 = ConstLoad -1;
%31 = typeof %12;
%29 = <ballerina/io:1.6.0:Printable> %31;
%22 = newArray typeRefDesc<>[][%23]{%29};
%32 = println(%22) -> bb4;
}
bb4 {
%0 = ConstLoad 0;
GOTO bb5;
}
bb5 {
return;
}
}
This issue is NOT closed with a proper Reason/ label. Make sure to add proper reason label before closing. Please add or leave a comment with the proper reason label now.
- Reason/EngineeringMistake - The issue occurred due to a mistake made in the past.
- Reason/Regression - The issue has introduced a regression.
- Reason/MultipleComponentInteraction - Issue occured due to interactions in multiple components.
- Reason/Complex - Issue occurred due to complex scenario.
- Reason/Invalid - Issue is invalid.
- Reason/Other - None of the above cases.