Bug 8339 – is(typeof(...)) is reporting true when it's false due to nested function error
Status
RESOLVED
Resolution
FIXED
Severity
blocker
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2012-07-02T22:43:00Z
Last change time
2012-12-28T17:08:07Z
Keywords
pull, rejects-valid
Assigned to
nobody
Creator
issues.dlang
Comments
Comment #0 by issues.dlang — 2012-07-02T22:43:22Z
This code fails to compile:
import std.algorithm;
private bool testEmptyInit(R)()
{
static if(is(typeof({R range;})))
{
R range;
return range.empty;
}
else
return false;
}
void main()
{
testEmptyInit!(typeof(filter!"true"([0, 1, 2, 3])));
}
giving this error
h.d(7): Error: function std.algorithm.filter!("true").filter!(int[]).filter is a nested function and cannot be accessed from h.testEmptyInit!(FilteredRange).testEmptyInit
So, the compiler thinks that is(typeof({R range;})) is true for the type of filter's result and then it gives an error saying that it's invalid to use it, meaning that it's _not_ valid and therefore is(typeof({R range;})) should be false.
If bug# 5941 were fixed, this wouldn't be as big an issue (though the fact that you can get an error for using a construct when the test for using it passes is definitely a bug regardless), but as long as bug# 5941 exists, this is a major blocker for being able to create a template to check for whether the init value of a range type is empty or not.
Comment #1 by clugdbug — 2012-07-12T06:11:44Z
>So, the compiler thinks that is(typeof({R range;})) is true for the type of
>filter's result and then it gives an error saying that it's invalid to use it,
>meaning that it's _not_ valid and therefore is(typeof({R range;})) should be
>false.
That doesn't follow.
is(typeof(X)) only checks for a valid type. It does *not* check that the code compiles. Checking that typeof(X) compiles is weaker than checking that X compiles. There are several cases where you can obtain a type from something you cannot possibly use. For example you can use typeof(this) in a static member function.
OTOH
__traits(compiles, {R range; }) almost certainly behaves the same way, but it isn't supposed to.
The issue is that the 'nested function' error is happening in the glue layer. It should be happening in the front end.
Comment #2 by issues.dlang — 2012-07-15T22:48:35Z
We use is(typeof(exp)) to check for compilability all over the place. Are you saying that we should be using __traits(compiles, exp) instead?
Using __traits(compiles, {R range;}) still fails here. But should it work as I'm trying to do here if the glue layer issues is fixed?
If not, how am I supposed to test that I can actually _use_ R.init in addition to it existing? Or is it the case that I should _always_ be able to use R.init if it exists?
Comment #3 by clugdbug — 2012-07-16T07:13:18Z
(In reply to comment #2)
> We use is(typeof(exp)) to check for compilability all over the place. Are you
> saying that we should be using __traits(compiles, exp) instead?
Probably. Mostly is(typeof()) does what you want, but just be aware that it's a trick. It's just checking for existence of a type, not for compilability.
It's widespread because it works for D1, which doesn't have __traits.
It's also rather better tested than __traits...
> Using __traits(compiles, {R range;}) still fails here. But should it work as
> I'm trying to do here if the glue layer issues is fixed?
Yes, it should work.