@@ -281,6 +281,9 @@ func (f *FunctionDecl) AddOverload(overload *OverloadDecl) error {
281
281
}
282
282
return fmt .Errorf ("overload redefinition in function. %s: %s has multiple definitions" , f .Name (), oID )
283
283
}
284
+ if overload .HasLateBinding () != o .HasLateBinding () {
285
+ return fmt .Errorf ("overload with late binding cannot be added to function %s: cannot mix late and non-late bindings" , f .Name ())
286
+ }
284
287
}
285
288
f .overloadOrdinals = append (f .overloadOrdinals , overload .ID ())
286
289
f .overloads [overload .ID ()] = overload
@@ -300,6 +303,19 @@ func (f *FunctionDecl) OverloadDecls() []*OverloadDecl {
300
303
return overloads
301
304
}
302
305
306
+ // Returns true if the function has late bindings. A function cannot mix late bindings with other bindings.
307
+ func (f * FunctionDecl ) HasLateBinding () bool {
308
+ if f == nil {
309
+ return false
310
+ }
311
+ for _ , oID := range f .overloadOrdinals {
312
+ if f .overloads [oID ].HasLateBinding () {
313
+ return true
314
+ }
315
+ }
316
+ return false
317
+ }
318
+
303
319
// Bindings produces a set of function bindings, if any are defined.
304
320
func (f * FunctionDecl ) Bindings () ([]* functions.Overload , error ) {
305
321
var emptySet []* functions.Overload
@@ -308,8 +324,10 @@ func (f *FunctionDecl) Bindings() ([]*functions.Overload, error) {
308
324
}
309
325
overloads := []* functions.Overload {}
310
326
nonStrict := false
327
+ hasLateBinding := false
311
328
for _ , oID := range f .overloadOrdinals {
312
329
o := f .overloads [oID ]
330
+ hasLateBinding = hasLateBinding || o .HasLateBinding ()
313
331
if o .hasBinding () {
314
332
overload := & functions.Overload {
315
333
Operator : o .ID (),
@@ -327,6 +345,9 @@ func (f *FunctionDecl) Bindings() ([]*functions.Overload, error) {
327
345
if len (overloads ) != 0 {
328
346
return nil , fmt .Errorf ("singleton function incompatible with specialized overloads: %s" , f .Name ())
329
347
}
348
+ if hasLateBinding {
349
+ return nil , fmt .Errorf ("singleton function incompatible with late bindings: %s" , f .Name ())
350
+ }
330
351
overloads = []* functions.Overload {
331
352
{
332
353
Operator : f .Name (),
@@ -576,6 +597,9 @@ type OverloadDecl struct {
576
597
argTypes []* types.Type
577
598
resultType * types.Type
578
599
isMemberFunction bool
600
+ // hasLateBinding indicates that the function has a binding which is not known at compile time.
601
+ // This is useful for functions which have side-effects or are not deterministically computable.
602
+ hasLateBinding bool
579
603
// nonStrict indicates that the function will accept error and unknown arguments as inputs.
580
604
nonStrict bool
581
605
// operandTrait indicates whether the member argument should have a specific type-trait.
@@ -640,6 +664,14 @@ func (o *OverloadDecl) IsNonStrict() bool {
640
664
return o .nonStrict
641
665
}
642
666
667
+ // HasLateBinding returns whether the overload has a binding which is not known at compile time.
668
+ func (o * OverloadDecl ) HasLateBinding () bool {
669
+ if o == nil {
670
+ return false
671
+ }
672
+ return o .hasLateBinding
673
+ }
674
+
643
675
// OperandTrait returns the trait mask of the first operand to the overload call, e.g.
644
676
// `traits.Indexer`
645
677
func (o * OverloadDecl ) OperandTrait () int {
@@ -816,6 +848,9 @@ func UnaryBinding(binding functions.UnaryOp) OverloadOpt {
816
848
if len (o .ArgTypes ()) != 1 {
817
849
return nil , fmt .Errorf ("unary function bound to non-unary overload: %s" , o .ID ())
818
850
}
851
+ if o .hasLateBinding {
852
+ return nil , fmt .Errorf ("overload already has a late binding: %s" , o .ID ())
853
+ }
819
854
o .unaryOp = binding
820
855
return o , nil
821
856
}
@@ -831,6 +866,9 @@ func BinaryBinding(binding functions.BinaryOp) OverloadOpt {
831
866
if len (o .ArgTypes ()) != 2 {
832
867
return nil , fmt .Errorf ("binary function bound to non-binary overload: %s" , o .ID ())
833
868
}
869
+ if o .hasLateBinding {
870
+ return nil , fmt .Errorf ("overload already has a late binding: %s" , o .ID ())
871
+ }
834
872
o .binaryOp = binding
835
873
return o , nil
836
874
}
@@ -843,11 +881,26 @@ func FunctionBinding(binding functions.FunctionOp) OverloadOpt {
843
881
if o .hasBinding () {
844
882
return nil , fmt .Errorf ("overload already has a binding: %s" , o .ID ())
845
883
}
884
+ if o .hasLateBinding {
885
+ return nil , fmt .Errorf ("overload already has a late binding: %s" , o .ID ())
886
+ }
846
887
o .functionOp = binding
847
888
return o , nil
848
889
}
849
890
}
850
891
892
+ // LateFunctionBinding indicates that the function has a binding which is not known at compile time.
893
+ // This is useful for functions which have side-effects or are not deterministically computable.
894
+ func LateFunctionBinding () OverloadOpt {
895
+ return func (o * OverloadDecl ) (* OverloadDecl , error ) {
896
+ if o .hasBinding () {
897
+ return nil , fmt .Errorf ("overload already has a binding: %s" , o .ID ())
898
+ }
899
+ o .hasLateBinding = true
900
+ return o , nil
901
+ }
902
+ }
903
+
851
904
// OverloadIsNonStrict enables the function to be called with error and unknown argument values.
852
905
//
853
906
// Note: do not use this option unless absoluately necessary as it should be an uncommon feature.
0 commit comments