dotnet / fsharp

The F# compiler, F# core library, F# language service, and F# tooling integration for Visual Studio
https://dotnet.microsoft.com/languages/fsharp
MIT License
3.94k stars 788 forks source link

Problems when passing "null" to attribute parameters e.g. DefaultParameterValue attribute #719

Closed eiriktsarpalis closed 7 years ago

eiriktsarpalis commented 9 years ago

When writing APIs intended for C# consumption, it is common practice to attach the OptionalParameter and DefaultParameterValue attributes to any F# optional parameter (see also http://bugsquash.blogspot.gr/2012/08/optional-parameters-interop-c-f.html).

I have identified an issue where the compiler fails with an unhandled exception when attempting to attach these attributes to optional parameters defined in abstract methods. Here's a minimal reproduction:

This is foo.fs:

namespace Foo

open System.Runtime.InteropServices

type IFoo =
    abstract Test : [<DefaultParameterValueAttribute(null)>]?value:int -> string

And here is bar.fs:

namespace Bar

open Foo

type Bar =
    interface IFoo with
        member __.Test (?value:int) = value.ToString()

From the command line, running the following jobs:

fsc -a foo.fs
fsc -a -r foo.dll bar.fs

Results in the following error:

C:\Users\eirik\Desktop>fsc -a -r foo.dll bar.fs
Microsoft (R) F# Compiler version 14.0.23413.0
Copyright (c) Microsoft Corporation. All Rights Reserved.

unknown(1,1): warning FS3186: An error occurred while reading the F# metadata node at position 0 in table 'itypars' of assembly 'foo, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. The node had no matching declaration. Please report this warning. You may need to recompile the F# assembly you are using.

error FS0193: internal error: Object reference not set to an instance of an object.

error FS0193: internal error: Object reference not set to an instance of an object.

Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.FSharp.Compiler.Tast.stripTyparEqnsAux(Boolean canShortcut, TType ty)
   at Microsoft.FSharp.Compiler.TastPickle.clo@1561-22.Invoke(TType ty, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_array@421.Invoke(T[] x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_expr@2371-5.Invoke(Expr expr, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_attrib_expr(AttribExpr _arg3, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_attrib@1782.Invoke(AttribExpr arg00@, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_array@421.Invoke(T[] x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_attrib(Attrib _arg2, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.clo@2510-31.Invoke(Attrib arg00@, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_array@421.Invoke(T[] x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_slotparam(SlotParam _arg8, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_slotsig@2471.Invoke(SlotParam arg00@, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_array@421.Invoke(T[] x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_array@421.Invoke(T[] x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_slotsig(SlotSig _arg9, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_member_info@1791.Invoke(SlotSig arg00@, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_array@421.Invoke(T[] x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_member_info(ValMemberInfo x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_ValData@1832-2.Invoke(ValMemberInfo x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_option[a](FSharpFunc`2 f, FSharpOption`1 x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_ValData@1832-3.Invoke(FSharpOption`1 x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_ValData(ValData x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_Val@1856.Invoke(ValData x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_osgn_decl[a,b](NodeOutTable`2 outMap, FSharpFunc`2 p, b x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_modul_typ@1861.Invoke(Val x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_array@421.Invoke(T[] x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_modul_typ(ModuleOrNamespaceType x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_entity_spec_data@1737-3.Invoke(ModuleOrNamespaceType x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_lazy@452.Invoke(Lazy`1 x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_entity_spec_data(EntityData x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_tycon_spec@1769.Invoke(EntityData x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_osgn_decl[a,b](NodeOutTable`2 outMap, FSharpFunc`2 p, b x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_modul_typ@1862-3.Invoke(Entity x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_array@421.Invoke(T[] x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_modul_typ(ModuleOrNamespaceType x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_entity_spec_data@1737-3.Invoke(ModuleOrNamespaceType x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_lazy@452.Invoke(Lazy`1 x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_entity_spec_data(EntityData x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_tycon_spec@1769.Invoke(EntityData x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.p_osgn_decl[a,b](NodeOutTable`2 outMap, FSharpFunc`2 p, b x, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.pickleCcuInfo@2532.Invoke(PickledCcuInfo minfo, WriterState st)
   at Microsoft.FSharp.Compiler.TastPickle.pickleObjWithDanglingCcus[T](String file, TcGlobals g, CcuThunk scope, FSharpFunc`2 p, T x)
   at Microsoft.FSharp.Compiler.CompileOps.PickleToResource[a](String file, TcGlobals g, CcuThunk scope, String rname, FSharpFunc`2 p, a x)
   at Microsoft.FSharp.Compiler.CompileOps.WriteSignatureData(TcConfig tcConfig, TcGlobals tcGlobals, Remap exportRemapping, CcuThunk ccu, String file)
   at Microsoft.FSharp.Compiler.Driver.EncodeInterfaceData(TcConfig tcConfig, TcGlobals tcGlobals, Remap exportRemapping, ErrorLogger _errorLogger, CcuThunk generatedCcu, String outfile, Exiter exiter)
   at Microsoft.FSharp.Compiler.ErrorLogger.ErrorLoggerExtensions.ReraiseIfWatsonable(Exception exn)
   at Microsoft.FSharp.Compiler.ErrorLogger.ErrorLoggerExtensions.ErrorLogger.ErrorRecovery(ErrorLogger x, Exception exn, range m)
   at Microsoft.FSharp.Compiler.Driver.EncodeInterfaceData(TcConfig tcConfig, TcGlobals tcGlobals, Remap exportRemapping, ErrorLogger _errorLogger, CcuThunk generatedCcu, String outfile, Exiter exiter)
   at Microsoft.FSharp.Compiler.Driver.main2[a,b,c,d,e,f](Args`1 _arg1)
   at Microsoft.FSharp.Compiler.Driver.typecheckAndCompile(String[] argv, Boolean bannerAlreadyPrinted, Exiter exiter, ErrorLoggerProvider errorLoggerProvider)
   at Microsoft.FSharp.Compiler.Driver.mainCompile(String[] argv, Boolean bannerAlreadyPrinted, Exiter exiter)
   at Microsoft.FSharp.Compiler.CommandLineMain.Driver.main(String[] argv)
   at Microsoft.FSharp.Compiler.CommandLineMain.main(String[] argv)
   at Microsoft.FSharp.Compiler.ErrorLogger.ErrorLoggerExtensions.ReraiseIfWatsonable(Exception exn)
   at Microsoft.FSharp.Compiler.ErrorLogger.ErrorLoggerExtensions.ErrorLogger.ErrorRecovery(ErrorLogger x, Exception exn, range m)
   at Microsoft.FSharp.Compiler.CommandLineMain.main(String[] argv)
dsyme commented 9 years ago

This is a workaround:

type IFoo =
    abstract Test : [<DefaultParameterValueAttribute(null:obj)>]?value:int -> string
eiriktsarpalis commented 9 years ago

Great, that works

dsyme commented 9 years ago

The bug feels like it must be because we are failing to collect a type inference variable in the attribute argument in the "FindUnsolved.fs" code, roughly here: https://github.com/Microsoft/visualfsharp/blob/2d413fb940aa1677688454c50b8ec05cd3b6f78f/src/fsharp/FindUnsolved.fs#L178. However we are calling that function for custom attributes on parameters - and the function itself looks correct, so I'm not entirely clear where the bug is

One thing I notice that accExpr is not being called for the second "value-of-the-attribute" expression in each attribute, which may be relevant.

dsyme commented 7 years ago

I think this is the root cause of https://github.com/Microsoft/visualfsharp/issues/1626

dsyme commented 7 years ago

@eiriktsarpalis It's been a long time but finally tracked this one down https://github.com/Microsoft/visualfsharp/pull/3273