Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Cannot bind to trait with missing parameters for unbound types to check trait conformance #3290

Closed
martinvuyk opened this issue Jul 23, 2024 · 5 comments
Labels
bug Something isn't working mojo-repo Tag all issues with this label

Comments

@martinvuyk
Copy link
Contributor

Bug description

main problem is this part:

    @staticmethod
    fn getservbyname(
        name: String, proto: SockProtocol = SockProtocol.TCP
    ) -> Optional[SockAddr[sock_family, *_]]:
        ...

error output:

parametric type 'SockAddr[sock_family, ?, ?, ?, ?, ?, ?, ?, ?]' cannot bind to trait with missing parametersmojo
'Optional' parameter #0 has 'CollectionElement' type, but value has type 'AnyStruct[SockAddr[sock_family, ?, ?, ?, ?, ?, ?, ?, ?]]'

Repro:

struct SockPlatform:
    alias LINUX = "LINUX"
    """LINUX."""
    ...
    var _selected: StringLiteral

    fn __init__(inout self, selected: StringLiteral):
        """Construct an instance.

        Args:
            selected: The selected value.
        """
        self._selected = selected


struct SockType:
    """Socket Type."""

    alias SOCK_STREAM = "SOCK_STREAM"
    """SOCK_STREAM."""
    ...
    var _selected: StringLiteral

    fn __init__(inout self, selected: StringLiteral):
        """Construct an instance.

        Args:
            selected: The selected value.
        """
        self._selected = selected


struct SockProtocol:
    """Socket Transmission Protocol."""

    alias TCP = "TCP"
    """Transmission Control Protocol."""
    ...
    var _selected: StringLiteral

    fn __init__(inout self, selected: StringLiteral):
        """Construct an instance.

        Args:
            selected: The selected value.
        """
        self._selected = selected


struct SockFamily:
    """Socket Address Family."""

    alias AF_INET = "AF_INET"
    """AF_INET."""
    ...
    var _selected: StringLiteral

    fn __init__(inout self, selected: StringLiteral):
        """Construct an instance.

        Args:
            selected: The selected value.
        """
        self._selected = selected
    ...

@value
struct SockAddr[
    sock_family: SockFamily,
    T0: CollectionElement,
    T1: CollectionElement,
    T2: CollectionElement = NoneType,
    T3: CollectionElement = NoneType,
    T4: CollectionElement = NoneType,
    T5: CollectionElement = NoneType,
    T6: CollectionElement = NoneType,
    T7: CollectionElement = NoneType,
](CollectionElement):
    ...


@value
struct Socket[
    sock_family: SockFamily = SockFamily.AF_INET,
    sock_type: SockType = SockType.SOCK_STREAM,
    sock_protocol: SockProtocol = SockProtocol.TCP,
    sock_platform: SockPlatform = SockPlatform.LINUX,
](CollectionElement):
    """Struct for using Sockets. In the future this struct should be able to
    use any implementation that conforms to the SocketInterface trait, once
    traits can have attributes and have parameters defined. This will allow the
    user to implement the interface for whatever functionality is missing and
    inject the type.

    Parameters:
        sock_family: The socket family e.g. `SockFamily.AF_INET`.
        sock_type: The socket type e.g. `SockType.SOCK_STREAM`.
        sock_protocol: The socket protocol e.g. `SockProtocol.TCP`.
        sock_platform: The socket platform e.g. `SockPlatform.LINUX`.
    """

    ...

    @staticmethod
    fn getservbyname(
        name: String, proto: SockProtocol = SockProtocol.TCP
    ) -> Optional[SockAddr[sock_family, *_]]:
        ...

Steps to reproduce

  • Include relevant code snippet or link to code that did not work as expected.
  • If applicable, add screenshots to help explain the problem.
  • If using the Playground, name the pre-existing notebook that failed and the steps that led to failure.
  • Include anything else that might help us debug the issue.

System information

- What OS did you do install Mojo on ?
- Provide version information for Mojo by pasting the output of `mojo -v`

`mojo 2024.7.2205`

- Provide Modular CLI version by pasting the output of `modular -v`
@martinvuyk martinvuyk added bug Something isn't working mojo-repo Tag all issues with this label labels Jul 23, 2024
@soraros
Copy link
Contributor

soraros commented Jul 23, 2024

I don't think it's related to trait bound check: it won't compile even if you remove the Optional. I think it's really that explicit unbinding syntax doesn't work in return type.

Smaller repro.

@value
struct S[T: CollectionElement]:
    ...

fn g() -> S:
    ...

I'm not sure it should work though. The compiler can't infer the return type, and I think you what want was existential which we currently don't support.

@martinvuyk
Copy link
Contributor Author

martinvuyk commented Jul 23, 2024

This works though which to me expresses the same thing but it's horribly verbose

    @staticmethod
    fn getservbyname[
        T0: CollectionElement,
        T1: CollectionElement,
        T2: CollectionElement,
        T3: CollectionElement,
        T4: CollectionElement,
        T5: CollectionElement,
        T6: CollectionElement,
        T7: CollectionElement, //,
    ](name: String, proto: SockProtocol = SockProtocol.TCP) -> Optional[
        SockAddr[sock_family, T0, T1, T2, T3, T4, T5, T6, T7]
    ]:
        ...

@suahelen
Copy link

I think the error is that T1 and T2 do not have a default and you do not specify them explicitly in the function declaration. If you give it a default it compiles for me.

@value
struct S[sock_family: Int](CollectionElement):
    fn __init__(inout self):
        pass

    fn __moveinit__(inout self, owned other: Self) -> None:
        pass

    fn __copyinit__(inout self, other: Self) -> None:
        pass

    @staticmethod
    fn g(inout self) -> Optional[SockAddr[Self.sock_family]]:
        return Optional[SockAddr[Self.sock_family]](None)


@value
struct SockAddr[
    sock_family: Int,
    T0: CollectionElement = Nonetype, # does not compile if one of them does not have a default
    T1: CollectionElement = NoneType,
](CollectionElement):
    fn __init__(inout self):
        pass

    fn __moveinit__(inout self, owned other: Self) -> None:
        pass

    fn __copyinit__(inout self, other: Self) -> None:
        pass


fn main():
    var s = S[1]()
    pass

@suahelen
Copy link

According to the error message I assume that a check is done on the acutal object passed at compile time. And if nothing is supplied it cannot be evaluated properly.

Also according to the error message. I assume that actually none T0-T9 had a default type when you got the error message ;)
Because i you will get a '?' for every argument where the type cannot be evaluated.
Like so :
error: parametric type 'SockAddr[sock_family, ?, NoneType]' cannot bind to trait with missing parameters

@martinvuyk
Copy link
Contributor Author

Hi, thank you for the example it made me realize what the underlying problem is.

My logic itself is wrong

@staticmethod
fn g0[
    T0: CollectionElement,
    T1: CollectionElement, //,
](address: SockAddr[sock_family, T0, T1]) -> Optional[String]:
    ...

@staticmethod
fn g1[
    T0: CollectionElement,
    T1: CollectionElement, //,
](address: SockAddr[sock_family, T0, T1]) -> Optional[
    SockAddr[sock_family, T0, T1]
]:
    ...

@staticmethod
fn g2(address: SockAddr[sock_family, *_]) -> Optional[String]:
    ...

@staticmethod
fn g3(
    address: SockAddr[sock_family, *_]
) -> Optional[SockAddr[sock_family, *_]]:
    ...

@staticmethod
fn g4(address: SockAddr[sock_family, *_]) -> Optional[__type_of(address)]:
    ...

g0, g1, g2, and g4 work fine. The problem is that g3 has no way of inferring the types that will be going out by what is coming in, since it could be pretty much any type combination imaginable.

I think it's really that explicit unbinding syntax doesn't work in return type.
...
The compiler can't infer the return type

so @soraros you were right here 👍 , it has to either be bound to an incoming value of the same type or explicitly declared as function parameters that are not infer only (//)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working mojo-repo Tag all issues with this label
Projects
None yet
Development

No branches or pull requests

3 participants