Watch, Follow, &
Connect with Us
Public Report
Report From: Delphi-BCB/Compiler/Delphi/Language/Overloading/Method    [ Add a report in this area ]  
Report #:  118897   Status: Closed
method overload resolution fails when passing @ parameter to overloaded methods mixing Pointer and specific pointer parameters.
Project:  Delphi Build #:  18.0.4905.60485
Version:    18.1 Submitted By:   Jeroen Pluimers
Report Type:  Basic functionality failure Date Reported:  9/11/2013 11:07:39 AM
Severity:    Infrequently encountered problem Last Updated: 12/10/2013 6:29:31 PM
Platform:    All platforms Internal Tracking #:   43933
Resolution: Fixed (Resolution Comments) Resolved in Build: : XE5 Update2
Duplicate of:  None
Voting and Rating
Overall Rating: No Ratings Yet
0.00 out of 5
Total Votes: None
Description
method overload resolution fails when passing @ parameter to overloaded methods mixing Pointer and specific pointer parameters.
it does not matter if the default parameters are involved

Affected signatures in global methods, instance methods and interface methods:

    procedure Log(const Description: string; const Item: Pointer); overload;
    procedure Log(const Description: string; const TypeTypeInfo: PTypeInfo); overload;

    procedure LogDefault(const Description: string; const Item: Pointer); overload;
    procedure LogDefault(const Description: string; const TypeTypeInfo: PTypeInfo; const Prefix: string = ''); overload;
Steps to Reproduce:
No "Overload resolution error" lines expected when running this program:

program MethodOlverloadResolutionError;

// method overload resolution fails when passing @ parameter to overloaded methods mixing Pointer and specific pointer parameters.
// it does not matter if the default parameters are involved

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  System.TypInfo;

var
  RaiseEOverloadResolutionError: Boolean = False;

type
  EOverloadResolutionError = class(Exception)
    constructor Create(const Description: string; const Method: string);
  end;

  IDescriptionLogger = interface(IInterface)
    ['{98588095-29C8-4C19-9BDC-2697D51F8BCA}']
    procedure Log(const Description: string; const Item: Pointer); overload;
    procedure Log(const Description: string; const TypeTypeInfo: PTypeInfo); overload;
    procedure LogDefault(const Description: string; const Item: Pointer); overload;
    procedure LogDefault(const Description: string; const TypeTypeInfo: PTypeInfo; const Prefix: string = ''); overload;
  end;

  TLogger = class(TInterfacedObject, IDescriptionLogger)
    procedure Log(const Description: string; const Item: Pointer); overload;
    procedure Log(const Description: string; const TypeTypeInfo: PTypeInfo); overload;
    procedure LogDefault(const Description: string; const Item: Pointer); overload;
    procedure LogDefault(const Description: string; const TypeTypeInfo: PTypeInfo; const Prefix: string = ''); overload;
  end;

procedure LogAndCheck(const Description: string; const Method: string; const Expected: string);
var
  OverloadResolutionError: EOverloadResolutionError;
begin
  Writeln(Description, ' ', Method);
  if 0 = Pos(Expected, Description) then
  begin
    OverloadResolutionError := EOverloadResolutionError.Create(Description, Method);
    if RaiseEOverloadResolutionError then
      raise OverloadResolutionError
    else
    begin
      Writeln(OverloadResolutionError.Message);
      OverloadResolutionError.Free();
    end;
  end;
end;

procedure LogMethod(const Description: string; const Item: Pointer); overload;
const
  Method = 'procedure LogMethod(const Description: string; const Item: Pointer);';
begin
  LogAndCheck(Description, Method, 'Pointer');
end;

procedure LogMethod(const Description: string; const TypeTypeInfo: PTypeInfo); overload;
const
  Method = 'procedure LogMethod(const Description: string; const TypeTypeInfo: PTypeInfo);';
begin
  LogAndCheck(Description, Method, 'PTypeInfo');
end;

procedure LogMethodDefault(const Description: string; const Item: Pointer); overload;
const
  Method = 'procedure LogMethodDefault(const Description: string; const Item: Pointer);';
begin
  LogAndCheck(Description, Method, 'Pointer');
end;

procedure LogMethodDefault(const Description: string; const TypeTypeInfo: PTypeInfo; const Prefix: string = ''); overload;
const
  Method = 'procedure LogMethodDefault(const Description: string; const TypeTypeInfo: PTypeInfo; const Prefix: string = '''');';
begin
  LogAndCheck(Description, Method, 'PTypeInfo');
end;

procedure TLogger.Log(const Description: string; const Item: Pointer);
begin
  LogMethod(Description, Item);
end;

procedure TLogger.Log(const Description: string; const TypeTypeInfo: PTypeInfo);
begin
  LogMethod(Description, TypeTypeInfo);
end;

procedure TLogger.LogDefault(const Description: string; const Item: Pointer);
begin
  LogMethodDefault(Description, Item);
end;

procedure TLogger.LogDefault(const Description: string; const TypeTypeInfo: PTypeInfo; const Prefix: string = '');
begin
  LogMethodDefault(Description, TypeTypeInfo, Prefix);
end;

constructor EOverloadResolutionError.Create(const Description, Method: string);
begin
  inherited CreateFmt('Overload resolution error: "%s" parameter called "%s"', [Description, Method]);
end;

procedure Main();
var
  Logger: TLogger;
  DescriptionLogger: IDescriptionLogger;
  Item: Pointer;
  TypeTypeInfo: PTypeInfo;
begin
  Item := nil;
  TypeTypeInfo := nil;

  Writeln('LogMethod:');
  LogMethod('@Pointer', @Logger); // error: calls the PTypeInfo overload
  LogMethod('Pointer', Item);
  LogMethod('PTypeInfo', TypeTypeInfo);

  Writeln;
  Writeln('LogMethodDefault:');
  LogMethodDefault('@Pointer', @Logger); // error: calls the PTypeInfo overload
  LogMethodDefault('Pointer', Item);
  LogMethodDefault('PTypeInfo', TypeTypeInfo);

  Logger := TLogger.Create();
  DescriptionLogger := Logger;
  try
    Writeln;
    Writeln('Logger.Log:');
    Logger.Log('@Pointer', @Logger); // error: calls the PTypeInfo overload
    Logger.Log('Pointer', Item);
    Logger.Log('PTypeInfo', TypeTypeInfo);

    Writeln;
    Writeln('Logger.LogDefault:');
    Logger.LogDefault('@Pointer', @Logger); // error: calls the PTypeInfo overload
    Logger.LogDefault('Pointer', Item);
    Logger.LogDefault('PTypeInfo', TypeTypeInfo);

    Writeln;
    Writeln('DescriptionLogger.Log:');
    DescriptionLogger.Log('@Pointer', @Logger); // error: calls the PTypeInfo overload
    DescriptionLogger.Log('Pointer', Item);
    DescriptionLogger.Log('PTypeInfo', TypeTypeInfo);

    Writeln;
    Writeln('DescriptionLogger.LogDefault:');
    DescriptionLogger.LogDefault('@Pointer', @DescriptionLogger); // error: calls the PTypeInfo overload
    DescriptionLogger.LogDefault('Pointer', Item);
    DescriptionLogger.LogDefault('PTypeInfo', TypeTypeInfo);
  finally
    DescriptionLogger := nil;
  end;
end;

begin
  try
    Main();
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
Workarounds
None
Attachment
MethodOlverloadResolutionError.zip
Comments

Remy Lebeau (TeamB) at 9/11/2013 12:17:30 PM -
By default, the '@' operator returns an untyped pointer.  Try using the {$TYPEDADDRESS ON} directive to avoid that (it is OFF by default).

Jeroen Pluimers at 9/16/2013 6:59:00 AM -
It works with {$TYPEDADDRESS ON} at the call site, but that should not matter: with the default {$TYPEDADDRESS OFF} the pointers should be untyped, and call the untyped overload. But with {$TYPEDADDRESS OFF} they call the typed overload.

Server Response from: ETNACODE01