Project

General

Profile

Bug #11897

Can't resolve constructor requiring integer parameter with an int64 (eventually constant) argument

Added by Alexandru Lungu 23 days ago. Updated 5 days ago.

Status:
Test
Priority:
Normal
Target version:
-
Start date:
Due date:
% Done:

100%

billable:
No
vendor_id:
GCD
case_num:
version_reported:
version_resolved:
production:
No
env_name:
topics:

Related issues

Related to Base Language - Bug #10004: NativeInvoker fails if an argument is of type integerConstant WIP
Related to Base Language - Bug #9060: Cache oftenly used values that are immutable Internal Test

History

#1 Updated by Alexandru Lungu 23 days ago

  • Related to Bug #10004: NativeInvoker fails if an argument is of type integerConstant added

#2 Updated by Alexandru Lungu 23 days ago

  • Related to Bug #9060: Cache oftenly used values that are immutable added

#3 Updated by Alexandru Lungu 23 days ago

  • Subject changed from Can't resolve constructor requiring integer parameter with an int64 argument to Can't resolve constructor requiring integer parameter with an int64constant argument

Constructor look-up

I encountered the following issue with int64constant. In ControlFlowOps.resolveLegacyEntry, used when looking-up a suitable constructor when creating a new legacy object, there is:

if ((int64.class == sigType     && decimal.class == candidateType)     ||
                      (integer.class == sigType   && (decimal.class == candidateType     || 
                                                      int64.class == candidateType))     ||
                      (character.class == sigType && longchar.class == candidateType)    ||
                      (datetime.class == sigType  && datetimetz.class == candidateType)  ||
                      (date.class == sigType      && (datetime.class == candidateType    || 
                                                      datetimetz.class == candidateType)))

This doesn't account for int64constant or other *constant variants. There is a previous args[i] = normalizeType(arg, sigType, candidateType);, but I am not entirely sure it it is the responsibility of this method to resolve the *constant variants ... it may be, but currently it is not.

The code block above is from the INPUT mode, but OUTPUT mode has its own such conditional. Example to replicate:

def var value as int.
def var instance as MyClass.
instance = new MyClass(input value + 1).
class MyClass:

   constructor public MyClass (input p as integer):

   end.

end.

PS: The thingy here is that value + 1 yields int64constant instead of integer.

   public static int64 plus(integer op1, int op2)
   {
      return plus((int64) op1, int64.of((long) op2));
   }

from MathOps. I guess it is correctly that it returns int64, because it may overflow and OE is silently promoting the expression to int64 to hold the result.

Audit the use of constants

I think we discussed in #9060 about auditing all places where syntax like <BDT>.class is used in order to upgrade them to account for *constant variants. This task is the second example where this audit doesn't seem sufficient; #10004 is the first one.

Artur, please leverage AI capability to generate a report on FWD of places where there are still <BDT>.class syntax which doesn't include *constant variants yet. Consider building a unit test suite in the process.

PS: Please mind the BaseDataTypeConstant decorator to simplify integration.

#4 Updated by Alexandru Lungu 23 days ago

  • Status changed from New to WIP
  • Assignee set to Artur Școlnic

#6 Updated by Alexandru Lungu 23 days ago

deleted

#7 Updated by Alexandru Lungu 23 days ago

Never mind, I think this is not about the int64constant. It is resolved by calculateType.
The if conditional however is too strict for #11897-3. Apparently, you can use an int64 argument for an integer parameter on constructor call as long as it is enough to fit.

#8 Updated by Alexandru Lungu 23 days ago

  • Subject changed from Can't resolve constructor requiring integer parameter with an int64constant argument to Can't resolve constructor requiring integer parameter with an int64 (eventually constant) argument

Indeed, the problem on this is that there is no implicit coercion assumed by the resolveLegacyEntry method. One can use an int64 argument for an integer parameter. It is not consider a "narrowing".

Argument Ctor1 Ctor 2 overload Ctor chosen FWD
int64 integer int64 int64 Good
integer integer int64 integer Good
integer + 1 integer int64 integer or Value 2147483648 too large to fit in INTEGER. (15747) on overflow plus always returns int64, the int64 ctor is always picked
int64 + 1 integer int64 int64 Good
integer integer - integer Good
integer int64 - int64 (widen) Good (we have widening works)
int64 integer - Parameter 1 for CONSTRUCTOR Cls is not type compatible with its definition. (12905) or Cannot use NEW statement with class 'Cls' because no constructor found with matching signature. (13840) on overload Ambiguous runtime method call. Could not resolve <class-name> reference. (13844) is thrown in FWD.
int64 int64 - int64 Good

My concern is with the 3rd row. I think MathOps shall return int64, but the actual instance should be either int64.of() or integer.of() depending whether it actually fits within bounds. The type coercion is not done by the arithmetic operator, but by the function invocation / ctor lookup / assignment / etc.

This task is about a regression because I am most certain the tests I am running now were successful at some point. Thus, this is why I may be biased into relating it with #9060.

#11 Updated by Artur Școlnic 22 days ago

  • Assignee changed from Artur Școlnic to Eric Faulhaber
  • vendor_id deleted (GCD)

The issues are confirmed with test cases, also THIS-OBJECT(i + 1) / SUPER(i + 1) results in the same error, working on the fixes.

#12 Updated by Artur Școlnic 22 days ago

  • vendor_id set to GCD
  • Assignee changed from Eric Faulhaber to Artur Școlnic

#13 Updated by Greg Shah 22 days ago

  • reviewer Constantin Asofiei added

#14 Updated by Artur Școlnic 21 days ago

  • Status changed from WIP to Review

In the 4GL, intVar + 1 is still an integer expression, so it should pick a constructor's integer overload — but FWD's arithmetic always produces an int64, so the int64 overload was chosen instead. This happened in two places: a NEW whose argument was written with an explicit INPUT keyword, and THIS-OBJECT/SUPER constructor chaining. Conversion now tags those arguments with their original integer type, so the right constructor is picked, and a new 29-test slice covers both cases — green on OpenEdge 12.8 and on FWD with 11897a.

Constantin, please review 11897a.

#15 Updated by Constantin Asofiei 20 days ago

Only one change I would suggest - move the operators check directly in the while, instead of:

         <while>vref != null                 and
                (vref.type == prog.kw_input  or
                 vref.type == prog.kw_output or
                 vref.type == prog.kw_in_out)
            <action>vref = vref.nextSibling</action>
         </while>

         <rule>vref != null and evalLib("operators", vref.type)
            <action>match = true</action>
         </rule>

have something like:
         <while>vref != null
            <rule>evalLib("operators", vref.type)
               <action>match = true</action>
               <break />
            </rule>
            <action>vref = vref.nextSibling</action>
         </while>

#16 Updated by Constantin Asofiei 20 days ago

Also, is there any way to have a hierarchy like PARAMETER/EXPRESSION/LPARENS/<operator> or something like this? I mean, the operator not being direct child of PARAMETER?

Otherwise, please post how the AST looks like in the NEW, THIS-OBJECT and SUPER, with i.e. new oo.foo(input ((10))).

#17 Updated by Artur Școlnic 20 days ago

PARAMETER/EXPRESSION/... is real, but only for THIS-OBJECT and SUPER. For NEW the EXPRESSION is normalized away.
NEW — post-annotation, new tests.astprobe.ProbeTarget(...):

input ((10))      PARAMETER [param_index=0]        input (i + 1)   PARAMETER [param_index=0]
                     KW_INPUT                                         KW_INPUT
                     NUM_LITERAL '10' [param_index=0]                 LPARENS [param_index=0]
                                                                         PLUS
input i + 1       PARAMETER [param_index=0]                                  VAR_INT 'i'
                     KW_INPUT                                                NUM_LITERAL '1'
                     PLUS [param_index=0]
                        VAR_INT 'i'                 ((i + 1))       PARAMETER [param_index=0]
                        NUM_LITERAL '1'             (no mode)          LPARENS [param_index=0]
                                                                         PLUS

No EXPRESSION node; param_index on both the PARAMETER and the value. Note ((10)) loses both paren layers and ((i + 1)) keeps exactly one LPARENS — nesting never accumulates.

THIS-OBJECT / SUPER — this-object(input ((seed + 1))) and super(input ((10))):

KW_THIS_OBJ                             KW_SUPER
   LPARENS                                 LPARENS
      PARAMETER                               PARAMETER
         KW_INPUT                                KW_INPUT
         EXPRESSION [param_index=0]              EXPRESSION [param_index=0]
            LPARENS                                 NUM_LITERAL '10'
               PLUS

#18 Updated by Constantin Asofiei 20 days ago

OK, then lets stay with your rules, get the first child after discarding kw_input/output/in_out and check for EXPRESSION and LPARENS.

#19 Updated by Artur Școlnic 20 days ago

  • Status changed from Review to Internal Test
  • % Done changed from 0 to 100

I committed the final version, will start regression testing.

#20 Updated by Artur Școlnic 16 days ago

There are only 2 projects with the target patterns in the sources, POC and the large gui app.
Alex, could you please convert POC with 11897a or arrange for someone who has it to convert?
Serban agreed to convert the other app.

#21 Updated by Artur Școlnic 15 days ago

  • Status changed from Internal Test to WIP
  • % Done changed from 100 to 90

The changes regressed the multi tenant project, investigating.

#22 Updated by Artur Școlnic 15 days ago

  • Status changed from WIP to Internal Test
  • % Done changed from 90 to 100

False alarm, the multi tenant app is ok.

#23 Updated by Artur Școlnic 12 days ago

Danut, please test POC with 11897a, conversion and runtime.
Alex, please send Danut the details for the runtime testing for POC, i.e.the scenario that was failing for you.

#24 Updated by Alexandru Lungu 12 days ago

You can find it in #10566-54: the exact test and module.

#25 Updated by Artur Școlnic 8 days ago

Alexandru Lungu wrote:

You can find it in #10566-54: the exact test and module.

The test passed with 11897a and did not regress any other tests.

#26 Updated by Artur Școlnic 6 days ago

I think 11897a can be merged.

#27 Updated by Constantin Asofiei 6 days ago

  • Status changed from Internal Test to Merge Pending

11897a can be merged after 8902a

#28 Updated by Artur Școlnic 6 days ago

  • Status changed from Merge Pending to Test

11897a was merged to trunk/16792.

Also available in: Atom PDF