# V3002 effect_label_not_permitted

URL: /docs/errors/V3002
Markdown: /docs/errors/V3002.md

> A closed effect row was required to be empty or smaller, but an effect label had to be in it (row unification {A | r} ~ {} failed, design §5.2).

An error from the `effect` phase. `sakura explain V3002` prints this explanation offline.

A closed effect row was required to be empty or smaller, but an effect label had to be in it
(row unification `{A | r} ~ {}` failed, design §5.2). The usual cause is passing an effectful
function where a parameter's type is a pure `fn() -> T`. Make the parameter's row a variable so
the callee carries the argument's effects through, or handle the effect before passing the
function.

Wrong:

```sakura
fn apply(f: fn() -> Int) -> Int { f() }
fn noisy() -> Int ! {Console} { apply(loud_one) }
```

Fixed:

```sakura
fn apply<e>(f: fn() -> Int ! e) -> Int ! e { f() }
```

## Wrong program [#wrong-program]

[`compiler/tests/ui/V3002_effect_label_not_permitted.sakura`](https://github.com/icantcodefyi/sakuralang/blob/master/compiler/tests/ui/V3002_effect_label_not_permitted.sakura), which the compiler's ui suite runs through `sakura check`:

```sakura
fn apply(f: fn() -> Int) -> Int { f() }

fn loud_one() -> Int ! {Console} {
  Console.print("side effect")
  1
}

fn noisy() -> Int ! {Console} { apply(loud_one) }
```

`sakura check --json` reports this record (pretty-printed; `$DIR` is the fixture's directory):

```json
{
  "schema_version": "1.0",
  "kind": "diagnostic",
  "id": "d:eecd3c1441de6f7a",
  "code": "V3002",
  "severity": "error",
  "phase": "effect",
  "message": "expected `fn() -> Int`, found `fn() -> Int ! {Console}`: effect `Console` is performed by this value but not allowed by the expected type",
  "snapshot": "sha256:$SNAPSHOT",
  "symbol_id": "main::V3002_effect_label_not_permitted::noisy",
  "spans": [
    {
      "uri": "file://$DIR/V3002_effect_label_not_permitted.sakura",
      "content_hash": "sha256:a4b6e19ab0cafb694cd04bc0664109475cfca1b6e88f0e7eafea82702d83df5f",
      "start_byte": 186,
      "end_byte": 194,
      "role": "primary",
      "label": "this has type `fn() -> Int ! {Console}`"
    }
  ],
  "related_ids": [],
  "expected": {
    "render": "fn() -> Int"
  },
  "actual": {
    "render": "fn() -> Int ! {Console}"
  },
  "obligation": null,
  "counterexample": null,
  "explanation_uri": "sakura://explain/V3002",
  "fixes": []
}
```

## Fixed program [#fixed-program]

[`compiler/tests/ui/V3002_effect_label_not_permitted.fixed.sakura`](https://github.com/icantcodefyi/sakuralang/blob/master/compiler/tests/ui/V3002_effect_label_not_permitted.fixed.sakura), which `sakura check` accepts with no diagnostics:

```sakura
fn apply<e>(f: fn() -> Int ! e) -> Int ! e { f() }

fn loud_one() -> Int ! {Console} {
  Console.print("side effect")
  1
}

fn noisy() -> Int ! {Console} { apply(loud_one) }
```
