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

Enforce AttributeTargets.Interface #17173

Merged

Conversation

edgarfgp
Copy link
Contributor

@edgarfgp edgarfgp commented May 17, 2024

Description

Enforce AttributeTargets.Interface

  • AttributeTargets.Interface should only work on interfaces
  • AttributeTargets.Class should only work on classes
open System

[<AttributeUsage(AttributeTargets.Interface)>]
type CustomInterfaceAttribute() =
    inherit Attribute()

[<AttributeUsage(AttributeTargets.Class)>]
type CustomClassAttribute() =
    inherit Attribute()

[<CustomClass>] // Should fail, but does not
type IFoo =
    abstract member Foo : string

[<CustomClass>] // Should fail, but does not
[<Interface>]
type IFoo2 =
    abstract member Foo : string
    
[<CustomInterface>] // Should fail, but does not
type Foo() = class end

[<Class; CustomInterface>] // Should fail, but does not
type Foo2() = class end

See C# version for reference sharplab

Checklist

  • Test cases added
  • Release notes entry updated

Copy link
Contributor

github-actions bot commented May 17, 2024

⚠️ Release notes required, but author opted out

Warning

Author opted out of release notes, check is disabled for this pull request.
cc @dotnet/fsharp-team-msft

@edgarfgp
Copy link
Contributor Author

AllowNullLiteralAttribute needs updating

@edgarfgp
Copy link
Contributor Author

Interesting. VS Integration is using System.Runtime.InteropServices.ClassInterface attribute docs which is meant to be used only on a class

  /// <summary>Indicates the type of class interface to be generated for a class exposed to COM, if an interface is generated at all.</summary>
  [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, Inherited = false)]
  public sealed class ClassInterfaceAttribute : Attribute
  {
    /// <summary>Initializes a new instance of the <see cref="T:System.Runtime.InteropServices.ClassInterfaceAttribute" /> class with the specified <see cref="T:System.Runtime.InteropServices.ClassInterfaceType" /> enumeration member.</summary>
    /// <param name="classInterfaceType">One of the <see cref="T:System.Runtime.InteropServices.ClassInterfaceType" /> values that describes the type of interface that is generated for a class.</param>
    public ClassInterfaceAttribute(ClassInterfaceType classInterfaceType)
    {
      this.Value = classInterfaceType;
    }

sharplab

[<System.Runtime.InteropServices.ClassInterface(ClassInterfaceType.None)>] // This is allowed but should not
type public IVsMicrosoftInstalledProduct =
    inherit IVsInstalledProduct
    abstract IdBmpSplashM : byref<uint32> -> unit

[<System.Runtime.InteropServices.ClassInterface(ClassInterfaceType.None)>]
type Foo() = class end

sharplab

using System.Runtime.InteropServices;

[ClassInterface(ClassInterfaceType.AutoDispatch)]
public class MyClass
{
}

[ClassInterface(ClassInterfaceType.AutoDispatch)] // This raises an error in C#
public interface IFoo {}

cc @vzarytovskii seems like System.Runtime.InteropServices.ClassInterface has been wrongly used here ?

@vzarytovskii
Copy link
Member

Not sure what to do with it, it'll probably need to be an abstract class. This is legacy project system, so won't be able to test it that easy, and we have to support it.

@edgarfgp edgarfgp force-pushed the enfortce-attribute-target-on-interfaces branch from 0c3c7a3 to eeea1fc Compare May 18, 2024 13:34
@edgarfgp edgarfgp force-pushed the enfortce-attribute-target-on-interfaces branch from eeea1fc to 85d80ab Compare May 18, 2024 14:19
@edgarfgp
Copy link
Contributor Author

Not sure what to do with it, it'll probably need to be an abstract class. This is legacy project system, so won't be able to test it that easy, and we have to support it.

Yeah an AbstractClass will be ok here but it won't be able to inherit from an interface IVsInstalledProduct(seems to be a close source so I can't see the defined members)

@edgarfgp
Copy link
Contributor Author

edgarfgp commented May 18, 2024

Ohh Thanks my googling failed 😅

@majocha
Copy link
Contributor

majocha commented May 18, 2024

Yeah, we don't actually implement it, so it's not really used as the docs prescribe. This is some ancient COM trickery that worked long time ago but not necessarily still do.

In fact I just comment out that whole IVsMicrosoftInstalledProduct interface, started VS debug instance and things seem to work the same without it:
image

@edgarfgp
Copy link
Contributor Author

Yeah, we don't actually implement it, so it's not really used as the docs prescribe. This is some ancient COM trickery that worked long time ago but not necessarily still do.

In fact I just comment out that whole IVsMicrosoftInstalledProduct interface, started VS debug instance and things seem to work the same without it

If it is not longer used/needed we could just comment out / remove this code.

ideally enforcing the right attribute targets in the compiler should not depend on the use of this interface

@abelbraaksma
Copy link
Contributor

abelbraaksma commented May 19, 2024

I'd really like this change and for the compiler to enforce attribute targets, but technically this would be a backward incompatible change, right? Do we have a lang suggestion or bug or issue report (I believe this has come up several times)?

Ah, wait, found it: #8547.

And related are all these: #16692, #16764, #16845, #16790. I assume my point above has already been discussed before then ;).

And there's mention of an RFC by you (@edgarfgp), can we link that from the original post above, or is that TODO? #8547 (comment)

@edgarfgp
Copy link
Contributor Author

edgarfgp commented May 19, 2024

I'd really like this change and for the compiler to enforce attribute targets, but technically this would be a backward incompatible change, right? Do we have a lang suggestion or bug or issue report (I believe this has come up several times)?

Ah, wait, found it: #8547.

And related are all these: #16692, #16764, #16845, #16790. I assume my point above has already been discussed before then ;).

And there's mention of an RFC by you (@edgarfgp), can we link that from the original post above, or is that TODO? #8547 (comment)

@abelbraaksma Once I have addressed all the AttributeTargets inconsistencies I would be willing to write an RFC to properly spec this. This is behind a LangVersion preview.

@edgarfgp edgarfgp added the NO_RELEASE_NOTES Label for pull requests which signals, that user opted-out of providing release notes label May 20, 2024
@edgarfgp edgarfgp marked this pull request as ready for review May 20, 2024 09:48
@edgarfgp edgarfgp requested a review from a team as a code owner May 20, 2024 09:48
Copy link
Member

@psfinaki psfinaki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your continuous work here, Edgar :)

Yeah so the VS change looks a bit risky, but since Jakub tested the related functionality, I don't think we should block the fix by that thing. Also, this is a well-isolated PR, so can be reverted quickly if needed.

@psfinaki psfinaki merged commit 3e1f9e7 into dotnet:main May 21, 2024
32 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NO_RELEASE_NOTES Label for pull requests which signals, that user opted-out of providing release notes
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

None yet

6 participants