Math.NET Numerics
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

2215 lines
97 KiB

// (c) Microsoft Corporation. All rights reserved
/// tinfos, minfos, finfos, pinfos - summaries of information for references
/// to .NET and F# constructs.
#light
module (* internal *) Microsoft.FSharp.Compiler.Infos
open Internal.Utilities
open Internal.Utilities.Pervasives
open Microsoft.FSharp.Compiler.AbstractIL
open Microsoft.FSharp.Compiler.AbstractIL.IL
open Microsoft.FSharp.Compiler.AbstractIL.Internal
open Microsoft.FSharp.Compiler.AbstractIL.Internal.Library
open Microsoft.FSharp.Compiler
open Microsoft.FSharp.Compiler.AbstractIL.Diagnostics
open Microsoft.FSharp.Compiler.Range
open Microsoft.FSharp.Compiler.Ast
open Microsoft.FSharp.Compiler.ErrorLogger
open Microsoft.FSharp.Compiler.Tast
open Microsoft.FSharp.Compiler.Tastops
open Microsoft.FSharp.Compiler.Env
open Microsoft.FSharp.Compiler.AbstractIL.IL (* Abstract IL *)
open Microsoft.FSharp.Compiler.Lib
open Microsoft.FSharp.Text.Printf
//-------------------------------------------------------------------------
// From IL types to F# types
//-------------------------------------------------------------------------
/// importInst gives the context for interpreting type variables
let ImportType scoref amap m importInst ilty =
ilty |> rescope_typ scoref |> Import.ImportILType amap m importInst
//-------------------------------------------------------------------------
// Fold the hierarchy.
// REVIEW: this code generalizes the iteration used below for member lookup.
//-------------------------------------------------------------------------
let is_fsobjmodel_or_exn_typ g typ =
is_fsobjmodel_typ g typ ||
(is_stripped_tyapp_typ g typ && (tcref_of_stripped_typ g typ).IsExceptionDecl)
let SuperTypeOfType g amap m typ =
let typ = strip_tpeqns_and_tcabbrevs_and_measureable g typ
if is_il_named_typ g typ then
let tcref,tinst = dest_stripped_tyapp_typ g typ
let scoref,_,tdef = tcref.ILTyconInfo
match tdef.tdExtends with
| None -> None
| Some ilty -> Some (ImportType scoref amap m tinst ilty)
elif is_fsobjmodel_or_exn_typ g typ then
let tcref,tinst = dest_stripped_tyapp_typ g typ
Some (InstType (mk_inst_for_stripped_typ g typ) (super_of_tycon g (deref_tycon tcref)))
elif is_any_array_typ g typ then
Some(g.system_Array_typ)
elif is_ref_typ g typ && not (is_obj_typ g typ) then
Some(g.obj_ty)
elif is_tuple_struct_typ g typ then
//Some(g.system_Value_typ)
Some(g.obj_ty)
else None
let mk_System_Collections_Generic_IList_ty g ty = TType_app(g.tcref_System_Collections_Generic_IList,[ty])
let ImplementsOfType g amap m typ =
let itys =
if is_stripped_tyapp_typ g typ then
let tcref,tinst = dest_stripped_tyapp_typ g typ
if tcref.IsMeasureableReprTycon then
[g.mk_IComparable_ty;
g.mk_IConvertible_ty;
g.mk_IFormattable_ty;
mk_tyapp_ty g.system_GenericIComparable_tcref [typ];
mk_tyapp_ty g.system_GenericIEquatable_tcref [typ]]
elif tcref.IsILTycon then
let scoref,_,tdef = tcref.ILTyconInfo
List.map (ImportType scoref amap m tinst) tdef.tdImplements
else
let inst = mk_inst_for_stripped_typ g typ
List.map (fun (x,_,_) -> InstType inst x) tcref.TypeContents.tcaug_implements
else []
let itys =
if is_il_arr1_typ g typ then
mk_System_Collections_Generic_IList_ty g (dest_il_arr1_typ g typ) :: itys
else
itys
itys
// Traverse the type hierarchy, e.g. f D (f C (f System.Object acc)).
let rec FoldHierarchyOfTypeAux ndeep followInterfaces f g amap m typ (visited,acc) =
if ListSet.mem (type_equiv g) typ visited then visited,acc else
let state = typ::visited, acc
if verbose then dprintf "--> FoldHierarchyOfTypeAux, ndeep = %d, typ = %s...\n" ndeep ((DebugPrint.showType typ));
if ndeep > 100 then (errorR(Error("recursive class hierarchy (detected in FoldHierarchyOfTypeAux), typ = "^(DebugPrint.showType typ),m)); (visited,acc)) else
let visited,acc =
if is_interface_typ g typ then
List.foldBack
(FoldHierarchyOfTypeAux (ndeep+1) followInterfaces f g amap m)
(ImplementsOfType g amap m typ)
(FoldHierarchyOfTypeAux ndeep followInterfaces f g amap m g.obj_ty state)
elif is_typar_typ g typ then
let tp = dest_typar_typ g typ
let state = FoldHierarchyOfTypeAux (ndeep+1) followInterfaces f g amap m g.obj_ty state
List.foldBack
(fun x vacc ->
match x with
| TTyparMayResolveMemberConstraint _
| TTyparDefaultsToType _
| TTyparIsEnum _
| TTyparIsDelegate _
| TTyparSupportsNull _
| TTyparIsNotNullableValueType _
| TTyparIsReferenceType _
| TTyparSimpleChoice _
| TTyparRequiresDefaultConstructor _ -> vacc
| TTyparCoercesToType(cty,_) ->
FoldHierarchyOfTypeAux (ndeep + 1) followInterfaces f g amap m cty vacc)
tp.Constraints
state
else
let state =
if followInterfaces then
List.foldBack
(FoldHierarchyOfTypeAux (ndeep+1) followInterfaces f g amap m)
(ImplementsOfType g amap m typ)
state
else
state
let state =
Option.fold_right
(FoldHierarchyOfTypeAux (ndeep+1) followInterfaces f g amap m)
(SuperTypeOfType g amap m typ)
state
state
(visited,f typ acc)
/// Fold, do not follow interfaces
let FoldPrimaryHierarchyOfType f g amap m typ acc = FoldHierarchyOfTypeAux 0 false f g amap m typ ([],acc) |> snd
/// Fold, following interfaces
let FoldEntireHierarchyOfType f g amap m typ acc = FoldHierarchyOfTypeAux 0 true f g amap m typ ([],acc) |> snd
/// Iterate, following interfaces
let IterateEntireHierarchyOfType f g amap m typ = FoldHierarchyOfTypeAux 0 true (fun ty () -> f ty) g amap m typ ([],()) |> snd
let ExistsInEntireHierarchyOfType f g amap m typ =
FoldHierarchyOfTypeAux 0 true (fun ty acc -> acc || f ty ) g amap m typ ([],false) |> snd
let SearchEntireHierarchyOfType f g amap m typ =
FoldHierarchyOfTypeAux 0 true
(fun ty acc ->
match acc with
| None -> if f ty then Some(ty) else None
| Some _ -> acc)
g amap m typ ([],None)
|> snd
let AllSuperTypesOfType g amap m ty = FoldHierarchyOfTypeAux 0 true (ListSet.insert (type_equiv g)) g amap m ty ([],[]) |> snd
let mdef_is_ctor md = md.mdName = ".ctor"
let mdef_is_cctor md = md.mdName = ".cctor"
let mdef_is_protected md =
not (mdef_is_ctor md) &&
not (mdef_is_cctor md) &&
(md.mdAccess = MemAccess_family) &&
not md.mdCallconv.IsStatic
let ImportTypeFromMetadata amap m scoref tinst minst ilty =
ImportType scoref amap m (tinst@minst) ilty
//-------------------------------------------------------------------------
// Predicates and properties on values and members
//-------------------------------------------------------------------------
let PropertyNameOfMemberValRef (vref:ValRef) =
assert(vref.IsMember)
(the (vref.MemberInfo)).PropertyName
let MemberRefIsVirtual (vref:ValRef) =
let flags = vref.MemberInfo.Value.MemberFlags
flags.MemberIsVirtual || flags.MemberIsDispatchSlot || flags.MemberIsOverrideOrExplicitImpl
// REVIEW: This whole predicate is very dubious. We should not need the notion of "DefiniteFSharpOverride" at all
let MemberRefIsDefiniteFSharpOverride (vref:ValRef) =
let membInfo = vref.MemberInfo.Value
let flags = membInfo.MemberFlags
not flags.MemberIsDispatchSlot && (flags.MemberIsOverrideOrExplicitImpl || nonNil membInfo.ImplementedSlotSigs)
let MemberRefIsDispatchSlot (vref:ValRef) =
let membInfo = vref.MemberInfo.Value
membInfo.MemberFlags.MemberIsDispatchSlot
let MemberRefIsAbstract (vref:ValRef) =
let membInfo = vref.MemberInfo.Value
membInfo.MemberFlags.MemberIsDispatchSlot && not membInfo.IsImplemented
type ValRef with
member x.IsFSharpEventProperty(g) =
x.IsMember && CompileAsEvent g x.Attribs && not x.IsExtensionMember
//-------------------------------------------------------------------------
// Basic infos
//-------------------------------------------------------------------------
type ILTypeInfo =
| ILTypeInfo of TyconRef * ILTypeRef * tinst * ILTypeDef
member x.TyconRef = let (ILTypeInfo(tcref,_,_,_)) = x in tcref
member x.ILTypeRef = let (ILTypeInfo(_,tref,_,_)) = x in tref
member x.TypeInst = let (ILTypeInfo(_,_,tinst,_)) = x in tinst
member x.RawMetadata = let (ILTypeInfo(_,_,_,tdef)) = x in tdef
member x.ToType = TType_app(x.TyconRef,x.TypeInst)
member x.ILScopeRef = x.ILTypeRef.Scope
member x.Name = x.ILTypeRef.Name
member x.IsValueType = is_value_or_enum_tdef x.RawMetadata
type TypeInfo =
| ILType of ILTypeInfo
| FSType of Tast.typ
type ILMethInfo =
| ILMethInfo of ILTypeInfo * ILTypeRef option (* extension? *) * ILMethodDef * typars (* typars are the uninstantiated generic method args *)
member x.ILTypeInfo = let (ILMethInfo(tinfo,_,_,_)) = x in tinfo
member x.RawMetadata = let (ILMethInfo(_,_,md,_)) = x in md
member x.ExtensionMethodInfo = let (ILMethInfo(_,extInfo,_,_)) = x in extInfo
member x.ILTypeRef = x.ILTypeInfo.ILTypeRef
member x.ILName = x.RawMetadata.Name
// methods to hide logic related to extension methods
member x.IsCSharpExtensionMethod = x.ExtensionMethodInfo.IsSome
member x.ActualILTypeRef =
match x.ExtensionMethodInfo with
| None -> x.ILTypeRef
| Some info -> info
member x.ActualTypeInst =
match x.ExtensionMethodInfo with
| None -> x.ILTypeInfo.TypeInst
| Some info -> []
member x.MetadataScope = x.ActualILTypeRef.Scope
member x.ParamMetadata =
let ps = x.RawMetadata.mdParams in
if x.IsCSharpExtensionMethod then List.tl ps else ps
member x.NumParams = x.ParamMetadata.Length
member x.GenericArity = x.RawMetadata.mdGenericParams.Length
member x.IsConstructor = x.RawMetadata |> mdef_is_ctor
member x.IsClassConstructor = x.RawMetadata |> mdef_is_cctor
member x.IsProtectedAccessibility = x.RawMetadata |> mdef_is_protected
member x.IsVirtual = x.RawMetadata.IsVirtual
member x.IsFinal = x.RawMetadata.IsFinal
member x.IsAbstract =
match x.RawMetadata.mdKind with
| MethodKind_virtual vinfo -> vinfo.virtAbstract
| _ -> false
/// Does it appear to the user as a static method?
member x.IsStatic =
not x.IsCSharpExtensionMethod && // all C# extension methods are instance
x.RawMetadata.mdCallconv.IsStatic
/// Does it have the .NET IL 'newslot' flag set, and is also a virtual?
member x.IsNewSlot =
match x.RawMetadata.mdKind with
| MethodKind_virtual vinfo -> vinfo.virtNewslot
| _ -> false
/// Does it appear to the user as an instance method?
member x.IsInstance = not x.IsConstructor && not x.IsStatic
member x.ArgTypes(amap,m,minst) =
x.ParamMetadata |> List.map (fun p -> ImportTypeFromMetadata amap m x.MetadataScope x.ActualTypeInst minst p.Type)
member x.ParamInfos(amap,m,minst) =
x.ParamMetadata |> List.map (fun p -> p.Name, ImportTypeFromMetadata amap m x.MetadataScope x.ActualTypeInst minst p.Type)
member x.EnclosingType = x.ILTypeInfo.ToType
type MethInfo =
| FSMeth of TcGlobals * Tast.typ * ValRef
| ILMeth of TcGlobals * ILMethInfo
| DefaultStructCtor of TcGlobals * Tast.typ
/// Get the enclosing ("parent") type of the method info.
member x.EnclosingType =
match x with
| ILMeth(g,x) -> x.EnclosingType
| FSMeth(g,typ,_) -> typ
| DefaultStructCtor(g,typ) -> typ
type ILFieldInfo =
| ILFieldInfo of ILTypeInfo * ILFieldDef (* .NET IL fields *)
member x.ILTypeInfo = (let (ILFieldInfo(tinfo,_)) = x in tinfo)
member x.RawMetadata = (let (ILFieldInfo(_,pd)) = x in pd)
member x.ScopeRef = x.ILTypeInfo.ILScopeRef
member x.ILTypeRef = x.ILTypeInfo.ILTypeRef
member x.TypeInst = x.ILTypeInfo.TypeInst
member x.FieldName = x.RawMetadata.fdName
member x.IsInitOnly = x.RawMetadata.fdInitOnly
member x.IsValueType = x.ILTypeInfo.IsValueType
member x.IsStatic = x.RawMetadata.fdStatic
member x.LiteralValue = if x.RawMetadata.fdLiteral then x.RawMetadata.fdInit else None
member x.ILFieldRef= rescope_fref x.ScopeRef (mk_fref_in_tref(x.ILTypeRef,x.FieldName,x.RawMetadata.fdType))
type RecdFieldInfo =
| RecdFieldInfo of tinst * Tast.RecdFieldRef (* F# fields *)
member x.TypeInst = let (RecdFieldInfo(tinst,_)) = x in tinst
member x.RecdFieldRef = let (RecdFieldInfo(_,rfref)) = x in rfref
member x.RecdField = x.RecdFieldRef.RecdField
member x.IsStatic = x.RecdField.IsStatic
member x.LiteralValue = x.RecdField.LiteralValue
member x.TyconRef = x.RecdFieldRef.TyconRef
member x.Tycon = x.RecdFieldRef.Tycon
member x.Name = x.RecdField.Name
member x.FieldType = actual_rtyp_of_rfref x.RecdFieldRef x.TypeInst
member x.EnclosingType = TType_app (x.RecdFieldRef.TyconRef,x.TypeInst)
type UnionCaseInfo =
| UnionCaseInfo of tinst * Tast.UnionCaseRef
member x.TypeInst = let (UnionCaseInfo(tinst,_)) = x in tinst
member x.UnionCaseRef = let (UnionCaseInfo(_,ucref)) = x in ucref
member x.UnionCase = x.UnionCaseRef.UnionCase
member x.TyconRef = x.UnionCaseRef.TyconRef
member x.Tycon = x.UnionCaseRef.Tycon
member x.Name = x.UnionCase.DisplayName
type ILPropInfo =
| ILPropInfo of ILTypeInfo * ILPropertyDef
member x.ILTypeInfo = match x with (ILPropInfo(tinfo,_)) -> tinfo
member x.RawMetadata = match x with (ILPropInfo(_,pd)) -> pd
member x.PropertyName = x.RawMetadata.propName
member x.GetterMethod =
assert (x.HasGetter)
let mdef = resolve_mref x.ILTypeInfo.RawMetadata (the x.RawMetadata.propGet)
ILMethInfo(x.ILTypeInfo,None,mdef,[])
member x.SetterMethod =
assert (x.HasSetter)
let mdef = resolve_mref x.ILTypeInfo.RawMetadata (the x.RawMetadata.propSet)
ILMethInfo(x.ILTypeInfo,None,mdef,[])
member x.HasGetter = isSome x.RawMetadata.propGet
member x.HasSetter = isSome x.RawMetadata.propSet
member x.IsStatic = (x.RawMetadata.propCallconv = CC_static)
type PropInfo =
| FSProp of TcGlobals * Tast.typ * ValRef option * ValRef option
| ILProp of TcGlobals * ILPropInfo
type ILEventInfo =
| ILEventInfo of ILTypeInfo * ILEventDef
member x.RawMetadata = match x with (ILEventInfo(_,ed)) -> ed
member x.ILTypeInfo = match x with (ILEventInfo(tinfo,_)) -> tinfo
member x.AddMethod =
let mdef = resolve_mref x.ILTypeInfo.RawMetadata x.RawMetadata.eventAddOn
ILMethInfo(x.ILTypeInfo,None,mdef,[])
member x.RemoveMethod =
let mdef = resolve_mref x.ILTypeInfo.RawMetadata x.RawMetadata.eventRemoveOn
ILMethInfo(x.ILTypeInfo,None,mdef,[])
member x.TypeRef = x.ILTypeInfo.ILTypeRef
member x.Name = x.RawMetadata.eventName
member x.IsStatic = x.AddMethod.IsStatic
type EventInfo =
| FSEvent of TcGlobals * PropInfo * ValRef * ValRef
| ILEvent of TcGlobals * ILEventInfo
/// Copy constraints. If the constraint comes from a type parameter associated
/// with a type constructor then we are simply renaming type variables. If it comes
/// from a generic method in a generic class (e.g. typ.M<_>) then we may be both substituting the
/// instantiation associated with 'typ' as well as copying the type parameters associated with
/// M and instantiating their constraints
///
/// Note: this now looks identical to constraint instantiation.
let CopyTyparConstraints m tprefInst (tporig:Typar) =
tporig.Constraints
|> List.map (fun tpc ->
match tpc with
| TTyparCoercesToType(ty,_) ->
TTyparCoercesToType (InstType tprefInst ty,m)
| TTyparDefaultsToType(priority,ty,_) ->
TTyparDefaultsToType (priority,InstType tprefInst ty,m)
| TTyparSupportsNull _ ->
TTyparSupportsNull m
| TTyparIsEnum(uty,_) ->
TTyparIsEnum (InstType tprefInst uty,m)
| TTyparIsDelegate(aty, bty,_) ->
TTyparIsDelegate (InstType tprefInst aty,InstType tprefInst bty,m)
| TTyparIsNotNullableValueType _ ->
TTyparIsNotNullableValueType m
| TTyparIsReferenceType _ ->
TTyparIsReferenceType m
| TTyparSimpleChoice (tys,_) ->
TTyparSimpleChoice (List.map (InstType tprefInst) tys,m)
| TTyparRequiresDefaultConstructor _ ->
TTyparRequiresDefaultConstructor m
| TTyparMayResolveMemberConstraint(traitInfo,_) ->
TTyparMayResolveMemberConstraint (inst_trait tprefInst traitInfo,m))
/// The constraints for each typar copied from another typar can only be fixed up once
/// we have generated all the new constraints, e.g. f<A :> List<B>, B :> List<A>> ...
let FixupNewTypars m ftctps tinst tpsorig tps =
let renaming,tptys = (mk_typar_to_typar_renaming tpsorig tps)
let tprefInst = (mk_typar_inst ftctps tinst) @ renaming
List.iter2 (fun tporig tp -> fixup_typar_constraints tp (CopyTyparConstraints m tprefInst tporig)) tpsorig tps;
renaming,tptys
//-------------------------------------------------------------------------
// tinfos
//-------------------------------------------------------------------------
let inst_il_tinfo inst (ILTypeInfo(tcref,tref,tinst,tdef)) = ILTypeInfo(tcref,tref,inst_types inst tinst,tdef)
let FormalTyparsOfILTypeInfo m (x:ILTypeInfo) = x.TyconRef.Typars(m)
let tdef_of_il_typ g ty = (tcref_of_stripped_typ g ty).ILTyconRawMetadata
let tinfo_of_il_typ g ty =
if is_il_named_typ g ty then
let tcref,tinst = dest_stripped_tyapp_typ g ty
let scoref,enc,tdef = tcref.ILTyconInfo
let tref = tref_for_nested_tdef scoref (enc,tdef)
ILTypeInfo(tcref,tref,tinst,tdef)
else
failwith "tinfo_of_il_typ"
/// Build IL method infos.
let mk_il_minfo amap m (tinfo:ILTypeInfo) (extInfo:ILTypeRef option) md =
let tinst,scoref =
match extInfo with
| None ->
tinfo.TypeInst,tinfo.ILScopeRef
| Some tref ->
// C# extension methods have no type typars
[], tref.Scope
let mtps = Import.ImportIlTypars (fun () -> amap) m scoref tinst md.mdGenericParams
ILMeth (amap.g,ILMethInfo(tinfo,extInfo, md,mtps))
//-------------------------------------------------------------------------
// il_minfo, il_pinfo
//-------------------------------------------------------------------------
// Get the logical object parameters of a type
let objtys_of_il_minfo amap m (x:ILMethInfo) minst =
// all C# extension methods are instance
if x.IsCSharpExtensionMethod then
x.RawMetadata.Parameters |> List.hd |> (fun p -> [ImportTypeFromMetadata amap m x.MetadataScope x.ActualTypeInst minst p.Type])
elif x.IsInstance then
[x.EnclosingType]
else
[]
let ImportReturnTypeFromMetaData amap m ty scoref tinst minst =
match ty with
| Type_void -> None
| retTy -> Some (ImportTypeFromMetadata amap m scoref tinst minst retTy)
let GetCompiledReturnTyOfILMethod amap m (x:ILMethInfo) minst =
ImportReturnTypeFromMetaData amap m x.RawMetadata.mdReturn.Type x.MetadataScope x.ActualTypeInst minst
let GetFSharpReturnTyOfILMethod amap m minfo minst =
GetCompiledReturnTyOfILMethod amap m minfo minst
|> GetFSharpViewOfReturnType amap.g
let mref_of_il_minfo (minfo:ILMethInfo) =
let mref = mk_mref_to_mdef (minfo.ActualILTypeRef,minfo.RawMetadata)
rescope_mref minfo.MetadataScope mref
let inst_il_minfo amap m inst (x:ILMethInfo) =
mk_il_minfo amap m (inst_il_tinfo inst x.ILTypeInfo) x.ExtensionMethodInfo x.RawMetadata
let il_minfo_is_DllImport g (minfo:ILMethInfo) =
let (AttribInfo(tref,_)) = g.attrib_DllImportAttribute
minfo.RawMetadata.mdCustomAttrs |> ILThingDecodeILAttrib g tref |> isSome
/// Build an expression node that is a call to a .NET method. *)
let mk_il_minfo_call g amap m isProp (minfo:ILMethInfo) vFlags minst direct args =
let isStatic = not (minfo.IsConstructor || minfo.IsInstance)
let valu = minfo.ILTypeInfo.IsValueType
let ctor = minfo.IsConstructor
if minfo.IsClassConstructor then
error (InternalError (minfo.ILName^": cannot call a class constructor",m));
let useCallvirt =
not valu && not direct && minfo.IsVirtual
let isProtected = minfo.IsProtectedAccessibility
let mref = mref_of_il_minfo minfo
let newobj = ctor && (vFlags = NormalValUse)
let exprty = if ctor then minfo.EnclosingType else GetFSharpReturnTyOfILMethod amap m minfo minst
// The thing might be an extension method, in which case adjust the instantiations
let actualTypeInst = minfo.ActualTypeInst
let actualMethInst = minst
let retTy = (if not ctor && (mref.ReturnType = IL.Type_void) then [] else [exprty])
let isDllImport = il_minfo_is_DllImport g minfo
TExpr_op(TOp_ilcall((useCallvirt,isProtected,valu,newobj,vFlags,isProp,isDllImport,None,mref),actualTypeInst,actualMethInst, retTy),[],args,m),
exprty
let mk_obj_ctor_call g m =
let mref = (mk_nongeneric_ctor_mspec(g.ilg.tref_Object,AsObject,[])).MethodRef
TExpr_op(TOp_ilcall((false,false,false,false,CtorValUsedAsSuperInit,false,false,None,mref),[],[],[g.obj_ty]),[],[],m)
//-------------------------------------------------------------------------
// .NET Property Infos
//-------------------------------------------------------------------------
let pdef_accessibility tdef pd =
match pd.propGet with
| Some mref -> (resolve_mref tdef mref).mdAccess
| None ->
match pd.propSet with
None -> MemAccess_public
| Some mref -> (resolve_mref tdef mref).mdAccess
let il_pinfo_is_protected (pinfo:ILPropInfo) =
(pinfo.HasGetter && pinfo.GetterMethod.IsProtectedAccessibility) ||
(pinfo.HasSetter && pinfo.SetterMethod.IsProtectedAccessibility)
let il_pinfo_is_virt (pinfo:ILPropInfo) =
(pinfo.HasGetter && pinfo.GetterMethod.IsVirtual) ||
(pinfo.HasSetter && pinfo.SetterMethod.IsVirtual)
let il_pinfo_is_newslot (pinfo:ILPropInfo) =
(pinfo.HasGetter && pinfo.GetterMethod.IsNewSlot) ||
(pinfo.HasSetter && pinfo.SetterMethod.IsNewSlot)
let il_pinfo_is_abstract (pinfo:ILPropInfo) =
(pinfo.HasGetter && pinfo.GetterMethod.IsAbstract) ||
(pinfo.HasSetter && pinfo.SetterMethod.IsAbstract)
let params_of_il_pinfo amap m (ILPropInfo (tinfo,pdef)) =
pdef.propArgs |> List.map (fun ty -> None, ImportTypeFromMetadata amap m tinfo.ILScopeRef tinfo.TypeInst [] ty)
let vtyp_of_il_pinfo amap m (ILPropInfo(tinfo,pdef)) =
ImportTypeFromMetadata amap m tinfo.ILScopeRef tinfo.TypeInst [] pdef.propType
//-------------------------------------------------------------------------
// .NET Event Infos
//-------------------------------------------------------------------------
let edef_accessibility tdef ed = (resolve_mref tdef ed.eventAddOn).mdAccess
let DelegateTypeOfILEventInfo amap m (ILEventInfo(tinfo,edef)) =
ImportTypeFromMetadata amap m tinfo.ILScopeRef tinfo.TypeInst [] (the edef.eventType)
//-------------------------------------------------------------------------
// Testing equality & calculating hash codes of method/prop/event infos
//-------------------------------------------------------------------------
/// Do two minfos have the same underlying definitions?
/// Used to merge operator overloads collected from left and right of an operator constraint
let MethInfosUseIdenticalDefinitions g x1 x2 =
match x1,x2 with
| ILMeth(g,x1), ILMeth(_,x2) -> (x1.RawMetadata === x2.RawMetadata)
| FSMeth(g,ty1,vref1), FSMeth(_,ty2,vref2) -> g.vref_eq vref1 vref2
| DefaultStructCtor(g,ty1), DefaultStructCtor(_,ty2) -> tcref_eq g (tcref_of_stripped_typ g ty1) (tcref_of_stripped_typ g ty2)
| _ -> false
/// Tests whether two property infos have the same underlying defintion
/// (uses the same techniques as pervious 'MethInfosUseIdenticalDefinitions')
let PropInfosUseIdenticalDefinitions x1 x2 =
let optVrefEq g = function
| Some(v1), Some(v2) -> g.vref_eq v1 v2
| None, None -> true
| _ -> false
match x1,x2 with
| ILProp(g, x1), ILProp(_, x2) -> (x1.RawMetadata === x2.RawMetadata)
| FSProp(g, ty1, vrefa1, vrefb1), FSProp(_, ty2, vrefa2, vrefb2) ->
(optVrefEq g (vrefa1, vrefa2)) && (optVrefEq g (vrefb1, vrefb2))
| _ -> false
/// Test whether two event infos have the same underlying defintion (similar as above)
let EventInfosUseIdenticalDefintions x1 x2 =
match x1, x2 with
| FSEvent(g, pi1, vrefa1, vrefb1), FSEvent(_, pi2, vrefa2, vrefb2) ->
PropInfosUseIdenticalDefinitions pi1 pi2 && g.vref_eq vrefa1 vrefa2 && g.vref_eq vrefb1 vrefb2
| ILEvent(g, x1), ILEvent(_, x2) -> (x1.RawMetadata === x2.RawMetadata)
| _ -> false
/// Calculates a hash code of method info. Note: this is a very imperfect implementation,
/// but it works decently for comparing methods in the language service...
let GetMethInfoHashCode mi =
match mi with
| ILMeth(_,x1) -> hash x1.RawMetadata.Name
| FSMeth(_,_,vref) -> hash vref.CompiledName
| DefaultStructCtor(_,ty) -> hash ty
/// Calculates a hash code of property info (similar as previous)
let GetPropInfoHashCode mi =
match mi with
| ILProp(_, x1) -> hash x1.RawMetadata.Name
| FSProp(_,_,vrefOpt1, vrefOpt2) ->
// Value to hash is option<string>*option<string>, which can be hashed efficiently
let vth = vrefOpt1 |> Option.map (fun vr -> vr.CompiledName), vrefOpt2 |> Option.map (fun vr -> vr.CompiledName)
hash(vth)
/// Calculates a hash code of event info (similar as previous)
let GetEventInfoHashCode mi =
match mi with
| ILEvent(_, x1) -> hash x1.RawMetadata.Name
| FSEvent(_, pi, vref1, vref2) -> hash (GetPropInfoHashCode pi, vref1.CompiledName, vref2.CompiledName)
//-------------------------------------------------------------------------
// minfo, pinfo
//-------------------------------------------------------------------------
/// Apply a type instantiation to a method info, i.e. apply the instantiation to the enclosing type.
let InstMethInfo amap m inst = function
| ILMeth(g,x) -> inst_il_minfo amap m inst x
| FSMeth(g,typ,vref) -> FSMeth(g,InstType inst typ,vref)
| DefaultStructCtor(g,typ) -> DefaultStructCtor(g,InstType inst typ)
let AnalyzeTypeOfMemberVal g (typ,vref) =
(* if vref.RecursiveValInfo then retTy else *)
let tps,_,retTy,_ = GetTypeOfMemberInMemberForm g vref
let parentTyargs = tinst_of_stripped_typ g typ
let memberParentTypars,memberMethodTypars = List.chop parentTyargs.Length tps
memberParentTypars,memberMethodTypars,retTy,parentTyargs
type MethInfo with
member x.LogicalName =
match x with
| ILMeth(g,y) -> y.ILName
| FSMeth(_,_,vref) -> vref.MemberInfo.Value.LogicalName
| DefaultStructCtor _ -> ".ctor"
member x.ActualTypeInst =
match x with
| ILMeth(g,y) -> y.ActualTypeInst
| FSMeth(g,_,_) | DefaultStructCtor(g,_) -> tinst_of_stripped_typ g x.EnclosingType
member x.FormalMethodTypars =
match x with
| ILMeth(g,ILMethInfo(tinfo,extInfo,_,mtps)) -> mtps
| FSMeth(g,typ,vref) ->
let _,mtps,_,_ = AnalyzeTypeOfMemberVal g (typ,vref)
mtps
| DefaultStructCtor _ -> []
member x.FormalMethodInst = generalize_typars x.FormalMethodTypars
member x.XmlDoc =
match x with
| ILMeth(_,x) -> emptyXmlDoc
| FSMeth(_,_,vref) -> vref.XmlDoc
| DefaultStructCtor _ -> emptyXmlDoc
member x.ArbitraryValRef =
match x with
| ILMeth(g,x) -> None
| FSMeth(g,_,vref) -> Some(vref)
| DefaultStructCtor _ -> None
let mk_fs_minfo_tinst ttps mtps tinst minst = (mk_typar_inst ttps tinst @ mk_typar_inst mtps minst)
let CompiledReturnTyOfMeth amap m minfo minst =
match minfo with
| ILMeth(g,ilminfo) -> GetCompiledReturnTyOfILMethod amap m ilminfo minst
| FSMeth(g,typ,vref) ->
let ttps,mtps,retTy,tinst = AnalyzeTypeOfMemberVal g (typ,vref)
Option.map (InstType (mk_fs_minfo_tinst ttps mtps tinst minst)) retTy
| DefaultStructCtor _ -> None
let FSharpReturnTyOfMeth amap m minfo minst =
CompiledReturnTyOfMeth amap m minfo minst |> GetFSharpViewOfReturnType amap.g
let ParamOfArgInfo (ty,TopArgInfo(_,id)) = (Option.map text_of_id id,ty)
let ParamsOfMember g vref = ArgInfosOfMember g vref |> List.mapSquared ParamOfArgInfo
let InstParam inst param =
map2'2 (InstType inst) param
let InstParams inst paramTypes =
paramTypes |> List.mapSquared (InstParam inst)
let ParamTypesOfMethInfo amap m minfo minst =
match minfo with
| ILMeth(g,ilminfo) ->
[ ilminfo.ArgTypes(amap,m,minst) ]
| FSMeth(g,typ,vref) ->
let ttps,mtps,_,tinst = AnalyzeTypeOfMemberVal g (typ,vref)
let paramTypes = ParamsOfMember g vref
let inst = (mk_fs_minfo_tinst ttps mtps tinst minst)
paramTypes |> List.mapSquared (snd >> InstType inst)
| DefaultStructCtor _ -> []
let ObjTypesOfMethInfo amap m minfo minst =
match minfo with
| ILMeth(g,ilminfo) -> objtys_of_il_minfo amap m ilminfo minst
| FSMeth(g,typ,vref) -> if vref.IsInstanceMember then [typ] else []
| DefaultStructCtor _ -> []
/// The caller-side value for the optional arg, is any
type OptionalArgCallerSideValue =
| Constant of IL.ILFieldInit
| DefaultValue
| MissingValue
| WrapperForIDispatch
| WrapperForIUnknown
| PassByRef of Tast.typ * OptionalArgCallerSideValue
type OptionalArgInfo =
/// The argument is not optional
| NotOptional
/// The argument is optional, and is an F# callee-side optional arg
| CalleeSide
/// The argument is optional, and is a caller-side .NET optional or default arg
| CallerSide of OptionalArgCallerSideValue
let ParamAttribsOfMethInfo amap m minfo =
match minfo with
| ILMeth(g,x) ->
x.ParamMetadata
|> List.map (fun p ->
let isParamArrayArg = ILThingHasAttrib g.attrib_ParamArrayAttribute p.paramCustomAttrs
let isOutArg = (p.paramOut && not p.paramIn)
(* Note: we get default argument values frmo VB and other .NET language metadata *)
let optArgInfo =
if p.paramOptional then
CallerSide (match p.paramDefault with
| None ->
let rec analyze ty =
if is_byref_typ g ty then
let ty = dest_byref_typ g ty
PassByRef (ty, analyze ty)
elif is_obj_typ g ty then
if ILThingHasAttrib g.attrib_IDispatchConstantAttribute p.paramCustomAttrs then
WrapperForIDispatch
elif ILThingHasAttrib g.attrib_IUnknownConstantAttribute p.paramCustomAttrs then
WrapperForIUnknown
else
MissingValue
else
DefaultValue
analyze (ImportTypeFromMetadata amap m x.MetadataScope x.ActualTypeInst [] p.Type)
| Some v -> Constant v)
else NotOptional
(isParamArrayArg, isOutArg, optArgInfo))
|> List.singleton
| FSMeth(g,_,vref) ->
vref
|> ArgInfosOfMember g
|> List.mapSquared (fun (ty,TopArgInfo(attrs,nm)) ->
let isParamArrayArg = HasAttrib g g.attrib_ParamArrayAttribute attrs
// Design Suggestion 1427: Can't specify "out" args in F#
let isOutArg = false
let isOptArg = HasAttrib g g.attrib_OptionalArgumentAttribute attrs
// Note: can't specify caller-side default arguments in F#, by design (default is specified on the callee-side)
let optArgInfo = if isOptArg then CalleeSide else NotOptional
(isParamArrayArg,isOutArg,optArgInfo))
| DefaultStructCtor _ ->
[[]]
// REVIEW: should attributes always be empty here?
let mk_slotparam (ty,TopArgInfo(attrs,nm)) = TSlotParam(Option.map text_of_id nm, ty, false,false,false,attrs)
let mk_slotsig (nm,typ,ctps,mtps,paraml,retTy) = copy_slotsig (TSlotSig(nm,typ,ctps,mtps,paraml, retTy))
// slotsigs must contain the formal types for the arguments and return type
// a _formal_ 'void' return type is represented as a 'unit' type.
// slotsigs are independent of instantiation: if an instantiation
// happens to make the return type 'unit' (i.e. it was originally a variable type
// then that does not correspond to a slotsig compiled as a 'void' return type.
// REVIEW: should we copy down attributes to slot params?
let SlotsigOfILMethInfo g amap m (ILMethInfo(tinfo,_,mdef,filmtps)) =
let tcref = tcref_of_stripped_typ g tinfo.ToType
let filtctps = tcref.Typars(m)
let ftctps = CopyTypars filtctps
let _,ftctptys = FixupNewTypars m [] [] filtctps ftctps
let ftinfo = tinfo_of_il_typ g (TType_app(tcref,ftctptys))
let fmtps = CopyTypars filmtps
let _,fmtptys = FixupNewTypars m ftctps ftctptys filmtps fmtps
let frty = ImportReturnTypeFromMetaData amap m mdef.mdReturn.Type ftinfo.ILScopeRef ftinfo.TypeInst fmtptys
let fparams =
[ mdef.mdParams |> List.map (fun p ->
TSlotParam(p.paramName, ImportTypeFromMetadata amap m ftinfo.ILScopeRef ftinfo.TypeInst fmtptys p.Type,p.paramIn, p.paramOut, p.paramOptional,[])) ]
mk_slotsig(mdef.mdName,tinfo.ToType,ftctps, fmtps,fparams, frty)
let SlotSigOfMethodInfo amap m minfo =
match minfo with
| ILMeth(g,x) -> SlotsigOfILMethInfo g amap m x
| FSMeth(g,typ,vref) ->
match vref.RecursiveValInfo with
| ValInRecScope(false) -> error(Error("Invalid recursive reference to an abstract slot",m));
| _ -> ()
let tps,_,retTy,_ = GetTypeOfMemberInMemberForm g vref
let ctps = (tcref_of_stripped_typ g typ).Typars(m)
let ctpsorig,fmtps = List.chop ctps.Length tps
let crenaming,_ = mk_typar_to_typar_renaming ctpsorig ctps
let fparams =
vref
|> ArgInfosOfMember g
//|> (function [argInfos] -> argInfos | _ -> error(Error("An abstract slot may not have a curried type. Use a type 'M : arg1 * ... * argN -> result'",m)))
|> List.mapSquared (map1'2 (InstType crenaming) >> mk_slotparam )
let frty = Option.map (InstType crenaming) retTy
mk_slotsig(minfo.LogicalName,minfo.EnclosingType,ctps,fmtps,fparams, frty)
| DefaultStructCtor _ -> error(InternalError("no slotsig for DefaultStructCtor",m))
// The slotsig returned by SlotSigOfMethodInfo is in terms of the type parameters on the parent type of the overriding method,
//
// Reverse-map the slotsig so it is in terms of the type parameters for the overriding method
let ReparentSlotSigToUseMethodTypars g amap m ovByMethValRef slotsig =
match PartitionValRefTypars g ovByMethValRef with
| Some(_,ctps,_,_,_) ->
let parentToMemberInst,_ = mk_typar_to_typar_renaming (ovByMethValRef.MemberApparentParent.Typars(m)) ctps
let res = inst_slotsig parentToMemberInst slotsig
if verbose then dprintf "adjust slot %s, #parentToMemberInst = %d, before = %s, after = %s\n" (Layout.showL (ValRefL ovByMethValRef)) (List.length parentToMemberInst) (Layout.showL(SlotSigL slotsig)) (Layout.showL(SlotSigL res));
res
| None ->
(* Note: it appears PartitionValRefTypars should never return 'None' *)
slotsig
type MethInfo with
member x.NumArgs =
match x with
| ILMeth(g,x) -> [x.NumParams]
| FSMeth(g,_,vref) -> ParamsOfMember g vref |> List.map List.length
| DefaultStructCtor _ -> [0]
/// Does the method appear to the user as an instance method?
member x.IsInstance =
match x with
| ILMeth(g,x) -> x.IsInstance
| FSMeth(g,_,vref) -> vref.IsInstanceMember
| DefaultStructCtor _ -> false
member x.GenericArity =
match x with
| ILMeth(g,x) -> x.GenericArity
| FSMeth(g,typ,vref) ->
let _,mtps,_,_ = AnalyzeTypeOfMemberVal g (typ,vref)
mtps.Length
| DefaultStructCtor _ -> 0
member x.IsProtectedAccessiblity =
match x with
| ILMeth(g,x) -> x.IsProtectedAccessibility
| FSMeth _ -> false
| DefaultStructCtor _ -> false
member x.IsVirtual =
match x with
| ILMeth(g,x) -> x.IsVirtual
| FSMeth(g,_,vref) -> MemberRefIsVirtual vref
| DefaultStructCtor _ -> false
member x.IsConstructor =
match x with
| ILMeth(g,x) -> x.IsConstructor
| FSMeth(g,_,vref) ->
let flags = (the (vref.MemberInfo)).MemberFlags
(flags.MemberKind = MemberKindConstructor)
| DefaultStructCtor _ -> true
member x.IsClassConstructor =
match x with
| ILMeth(g,x) -> x.IsClassConstructor
| FSMeth _ -> false
| DefaultStructCtor _ -> false
// REVIEW: check this for consistency between IL and F# metadata
member x.IsDispatchSlot =
match x with
| ILMeth(g,x) ->
x.IsVirtual
| FSMeth(g,_,vref) as x ->
is_interface_typ g x.EnclosingType ||
(let membInfo = (the (vref.MemberInfo))
membInfo.MemberFlags.MemberIsDispatchSlot)
| DefaultStructCtor _ -> false
member x.IsFinal =
not x.IsVirtual ||
match x with
| ILMeth(g,x) -> x.IsFinal
| FSMeth(g,_,vref) as x -> false
| DefaultStructCtor _ -> true
member x.IsAbstract =
match x with
| ILMeth(g,x) -> x.IsAbstract
| FSMeth(g,_,vref) as x ->
is_interface_typ g x.EnclosingType ||
MemberRefIsAbstract vref
| DefaultStructCtor _ -> false
member x.TcGlobals =
match x with
| ILMeth(g,_) -> g
| FSMeth(g,_,_) -> g
| DefaultStructCtor (g,_) -> g
member x.IsNewSlot =
is_interface_typ x.TcGlobals x.EnclosingType ||
(x.IsVirtual &&
(match x with
| ILMeth(g,x) -> x.IsNewSlot
| FSMeth(g,_,vref) -> MemberRefIsDispatchSlot vref
| DefaultStructCtor _ -> false))
member x.IsDefiniteFSharpOverride =
match x with
| ILMeth(g,x) -> false
| FSMeth(g,_,vref) -> MemberRefIsDefiniteFSharpOverride vref
| DefaultStructCtor _ -> false
member x.IsExtensionMember =
match x with
| ILMeth(g,x) -> x.ExtensionMethodInfo.IsSome
| FSMeth(g,_,vref) -> vref.IsExtensionMember
| DefaultStructCtor _ -> false
member x.IsFSharpEventProperty =
match x with
| FSMeth(g,_,vref) -> vref.IsFSharpEventProperty(g)
| _ -> false
/// Type-qualified static property accessors for properties commonly used as first-class values
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module MethInfo =
let IsVirtual(m:MethInfo) = m.IsVirtual
let IsNewSlot(m:MethInfo) = m.IsNewSlot
let IsDefiniteFSharpOverride(m:MethInfo) = m.IsDefiniteFSharpOverride
let LogicalName(m:MethInfo) = m.LogicalName
let minfo_is_nullary (minfo:MethInfo) = (minfo.NumArgs = [0])
let minfo_is_struct g (x:MethInfo) = x.EnclosingType|> is_struct_typ g
type PropInfo with
member x.PropertyName =
match x with
| ILProp(_,x) -> x.PropertyName
| FSProp(_,typ,Some vref,_)
| FSProp(_,typ,_, Some vref) ->
PropertyNameOfMemberValRef vref
| FSProp _ -> failwith "unreachable"
member x.GetterMethod =
match x with
| ILProp(g,x) -> ILMeth(g,x.GetterMethod)
| FSProp(g,typ,Some vref,_) -> FSMeth(g,typ,vref)
| FSProp _ -> failwith "no getter method"
member x.SetterMethod =
match x with
| ILProp(g,x) -> ILMeth(g,x.SetterMethod)
| FSProp(g,typ,_,Some vref) -> FSMeth(g,typ,vref)
| FSProp _ -> failwith "no setter method"
member x.HasGetter =
match x with
| ILProp(_,x) -> x.HasGetter
| FSProp(_,_,x,_) -> isSome x
member x.HasSetter =
match x with
| ILProp(_,x) -> x.HasSetter
| FSProp(_,_,_,x) -> isSome x
member x.EnclosingType =
match x with
| ILProp(_,x) -> x.ILTypeInfo.ToType
| FSProp(_,typ,_,_) -> typ
/// True if the getter (or, if absent, the setter) is a virtual method
// REVIEW: for IL properties this is getter OR setter. For F# properties it is getter ELSE setter
member x.IsVirtualProperty =
match x with
| ILProp(_,x) -> il_pinfo_is_virt x
| FSProp(_,typ,Some vref,_)
| FSProp(_,typ,_, Some vref) -> MemberRefIsVirtual vref
| FSProp _-> failwith "unreachable"
// REVIEW: this doesn't accord precisely with the IsNewSlot definition for members
member x.IsNewSlot =
match x with
| ILProp(_,x) -> il_pinfo_is_newslot x
| FSProp(_,typ,Some vref,_)
| FSProp(_,typ,_, Some vref) -> MemberRefIsDispatchSlot vref
| FSProp(_,_,None,None) -> failwith "unreachable"
/// True if the getter (or, if absent, the setter) for the property is a dispatch slot
// REVIEW: for IL properties this is getter OR setter. For F# properties it is getter ELSE setter
member x.IsDispatchSlot =
match x with
| ILProp(_,x) -> il_pinfo_is_virt x
| FSProp(g,typ,Some vref,_)
| FSProp(g,typ,_, Some vref) ->
is_interface_typ g typ ||
(let membInfo = (the (vref.MemberInfo))
membInfo.MemberFlags.MemberIsDispatchSlot)
| FSProp _ -> failwith "unreachable"
member x.IsAbstract =
match x with
| ILProp(_,x) -> il_pinfo_is_abstract x
| FSProp(_,typ,Some vref,_)
| FSProp(_,typ,_, Some vref) -> MemberRefIsAbstract vref
| FSProp _ -> failwith "unreachable"
member x.IsStatic =
match x with
| ILProp(_,x) -> x.IsStatic
| FSProp(_,_,Some vref,_)
| FSProp(_,_,_, Some vref) -> not vref.IsInstanceMember
| FSProp(_,_,None,None) -> failwith "unreachable"
member x.IsDefiniteFSharpOverride =
match x with
| ILProp _ -> false
| FSProp(_,_,Some vref,_)
| FSProp(_,_,_,Some vref) -> MemberRefIsDefiniteFSharpOverride vref
| FSProp(_,_,None,None) -> failwith "unreachable"
member x.IsIndexer =
match x with
| ILProp(_,ILPropInfo(tinfo,pdef)) -> pdef.propArgs <> []
| FSProp(g,typ,Some vref,_) ->
// A getter has signature { OptionalObjectType } -> Unit -> PropertyType
// A getter indexer has signature { OptionalObjectType } -> TupledIndexerArguments -> PropertyType
let arginfos = ArgInfosOfMember g vref
arginfos.Length = 1 && arginfos.Head.Length >= 1
| FSProp(g,typ,_, Some vref) ->
// A setter has signature { OptionalObjectType } -> PropertyType -> Void
// A setter indexer has signature { OptionalObjectType } -> TupledIndexerArguments -> PropertyType -> Void
let arginfos = ArgInfosOfMember g vref
arginfos.Length = 1 && arginfos.Head.Length >= 2
| FSProp(_,typ,None,None) ->
failwith "unreachable"
member x.IsFSharpEventProperty =
match x with
| FSProp(g,typ,Some vref,None) -> vref.IsFSharpEventProperty(g)
| _ -> false
member x.XmlDoc =
match x with
| ILProp(_,x) -> emptyXmlDoc
| FSProp(_,typ,Some vref,_)
| FSProp(_,typ,_, Some vref) -> vref.XmlDoc
| FSProp(_,typ,None,None) -> failwith "unreachable"
member x.IsValueType =
match x with
| ILProp(g,_) -> x.EnclosingType |> is_struct_typ g
| FSProp(g,_,_,_) -> x.EnclosingType |> is_struct_typ g
member x.ArbitraryValRef =
match x with
| ILProp(_,x) -> None
| FSProp(_,typ,Some vref,_)
| FSProp(_,typ,_, Some vref) -> Some(vref)
| FSProp(_,typ,None,None) -> failwith "unreachable"
/// Type-qualified static property accessors for properties commonly used as first-class values
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module PropInfo =
let HasGetter(m:PropInfo) = m.HasGetter
let IsVirtualProperty(m:PropInfo) = m.IsVirtualProperty
let IsDefiniteFSharpOverride(m:PropInfo) = m.IsDefiniteFSharpOverride
let IsNewSlot(m:PropInfo) = m.IsNewSlot
let HasSetter(m:PropInfo) = m.HasSetter
let EnclosingType(m:PropInfo) = m.EnclosingType
let PropertyName(m:PropInfo) = m.PropertyName
let ParamNamesAndTypesOfPropInfo amap m = function
| ILProp (_,x) -> params_of_il_pinfo amap m x
| FSProp (g,typ,Some vref,_)
| FSProp (g,typ,_,Some vref) ->
let ttps,mtps,retTy,tinst = AnalyzeTypeOfMemberVal amap.g (typ,vref)
let inst = mk_typar_inst ttps tinst
ArgInfosOfPropertyVal g (deref_val vref) |> List.map (ParamOfArgInfo >> InstParam inst)
| FSProp _ -> failwith "param_typs_of_pinfo: unreachable"
let PropertyTypeOfPropInfo amap m = function
| ILProp (_,x) -> vtyp_of_il_pinfo amap m x
| FSProp (g,typ,Some vref,_)
| FSProp (g,typ,_,Some vref) ->
let ttps,mtps,retTy,tinst = AnalyzeTypeOfMemberVal amap.g (typ,vref)
let inst = mk_typar_inst ttps tinst
ReturnTypeOfPropertyVal g (deref_val vref)
|> InstType inst
| FSProp _ -> failwith "vtyp_typs_of_pinfo: unreachable"
let ParamTypesOfPropInfo amap m pinfo = List.map snd (ParamNamesAndTypesOfPropInfo amap m pinfo)
/// Used to hide/filter members from super classes based on signature *)
let PropInfosEquivByNameAndPartialSig erasureFlag g amap m (pinfo:PropInfo) (pinfo2:PropInfo) =
pinfo.PropertyName = pinfo2.PropertyName &&
let argtys = ParamTypesOfPropInfo amap m pinfo
let argtys2 = ParamTypesOfPropInfo amap m pinfo2
List.lengthsEqAndForall2 (type_equiv_aux erasureFlag g) argtys argtys2
//-------------------------------------------------------------------------
// events
//-------------------------------------------------------------------------
exception BadEventTransformation of range
/// Properties compatible with type IDelegateEvent and atributed with CLIEvent are special: we generate metadata and add/remove methods
/// to make them into a .NET event, and mangle the name of a property.
/// We don't handle static, indexer or abstract properties correctly.
/// Note the name mangling doesn't affect the name of the get/set methods for the property
/// and so doesn't affect how we compile F# accesses to the property.
let TypConformsToIDelegateEvent g ty =
is_fslib_IDelegateEvent_ty g ty && is_delegate_typ g (dest_fslib_IDelegateEvent_ty g ty)
/// Create an error object to raise should an event not have the shape expected by the .NET idiom described further below
let nonStandardEventError nm m =
Error ("The event '"^nm^" has a non-standard type. If this event is declared in another .NET language, you may need to access this event using the explicit add_"^nm^" and remove_"^nm^" methods for the event. If this event is declared in F#, make the type of the event an instantiation of either 'IDelegateEvent<_>' or 'IEvent<_,_>'",m)
let FindDelegateTypeOfPropertyEvent g amap nm m ty =
match SearchEntireHierarchyOfType (TypConformsToIDelegateEvent g) g amap m ty with
| None -> error(nonStandardEventError nm m)
| Some ty -> dest_fslib_IDelegateEvent_ty g ty
type EventInfo with
member x.EventName = match x with ILEvent(_,e) -> e.Name | FSEvent (_,p,_,_) -> p.PropertyName
member x.IsStatic = match x with ILEvent(_,e) -> e.IsStatic | FSEvent (_,p,_,_) -> p.IsStatic
member x.GetDelegateType(amap,m) =
match x with
| ILEvent(_,e) ->
if isNone e.RawMetadata.eventType then error (nonStandardEventError x.EventName m);
DelegateTypeOfILEventInfo amap m e
| FSEvent(g,p,_,_) ->
FindDelegateTypeOfPropertyEvent g amap x.EventName m (PropertyTypeOfPropInfo amap m p)
member x.IsValueType =
match x with
| ILEvent(_,e) -> e.ILTypeInfo.IsValueType
| FSEvent (_,p,_,_) -> p.IsValueType
member x.GetAddMethod(m) =
match x with
| ILEvent(g,e) -> ILMeth(g,e.AddMethod)
| FSEvent(g,p,addValRef,_) -> FSMeth(g,p.EnclosingType,addValRef)
member x.GetRemoveMethod(m) =
match x with
| ILEvent(g,e) -> ILMeth(g,e.RemoveMethod)
| FSEvent(g,p,_,removeValRef) -> FSMeth(g,p.EnclosingType,removeValRef)
//-------------------------------------------------------------------------
// finfo
//-------------------------------------------------------------------------
let FieldTypeOfILFieldInfo amap m (ILFieldInfo (tinfo,fdef)) =
ImportTypeFromMetadata amap m tinfo.ILScopeRef tinfo.TypeInst [] fdef.fdType
type ParamData = ParamData of bool * bool * OptionalArgInfo * string option * typ
let ParamDatasOfMethInfo amap m minfo minst =
let paramInfos =
match minfo with
| ILMeth(g,ilminfo) ->
[ ilminfo.ParamInfos(amap,m,minst) ]
| FSMeth(g,typ,vref) ->
let ttps,mtps,_,tinst = AnalyzeTypeOfMemberVal g (typ,vref)
let paramTypes = ParamsOfMember g vref
let inst = (mk_fs_minfo_tinst ttps mtps tinst minst)
paramTypes |> InstParams inst
| DefaultStructCtor _ ->
[[]]
let paramAttribs = ParamAttribsOfMethInfo amap m minfo
(paramAttribs,paramInfos) ||> List.map2 (List.map2 (fun (isParamArrayArg,isOutArg,optArgInfo) (nmOpt,pty)->
ParamData(isParamArrayArg,isOutArg,optArgInfo,nmOpt,pty)))
//-------------------------------------------------------------------------
// Printing
//-------------------------------------------------------------------------
let FormatMethArgToBuffer denv os (ParamData(isParamArrayArg,isOutArg,optArgInfo,nmOpt,pty)) =
let isOptArg = optArgInfo <> NotOptional
match nmOpt, isOptArg, try_dest_option_ty denv.g pty with
// Layout an optional argument
| Some(nm), true, Some(pty) ->
bprintf os "?%s: %a" nm (NicePrint.output_typ denv) pty
// Layout an unnamed argument
| None, _,_ ->
bprintf os "%a" (NicePrint.output_typ denv) pty;
// Layout a named argument
| Some nm,_,_ ->
bprintf os "%s: %a" nm (NicePrint.output_typ denv) pty
let FormatMethInfoToBuffer amap m denv os minfo =
match minfo with
| DefaultStructCtor(g,typ) ->
bprintf os "%a()" (NicePrint.output_tcref denv) (tcref_of_stripped_typ g minfo.EnclosingType);
| FSMeth(g,_,vref) ->
NicePrint.output_qualified_val_spec denv os (deref_val vref)
| ILMeth(g,ilminfo) ->
// Prettify this baby
let minfo,minst =
let (ILMethInfo(ILTypeInfo(tcref,tref,tinst,tdef),extInfo,mdef,filmtps)) = ilminfo
let _,tys,_ = PrettyTypes.PrettifyTypesN g (tinst @ minfo.FormalMethodInst)
let tinst,minst = List.chop tinst.Length tys
let minfo = mk_il_minfo amap m (ILTypeInfo(tcref,tref,tinst,tdef)) extInfo mdef
minfo,minst
let retTy = FSharpReturnTyOfMeth amap m minfo minst
bprintf os "%a" (NicePrint.output_tcref denv) (tcref_of_stripped_typ g minfo.EnclosingType);
if minfo.LogicalName = ".ctor" then
bprintf os "("
else
bprintf os ".%a(" (NicePrint.output_typars denv minfo.LogicalName) minfo.FormalMethodTypars;
let paramDatas = ParamDatasOfMethInfo amap m minfo minst
paramDatas |> List.iter (List.iteri (fun i arg ->
if i > 0 then bprintf os ", ";
FormatMethArgToBuffer denv os arg))
bprintf os ") : %a" (NicePrint.output_typ denv) retTy
let string_of_minfo amap m denv d = bufs (fun buf -> FormatMethInfoToBuffer amap m denv buf d)
let string_of_param_data denv paramData = bufs (fun buf -> FormatMethArgToBuffer denv buf paramData)
(*-------------------------------------------------------------------------
!* Basic accessibility logic
*------------------------------------------------------------------------- *)
/// What keys do we have to access other constructs?
type AccessorDomain =
| AccessibleFrom of
CompilationPath list * (* we have the keys to access any members private to the given paths *)
TyconRef option (* we have the keys to access any protected members of the super types of 'TyconRef' *)
| AccessibleFromEverywhere
| AccessibleFromSomeFSharpCode // everything but .NET private/internal stuff
| AccessibleFromSomewhere // everything
module AccessibilityLogic =
let private il_tyaccess_accessible access =
access = TypeAccess_public || access = TypeAccess_nested MemAccess_public
let private IsAccessible ad taccess =
match ad with
| AccessibleFromEverywhere -> can_access_from_everywhere taccess
| AccessibleFromSomeFSharpCode -> can_access_from_somewhere taccess
| AccessibleFromSomewhere -> true
| AccessibleFrom (cpaths,tcrefViewedFromOption) ->
(* REVIEW: protected access in F# code *)
List.exists (can_access_from taccess) cpaths
let private CheckILMemberAccess g amap m (ILTypeInfo(tcrefOfViewedItem,_,_,_)) ad access =
match ad with
| AccessibleFromEverywhere ->
access = MemAccess_public
| AccessibleFromSomeFSharpCode ->
(access = MemAccess_public ||
access = MemAccess_family ||
access = MemAccess_famorassem)
| AccessibleFrom (cpaths,tcrefViewedFromOption) ->
let accessibleByFamily =
((access = MemAccess_family ||
access = MemAccess_famorassem) &&
match tcrefViewedFromOption with
| None -> false
| Some tcrefViewedFrom ->
ExistsInEntireHierarchyOfType (fun typ -> is_stripped_tyapp_typ g typ && tcref_eq g (tcref_of_stripped_typ g typ) tcrefOfViewedItem) g amap m (generalize_tcref tcrefViewedFrom |> snd))
let accessibleByInternalsVisibleTo =
(access = MemAccess_assembly && can_access_cpath_from_one_of cpaths tcrefOfViewedItem.CompilationPath)
(access = MemAccess_public) || accessibleByFamily || accessibleByInternalsVisibleTo
| AccessibleFromSomewhere ->
true
let private tdef_accessible tdef =
il_tyaccess_accessible tdef.tdAccess
// is tcref visible through the AccessibleFrom(cpaths,_)? note: InternalsVisibleTo extends those cpaths.
let private tcref_accessible_via_visible_to ad (tcrefOfViewedItem:TyconRef) =
match ad with
| AccessibleFromEverywhere | AccessibleFromSomewhere | AccessibleFromSomeFSharpCode -> false
| AccessibleFrom (cpaths,tcrefViewedFromOption) ->
can_access_cpath_from_one_of cpaths tcrefOfViewedItem.CompilationPath
let private il_tinfo_accessible ad (ILTypeInfo(tcrefOfViewedItem,_,tinst,tdef)) =
tdef_accessible tdef || tcref_accessible_via_visible_to ad tcrefOfViewedItem
let private il_mem_accessible g amap m ad tinfo access =
il_tinfo_accessible ad tinfo && CheckILMemberAccess g amap m tinfo ad access
let IsEntityAccessible ad (tcref:TyconRef) =
if tcref.IsILTycon then
(tcref_accessible_via_visible_to ad tcref) || // either: visibleTo (e.g. InternalsVisibleTo)
(let scoref,enc,tdef = tcref.ILTyconInfo // or: accessible, along with all enclosing types
List.forall tdef_accessible enc &&
tdef_accessible tdef)
else
tcref.Accessibility |> IsAccessible ad
let CheckTyconAccessible m ad tcref =
let res = IsEntityAccessible ad tcref
if not res then
errorR(Error("The type '"^tcref.DisplayName^"' is not accessible from this code location",m))
res
let IsTyconReprAccessible ad tcref =
IsEntityAccessible ad tcref &&
IsAccessible ad tcref.TypeReprAccessibility
let CheckTyconReprAccessible m ad tcref =
CheckTyconAccessible m ad tcref &&
(let res = IsAccessible ad tcref.TypeReprAccessibility
if not res then
errorR (Error ("The union cases or fields of the type '"^tcref.DisplayName^"' are not accessible from this code location",m));
res)
let rec IsTypeAccessible g ad ty =
not (is_stripped_tyapp_typ g ty) ||
let tcref,tinst = dest_stripped_tyapp_typ g ty
IsEntityAccessible ad tcref && IsTypeInstAccessible g ad tinst
and IsTypeInstAccessible g ad tinst =
match tinst with
| [] -> true
| _ -> List.forall (IsTypeAccessible g ad) tinst
let IsILFieldInfoAccessible g amap m ad (ILFieldInfo (tinfo,fd)) =
il_mem_accessible g amap m ad tinfo fd.fdAccess
let IsILEventInfoAccessible g amap m ad (ILEventInfo (tinfo,edef)) =
il_mem_accessible g amap m ad tinfo (edef_accessibility tinfo.RawMetadata edef)
let IsILMethInfoAccessible g amap m ad (ILMethInfo (tinfo,_,mdef,_)) =
il_mem_accessible g amap m ad tinfo mdef.mdAccess
let IsILPropInfoAccessible g amap m ad (ILPropInfo(tinfo,pdef)) =
il_mem_accessible g amap m ad tinfo (pdef_accessibility tinfo.RawMetadata pdef)
let IsValAccessible ad (vref:ValRef) =
vref.Accessibility |> IsAccessible ad
let CheckValAccessible m ad (vref:ValRef) =
if not (IsValAccessible ad vref) then
errorR (Error ("The value '"^vref.MangledName^"' is not accessible from this code location",m))
let IsUnionCaseAccessible ad (ucref:UnionCaseRef) =
IsTyconReprAccessible ad ucref.TyconRef &&
IsAccessible ad ucref.UnionCase.Accessibility
let CheckUnionCaseAccessible m ad (ucref:UnionCaseRef) =
CheckTyconReprAccessible m ad ucref.TyconRef &&
(let res = IsAccessible ad ucref.UnionCase.Accessibility
if not res then
errorR (Error ("The union case '"^ucref.CaseName^"' is not accessible from this code location",m))
res)
let IsRecdFieldAccessible ad (rfref:RecdFieldRef) =
IsTyconReprAccessible ad rfref.TyconRef &&
IsAccessible ad rfref.RecdField.Accessibility
let CheckRecdFieldAccessible m ad (rfref:RecdFieldRef) =
CheckTyconReprAccessible m ad rfref.TyconRef &&
(let res = IsAccessible ad rfref.RecdField.Accessibility
if not res then
errorR (Error ("The record, struct or class field '"^rfref.FieldName^"' is not accessible from this code location",m))
res)
let CheckRecdFieldInfoAccessible m ad (rfinfo:RecdFieldInfo) =
CheckRecdFieldAccessible m ad rfinfo.RecdFieldRef |> ignore
let CheckILFieldInfoAccessible g amap m ad finfo =
if not (IsILFieldInfoAccessible g amap m ad finfo) then
errorR (Error (sprintf "The struct or class field '%s' is not accessible from this code location" finfo.FieldName,m))
let IsMethInfoAccessible amap m ad = function
| ILMeth (g,x) -> IsILMethInfoAccessible g amap m ad x
| FSMeth (_,_,vref) -> IsValAccessible ad vref
| DefaultStructCtor(g,typ) -> IsTypeAccessible g ad typ
let IsPropInfoAccessible g amap m ad = function
| ILProp (_,x) -> IsILPropInfoAccessible g amap m ad x
| FSProp (_,_,Some vref,_)
| FSProp (_,_,_,Some vref) -> IsValAccessible ad vref
| _ -> false
open AccessibilityLogic
(*-------------------------------------------------------------------------
!* Check custom attributes
*------------------------------------------------------------------------- *)
exception Obsolete of string * range
module AttributeChecking =
let private bindMethInfoAttributes minfo f1 f2 =
match minfo with
| ILMeth (_,x) -> f1 x.RawMetadata.mdCustomAttrs
| FSMeth (_,_,vref) -> f2 vref.Attribs
| DefaultStructCtor _ -> f2 []
let private checkILAttributes g cattrs m =
let (AttribInfo(tref,_)) = g.attrib_SystemObsolete
match ILThingDecodeILAttrib g tref cattrs with
| Some ([CustomElem_string (Some(msg)) ],_) ->
WarnD(Obsolete(msg,m))
| Some ([CustomElem_string (Some(msg)); CustomElem_bool isError ],_) ->
(if isError then ErrorD else WarnD) (Obsolete(msg,m))
| Some ([CustomElem_string None ],_) ->
WarnD(Obsolete("",m))
| Some _ ->
WarnD(Obsolete("",m))
| None ->
CompleteD
let TryBindMethInfoAttribute g (AttribInfo(atref,_) as attribSpec) minfo f1 f2 =
bindMethInfoAttributes minfo
(fun ilAttribs -> ILThingDecodeILAttrib g atref ilAttribs |> Option.bind f1)
(fun fsAttribs -> TryFindAttrib g attribSpec fsAttribs |> Option.bind f2)
let CheckFSharpAttributes g attribs m =
if isNil attribs then CompleteD
else
(match TryFindAttrib g g.attrib_SystemObsolete attribs with
| Some(Attrib(_,_,[ AttribStringArg(s) ],_,_)) ->
WarnD(Obsolete(s,m))
| Some(Attrib(_,_,[ AttribStringArg(s); AttribBoolArg(isError) ],_,_)) ->
(if isError then ErrorD else WarnD) (Obsolete(s,m))
| Some _ ->
WarnD(Obsolete("", m))
| None ->
CompleteD
) ++ (fun () ->
match TryFindAttrib g g.attrib_OCamlCompatibilityAttribute attribs with
| Some(Attrib(_,_,[ AttribStringArg(s) ],_,_)) ->
WarnD(OCamlCompatibility(s,m))
| Some _ ->
WarnD(OCamlCompatibility("", m))
| None ->
CompleteD
) ++ (fun () ->
match TryFindAttrib g g.attrib_ExperimentalAttribute attribs with
| Some(Attrib(_,_,[ AttribStringArg(s) ],_,_)) ->
WarnD(Experimental(s,m))
| Some _ ->
WarnD(Experimental("This construct is experimental", m))
| _ ->
CompleteD
) ++ (fun () ->
match TryFindAttrib g g.attrib_UnverifiableAttribute attribs with
| Some _ ->
WarnD(PossibleUnverifiableCode(m))
| _ ->
CompleteD
)
let CheckILAttribsForUnseen g cattrs m =
let (AttribInfo(tref,_)) = g.attrib_SystemObsolete
isSome (ILThingDecodeILAttrib g tref cattrs)
let CheckAttribsForUnseen g attribs m =
nonNil attribs &&
(isSome (TryFindAttrib g g.attrib_SystemObsolete attribs) ||
(not g.mlCompatibility && isSome (TryFindAttrib g g.attrib_OCamlCompatibilityAttribute attribs))
)
// REVIEW: consider filter out experimental and unverifiable depending on context
let CheckPropInfoAttributes pinfo m =
match pinfo with
| ILProp(g,ILPropInfo(tinfo,pdef)) -> checkILAttributes g pdef.propCustomAttrs m
| FSProp(g,typ,Some vref,_)
| FSProp(g,typ,_,Some vref) -> CheckFSharpAttributes g vref.Attribs m
| FSProp _ -> failwith "CheckPropInfoAttributes: unreachable"
let CheckILFieldAttributes g (finfo:ILFieldInfo) m =
checkILAttributes g finfo.RawMetadata.fdCustomAttrs m |> CommitOperationResult
let CheckMethInfoAttributes g m minfo =
match bindMethInfoAttributes minfo
(fun ilAttribs -> Some(checkILAttributes g ilAttribs m))
(fun fsAttribs -> Some(CheckFSharpAttributes g fsAttribs m)) with
| Some res -> res
| None -> CompleteD (* no attribute = no errors *)
let MethInfoIsUnseen g m minfo =
match bindMethInfoAttributes minfo
(fun ilAttribs -> Some(CheckILAttribsForUnseen g ilAttribs m))
(fun fsAttribs -> Some(CheckAttribsForUnseen g fsAttribs m)) with
| Some res -> res
| None -> false
let PropInfoIsUnseen m pinfo =
match pinfo with
| ILProp (g,ILPropInfo(tinfo,pdef)) -> CheckILAttribsForUnseen g pdef.propCustomAttrs m
| FSProp (g,typ,Some vref,_)
| FSProp (g,typ,_,Some vref) -> CheckAttribsForUnseen g vref.Attribs m
| FSProp _ -> failwith "CheckPropInfoAttributes: unreachable"
let CheckEntityAttributes g (x:TyconRef) m =
if x.IsILTycon then
let tdef = x.ILTyconRawMetadata
checkILAttributes g tdef.tdCustomAttrs m
else CheckFSharpAttributes g x.Attribs m
let CheckUnionCaseAttributes g (x:UnionCaseRef) m =
CheckEntityAttributes g x.TyconRef m ++ (fun () ->
CheckFSharpAttributes g x.Attribs m)
let CheckRecdFieldAttributes g (x:RecdFieldRef) m =
CheckEntityAttributes g x.TyconRef m ++ (fun () ->
CheckFSharpAttributes g x.PropertyAttribs m)
let CheckValAttributes g (x:ValRef) m =
CheckFSharpAttributes g x.Attribs m
let CheckRecdFieldInfoAttributes g (x:RecdFieldInfo) m =
CheckRecdFieldAttributes g x.RecdFieldRef m
open AttributeChecking
//-------------------------------------------------------------------------
// Build calls to F# methods
//-------------------------------------------------------------------------
/// Consume the arguments in chunks and build applications. This copes with various F# calling signatures
/// all of which ultimately become 'methods'.
/// QUERY: this looks overly complex considering that we are doing a fundamentally simple
/// thing here.
let BuildFSharpMethodApp g m vref vexp vexprty (args: expr list) =
let arities = (arity_of_val (deref_val vref)).AritiesOfArgs
let args3,(leftover,retTy) =
List.mapfold
(fun (args,fty) arity ->
match arity,args with
| (0|1),[] when type_equiv g (domain_of_fun_typ g fty) g.unit_ty -> mk_unit g m, (args, range_of_fun_typ g fty)
| 0,(arg::argst)->
warning(InternalError(sprintf "Unexpected zero arity, args = %s" (Layout.showL (Layout.sepListL (Layout.rightL ";") (List.map ExprL args))),m));
arg, (argst, range_of_fun_typ g fty)
| 1,(arg :: argst) -> arg, (argst, range_of_fun_typ g fty)
| 1,[] -> error(InternalError("expected additional arguments here",m))
| _ ->
if args.Length < arity then error(InternalError("internal error in getting arguments, n = "^string arity^", #args = "^string args.Length,m));
let tupargs,argst = List.chop arity args
let tuptys = tupargs |> List.map (type_of_expr g)
(mk_tupled g m tupargs tuptys),
(argst, range_of_fun_typ g fty) )
(args,vexprty)
arities
if not leftover.IsEmpty then error(InternalError("Unexpected "^string(leftover.Length)^" remaining arguments in method application",m));
mk_appl g ((vexp,vexprty),[],args3,m),
retTy
let BuildFSharpMethodCall g m (typ,vref:ValRef) vFlags minst args =
let vexp = TExpr_val (vref,vFlags,m)
let vexpty = vref.Type
let tpsorig,tau = vref.TypeScheme
let vtinst = tinst_of_stripped_typ g typ @ minst
if tpsorig.Length <> vtinst.Length then error(InternalError("BuildFSharpMethodCall: unexpected List.length mismatch",m));
let expr = mk_tyapp m (vexp,vexpty) vtinst
let exprty = InstType (mk_typar_inst tpsorig vtinst) tau
/// REVIEW: this is passing in the instantiated type. Should this be the formal type?
BuildFSharpMethodApp g m vref expr exprty args
//-------------------------------------------------------------------------
// Sets of methods up the hierarchy, ignoring duplicates by name and sig.
// Used to collect sets of virtual methods, protected methods, protected
// properties etc.
// REVIEW: this code generalizes the iteration used below for member lookup.
// REVIEW: this doesn't take into account newslot decls.
//-------------------------------------------------------------------------
let MemberIsExplicitImpl g (membInfo:ValMemberInfo) =
membInfo.MemberFlags.MemberIsOverrideOrExplicitImpl &&
match membInfo.ImplementedSlotSigs with
| [] -> false
| slotsigs -> slotsigs |> List.forall (fun slotsig -> is_interface_typ g slotsig.ImplementedType )
let SelectFromMemberVals g f (tcref:TyconRef) =
let aug = tcref.TypeContents
aug.tcaug_adhoc |> NameMultiMap.chooseRange (fun vref ->
match vref.MemberInfo with
// The 'when' condition is a workaround for the fact that values providing
// override and interface implementations are published in inferred module types
// These cannot be selected directly via the "." notation.
// However, it certainly is useful to be able to publish these values, as we can in theory
// optimize code to make direct calls to these methods.
| Some membInfo when (not (MemberIsExplicitImpl g membInfo)) ->
f membInfo vref
| _ ->
None)
let checkFilter optFilter nm = match optFilter with None -> true | Some n2 -> nm = n2
let TrySelectMemberVal g optFilter typ membInfo vref =
if checkFilter optFilter membInfo.CompiledName then
let tinst = tinst_of_stripped_typ g typ
let ntinst = List.length tinst
Some(FSMeth(g,typ,vref))
else None
let GetImmediateIntrinsicMethInfosOfType (optFilter,ad) g amap m typ =
let minfos =
if is_il_named_typ g typ then
let tinfo = tinfo_of_il_typ g typ
let mdefs = (match optFilter with None -> dest_mdefs | Some(nm) -> find_mdefs_by_name nm) tinfo.RawMetadata.tdMethodDefs
mdefs |> List.map (mk_il_minfo amap m tinfo None)
elif not (is_stripped_tyapp_typ g typ) then []
else SelectFromMemberVals g (TrySelectMemberVal g optFilter typ) (tcref_of_stripped_typ g typ)
let minfos = minfos |> List.filter (IsMethInfoAccessible amap m ad)
minfos
/// Join up getters and setters which are not associated in the F# data structure
type PropertyCollector(g,amap,m,typ,optFilter,ad) =
let hashIdentity =
Microsoft.FSharp.Collections.HashIdentity.FromFunctions
(PropInfo.PropertyName >> hash)
(fun pinfo1 pinfo2 ->
PropInfosEquivByNameAndPartialSig EraseNone g amap m pinfo1 pinfo2 &&
pinfo1.IsDefiniteFSharpOverride = pinfo2.IsDefiniteFSharpOverride )
let props = new System.Collections.Generic.Dictionary<PropInfo,PropInfo>(hashIdentity)
let add pinfo =
if props.ContainsKey(pinfo) then
match props.[pinfo], pinfo with
| FSProp (_,typ,Some vref1,_), FSProp (_,_,_,Some vref2)
| FSProp (_,typ,_,Some vref2), FSProp (_,_,Some vref1,_) ->
let pinfo = FSProp (g,typ,Some vref1,Some vref2)
props.[pinfo] <- pinfo
| _ ->
// This assert first while editing bad code. We will give a warning later in check.ml
//assert ("unexpected case"= "")
()
else
props.[pinfo] <- pinfo
member x.Collect(membInfo,vref) =
match membInfo.MemberFlags.MemberKind with
| MemberKindPropertyGet ->
let nm = PropertyNameOfMemberValRef vref
let pinfo = FSProp(g,typ,Some vref,None)
if checkFilter optFilter nm && IsPropInfoAccessible g amap m ad pinfo then
add pinfo
| MemberKindPropertySet ->
let nm = PropertyNameOfMemberValRef vref
let pinfo = FSProp(g,typ,None,Some vref)
if checkFilter optFilter nm && IsPropInfoAccessible g amap m ad pinfo then
add pinfo
| _ ->
()
member x.Close() = [ for KeyValue(_,pinfo) in props -> pinfo ]
let GetImmediateIntrinsicPropInfosOfType (optFilter,ad) g amap m typ =
let pinfos =
if is_il_named_typ g typ then
let tinfo = tinfo_of_il_typ g typ
let pdefs = (match optFilter with None -> dest_pdefs | Some(nm) -> find_pdefs nm) tinfo.RawMetadata.tdProperties
pdefs |> List.map (fun pd -> ILProp(g,ILPropInfo(tinfo,pd)))
elif not (is_stripped_tyapp_typ g typ) then []
else
let propCollector = new PropertyCollector(g,amap,m,typ,optFilter,ad)
SelectFromMemberVals g
(fun membInfo vref -> propCollector.Collect(membInfo,vref); None)
(tcref_of_stripped_typ g typ) |> ignore
propCollector.Close()
let pinfos = pinfos |> List.filter (IsPropInfoAccessible g amap m ad)
pinfos
//---------------------------------------------------------------------------
//
//-------------------------------------------------------------------------
type HierarchyItem =
| MethodItem of MethInfo list list
| PropertyItem of PropInfo list list
| RecdFieldItem of RecdFieldInfo
| ILEventItem of ILEventInfo list
| ILFieldItem of ILFieldInfo list
/// An InfoReader is an object to help us read and cache infos.
/// We create one of these for each file we typecheck.
///
/// REVIEW: We could consider sharing one InfoReader across an entire compilation
/// run or have one global one for each (g,amap) pair.
type InfoReader(g:TcGlobals, amap:Import.ImportMap) =
let getImmediateIntrinsicILFieldsOfType (optFilter,ad) m typ =
let infos =
if is_il_named_typ g typ then
let tinfo = tinfo_of_il_typ g typ
let fdefs = (match optFilter with None -> dest_fdefs | Some(nm) -> find_fdefs nm) tinfo.RawMetadata.tdFieldDefs
List.map (fun pd -> ILFieldInfo(tinfo,pd)) fdefs
elif not (is_stripped_tyapp_typ g typ) then []
else []
let infos = infos |> List.filter (IsILFieldInfoAccessible g amap m ad)
infos
let getImmediateIntrinsicILEventsOfType (optFilter,ad) m typ =
let infos =
if is_il_named_typ g typ then
let tinfo = tinfo_of_il_typ g typ
let edefs = (match optFilter with None -> dest_edefs | Some(nm) -> find_edefs nm) tinfo.RawMetadata.tdEvents
List.map (fun pd -> ILEventInfo(tinfo,pd)) edefs
elif not (is_stripped_tyapp_typ g typ) then []
else []
let infos = infos |> List.filter (IsILEventInfoAccessible g amap m ad)
infos
let mk_rfinfo g typ tcref fspec = RecdFieldInfo(tinst_of_stripped_typ g typ,rfref_of_rfield tcref fspec)
let getImmediateIntrinsicRecdFieldsOfType nm typ =
match try_tcref_of_stripped_typ g typ with
| None -> None
| Some tcref ->
(* Note;secret fields are not allowed in lookups here, as we're only looking *)
(* up user-visible fields in name resolution. *)
match tcref.GetFieldByName nm with
| Some rfield when not rfield.IsCompilerGenerated -> Some (mk_rfinfo g typ tcref rfield)
| _ -> None
/// The primitive reader for the method info sets up a hierarchy
let readRawIntrinsicMethodSetsUncached ((optFilter,ad),m,typ) =
FoldPrimaryHierarchyOfType (fun typ acc -> GetImmediateIntrinsicMethInfosOfType (optFilter,ad) g amap m typ :: acc) g amap m typ []
/// The primitive reader for the property info sets up a hierarchy
let readRawIntrinsicPropertySetsUncached ((optFilter,ad),m,typ) =
FoldPrimaryHierarchyOfType (fun typ acc -> GetImmediateIntrinsicPropInfosOfType (optFilter,ad) g amap m typ :: acc) g amap m typ []
let readIlFieldInfosUncached ((optFilter,ad),m,typ) =
FoldPrimaryHierarchyOfType (fun typ acc -> getImmediateIntrinsicILFieldsOfType (optFilter,ad) m typ @ acc) g amap m typ []
let readIlEventInfosUncached ((optFilter,ad),m,typ) =
FoldPrimaryHierarchyOfType (fun typ acc -> getImmediateIntrinsicILEventsOfType (optFilter,ad) m typ @ acc) g amap m typ []
let findRecdFieldInfoUncached (nm,m,typ) =
FoldPrimaryHierarchyOfType (fun typ acc -> match getImmediateIntrinsicRecdFieldsOfType nm typ with None -> acc | Some v -> Some v) g amap m typ None
let readEntireTypeHierachyUncached ((),m,typ) =
FoldEntireHierarchyOfType (fun typ acc -> typ :: acc) g amap m typ []
let readPrimaryTypeHierachyUncached ((),m,typ) =
FoldPrimaryHierarchyOfType (fun typ acc -> typ :: acc) g amap m typ []
/// The primitive reader for the named items up a hierarchy
let readRawIntrinsicNamedItemsUncached ((nm,ad),m,typ) =
let optFilter = Some(nm)
FoldPrimaryHierarchyOfType (fun typ acc ->
let minfos = GetImmediateIntrinsicMethInfosOfType (optFilter,ad) g amap m typ
let pinfos = GetImmediateIntrinsicPropInfosOfType (optFilter,ad) g amap m typ
let finfos = getImmediateIntrinsicILFieldsOfType (optFilter,ad) m typ
let einfos = getImmediateIntrinsicILEventsOfType (optFilter,ad) m typ
let rfinfos = getImmediateIntrinsicRecdFieldsOfType nm typ
match acc with
| Some(MethodItem(inheritedMethSets)) when nonNil minfos -> Some(MethodItem (minfos::inheritedMethSets))
| _ when nonNil minfos -> Some(MethodItem ([minfos]))
| Some(PropertyItem(inheritedPropSets)) when nonNil pinfos -> Some(PropertyItem(pinfos::inheritedPropSets))
| _ when nonNil pinfos -> Some(PropertyItem([pinfos]))
| _ when nonNil finfos -> Some(ILFieldItem(finfos))
| _ when nonNil einfos -> Some(ILEventItem(einfos))
| _ when isSome rfinfos -> Some(RecdFieldItem(rfinfos.Value))
| _ -> acc)
g amap m
typ
None
let makeInfoCache g f =
new MemoizationTable<_,_>
(compute=f,
// Only cache closed, monomorphic types (closed = all members for the type
// have been processed). Also don't cache anything involving an inference equations or
// type abbreviations. Generic type instantiations could be processed, but we have
// to be very careful not to cache anything that depends on inference equations or
// type abbreviations, and most instantiations involve some type variables anyway
canMemoize=(fun (flags,(_:range),typ) ->
match typ with
| TType_app(tcref,[]) -> tcref.TypeContents.tcaug_closed
| _ -> false),
keyEquals=(fun (flags1,_,typ1) (flags2,_,typ2) ->
// Ignore the ranges!
(flags1 = flags2) &&
match typ1,typ2 with
| TType_app(tcref1,[]),TType_app(tcref2,[]) -> tcref_eq g tcref1 tcref2
| _ -> false),
keyHash= (fun (flags,_,typ) ->
hash flags +
(match typ with
| TType_app(tcref,[]) -> hash tcref.MangledName
| _ -> 0)))
let methodInfoCache = makeInfoCache g readRawIntrinsicMethodSetsUncached
let propertyInfoCache = makeInfoCache g readRawIntrinsicPropertySetsUncached
let ilFieldInfoCache = makeInfoCache g readIlFieldInfosUncached
let ilEventInfoCache = makeInfoCache g readIlEventInfosUncached
let recdFieldInfoCache = makeInfoCache g findRecdFieldInfoUncached
let namedItemsCache = makeInfoCache g readRawIntrinsicNamedItemsUncached
let entireTypeHierarchyCache = makeInfoCache g readEntireTypeHierachyUncached
let primaryTypeHierarchyCache = makeInfoCache g readPrimaryTypeHierachyUncached
member x.g = g
member x.amap = amap
/// Read the method infos for a type
///
/// Cache the result for monomorphic types
member x.GetRawIntrinsicMethodSetsOfType (optFilter,ad,m,typ) =
methodInfoCache.Apply(((optFilter,ad),m,typ))
member x.GetRawIntrinsicPropertySetsOfType (optFilter,ad,m,typ) =
propertyInfoCache.Apply(((optFilter,ad),m,typ))
member x.GetILFieldInfosOfType (optFilter,ad,m,typ) =
ilFieldInfoCache.Apply(((optFilter,ad),m,typ))
member x.GetILEventInfosOfType (optFilter,ad,m,typ) =
ilEventInfoCache.Apply(((optFilter,ad),m,typ))
member x.TryFindRecdFieldInfoOfType (nm,m,typ) =
recdFieldInfoCache.Apply((nm,m,typ))
member x.TryFindNamedItemOfType (nm,ad,m,typ) =
namedItemsCache.Apply(((nm,ad),m,typ))
member x.ReadEntireTypeHierachy (m,typ) =
entireTypeHierarchyCache.Apply(((),m,typ))
member x.ReadPrimaryTypeHierachy (m,typ) =
primaryTypeHierarchyCache.Apply(((),m,typ))
(*-------------------------------------------------------------------------
!* Constructor infos
*------------------------------------------------------------------------- *)
let private ConstructorInfosOfILType g amap m typ =
let tdef = tdef_of_il_typ g typ
tdef.Methods
|> IL.find_mdefs_by_name ".ctor"
|> List.filter (fun md -> match md.mdKind with MethodKind_ctor -> true | _ -> false)
|> List.map (mk_il_minfo amap m (tinfo_of_il_typ g typ) None)
let GetIntrinsicConstructorInfosOfType (infoReader:InfoReader) m ty =
let g = infoReader.g
let amap = infoReader.amap
if verbose then dprintf "--> GetIntrinsicConstructorInfosOfType\n";
if is_stripped_tyapp_typ g ty then
if is_il_named_typ g ty then
ConstructorInfosOfILType g amap m ty
else
let tcref = tcref_of_stripped_typ g ty
let nm = ".ctor"
let aug = tcref.TypeContents
(* tcaug_adhoc cleanup: this should select from all accessible/available vrefs *)
(* that are part of any augmentation of this type. That's assuming that constructors can *)
(* be in augmentations. *)
let vrefs = NameMultiMap.find nm aug.tcaug_adhoc
vrefs
|> List.choose(fun vref ->
match vref.MemberInfo with
| Some membInfo when (membInfo.MemberFlags.MemberKind = MemberKindConstructor) -> Some(vref)
| _ -> None)
|> List.map (fun x -> FSMeth(g,ty,x))
else []
(*-------------------------------------------------------------------------
!* Method signatures
*------------------------------------------------------------------------- *)
let FormalTyparsOfEnclosingTypeOfMethInfo m minfo =
match minfo with
| ILMeth(g,ilminfo) ->
// For extension methods all type variables are on the method
if ilminfo.IsCSharpExtensionMethod then
[]
else
ilminfo.ILTypeInfo |> FormalTyparsOfILTypeInfo m
| FSMeth(g,typ,vref) ->
let ttps,_,_,_ = AnalyzeTypeOfMemberVal g (typ,vref)
ttps
| DefaultStructCtor(g,typ) ->
(tcref_of_stripped_typ g typ).Typars(m)
let CompiledSigOfMeth g amap m (minfo:MethInfo) =
let fmtps = minfo.FormalMethodTypars
let fminst = generalize_typars fmtps
let vargtys = ParamTypesOfMethInfo amap m minfo fminst
let vrty = CompiledReturnTyOfMeth amap m minfo fminst
// The formal method typars returned are completely formal - they don't take into account the instantiation
// of the enclosing type. For example, they may have constraints involving the _formal_ type parameters
// of the enclosing type. This instaniations can be used to interpret those type parameters
let fmtpinst =
let tinst = tinst_of_stripped_typ g minfo.EnclosingType
let ttps = FormalTyparsOfEnclosingTypeOfMethInfo m minfo
mk_typar_inst ttps tinst
vargtys,vrty,fmtps,fmtpinst
/// Used to hide/filter members from super classes based on signature
let MethInfosEquivByNameAndPartialSig erasureFlag g amap m (minfo:MethInfo) (minfo2:MethInfo) =
(minfo.LogicalName = minfo2.LogicalName) &&
(minfo.GenericArity = minfo2.GenericArity) &&
let fmtps = minfo.FormalMethodTypars
let fminst = generalize_typars fmtps
let fmtps2 = minfo2.FormalMethodTypars
let fminst2 = generalize_typars fmtps2
let argtys = ParamTypesOfMethInfo amap m minfo fminst
let argtys2 = ParamTypesOfMethInfo amap m minfo2 fminst2
(argtys,argtys2) ||> List.lengthsEqAndForall2 (List.lengthsEqAndForall2 (type_aequiv_aux erasureFlag g (mk_tyeq_env fmtps fmtps2)))
/// Used to hide/filter members from super classes based on signature
let MethInfosEquivByNameAndSig erasureFlag g amap m minfo minfo2 =
MethInfosEquivByNameAndPartialSig erasureFlag g amap m minfo minfo2 &&
let argtys,retTy,fmtps,_ = CompiledSigOfMeth g amap m minfo
let argtys2,rty2,fmtps2,_ = CompiledSigOfMeth g amap m minfo2
match retTy,rty2 with
| None,None -> true
| Some retTy,Some rty2 -> type_aequiv_aux erasureFlag g (mk_tyeq_env fmtps fmtps2) retTy rty2
| _ -> false
/// Used to hide/filter members from super classes based on signature *)
let PropInfosEquivByNameAndSig erasureFlag g amap m pinfo pinfo2 =
PropInfosEquivByNameAndPartialSig erasureFlag g amap m pinfo pinfo2 &&
let retTy = PropertyTypeOfPropInfo amap m pinfo
let rty2 = PropertyTypeOfPropInfo amap m pinfo2
type_equiv_aux erasureFlag g retTy rty2
/// nb. Prefer items toward the top of the hierarchy if the items are virtual
/// but not when resolving base calls. Also get overrides instead
/// of abstract slots when measuring whether a class/interface implements all its
/// required slots.
type FindMemberFlag =
| IgnoreOverrides
| PreferOverrides
/// The input list is sorted from most-derived to least-derived type, so any System.Object methods
/// are at the end of the list. Return a filtered list where prior/subsequent members matching by name and
/// that are in the same equivalence class have been removed. We keep a name-indexed table to
/// be more efficient when we check to see if we've already seen a particular named method.
type IndexedList<'a>(itemLists: 'a list list, itemsByName: 'a NameMultiMap) =
member x.Items = itemLists
member x.ItemsWithName(nm) = NameMultiMap.find nm itemsByName
member x.AddItems(items,nmf) = IndexedList<'a>(items::itemLists,List.foldBack (fun x acc -> NameMultiMap.add (nmf x) x acc) items itemsByName )
/// Add all the items to the IndexedList if better items are not already present. This is used to hide methods
/// in super classes and/or hide overrides of methods in subclasses.
///
/// Assume no items in 'items' are equivalent according to 'equiv'. This is valid because each step in a
/// .NET class hierarchy introduces a consistent set of methods, none of which hide each other within the
/// given set. This is an important optimization because it means we don't have to List.filter for equivalence between the
/// large overload sets introduced by methods like System.WriteLine.
///
/// Assume items can be given names by 'nmf', where two items with different names are
/// not equivalent.
let private addItemsToIndexedList noBetterThan nmf items (ilist:IndexedList<_>) =
// Have we already seen an item with the same name and that is in the same equivalence class?
// If so, ignore this one. Note we can check against the original incoming 'ilist' because we are assuming that
// none the elements of 'items' are equivalent.
let items = items |> List.filter (fun item -> not (List.exists (noBetterThan item) (ilist.ItemsWithName(nmf item))))
ilist.AddItems(items,nmf)
let private emptyIndexedList() = IndexedList([],NameMultiMap.empty)
let private excludePriorItems noBetterThan nmf =
let rec loop itemLists =
match itemLists with
| [] -> emptyIndexedList()
| items :: rest -> addItemsToIndexedList noBetterThan nmf items (loop rest)
fun itemLists -> (loop itemLists).Items
let private excludeSubsequentItems equiv nmf =
let rec loop itemLists (acc:IndexedList<_>) =
match itemLists with
| [] -> List.rev acc.Items
| items :: rest -> loop rest (addItemsToIndexedList equiv nmf items acc)
fun itemLists -> loop itemLists (emptyIndexedList())
let private filterOverrides findFlag (isvirt:'a->bool,isNewSlot,isDefiniteOverride,equivSigs,nmf:'a->string) items =
let equivVirts x y = isvirt x && isvirt y && equivSigs x y
match findFlag with
| PreferOverrides ->
items
// For each F#-declared override, get rid of any equivalent abstract member in the same type
// This is because F# abstract members with default overrides give rise to two members with the
// same logical signature in the same type, e.g.
// type ClassType1() =
// abstract VirtualMethod1: string -> int
// default x.VirtualMethod1(s) = 3
|> List.map (fun items ->
let definiteOverrides = items |> List.filter isDefiniteOverride
items |> List.filter (fun item -> (isDefiniteOverride item || not (List.exists (equivVirts item) definiteOverrides))))
// get rid of any virtuals that are signature-equivalent to virtuals in supertypes
|> excludeSubsequentItems equivVirts nmf
| IgnoreOverrides ->
(* A new virtual with the same signature is no better than the original unless it is new slot *)
let noBetterThan item orig = not (isNewSlot item) && equivVirts item orig
items
// Get rid of any F#-declared overrides. THese may occur in the same type as the abstract member (unlike with .NET metadata)
// Include any 'newslot' declared methods.
|> List.map (List.filter (fun x -> not (isDefiniteOverride x)))
// get rid of any virtuals that are signature-equivalent to virtuals in subtypes
|> excludePriorItems noBetterThan nmf
let FilterOverridesOfMethInfos findFlag g amap m minfos =
filterOverrides findFlag (MethInfo.IsVirtual,MethInfo.IsNewSlot,MethInfo.IsDefiniteFSharpOverride,MethInfosEquivByNameAndSig EraseNone g amap m,MethInfo.LogicalName) minfos
let FilterOverridesOfPropInfos findFlag g amap m props =
filterOverrides findFlag (PropInfo.IsVirtualProperty,PropInfo.IsNewSlot,PropInfo.IsDefiniteFSharpOverride,PropInfosEquivByNameAndSig EraseNone g amap m, PropInfo.PropertyName) props
let ExcludeHiddenOfMethInfos g amap m (minfos:MethInfo list list) =
minfos
|> excludeSubsequentItems
(fun m1 m2 ->
(* only hide those truly from super classes *)
not (tcref_eq g (tcref_of_stripped_typ g m1.EnclosingType) (tcref_of_stripped_typ g m2.EnclosingType)) &&
MethInfosEquivByNameAndPartialSig EraseNone g amap m m1 m2)
MethInfo.LogicalName
|> List.concat
let ExcludeHiddenOfPropInfos g amap m pinfos =
pinfos
|> excludeSubsequentItems (PropInfosEquivByNameAndPartialSig EraseNone g amap m) PropInfo.PropertyName
|> List.concat
let GetIntrinsicMethInfoSetsOfType (infoReader:InfoReader) (optFilter,ad) findFlag m typ =
infoReader.GetRawIntrinsicMethodSetsOfType(optFilter,ad,m ,typ)
|> FilterOverridesOfMethInfos findFlag infoReader.g infoReader.amap m
let GetIntrinsicPropInfoSetsOfType (infoReader:InfoReader) (optFilter,ad) findFlag m typ =
infoReader.GetRawIntrinsicPropertySetsOfType(optFilter,ad, m,typ)
|> FilterOverridesOfPropInfos findFlag infoReader.g infoReader.amap m
let GetIntrinsicMethInfosOfType infoReader (optFilter,ad) findFlag m typ =
GetIntrinsicMethInfoSetsOfType infoReader (optFilter,ad) findFlag m typ |> List.concat
let GetIntrinsicPropInfosOfType infoReader (optFilter,ad) findFlag m typ =
GetIntrinsicPropInfoSetsOfType infoReader (optFilter,ad) findFlag m typ |> List.concat
let TryFindIntrinsicNamedItemOfType (infoReader:InfoReader) (nm,ad) findFlag m typ =
match infoReader.TryFindNamedItemOfType(nm,ad, m,typ) with
| Some item ->
match item with
| PropertyItem psets -> Some(PropertyItem (psets |> FilterOverridesOfPropInfos findFlag infoReader.g infoReader.amap m))
| MethodItem msets -> Some(MethodItem (msets |> FilterOverridesOfMethInfos findFlag infoReader.g infoReader.amap m))
| _ -> Some(item)
| None -> None
/// Try to detect the existence of a method on a type
/// Used for
/// -- getting the GetEnumerator, get_Current, MoveNext methods for enumerable types
/// -- getting the Dispose method when resolving the 'use' construct
/// -- getting the various methods used to desugar the computation expression syntax
let TryFindMethInfo infoReader m ad nm ty =
GetIntrinsicMethInfosOfType infoReader (Some(nm),ad) IgnoreOverrides m ty
let TryFindPropInfo infoReader m ad nm ty =
GetIntrinsicPropInfosOfType infoReader (Some(nm),ad) IgnoreOverrides m ty
/// Make a call to a method info. Used by the optimizer only to build
/// calls to the type-directed resolutions of overloaded operators
let MakeMethInfoCall amap m minfo minst args =
let vFlags = NormalValUse in (* correct unless if we allow wild trait constraints like "T has a ctor and can be used as a parent class" *)
match minfo with
| ILMeth(g,ilminfo) ->
let direct = not minfo.IsVirtual
let isProp = false in (* not necessarily correct, but this is only used post-creflect where this flag is irrelevant *)
mk_il_minfo_call g amap m isProp ilminfo vFlags minst direct args |> fst
| FSMeth(g,typ,vref) ->
BuildFSharpMethodCall g m (typ,vref) vFlags minst args |> fst
| DefaultStructCtor(_,typ) ->
mk_ilzero (m,typ)
/// Given a delegate type work out the minfo, argument types, return type
/// and F# function type by looking at the Invoke signature of the delegate.
let GetSigOfFunctionForDelegate (infoReader:InfoReader) delty m ad =
let g = infoReader.g
let amap = infoReader.amap
let minfo =
match GetIntrinsicMethInfosOfType infoReader (Some "Invoke",ad) IgnoreOverrides m delty with
| [h] -> h
| [] -> error(Error("No Invoke methods found for delegate type",m))
| h :: _ -> warning(InternalError("More than one Invoke method found for delegate type",m)); h
let minst = [] // a delegate's Invoke method is never generic
let basicDelArgTys = ParamTypesOfMethInfo amap m minfo minst
if basicDelArgTys.Length <> 1 then error(Error("Delegates are not allowed to have curried signatures",m))
let basicDelArgTys = basicDelArgTys.Head
let delArgTys = if isNil basicDelArgTys then [g.unit_ty] else basicDelArgTys
let delRetTy = FSharpReturnTyOfMeth amap m minfo minst
CheckMethInfoAttributes g m minfo |> CommitOperationResult;
let fty = mk_iterated_fun_ty delArgTys delRetTy
minfo,basicDelArgTys,delRetTy,fty
let TryDestStandardDelegateTyp (infoReader:InfoReader) m ad delTy =
let g = infoReader.g
let amap = infoReader.amap
let minfo,delArgTys,delRetTy,_ = GetSigOfFunctionForDelegate infoReader delTy m ad
match delArgTys with
| senderTy :: argTys when (is_obj_typ g senderTy) -> Some(mk_tupled_ty g argTys,delRetTy)
| _ -> None
(* We take advantage of the following idiom to simplify away the bogus "object" parameter of the
of the "Add" methods associated with events. If you want to access it you
can use AddHandler instead.
The .NET Framework guidelines indicate that the delegate type used for
an event should take two parameters, an "object source" parameter
indicating the source of the event, and an "e" parameter that
encapsulates any additional information about the event. The type of
the "e" parameter should derive from the EventArgs class. For events
that do not use any additional information, the .NET Framework has
already defined an appropriate delegate type: EventHandler.
(from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csref/html/vcwlkEventsTutorial.asp)
*)
let IsStandardEventInfo (infoReader:InfoReader) m ad (einfo:EventInfo) =
let dty = einfo.GetDelegateType(infoReader.amap,m)
match TryDestStandardDelegateTyp infoReader m ad dty with
| Some _ -> true
| None -> false
/// Get the (perhaps tupled) argument type accepted by an event
let ArgsTypOfEventInfo (infoReader:InfoReader) m ad (einfo:EventInfo) =
let g = infoReader.g
let amap = infoReader.amap
let dty = einfo.GetDelegateType(amap,m)
match TryDestStandardDelegateTyp infoReader m ad dty with
| Some(argtys,_) -> argtys
| None -> error(nonStandardEventError einfo.EventName m)
/// Get the type of the event when looked at as if it is a property
/// Used when displaying the property in Intellisense
let PropTypOfEventInfo (infoReader:InfoReader) m ad (einfo:EventInfo) =
let g = infoReader.g
let amap = infoReader.amap
let delTy = einfo.GetDelegateType(amap,m)
let argsTy = ArgsTypOfEventInfo infoReader m ad einfo
mk_fslib_IEvent2_ty g delTy argsTy