csharpfftfsharpintegrationinterpolationlinear-algebramathdifferentiationmatrixnumericsrandomregressionstatisticsmathnet
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.
2091 lines
102 KiB
2091 lines
102 KiB
// (c) Microsoft Corporation. All rights reserved
|
|
|
|
#light
|
|
|
|
module (* internal *) Microsoft.FSharp.Compiler.Nameres
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Name environment and name resolution
|
|
//-------------------------------------------------------------------------
|
|
|
|
open Internal.Utilities
|
|
open Internal.Utilities.Pervasives
|
|
open Microsoft.FSharp.Compiler
|
|
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.Import
|
|
open Microsoft.FSharp.Compiler.Env
|
|
open Microsoft.FSharp.Compiler.Lib
|
|
open Microsoft.FSharp.Compiler.AbstractIL
|
|
open Microsoft.FSharp.Compiler.AbstractIL.Internal
|
|
open Microsoft.FSharp.Compiler.AbstractIL.Internal.Library
|
|
|
|
open Microsoft.FSharp.Compiler.AbstractIL.Diagnostics
|
|
open Microsoft.FSharp.Compiler.AbstractIL.IL // Abstract IL
|
|
open Microsoft.FSharp.Compiler.Outcome
|
|
open Microsoft.FSharp.Compiler.Infos
|
|
open Microsoft.FSharp.Compiler.Infos.AccessibilityLogic
|
|
open Microsoft.FSharp.Compiler.Infos.AttributeChecking
|
|
open Microsoft.FSharp.Compiler.Layout
|
|
open Microsoft.FSharp.Compiler.PrettyNaming
|
|
|
|
type NameResolver(g:TcGlobals,
|
|
amap: Import.ImportMap,
|
|
infoReader: InfoReader,
|
|
instantiationGenerator: (range -> typars -> tinst)) =
|
|
/// Used to transform typars into new inference typars
|
|
// instantiationGenerator is a function to help us create the
|
|
// type parameters by copying them from type parameter specifications read
|
|
// from IL code.
|
|
//
|
|
// When looking up items in generic types we create a fresh instantiation
|
|
// of the type, i.e. instantiate the type with inference variables.
|
|
// This means the item is returned ready for use by the type inference engine
|
|
// without further freshening. However it does mean we end up plumbing 'instantiationGenerator'
|
|
// around a bit more than we would like to, which is a bit annoying.
|
|
member nr.instantiationGenerator = instantiationGenerator
|
|
member nr.g = g
|
|
member nr.amap = amap
|
|
member nr.InfoReader = infoReader
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Helpers for unionconstrs and recdfields
|
|
//-------------------------------------------------------------------------
|
|
|
|
let UnionCaseRefsInTycon modref (tycon:Tycon) =
|
|
tycon.UnionCasesAsList |> List.map (ucref_of_ucase (MakeNestedTcref modref tycon))
|
|
|
|
let UnionCaseRefsInModuleOrNamespace (modref:ModuleOrNamespaceRef) =
|
|
List.foldBack (UnionCaseRefsInTycon modref >> (@)) (NameMap.range modref.ModuleOrNamespaceType.AllEntities) []
|
|
|
|
let IsUnionCaseInTycon (id:ident) (tycon :Tycon) = isSome (tycon.GetUnionCaseByName id.idText)
|
|
|
|
let IsRecdFieldInTycon (id:ident) (tycon :Tycon) = tycon.GetFieldByName(id.idText).IsSome
|
|
|
|
let IsRecdFieldInUnionCase (id:ident) (ucase:UnionCase) = ucase.GetFieldByName id.idText |> isSome
|
|
|
|
let TryFindTypeWithUnionCase (modref:ModuleOrNamespaceRef) id =
|
|
NameMap.tryFindInRange (IsUnionCaseInTycon id) modref.ModuleOrNamespaceType.AllEntities
|
|
|
|
let TryFindTypeWithRecdField (mty:ModuleOrNamespaceType) id =
|
|
NameMap.tryFindInRange (IsRecdFieldInTycon id) mty.AllEntities
|
|
|
|
let ActivePatternElemsOfValRef vref =
|
|
match apinfo_of_vref vref with
|
|
| Some (APInfo(_,nms,_) as apinfo) -> List.mapi (fun i _ -> APElemRef(apinfo,vref, i)) nms
|
|
| None -> []
|
|
|
|
let ActivePatternElemsOfVal modref vspec =
|
|
ActivePatternElemsOfValRef (mk_vref_in_modref modref vspec)
|
|
|
|
|
|
let ActivePatternElemsOfModuleOrNamespace (modref:ModuleOrNamespaceRef) : ActivePatternElemRef NameMap =
|
|
let mtyp = modref.ModuleOrNamespaceType
|
|
cacheOptRef mtyp.ActivePatternsLookupTable (fun () ->
|
|
let aprefs = List.foldBack (ActivePatternElemsOfVal modref >> (@)) (NameMap.range mtyp.AllValuesAndMembers) []
|
|
List.foldBack (fun apref acc -> NameMap.add (name_of_apref apref) apref acc) aprefs Map.empty)
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
|
|
// Note: Active patterns are encoded like this:
|
|
// let (|A|B|) x = if x < 0 then A else B // A and B are reported as results using 'Item_apres'
|
|
// match () with | A | B -> () // A and B are reported using 'ITem_apelem'
|
|
|
|
[<StructuralEquality(false); StructuralComparison(false)>]
|
|
type NamedItem =
|
|
(* These exist in the "eUnqualifiedItems" List.map in the type environment. *)
|
|
| Item_val of ValRef
|
|
| Item_ucase of UnionCaseInfo
|
|
| Item_apres of ActivePatternInfo * typ * int
|
|
| Item_apelem of ActivePatternElemRef
|
|
| Item_ecref of TyconRef
|
|
| Item_recdfield of RecdFieldInfo
|
|
|
|
(* The following are never in the items table but are valid results of binding *)
|
|
(* an identitifer in different circumstances. *)
|
|
| Item_newdef of ident
|
|
| Item_il_field of ILFieldInfo
|
|
| Item_event of EventInfo
|
|
| Item_property of string * PropInfo list
|
|
| Item_meth_group of string * MethInfo list
|
|
| Item_ctor_group of string * MethInfo list
|
|
| Item_fake_intf_ctor of Tast.typ
|
|
| Item_delegate_ctor of Tast.typ
|
|
| Item_typs of string * Tast.typ list
|
|
| Item_modrefs of Tast.ModuleOrNamespaceRef list
|
|
| Item_implicit_op of ident
|
|
| Item_param_name of ident
|
|
| Item_prop_name of ident
|
|
|
|
|
|
let MakeMethGroup (nm,minfos:MethInfo list) =
|
|
let minfos = minfos |> List.sortBy (fun minfo -> minfo.NumArgs |> List.sum)
|
|
Item_meth_group (nm,minfos)
|
|
|
|
let MakeCtorGroup (nm,minfos:MethInfo list) =
|
|
let minfos = minfos |> List.sortBy (fun minfo -> minfo.NumArgs |> List.sum)
|
|
Item_ctor_group (nm,minfos)
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
|
|
type ExtensionMember =
|
|
| FSExtMem of ValRef
|
|
| ILExtMem of ILTypeRef * ILMethodDef
|
|
static member Equality g e1 e2 =
|
|
match e1, e2 with
|
|
| FSExtMem vref1, FSExtMem vref2 -> g.vref_eq vref1 vref2
|
|
| ILExtMem (_,md1), ILExtMem (_,md2) -> md1 === md2
|
|
| _ -> false
|
|
|
|
[<StructuralEquality(false); StructuralComparison(false)>]
|
|
type NameResolutionEnv =
|
|
{ /// Display environment information for output
|
|
eDisplayEnv: DisplayEnv;
|
|
|
|
/// Values and Data Tags available by unqualified name
|
|
eUnqualifiedItems: NamedItem NameMap;
|
|
|
|
/// Data Tags and Active Pattern Tags available by unqualified name
|
|
ePatItems: NamedItem NameMap;
|
|
|
|
/// Modules accessible via "." notation. Note this is a multi-map.
|
|
/// Adding a module abbreviation adds it a local entry to this List.map.
|
|
/// Likewise adding a ccu or opening a path adds entries to this List.map.
|
|
|
|
|
|
/// REVIEW (old comment)
|
|
/// "The boolean flag is means the namespace or module entry shouldn't 'really' be in the
|
|
/// map, and if it is everr used to resolve a name then we give a warning.
|
|
/// This is used to give warnings on unqualified namespace accesses, e.g.
|
|
/// open System
|
|
/// open Collections <--- give a warning
|
|
/// let v = new Collections.Generic.List<int>() <--- give a warning"
|
|
|
|
eModulesAndNamespaces: (Tast.ModuleOrNamespaceRef list) NameMap;
|
|
|
|
/// Fully qualified modules and namespaces. 'open' does not change this.
|
|
eFullyQualifiedModulesAndNamespaces: (Tast.ModuleOrNamespaceRef list) NameMap;
|
|
|
|
/// RecdField labels in scope. RecdField labels are those where type are inferred
|
|
/// by label rather than by known type annotation.
|
|
/// Bools indicate if from a record, where no warning is given on indeterminate lookup
|
|
eFieldLabels: (Tast.RecdFieldRef * bool) NameMultiMap;
|
|
|
|
/// Tycons indexed by the various names that may be used to access them, e.g.
|
|
/// "List" --> multiple tycon_refs for the various tycons accessible by this name.
|
|
/// "List`1" --> TyconRef
|
|
eTyconsByAccessNames: TyconRef NameMultiMap;
|
|
|
|
/// Tycons available by unqualified, demangled names (i.e. (List,1) --> TyconRef)
|
|
eTyconsByDemangledNameAndArity: Map<NameArityPair,TyconRef>;
|
|
|
|
/// Extension members by type and name
|
|
eExtensionMembers: ExtensionMember TcrefMultiMap;
|
|
|
|
/// Typars (always available by unqualified names). Further typars can be
|
|
/// in the tpenv, a structure folded through each top-level definition.
|
|
eTypars: Typar NameMap;
|
|
|
|
}
|
|
|
|
static member Empty(g) =
|
|
{ eDisplayEnv=empty_denv g;
|
|
eModulesAndNamespaces=Map.empty;
|
|
eFullyQualifiedModulesAndNamespaces = Map.empty;
|
|
eFieldLabels=Map.empty;
|
|
eUnqualifiedItems=Map.empty;
|
|
ePatItems=Map.empty;
|
|
eTyconsByAccessNames=Map.empty;
|
|
eTyconsByDemangledNameAndArity=Map.empty;
|
|
eExtensionMembers=tcref_map_empty();
|
|
eTypars=Map.empty; }
|
|
member x.DisplayEnv = x.eDisplayEnv
|
|
member x.UnqualifiedItems = x.eUnqualifiedItems
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
// NamedItem functions
|
|
//-------------------------------------------------------------------------
|
|
|
|
let DisplayNameOfItem g d =
|
|
match d with
|
|
| Item_val v -> v.DisplayName
|
|
| Item_apelem apref -> name_of_apref apref
|
|
| Item_ucase(ucr) -> DecompileOpName ucr.UnionCase.DisplayName
|
|
| Item_ecref(ecr) -> ecr.DemangledExceptionName
|
|
| Item_recdfield(rfinfo) -> DecompileOpName rfinfo.RecdField.Name
|
|
| Item_newdef(id) -> id.idText
|
|
| Item_il_field(finfo) -> finfo.FieldName
|
|
| Item_event(einfo) -> einfo.EventName
|
|
| Item_property(nm,pinfos) -> nm
|
|
| Item_meth_group(nm,_) -> nm
|
|
| Item_ctor_group(nm,_) -> DemangleGenericTypeName nm
|
|
| Item_fake_intf_ctor typ
|
|
| Item_delegate_ctor typ -> DemangleGenericTypeName (tcref_of_stripped_typ g typ).MangledName
|
|
| Item_typs(nm,tcref) -> DemangleGenericTypeName nm
|
|
| Item_modrefs(modref :: _) -> demangled_name_of_modref modref
|
|
| Item_param_name(id) -> id.idText
|
|
| Item_prop_name(id) -> id.idText
|
|
| _ -> ""
|
|
|
|
|
|
// Add a value to the relevant table
|
|
//
|
|
// Object model members are not added to the name resolution environment *)
|
|
// because they use compiler-internal mangled names. *)
|
|
let AddValRefToItems (vref:ValRef) eUnqualifiedItems =
|
|
match vref.MemberInfo with
|
|
| Some _ -> eUnqualifiedItems
|
|
| None -> NameMap.add vref.MangledName (Item_val vref) eUnqualifiedItems
|
|
|
|
let AddValRefToExtensionMembers (vref:ValRef) eExtensionMembers =
|
|
if vref.IsMember && vref.IsExtensionMember then
|
|
tcref_mmap_add vref.MemberApparentParent (FSExtMem vref) eExtensionMembers
|
|
else
|
|
eExtensionMembers
|
|
|
|
let AddActivePatternRefToPatternItems apref tab =
|
|
NameMap.add (name_of_apref apref) (Item_apelem apref) tab
|
|
|
|
|
|
/// This entrypoint is used to add some extra items to the environment for Visual Studio, e.g. static members
|
|
let AddFakeNamedValRefToNameEnv nm vref nenv =
|
|
{nenv with eUnqualifiedItems= NameMap.add nm (Item_val vref) nenv.eUnqualifiedItems }
|
|
|
|
/// This entrypoint is used to add some extra items to the environment for Visual Studio, e.g. record members
|
|
let AddFakeNameToNameEnv nm item nenv =
|
|
{nenv with eUnqualifiedItems= NameMap.add nm item nenv.eUnqualifiedItems }
|
|
|
|
let AddValRefToNameEnv vref nenv =
|
|
{nenv with eUnqualifiedItems= AddValRefToItems vref nenv.eUnqualifiedItems;
|
|
eExtensionMembers = AddValRefToExtensionMembers vref nenv.eExtensionMembers;
|
|
ePatItems =
|
|
(let ePatItems = List.foldBack AddActivePatternRefToPatternItems (ActivePatternElemsOfValRef vref) nenv.ePatItems
|
|
|
|
(* Add literal constants to the environment available for resolving items in patterns *)
|
|
let ePatItems =
|
|
match vref.LiteralValue with
|
|
| None -> ePatItems
|
|
| Some _ -> NameMap.add vref.MangledName (Item_val vref) ePatItems
|
|
|
|
ePatItems) }
|
|
|
|
let AddActivePatternResultTagsToNameEnv apinfo ty nenv =
|
|
let nms = names_of_apinfo apinfo
|
|
let apresl = nms |> List.mapi (fun j nm -> nm, j)
|
|
{ nenv with eUnqualifiedItems= List.foldBack (fun (nm,j) acc -> Map.add nm (Item_apres(apinfo,ty,j)) acc) apresl nenv.eUnqualifiedItems; }
|
|
|
|
let GeneralizeUnionCaseRef (ucref:UnionCaseRef) =
|
|
UnionCaseInfo(fst(generalize_tcref ucref.TyconRef), ucref)
|
|
|
|
let private AddTyconRefToNameEnv (g:TcGlobals) amap m nenv (tcref:TyconRef) =
|
|
let AddRecdField (rfref:RecdFieldRef) tab = NameMultiMap.add rfref.FieldName (rfref,rfref.TyconRef.IsRecordTycon) tab
|
|
let AddUnionCase tab (ucref:UnionCaseRef) = Map.add ucref.CaseName (Item_ucase (GeneralizeUnionCaseRef ucref)) tab
|
|
let AddUnionCases tab ucrefs = List.fold AddUnionCase tab ucrefs
|
|
let isIL = tcref.IsILTycon
|
|
let ucrefs = if isIL then [] else tcref.UnionCasesAsList |> List.map (ucref_of_ucase tcref)
|
|
let flds = if isIL then [| |] else tcref.AllFieldsArray
|
|
|
|
let eExtensionMembers =
|
|
let csharpExtensionMeths =
|
|
if isIL then
|
|
let scoref,enc,tdef = tcref.ILTyconInfo
|
|
if ILThingHasExtensionAttribute tdef.tdCustomAttrs then
|
|
let tref = ILTypeInfo(tcref,tref_for_nested_tdef scoref (enc,tdef),[],tdef)
|
|
|
|
if verbose then dprintfn "found extension attribute on type %s" tcref.MangledName
|
|
|
|
dest_mdefs tdef.tdMethodDefs |> List.collect (fun md ->
|
|
if ILThingHasExtensionAttribute md.mdCustomAttrs then
|
|
match md.mdParams with
|
|
| thisParam :: _ ->
|
|
let ilty = thisParam.Type
|
|
match ilty with
|
|
| Type_boxed tspec
|
|
| Type_value tspec ->
|
|
let tcref = (tspec |> rescope_tspec scoref).TypeRef |> Import.ImportILTypeRef amap m
|
|
if verbose then dprintfn "found extension method %s on type %s" md.Name tcref.MangledName
|
|
|
|
[(tcref, tref, md)]
|
|
// Do not import extension members whose 'this' is only a type parameter
|
|
| _ ->
|
|
[]
|
|
| _ ->
|
|
[]
|
|
else
|
|
[])
|
|
else
|
|
[]
|
|
else
|
|
[]
|
|
if verbose then dprintfn "found %d extension members on type %s" csharpExtensionMeths.Length tcref.MangledName
|
|
(nenv.eExtensionMembers,csharpExtensionMeths) ||> List.fold (fun tab (tcref,tref,md) ->
|
|
tcref_mmap_add tcref (ILExtMem (tref.ILTypeRef, md)) tab)
|
|
|
|
|
|
{ nenv with
|
|
eFieldLabels=
|
|
(if isIL then nenv.eFieldLabels
|
|
else (nenv.eFieldLabels,flds) ||> Array.fold_left (fun acc f ->
|
|
if f.IsStatic || f.IsCompilerGenerated then acc
|
|
else AddRecdField (rfref_of_rfield tcref f) acc)) ;
|
|
eUnqualifiedItems =
|
|
(if isIL then nenv.eUnqualifiedItems else AddUnionCases nenv.eUnqualifiedItems ucrefs);
|
|
ePatItems =
|
|
(if isIL then nenv.ePatItems else AddUnionCases nenv.ePatItems ucrefs);
|
|
eExtensionMembers =
|
|
eExtensionMembers;
|
|
eTyconsByDemangledNameAndArity=
|
|
AddTyconsByDemangledNameAndArity tcref.MangledName (tcref.Typars(m)) tcref nenv.eTyconsByDemangledNameAndArity;
|
|
eTyconsByAccessNames=
|
|
AddTyconsByAccessNames tcref.MangledName tcref nenv.eTyconsByAccessNames }
|
|
|
|
let AddTyconRefsToNameEnv g amap m tcrefs nenv =
|
|
List.fold (AddTyconRefToNameEnv g amap m) nenv tcrefs
|
|
|
|
let AddExceptionDeclsToNameEnv (ecref:TyconRef) nenv =
|
|
assert ecref.IsExceptionDecl
|
|
let add_ecref_to_tab tab = NameMap.add ecref.DemangledExceptionName (Item_ecref ecref) tab
|
|
{nenv with
|
|
eUnqualifiedItems=add_ecref_to_tab nenv.eUnqualifiedItems;
|
|
ePatItems = add_ecref_to_tab nenv.ePatItems }
|
|
|
|
let AddModuleAbbrevToNameEnv (id:ident) modrefs nenv =
|
|
{nenv with
|
|
eModulesAndNamespaces=
|
|
let add old nw = nw @ old
|
|
NameMap.layerAdditive add (Map.add id.idText modrefs Map.empty) nenv.eModulesAndNamespaces }
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Open a structure or an IL namespace
|
|
//-------------------------------------------------------------------------
|
|
|
|
let modrefs_of_mtyp modref (mty:ModuleOrNamespaceType) =
|
|
mty.ModulesAndNamespacesByDemangledName |> NameMap.map (MakeNestedTcref modref)
|
|
|
|
let foldIf pred f x acc = if pred x then f x acc else acc
|
|
|
|
// Recursive because of "AutoOpen", i.e. adding a module reference may automatically open further modules
|
|
|
|
let rec AddModrefsToNameEnv g amap m topRooted ad modrefs nenv =
|
|
let AddModrefs modrefs tab =
|
|
let add old nw =
|
|
if IsEntityAccessible ad nw then
|
|
if verbose then dprintf "AddModrefs, nm = %s, #old = %d\n" (demangled_name_of_modref nw) (List.length old);
|
|
let isPartialNamespace = not topRooted && not nw.IsNamespace
|
|
((* isPartialNamespace, *) nw) :: old
|
|
else
|
|
old
|
|
NameMap.layerAdditive add modrefs tab
|
|
let nenv =
|
|
{nenv with
|
|
eModulesAndNamespaces= AddModrefs modrefs nenv.eModulesAndNamespaces;
|
|
eFullyQualifiedModulesAndNamespaces =
|
|
(if topRooted
|
|
then AddModrefs modrefs nenv.eFullyQualifiedModulesAndNamespaces
|
|
else nenv.eFullyQualifiedModulesAndNamespaces) }
|
|
let nenv =
|
|
(nenv,NameMap.range modrefs) ||> List.fold (fun nenv modref ->
|
|
if modref.IsModule && TryFindBoolAttrib g g.attrib_AutoOpenAttribute modref.Attribs = Some(true) then
|
|
AddModuleOrNamespaceContentsToNameEnv g amap ad m modref nenv
|
|
else
|
|
nenv)
|
|
nenv
|
|
|
|
and AddModuleOrNamespaceContentsToNameEnv (g:TcGlobals) amap (ad:AccessorDomain) m (modref:ModuleOrNamespaceRef) nenv =
|
|
let mty = modref.ModuleOrNamespaceType
|
|
let tycons = mty.TypeAndExceptionDefinitions
|
|
let exncs = mty.ExceptionDefinitions
|
|
let nenv = { nenv with eDisplayEnv= denv_add_open_modref modref nenv.eDisplayEnv }
|
|
let nenv = List.foldBack (MakeNestedTcref modref >> foldIf (IsEntityAccessible ad) (AddExceptionDeclsToNameEnv)) exncs nenv
|
|
let nenv = NameMap.foldRange (mk_vref_in_modref modref >> foldIf (IsValAccessible ad) (AddValRefToNameEnv)) mty.AllValuesAndMembers nenv
|
|
let nenv = AddTyconRefsToNameEnv g amap m (tycons |> List.map (MakeNestedTcref modref) |> List.filter (IsEntityAccessible ad) ) nenv
|
|
let modrefs = modrefs_of_mtyp modref mty
|
|
let nenv = AddModrefsToNameEnv g amap m false ad modrefs nenv
|
|
nenv
|
|
|
|
let AddModrefToNameEnv g amap m topRooted ad modref nenv =
|
|
AddModrefsToNameEnv g amap m topRooted ad (Map.add (demangled_name_of_modref modref) modref Map.empty) nenv
|
|
|
|
|
|
type CheckForDuplicateTyparFlag =
|
|
| CheckForDuplicateTypars
|
|
| NoCheckForDuplicateTypars
|
|
|
|
let AddDeclaredTyparsToNameEnv check typars nenv =
|
|
let typarmap =
|
|
List.foldBack
|
|
(fun (tp:Typar) sofar ->
|
|
begin match check with
|
|
| CheckForDuplicateTypars ->
|
|
if Map.mem tp.Name sofar then errorR (Duplicate("type parameter",tp.DisplayName,tp.Range))
|
|
| NoCheckForDuplicateTypars ->
|
|
()
|
|
end;
|
|
Map.add tp.Name tp sofar) typars Map.empty
|
|
{nenv with eTypars=NameMap.layer typarmap nenv.eTypars }
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Lookup tables
|
|
//--------------------------------------------------------------------------
|
|
|
|
let tryname s t (id:ident) =
|
|
try Map.find id.idText t
|
|
with Not_found -> error (UndefinedName(0,s,id,NameMap.domainL t))
|
|
|
|
//-------------------------------------------------------------------------
|
|
// FreshenTycon and instantiationGenerator.
|
|
//-------------------------------------------------------------------------
|
|
|
|
let FreshenTycon (ncenv: NameResolver) m (tcref:TyconRef) =
|
|
let tinst = ncenv.instantiationGenerator m (tcref.Typars(m))
|
|
TType_app(tcref,tinst)
|
|
|
|
let FreshenUnionCaseRef (ncenv: NameResolver) m (ucref:UnionCaseRef) =
|
|
let tinst = ncenv.instantiationGenerator m (ucref.TyconRef.Typars(m))
|
|
UnionCaseInfo(tinst,ucref)
|
|
|
|
/// This must be called after fetching unqualified items that may need to be freshened
|
|
let FreshenUnqualifiedItem (ncenv: NameResolver) m res =
|
|
match res with
|
|
| Item_ucase (UnionCaseInfo(_,ucref)) -> Item_ucase (FreshenUnionCaseRef ncenv m ucref)
|
|
| _ -> res
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Resolve module paths, value, field etc. lookups. Doing this involves
|
|
// searching through many possibilities and disambiguating. Hence first
|
|
// define some ways of combining multiple results and for carrying
|
|
// error information. Errors are generally undefined names and are
|
|
// reported by returning the error that occurs at greatest depth in the
|
|
// sequence of identifiers.
|
|
//-------------------------------------------------------------------------
|
|
|
|
// Accumulate a set of possible results.
|
|
// If neither operations succeed, return an approximate error.
|
|
// If one succeeds, return that one.
|
|
// Prefer the error associated with the first argument.
|
|
let OneResult res =
|
|
match res with
|
|
| Result x -> Result [x]
|
|
| Exception e -> Exception e
|
|
|
|
let OneSuccess x = Result [x]
|
|
|
|
let AddResults res1 res2 =
|
|
match res1, res2 with
|
|
| Result [],_ -> res2
|
|
| _,Result [] -> res1
|
|
| Result x,Result l -> Result (x @ l)
|
|
| Exception _,Result l -> Result l
|
|
| Result x,Exception _ -> Result x
|
|
(* This prefers error messages coming from deeper failing long identifier paths *)
|
|
| Exception (UndefinedName(n1,_,_,_) as e1),Exception (UndefinedName(n2,_,_,_) as e2) ->
|
|
if n1 < n2 then Exception e2 else Exception e1
|
|
(* Prefer more concrete errors about things being undefined *)
|
|
| Exception (UndefinedName(n1,_,_,_) as e1),Exception (Error _) -> Exception e1
|
|
| Exception (Error _),Exception (UndefinedName(n1,_,_,_) as e2) -> Exception e2
|
|
| Exception e1,Exception _ -> Exception e1
|
|
|
|
let (+++) x y = AddResults x y
|
|
let NoResultsOrUsefulErrors = Result []
|
|
|
|
// REVIEW: make this tail recursive
|
|
let rec CollectResults f = function
|
|
| [] -> NoResultsOrUsefulErrors
|
|
| [h] -> OneResult (f h)
|
|
| h :: t -> AddResults (OneResult (f h)) (CollectResults f t)
|
|
|
|
let AtMostOneResult m res =
|
|
match res with
|
|
| Exception err -> raze err
|
|
| Result [] -> raze (Error("invalid module/expression/type",m))
|
|
| Result [res] -> success res
|
|
| Result (res :: _) -> success res (* raze (Error("this module/expression/type is ambiguous",m))*)
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Resolve (possibly mangled) type names
|
|
//-------------------------------------------------------------------------
|
|
|
|
/// Qualified lookups where the number of generic arguments is known
|
|
/// from context, e.g. Module.Type<args>. In theory the full names suh as ``List`1`` can
|
|
/// be used to qualify access if needed
|
|
let LookupTypeNameInEntityHaveArity nm ntyargs (mty:ModuleOrNamespaceType) =
|
|
if IsMangledGenericName nm || ntyargs = 0 then
|
|
mty.TypesByMangledName.TryFind nm
|
|
else
|
|
mty.TypesByMangledName.TryFind (nm^"`"^string ntyargs)
|
|
|
|
/// Unqualified lookups where the number of generic arguments is known
|
|
/// from context, e.g. List<arg>. Rebindings due to 'open' may have rebound identifiers.
|
|
let LookupTypeNameInEnvHaveArity nm ntyargs nenv =
|
|
if IsMangledGenericName nm then
|
|
nenv.eTyconsByDemangledNameAndArity.TryFind(DecodeGenericTypeName nm)
|
|
+?? (fun () -> nenv.eTyconsByAccessNames.TryFind nm |> Option.map List.hd)
|
|
else
|
|
nenv.eTyconsByDemangledNameAndArity.TryFind(NameArityPair(nm,ntyargs))
|
|
+?? (fun () -> nenv.eTyconsByAccessNames.TryFind nm |> Option.map List.hd)
|
|
|
|
/// Unqualified lookups where the number of generic arguments is NOT known
|
|
/// from context. This is used in five places:
|
|
/// - static member lookups, e.g. MyType.StaticMember(3)
|
|
/// - e.g. MyModule.MyType.StaticMember(3)
|
|
/// - type-qualified field names, e.g. { RecordType.field = 3 }
|
|
/// - type-qualified constructor names, e.g. match x with UnionType.A -> 3
|
|
/// - identifiers to constructors for better error messages, e.g. 'String(3)' after 'open System'
|
|
/// - the special single-constructor rule in tc_tycon_cores
|
|
///
|
|
/// Because of the potential ambiguity multiple results can be returned.
|
|
/// Explicit type annotations can be added where needed to specify the generic arity.
|
|
///
|
|
/// In theory the full names such as ``RecordType`1`` can
|
|
/// also be used to qualify access if needed, though this is almost never needed.
|
|
|
|
let LookupTypeNameNoArity nm byDemangledNameAndArity byAccessNames =
|
|
if IsMangledGenericName nm then
|
|
match Map.tryfind (DecodeGenericTypeName nm) byDemangledNameAndArity with
|
|
| Some res -> [res]
|
|
| None ->
|
|
match Map.tryfind nm byAccessNames with
|
|
| Some res -> res
|
|
| None -> []
|
|
else
|
|
NameMultiMap.find nm byAccessNames
|
|
|
|
let LookupTypeNameInEnvNoArity nm nenv =
|
|
LookupTypeNameNoArity nm nenv.eTyconsByDemangledNameAndArity nenv.eTyconsByAccessNames
|
|
|
|
let LookupTypeNameInEntityNoArity m nm (mtyp:ModuleOrNamespaceType) =
|
|
LookupTypeNameNoArity nm (mtyp.TypesByDemangledNameAndArity(m)) mtyp.TypesByAccessNames
|
|
|
|
type TypeNameInExprOrPatFlag = ResolveTypeNamesToCtors | ResolveTypeNamesToTypeRefs
|
|
type TypeNameResInfo = TypeNameInExprOrPatFlag * int option
|
|
let DefaultTypeNameResInfo = (ResolveTypeNamesToCtors,None)
|
|
|
|
|
|
let LookupTypeNameInEnvMaybeHaveArity nm ((_,numTyargsOpt):TypeNameResInfo) nenv =
|
|
match numTyargsOpt with
|
|
| None -> LookupTypeNameInEnvNoArity nm nenv
|
|
| Some ntyargs -> LookupTypeNameInEnvHaveArity nm ntyargs nenv |> Option.to_list
|
|
|
|
let LookupTypeNameInEntityMaybeHaveArity ad m nm numTyargsOpt (modref: ModuleOrNamespaceRef) =
|
|
let mtyp = modref.ModuleOrNamespaceType
|
|
let tycons =
|
|
match numTyargsOpt with
|
|
| None ->
|
|
LookupTypeNameInEntityNoArity m nm mtyp
|
|
| Some ntyargs ->
|
|
LookupTypeNameInEntityHaveArity nm ntyargs mtyp |> Option.to_list
|
|
tycons
|
|
|> List.map (MakeNestedTcref modref)
|
|
|> List.filter (IsEntityAccessible ad)
|
|
|
|
|
|
let GetNestedTypesOfType ad (ncenv:NameResolver) (optFilter,numTyargsOpt) m typ =
|
|
let g = ncenv.g
|
|
ncenv.InfoReader.ReadPrimaryTypeHierachy(m,typ) |> List.collect (fun typ ->
|
|
if is_stripped_tyapp_typ g typ then
|
|
let tcref,tinst = dest_stripped_tyapp_typ g typ
|
|
let tycon = deref_tycon tcref
|
|
let mty = tycon.ModuleOrNamespaceType
|
|
// Handle the .NET/C# business where nested generic types implictly accumulate the type parameters
|
|
// from their enclosing types.
|
|
let MakeNestedType (tcrefNested:TyconRef) =
|
|
let _,tps = List.chop tinst.Length (tcrefNested.Typars(m))
|
|
let tinstNested = ncenv.instantiationGenerator m tps
|
|
mk_tyapp_ty tcrefNested (tinst @ tinstNested)
|
|
|
|
match optFilter with
|
|
| Some nm ->
|
|
LookupTypeNameInEntityMaybeHaveArity ad m nm numTyargsOpt tcref
|
|
|> List.map MakeNestedType
|
|
| None ->
|
|
mty.TypesByAccessNames
|
|
|> NameMultiMap.range
|
|
|> List.map (MakeNestedTcref tcref >> MakeNestedType)
|
|
|> List.filter (IsTypeAccessible g ad)
|
|
else [])
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Report environments to visual studio. We stuff intermediary results
|
|
// into a global variable. A little unpleasant.
|
|
// REVIEW: We could at least put the global in cenv!!!
|
|
//-------------------------------------------------------------------------
|
|
|
|
// Represents a type of the occurence when reporting name in name resolution
|
|
type ItemOccurence =
|
|
// This is a binding / declaration of the item
|
|
| Binding = 0
|
|
// This is a usage of the item
|
|
| Use = 1
|
|
// Inside pattern matching
|
|
| Pattern = 2
|
|
|
|
type ITypecheckResultsSink =
|
|
abstract NotifyEnvWithScope : range * NameResolutionEnv * AccessorDomain -> unit
|
|
abstract NotifyExprHasType : pos * typ * Tastops.DisplayEnv * NameResolutionEnv * AccessorDomain * range -> unit
|
|
abstract NotifyNameResolution : pos * NamedItem * ItemOccurence * Tastops.DisplayEnv * NameResolutionEnv * AccessorDomain * range -> unit
|
|
|
|
let GlobalTypecheckResultsSink : ITypecheckResultsSink option ref = ref None
|
|
|
|
let CallEnvSink(scopem,nenv,ad) =
|
|
match !GlobalTypecheckResultsSink with
|
|
| None -> ()
|
|
| Some sink -> sink.NotifyEnvWithScope(scopem,nenv,ad)
|
|
|
|
let CallNameResolutionSink(m,nenv,item,occurenceType,denv,ad) =
|
|
match !GlobalTypecheckResultsSink with
|
|
| None -> ()
|
|
| Some sink -> sink.NotifyNameResolution(end_of_range m,item,occurenceType,denv,nenv,ad,m)
|
|
|
|
let CallExprHasTypeSink(m,nenv,typ,denv,ad) =
|
|
match !GlobalTypecheckResultsSink with
|
|
| None -> ()
|
|
| Some sink -> sink.NotifyExprHasType(end_of_range m,typ,denv,nenv,ad,m)
|
|
|
|
|
|
/// Checks if the type variables associated with the result of a resolution are inferrable,
|
|
/// i.e. occur in the arguments or return type of the resolution. If not give a warning
|
|
/// about a type instantiation being needed.
|
|
type ResultTyparChecker = unit -> bool
|
|
|
|
let CheckAllTyparsInferrable g amap m item =
|
|
match item with
|
|
| Item_val v -> true
|
|
| Item_apelem apref -> true
|
|
| Item_ucase(ucr) -> true
|
|
| Item_ecref(ecr) -> true
|
|
| Item_recdfield(rfinfo) -> true
|
|
| Item_newdef(id) -> true
|
|
|
|
| Item_il_field(finfo) -> true
|
|
| Item_event(einfo) -> true
|
|
|
|
| Item_property(nm,pinfos) ->
|
|
pinfos |> List.forall (fun pinfo ->
|
|
let freeInEnclosingType = free_in_type CollectTyparsNoCaching pinfo.EnclosingType
|
|
let freeInArgsAndRetType =
|
|
acc_free_in_types CollectTyparsNoCaching (ParamTypesOfPropInfo amap m pinfo)
|
|
(free_in_type CollectTyparsNoCaching (PropertyTypeOfPropInfo amap m pinfo))
|
|
let free = Zset.diff freeInEnclosingType.FreeTypars freeInArgsAndRetType.FreeTypars
|
|
free.IsEmpty)
|
|
|
|
| Item_meth_group(nm,minfos) ->
|
|
minfos |> List.forall (fun minfo ->
|
|
let fminst = minfo.FormalMethodInst
|
|
let freeInEnclosingType = free_in_type CollectTyparsNoCaching minfo.EnclosingType
|
|
let freeInArgsAndRetType =
|
|
List.foldBack (acc_free_in_types CollectTyparsNoCaching) (ParamTypesOfMethInfo amap m minfo fminst)
|
|
(acc_free_in_types CollectTyparsNoCaching (ObjTypesOfMethInfo amap m minfo fminst)
|
|
(free_in_type CollectTyparsNoCaching (FSharpReturnTyOfMeth amap m minfo fminst)))
|
|
let free = Zset.diff freeInEnclosingType.FreeTypars freeInArgsAndRetType.FreeTypars
|
|
free.IsEmpty)
|
|
|
|
| Item_ctor_group(nm,_) -> true
|
|
| Item_fake_intf_ctor typ
|
|
| Item_delegate_ctor typ -> true
|
|
| Item_typs(nm,tcref) -> true
|
|
| Item_modrefs(modref :: _) -> true
|
|
| Item_param_name(id) -> true
|
|
| Item_prop_name(id) -> true
|
|
| _ -> true
|
|
|
|
/// Keeps track of information relevant to the chosen resolution of a long identifier
|
|
///
|
|
/// When we resolve an item such as System.Console.In we
|
|
/// resolve it in one step to a property/val/method etc. item. However
|
|
/// Visual Studio needs to know about the exact resolutions of the names
|
|
/// System and Console, i.e. the 'entity path' of the resolution.
|
|
///
|
|
/// Each of the resolution routines keeps track of the entity path and
|
|
/// ultimately calls ResolutionInfo.SendToSink to record it for
|
|
/// later use by Visual Studio.
|
|
type ResolutionInfo =
|
|
| ResolutionInfo of (*entityPath, reversed*)(range * EntityRef) list * (*warnings/errors*)(ResultTyparChecker -> unit)
|
|
|
|
static member SendToSink(ncenv: NameResolver,nenv,ad,ResolutionInfo(entityPath,warnings),typarChecker) =
|
|
entityPath |> List.iter (fun (m,eref:EntityRef) ->
|
|
CheckEntityAttributes ncenv.g eref m |> CommitOperationResult;
|
|
CheckTyconAccessible m ad eref |> ignore;
|
|
let item = if eref.IsModuleOrNamespace then Item_modrefs([eref]) else Item_typs(eref.DisplayName,[FreshenTycon ncenv m eref])
|
|
CallNameResolutionSink(m,nenv,item,ItemOccurence.Use,nenv.eDisplayEnv,ad))
|
|
warnings(typarChecker)
|
|
|
|
static member Empty =
|
|
ResolutionInfo([],(fun typarChecker -> ()))
|
|
|
|
member x.AddEntity info =
|
|
let (ResolutionInfo(entityPath,warnings)) = x
|
|
ResolutionInfo(info::entityPath,warnings)
|
|
|
|
member x.AddWarning f =
|
|
let (ResolutionInfo(entityPath,warnings)) = x
|
|
ResolutionInfo(entityPath,(fun typarChecker -> f typarChecker; warnings typarChecker))
|
|
|
|
|
|
|
|
let CheckForMultipleGenericTypeAmbiguities (tcrefs:(ResolutionInfo * TyconRef) list) ((typeNameResFlag,numTyargsOpt):TypeNameResInfo) m =
|
|
// Given ambiguous C<>, C<_> we resolve the ambiguous 'C.M' to C<> without warning
|
|
// Given ambiguous C<_>, C<_,_> we resolve the ambiguous 'C.M' to C<_> with an ambiguity error
|
|
// Given C<_> we resolve the ambiguous 'C.M' to C<_> with a warning if the argument or return types can't be inferred
|
|
|
|
// Given ambiguous C<>, C<_> we resolve the ambiguous 'C()' to C<> without warning
|
|
// Given ambiguous C<_>, C<_,_> we resolve the ambiguous 'C()' to C<_> with an ambiguity error
|
|
// Given C<_> we resolve the ambiguous 'C()' to C<_> with a warning if the argument or return types can't be inferred
|
|
|
|
let tcrefs =
|
|
tcrefs
|
|
// remove later duplicates (if we've opened the same module more than once)
|
|
|> Seq.distinct_by (fun (_,tcref) -> tcref.Stamp)
|
|
|> Seq.to_list
|
|
// List.sort_by is a STABLE sort (the order matters!)
|
|
|> List.sort_by (fun (_,tcref) -> tcref.Typars(m).Length)
|
|
|
|
match tcrefs with
|
|
| ((resInfo,tcref) :: _) when
|
|
// multiple types
|
|
tcrefs.Length > 1 &&
|
|
// no explicit type instantiation
|
|
isNone numTyargsOpt &&
|
|
// some type arguments required on all types (note sorted by typar count above)
|
|
tcref.Typars(m).Length > 0 &&
|
|
// plausible types have different arities
|
|
(tcrefs |> Seq.distinct_by (fun (_,tcref) -> tcref.Typars(m).Length) |> Seq.length > 1) ->
|
|
[ for (resInfo,tcref) in tcrefs do
|
|
let resInfo = resInfo.AddWarning (fun typarChecker -> errorR(Error(sprintf "Multiple types exist called '%s', taking different numbers of generic parameters. Provide a type instantiation to disambiguate the type resolution, e.g. '%s'" tcref.DisplayName tcref.DisplayNameWithUnderscoreTypars,m)))
|
|
yield (resInfo,tcref) ]
|
|
|
|
| [(resInfo,tcref)] when isNone numTyargsOpt && tcref.Typars(m).Length > 0 && typeNameResFlag = ResolveTypeNamesToTypeRefs ->
|
|
let resInfo =
|
|
resInfo.AddWarning (fun typarChecker ->
|
|
if not (typarChecker()) then
|
|
warning(Error(sprintf "The instantiation of the generic type '%s' is missing and can't be inferred from the arguments or return type of this member. Consider providing a type instantiation when accessing this type, e.g. '%s'" tcref.DisplayName tcref.DisplayNameWithUnderscoreTypars,m)))
|
|
[(resInfo,tcref)]
|
|
|
|
| _ ->
|
|
tcrefs
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Consume ids that refer to a namespace
|
|
//-------------------------------------------------------------------------
|
|
|
|
type FullyQualifiedFlag =
|
|
// Only resolve full paths.
|
|
// This is urrently unused, but would be needed for a fully-qualified syntax, so leaving it in the code
|
|
| FullyQualified
|
|
| OpenQualified
|
|
|
|
let ResolveLongIndentAsModuleOrNamespace fullyQualified (nenv:NameResolutionEnv) ad (lid:ident list) =
|
|
match lid with
|
|
| [] -> NoResultsOrUsefulErrors
|
|
| id:: rest ->
|
|
let tab =
|
|
match fullyQualified with
|
|
| FullyQualified -> nenv.eFullyQualifiedModulesAndNamespaces
|
|
| OpenQualified -> nenv.eModulesAndNamespaces
|
|
|
|
match tab.TryFind(id.idText) with
|
|
| Some modrefs ->
|
|
|
|
/// Look through the sub-namespaces and/or modules
|
|
let rec look depth modref (mty:ModuleOrNamespaceType) (lid:ident list) =
|
|
match lid with
|
|
| [] -> success (depth,modref,mty)
|
|
| id:: rest ->
|
|
match mty.ModulesAndNamespacesByDemangledName.TryFind(id.idText) with
|
|
| Some mspec when IsEntityAccessible ad (MakeNestedTcref modref mspec) ->
|
|
let subref = MakeNestedTcref modref mspec
|
|
look (depth+1) subref mspec.ModuleOrNamespaceType rest
|
|
| _ -> raze (UndefinedName(depth,"namespace",id,[]))
|
|
|
|
modrefs |> CollectResults (fun modref ->
|
|
if IsEntityAccessible ad modref then
|
|
look 1 modref modref.ModuleOrNamespaceType rest
|
|
else
|
|
raze (UndefinedName(0,"namespace or module",id,[])))
|
|
| None ->
|
|
raze (UndefinedName(0,"namespace or module",id,[]))
|
|
|
|
|
|
let ResolveLongIndentAsModuleOrNamespaceThen fullyQualified (nenv:NameResolutionEnv) ad lid f =
|
|
match lid with
|
|
| [] -> NoResultsOrUsefulErrors
|
|
| id :: rest ->
|
|
match ResolveLongIndentAsModuleOrNamespace fullyQualified nenv ad [id] with
|
|
| Result modrefs ->
|
|
modrefs |> CollectResults (fun (depth,modref,mty) ->
|
|
let resInfo = ResolutionInfo.Empty.AddEntity(id.idRange,modref)
|
|
f resInfo (depth+1) id.idRange modref mty rest)
|
|
| Exception err -> Exception err
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Bind name used in "new Foo.Bar(...)" constructs
|
|
//-------------------------------------------------------------------------
|
|
|
|
let private ResolveObjectConstructorPrim (ncenv:NameResolver) edenv resInfo m ad typ =
|
|
let g = ncenv.g
|
|
let amap = ncenv.amap
|
|
if verbose then dprintf "--> ResolveObjectConstructor\n";
|
|
if is_delegate_typ g typ then
|
|
success (resInfo,Item_delegate_ctor typ,[])
|
|
else
|
|
let cinfos = GetIntrinsicConstructorInfosOfType ncenv.InfoReader m typ
|
|
if is_interface_typ g typ && isNil cinfos then
|
|
success (resInfo,Item_fake_intf_ctor typ, [])
|
|
else
|
|
let defaultStructCtorInfo =
|
|
if (is_struct_typ g typ && not(cinfos |> List.exists minfo_is_nullary)) then
|
|
[DefaultStructCtor(g,typ)]
|
|
else []
|
|
if verbose then dprintf "--> ResolveObjectConstructor (2)\n";
|
|
if (isNil defaultStructCtorInfo && isNil cinfos) or not (is_stripped_tyapp_typ g typ) then
|
|
raze (Error("No constructors are available for the type '"^NicePrint.pretty_string_of_typ edenv typ^"'",m))
|
|
else
|
|
let cinfos = cinfos |> List.filter (IsMethInfoAccessible amap m ad)
|
|
success (resInfo,MakeCtorGroup ((tcref_of_stripped_typ g typ).MangledName, (defaultStructCtorInfo@cinfos)),[])
|
|
|
|
let ResolveObjectConstructor (ncenv:NameResolver) edenv m ad typ =
|
|
ResolveObjectConstructorPrim (ncenv:NameResolver) edenv [] m ad typ |?> (fun (resInfo,item,rest) -> (item,rest))
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Bind IL "." notation (member lookup or lookup in a type)
|
|
//-------------------------------------------------------------------------
|
|
|
|
let IntrinsicPropInfosOfTypeInScope (infoReader:InfoReader) (optFilter, ad) findFlag m typ =
|
|
let g = infoReader.g
|
|
let amap = infoReader.amap
|
|
let pinfos = GetIntrinsicPropInfoSetsOfType infoReader (optFilter, ad) findFlag m typ
|
|
let pinfos = pinfos |> ExcludeHiddenOfPropInfos g amap m
|
|
pinfos
|
|
|
|
let ExtensionPropInfosOfTypeInScope (infoReader:InfoReader) eExtensionMembers (optFilter, ad) findFlag m typ =
|
|
let g = infoReader.g
|
|
let amap = infoReader.amap
|
|
infoReader.ReadEntireTypeHierachy(m,typ) |> List.collect (fun typ ->
|
|
if (is_stripped_tyapp_typ g typ) then
|
|
let tcref = tcref_of_stripped_typ g typ
|
|
(* NOTE: multiple "open"'s push multiple duplicate values into eExtensionMembers *)
|
|
(* REVIEW: this looks a little slow: ListSet.setify is quadratic. *)
|
|
let extValRefs = ListSet.setify (ExtensionMember.Equality g) (tcref_mmap_find tcref eExtensionMembers)
|
|
let propCollector = new PropertyCollector(g,amap,m,typ,optFilter,ad)
|
|
extValRefs |> List.iter (fun emem ->
|
|
match emem with
|
|
| FSExtMem vref ->
|
|
match vref.MemberInfo with
|
|
| None -> ()
|
|
| Some(membInfo) -> propCollector.Collect(membInfo,vref)
|
|
| ILExtMem _ ->
|
|
// No extension properties coming from .NET
|
|
())
|
|
propCollector.Close()
|
|
else [])
|
|
|
|
let AllPropInfosOfTypeInScope infoReader eExtensionMembers (optFilter, ad) findFlag m typ =
|
|
IntrinsicPropInfosOfTypeInScope infoReader (optFilter, ad) findFlag m typ
|
|
@ ExtensionPropInfosOfTypeInScope infoReader eExtensionMembers (optFilter, ad) findFlag m typ
|
|
|
|
let IntrinsicMethInfosOfType (infoReader:InfoReader) (optFilter,ad) findFlag m typ =
|
|
let g = infoReader.g
|
|
let amap = infoReader.amap
|
|
let minfos = GetIntrinsicMethInfoSetsOfType infoReader (optFilter,ad) findFlag m typ
|
|
let minfos = minfos |> ExcludeHiddenOfMethInfos g amap m
|
|
minfos
|
|
|
|
let ImmediateExtensionMethInfosOfTypeInScope (infoReader:InfoReader) eExtensionMembers (optFilter,ad) findFlag m typ =
|
|
let g = infoReader.g
|
|
if (is_stripped_tyapp_typ g typ) then
|
|
let tcref = tcref_of_stripped_typ g typ
|
|
// NOTE: multiple "open"'s push multiple duplicate values into eExtensionMembers
|
|
// REVIEW: this looks a little slow: ListSet.setify is quadratic.
|
|
let extValRefs = ListSet.setify (ExtensionMember.Equality g) (tcref_mmap_find tcref eExtensionMembers)
|
|
extValRefs |> List.choose (fun emem ->
|
|
match emem with
|
|
| FSExtMem vref ->
|
|
match vref.MemberInfo with
|
|
| None -> None
|
|
| Some(membInfo) -> TrySelectMemberVal g optFilter typ membInfo vref
|
|
| ILExtMem (actualParent,md) when (match optFilter with None -> true | Some(nm) -> nm = md.mdName) ->
|
|
// 'typ' is the logical parent
|
|
let tinfo = tinfo_of_il_typ g typ
|
|
Some(mk_il_minfo infoReader.amap m tinfo (Some(actualParent)) md)
|
|
| _ ->
|
|
None)
|
|
else []
|
|
|
|
let ExtensionMethInfosOfTypeInScope (infoReader:InfoReader) eExtensionMembers (optFilter,ad) findFlag m typ =
|
|
let g = infoReader.g
|
|
infoReader.ReadEntireTypeHierachy(m,typ) |> List.collect (fun typ ->
|
|
ImmediateExtensionMethInfosOfTypeInScope infoReader eExtensionMembers (optFilter,ad) findFlag m typ)
|
|
|
|
let AllMethInfosOfTypeInScope infoReader eExtensionMembers (optFilter,ad) findFlag m typ =
|
|
IntrinsicMethInfosOfType infoReader (optFilter,ad) findFlag m typ
|
|
@ ExtensionMethInfosOfTypeInScope infoReader eExtensionMembers (optFilter,ad) findFlag m typ
|
|
|
|
|
|
exception IndeterminateType of range
|
|
|
|
type LookupKind =
|
|
| RecdField
|
|
| Pattern
|
|
| Expr
|
|
| Type
|
|
| Ctor
|
|
|
|
|
|
let TryFindUnionCaseOfType g typ nm =
|
|
if is_stripped_tyapp_typ g typ then
|
|
let tcref,tinst = dest_stripped_tyapp_typ g typ
|
|
match tcref.GetUnionCaseByName nm with
|
|
| None -> None
|
|
| Some ucase -> Some(UnionCaseInfo(tinst,ucref_of_ucase tcref ucase))
|
|
else
|
|
None
|
|
|
|
// REVIEW: this shows up on performance logs. Consider for example endles resolutions of "List.map" to
|
|
// the empty set of results, or "x.Length" for a list or array type. This indicates it could be worth adding a cache here.
|
|
let rec ResolveLongIdentInTypePrim (ncenv:NameResolver) nenv lookupKind (resInfo:ResolutionInfo) depth m ad (lid:ident list) findFlag typeNameResInfo typ =
|
|
let g = ncenv.g
|
|
match lid with
|
|
| [] -> error(InternalError("ResolveLongIdentInTypePrim",m))
|
|
| id :: rest ->
|
|
let nm = id.idText // used to filter the searches of the tables
|
|
let optFilter = Some(nm) // used to filter the searches of the tables
|
|
let contentsSearchAccessible =
|
|
let unionCaseSearch =
|
|
if (match lookupKind with Expr | Pattern -> true | _ -> false) then
|
|
TryFindUnionCaseOfType g typ nm
|
|
else
|
|
None
|
|
// Lookup: datatype constructors take precedence
|
|
match unionCaseSearch with
|
|
| Some ucase ->
|
|
success(resInfo,Item_ucase(ucase),rest)
|
|
| None ->
|
|
match TryFindIntrinsicNamedItemOfType ncenv.InfoReader (nm,ad) findFlag m typ with
|
|
| Some (PropertyItem psets) when (match lookupKind with Expr -> true | _ -> false) ->
|
|
let pinfos = psets |> ExcludeHiddenOfPropInfos g ncenv.amap m
|
|
let item =
|
|
match pinfos with
|
|
| [pinfo] when pinfo.IsFSharpEventProperty ->
|
|
let minfos1 = GetImmediateIntrinsicMethInfosOfType (Some("add_"^nm),ad) g ncenv.amap m typ
|
|
let minfos2 = GetImmediateIntrinsicMethInfosOfType (Some("remove_"^nm),ad) g ncenv.amap m typ
|
|
match minfos1,minfos2 with
|
|
| [FSMeth(_,_,addValRef)],[FSMeth(_,_,removeValRef)] ->
|
|
// FOUND PROPERTY-AS-EVENT AND CORRESPONDING ADD/REMOVE METHODS
|
|
Item_event(FSEvent(g,pinfo,addValRef,removeValRef))
|
|
| _ ->
|
|
// FOUND PROPERTY-AS-EVENT BUT DIDN'T FIND CORRESPONDING ADD/REMOVE METHODS
|
|
Item_property (nm,pinfos)
|
|
| _ ->
|
|
Item_property (nm,pinfos)
|
|
|
|
|
|
success (resInfo,item,rest)
|
|
|
|
| Some(MethodItem msets) when (match lookupKind with Expr -> true | _ -> false) ->
|
|
let minfos = msets |> ExcludeHiddenOfMethInfos g ncenv.amap m
|
|
success (resInfo,MakeMethGroup (nm,minfos),rest)
|
|
|
|
| Some (ILFieldItem (finfo:: _)) when (match lookupKind with Expr | Pattern -> true | _ -> false) ->
|
|
success (resInfo,Item_il_field finfo,rest)
|
|
|
|
| Some (ILEventItem (einfo :: _)) when (match lookupKind with Expr -> true | _ -> false) ->
|
|
success (resInfo,Item_event (ILEvent(g,einfo)),rest)
|
|
| Some (RecdFieldItem (rfinfo)) when (match lookupKind with Expr | RecdField | Pattern -> true | _ -> false) ->
|
|
success(resInfo,Item_recdfield(rfinfo),rest)
|
|
| _ ->
|
|
let pinfos = ExtensionPropInfosOfTypeInScope ncenv.InfoReader nenv.eExtensionMembers (optFilter, ad) findFlag m typ
|
|
if nonNil(pinfos) && (match lookupKind with Expr -> true | _ -> false) then
|
|
success (resInfo,Item_property (nm,pinfos),rest) else
|
|
|
|
let minfos = ExtensionMethInfosOfTypeInScope ncenv.InfoReader nenv.eExtensionMembers (optFilter,ad) findFlag m typ
|
|
if nonNil(minfos) && (match lookupKind with Expr -> true | _ -> false) then
|
|
success (resInfo,MakeMethGroup (nm,minfos),rest) else
|
|
|
|
if is_typar_typ g typ then raze (IndeterminateType(union_ranges m id.idRange))
|
|
else raze (UndefinedName (depth,"field, constructor or member", id,[]))
|
|
|
|
let nestedSearchAccessible =
|
|
let nestedTypes = GetNestedTypesOfType ad ncenv (Some nm,(if isNil rest then snd typeNameResInfo else None)) m typ
|
|
let typeNameResFlag,numTyargsOpt = typeNameResInfo
|
|
if isNil rest then
|
|
if isNil nestedTypes then
|
|
NoResultsOrUsefulErrors
|
|
else
|
|
match typeNameResFlag with
|
|
| ResolveTypeNamesToCtors ->
|
|
nestedTypes |> CollectResults (ResolveObjectConstructorPrim ncenv nenv.eDisplayEnv resInfo m ad)
|
|
| ResolveTypeNamesToTypeRefs ->
|
|
OneSuccess (resInfo,Item_typs (nm,nestedTypes),rest)
|
|
else
|
|
ResolveLongIdentInTypes ncenv nenv lookupKind resInfo (depth+1) m ad rest findFlag typeNameResInfo nestedTypes
|
|
(OneResult contentsSearchAccessible +++ nestedSearchAccessible)
|
|
|
|
and ResolveLongIdentInTypes (ncenv:NameResolver) nenv lookupKind resInfo depth m ad lid findFlag typeNameResInfo typs =
|
|
typs |> CollectResults (ResolveLongIdentInTypePrim ncenv nenv lookupKind resInfo depth m ad lid findFlag typeNameResInfo >> AtMostOneResult m)
|
|
|
|
let ResolveLongIdentInType ncenv nenv lookupKind m ad lid findFlag typeNameResInfo typ =
|
|
let resInfo,item,rest =
|
|
ResolveLongIdentInTypePrim (ncenv:NameResolver) nenv lookupKind ResolutionInfo.Empty 0 m ad lid findFlag typeNameResInfo typ
|
|
|> AtMostOneResult m
|
|
|> ForceRaise
|
|
ResolutionInfo.SendToSink(ncenv,nenv,ad,resInfo,(fun () -> CheckAllTyparsInferrable ncenv.g ncenv.amap m item));
|
|
item,rest
|
|
|
|
// QUERY (instantiationGenerator cleanup): it would be really nice not to flow instantiationGenerator to here.
|
|
// This would help make it the separation between name resolution and
|
|
// type inference more obvious. However this would mean each caller
|
|
// would have to freshen.
|
|
let private ResolveLongIdentInTyconRef (ncenv:NameResolver) nenv lookupKind resInfo depth m ad lid typeNameResInfo tcref =
|
|
let typ = (FreshenTycon ncenv m tcref)
|
|
typ |> ResolveLongIdentInTypePrim ncenv nenv lookupKind resInfo depth m ad lid IgnoreOverrides typeNameResInfo
|
|
|
|
let private ResolveLongIdentInTyconRefs (ncenv:NameResolver) nenv lookupKind depth m ad lid typeNameResInfo idRange tcrefs =
|
|
// The basic search
|
|
tcrefs |> CollectResults (fun (resInfo:ResolutionInfo,tcref) ->
|
|
let resInfo = resInfo.AddEntity(idRange,tcref)
|
|
tcref |> ResolveLongIdentInTyconRef ncenv nenv lookupKind resInfo depth m ad lid typeNameResInfo |> AtMostOneResult m)
|
|
|
|
//-------------------------------------------------------------------------
|
|
// ResolveExprLongIdentInModuleOrNamespace
|
|
//-------------------------------------------------------------------------
|
|
|
|
let (|AccessibleEntityRef|_|) ad modref mspec =
|
|
let eref = MakeNestedTcref modref mspec
|
|
if IsEntityAccessible ad eref then Some(eref) else None
|
|
|
|
|
|
let rec ResolveExprLongIdentInModuleOrNamespace (ncenv:NameResolver) nenv typeNameResInfo ad resInfo depth m modref (mty:ModuleOrNamespaceType) (lid :ident list) =
|
|
// resInfo records the modules or namespaces actually relevant to a resolution
|
|
let g = ncenv.g
|
|
match lid with
|
|
| [] -> raze (InternalError("ResolveExprLongIdentInModuleOrNamespace",m))
|
|
| id :: rest ->
|
|
match mty.AllValuesAndMembers.TryFind(id.idText) with
|
|
| Some vspec when IsValAccessible ad (mk_vref_in_modref modref vspec) ->
|
|
success(resInfo,Item_val (mk_vref_in_modref modref vspec),rest)
|
|
| _->
|
|
match TryFindTypeWithUnionCase modref id with
|
|
| Some tycon when IsTyconReprAccessible ad (MakeNestedTcref modref tycon) ->
|
|
let ucref = mk_ucref (MakeNestedTcref modref tycon) id.idText
|
|
let ucinfo = FreshenUnionCaseRef ncenv m ucref
|
|
success (resInfo,Item_ucase ucinfo,rest)
|
|
| _ ->
|
|
match mty.ExceptionDefinitionsByDemangledName.TryFind(id.idText) with
|
|
| Some excon when IsTyconReprAccessible ad (MakeNestedTcref modref excon) ->
|
|
success (resInfo,Item_ecref (MakeNestedTcref modref excon),rest)
|
|
| _ ->
|
|
|
|
(* Something in a type? *)
|
|
let tyconSearch =
|
|
let tcrefs = LookupTypeNameInEntityMaybeHaveArity ad id.idRange id.idText (if nonNil rest then None else snd typeNameResInfo) modref
|
|
let tcrefs = tcrefs |> List.map (fun tcref -> (resInfo,tcref))
|
|
if (nonNil rest) then
|
|
let tcrefs = CheckForMultipleGenericTypeAmbiguities tcrefs (ResolveTypeNamesToTypeRefs,None) m
|
|
ResolveLongIdentInTyconRefs ncenv nenv LookupKind.Expr (depth+1) m ad rest typeNameResInfo id.idRange tcrefs
|
|
(* check if we've got some explicit type arguments *)
|
|
else
|
|
let tcrefs = CheckForMultipleGenericTypeAmbiguities tcrefs typeNameResInfo m
|
|
match fst typeNameResInfo with
|
|
| ResolveTypeNamesToTypeRefs ->
|
|
success [ for (resInfo,tcref) in tcrefs do
|
|
let typ = FreshenTycon ncenv m tcref
|
|
let item = (resInfo,Item_typs(id.idText,[typ]),[])
|
|
yield item ]
|
|
| ResolveTypeNamesToCtors ->
|
|
let typs = tcrefs |> List.map (fun (resInfo, tcref) -> resInfo, FreshenTycon ncenv m tcref)
|
|
typs |> CollectResults (fun (resInfo,typ) -> ResolveObjectConstructorPrim ncenv nenv.eDisplayEnv resInfo id.idRange ad typ)
|
|
|
|
(* Something in a sub-namespace or sub-module *)
|
|
let moduleSearch =
|
|
if (nonNil rest) then
|
|
match mty.ModulesAndNamespacesByDemangledName.TryFind(id.idText) with
|
|
| Some(AccessibleEntityRef ad modref submodref) ->
|
|
let resInfo = resInfo.AddEntity(id.idRange,submodref)
|
|
|
|
OneResult (ResolveExprLongIdentInModuleOrNamespace ncenv nenv typeNameResInfo ad resInfo (depth+1) m submodref submodref.ModuleOrNamespaceType rest)
|
|
| _ ->
|
|
NoResultsOrUsefulErrors
|
|
else
|
|
NoResultsOrUsefulErrors
|
|
|
|
AtMostOneResult id.idRange ( tyconSearch +++ moduleSearch +++ raze (UndefinedName(depth,"value, constructor, namespace or type",id,[])))
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
/// Resolve F# "A.B.C" syntax in expressions
|
|
/// Not all of the sequence will necessarily be swallowed, i.e. we return some identifiers
|
|
/// that may represent further actions, e.g. further lookups.
|
|
|
|
let ResolveExprLongIdent (ncenv:NameResolver) m ad nenv typeNameResInfo lid =
|
|
let g = ncenv.g
|
|
let resInfo = ResolutionInfo.Empty
|
|
match lid with
|
|
| [] -> error (Error("invalid expression: "^text_of_lid lid, m))
|
|
| [id] ->
|
|
// Single identifier. This is the basic rule: lookup the environment! simple enough
|
|
match nenv.eUnqualifiedItems.TryFind(id.idText) with
|
|
| Some res ->
|
|
FreshenUnqualifiedItem ncenv m res, []
|
|
| None ->
|
|
// Check if it's a type name, e.g. a constructor call or a type instantiation
|
|
let ctorSearch =
|
|
let tcrefs = LookupTypeNameInEnvMaybeHaveArity id.idText typeNameResInfo nenv
|
|
let tcrefs = tcrefs |> List.map (fun tcref -> (resInfo,tcref))
|
|
let tcrefs = CheckForMultipleGenericTypeAmbiguities tcrefs typeNameResInfo m
|
|
match fst typeNameResInfo with
|
|
| ResolveTypeNamesToCtors ->
|
|
let tcrefs = tcrefs |> List.filter (fun (_,tcref) -> tcref.IsILTycon || tcref.IsFSharpObjectModelTycon)
|
|
let typs = tcrefs |> List.map (fun (resInfo,tcref) -> (resInfo,FreshenTycon ncenv m tcref))
|
|
typs
|
|
|> CollectResults (fun (resInfo,typ) -> ResolveObjectConstructorPrim ncenv nenv.eDisplayEnv resInfo id.idRange ad typ)
|
|
| ResolveTypeNamesToTypeRefs ->
|
|
let typs = tcrefs |> List.map (fun (resInfo,tcref) -> (resInfo,FreshenTycon ncenv m tcref))
|
|
success (typs |> List.map (fun (resInfo,typ) -> (resInfo,Item_typs(id.idText,[typ]),[])))
|
|
|
|
|
|
let implicitOpSearch =
|
|
if IsMangledOpName id.idText then
|
|
success [(resInfo,Item_implicit_op id,[])]
|
|
else NoResultsOrUsefulErrors
|
|
|
|
let failingCase = raze (UndefinedName(0,"value or constructor",id,[]))
|
|
let search = ctorSearch +++ implicitOpSearch +++ failingCase
|
|
let resInfo,item,rest = ForceRaise (AtMostOneResult m search)
|
|
ResolutionInfo.SendToSink(ncenv,nenv,ad,resInfo,(fun () -> CheckAllTyparsInferrable ncenv.g ncenv.amap m item));
|
|
item,rest
|
|
|
|
|
|
// A compound identifier.
|
|
// It still might be a value in the environment, or something in an F# module, namespace, typ, or nested type
|
|
| id :: rest ->
|
|
|
|
// Values in the environment take total priority, but contructors do NOT for compound lookups, e.g. if someone in some imported
|
|
// module has defined a constructor "String" (common enough) then "String.foo" doesn't give an error saying 'constructors have no members'
|
|
// Instead we go lookup the String module or type.
|
|
let ValIsInEnv nm =
|
|
(match nenv.eUnqualifiedItems.TryFind(nm) with Some(Item_val _) -> true | _ -> false)
|
|
|
|
if ValIsInEnv id.idText &&
|
|
(* Workaround for bug 908: adding "int", "float" etc. as functions has broken their use as types, and now System.Int32 etc. have *)
|
|
(* to be used instead. Here we are friendly and allow them to be used as types and just give a warning instead. *)
|
|
(* Here we check that the thing being referenced is indeed a function value, and we know that we're doing a "int.Foo" lookup *)
|
|
(* which doesn't make sense on a function value, so we give a warning and revert to the old interpretation. *)
|
|
match nenv.eUnqualifiedItems.[id.idText] with
|
|
| Item_val vref when
|
|
(let nm = vref.MangledName
|
|
(match nm with "string" | "int" | "float" | "float32" | "single" | "double" | "sbyte" | "byte" | "int16" | "uint16" | "int32" | "uint32" -> true | _ -> false)
|
|
&& let _,tau = vref.TypeScheme in is_fun_typ g tau)
|
|
->
|
|
warning(Error(sprintf "The standard definition of the identifier '%s' is now a function used to convert values to type '%s', or will be in a future release. Access static methods via the canonical uppercase name for the type, e.g. replace 'int.Parse(...)' with 'System.Int32.Parse(...)'" vref.MangledName vref.MangledName,id.idRange));
|
|
false
|
|
| _ -> true
|
|
then
|
|
nenv.eUnqualifiedItems.[id.idText], rest
|
|
else
|
|
// Otherwise modules are searched first. REVIEW: modules and types should be searched together.
|
|
// For each module referenced by 'id', search the module as if it were an F# module and/or a .NET namespace.
|
|
let moduleSearch ad =
|
|
ResolveLongIndentAsModuleOrNamespaceThen OpenQualified nenv ad lid
|
|
(ResolveExprLongIdentInModuleOrNamespace ncenv nenv typeNameResInfo ad)
|
|
|
|
// REVIEW: somewhat surprisingly, this shows up on performance traces, with tcrefs non-nil.
|
|
// This seems strange since we would expect in the vast majority of cases tcrefs is empty here.
|
|
let tyconSearch ad =
|
|
let tcrefs = LookupTypeNameInEnvNoArity id.idText nenv
|
|
let tcrefs = tcrefs |> List.map (fun tcref -> (resInfo,tcref))
|
|
let tcrefs = CheckForMultipleGenericTypeAmbiguities tcrefs (ResolveTypeNamesToTypeRefs,None) m
|
|
ResolveLongIdentInTyconRefs ncenv nenv LookupKind.Expr 1 m ad rest typeNameResInfo id.idRange tcrefs
|
|
|
|
let envSearch =
|
|
match Map.tryfind id.idText nenv.eUnqualifiedItems with
|
|
| Some res -> OneSuccess (resInfo,FreshenUnqualifiedItem ncenv m res,rest)
|
|
| None -> NoResultsOrUsefulErrors
|
|
|
|
let search = moduleSearch ad +++ tyconSearch ad +++ envSearch
|
|
|
|
let resInfo,item,rest =
|
|
match AtMostOneResult m search with
|
|
| Result _ as res ->
|
|
ForceRaise res
|
|
| _ ->
|
|
let failingCase = raze (UndefinedName(0,"value, namespace, type or module",id,[]))
|
|
ForceRaise (AtMostOneResult m (search +++ moduleSearch AccessibleFromSomeFSharpCode +++ tyconSearch AccessibleFromSomeFSharpCode +++ failingCase))
|
|
ResolutionInfo.SendToSink(ncenv,nenv,ad,resInfo,(fun () -> CheckAllTyparsInferrable ncenv.g ncenv.amap m item));
|
|
item,rest
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Resolve F#/IL "." syntax in patterns
|
|
//-------------------------------------------------------------------------
|
|
|
|
let rec ResolvePatternLongIdentInModuleOrNamespace (ncenv:NameResolver) nenv numTyArgsOpt ad resInfo depth m modref (mty:ModuleOrNamespaceType) lid =
|
|
let g = ncenv.g
|
|
if verbose then dprintf "--> ResolvePatternLongIdentInModuleOrNamespace edenv, lid = %s@%a\n" (text_of_lid lid) output_range m ;
|
|
match lid with
|
|
| [] -> raze (Error("ResolvePatternLongIdentInModuleOrNamespace edenv",m))
|
|
| id :: rest ->
|
|
match TryFindTypeWithUnionCase modref id with
|
|
| Some tycon when IsTyconReprAccessible ad (MakeNestedTcref modref tycon) ->
|
|
let tcref = MakeNestedTcref modref tycon
|
|
let ucref = mk_ucref tcref id.idText
|
|
let ucinfo = FreshenUnionCaseRef ncenv m ucref
|
|
success (resInfo,Item_ucase ucinfo,rest)
|
|
| _ ->
|
|
match mty.ExceptionDefinitionsByDemangledName.TryFind(id.idText) with
|
|
| Some exnc when IsEntityAccessible ad (MakeNestedTcref modref exnc) ->
|
|
success (resInfo,Item_ecref (MakeNestedTcref modref exnc),rest)
|
|
| _ ->
|
|
// An active pattern constructor in a module
|
|
match (ActivePatternElemsOfModuleOrNamespace modref).TryFind(id.idText) with
|
|
| Some ( APElemRef(_,vref,_) as apref) when IsValAccessible ad vref ->
|
|
success (resInfo,Item_apelem apref,rest)
|
|
| _ ->
|
|
match mty.AllValuesAndMembers.TryFind(id.idText) with
|
|
| Some vspec when IsValAccessible ad (mk_vref_in_modref modref vspec) ->
|
|
success(resInfo,Item_val (mk_vref_in_modref modref vspec),rest)
|
|
| _ ->
|
|
// Something in a type? e.g. a literal field
|
|
let tcrefs = LookupTypeNameInEntityMaybeHaveArity ad id.idRange id.idText None modref
|
|
let tcrefs = tcrefs |> List.map (fun tcref -> (resInfo,tcref))
|
|
let tyconSearch =
|
|
match lid with
|
|
| tn:: rest when nonNil rest ->
|
|
ResolveLongIdentInTyconRefs (ncenv:NameResolver) nenv LookupKind.Pattern (depth+1) m ad rest numTyArgsOpt id.idRange tcrefs
|
|
| _ ->
|
|
NoResultsOrUsefulErrors
|
|
// Constructor of a type?
|
|
let ctorSearch =
|
|
let typs = tcrefs |> List.map (fun (resInfo,tcref) -> (resInfo,FreshenTycon ncenv m tcref))
|
|
typs |> CollectResults (fun (resInfo,typ) -> ResolveObjectConstructorPrim ncenv nenv.eDisplayEnv resInfo id.idRange ad typ)
|
|
// Something in a sub-namespace or sub-module or nested-type
|
|
let moduleSearch =
|
|
if (nonNil rest) then
|
|
match mty.ModulesAndNamespacesByDemangledName.TryFind(id.idText) with
|
|
| Some(AccessibleEntityRef ad modref submodref) ->
|
|
let resInfo = resInfo.AddEntity(id.idRange,submodref)
|
|
OneResult (ResolvePatternLongIdentInModuleOrNamespace ncenv nenv numTyArgsOpt ad resInfo (depth+1) m submodref submodref.ModuleOrNamespaceType rest)
|
|
| _ ->
|
|
NoResultsOrUsefulErrors
|
|
else NoResultsOrUsefulErrors
|
|
let res = AtMostOneResult id.idRange ( tyconSearch +++ ctorSearch +++ moduleSearch +++ raze (UndefinedName(depth,"constructor, module or namespace",id,[])))
|
|
res
|
|
|
|
exception UpperCaseIdentifierInPattern of range
|
|
type WarnOnUpperFlag = WarnOnUpperCase | AllIdsOK
|
|
|
|
|
|
// Long ID in a pattern
|
|
let ResolvePatternLongIdent (ncenv:NameResolver) warnOnUpper newDef m ad nenv numTyArgsOpt (lid:ident list) =
|
|
let g = ncenv.g
|
|
match lid with
|
|
// Single identifiers in patterns
|
|
| [id] ->
|
|
// Single identifiers in patterns - bind to constructors and active patterns
|
|
// For the special case of
|
|
// let C = x
|
|
match nenv.ePatItems.TryFind(id.idText) with
|
|
| Some res when not newDef -> FreshenUnqualifiedItem ncenv m res
|
|
| _ ->
|
|
// Single identifiers in patterns - variable bindings
|
|
if not newDef &&
|
|
(warnOnUpper = WarnOnUpperCase) &&
|
|
id.idText.Length >= 3 &&
|
|
System.Char.ToLowerInvariant id.idText.[0] <> id.idText.[0] then
|
|
warning(UpperCaseIdentifierInPattern(m));
|
|
Item_newdef id
|
|
|
|
// Long identifiers in patterns
|
|
| _ ->
|
|
if verbose then dprintf "--> ResolvePatternLongIdent, lid = %s@%a\n" (text_of_lid lid) output_range m ;
|
|
let moduleSearch ad =
|
|
ResolveLongIndentAsModuleOrNamespaceThen OpenQualified nenv ad lid
|
|
(ResolvePatternLongIdentInModuleOrNamespace ncenv nenv numTyArgsOpt ad)
|
|
let tyconSearch ad =
|
|
match lid with
|
|
| tn:: rest when nonNil rest ->
|
|
let tcrefs = LookupTypeNameInEnvNoArity tn.idText nenv
|
|
let tcrefs = tcrefs |> List.map (fun tcref -> (ResolutionInfo.Empty,tcref))
|
|
ResolveLongIdentInTyconRefs ncenv nenv LookupKind.Pattern 1 tn.idRange ad rest numTyArgsOpt tn.idRange tcrefs
|
|
| _ ->
|
|
NoResultsOrUsefulErrors
|
|
let resInfo,res,rest =
|
|
match AtMostOneResult m (tyconSearch ad +++ moduleSearch ad) with
|
|
| Result _ as res -> ForceRaise res
|
|
| _ ->
|
|
ForceRaise (AtMostOneResult m (tyconSearch AccessibleFromSomeFSharpCode +++ moduleSearch AccessibleFromSomeFSharpCode))
|
|
ResolutionInfo.SendToSink(ncenv,nenv,ad,resInfo,(fun () -> true));
|
|
|
|
if nonNil rest then error(Error("this is not a constructor or literal, or a constructor is being used incorrectly",(List.hd rest).idRange));
|
|
res
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Resolve F#/IL "." syntax in types
|
|
//-------------------------------------------------------------------------
|
|
|
|
let rec ResolveTypeLongIdentInTypePrim (ncenv:NameResolver) typeNameResInfo ad resInfo depth m tcref (lid: ident list) =
|
|
match lid with
|
|
| [] -> error(Error("Unexpected empty long identifier",m))
|
|
| [id] ->
|
|
let tcrefs = LookupTypeNameInEntityMaybeHaveArity ad id.idRange id.idText (snd typeNameResInfo) tcref
|
|
let tcrefs = tcrefs |> List.map (fun tcref -> (resInfo,tcref))
|
|
let tcrefs = CheckForMultipleGenericTypeAmbiguities tcrefs typeNameResInfo m
|
|
match tcrefs with
|
|
| tcref :: _ -> success tcref
|
|
| [] -> raze (UndefinedName(depth,"type",id,[]))
|
|
| id::rest ->
|
|
// Search nested types
|
|
let tyconSearch =
|
|
let tcrefs = LookupTypeNameInEntityMaybeHaveArity ad id.idRange id.idText None tcref
|
|
let tcrefs = tcrefs |> List.map (fun tcref -> (resInfo,tcref))
|
|
let tcrefs = CheckForMultipleGenericTypeAmbiguities tcrefs (fst typeNameResInfo,None) m
|
|
tcrefs |> CollectResults (fun (resInfo,tcref) -> ResolveTypeLongIdentInTypePrim ncenv typeNameResInfo ad resInfo (depth+1) m tcref rest)
|
|
AtMostOneResult m tyconSearch
|
|
|
|
let ResolveTypeLongIdentInType (ncenv:NameResolver) nenv typeNameResInfo ad m tcref (lid: ident list) =
|
|
let resInfo,tcref = ForceRaise (ResolveTypeLongIdentInTypePrim ncenv typeNameResInfo ad ResolutionInfo.Empty 0 m tcref lid)
|
|
ResolutionInfo.SendToSink(ncenv,nenv,ad,resInfo,(fun () -> true));
|
|
tcref
|
|
|
|
|
|
let rec private ResolveTypeLongIdentInModuleOrNamespace (ncenv:NameResolver) typeNameResInfo ad (resInfo:ResolutionInfo) depth m modref mty (lid: ident list) =
|
|
let g = ncenv.g
|
|
match lid with
|
|
| [] -> error(Error("Unexpected empty long identifier",m))
|
|
| [id] ->
|
|
// On all paths except error reporting we have isSome(numTyargsOpt), hence get at most one result back
|
|
let tcrefs = LookupTypeNameInEntityMaybeHaveArity ad id.idRange id.idText (snd typeNameResInfo) modref
|
|
if nonNil tcrefs then
|
|
tcrefs |> CollectResults (fun tcref -> success(resInfo,tcref))
|
|
else
|
|
raze (UndefinedName(depth,"type",id,[]))
|
|
| id::rest ->
|
|
let modulSearch =
|
|
match modref.ModuleOrNamespaceType.ModulesAndNamespacesByDemangledName.TryFind(id.idText) with
|
|
| Some(AccessibleEntityRef ad modref submodref) ->
|
|
let resInfo = resInfo.AddEntity(id.idRange,submodref)
|
|
ResolveTypeLongIdentInModuleOrNamespace ncenv typeNameResInfo ad resInfo (depth+1) m submodref submodref.ModuleOrNamespaceType rest
|
|
| _ ->
|
|
raze (UndefinedName(depth,"module or namespace",id,[]))
|
|
let tyconSearch =
|
|
let tcrefs = LookupTypeNameInEntityMaybeHaveArity ad id.idRange id.idText None modref
|
|
tcrefs |> CollectResults (fun tcref -> ResolveTypeLongIdentInTypePrim ncenv typeNameResInfo ad resInfo (depth+1) m tcref rest)
|
|
tyconSearch +++ modulSearch
|
|
|
|
let ResolveTypeLongIdentPrim (ncenv:NameResolver) fullyQualified m nenv ad (lid: ident list) ntyargs =
|
|
let g = ncenv.g
|
|
match lid with
|
|
| [] -> error(Error("Unexpected empty long identifier",m))
|
|
| [id] ->
|
|
match LookupTypeNameInEnvHaveArity id.idText ntyargs nenv with
|
|
| Some res -> success(ResolutionInfo.Empty,res)
|
|
| None ->
|
|
(* For Good Error Reporting! *)
|
|
let tcrefs = LookupTypeNameInEnvNoArity id.idText nenv
|
|
match tcrefs with
|
|
| tcref :: tcrefs ->
|
|
// Note: This path is only for error reporting
|
|
//CheckForMultipleGenericTypeAmbiguities tcref rest typeNameResInfo m;
|
|
success(ResolutionInfo.Empty,tcref)
|
|
| [] ->
|
|
raze (UndefinedName(0,"type",id,NameMap.domainL nenv.eTyconsByAccessNames))
|
|
| id::rest ->
|
|
let typeNameResInfo = (ResolveTypeNamesToTypeRefs,Some(ntyargs))
|
|
let tyconSearch =
|
|
match LookupTypeNameInEnvHaveArity id.idText ntyargs nenv with
|
|
| Some tcref when IsEntityAccessible ad tcref ->
|
|
OneResult (ResolveTypeLongIdentInTypePrim ncenv typeNameResInfo ad ResolutionInfo.Empty 1 m tcref rest)
|
|
| _ ->
|
|
NoResultsOrUsefulErrors
|
|
let modulSearch =
|
|
ResolveLongIndentAsModuleOrNamespaceThen fullyQualified nenv ad lid
|
|
(ResolveTypeLongIdentInModuleOrNamespace ncenv typeNameResInfo ad)
|
|
|?> (fun res -> List.concat res)
|
|
|
|
let modulSearchFailed =
|
|
ResolveLongIndentAsModuleOrNamespaceThen fullyQualified nenv AccessibleFromSomeFSharpCode lid
|
|
(ResolveTypeLongIdentInModuleOrNamespace ncenv (ResolveTypeNamesToTypeRefs,None) ad)
|
|
|?> (fun res -> List.concat res)
|
|
(*
|
|
let tyconSearchFailed =
|
|
(* For Good Error Reporting! *)
|
|
match LookupTypeNameInEnvNoArity id.idText nenv with
|
|
| [] -> NoResultsOrUsefulErrors
|
|
| tcrefs -> success(tcrefs)
|
|
*)
|
|
match tyconSearch +++ modulSearch with
|
|
| Result results ->
|
|
// NOTE: we delay checking the CheckForMultipleGenericTypeAmbiguities condition until right at the end after we've
|
|
// collected all possible resolutions of the type
|
|
let tcrefs = CheckForMultipleGenericTypeAmbiguities results typeNameResInfo m
|
|
match tcrefs with
|
|
| (resInfo,tcref) :: _ ->
|
|
// We've already reported the ambiguity, possibly as an error. Now just take the first possible result.
|
|
success(resInfo,tcref)
|
|
| [] ->
|
|
// failing case - report nice ambiguity errors even in this case
|
|
AtMostOneResult m ((tyconSearch +++ modulSearch +++ modulSearchFailed) |?> (fun tcrefs -> CheckForMultipleGenericTypeAmbiguities tcrefs typeNameResInfo m))
|
|
|
|
| _ ->
|
|
// failing case - report nice ambiguity errors even in this case
|
|
AtMostOneResult m ((tyconSearch +++ modulSearch +++ modulSearchFailed) |?> (fun tcrefs -> CheckForMultipleGenericTypeAmbiguities tcrefs typeNameResInfo m))
|
|
|
|
|
|
let ResolveTypeLongIdent (ncenv:NameResolver) occurence fullyQualified nenv ad (lid: ident list) ntyargs =
|
|
let m = range_of_lid lid
|
|
let res = ResolveTypeLongIdentPrim ncenv fullyQualified m nenv ad lid ntyargs
|
|
// Register the result as a name resolution
|
|
match res with
|
|
| Result (resInfo,tcref) ->
|
|
ResolutionInfo.SendToSink(ncenv,nenv,ad,resInfo,(fun () -> true));
|
|
CallNameResolutionSink(m,nenv,Item_typs(tcref.DisplayName,[FreshenTycon ncenv m tcref]),occurence,nenv.eDisplayEnv,ad)
|
|
| _ -> ()
|
|
res |?> snd
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Resolve F#/IL "." syntax in records etc.
|
|
//-------------------------------------------------------------------------
|
|
|
|
exception DeprecatedClassFieldInference of range
|
|
|
|
let rec ResolveFieldInModuleOrNamespace (ncenv:NameResolver) nenv ad (resInfo:ResolutionInfo) depth m modref mty lid =
|
|
let typeNameResInfo = DefaultTypeNameResInfo
|
|
let g = ncenv.g
|
|
if verbose then dprintf "--> ResolveFieldInModuleOrNamespace edenv, lid = %s@%a\n" (text_of_lid lid) output_range m ;
|
|
match lid with
|
|
| id::rest ->
|
|
let error = raze (UndefinedName(depth,"record label or namespace",id,[]))
|
|
(* search for module-qualified names, e.g. { Microsoft.FSharp.Core.contents = 1 } *)
|
|
let modulScopedFieldNames =
|
|
match TryFindTypeWithRecdField mty id with
|
|
| Some tycon when IsEntityAccessible ad (MakeNestedTcref modref tycon) ->
|
|
success(mk_rfref_in_tcref modref tycon id, rest)
|
|
| _ -> error
|
|
// search for type-qualified names, e.g. { Microsoft.FSharp.Core.Ref.contents = 1 }
|
|
let tyconSearch =
|
|
match lid with
|
|
| tn:: rest when nonNil rest ->
|
|
let tcrefs = LookupTypeNameInEntityMaybeHaveArity ad id.idRange id.idText None modref
|
|
let tcrefs = tcrefs |> List.map (fun tcref -> (ResolutionInfo.Empty,tcref))
|
|
let tyconSearch = ResolveLongIdentInTyconRefs ncenv nenv LookupKind.RecdField (depth+1) m ad rest typeNameResInfo id.idRange tcrefs
|
|
// choose only fields
|
|
let tyconSearch = tyconSearch |?> List.choose (function (_,Item_recdfield(RecdFieldInfo(_,rfref)),rest) -> Some(rfref,rest) | _ -> None)
|
|
tyconSearch
|
|
| _ ->
|
|
NoResultsOrUsefulErrors
|
|
(* search for names in nested modules, e.g. { Microsoft.FSharp.Core.contents = 1 } *)
|
|
let modulSearch =
|
|
if nonNil rest then
|
|
match mty.ModulesAndNamespacesByDemangledName.TryFind(id.idText) with
|
|
| Some(AccessibleEntityRef ad modref submodref) ->
|
|
let resInfo = resInfo.AddEntity(id.idRange,submodref)
|
|
ResolveFieldInModuleOrNamespace ncenv nenv ad resInfo (depth+1) m submodref submodref.ModuleOrNamespaceType rest
|
|
| _ ->
|
|
error
|
|
else error
|
|
AtMostOneResult m (OneResult modulScopedFieldNames +++ tyconSearch +++ OneResult modulSearch)
|
|
| [] -> failwith "ResolveFieldInModuleOrNamespace edenv"
|
|
|
|
let ResolveField (ncenv:NameResolver) nenv ad typ (mp,id:ident) =
|
|
let typeNameResInfo = DefaultTypeNameResInfo
|
|
let g = ncenv.g
|
|
let m = id.idRange
|
|
match mp with
|
|
| [] ->
|
|
if is_stripped_tyapp_typ g typ then
|
|
match ncenv.InfoReader.TryFindRecdFieldInfoOfType(id.idText,m,typ) with
|
|
| Some (RecdFieldInfo(_,rfref)) -> [(rfref,true)]
|
|
| None -> error(Error(sprintf "The type %s does not contain a field %s" (NicePrint.pretty_string_of_typ nenv.eDisplayEnv typ) id.idText,m))
|
|
else
|
|
let frefs = tryname "record label" nenv.eFieldLabels id
|
|
(* Eliminate duplicates arising from multiple 'open' *)
|
|
let frefs = frefs |> ListSet.setify (fun (fref1,_) (fref2,_) -> tcref_eq g fref1.TyconRef fref2.TyconRef)
|
|
frefs
|
|
|
|
| _ ->
|
|
let lid = (mp@[id])
|
|
let tyconSearch ad =
|
|
match lid with
|
|
| tn:: (_ :: _ as rest) ->
|
|
let m = tn.idRange
|
|
let tcrefs = LookupTypeNameInEnvNoArity tn.idText nenv
|
|
let tcrefs = tcrefs |> List.map (fun tcref -> (ResolutionInfo.Empty,tcref))
|
|
let tyconSearch = ResolveLongIdentInTyconRefs ncenv nenv LookupKind.RecdField 1 m ad rest typeNameResInfo tn.idRange tcrefs
|
|
// choose only fields
|
|
let tyconSearch = tyconSearch |?> List.choose (function (_,Item_recdfield(RecdFieldInfo(_,rfref)),rest) -> Some(rfref,rest) | _ -> None)
|
|
tyconSearch
|
|
| _ -> NoResultsOrUsefulErrors
|
|
let modulSearch ad =
|
|
ResolveLongIndentAsModuleOrNamespaceThen OpenQualified nenv ad lid
|
|
(ResolveFieldInModuleOrNamespace ncenv nenv ad)
|
|
let item,rest = ForceRaise (AtMostOneResult m (modulSearch ad +++ tyconSearch ad +++ modulSearch AccessibleFromSomeFSharpCode +++ tyconSearch AccessibleFromSomeFSharpCode))
|
|
if nonNil rest then errorR(Error("invalid field label",(List.hd rest).idRange));
|
|
[(item,true)]
|
|
|
|
/// Generate a new reference to a record field with a fresh type instantiation
|
|
let FreshenRecdFieldRef (ncenv:NameResolver) m (rfref:RecdFieldRef) =
|
|
Item_recdfield(RecdFieldInfo(ncenv.instantiationGenerator m (rfref.Tycon.Typars(m)), rfref))
|
|
|
|
|
|
|
|
/// Resolve F#/IL "." syntax in expressions (2).
|
|
/// We have an expr. on the left, and we do an access, e.g.
|
|
/// (f obj).field or (f obj).meth. The basic rule is that if l-r type
|
|
/// inference has determined the outer type then we can proceed in a simple fashion. The exception
|
|
/// to the rule is for field types, which applies if l-r was insufficient to
|
|
/// determine any valid members
|
|
//
|
|
// QUERY (instantiationGenerator cleanup): it would be really nice not to flow instantiationGenerator to here.
|
|
let private ResolveExprDotLongIdent (ncenv:NameResolver) m ad nenv typ lid findFlag =
|
|
let g = ncenv.g
|
|
let typeNameResInfo = DefaultTypeNameResInfo
|
|
let adhoctDotSearchAccessible = AtMostOneResult m (ResolveLongIdentInTypePrim ncenv nenv LookupKind.Expr ResolutionInfo.Empty 1 m ad lid findFlag typeNameResInfo typ)
|
|
match adhoctDotSearchAccessible with
|
|
| Exception _ ->
|
|
// If the dot is not resolved by adhoc overloading then look for a record field
|
|
// that can resolve the name.
|
|
let dotFieldIdSearch =
|
|
match lid with
|
|
// A unique record label access, e.g expr.field
|
|
| id::rest when nenv.eFieldLabels.ContainsKey(id.idText) ->
|
|
match nenv.eFieldLabels.[id.idText] with
|
|
| [] -> NoResultsOrUsefulErrors
|
|
| (rfref,isRecdField) :: _ ->
|
|
if not isRecdField then errorR(DeprecatedClassFieldInference(m));
|
|
// NOTE (instantiationGenerator cleanup): we need to freshen here because we don't know the type.
|
|
// But perhaps the caller should freshen??
|
|
let item = FreshenRecdFieldRef ncenv m rfref
|
|
OneSuccess (ResolutionInfo.Empty,item,rest)
|
|
| _ -> NoResultsOrUsefulErrors
|
|
|
|
// A unique record label access qualified by a module, e.g expr.Module.field
|
|
// Really for OCaml compat. only
|
|
let moduleFieldIdSearch =
|
|
match lid with
|
|
| id::(_ :: _ as rest) when nenv.eModulesAndNamespaces.ContainsKey(id.idText) ->
|
|
ResolveLongIndentAsModuleOrNamespaceThen OpenQualified nenv ad lid
|
|
(ResolveFieldInModuleOrNamespace ncenv nenv ad)
|
|
(* QUERY: should caller freshen? *)
|
|
|?> List.map (fun (rfref,rest) ->
|
|
warning(OCamlCompatibility("This lookup resolves to a record field by using the syntax 'expr.Module.field'. Although this is allowed for OCaml compatibility, the style is considered deprecated for F#. Consider using a simple field lookup 'expr.field', perhaps with an annotation to constrain the type of 'expr'",m));
|
|
(ResolutionInfo.Empty,FreshenRecdFieldRef ncenv m rfref,rest))
|
|
| _ -> NoResultsOrUsefulErrors
|
|
let search = dotFieldIdSearch +++ moduleFieldIdSearch
|
|
match AtMostOneResult m search with
|
|
| Result _ as res -> ForceRaise res
|
|
| _ ->
|
|
let adhoctDotSearchAll = ResolveLongIdentInTypePrim ncenv nenv LookupKind.Expr ResolutionInfo.Empty 1 m AccessibleFromSomeFSharpCode lid findFlag typeNameResInfo typ
|
|
ForceRaise (AtMostOneResult m (search +++ adhoctDotSearchAll))
|
|
|
|
| Result _ ->
|
|
ForceRaise adhoctDotSearchAccessible
|
|
|
|
let ComputeItemRange wholem (lid: ident list) rest =
|
|
match rest with
|
|
| [] -> wholem
|
|
| _ ->
|
|
let ids,_ = List.chop (max 0 (lid.Length - rest.Length)) lid
|
|
match ids with
|
|
| [] -> wholem
|
|
| _ -> range_of_lid ids
|
|
|
|
/// Filters method groups that will be sent to Visual Studio IntelliSense
|
|
/// to include only static/instance members
|
|
let filterMethodGroups (ncenv:NameResolver) itemRange item staticOnly =
|
|
match item with
|
|
| Item_meth_group(nm, minfos) ->
|
|
let minfos = minfos |> List.filter (fun minfo ->
|
|
staticOnly = (ObjTypesOfMethInfo ncenv.amap itemRange minfo minfo.FormalMethodInst |> isNil))
|
|
Item_meth_group(nm, minfos)
|
|
| item -> item
|
|
|
|
/// Called for 'TypeName.Bar' - for VS IntelliSense, we can filter out instance members from method groups
|
|
let ResolveLongIdentAsExprAndComputeRange (ncenv:NameResolver) wholem ad nenv typeNameResInfo lid =
|
|
let item,rest = ResolveExprLongIdent ncenv wholem ad nenv typeNameResInfo lid
|
|
let itemRange = ComputeItemRange wholem lid rest
|
|
|
|
// Record the precise resolution of the field for intellisense
|
|
CallNameResolutionSink(itemRange, nenv, filterMethodGroups ncenv itemRange item true, ItemOccurence.Use, nenv.DisplayEnv, ad);
|
|
item, itemRange, rest
|
|
|
|
/// Called for 'expression.Bar' - for VS IntelliSense, we can filter out static members from method groups
|
|
let ResolveExprDotLongIdentAndComputeRange (ncenv:NameResolver) wholem ad nenv typ lid findFlag =
|
|
let resInfo,item,rest = ResolveExprDotLongIdent ncenv wholem ad nenv typ lid findFlag
|
|
let itemRange = ComputeItemRange wholem lid rest
|
|
ResolutionInfo.SendToSink(ncenv,nenv,ad,resInfo,(fun () -> CheckAllTyparsInferrable ncenv.g ncenv.amap itemRange item));
|
|
|
|
// Record the precise resolution of the field for intellisense
|
|
CallNameResolutionSink(itemRange, nenv, filterMethodGroups ncenv itemRange item false, ItemOccurence.Use, nenv.DisplayEnv, ad);
|
|
item, itemRange, rest
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Given an nenv resolve partial paths to sets of names, used by interactive
|
|
// environments (Visual Studio)
|
|
//
|
|
// ptc = partial type check
|
|
// ptci = partial type check item
|
|
//
|
|
// There are some inefficiencies in this code - e.g. we often
|
|
// create potentially large lists of methods/fields/properties and then
|
|
// immiediately List.filter them. We also use lots of "map/concats". Dosen't
|
|
// seem to hit the interactive experience too badly though.
|
|
//-------------------------------------------------------------------------
|
|
|
|
let FakeInstantiationGenerator (m:range) gps = List.map mk_typar_ty gps
|
|
|
|
// note: making local refs is ok since it is only used by VS
|
|
let ptci_of_vref v = Item_val(v)
|
|
let ptci_of_ucref v = Item_ucase v
|
|
let ptci_of_ecref v = Item_ecref v
|
|
let ptci_of_submodul v = Item_modrefs [v]
|
|
let ptci_of_recdfield v = Item_recdfield v
|
|
let ptci_of_il_finfo finfo = Item_il_field finfo
|
|
let ptci_of_einfo x = Item_event x
|
|
let ptci_of_pinfo (pinfo:PropInfo) = Item_property (pinfo.PropertyName,[pinfo])
|
|
let ptci_of_minfos (nm,minfos) = MakeMethGroup(nm,minfos)
|
|
|
|
let IsTyconUnseenObsoleteSpec ad g m (x:TyconRef) allowObsolete =
|
|
not (IsEntityAccessible ad x) ||
|
|
((not allowObsolete) &&
|
|
(if x.IsILTycon then
|
|
CheckILAttribsForUnseen g x.ILTyconRawMetadata.tdCustomAttrs m
|
|
else
|
|
CheckAttribsForUnseen g x.Attribs m))
|
|
|
|
let IsTyconUnseen ad g m (x:TyconRef) = IsTyconUnseenObsoleteSpec ad g m x false
|
|
|
|
let IsValUnseen ad g m (v:ValRef) =
|
|
not (IsValAccessible ad v) ||
|
|
v.IsCompilerGenerated ||
|
|
CheckAttribsForUnseen g v.Attribs m
|
|
|
|
let IsUnionCaseUnseen ad g m (ucref:UnionCaseRef) =
|
|
not (IsUnionCaseAccessible ad ucref) ||
|
|
IsTyconUnseen ad g m ucref.TyconRef ||
|
|
CheckAttribsForUnseen g ucref.Attribs m
|
|
|
|
let ItemIsUnseen ad g m item =
|
|
match item with
|
|
| Item_val x -> IsValUnseen ad g m x
|
|
| Item_ucase x -> IsUnionCaseUnseen ad g m x.UnionCaseRef
|
|
| Item_ecref x -> IsTyconUnseen ad g m x
|
|
| _ -> false
|
|
|
|
let ptci_of_tycon ncenv m (x:TyconRef) =
|
|
Item_typs (x.DisplayName,[FreshenTycon ncenv m x])
|
|
|
|
let ptci_of_typ g x =
|
|
let nm = if is_stripped_tyapp_typ g x then (tcref_of_stripped_typ g x).DisplayName else "?"
|
|
Item_typs (nm,[x])
|
|
|
|
// Filter out 'PrivateImplementationDetail' classes
|
|
let IsInterestingModuleName nm =
|
|
String.length nm >= 1 &&
|
|
String.sub nm 0 1 <> "<"
|
|
|
|
let rec PartialResolveLookupInModuleOrNamespaceAsModuleOrNamespaceThen f plid (modref:ModuleOrNamespaceRef) =
|
|
if verbose then dprintf "PartialResolveLookupInModuleOrNamespaceAsModuleOrNamespaceThen, plid = %s\n" (text_of_path plid);
|
|
let mty = modref.ModuleOrNamespaceType
|
|
match plid with
|
|
| [] -> f modref
|
|
| id:: rest ->
|
|
match mty.ModulesAndNamespacesByDemangledName.TryFind(id) with
|
|
| Some mty -> PartialResolveLookupInModuleOrNamespaceAsModuleOrNamespaceThen f rest (MakeNestedTcref modref mty)
|
|
| None -> []
|
|
|
|
let PartialResolveLongIndentAsModuleOrNamespaceThen (nenv:NameResolutionEnv) plid f =
|
|
if verbose then dprintf "PartialResolveLongIndentAsModuleOrNamespaceThen, plid = %s\n" (text_of_path plid);
|
|
match plid with
|
|
| id:: rest ->
|
|
match Map.tryfind id nenv.eModulesAndNamespaces with
|
|
| Some(modrefs) ->
|
|
List.collect (PartialResolveLookupInModuleOrNamespaceAsModuleOrNamespaceThen f rest) modrefs
|
|
| None ->
|
|
[]
|
|
| [] -> []
|
|
|
|
let ResolveCompletionsInType (ncenv: NameResolver) nenv m ad statics typ =
|
|
let g = ncenv.g
|
|
let amap = ncenv.amap
|
|
let rfinfos =
|
|
if is_stripped_tyapp_typ g typ then
|
|
let tc,tinst = dest_stripped_tyapp_typ g typ
|
|
(all_rfrefs_of_tcref tc)
|
|
|> List.filter (IsRecdFieldAccessible ad)
|
|
|> List.filter (fun fref -> fref.RecdField.IsStatic = statics)
|
|
|> List.filter (fun fref -> not fref.RecdField.IsCompilerGenerated)
|
|
|> List.map (fun fref -> RecdFieldInfo(tinst,fref))
|
|
else []
|
|
|
|
let ucinfos =
|
|
if statics && is_stripped_tyapp_typ g typ then
|
|
let tc,tinst = dest_stripped_tyapp_typ g typ
|
|
ucrefs_of_tcref tc
|
|
|> List.filter (IsUnionCaseUnseen ad g m >> not)
|
|
|> List.map (fun ucref -> Item_ucase(UnionCaseInfo(tinst,ucref)))
|
|
else []
|
|
|
|
let einfos =
|
|
ncenv.InfoReader.GetILEventInfosOfType(None,ad,m,typ)
|
|
|> List.filter (IsILEventInfoAccessible g amap m ad)
|
|
|> List.map (fun x -> ILEvent(g,x))
|
|
|> List.filter (fun x ->
|
|
IsStandardEventInfo ncenv.InfoReader m ad x &&
|
|
x.IsStatic = statics)
|
|
|
|
let nestedTypes =
|
|
typ
|
|
|> GetNestedTypesOfType ad ncenv (None,None) m
|
|
|
|
let finfos =
|
|
ncenv.InfoReader.GetILFieldInfosOfType(None,ad,m,typ)
|
|
|> List.filter (fun (ILFieldInfo(ty,fld) as x) ->
|
|
fld.fdSpecialName = false &&
|
|
x.IsStatic = statics &&
|
|
IsILFieldInfoAccessible g amap m ad x)
|
|
|
|
let pinfos =
|
|
AllPropInfosOfTypeInScope ncenv.InfoReader nenv.eExtensionMembers (None,ad) IgnoreOverrides m typ
|
|
|> List.filter (fun x ->
|
|
x.IsStatic = statics &&
|
|
not (PropInfoIsUnseen m x) &&
|
|
IsPropInfoAccessible g amap m ad x)
|
|
|
|
// Exclude get_ and set_ methods accessed by properties
|
|
let pinfoMethNames =
|
|
(pinfos
|
|
|> List.filter PropInfo.HasGetter
|
|
|> List.map (fun pinfo -> pinfo.GetterMethod.LogicalName))
|
|
@
|
|
(pinfos
|
|
|> List.filter PropInfo.HasSetter
|
|
|> List.map (fun pinfo -> pinfo.SetterMethod.LogicalName))
|
|
|
|
let einfoMethNames =
|
|
[ for e in einfos do
|
|
match e with
|
|
| ILEvent(_, e) ->
|
|
yield e.AddMethod.ILName
|
|
yield e.RemoveMethod.ILName
|
|
| _ ->
|
|
() ]
|
|
|
|
let names = Zset.addList pinfoMethNames (Zset.addList einfoMethNames (Zset.empty String.order))
|
|
|
|
let minfo_filter (minfo:MethInfo) =
|
|
// Only show the Finalize, MemberwiseClose etc. methods on System.Object for values whose static type really is
|
|
// System.Object. Few of these are typically used from F#.
|
|
(type_equiv g typ g.obj_ty
|
|
|| minfo.LogicalName = "GetType"
|
|
|| minfo.LogicalName = "GetHashCode"
|
|
|| minfo.LogicalName = "ToString"
|
|
|| (minfo.IsInstance && minfo.LogicalName = "Equals")
|
|
|| not (type_equiv g minfo.EnclosingType g.obj_ty)) &&
|
|
not minfo.IsInstance = statics &&
|
|
IsMethInfoAccessible amap m ad minfo &&
|
|
not (MethInfoIsUnseen g m minfo) &&
|
|
not minfo.IsConstructor &&
|
|
not minfo.IsClassConstructor &&
|
|
not (names.Contains minfo.LogicalName)
|
|
|
|
// REVIEW: add a name List.filter here in the common cases?
|
|
let minfos =
|
|
AllMethInfosOfTypeInScope ncenv.InfoReader nenv.eExtensionMembers (None,ad) IgnoreOverrides m typ
|
|
|> List.filter minfo_filter
|
|
|
|
// Partition methods into overload sets
|
|
let rec partitionl (l:MethInfo list) acc =
|
|
match l with
|
|
| [] -> acc
|
|
| h::t ->
|
|
let nm = h.LogicalName
|
|
partitionl t (NameMultiMap.add nm h acc)
|
|
|
|
// Build the results
|
|
ucinfos @
|
|
List.map ptci_of_recdfield rfinfos @
|
|
List.map ptci_of_pinfo pinfos @
|
|
List.map ptci_of_il_finfo finfos @
|
|
List.map ptci_of_einfo einfos @
|
|
List.map (ptci_of_typ g) nestedTypes @
|
|
List.map ptci_of_minfos (NameMap.to_list (partitionl minfos Map.empty))
|
|
|
|
|
|
let rec ResolvePartialLongIdentInType (ncenv: NameResolver) nenv m ad statics plid typ =
|
|
let g = ncenv.g
|
|
let amap = ncenv.amap
|
|
if verbose then dprintf "ResolvePartialLongIdentInType , typ = '%s', plid = '%s'\n" (NicePrint.pretty_string_of_typ (empty_denv g) typ) (text_of_path plid);
|
|
match plid with
|
|
| [] -> ResolveCompletionsInType ncenv nenv m ad statics typ
|
|
| id :: rest ->
|
|
|
|
let rfinfos =
|
|
if is_stripped_tyapp_typ g typ then
|
|
let tc,tinst = dest_stripped_tyapp_typ g typ
|
|
(all_rfrefs_of_tcref tc)
|
|
|> List.filter (IsRecdFieldAccessible ad)
|
|
|> List.filter (fun fref -> fref.RecdField.IsStatic = statics)
|
|
|> List.filter (fun fref -> not fref.RecdField.IsCompilerGenerated)
|
|
|> List.map (fun fref -> RecdFieldInfo(tinst,fref))
|
|
else
|
|
[]
|
|
|
|
let nestedTypes =
|
|
typ
|
|
|> GetNestedTypesOfType ad ncenv (Some(id),None) m
|
|
|
|
let ucinfos =
|
|
if statics && is_stripped_tyapp_typ g typ then
|
|
let tc,tinst = dest_stripped_tyapp_typ g typ
|
|
ucrefs_of_tcref tc
|
|
|> List.filter (IsUnionCaseUnseen ad g m >> not)
|
|
|> List.map (fun ucref -> Item_ucase(UnionCaseInfo(tinst,ucref)))
|
|
else []
|
|
|
|
// e.g. <val-id>.<recdfield-id>.<more>
|
|
(rfinfos |> List.filter (fun x -> x.Name = id)
|
|
|> List.collect (fun x -> x.FieldType |> ResolvePartialLongIdentInType ncenv nenv m ad false rest)) @
|
|
|
|
// e.g. <val-id>.<property-id>.<more>
|
|
(typ
|
|
|> AllPropInfosOfTypeInScope ncenv.InfoReader nenv.eExtensionMembers (Some(id),ad) IgnoreOverrides m
|
|
|> List.filter (fun x -> x.IsStatic = statics)
|
|
|> List.filter (IsPropInfoAccessible g amap m ad)
|
|
|> List.collect (PropertyTypeOfPropInfo amap m >> ResolvePartialLongIdentInType ncenv nenv m ad false rest)) @
|
|
|
|
// e.g. <val-id>.<event-id>.<more>
|
|
(ncenv.InfoReader.GetILEventInfosOfType(Some(id),ad,m,typ)
|
|
|> List.map (fun x -> ILEvent(g,x))
|
|
|> List.collect (PropTypOfEventInfo ncenv.InfoReader m ad >> ResolvePartialLongIdentInType ncenv nenv m ad false rest)) @
|
|
|
|
// nested types!
|
|
(nestedTypes
|
|
|> List.collect (ResolvePartialLongIdentInType ncenv nenv m ad statics rest)) @
|
|
|
|
// e.g. <val-id>.<il-field-id>.<more>
|
|
(ncenv.InfoReader.GetILFieldInfosOfType(Some(id),ad,m,typ)
|
|
|> List.filter (fun x ->
|
|
not x.RawMetadata.fdSpecialName &&
|
|
x.IsStatic = statics &&
|
|
IsILFieldInfoAccessible g amap m ad x)
|
|
|> List.collect (FieldTypeOfILFieldInfo amap m >> ResolvePartialLongIdentInType ncenv nenv m ad false rest))
|
|
|
|
let ptcis_of_tycon_ctors (ncenv:NameResolver) m ad (tcref:TyconRef) =
|
|
let g = ncenv.g
|
|
let amap = ncenv.amap
|
|
// Don't show constructors for type abbreviations. See FSharp 1.0 bug 2881
|
|
if tcref.IsTypeAbbrev then
|
|
[]
|
|
else
|
|
let typ = FreshenTycon ncenv m tcref
|
|
match ResolveObjectConstructor ncenv (empty_denv g) m ad typ with
|
|
| Result (item,_) ->
|
|
begin match item with
|
|
| Item_ctor_group(nm,cinfos) ->
|
|
cinfos
|
|
|> List.filter (IsMethInfoAccessible amap m ad)
|
|
|> List.filter (MethInfoIsUnseen g m >> not)
|
|
|> List.map (fun minfo -> MakeCtorGroup(nm,[minfo]))
|
|
| item ->
|
|
[item]
|
|
end
|
|
| Exception _ -> []
|
|
|
|
(* import.ml creates somewhat fake modules for nested members of types (so that *)
|
|
(* types never contain other types) *)
|
|
let not_fake_container_modul tyconNames nm =
|
|
not (Set.mem nm tyconNames)
|
|
|
|
/// Check is a namesapce or module contains something accessible
|
|
let rec private EntityRefContainsSomethingAccessible (ncenv: NameResolver) m ad (modref:ModuleOrNamespaceRef) =
|
|
let g = ncenv.g
|
|
let mty = modref.ModuleOrNamespaceType
|
|
|
|
// Search the values in the module for an accessible value
|
|
// BUG: we're not applying accessibility checks here, just looking for any value
|
|
(mty.AllValuesAndMembers
|
|
|> NameMap.exists (fun _ v ->
|
|
let vref = mk_vref_in_modref modref v
|
|
not vref.IsCompilerGenerated &&
|
|
not (IsValUnseen ad g m vref) &&
|
|
isNone(vref.MemberInfo))) ||
|
|
|
|
// Search the types in the namespace/module for an accessible tycon
|
|
(mty.AllEntities
|
|
|> NameMap.exists (fun _ tc ->
|
|
not tc.IsModuleOrNamespace &&
|
|
not (IsTyconUnseen ad g m (MakeNestedTcref modref tc)))) ||
|
|
|
|
// Search the sub-modules of the namespace/modulefor something accessible
|
|
(mty.ModulesAndNamespacesByDemangledName
|
|
|> NameMap.exists (fun _ submod ->
|
|
let submodref = MakeNestedTcref modref submod
|
|
EntityRefContainsSomethingAccessible ncenv m ad submodref))
|
|
|
|
let rec ResolvePartialLongIdentInModuleOrNamespace (ncenv: NameResolver) nenv m ad (modref:ModuleOrNamespaceRef) plid allowObsolete =
|
|
let g = ncenv.g
|
|
let amap = ncenv.amap
|
|
if verbose then dprintf "ResolvePartialLongIdentInModuleOrNamespace, plid = %s\n" (text_of_path plid);
|
|
let mty = modref.ModuleOrNamespaceType
|
|
|
|
let tycons =
|
|
mty.TypeDefinitions
|
|
|> List.filter (fun tycon -> not (IsTyconUnseen ad g m (MakeNestedTcref modref tycon)))
|
|
|
|
let iltyconNames =
|
|
mty.TypesByAccessNames
|
|
|> NameMultiMap.range
|
|
|> List.choose (fun (tycon:Tycon) -> if tycon.IsILTycon then Some(tycon.DisplayName) else None)
|
|
|> Set.of_seq
|
|
|
|
match plid with
|
|
| [] ->
|
|
|
|
// Collect up the accessible values in the module, excluding the members
|
|
(mty.AllValuesAndMembers
|
|
|> NameMap.range
|
|
|> List.map (mk_vref_in_modref modref)
|
|
|> List.filter (fun v -> v.MemberInfo.IsNone)
|
|
|> List.filter (IsValUnseen ad g m >> not)
|
|
|> List.map ptci_of_vref)
|
|
|
|
// Collect up the accessible discriminated union cases in the module
|
|
@ (UnionCaseRefsInModuleOrNamespace modref
|
|
|> List.filter (IsUnionCaseUnseen ad g m >> not)
|
|
|> List.map GeneralizeUnionCaseRef
|
|
|> List.map ptci_of_ucref)
|
|
|
|
// Collect up the accessible active patterns in the module
|
|
@ (ActivePatternElemsOfModuleOrNamespace modref
|
|
|> NameMap.range
|
|
|> List.filter (fun apref -> apref.ActivePatternVal |> IsValUnseen ad g m |> not)
|
|
|> List.map Item_apelem)
|
|
|
|
|
|
// Collect up the accessible F# exception declarations in the module
|
|
@ (mty.ExceptionDefinitionsByDemangledName
|
|
|> NameMap.range
|
|
|> List.map (MakeNestedTcref modref)
|
|
|> List.filter (IsTyconUnseen ad g m >> not)
|
|
|> List.map ptci_of_ecref)
|
|
|
|
// Collect up the accessible sub-modules
|
|
@ (mty.ModulesAndNamespacesByDemangledName
|
|
|> NameMap.range
|
|
|> List.filter (demangled_name_of_modul >> not_fake_container_modul iltyconNames)
|
|
|> List.filter (demangled_name_of_modul >> IsInterestingModuleName)
|
|
|> List.map (MakeNestedTcref modref)
|
|
|> List.filter (IsTyconUnseen ad g m >> not)
|
|
|> List.filter (EntityRefContainsSomethingAccessible ncenv m ad)
|
|
|> List.map ptci_of_submodul)
|
|
|
|
(* Get all the types and .NET constructor groups accessible from here *)
|
|
@ (tycons
|
|
|> List.map (MakeNestedTcref modref >> ptci_of_tycon ncenv m) )
|
|
|
|
@ (tycons
|
|
|> List.map (MakeNestedTcref modref >> ptcis_of_tycon_ctors ncenv m ad) |> List.concat)
|
|
|
|
| id :: rest ->
|
|
(match mty.ModulesAndNamespacesByDemangledName.TryFind(id) with
|
|
| Some mspec
|
|
when not (IsTyconUnseenObsoleteSpec ad g m (MakeNestedTcref modref mspec) allowObsolete) ->
|
|
let allowObsolete = rest <> [] && allowObsolete
|
|
ResolvePartialLongIdentInModuleOrNamespace ncenv nenv m ad (MakeNestedTcref modref mspec) rest allowObsolete
|
|
| _ -> [])
|
|
|
|
@ (LookupTypeNameInEntityNoArity m id mty
|
|
|> List.collect (fun tycon ->
|
|
let tcref = MakeNestedTcref modref tycon
|
|
if not (IsTyconUnseenObsoleteSpec ad g m tcref allowObsolete) then
|
|
tcref |> generalize_tcref |> snd |> ResolvePartialLongIdentInType ncenv nenv m ad true rest
|
|
else
|
|
[]))
|
|
|
|
/// allowObsolete - specifies whether we should return obsolete types & modules
|
|
/// as (no other obsolete items are returned)
|
|
let ResolvePartialLongIdent (ncenv: NameResolver) nenv m ad plid allowObsolete =
|
|
let g = ncenv.g
|
|
match plid with
|
|
| [] ->
|
|
let iltyconNames =
|
|
nenv.eTyconsByAccessNames
|
|
|> NameMultiMap.range
|
|
|> List.choose (fun (tyconRef) -> if tyconRef.IsILTycon then Some(tyconRef.DisplayName) else None)
|
|
|> Set.of_seq
|
|
|
|
let items =
|
|
nenv.eUnqualifiedItems
|
|
|> NameMap.range
|
|
|> List.filter (ItemIsUnseen ad g m >> not)
|
|
|
|
let apats =
|
|
nenv.ePatItems
|
|
|> NameMap.range
|
|
|> List.filter (function Item_apelem v -> true | _ -> false)
|
|
|
|
let mods =
|
|
nenv.eModulesAndNamespaces
|
|
|> NameMultiMap.range
|
|
|> List.filter (demangled_name_of_modref >> IsInterestingModuleName )
|
|
|> List.filter (demangled_name_of_modref >> not_fake_container_modul iltyconNames)
|
|
|> List.filter (EntityRefContainsSomethingAccessible ncenv m ad)
|
|
|> List.filter (IsTyconUnseen ad g m >> not)
|
|
|> List.map ptci_of_submodul
|
|
|
|
let tycons =
|
|
nenv.eTyconsByDemangledNameAndArity
|
|
|> NameMap.range
|
|
|> List.filter (fun tcref -> not tcref.IsExceptionDecl)
|
|
|> List.filter (IsTyconUnseen ad g m >> not)
|
|
|> List.map (ptci_of_tycon ncenv m)
|
|
|
|
// Get all the constructors accessible from here
|
|
let constructors =
|
|
nenv.eTyconsByDemangledNameAndArity
|
|
|> NameMap.range
|
|
|> List.filter (IsTyconUnseen ad g m >> not)
|
|
|> List.collect (ptcis_of_tycon_ctors ncenv m ad)
|
|
|
|
items @ apats @ mods @ tycons @ constructors
|
|
|
|
| id :: rest ->
|
|
|
|
(* Look in the namespaces 'id' *)
|
|
PartialResolveLongIndentAsModuleOrNamespaceThen nenv [id] (fun modref ->
|
|
let allowObsolete = rest <> [] && allowObsolete
|
|
if EntityRefContainsSomethingAccessible ncenv m ad modref then
|
|
ResolvePartialLongIdentInModuleOrNamespace ncenv nenv m ad modref rest allowObsolete
|
|
else
|
|
[])
|
|
|
|
(* Look for values called 'id' that accept the dot-notation *)
|
|
@ (if nenv.eUnqualifiedItems.ContainsKey(id) then
|
|
(* v.lookup : member of a value *)
|
|
let v = Map.find id nenv.eUnqualifiedItems
|
|
match v with
|
|
| Item_val x ->
|
|
if verbose then dprintf "ResolvePartialLongIdent (through val), plid = %s\n" (text_of_path plid);
|
|
let typ = x.Type
|
|
let typ = if x.BaseOrThisInfo = CtorThisVal then dest_refcell_ty g typ else typ
|
|
ResolvePartialLongIdentInType ncenv nenv m ad false rest typ
|
|
| _ -> []
|
|
else [])
|
|
@
|
|
(* type.lookup : lookup a static something in a type *)
|
|
(LookupTypeNameInEnvNoArity id nenv |> List.collect (FreshenTycon ncenv m >> ResolvePartialLongIdentInType ncenv nenv m ad true rest))
|
|
|
|
|
|
|