Skip to content

bug - Rust interop over-borrows generic by-value decode arguments #609

@dannymeijer

Description

@dannymeijer

Area

  • Compiler (frontend/backend/codegen)

Summary

Expected: when an external Rust associated function takes a generic by-value parameter such as prost::Message::decode(buf: impl Buf), Incan should emit a valid by-value argument shape, or a valid mutable borrow if the selected Rust API requires &mut T.

Actual: Incan accepts the source, but generated Rust adds a shared borrow to the decode argument. For Cursor<Vec<u8>>, this emits FileDescriptorSet::decode(&cursor), which fails because &Cursor<Vec<u8>> does not implement bytes::Buf. The same shape surfaced in InQL as ConsumerPlan::decode(&encoded.as_slice()), producing &&[u8].

This appears to come from the external-method fallback that treats methods named decode as requiring a shared borrow when Rust metadata resolves the parameter as a generic shape. That heuristic is wrong for prost::Message::decode(buf: impl Buf).

Reproduction steps

Minimal project:

incan.toml

[project]
name = "prost_decode_repro"
version = "0.1.0"

[rust-dependencies]
prost = "0.14"
prost-types = "0.14"

src/lib.incn

from rust::prost import DecodeError, Message
from rust::prost_types import FileDescriptorSet
from rust::std::io import Cursor


pub def decode_descriptor(data: bytes) -> Result[FileDescriptorSet, DecodeError]:
    mut cursor = Cursor.new(data)
    return FileDescriptorSet.decode(cursor)

Run:

incan build --lib src/lib.incn target/lib

Generated Rust excerpt:

pub fn decode_descriptor(data: Vec<u8>) -> Result<FileDescriptorSet, DecodeError> {
    let mut cursor = Cursor::new(data);
    return FileDescriptorSet::decode(&cursor);
}

Output / logs

error[E0277]: the trait bound `&std::io::Cursor<Vec<u8>>: Buf` is not satisfied
   --> src/lib.rs:12:38
    |
 12 |     return FileDescriptorSet::decode(&cursor);
    |            ------------------------- ^^^^^^^ the trait `Buf` is not implemented for `&std::io::Cursor<Vec<u8>>`
    |            |
    |            required by a bound introduced by this call
    |
    = help: the following other types implement trait `Buf`:
              &[u8]
              &mut T
              Box<T>
              BytesMut
              VecDeque<u8>
              prost::bytes::Bytes
              prost::bytes::buf::Chain<T, U>
              prost::bytes::buf::Take<T>
note: required by a bound in `decode`
   --> prost-0.14.3/src/message.rs:105:29
    |
105 |     fn decode(mut buf: impl Buf) -> Result<Self, DecodeError>
    |                             ^^^ required by this bound in `Message::decode`

InQL surfaced the same bug while compiling src/session/datafusion_backend.incn:

error[E0277]: the trait bound `&&[u8]: Buf` is not satisfied
   --> src/session/datafusion_backend.rs:461:32
    |
461 |     match ConsumerPlan::decode(&encoded.as_slice()) {
    |           -------------------- ^^^^^^^^^^^^^^^^^^^ the trait `Buf` is not implemented for `&&[u8]`

Environment

OS: macOS / Darwin, local development workspace
Rust: rustc 1.96.0-nightly (362211dc2 2026-03-24)
Incan: 0.3.0-dev.50, commit 8a9860d5
Command: incan build --lib src/lib.incn target/lib

Blocking status: blocks the InQL #25 v0.3 showcase transition unless InQL carries a temporary Rust helper around protobuf decode. I have not applied such a workaround yet.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingincan compilerSuggestions, features, or bugs related to the Compiler (frontend/backend/codegen)

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions