Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Latest at-view macro changes break previously valid code ("invalid let syntax") #53107

Closed
tkemmer opened this issue Jan 29, 2024 · 3 comments · Fixed by #53108
Closed

Latest at-view macro changes break previously valid code ("invalid let syntax") #53107

tkemmer opened this issue Jan 29, 2024 · 3 comments · Fixed by #53108
Labels
compiler:lowering Syntax lowering (compiler front end, 2nd stage)

Comments

@tkemmer
Copy link

tkemmer commented Jan 29, 2024

I noticed a possible breakage of the at-view macro in the current master (since 0588cd4) under very specific circumstances while tracking down a precompilation error of BioStructures.jl w/ Gihub CI and Julia nightly pointing to this particular line of code:

https://github.com/BioJulia/BioStructures.jl/blob/69b48127811f0ec235bd17e25838af7ceffd4087/src/spatial.jl#L205

The associated error is:

ERROR: LoadError: syntax: invalid let syntax around /home/runner/.julia/packages/BioStructures/UfNVa/src/spatial.jl:205

Corresponding versioninfo() of the Github runner:

Julia Version 1.11.0-DEV.1400
Commit 08d229f4a7c (2024-01-29 11:51 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 4 × AMD EPYC 7763 64-Core Processor
  WORD_SIZE: 64
  LLVM: libLLVM-[16](https://github.com/hildebrandtlab/BiochemicalAlgorithms.jl/actions/runs/7697322191/job/20974110704#step:3:17).0.6 (ORCJIT, znver3)
Threads: 1 default, 0 interactive, 1 GC (on 4 virtual cores)

Please find below a MWE to trigger the same error as above. A few conditions seem to be required for the error to trigger, particularly:

  • the matrix needs to be wrapped in a lazy transformation such as transpose or adjoint (working directly on the matrix, does not trigger the error)
  • the projected vector (column or row) needs to be addressed via end in some way (replacing end by the corresponding column index in the example below does not trigger the error)
  • the view needs to be broadcast-transformed in-place using something like .+= or .*= (broadcast assignment .= does not trigger the error)

MWE

Expected behavior (before 0588cd4):

julia> M = [1 2 3; 4 5 6; 7 8 9]
3×3 Matrix{Int64}:
 1  2  3
 4  5  6
 7  8  9

julia> @view(transpose(M)[:,end])
3-element view(transpose(::Matrix{Int64}), :, 3) with eltype Int64:
 7
 8
 9

julia> @view(transpose(M)[:,end]) .+= [1, 1, 1]
3-element view(transpose(::Matrix{Int64}), :, 3) with eltype Int64:
  8
  9
 10

julia> M
3×3 Matrix{Int64}:
 1  2   3
 4  5   6
 8  9  10

Since 0588cd4:

julia> M = [1 2 3; 4 5 6; 7 8 9]
3×3 Matrix{Int64}:
 1  2  3
 4  5  6
 7  8  9

julia> @view(transpose(M)[:,end])
3-element view(transpose(::Matrix{Int64}), :, 3) with eltype Int64:
 7
 8
 9

julia> @view(transpose(M)[:,end]) .+= [1, 1, 1]
ERROR: syntax: invalid let syntax around REPL[47]:1
Stacktrace:
 [1] top-level scope
   @ REPL[47]:1

MWE output produced using Julia 1.11.0-DEV.1394 (dcb196e) before and after cherry-picking 0588cd4, respectively.

@tkemmer tkemmer changed the title Latest at-view macro changes break previously valid code ( Latest at-view macro changes break previously valid code ("invalid let syntax") Jan 29, 2024
@BioTurboNick
Copy link
Contributor

BioTurboNick commented Jan 29, 2024

On one level, it seems like it should be an error to put a view on the LHS (without a second level of indexing). However, the issue also occurs when using @views to wrap a block for convenience:

julia> @views transpose(M)[:,end] .+= M[1:3]
ERROR: syntax: invalid let syntax around REPL[6]:1

EDIT: Oh, interesting - it's the same error on 1.10, 1.9, and 1.6 (skipped others) when using @views.

@mbauman
Copy link
Member

mbauman commented Jan 29, 2024

Oh this is fascinating — I think the change itself was valid, but it's exposing a quirk in lowering of all places. Specifically, it's that lowering can handle the complicated true && let ... end .+= 1 but not the simpler expression (perhaps that's precisely because this is the path we took here).

julia> Meta.@lower (let x=x; x; end) .+= 1
:($(Expr(:error, "invalid let syntax around REPL[20]:1")))

julia> Meta.@lower (true && let x=x; x; end) .+= 1
:($(Expr(:thunk, CodeInfo(
    @ none within `top-level scope`
1%1  = x
│         x = %1
│   @ REPL[24]:1 within `top-level scope`%3  = x
└──       goto #3 if not true
2@_2 = %3
└──       goto #4
3@_2 = false
4%8  = @_2%9  = Base.broadcasted(+, %8, 1)
│   %10 = Base.materialize!(%8, %9)
└──       return %10
))))

julia> Meta.@lower (nothing; let x=x; x; end) .+= 1
:($(Expr(:thunk, CodeInfo(
    @ none within `top-level scope`
1%1 = x
│        x = %1
│   @ REPL[23]:1 within `top-level scope`%3 = x
│        nothing%5 = Base.broadcasted(+, %3, 1)
│   %6 = Base.materialize!(%3, %5)
└──      return %6
))))

@mbauman mbauman added the compiler:lowering Syntax lowering (compiler front end, 2nd stage) label Jan 29, 2024
@vtjnash
Copy link
Member

vtjnash commented Jan 29, 2024

Duplicate of #44356, #35171, others?

vtjnash pushed a commit that referenced this issue Jan 30, 2024
When the frontend lowers an expression like `lhs .+= rhs`, it needs to
prevent evaluating the LHS more than once before re-writing to `lhs .=
lhs .+ rhs`. If the LHS was a `let` block — commonly generated by
`@views` and (since #53064) `@view` — the lowering pass had previously
been emitting an invalid `let` temporary. This very directly addresses
that case.

Fixes #53107.
Fixes #44356.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler:lowering Syntax lowering (compiler front end, 2nd stage)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants