Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
racket-variant: ["CS"]
enable-contracts: [true, false]
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v6.0.1
- uses: Bogdanp/[email protected]
with:
architecture: x64
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/resyntax-analyze.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v4.2.2
uses: actions/checkout@v6.0.1
# See https://github.com/actions/checkout/issues/118.
with:
fetch-depth: 0
Expand All @@ -48,7 +48,7 @@ jobs:
- name: Analyze changed files
run: xvfb-run racket -l- resyntax/cli analyze --local-git-repository . "origin/${GITHUB_BASE_REF}" --output-as-github-review --output-to-file ./resyntax-review.json
- name: Upload analysis artifact
uses: actions/upload-artifact@v4.6.1
uses: actions/upload-artifact@v6.0.0
with:
name: resyntax-review
path: resyntax-review.json
2 changes: 1 addition & 1 deletion .github/workflows/resyntax-autofixer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4.2.2
uses: actions/checkout@v6.0.1
- name: Install Racket
uses: Bogdanp/[email protected]
with:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/resyntax-submit-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v4.2.2
uses: actions/checkout@v6.0.1
- name: Download Resyntax analysis
# This uses a github script instead of the download-artifact action because
# that action doesn't work for artifacts uploaded by other workflows. See
# https://github.com/actions/download-artifact/issues/130 for more info.
uses: actions/github-script@v7.0.1
uses: actions/github-script@v8.0.0
with:
script: |
var artifacts = await github.rest.actions.listWorkflowRunArtifacts({
Expand All @@ -48,7 +48,7 @@ jobs:
fs.writeFileSync('${{github.workspace}}/resyntax-review.zip', Buffer.from(download.data));
- run: unzip resyntax-review.zip
- name: Create pull request review
uses: actions/github-script@v7.0.1
uses: actions/github-script@v8.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
Expand Down
4 changes: 4 additions & 0 deletions typed-racket-lib/typed-racket/infer/dmap.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@
#f]
[((struct dcon-dotted _) (struct dcon _))
#f]
[((struct dcon-exact _) (struct dcon-dotted _))
#f]
[((struct dcon-dotted _) (struct dcon-exact _))
#f]
[(_ _) (int-err "Got non-dcons: ~a ~a" dc1 dc2)]))

;; dmap dmap -> dmap or #f
Expand Down
47 changes: 43 additions & 4 deletions typed-racket-lib/typed-racket/private/parse-type.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,36 @@
[_ null]))


;; Symbol Type -> Boolean
;; Check if a row type variable appears in invalid positions (not as Class row-ext)
;; Returns #t if there are invalid usages
(define (row-var-in-invalid-position? var-name type)
(define found-invalid #f)
(let check! ([ty type] [in-row-ext? #f])
(match ty
[(F: (== var-name))
;; Found the row variable - it's invalid unless we're in a row-ext position
(unless in-row-ext?
(set! found-invalid #t))]
[(Class: row-ext inits fields methods augments init-rest)
;; For Class, check row-ext with the flag set (valid position for row var)
(when row-ext
(check! row-ext #t))
;; Check types in the row's members for invalid uses
;; These are lists of tuples: (list name Type ...)
(for ([entry (in-list inits)])
(check! (second entry) #f))
(for ([entry (in-list fields)])
(check! (second entry) #f))
(for ([entry (in-list methods)])
(check! (second entry) #f))
(for ([entry (in-list augments)])
(check! (second entry) #f))
(when init-rest
(check! init-rest #f))]
[_ (Rep-for-each ty (lambda (t) (check! t #f)))]))
found-invalid)

;; Syntax -> Type
;; Parse a Forall type
(define (parse-all-type stx do-parse)
Expand Down Expand Up @@ -227,6 +257,10 @@
;; should be no need to extend the constraint environment
(define body-type
(extend-tvars (list var*) (do-parse #'t.type)))
;; Check that row variable only appears in valid positions (Class #:row-var)
(when (row-var-in-invalid-position? var* body-type)
(parse-error "row type variable used in invalid position; row type variables may only appear in (Class #:row-var ...)"
"variable" var*))
(make-PolyRow
(list var*)
;; No constraints listed, so we need to infer the constraints
Expand All @@ -238,10 +272,15 @@
(define constraints (attribute constr.constraints))
(extend-row-constraints (list var*) (list constraints)
(extend-tvars (list var*)
(make-PolyRow
(list var*)
(do-parse #'t.type)
constraints)))]
(let ([body-type (do-parse #'t.type)])
;; Check that row variable only appears in valid positions (Class #:row-var)
(when (row-var-in-invalid-position? var* body-type)
(parse-error "row type variable used in invalid position; row type variables may only appear in (Class #:row-var ...)"
"variable" var*))
(make-PolyRow
(list var*)
body-type
constraints))))]
[(:All^ (_:id ...) _ _ _ ...) (parse-error "too many forms in body of All type")]
[(:All^ . rest) (parse-error "bad syntax")]))

Expand Down
14 changes: 13 additions & 1 deletion typed-racket-lib/typed-racket/private/type-contract.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -1389,7 +1389,19 @@
(define (has-struct-property->sc orig-id)
;; we can't call syntax-local-value/immediate in has-struct-property case in parse-type
(define-values (a prop-name) (syntax-local-value/immediate orig-id (λ () (values #t orig-id))))
(match-define (Struct-Property: _ pred?) (lookup-id-type/lexical prop-name))
(define pred?
(match (lookup-id-type/lexical prop-name)
[(Struct-Property: _ (? values p)) p]
[(Struct-Property: _ #f)
(tc-error/fields "struct property has no predicate"
#:stx orig-id
"property" (syntax-e orig-id))]
[#f (tc-error/fields "could not find type for struct property"
#:stx orig-id
"property" (syntax-e orig-id))]
[other (tc-error/fields "expected a Struct-Property type"
#:stx orig-id
"given type" other)]))
;; if original-name is only set when the type is added via require/typed

;; the original-name of `prop-name` is its original referece in the unexpanded program.
Expand Down
15 changes: 9 additions & 6 deletions typed-racket-lib/typed-racket/static-contracts/instantiate.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,15 @@
(set! bound (cons name* bound))
;; traverse what `name` refers to
(define r (ref name*))
;; ref returns a rib, get the one definition we want
(define target (for/first ([k (in-list (car r))]
[v (in-list (cdr r))]
#:when (free-identifier=? name* k))
v))
(loop target #f))]
;; r can be #f if the name is not in all-name-defs
(when r
;; ref returns a rib, get the one definition we want
(define target (for/first ([k (in-list (car r))]
[v (in-list (cdr r))]
#:when (free-identifier=? name* k))
v))
(when target
(loop target #f))))]
[else (sc-traverse sc loop)]))
(for*/hash ([b (in-list bound)]
[v (in-value (ref b))]
Expand Down
17 changes: 14 additions & 3 deletions typed-racket-lib/typed-racket/typecheck/check-below.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
"tc-envops.rkt")

(provide/cond-contract
[check-below (-->i ([s (t) (if (Type? t)
[check-below (-->i ([s (t) (if (or (Type? t) (Row? t))
(-or/c full-tc-results/c Type?)
full-tc-results/c)]
[t (-or/c Type? tc-results/c)])
[_ (t) (if (Type? t) Type? full-tc-results/c)])]
[t (-or/c Type? Row? tc-results/c)])
[_ (t) (if (or (Type? t) (Row? t)) Type? full-tc-results/c)])]
[cond-check-below (-->i ([s (-or/c Type? full-tc-results/c)]
[t (s) (-or/c #f (if (Type? s) Type? tc-results/c))])
[_ (s) (-or/c #f (if (Type? s) Type? full-tc-results/c))])])
Expand Down Expand Up @@ -193,6 +193,17 @@
(expected-but-got t2 t1))
(upgrade-trusted-rng t1 expected)]

;; Handle void or other invalid inputs from error propagation
[((? void?) expected) (fix-results expected)]
[(actual (? void?)) actual]

;; Handle Row types from row-polymorphic instantiation
;; Row is not a Type?, so it needs special handling
[((tc-result1: t1 _ _) (? Row?))
;; For row polymorphism, just return the actual type
;; The row constraint checking happens elsewhere
t1]

[(a b) (int-err "unexpected input for check-below: ~a ~a" a b)]))

;; shallow: if the top-level arrow on t1 is reliable, then upgrade the top-level arrow in t2
Expand Down
3 changes: 2 additions & 1 deletion typed-racket-lib/typed-racket/typecheck/check-class-unit.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -1470,7 +1470,8 @@
(make-PolyDots ns (function->method body self-type))]
[(PolyRow-names: ns body constraints)
(make-PolyRow ns (function->method body self-type) constraints)]
[_ (int-err "function->method: ~a" type)]))
[_ (tc-error/expr "expected a function type for method, got: ~a" type
#:return (make-Fun (list (make-Arrow null #f null (make-Values (list (-result -Bottom))) #f))))]))

;; method->function : Function -> Function
;; Turn a "real" method type back into a function type
Expand Down
16 changes: 13 additions & 3 deletions typed-racket-lib/typed-racket/types/prop-ops.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@
(match res
[(tc-any-results: _) res]
[(tc-results: tcrs db)
(-tc-results (map update-ps tcrs) db)]))
(-tc-results (map update-ps tcrs) db)]
;; Handle error cases (e.g., void from error propagation)
[_ res]))


;; atomic-contradiction?: Prop? Prop? -> boolean?
Expand Down Expand Up @@ -411,7 +413,9 @@
[(tc-result: t (PropSet: p+ p-) o)
(-tc-result t (-PS (-and prop p+) (-and prop p-)) o)])
tcrs)
db)])
db)]
;; Handle error cases where results is invalid (e.g., void from error propagation)
[(_ _) results])


;; ands the given type prop to both sides of the given arr for each argument
Expand All @@ -428,7 +432,13 @@
rst
kws
(make-Values (list (-result tp (-PS (-and p+ new-props) (-and p- new-props)) op)))
rng-T+)))])])
rng-T+)))]
;; Range doesn't have expected PropSet - return unchanged
[_ arr])]
;; Multiple arrows (case->) or other function types - return unchanged
[((Fun: _) _) arr]
;; Any other type - return unchanged (e.g., error types)
[(_ _) arr])

;; tc-results/c -> tc-results/c
(define/match (erase-props tc)
Expand Down
4 changes: 3 additions & 1 deletion typed-racket-lib/typed-racket/types/type-table.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@
(add1 index)
(pretty-format-rep (cleanup-type type)
#:indent 2)))))]
[(tc-any-results: _) "AnyValues"]))
[(tc-any-results: _) "AnyValues"]
;; Handle invalid results from error propagation
[_ #f]))
(cond [(not printed-type-thunks) tooltips]
[else
(append (make-tooltip-vector stx printed-type-thunks pos span)
Expand Down
12 changes: 12 additions & 0 deletions typed-racket-test/fail/gh-issue-1146.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#;
(exn-pred #rx"row type variable used in invalid position")
#lang typed/racket

;; Issue #1146: Row type variables should only appear in (Class #:row-var ...),
;; not directly as types like (-> r r). Previously this caused internal errors;
;; now it produces a proper type error.

(: hi (All (r #:row)
(-> r r)))
(define (hi a)
a)
10 changes: 10 additions & 0 deletions typed-racket-test/fail/gh-issue-1352.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#;
(exn-pred #rx"struct property has no predicate")
#lang typed/racket

;; Issue #1352: syntax-property: contract violation with Has-Struct-Property
;; Bug in type-contract.rkt has-struct-property->sc function

(require/typed racket/stream
[prop:stream (Struct-Property Any)]
[stream->list (-> (Has-Struct-Property prop:stream) (List Any))])
19 changes: 19 additions & 0 deletions typed-racket-test/fail/gh-issue-509.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#;
(exn-pred #rx"Type Checker")
#lang typed/racket

;; Issue #509: Internal Typechecker Error: Got non-dcons
;; Bug in dmap.rkt where loop variables shadow struct field bindings

(define-type Filter
(All (a b ...) (-> (-> a b ... b Any) (Listof a) (Listof b) ... (Listof a))))

(: filter* Filter)
(define (filter* p? l)
(cond
[(andmap empty? l) '[]]
[else (define fst ({inst map a b ...} first l))
(define rst (apply filter* p? ({inst map a b ...} rest l)))
(if (apply p? fst) (cons fst rst) rst)]))

(filter* (lambda ({x : Integer}) (> x 1)) '(0 1 2))
15 changes: 15 additions & 0 deletions typed-racket-test/fail/gh-issue-929.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#;
(exn-pred #rx"Type Checker")
#lang typed/racket

;; Issue #929: Internal Typechecker Error: function->method: Error
;; The error occurs when using ->m (a contract form, not a type) in a method annotation
;; This should give a user-friendly error, not an internal error

(define state%
(class object% (init-field (C : Number))
(super-new)

(: final? (->m Boolean)) ;; ->m is not a valid type, should error gracefully
(define/public (final?)
(number? C))))
16 changes: 16 additions & 0 deletions typed-racket-test/succeed/gh-issue-1157.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#lang typed/racket

;; Issue #1157: Regression test - previously caused "define/match: no matching clause"
;; internal error when type checking case-> functions with keyword arguments.
;; Fixed by adding defensive patterns to add-unconditional-prop, add-unconditional-prop-all-args,
;; reduce-tc-results/subsumption, check-below, and type-table->tooltips.

(provide func)

(: func (case-> [-> #:bool True One]
[-> #:bool False Zero]))
(define (func #:bool b)
(cond [(eq? #t b) 1]
[(eq? #f b) 0]))

;; Just defining and exporting the function validates that the type checker doesn't crash.
15 changes: 15 additions & 0 deletions typed-racket-test/succeed/gh-issue-1158.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#lang typed/racket/base

;; Issue #1158: Regression test - previously caused car: contract violation
;; during contract generation with recursive MListof.
;; Fixed by adding null checks in compute-defs in static-contracts/instantiate.rkt

(provide func-1 func-2)

(define-type MNulls (MListof MNulls))

(: func-1 [-> MNulls Any]) (define (func-1 ns) 1)
(: func-2 [-> MNulls Any]) (define (func-2 ns) 2)

(displayln (func-1 '()))
(displayln (func-2 '()))
20 changes: 20 additions & 0 deletions typed-racket-test/succeed/gh-issue-848.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#lang typed/racket/base

;; Issue #848: Regression test - previously caused car: contract violation
;; with recursive case-> types during contract generation.
;; Fixed by adding null checks in compute-defs in static-contracts/instantiate.rkt

(provide
new-T
consume-T)

(define-type T
(case->
['a -> Any]
['b -> (-> T)]))

(: new-T : -> T)
(define (new-T) (new-T))

(: consume-T : T -> Nothing)
(define (consume-T t) (consume-T t))
Loading
Loading