Skip to content

Commit 3caf478

Browse files
claudesamth
authored andcommitted
Fix numeric literal type checking against union types
The bug occurred when checking numeric literals (e.g., 2) against union types containing exact numeric values (e.g., (U 1 2)). Root cause: - Value types like (-val 2) were not being interned, so each call to (-val 2) created a new instance - When unions were created from type annotations like (U 1 2), they stored specific Value instances in their element hash - During subtype checking, a freshly created (-val 2) would not match the Value instance stored in the union's hash, causing the subtype check to fail - This made (f 2) fail type checking when f : (U 1 2) -> ... Solution: 1. Added value-intern-table to intern all Value type instances 2. Modified Value's custom constructor to use intern-single-ref! 3. Now (-val 2) always returns the same instance, making hash lookups in subtype checking work correctly Behavior: - Without expected type: literals get general types (e.g., -PosByte) - With expected type: literals get the expected type after successful subtype checking This fixes the asymmetry where (f 1) worked but (f 2) failed. Originally reported by Matthias Felleisen.
1 parent 5c1da6d commit 3caf478

2 files changed

Lines changed: 42 additions & 1 deletion

File tree

typed-racket-lib/typed-racket/rep/type-rep.rkt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -939,7 +939,11 @@
939939
[0 -Zero]
940940
[1 -One]
941941
[(? (lambda (x) (eq? x unsafe-undefined))) -Unsafe-Undefined]
942-
[_ (make-Value val)])])
942+
[_ (intern-single-ref! value-intern-table
943+
val
944+
#:construct (make-Value val))])])
945+
946+
(define value-intern-table (make-weak-hash))
943947

944948

945949
;;************************************************************
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#lang typed/racket
2+
3+
;; Test for numeric literal type checking against union types
4+
;; Bug: numeric literals should be typed as Value types when the
5+
;; expected type is a union of exact numeric values
6+
7+
(define-type Oops (U 1 2))
8+
9+
(: f (Oops -> Oops))
10+
(define (f x) x)
11+
12+
;; Both of these should work
13+
(f 1)
14+
(f 2)
15+
16+
;; Test with larger numeric literals
17+
(define-type Numbers (U 0 1 2 3 10 100))
18+
19+
(: g (Numbers -> Numbers))
20+
(define (g x) x)
21+
22+
(g 0)
23+
(g 1)
24+
(g 2)
25+
(g 3)
26+
(g 10)
27+
(g 100)
28+
29+
;; Test with negative numbers
30+
(define-type SignedNumbers (U -1 0 1))
31+
32+
(: h (SignedNumbers -> SignedNumbers))
33+
(define (h x) x)
34+
35+
(h -1)
36+
(h 0)
37+
(h 1)

0 commit comments

Comments
 (0)