Skip to content

Implement support for constant expressions #116

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
2 tasks done
Cirras opened this issue Nov 30, 2023 · 0 comments
Open
2 tasks done

Implement support for constant expressions #116

Cirras opened this issue Nov 30, 2023 · 0 comments
Labels
engine Improvements to the core engine enhancement Improvements to an existing feature

Comments

@Cirras
Copy link
Collaborator

Cirras commented Nov 30, 2023

Prerequisites

  • This improvement has not already been suggested.
  • This improvement would be generally useful, not specific to my code or setup.

Engine area

Delphi language support

Improvement description

Background

The Delphi compiler implements the following optimizations around constant expressions:

  • constant folding
  • constant propagation

This has significant implications for type resolution - see example.

Example

// overload for each integer type:
procedure X(B: Byte); overload;     begin WriteLn('Byte');     end;
procedure X(S: ShortInt); overload; begin WriteLn('ShortInt'); end;
procedure X(S: SmallInt); overload; begin WriteLn('SmallInt'); end;
procedure X(W: Word); overload;     begin WriteLn('Word');     end;
procedure X(I: Integer); overload;  begin WriteLn('Integer');  end;
procedure X(C: Cardinal); overload; begin WriteLn('Cardinal'); end;
procedure X(I: Int64); overload;    begin WriteLn('Int64');    end;
procedure X(U: UInt64); overload;   begin WriteLn('UInt64');   end;

const
  CFive = 5;         // technically ShortInt, but the value "5" is propagated to constant expressions
  CHundred = 25 * 4; // technically ShortInt, but the value "100" is propagated to constant expressions

procedure Test;
var
  I8: ShortInt;
  I16: SmallInt;
  I32: Integer;
  I64: Int64;
  U8: Byte;
  U16: Word;
  U32: Cardinal;
  U64: UInt64;
begin
  // For variables, all we need to do to lose the original type is tack on a unary `+`.
  // This is because the expression is evaluated at runtime, and only the following options are available at runtime:
  //
  // Positive(Integer): Integer
  // Positive(Cardinal): Cardinal
  // Positive(Int64): Int64
  // Positive(UInt64): UInt64

  X(+I8);  // Integer
  X(+I16); // Integer
  X(+I32); // Integer
  X(+I64); // Int64

  X(+U8);  // Integer
  X(+U16); // Integer
  X(+U32); // Cardinal
  X(+U64); // UInt64

  // But for constant expressions, that unary `+` (and indeed, all other arithmetic operators) are done at compile-time.
  // The type is resolved *after* the expression is evaluated, based on the value.

  X(+(0));                   // ShortInt
  X(+(128));                 // Byte
  X(+(256));                 // SmallInt
  X(+(32768));               // Word
  X(+(65536));               // Integer
  X(+(2147483648));          // Cardinal
  X(+(4294967296));          // Int64
  X(+(9223372036854775808)); // UInt64

  // The following constant expressions feature constant propagation.

  X(+CFive);                 // ShortInt
  X(+CHundred);              // ShortInt
  X(+(CHundred + CHundred)); // Byte
  X(+(256 - CFive));         // Byte
end;

See Also

Rationale

This is required for fully accurate type resolution.

Known affected areas

  • Type conversions from array constructor -> set
  • Expression type resolution (especially unary -)
  • Subrange type modeling (low and high are constant expressions)

Other benefits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
engine Improvements to the core engine enhancement Improvements to an existing feature
Projects
None yet
Development

No branches or pull requests

1 participant