Errors
What each error means and how to fix it. Every example here was given to the compiler, which rejected it with the code shown and accepted the fix.
Reading an error
K2-OWN-001: value was moved or is not initialized at game.kon:4:11
K2-RELATED: related ownership location at game.kon:3:17
The code comes first, then what went wrong, then the file, line and column. K2-RELATED names the other place involved, here the line that gave the value away.
Ownership
K2-OWN-001 Used after it was handed over
A value has one owner. After take, the old name no longer holds it.
func main(): i32 {
var a: List<u8> = list[]
let b = take a
print(a.length)
return 0
}Use the new name:
func main(): i32 {
var a: List<u8> = list[]
let b = take a
print(b.length)
return 0
}
K2-OWN-002 Handing over without saying so
Passing a named value to a parameter that keeps it moves the value, so the call has to show that.
func keep(a: List<u8>) {
}
func main(): i32 {
var a: List<u8> = list[]
keep(a)
return 0
}Say take, or have the function take view if it only reads:
func keep(a: List<u8>) {
}
func main(): i32 {
var a: List<u8> = list[]
keep(take a)
return 0
}
K2-OWN-004 Might already be gone here
On some way through the code the value may be gone by this point. A defer still needs what it uses, so returning that value first is one way to get here.
func make(): String {
let t = String("x")
defer {
print(t)
}
return t
}
func main(): i32 {
let r = make()
return 0
}Return a copy, or stop using it in the defer:
func make(): String {
var t = String("x")
return take t
}
func main(): i32 {
let r = make()
print(r)
return 0
}
K2-BORROW-001 Changing what something else is using
While a value is lent out for edit, nothing else may read it, including another argument of the same call.
func grow(a: edit List<u8>, size: u64) {
}
func main(): i32 {
var a: List<u8> = list[]
grow(edit a, a.length)
return 0
}Read it into a name first:
func grow(a: edit List<u8>, size: u64) {
}
func main(): i32 {
var a: List<u8> = list[]
let size = a.length
grow(edit a, size)
return 0
}
K2-BORROW-002 Changing something that cannot change
An edit loan needs a value declared with var.
func fill(a: edit List<u8>) {
}
func main(): i32 {
let a: List<u8> = list[]
fill(edit a)
return 0
}Declare it with var:
func fill(a: edit List<u8>) {
}
func main(): i32 {
var a: List<u8> = list[]
fill(edit a)
return 0
}
K2-BORROW-003 Returning a borrow without saying from where
A function that returns a view has to name the parameter it comes from, so callers know how long it lasts.
func same(a: view List<u8>): view List<u8> {
return view a
}
func main(): i32 {
let a: List<u8> = list[]
let b = same(a)
return 0
}Add from with the parameter:
func same(a: view List<u8>): view List<u8> from a {
return view a
}
func main(): i32 {
let a: List<u8> = list[]
let b = same(a)
print(b.length)
return 0
}
K2-BORROW-004 A borrow outlives its owner
The owner would be freed while something still points at it, which is what this rule exists to stop.
func make(): view String {
let t = String("x")
return view t
}
func main(): i32 {
let b = make()
return 0
}Return the value itself:
func make(): String {
var t = String("x")
return take t
}
func main(): i32 {
let b = make()
print(b)
return 0
}
K2-CALL-001 The argument does not match the parameter
The parameter says edit but the call does not, or a temporary was passed where a named value is needed.
func fill(a: edit List<u8>) {
}
func main(): i32 {
var a: List<u8> = list[]
fill(a)
return 0
}Write edit at the call, and bind a temporary to a name first:
func fill(a: edit List<u8>) {
}
func main(): i32 {
var a: List<u8> = list[]
fill(edit a)
return 0
}
K2-DEFER-001 Leaving from inside a defer
A defer runs while the block is already ending, so it cannot return or move control elsewhere.
func main(): i32 {
defer {
return 0
}
return 0
}Keep cleanup only in the defer:
func main(): i32 {
defer {
print("done")
}
return 0
}
K2-GUARD-001 A guard that changes something
A when guard is only a question, so it must not change anything.
func bump(a: edit i32): bool {
a += 1
return true
}
func main(): i32 {
var count: i32 = 0
let found = some(1)
match found {
some(v) when bump(edit count) => { print(v) }
_ => { }
}
return 0
}Make the change inside the arm:
func main(): i32 {
var count: i32 = 0
let found = some(1)
match found {
some(v) when v > 0 => { count += 1 }
_ => { }
}
print(count)
return 0
}
K2-GUARD-003 A guard that allocates
A guard must not allocate memory either.
func main(): i32 {
let found = some(1)
match found {
some(v) when String("a").byteLength > 0 => { print(v) }
_ => { }
}
return 0
}Work the answer out before the match:
func main(): i32 {
let found = some(1)
let name = String("a")
let named = name.byteLength > 0
match found {
some(v) when named => { print(v) }
_ => { }
}
return 0
}
Syntax, names and types
These give a code and one word, with the exact line.
K2-SYN-003 The code cannot be read here
Common causes are a semicolon, two statements on one line, or old fn syntax. Literal braces in text are written {{ and }}.
func main(): i32 {
let a = 1; let b = 2
return 0
}One statement per line:
func main(): i32 {
let a: i32 = 1
let b: i32 = 2
print(a + b)
return 0
}
K2-TYPE-002 The types do not match
Numbers never convert by themselves. An expression starting with a plain number may need a type too: write x + 1 rather than 1 + x. This code is also used, with the word name, for a name that does not exist, is not pub in the imported file, or is .length on text, where .byteLength is what you want.
func main(): i32 {
let a: i32 = 1
let b: u8 = a
return 0
}Convert with as:
func main(): i32 {
let a: i32 = 1
let b = a as u8
print(b)
return 0
}
K2-TYPE-001 The type cannot be worked out
An empty list could hold anything, so say what.
func main(): i32 {
let a = list[]
return 0
}Write the type:
func main(): i32 {
let a: List<u8> = list[]
print(a.length)
return 0
}
K2-MATCH-001 A case is missing from match
A match has to cover every case.
enum Light {
Red
Green
}
func main(): i32 {
let light = Light.Red
match light {
Light.Red => { print(1) }
}
return 0
}Add the rest, or _ for all of them:
enum Light {
Red
Green
}
func main(): i32 {
let light = Light.Red
match light {
Light.Red => { print(1) }
Light.Green => { print(2) }
}
return 0
}
K2-UNSAFE-001 A foreign call outside unsafe
The compiler cannot check C code, so calling it has to be marked.
extern "C" func abs(value: i32): i32
func main(): i32 {
print(abs(-1))
return 0
}Put it in unsafe:
extern "C" func abs(value: i32): i32
func main(): i32 {
var result: i32 = 0
unsafe {
result = abs(-1)
}
print(result)
return 0
}
K2-IFACE-001 A type does not do what its interface asks
A type marked implements needs every method of that interface.
interface Named {
func label(view self): i32
}
struct Cat implements Named {
lives: i32
}
func main(): i32 {
return 0
}Add the method:
interface Named {
func label(view self): i32
}
struct Cat implements Named {
lives: i32
func label(view self): i32 {
return self.lives
}
}
func main(): i32 {
return 0
}
K2-CONST-001 A constant that cannot be worked out
A constant has to be computable when compiling, so constants cannot depend on each other in a circle.
const A: i32 = B
const B: i32 = A
func main(): i32 {
return 0
}Give it a starting value:
const A: i32 = 1
const B: i32 = A
func main(): i32 {
print(B)
return 0
}
K2-ALIAS-002 A type name used twice
Each type name means one thing. K2-ALIAS-001 is the same family, for an alias that refers to itself.
type Count = i32
type Count = u32
func main(): i32 {
return 0
}Use two names:
type Count = i32
type Total = u32
func main(): i32 {
return 0
}
K2-FFI-001 A type C cannot take
Only simple values cross to C so far, not owned values such as String.
extern "C" func show(value: String)
func main(): i32 {
return 0
}Send simple values:
extern "C" func abs(value: i32): i32
func main(): i32 {
return 0
}
K2-FRONTEND-001 Not supported by the compiler yet
Valid in the specification, but the compiler cannot do it yet. The status page lists what is missing.
func main(): i32 {
let n: i32 = 2
print("n = {n}")
return 0
}Write it another way:
func main(): i32 {
let n: i32 = 2
print("n =")
print(n)
return 0
}
While running
These stop the program instead of letting it continue with bad data. An index past the end and division by zero stop it with no message for now; the exit code shows a crash.
| You see | Means |
|---|---|
K2-BOUNDS | A text slice outside the text. |
K2-UTF8 | A text slice that would cut a character in two. |
While building
| You see | Means |
|---|---|
K2-LINK | Linking failed. If you import a file with C functions by a plain path, it needs --link; std/ imports do not. |
K2-OUTPUT | The output file would overwrite the source or the compiler, or the build folder could not be made. |
K2-CODEGEN, K2-OPTIMIZE | The code passed its checks, but generating or optimizing it failed. This points at the compiler, not at your code. |