Skip to content

Commit d9edcfd

Browse files
committed
Resolve callable foreign unions safely
1 parent dd80944 commit d9edcfd

3 files changed

Lines changed: 73 additions & 3 deletions

File tree

beagle-lib/private/check.rkt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7140,7 +7140,7 @@
71407140
inferred-call-type]
71417141
[else raw-type]))
71427142
(cond
7143-
[(type-foreign? fn-type)
7143+
[(foreign-call-contract-v1? fn-type)
71447144
(define arguments (call-form-args e))
71457145
(define-values (argument-evidence argument-types)
71467146
(infer-foreign-arguments arguments env))
@@ -7310,7 +7310,7 @@
73107310

73117311
(define (infer-jst-call-contract raw-contract selector receiver-type args env e)
73127312
(cond
7313-
[(type-foreign? raw-contract)
7313+
[(foreign-call-contract-v1? raw-contract)
73147314
(define-values (argument-evidence argument-types)
73157315
(infer-foreign-arguments args env))
73167316
(foreign-call-v1 raw-contract argument-evidence argument-types)]

beagle-lib/private/foreign-interface-v1.rkt

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4128,8 +4128,30 @@
41284128
(hash-ref (car selected) 'return)
41294129
(cdr selected)))
41304130

4131+
(define (foreign-call-contract-v1? type)
4132+
(cond
4133+
[(type-foreign? type) #t]
4134+
[(type-union? type)
4135+
(and
4136+
(pair? (type-union-alts type))
4137+
(andmap foreign-call-contract-v1? (type-union-alts type)))]
4138+
[else #f]))
4139+
4140+
(define (foreign-call-alternatives type)
4141+
(if (type-union? type)
4142+
(append-map foreign-call-alternatives (type-union-alts type))
4143+
(list type)))
4144+
41314145
(define (foreign-call-v1 type expressions actuals)
4132-
(foreign-invoke-v1 type expressions actuals 'call))
4146+
(unless (foreign-call-contract-v1? type)
4147+
(raise-argument-error 'foreign-call-v1 "foreign call contract" type))
4148+
(define results
4149+
(for/list ([alternative (in-list (foreign-call-alternatives type))])
4150+
(foreign-invoke-v1 alternative expressions actuals 'call)))
4151+
(define unique-results (remove-duplicates results equal?))
4152+
(if (null? (cdr unique-results))
4153+
(car unique-results)
4154+
(type-union unique-results)))
41334155

41344156
(define (foreign-construct-v1 type expressions actuals)
41354157
(foreign-invoke-v1 type expressions actuals 'construct))
@@ -4451,6 +4473,7 @@
44514473
foreign-type-compatible-v1
44524474
foreign-ambient-value-types-v1
44534475
foreign-native-member-type-v1
4476+
foreign-call-contract-v1?
44544477
foreign-call-v1
44554478
foreign-construct-v1
44564479
foreign-member-type-v1

beagle-test/tests/foreign-interface-v1-checker.rkt

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,53 @@
559559
(foreign-call-v1 (foreign-type "n:overloaded") (list 7) (list INT))
560560
FLOAT))
561561

562+
(test-case "callable foreign unions require every alternative to accept the call"
563+
(define interface
564+
(make-interface
565+
(list
566+
(wire-export "LeftCallable" "callable:left")
567+
(wire-export "NumericCallable" "callable:numeric")
568+
(wire-export "RightCallable" "callable:right"))
569+
(list
570+
(wire-function
571+
"callable:left"
572+
(wire-signature
573+
(list (wire-parameter "value" "callable:string"))
574+
"callable:string"))
575+
(wire-function
576+
"callable:numeric"
577+
(wire-signature
578+
(list (wire-parameter "value" "callable:number"))
579+
"callable:number"))
580+
(wire-primitive "callable:number" "number")
581+
(wire-function
582+
"callable:right"
583+
(wire-signature
584+
(list (wire-parameter "value" "callable:string"))
585+
"callable:number"))
586+
(wire-primitive "callable:string" "string"))))
587+
(define interface-id (foreign-interface-v1-semantic-id interface))
588+
(define (callable node-id) (type-foreign interface-id node-id))
589+
(parameterize ([current-foreign-interfaces (hash interface-id interface)])
590+
(check-equal?
591+
(foreign-call-v1
592+
(type-union
593+
(list (callable "callable:left") (callable "callable:right")))
594+
(list "value")
595+
(list STRING))
596+
(type-union (list STRING FLOAT)))
597+
(check-foreign-error/in
598+
interface-id
599+
'overload-mismatch
600+
"callable:numeric"
601+
(lambda ()
602+
(foreign-call-v1
603+
(type-union
604+
(list (callable "callable:left") (callable "callable:numeric")))
605+
(list "value")
606+
(list STRING))))
607+
(void)))
608+
562609
(test-foreign-query INTERFACE
563610
"repeated generic variables reject incompatible evidence"
564611
(check-equal?

0 commit comments

Comments
 (0)