Skip to content

Commit 26fc759

Browse files
committed
Clamp syntax version to v1.13 minimum in get_project_syntax_version
Fix issue where packages with ancient compat declarations like `julia = "1"` would have their syntax version set to v1.0, causing the parser to reject newer syntax features like `import ... as`. Since syntax versioning was introduced in Julia 1.14, we now clamp the syntax version to at least v1.13 (NON_VERSIONED_SYNTAX) to match the logic in Base.loading.jl. This also fixes a bug in the original function where it referenced `syntax_table["julia_version"]` instead of `p.julia_syntax_version`. Fixes JuliaLang/julia#60273
1 parent 7a82e43 commit 26fc759

File tree

2 files changed

+49
-8
lines changed

2 files changed

+49
-8
lines changed

src/Operations.jl

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ import ...Pkg: usable_io, discover_repo, create_cachedir_tag, manifest_rel_path
2222
# Utils #
2323
#########
2424

25+
# Syntax versioning was first introduced in Julia 1.14, so we clamp the
26+
# syntax version to this minimum to avoid enforcing old syntax rules for
27+
# packages with ancient compat declarations (e.g., compat.julia = "1").
28+
# This mirrors Base.NON_VERSIONED_SYNTAX in loading.jl.
29+
const NON_VERSIONED_SYNTAX = v"1.13"
30+
2531
# Helper functions for yanked package checking
2632
function is_pkgversion_yanked(uuid::UUID, version::VersionNumber, registries::Vector{Registry.RegistryInstance} = Registry.reachable_registries())
2733
for reg in registries
@@ -386,29 +392,44 @@ this precedence order:
386392
2. If `compat.julia` is specified, use the minimum version from the compat range
387393
3. Otherwise, default to the current Julia VERSION
388394
395+
The result is clamped to at least `NON_VERSIONED_SYNTAX` (v1.13) since syntax
396+
versioning was introduced in Julia 1.14. This prevents packages with ancient
397+
compat declarations (e.g., `julia = "1"`) from having their syntax version set
398+
too low, which would cause the parser to reject newer syntax features.
399+
389400
This information is used to populate the `syntax.julia_version` field in the
390401
Manifest.toml, allowing Base's loading system to parse each package with the
391402
correct syntax version.
392403
"""
393404
function get_project_syntax_version(p::Project)::VersionNumber
405+
sv = nothing
406+
394407
# First check syntax.julia_version entry in Project.other
395408
if p.julia_syntax_version !== nothing
396-
return VersionNumber(syntax_table["julia_version"])
397-
end
398-
399-
# If not found, default to minimum(compat["julia"])
400-
if haskey(p.compat, "julia")
409+
sv = p.julia_syntax_version
410+
elseif haskey(p.compat, "julia")
411+
# If not found, default to minimum(compat["julia"])
401412
julia_compat = p.compat["julia"]
402413
# Get the minimum version from the first range
403414
if !isempty(julia_compat.val.ranges)
404415
first_range = first(julia_compat.val.ranges)
405416
lower_bound = first_range.lower
406-
return VersionNumber(lower_bound.t[1], lower_bound.t[2], lower_bound.t[3])
417+
sv = VersionNumber(lower_bound.t[1], lower_bound.t[2], lower_bound.t[3])
407418
end
408419
end
409420

410-
# Finally, if neither of those are set, default to the current Julia version
411-
return VERSION
421+
# If no version was found, default to the current Julia version
422+
if sv === nothing
423+
sv = VERSION
424+
end
425+
426+
# Clamp to at least NON_VERSIONED_SYNTAX since syntax versioning was
427+
# introduced in Julia 1.14
428+
if sv <= NON_VERSIONED_SYNTAX
429+
sv = NON_VERSIONED_SYNTAX
430+
end
431+
432+
return sv
412433
end
413434

414435
# This has to be done after the packages have been downloaded

test/manifests.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,4 +648,24 @@ end
648648
end
649649
end
650650

651+
@testset "Syntax version clamping" begin
652+
# Test that old compat/syntax declarations are clamped to v1.13 (NON_VERSIONED_SYNTAX)
653+
test_cases = [
654+
("[compat]\njulia = \"1\"", v"1.13"), # ancient compat clamped
655+
("[compat]\njulia = \"1.6\"", v"1.13"), # old compat clamped
656+
("[compat]\njulia = \"1.14\"", v"1.14"), # new compat not clamped
657+
("[syntax]\njulia_version = \"1.0\"", v"1.13"), # explicit old clamped
658+
("[syntax]\njulia_version = \"1.14\"", v"1.14"), # explicit new not clamped
659+
]
660+
mktempdir() do test_dir
661+
for (i, (section, expected)) in enumerate(test_cases)
662+
pkg_dir = joinpath(test_dir, "Pkg$i")
663+
mkpath(pkg_dir)
664+
write(joinpath(pkg_dir, "Project.toml"), "name = \"Pkg$i\"\nuuid = \"12345678-1234-1234-1234-12345678901$i\"\n$section\n")
665+
project = Pkg.Types.read_project(joinpath(pkg_dir, "Project.toml"))
666+
@test Pkg.Operations.get_project_syntax_version(project) == expected
667+
end
668+
end
669+
end
670+
651671
end # module

0 commit comments

Comments
 (0)