Jelajahi Sumber

fcl-passrc: resolver: record const

git-svn-id: trunk@38868 -
Mattias Gaertner 7 tahun lalu
induk
melakukan
70b4a4b9a5

+ 2 - 0
packages/fcl-passrc/src/pasresolveeval.pas

@@ -168,6 +168,7 @@ const
   nTypeCycleFound = 3106;
   nTypeXIsNotYetCompletelyDefined = 3107;
   nDuplicateCaseValueXatY = 3108;
+  nMissingFieldsX = 3109;
 
 // resourcestring patterns of messages
 resourcestring
@@ -268,6 +269,7 @@ resourcestring
   sTypeCycleFound = 'Type cycle found';
   sTypeXIsNotYetCompletelyDefined = 'type "%s" is not yet completely defined';
   sDuplicateCaseValueXatY = 'Duplicate case value "%s", other at %s';
+  sMissingFieldsX = 'Missing fields: "%s"';
 
 type
   { TResolveData - base class for data stored in TPasElement.CustomData }

+ 263 - 5
packages/fcl-passrc/src/pasresolver.pp

@@ -47,6 +47,7 @@ Works:
 - record
   - variants
   - const param makes children const too
+  - const  TRecordValues
 - class:
   - forward declaration
   - instance.a
@@ -146,6 +147,7 @@ Works:
   - TypedPointer:=TypedPointer
   - TypedPointer:=@Some
   - pointer[index], (@i)[index]
+  - dispose(pointerofrecord), new(pointerofrecord)
 - emit hints
   - platform, deprecated, experimental, library, unimplemented
   - hiding ancestor method
@@ -210,10 +212,7 @@ ToDo:
 - fail to write a loop var inside the loop
 - nested classes
 - records - TPasRecordType,
-   - const  TRecordValues
    - function default(record type): record
-   - pointer of record
-- dispose(pointerofrecord), new(pointerofrecord)
 - proc: check if forward and impl default values match
 - call array of proc without ()
 - array+array
@@ -1269,6 +1268,7 @@ type
       Access: TResolvedRefAccess): boolean; virtual;
     procedure ResolveSetParamsExpr(Params: TParamsExpr); virtual;
     procedure ResolveArrayValues(El: TArrayValues); virtual;
+    procedure ResolveRecordValues(El: TRecordValues); virtual;
     function ResolveAccessor(Expr: TPasExpr): TPasElement;
     procedure SetResolvedRefAccess(Expr: TPasExpr; Ref: TResolvedReference;
       Access: TResolvedRefAccess); virtual;
@@ -1337,6 +1337,10 @@ type
       out ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags;
       StartEl: TPasElement);
     procedure ComputeDereference(El: TUnaryExpr; var ResolvedEl: TPasResolverResult);
+    procedure ComputeArrayValuesExpectedType(El: TArrayValues; out ResolvedEl: TPasResolverResult;
+      Flags: TPasResolverComputeFlags; StartEl: TPasElement = nil);
+    procedure ComputeRecordValues(El: TRecordValues; out ResolvedEl: TPasResolverResult;
+      Flags: TPasResolverComputeFlags; StartEl: TPasElement = nil);
     procedure CheckIsClass(El: TPasElement; const ResolvedEl: TPasResolverResult);
     function CheckTypeCastClassInstanceToClass(
       const FromClassRes, ToClassRes: TPasResolverResult;
@@ -4542,6 +4546,8 @@ begin
     FinishClassType(TPasClassType(El))
   else if C=TPasClassOfType then
     FinishClassOfType(TPasClassOfType(El))
+  else if C=TPasPointerType then
+    FinishPointerType(TPasPointerType(El))
   else if C=TPasArrayType then
     FinishArrayType(TPasArrayType(El))
   else if (C=TPasAliasType) or (C=TPasTypeAliasType) then
@@ -4848,6 +4854,8 @@ var
 begin
   TypeEl:=ResolveAliasType(El.DestType);
   if TypeEl is TUnresolvedPendingRef then exit;
+  if El.DestType.Parent=El then
+    RaiseMsg(20180429094237,nNotYetImplemented,sNotYetImplemented,['pointer of anonymous type'],El.DestType);
   CheckPointerCycle(El);
 end;
 
@@ -7350,6 +7358,13 @@ begin
         [],El);
     ResolveArrayValues(TArrayValues(El));
     end
+  else if ElClass=TRecordValues then
+    begin
+    if Access<>rraRead then
+      RaiseMsg(20180429103024,nVariableIdentifierExpected,sVariableIdentifierExpected,
+        [],El);
+    ResolveRecordValues(TRecordValues(El));
+    end
   else
     RaiseNotYetImplemented(20170222184329,El);
 
@@ -8221,6 +8236,101 @@ begin
     ResolveExpr(El.Values[i],rraRead);
 end;
 
+procedure TPasResolver.ResolveRecordValues(El: TRecordValues);
+
+  function GetMember(RecType: TPasRecordType; const aName: string): TPasElement;
+  var
+    i: Integer;
+  begin
+    for i:=0 to RecType.Members.Count-1 do
+      begin
+      Result:=TPasElement(RecType.Members[i]);
+      if SameText(Result.Name,aName) then
+        exit;
+      end;
+    if (RecType.VariantEl is TPasVariable) then
+      begin
+      Result:=TPasVariable(RecType.VariantEl);
+      if SameText(Result.Name,aName) then
+        exit;
+      end;
+    if RecType.Variants<>nil then
+      for i:=0 to RecType.Variants.Count-1 do
+        begin
+        Result:=GetMember(TPasVariant(RecType.Variants[i]).Members,aName);
+        if Result<>nil then
+          exit;
+        end;
+    Result:=nil;
+  end;
+
+var
+  i, j: Integer;
+  Member: TPasElement;
+  RecType: TPasRecordType;
+  Field: PRecordValuesItem;
+  s: String;
+  ResolvedEl: TPasResolverResult;
+begin
+  {$IFDEF VerbosePasResolver}
+  writeln('TPasResolver.ResolveRecordValues ',El.Fields[0].Name,' ',GetObjName(El.Parent),' ',GetObjName(El.Parent.Parent));
+  {$ENDIF}
+  ComputeElement(El,ResolvedEl,[]);
+  if (ResolvedEl.BaseType<>btContext)
+      or (ResolvedEl.LoTypeEl.ClassType<>TPasRecordType) then
+    begin
+    RaiseIncompatibleTypeDesc(20180429104135,nIncompatibleTypesGotExpected,
+      [],'record value',GetTypeDescription(ResolvedEl),El);
+    end;
+  RecType:=TPasRecordType(ResolvedEl.LoTypeEl);
+  //writeln('TPasResolver.ResolveRecordValues ',GetObjName(El.Parent),' ',GetObjName(RecType));
+  for i:=0 to length(El.Fields)-1 do
+    begin
+    Field:[email protected][i];
+    // check member exists
+    Member:=GetMember(RecType,Field^.Name);
+    if Member=nil then
+      RaiseIdentifierNotFound(20180429104703,Field^.Name,Field^.NameExp);
+    if not (Member is TPasVariable) then
+      RaiseMsg(20180429121933,nVariableIdentifierExpected,sVariableIdentifierExpected,
+        [],Field^.ValueExp);
+    CreateReference(Member,Field^.NameExp,rraAssign);
+    // check duplicates
+    for j:=0 to i-1 do
+      if SameText(Field^.Name,El.Fields[j].Name) then
+        RaiseMsg(20180429104942,nDuplicateIdentifier,sDuplicateIdentifier,
+          [Field^.Name,GetElementSourcePosStr(El.Fields[j].NameExp)],Field^.NameExp);
+    // resolve expression
+    ResolveExpr(El.Fields[i].ValueExp,rraRead);
+    // check compatible
+    CheckAssignCompatibility(Member,Field^.ValueExp);
+    end;
+  // hint for missing fields
+  s:='';
+  for i:=0 to RecType.Members.Count-1 do
+    begin
+    Member:=TPasElement(RecType.Members[i]);
+    if not (Member is TPasVariable) then continue;
+    j:=length(El.Fields)-1;
+    while (j>=0) and not SameText(Member.Name,El.Fields[j].Name) do
+      dec(j);
+    //writeln('TPasResolver.ResolveRecordValues ',GetObjName(Member),' ',j);
+    if j<0 then
+      begin
+      if s<>'' then s:=s+', ';
+      if length(s)>30 then
+        begin
+        s:=s+'...';
+        break;
+        end;
+      s:=s+Member.Name;
+      end;
+    end;
+  // ToDo: hint for missing variants
+  if s<>'' then
+    LogMsg(20180429121127,mtHint,nMissingFieldsX,sMissingFieldsX,[s],El);
+end;
+
 function TPasResolver.ResolveAccessor(Expr: TPasExpr): TPasElement;
 var
   Prim: TPrimitiveExpr;
@@ -9934,6 +10044,150 @@ begin
     [OpcodeStrings[eopDeref],GetResolverResultDescription(ResolvedEl)],El);
 end;
 
+procedure TPasResolver.ComputeArrayValuesExpectedType(El: TArrayValues; out
+  ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags;
+  StartEl: TPasElement);
+// (expr, expr, ...)
+var
+  Parent: TPasElement;
+  HiTypeEl, LoTypeEl: TPasType;
+  Field: PRecordValuesItem;
+  Ref: TResolvedReference;
+  Member: TPasVariable;
+  i: Integer;
+  ArrType: TPasArrayType;
+begin
+  Parent:=El.Parent;
+  if Parent is TPasVariable then
+    begin
+    HiTypeEl:=TPasVariable(Parent).VarType;
+    if HiTypeEl=nil then
+      RaiseMsg(20180429171628,nSyntaxErrorExpectedButFound,sSyntaxErrorExpectedButFound,
+        ['const','array values'],El);
+    LoTypeEl:=ResolveAliasType(HiTypeEl);
+    if LoTypeEl.ClassType=TPasArrayType then
+      // ok
+    else
+      RaiseIncompatibleTypeDesc(20180429171714,nIncompatibleTypesGotExpected,
+        [],'array value',GetTypeDescription(HiTypeEl),El);
+    SetResolverValueExpr(ResolvedEl,btContext,LoTypeEl,HiTypeEl,
+       El,[rrfReadable]);
+    end
+  else if Parent.ClassType=TRecordValues then
+    begin
+    // record field array
+    // get field
+    i:=length(TRecordValues(Parent).Fields)-1;
+    while (i>=0) and (TRecordValues(Parent).Fields[i].ValueExp<>El) do
+      dec(i);
+    if i<0 then
+      RaiseInternalError(20180429181150);
+    Field:=@TRecordValues(Parent).Fields[i];
+    // get member
+    Ref:=Field^.NameExp.CustomData as TResolvedReference;
+    Member:=Ref.Declaration as TPasVariable;
+    if Member=nil then
+      RaiseInternalError(20180429181210);
+    ComputeElement(Member,ResolvedEl,[],StartEl);
+    ResolvedEl.Flags:=[rrfReadable];
+    end
+  else if Parent.ClassType=TArrayValues then
+    begin
+    // array of array
+    ComputeArrayValuesExpectedType(TArrayValues(Parent),ResolvedEl,Flags,StartEl);
+    if (ResolvedEl.BaseType=btContext)
+        and (ResolvedEl.LoTypeEl.ClassType=TPasArrayType) then
+      begin
+      ArrType:=TPasArrayType(ResolvedEl.LoTypeEl);
+      if length(ArrType.Ranges)>1 then
+        RaiseNotYetImplemented(20180429180930,El);
+      HiTypeEl:=ArrType.ElType;
+      LoTypeEl:=ResolveAliasType(HiTypeEl);
+      if LoTypeEl.ClassType<>TPasArrayType then
+        RaiseIncompatibleTypeDesc(20180429180938,nIncompatibleTypesGotExpected,
+          [],'array values',GetTypeDescription(HiTypeEl),El);
+      SetResolverValueExpr(ResolvedEl,btContext,LoTypeEl,HiTypeEl,
+         El,[rrfReadable]);
+      end
+    else
+      RaiseIncompatibleTypeDesc(20180429173143,nIncompatibleTypesGotExpected,
+        [],'array values',GetTypeDescription(ResolvedEl),El);
+    end
+  else
+    SetResolverValueExpr(ResolvedEl,btSet,nil,nil,TArrayValues(El),[rrfReadable]);
+end;
+
+procedure TPasResolver.ComputeRecordValues(El: TRecordValues; out
+  ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags;
+  StartEl: TPasElement);
+// (name:expr; name:expr; ...)
+var
+  Parent, Member: TPasElement;
+  LoTypeEl, HiTypeEl: TPasType;
+  i: Integer;
+  Field: PRecordValuesItem;
+  Ref: TResolvedReference;
+  ArrType: TPasArrayType;
+begin
+  Parent:=El.Parent;
+  if Parent is TPasVariable then
+    begin
+    HiTypeEl:=TPasVariable(Parent).VarType;
+    if HiTypeEl=nil then
+      RaiseMsg(20180429105451,nSyntaxErrorExpectedButFound,sSyntaxErrorExpectedButFound,
+        ['const','record values'],El);
+    LoTypeEl:=ResolveAliasType(HiTypeEl);
+    if LoTypeEl.ClassType<>TPasRecordType then
+      RaiseIncompatibleTypeDesc(20180429104135,nIncompatibleTypesGotExpected,
+        [],'record value',GetTypeDescription(HiTypeEl),El);
+    SetResolverValueExpr(ResolvedEl,btContext,LoTypeEl,HiTypeEl,
+       El,[rrfReadable]);
+    end
+  else if Parent.ClassType=TRecordValues then
+    begin
+    // nested record
+    // get field
+    i:=length(TRecordValues(Parent).Fields)-1;
+    while (i>=0) and (TRecordValues(Parent).Fields[i].ValueExp<>El) do
+      dec(i);
+    if i<0 then
+      RaiseInternalError(20180429130244);
+    Field:=@TRecordValues(Parent).Fields[i];
+    // get member
+    Ref:=Field^.NameExp.CustomData as TResolvedReference;
+    Member:=Ref.Declaration as TPasVariable;
+    if Member=nil then
+      RaiseInternalError(20180429130548);
+    ComputeElement(Member,ResolvedEl,[],StartEl);
+    ResolvedEl.Flags:=[rrfReadable];
+    end
+  else if Parent.ClassType=TArrayValues then
+    begin
+    // array of record
+    ComputeArrayValuesExpectedType(TArrayValues(Parent),ResolvedEl,Flags,StartEl);
+    if (ResolvedEl.BaseType=btContext)
+        and (ResolvedEl.LoTypeEl.ClassType=TPasArrayType) then
+      begin
+      ArrType:=TPasArrayType(ResolvedEl.LoTypeEl);
+      if length(ArrType.Ranges)>1 then
+        RaiseNotYetImplemented(20180429180450,El);
+      HiTypeEl:=ArrType.ElType;
+      LoTypeEl:=ResolveAliasType(HiTypeEl);
+      if LoTypeEl.ClassType<>TPasRecordType then
+        RaiseIncompatibleTypeDesc(20180429180642,nIncompatibleTypesGotExpected,
+          [],'record values',GetTypeDescription(HiTypeEl),El);
+      SetResolverValueExpr(ResolvedEl,btContext,LoTypeEl,HiTypeEl,
+         El,[rrfReadable]);
+      end
+    else
+      RaiseIncompatibleTypeDesc(20180429173143,nIncompatibleTypesGotExpected,
+        [],'array values',GetTypeDescription(ResolvedEl),El);
+    end
+  else
+    RaiseMsg(20180429110227,nSyntaxErrorExpectedButFound,sSyntaxErrorExpectedButFound,
+     ['const','(name:'],El);
+end;
+
 procedure TPasResolver.CheckIsClass(El: TPasElement;
   const ResolvedEl: TPasResolverResult);
 var
@@ -14784,9 +15038,11 @@ var
   w: WideChar;
   LTypeEl: TPasType;
 begin
-  if (LeftResolved.LoTypeEl<>nil) and (LeftResolved.LoTypeEl.ClassType=TPasArrayType) then
-    exit; // arrays are checked by element, not by the whole value
   LTypeEl:=LeftResolved.LoTypeEl;
+  if (LTypeEl<>nil)
+      and ((LTypeEl.ClassType=TPasArrayType)
+        or (LTypeEl.ClassType=TPasRecordType)) then
+    exit; // arrays and records are checked by element, not by the whole value
   if LTypeEl is TPasClassOfType then
     exit; // class-of are checked only by type, not by value
   RValue:=Eval(RHS,[refAutoConst]);
@@ -17760,6 +18016,8 @@ begin
     SetResolverIdentifier(ResolvedEl,btContext,El,TPasArrayType(El),TPasArrayType(El),[])
   else if ElClass=TArrayValues then
     SetResolverValueExpr(ResolvedEl,btSet,nil,nil,TArrayValues(El),[rrfReadable])
+  else if ElClass=TRecordValues then
+    ComputeRecordValues(TRecordValues(El),ResolvedEl,Flags,StartEl)
   else if ElClass=TPasStringType then
     begin
     SetResolverTypeExpr(ResolvedEl,btShortString,

+ 212 - 39
packages/fcl-passrc/tests/tcresolver.pas

@@ -421,7 +421,6 @@ type
     Procedure TestProc_TypeCastFunctionResult;
     Procedure TestProc_ImplicitCalls;
     Procedure TestProc_Absolute;
-    // ToDo: fail builtin functions in constant with non const param
 
     // record
     Procedure TestRecord;
@@ -433,6 +432,13 @@ type
     Procedure TestRecord_WriteNestedConstParamWithFail;
     Procedure TestRecord_TypeCast;
     Procedure TestRecord_NewDispose;
+    Procedure TestRecord_Const;
+    Procedure TestRecord_Const_DuplicateFail;
+    Procedure TestRecord_Const_ExprMismatchFail;
+    Procedure TestRecord_Const_MissingHint;
+    Procedure TestRecord_Const_UntypedFail;
+    Procedure TestRecord_Const_NestedRecord;
+    Procedure TestRecord_Const_Variant;
 
     // class
     Procedure TestClass;
@@ -528,7 +534,6 @@ type
     Procedure TestClass_EnumeratorFunc;
     Procedure TestClass_ForInPropertyStaticArray;
     Procedure TestClass_TypeAlias;
-    // Todo: Fail to use class.method in constant or type, e.g. const p = @o.doit;
 
     // published
     Procedure TestClass_PublishedClassVarFail;
@@ -655,6 +660,7 @@ type
     Procedure TestArrayOfArray_NameAnonymous;
     Procedure TestFunctionReturningArray;
     Procedure TestArray_LowHigh;
+    Procedure TestArray_LowVarFail;
     Procedure TestArray_AssignSameSignatureFail;
     Procedure TestArray_Assigned;
     Procedure TestPropertyOfTypeArray;
@@ -667,6 +673,9 @@ type
     Procedure TestArrayEnumTypeSetLengthFail;
     Procedure TestArrayEnumCustomRange;
     Procedure TestArray_DynArrayConst;
+    Procedure TestArray_Static_Const;
+    Procedure TestArray_Record_Const;
+    Procedure TestArray_MultiDim_Const;
     Procedure TestArray_AssignNilToStaticArrayFail1;
     Procedure TestArray_SetLengthProperty;
     Procedure TestStaticArray_SetlengthFail;
@@ -686,7 +695,6 @@ type
     Procedure TestArray_TypeCastWrongElTypeFail;
     Procedure TestArray_ConstDynArrayWrite;
     Procedure TestArray_ConstOpenArrayWriteFail;
-    Procedure TestArray_Static_Const;
 
     // array of const
     Procedure TestArrayOfConst;
@@ -732,6 +740,7 @@ type
 
     // pointer
     Procedure TestPointer;
+    Procedure TestPointer_AnonymousSetFail;
     Procedure TestPointer_AssignPointerToClassFail;
     Procedure TestPointer_TypecastToMethodTypeFail;
     Procedure TestPointer_TypecastFromMethodTypeFail;
@@ -6639,27 +6648,28 @@ end;
 procedure TTestResolver.TestRecordVariantNested;
 begin
   StartProgram(false);
-  Add('type');
-  Add('  {#TRec}TRec = record');
-  Add('    {#Size}Size: longint;');
-  Add('    case {#vari}vari: longint of');
-  Add('    0: ({#b}b: longint)');
-  Add('    1: ({#c}c:');
-  Add('          record');
-  Add('            {#d}d: longint;');
-  Add('            case {#e}e: longint of');
-  Add('            0: ({#f}f: longint)');
-  Add('          end)');
-  Add('  end;');
-  Add('var');
-  Add('  {#r}{=TRec}r: TRec;');
-  Add('begin');
-  Add('  {@r}r.{@Size}Size:=3;');
-  Add('  {@r}r.{@vari}vari:=4;');
-  Add('  {@r}r.{@b}b:=5;');
-  Add('  {@r}r.{@c}c.{@d}d:=6;');
-  Add('  {@r}r.{@c}c.{@e}e:=7;');
-  Add('  {@r}r.{@c}c.{@f}f:=8;');
+  Add([
+  'type',
+  '  {#TRec}TRec = record',
+  '    {#Size}Size: longint;',
+  '    case {#vari}vari: longint of',
+  '    0: ({#b}b: longint)',
+  '    1: ({#c}c:',
+  '          record',
+  '            {#d}d: longint;',
+  '            case {#e}e: longint of',
+  '            0: ({#f}f: longint)',
+  '          end)',
+  '  end;',
+  'var',
+  '  {#r}{=TRec}r: TRec;',
+  'begin',
+  '  {@r}r.{@Size}Size:=3;',
+  '  {@r}r.{@vari}vari:=4;',
+  '  {@r}r.{@b}b:=5;',
+  '  {@r}r.{@c}c.{@d}d:=6;',
+  '  {@r}r.{@c}c.{@e}e:=7;',
+  '  {@r}r.{@c}c.{@f}f:=8;']);
   ParseProgram;
 end;
 
@@ -6771,6 +6781,109 @@ begin
   ParseProgram;
 end;
 
+procedure TTestResolver.TestRecord_Const;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  TPoint = record x, y: longint; end;',
+  'const r: TPoint = (x:1; y:2);',
+  'begin',
+  '']);
+  ParseProgram;
+end;
+
+procedure TTestResolver.TestRecord_Const_DuplicateFail;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  TPoint = record x, y: longint; end;',
+  'const r: TPoint = (x:1; x:2);',
+  'begin',
+  '']);
+  CheckResolverException('Duplicate identifier "x" at afile.pp(4,20)',nDuplicateIdentifier);
+end;
+
+procedure TTestResolver.TestRecord_Const_ExprMismatchFail;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  TPoint = record x, y: longint; end;',
+  'const r: TPoint = (x:1; x:2);',
+  'begin',
+  '']);
+  CheckResolverException('Duplicate identifier "x" at afile.pp(4,20)',nDuplicateIdentifier);
+end;
+
+procedure TTestResolver.TestRecord_Const_MissingHint;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  TPoint = record x, y: longint; end;',
+  'const r: TPoint = (x:1);',
+  'begin',
+  '']);
+  ParseProgram;
+  CheckResolverHint(mtHint,nMissingFieldsX,'Missing fields: "y"');
+end;
+
+procedure TTestResolver.TestRecord_Const_UntypedFail;
+begin
+  StartProgram(false);
+  Add([
+  'const r = (x:1);',
+  'begin',
+  '']);
+  CheckResolverException('Syntax error, "const" expected but "record values" found',nSyntaxErrorExpectedButFound);
+end;
+
+procedure TTestResolver.TestRecord_Const_NestedRecord;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  TPoint = record x, y: longint; end;',
+  '  TSrc = record',
+  '    Id: longint;',
+  '    XY: TPoint',
+  '  end;',
+  'const r: TSrc = (Id:1; XY: (x:2; y:3));',
+  'begin',
+  '']);
+  ParseProgram;
+end;
+
+procedure TTestResolver.TestRecord_Const_Variant;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  {#TRec}TRec = record',
+  '    {#Size}Size: longint;',
+  '    case {#vari}vari: longint of',
+  '    0: ({#b}b: longint);',
+  '    1: ({#c}c:',
+  '          record',
+  '            {#d}d: longint;',
+  '            case {#e}e: longint of',
+  '            0: ({#f}f: longint)',
+  '          end)',
+  '  end;',
+  'const',
+  '  {#r}r: TRec = (',
+  '    {@Size}Size:2;',
+  '    {@c}c:(',
+  '      {@d}d:3;',
+  '      {@f}f:4',
+  '    )',
+  '  );',
+  'begin']);
+  ParseProgram;
+end;
+
 procedure TTestResolver.TestClass;
 begin
   StartProgram(false);
@@ -11230,6 +11343,16 @@ begin
   ParseProgram;
 end;
 
+procedure TTestResolver.TestArray_LowVarFail;
+begin
+  StartProgram(false);
+  Add([
+  'var a: array of longint;',
+  'const l = length(a);',
+  'begin']);
+  CheckResolverException(sConstantExpressionExpected,nConstantExpressionExpected);
+end;
+
 procedure TTestResolver.TestArray_AssignSameSignatureFail;
 begin
   StartProgram(false);
@@ -11470,6 +11593,61 @@ begin
   CheckResolverUnexpectedHints;
 end;
 
+procedure TTestResolver.TestArray_Static_Const;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  TIntArr = array[1..3] of longint;',
+  'const',
+  '  a = low(TIntArr)+high(TIntArr);',
+  '  b: array[1..3] of longint = (10,11,12);',
+  '  c: array[boolean] of TIntArr = ((21,22,23),(31,32,33));',
+  'begin']);
+  ParseProgram;
+  CheckResolverUnexpectedHints;
+end;
+
+procedure TTestResolver.TestArray_Record_Const;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  TPoint = record x, y: longint; end;',
+  '  TDynArray = array of TPoint;',
+  '  TStaticArray = array[1..2] of TPoint;',
+  '  TRecArr = record',
+  '    DA: TDynArray;',
+  '    SA: TStaticArray;',
+  '  end;',
+  'const',
+  '  sa: TStaticArray = ( (x:2; y:3), (x:12;y:14) );',
+  '  da: TDynArray = ( (x:22; y:23), (x:32;y:34) );',
+  '  ra: TRecArr = (',
+  '    DA: ( (x:42; y:43), (x:44;y:45) );',
+  '    SA: ( (x:51; y:52), (x:53;y:54) );',
+  '  );',
+  'begin',
+  '']);
+  ParseProgram;
+end;
+
+procedure TTestResolver.TestArray_MultiDim_Const;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  TDynArray = array of longint;',
+  '  TArrOfArr = array[1..2] of TDynArray;',
+  '  TMultiDimArr = array[1..2,3..4] of longint;',
+  'const',
+  '  AoA: TArrOfArr = ( (1,2), (2,3) );',
+  '  MultiDimArr: TMultiDimArr = ( (11,12), (13,14) );',
+  'begin',
+  '']);
+  ParseProgram;
+end;
+
 procedure TTestResolver.TestArray_AssignNilToStaticArrayFail1;
 begin
   StartProgram(false);
@@ -11772,21 +11950,6 @@ begin
   CheckResolverException('Variable identifier expected',nVariableIdentifierExpected);
 end;
 
-procedure TTestResolver.TestArray_Static_Const;
-begin
-  StartProgram(false);
-  Add([
-  'type',
-  '  TIntArr = array[1..3] of longint;',
-  'const',
-  '  a = low(TIntArr)+high(TIntArr);',
-  '  b: array[1..3] of longint = (10,11,12);',
-  '  c: array[boolean] of TIntArr = ((21,22,23),(31,32,33));',
-  'begin']);
-  ParseProgram;
-  CheckResolverUnexpectedHints;
-end;
-
 procedure TTestResolver.TestArrayOfConst;
 begin
   StartProgram(false);
@@ -12819,6 +12982,16 @@ begin
   ParseProgram;
 end;
 
+procedure TTestResolver.TestPointer_AnonymousSetFail;
+begin
+  StartProgram(false);
+  Add([
+  'type p = ^(red, green);',
+  'begin']);
+  CheckResolverException('not yet implemented: pointer of anonymous type',
+    nNotYetImplemented);
+end;
+
 procedure TTestResolver.TestPointer_AssignPointerToClassFail;
 begin
   StartProgram(false);