forked from nosami/visualfsharp
/
MethodCalls.fs
1972 lines (1688 loc) · 102 KB
/
MethodCalls.fs
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.
/// Logic associated with resolving method calls.
module internal FSharp.Compiler.MethodCalls
open Internal.Utilities
open FSharp.Compiler
open FSharp.Compiler.AbstractIL.IL
open FSharp.Compiler.AbstractIL.Internal.Library
open FSharp.Compiler.AccessibilityLogic
open FSharp.Compiler.AttributeChecking
open FSharp.Compiler.ErrorLogger
open FSharp.Compiler.Features
open FSharp.Compiler.InfoReader
open FSharp.Compiler.Infos
open FSharp.Compiler.Lib
open FSharp.Compiler.NameResolution
open FSharp.Compiler.PrettyNaming
open FSharp.Compiler.Range
open FSharp.Compiler.SyntaxTree
open FSharp.Compiler.SyntaxTreeOps
open FSharp.Compiler.TcGlobals
open FSharp.Compiler.TypedTree
open FSharp.Compiler.TypedTreeBasics
open FSharp.Compiler.TypedTreeOps
open FSharp.Compiler.TypedTreeOps.DebugPrint
open FSharp.Compiler.TypeRelations
#if !NO_EXTENSIONTYPING
open FSharp.Compiler.ExtensionTyping
#endif
//-------------------------------------------------------------------------
// Sets of methods involved in overload resolution and trait constraint
// satisfaction.
//-------------------------------------------------------------------------
/// In the following, 'T gets instantiated to:
/// 1. the expression being supplied for an argument
/// 2. "unit", when simply checking for the existence of an overload that satisfies
/// a signature, or when finding the corresponding witness.
/// Note the parametricity helps ensure that overload resolution doesn't depend on the
/// expression on the callside (though it is in some circumstances allowed
/// to depend on some type information inferred syntactically from that
/// expression, e.g. a lambda expression may be converted to a delegate as
/// an adhoc conversion.
///
/// The bool indicates if named using a '?', making the caller argument explicit-optional
type CallerArg<'T> =
/// CallerArg(ty, range, isOpt, exprInfo)
| CallerArg of ty: TType * range: range * isOpt: bool * exprInfo: 'T
member x.CallerArgumentType = (let (CallerArg(ty, _, _, _)) = x in ty)
member x.Range = (let (CallerArg(_, m, _, _)) = x in m)
member x.IsExplicitOptional = (let (CallerArg(_, _, isOpt, _)) = x in isOpt)
member x.Expr = (let (CallerArg(_, _, _, expr)) = x in expr)
/// Represents the information about an argument in the method being called
type CalledArg =
{ Position: struct (int * int)
IsParamArray : bool
OptArgInfo : OptionalArgInfo
CallerInfo : CallerInfo
IsInArg: bool
IsOutArg: bool
ReflArgInfo: ReflectedArgInfo
NameOpt: Ident option
CalledArgumentType : TType }
let CalledArg (pos, isParamArray, optArgInfo, callerInfo, isInArg, isOutArg, nameOpt, reflArgInfo, calledArgTy) =
{ Position=pos
IsParamArray=isParamArray
OptArgInfo=optArgInfo
CallerInfo=callerInfo
IsInArg=isInArg
IsOutArg=isOutArg
ReflArgInfo=reflArgInfo
NameOpt=nameOpt
CalledArgumentType=calledArgTy }
/// Represents a match between a caller argument and a called argument, arising from either
/// a named argument or an unnamed argument.
type AssignedCalledArg<'T> =
{ /// The identifier for a named argument, if any
NamedArgIdOpt : Ident option
/// The called argument in the method
CalledArg: CalledArg
/// The argument on the caller side
CallerArg: CallerArg<'T> }
member x.Position = x.CalledArg.Position
/// Represents the possibilities for a named-setter argument (a property, field, or a record field setter)
type AssignedItemSetterTarget =
| AssignedPropSetter of PropInfo * MethInfo * TypeInst (* the MethInfo is a non-indexer setter property *)
| AssignedILFieldSetter of ILFieldInfo
| AssignedRecdFieldSetter of RecdFieldInfo
/// Represents the resolution of a caller argument as a named-setter argument
type AssignedItemSetter<'T> = AssignedItemSetter of Ident * AssignedItemSetterTarget * CallerArg<'T>
type CallerNamedArg<'T> =
| CallerNamedArg of Ident * CallerArg<'T>
member x.Ident = (let (CallerNamedArg(id, _)) = x in id)
member x.Name = x.Ident.idText
member x.CallerArg = (let (CallerNamedArg(_, a)) = x in a)
/// Represents the list of unnamed / named arguments at method call site
/// remark: The usage of list list is due to tupling and currying of arguments,
/// stemming from SynValInfo in the AST.
[<Struct>]
type CallerArgs<'T> =
{
Unnamed: CallerArg<'T> list list
Named: CallerNamedArg<'T> list list
}
static member Empty : CallerArgs<'T> = { Unnamed = []; Named = [] }
member x.CallerArgCounts = List.length x.Unnamed, List.length x.Named
member x.CurriedCallerArgs = List.zip x.Unnamed x.Named
member x.ArgumentNamesAndTypes =
let unnamed = x.Unnamed |> List.collect (List.map (fun i -> None, i.CallerArgumentType))
let named = x.Named |> List.collect (List.map (fun i -> Some i.Name, i.CallerArg.CallerArgumentType))
unnamed @ named
//-------------------------------------------------------------------------
// Callsite conversions
//-------------------------------------------------------------------------
// If the called method argument is a delegate type, and the caller is known to be a function type, then the caller may provide a function
// If the called method argument is an Expression<T> type, and the caller is known to be a function type, then the caller may provide a T
// If the called method argument is an [<AutoQuote>] Quotations.Expr<T>, and the caller is not known to be a quoted expression type, then the caller may provide a T
let AdjustCalledArgTypeForLinqExpressionsAndAutoQuote (infoReader: InfoReader) callerArgTy (calledArg: CalledArg) m =
let g = infoReader.g
let calledArgTy = calledArg.CalledArgumentType
let adjustDelegateTy calledTy =
let (SigOfFunctionForDelegate(_, delArgTys, _, fty)) = GetSigOfFunctionForDelegate infoReader calledTy m AccessibleFromSomewhere
let delArgTys = if isNil delArgTys then [g.unit_ty] else delArgTys
if (fst (stripFunTy g callerArgTy)).Length = delArgTys.Length then
fty
else
calledArgTy
if isDelegateTy g calledArgTy && isFunTy g callerArgTy then
adjustDelegateTy calledArgTy
elif isLinqExpressionTy g calledArgTy && isFunTy g callerArgTy then
let calledArgTyNoExpr = destLinqExpressionTy g calledArgTy
if isDelegateTy g calledArgTyNoExpr then
adjustDelegateTy calledArgTyNoExpr
else
calledArgTy
elif calledArg.ReflArgInfo.AutoQuote && isQuotedExprTy g calledArgTy && not (isQuotedExprTy g callerArgTy) then
destQuotedExprTy g calledArgTy
else calledArgTy
/// Adjust the called argument type to take into account whether the caller's argument is CSharpMethod(?arg=Some(3)) or CSharpMethod(arg=1)
let AdjustCalledArgTypeForOptionals (g: TcGlobals) enforceNullableOptionalsKnownTypes (calledArg: CalledArg) calledArgTy (callerArg: CallerArg<_>) =
if callerArg.IsExplicitOptional then
match calledArg.OptArgInfo with
// CSharpMethod(?x = arg), optional C#-style argument, may have nullable type
| CallerSide _ ->
if g.langVersion.SupportsFeature LanguageFeature.NullableOptionalInterop then
if isNullableTy g calledArgTy then
mkOptionTy g (destNullableTy g calledArgTy)
else
mkOptionTy g calledArgTy
else
calledArgTy
// FSharpMethod(?x = arg), optional F#-style argument
| CalleeSide ->
// In this case, the called argument will already have option type
calledArgTy
| NotOptional ->
// This condition represents an error but the error is raised in later processing
calledArgTy
else
match calledArg.OptArgInfo with
// CSharpMethod(x = arg), non-optional C#-style argument, may have type Nullable<ty>.
| NotOptional when not (g.langVersion.SupportsFeature LanguageFeature.NullableOptionalInterop) ->
calledArgTy
// The arg should have type ty. However for backwards compat, we also allow arg to have type Nullable<ty>
| NotOptional
// CSharpMethod(x = arg), optional C#-style argument, may have type Nullable<ty>.
| CallerSide _ ->
if isNullableTy g calledArgTy && g.langVersion.SupportsFeature LanguageFeature.NullableOptionalInterop then
// If inference has worked out it's a nullable then use this
if isNullableTy g callerArg.CallerArgumentType then
calledArgTy
// If inference has worked out it's a struct (e.g. an int) then use this
elif isStructTy g callerArg.CallerArgumentType then
destNullableTy g calledArgTy
// If neither and we are at the end of overload resolution then use the Nullable
elif enforceNullableOptionalsKnownTypes then
calledArgTy
// If at the beginning of inference then use a type variable.
else
let destTy = destNullableTy g calledArgTy
match calledArg.OptArgInfo with
// Use the type variable from the Nullable if called arg is not optional.
| NotOptional when isTyparTy g destTy ->
destTy
| _ ->
let compgenId = mkSynId range0 unassignedTyparName
mkTyparTy (Construct.NewTypar (TyparKind.Type, TyparRigidity.Flexible, Typar(compgenId, NoStaticReq, true), false, TyparDynamicReq.No, [], false, false))
else
calledArgTy
// FSharpMethod(x = arg), optional F#-style argument, should have option type
| CalleeSide ->
if isOptionTy g calledArgTy then
destOptionTy g calledArgTy
else
calledArgTy
// F# supports three adhoc conversions at method callsites (note C# supports more, though ones
// such as implicit conversions interact badly with type inference).
//
// 1. The use of "(fun x y -> ...)" when a delegate it expected. This is not part of
// the ":>" coercion relationship or inference constraint problem as
// such, but is a special rule applied only to method arguments.
//
// The function AdjustCalledArgType detects this case based on types and needs to know that the type being applied
// is a function type.
//
// 2. The use of "(fun x y -> ...)" when Expression<delegate> it expected. This is similar to above.
//
// 3. Two ways to pass a value where a byref is expected. The first (default)
// is to use a reference cell, and the interior address is taken automatically
// The second is an explicit use of the "address-of" operator "&e". Here we detect the second case,
// and record the presence of the syntax "&e" in the pre-inferred actual type for the method argument.
// The function AdjustCalledArgType detects this and refuses to apply the default byref-to-ref transformation.
//
// The function AdjustCalledArgType also adjusts for optional arguments.
let AdjustCalledArgType (infoReader: InfoReader) isConstraint enforceNullableOptionalsKnownTypes (calledArg: CalledArg) (callerArg: CallerArg<_>) =
let g = infoReader.g
let m = callerArg.Range
// #424218 - when overload resolution is part of constraint solving - do not perform type-directed conversions
let calledArgTy = calledArg.CalledArgumentType
let callerArgTy = callerArg.CallerArgumentType
if isConstraint then
calledArgTy
else
// If the called method argument is an inref type, then the caller may provide a byref or value
if isInByrefTy g calledArgTy then
#if IMPLICIT_ADDRESS_OF
if isByrefTy g callerArgTy then
calledArgTy
else
destByrefTy g calledArgTy
#else
calledArgTy
#endif
// If the called method argument is a (non inref) byref type, then the caller may provide a byref or ref.
elif isByrefTy g calledArgTy then
if isByrefTy g callerArgTy then
calledArgTy
else
mkRefCellTy g (destByrefTy g calledArgTy)
else
let calledArgTy2 = AdjustCalledArgTypeForLinqExpressionsAndAutoQuote infoReader callerArgTy calledArg m
let calledArgTy3 = AdjustCalledArgTypeForOptionals g enforceNullableOptionalsKnownTypes calledArg calledArgTy2 callerArg
calledArgTy3
//-------------------------------------------------------------------------
// CalledMeth
//-------------------------------------------------------------------------
type CalledMethArgSet<'T> =
{ /// The called arguments corresponding to "unnamed" arguments
UnnamedCalledArgs : CalledArg list
/// Any unnamed caller arguments not otherwise assigned
UnnamedCallerArgs : CallerArg<'T> list
/// The called "ParamArray" argument, if any
ParamArrayCalledArgOpt : CalledArg option
/// Any unnamed caller arguments assigned to a "param array" argument
ParamArrayCallerArgs : CallerArg<'T> list
/// Named args
AssignedNamedArgs: AssignedCalledArg<'T> list }
member x.NumUnnamedCallerArgs = x.UnnamedCallerArgs.Length
member x.NumAssignedNamedArgs = x.AssignedNamedArgs.Length
member x.NumUnnamedCalledArgs = x.UnnamedCalledArgs.Length
let MakeCalledArgs amap m (minfo: MethInfo) minst =
// Mark up the arguments with their position, so we can sort them back into order later
let paramDatas = minfo.GetParamDatas(amap, m, minst)
paramDatas |> List.mapiSquared (fun i j (ParamData(isParamArrayArg, isInArg, isOutArg, optArgInfo, callerInfoFlags, nmOpt, reflArgInfo, typeOfCalledArg)) ->
{ Position=struct(i,j)
IsParamArray=isParamArrayArg
OptArgInfo=optArgInfo
CallerInfo = callerInfoFlags
IsInArg=isInArg
IsOutArg=isOutArg
ReflArgInfo=reflArgInfo
NameOpt=nmOpt
CalledArgumentType=typeOfCalledArg })
/// Represents the syntactic matching between a caller of a method and the called method.
///
/// The constructor takes all the information about the caller and called side of a method, match up named arguments, property setters etc.,
/// and returns a CalledMeth object for further analysis.
type CalledMeth<'T>
(infoReader: InfoReader,
nameEnv: NameResolutionEnv option,
isCheckingAttributeCall,
/// a function to help generate fresh type variables the property setters methods in generic classes
freshenMethInfo,
/// range
m,
/// the access domain of the place where the call is taking place
ad,
/// the method we're attempting to call
minfo: MethInfo,
/// the 'called type arguments', i.e. the fresh generic instantiation of the method we're attempting to call
calledTyArgs,
/// the 'caller type arguments', i.e. user-given generic instantiation of the method we're attempting to call
// todo: consider CallerTypeArgs record
callerTyArgs: TType list,
/// the property related to the method we're attempting to call, if any
pinfoOpt: PropInfo option,
/// the types of the actual object argument, if any
callerObjArgTys: TType list,
/// the 'caller method arguments', i.e. a list of user-given parameter expressions, split between unnamed and named arguments
callerArgs: CallerArgs<'T>,
/// do we allow the use of a param args method in its "expanded" form?
allowParamArgs: bool,
/// do we allow the use of the transformation that converts out arguments as tuple returns?
allowOutAndOptArgs: bool,
/// method parameters
tyargsOpt : TType option)
=
let g = infoReader.g
let methodRetTy = minfo.GetFSharpReturnTy(infoReader.amap, m, calledTyArgs)
let fullCurriedCalledArgs = MakeCalledArgs infoReader.amap m minfo calledTyArgs
do assert (fullCurriedCalledArgs.Length = fullCurriedCalledArgs.Length)
let argSetInfos =
(callerArgs.CurriedCallerArgs, fullCurriedCalledArgs) ||> List.map2 (fun (unnamedCallerArgs, namedCallerArgs) fullCalledArgs ->
// Find the arguments not given by name
let unnamedCalledArgs =
fullCalledArgs |> List.filter (fun calledArg ->
match calledArg.NameOpt with
| Some nm -> namedCallerArgs |> List.forall (fun (CallerNamedArg(nm2, _e)) -> nm.idText <> nm2.idText)
| None -> true)
// See if any of them are 'out' arguments being returned as part of a return tuple
let minArgs, unnamedCalledArgs, unnamedCalledOptArgs, unnamedCalledOutArgs =
let nUnnamedCallerArgs = unnamedCallerArgs.Length
let nUnnamedCalledArgs = unnamedCalledArgs.Length
if allowOutAndOptArgs && nUnnamedCallerArgs < nUnnamedCalledArgs then
let unnamedCalledArgsTrimmed, unnamedCalledOptOrOutArgs = List.splitAt nUnnamedCallerArgs unnamedCalledArgs
// Check if all optional/out arguments are byref-out args
if unnamedCalledOptOrOutArgs |> List.forall (fun x -> x.IsOutArg && isByrefTy g x.CalledArgumentType) then
nUnnamedCallerArgs - 1, unnamedCalledArgsTrimmed, [], unnamedCalledOptOrOutArgs
// Check if all optional/out arguments are optional args
elif unnamedCalledOptOrOutArgs |> List.forall (fun x -> x.OptArgInfo.IsOptional) then
nUnnamedCallerArgs - 1, unnamedCalledArgsTrimmed, unnamedCalledOptOrOutArgs, []
// Otherwise drop them on the floor
else
nUnnamedCalledArgs - 1, unnamedCalledArgs, [], []
else
nUnnamedCalledArgs - 1, unnamedCalledArgs, [], []
let (unnamedCallerArgs, paramArrayCallerArgs), unnamedCalledArgs, paramArrayCalledArgOpt =
let supportsParamArgs =
allowParamArgs &&
minArgs >= 0 &&
unnamedCalledArgs |> List.last |> (fun calledArg -> calledArg.IsParamArray && isArray1DTy g calledArg.CalledArgumentType)
if supportsParamArgs && unnamedCallerArgs.Length >= minArgs then
let a, b = List.frontAndBack unnamedCalledArgs
List.splitAt minArgs unnamedCallerArgs, a, Some(b)
else
(unnamedCallerArgs, []), unnamedCalledArgs, None
let assignedNamedArgs =
fullCalledArgs |> List.choose (fun calledArg ->
match calledArg.NameOpt with
| Some nm ->
namedCallerArgs |> List.tryPick (fun (CallerNamedArg(nm2, callerArg)) ->
if nm.idText = nm2.idText then Some { NamedArgIdOpt = Some nm2; CallerArg=callerArg; CalledArg=calledArg }
else None)
| _ -> None)
let unassignedNamedItems =
namedCallerArgs |> List.filter (fun (CallerNamedArg(nm, _e)) ->
fullCalledArgs |> List.forall (fun calledArg ->
match calledArg.NameOpt with
| Some nm2 -> nm.idText <> nm2.idText
| None -> true))
let attributeAssignedNamedItems =
if isCheckingAttributeCall then
// The process for assigning names-->properties is substantially different for attribute specifications
// because it permits the bindings of names to immutable fields. So we use the old
// code for this.
unassignedNamedItems
else
[]
let assignedNamedProps, unassignedNamedItems =
let returnedObjTy = if minfo.IsConstructor then minfo.ApparentEnclosingType else methodRetTy
unassignedNamedItems |> List.splitChoose (fun (CallerNamedArg(id, e) as arg) ->
let nm = id.idText
let pinfos = GetIntrinsicPropInfoSetsOfType infoReader (Some nm) ad AllowMultiIntfInstantiations.Yes IgnoreOverrides id.idRange returnedObjTy
let pinfos = pinfos |> ExcludeHiddenOfPropInfos g infoReader.amap m
match pinfos with
| [pinfo] when pinfo.HasSetter && not pinfo.IsIndexer ->
let pminfo = pinfo.SetterMethod
let pminst = freshenMethInfo m pminfo
Choice1Of2(AssignedItemSetter(id, AssignedPropSetter(pinfo, pminfo, pminst), e))
| _ ->
let epinfos =
match nameEnv with
| Some ne -> ExtensionPropInfosOfTypeInScope ResultCollectionSettings.AllResults infoReader ne (Some nm) ad m returnedObjTy
| _ -> []
match epinfos with
| [pinfo] when pinfo.HasSetter && not pinfo.IsIndexer ->
let pminfo = pinfo.SetterMethod
let pminst = match minfo with
| MethInfo.FSMeth(_, TType.TType_app(_, types), _, _) -> types
| _ -> freshenMethInfo m pminfo
let pminst = match tyargsOpt with
| Some(TType.TType_app(_, types)) -> types
| _ -> pminst
Choice1Of2(AssignedItemSetter(id, AssignedPropSetter(pinfo, pminfo, pminst), e))
| _ ->
match infoReader.GetILFieldInfosOfType(Some(nm), ad, m, returnedObjTy) with
| finfo :: _ ->
Choice1Of2(AssignedItemSetter(id, AssignedILFieldSetter(finfo), e))
| _ ->
match infoReader.TryFindRecdOrClassFieldInfoOfType(nm, m, returnedObjTy) with
| ValueSome rfinfo ->
Choice1Of2(AssignedItemSetter(id, AssignedRecdFieldSetter(rfinfo), e))
| _ ->
Choice2Of2(arg))
let names = System.Collections.Generic.HashSet<_>()
for CallerNamedArg(nm, _) in namedCallerArgs do
if not (names.Add nm.idText) then
errorR(Error(FSComp.SR.typrelNamedArgumentHasBeenAssignedMoreThenOnce nm.idText, m))
let argSet = { UnnamedCalledArgs=unnamedCalledArgs; UnnamedCallerArgs=unnamedCallerArgs; ParamArrayCalledArgOpt=paramArrayCalledArgOpt; ParamArrayCallerArgs=paramArrayCallerArgs; AssignedNamedArgs=assignedNamedArgs }
(argSet, assignedNamedProps, unassignedNamedItems, attributeAssignedNamedItems, unnamedCalledOptArgs, unnamedCalledOutArgs))
let argSets = argSetInfos |> List.map (fun (x, _, _, _, _, _) -> x)
let assignedNamedProps = argSetInfos |> List.collect (fun (_, x, _, _, _, _) -> x)
let unassignedNamedItems = argSetInfos |> List.collect (fun (_, _, x, _, _, _) -> x)
let attributeAssignedNamedItems = argSetInfos |> List.collect (fun (_, _, _, x, _, _) -> x)
let unnamedCalledOptArgs = argSetInfos |> List.collect (fun (_, _, _, _, x, _) -> x)
let unnamedCalledOutArgs = argSetInfos |> List.collect (fun (_, _, _, _, _, x) -> x)
member x.infoReader = infoReader
member x.amap = infoReader.amap
/// the method we're attempting to call
member x.Method = minfo
/// the instantiation of the method we're attempting to call
member x.CalledTyArgs = calledTyArgs
member x.AllCalledArgs = fullCurriedCalledArgs
/// the instantiation of the method we're attempting to call
member x.CalledTyparInst =
let tps = minfo.FormalMethodTypars
if tps.Length = calledTyArgs.Length then mkTyparInst tps calledTyArgs else []
/// the formal instantiation of the method we're attempting to call
member x.CallerTyArgs = callerTyArgs
/// The types of the actual object arguments, if any
member x.CallerObjArgTys = callerObjArgTys
/// The argument analysis for each set of curried arguments
member x.ArgSets = argSets
/// return type after implicit deference of byref returns is taken into account
member x.CalledReturnTypeAfterByrefDeref =
let retTy = methodRetTy
if isByrefTy g retTy then destByrefTy g retTy else retTy
/// return type after tupling of out args is taken into account
member x.CalledReturnTypeAfterOutArgTupling =
let retTy = x.CalledReturnTypeAfterByrefDeref
if isNil unnamedCalledOutArgs then
retTy
else
let outArgTys = unnamedCalledOutArgs |> List.map (fun calledArg -> destByrefTy g calledArg.CalledArgumentType)
if isUnitTy g retTy then mkRefTupledTy g outArgTys
else mkRefTupledTy g (retTy :: outArgTys)
/// named setters
member x.AssignedItemSetters = assignedNamedProps
/// the property related to the method we're attempting to call, if any
member x.AssociatedPropertyInfo = pinfoOpt
/// unassigned args
member x.UnassignedNamedArgs = unassignedNamedItems
/// args assigned to specify values for attribute fields and properties (these are not necessarily "property sets")
member x.AttributeAssignedNamedArgs = attributeAssignedNamedItems
/// unnamed called optional args: pass defaults for these
member x.UnnamedCalledOptArgs = unnamedCalledOptArgs
/// unnamed called out args: return these as part of the return tuple
member x.UnnamedCalledOutArgs = unnamedCalledOutArgs
static member GetMethod (x: CalledMeth<'T>) = x.Method
member x.NumArgSets = x.ArgSets.Length
member x.HasOptArgs = not (isNil x.UnnamedCalledOptArgs)
member x.HasOutArgs = not (isNil x.UnnamedCalledOutArgs)
member x.UsesParamArrayConversion = x.ArgSets |> List.exists (fun argSet -> argSet.ParamArrayCalledArgOpt.IsSome)
member x.ParamArrayCalledArgOpt = x.ArgSets |> List.tryPick (fun argSet -> argSet.ParamArrayCalledArgOpt)
member x.ParamArrayCallerArgs = x.ArgSets |> List.tryPick (fun argSet -> if Option.isSome argSet.ParamArrayCalledArgOpt then Some argSet.ParamArrayCallerArgs else None )
member x.GetParamArrayElementType() =
// turned as a method to avoid assert in variable inspector
assert (x.UsesParamArrayConversion)
x.ParamArrayCalledArgOpt.Value.CalledArgumentType |> destArrayTy x.amap.g
member x.NumAssignedProps = x.AssignedItemSetters.Length
member x.CalledObjArgTys(m) =
match x.Method.GetObjArgTypes(x.amap, m, x.CalledTyArgs) with
| [ thisArgTy ] when isByrefTy g thisArgTy -> [ destByrefTy g thisArgTy ]
| res -> res
member x.NumCalledTyArgs = x.CalledTyArgs.Length
member x.NumCallerTyArgs = x.CallerTyArgs.Length
member x.AssignsAllNamedArgs = isNil x.UnassignedNamedArgs
member x.HasCorrectArity =
(x.NumCalledTyArgs = x.NumCallerTyArgs) &&
x.ArgSets |> List.forall (fun argSet -> argSet.NumUnnamedCalledArgs = argSet.NumUnnamedCallerArgs)
member x.HasCorrectGenericArity =
(x.NumCalledTyArgs = x.NumCallerTyArgs)
member x.IsAccessible(m, ad) =
IsMethInfoAccessible x.amap m ad x.Method
member x.HasCorrectObjArgs(m) =
x.CalledObjArgTys(m).Length = x.CallerObjArgTys.Length
member x.IsCandidate(m, ad) =
x.IsAccessible(m, ad) &&
x.HasCorrectArity &&
x.HasCorrectObjArgs(m) &&
x.AssignsAllNamedArgs
member x.AssignedUnnamedArgs =
// We use Seq.map2 to tolerate there being mismatched caller/called args
x.ArgSets |> List.map (fun argSet ->
(argSet.UnnamedCalledArgs, argSet.UnnamedCallerArgs) ||> Seq.map2 (fun calledArg callerArg ->
{ NamedArgIdOpt=None; CalledArg=calledArg; CallerArg=callerArg }) |> Seq.toList)
member x.AssignedNamedArgs =
x.ArgSets |> List.map (fun argSet -> argSet.AssignedNamedArgs)
member x.AllUnnamedCalledArgs = x.ArgSets |> List.collect (fun x -> x.UnnamedCalledArgs)
member x.TotalNumUnnamedCalledArgs = x.ArgSets |> List.sumBy (fun x -> x.NumUnnamedCalledArgs)
member x.TotalNumUnnamedCallerArgs = x.ArgSets |> List.sumBy (fun x -> x.NumUnnamedCallerArgs)
member x.TotalNumAssignedNamedArgs = x.ArgSets |> List.sumBy (fun x -> x.NumAssignedNamedArgs)
override x.ToString() = "call to " + minfo.ToString()
let NamesOfCalledArgs (calledArgs: CalledArg list) =
calledArgs |> List.choose (fun x -> x.NameOpt)
//-------------------------------------------------------------------------
// Helpers dealing with propagating type information in method overload resolution
//-------------------------------------------------------------------------
type ArgumentAnalysis =
| NoInfo
| ArgDoesNotMatch
| CallerLambdaHasArgTypes of TType list
| CalledArgMatchesType of TType
let InferLambdaArgsForLambdaPropagation origRhsExpr =
let rec loop e =
match e with
| SynExpr.Lambda (_, _, _, rest, _, _) -> 1 + loop rest
| SynExpr.MatchLambda _ -> 1
| _ -> 0
loop origRhsExpr
let ExamineArgumentForLambdaPropagation (infoReader: InfoReader) (arg: AssignedCalledArg<SynExpr>) =
let g = infoReader.g
// Find the explicit lambda arguments of the caller. Ignore parentheses.
let argExpr = match arg.CallerArg.Expr with SynExpr.Paren (x, _, _, _) -> x | x -> x
let countOfCallerLambdaArg = InferLambdaArgsForLambdaPropagation argExpr
// Adjust for Expression<_>, Func<_, _>, ...
let adjustedCalledArgTy = AdjustCalledArgType infoReader false false arg.CalledArg arg.CallerArg
if countOfCallerLambdaArg > 0 then
// Decompose the explicit function type of the target
let calledLambdaArgTys, _calledLambdaRetTy = stripFunTy g adjustedCalledArgTy
if calledLambdaArgTys.Length >= countOfCallerLambdaArg then
// success
CallerLambdaHasArgTypes calledLambdaArgTys
elif isDelegateTy g (if isLinqExpressionTy g adjustedCalledArgTy then destLinqExpressionTy g adjustedCalledArgTy else adjustedCalledArgTy) then
// delegate arity mismatch
ArgDoesNotMatch
else
// not a function type on the called side - no information
NoInfo
else
// not a lambda on the caller side - push information from caller to called
CalledArgMatchesType(adjustedCalledArgTy)
let ExamineMethodForLambdaPropagation (x: CalledMeth<SynExpr>) =
let unnamedInfo = x.AssignedUnnamedArgs |> List.mapSquared (ExamineArgumentForLambdaPropagation x.infoReader)
let namedInfo = x.AssignedNamedArgs |> List.mapSquared (fun arg -> (arg.NamedArgIdOpt.Value, ExamineArgumentForLambdaPropagation x.infoReader arg))
if unnamedInfo |> List.existsSquared (function CallerLambdaHasArgTypes _ -> true | _ -> false) ||
namedInfo |> List.existsSquared (function (_, CallerLambdaHasArgTypes _) -> true | _ -> false) then
Some (unnamedInfo, namedInfo)
else
None
//-------------------------------------------------------------------------
// Additional helpers for building method calls and doing TAST generation
//-------------------------------------------------------------------------
/// Is this a 'base' call (in the sense of C#)
let IsBaseCall objArgs =
match objArgs with
| [Expr.Val (v, _, _)] when v.BaseOrThisInfo = BaseVal -> true
| _ -> false
/// Compute whether we insert a 'coerce' on the 'this' pointer for an object model call
/// For example, when calling an interface method on a struct, or a method on a constrained
/// variable type.
let ComputeConstrainedCallInfo g amap m (objArgs, minfo: MethInfo) =
match objArgs with
| [objArgExpr] when not minfo.IsExtensionMember ->
let methObjTy = minfo.ApparentEnclosingType
let objArgTy = tyOfExpr g objArgExpr
if TypeDefinitelySubsumesTypeNoCoercion 0 g amap m methObjTy objArgTy
// Constrained calls to class types can only ever be needed for the three class types that
// are base types of value types
|| (isClassTy g methObjTy &&
(not (typeEquiv g methObjTy g.system_Object_ty ||
typeEquiv g methObjTy g.system_Value_ty ||
typeEquiv g methObjTy g.system_Enum_ty))) then
None
else
// The object argument is a value type or variable type and the target method is an interface or System.Object
// type. A .NET 2.0 generic constrained call is required
Some objArgTy
| _ ->
None
/// Adjust the 'this' pointer before making a call
/// Take the address of a struct, and coerce to an interface/base/constraint type if necessary
let TakeObjAddrForMethodCall g amap (minfo: MethInfo) isMutable m objArgs f =
let ccallInfo = ComputeConstrainedCallInfo g amap m (objArgs, minfo)
let wrap, objArgs =
match objArgs with
| [objArgExpr] ->
let hasCallInfo = ccallInfo.IsSome
let mustTakeAddress = hasCallInfo || minfo.ObjArgNeedsAddress(amap, m)
let objArgTy = tyOfExpr g objArgExpr
let isMutable =
match isMutable with
| DefinitelyMutates
| NeverMutates
| AddressOfOp -> isMutable
| PossiblyMutates ->
// Check to see if the method is read-only. Perf optimization.
// If there is an extension member whose first arg is an inref, we must return NeverMutates.
if mustTakeAddress && (minfo.IsReadOnly || minfo.IsReadOnlyExtensionMember (amap, m)) then
NeverMutates
else
isMutable
let wrap, objArgExprAddr, isReadOnly, _isWriteOnly =
mkExprAddrOfExpr g mustTakeAddress hasCallInfo isMutable objArgExpr None m
// Extension members and calls to class constraints may need a coercion for their object argument
let objArgExprCoerced =
if not hasCallInfo &&
not (TypeDefinitelySubsumesTypeNoCoercion 0 g amap m minfo.ApparentEnclosingType objArgTy) then
mkCoerceExpr(objArgExprAddr, minfo.ApparentEnclosingType, m, objArgTy)
else
objArgExprAddr
// Check to see if the extension member uses the extending type as a byref.
// If so, make sure we don't allow readonly/immutable values to be passed byref from an extension member.
// An inref will work though.
if isReadOnly && mustTakeAddress && minfo.IsExtensionMember then
minfo.TryObjArgByrefType(amap, m, minfo.FormalMethodInst)
|> Option.iter (fun ty ->
if not (isInByrefTy g ty) then
errorR(Error(FSComp.SR.tcCannotCallExtensionMethodInrefToByref(minfo.DisplayName), m)))
wrap, [objArgExprCoerced]
| _ ->
id, objArgs
let e, ety = f ccallInfo objArgs
wrap e, ety
//-------------------------------------------------------------------------
// Build method calls.
//-------------------------------------------------------------------------
/// Build an expression node that is a call to a .NET method.
let BuildILMethInfoCall g amap m isProp (minfo: ILMethInfo) valUseFlags minst direct args =
let valu = isStructTy g minfo.ApparentEnclosingType
let ctor = minfo.IsConstructor
if minfo.IsClassConstructor then
error (InternalError (minfo.ILName+": cannot call a class constructor", m))
let useCallvirt =
not valu && not direct && minfo.IsVirtual
let isProtected = minfo.IsProtectedAccessibility
let ilMethRef = minfo.ILMethodRef
let newobj = ctor && (match valUseFlags with NormalValUse -> true | _ -> false)
let exprTy = if ctor then minfo.ApparentEnclosingType else minfo.GetFSharpReturnTy(amap, m, minst)
let retTy = if not ctor && ilMethRef.ReturnType = ILType.Void then [] else [exprTy]
let isDllImport = minfo.IsDllImport g
Expr.Op (TOp.ILCall (useCallvirt, isProtected, valu, newobj, valUseFlags, isProp, isDllImport, ilMethRef, minfo.DeclaringTypeInst, minst, retTy), [], args, m),
exprTy
/// Build a call to an F# method.
///
/// Consume the arguments in chunks and build applications. This copes with various F# calling signatures
/// all of which ultimately become 'methods'.
///
/// QUERY: this looks overly complex considering that we are doing a fundamentally simple
/// thing here.
let BuildFSharpMethodApp g m (vref: ValRef) vexp vexprty (args: Exprs) =
let arities = (arityOfVal vref.Deref).AritiesOfArgs
let args3, (leftover, retTy) =
let exprL expr = exprL g expr
((args, vexprty), arities) ||> List.mapFold (fun (args, fty) arity ->
match arity, args with
| (0|1), [] when typeEquiv g (domainOfFunTy g fty) g.unit_ty -> mkUnit g m, (args, rangeOfFunTy g fty)
| 0, (arg :: argst) ->
let msg = Layout.showL (Layout.sepListL (Layout.rightL (Layout.TaggedTextOps.tagText ";")) (List.map exprL args))
warning(InternalError(sprintf "Unexpected zero arity, args = %s" msg, m))
arg, (argst, rangeOfFunTy g fty)
| 1, (arg :: argst) -> arg, (argst, rangeOfFunTy g fty)
| 1, [] -> error(InternalError("expected additional arguments here", m))
| _ ->
if args.Length < arity then
error(InternalError("internal error in getting arguments, n = "+string arity+", #args = "+string args.Length, m))
let tupargs, argst = List.splitAt arity args
let tuptys = tupargs |> List.map (tyOfExpr g)
(mkRefTupled g m tupargs tuptys),
(argst, rangeOfFunTy g fty) )
if not leftover.IsEmpty then error(InternalError("Unexpected "+string(leftover.Length)+" remaining arguments in method application", m))
mkApps g ((vexp, vexprty), [], args3, m),
retTy
/// Build a call to an F# method.
let BuildFSharpMethodCall g m (ty, vref: ValRef) valUseFlags minst args =
let vexp = Expr.Val (vref, valUseFlags, m)
let vexpty = vref.Type
let tpsorig, tau = vref.TypeScheme
let vtinst = argsOfAppTy g ty @ minst
if tpsorig.Length <> vtinst.Length then error(InternalError("BuildFSharpMethodCall: unexpected List.length mismatch", m))
let expr = mkTyAppExpr m (vexp, vexpty) vtinst
let exprty = instType (mkTyparInst tpsorig vtinst) tau
BuildFSharpMethodApp g m vref expr exprty args
/// Make a call to a method info. Used by the optimizer and code generator to build
/// calls to the type-directed solutions to member constraints.
let MakeMethInfoCall amap m minfo minst args =
let valUseFlags = NormalValUse // correct unless if we allow wild trait constraints like "T has a ctor and can be used as a parent class"
match minfo with
| ILMeth(g, ilminfo, _) ->
let direct = not minfo.IsVirtual
let isProp = false // not necessarily correct, but this is only used post-creflect where this flag is irrelevant
BuildILMethInfoCall g amap m isProp ilminfo valUseFlags minst direct args |> fst
| FSMeth(g, ty, vref, _) ->
BuildFSharpMethodCall g m (ty, vref) valUseFlags minst args |> fst
| DefaultStructCtor(_, ty) ->
mkDefault (m, ty)
#if !NO_EXTENSIONTYPING
| ProvidedMeth(amap, mi, _, m) ->
let isProp = false // not necessarily correct, but this is only used post-creflect where this flag is irrelevant
let ilMethodRef = Import.ImportProvidedMethodBaseAsILMethodRef amap m mi
let isConstructor = mi.PUntaint((fun c -> c.IsConstructor), m)
let valu = mi.PUntaint((fun c -> c.DeclaringType.IsValueType), m)
let actualTypeInst = [] // GENERIC TYPE PROVIDERS: for generics, we would have something here
let actualMethInst = [] // GENERIC TYPE PROVIDERS: for generics, we would have something here
let ilReturnTys = Option.toList (minfo.GetCompiledReturnTy(amap, m, [])) // GENERIC TYPE PROVIDERS: for generics, we would have more here
// REVIEW: Should we allow protected calls?
Expr.Op (TOp.ILCall (false, false, valu, isConstructor, valUseFlags, isProp, false, ilMethodRef, actualTypeInst, actualMethInst, ilReturnTys), [], args, m)
#endif
#if !NO_EXTENSIONTYPING
// This imports a provided method, and checks if it is a known compiler intrinsic like "1 + 2"
let TryImportProvidedMethodBaseAsLibraryIntrinsic (amap: Import.ImportMap, m: range, mbase: Tainted<ProvidedMethodBase>) =
let methodName = mbase.PUntaint((fun x -> x.Name), m)
let declaringType = Import.ImportProvidedType amap m (mbase.PApply((fun x -> x.DeclaringType), m))
match tryTcrefOfAppTy amap.g declaringType with
| ValueSome declaringEntity ->
if not declaringEntity.IsLocalRef && ccuEq declaringEntity.nlr.Ccu amap.g.fslibCcu then
let n = mbase.PUntaint((fun x -> x.GetParameters().Length), m)
match amap.g.knownIntrinsics.TryGetValue ((declaringEntity.LogicalName, None, methodName, n)) with
| true, vref -> Some vref
| _ ->
match amap.g.knownFSharpCoreModules.TryGetValue declaringEntity.LogicalName with
| true, modRef ->
modRef.ModuleOrNamespaceType.AllValsByLogicalName
|> Seq.tryPick (fun (KeyValue(_, v)) -> if (v.CompiledName amap.g.CompilerGlobalState) = methodName then Some (mkNestedValRef modRef v) else None)
| _ -> None
else
None
| _ ->
None
#endif
/// Build an expression that calls a given method info.
/// This is called after overload resolution, and also to call other
/// methods such as 'setters' for properties.
// tcVal: used to convert an F# value into an expression. See tc.fs.
// isProp: is it a property get?
// minst: the instantiation to apply for a generic method
// objArgs: the 'this' argument, if any
// args: the arguments, if any
let BuildMethodCall tcVal g amap isMutable m isProp minfo valUseFlags minst objArgs args =
let direct = IsBaseCall objArgs
TakeObjAddrForMethodCall g amap minfo isMutable m objArgs (fun ccallInfo objArgs ->
let allArgs = objArgs @ args
let valUseFlags =
if direct && (match valUseFlags with NormalValUse -> true | _ -> false) then
VSlotDirectCall
else
match ccallInfo with
| Some ty ->
// printfn "possible constrained call to '%s' at %A" minfo.LogicalName m
PossibleConstrainedCall ty
| None ->
valUseFlags
match minfo with
#if !NO_EXTENSIONTYPING
// By this time this is an erased method info, e.g. one returned from an expression
// REVIEW: copied from tastops, which doesn't allow protected methods
| ProvidedMeth (amap, providedMeth, _, _) ->
// TODO: there is a fair bit of duplication here with mk_il_minfo_call. We should be able to merge these
/// Build an expression node that is a call to a extension method in a generated assembly
let enclTy = minfo.ApparentEnclosingType
// prohibit calls to methods that are declared in specific array types (Get, Set, Address)
// these calls are provided by the runtime and should not be called from the user code
if isArrayTy g enclTy then
let tpe = TypeProviderError(FSComp.SR.tcRuntimeSuppliedMethodCannotBeUsedInUserCode(minfo.DisplayName), providedMeth.TypeProviderDesignation, m)
error tpe
let valu = isStructTy g enclTy
let isCtor = minfo.IsConstructor
if minfo.IsClassConstructor then
error (InternalError (minfo.LogicalName + ": cannot call a class constructor", m))
let useCallvirt = not valu && not direct && minfo.IsVirtual
let isProtected = minfo.IsProtectedAccessibility
let exprTy = if isCtor then enclTy else minfo.GetFSharpReturnTy(amap, m, minst)
match TryImportProvidedMethodBaseAsLibraryIntrinsic (amap, m, providedMeth) with
| Some fsValRef ->
//reraise() calls are converted to TOp.Reraise in the type checker. So if a provided expression includes a reraise call
// we must put it in that form here.
if valRefEq amap.g fsValRef amap.g.reraise_vref then
mkReraise m exprTy, exprTy
else
let vexp, vexpty = tcVal fsValRef valUseFlags (minfo.DeclaringTypeInst @ minst) m
BuildFSharpMethodApp g m fsValRef vexp vexpty allArgs
| None ->
let ilMethRef = Import.ImportProvidedMethodBaseAsILMethodRef amap m providedMeth
let isNewObj = isCtor && (match valUseFlags with NormalValUse -> true | _ -> false)
let actualTypeInst =
if isRefTupleTy g enclTy then argsOfAppTy g (mkCompiledTupleTy g false (destRefTupleTy g enclTy)) // provided expressions can include method calls that get properties of tuple types
elif isFunTy g enclTy then [ domainOfFunTy g enclTy; rangeOfFunTy g enclTy ] // provided expressions can call Invoke
else minfo.DeclaringTypeInst
let actualMethInst = minst
let retTy = if not isCtor && (ilMethRef.ReturnType = ILType.Void) then [] else [exprTy]
let noTailCall = false
let expr = Expr.Op (TOp.ILCall (useCallvirt, isProtected, valu, isNewObj, valUseFlags, isProp, noTailCall, ilMethRef, actualTypeInst, actualMethInst, retTy), [], allArgs, m)
expr, exprTy
#endif
// Build a call to a .NET method
| ILMeth(_, ilMethInfo, _) ->
BuildILMethInfoCall g amap m isProp ilMethInfo valUseFlags minst direct allArgs
// Build a call to an F# method
| FSMeth(_, _, vref, _) ->
// Go see if this is a use of a recursive definition... Note we know the value instantiation
// we want to use so we pass that in order not to create a new one.
let vexp, vexpty = tcVal vref valUseFlags (minfo.DeclaringTypeInst @ minst) m
BuildFSharpMethodApp g m vref vexp vexpty allArgs
// Build a 'call' to a struct default constructor
| DefaultStructCtor (g, ty) ->
if not (TypeHasDefaultValue g m ty) then
errorR(Error(FSComp.SR.tcDefaultStructConstructorCall(), m))
mkDefault (m, ty), ty)
//-------------------------------------------------------------------------
// Adjust caller arguments as part of building a method call
//-------------------------------------------------------------------------
/// Build a call to the System.Object constructor taking no arguments,
let BuildObjCtorCall (g: TcGlobals) m =
let ilMethRef = (mkILCtorMethSpecForTy(g.ilg.typ_Object, [])).MethodRef
Expr.Op (TOp.ILCall (false, false, false, false, CtorValUsedAsSuperInit, false, true, ilMethRef, [], [], [g.obj_ty]), [], [], m)
/// Implements the elaborated form of adhoc conversions from functions to delegates at member callsites
let BuildNewDelegateExpr (eventInfoOpt: EventInfo option, g, amap, delegateTy, invokeMethInfo: MethInfo, delArgTys, f, fty, m) =
let slotsig = invokeMethInfo.GetSlotSig(amap, m)
let delArgVals, expr =
let topValInfo = ValReprInfo([], List.replicate (max 1 (List.length delArgTys)) ValReprInfo.unnamedTopArg, ValReprInfo.unnamedRetVal)
// Try to pull apart an explicit lambda and use it directly
// Don't do this in the case where we're adjusting the arguments of a function used to build a .NET-compatible event handler
let lambdaContents =
if Option.isSome eventInfoOpt then
None
else
tryDestTopLambda g amap topValInfo (f, fty)
match lambdaContents with
| None ->
if List.exists (isByrefTy g) delArgTys then
error(Error(FSComp.SR.tcFunctionRequiresExplicitLambda(List.length delArgTys), m))
let delArgVals = delArgTys |> List.mapi (fun i argty -> fst (mkCompGenLocal m ("delegateArg" + string i) argty))
let expr =
let args =
match eventInfoOpt with
| Some einfo ->
match delArgVals with
| [] -> error(nonStandardEventError einfo.EventName m)