4

In XE7 we have the new compiler intrinsic function GetTypeKind (as yet undocumented) that allows us to extract the flavor of a type at compile time.

The following code will generate a run-time error if the wrong type is used:

//make sure T is a procedure/function
procedure TDetours<T>.CheckTType;
{$IF CompilerVersion >= 28}
begin
  // XE7 and up:Resolve all tests at compiletime.
  if (Sizeof(T) <> Sizeof(Pointer)) or (GetTypeKind(T) <> tkProcedure) then begin
    raise DetourException.Create('T must be a procedure or function');
  end;
{$ELSE}
  //Code for pre-XE7 versions
{$ENDIF}
end;

I want the compiler to generate a compile-time error if the correct type kind is not used.
This allows be to catch any errors at an earlier stage. Is this possible?

My line of thinking is as follows:
- If the test is false then the code inside the test does not get generated.
- If the test is true then code does get generated.

Is there some code that I can put into the test that will trip up the compiler when generating code, but does not make the parser stop working?

Johan
  • 74,508
  • 24
  • 191
  • 319

1 Answers1

3

In XE7 we have the new compiler intrinsic function GetTypeKind (as yet undocumented) that allows us to extract the flavor of a type at compile time.

In order for you to be able to do this, you would need to be able to put GetTypeKind into a conditional expression. So that you might write code like this:

{$IF GetTypeKind(T) <> tkProcedure}
  {$Message Fatal 'Invalid type'}
{$ENDIF}

But the compiler does not accept this. The compiler requires the expression in the $IF conditional to be a constant expression, and GetTypeKind(T) <> tkProcedure is not.

I want the compiler to generate a compile-time error if the correct type kind is not used. This allows be to catch any errors at an earlier stage. Is this possible?

This is not possible. The only mechanism you have available is generic constraints. And generic constraints do not have sufficient granularity to specify the constraint that you require.

I think that your best bet is to put an assertion in the class constructor. It would look like this:

class constructor TDetours<T>.CreateClass;
begin
  Assert(Sizeof(T) = Sizeof(Pointer));
  Assert(GetTypeKind(T) = tkProcedure);
end;
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • I've updated the question to make my intent clearer. – Johan Apr 08 '15 at 15:20
  • According to Stefan Glienke GetTypeKind does resolve at compile time, see: http://delphisorcery.blogspot.com/2014/10/new-language-feature-in-xe7.html – Johan Apr 08 '15 at 15:30
  • Fair enough. You still can't make a constant expression with it though. – David Heffernan Apr 08 '15 at 15:42
  • 2
    I suspect that the compiler generates code for all code paths and that the linker than eliminates those code paths that are never executed. If that's the case then there is indeed no way this can be done, bummer, – Johan Apr 08 '15 at 15:52
  • I don't think that detail is relevant. You've simply no chance with a Pascal `if` because the parser is bound to parse all of your code. All you can possibly hope for is to use a conditional since that's the only way to stop the parser from parsing code in your source file. – David Heffernan Apr 08 '15 at 16:01