@@ -2194,12 +2194,166 @@ implementation
21942194 end ;
21952195
21962196
2197+ { builds a field-by-field equality/inequality chain for two tuple
2198+ records of identical shape; expects l and r already typechecked }
2199+ function build_tuple_eq_chain (l,r:tnode;wantequal:boolean):tnode;
2200+ var
2201+ recdef : trecorddef;
2202+ sym : tsym;
2203+ fsym : tfieldvarsym;
2204+ i,fcount : longint;
2205+ cmp,subl,subr,chain : tnode;
2206+ begin
2207+ recdef:=trecorddef(l.resultdef);
2208+ chain:=nil ;
2209+ fcount:=0 ;
2210+ for i:=0 to recdef.symtable.symlist.count-1 do
2211+ begin
2212+ sym:=tsym(recdef.symtable.symlist[i]);
2213+ if sym.typ<>fieldvarsym then
2214+ continue;
2215+ fsym:=tfieldvarsym(sym);
2216+ subl:=csubscriptnode.create(fsym,l.getcopy);
2217+ subr:=csubscriptnode.create(fsym,r.getcopy);
2218+ if wantequal then
2219+ cmp:=caddnode.create(equaln,subl,subr)
2220+ else
2221+ cmp:=caddnode.create(unequaln,subl,subr);
2222+ if chain=nil then
2223+ chain:=cmp
2224+ else if wantequal then
2225+ chain:=caddnode.create(andn,chain,cmp)
2226+ else
2227+ chain:=caddnode.create(orn,chain,cmp);
2228+ inc(fcount);
2229+ end ;
2230+ if chain=nil then
2231+ chain:=cordconstnode.create(ord(wantequal),pasbool1type,false);
2232+ l.free;
2233+ r.free;
2234+ result:=chain;
2235+ end ;
2236+
2237+
2238+ { Recursively builds a lexicographic comparison chain:
2239+ (l.fi < r.fi) OR ((l.fi = r.fi) AND tail), with the last level
2240+ using last_op (< or <=). The caller provides the fieldsyms list
2241+ in order and starts at field_idx=0. }
2242+ function build_lex_rest (l,r:tnode;const fields:array of tfieldvarsym;
2243+ field_idx:longint;last_op:tnodetype):tnode;
2244+ var
2245+ subl,subr,subl_eq,subr_eq,eqcmp,ltcmp,tail : tnode;
2246+ begin
2247+ if field_idx=high(fields) then
2248+ begin
2249+ subl:=csubscriptnode.create(fields[field_idx],l.getcopy);
2250+ subr:=csubscriptnode.create(fields[field_idx],r.getcopy);
2251+ result:=caddnode.create(last_op,subl,subr);
2252+ exit;
2253+ end ;
2254+ subl:=csubscriptnode.create(fields[field_idx],l.getcopy);
2255+ subr:=csubscriptnode.create(fields[field_idx],r.getcopy);
2256+ ltcmp:=caddnode.create(ltn,subl,subr);
2257+ subl_eq:=csubscriptnode.create(fields[field_idx],l.getcopy);
2258+ subr_eq:=csubscriptnode.create(fields[field_idx],r.getcopy);
2259+ eqcmp:=caddnode.create(equaln,subl_eq,subr_eq);
2260+ tail:=build_lex_rest(l,r,fields,field_idx+1 ,last_op);
2261+ result:=caddnode.create(orn,ltcmp,caddnode.create(andn,eqcmp,tail));
2262+ end ;
2263+
2264+
2265+ { Expands a tuple < / <= / > / >= comparison into a lexicographic
2266+ chain. > and >= are rewritten by swapping l and r so the chain
2267+ builder only needs to handle < and <=. }
2268+ function build_tuple_lex_chain (l,r:tnode;op:tnodetype):tnode;
2269+ var
2270+ recdef : trecorddef;
2271+ sym : tsym;
2272+ fields : array of tfieldvarsym;
2273+ i,fcount : longint;
2274+ last_op : tnodetype;
2275+ tmp : tnode;
2276+ begin
2277+ if op in [gtn,gten] then
2278+ begin
2279+ tmp:=l; l:=r; r:=tmp;
2280+ if op=gtn then op:=ltn else op:=lten;
2281+ end ;
2282+ last_op:=op;
2283+ recdef:=trecorddef(l.resultdef);
2284+ fcount:=0 ;
2285+ setlength(fields,recdef.symtable.symlist.count);
2286+ for i:=0 to recdef.symtable.symlist.count-1 do
2287+ begin
2288+ sym:=tsym(recdef.symtable.symlist[i]);
2289+ if sym.typ=fieldvarsym then
2290+ begin
2291+ fields[fcount]:=tfieldvarsym(sym);
2292+ inc(fcount);
2293+ end ;
2294+ end ;
2295+ setlength(fields,fcount);
2296+ if fcount=0 then
2297+ result:=cordconstnode.create(0 ,pasbool1type,false)
2298+ else
2299+ result:=build_lex_rest(l,r,fields,0 ,last_op);
2300+ l.free;
2301+ r.free;
2302+ end ;
2303+
2304+
21972305 function taddnode.pass_typecheck :tnode;
21982306 begin
21992307 { This function is small to keep the stack small for recursive of
22002308 large + operations }
22012309 typecheckpass(left);
22022310 typecheckpass(right);
2311+ { tuple equality / inequality }
2312+ if (nodetype in [equaln,unequaln]) and
2313+ assigned(left.resultdef) and assigned(right.resultdef) and
2314+ (left.resultdef.typ=recorddef) and (right.resultdef.typ=recorddef) and
2315+ (df_tuple in left.resultdef.defoptions) and
2316+ (df_tuple in right.resultdef.defoptions) then
2317+ begin
2318+ if tuples_have_equal_shape(trecorddef(left.resultdef),trecorddef(right.resultdef)) then
2319+ begin
2320+ result:=build_tuple_eq_chain(left,right,nodetype=equaln);
2321+ left:=nil ;
2322+ right:=nil ;
2323+ typecheckpass(result);
2324+ end
2325+ else
2326+ begin
2327+ { different shapes: always false for =, always true for <> }
2328+ left.free; left:=nil ;
2329+ right.free; right:=nil ;
2330+ result:=cordconstnode.create(ord(nodetype=unequaln),pasbool1type,false);
2331+ end ;
2332+ exit;
2333+ end ;
2334+ { tuple lexicographic ordering: < <= > >= }
2335+ if (nodetype in [ltn,lten,gtn,gten]) and
2336+ assigned(left.resultdef) and assigned(right.resultdef) and
2337+ (left.resultdef.typ=recorddef) and (right.resultdef.typ=recorddef) and
2338+ (df_tuple in left.resultdef.defoptions) and
2339+ (df_tuple in right.resultdef.defoptions) then
2340+ begin
2341+ if tuples_have_equal_shape(trecorddef(left.resultdef),trecorddef(right.resultdef)) then
2342+ begin
2343+ result:=build_tuple_lex_chain(left,right,nodetype);
2344+ left:=nil ;
2345+ right:=nil ;
2346+ typecheckpass(result);
2347+ end
2348+ else
2349+ begin
2350+ Message(type_e_tuples_not_comparable);
2351+ left.free; left:=nil ;
2352+ right.free; right:=nil ;
2353+ result:=cordconstnode.create(0 ,pasbool1type,false);
2354+ end ;
2355+ exit;
2356+ end ;
22032357 result:=pass_typecheck_internal;
22042358 end ;
22052359
0 commit comments