Skip to content

Mistaken "invalid redefinition" for self-referential types #54757

@Liozou

Description

@Liozou

"Redefining" a struct with the identical definition does nothing and is legal:

julia> struct NoRec end;

julia> struct NoRec end;

However, this fails when the struct references itself in its supertype:

julia> struct Rec <: AbstractVector{Rec} end;

julia> struct Rec <: AbstractVector{Rec} end;
ERROR: invalid redefinition of constant Main.Rec
Stacktrace:
 [1] top-level scope
   @ REPL[2]:1

In practice, this creates problems with Revise: in any file that contains such a type, any modification unrelated to the type triggers this "ERROR: invalid redefinition of constant" and blocks Revise, with no way of unblocking it: see timholy/Revise.jl#813


I believe the cause of this error comes from Core._equiv_typedef, which behaves differently on NoRec and Rec. For two instances of NoRec, we have

julia> var"#1001#NoRec" = Core._structtype(Main, :NoRec, Core.svec(), Core.svec(), Core.svec(), false, 1); Core._setsuper!(var"#1001#NoRec", Any)

julia> var"#1000#NoRec" = Core._structtype(Main, :NoRec, Core.svec(), Core.svec(), Core.svec(), false, 1); Core._setsuper!(var"#1000#NoRec", Any)

julia> Core._equiv_typedef(var"#1000#NoRec", var"#1001#NoRec")
true

but for two instances of Rec it becomes:

julia> var"#1000#Rec" = Core._structtype(Main, :Rec, Core.svec(), Core.svec(), Core.svec(), false, 1); Core._setsuper!(var"#1000#Rec", Core.apply_type(AbstractVector, var"#1000#Rec"))

julia> var"#1001#Rec" = Core._structtype(Main, :Rec, Core.svec(), Core.svec(), Core.svec(), false, 1); Core._setsuper!(var"#1001#Rec", Core.apply_type(AbstractVector, var"#1001#Rec"))

julia> Core._equiv_typedef(var"#1000#Rec", var"#1001#Rec")
false

So a fix could consist in teaching equiv_type to handle this kind of self-reference, i.e. to fix the following approach:

julia/src/builtins.c

Lines 2222 to 2225 in 7197c9e

a = jl_rewrap_unionall((jl_value_t*)dta->super, dta->name->wrapper);
b = jl_rewrap_unionall((jl_value_t*)dtb->super, dtb->name->wrapper);
if (!jl_types_equal(a, b))
goto no;

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureIndicates new feature / enhancement requeststypes and dispatchTypes, subtyping and method dispatch

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions