Bug 17661 – New isInputRange rejects valid input range

Status
RESOLVED
Resolution
FIXED
Severity
regression
Priority
P1
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2017-07-17T22:04:47Z
Last change time
2018-01-05T13:31:09Z
Keywords
pull
Assigned to
No Owner
Creator
hsteoh

Comments

Comment #0 by hsteoh — 2017-07-17T22:04:47Z
Code (compile with -dip25 -dip1000): -------- import std.range.primitives; struct C { private S* impl; } struct S { bool empty; @property C front() return { return C(&this); } void popFront() { } static assert(isInputRange!S); // FAILS } -------- Prior to git commit 82c3371d85154b7f98b1c9187b79805a50fc59dd, the assert passes. However, the new isInputRange checks introduced by this commit causes the above breakage. The problem is the new clause `typeof((R r) => r.front` in the new isInputRange. Because S.front returns a reference to `this` it carries the `return` annotation, so the compiler does not reject `front`. However, the check in isInputRange does not have this annotation, so the compiler rejects it as escaping a reference to `this`, thus causing isInputRange to fail to recognize S as an input range.
Comment #1 by andrei — 2017-07-17T22:51:03Z
Can you try replacing the clause is(typeof((R r) => r.front)) with is(typeof((R r) => r.front)) || is(typeof((R r) return => r.front)) ? If that works you may want to create a PR with it. Thanks!
Comment #2 by hsteoh — 2017-07-17T23:01:31Z
Haha, I tried doing that but ran into another bug: ------ struct C { private S* impl; } struct S { bool empty; @property C front() return { return C(&this); } void popFront() { } pragma(msg, typeof((S r) return => r.front)); } ------ Compiler output (dmd -dip25 -dip1000): ------ test.d(10): Error: returning r.front() escapes a reference to parameter r, perhaps annotate with return _error_ ------ Because of this, isInputRange still doesn't work, with your proposed change. Apparently dmd fails to pick up the `return` annotation for some reason. Which is actually rather strange, because: ------- pragma(msg, typeof((int* r) return => r)); ------- prints: ------- int* function(return int* r) pure nothrow @nogc return @safe ------- so obviously the syntax is correct, and at least some of the time dmd is able to process it correctly. I've no idea why it doesn't pick up the annotation and/or process it correctly when in the first code snippet above.
Comment #3 by schveiguy — 2017-07-19T14:01:00Z
(In reply to Andrei Alexandrescu from comment #1) > is(typeof((R r) => r.front)) || is(typeof((R r) return => r.front)) I'm new to the "return" annotation, but is that right? I mean, I thought return was supposed to be an annotation on the parameter, not the function itself (which in this case is actually not a member function). I would have expected: (return R r) => r.front
Comment #4 by andrei — 2017-07-28T01:15:49Z
hsteoh, could you please submit those as a separate bug report for dmd and create a phobos PR using the simplest workaround you can find? That PR would close this bug, and the other bug will be for the compiler. Thanks!
Comment #5 by code — 2017-08-03T18:49:42Z
Well in, (R r) return => r.front, the return applies to the delegate context, but you're escaping a reference to the argument. What you want to check is `(return ref R r) => r.front`. Also rewriting your front methods to a free functions helps understanding. C front(return ref S _this) { return C(&_this); } Obviously allowing (R r) => front(r) would return a dangling reference to the value parameter. NB, if your front methods leaked a field of the range (e.g. a pointer), you'd need a `return scope` front methods, but the `(R r) => r.front` check is fine, since the parameter `r` isn't scoped, i.e. it might leak any pointer fields.
Comment #6 by hsteoh — 2017-08-10T00:35:38Z
Comment #7 by hsteoh — 2017-08-10T00:36:42Z
According to what Martin Nowak just said, there is no dmd bug, is that right? So we only need to fix Phobos.
Comment #8 by github-bugzilla — 2017-08-14T10:52:12Z
Commits pushed to master at https://github.com/dlang/phobos https://github.com/dlang/phobos/commit/be9ad6a311a53e9ab8d2a8b69777b73d33b279c3 Fix issue 17661: isInputRange should work with .front that returns reference to parameter. https://github.com/dlang/phobos/commit/6b460ab71750ae4d405ec392581d781a7d4f4e2a Merge pull request #5688 from quickfur/issue17661 Issue 17661: isInputRange should accept .front that returns reference to range merged-on-behalf-of: Petar Kirov <[email protected]>
Comment #9 by github-bugzilla — 2017-08-16T13:24:37Z
Commits pushed to stable at https://github.com/dlang/phobos https://github.com/dlang/phobos/commit/be9ad6a311a53e9ab8d2a8b69777b73d33b279c3 Fix issue 17661: isInputRange should work with .front that returns reference to parameter. https://github.com/dlang/phobos/commit/6b460ab71750ae4d405ec392581d781a7d4f4e2a Merge pull request #5688 from quickfur/issue17661
Comment #10 by github-bugzilla — 2018-01-05T13:31:09Z
Commits pushed to dmd-cxx at https://github.com/dlang/phobos https://github.com/dlang/phobos/commit/be9ad6a311a53e9ab8d2a8b69777b73d33b279c3 Fix issue 17661: isInputRange should work with .front that returns reference to parameter. https://github.com/dlang/phobos/commit/6b460ab71750ae4d405ec392581d781a7d4f4e2a Merge pull request #5688 from quickfur/issue17661