From d221f42a578316c99fc74674b037e54725bfbdbc Mon Sep 17 00:00:00 2001 From: Sven/Sarah Barth Date: Sun, 6 Nov 2022 21:56:41 +0100 Subject: [PATCH] * ensure that the correct overload is picked for function reference parameters + added tests --- compiler/htypechk.pas | 20 ++++++++++++--- tests/test/tfuncref50.pp | 54 ++++++++++++++++++++++++++++++++++++++++ tests/test/tfuncref51.pp | 54 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 tests/test/tfuncref50.pp create mode 100644 tests/test/tfuncref51.pp diff --git a/compiler/htypechk.pas b/compiler/htypechk.pas index 251749b9ff..02139f73c5 100644 --- a/compiler/htypechk.pas +++ b/compiler/htypechk.pas @@ -2983,11 +2983,17 @@ implementation returns a procdef we need to find the correct overloaded procdef that matches the expected procvar. The loadnode temporary returned the first procdef (PFV) } - if (def_to.typ=procvardef) and + if ( + (def_to.typ=procvardef) or + is_funcref(def_to) + ) and (currpt.left.nodetype=loadn) and (currpt.left.resultdef.typ=procdef) then begin - pdtemp:=tprocsym(Tloadnode(currpt.left).symtableentry).Find_procdef_byprocvardef(Tprocvardef(def_to)); + if def_to.typ=procvardef then + pdtemp:=tprocsym(Tloadnode(currpt.left).symtableentry).Find_procdef_byprocvardef(Tprocvardef(def_to)) + else + pdtemp:=tprocsym(tloadnode(currpt.left).symtableentry).find_procdef_byfuncrefdef(tobjectdef(def_to)); if assigned(pdtemp) then begin tloadnode(currpt.left).setprocdef(pdtemp); @@ -2998,7 +3004,10 @@ implementation { same as above, but for the case that we have a proc-2-procvar conversion together with a load } - if (def_to.typ=procvardef) and + if ( + (def_to.typ=procvardef) or + is_funcref(def_to) + ) and (currpt.left.nodetype=typeconvn) and (ttypeconvnode(currpt.left).convtype=tc_proc_2_procvar) and (ttypeconvnode(currpt.left).totypedef=voidtype) and @@ -3006,7 +3015,10 @@ implementation (ttypeconvnode(currpt.left).left.nodetype=loadn) and (ttypeconvnode(currpt.left).left.resultdef.typ=procdef) then begin - pdtemp:=tprocsym(tloadnode(ttypeconvnode(currpt.left).left).symtableentry).Find_procdef_byprocvardef(Tprocvardef(def_to)); + if def_to.typ=procvardef then + pdtemp:=tprocsym(tloadnode(ttypeconvnode(currpt.left).left).symtableentry).Find_procdef_byprocvardef(Tprocvardef(def_to)) + else + pdtemp:=tprocsym(tloadnode(ttypeconvnode(currpt.left).left).symtableentry).find_procdef_byfuncrefdef(tobjectdef(def_to)); if assigned(pdtemp) then begin tloadnode(ttypeconvnode(currpt.left).left).setprocdef(pdtemp); diff --git a/tests/test/tfuncref50.pp b/tests/test/tfuncref50.pp new file mode 100644 index 0000000000..3a1157b45b --- /dev/null +++ b/tests/test/tfuncref50.pp @@ -0,0 +1,54 @@ +program tfuncref50; + +{$mode delphi} +{$modeswitch functionreferences} + +type + TFunc = reference to function(aArg: LongInt): LongInt; + +function Test(aArg: TFunc): LongInt; +begin + Result := aArg(42); +end; + +type + TTest = class + function Method(aArg: String): LongInt; overload; + function Method(aArg: LongInt): LongInt; overload; + procedure DoTest; + end; + +function TTest.Method(aArg: String): LongInt; +begin + Result := 1; +end; + +function TTest.Method(aArg: LongInt): LongInt; +begin + Result := 2; +end; + +procedure TTest.DoTest; +begin + Test(Method); +end; + +function Func(aArg: String): LongInt; overload; +begin + Result := 1; +end; + +function Func(aArg: LongInt): LongInt; overload; +begin + Result := 2; +end; + +var + t: TTest; +begin + t := TTest.Create; + t.DoTest; + t.Free; + if Test(Func) <> 2 then + Halt(2); +end. diff --git a/tests/test/tfuncref51.pp b/tests/test/tfuncref51.pp new file mode 100644 index 0000000000..a09b7fbf23 --- /dev/null +++ b/tests/test/tfuncref51.pp @@ -0,0 +1,54 @@ +program tfuncref51; + +{$mode objfpc} +{$modeswitch functionreferences} + +type + TFunc = reference to function(aArg: LongInt): LongInt; + +function Test(aArg: TFunc): LongInt; +begin + Result := aArg(42); +end; + +type + TTest = class + function Method(aArg: String): LongInt; overload; + function Method(aArg: LongInt): LongInt; overload; + procedure DoTest; + end; + +function TTest.Method(aArg: String): LongInt; +begin + Result := 1; +end; + +function TTest.Method(aArg: LongInt): LongInt; +begin + Result := 2; +end; + +procedure TTest.DoTest; +begin + Test(@Method); +end; + +function Func(aArg: String): LongInt; overload; +begin + Result := 1; +end; + +function Func(aArg: LongInt): LongInt; overload; +begin + Result := 2; +end; + +var + t: TTest; +begin + t := TTest.Create; + t.DoTest; + t.Free; + if Test(@Func) <> 2 then + Halt(2); +end.