refactor: use Exit(X) shorthand for Result-then-Exit early returns

Now that Exit(X) is supported (0f63626), replace the historical
'Result := X; Exit;' workaround with the Exit(X) function-result shorthand
across compiler, runtime, and stdlib (305 sites).

Only same-indentation pairs are merged: a 'Result := X;' immediately followed
by an 'Exit;' at the same indentation level. Sites where the trailing 'Exit;'
is less-indented than the assignment are left untouched — there the Exit
belongs to an enclosing for/else/if block, not to the assignment, so merging
would change control flow (e.g. the xor/and numeric-result branch in
uSemantic falling through to the Boolean-operand check). 14 such sites are
deliberately not converted.

Three converted sites sit inside a real try/finally (uSemantic overload/
generic resolution); each try body already contained bare Exit; statements
and its finally body is a plain local-list Free, so control flow is unchanged.
A new e2e test (TestRun_ExitValueThroughFinally) confirms Exit(X) from inside
a try/finally runs the finally body and returns the value.

Self-hosting fixpoint verified clean (stage-2 IR == stage-3 IR).
This commit is contained in:
Graeme Geldenhuys 2026-06-03 00:33:40 +01:00
parent 0f63626397
commit 99b7761bf4
20 changed files with 342 additions and 610 deletions

View file

@ -175,8 +175,7 @@ begin
Arg := ParamStr(I);
if (Length(Arg) >= 2) and (StrAt(Arg, 0) = Ord('-')) and (StrAt(Arg, 1) <> Ord('-')) then
begin
Result := True;
Exit;
Exit(True);
end;
end;
end;

View file

@ -145,8 +145,7 @@ function IntByteSize(AType: TTypeDesc): Integer;
begin
if AType = nil then
begin
Result := 4;
Exit;
Exit(4);
end;
case AType.Kind of
tyByte, tyBoolean: Result := 1;
@ -165,8 +164,7 @@ function IsUnsignedInt(AType: TTypeDesc): Boolean;
begin
if AType = nil then
begin
Result := False;
Exit;
Exit(False);
end;
Result := AType.Kind in [tyByte, tyBoolean, tyWord, tyUInt32, tyUInt64, tyEnum];
end;
@ -404,8 +402,7 @@ begin
T := Self.GlobalType(TIdentExpr(AExpr).Name);
if T <> nil then
begin
Result := T;
Exit;
Exit(T);
end;
end;
Result := AExpr.ResolvedType;

View file

@ -143,8 +143,7 @@ begin
for I := 0 to (AIndex - Seen) - 1 do
Entry := Pointer(Entry) + 16; { skip name + addr pair }
EntName := Entry^;
Result := string(PChar(EntName));
Exit;
Exit(string(PChar(EntName)));
end;
Seen := Seen + Local;
end;
@ -238,8 +237,7 @@ var
begin
if (AFilters = nil) or (AFilters.Count = 0) then
begin
Result := True;
Exit;
Exit(True);
end;
for I := 0 to AFilters.Count - 1 do
begin
@ -248,8 +246,7 @@ begin
Continue;
if (FMethod = '') or (FMethod = AMethod) then
begin
Result := True;
Exit;
Exit(True);
end;
end;
Result := False;
@ -267,16 +264,14 @@ var
begin
if (AFilters = nil) or (AFilters.Count = 0) then
begin
Result := True;
Exit;
Exit(True);
end;
for I := 0 to AFilters.Count - 1 do
begin
SplitSuiteSpec(AFilters.Strings[I], FSuite, FMethod);
if FSuite = ASuite then
begin
Result := True;
Exit;
Exit(True);
end;
end;
Result := False;

File diff suppressed because it is too large Load diff

View file

@ -223,8 +223,7 @@ var
begin
if AType = nil then
begin
Result := 'Pointer';
Exit;
Exit('Pointer');
end;
case AType.Kind of
tyString:

View file

@ -194,8 +194,7 @@ begin
begin
Advance; { consume 'class' }
Expect(tkOf);
Result := 'class of ' + Self.ParseTypeName;
Exit;
Exit('class of ' + Self.ParseTypeName);
end;
if not Check(tkIdent) then
raise EParseError.Create(Format('Expected type name at line %d col %d in %s',
@ -1860,38 +1859,32 @@ begin
if Check(tkIf) then
begin
Result := ParseIfStmt;
Exit;
Exit(ParseIfStmt);
end;
if Check(tkWhile) then
begin
Result := ParseWhileStmt;
Exit;
Exit(ParseWhileStmt);
end;
if Check(tkRepeat) then
begin
Result := ParseRepeatStmt;
Exit;
Exit(ParseRepeatStmt);
end;
if Check(tkFor) then
begin
Result := ParseForStmt;
Exit;
Exit(ParseForStmt);
end;
if Check(tkTry) then
begin
Result := ParseTryStmt;
Exit;
Exit(ParseTryStmt);
end;
if Check(tkRaise) then
begin
Result := ParseRaiseStmt;
Exit;
Exit(ParseRaiseStmt);
end;
if Check(tkExit) then
@ -1909,8 +1902,7 @@ begin
ExitS.Value := Self.ParseExpr;
Expect(tkRParen);
end;
Result := ExitS;
Exit;
Exit(ExitS);
end;
if Check(tkBreak) then
@ -1933,20 +1925,17 @@ begin
if Check(tkInherited) then
begin
Result := ParseInheritedStmt;
Exit;
Exit(ParseInheritedStmt);
end;
if Check(tkCase) then
begin
Result := ParseCaseStmt;
Exit;
Exit(ParseCaseStmt);
end;
if Check(tkBegin) then
begin
Result := ParseCompoundStmt;
Exit;
Exit(ParseCompoundStmt);
end;
if not Check(tkIdent) then
@ -1976,8 +1965,7 @@ begin
SubAssign.Free;
raise;
end;
Result := SubAssign;
Exit;
Exit(SubAssign);
end;
if Check(tkCaret) then
@ -2148,8 +2136,7 @@ begin
MCall.Free;
MCall := nil;
FldAssign.Expr := ParseExpr;
Result := FldAssign;
Exit;
Exit(FldAssign);
end;
Result := MCall;
end
@ -2201,8 +2188,7 @@ begin
if not Check(tkRParen) then
ParseMethodCallArgList(MCall);
Expect(tkRParen);
Result := MCall;
Exit;
Exit(MCall);
end;
FldNode := TFieldAccessExpr.Create;
FldNode.Line := Line;
@ -2222,8 +2208,7 @@ begin
TFieldAccessExpr(CastRcv).Base := nil;
CastRcv.Free;
FldAssign.Expr := ParseExpr;
Result := FldAssign;
Exit;
Exit(FldAssign);
end;
raise EParseError.Create(Format(
'Expected method call or assignment after chain at line %d col %d in %s',
@ -2291,8 +2276,7 @@ begin
if not Check(tkRParen) then
ParseMethodCallArgList(MCall);
Expect(tkRParen);
Result := MCall;
Exit;
Exit(MCall);
end;
FldNode := TFieldAccessExpr.Create;
FldNode.Line := Line;
@ -2313,8 +2297,7 @@ begin
TFieldAccessExpr(CastRcv).Base := nil; { transfer ownership }
CastRcv.Free;
FldAssign.Expr := ParseExpr;
Result := FldAssign;
Exit;
Exit(FldAssign);
end;
{ No-arg method call: Func(...).Field treated as Func(...).Method }
if CastRcv is TFieldAccessExpr then
@ -2327,8 +2310,7 @@ begin
MCall.ObjExpr := TFieldAccessExpr(CastRcv).Base;
TFieldAccessExpr(CastRcv).Base := nil;
CastRcv.Free;
Result := MCall;
Exit;
Exit(MCall);
end;
raise EParseError.Create(Format(
'Expected method call after typecast at line %d col %d in %s',
@ -2343,8 +2325,7 @@ begin
while FCallNode.Args.Count > 0 do
Call.Args.Add(FCallNode.Args.Extract(FCallNode.Args.Items[0]));
FCallNode.Free;
Result := Call;
Exit;
Exit(Call);
end;
Call := TProcCall.Create;
Call.Line := Line;

View file

@ -248,8 +248,7 @@ var
begin
if SameText(AAttrName, ACanonical) then
begin
Result := True;
Exit;
Exit(True);
end;
Suffix := ACanonical + 'Attribute';
Result := SameText(AAttrName, Suffix);
@ -261,14 +260,12 @@ var
begin
if AAttrs = nil then
begin
Result := False;
Exit;
Exit(False);
end;
for I := 0 to AAttrs.Count - 1 do
if AttrMatches(AAttrs.Strings[I], 'Weak') then
begin
Result := True;
Exit;
Exit(True);
end;
Result := False;
end;
@ -279,14 +276,12 @@ var
begin
if AAttrs = nil then
begin
Result := False;
Exit;
Exit(False);
end;
for I := 0 to AAttrs.Count - 1 do
if AttrMatches(AAttrs.Strings[I], 'Unretained') then
begin
Result := True;
Exit;
Exit(True);
end;
Result := False;
end;
@ -307,8 +302,7 @@ begin
begin
if SameText(Walk.Name, 'TCustomAttribute') then
begin
Result := True;
Exit;
Exit(True);
end;
Walk := Walk.Parent;
end;
@ -325,8 +319,7 @@ begin
if (Sym <> nil) and (Sym.TypeDesc is TRecordTypeDesc) and
IsCustomAttributeClass(ARawName) then
begin
Result := ARawName;
Exit;
Exit(ARawName);
end;
Sym := FTable.Lookup(ARawName + 'Attribute');
if (Sym <> nil) and (Sym.TypeDesc is TRecordTypeDesc) and
@ -424,8 +417,7 @@ begin
begin
if Walk = AExpected then
begin
Result := True;
Exit;
Exit(True);
end;
Walk := Walk.Parent;
end;
@ -1414,14 +1406,12 @@ begin
for I := 0 to AParamNames.Count - 1 do
if SameText(Result, AParamNames.Strings[I]) then
begin
Result := AArgs.Strings[I];
Exit;
Exit(AArgs.Strings[I]);
end;
{ Prefix caret: ^T → ^Integer, ^^T → ^^Integer, etc. }
if (Length(Result) > 0) and (StrAt(Result, 0) = Ord('^')) then
begin
Result := '^' + Self.SubstTypeParam(StrCopyTail(Result, 1), AParamNames, AArgs);
Exit;
Exit('^' + Self.SubstTypeParam(StrCopyTail(Result, 1), AParamNames, AArgs));
end;
{ Generic instantiation: SomeName<T,...> — substitute each type argument }
BrOpen := StrPos('<', Result);
@ -1856,8 +1846,7 @@ begin
Sym := FTable.Lookup(ATypeName);
if (Sym <> nil) and (Sym.TypeDesc is TInterfaceTypeDesc) then
begin
Result := TInterfaceTypeDesc(Sym.TypeDesc);
Exit;
Exit(TInterfaceTypeDesc(Sym.TypeDesc));
end;
{ Build mangled name: IEqualityComparer<Integer> → IEqualityComparer_Integer }
@ -3255,8 +3244,7 @@ begin
Idx := FMethodIndex.IndexOf(Key);
if Idx >= 0 then
begin
Result := TMethodDecl(FMethodIndex.Objects[Idx]);
Exit;
Exit(TMethodDecl(FMethodIndex.Objects[Idx]));
end;
{ Walk to parent }
Sym := FTable.Lookup(CurrName);
@ -3344,8 +3332,7 @@ begin
begin
if ArityMatch.Count = 1 then
begin
Result := TMethodDecl(ArityMatch.Items[0]);
Exit;
Exit(TMethodDecl(ArityMatch.Items[0]));
end;
Exit; { ambiguous-by-arity-only — caller must score with args }
end;
@ -3758,8 +3745,7 @@ begin
for I := 0 to ADecl.Params.Count - 1 do
if SameText(TMethodParam(ADecl.Params.Items[I]).ParamName, AName) then
begin
Result := True;
Exit;
Exit(True);
end;
end;
@ -3792,8 +3778,7 @@ begin
end;
if AExpr is TNotExpr then
begin
Result := ExprRejectsInline(TNotExpr(AExpr).Expr, ASelfDecl);
Exit;
Exit(ExprRejectsInline(TNotExpr(AExpr).Expr, ASelfDecl));
end;
end;
@ -3834,15 +3819,13 @@ begin
for I := 0 to Cmp.Stmts.Count - 1 do
if StmtRejectsInline(TASTStmt(Cmp.Stmts.Items[I]), ASelfDecl, AStmtCount) then
Exit;
Result := False;
Exit;
Exit(False);
end;
if AStmt is TExitStmt then
begin
Inc(AStmtCount);
Result := False;
Exit;
Exit(False);
end;
if AStmt is TIfStmt then
@ -3853,8 +3836,7 @@ begin
if StmtRejectsInline(Ifs.ThenStmt, ASelfDecl, AStmtCount) then Exit;
if (Ifs.ElseStmt <> nil) and
StmtRejectsInline(Ifs.ElseStmt, ASelfDecl, AStmtCount) then Exit;
Result := False;
Exit;
Exit(False);
end;
if AStmt is TAssignment then
@ -3865,8 +3847,7 @@ begin
{ Assignment to a parameter requires updating the caller-side temp,
which the simple inliner does not support. Reject. }
if AssignmentTargetsParameter(Asg.Name, ASelfDecl) then Exit;
Result := False;
Exit;
Exit(False);
end;
if AStmt is TProcCall then
@ -3879,8 +3860,7 @@ begin
for I := 0 to TProcCall(AStmt).Args.Count - 1 do
if ExprRejectsInline(TASTExpr(TProcCall(AStmt).Args.Items[I]), ASelfDecl) then
Exit;
Result := False;
Exit;
Exit(False);
end;
if AStmt is TCaseStmt then
@ -3897,8 +3877,7 @@ begin
end;
if (Cs.ElseStmt <> nil) and
StmtRejectsInline(Cs.ElseStmt, ASelfDecl, AStmtCount) then Exit;
Result := False;
Exit;
Exit(False);
end;
{ Unknown statement form: reject conservatively. }
@ -5037,8 +5016,7 @@ var
begin
if AType = nil then
begin
Result := '?';
Exit;
Exit('?');
end;
case AType.Kind of
tyInteger: Base := 'i';
@ -5098,8 +5076,7 @@ begin
for I := 0 to ADecl.Params.Count - 1 do
if TMethodParam(ADecl.Params.Items[I]).DefaultValue <> nil then
begin
Result := I;
Exit;
Exit(I);
end;
Result := ADecl.Params.Count;
end;
@ -5282,15 +5259,13 @@ begin
Elem := TASTExpr(AExpr.Elements.Items[I]);
if not (Elem is TIdentExpr) then
begin
Result := nil;
Exit;
Exit(nil);
end;
Sym := FTable.Lookup(TIdentExpr(Elem).Name);
if (Sym = nil) or (Sym.Kind <> skConstant) or (Sym.TypeDesc = nil) or
(Sym.TypeDesc.Kind <> tyEnum) then
begin
Result := nil;
Exit;
Exit(nil);
end;
if Result = nil then
Result := Sym.TypeDesc
@ -5346,30 +5321,26 @@ begin
(TOpenArrayTypeDesc(AParam).ElementType =
TOpenArrayTypeDesc(AArg).ElementType) then
begin
Result := 2;
Exit;
Exit(2);
end;
{ Static array coerced to open-array: widening match (score 1) }
if (AParam.Kind = tyOpenArray) and (AArg.Kind = tyStaticArray) and
(TOpenArrayTypeDesc(AParam).ElementType =
TStaticArrayTypeDesc(AArg).ElementType) then
begin
Result := 1;
Exit;
Exit(1);
end;
{ Same numeric kind = exact match (same kind, just possibly different
descriptor instance). }
if AParam.IsNumeric and AArg.IsNumeric and (AParam.Kind = AArg.Kind) then
begin
Result := 2;
Exit;
Exit(2);
end;
{ Numeric widening: both numerics, kinds differ. Captures
Integer→Int64, Integer→Double, Single→Double, Byte→Integer, etc. }
if AParam.IsNumeric and AArg.IsNumeric then
begin
Result := 1;
Exit;
Exit(1);
end;
{ Fall-through: probe full assignability via CheckTypesMatch. This
covers nil-literal, class subtypes, untyped-Pointer compatibility,
@ -5430,8 +5401,7 @@ begin
begin
if ArityMatch.Count = 1 then
begin
Result := TMethodDecl(ArityMatch.Items[0]);
Exit;
Exit(TMethodDecl(ArityMatch.Items[0]));
end;
{ zero-arg ambiguity is impossible — same name + zero params would
have been rejected by the symbol-table chain, but be defensive. }
@ -5817,8 +5787,7 @@ begin
AExpr.Line, AExpr.Col);
AExpr.IsBuiltinHasClassAttr := True;
AExpr.ResolvedType := FTable.TypeBoolean;
Result := AExpr.ResolvedType;
Exit;
Exit(AExpr.ResolvedType);
end;
{ SizeOf(TypeName) or SizeOf(expression) — compile-time byte size,
@ -6906,8 +6875,7 @@ begin
AExpr.ResolvedMethod := MDecl;
AExpr.ResolvedClassType := ObjSym.TypeDesc;
AExpr.IsConstructorCall := True;
Result := ObjSym.TypeDesc;
Exit;
Exit(ObjSym.TypeDesc);
end;
if not (ObjSym.Kind in [skVariable, skParameter, skVarParameter]) then
@ -7202,15 +7170,13 @@ begin
begin
AAccess.IsClassNameAccess := True;
AAccess.ResolvedType := FTable.TypeString;
Result := FTable.TypeString;
Exit;
Exit(FTable.TypeString);
end;
if SameText(AAccess.FieldName, 'ClassType') and (BaseType.Kind = tyClass) then
begin
AAccess.IsClassTypeAccess := True;
AAccess.ResolvedType := FTable.TypePointer; { TClass = Pointer for now }
Result := FTable.TypePointer;
Exit;
Exit(FTable.TypePointer);
end;
RT := TRecordTypeDesc(BaseType);
FldInfo := RT.FindField(AAccess.FieldName);
@ -7221,8 +7187,7 @@ begin
begin
AAccess.FieldName := PropInfo.ReadField;
AAccess.FieldInfo := RT.FindField(PropInfo.ReadField);
Result := PropInfo.TypeDesc;
Exit;
Exit(PropInfo.TypeDesc);
end;
{ Method-backed property (including indexed: the parser attaches the
'[idx]' to AAccess.PropIndexExpr when it parses 'Base.Prop[idx]'). }
@ -7248,8 +7213,7 @@ begin
if AAccess.ResolvedMethod <> nil then
begin
AAccess.IsMethodCall := True;
Result := TMethodDecl(AAccess.ResolvedMethod).ResolvedReturnType;
Exit;
Exit(TMethodDecl(AAccess.ResolvedMethod).ResolvedReturnType);
end;
{ Built-in TObject.ToString: virtual dispatch yielding string.
Every class inherits this via vtable slot 1. }
@ -7275,8 +7239,7 @@ begin
AAccess.ConstArrayType := Sym.TypeDesc;
end;
AAccess.ResolvedType := Sym.TypeDesc;
Result := Sym.TypeDesc;
Exit;
Exit(Sym.TypeDesc);
end;
SemanticError(
Format('Type ''%s'' has no field ''%s''',
@ -7441,13 +7404,11 @@ begin
begin
AnalyseExpr(AAccess.PropIndexExpr);
AAccess.ResolvedType := TStaticArrayTypeDesc(Sym.TypeDesc).ElementType;
Result := AAccess.ResolvedType;
Exit;
Exit(AAccess.ResolvedType);
end;
end;
AAccess.ResolvedType := Sym.TypeDesc;
Result := Sym.TypeDesc;
Exit;
Exit(Sym.TypeDesc);
end;
SemanticError(
Format('Unknown class method ''%s'' on type ''%s''',
@ -7460,8 +7421,7 @@ begin
AAccess.Line, AAccess.Col);
AAccess.IsConstructorCall := True;
AAccess.ResolvedMethod := FindMethodDecl(TRecordTypeDesc(RecSym.TypeDesc).Name, 'Create');
Result := RecSym.TypeDesc;
Exit;
Exit(RecSym.TypeDesc);
end;
{ Field access on variable or parameter }
@ -7511,15 +7471,13 @@ begin
begin
AAccess.IsClassNameAccess := True;
AAccess.ResolvedType := FTable.TypeString;
Result := FTable.TypeString;
Exit;
Exit(FTable.TypeString);
end;
if SameText(AAccess.FieldName, 'ClassType') and (RecSym.TypeDesc.Kind = tyClass) then
begin
AAccess.IsClassTypeAccess := True;
AAccess.ResolvedType := FTable.TypePointer;
Result := FTable.TypePointer;
Exit;
Exit(FTable.TypePointer);
end;
RT := TRecordTypeDesc(RecSym.TypeDesc);
@ -7592,13 +7550,11 @@ begin
begin
AnalyseExpr(AAccess.PropIndexExpr);
AAccess.ResolvedType := TStaticArrayTypeDesc(Sym.TypeDesc).ElementType;
Result := AAccess.ResolvedType;
Exit;
Exit(AAccess.ResolvedType);
end;
end;
AAccess.ResolvedType := Sym.TypeDesc;
Result := Sym.TypeDesc;
Exit;
Exit(Sym.TypeDesc);
end;
SemanticError(
Format('Type ''%s'' has no field ''%s''',
@ -7724,8 +7680,7 @@ begin
Format('Right operand of ''%s'' must be Boolean, got ''%s''',
[BinaryOpName(ABin.Op), RType.Name]),
ABin.Line, ABin.Col);
Result := FTable.TypeBoolean;
Exit;
Exit(FTable.TypeBoolean);
end;
if IsComparisonOp(ABin.Op) then
@ -7774,20 +7729,17 @@ begin
{ String concatenation: s1 + s2 → string }
if (ABin.Op = boAdd) and LType.IsString and RType.IsString then
begin
Result := FTable.TypeString;
Exit;
Exit(FTable.TypeString);
end;
{ Pointer arithmetic: Pointer/PChar + Integer or Integer + Pointer → same type }
if (ABin.Op in [boAdd, boSub]) and (LType.Kind in [tyPointer, tyPChar]) and RType.IsNumeric then
begin
Result := LType;
Exit;
Exit(LType);
end;
if (ABin.Op = boAdd) and LType.IsNumeric and (RType.Kind in [tyPointer, tyPChar]) then
begin
Result := RType;
Exit;
Exit(RType);
end;
{ Shift operators: result has the left operand's type; right is the shift amount }
@ -8068,8 +8020,7 @@ begin
ProcDesc.ReturnType := MD.ResolvedReturnType;
FldExpr.ResolvedType := ProcDesc;
AExpr.ResolvedType := ProcDesc;
Result := ProcDesc;
Exit;
Exit(ProcDesc);
end;
end;
end;
@ -8223,8 +8174,7 @@ begin
SemanticError(
'Expression is not callable — expected procedural type',
AExpr.Line, AExpr.Col);
Result := FTable.TypeInteger;
Exit;
Exit(FTable.TypeInteger);
end;
ProcDesc := TProceduralTypeDesc(CalleeType);
AExpr.ResolvedProcType := ProcDesc;
@ -8364,8 +8314,7 @@ begin
if AExpr.Elements.Count = 0 then
begin
AExpr.ResolvedType := nil;
Result := nil;
Exit;
Exit(nil);
end;
ElemType := AnalyseExpr(TASTExpr(AExpr.Elements.Items[0]));
for I := 1 to AExpr.Elements.Count - 1 do

View file

@ -731,8 +731,7 @@ begin
E := TVTableEntry(FVTable.Items[I]);
if SameText(E.MethName, AMethodName) then
begin
Result := I;
Exit;
Exit(I);
end;
end;
end;
@ -812,8 +811,7 @@ begin
for I := 0 to Walk.FProperties.Count - 1 do
if SameText(TPropertyInfo(Walk.FProperties.Items[I]).Name, AName) then
begin
Result := TPropertyInfo(Walk.FProperties.Items[I]);
Exit;
Exit(TPropertyInfo(Walk.FProperties.Items[I]));
end;
Walk := Walk.Parent;
end;
@ -834,8 +832,7 @@ begin
P := TPropertyInfo(Walk.FProperties.Items[I]);
if (P.IndexParamName <> '') and (P.ReadMethod <> '') then
begin
Result := P;
Exit;
Exit(P);
end;
end;
Walk := Walk.Parent;
@ -931,8 +928,7 @@ begin
CurPar := CurPar + 1
else if CurPar = AParamIndex then
begin
Result := Flags[Idx] = '1';
Exit;
Exit(Flags[Idx] = '1');
end;
Idx := Idx + 1;
end;
@ -1010,11 +1006,9 @@ begin
Tail := Tail.NextOverload;
Tail.NextOverload := ASymbol;
FSymbols.Add(ASymbol); { take ownership; lookup walks the chain via Existing }
Result := True;
Exit;
Exit(True);
end;
Result := False;
Exit;
Exit(False);
end;
FSymbols.Add(ASymbol);
{ Store the TSymbol pointer directly in the string list's Objects slot. }
@ -1072,8 +1066,7 @@ begin
for I := 0 to Members.Count - 1 do
if SameText(Members.Strings[I], AMember) then
begin
Result := I;
Exit;
Exit(I);
end;
Result := -1;
end;

View file

@ -100,8 +100,7 @@ begin
Candidate := IncludeTrailingPathDelimiter(ADir) + ABaseName;
if FileExists(Candidate) then
begin
Result := Candidate;
Exit;
Exit(Candidate);
end;
{ Blaise Pos: -1 = not found. `< 0` is the "not present" test. }
if IsWindowsHost and (Pos('.exe', LowerCase(ABaseName)) < 0) then
@ -109,8 +108,7 @@ begin
Candidate := IncludeTrailingPathDelimiter(ADir) + ABaseName + '.exe';
if FileExists(Candidate) then
begin
Result := Candidate;
Exit;
Exit(Candidate);
end;
end;
Result := '';
@ -144,8 +142,7 @@ begin
Hit := TrySingleName(Entry, ABaseName);
if Hit <> '' then
begin
Result := Hit;
Exit;
Exit(Hit);
end;
end;
end;
@ -181,8 +178,7 @@ begin
EnvPath := GetEnvironmentVariable(AEnvVar);
if (EnvPath <> '') and FileExists(EnvPath) then
begin
Result := EnvPath;
Exit;
Exit(EnvPath);
end;
end;
Hit := TryCandidate(ACandA);

View file

@ -68,15 +68,13 @@ begin
Path := Base + LowerCase(AName) + '.pas';
if FileExists(Path) then
begin
Result := Path;
Exit;
Exit(Path);
end;
{ Fallback: exact case as written in the uses clause }
Path := Base + AName + '.pas';
if FileExists(Path) then
begin
Result := Path;
Exit;
Exit(Path);
end;
end;
Result := '';

View file

@ -37,6 +37,7 @@ type
{ Non-local exit (Exit/Break) must run intervening finally bodies. }
procedure TestRun_ExitThroughFinally;
procedure TestRun_ExitValueThroughFinally;
procedure TestRun_ExitThroughNestedFinally;
procedure TestRun_BreakThroughFinally;
@ -124,6 +125,29 @@ const
end.
''';
{ Exit(X) from inside a try/finally must assign the result, run the finally
body, then return the value to the caller. Guards the refactor that
replaces the 'Result := X; Exit;' workaround with 'Exit(X)' in source
that sits inside try/finally. }
SrcExitValueThroughFinally = '''
program P;
function Pick(b: Boolean): Integer;
begin
Result := -1;
try
if b then Exit(42);
WriteLn('unreached')
finally
WriteLn('in_finally')
end;
Result := 7
end;
begin
WriteLn(Pick(True));
WriteLn(Pick(False))
end.
''';
{ Exit nested two levels deep must run both finally bodies, innermost first. }
SrcExitThroughNestedFinally = '''
program P;
@ -350,6 +374,19 @@ begin
'in_try' + LE + 'in_finally' + LE + 'after' + LE, Output);
end;
procedure TE2EExceptionTests.TestRun_ExitValueThroughFinally;
var Output: string; RCode: Integer;
begin
if not ToolchainAvailable then begin Ignore('toolchain unavailable'); Exit; end;
AssertTrue('compile+run', CompileAndRun(SrcExitValueThroughFinally, Output, RCode));
AssertEquals('exit code', 0, RCode);
{ True: Exit(42) sets Result, runs finally, returns 42.
False: falls through, runs finally, then Result := 7. }
AssertEquals('stdout',
'in_finally' + LE + '42' + LE +
'unreached' + LE + 'in_finally' + LE + '7' + LE, Output);
end;
procedure TE2EExceptionTests.TestRun_ExitThroughNestedFinally;
var Output: string; RCode: Integer;
begin

View file

@ -411,8 +411,7 @@ var
begin
if S1 = S2 then
begin
Result := 1;
Exit;
Exit(1);
end;
if S1 = nil then
Len1 := 0
@ -430,13 +429,11 @@ begin
end;
if Len1 <> Len2 then
begin
Result := 0;
Exit;
Exit(0);
end;
if Len1 = 0 then
begin
Result := 1;
Exit;
Exit(1);
end;
C1 := PChar(S1); { data IS the pointer }
C2 := PChar(S2);
@ -506,8 +503,7 @@ var
begin
if Self = nil then
begin
Result := nil;
Exit;
Exit(nil);
end;
Slot := Self; { instance: first 8 bytes = vptr }
VTable := Slot^; { VTable points to vtable data }
@ -561,8 +557,7 @@ begin
Entry := Pointer(Entry) + 8;
if _StringEquals(EntName, Name) <> 0 then
begin
Result := EntAddr;
Exit;
Exit(EntAddr);
end;
end;
end;
@ -588,8 +583,7 @@ begin
begin
if Current = AParent then
begin
Result := True;
Exit;
Exit(True);
end;
TI := Current; { typeinfo[0] = parent pointer }
Current := TI^;
@ -690,8 +684,7 @@ begin
begin
if Entry^ = AAttrTI then
begin
Result := True;
Exit;
Exit(True);
end;
Entry := Pointer(Entry) + 8;
end;

View file

@ -72,8 +72,7 @@ begin
Base := _BlaiseGetMem(13);
if Base = nil then
begin
Result := nil;
Exit;
Exit(nil);
end;
RC := Base;
RC^ := 0;
@ -140,8 +139,7 @@ begin
Exc := g_current_exception;
if Exc = nil then
begin
Result := ExcStrEmpty;
Exit;
Exit(ExcStrEmpty);
end;
MsgSlot := Exc + 8;
Msg := MsgSlot^;
@ -174,8 +172,7 @@ begin
begin
if TI = Target then
begin
Result := 1;
Exit;
Exit(1);
end;
ParentSlot := TI;
TI := ParentSlot^;
@ -202,8 +199,7 @@ begin
begin
if Impl^ = IntfTI then
begin
Result := 1;
Exit;
Exit(1);
end;
Impl := Pointer(Impl) + 16;
end;
@ -234,8 +230,7 @@ begin
if Impl^ = IntfTI then
begin
ItabSlot := Pointer(Impl) + 8;
Result := ItabSlot^;
Exit;
Exit(ItabSlot^);
end;
Impl := Pointer(Impl) + 16;
end;

View file

@ -54,8 +54,7 @@ begin
Base := _BlaiseGetMem(BLAISE_STR_HDR + Cap);
if Base = nil then
begin
Result := nil;
Exit;
Exit(nil);
end;
RC := Base; RC^ := 1;
LN := Base + 4; LN^ := Len;
@ -123,8 +122,7 @@ var
begin
if X = 0 then
begin
Result := 64;
Exit;
Exit(64);
end;
N := 0;
if (X shr 32) = 0 then begin N := N + 32; X := X shl 32; end;
@ -645,8 +643,7 @@ var
begin
if E = 0 then
begin
Result := 1.0;
Exit;
Exit(1.0);
end;
if E < 0 then
N := -E
@ -682,8 +679,7 @@ var
begin
if S = nil then
begin
Result := 0.0;
Exit;
Exit(0.0);
end;
P := PChar(S);
I := 0;
@ -710,14 +706,12 @@ begin
Bits := Int64($FFF0000000000000)
else
Bits := Int64($7FF0000000000000);
Result := BitsToDouble(Bits);
Exit;
Exit(BitsToDouble(Bits));
end;
if (C = 110) or (C = 78) then
begin
Bits := Int64($7FF8000000000000);
Result := BitsToDouble(Bits);
Exit;
Exit(BitsToDouble(Bits));
end;
{ Parse mantissa digits }

View file

@ -172,8 +172,7 @@ begin
Base := MmapAlloc(Int64(ARENA_SIZE));
if Base = nil then
begin
Result := nil;
Exit;
Exit(nil);
end;
A := PArena(Base);
A^.Base := Base;
@ -200,15 +199,13 @@ begin
Hdr^.AllocSize := Size;
Hdr^.Flags := FLAG_SMALL;
A^.Offset := A^.Offset + Needed;
Result := Pointer(PtrUInt(Hdr) + HEADER_SIZE);
Exit;
Exit(Pointer(PtrUInt(Hdr) + HEADER_SIZE));
end;
A := AllocArena;
if A = nil then
begin
Result := nil;
Exit;
Exit(nil);
end;
Hdr := Pointer(PtrUInt(A^.Base) + PtrUInt(A^.Offset));
Hdr^.AllocSize := Size;
@ -231,8 +228,7 @@ begin
FreeLists[Idx] := Node^.Next;
Hdr := PBlockHeader(Pointer(PtrUInt(Node) - HEADER_SIZE));
Hdr^.AllocSize := Size;
Result := Pointer(Node);
Exit;
Exit(Pointer(Node));
end;
Result := ArenaAlloc(Size);
@ -273,8 +269,7 @@ begin
Hdr^.TotalMapped := CachedSize;
Hdr^.AllocSize := Size;
Hdr^.Flags := FLAG_LARGE;
Result := Pointer(PtrUInt(Hdr) + LARGE_HEADER);
Exit;
Exit(Pointer(PtrUInt(Hdr) + LARGE_HEADER));
end;
Base := _libc_mremap(Pointer(Node), CachedSize, Needed, MREMAP_MAYMOVE);
if not MapFailed(Base) then
@ -283,8 +278,7 @@ begin
Hdr^.TotalMapped := Needed;
Hdr^.AllocSize := Size;
Hdr^.Flags := FLAG_LARGE;
Result := Pointer(PtrUInt(Base) + LARGE_HEADER);
Exit;
Exit(Pointer(PtrUInt(Base) + LARGE_HEADER));
end;
_libc_munmap(Pointer(Node), CachedSize);
end;
@ -293,8 +287,7 @@ begin
Base := MmapAlloc(Total);
if Base = nil then
begin
Result := nil;
Exit;
Exit(nil);
end;
Hdr := PLargeHeader(Base);
Hdr^.TotalMapped := Total;
@ -352,8 +345,7 @@ function _BlaiseGetMem(Size: Integer): Pointer;
begin
if Size <= 0 then
begin
Result := nil;
Exit;
Exit(nil);
end;
if Size > LARGE_THRESHOLD then
Result := LargeGetMem(Size)
@ -380,14 +372,12 @@ var
begin
if Ptr = nil then
begin
Result := _BlaiseGetMem(NewSize);
Exit;
Exit(_BlaiseGetMem(NewSize));
end;
if NewSize <= 0 then
begin
_BlaiseFreeMem(Ptr);
Result := nil;
Exit;
Exit(nil);
end;
OldSize := GetAllocSize(Ptr);
if (not IsLarge(Ptr)) and (NewSize <= LARGE_THRESHOLD) then
@ -396,8 +386,7 @@ begin
begin
Hdr := PBlockHeader(Pointer(PtrUInt(Ptr) - HEADER_SIZE));
Hdr^.AllocSize := NewSize;
Result := Ptr;
Exit;
Exit(Ptr);
end;
end;
if IsLarge(Ptr) and (NewSize > LARGE_THRESHOLD) then
@ -408,8 +397,7 @@ begin
if NewMapped = OldMapped then
begin
LHdr^.AllocSize := NewSize;
Result := Ptr;
Exit;
Exit(Ptr);
end;
Base := Pointer(LHdr);
NewBase := _libc_mremap(Base, OldMapped, NewMapped, MREMAP_MAYMOVE);
@ -419,8 +407,7 @@ begin
LHdr^.TotalMapped := NewMapped;
LHdr^.AllocSize := NewSize;
LHdr^.Flags := FLAG_LARGE;
Result := Pointer(PtrUInt(NewBase) + LARGE_HEADER);
Exit;
Exit(Pointer(PtrUInt(NewBase) + LARGE_HEADER));
end;
end;
Result := _BlaiseGetMem(NewSize);

View file

@ -153,8 +153,7 @@ begin
Base := _BlaiseGetMem(Integer(TotalL));
if Base = nil then
begin
Result := nil;
Exit;
Exit(nil);
end;
RC := Base; { RefCount at base+0 }
RC^ := 0;
@ -191,13 +190,11 @@ begin
SubLen := StrLen(Sub);
if SubLen = 0 then
begin
Result := 0;
Exit;
Exit(0);
end;
if SubLen > SLen then
begin
Result := -1;
Exit;
Exit(-1);
end;
SData := StrData(S);
SubData := StrData(Sub);
@ -217,8 +214,7 @@ begin
end;
if Match then
begin
Result := I;
Exit;
Exit(I);
end;
Inc(I);
end;
@ -241,13 +237,11 @@ begin
SubLen := StrLen(Sub);
if SubLen = 0 then
begin
Result := 0;
Exit;
Exit(0);
end;
if (SubLen > SLen) or (StartPos >= SLen) then
begin
Result := -1;
Exit;
Exit(-1);
end;
SData := StrData(S);
SubData := StrData(Sub);
@ -268,8 +262,7 @@ begin
end;
if Match then
begin
Result := I;
Exit;
Exit(I);
end;
Inc(I);
end;
@ -289,8 +282,7 @@ begin
if From < 0 then From := 0;
if From >= SLen then
begin
Result := StrAlloc(0);
Exit;
Exit(StrAlloc(0));
end;
{ Avoid signed overflow when Count is large (Copy(S, N, MaxInt) idiom) —
compare Count against (SLen - From) instead of (From + Count) > SLen. }
@ -468,8 +460,7 @@ begin
Len2 := StrLen(S2);
if Len1 <> Len2 then
begin
Result := 0;
Exit;
Exit(0);
end;
D1 := StrData(S1);
D2 := StrData(S2);
@ -481,8 +472,7 @@ begin
if (C2 >= 65) and (C2 <= 90) then C2 := C2 + 32;
if C1 <> C2 then
begin
Result := 0;
Exit;
Exit(0);
end;
end;
Result := 1;
@ -755,8 +745,7 @@ begin
Len := StrLen(S);
if (I < 0) or (I >= Len) then
begin
Result := 0;
Exit;
Exit(0);
end;
Data := StrData(S);
Result := Data[I];
@ -811,8 +800,7 @@ begin
C2 := D2[I];
if C1 <> C2 then
begin
Result := C1 - C2;
Exit;
Exit(C1 - C2);
end;
end;
Result := Len1 - Len2;
@ -841,8 +829,7 @@ begin
if (C2 >= 65) and (C2 <= 90) then C2 := C2 + 32;
if C1 <> C2 then
begin
Result := C1 - C2;
Exit;
Exit(C1 - C2);
end;
end;
Result := Len1 - Len2;
@ -858,8 +845,7 @@ var
begin
if P = nil then
begin
Result := StrAlloc(0);
Exit;
Exit(StrAlloc(0));
end;
Len := 0;
while P[Len] <> 0 do
@ -1115,8 +1101,7 @@ begin
if P[I] = 47 then SlashPos := I;
if SlashPos < 0 then
begin
Result := StrAlloc(0);
Exit;
Exit(StrAlloc(0));
end;
Result := StrAlloc(SlashPos + 1);
if Result <> nil then MemCopy(Result, P, SlashPos + 1);
@ -1134,8 +1119,7 @@ begin
if P[I] = 47 then SlashPos := I;
if (SlashPos < 0) or (SlashPos = 0) then
begin
Result := StrAlloc(0);
Exit;
Exit(StrAlloc(0));
end;
Result := StrAlloc(SlashPos);
if Result <> nil then MemCopy(Result, P, SlashPos);
@ -1158,8 +1142,7 @@ begin
end;
if (LastDot < 0) or ((LastSep >= 0) and (LastDot < LastSep)) then
begin
Result := StrAlloc(0);
Exit;
Exit(StrAlloc(0));
end;
ExtLen := PLen - LastDot;
Result := StrAlloc(ExtLen);
@ -1213,8 +1196,7 @@ var
begin
if Ptr = nil then
begin
Result := 0;
Exit;
Exit(0);
end;
{ length is stored at offset −4 from data pointer }
LenPtr := Ptr - 4;
@ -1240,8 +1222,7 @@ begin
begin
if Ptr <> nil then
_BlaiseFreeMem(Ptr - DA_HDR);
Result := nil;
Exit;
Exit(nil);
end;
DataSz := DA_HDR + NewLen * ElemSize;
NewBase := _BlaiseGetMem(DataSz);

View file

@ -85,16 +85,14 @@ begin
begin
if E^.Target = ATarget then
begin
Result := E;
Exit;
Exit(E);
end;
E := E^.Next;
end;
E := PWeakEntry(_BlaiseGetMem(24));
if E = nil then
begin
Result := nil;
Exit;
Exit(nil);
end;
E^.Target := ATarget;
E^.Slots := nil;

View file

@ -1050,8 +1050,7 @@ begin
begin
libc_close(P^.PipeFd);
P^.PipeFd := -1;
Result := StrAlloc(0);
Exit;
Exit(StrAlloc(0));
end;
R := StrAlloc(Integer(N));
if R <> nil then

View file

@ -310,8 +310,7 @@ begin
for I := 0 to High(Arr) do
if Arr[I] = Str then
begin
Result := I;
Exit;
Exit(I);
end;
Result := -1;
end;
@ -328,8 +327,7 @@ begin
EL := LowerCase(Arr[I]);
if EL = SL then
begin
Result := I;
Exit;
Exit(I);
end;
end;
Result := -1;
@ -354,8 +352,7 @@ begin
NewLen := Length(NewP);
if (SLen = 0) or (OldLen = 0) then
begin
Result := S;
Exit;
Exit(S);
end;
SP := PChar(S);
OP := PChar(OldP);
@ -421,8 +418,7 @@ var
begin
if (Count <= 0) or (Length(S) = 0) then
begin
Result := '';
Exit;
Exit('');
end;
SB := TStringBuilder.Create;
for I := 1 to Count do
@ -501,8 +497,7 @@ begin
Len := Length(S);
if Len >= Width then
begin
Result := S;
Exit;
Exit(S);
end;
PadCount := Width - Len;
SB := TStringBuilder.Create;
@ -521,8 +516,7 @@ begin
Len := Length(S);
if Len >= Width then
begin
Result := S;
Exit;
Exit(S);
end;
PadCount := Width - Len;
SB := TStringBuilder.Create;
@ -604,8 +598,7 @@ var
begin
if High(Parts) < 0 then
begin
Result := '';
Exit;
Exit('');
end;
SB := TStringBuilder.Create;
for I := 0 to High(Parts) do

View file

@ -81,8 +81,7 @@ var
begin
if APath = '' then
begin
Result := GetCurrentDir;
Exit;
Exit(GetCurrentDir);
end;
{ Determine base: absolute or relative }