Re: [fpc-devel] Implicit function specialization precedence
Am 15.05.2021 um 20:08 schrieb Ryan Joseph via fpc-devel: On May 15, 2021, at 10:49 AM, Ryan Joseph wrote: Also it looks like ChangeOwnerAndName isn't making the compiler happy. Sorry for the noise, I figured out it was because the name had spaces. How should I make the name then? I'm doing this for now which is certainly unique but it's not standard. newtype:=ctypesym.create(def.fullownerhierarchyname(false)+typName[def.typ]+'$'+def.unique_id_str,def); It will make names like below which don't upset the assembler. SOMETESTUNIT.arraydef$5 Anyways, I put up a patch on the bug tracker (https://bugs.freepascal.org/view.php?id=35261) for you to review and see if I did this right. I had already wondered why that worked previously. But yes, that approach is better. Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Am 15.05.2021 um 18:27 schrieb Ryan Joseph via fpc-devel: On May 13, 2021, at 2:38 PM, Sven Barth wrote: Ah, you need to use ChangeOwnerAndName then and simply pass in the same name you used for the constructor (cause otherwise it tries to use the name that is currently stored in the list). Looking at this again today and I have yet another question to confirm. I create one of the types using ctypesym.create but the others were just references from the system unit. We only want to change owner of the symbol I create, right? Not the system unit ones? If not changing owner maybe we need to add some ref count or something? just confirming to make sure. You only need to change the owner of those you create using ctypesym.create. The others are preexisting and you must not touch them in any way. Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On May 15, 2021, at 10:49 AM, Ryan Joseph wrote: > > Also it looks like ChangeOwnerAndName isn't making the compiler happy. Sorry for the noise, I figured out it was because the name had spaces. How should I make the name then? I'm doing this for now which is certainly unique but it's not standard. newtype:=ctypesym.create(def.fullownerhierarchyname(false)+typName[def.typ]+'$'+def.unique_id_str,def); It will make names like below which don't upset the assembler. SOMETESTUNIT.arraydef$5 Anyways, I put up a patch on the bug tracker (https://bugs.freepascal.org/view.php?id=35261) for you to review and see if I did this right. Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On May 15, 2021, at 10:27 AM, Ryan Joseph wrote: > > Looking at this again today and I have yet another question to confirm. I > create one of the types using ctypesym.create but the others were just > references from the system unit. We only want to change owner of the symbol I > create, right? Not the system unit ones? If not changing owner maybe we need > to add some ref count or something? just confirming to make sure. Also it looks like ChangeOwnerAndName isn't making the compiler happy. The dynamic array creates an unnamed typesym like this. (def is the array def for [1,2,3]) newtype:=ctypesym.create(def.typename,def); newtype.owner:=def.owner; And specialized like this: generic procedure DoThis(p1: T); begin end; begin DoThis([1,2,3]); end; Then during assembling I get these errors. Assembling (pipe) /Users/ryanjoseph/Developer/Projects/FPC/macro_test/output/timpfuncspez0.s :40:50: error: unexpected token in directive .globl _P$TIMPFUNCSPEZ19_$$_DOTHIS$1$CRCC2373297${Array Of Const/Constant Open} Array of ShortInt ^ :41:60: error: unexpected token in directive .private_extern _P$TIMPFUNCSPEZ19_$$_DOTHIS$1$CRCC2373297${Array Of Const/Constant Open} Array of ShortInt ^ :42:44: error: unknown token in expression _P$TIMPFUNCSPEZ19_$$_DOTHIS$1$CRCC2373297${Array Of Const/Constant Open} Array of ShortInt: ^ :117:50: error: invalid register name call_P$TIMPFUNCSPEZ19_$$_DOTHIS$1$CRCC2373297${Array Of Const/Constant Open} Array of ShortInt ^ :117:50: error: Expected an op-mask register at this point call_P$TIMPFUNCSPEZ19_$$_DOTHIS$1$CRCC2373297${Array Of Const/Constant Open} Array of ShortInt ^ :283:50: error: unexpected token in '.quad' directive .quad _P$TIMPFUNCSPEZ19_$$_DOTHIS$1$CRCC2373297${Array Of Const/Constant Open} Array of ShortInt ^ error: There were 1 errors compiling module, stopping error: Compilation aborted Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On May 13, 2021, at 2:38 PM, Sven Barth wrote: > > Ah, you need to use ChangeOwnerAndName then and simply pass in the same name > you used for the constructor (cause otherwise it tries to use the name that > is currently stored in the list). Looking at this again today and I have yet another question to confirm. I create one of the types using ctypesym.create but the others were just references from the system unit. We only want to change owner of the symbol I create, right? Not the system unit ones? If not changing owner maybe we need to add some ref count or something? just confirming to make sure. function create_unamed_typesym(def:tdef): tsym; var newtype: tsym; begin newtype:=nil; if is_conststring_array(def) then begin { for constant strings we need to respect various modeswitches } if (cs_refcountedstrings in current_settings.localswitches) then begin if m_default_unicodestring in current_settings.modeswitches then newtype:=cunicodestringtype.typesym else newtype:=cansistringtype.typesym; end else newtype:=cshortstringtype.typesym; end else if def.typ=stringdef then newtype:=tstringdef(def).get_default_string_type.typesym else begin newtype:=ctypesym.create(def.typename,def); newtype.owner:=def.owner; end; if newtype=nil then internalerror(2021020904); result:=newtype; end; Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Am 12.05.2021 um 17:50 schrieb Ryan Joseph via fpc-devel: On May 9, 2021, at 1:30 AM, Sven Barth wrote: Essentially it will boil down to sym.ChangeOwner(pd.parast) However you need to keep the Owner (which is different from what you change with ChangeOwner) different as otherwise is_specialization of the procdef will not work correctly. I'm saving the storing symbols in tcallcandiates so they can be available when maybe_add_pending_specialization is called once the call node chooses the specialization, and then I ran into this problem. The symbol I make in create_unamed_typesym has FOwner nil so calling TFPHashObject.ChangeOwner crashes. Did I not make the symbol correctly or do I need to do something before calling ChangeOwner? Ah, you need to use ChangeOwnerAndName then and simply pass in the same name you used for the constructor (cause otherwise it tries to use the name that is currently stored in the list). Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On May 9, 2021, at 1:30 AM, Sven Barth wrote: > > Essentially it will boil down to sym.ChangeOwner(pd.parast) > > However you need to keep the Owner (which is different from what you change > with ChangeOwner) different as otherwise is_specialization of the procdef > will not work correctly. > I'm saving the storing symbols in tcallcandiates so they can be available when maybe_add_pending_specialization is called once the call node chooses the specialization, and then I ran into this problem. The symbol I make in create_unamed_typesym has FOwner nil so calling TFPHashObject.ChangeOwner crashes. Did I not make the symbol correctly or do I need to do something before calling ChangeOwner? Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Ryan Joseph via fpc-devel schrieb am Sa., 8. Mai 2021, 22:33: > > > > On May 8, 2021, at 12:04 PM, Sven Barth > wrote: > > > > You need to use ChangeOwner as well, but as I wrote you need to pay > attention for which created symbol you do it at what time. > > Ok, maybe this is what I got wrong didn't use ChangeOwner. When you say > "add to" what exactly do you mean? Please post a single line code snippet > even. Thanks. > Essentially it will boil down to sym.ChangeOwner(pd.parast) However you need to keep the Owner (which is different from what you change with ChangeOwner) different as otherwise is_specialization of the procdef will not work correctly. Regards, Sven > ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On May 8, 2021, at 12:04 PM, Sven Barth wrote: > > You need to use ChangeOwner as well, but as I wrote you need to pay attention > for which created symbol you do it at what time. Ok, maybe this is what I got wrong didn't use ChangeOwner. When you say "add to" what exactly do you mean? Please post a single line code snippet even. Thanks. Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Am 22.04.2021 um 17:52 schrieb Ryan Joseph via fpc-devel: On Apr 16, 2021, at 11:35 AM, Ryan Joseph wrote: Got this all integrated and put up the changes to https://bugs.freepascal.org/view.php?id=35261. Now I'm waiting for another final review. :) The next thing to do now is to handle a memory leak. From the bug tracker: You essentially need to make sure the symbols become part of the specialization that is picked in the end (cause you create the symbols in make_param_list only once, but you might use them for multiple generic overloads of which at most one will be picked). What you might be able to do is the following (have not looked at it in detail yet): - those symbols you directly add to genericparams you ensure that their owner is the specialization right away (after generate_specialization_phase1) - those symbols you add to callerparams you'll probably have to bubble up to htypechk and have that somehow add these syms to the final specialization if it is picked and free them otherwise My response: I looked at this again and it looks like there is just one place where we can leak memory now and that's those lines from create_unamed_typesym. newtype:=ctypesym.create(def.typename,def); newtype.owner:=def.owner; I set the owner of the new typesym to the target def but what does that even do? I think you're saying I need to set the owner of that symbol to be a procdef but I don't see how the helps the memory get freed. I would think when the specialization is freed we could check some flag in the generic params and if they are not owned then we free them then. And with that I'm stuck. :) I don't know how the symbols in the compiler are memory managed but I don't see setting their owner is helping them get freed. I've tried setting their owner to the procdef.owner being specialized but that does't do anything either. I guess I don't understand what adding them to "the final specialization" means so please clarify. My naive assumption would be to add them to a list in tspecializationcontext and free them when the content is freed because I don't think the symbols are used after the implicit specialization is finished and a proc def is produced, but I may be wrong about that. You need to use ChangeOwner as well, but as I wrote you need to pay attention for which created symbol you do it at what time. The ones you create in is_possible_specialization you need to add to the specialization you do in the following generate_implicit_specialization as those are only created for that specific specialization (though you also need to free it if you leave is_possible_specialization with False which you currently don't do). The ones you create in make_param_list you need to pass back to htypechk so that they can either be added to the final specialization (if selected out of multiple ones) or to be freed if none of the ones created by that invocation to try_implicit_specialization is picked. That is because they would be shared by all the specializations. Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Am 06.05.2021 um 17:33 schrieb Ryan Joseph via fpc-devel: I found something sneaky I'd like to confirm before I decide what to do about it. 1) "T" in TAnyClass is specialized as Integer from the first parameter with TSomeClass (which is TAnyClass). 2) "U" is getting specialized as String by looking at the parameters in Compare() in which "U"(the second generic parameter) is String. This specializes the procedure correctly but it uses a very sneaky method which is very hard to discern. I feel like that if a generic parameter is already used (like T in specialize TCallback) then no further attempt should be made to look at the parameters and in the example below "U" would not be found and the function would fail to implicitly specialize. There is nothing sneaky if one defines that the parameters are evaluated left to right and those that are already found and used later on (like T) are simply fixed then thus in the example it uses the already found type. But if the picked type wouldn't mach, for example if TCallback<,> would be declared as TCallback instead then trying to specialize the function would simply fail. Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
I found something sneaky I'd like to confirm before I decide what to do about it. 1) "T" in TAnyClass is specialized as Integer from the first parameter with TSomeClass (which is TAnyClass). 2) "U" is getting specialized as String by looking at the parameters in Compare() in which "U"(the second generic parameter) is String. This specializes the procedure correctly but it uses a very sneaky method which is very hard to discern. I feel like that if a generic parameter is already used (like T in specialize TCallback) then no further attempt should be made to look at the parameters and in the example below "U" would not be found and the function would fail to implicitly specialize. == type generic TAnyClass = class type TElem = U; end; type TSomeClass = specialize TAnyClass; type generic TCallback = function(a: T; b: U): integer; function Compare(a: TSomeClass.TElem; b: string): integer; begin result := 1; end; generic procedure DoThis(aClass: specialize TAnyClass; callback: specialize TCallback); begin callback(1, 'string'); end; begin DoThis(TSomeClass.Create, @Compare); end. Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On Apr 22, 2021, at 9:52 AM, Ryan Joseph wrote: > >> Got this all integrated and put up the changes to >> https://bugs.freepascal.org/view.php?id=35261. Now I'm waiting for another >> final review. :) > > The next thing to do now is to handle a memory leak. From the bug tracker: I just noticed a week has passed on this. Sven, do you have a reply to my previous message to clarify a little? I could make a guess at what you want but I'll probably just waste more time doing the wrong thing. :P Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On Apr 16, 2021, at 11:35 AM, Ryan Joseph wrote: > > Got this all integrated and put up the changes to > https://bugs.freepascal.org/view.php?id=35261. Now I'm waiting for another > final review. :) The next thing to do now is to handle a memory leak. From the bug tracker: > You essentially need to make sure the symbols become part of the > specialization that is picked in the end (cause you create the symbols in > make_param_list only once, but you might use them for multiple generic > overloads of which at most one will be picked). > What you might be able to do is the following (have not looked at it in > detail yet): > - those symbols you directly add to genericparams you ensure that their owner > is the specialization right away (after generate_specialization_phase1) > - those symbols you add to callerparams you'll probably have to bubble up to > htypechk and have that somehow add these syms to the final specialization if > it is picked and free them otherwise My response: > I looked at this again and it looks like there is just one place where we can > leak memory now and that's those lines from create_unamed_typesym. > > newtype:=ctypesym.create(def.typename,def); > newtype.owner:=def.owner; > > I set the owner of the new typesym to the target def but what does that even > do? I think you're saying I need to set the owner of that symbol to be a > procdef but I don't see how the helps the memory get freed. I would think > when the specialization is freed we could check some flag in the generic > params and if they are not owned then we free them then. And with that I'm stuck. :) I don't know how the symbols in the compiler are memory managed but I don't see setting their owner is helping them get freed. I've tried setting their owner to the procdef.owner being specialized but that does't do anything either. I guess I don't understand what adding them to "the final specialization" means so please clarify. My naive assumption would be to add them to a list in tspecializationcontext and free them when the content is freed because I don't think the symbols are used after the implicit specialization is finished and a proc def is produced, but I may be wrong about that. Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On Apr 16, 2021, at 2:44 AM, Sven Barth via fpc-devel > wrote: > > Yes, do that for now. > Got this all integrated and put up the changes to https://bugs.freepascal.org/view.php?id=35261. Now I'm waiting for another final review. :) Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Ryan Joseph via fpc-devel schrieb am Fr., 16. Apr. 2021, 00:38: > > > > On Apr 14, 2021, at 3:49 PM, Ryan Joseph wrote: > > > > It works but it thinks this array is array of const also so it's too > strict I believe. > > > > ['aaa', 'bbb']; > > About this, shouldn't we just be doing this? Any array constructor that > has elements which are which are incompatible is "array of const"? from > tarrayconstructornode.pass_typecheck: > > if eq=te_incompatible then >diff:=true; Yes, do that for now. Regards, Sven > ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On Apr 14, 2021, at 3:49 PM, Ryan Joseph wrote: > > It works but it thinks this array is array of const also so it's too strict I > believe. > > ['aaa', 'bbb']; About this, shouldn't we just be doing this? Any array constructor that has elements which are which are incompatible is "array of const"? from tarrayconstructornode.pass_typecheck: if eq=te_incompatible then diff:=true; Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On Apr 14, 2021, at 11:39 PM, Sven Barth wrote: > > Well, then I'll have to improve the check. But for now you can continue, > right? I can continue but if I include the check some tests will fail. Currently I've only made some changes in create_unamed_typesym and now this check to reject array of const. Everything else is done AKAIK unless we discover more bugs in the tests (which I've uploaded on the bug tracker). Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Am 14.04.2021 um 23:49 schrieb Ryan Joseph via fpc-devel: On Apr 14, 2021, at 2:33 PM, Sven Barth wrote: Had a bit of time to look at this. You can try the attached patch. You can then check for both ado_IsConstructor and ado_IsArrayOfConst to detect such a mixed array. It works but it thinks this array is array of const also so it's too strict I believe. ['aaa', 'bbb']; Well, then I'll have to improve the check. But for now you can continue, right? Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On Apr 14, 2021, at 2:33 PM, Sven Barth wrote: > > Had a bit of time to look at this. You can try the attached patch. You can > then check for both ado_IsConstructor and ado_IsArrayOfConst to detect such a > mixed array. It works but it thinks this array is array of const also so it's too strict I believe. ['aaa', 'bbb']; Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Am 11.04.2021 um 23:38 schrieb Ryan Joseph via fpc-devel: On Apr 11, 2021, at 3:33 PM, Sven Barth wrote: Looking at it, it could be that there is a bug in tarrayconstructornode.pass_typecheck that hasn't really surfaced yet... I'll have to look at that first, but I don't know when I'll have the time for that. sure I'll just leave it as is for now then. By the time the overloading happens it must know the array constructor is array of const but it should ideally be known by the time tarrayconstructornode.pass_typecheck is executed. Had a bit of time to look at this. You can try the attached patch. You can then check for both ado_IsConstructor and ado_IsArrayOfConst to detect such a mixed array. Regards, Sven diff --git a/compiler/defutil.pas b/compiler/defutil.pas index 852d2cfa5a..b9c50dfa87 100644 --- a/compiler/defutil.pas +++ b/compiler/defutil.pas @@ -821,7 +821,10 @@ implementation function is_array_of_const(p : tdef) : boolean; begin result:=(p.typ=arraydef) and - (ado_IsArrayOfConst in tarraydef(p).arrayoptions); + (ado_IsArrayOfConst in tarraydef(p).arrayoptions) and + { consider it an array-of-const in the strict sense only if it + isn't an array constructor } + not (ado_IsConstructor in tarraydef(p).arrayoptions); end; function is_conststring_array(p: tdef): boolean; diff --git a/compiler/nld.pas b/compiler/nld.pas index 7be26db2bc..bdea9cfb0f 100644 --- a/compiler/nld.pas +++ b/compiler/nld.pas @@ -1113,6 +1113,7 @@ implementation hdef : tdef; hp: tarrayconstructornode; len : longint; +diff, varia : boolean; eq: tequaltype; hnodetype : tnodetype; @@ -1136,6 +1137,7 @@ implementation hnodetype:=errorn; len:=0; varia:=false; +diff:=false; if assigned(left) then begin hp:=self; @@ -1164,6 +1166,8 @@ implementation end else eq:=compare_defs(hdef,hp.left.resultdef,hp.left.nodetype); + if eq___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On Apr 11, 2021, at 3:33 PM, Sven Barth wrote: > > Looking at it, it could be that there is a bug in > tarrayconstructornode.pass_typecheck that hasn't really surfaced yet... I'll > have to look at that first, but I don't know when I'll have the time for that. sure I'll just leave it as is for now then. By the time the overloading happens it must know the array constructor is array of const but it should ideally be known by the time tarrayconstructornode.pass_typecheck is executed. Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Am 11.04.2021 um 22:27 schrieb Ryan Joseph via fpc-devel: On Apr 10, 2021, at 9:47 AM, Ryan Joseph wrote: Just checked and pass_typecheck is called before overloading but ado_IsVariant is simply never set for that array. In tarraydef.GetTypeName you can see that "array of const" is associated with many flags so maybe we need to make a new flag which means "non-uniform elements"? I could probably easily build that into pass_typecheck for array constructors. ... if (ado_isarrayofconst in arrayoptions) or (ado_isConstructor in arrayoptions) then begin if (ado_isvariant in arrayoptions) or ((highrange=-1) and (lowrange=0)) then GetTypeName:='Array Of Const' else GetTypeName:='{Array Of Const/Constant Open} Array of '+elementdef.typename; end Any word on what I should do about this? If those flags present are not sufficient I'll add another flag but if that's not acceptable I'll simply have to allow the user to specialize with these array types, even though they will fail later one when the function is selected during overloading. Once I know that I'll submit another patch including the other changes that were requested. Looking at it, it could be that there is a bug in tarrayconstructornode.pass_typecheck that hasn't really surfaced yet... I'll have to look at that first, but I don't know when I'll have the time for that. Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On Apr 10, 2021, at 9:47 AM, Ryan Joseph wrote: > > Just checked and pass_typecheck is called before overloading but > ado_IsVariant is simply never set for that array. In tarraydef.GetTypeName > you can see that "array of const" is associated with many flags so maybe we > need to make a new flag which means "non-uniform elements"? I could probably > easily build that into pass_typecheck for array constructors. > > ... > if (ado_isarrayofconst in arrayoptions) or > (ado_isConstructor in arrayoptions) then > begin > if (ado_isvariant in arrayoptions) or ((highrange=-1) and > (lowrange=0)) then > GetTypeName:='Array Of Const' > else > GetTypeName:='{Array Of Const/Constant Open} Array of > '+elementdef.typename; > end > Any word on what I should do about this? If those flags present are not sufficient I'll add another flag but if that's not acceptable I'll simply have to allow the user to specialize with these array types, even though they will fail later one when the function is selected during overloading. Once I know that I'll submit another patch including the other changes that were requested. Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On Apr 10, 2021, at 9:18 AM, Ryan Joseph wrote: > > I checked before and here's what I got. Maybe pass_typecheck hasn't been > called yet? If not I'll have to reproduce that code and determine how it > knows the elements are not uniform. Thanks. Just checked and pass_typecheck is called before overloading but ado_IsVariant is simply never set for that array. In tarraydef.GetTypeName you can see that "array of const" is associated with many flags so maybe we need to make a new flag which means "non-uniform elements"? I could probably easily build that into pass_typecheck for array constructors. ... if (ado_isarrayofconst in arrayoptions) or (ado_isConstructor in arrayoptions) then begin if (ado_isvariant in arrayoptions) or ((highrange=-1) and (lowrange=0)) then GetTypeName:='Array Of Const' else GetTypeName:='{Array Of Const/Constant Open} Array of '+elementdef.typename; end Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On Apr 10, 2021, at 6:54 AM, Sven Barth wrote: > > As an additional note: if you take a look at > tarrayconstructornode.pass_typecheck you can see that the array type always > has the ado_IsConstructor set and if it contains of incompatible types the > ado_IsVariant is set as well. So if ado_IsVariant is *not* set, then you can > rely on the elementdef of the arraydef. I checked before and here's what I got. Maybe pass_typecheck hasn't been called yet? If not I'll have to reproduce that code and determine how it knows the elements are not uniform. Thanks. elecount:4 typesym:{Array Of Const/Constant Open} Array of ShortInt ado_IsConvertedPointer: FALSE ado_IsDynamicArray: FALSE ado_IsVariant: FALSE ado_IsConstructor: TRUE ado_IsArrayOfConst: FALSE ado_IsConstString: FALSE ado_IsBitPacked: FALSE ado_IsVector: FALSE ado_IsGeneric: FALSE writeln('elecount:',tarraydef(caller_def).elecount); writeln('typesym:',tarraydef(caller_def).typesym.realname); writeln('ado_IsConvertedPointer: ',ado_IsConvertedPointer in tarraydef(caller_def).arrayoptions); writeln('ado_IsDynamicArray: ',ado_IsDynamicArray in tarraydef(caller_def).arrayoptions); writeln('ado_IsVariant: ',ado_IsVariant in tarraydef(caller_def).arrayoptions); writeln('ado_IsConstructor: ',ado_IsConstructor in tarraydef(caller_def).arrayoptions); writeln('ado_IsArrayOfConst: ',ado_IsArrayOfConst in tarraydef(caller_def).arrayoptions); writeln('ado_IsConstString: ',ado_IsConstString in tarraydef(caller_def).arrayoptions); writeln('ado_IsBitPacked: ',ado_IsBitPacked in tarraydef(caller_def).arrayoptions); writeln('ado_IsVector: ',ado_IsVector in tarraydef(caller_def).arrayoptions); writeln('ado_IsGeneric: ',ado_IsGeneric in tarraydef(caller_def).arrayoptions); Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Am 10.04.2021 um 10:38 schrieb Sven Barth: Am 10.04.2021 um 00:43 schrieb Ryan Joseph via fpc-devel: On Apr 9, 2021, at 4:31 PM, Sven Barth via fpc-devel wrote: You mean what you did for is_array_literal? A pure array constructor can be found with is_array_constructor, though it might be better to use is_open_array, cause someone might pass an open array parameter to a generic function (those will be unnamed as well). Maybe the email didn't go through? How to identify this "array of const constructor" type. I want to reject these for implicit specialization but I can't identity them. DoThis([ 1, 'string', 'c', TObject.Create ]) You can't really differentiate these from array constructors with just one type, because the type is only really determined once the overload is chosen as that kind of array could be an array of const, an array of Variant or maybe even an array of LongInt if there are suitable operator overloads in scope. So, yeah, it's kinda hard to decide what type to use... *Now* your other mail arrived. ;) As an additional note: if you take a look at tarrayconstructornode.pass_typecheck you can see that the array type always has the ado_IsConstructor set and if it contains of incompatible types the ado_IsVariant is set as well. So if ado_IsVariant is *not* set, then you can rely on the elementdef of the arraydef. Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Am 10.04.2021 um 00:43 schrieb Ryan Joseph via fpc-devel: On Apr 9, 2021, at 4:31 PM, Sven Barth via fpc-devel wrote: You mean what you did for is_array_literal? A pure array constructor can be found with is_array_constructor, though it might be better to use is_open_array, cause someone might pass an open array parameter to a generic function (those will be unnamed as well). Maybe the email didn't go through? How to identify this "array of const constructor" type. I want to reject these for implicit specialization but I can't identity them. DoThis([ 1, 'string', 'c', TObject.Create ]) You can't really differentiate these from array constructors with just one type, because the type is only really determined once the overload is chosen as that kind of array could be an array of const, an array of Variant or maybe even an array of LongInt if there are suitable operator overloads in scope. So, yeah, it's kinda hard to decide what type to use... Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On Apr 9, 2021, at 4:31 PM, Sven Barth via fpc-devel > wrote: > > You mean what you did for is_array_literal? A pure array constructor can be > found with is_array_constructor, though it might be better to use > is_open_array, cause someone might pass an open array parameter to a generic > function (those will be unnamed as well). Maybe the email didn't go through? How to identify this "array of const constructor" type. I want to reject these for implicit specialization but I can't identity them. DoThis([ 1, 'string', 'c', TObject.Create ]) Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Am 09.04.2021 um 23:52 schrieb Ryan Joseph via fpc-devel: On Apr 9, 2021, at 3:08 PM, Sven Barth wrote: Possibly, yes... You could provide the various utility functions in a separate patch. Well I'm going to use them for this patch so they would all be batched together. Any idea about the "array of const" issue I raised in the other email? Once that's done I'll submit another very patch. Getting very close now unless I missed some test cases... You mean what you did for is_array_literal? A pure array constructor can be found with is_array_constructor, though it might be better to use is_open_array, cause someone might pass an open array parameter to a generic function (those will be unnamed as well). Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On Apr 9, 2021, at 3:08 PM, Sven Barth wrote: > > Possibly, yes... > > You could provide the various utility functions in a separate patch. Well I'm going to use them for this patch so they would all be batched together. Any idea about the "array of const" issue I raised in the other email? Once that's done I'll submit another very patch. Getting very close now unless I missed some test cases... Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Am 09.04.2021 um 18:12 schrieb Ryan Joseph via fpc-devel: On Apr 8, 2021, at 11:37 PM, Sven Barth via fpc-devel wrote: That is because before the introduction of type helpers such functions weren't really needed. Other mechanisms caught such constants, but for both type helpers and these implicit specializations it's hard to do it another way. Ok then I'll add a is_constant_string function for later use. What about this function I'm using, should it be in defutils.pas also? I need this so I can distinguish "unnamed array literals" like ['a','b','c'] from short strings like 'abc'. They may be internally identical to arrays but conceptionally they are different. Not sure about the naming so I chose "array literal" but "anonymous array" would make sense also. function is_array_literal(def:tdef): boolean; begin result := (def.typ=arraydef) and not is_constant_string(def); end; This will lead to false assumptions, cause it will return True for *any* arraydef that's not a constant string. Btw, this block (from create_unamed_typesym) could be a useful helper function in tstringdef, such as "get_default_system_type". I needed something similar to get the char type for a string def (and added that method already) so this is another logical extension to that. case tstringdef(def).stringtype of st_shortstring: newtype:=search_system_type('SHORTSTRING'); { st_longstring is currently not supported but when it is this case will need to be supplied } st_longstring: internalerror(2021040801); st_ansistring: newtype:=search_system_type('ANSISTRING'); st_widestring: newtype:=search_system_type('WIDESTRING'); st_unicodestring: newtype:=search_system_type('UNICODESTRING'); end Possibly, yes... You could provide the various utility functions in a separate patch. Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
I just realized one more type introspection related issue. This currently will specialize as DoThis because the array constructor element type is "shortint" as is derived from the first element 1. This of course is not correct so I'd like to reject "array of const constructors" but I don't see how to know what when I get this type. I thought the tarraydef would have ado_IsArrayOfConst set but it does not, so how do I know the array constructor has multiple element types? generic procedure DoThis(a: array of T); begin end; begin DoThis([ 1, 'string', 'c', TObject.Create ]) end. Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On Apr 8, 2021, at 11:37 PM, Sven Barth via fpc-devel > wrote: > > That is because before the introduction of type helpers such functions > weren't really needed. Other mechanisms caught such constants, but for both > type helpers and these implicit specializations it's hard to do it another > way. Ok then I'll add a is_constant_string function for later use. What about this function I'm using, should it be in defutils.pas also? I need this so I can distinguish "unnamed array literals" like ['a','b','c'] from short strings like 'abc'. They may be internally identical to arrays but conceptionally they are different. Not sure about the naming so I chose "array literal" but "anonymous array" would make sense also. function is_array_literal(def:tdef): boolean; begin result := (def.typ=arraydef) and not is_constant_string(def); end; Btw, this block (from create_unamed_typesym) could be a useful helper function in tstringdef, such as "get_default_system_type". I needed something similar to get the char type for a string def (and added that method already) so this is another logical extension to that. case tstringdef(def).stringtype of st_shortstring: newtype:=search_system_type('SHORTSTRING'); { st_longstring is currently not supported but when it is this case will need to be supplied } st_longstring: internalerror(2021040801); st_ansistring: newtype:=search_system_type('ANSISTRING'); st_widestring: newtype:=search_system_type('WIDESTRING'); st_unicodestring: newtype:=search_system_type('UNICODESTRING'); end Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Am 09.04.2021 um 04:20 schrieb Ryan Joseph via fpc-devel: On Apr 8, 2021, at 3:53 PM, Sven Barth wrote: 1. you should not blindly assume that the def is a stringdef if it's not an arraydef; at least use an internalerror to protect against problems here 2. if it's really a stringdef and the return type is st_shortstring you should indeed use SHORTSTRING (it's only constant strings which are a bit more, let's say "dynamic") 3. do an internalerror for st_longstring as those are currently not implemented 4. due to 2. you can move the case of newtype=nil into the if-clause with the arraydef Otherwise, yes, the check for the string type is correct. I didn't know how constant strings we identified until just now so I can correct that. Can we make "(def.typ=arraydef) and (ado_isconststring in tarraydef(def).arrayoptions)" into a function in defutils.pas and call it is_constant_string? That would have been easily visible to me and lead me in the right direction from the start. I also had problems with array literals like [1,2,3] which there is no clear utility function for and prompted me to make is_array_literal() which is private right now (and probably not very correct in design). Moving that to a public space would be sensible also I think. That is because before the introduction of type helpers such functions weren't really needed. Other mechanisms caught such constants, but for both type helpers and these implicit specializations it's hard to do it another way. Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On Apr 8, 2021, at 3:53 PM, Sven Barth wrote: > > 1. you should not blindly assume that the def is a stringdef if it's not an > arraydef; at least use an internalerror to protect against problems here > 2. if it's really a stringdef and the return type is st_shortstring you > should indeed use SHORTSTRING (it's only constant strings which are a bit > more, let's say "dynamic") > 3. do an internalerror for st_longstring as those are currently not > implemented > 4. due to 2. you can move the case of newtype=nil into the if-clause with the > arraydef > > Otherwise, yes, the check for the string type is correct. I didn't know how constant strings we identified until just now so I can correct that. Can we make "(def.typ=arraydef) and (ado_isconststring in tarraydef(def).arrayoptions)" into a function in defutils.pas and call it is_constant_string? That would have been easily visible to me and lead me in the right direction from the start. I also had problems with array literals like [1,2,3] which there is no clear utility function for and prompted me to make is_array_literal() which is private right now (and probably not very correct in design). Moving that to a public space would be sensible also I think. Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Am 08.04.2021 um 19:28 schrieb Ryan Joseph via fpc-devel: On Apr 7, 2021, at 1:56 PM, Ryan Joseph wrote: Ok, so with $H+ constant strings will be specialized as AnsiStrings. And there is another unicode string mode I should do a similar thing with? Also if you happen to know where I can get the state of $H+ that would be helpful otherwise I need to track it down in the debugger. :) I think I got this part figured out (see function below). I'm going to upload another patch and a bunch of unit tests on the bug tracker but I'm leaving my latest ambiguous function call as-is until further notice. it's sneaky like it is but it follows rules which you can manipulate using casting. == function create_unamed_typesym(def:tdef): tsym; var newtype: tsym; begin newtype:=nil; if is_stringlike(def) then begin if (def.typ=arraydef) and (ado_isconststring in tarraydef(def).arrayoptions) then newtype:=nil else case tstringdef(def).stringtype of st_shortstring: newtype:=nil; st_longstring, st_ansistring: newtype:=search_system_type('ANSISTRING'); st_widestring: newtype:=search_system_type('WIDESTRING'); st_unicodestring: newtype:=search_system_type('UNICODESTRING'); end; { not better string type was found so chose the default string type } if newtype=nil then begin if (cs_refcountedstrings in current_settings.localswitches) then begin if m_default_unicodestring in current_settings.modeswitches then newtype:=search_system_type('UNICODESTRING') else newtype:=search_system_type('ANSISTRING'); end else newtype:=search_system_type('SHORTSTRING'); end; end else begin newtype:=ctypesym.create(def.typename,def); newtype.owner:=def.owner; end; if newtype=nil then internalerror(2021020904); result:=newtype; end; 1. you should not blindly assume that the def is a stringdef if it's not an arraydef; at least use an internalerror to protect against problems here 2. if it's really a stringdef and the return type is st_shortstring you should indeed use SHORTSTRING (it's only constant strings which are a bit more, let's say "dynamic") 3. do an internalerror for st_longstring as those are currently not implemented 4. due to 2. you can move the case of newtype=nil into the if-clause with the arraydef Otherwise, yes, the check for the string type is correct. Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Am 07.04.2021 um 23:21 schrieb Ryan Joseph via fpc-devel: With the requested changes I believe some precedence rules have changed. These both should be "Can't determine which overloaded function to call" errors or the non-generic should take precedence because the functions are ambiguous (by appearance at least). Currently the compiler thinks DoThis is better than the non-generic and this may be because it was specialized as DoThis because the parameter of "1" is a ShortInt. What should the rule be here? = procedure DoThis(a: word; b: word); begin end; generic procedure DoThis(a:T; b: word); begin end; begin DoThis(1,1); // DoThis end. In Delphi this takes the non-generic. But I think this comes into a region where things are not clearly documented, thus it's hard to get things "right". In theory one could move the generic check in front of the ordinal check and it should work, but it could get wonky again if you pass e.g. a LongInt into this (Delphi keeps insisting on using the non-generic with a LongInt constant parameter even though if you have two non-generic overloads it will complain that it violates the range of Word and ShortInt... go figure... - with a LongInt variable it will use the generic) Let it be as it is now... this will only result in headaches either way. = generic procedure DoThis(a:T; b: word); begin end; generic procedure DoThis(a: word; b: T); begin end; begin DoThis(1,1); // Can't determine which overloaded function to call end. = This is correct. Delphi behaves the same here (and it would be the same in the non-generic case with T being replaced by ShortInt). Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On Apr 7, 2021, at 1:56 PM, Ryan Joseph wrote: > > Ok, so with $H+ constant strings will be specialized as AnsiStrings. And > there is another unicode string mode I should do a similar thing with? Also > if you happen to know where I can get the state of $H+ that would be helpful > otherwise I need to track it down in the debugger. :) I think I got this part figured out (see function below). I'm going to upload another patch and a bunch of unit tests on the bug tracker but I'm leaving my latest ambiguous function call as-is until further notice. it's sneaky like it is but it follows rules which you can manipulate using casting. == function create_unamed_typesym(def:tdef): tsym; var newtype: tsym; begin newtype:=nil; if is_stringlike(def) then begin if (def.typ=arraydef) and (ado_isconststring in tarraydef(def).arrayoptions) then newtype:=nil else case tstringdef(def).stringtype of st_shortstring: newtype:=nil; st_longstring, st_ansistring: newtype:=search_system_type('ANSISTRING'); st_widestring: newtype:=search_system_type('WIDESTRING'); st_unicodestring: newtype:=search_system_type('UNICODESTRING'); end; { not better string type was found so chose the default string type } if newtype=nil then begin if (cs_refcountedstrings in current_settings.localswitches) then begin if m_default_unicodestring in current_settings.modeswitches then newtype:=search_system_type('UNICODESTRING') else newtype:=search_system_type('ANSISTRING'); end else newtype:=search_system_type('SHORTSTRING'); end; end else begin newtype:=ctypesym.create(def.typename,def); newtype.owner:=def.owner; end; if newtype=nil then internalerror(2021020904); result:=newtype; end; Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
With the requested changes I believe some precedence rules have changed. These both should be "Can't determine which overloaded function to call" errors or the non-generic should take precedence because the functions are ambiguous (by appearance at least). Currently the compiler thinks DoThis is better than the non-generic and this may be because it was specialized as DoThis because the parameter of "1" is a ShortInt. What should the rule be here? = procedure DoThis(a: word; b: word); begin end; generic procedure DoThis(a:T; b: word); begin end; begin DoThis(1,1); // DoThis end. = generic procedure DoThis(a:T; b: word); begin end; generic procedure DoThis(a: word; b: T); begin end; begin DoThis(1,1); // Can't determine which overloaded function to call end. = Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On Apr 7, 2021, at 1:42 PM, Sven Barth via fpc-devel > wrote: > > Yes, we want to change that for two reasons: > - the constant string might be larger than 255 characters > - ShortString is worse for passing as a by-value parameter (which will be the > default after all) than AnsiString or UnicodeString as ShortString is > completely copied while Ansi-/UnicodeString are only references with > reference count adjustments Ok, so with $H+ constant strings will be specialized as AnsiStrings. And there is another unicode string mode I should do a similar thing with? Also if you happen to know where I can get the state of $H+ that would be helpful otherwise I need to track it down in the debugger. :) Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Am 07.04.2021 um 18:16 schrieb Ryan Joseph via fpc-devel: On Apr 6, 2021, at 11:34 PM, Sven Barth wrote: In the second case the compiler will have the non-generic Test(String) due to the implicit operator as well as Test(LongInt) due to the implicit specialization. Here it will pick the generic one, because a call without a type conversion is considered better. I finally get what you're saying and get the correct results now after moving my check inside the if/then block. I didn't realize that the operator overload was causing a type conversion that the overloading system knew about. So the non-generic still wins unless the type conversion happened due to the operator overload and then the generic wins. Writeln(Test('Hello World')); // Test(String) Writeln(Test(42)); // Test Writeln(Test(String(42))); // Test(String) Good. :) As for $H+ do we really want string literals likes 'ABC' to change? I wouldn't think so. Here's my string literal type symbol conversion in create_unamed_typesym I'm using now: case tstringdef(def).stringtype of st_shortstring: newtype:=search_system_type('SHORTSTRING'); st_longstring, st_ansistring: newtype:=search_system_type('ANSISTRING'); st_widestring: newtype:=search_system_type('WIDESTRING'); st_unicodestring: newtype:=search_system_type('UNICODESTRING'); end; 'Hello World' is parsed as st_shortstring so we use System.ShortString for specialization. Given that I don't think I need to do anything with $H+. Yes, we want to change that for two reasons: - the constant string might be larger than 255 characters - ShortString is worse for passing as a by-value parameter (which will be the default after all) than AnsiString or UnicodeString as ShortString is completely copied while Ansi-/UnicodeString are only references with reference count adjustments Also your check is wrong as the def that returns True for is_stringlike might not be a stringdef. In the case of a constant string it's an arraydef with ado_ConstantString in arrayoptions (and that's how you can detect constant strings which *need* this treatment). Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On Apr 6, 2021, at 11:34 PM, Sven Barth wrote: > > In the second case the compiler will have the non-generic Test(String) due to > the implicit operator as well as Test(LongInt) due to the implicit > specialization. Here it will pick the generic one, because a call without a > type conversion is considered better. I finally get what you're saying and get the correct results now after moving my check inside the if/then block. I didn't realize that the operator overload was causing a type conversion that the overloading system knew about. So the non-generic still wins unless the type conversion happened due to the operator overload and then the generic wins. Writeln(Test('Hello World')); // Test(String) Writeln(Test(42)); // Test Writeln(Test(String(42))); // Test(String) As for $H+ do we really want string literals likes 'ABC' to change? I wouldn't think so. Here's my string literal type symbol conversion in create_unamed_typesym I'm using now: case tstringdef(def).stringtype of st_shortstring: newtype:=search_system_type('SHORTSTRING'); st_longstring, st_ansistring: newtype:=search_system_type('ANSISTRING'); st_widestring: newtype:=search_system_type('WIDESTRING'); st_unicodestring: newtype:=search_system_type('UNICODESTRING'); end; 'Hello World' is parsed as st_shortstring so we use System.ShortString for specialization. Given that I don't think I need to do anything with $H+. Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Am 06.04.2021 um 23:11 schrieb Ryan Joseph via fpc-devel: On Apr 6, 2021, at 12:57 PM, Sven Barth wrote: In the example you posted below, I agree with you, but that is not what I said. Look at my example again: Also could you please verify that $H+ isn't causing problems? The string literal 'Hello World' is a short string but "String" is an AnsiString so that may influence the results you're expecting. However even without the operator I don't know how to delineate between the explicit cast vs the non-explicit cast. Writeln(Test('Hello World')); Writeln(Test(String('Hello World'))); These both appear to be equal as far as is_better_candidate is concerned. First of *you* need to make sure that the type you pick for the generic parameter for a string constant is the correct one matching the $H+ directive as well as the UnicodeString modeswitch (and if the string constant contains WideChar elements it needs to be a UnicodeString anyway). That's where you currently search for the SHORTSTRING type. Then you only need to make sure that the check for generic vs. non-generic is in place as I said in the other mail and the compiler will do the rest for you. You don't need to do *anything*. Your task is merely to provide the compiler with the suitable overload candidates and a way to check their order and it will already do all the rest. Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Am 06.04.2021 um 22:47 schrieb Ryan Joseph via fpc-devel: On Apr 6, 2021, at 12:57 PM, Sven Barth wrote: In this specific case the two functions also are *not* ambigous, because for the non-generic Test the parameter requires an implicit conversion, but the implicit specialization does not. For example if there would be a "Test(aArg: LongInt)" instead of the generic the compiler would pick that instead of the string one. So if you move the check for generic vs. non-generic to the end of is_better_candidate all the other rules to determine this will take precedence. So the root of the problem is that we have no way to choose the generic function via explicit casting? That makes sense and presumably I can use the final result of is_better_candidate to determine this? You simply need to put your check for generic vs. not-generic after the check for ordinal_distance inside is_better_candidate instead of at the start of the function. In your example: Writeln(Test('Hello World')); // is_better_candidate res = -1 Writeln(Test(42)); // is_better_candidate res = 1 Writeln(Test(String(42))); // is_better_candidate res = -1 I'm struggling to see how the operator influenced the result. Res is -1 in both cases so how do we know which Test we want to call? The compiler is free to use implicit operator overloads when determining the overload to pick. When the compiler sees the first call to Test it will have the non-generic Test(String) in its candidate list as well as Test(String) due to the implicit specialization. Here it will use the non-generic one. In the second case the compiler will have the non-generic Test(String) due to the implicit operator as well as Test(LongInt) due to the implicit specialization. Here it will pick the generic one, because a call without a type conversion is considered better. In the third case the will will contain Test(String) as well as Test(String) due to the parameter being explicitely casted to String with the compiler again picking the non-generic one. Without the explicit cast by the user the compiler would have picked the Test, but using a cast to the type of non-generic function one is able to enforce the non-generic function (for example to avoid an error during specialization if the Test<> function would not be able to handle the LongInt type). Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On Apr 6, 2021, at 12:57 PM, Sven Barth wrote: > > In the example you posted below, I agree with you, but that is not what I > said. Look at my example again: Also could you please verify that $H+ isn't causing problems? The string literal 'Hello World' is a short string but "String" is an AnsiString so that may influence the results you're expecting. However even without the operator I don't know how to delineate between the explicit cast vs the non-explicit cast. Writeln(Test('Hello World')); Writeln(Test(String('Hello World'))); These both appear to be equal as far as is_better_candidate is concerned. Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
> On Apr 6, 2021, at 12:57 PM, Sven Barth wrote: > > In this specific case the two functions also are *not* ambigous, because for > the non-generic Test the parameter requires an implicit conversion, but the > implicit specialization does not. For example if there would be a "Test(aArg: > LongInt)" instead of the generic the compiler would pick that instead of the > string one. So if you move the check for generic vs. non-generic to the end > of is_better_candidate all the other rules to determine this will take > precedence. So the root of the problem is that we have no way to choose the generic function via explicit casting? That makes sense and presumably I can use the final result of is_better_candidate to determine this? In your example: Writeln(Test('Hello World')); // is_better_candidate res = -1 Writeln(Test(42)); // is_better_candidate res = 1 Writeln(Test(String(42))); // is_better_candidate res = -1 I'm struggling to see how the operator influenced the result. Res is -1 in both cases so how do we know which Test we want to call? Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Implicit function specialization precedence
Am 06.04.2021 um 17:45 schrieb Ryan Joseph via fpc-devel: Finally some movement is happening on implicit function specialization and I'm almost finished now except some questions about precedence have been raised again. Initially I thought we decided on non-generic functions taking precedence in the case of *any* name collisions (the original thread https://lists.freepascal.org/pipermail/fpc-pascal/2018-December/055225.html) but Sven is saying now that this isn't the case (see the remarks on the bug report https://bugs.freepascal.org/view.php?id=35261). I'm asking this here not to go over Svens head but in hopes to get some answers quicker (it can take us weeks sometimes to round trip even simple questions). Currently what I implemented is that in the case below non-generic Test() will take precedence even though Test could be specialized and indeed even comes after. My questions: 1) What is required for Delphi compatibility? I never used Delphi and I thought we decided this initially for Delphi compatibility. Of course we can make a Delphi mode only option if we need to. 2) Svens final remarks on the bug tracker are "Right now your code will pick the existing String overload even if specializing the generic might be the better choice. If the user really wants the String one (or if the specializing the generic does not work) the user can still force the String overload by casting the parameter to a String.". I'm confused about this because Test(String) and Test are both identical and thus I don't see what is the "better choice". Personally I feel like we should fallback to the non-generic function as a way to resolve ambiguity but I can also see why Test should take precedence simply because it comes after Test(). In the example you posted below, I agree with you, but that is not what I said. Look at my example again: === code begin === program timplicitspez; {$mode objfpc}{$H+} {$modeswitch IMPLICITFUNCTIONSPECIALIZATION} function Test(const aStr: String): LongInt; begin Result := 1; end; generic function Test(aT: T): LongInt; begin Result := 2; end; operator := (aArg: LongInt): String; begin { potentially expensive conversion } Result := ''; end; begin Writeln(Test('Hello World')); Writeln(Test(42)); end. === code end === The important part here is the operator overload. If the generic function would not exist then the compiler would simply call the operator overload to convert the 42 to a String and call the function with the string overload. While in this example the conversion is essential a no-op in reality it might be more complex and expensive thus it might be better to use the implicit specialization of the 42 as is (in this case it would be a LongInt I think). Right now there is no possibility to enforce the use of the implicit specialization. In this specific case the two functions also are *not* ambigous, because for the non-generic Test the parameter requires an implicit conversion, but the implicit specialization does not. For example if there would be a "Test(aArg: LongInt)" instead of the generic the compiler would pick that instead of the string one. So if you move the check for generic vs. non-generic to the end of is_better_candidate all the other rules to determine this will take precedence. And to pick the non-generic one can do this in the above example: Test(String(42)), because here the type your implicit specialization code will receive will be String already and thus the generic vs. non-generic check will catch it and prefer the non-generic one. Also Delphi agrees with me: === code begin === program timplspez; {$APPTYPE CONSOLE} uses SysUtils; type TFoo = record f: LongInt; class operator Implicit(aArg: LongInt): TFoo; end; TTest = record class function Test(aArg: TFoo): LongInt; overload; static; class function Test(aArg: T): LongInt; overload; static; end; class operator TFoo.Implicit(aArg: LongInt): TFoo; begin Result.f := aArg; end; class function TTest.Test(aArg: TFoo): LongInt; begin Result := 1; end; class function TTest.Test(aArg: T): LongInt; begin Result := 2; end; var f: TFoo; begin f := 21; Writeln(TTest.Test(f)); Writeln(TTest.Test(42)); Writeln(TTest.Test(TFoo(42))); Readln; end. === code end === === output begin === 1 2 1 === output end === This should answer both your points, cause they're related. Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel