Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fully qualified name, unqualified name with import declaration resolve differently

Tags:

f#

This works

open System
let f = Action(fun () -> Unchecked.defaultof<_>)

But this

let f = System.Action(fun () -> Unchecked.defaultof<_>)

produces the compilation error

Multiple types exist called 'Action', taking different numbers of generic parameters. Provide a type instantiation to disambiguate the type resolution, e.g. 'Action<,,_,,,_,,,_>'.

I know I can fix it by adding a type parameter placeholder (System.Action<_>(...)), but any idea why they behave differently?

EDIT

Found this in the spec, section 14.1.9:

When a module or namespace declaration group F is opened, items are added to the name environment as follows:

  • Add the type to the TypeNames table. If the type has a CLI-mangled generic name such as List'1 then an entry is added under both List and List'1.

Is this behavior replicated for fully-qualified types (with omitted type parameters)? It doesn't appear so.

like image 858
Daniel Avatar asked Jan 04 '12 19:01

Daniel


1 Answers

I agree with @James that this is related to the bug submitted on Connect, but I think it is a slightly different case. Anyway, I think this is not the intended behaviour. Could you report it to fsbugs at microsoft dot com?

Anyway - I did some debugging and here is what I found so far:

It seems that the compiler uses different code paths to resolve the name Action and the name System.Action. When resolving the other, it searches all loaded modules (i.e. assemblies) for a type named System.Action (see ResolveLongIndentAsModuleOrNamespaceThen function in the nameres.fs file of the open-source release).

This finds the two definitions of Action (one in mscorlib and another in System.Core). I think the issue comes from the fact that the name resolution simply iterates over the results - it finds the first one (from System.Core), which doesn't have a usable overload (because it ranges from Action<_,_,_,_,_> to a version with about 15 type parameters). After finding this type, it reports an error without even looking whether there is another type (in another assembly) that could be used.

If you don't reference system assemblies, then the F# compiler resolves the overload just fine. Running the compiler without parameters references the default assembly set, so this doesn't work:

fsc test.fs 

but if I add the --noframework flag, then it compiles without issues:

fsc --noframework test.fs
like image 182
Tomas Petricek Avatar answered Sep 18 '22 13:09

Tomas Petricek