So, I was working on yet another app, and stumbled onto yet another Delphi compiler/RTL issue.

Here's a sample reproducible test case:

program MercuryApp;
// chuacw
{$APPTYPE CONSOLE}
{$R *.res}
uses
  System.SysUtils,
  System.Classes;

var
  LLine: AnsiString;
  List: TStringList;
  Count: Integer;
begin
  ReportMemoryLeaksOnShutdown := True;

  Count := 0;

  List := TStringList.Create;
  try
    List.Add('Hello world');
    List.Add('Goodbye!');

    for LLine in List do // Compiler warning Implicit string cast with potential data loss from 'string' to 'AnsiString'
      WriteLn(LLine);

  // String cast to eliminate warning
    for LLine in AnsiString(List) do // But goes into an infinite loop!!!
      begin
        WriteLn(LLine);
        Inc(Count);
      end;
  finally
    List.Free;
  end;
end.

As you can see, I was trying to enumerate through the items in a TStringList, which is a container for strings.
However, what I'm using to enumerate through the items, is an AnsiString, instead of a string.

So, trying to eliminate the warning, I casted the TStringList into an AnsiString, and that's when the trouble began!

How do you distinguish between casting TStringList into an AnsiString, and distingush casting the items returned by GetCurrent into an AnsiString?

The proper way to do it would be as follows, but is there an easier or undocumented way? The problem is that since there's no formal Delphi grammar listed on the Embarcadero docwiki site, it's challenging to discover what's the proper grammar to do so.

 

program MercuryApp;
var
  LLine: AnsiString;
  ALine: string;
  List: TStringList;
begin

    for ALine in List do
      begin
        LLine := AnsiString(ALine);
        // do whatever with LLine here
      end;
  ...
end.