Skip to content

cgen/checker: module-qualified static method as map callback misresolved as enum value #27328

@medvednikov

Description

@medvednikov

Description

Passing a module-qualified static method (mod.Type.method) as a first-class function value (e.g. as a map/filter callback) is misresolved by the compiler. The same expression works correctly when the type is declared in the same module, but across module boundaries it is misinterpreted as an enum value.

This was originally observed in the wild as a C-compilation failure (the static method name was emitted as a bare, undefined C identifier). On current master it surfaces one step earlier as a checker error that wrongly claims the struct is an enum.

Reproduction

mtime/mtime.v:

module mtime

pub struct MTime {
pub:
	unix i64
}

pub fn MTime.from(n int) MTime {
	return MTime{unix: n}
}

main.v:

module main

import mtime

fn main() {
	nums := [1, 2, 3]
	ms := nums.map(mtime.MTime.from)
	println(ms.len)
}
v run .

Actual

main.v:7:23: error: unknown enum `mtime.MTime` (type_idx=0)
    6 |     nums := [1, 2, 3]
    7 |     ms := nums.map(mtime.MTime.from)
      |                          ~~~~~~~~~~

mtime.MTime is a struct with a static method from, not an enum. The compiler parses mtime.MTime.from as EnumVal{enum: mtime.MTime, variant: from}.

The explicit-call form fails the same way:

ms := nums.map(mtime.MTime.from(it))
// error: unknown function: mtime.MTime__static__from
//        type mismatch, `mtime.MTime__static__from` does not return anything

Expected

Cross-module behaves like same-module. The following same-module program compiles and runs correctly (prints 6):

struct Foo { x int }

fn Foo.from(n int) Foo { return Foo{x: n} }

fn main() {
	nums := [1, 2, 3]
	a := nums.map(Foo.from(it)) // call form: works
	b := nums.map(Foo.from)     // value form: works
	println(a.len + b.len)
}

So the static-method-as-callback feature itself works — it only breaks when the type is reached through a module qualifier.

Originally observed C output (from a real bug report)

A .map() over []time.Time producing []common.mtime.MTime emitted the static factory as a bare identifier instead of a call, which then failed at the C compiler:

common__mtime__MTime _t25 = common__mtime__MTime__static__from;   // undefined: should be ..._from(it)
builtin__array_push_noscan((array*)&_t24, &_t25);
error: 'common__mtime__MTime__static__from' undeclared (first use in this function)

Environment

  • V 0.5.1
  • Reproduced on macOS; original report on Linux (cc)

Note

You can use the 👍 reaction to increase the issue's priority for developers.

Please note that only the 👍 reaction to the issue itself counts as a vote.
Other reactions and those to comments will not be taken into account.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugs.vlang.ioReported via the bugs.vlang.io crash reporter

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions