Watch, Follow, &
Connect with Us
Public Report
Report From: Delphi-BCB/Compiler/Delphi/Generics    [ Add a report in this area ]  
Report #:  120211   Status: Closed
Generic type parameter is replaced by constrained type for some operations
Project:  Delphi Build #:  XE3, ... XE5
Version:    19.0 Submitted By:   Asbjørn Heid
Report Type:  Basic functionality failure Date Reported:  11/3/2013 2:42:32 PM
Severity:    Infrequently encountered problem Last Updated: 4/15/2014 6:37:18 PM
Platform:    All versions Internal Tracking #:   44684
Resolution: Fixed (Resolution Comments) Resolved in Build: : XE6
Duplicate of:  None
Voting and Rating
Overall Rating: No Ratings Yet
0.00 out of 5
Total Votes: 10
Description
I've noticed this problem in different cases, but the issue is the same.

Constrain a type parameter by a base class. Some operations in the generic method will then use the base class instead of the actual parameterized type.

For example, running the program in Steps one would expect the output to be
  Pass 1
  Pass 2
  Pass 3

however the output is only
  Pass 1
  Pass 2

meaning it references the constrained type's Get method (Value<integer>.Get) instead of the type parameter's Get method (IntegerValue.Get).

If there are some curious internal limitations why the program in Steps cannot pass the final test, then the compiler should at least generate an error message. Ideally it should be fixed to pass the final test.

Without the final test passing one cannot get a function pointer  to one of the type parameter's class methods.
Steps to Reproduce:
--------
program Project1;
{$APPTYPE CONSOLE}

type
  Value<T> = class
  public
    class function Get: T; virtual; abstract;
  end;

  IntegerValue = class(Value<integer>)
  public
    class function Get: integer; override;
  end;

class function IntegerValue.Get: integer;
begin
  result := 42;
end;

type
  TRec = class
    class procedure Foo<T; V: Value<T>>();
  end;

class procedure TRec.Foo<T, V>;
var
  p1, p2: Pointer;
begin
  p1 := pointer(Value<integer>);
  p2 := pointer(V);

  if p1 <> p2 then
    WriteLn('Pass 1');

  p1 := pointer(@Value<integer>.Get);
  p2 := pointer(@IntegerValue.Get);

  if p1 <> p2 then
    WriteLn('Pass 2');

  p1 := pointer(@Value<integer>.Get);
  p2 := pointer(@V.Get);

  if p1 <> p2 then
    WriteLn('Pass 3');
end;

begin
  TRec.Foo<integer, IntegerValue>();
end.
--------
Workarounds
None
Attachment
None
Comments

None

Server Response from: ETNACODE01