-
Notifications
You must be signed in to change notification settings - Fork 858
Expand file tree
/
Copy pathInfoReader.fs
More file actions
1316 lines (1141 loc) · 68 KB
/
InfoReader.fs
File metadata and controls
1316 lines (1141 loc) · 68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
/// Select members from a type by name, searching the type hierarchy if needed
module internal FSharp.Compiler.InfoReader
open System
open System.Collections.Concurrent
open System.Collections.Generic
open Internal.Utilities.Library
open FSharp.Compiler
open FSharp.Compiler.AbstractIL.IL
open FSharp.Compiler.AccessibilityLogic
open FSharp.Compiler.AttributeChecking
open FSharp.Compiler.DiagnosticsLogger
open FSharp.Compiler.Features
open FSharp.Compiler.Infos
open FSharp.Compiler.Syntax
open FSharp.Compiler.TcGlobals
open FSharp.Compiler.Text
open FSharp.Compiler.Text.Range
open FSharp.Compiler.TypedTree
open FSharp.Compiler.TypedTreeOps
open FSharp.Compiler.TypedTreeBasics
open FSharp.Compiler.TypeHierarchy
open FSharp.Compiler.TypeRelations
open Import
/// Use the given function to select some of the member values from the members of an F# type
let SelectImmediateMemberVals g optFilter f withExplicitImpl (tcref: TyconRef) =
let chooser (vref: ValRef) =
match vref.MemberInfo with
// The 'when' condition is a workaround for the fact that values providing
// override and interface implementations are published in inferred module types
// These cannot be selected directly via the "." notation.
// However, it certainly is useful to be able to publish these values, as we can in theory
// optimize code to make direct calls to these methods.
| Some membInfo when withExplicitImpl || not (ValRefIsExplicitImpl g vref) ->
f membInfo vref
| _ ->
None
match optFilter with
| None -> tcref.MembersOfFSharpTyconByName |> NameMultiMap.chooseRange chooser
| Some nm -> tcref.MembersOfFSharpTyconByName |> NameMultiMap.find nm |> List.choose chooser
/// Check whether a name matches an optional filter
let private checkFilter optFilter (nm: string) = match optFilter with None -> true | Some n2 -> nm = n2
/// Try to select an F# value when querying members, and if so return a MethInfo that wraps the F# value.
let TrySelectMemberVal g optFilter ty pri _membInfo (vref: ValRef) =
if checkFilter optFilter vref.LogicalName then
Some(FSMeth(g, ty, vref, pri))
else
None
let rec GetImmediateIntrinsicMethInfosOfTypeAux (optFilter, ad) g amap m withExplicitImpl origTy metadataTy =
let minfos =
match metadataOfTy g metadataTy with
#if !NO_TYPEPROVIDERS
| ProvidedTypeMetadata info ->
let st = info.ProvidedType
let meths =
match optFilter with
| Some name ->
st.PApplyFilteredArray ((fun st -> st.GetMethods()),(fun mi -> mi.Name = name), "GetMethods", m)
| None -> st.PApplyArray ((fun st -> st.GetMethods()), "GetMethods", m)
[ for mi in meths -> ProvidedMeth(amap, mi.Coerce(m), None, m) ]
#endif
| ILTypeMetadata _ ->
let tinfo = ILTypeInfo.FromType g origTy
let mdefs = tinfo.RawMetadata.Methods
let mdefs = match optFilter with None -> mdefs.AsList() | Some nm -> mdefs.FindByName nm
mdefs |> List.map (fun mdef -> MethInfo.CreateILMeth(amap, m, origTy, mdef))
| FSharpOrArrayOrByrefOrTupleOrExnTypeMetadata ->
// Tuple types also support the methods get_Item1-8, get_Rest from the compiled tuple type.
// In this case convert to the .NET Tuple type that carries metadata and try again
if isAnyTupleTy g metadataTy then
let betterMetadataTy = convertToTypeWithMetadataIfPossible g metadataTy
GetImmediateIntrinsicMethInfosOfTypeAux (optFilter, ad) g amap m withExplicitImpl origTy betterMetadataTy
// Function types support methods FSharpFunc<_, _>.FromConverter and friends from .NET metadata,
// but not instance methods (you can't write "f.Invoke(x)", you have to write "f x")
elif isFunTy g metadataTy then
let betterMetadataTy = convertToTypeWithMetadataIfPossible g metadataTy
GetImmediateIntrinsicMethInfosOfTypeAux (optFilter, ad) g amap m withExplicitImpl origTy betterMetadataTy
|> List.filter (fun minfo -> not minfo.IsInstance)
else
match tryTcrefOfAppTy g metadataTy with
| ValueNone -> []
| ValueSome tcref ->
SelectImmediateMemberVals g optFilter (TrySelectMemberVal g optFilter origTy None) withExplicitImpl tcref
let minfos = minfos |> List.filter (IsMethInfoAccessible amap m ad)
minfos
/// Query the immediate methods of an F# type, not taking into account inherited methods. The optFilter
/// parameter is an optional name to restrict the set of properties returned.
let GetImmediateIntrinsicMethInfosOfType (optFilter, ad) g amap m ty =
GetImmediateIntrinsicMethInfosOfTypeAux (optFilter, ad) g amap m false ty ty
let GetImmediateIntrinsicMethInfosWithExplicitImplOfType (optFilter, ad) g amap m ty =
GetImmediateIntrinsicMethInfosOfTypeAux (optFilter, ad) g amap m true ty ty
/// Query the immediate methods of an F# type, not taking into account inherited methods. The optFilter
/// parameter is an optional name to restrict the set of properties returned.
let GetImmediateTraitsInfosOfType optFilter g ty =
match tryDestTyparTy g ty with
| ValueSome tp ->
let infos = GetTraitConstraintInfosOfTypars g [tp]
match optFilter with
| None ->
[ for traitInfo in infos do
match traitInfo.MemberFlags.MemberKind with
| SynMemberKind.PropertySet ->
// A setter property trait only can be utilized via
// ^T.set_Property(v)
traitInfo.WithMemberKind(SynMemberKind.Member)
| _ ->
traitInfo ]
| Some nm ->
[ for traitInfo in infos do
match traitInfo.MemberFlags.MemberKind with
| SynMemberKind.PropertyGet ->
// A getter property trait can be utilized via
// ^T.Property
// ^T.get_Property()
// The latter doesn't appear in intellisense
if nm = traitInfo.MemberDisplayNameCore then
traitInfo
let traitInfo2 = traitInfo.WithMemberKind(SynMemberKind.Member)
if nm = traitInfo2.MemberDisplayNameCore then
traitInfo2
| SynMemberKind.PropertySet ->
// A setter property trait only can be utilized via
// ^T.set_Property(v)
let traitInfo2 = traitInfo.WithMemberKind(SynMemberKind.Member)
if nm = traitInfo2.MemberDisplayNameCore then
traitInfo2
| _ ->
// Method traits can be utilized via
// ^T.Member(v)
if nm = traitInfo.MemberDisplayNameCore then
traitInfo
]
| _ ->
[]
/// A helper type to help collect properties.
///
/// Join up getters and setters which are not associated in the F# data structure
type PropertyCollector(g, amap, m, ty, optFilter, ad) =
let hashIdentity =
HashIdentity.FromFunctions
(fun (pinfo: PropInfo) -> hash pinfo.PropertyName)
(fun pinfo1 pinfo2 ->
pinfo1.IsStatic = pinfo2.IsStatic &&
PropInfosEquivByNameAndPartialSig EraseNone g amap m pinfo1 pinfo2 &&
pinfo1.IsDefiniteFSharpOverride = pinfo2.IsDefiniteFSharpOverride )
let props = ConcurrentDictionary<PropInfo, PropInfo>(hashIdentity)
let add pinfo =
match props.TryGetValue pinfo, pinfo with
| (true, FSProp (_, ty, Some vref1, _)), FSProp (_, _, _, Some vref2)
| (true, FSProp (_, ty, _, Some vref2)), FSProp (_, _, Some vref1, _) ->
let pinfo = FSProp (g, ty, Some vref1, Some vref2)
props[pinfo] <- pinfo
| (true, _), _ ->
// This assert fires while editing bad code. We will give a warning later in check.fs
//assert ("unexpected case"= "")
()
| _ ->
props[pinfo] <- pinfo
member _.Collect(membInfo: ValMemberInfo, vref: ValRef) =
match membInfo.MemberFlags.MemberKind with
| SynMemberKind.PropertyGet ->
let pinfo = FSProp(g, ty, Some vref, None)
if checkFilter optFilter vref.PropertyName && IsPropInfoAccessible g amap m ad pinfo then
add pinfo
| SynMemberKind.PropertySet ->
let pinfo = FSProp(g, ty, None, Some vref)
if checkFilter optFilter vref.PropertyName && IsPropInfoAccessible g amap m ad pinfo then
add pinfo
| _ ->
()
member _.Close() = [ for KeyValue(_, pinfo) in props -> pinfo ]
let rec GetImmediateIntrinsicPropInfosOfTypeAux (optFilter, ad) g amap m withExplicitImpl origTy metadataTy =
let pinfos =
match metadataOfTy g metadataTy with
#if !NO_TYPEPROVIDERS
| ProvidedTypeMetadata info ->
let st = info.ProvidedType
let matchingProps =
match optFilter with
| Some name ->
match st.PApply((fun st -> st.GetProperty name), m) with
| Tainted.Null -> [||]
| Tainted.NonNull pi -> [|pi|]
| None ->
st.PApplyArray((fun st -> st.GetProperties()), "GetProperties", m)
matchingProps
|> Seq.map(fun pi -> ProvidedProp(amap, pi, m))
|> List.ofSeq
#endif
| ILTypeMetadata _ ->
let tinfo = ILTypeInfo.FromType g origTy
let pdefs = tinfo.RawMetadata.Properties
let pdefs = match optFilter with None -> pdefs.AsList() | Some nm -> pdefs.LookupByName nm
pdefs |> List.map (fun pdef -> ILProp(ILPropInfo(tinfo, pdef)))
| FSharpOrArrayOrByrefOrTupleOrExnTypeMetadata ->
// Tuple types also support the properties Item1-8, Rest from the compiled tuple type
// In this case convert to the .NET Tuple type that carries metadata and try again
if isAnyTupleTy g metadataTy || isFunTy g metadataTy then
let betterMetadataTy = convertToTypeWithMetadataIfPossible g metadataTy
GetImmediateIntrinsicPropInfosOfTypeAux (optFilter, ad) g amap m withExplicitImpl origTy betterMetadataTy
else
match tryTcrefOfAppTy g metadataTy with
| ValueNone -> []
| ValueSome tcref ->
let propCollector = PropertyCollector(g, amap, m, origTy, optFilter, ad)
SelectImmediateMemberVals g None (fun membInfo vref -> propCollector.Collect(membInfo, vref); None) withExplicitImpl tcref |> ignore
propCollector.Close()
let pinfos = pinfos |> List.filter (IsPropInfoAccessible g amap m ad)
pinfos
/// Query the immediate properties of an F# type, not taking into account inherited properties. The optFilter
/// parameter is an optional name to restrict the set of properties returned.
let GetImmediateIntrinsicPropInfosOfType (optFilter, ad) g amap m ty =
GetImmediateIntrinsicPropInfosOfTypeAux (optFilter, ad) g amap m false ty ty
let GetImmediateIntrinsicPropInfosWithExplicitImplOfType (optFilter, ad) g amap m ty =
GetImmediateIntrinsicPropInfosOfTypeAux (optFilter, ad) g amap m true ty ty
// Checks whether the given type has an indexer property.
let IsIndexerType g amap ty =
isArray1DTy g ty ||
isListTy g ty ||
match tryTcrefOfAppTy g ty with
| ValueSome tcref ->
let entityTy = generalizedTyconRef g tcref
let props = GetImmediateIntrinsicPropInfosOfType (None, AccessibleFromSomeFSharpCode) g amap range0 entityTy
props |> List.exists (fun x -> x.PropertyName = "Item")
| ValueNone -> false
/// Get the items that are considered the most specific in the hierarchy out of the given items by type.
/// REVIEW: Note complexity O(N^2)
let GetMostSpecificItemsByType g amap f xs =
[ for x in xs do
match f x with
| None -> ()
| Some (xTy, m) ->
let isEqual =
xs
|> List.forall (fun y ->
match f y with
| None -> true
| Some (yTy, _) ->
if typeEquiv g xTy yTy then true
else not (TypeFeasiblySubsumesType 0 g amap m xTy CanCoerce yTy))
if isEqual then
yield x ]
/// Finds the most specific methods from a method collection by a given method's signature.
let GetMostSpecificMethodInfosByMethInfoSig g amap m (ty, minfo) minfos =
minfos
|> GetMostSpecificItemsByType g amap (fun (ty2, minfo2) ->
let isEqual =
typeEquiv g ty ty2 &&
MethInfosEquivByPartialSig EraseNone true g amap m minfo minfo2
if isEqual then
Some(minfo2.ApparentEnclosingType, m)
else
None)
/// From the given method sets, filter each set down to the most specific ones.
let FilterMostSpecificMethInfoSets g amap m (minfoSets: NameMultiMap<_>) : NameMultiMap<_> =
minfoSets
|> Map.map (fun _ minfos ->
([], minfos)
||> List.fold (fun minfoSpecifics (ty, minfo) ->
let alreadySeen =
minfoSpecifics
|> List.exists (fun (tySpecific, minfoSpecific) ->
typeEquiv g ty tySpecific &&
MethInfosEquivByPartialSig EraseNone true g amap m minfo minfoSpecific)
if alreadySeen then
minfoSpecifics
else
GetMostSpecificMethodInfosByMethInfoSig g amap m (ty, minfo) minfos @ minfoSpecifics))
/// Sets of methods up the hierarchy, ignoring duplicates by name and sig.
/// Used to collect sets of virtual methods, protected methods, protected
/// properties etc.
type HierarchyItem =
| TraitItem of TraitConstraintInfo list
| MethodItem of MethInfo list list
| PropertyItem of PropInfo list list
| RecdFieldItem of RecdFieldInfo
| EventItem of EventInfo list
| ILFieldItem of ILFieldInfo list
//-------------------------------------------------------------------------
// Collecting methods and properties taking into account hiding rules in the hierarchy
/// Indicates if we prefer overrides or abstract slots.
type FindMemberFlag =
/// Prefer items toward the top of the hierarchy, which we do if the items are virtual
/// but not when resolving base calls.
| IgnoreOverrides
/// Get overrides instead of abstract slots when measuring whether a class/interface implements all its required slots.
| PreferOverrides
/// Similar to "IgnoreOverrides", but filters the items bottom-to-top,
/// and discards all when finds first non-virtual member which hides one above it in hierarchy.
| DiscardOnFirstNonOverride
/// The input list is sorted from most-derived to least-derived type, so any System.Object methods
/// are at the end of the list. Return a filtered list where prior/subsequent members matching by name and
/// that are in the same equivalence class have been removed. We keep a name-indexed table to
/// be more efficient when we check to see if we've already seen a particular named method.
type private IndexedList<'T>(itemLists: 'T list list, itemsByName: NameMultiMap<'T>) =
/// Get the item sets
member _.Items = itemLists
/// Get the items with a particular name
member _.ItemsWithName(nm) = NameMultiMap.find nm itemsByName
/// Add new items, extracting the names using the given function.
member _.AddItems(items, nmf) = IndexedList<'T>(items :: itemLists, List.foldBack (fun x acc -> NameMultiMap.add (nmf x) x acc) items itemsByName )
/// Get an empty set of items
static member Empty = IndexedList<'T>([], NameMultiMap.empty)
/// Filter a set of new items to add according to the content of the list. Only keep an item
/// if it passes 'keepTest' for all matching items already in the list.
member x.FilterNewItems keepTest nmf itemsToAdd =
// Have we already seen an item with the same name and that is in the same equivalence class?
// If so, ignore this one. Note we can check against the original incoming 'ilist' because we are assuming that
// none the elements of 'itemsToAdd' are equivalent.
itemsToAdd |> List.filter (fun item -> List.forall (keepTest item) (x.ItemsWithName(nmf item)))
/// An InfoReader is an object to help us read and cache infos.
/// We create one of these for each file we typecheck.
type InfoReader(g: TcGlobals, amap: ImportMap) as this =
/// Get the declared IL fields of a type, not including inherited fields
let GetImmediateIntrinsicILFieldsOfType (optFilter, ad) m ty =
let infos =
match metadataOfTy g ty with
#if !NO_TYPEPROVIDERS
| ProvidedTypeMetadata info ->
let st = info.ProvidedType
match optFilter with
| None ->
[ for fi in st.PApplyArray((fun st -> st.GetFields()), "GetFields", m) -> ProvidedField(amap, fi, m) ]
| Some name ->
match st.PApply ((fun st -> st.GetField name), m) with
| Tainted.Null -> []
| Tainted.NonNull fi -> [ ProvidedField(amap, fi, m) ]
#endif
| ILTypeMetadata _ ->
let tinfo = ILTypeInfo.FromType g ty
let fdefs = tinfo.RawMetadata.Fields
let fdefs = match optFilter with None -> fdefs.AsList() | Some nm -> fdefs.LookupByName nm
fdefs |> List.map (fun pd -> ILFieldInfo(tinfo, pd))
| FSharpOrArrayOrByrefOrTupleOrExnTypeMetadata ->
[]
let infos = infos |> List.filter (IsILFieldInfoAccessible g amap m ad)
infos
/// Get the declared events of a type, not including inherited events, and not including F#-declared CLIEvents
let ComputeImmediateIntrinsicEventsOfType (optFilter, ad) m ty =
let infos =
match metadataOfTy g ty with
#if !NO_TYPEPROVIDERS
| ProvidedTypeMetadata info ->
let st = info.ProvidedType
match optFilter with
| None ->
[ for ei in st.PApplyArray((fun st -> st.GetEvents()), "GetEvents", m) -> ProvidedEvent(amap, ei, m) ]
| Some name ->
match st.PApply ((fun st -> st.GetEvent name), m) with
| Tainted.Null -> []
| Tainted.NonNull ei -> [ ProvidedEvent(amap, ei, m) ]
#endif
| ILTypeMetadata _ ->
let tinfo = ILTypeInfo.FromType g ty
let edefs = tinfo.RawMetadata.Events
let edefs = match optFilter with None -> edefs.AsList() | Some nm -> edefs.LookupByName nm
[ for edef in edefs do
let ileinfo = ILEventInfo(tinfo, edef)
if IsILEventInfoAccessible g amap m ad ileinfo then
yield ILEvent ileinfo ]
| FSharpOrArrayOrByrefOrTupleOrExnTypeMetadata ->
[]
infos
/// Make a reference to a record or class field
let MakeRecdFieldInfo g ty (tcref: TyconRef) fspec =
RecdFieldInfo(argsOfAppTy g ty, tcref.MakeNestedRecdFieldRef fspec)
/// Get the F#-declared record fields or class 'val' fields of a type
let GetImmediateIntrinsicRecdOrClassFieldsOfType (optFilter, _ad) _m ty =
match tryTcrefOfAppTy g ty with
| ValueNone -> []
| ValueSome tcref ->
// Note;secret fields are not allowed in lookups here, as we're only looking
// up user-visible fields in name resolution.
match optFilter with
| Some nm ->
match tcref.GetFieldByName nm with
| Some rfield when not rfield.IsCompilerGenerated -> [MakeRecdFieldInfo g ty tcref rfield]
| _ -> []
| None ->
[ for fdef in tcref.AllFieldsArray do
if not fdef.IsCompilerGenerated then
yield MakeRecdFieldInfo g ty tcref fdef ]
/// The primitive reader for the method info sets up a hierarchy
let GetIntrinsicMethodSetsUncached ((optFilter, ad, allowMultiIntfInst), m, ty) =
FoldPrimaryHierarchyOfType (fun ty acc -> GetImmediateIntrinsicMethInfosOfType (optFilter, ad) g amap m ty :: acc) g amap m allowMultiIntfInst ty []
/// The primitive reader for the property info sets up a hierarchy
let GetIntrinsicPropertySetsUncached ((optFilter, ad, allowMultiIntfInst), m, ty) =
FoldPrimaryHierarchyOfType (fun ty acc -> GetImmediateIntrinsicPropInfosOfType (optFilter, ad) g amap m ty :: acc) g amap m allowMultiIntfInst ty []
let GetIntrinsicILFieldInfosUncached ((optFilter, ad), m, ty) =
FoldPrimaryHierarchyOfType (fun ty acc -> GetImmediateIntrinsicILFieldsOfType (optFilter, ad) m ty @ acc) g amap m AllowMultiIntfInstantiations.Yes ty []
let GetIntrinsicEventInfosUncached ((optFilter, ad), m, ty) =
FoldPrimaryHierarchyOfType (fun ty acc -> ComputeImmediateIntrinsicEventsOfType (optFilter, ad) m ty @ acc) g amap m AllowMultiIntfInstantiations.Yes ty []
let GetIntrinsicRecdOrClassFieldInfosUncached ((optFilter, ad), m, ty) =
FoldPrimaryHierarchyOfType (fun ty acc -> GetImmediateIntrinsicRecdOrClassFieldsOfType (optFilter, ad) m ty @ acc) g amap m AllowMultiIntfInstantiations.Yes ty []
let GetEntireTypeHierarchyUncached (allowMultiIntfInst, m, ty) =
FoldEntireHierarchyOfType (fun ty acc -> ty :: acc) g amap m allowMultiIntfInst ty []
let GetPrimaryTypeHierarchyUncached (allowMultiIntfInst, m, ty) =
FoldPrimaryHierarchyOfType (fun ty acc -> ty :: acc) g amap m allowMultiIntfInst ty []
/// The primitive reader for the named items up a hierarchy
let GetIntrinsicNamedItemsUncached ((nm, ad, includeConstraints), m, ty) =
if nm = ".ctor" then None else // '.ctor' lookups only ever happen via constructor syntax
let optFilter = Some nm
FoldPrimaryHierarchyOfType (fun ty acc ->
let qinfos = if includeConstraints then GetImmediateTraitsInfosOfType optFilter g ty else []
let minfos = GetImmediateIntrinsicMethInfosOfType (optFilter, ad) g amap m ty
let pinfos = GetImmediateIntrinsicPropInfosOfType (optFilter, ad) g amap m ty
let finfos = GetImmediateIntrinsicILFieldsOfType (optFilter, ad) m ty
let einfos = ComputeImmediateIntrinsicEventsOfType (optFilter, ad) m ty
let rfinfos = GetImmediateIntrinsicRecdOrClassFieldsOfType (optFilter, ad) m ty
match acc with
| _ when not (isNil qinfos) -> Some(TraitItem qinfos)
| Some(MethodItem(inheritedMethSets)) when not (isNil minfos) -> Some(MethodItem (minfos :: inheritedMethSets))
| _ when not (isNil minfos) -> Some(MethodItem [minfos])
| Some(PropertyItem(inheritedPropSets)) when not (isNil pinfos) -> Some(PropertyItem(pinfos :: inheritedPropSets))
| _ when not (isNil pinfos) -> Some(PropertyItem([pinfos]))
| _ when not (isNil finfos) -> Some(ILFieldItem(finfos))
| _ when not (isNil einfos) -> Some(EventItem(einfos))
| _ when not (isNil rfinfos) ->
match rfinfos with
| [single] -> Some(RecdFieldItem(single))
| _ -> failwith "Unexpected multiple fields with the same name" // Because an explicit name (i.e., nm) was supplied, there will be only one element at most.
| _ -> acc)
g amap m
AllowMultiIntfInstantiations.Yes
ty
None
let GetImmediateIntrinsicOverrideMethodSetsOfType optFilter m (interfaceTys: TType list) ty acc =
match tryAppTy g ty with
| ValueSome (tcref, _) when tcref.IsILTycon && tcref.ILTyconRawMetadata.IsInterface ->
let mimpls = tcref.ILTyconRawMetadata.MethodImpls.AsList()
let mdefs = tcref.ILTyconRawMetadata.Methods
// MethodImpls contains a list of methods that override.
// OverrideBy is the method that does the overriding.
// Overrides is the method being overridden.
(acc, mimpls)
||> List.fold (fun acc ilMethImpl ->
let overridesName = ilMethImpl.Overrides.MethodRef.Name
let overrideBy = ilMethImpl.OverrideBy
let canAccumulate =
match optFilter with
| None -> true
| Some name when name = overridesName -> true
| _ -> false
if canAccumulate then
match mdefs.TryFindInstanceByNameAndCallingSignature (overrideBy.Name, overrideBy.MethodRef.GetCallingSignature()) with
| Some mdef ->
let overridesILTy = ilMethImpl.Overrides.DeclaringType
let overridesTyFullName = overridesILTy.TypeRef.FullName
let overridesTyOpt =
interfaceTys
|> List.tryPick (fun ty ->
match tryTcrefOfAppTy g ty with
| ValueSome tcref when tcref.IsILTycon && tcref.ILTyconRawMetadata.Name = overridesTyFullName ->
generalizedTyconRef g tcref
|> Some
| _ ->
None)
match overridesTyOpt with
| Some overridesTy ->
NameMultiMap.add overridesName (overridesTy, MethInfo.CreateILMeth(amap, m, ty, mdef)) acc
| _ ->
acc
| _ ->
acc
else
acc)
| _ -> acc
/// Visiting each type in the hierarchy and accumulate most specific methods that are the OverrideBy target from types.
let GetIntrinsicMostSpecificOverrideMethodSetsUncached ((optFilter, _ad, allowMultiIntfInst), m, ty) : NameMultiMap<_> =
let interfaceTys =
FoldPrimaryHierarchyOfType (fun ty acc ->
if isInterfaceTy g ty then ty :: acc
else acc) g amap m allowMultiIntfInst ty []
(NameMultiMap.Empty, interfaceTys)
||> List.fold (fun acc ty -> GetImmediateIntrinsicOverrideMethodSetsOfType optFilter m interfaceTys ty acc)
|> FilterMostSpecificMethInfoSets g amap m
/// Add all the items to the IndexedList, preferring the ones in the super-types. This is used to hide methods
/// in super classes and/or hide overrides of methods in subclasses.
///
/// Assume no items in 'items' are equivalent according to 'equivTest'. This is valid because each step in a
/// .NET class hierarchy introduces a consistent set of methods, none of which hide each other within the
/// given set. This is an important optimization because it means we don't have filter for equivalence between the
/// large overload sets introduced by methods like System.WriteLine.
///
/// Assume items can be given names by 'nmf', where two items with different names are
/// not equivalent.
static let FilterItemsInSubTypesBasedOnItemsInSuperTypes nmf keepTest itemLists =
let rec loop itemLists =
match itemLists with
| [] -> IndexedList.Empty
| items :: itemsInSuperTypes ->
let ilist = loop itemsInSuperTypes
let itemsToAdd = ilist.FilterNewItems keepTest nmf items
ilist.AddItems(itemsToAdd, nmf)
(loop itemLists).Items
/// Add all the items to the IndexedList, preferring the ones in the sub-types.
static let FilterItemsInSuperTypesBasedOnItemsInSubTypes nmf keepTest itemLists =
let rec loop itemLists (indexedItemsInSubTypes: IndexedList<_>) =
match itemLists with
| [] -> List.rev indexedItemsInSubTypes.Items
| items :: itemsInSuperTypes ->
let itemsToAdd = items |> List.filter (fun item -> keepTest item (indexedItemsInSubTypes.ItemsWithName(nmf item)))
let ilist = indexedItemsInSubTypes.AddItems(itemsToAdd, nmf)
loop itemsInSuperTypes ilist
loop itemLists IndexedList.Empty
static let ExcludeItemsInSuperTypesBasedOnEquivTestWithItemsInSubTypes nmf equivTest itemLists =
FilterItemsInSuperTypesBasedOnItemsInSubTypes nmf (fun item1 items -> not (items |> List.exists (fun item2 -> equivTest item1 item2))) itemLists
/// Filter the overrides of methods or properties, either keeping the overrides or keeping the dispatch slots.
static let FilterOverrides findFlag (isVirt:'a->bool, isNewSlot, isDefiniteOverride, isFinal, isAbstract, equivSigs, nmf:'a->string) items =
let equivVirts x y = isVirt x && isVirt y && equivSigs x y
let filterDefiniteOverrides = List.filter(isDefiniteOverride >> not)
match findFlag with
| DiscardOnFirstNonOverride ->
items
|> List.map filterDefiniteOverrides
|> ExcludeItemsInSuperTypesBasedOnEquivTestWithItemsInSubTypes nmf (fun newItem priorItem ->
equivSigs newItem priorItem &&
isVirt newItem && not (isVirt priorItem)
)
| PreferOverrides ->
items
// For each F#-declared override, get rid of any equivalent abstract member in the same type
// This is because F# abstract members with default overrides give rise to two members with the
// same logical signature in the same type, e.g.
// type ClassType1() =
// abstract VirtualMethod1: string -> int
// default x.VirtualMethod1(s) = 3
|> List.map (fun items ->
let definiteOverrides = items |> List.filter isDefiniteOverride
items |> List.filter (fun item -> (isDefiniteOverride item || not (List.exists (equivVirts item) definiteOverrides))))
// only keep virtuals that are not signature-equivalent to virtuals in subtypes
|> ExcludeItemsInSuperTypesBasedOnEquivTestWithItemsInSubTypes nmf equivVirts
| IgnoreOverrides ->
let equivNewSlots x y = isNewSlot x && isNewSlot y && equivSigs x y
items
// Remove any F#-declared overrides. These may occur in the same type as the abstract member (unlike with .NET metadata)
// Include any 'newslot' declared methods.
|> List.map filterDefiniteOverrides
// Remove any virtuals that are signature-equivalent to virtuals in subtypes, except for newslots
// That is, keep if it's
// (a) not virtual
// (b) is a new slot or
// (c) not equivalent
// (d) is abstract (e.g. C# 'abstract override' re-abstracting a base virtual method)
// We keep virtual finals around for error detection later on
|> FilterItemsInSubTypesBasedOnItemsInSuperTypes nmf (fun newItem priorItem ->
(isVirt newItem && isFinal newItem) || not (isVirt newItem) || isNewSlot newItem || isAbstract newItem || not (equivVirts newItem priorItem) )
// Remove any abstract slots in supertypes that are (a) hidden by another newslot and (b) implemented
// We leave unimplemented ones around to give errors, e.g. for
// [<AbstractClass>]
// type PA() =
// abstract M : int -> unit
//
// [<AbstractClass>]
// type PB<'a>() =
// inherit PA()
// abstract M : 'a -> unit
//
// [<AbstractClass>]
// type PC() =
// inherit PB<int>()
// // Here, PA.M and PB<int>.M have the same signature, so PA.M is unimplementable.
// // REVIEW: in future we may give a friendly error at this point
//
// type PD() =
// inherit PC()
// override this.M(x: int) = ()
|> FilterItemsInSuperTypesBasedOnItemsInSubTypes nmf (fun item1 superTypeItems ->
not (isNewSlot item1 &&
superTypeItems |> List.exists (equivNewSlots item1) &&
superTypeItems |> List.exists (fun item2 -> isDefiniteOverride item1 && equivVirts item1 item2)))
/// Filter the overrides of methods, either keeping the overrides or keeping the dispatch slots.
static let FilterOverridesOfMethInfos findFlag g amap m minfos =
minfos
|> FilterOverrides findFlag
((fun (minfo: MethInfo) -> minfo.IsVirtual),
(fun minfo -> minfo.IsNewSlot),
(fun minfo -> minfo.IsDefiniteFSharpOverride),
(fun minfo -> minfo.IsFinal),
(fun minfo -> minfo.IsAbstract),
MethInfosEquivByNameAndSig EraseNone true g amap m,
(fun minfo -> minfo.LogicalName))
static let PropsGetterSetterEquiv innerEquality (p1:PropInfo) (p2:PropInfo) : bool =
p1.HasGetter = p2.HasGetter &&
p1.HasSetter = p2.HasSetter &&
innerEquality p1 p2
/// Filter the overrides of properties, either keeping the overrides or keeping the dispatch slots.
static let FilterOverridesOfPropInfos findFlag g amap m props =
props
|> FilterOverrides findFlag
((fun (pinfo: PropInfo) -> pinfo.IsVirtualProperty),
(fun pinfo -> pinfo.IsNewSlot),
(fun pinfo -> pinfo.IsDefiniteFSharpOverride),
(fun _ -> false), // isFinal
(fun _ -> false), // isAbstract
PropsGetterSetterEquiv (PropInfosEquivByNameAndSig EraseNone g amap m),
(fun pinfo -> pinfo.PropertyName))
//type A() =
// abstract E: int with get, set
// default val E = 0 with get
// Will get (A::E with get, A::E with get, set)
// -----
//type A() =
// member val A = 0 with get, set
//type B() =
// inherit A()
// static member val A = 0
// Will get (static B::A, None)
static let FilterOverridesOfPropInfosWithOverriddenProp findFlag g amap m props =
let checkProp prop prop2 =
not(obj.ReferenceEquals(prop, prop2)) &&
PropInfosEquivByNameAndSig EraseNone g amap m prop prop2 &&
if prop.HasGetter && prop.HasSetter then false
elif prop.HasGetter then prop2.HasSetter
elif prop.HasSetter then prop2.HasGetter
else false
let rec findPropBefore prop hasMetTheProp =
function
| props :: t when hasMetTheProp ->
match props |> List.tryFind (checkProp prop) with
| Some p -> ValueSome p
| None -> findPropBefore prop true t
| props :: t ->
if props |> List.exists (fun i -> obj.ReferenceEquals(prop, i)) then
match props |> List.tryFind (checkProp prop) with
| Some p -> ValueSome p
| None -> findPropBefore prop true t
else findPropBefore prop false t
| _ -> ValueNone
props
|> FilterOverridesOfPropInfos findFlag g amap m
|> List.map (List.map (fun prop -> struct(prop, if findFlag = FindMemberFlag.IgnoreOverrides || prop.IsNewSlot then ValueNone else findPropBefore prop false props)))
/// Exclude methods from super types which have the same signature as a method in a more specific type.
static let ExcludeHiddenOfMethInfosImpl g amap m (minfos: MethInfo list list) =
minfos
|> ExcludeItemsInSuperTypesBasedOnEquivTestWithItemsInSubTypes
(fun minfo -> minfo.LogicalName)
(fun m1 m2 ->
// only hide those truly from super classes
not (tyconRefEq g m1.DeclaringTyconRef m2.DeclaringTyconRef) &&
MethInfosEquivByNameAndPartialSig EraseNone true g amap m m1 m2)
|> List.concat
/// Exclude properties from super types which have the same name as a property in a more specific type.
static let ExcludeHiddenOfPropInfosImpl g amap m pinfos =
pinfos
|> ExcludeItemsInSuperTypesBasedOnEquivTestWithItemsInSubTypes (fun (pinfo: PropInfo) -> pinfo.PropertyName) (PropsGetterSetterEquiv (PropInfosEquivByNameAndPartialSig EraseNone g amap m))
|> List.concat
/// Make a cache for function 'f' keyed by type (plus some additional 'flags') that only
/// caches computations for monomorphic types.
let MakeInfoCache name f (flagsEq : IEqualityComparer<_>) =
MemoizationTable<_, _>
(name, compute=f,
// Only cache closed, monomorphic types (closed = all members for the type
// have been processed). Generic type instantiations could be processed if we had
// a decent hash function for these.
// Nullness of `ty` (TType_app) is not considered here, as the info is used to load members of the type
// It would matter for different generic instantiations of the same type, but we don't cache that here - TType_app is always matched for `[]` typars.
canMemoize=(fun (_flags, _: range, ty) ->
match stripTyEqns g ty with
| TType_app(tcref, [], _) -> tcref.TypeContents.tcaug_closed
| _ -> false),
keyComparer=
{ new IEqualityComparer<_> with
member _.GetHashCode((flags, _, ty)) =
// Ignoring the ranges - that's OK.
flagsEq.GetHashCode flags +
(match stripTyEqns g ty with
| TType_app(tcref, [], _) -> hash tcref.LogicalName
| _ -> 0)
member _.Equals((flags1, _, ty1), (flags2, _, ty2)) =
// Ignoring the ranges - that's OK.
flagsEq.Equals(flags1, flags2) &&
match stripTyEqns g ty1, stripTyEqns g ty2 with
| TType_app(tcref1, [], _),TType_app(tcref2, [], _) -> tyconRefEq g tcref1 tcref2
| _ -> false })
let FindImplicitConversionsUncached (ad, m, ty) =
if isTyparTy g ty then
[]
// F# ignores the op_Implicit conversions defined on the 'Option' and 'ValueOption' types
elif isOptionTy g ty || isValueOptionTy g ty then
[]
else
this.TryFindIntrinsicMethInfo m ad "op_Implicit" ty
let IsInterfaceTypeWithMatchingStaticAbstractMemberUncached ((ad, nm), m, ty) =
ExistsInEntireHierarchyOfType (fun parentTy ->
let meths = this.TryFindIntrinsicMethInfo m ad nm parentTy
meths |> List.exists (fun meth ->
not meth.IsInstance &&
meth.IsDispatchSlot &&
isInterfaceTy g meth.ApparentEnclosingAppType
))
g amap m AllowMultiIntfInstantiations.Yes ty
let GetUnimplementedStaticAbstractMemberOfTypeUncached (_flags, m, interfaceTy) =
if not (isInterfaceTy g interfaceTy) then
None
else
let checkMembersOfInterface (ty: TType) =
let meths = this.GetIntrinsicMethInfosOfType None AccessibleFromSomeFSharpCode AllowMultiIntfInstantiations.Yes IgnoreOverrides m ty
meths |> List.tryPick (fun (minfo: MethInfo) ->
// Static abstract non-sealed (non-DIM) members
if not minfo.IsInstance && minfo.IsAbstract && not minfo.IsFinal then
Some minfo.DisplayNameCore
else
None
)
match checkMembersOfInterface interfaceTy with
| Some name -> Some name
| None ->
let baseInterfaces = AllInterfacesOfType g amap m AllowMultiIntfInstantiations.Yes interfaceTy
baseInterfaces |> List.tryPick checkMembersOfInterface
let hashFlags0 =
{ new IEqualityComparer<string option * AccessorDomain * AllowMultiIntfInstantiations> with
member _.GetHashCode((filter: string option, ad: AccessorDomain, _allowMultiIntfInst1)) = hash filter + AccessorDomain.CustomGetHashCode ad
member _.Equals((filter1, ad1, allowMultiIntfInst1), (filter2, ad2, allowMultiIntfInst2)) =
(filter1 = filter2) && AccessorDomain.CustomEquals(g, ad1, ad2) && allowMultiIntfInst1 = allowMultiIntfInst2 }
let hashFlags1 =
{ new IEqualityComparer<string option * AccessorDomain> with
member _.GetHashCode((filter: string option, ad: AccessorDomain)) = hash filter + AccessorDomain.CustomGetHashCode ad
member _.Equals((filter1, ad1), (filter2, ad2)) = (filter1 = filter2) && AccessorDomain.CustomEquals(g, ad1, ad2) }
let hashFlags2 =
{ new IEqualityComparer<string * AccessorDomain * bool> with
member _.GetHashCode((nm: string, ad: AccessorDomain, includeConstraints)) =
hash nm + AccessorDomain.CustomGetHashCode ad + hash includeConstraints
member _.Equals((nm1, ad1, includeConstraints1), (nm2, ad2, includeConstraints2)) =
(nm1 = nm2) && AccessorDomain.CustomEquals(g, ad1, ad2) && (includeConstraints1 = includeConstraints2) }
let hashFlags3 =
{ new IEqualityComparer<AccessorDomain> with
member _.GetHashCode((ad: AccessorDomain)) = AccessorDomain.CustomGetHashCode ad
member _.Equals(ad1, ad2) = nullSafeEquality ad1 ad2 (fun ad1 ad2 -> AccessorDomain.CustomEquals(g, ad1, ad2)) }
let hashFlags4 =
{ new IEqualityComparer<AccessorDomain * string> with
member _.GetHashCode((ad, nm)) = AccessorDomain.CustomGetHashCode ad + hash nm
member _.Equals((ad1, nm1), (ad2, nm2)) = AccessorDomain.CustomEquals(g, ad1, ad2) && (nm1 = nm2) }
let methodInfoCache = MakeInfoCache "methodInfoCache" GetIntrinsicMethodSetsUncached hashFlags0
let propertyInfoCache = MakeInfoCache "propertyInfoCache" GetIntrinsicPropertySetsUncached hashFlags0
let recdOrClassFieldInfoCache = MakeInfoCache "recdOrClassFieldInfoCache" GetIntrinsicRecdOrClassFieldInfosUncached hashFlags1
let ilFieldInfoCache = MakeInfoCache "ilFieldInfoCache" GetIntrinsicILFieldInfosUncached hashFlags1
let eventInfoCache = MakeInfoCache "eventInfoCache" GetIntrinsicEventInfosUncached hashFlags1
let namedItemsCache = MakeInfoCache "namedItemsCache" GetIntrinsicNamedItemsUncached hashFlags2
let mostSpecificOverrideMethodInfoCache = MakeInfoCache "mostSpecificOverrideMethodInfoCache" GetIntrinsicMostSpecificOverrideMethodSetsUncached hashFlags0
let entireTypeHierarchyCache = MakeInfoCache "entireTypeHierarchyCache" GetEntireTypeHierarchyUncached HashIdentity.Structural
let primaryTypeHierarchyCache = MakeInfoCache "primaryTypeHierarchyCache" GetPrimaryTypeHierarchyUncached HashIdentity.Structural
let implicitConversionCache = MakeInfoCache "implicitConversionCache" FindImplicitConversionsUncached hashFlags3
let isInterfaceWithStaticAbstractMethodCache = MakeInfoCache "isInterfaceWithStaticAbstractMethodCache" IsInterfaceTypeWithMatchingStaticAbstractMemberUncached hashFlags4
let unimplementedStaticAbstractMemberCache =
MakeInfoCache
"unimplementedStaticAbstractMemberCache"
GetUnimplementedStaticAbstractMemberOfTypeUncached
hashFlags0
// Runtime feature support
let isRuntimeFeatureSupported runtimeFeature =
match g.System_Runtime_CompilerServices_RuntimeFeature_ty with
| Some runtimeFeatureTy ->
GetIntrinsicILFieldInfosUncached ((None, AccessorDomain.AccessibleFromEverywhere), range0, runtimeFeatureTy)
|> List.exists (fun (ilFieldInfo: ILFieldInfo) -> ilFieldInfo.FieldName = runtimeFeature)
| _ ->
false
let isRuntimeFeatureDefaultImplementationsOfInterfacesSupported =
lazy isRuntimeFeatureSupported "DefaultImplementationsOfInterfaces"
let isRuntimeFeatureVirtualStaticsInInterfacesSupported =
lazy isRuntimeFeatureSupported "VirtualStaticsInInterfaces"
member _.g = g
member _.amap = amap
/// Read the raw method sets of a type, including inherited ones. Cache the result for monomorphic types
member _.GetRawIntrinsicMethodSetsOfType (optFilter, ad, allowMultiIntfInst, m, ty) =
methodInfoCache.Apply(((optFilter, ad, allowMultiIntfInst), m, ty))
/// Read the raw property sets of a type, including inherited ones. Cache the result for monomorphic types
member _.GetRawIntrinsicPropertySetsOfType (optFilter, ad, allowMultiIntfInst, m, ty) =
propertyInfoCache.Apply(((optFilter, ad, allowMultiIntfInst), m, ty))
/// Read the record or class fields of a type, including inherited ones. Cache the result for monomorphic types.
member _.GetRecordOrClassFieldsOfType (optFilter, ad, m, ty) =
recdOrClassFieldInfoCache.Apply(((optFilter, ad), m, ty))
/// Read the IL fields of a type, including inherited ones. Cache the result for monomorphic types.
member _.GetILFieldInfosOfType (optFilter, ad, m, ty) =
ilFieldInfoCache.Apply(((optFilter, ad), m, ty))
member _.GetImmediateIntrinsicEventsOfType (optFilter, ad, m, ty) =
ComputeImmediateIntrinsicEventsOfType (optFilter, ad) m ty
/// Read the events of a type, including inherited ones. Cache the result for monomorphic types.
member _.GetEventInfosOfType (optFilter, ad, m, ty) =
eventInfoCache.Apply(((optFilter, ad), m, ty))
/// Try and find a record or class field for a type.
member _.TryFindRecdOrClassFieldInfoOfType (nm, m, ty) =
match recdOrClassFieldInfoCache.Apply((Some nm, AccessibleFromSomewhere), m, ty) with
| [] -> ValueNone
| [single] -> ValueSome single
| flds ->
// multiple fields with the same name can come from different classes,
// so filter them by the given type name
match tryTcrefOfAppTy g ty with
| ValueNone -> ValueNone
| ValueSome tcref ->
match flds |> List.filter (fun rfinfo -> tyconRefEq g tcref rfinfo.TyconRef) with
| [] -> ValueNone
| [single] -> ValueSome single
| _ -> failwith "unexpected multiple fields with same name" // Because it should have been already reported as duplicate fields
/// Try and find an item with the given name in a type.
member _.TryFindNamedItemOfType ((nm, ad, includeConstraints), m, ty) =
namedItemsCache.Apply(((nm, ad, includeConstraints), m, ty))
/// Read the raw method sets of a type that are the most specific overrides. Cache the result for monomorphic types
member _.GetIntrinsicMostSpecificOverrideMethodSetsOfType (optFilter, ad, allowMultiIntfInst, m, ty) =
mostSpecificOverrideMethodInfoCache.Apply(((optFilter, ad, allowMultiIntfInst), m, ty))
/// Get the super-types of a type, including interface types.
member _.GetEntireTypeHierarchy (allowMultiIntfInst, m, ty) =
entireTypeHierarchyCache.Apply((allowMultiIntfInst, m, ty))
/// Get the super-types of a type, excluding interface types.
member _.GetPrimaryTypeHierarchy (allowMultiIntfInst, m, ty) =
primaryTypeHierarchyCache.Apply((allowMultiIntfInst, m, ty))
/// Check if the given language feature is supported by the runtime.
member _.IsLanguageFeatureRuntimeSupported langFeature =
match langFeature with
// Both default and static interface method consumption features are tied to the runtime support of DIMs.
| LanguageFeature.DefaultInterfaceMemberConsumption -> isRuntimeFeatureDefaultImplementationsOfInterfacesSupported.Value
| LanguageFeature.InterfacesWithAbstractStaticMembers -> isRuntimeFeatureVirtualStaticsInInterfacesSupported.Value
| _ -> true
/// Get the declared constructors of any F# type
member infoReader.GetIntrinsicConstructorInfosOfTypeAux m origTy metadataTy =
protectAssemblyExploration [] (fun () ->
let g = infoReader.g
let amap = infoReader.amap
match metadataOfTy g metadataTy with
#if !NO_TYPEPROVIDERS
| ProvidedTypeMetadata info ->
let st = info.ProvidedType
[ for ci in st.PApplyArray((fun st -> st.GetConstructors()), "GetConstructors", m) do
yield ProvidedMeth(amap, ci.Coerce(m), None, m) ]
#endif
| ILTypeMetadata _ ->
let tinfo = ILTypeInfo.FromType g origTy
tinfo.RawMetadata.Methods.FindByName ".ctor"
|> List.filter (fun md -> md.IsConstructor)
|> List.map (fun mdef -> MethInfo.CreateILMeth (amap, m, origTy, mdef))
| FSharpOrArrayOrByrefOrTupleOrExnTypeMetadata ->
// Tuple types also support constructors. In this case convert to the .NET Tuple type that carries metadata and try again
// Function types also support constructors. In this case convert to the FSharpFunc type that carries metadata and try again
if isAnyTupleTy g metadataTy || isFunTy g metadataTy then
let betterMetadataTy = convertToTypeWithMetadataIfPossible g metadataTy
infoReader.GetIntrinsicConstructorInfosOfTypeAux m origTy betterMetadataTy
else
match tryTcrefOfAppTy g metadataTy with
| ValueNone -> []
| ValueSome tcref ->
tcref.MembersOfFSharpTyconByName
|> NameMultiMap.find ".ctor"
|> List.choose(fun vref ->
match vref.MemberInfo with
| Some membInfo when (membInfo.MemberFlags.MemberKind = SynMemberKind.Constructor) -> Some vref
| _ -> None)
|> List.map (fun x -> FSMeth(g, origTy, x, None))
)
static member ExcludeHiddenOfMethInfos g amap m minfos =
ExcludeHiddenOfMethInfosImpl g amap m minfos
static member ExcludeHiddenOfPropInfos g amap m pinfos =
ExcludeHiddenOfPropInfosImpl g amap m pinfos
/// Get the sets of intrinsic methods in the hierarchy (not including extension methods)
member infoReader.GetIntrinsicMethInfoSetsOfType optFilter ad allowMultiIntfInst findFlag m ty =
infoReader.GetRawIntrinsicMethodSetsOfType(optFilter, ad, allowMultiIntfInst, m, ty)
|> FilterOverridesOfMethInfos findFlag infoReader.g infoReader.amap m
/// Get the sets intrinsic properties in the hierarchy (not including extension properties)
member infoReader.GetIntrinsicPropInfoSetsOfType optFilter ad allowMultiIntfInst findFlag m ty =
infoReader.GetRawIntrinsicPropertySetsOfType(optFilter, ad, allowMultiIntfInst, m, ty)
|> FilterOverridesOfPropInfos findFlag infoReader.g infoReader.amap m
/// Get the flattened list of intrinsic methods in the hierarchy
member infoReader.GetIntrinsicMethInfosOfType optFilter ad allowMultiIntfInst findFlag m ty =
infoReader.GetIntrinsicMethInfoSetsOfType optFilter ad allowMultiIntfInst findFlag m ty |> List.concat
/// Get the flattened list of intrinsic properties in the hierarchy
member infoReader.GetIntrinsicPropInfosOfType optFilter ad allowMultiIntfInst findFlag m ty =
infoReader.GetIntrinsicPropInfoSetsOfType optFilter ad allowMultiIntfInst findFlag m ty |> List.concat
/// Get the flattened list of intrinsic properties in the hierarchy
member infoReader.GetIntrinsicPropInfoWithOverriddenPropOfType optFilter ad allowMultiIntfInst findFlag m ty =
infoReader.GetRawIntrinsicPropertySetsOfType(optFilter, ad, allowMultiIntfInst, m, ty)
|> FilterOverridesOfPropInfosWithOverriddenProp findFlag infoReader.g infoReader.amap m
|> List.concat
member _.GetTraitInfosInType optFilter ty =
GetImmediateTraitsInfosOfType optFilter g ty
member infoReader.TryFindIntrinsicNamedItemOfType (nm, ad, includeConstraints) findFlag m ty =
match infoReader.TryFindNamedItemOfType((nm, ad, includeConstraints), m, ty) with