vlang / v

Simple, fast, safe, compiled language for developing maintainable software. Compiles itself in <1s with zero library dependencies. Supports automatic C => V translation. https://vlang.io
MIT License
35.76k stars 2.16k forks source link

A mysterious "too few arguments to function builder error" #12661

Closed aalekhpatel07 closed 2 years ago

aalekhpatel07 commented 2 years ago

V doctor:

OS: linux, Linux version 5.14.18-300.fc35.x86_64 (mockbuild@bkernel01.iad2.fedoraproject.org) (gcc (GCC) 11.2.1 20210728 (Red Hat 11.2.1-1), GNU ld version 2.37-10.fc35) #1 SMP Fri Nov 12 16:43:17 UTC 2021
Processor: 24 cpus, 64bit, little endian, AMD Ryzen 9 3900X 12-Core Processor
CC version: cc (GCC) 11.2.1 20210728 (Red Hat 11.2.1-1)

getwd: /home/infinity/dev/advent-of-code-2021
vmodules: /home/infinity/.vmodules
vroot: /home/infinity/dev/vlang
vexe: /home/infinity/dev/vlang/v
vexe mtime: 2021-11-23 14:07:38
is vroot writable: true
is vmodules writable: true
V full version: V 0.2.4 12ffe04

Git version: git version 2.33.1
Git vroot status: Error: fatal: not a git repository (or any parent up to mount point /)
Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).
.git/config present: false
thirdparty/tcc status: thirdparty-linux-amd64 333c14de

What did you do? v -g -o vdbg cmd/v && vdbg ./src/03.v

import os

struct BitFrequency {
mut:
    zeroes i64
    ones   i64
}

fn parse_input_first(lines []string) ?[]BitFrequency {
    number_of_bins := lines[0].len
    mut bitfreqs := []BitFrequency{len: number_of_bins, cap: number_of_bins, init: BitFrequency{0, 0}}

    for w_idx, w in lines {
        for idx, elem in w {
            if elem == 48 {
                bitfreqs[idx].zeroes += 1
            } else if elem == 49 {
                bitfreqs[idx].ones += 1
            } else {
                panic('Whoops')
            }
        }
    }

    return bitfreqs
}

struct Tournament {
    words []string
}

fn battle(t Tournament, idx int) Tournament {
    if t.words.len == 1 {
        return t
    }

    zeroes := t.words.filter(fn [idx] (w string) bool {
        return w[idx] == 48
    })

    ones := t.words.filter(fn [idx] (w string) bool {
        return w[idx] == 49
    })

    if ones.len >= zeroes.len {
        return Tournament{ones}
    }
    return Tournament{zeroes}
}

fn play(t Tournament, idx int) string {
    if t.words.len == 1 {
        return t.words[0]
    } else {
        return play(battle(t, idx + 1), idx + 1)
    }
}

fn part_1(arr []BitFrequency) i64 {
    mut gamma_rate := i64(0)
    mut epsilon := i64(0)

    mut pow := 1
    for item in arr.reverse() {
        if item.ones > item.zeroes {
            gamma_rate += pow
        } else if item.zeroes > item.ones {
            epsilon += pow
        }
        pow *= 2
    }

    return gamma_rate * epsilon
}

fn part_2(t Tournament) int {
    mut oxygen_generator_rating := int(0)
    mut co2_scrubber_rating := int(0)

    mut winner := battle(t, 0)
    println(winner)

    return 0
}

fn main() {
    lines := os.get_lines()
    bitfreqs := parse_input_first(lines) ?

    ans_1 := part_1(bitfreqs)

    tournament := Tournament{lines}
    ans_2 := part_2(tournament)

    println('part_1: $ans_1 \npart_2: $ans_2')
}

What did you expect to see?

Anything but a mysterious "too few arguments to function builder error".

What did you see instead?

./src/03.v:13:6: warning: unused variable: `w_idx`
   11 |     mut bitfreqs := []BitFrequency{len: number_of_bins, cap: number_of_bins, init: BitFrequency{0, 0}}
   12 | 
   13 |     for w_idx, w in lines {
      |         ~~~~~
   14 |         for idx, elem in w {
   15 |             if elem == 48 {
./src/03.v:77:6: warning: unused variable: `oxygen_generator_rating`
   75 | 
   76 | fn part_2(t Tournament) int {
   77 |     mut oxygen_generator_rating := int(0)
      |         ~~~~~~~~~~~~~~~~~~~~~~~
   78 |     mut co2_scrubber_rating := int(0)
   79 |
./src/03.v:78:6: warning: unused variable: `co2_scrubber_rating`
   76 | fn part_2(t Tournament) int {
   77 |     mut oxygen_generator_rating := int(0)
   78 |     mut co2_scrubber_rating := int(0)
      |         ~~~~~~~~~~~~~~~~~~~
   79 | 
   80 |     mut winner := battle(t, 0)
==================
/tmp/v_1000/03.12531713133877352878.tmp.c:15108: error: too few arguments to function
...
==================
(Use `v -cg` to print the entire error message)

builder error: 
==================
C error. This should never happen.

This is a compiler bug, please report it using `v bug file.v`.

https://github.com/vlang/v/issues/new/choose

You can also use #help on Discord: https://discord.gg/vlang
mvenditto commented 2 years ago

seem like a problem with closures used in that context. assigning the anon fn to a variable first, than passing that to filter seems to workaround the problem for some reason

fn battle(t Tournament, idx int) Tournament {
        if t.words.len == 1 {
                return t
        }

        f1 := fn [idx] (w string) bool {
                return w[idx] == 48
        }

        zeroes := t.words.filter(f1)

        f2 := fn [idx] (w string) bool {
                return w[idx] == 49
        }

        ones := t.words.filter(f2)

        if ones.len >= zeroes.len {
                return Tournament{ones}
        }
        return Tournament{zeroes}
}
aalekhpatel07 commented 2 years ago

It might be a valid workaround but I think I'd be interested to learn a reason for why binding closures to variables before passing them is okay but passing raw closures are not.

medvednikov commented 2 years ago

Fixed.