diff --git a/.gitattributes b/.gitattributes index f09a738720..87e309bb45 100644 --- a/.gitattributes +++ b/.gitattributes @@ -9273,6 +9273,7 @@ tests/test/tobjc2.pp svneol=native#text/plain tests/test/tobjc20.pp svneol=native#text/plain tests/test/tobjc21.pp svneol=native#text/plain tests/test/tobjc22.pp svneol=native#text/plain +tests/test/tobjc22a.pp svneol=native#text/plain tests/test/tobjc23.pp svneol=native#text/plain tests/test/tobjc24.pp svneol=native#text/plain tests/test/tobjc25.pp svneol=native#text/plain diff --git a/compiler/defcmp.pas b/compiler/defcmp.pas index d9ebbbf449..475b6a6282 100644 --- a/compiler/defcmp.pas +++ b/compiler/defcmp.pas @@ -1268,7 +1268,7 @@ implementation eq:=te_convert_l1; end { All Objective-C classes are compatible with ID } - else if is_objcclass(def_to) and + else if is_objc_class_or_protocol(def_to) and (def_from=objc_idtype) then begin doconv:=tc_equal; diff --git a/compiler/symtable.pas b/compiler/symtable.pas index 1233b809dc..e5cc583f09 100644 --- a/compiler/symtable.pas +++ b/compiler/symtable.pas @@ -1981,6 +1981,7 @@ implementation var hashedid : THashedIDString; orgclass : tobjectdef; + i : longint; begin orgclass:=classh; { The contextclassh is used for visibility. The classh must be equal to @@ -1991,7 +1992,9 @@ implementation internalerror(200811161); result:=false; hashedid.id:=s; - while assigned(classh) do + { an Objective-C protocol can inherit from multiple other protocols + -> uses ImplementedInterfaces instead } + if is_objcprotocol(classh) then begin srsymtable:=classh.symtable; srsym:=tsym(srsymtable.FindWithHash(hashedid)); @@ -2002,7 +2005,30 @@ implementation result:=true; exit; end; - classh:=classh.childof; + for i:=0 to classh.ImplementedInterfaces.count-1 do + begin + if searchsym_in_class(TImplementedInterface(classh.ImplementedInterfaces[i]).intfdef,contextclassh,s,srsym,srsymtable) then + begin + result:=true; + exit; + end; + end; + end + else + begin + while assigned(classh) do + begin + srsymtable:=classh.symtable; + srsym:=tsym(srsymtable.FindWithHash(hashedid)); + if assigned(srsym) and + is_visible_for_object(srsym,contextclassh) then + begin + addsymref(srsym); + result:=true; + exit; + end; + classh:=classh.childof; + end; end; if is_objcclass(orgclass) then result:=search_class_helper(orgclass,s,srsym,srsymtable) diff --git a/tests/test/tobjc22a.pp b/tests/test/tobjc22a.pp new file mode 100644 index 0000000000..0614733dd2 --- /dev/null +++ b/tests/test/tobjc22a.pp @@ -0,0 +1,67 @@ +{ %target=darwin } +{ %cpu=powerpc,powerpc64,i386,x86_64,arm } + +{ Written by Jonas Maebe in 2009, released into the public domain } + +program protocoltest; + +{$mode objfpc}{$H+} +{$modeswitch objectivec1} + +type + MyProtocolA = objcprotocol + function newMethod: longint; message 'n'; + end; + + MyProtocolB = objcprotocol(MyProtocolA) + class function newClassMethod: longint; message 'newClassMethod'; + end; + + + { TMyObject } + + TMyObjectA = objcclass(NSObject, MyProtocolA) + function newMethod: longint; + end; + + TMyObjectB = objcclass(NSObject,MyProtocolB) + function newMethod: longint; + class function newClassMethod: longint; + end; + +{ TMyObjectA } + +function TMyObjectA.newMethod: longint; +begin + result:=1; +end; + +{ TMyObjectB } + +function TMyObjectB.newMethod: longint; +begin + result:=3; +end; + +class function TMyObjectB.newClassMethod: longint; +begin + result:=4; +end; + + +var + a : MyProtocolA; + b : MyProtocolB; +begin + a:=TMyObjectA.alloc.init; + b:=TMyObjectB.alloc.init; + if a.newMethod<>1 then + halt(1); + if b.newMethod<>3 then + halt(3); + if b.newclassmethod<>4 then + halt(4); + id(a).release; + id(b).release; +end. +