D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 16410 - attribute inference for final methods of templated classes
Summary: attribute inference for final methods of templated classes
Status: RESOLVED INVALID
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P1 normal
Assignee: No Owner
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2016-08-21 13:42 UTC by Lodovico Giaretta
Modified: 2022-11-10 13:15 UTC (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Lodovico Giaretta 2016-08-21 13:42:02 UTC
Example code:

class Bar(T)
{
    T t;

    // the following function is not inferred @nogc
    // changing return type to auto solves the issue
    ulong get()
    {
        return t.length;
    }
}

@nogc void main()
{
    import std.experimental.allocator;
    import std.experimental.allocator.mallocator;

    auto alloc = Mallocator.instance;	

    auto x = alloc.make!(Bar!string).check;
    // error: @nogc main cannot call non-@nogc function check
}
Comment 1 Lodovico Giaretta 2016-08-21 13:50:13 UTC
I forgot to mention that if Bar is a templated struct, attribute inference happens correctly, even with an explicit return type.
So this is a bug specific to templated classes.
Comment 2 basile-z 2016-08-21 14:11:48 UTC
This is an enhancement request not a bug report. 

The member function itself is not a template and since attribs are infered only for templated functions the error message is correct. 

With "auto" return type the member function becomes a template so it works. It would also work with a template this parameter or with empty CT parameters.

°°°°°°°°°°°°°°°°°°°°°°°
class Bar(T)
{
    T t;
    ulong a()(){return t.length;}
    ulong b(this T)(){return t.length;}
    auto c(){return t.length;}
}

@nogc void main()
{
    import std.experimental.allocator;
    import std.experimental.allocator.mallocator;
    auto alloc = Mallocator.instance;
    auto a = alloc.make!(Bar!string).a;
    auto b = alloc.make!(Bar!string).b;
    auto c = alloc.make!(Bar!string).c;
}
°°°°°°°°°°°°°°°°°°°°°°°

Definitively not a "rejects-valid".
Comment 3 Lodovico Giaretta 2016-08-21 14:24:43 UTC
(In reply to b2.temp from comment #2)
> This is an enhancement request not a bug report. 

I have to disagree with you. See my points below.

> The member function itself is not a template and since attribs are infered
> only for templated functions the error message is correct. 

The member function is not a template, but it's part of a template and depends on the template arguments. I would understand your point if the function did not depend on T.

Also, the same thing, with `struct Bar(T)` instead of `class Bar(T)` supports inference, so your argument does not hold, because even there the member function is not a template itself, but only part of a template.

> With "auto" return type the member function becomes a template so it works.

I don't think that `auto` as a return types makes a function become a template. If it does, it's worth an enhancement, as I don't want the following function to be a template, it does not make any sense:

auto get3() { return 3UL; }
Comment 4 basile-z 2016-08-21 14:58:09 UTC
(In reply to Lodovico Giaretta from comment #3)
> (In reply to b2.temp from comment #2)
> > With "auto" return type the member function becomes a template so it works.
> 
> I don't think that `auto` as a return types makes a function become a
> template. If it does, it's worth an enhancement, as I don't want the
> following function to be a template, it does not make any sense:
> 
> auto get3() { return 3UL; }

Yes you're right this is not a template:

https://dlang.org/spec/attribute.html#auto

but auto return type is made for this case, i.e when attribute inference is needed.
Comment 5 Lodovico Giaretta 2016-08-21 15:05:42 UTC
(In reply to b2.temp from comment #4)
> but auto return type is made for this case, i.e when attribute inference is
> needed.

The problem is that I'm in this situation:

==========================
interface Foo
{
    int doSomething();
}
class Bar(T): Foo
{
    override int doSomething()
    {
        // do something with T
    }
}
==========================

There's no way to have Bar.doSomething @nogc currently because
1) I cannot put @nogc on Foo.doSomething, because in general it is not @nogc.
2) I cannot put @nogc on Bar.doSomething, because it may use the gc depending on T
3) I cannot use the "auto return trick" to trigger inference, because auto return cannot be used with override.

So currently there's no way to use Bar!T in @nogc code even for T's that are @nogc.
Comment 6 basile-z 2016-08-21 15:07:18 UTC
(In reply to Lodovico Giaretta from comment #1)
> I forgot to mention that if Bar is a templated struct, attribute inference
> happens correctly, even with an explicit return type.
> So this is a bug specific to templated classes.

oops I've forget to read that. Repairing modifications now.
Comment 7 Steven Schveighoffer 2016-08-23 13:51:21 UTC
I thought that templated classes would infer attributes. But thinking about this some more, I wonder if that's correct for virtual base functions?

I can envision this scenario:

class Foo(T)
{
   string bar() { return "hi"; }
}

class Bar(T) : Foo!T
{
   override string bar() { return super.bar() ~ T.stringof; }
}

Should Foo(T).bar be @nogc? It would be inferred that if Foo was a struct. But in this case, it is preventing possibly intended behavior.
Comment 8 Lodovico Giaretta 2016-08-23 14:51:53 UTC
(In reply to Steven Schveighoffer from comment #7)
> I thought that templated classes would infer attributes. But thinking about
> this some more, I wonder if that's correct for virtual base functions?
> 
> I can envision this scenario:
> 
> class Foo(T)
> {
>    string bar() { return "hi"; }
> }
> 
> class Bar(T) : Foo!T
> {
>    override string bar() { return super.bar() ~ T.stringof; }
> }
> 
> Should Foo(T).bar be @nogc? It would be inferred that if Foo was a struct.
> But in this case, it is preventing possibly intended behavior.

Sorry, I don't understand why Foo!T.bar being @nogc would prevent possibly intended behaviour. Can you please elaborate on this?
Comment 9 Lodovico Giaretta 2016-08-23 15:04:24 UTC
(In reply to Lodovico Giaretta from comment #8)
> Sorry, I don't understand why Foo!T.bar being @nogc would prevent possibly
> intended behaviour. Can you please elaborate on this?

Nevermind, got that. If a method is inferred @nogc, it can no longer be overridden as non-@nogc. This is correct. My bad.

Then a new question arises: why cannot attribute inference happen for *final* methods of templated classes?
Comment 10 Lodovico Giaretta 2016-08-23 15:08:06 UTC
(In reply to Lodovico Giaretta from comment #9)
> Then a new question arises: why cannot attribute inference happen for
> *final* methods of templated classes?

Small precisation: I mean *final override* methods. For final (non-virtual) methods it already happens.
Comment 11 Steven Schveighoffer 2016-08-23 15:52:52 UTC
(In reply to Lodovico Giaretta from comment #10)
> (In reply to Lodovico Giaretta from comment #9)
> > Then a new question arises: why cannot attribute inference happen for
> > *final* methods of templated classes?
> 
> Small precisation: I mean *final override* methods. For final (non-virtual)
> methods it already happens.

I think it should, where possible. That is, if you can override a non-@nogc method with a @nogc method (and if not, I think you should be able to), then inference of the attribute should happen for final methods.
Comment 12 RazvanN 2022-11-10 13:15:10 UTC
(In reply to Lodovico Giaretta from comment #10)
> (In reply to Lodovico Giaretta from comment #9)
> > Then a new question arises: why cannot attribute inference happen for
> > *final* methods of templated classes?
> 
> Small precisation: I mean *final override* methods. For final (non-virtual)
> methods it already happens.

The compiler cannot infer the attributes for final override methods because you already may have some constraints from the overriding function. For example, if the overriden function is @safe, the overriding function must also be @safe. Technically, the overriden function dictates the interface. I think it might be surprising to the attributes for overrides, even if they are final.

I think we can close this issue as INVALID.