Skip to content

Commit 5767ec8

Browse files
[All] Fix StringBuilder.Chars getter and setter (#4339)
Co-authored-by: Dag Brattli <dag.brattli@cognite.com>
1 parent c39d624 commit 5767ec8

File tree

11 files changed

+133
-74
lines changed

11 files changed

+133
-74
lines changed

src/Fable.Cli/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2727
* [Python] Fix type annotations for protocols, ABCs, Atom, and Set module (by @dbrattli)
2828
* [Python] Fix type annotations for async functions, date operations, and None handling (by @dbrattli)
2929
* [Python] Fix type annotations for tuple indexing, generic defaults, and reflection (by @dbrattli)
30+
* [All] Fix `StringBuilder.Chars` getter and setter (by @MangelMaxime)
3031

3132
### Removed
3233

src/Fable.Compiler/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2727
* [Python] Fix type annotations for protocols, ABCs, Atom, and Set module (by @dbrattli)
2828
* [Python] Fix type annotations for async functions, date operations, and None handling (by @dbrattli)
2929
* [Python] Fix type annotations for tuple indexing, generic defaults, and reflection (by @dbrattli)
30+
* [All] Fix `StringBuilder.Chars` getter and setter (by @MangelMaxime)
3031

3132
## 5.0.0-alpha.21 - 2025-12-26
3233

src/fable-library-dart/System.Text.fs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -101,35 +101,35 @@ type StringBuilder(value: string, capacity: int) =
101101

102102
with get (index: int) =
103103
let mutable len = 0
104-
let mutable i = -1
104+
let mutable i = 0
105105

106-
while i + 1 < buf.Count && len < index do
107-
i <- i + 1
106+
while i < buf.Count && len + buf[i].Length <= index do
108107
len <- len + buf[i].Length
108+
i <- i + 1
109109

110-
if index < 0 || i < 0 || i >= buf.Count then
110+
if index < 0 || i >= buf.Count then
111111
failwith "Index was outside the bounds of the array"
112112
else
113-
let pos = len - index - 1
113+
let pos = index - len
114114
buf[i][pos]
115115

116116
and set (index: int) (value: char) =
117117
let mutable len = 0
118-
let mutable i = -1
118+
let mutable i = 0
119119

120-
while i + 1 < buf.Count && len < index do
121-
i <- i + 1
120+
while i < buf.Count && len + buf[i].Length <= index do
122121
len <- len + buf[i].Length
122+
i <- i + 1
123123

124-
if index < 0 || i < 0 || i >= buf.Count then
124+
if index < 0 || i >= buf.Count then
125125
failwith "Index was outside the bounds of the array"
126126
else
127-
let pos = len - index - 1
128-
buf[i] <- buf[i][0 .. (pos - 1)] + (string value) + buf[i][(pos + 1) ..]
127+
let pos = index - len
128+
buf[i] <- buf[i][0 .. (pos - 1)] + (string<char> value) + buf[i][(pos + 1) ..]
129129

130130
member x.Replace(oldValue: char, newValue: char) =
131-
let oldValue = string oldValue
132-
let newValue = string newValue
131+
let oldValue = string<char> oldValue
132+
let newValue = string<char> newValue
133133

134134
for i = buf.Count - 1 downto 0 do
135135
buf[i] <- buf[i].Replace(oldValue, newValue)

src/fable-library-py/fable_library/System.Text.fs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ type StringBuilder(value: string, capacity: int) =
1515
new() = StringBuilder("", 16)
1616

1717
member x.Append(s: string | null) =
18-
buf.Add(string s)
18+
buf.Add(string<string | null> s)
1919
x
2020

2121
member x.Append(s: string | null, startIndex: int, count: int) =
22-
buf.Add((string s).Substring(startIndex, count))
22+
buf.Add((string<string | null> s).Substring(startIndex, count))
2323
x
2424

2525
member x.Append(c: char) =
@@ -104,31 +104,31 @@ type StringBuilder(value: string, capacity: int) =
104104

105105
with get (index: int) =
106106
let mutable len = 0
107-
let mutable i = -1
107+
let mutable i = 0
108108

109-
while i + 1 < buf.Count && len < index do
110-
i <- i + 1
109+
while i < buf.Count && len + buf[i].Length <= index do
111110
len <- len + buf[i].Length
111+
i <- i + 1
112112

113-
if index < 0 || i < 0 || i >= buf.Count then
113+
if index < 0 || i >= buf.Count then
114114
failwith "Index was outside the bounds of the array"
115115
else
116-
let pos = len - index - 1
116+
let pos = index - len
117117
buf[i][pos]
118118

119119
and set (index: int) (value: char) =
120120
let mutable len = 0
121-
let mutable i = -1
121+
let mutable i = 0
122122

123-
while i + 1 < buf.Count && len < index do
124-
i <- i + 1
123+
while i < buf.Count && len + buf[i].Length <= index do
125124
len <- len + buf[i].Length
125+
i <- i + 1
126126

127-
if index < 0 || i < 0 || i >= buf.Count then
127+
if index < 0 || i >= buf.Count then
128128
failwith "Index was outside the bounds of the array"
129129
else
130-
let pos = len - index - 1
131-
buf[i] <- buf[i][0 .. (pos - 1)] + (string value) + buf[i][(pos + 1) ..]
130+
let pos = index - len
131+
buf[i] <- buf[i][0 .. (pos - 1)] + (string<char> value) + buf[i][(pos + 1) ..]
132132

133133
member x.Replace(oldValue: char, newValue: char) =
134134
for i = buf.Count - 1 downto 0 do

src/fable-library-rust/src/System.Text.fs

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,24 @@ type StringBuilder(value: string, capacity: int) =
1717
buf.Add(s)
1818
x
1919

20-
member x.Append(o: bool) = x.Append(string o)
21-
member x.Append(c: char) = x.Append(string c)
20+
member x.Append(o: bool) = x.Append(string<bool> o)
21+
member x.Append(c: char) = x.Append(string<char> c)
2222

2323
member x.Append(c: char, repeatCount: int) =
2424
let s = String.replicate repeatCount (string<char> c)
2525
buf.Add(s)
2626
x
2727

28-
member x.Append(o: int8) = x.Append(string o)
29-
member x.Append(o: byte) = x.Append(string o)
30-
member x.Append(o: int16) = x.Append(string o)
31-
member x.Append(o: uint16) = x.Append(string o)
32-
member x.Append(o: int32) = x.Append(string o)
33-
member x.Append(o: uint32) = x.Append(string o)
34-
member x.Append(o: int64) = x.Append(string o)
35-
member x.Append(o: uint64) = x.Append(string o)
36-
member x.Append(o: float32) = x.Append(string o)
37-
member x.Append(o: float) = x.Append(string o)
28+
member x.Append(o: int8) = x.Append(string<int8> o)
29+
member x.Append(o: byte) = x.Append(string<byte> o)
30+
member x.Append(o: int16) = x.Append(string<int16> o)
31+
member x.Append(o: uint16) = x.Append(string<uint16> o)
32+
member x.Append(o: int32) = x.Append(string<int32> o)
33+
member x.Append(o: uint32) = x.Append(string<uint32> o)
34+
member x.Append(o: int64) = x.Append(string<int64> o)
35+
member x.Append(o: uint64) = x.Append(string<uint64> o)
36+
member x.Append(o: float32) = x.Append(string<float32> o)
37+
member x.Append(o: float) = x.Append(string<float> o)
3838

3939
member x.Append(s: string, index: int, count: int) = x.Append(s.Substring(index, count))
4040

@@ -57,31 +57,31 @@ type StringBuilder(value: string, capacity: int) =
5757

5858
with get (index: int) =
5959
let mutable len = 0
60-
let mutable i = -1
60+
let mutable i = 0
6161

62-
while i + 1 < buf.Count && len < index do
63-
i <- i + 1
62+
while i < buf.Count && len + buf[i].Length <= index do
6463
len <- len + buf[i].Length
64+
i <- i + 1
6565

66-
if index < 0 || i < 0 || i >= buf.Count then
66+
if index < 0 || i >= buf.Count then
6767
failwith "Index was outside the bounds of the array"
6868
else
69-
let pos = len - index - 1
69+
let pos = index - len
7070
buf[i][pos]
7171

7272
and set (index: int) (value: char) =
7373
let mutable len = 0
74-
let mutable i = -1
74+
let mutable i = 0
7575

76-
while i + 1 < buf.Count && len < index do
77-
i <- i + 1
76+
while i < buf.Count && len + buf[i].Length <= index do
7877
len <- len + buf[i].Length
78+
i <- i + 1
7979

80-
if index < 0 || i < 0 || i >= buf.Count then
80+
if index < 0 || i >= buf.Count then
8181
failwith "Index was outside the bounds of the array"
8282
else
83-
let pos = len - index - 1
84-
buf[i] <- buf[i][0 .. (pos - 1)] + (string value) + buf[i][(pos + 1) ..]
83+
let pos = index - len
84+
buf[i] <- buf[i][0 .. (pos - 1)] + (string<char> value) + buf[i][(pos + 1) ..]
8585

8686
member x.Length =
8787
let mutable len = 0
@@ -92,8 +92,8 @@ type StringBuilder(value: string, capacity: int) =
9292
len
9393

9494
member x.Replace(oldValue: char, newValue: char) =
95-
let oldValue = string oldValue
96-
let newValue = string newValue
95+
let oldValue = string<char> oldValue
96+
let newValue = string<char> newValue
9797

9898
for i = buf.Count - 1 downto 0 do
9999
buf[i] <- buf[i].Replace(oldValue, newValue)

src/fable-library-ts/System.Text.fs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ type StringBuilder(value: string, capacity: int) =
1212
new() = StringBuilder("", 16)
1313

1414
member x.Append(s: string | null) =
15-
buf.Add(string s)
15+
buf.Add(string<string | null> s)
1616
x
1717

1818
member x.Append(s: string | null, startIndex: int, count: int) =
19-
buf.Add((string s).Substring(startIndex, count))
19+
buf.Add((string<string | null> s).Substring(startIndex, count))
2020
x
2121

2222
member x.Append(c: char) =
@@ -101,31 +101,31 @@ type StringBuilder(value: string, capacity: int) =
101101

102102
with get (index: int) =
103103
let mutable len = 0
104-
let mutable i = -1
104+
let mutable i = 0
105105

106-
while i + 1 < buf.Count && len < index do
107-
i <- i + 1
106+
while i < buf.Count && len + buf[i].Length <= index do
108107
len <- len + buf[i].Length
108+
i <- i + 1
109109

110-
if index < 0 || i < 0 || i >= buf.Count then
110+
if index < 0 || i >= buf.Count then
111111
failwith "Index was outside the bounds of the array"
112112
else
113-
let pos = len - index - 1
113+
let pos = index - len
114114
buf[i][pos]
115115

116116
and set (index: int) (value: char) =
117117
let mutable len = 0
118-
let mutable i = -1
118+
let mutable i = 0
119119

120-
while i + 1 < buf.Count && len < index do
121-
i <- i + 1
120+
while i < buf.Count && len + buf[i].Length <= index do
122121
len <- len + buf[i].Length
122+
i <- i + 1
123123

124-
if index < 0 || i < 0 || i >= buf.Count then
124+
if index < 0 || i >= buf.Count then
125125
failwith "Index was outside the bounds of the array"
126126
else
127-
let pos = len - index - 1
128-
buf[i] <- buf[i][0 .. (pos - 1)] + (string value) + buf[i][(pos + 1) ..]
127+
let pos = index - len
128+
buf[i] <- buf[i][0 .. (pos - 1)] + (string<char> value) + buf[i][(pos + 1) ..]
129129

130130
member x.Replace(oldValue: char, newValue: char) =
131131
for i = buf.Count - 1 downto 0 do

tests/Dart/src/StringTests.fs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,13 +145,20 @@ let tests() =
145145
testCase "StringBuilder.Chars works" <| fun () ->
146146
let sb = System.Text.StringBuilder()
147147
.Append("abc")
148+
.Append("def")
149+
sb.Chars(0) |> equal 'a'
148150
sb.Chars(1) |> equal 'b'
151+
sb.Chars(2) |> equal 'c'
152+
sb.Chars(3) |> equal 'd'
153+
sb.Chars(4) |> equal 'e'
154+
sb.Chars(5) |> equal 'f'
149155

150156
testCase "StringBuilder.Chars throws when index is out of bounds" <| fun () ->
157+
let sb = System.Text.StringBuilder()
158+
.Append("abc")
151159
throwsAnyError <| fun () ->
152-
let sb = System.Text.StringBuilder()
153-
.Append("abc")
154160
sb.Chars(-1) |> ignore
161+
throwsAnyError <| fun () ->
155162
sb.Chars(3) |> ignore
156163

157164
testCase "StringBuilder.Replace works" <| fun () ->
@@ -173,6 +180,11 @@ let tests() =
173180
sb[1] <- 'x'
174181
sb.ToString() |> equal "axc"
175182

183+
throwsAnyError <| fun () ->
184+
sb[-1] <- 'y'
185+
throwsAnyError <| fun () ->
186+
sb[3] <- 'z'
187+
176188
// Formatting
177189

178190
// testCase "kprintf works" <| fun () ->

tests/Js/Main/StringTests.fs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,20 @@ let tests = testList "Strings" [
123123
testCase "StringBuilder.Chars works" <| fun () ->
124124
let sb = System.Text.StringBuilder()
125125
.Append("abc")
126+
.Append("def")
127+
sb.Chars(0) |> equal 'a'
126128
sb.Chars(1) |> equal 'b'
129+
sb.Chars(2) |> equal 'c'
130+
sb.Chars(3) |> equal 'd'
131+
sb.Chars(4) |> equal 'e'
132+
sb.Chars(5) |> equal 'f'
127133

128134
testCase "StringBuilder.Chars throws when index is out of bounds" <| fun () ->
135+
let sb = System.Text.StringBuilder()
136+
.Append("abc")
129137
throwsAnyError <| fun () ->
130-
let sb = System.Text.StringBuilder()
131-
.Append("abc")
132138
sb.Chars(-1) |> ignore
139+
throwsAnyError <| fun () ->
133140
sb.Chars(3) |> ignore
134141

135142
testCase "StringBuilder.Replace works" <| fun () ->
@@ -150,6 +157,10 @@ let tests = testList "Strings" [
150157
.Append("abc")
151158
sb[1] <- 'x'
152159
sb.ToString() |> equal "axc"
160+
throwsAnyError <| fun () ->
161+
sb[-1] <- 'y'
162+
throwsAnyError <| fun () ->
163+
sb[3] <- 'z'
153164

154165
// Formatting
155166

tests/Php/TestString.fs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,14 +218,21 @@ let ``StringBuilder.AppendFormat with provider works`` () =
218218
let ``StringBuilder.Chars works`` () =
219219
let sb = System.Text.StringBuilder()
220220
.Append("abc")
221+
.Append("def")
222+
sb.Chars(0) |> equal 'a'
221223
sb.Chars(1) |> equal 'b'
224+
sb.Chars(2) |> equal 'c'
225+
sb.Chars(3) |> equal 'd'
226+
sb.Chars(4) |> equal 'e'
227+
sb.Chars(5) |> equal 'f'
222228

223229
[<Fact>]
224230
let ``StringBuilder.Chars throws when index is out of bounds`` () =
231+
let sb = System.Text.StringBuilder()
232+
.Append("abc")
225233
throwsAnyError <| fun () ->
226-
let sb = System.Text.StringBuilder()
227-
.Append("abc")
228234
sb.Chars(-1) |> ignore
235+
throwsAnyError <| fun () ->
229236
sb.Chars(3) |> ignore
230237

231238
[<Fact>]
@@ -249,6 +256,10 @@ let ``StringBuilder index setter works`` () =
249256
.Append("abc")
250257
sb[1] <- 'x'
251258
sb.ToString() |> equal "axc"
259+
throwsAnyError <| fun () ->
260+
sb[-1] <- 'y'
261+
throwsAnyError <| fun () ->
262+
sb[3] <- 'z'
252263

253264
[<Fact>]
254265
let ``test Conversion char to int works`` () =

0 commit comments

Comments
 (0)