Thread overview
Bug?
May 11, 2020
Jack Applegame
May 11, 2020
Jack Applegame
May 11, 2020
Jack Applegame
May 11, 2020
Adam D. Ruppe
May 11, 2020
Jack Applegame
May 11, 2020
Adam D. Ruppe
May 11, 2020
Simen Kjærås
May 11, 2020
Jack Applegame
May 11, 2020
Why doesn't it compile?

```
struct Range(R) {
    import std.array : empty, front, popFront;
    R range;
    bool empty() const { return range.empty; }
    auto front() const { return range.front; }
    void popFront() { range.popFront(); }
}

void main() {
    auto rng = Range!string("1234");
    assert(rng.front == 1);
}
```

onlineapp.d(11): Error: void has no value
onlineapp.d(11): Error: incompatible types for (rng.front) == (1): void and int

try here: https://run.dlang.io/is/Dg8Fpr

If you move the import to the global scope, you will get a weird result:

```
import std.stdio;
import std.array : empty, front, popFront;

struct Range(R) {
    R range;
    bool empty() const { return range.empty; }
    auto front() const { return range.front; }
    void popFront() { range.popFront(); }
}

void main() {
    auto rng = Range!string("1234");
    writefln("front: %s", rng.front);
    assert(rng.front == 1);
}
```

front: 1
core.exception.AssertError@onlineapp.d(14): Assertion failure
----------------
??:? _d_assertp [0x56107489bc75]
onlineapp.d:14 _Dmain [0x561074889902]

try here: https://run.dlang.io/is/arieKR

WAT???

May 11, 2020
On Monday, 11 May 2020 at 12:20:06 UTC, Jack Applegame wrote:
>     assert(rng.front == 1);

Damn! I made a typo. It must be:

assert(rng.front == '1')

So the second example works fine.
May 11, 2020
And the first example still doesn't compile:

```
struct Range(R) {
	import std.array : empty, front, popFront;
    R range;
    bool empty() const { return range.empty; }
    auto front() const { return range.front; }
    void popFront() { range.popFront(); }
}

void main() {
    auto rng = Range!string("1234");
    assert(rng.front == '1');
}
```

onlineapp.d(11): Error: void has no value
onlineapp.d(11): Error: incompatible types for (rng.front) == ('1'): void and char
```
May 11, 2020
On Monday, 11 May 2020 at 12:20:06 UTC, Jack Applegame wrote:
> If you move the import to the global scope

UFCS is only defined to work with global scope functions. A restricted import (module : symbol, symbols) puts things in local scope so ufcs doesn't apply.

(interestingly an unrestricted import does NOT do that, it keeps the functions in their original scope, so UFCS works if you locally `import std.range;` but not if you `import std.range : front, popFront, empty;`! lol. but this is... im pretty sure by design, it has been this way for ages.)
May 11, 2020
On Monday, 11 May 2020 at 12:30:22 UTC, Adam D. Ruppe wrote:
> UFCS is only defined to work with global scope functions. A restricted import (module : symbol, symbols) puts things in local scope so ufcs doesn't apply.

But in this case the error should be displayed for lines 4 and 5, not 11.
Line 11 contains a call to a member function, not UFCS.

In addition, if you add the parentheses, then it works:
assert(rng.front() == '1');


May 11, 2020
On 5/11/20 8:44 AM, Jack Applegame wrote:
> On Monday, 11 May 2020 at 12:30:22 UTC, Adam D. Ruppe wrote:
>> UFCS is only defined to work with global scope functions. A restricted import (module : symbol, symbols) puts things in local scope so ufcs doesn't apply.
> 
> But in this case the error should be displayed for lines 4 and 5, not 11.
> Line 11 contains a call to a member function, not UFCS.
> 
> In addition, if you add the parentheses, then it works:
> assert(rng.front() == '1');
> 
> 

Yeah, this is definitely a bug. If I change the return type of front to dchar from auto, it still thinks it's returning void.

Calling things like popFront without parentheses has an error "rng.popFront has no effect".

Clearly something isn't connecting properly, it's almost like it's resolving to the function itself instead of calling it.

-Steve
May 11, 2020
On Monday, 11 May 2020 at 12:44:45 UTC, Jack Applegame wrote:
> On Monday, 11 May 2020 at 12:30:22 UTC, Adam D. Ruppe wrote:
>> UFCS is only defined to work with global scope functions. A restricted import (module : symbol, symbols) puts things in local scope so ufcs doesn't apply.
>
> But in this case the error should be displayed for lines 4 and 5, not 11.
> Line 11 contains a call to a member function, not UFCS.
>
> In addition, if you add the parentheses, then it works:
> assert(rng.front() == '1');

You're right, and it absolutely seems the call on lines 4 and 5 work correctly. Instead, the compiler is confused by the presence of two different overloads for front in Range!T, and doesn't attempt to call the one it can call. We get the exact same behavior here:

struct S {
    int gun()(int i) { return 0; }
    alias fun = gun;
    int fun() { return 1; }
}

static assert(S().fun == 1);

Filed here: https://issues.dlang.org/show_bug.cgi?id=20821

--
  Simen
May 11, 2020
On Monday, 11 May 2020 at 13:12:37 UTC, Simen Kjærås wrote:
> Filed here: https://issues.dlang.org/show_bug.cgi?id=20821

Thanks.
May 11, 2020
On Monday, 11 May 2020 at 13:06:59 UTC, Steven Schveighoffer wrote:
> Clearly something isn't connecting properly, it's almost like it's resolving to the function itself instead of calling it.

Since the imported front is also a local symbol the compiler probably thinks it is overloaded and not handling that right.....