fsharp icon indicating copy to clipboard operation
fsharp copied to clipboard

F# compiler does not enforce attribute targets

Open njlr opened this issue 5 years ago • 7 comments

Compile this code:

open System

[<AttributeUsage(AttributeTargets.Method)>]
type MethodOnlyAttribute() = 
  inherit System.Attribute()

[<MethodOnly>]
let abc () =
  "abc"

[<MethodOnly>]
let def =
  "def"

Expected behavior

Compilation should fail because def is not a method; it is a string.

Actual behavior

The code compiles.

Known workarounds

Take care not to use attributes incorrectly.

Related information

https://github.com/dotnet/fsharp/issues/4460 is not quite the same, but a fix will probably touch the same code.

  • Operating system: Linux
  • .NET Runtime kind: .NET Core, Fable
  • Editing Tools: Visual Studio Code

njlr avatar Feb 11 '20 10:02 njlr

So this one is kinda funky. F# functions emit as methods, so it's technically correct that you can use MethodOnly on an F# function.

However, in F# semantics there is a very loose distinction (often no distinction) between F# functions and values. F# supports "normal" functions like let add x y = x + y, but also function values like this to support partial application:

let add x = fun y -> x + y
let add' x y = x + y

And you can apply the attribute to that as well. The typechecker doesn't distinguish between the two functions (at least not how you might expect). The consequence of that is you can apply the attribute to something that emits as a property.

I would argue that this is a bug, but fixing it would also be a breaking change, so the best we can do is emit a warning.

cartermp avatar Feb 11 '20 16:02 cartermp

Does the same funkiness apply for AttributeTargets that target types?

Such as:

  • AttributeTargets.Class
  • AttributeTargets.Interface
  • AttributeTargets.Struct

I ran into this while consuming a C# library (I only have limited F# experience) that had attributes with these targets. E.g. the following situations compile but some wouldn't in C#:

open System

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

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

[<AttributeUsage(AttributeTargets.Struct)>]
type StructTargetAttribute() =
    inherit Attribute()

[<ClassTarget>] // Valid
[<InterfaceTarget>] // Invalid
[<StructTarget>] // Invalid
type C() =
    member _.M() = ()

[<ClassTarget>] // Invalid
[<InterfaceTarget>] // Valid
[<StructTarget>] // Invalid
type I =
    abstract member prop: string
    
[<ClassTarget>] // Valid
[<InterfaceTarget>] // Invalid
[<StructTarget>] // Invalid
type RecRef = {
    prop: string
}

[<ClassTarget>] // Invalid
[<InterfaceTarget>] // Invalid
[<StructTarget>] // Valid
[<Struct>]
type RecStruct = {
    prop: string
}

twaalewijn avatar Jul 04 '20 21:07 twaalewijn

Yes, this should give a warning or error that the attribute is not applicable to def.

I will also list this as a spec clarification issue in https://github.com/fsharp/fsfoundation/issues/841 - we should indicate for each language element exactly which attribute targets are allowed. Some parts of the spec do record this but not all.

dsyme avatar Aug 31 '20 18:08 dsyme

This trips us from time to time while writing tests in xunit where people forget to put unit after the let function

    [<Fact>]
    let ``When receiving should`` = ...

vs

    [<Fact>]
    let ``When receiving should`` () = ...

Would be very helpful with a compiler warning/error.

ly29 avatar Jun 09 '22 06:06 ly29

Yes, this should give a warning or error that the attribute is not applicable to def.

I will also list this as a spec clarification issue in fsharp/fsfoundation#841 - we should indicate for each language element exactly which attribute targets are allowed. Some parts of the spec do record this but not all.

Im adding the warning for this. @vzarytovskii @dsyme any plans on updating the lang specification about this? Want to help fixing all this inconsistencies but it is hard without knowing this

edgarfgp avatar Feb 19 '24 09:02 edgarfgp

Yes, this should give a warning or error that the attribute is not applicable to def.

I will also list this as a spec clarification issue in fsharp/fsfoundation#841 - we should indicate for each language element exactly which attribute targets are allowed. Some parts of the spec do record this but not all.

Im adding the warning for this. @vzarytovskii @dsyme any plans on updating the lang specification about this? Want to help fixing all this inconsistencies but it is hard without knowing this

It should be an rfc, since we treat those as additions to specification.

vzarytovskii avatar Feb 19 '24 09:02 vzarytovskii

Yes, this should give a warning or error that the attribute is not applicable to def.

I will also list this as a spec clarification issue in fsharp/fsfoundation#841 - we should indicate for each language element exactly which attribute targets are allowed. Some parts of the spec do record this but not all.

Im adding the warning for this. @vzarytovskii @dsyme any plans on updating the lang specification about this? Want to help fixing all this inconsistencies but it is hard without knowing this

It should be an rfc, since we treat those as additions to specification.

Yes RFC would be good to have that documented there . I can see 10+ issues related to AttributesTargets

edgarfgp avatar Feb 19 '24 09:02 edgarfgp