Skip to content

Commit 435516d

Browse files
authored
Undo the decision to publish incomplete types to the binding table (#56497)
This effectively reverts #36121 and replaces it with #36111, which was the originally proposed alternative to fix #36104. To recap, the question is what should happen for ``` module Foo struct F v::Foo.F end end ``` i.e. where the type reference tries to refer to the newly defined type via its global path. In #36121 we adjusted things so that we first assign the type to its global binding and then evaluate the field type (leaving the type in an incomplete state in the meantime). The primary reason that this choice was that we would have to deal with incomplete types assigned to global bindings anyway if we ever did #32658. However, I think this was the wrong choice. There is a difference between allowing incomplete types and semantically forcing incomplete types to be globally observable every time a new type is defined. The situation was a little different four years ago, but with more extensive threading (which can observe the incompletely constructed type) and the upcoming completion of bindings partition, the situation is different. For bindings partition in particular, this would require two invalidations on re-definition, one to the new incomplete type and then back to the complete type. I don't think this is worth it, for the (somewhat niche and possibly-should-be- deprecated-future) case of refering to incompletely defined types by their global names. So let's instead try the hack in #36111, which does a frontend rewrite of the global path. This should be sufficient to at least address the obvious cases.
1 parent 4cbeea5 commit 435516d

File tree

4 files changed

+32
-6
lines changed

4 files changed

+32
-6
lines changed

base/boot.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -984,6 +984,14 @@ Unsigned(x::Union{Float16, Float32, Float64, Bool}) = UInt(x)
984984
Integer(x::Integer) = x
985985
Integer(x::Union{Float16, Float32, Float64}) = Int(x)
986986

987+
# During definition of struct type `B`, if an `A.B` expression refers to
988+
# the eventual global name of the struct, then return the partially-initialized
989+
# type object.
990+
# TODO: remove. This is a shim for backwards compatibility.
991+
function struct_name_shim(@nospecialize(x), name::Symbol, mod::Module, @nospecialize(t))
992+
return x === mod ? t : getfield(x, name)
993+
end
994+
987995
# Binding for the julia parser, called as
988996
#
989997
# Core._parse(text, filename, lineno, offset, options)

src/julia-syntax.scm

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,19 @@
963963
(ctors-min-initialized (car expr))
964964
(ctors-min-initialized (cdr expr)))))
965965

966+
(define (insert-struct-shim field-types name)
967+
(map (lambda (x)
968+
(expr-replace (lambda (y)
969+
(and (length= y 3) (eq? (car y) '|.|)
970+
(or (equal? (caddr y) `(quote ,name))
971+
(equal? (caddr y) `(inert ,name)))))
972+
x
973+
(lambda (y)
974+
`(call (core struct_name_shim)
975+
,(cadr y) ,(caddr y)
976+
(thismodule) ,name))))
977+
field-types))
978+
966979
(define (struct-def-expr- name params bounds super fields0 mut)
967980
(receive
968981
(fields defs) (separate eventually-decl? fields0)
@@ -1022,11 +1035,9 @@
10221035
prev
10231036
params)
10241037
(quote parameters))))
1025-
'()))
1026-
;; otherwise do an assignment to trigger an error
1027-
(const (globalref (thismodule) ,name) ,name)))
1028-
(const (globalref (thismodule) ,name) ,name))
1029-
(call (core _typebody!) ,name (call (core svec) ,@field-types))
1038+
'())))))
1039+
(call (core _typebody!) ,name (call (core svec) ,@(insert-struct-shim field-types name)))
1040+
(const (globalref (thismodule) ,name) ,name)
10301041
(null)))
10311042
;; "inner" constructors
10321043
(scope-block

src/utils.scm

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@
4848
(any (lambda (y) (expr-contains-p p y filt))
4949
(cdr expr))))))
5050

51+
(define (expr-replace p expr repl)
52+
(cond ((p expr) (repl expr))
53+
((and (pair? expr) (not (quoted? expr)))
54+
(cons (car expr)
55+
(map (lambda (x) (expr-replace p x repl)) (cdr expr))))
56+
(else expr)))
57+
5158
;; find all subexprs satisfying `p`, applying `key` to each one
5259
(define (expr-find-all p expr key (filt (lambda (x) #t)))
5360
(if (filt expr)

test/core.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7669,7 +7669,7 @@ end
76697669
end
76707670
@test fieldtypes(M36104.T36104) == (Vector{M36104.T36104},)
76717671
@test_throws ErrorException("expected") @eval(struct X36104; x::error("expected"); end)
7672-
@test @isdefined(X36104)
7672+
@test !@isdefined(X36104)
76737673
struct X36104; x::Int; end
76747674
@test fieldtypes(X36104) == (Int,)
76757675
primitive type P36104 8 end

0 commit comments

Comments
 (0)