Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overriding a field included with record-type-inclusion doesn't remove the default value closure for that particular field being overriden #32012

Closed
rdhananjaya opened this issue Aug 4, 2021 · 4 comments · Fixed by #40579
Assignees
Labels
Priority/Blocker Reason/EngineeringMistake The issue occurred due to a mistake made in the past. Team/CompilerFE All issues related to Language implementation and Compiler, this exclude run times. Type/Bug

Comments

@rdhananjaya
Copy link
Member

Description:

type R0 record {
    int|string f = 1;
};

type R1 record {
    *R0;
    string f;
};

public function main() {
    R1 r1 = { f : "hello"};
}

This results in:

error: {ballerina/lang.map}InherentTypeViolation {"message":"invalid value for record field 'f': expected value of type 'string', found 'int'"}
        at $value$R0:R0$gen$.<init>(main.bal:2)
           main:main(main.bal:11)

Steps to reproduce:

Affected Versions:

OS, DB, other environment details and versions:

Related Issues (optional):

Suggested Labels (optional):

Suggested Assignees (optional):

@rdhananjaya rdhananjaya added Type/Bug Priority/Blocker Team/CompilerFE All issues related to Language implementation and Compiler, this exclude run times. Team/jBallerina All the issues related to BIR, JVM backend code generation and runtime and removed Team/CompilerFE All issues related to Language implementation and Compiler, this exclude run times. labels Aug 4, 2021
@rdhananjaya
Copy link
Member Author

rdhananjaya commented Aug 4, 2021

The culprit for this issue is when we initialize R1, it automatically calling the init of referenced types.

import ballerina/io;
type R record {|
    int hello = inc();
|};

type RR record {|
    *R;
    int hello = inc();
|};

public function main() {
    R|RR rr = <RR>{ hello: 22};
    lock {
        io:println(i); // prints 2 [`inc` method have invoked twise, even when value for `hello` is given to  the constructor]
    }
}

isolated int i = 0;

isolated function inc() returns int {
    lock {
        i = i + 1;
        return i;
    }
}

@MaryamZi
Copy link
Member

MaryamZi commented Aug 5, 2021

We desugar the initialization logic of all the fields into the generated init method of the record. This initializes all of the fields in the records for which default values have been specified.

With type inclusion, I believe including records call the init methods of the included records to initialize fields that are initialized in the included records. But this'll result in errors for examples like in the issue. Just removing the init call of the included record isn't an option because for some fields the default value will still come from the included record.

type R0 record {
    int|string f = 1;
    int? g = 1;
};

type R1 record {
    *R0;
    string f; 
    // g is initialized in R0
};

To properly support inclusion like in the example IMO we need to be able to selectively call the initialization logic for specific fields. We may need to introduce the concept of default value closures attached to each field.

@warunalakshitha
Copy link
Contributor

ATM calling the included record types in it calls generated during codegen. We can set a skipped field set during included record initialization but might cause more issues if we try to do that at runtime. Perfect solution would be to have default value closure for each field as @MaryamZi said. So we can independently initialize each record.

Copy link

github-actions bot commented Dec 6, 2023

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.

@chiranSachintha chiranSachintha added the Reason/EngineeringMistake The issue occurred due to a mistake made in the past. label Dec 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Priority/Blocker Reason/EngineeringMistake The issue occurred due to a mistake made in the past. Team/CompilerFE All issues related to Language implementation and Compiler, this exclude run times. Type/Bug
Projects
None yet
4 participants