@@ -20,10 +20,20 @@ open Microsoft.FSharp.Compiler.ErrorLogger
2020open Microsoft.FSharp .Compiler .ExtensionTyping
2121#endif
2222
23+ /// Represents an interface to some of the functionality of TcImports, for loading assemblies
24+ /// and accessing information about generated provided assemblies.
2325type AssemblyLoader =
26+
27+ /// Resolve an Abstract IL assembly reference to a Ccu
2428abstract LoadAssembly : range * ILAssemblyRef -> CcuResolutionResult
2529#if EXTENSIONTYPING
30+
31+ /// Get a flag indicating if an assembly is a provided assembly, plus the
32+ /// table of information recording remappings from type names in the provided assembly to type
33+ /// names in the statically linked, embedded assembly.
2634abstract GetProvidedAssemblyInfo : range * Tainted < ProvidedAssembly > -> bool * ProvidedAssemblyStaticLinkingMap option
35+
36+ /// Record a root for a [<Generate>] type to help guide static linking & type relocation
2737abstract RecordGeneratedTypeRoot : ProviderGeneratedType -> unit
2838#endif
2939
@@ -33,15 +43,22 @@ type AssemblyLoader =
3343// Import an IL types as F# types.
3444//-------------------------------------------------------------------------
3545
36- /// This is the context used for converting AbstractIL .NET and provided types to F# internal compiler data structures.
37- /// We currently cache the conversion of AbstractIL ILTypeRef nodes, based on hashes of these.
46+ /// Represents a context used by the import routines that convert AbstractIL types and provided
47+ /// types to F# internal compiler data structures.
48+ ///
49+ /// Also caches the conversion of AbstractIL ILTypeRef nodes, based on hashes of these.
50+ ///
51+ /// There is normally only one ImportMap for any assembly compilation, though additional instances can be created
52+ /// using tcImports.GetImportMap() if needed, and it is not harmful if multiple instances are used. The object
53+ /// serves as an interface through to the tables stored in the primary TcImports structures defined in build.fs.
3854[<Sealed>]
3955type ImportMap ( g : TcGlobals , assemblyLoader : AssemblyLoader ) =
4056let typeRefToTyconRefCache = new System.Collections.Generic.Dictionary< ILTypeRef, TyconRef>()
4157member this.g = g
4258member this.assemblyLoader = assemblyLoader
4359member this.ILTypeRefToTyconRefCache = typeRefToTyconRefCache
4460
61+ /// Import a reference to a type definition, given the AbstractIL data for the type reference
4562let ImportTypeRefData ( env : ImportMap ) m ( scoref , path , typeName ) =
4663let ccu =
4764match scorefwith
@@ -76,7 +93,7 @@ let ImportTypeRefData (env:ImportMap) m (scoref,path,typeName) =
7693| Some tcref-> tcref
7794
7895
79- /// Importan IL typeref as anF# type constructor.
96+ /// Importa reference to a typedefinition, given anAbstractIL ILTypeRef, without caching
8097//
8198// Note, the type names that flow to the point include the "mangled" type names used for static parameters for provided types.
8299// For example,
@@ -95,24 +112,25 @@ let ImportILTypeRefUncached (env:ImportMap) m (tref:ILTypeRef) =
95112 ImportTypeRefData( env: ImportMap) m( tref.Scope, path, typeName)
96113
97114
115+ /// Import a reference to a type definition, given an AbstractIL ILTypeRef, with caching
98116let ImportILTypeRef ( env : ImportMap ) m ( tref : ILTypeRef ) =
99117if env.ILTypeRefToTyconRefCache.ContainsKey( tref) then
100118 env.ILTypeRefToTyconRefCache.[ tref]
101119else
102120let tcref = ImportILTypeRefUncached env m tref
103- env.ILTypeRefToTyconRefCache.[ tref] <- tcref;
121+ env.ILTypeRefToTyconRefCache.[ tref] <- tcref
104122 tcref
105123
124+ /// Import a type, given an AbstractIL ILTypeRef and an F# type instantiation.
125+ ///
126+ /// Prefer the F# abbreviation for some built-in types, e.g. 'string' rather than
127+ /// 'System.String', since we prefer the F# abbreviation to the .NET equivalents.
106128let ImportTyconRefApp ( env : ImportMap ) tcref tyargs =
107- // 'better_tcref_map' prefers the F# abbreviation for some built-in types, e.g. 'string' rather than
108- // 'System.String', since users prefer the F# abbreviation to the .NET equivalents. Also on import
109- // we decompile uses of FSharpFunc and Tuple.
110129match env.g.better_ tcref_ map tcref tyargswith
111130| Some res-> res
112131| None-> TType_ app( tcref, tyargs)
113132
114- /// Import an IL type as an F# type
115- /// - The F# type check does the job of making the "void" into a "unit" value, whatever the repr. of "unit" is.
133+ /// Import an IL type as an F# type.
116134let rec ImportILType ( env : ImportMap ) m tinst typ =
117135match typwith
118136| ILType.Void->
@@ -141,6 +159,7 @@ let rec ImportILType (env:ImportMap) m tinst typ =
141159
142160#if EXTENSIONTYPING
143161
162+ /// Import a provided type reference as an F# type TyconRef
144163let ImportProvidedNamedType ( env : ImportMap ) ( m : range ) ( st : Tainted < ProvidedType >) =
145164// See if a reverse-mapping exists for a generated/relocated System.Type
146165match st.PUntaint(( fun st -> st.TryGetTyconRef()), m) with
@@ -149,6 +168,7 @@ let ImportProvidedNamedType (env:ImportMap) (m:range) (st:Tainted<ProvidedType>)
149168let tref = ExtensionTyping.GetILTypeRefOfProvidedType( st, m)
150169 ImportILTypeRef env m tref
151170
171+ /// Import a provided type as an AbstractIL type
152172let rec ImportProvidedTypeAsILType ( env : ImportMap ) ( m : range ) ( st : Tainted < ProvidedType >) =
153173if st.PUntaint(( fun x -> x.IsVoid), m) then ILType.Void
154174elif st.PUntaint(( fun st -> st.IsGenericParameter), m) then
@@ -184,6 +204,7 @@ let rec ImportProvidedTypeAsILType (env:ImportMap) (m:range) (st:Tainted<Provide
184204else
185205 mkILBoxedType tspec
186206
207+ /// Import a provided type as an F# type.
187208let rec ImportProvidedType ( env : ImportMap ) ( m : range ) (* (tinst:TypeInst)*) ( st : Tainted < ProvidedType >) =
188209
189210let g = env.g
@@ -246,6 +267,7 @@ let rec ImportProvidedType (env:ImportMap) (m:range) (* (tinst:TypeInst) *) (st:
246267 ImportTyconRefApp env tcref genericArgs
247268
248269
270+ /// Import a provided method reference as an Abstract IL method reference
249271let ImportProvidedMethodBaseAsILMethodRef ( env : ImportMap ) ( m : range ) ( mbase : Tainted < ProvidedMethodBase >) =
250272let tref = ExtensionTyping.GetILTypeRefOfProvidedType( mbase.PApply(( fun mbase -> mbase.DeclaringType), m), m)
251273
@@ -322,7 +344,11 @@ let ImportProvidedMethodBaseAsILMethodRef (env:ImportMap) (m:range) (mbase: Tain
322344//--------------------------------------------------------------------------
323345
324346
325- // tinst gives the type parameters for the enclosing type when converting the type parameters of a generic method
347+ /// Import a set of Abstract IL generic parameter specifications as a list of new
348+ /// F# generic parameters.
349+ ///
350+ /// Fixup the constrants so that any references to the generic parameters
351+ /// in the constraints now refer to the new generic parameters.
326352let ImportILGenericParameters amap m scoref tinst ( gps : ILGenericParameterDefs ) =
327353match gpswith
328354| [] -> []
@@ -341,6 +367,10 @@ let ImportILGenericParameters amap m scoref tinst (gps: ILGenericParameterDefs)
341367 tps
342368
343369
370+ /// Given a list of items each keyed by an ordered list of keys, apply 'nodef' to the each group
371+ /// with the same leading key. Apply 'tipf' to the elements where the keylist is empty, and return
372+ /// the overall results. Used to bucket types, so System.Char and System.Collections.Generic.List
373+ /// both get initially bucketed under 'System'.
344374let multisetDiscriminateAndMap nodef tipf ( items : ( 'Key list * 'Value )list ) =
345375// Find all the items with an empty key list and call 'tipf'
346376let tips =
@@ -361,9 +391,10 @@ let multisetDiscriminateAndMap nodef tipf (items: ('Key list * 'Value) list) =
361391
362392[ for ( KeyValue( key, items)) in buckets-> nodef key items]
363393
364- tips, nodes
394+ tips@ nodes
365395
366396
397+ /// Import an IL type definition as a new F# TAST Entity node.
367398let rec ImportILTypeDef amap m scoref cpath enc nm ( tdef : ILTypeDef ) =
368399let lazyModuleOrNamespaceTypeForNestedTypes =
369400lazy
@@ -380,44 +411,47 @@ let rec ImportILTypeDef amap m scoref cpath enc nm (tdef:ILTypeDef) =
380411 lazyModuleOrNamespaceTypeForNestedTypes
381412
382413
414+ /// Import a list of (possibly nested) IL types as a new ModuleOrNamespaceType node
415+ /// containing new entities, bucketing by namespace along the way.
383416and ImportILTypeDefList amap m cpath enc items =
384- // Split into the ones with namespaces and without
385- // This is a non-trivial function.
386- // Add the ones with namespaces in buckets
387- // That is, multi-set discriminate based in the first element of the namespace list (e.g. "System")
388- // and for each bag resulting from the discrimination fold-in a lazy computation to add the types under that bag
389- let rec add cpath items =
390- let tycons , namespaceModules =
391- items
392- |> multisetDiscriminateAndMap
393- // nodef - called for each bucket, where 'n' is the head element of the namespace used
394- // as a key in the discrimination, tgs is the remaining descriptors. We create a sub-module for 'n'
395- ( fun n tgs ->
396- let modty = lazy ( add( mkNestedCPath cpath n Namespace) tgs)
397- let mspec = NewModuleOrNamespace( Some cpath) taccessPublic( mkSynId m n) XmlDoc.Empty[] modty
398- mspec)
399-
400- // tipf - called if there are no namespace items left to discriminate on.
401- ( fun ( n , info :Lazy < _ >) ->
402- //Note: this scoref looks like it will always be identical to 'scoref'
403- let ( scoref2 , _ , lazyTypeDef : Lazy < ILTypeDef >) = info.Force()
404- ImportILTypeDef amap m scoref2 cpath enc n( lazyTypeDef.Force()))
405-
406- let kind = match encwith [] -> Namespace| _ -> ModuleOrType
407- NewModuleOrNamespaceType kind( tycons@ namespaceModules) []
417+ // Split into the ones with namespaces and without. Add the ones with namespaces in buckets.
418+ // That is, discriminate based in the first element of the namespace list (e.g. "System")
419+ // and, for each bag, fold-in a lazy computation to add the types under that bag .
420+ //
421+ // nodef - called for each bucket, where 'n' is the head element of the namespace used
422+ // as a key in the discrimination, tgs is the remaining descriptors. We create an entity for 'n'.
423+ //
424+ // tipf - called if there are no namespace items left to discriminate on.
425+ let entities =
426+ items
427+ |> multisetDiscriminateAndMap
428+ ( fun n tgs ->
429+ let modty = lazy ( ImportILTypeDefList amap m( mkNestedCPath cpath n Namespace) enc tgs)
430+ NewModuleOrNamespace( Some cpath) taccessPublic( mkSynId m n) XmlDoc.Empty[] modty)
431+ ( fun ( n , info :Lazy < _ >) ->
432+ let ( scoref2 , _ , lazyTypeDef : Lazy < ILTypeDef >) = info.Force()
433+ ImportILTypeDef amap m scoref2 cpath enc n( lazyTypeDef.Force()))
434+
435+ let kind = match encwith [] -> Namespace| _ -> ModuleOrType
436+ NewModuleOrNamespaceType kind entities[]
408437
409- add cpath items
410-
438+ /// Import a table of IL types as a ModuleOrNamespaceType.
439+ ///
411440and ImportILTypeDefs amap m scoref cpath enc ( tdefs : ILTypeDefs ) =
412441// We be very careful not to force a read of the type defs here
413442 tdefs.AsListOfLazyTypeDefs
414443|> List.map( fun ( ns , n , attrs , lazyTypeDef ) -> ( ns,( n, notlazy( scoref, attrs, lazyTypeDef))))
415444|> ImportILTypeDefList amap m cpath enc
416445
446+ /// Import the main type definitions in an IL assembly.
447+ ///
448+ /// Example: for a collection of types "System.Char", "System.Int32" and "Library.C"
449+ /// the return ModuleOrNamespaceType will contain namespace entities for "System" and "Library", which in turn contain
450+ /// type definition entities for ["Char"; "Int32"] and ["C"] respectively.
417451let ImportILAssemblyMainTypeDefs amap m scoref modul =
418452 modul.TypeDefs|> ImportILTypeDefs amap m scoref( CompPath( scoref,[])) []
419453
420- ///Read the "exported types" table for multi-module assemblies.
454+ ///Import the "exported types" table for multi-module assemblies.
421455let ImportILAssemblyExportedType amap m auxModLoader ( scoref : ILScopeRef ) ( exportedType : ILExportedTypeOrForwarder ) =
422456// Forwarders are dealt with separately in the ref->def dereferencing logic in tast.fs as they effectively give rise to type equivalences
423457if exportedType.IsForwarderthen
@@ -438,18 +472,20 @@ let ImportILAssemblyExportedType amap m auxModLoader (scoref:ILScopeRef) (export
438472let ns , n = splitILTypeName exportedType.Name
439473[ ImportILTypeDefList amap m( CompPath( scoref,[])) [] [( ns,( n, info))] ]
440474
441- ///Read the "exported types" table for multi-module assemblies.
475+ ///Import the "exported types" table for multi-module assemblies.
442476let ImportILAssemblyExportedTypes amap m auxModLoader scoref ( exportedTypes : ILExportedTypesAndForwarders ) =
443477[ for exportedTypein exportedTypes.AsListdo
444478yield ! ImportILAssemblyExportedType amap m auxModLoader scoref exportedType]
445479
480+ /// Import both the main type definitions and the "exported types" table, i.e. all the
481+ /// types defined in an IL assembly.
446482let ImportILAssemblyTypeDefs ( amap , m , auxModLoader , aref , mainmod : ILModuleDef ) =
447483let scoref = ILScopeRef.Assembly aref
448484let mtypsForExportedTypes = ImportILAssemblyExportedTypes amap m auxModLoader scoref mainmod.ManifestOfAssembly.ExportedTypes
449485let mainmod = ImportILAssemblyMainTypeDefs amap m scoref mainmod
450486 combineModuleOrNamespaceTypeList[] m( mainmod:: mtypsForExportedTypes)
451487
452- // Read the type forwarder table for an assembly
488+ /// Import the type forwarder table for an IL assembly
453489let ImportILAssemblyTypeForwarders ( amap , m , exportedTypes : ILExportedTypesAndForwarders ) =
454490// Note 'td' may be in another module or another assembly!
455491// Note: it is very important that we call auxModLoader lazily
@@ -470,6 +506,7 @@ let ImportILAssemblyTypeForwarders (amap, m, exportedTypes:ILExportedTypesAndFor
470506] |> Map.ofList
471507
472508
509+ /// Import an IL assembly as a new TAST CCU
473510let ImportILAssembly ( amap :( unit -> ImportMap ), m , auxModuleLoader , sref , sourceDir , filename , ilModule : ILModuleDef , invalidateCcu : IEvent < string >) =
474511 invalidateCcu|> ignore
475512let aref =