mirror of
https://github.com/Nexoniarz/Finch.git
synced 2026-11-03 00:44:27 +00:00
Warnings for big copies: a struct with 256+ bytes of plain data as a parameter or in for x in list
- on stderr (finch ir stays the IR), as yellow warnings in editors (@W in the index), once per place - str, arrays and maps inside a struct don't count: passing it copies only their handles - none in the compiler, the examples or the tests other than the new one - docs: the warning instead of "not planned"; what was and wasn't checked for Android Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016GzNP6r8dg6WDxUVZy8wjL
This commit is contained in:
parent
961ba951ec
commit
d557b5505e
15 changed files with 210 additions and 18 deletions
|
|
@ -151,7 +151,7 @@ Pick the guide that fits you:
|
|||
- [x] A standard library in Finch: `json`, `path`, `time`, `proc`, `fs`
|
||||
- [x] `const`, `if` as a value, `"\(x)"` in text, `"""` text, C unions and `#define` expressions
|
||||
- [x] `test` blocks and `finch test`, `finch fmt`, `finch.toml`, a build cache, the chain of calls on runtime errors
|
||||
- [x] Threads (`import thread`) and atomics; C++ files; `--target android` (built, not yet tried on a device)
|
||||
- [x] Threads (`import thread`) and atomics; C++ files; `--target android` (compiles; NDK linking and devices untried)
|
||||
|
||||
## Layout
|
||||
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ Wybierz przewodnik dla siebie:
|
|||
- [x] Biblioteka standardowa w Finchu: `json`, `path`, `time`, `proc`, `fs`
|
||||
- [x] `const`, `if` jako wartość, `"\(x)"` w tekście, tekst `"""`, unie C i wyrażenia `#define`
|
||||
- [x] Bloki `test` i `finch test`, `finch fmt`, `finch.toml`, cache budowania, łańcuch wywołań przy błędach
|
||||
- [x] Wątki (`import thread`) i operacje atomowe; pliki C++; `--target android` (budowane, jeszcze nie sprawdzone na urządzeniu)
|
||||
- [x] Wątki (`import thread`) i operacje atomowe; pliki C++; `--target android` (kompiluje się; linkowanie z NDK i urządzenia niesprawdzone)
|
||||
|
||||
## Struktura
|
||||
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ Automatic only when nothing is lost: smaller → bigger number, any int → floa
|
|||
|
||||
- Arrays, text and structs free themselves at the end of their block. No `free` needed.
|
||||
- `b := a` copies; a call's result moves; `return x` moves.
|
||||
- Passing a struct: `fn f(Body b)` works on its own copy (the caller's stays as it was), `fn f(ptr[Body] b)` changes the caller's (`f(body)` or `f(addr(body))`), a method gets `self` by address, never a copy.
|
||||
- Passing a struct: `fn f(Body b)` works on its own copy (the caller's stays as it was), `fn f(ptr[Body] b)` changes the caller's (`f(body)` or `f(addr(body))`), a method gets `self` by address, never a copy. A struct with 256+ bytes of numbers passed by value or in `for x in list` gets a warning.
|
||||
- `new(...)` + `free(...)` (often with `defer`) for linked lists, trees, sharing.
|
||||
- C memory: C's own functions (`malloc` / `free`, `fclose`, …).
|
||||
|
||||
|
|
|
|||
|
|
@ -503,6 +503,13 @@ makes the C-callable thunk. `atomic_add/sub/swap` lower to `atomicrmw add/sub/xc
|
|||
take a `ptr[T]` to any integer type. Finch's arrays, text and maps are not synchronised; sharing one between threads
|
||||
needs a mutex.
|
||||
|
||||
### Warnings
|
||||
|
||||
`warn()` prints `file:line:col: warning: …` to stderr (so `finch ir` stays pure IR) or, with `index`, an `@W` record the
|
||||
language server publishes with severity 2. One per source position. Two are given: a struct parameter, and the element of
|
||||
`for x in list`, whose plain data (`byteSize()`: numbers, nested structs, C `[N]T`; `str`/arrays/maps count 0, as only
|
||||
their handle is copied) is 256 bytes or more.
|
||||
|
||||
### Struct arguments by address
|
||||
|
||||
`argWant()` (call arguments only, not assignments): when a parameter is `ptr[S]` and the argument is a plain variable
|
||||
|
|
|
|||
|
|
@ -1134,11 +1134,20 @@ Not there yet:
|
|||
- Interfaces.
|
||||
- Unicode-aware text: `.len`, `s[i]` and `upper()` work on bytes / ASCII.
|
||||
- Checks that stop two threads from changing the same array at once (use a mutex).
|
||||
- Windows on ARM64, 32-bit systems, WebAssembly. Android is built (`--target android`) but not yet tried on a device.
|
||||
- Windows on ARM64, 32-bit systems, WebAssembly. `--target android` makes code for Android, but linking with the NDK and running on a device are untried.
|
||||
|
||||
On purpose, not planned: a warning for every big struct that gets copied. A copy in Finch is always visible in the
|
||||
code (`b := a`, passing a struct to a `Body b` parameter), a method never copies `self`, and `ptr[Body]` (or passing
|
||||
the variable to a `ptr[Body]` parameter) shares instead. A warning that fires on ordinary code would be noise.
|
||||
### Warnings about big copies
|
||||
|
||||
A struct with 256 bytes or more of plain data (numbers, structs of numbers, C's `[N]T`) is copied byte by byte when it
|
||||
is a parameter (`fn f(Body b)`) and in `for x in bodies`. Finch says so, and still builds the program:
|
||||
|
||||
```
|
||||
game.fch:27:11: warning: 'b' is a Body (264 bytes), copied on every call to weight; take ptr[Body] to share it instead (callers can still pass the variable as it is)
|
||||
game.fch:45:5: warning: each Body (264 bytes) is copied into 'x'; for i in 0..bodies.len with bodies[i] works on it in place
|
||||
```
|
||||
|
||||
Text, arrays and maps inside a struct don't count: passing the struct copies only their handles, not what they hold.
|
||||
`b := a` is not warned about: it says "copy" in the code. A method never copies `self`. Editors show the warnings in yellow.
|
||||
|
||||
See the [roadmap in the README](../../README.md#roadmap).
|
||||
|
||||
|
|
@ -1283,5 +1292,6 @@ Write the header (`float path_len(float x, float y);`, or let `cbindgen` write i
|
|||
|
||||
**Android**: `finch build game.fch --target android --shared` makes `libgame.so` for 64-bit ARM Android (API 24 and
|
||||
up) with the NDK's clang, found through `ANDROID_NDK_HOME` (or `FINCH_CC`). Load it from an app, for example through
|
||||
SDL3's Android project (the library's `SDL_main` is an `export fn`). This is new: it is built and checked here, but not
|
||||
yet tried on a device.
|
||||
SDL3's Android project (the library's `SDL_main` is an `export fn`). This is new and only partly checked: Finch's
|
||||
output compiles for Android (thread-local data goes through the emulated TLS older Android needs), but linking with the
|
||||
NDK and running on a device have not been tried yet.
|
||||
|
|
|
|||
|
|
@ -496,6 +496,13 @@ thunk wołany z C. `atomic_add/sub/swap` to `atomicrmw add/sub/xchg … seq_cst`
|
|||
`ptr[T]` do dowolnej liczby całkowitej. Tablice, teksty i mapy Fincha nie są synchronizowane; dzielenie ich między
|
||||
wątkami wymaga mutexu.
|
||||
|
||||
### Ostrzeżenia
|
||||
|
||||
`warn()` wypisuje `plik:linia:kolumna: warning: …` na stderr (więc `finch ir` daje samo IR) albo, w trybie `index`,
|
||||
rekord `@W`, który serwer języka publikuje z ważnością 2. Jedno na miejsce w kodzie. Są dwa: parametr-struktura oraz
|
||||
element `for x in lista`, gdy ich zwykłe dane (`byteSize()`: liczby, zagnieżdżone struktury, `[N]T` z C; `str`, tablice
|
||||
i mapy liczą się jako 0, bo kopiowany jest tylko ich uchwyt) mają 256 bajtów lub więcej.
|
||||
|
||||
### Struktura jako argument przez adres
|
||||
|
||||
`argWant()` (tylko argumenty wywołań, nie przypisania): gdy parametr to `ptr[S]`, a argument to zwykła zmienna typu `S`,
|
||||
|
|
|
|||
|
|
@ -1138,12 +1138,22 @@ Jeszcze nie ma:
|
|||
- Interfejsów.
|
||||
- Tekstu świadomego Unicode: `.len`, `s[i]` i `upper()` działają na bajtach / ASCII.
|
||||
- Pilnowania, żeby dwa wątki nie zmieniały tej samej tablicy naraz (do tego mutex).
|
||||
- Windowsa na ARM64, systemów 32-bitowych, WebAssembly. Android jest budowany (`--target android`), ale jeszcze nie
|
||||
sprawdzony na urządzeniu.
|
||||
- Windowsa na ARM64, systemów 32-bitowych, WebAssembly. `--target android` robi kod dla Androida, ale linkowanie
|
||||
z NDK i uruchomienie na urządzeniu nie były jeszcze próbowane.
|
||||
|
||||
Celowo nie planowane: ostrzeżenie przy każdym kopiowaniu dużej struktury. Kopię w Finchu zawsze widać w kodzie
|
||||
(`b := a`, struktura podana do parametru `Cialo c`), metoda nigdy nie kopiuje `self`, a `ptr[Cialo]` (albo zmienna
|
||||
podana do parametru `ptr[Cialo]`) współdzieli zamiast kopiować. Ostrzeżenie przy zwykłym kodzie byłoby szumem.
|
||||
### Ostrzeżenia o dużych kopiach
|
||||
|
||||
Struktura z 256 lub więcej bajtami zwykłych danych (liczby, struktury z liczb, `[N]T` z C) jest kopiowana bajt po bajcie,
|
||||
gdy jest parametrem (`fn f(Cialo c)`) i w `for x in ciala`. Finch o tym mówi, a program i tak buduje:
|
||||
|
||||
```
|
||||
gra.fch:27:11: warning: 'c' is a Cialo (264 bytes), copied on every call to waga; take ptr[Cialo] to share it instead (callers can still pass the variable as it is)
|
||||
gra.fch:45:5: warning: each Cialo (264 bytes) is copied into 'x'; for i in 0..ciala.len with ciala[i] works on it in place
|
||||
```
|
||||
|
||||
Teksty, tablice i mapy w strukturze się nie liczą: przekazanie struktury kopiuje tylko ich uchwyty, nie zawartość.
|
||||
`b := a` nie dostaje ostrzeżenia: w kodzie widać, że to kopia. Metoda nigdy nie kopiuje `self`. Edytory pokazują
|
||||
ostrzeżenia na żółto.
|
||||
|
||||
Plan rozwoju jest w [README](../../README.pl.md#plan-rozwoju).
|
||||
|
||||
|
|
@ -1288,5 +1298,6 @@ Napisz nagłówek (`float path_len(float x, float y);` albo niech napisze go `cb
|
|||
|
||||
**Android**: `finch build gra.fch --target android --shared` robi `libgra.so` dla 64-bitowego Androida na ARM (API 24
|
||||
i wyżej) clangiem z NDK, znalezionym przez `ANDROID_NDK_HOME` (albo `FINCH_CC`). Wczytaj go z aplikacji, na przykład
|
||||
przez projekt Androida z SDL3 (`SDL_main` biblioteki to `export fn`). To nowość: jest budowane i sprawdzane tutaj, ale
|
||||
jeszcze nie na urządzeniu.
|
||||
przez projekt Androida z SDL3 (`SDL_main` biblioteki to `export fn`). To nowość, sprawdzona tylko częściowo: kod Fincha
|
||||
kompiluje się dla Androida (dane wątków idą przez emulowane TLS, którego wymaga starszy Android), ale linkowanie z NDK
|
||||
i uruchomienie na urządzeniu nie były jeszcze próbowane.
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ Automatycznie tylko wtedy, gdy nic nie ginie: mniejsza → większa liczba, dowo
|
|||
|
||||
- Tablice, teksty i struktury zwalniają się same na końcu swojego bloku. Bez `free`.
|
||||
- `b := a` kopiuje; wynik wywołania jest przenoszony; `return x` przenosi.
|
||||
- Przekazywanie struktury: `fn f(Cialo c)` pracuje na własnej kopii (ta u wywołującego się nie zmienia), `fn f(ptr[Cialo] c)` zmienia tę u wywołującego (`f(cialo)` albo `f(addr(cialo))`), metoda dostaje `self` przez adres, nigdy kopię.
|
||||
- Przekazywanie struktury: `fn f(Cialo c)` pracuje na własnej kopii (ta u wywołującego się nie zmienia), `fn f(ptr[Cialo] c)` zmienia tę u wywołującego (`f(cialo)` albo `f(addr(cialo))`), metoda dostaje `self` przez adres, nigdy kopię. Struktura z 256+ bajtami liczb przekazana przez wartość albo w `for x in lista` dostaje ostrzeżenie.
|
||||
- `new(...)` + `free(...)` (często z `defer`) do list wiązanych, drzew, współdzielenia.
|
||||
- Pamięć z C: funkcjami z C (`malloc` / `free`, `fclose`, …).
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
- Highlighting for code inside text (`"hp \(hp)"`), `test "…" { }` blocks, `const`, `"""` text, `1e9`.
|
||||
- Built-ins `min`, `max`, `abs`, `clamp`, `assert` and `atomic_…` highlighted and described on hover.
|
||||
- Format Document (the language server runs `finch fmt` on the open file).
|
||||
- Warnings in yellow: a big struct copied on every call or in `for x in list`.
|
||||
|
||||
## 2.4.0
|
||||
|
||||
|
|
|
|||
66
src/gen.fch
66
src/gen.fch
|
|
@ -7,6 +7,7 @@ import ast
|
|||
import docs
|
||||
import cimport
|
||||
import platform
|
||||
import "stdio.h"
|
||||
|
||||
struct Var {
|
||||
str name
|
||||
|
|
@ -166,6 +167,7 @@ struct Ref {
|
|||
|
||||
struct Gen {
|
||||
[]ast.Program progs
|
||||
[]str warned // file:line:col of the warnings given
|
||||
bool trace // each function keeps a frame { prev, name, file, line } in @finch_trace
|
||||
str frame // the current function's frame ("" in helpers)
|
||||
str frameLine // where its line goes
|
||||
|
|
@ -337,6 +339,58 @@ fn fail(ptr[Gen] g, ast.Node n, str msg) {
|
|||
exit(1)
|
||||
}
|
||||
|
||||
// A warning: the program is still built. On stderr (finch ir's output stays the IR); an @W record for editors.
|
||||
fn warn(ptr[Gen] g, ast.Node n, str msg) {
|
||||
where := g.files[n.file] + ":" + str(n.line) + ":" + str(n.col)
|
||||
if g.warned.contains(where) {
|
||||
return // once per place (a generic function is built more than once)
|
||||
}
|
||||
g.warned.push(where)
|
||||
if g.index {
|
||||
g.idx.push("@W\t" + g.files[n.file] + "\t" + str(n.line) + "\t" + str(n.col) + "\t" + msg)
|
||||
return
|
||||
}
|
||||
fputs(where + ": warning: " + msg + "\n", stderr)
|
||||
}
|
||||
|
||||
// About how many bytes of plain data (numbers, structs of them, C's [N]T) a value has, for the copy warnings
|
||||
fn byteSize(ptr[Gen] g, ast.Type t) -> int {
|
||||
k := t.kind
|
||||
if k == "struct" {
|
||||
sd := g.structs[findStruct(g, t.module, t.name)]
|
||||
if sd.isC && sd.csize > 0 {
|
||||
return sd.csize
|
||||
}
|
||||
n := 0
|
||||
for ft in sd.ftypes {
|
||||
n += byteSize(g, ft)
|
||||
}
|
||||
return n
|
||||
}
|
||||
if k == "fixed" && t.elem.len > 0 {
|
||||
return t.count * byteSize(g, t.elem[0])
|
||||
}
|
||||
if k == "str" || k == "array" || k == "map" {
|
||||
return 0 // only its { ptr, len, cap } is copied when it is passed: not counted
|
||||
}
|
||||
if k == "ptr" || k == "enum" || k == "int" || k == "float" {
|
||||
return 8
|
||||
}
|
||||
return bitsOf(t) / 8 + int(bitsOf(t) == 1)
|
||||
}
|
||||
|
||||
// a struct this big passed or looped over by value is copied byte by byte each time
|
||||
fn bigCopy(ptr[Gen] g, ast.Type t) -> int {
|
||||
if t.kind != "struct" {
|
||||
return 0
|
||||
}
|
||||
n := byteSize(g, t)
|
||||
if n >= 256 {
|
||||
return n
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
fn emit(ptr[Gen] g, str line) {
|
||||
// with -g every call in a function that has debug info has to say where it is
|
||||
if g.dbgScope >= 0 && line.contains("call ") {
|
||||
|
|
@ -2306,6 +2360,10 @@ fn define(ptr[Gen] g, int si) {
|
|||
}
|
||||
for k in 0..g.cur.params.len {
|
||||
pt := g.cur.params[k]
|
||||
big := bigCopy(g, pt)
|
||||
if big > 0 {
|
||||
warn(g, f.kids[k], "'" + g.cur.pnames[k] + "' is a " + ast.show(pt) + " (" + str(big) + " bytes), copied on every call to " + f.name + "; take ptr[" + ast.show(pt) + "] to share it instead (callers can still pass the variable as it is)")
|
||||
}
|
||||
params.push(llty(g, pt) + " %p" + str(k))
|
||||
v := "%p" + str(k)
|
||||
if owning(g, pt) && !g.cur.borrow[k] {
|
||||
|
|
@ -2714,6 +2772,14 @@ fn eachStmt(ptr[Gen] g, ast.Node s) {
|
|||
et = lt.elem[0]
|
||||
}
|
||||
copyElems := r.isPlace && owning(g, et) && mutates(g, rootVar(s.kids[0]), s.kids[1])
|
||||
big := bigCopy(g, et)
|
||||
if big > 0 && s.text.len == 0 {
|
||||
list := "list"
|
||||
if s.kids[0].kind == "var" {
|
||||
list = s.kids[0].name
|
||||
}
|
||||
warn(g, s, "each " + ast.show(et) + " (" + str(big) + " bytes) is copied into '" + s.name + "'; for i in 0.." + list + ".len with " + list + "[i] works on it in place")
|
||||
}
|
||||
iv := alloca(g, "i64")
|
||||
store(g, "i64", "0", iv)
|
||||
cond := newLabel(g, "each.cond")
|
||||
|
|
|
|||
24
src/lsp.fch
24
src/lsp.fch
|
|
@ -83,6 +83,7 @@ struct Analysis {
|
|||
[]str imports
|
||||
[]str importKeys // the module each import is: btn -> ui/button
|
||||
Diag diag
|
||||
[]Diag warnings // shown in yellow; the program still builds
|
||||
}
|
||||
|
||||
struct Server {
|
||||
|
|
@ -324,6 +325,8 @@ fn parseOutput(str output) -> Analysis {
|
|||
a.structs[k].types.push(f[4])
|
||||
} else if tag == "@E" && f.len >= 7 {
|
||||
a.enums.push(EnumRec(module: f[1], name: f[2], file: f[3], line: intOf(f[4]), col: intOf(f[5]), variants: f[6].split(",")))
|
||||
} else if tag == "@W" && f.len >= 5 {
|
||||
a.warnings.push(Diag(has: true, file: f[1], line: intOf(f[2]), col: intOf(f[3]), message: f[4]))
|
||||
} else if tag == "@I" && f.len >= 2 {
|
||||
a.imports.push(f[1])
|
||||
if f.len >= 3 {
|
||||
|
|
@ -399,6 +402,27 @@ fn Server.publish(str path, Analysis a) {
|
|||
list.push(d)
|
||||
now.push(f)
|
||||
}
|
||||
for w in a.warnings {
|
||||
if w.file == f {
|
||||
d := json.new_object()
|
||||
wl := w.line - 1
|
||||
if wl < 0 {
|
||||
wl = 0
|
||||
}
|
||||
wc := w.col - 1
|
||||
if wc < 0 {
|
||||
wc = 0
|
||||
}
|
||||
d.set("range", range(wl, wc, wc + 1))
|
||||
d.set("severity", num(2))
|
||||
d.set("source", json.new_text("finch"))
|
||||
d.set("message", json.new_text(w.message))
|
||||
list.push(d)
|
||||
if !now.contains(f) {
|
||||
now.push(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
p := json.new_object()
|
||||
p.set("uri", json.new_text(pathToUri(f)))
|
||||
p.set("diagnostics", list)
|
||||
|
|
|
|||
|
|
@ -34,7 +34,8 @@ for f in run/*.fch new/*.fch; do
|
|||
failed=$((failed + 1)); echo "FAIL (build) $f"; head -5 "$tmp/err"; continue
|
||||
fi
|
||||
got=$(run_exe "$exe" "$input")
|
||||
if [ "$got" == "$(tr -d '\r' < "${f%.fch}.out")" ]; then
|
||||
# (warnings come from the build, which is not part of what the program prints)
|
||||
if [ "$got" == "$(tr -d '\r' < "${f%.fch}.out" | grep -v ': warning: ')" ]; then
|
||||
pass=$((pass + 1))
|
||||
else
|
||||
failed=$((failed + 1)); echo "FAIL $f"; diff <(echo "$got") "${f%.fch}.out" | head -10
|
||||
|
|
|
|||
|
|
@ -193,6 +193,15 @@ c.notify("textDocument/didChange", {"textDocument": {"uri": uri2, "version": 4},
|
|||
diags = c.diagnostics(uri2)
|
||||
check("error: unhandled failure", diags and "can fail" in diags[0]["message"], diags)
|
||||
|
||||
# a big struct copied on every call: a warning (yellow), not an error
|
||||
src4 = "struct V {\n" + "".join(" float f%d\n" % i for i in range(40)) + "}\n\nfn len2(V v) -> float {\n return v.f0\n}\n\nfn main() {\n print(len2(V()))\n}\n"
|
||||
path4 = os.path.join(d, "big.fch")
|
||||
open(path4, "w").write(src4)
|
||||
uri4 = pathlib.Path(path4).resolve().as_uri()
|
||||
c.notify("textDocument/didOpen", {"textDocument": {"uri": uri4, "languageId": "finch", "version": 1, "text": src4}})
|
||||
w4 = c.diagnostics(uri4)
|
||||
check("warning for a big copy", w4 and len(w4) == 1 and w4[0]["severity"] == 2 and "copied on every call" in w4[0]["message"] and w4[0]["range"]["start"]["line"] == 43, w4)
|
||||
|
||||
# a module imported under another name: completion after its name
|
||||
src3 = "import path as pt\n\nfn main() {\n print(pt.base(\"a/b\"))\n}\n"
|
||||
path3 = os.path.join(d, "alias.fch")
|
||||
|
|
|
|||
52
tests/new/big_copies.fch
Normal file
52
tests/new/big_copies.fch
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// a struct of 256 bytes or more copied without the code saying so: a warning (the program still builds)
|
||||
struct M4 {
|
||||
float a0
|
||||
float a1
|
||||
float a2
|
||||
float a3
|
||||
float b0
|
||||
float b1
|
||||
float b2
|
||||
float b3
|
||||
float c0
|
||||
float c1
|
||||
float c2
|
||||
float c3
|
||||
float d0
|
||||
float d1
|
||||
float d2
|
||||
float d3
|
||||
}
|
||||
|
||||
struct Body {
|
||||
M4 world
|
||||
M4 local
|
||||
int id
|
||||
}
|
||||
|
||||
fn weight(Body b) -> float { // warned: 264 bytes copied on every call
|
||||
return b.world.a0 + float(b.id)
|
||||
}
|
||||
|
||||
fn nudge(ptr[Body] b) { // shared: no warning
|
||||
b.world.a0 += 1.0
|
||||
}
|
||||
|
||||
fn small(M4 m) -> float { // 128 bytes: no warning
|
||||
return m.a0
|
||||
}
|
||||
|
||||
fn main() {
|
||||
b := Body(id: 2)
|
||||
nudge(b)
|
||||
print(weight(b), small(b.world))
|
||||
bodies := [b, b]
|
||||
total := 0.0
|
||||
for x in bodies { // warned: each element copied into x
|
||||
total += x.world.a0
|
||||
}
|
||||
for i in 0..bodies.len { // in place: no warning
|
||||
total += bodies[i].world.a0
|
||||
}
|
||||
print(total)
|
||||
}
|
||||
4
tests/new/big_copies.out
Normal file
4
tests/new/big_copies.out
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
new/big_copies.fch:27:11: warning: 'b' is a Body (264 bytes), copied on every call to weight; take ptr[Body] to share it instead (callers can still pass the variable as it is)
|
||||
new/big_copies.fch:45:5: warning: each Body (264 bytes) is copied into 'x'; for i in 0..bodies.len with bodies[i] works on it in place
|
||||
3 1
|
||||
4
|
||||
Loading…
Reference in a new issue