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

Avoid macro-expand recursion into Expr(:toplevel, ...) #53515

Merged

Conversation

topolarity
Copy link
Member

@topolarity topolarity commented Feb 28, 2024

Here's an example output from macroexpand:

Expr
  head: Symbol thunk
  args: Array{Any}((1,))
    1: Core.CodeInfo
      code: Array{Any}((2,))
        1: Expr
          head: Symbol toplevel
          args: Array{Any}((17,))
            1: Expr
              head: Symbol hygienic-scope
              args: Array{Any}((3,))
                1: LineNumberNode
                2: Module Base.Enums
                3: LineNumberNode
            2: Expr
              head: Symbol hygienic-scope
              args: Array{Any}((3,))
                1: Expr
                2: Module Base.Enums
                3: LineNumberNode
            3: Expr
              head: Symbol hygienic-scope
              args: Array{Any}((3,))
                1: LineNumberNode
                2: Module Base.Enums
                3: LineNumberNode
            4: Expr
              head: Symbol hygienic-scope
              args: Array{Any}((3,))
                1: Expr
                2: Module Base.Enums
                3: LineNumberNode
 ...

Currently fails during bootstrap with:

LoadError("sysimg.jl", 3, LoadError("Base.jl", 542, ErrorException("cannot document the following expression:\n\n#= mpfr.jl:65 =# @enum MPFRRoundingMode begin\n        #= mpfr.jl:66 =#\n        MPFRRoundNearest\n        #= mpfr.jl:67 =#\n        MPFRRoundToZero\n        #= mpfr.jl:68 =#\n        MPFRRoundUp\n        #= mpfr.jl:69 =#\n        MPFRRoundDown\n        #= mpfr.jl:70 =#\n        MPFRRoundFromZero\n        #= mpfr.jl:71 =#\n        MPFRRoundFaithful\n    end\n\n'@enum' not documentable. See 'Base.@__doc__' docs for details.\n")))

Perhaps we can do better than wrapping each Expr(:toplevel, ...) arg individually, or I should be filtering out the LineNumberNodes?

Keno added a commit that referenced this pull request Feb 29, 2024
The following is currently an error:
```
julia> module MyMacroModule
           macro mymacro end
       end
Main.MyMacroModule

julia> macro MyMacroModule.mymacro()
           1
       end
ERROR: syntax: invalid macro definition around REPL[2]:1
Stacktrace:
 [1] top-level scope
   @ REPL[2]:1
```

Discussing with Jeff, we didn't think there was any good reason
not to allow this, just a missing case in lowering. It's probably
not particularly useful (unlike the corresponding case for functions
that is used all the time), but it came up in writing a test case for #53515.
Keno added a commit that referenced this pull request Feb 29, 2024
The following is currently an error:
```
julia> module MyMacroModule
           macro mymacro end
       end
Main.MyMacroModule

julia> macro MyMacroModule.mymacro()
           1
       end
ERROR: syntax: invalid macro definition around REPL[2]:1
Stacktrace:
 [1] top-level scope
   @ REPL[2]:1
```

Discussing with Jeff, we didn't think there was any good reason
not to allow this, just a missing case in lowering. It's probably
not particularly useful (unlike the corresponding case for functions
that is used all the time), but it came up in writing a test case for #53515.
@Keno
Copy link
Member

Keno commented Mar 1, 2024

Alright, so @JeffBezanson and I had about a two hour long discussion on how to fix the doc macro case here.

To recap, the problem is that @doc (the macro being emitted implicitly by the implementation of doc strings, i.e. whenever you write "docstring" foo, you actually get @doc "docstring" foo") internally calls macroexpand as the first thing it does, in order to support documenting structures being generated by macros. In particular, those kinds of macros will internally use the macro Base.@__doc__ to annotate which of the structures they define should get the docstring. This macro just expands to

quote
Expr(:meta, :doc)
foo
end

and the outer @doc call will rewrite any blocks of that form back to

@doc "docstring from outer" foo 

One particular example of a macro that uses this facility is @enum, which essentially expands to Expr(:toplevel, :(@__doc__ primitive type ...))

Now, after this change, macroexpand no longer recurses into Expr(:toplevel), so if you're documenting an enum:

"""
A very poetic enum
"""
@enum MyEnum Our Fearful Trip Is Done

the toplevel @doc macro will macroexpand @enum and see Expr(:toplevel, :(@__doc__ primitive type MyNum ...)), but not any Expr(:meta, :doc).

Some options considered and discarded:

  1. a. Have the doc macro look for explicit, syntactic @__doc__ or @Base.__doc__ calls. I didn't like this, because it means that sometimes @__doc__ is syntactic, but sometimes it is evaluated. In particular, if @__doc__ is not imported in a scope, you could end up in a situation where a macro invocation only works if it is being documented (or vice versa). I thought this was too much of a trap.

  2. b. We considered having @doc call macroexpand1 rather than full macroexpand and require a syntactic @__doc__ chain-of-custody style thing. This seems kinda nice, except that it still has the problem from the previous point in that the @__doc__ is evaluated sometimes, but otherwise treated as a syntactic marker.

  3. a. Instead of recursing over the syntax tree, use a scoped value to hold the current docstring and have @__doc__ simply apply that to whatever it is being applied to when it is expanded. So, in particular, @doc "docstring" foo would basically expand to:

@with DOCSTRING => "foo" begin
@__doc__ foo
end

In particular, this would allow us to avoid @doc calling macroexpand internally at all, which is generally desirable.

@JeffBezanson didn't like this option because he thought that the scope of application should be lexical, not dynamic, so in particular:

@doc "docstring" eval(:(@__doc__ struct Foo))

Should not be able to document Foo.

  1. b. I proposed doing the same thing, but with a lexical rather than a scoped value, but this doesn't work, because the whole point of Expr(:toplevel) is that it doesn't observe let-bound values.

  2. We discussed having the the macro recurse over Expr(:toplevel), by introducing some sort of macro call for every argument, (for purposes of argument @doc2, i.e. a version of @doc that only applies to @__doc__). This seemed semantically sane, but the problem is that @doc is supposed to error if it didn't find any expression to document, but there doesn't seem any particular good way to do that here. You could allocate a mutable Ref{Bool}() and insert a check, but both Jeff and I were concerned about controlling the precise time of setting and checking that Ref, so we discarded this option also.

  3. Jeff proposed just not doing this change and forcing the macroception case to use eval internally.

  4. Have @doc internally call macroexpand on any Expr(:toplevel) arguments. This would restore the current behavior, but of course, it would cause @macroception to break if someone were to put a docstring on it, which is undesirable.

What we ultimately settled on is a variant of the last one that works as follows: If the Expr(:toplevel) argument has any explicit Expr(:meta, :doc) in it, leave it as is and do the usual replacement. On the other hand, if there are no Expr(:meta, :doc) calls in the Expr(:toplevel), do the proposal from point 5 above and explicitly recurse macroexpand. With this, @macroception like macros would have to explicitly emit Expr(:meta, :doc) rather than using @__doc__, but they don't work right now, so that's probably fine.

Keno added a commit that referenced this pull request Mar 1, 2024
The following is currently an error:
```
julia> module MyMacroModule
           macro mymacro end
       end
Main.MyMacroModule

julia> macro MyMacroModule.mymacro()
           1
       end
ERROR: syntax: invalid macro definition around REPL[2]:1
Stacktrace:
 [1] top-level scope
   @ REPL[2]:1
```

Discussing with Jeff, we didn't think there was any good reason not to
allow this, just a missing case in lowering. It's probably not
particularly useful (unlike the corresponding case for functions that is
used all the time), but it came up in writing a test case for #53515.
@Keno Keno force-pushed the ct/macroexpand-no-toplevel-recursion branch from e1662aa to 6647682 Compare March 1, 2024 23:35
@Keno Keno changed the title (WIP) Avoid macro-expand recursion into Expr(:toplevel, ...) Avoid macro-expand recursion into Expr(:toplevel, ...) Mar 3, 2024
@Keno Keno requested a review from JeffBezanson March 3, 2024 00:01
@Keno Keno added the needs pkgeval Tests for all registered packages should be run with this change label Mar 3, 2024
@Keno Keno marked this pull request as ready for review March 3, 2024 00:01
@Keno
Copy link
Member

Keno commented Mar 3, 2024

I have implemented the above proposed solution. I believe this should be ready to go, but we should pkgeval it, to see if there's any other impact.

@Keno
Copy link
Member

Keno commented Mar 3, 2024

@nanosoldier runtests()

@nanosoldier
Copy link
Collaborator

The package evaluation job you requested has completed - possible new issues were detected.
The full report is available.

@Keno
Copy link
Member

Keno commented Mar 4, 2024

Lots of failures, but most are PrecompileTools and SciMLBase. PrecompileTools has this, which got broken on this PR:

julia> macro foo()
               sym = gensym()
               Expr(:toplevel,
                       :($sym = 1),
                       :($sym))
       end
@foo (macro with 1 method)

julia> @foo()
ERROR: UndefVarError: `##228` not defined in `Main`
Suggestion: check for spelling errors or missing imports.
Stacktrace:
 [1] top-level scope
   @ REPL[3]:1
 [2] top-level scope

SciMLBase has:

julia> "A" @EnumX.enumx A
ERROR: cannot document the following expression:

$(Expr(:escape, :A))

Stacktrace:
 [1] error(::String, ::String)
   @ Base ./error.jl:44
 [2] top-level scope
   @ REPL[3]:1
 [3] top-level scope
   @ REPL[3]:1

which I haven't investigated yet, but probably just needs a small tweak to the doc macro support.

tecosaur pushed a commit to tecosaur/julia that referenced this pull request Mar 4, 2024
…aLang#53535)

The following is currently an error:
```
julia> module MyMacroModule
           macro mymacro end
       end
Main.MyMacroModule

julia> macro MyMacroModule.mymacro()
           1
       end
ERROR: syntax: invalid macro definition around REPL[2]:1
Stacktrace:
 [1] top-level scope
   @ REPL[2]:1
```

Discussing with Jeff, we didn't think there was any good reason not to
allow this, just a missing case in lowering. It's probably not
particularly useful (unlike the corresponding case for functions that is
used all the time), but it came up in writing a test case for JuliaLang#53515.
@vtjnash
Copy link
Member

vtjnash commented Mar 4, 2024

Looks like the EnumX is an implementation issue with the way that the @doc handles :meta :doc replacement in macro results. In particular, it starts like this:

:($(Expr(Symbol("hygienic-scope"), quote
    $(Expr(:meta, :doc))
    $(Expr(:escape, :A))
end

and ends like this:

:($(Expr(Symbol("hygienic-scope"), :(#= REPL[7]:2 =# @doc Main nothing "A" $(Expr(:escape, :A)) true), EnumX, :(#= REPL[7]:2 =#))))

but that ignores and skips over the hygienic-scope when copying the @doc expression, which changes the meaning of the @doc expression it tried to copy there. Later attempting recursive evaluation of that second @doc won't be able to evaluate what hygienic-scope contained it and thus cannot evaluate that escape node.

@Keno
Copy link
Member

Keno commented Mar 9, 2024

Alright, so to follow up, the offending pattern was removed from PrecompileTools in (JuliaLang/PrecompileTools.jl#36 - registration pending at JuliaRegistries/General#102567) and there's a larger discussion around the confusing macroexpand semantics in #53667. For the EnumX issue, I've updated this PR to not strip the hygenic-scope blocks, which fixes that case. Once the PrecompileTools registration is merged, I intend to re-run PkgEval.

@Keno
Copy link
Member

Keno commented Mar 9, 2024

@nanosoldier runtests(["UncertainEvidence", "MeanFilters", "CSyntax", "CassetteOverlay", "Wasmtime", "UnbalancedOptimalTransport", "TreeSitter", "SortTileRecursiveTree", "PrecompileTools", "WellKnownGeometry", "LinearRationalExpectations", "Losers", "CLIMAParameters", "HeterogeneousComputing", "ClimaParams", "OffsetArrays", "LibCImGui", "CUDD", "LMDB", "RunningQuantiles", "GPI2", "NonNegLeastSquaresMLJInterface", "SubSIt", "Assimp", "Polylabel", "ImGuiOpenGLBackend", "FreeType", "Snappy", "Ginkgo", "H3", "BlockMatching", "LimitedLDLFactorizations", "HybridArrays", "Hwloc", "EllipsisNotation", "Crossterm", "ArrayAllez", "HMatrices", "UnsafeAtomicsLLVM", "DataFlowTasks", "TiledIteration", "VLFeat", "GeoAcceleratedArrays", "Thrift", "ImPlot", "Crystallography", "LibCEED", "AffineMaps", "LinearInterpolations", "UCX", "Bumper", "StructArrays", "ViennaRNA", "Rotations", "HOHQMesh", "CarlemanLinearization", "SelfOrganizingMaps", "MathematicalSystems", "OneRule", "HydrophoneCalibrations", "SDFReader", "MaskedArrays", "FastAlmostBandedMatrices", "SBML", "MieScattering", "FAME", "AccurateArithmetic", "SQLiteCompress", "FastBroadcast", "LuxDeviceUtils", "OutlierDetectionNeighbors", "Proj4", "AbstractSDRs", "ThreadedDenseSparseMul", "MAGEMin_C", "AbstractNeuralNetworks", "ExampleJuggler", "ImGuiGLFWBackend", "JpegTurbo", "FixedEffects", "DataInterpolations", "Proj", "LegendrePolynomials", "AMGCLWrap", "Stencils", "Avro", "ImplicitPlots", "CZML", "ParallelKMeans", "BritishNationalGrid", "PrimitiveOneHot", "ExifViewer", "MLJDecisionTreeInterface", "Pseudospectra", "TerminalUserInterfaces", "RootSolvers", "ExaTron", "MLJClusteringInterface", "MonotonicSplines", "Sixel", "GeoInterfaceMakie", "RadeonProRender", "MiniFB", "LibGEOSMakie", "FreeTypeAbstraction", "SphericalHarmonics", "RBMsAnnealedImportanceSampling", "ContrastiveDivergenceRBM", "Raylib", "Parquet", "NonlinearProblemLibrary", "NLSolversBase", "ImageInTerminal", "DftFunctionals", "ScalarKernelFunctions", "DungBase", "HDF5Plugins", "GeoJSON", "ExtendableSparse", "SGtSNEpi", "UnivariateUnimodalHighestDensityRegion", "SurfaceFluxes", "CloudMicrophysics", "TemplateMatching", "ImageSmooth", "PolyesterForwardDiff", "BipolarSphericalHarmonics", "GraviPet", "Thermodynamics", "Shapefile", "OptimizationCMAEvolutionStrategy", "SymPyPythonCall", "StatsDiscretizations", "Ferrite", "SpectralResampling", "FastDMTransform", "OptimizationGCMAES", "LabelledArrays", "MarsagliaDiscreteSamplers", "FastHistograms", "BoxLeastSquares", "ImageFiltering", "InfrastructureModels", "MLJGLMInterface", "RayCastWorlds", "DecisionMakingUtils", "GDAL", "VectorizedStatistics", "MutualInformationImageRegistration", "oneAPIKernels", "MonteCarloSummary", "ECOS", "SeparableOptimization", "MathJaxRenderer", "GIFImages", "WGPUCompute", "FinanceCore", "SparseExtra", "AtomsIOPython", "Convex", "NLLSsolver", "RestrictedBoltzmannMachinesHDF5", "ReinforcementLearningTrajectories", "ImageCorners", "TropicalGEMM", "Ipaper", "IntervalMDP", "StatGeochemBase", "StateSpaceEcon", "CategoricalMonteCarlo", "WignerD", "Gaius", "CSFML", "TrainingPhantoms", "SixelTerm", "Chordal", "ObjectPools", "WASMCompiler", "LibRaw", "Powerful", "GeoArrayOps", "Geomorphometry", "AlgebraicSolving", "SimplexGridFactory", "RollingFunctions", "VisualGeometryOptimization", "TextEncodeBase", "SpheriCart", "ProximalOperators", "Vlasiator", "SimpleWorkflowRecipes", "CompressedSensing", "SmoQyDEAC", "Determinantal", "FastGeoProjections", "BytePairEncoding", "ImageEdgeDetection", "RandomWalkBVP", "LuxCUDA", "ImageDistances", "Batsrus", "PPTX", "StratiGraphics", "ImageComponentAnalysis", "ComputerVisionMetrics", "BigArrays", "OptimizationEvolutionary", "MatrixProfile", "CUDASIMDTypes", "StatisticalMeasuresBase", "GridVisualize", "GtkMarkdownTextView", "SQLREPL", "MaxEntropyGraphs", "RegularizedLeastSquares", "CurvilinearGrids", "GtkObservables", "DAEProblemLibrary", "DDEProblemLibrary", "DASSL", "BVProblemLibrary", "MicroscopePSFs", "VlasiatorPyPlot", "HallThruster", "DASKR", "OptimizationBBO", "FractionalDiffEq", "ChebParticleMesh", "DiffEqBase", "MLJNaiveBayesInterface", "ModiaResult", "Ripserer", "AdvancedVI", "RadiationDetectorDSP", "LifeContingencies", "SignalAlignment", "POMDPTesting", "WeightedArrays", "Thebes", "ArDCA", "SciMLNLSolve", "SodShockTube", "ModiaBase", "DynamicAxisWarping", "SimpleDiffEq", "MRFingerprintingRecon", "SeeToDee", "FinEtools", "AlgebraicMultigrid", "Jadex", "XGBoost", "TensorOperations", "NetworkHistogram", "MicroscopyLabels", "MLJXGBoostInterface", "FinEtoolsAcoustics", "LuxAMDGPU", "FinEtoolsHeatDiff", "SpmImages", "RedClust", "OptimizationNOMAD", "FinEtoolsMeshing", "ImageQualityIndexes", "HuggingFaceDatasets", "FinEtoolsDeforLinear", "CudaRBMs", "FinEtoolsFlexStructures", "OptimizationPolyalgorithms", "PointCloudRasterizers", "InvariantSets", "PointBasedValueIteration", "PassiveTracerFlows", "Falcons", "EmpiricalPotentials", "CalciumScoring", "NetDecOPF", "CountriesBorders", "PhysicalMeshes", "BoundaryValueProblems", "SciPyDiffEq", "SpeedMapping", "QRDecoders", "TIFFDatasets", "ImageSegmentation", "SimSearchManifoldLearning", "GeophysicalFlows", "GeoRegions", "PlasmaEquilibriumToolkit", "GeoDataFrames", "TaylorIntegration", "StartUpDG", "SurveyDataWeighting", "ModiaPlot_PyPlot", "MLJEnsembles", "StatisticalMeasures", "SignalTablesInterface_PyPlot", "UlamMethod", "NASAPrecipitation", "TaylorInversion", "MLJTestInterface", "MLJText", "Books", "OutlierDetectionTest", "SphericalFunctions", "GerryChain", "DeepFry", "EulerLagrange", "MLJIteration", "DerivableFunctionsBase", "OutlierDetection", "ParameterSpacePartitions", "ImageView", "DiffEqPhysics", "IterativeLQR", "CombinatorialSpaces", "JordanForm", "ReversePropagation", "Pathfinder", "PolaronMobility", "MLJTuning", "FractionalCalculus", "RandomFeatures", "MaximumEntropyMomentClosures", "GMT", "Unfolding", "GlobalSensitivity", "GenerativeTopographicMapping", "OptimizationSpeedMapping", "AlgebraicRelations", "PALEOsediment", "StatGeochem", "MathOptSymbolicAD", "ClimaCoreSpectra", "KdotP", "Photometry", "ClimaCorePlots", "ROMEO", "GMMParameterEstimation", "MixedModelsPermutations", "QuasiCopula", "EquationsSolver", "GeneralizedMonteCarlo", "ClosedLoopReachability", "ClimaCoreVTK", "Fortuna", "BenchmarkEnvironments", "RealPolyhedralHomotopy", "DirectTrajectoryOptimization", "MLJ", "JosephsonCircuits", "MAGEMinApp", "TensND", "ClimaCoreTempestRemap", "MultiStateSystems", "GeoEnergyIO", "StellaratorOptimization", "MLJTestIntegration", "GridapGmsh", "Queryverse", "BloqadeExpr", "Eikonal", "DIVAnd_HFRadar", "SymbolicControlSystems", "BloqadeDormandPrince", "ImageTracking", "VMEC", "ImageFeatures", "Walrus", "MakieLayout", "Phonetics", "Circuitscape", "ManifoldDiffEq", "GeometricProblems", "BloqadeMIS", "BellDiagonalQudits", "GameTheory", "StatisticalRethinking", "IndependentComponentAnalysis", "Omniscape", "LocalAnisotropies", "FSimZoo", "SpeedyWeather", "OrthogonalSphericalShellGrids", "PALEOmodel", "BLASBenchmarksCPU", "MzPlots", "VIDA", "AiidaDFTK", "FSimROS", "UnfoldSim", "BloqadeWaveforms", "FinEtoolsVoxelMesher", "ONSAS", "FinEtoolsVibInFluids", "BloqadeKrylov", "Hydro", "WGPUgfx", "ChargeTransport", "SMLMMetrics", "SMLMData", "MintsMakieRecipes", "FaceDetection", "CitableImage", "ImageColorThresholderApp", "Biplots", "RFFMakie", "PairPlots", "FastGaussianProcesses", "Makie", "FerriteViz", "Fable", "MakieDraw", "RPRMakie", "ItemResponsePlots", "AbstractGPsMakie", "Yunir", "SpectralStatistics", "GeoMakie", "MakieThemes", "AlgebraOfGraphics", "OptimizedEinsum", "AoGExtensions", "DiskArrayEngine", "MathepiaModels", "SemanticTrajectories", "PortfolioAnalytics", "NamedTrajectories", "Jchemo", "MicroTracker", "TrajectoryGamesBase", "Supernovae", "ModiaPlot_CairoMakie", "Porta", "TheNumberLine", "QuantumCliffordPlots", "ObservableCortex", "InteractiveDynamics", "OSMMakie", "MendelImpute", "NighttimeLights", "Tidier", "Foresight", "StateSpacePartitions"])

@vtjnash
Copy link
Member

vtjnash commented Mar 9, 2024

I think the expr copy to the matching meta doc might need to add some escape nodes matching the number of new scopes it entered, if any, and if the doc expression isn't trivial (eg a literal string as it usually is)?

The change to docm though looks like it was simple enough, which is great to see

@nanosoldier
Copy link
Collaborator

The package evaluation job you requested has completed - possible new issues were detected.
The full report is available.

@Keno
Copy link
Member

Keno commented Mar 9, 2024

LLVM-dependent failures are a different macro hygiene bug: #53673. I have a fix, which I'll push here also, so we can re-run pkgeval against that.

@Keno
Copy link
Member

Keno commented Mar 9, 2024

@nanosoldier runtests(["CSyntax", "TreeSitter", "FreeType", "Assimp", "Snappy", "Ginkgo", "Wasmtime", "LMDB", "LibCImGui", "GPI2", "CUDD", "H3", "ImGuiOpenGLBackend", "Hwloc", "ImPlot", "UnsafeAtomicsLLVM", "Thrift", "LimitedLDLFactorizations", "LibCEED", "GeoAcceleratedArrays", "CLIMAParameters", "ClimaParams", "ViennaRNA", "WellKnownGeometry", "SortTileRecursiveTree", "Polylabel", "UCX", "VLFeat", "ArrayAllez", "FAME", "MaskedArrays", "StructArrays", "OneRule", "LinearInterpolations", "SQLiteCompress", "NonNegLeastSquaresMLJInterface", "UnbalancedOptimalTransport", "Proj4", "HeterogeneousComputing", "AbstractNeuralNetworks", "AbstractSDRs", "ImGuiGLFWBackend", "BritishNationalGrid", "SelfOrganizingMaps", "Proj", "RadeonProRender", "PrimitiveOneHot", "MAGEMin_C", "MiniFB", "ParallelKMeans", "Avro", "FreeTypeAbstraction", "RootSolvers", "Raylib", "ExifViewer", "Parquet", "HOHQMesh", "Stencils", "MonotonicSplines", "ScalarKernelFunctions", "ExampleJuggler", "HDF5Plugins", "MLJDecisionTreeInterface", "RayCastWorlds", "StatsDiscretizations", "MLJClusteringInterface", "MLJGLMInterface", "GDAL", "oneAPIKernels", "FixedEffects", "WGPUCompute", "InfrastructureModels", "SixelTerm", "SeparableOptimization", "ImageInTerminal", "CSFML", "LibRaw", "Thermodynamics", "Convex", "Ferrite", "ReinforcementLearningTrajectories", "WASMCompiler", "LuxCUDA", "SimpleWorkflowRecipes", "ECOS", "FastGeoProjections", "TextEncodeBase", "PPTX", "BigArrays", "StatisticalMeasuresBase", "Chordal", "GtkMarkdownTextView", "SQLREPL", "SurfaceFluxes", "GIFImages", "SymPyPythonCall", "CurvilinearGrids", "IntervalMDP", "WeightedArrays", "BytePairEncoding", "CompressedSensing", "CUDASIMDTypes", "GtkObservables", "Thebes", "POMDPTesting", "RadiationDetectorDSP", "AdvancedVI", "MicroscopyLabels", "CudaRBMs", "NetworkHistogram", "HuggingFaceDatasets", "PointCloudRasterizers", "MLJXGBoostInterface", "MLJNaiveBayesInterface", "LuxAMDGPU", "XGBoost", "TIFFDatasets", "MLJEnsembles", "QRDecoders", "PassiveTracerFlows", "MLJText", "SodShockTube", "MLJTestInterface", "GeoDataFrames", "NetDecOPF", "OutlierDetectionTest", "UlamMethod", "GerryChain", "OutlierDetection", "PointBasedValueIteration", "CountriesBorders", "PhysicalMeshes", "ImageView", "GeophysicalFlows", "MLJTuning", "StatisticalMeasures", "MLJIteration", "DeepFry", "AlgebraicRelations", "GMT", "MLJTestIntegration", "MAGEMinApp", "StatGeochem", "ClimaCoreVTK", "GenerativeTopographicMapping", "GridapGmsh", "Fortuna", "GeoEnergyIO", "MultiStateSystems", "Queryverse", "MakieLayout", "MintsMakieRecipes", "BloqadeExpr", "OrthogonalSphericalShellGrids", "ImageColorThresholderApp", "Circuitscape", "Omniscape", "FastGaussianProcesses", "PairPlots", "FerriteViz", "Makie", "RFFMakie", "SpeedyWeather", "PALEOmodel", "GameTheory", "FSimZoo", "StatisticalRethinking", "MzPlots", "MakieDraw", "RPRMakie", "AbstractGPsMakie", "Yunir", "ONSAS", "Biplots", "ItemResponsePlots", "SpectralStatistics", "MakieThemes", "TheNumberLine", "TrajectoryGamesBase", "Jchemo", "Porta", "ObservableCortex", "QuantumCliffordPlots", "AlgebraOfGraphics", "Supernovae", "NamedTrajectories", "NighttimeLights", "ModiaPlot_CairoMakie", "InteractiveDynamics"])

@Keno
Copy link
Member

Keno commented Mar 9, 2024

I think the expr copy to the matching meta doc might need to add some escape nodes matching the number of new scopes it entered, if any, and if the doc expression isn't trivial (eg a literal string as it usually is)?

I've tried a bunch of examples, but I haven't yet been able to come up with a case that's actually failing. Do you have one in mind?

@nanosoldier
Copy link
Collaborator

The package evaluation job you requested has completed - possible new issues were detected.
The full report is available.

@vtjnash
Copy link
Member

vtjnash commented Mar 12, 2024

Those syntax errors seem related to the change here:

julia> using Test; Test.@testset for x in y; end

(type-error car cons ())
unexpected error: #0 (caddr (escape (= x y)))
#1 (resolve-letlike-assign
 (escape #0=(= x y)) #1=(#0#
                         (false) (arr . |#1#arr|) (default_rng_orig . |#2#default_rng_orig|)
                         (tls_seed_orig . |#3#tls_seed_orig|) (finish_errored . |#4#finish_errored|)
                         (ts . |#5#ts|) (first_iteration . |#6#first_iteration|))
 (#0# . #1#) #<julia: Test> ((line 1 |REPL[2]|)) () #f)

@Keno Keno force-pushed the ct/macroexpand-no-toplevel-recursion branch from 6ae6fd5 to 494420c Compare March 13, 2024 07:54
@Keno
Copy link
Member

Keno commented Mar 13, 2024

@nanosoldier runtests(["CSyntax", "TreeSitter", "FreeType", "Assimp", "Snappy", "Ginkgo", "Wasmtime", "LMDB", "LibCImGui", "GPI2", "CUDD", "H3", "ImGuiOpenGLBackend", "Hwloc", "ImPlot", "UnsafeAtomicsLLVM", "Thrift", "LimitedLDLFactorizations", "LibCEED", "GeoAcceleratedArrays", "CLIMAParameters", "ClimaParams", "ViennaRNA", "WellKnownGeometry", "SortTileRecursiveTree", "Polylabel", "UCX", "VLFeat", "ArrayAllez", "FAME", "MaskedArrays", "StructArrays", "OneRule", "LinearInterpolations", "SQLiteCompress", "NonNegLeastSquaresMLJInterface", "UnbalancedOptimalTransport", "Proj4", "HeterogeneousComputing", "AbstractNeuralNetworks", "AbstractSDRs", "ImGuiGLFWBackend", "BritishNationalGrid", "SelfOrganizingMaps", "Proj", "RadeonProRender", "PrimitiveOneHot", "MAGEMin_C", "MiniFB", "ParallelKMeans", "Avro", "FreeTypeAbstraction", "RootSolvers", "Raylib", "ExifViewer", "Parquet", "HOHQMesh", "Stencils", "MonotonicSplines", "ScalarKernelFunctions", "ExampleJuggler", "HDF5Plugins", "MLJDecisionTreeInterface", "RayCastWorlds", "StatsDiscretizations", "MLJClusteringInterface", "MLJGLMInterface", "GDAL", "oneAPIKernels", "FixedEffects", "WGPUCompute", "InfrastructureModels", "SixelTerm", "SeparableOptimization", "ImageInTerminal", "CSFML", "LibRaw", "Thermodynamics", "Convex", "Ferrite", "ReinforcementLearningTrajectories", "WASMCompiler", "LuxCUDA", "SimpleWorkflowRecipes", "ECOS", "FastGeoProjections", "TextEncodeBase", "PPTX", "BigArrays", "StatisticalMeasuresBase", "Chordal", "GtkMarkdownTextView", "SQLREPL", "SurfaceFluxes", "GIFImages", "SymPyPythonCall", "CurvilinearGrids", "IntervalMDP", "WeightedArrays", "BytePairEncoding", "CompressedSensing", "CUDASIMDTypes", "GtkObservables", "Thebes", "POMDPTesting", "RadiationDetectorDSP", "AdvancedVI", "MicroscopyLabels", "CudaRBMs", "NetworkHistogram", "HuggingFaceDatasets", "PointCloudRasterizers", "MLJXGBoostInterface", "MLJNaiveBayesInterface", "LuxAMDGPU", "XGBoost", "TIFFDatasets", "MLJEnsembles", "QRDecoders", "PassiveTracerFlows", "MLJText", "SodShockTube", "MLJTestInterface", "GeoDataFrames", "NetDecOPF", "OutlierDetectionTest", "UlamMethod", "GerryChain", "OutlierDetection", "PointBasedValueIteration", "CountriesBorders", "PhysicalMeshes", "ImageView", "GeophysicalFlows", "MLJTuning", "StatisticalMeasures", "MLJIteration", "DeepFry", "AlgebraicRelations", "GMT", "MLJTestIntegration", "MAGEMinApp", "StatGeochem", "ClimaCoreVTK", "GenerativeTopographicMapping", "GridapGmsh", "Fortuna", "GeoEnergyIO", "MultiStateSystems", "Queryverse", "MakieLayout", "MintsMakieRecipes", "BloqadeExpr", "OrthogonalSphericalShellGrids", "ImageColorThresholderApp", "Circuitscape", "Omniscape", "FastGaussianProcesses", "PairPlots", "FerriteViz", "Makie", "RFFMakie", "SpeedyWeather", "PALEOmodel", "GameTheory", "FSimZoo", "StatisticalRethinking", "MzPlots", "MakieDraw", "RPRMakie", "AbstractGPsMakie", "Yunir", "ONSAS", "Biplots", "ItemResponsePlots", "SpectralStatistics", "MakieThemes", "TheNumberLine", "TrajectoryGamesBase", "Jchemo", "Porta", "ObservableCortex", "QuantumCliffordPlots", "AlgebraOfGraphics", "Supernovae", "NamedTrajectories", "NighttimeLights", "ModiaPlot_CairoMakie", "InteractiveDynamics"])

@nanosoldier
Copy link
Collaborator

The package evaluation job you requested has completed - possible new issues were detected.
The full report is available.

@Keno
Copy link
Member

Keno commented Mar 13, 2024

CSyntax issue reduces to:

julia> Expr(:let, Expr(:block), Expr(:block, Expr(:toplevel, :(f(x) = x)), :(x=1)))
:(let
      $(Expr(:toplevel, :(f(x) = begin
          #= REPL[69]:1 =#
          x
      end)))
      x = 1
  end)

julia> eval(ans)
ERROR: syntax: SlotNumber objects should not occur in an AST
Stacktrace:
 [1] top-level scope
   @ none:1
 [2] top-level scope
   @ none:1
 [3] eval
   @ ./boot.jl:432 [inlined]
 [4] eval(x::Expr)
   @ Main ./sysimg.jl:48
 [5] top-level scope
   @ REPL[70]:1

@Keno
Copy link
Member

Keno commented Mar 14, 2024

@nanosoldier runtests(["CSyntax", "ItemResponsePlots", "TrajectoryGamesBase"])

@nanosoldier
Copy link
Collaborator

The package evaluation job you requested has completed - no new issues were detected.
The full report is available.

@Keno Keno force-pushed the ct/macroexpand-no-toplevel-recursion branch from 1d73b36 to 465955f Compare March 14, 2024 08:08
@Keno
Copy link
Member

Keno commented Mar 14, 2024

Alright, this is good to go. We've fixed all the pkgeval issues. @vtjnash still has some concerns about @doc's (non-)treatment of hygiene, but that's mostly unrelated. This PR does a little bit of that to fix the cases that were broken in actual user packages, but I think the full thing can be a separate later PR. It only really affects use cases where you have an interpolated doc string and are doing multiple levels of macro nesting. I also don't fully understand the solution that @vtjnash had in mind.

@Keno Keno removed the needs pkgeval Tests for all registered packages should be run with this change label Mar 14, 2024
@Keno Keno merged commit 612393c into JuliaLang:master Mar 14, 2024
7 of 8 checks passed
Keno added a commit that referenced this pull request Mar 20, 2024
The following is currently an error:
```
julia> module MyMacroModule
           macro mymacro end
       end
Main.MyMacroModule

julia> macro MyMacroModule.mymacro()
           1
       end
ERROR: syntax: invalid macro definition around REPL[2]:1
Stacktrace:
 [1] top-level scope
   @ REPL[2]:1
```

Discussing with Jeff, we didn't think there was any good reason not to
allow this, just a missing case in lowering. It's probably not
particularly useful (unlike the corresponding case for functions that is
used all the time), but it came up in writing a test case for #53515.
Keno added a commit that referenced this pull request Mar 20, 2024
Here's an example output from macroexpand:
```
Expr
  head: Symbol thunk
  args: Array{Any}((1,))
    1: Core.CodeInfo
      code: Array{Any}((2,))
        1: Expr
          head: Symbol toplevel
          args: Array{Any}((17,))
            1: Expr
              head: Symbol hygienic-scope
              args: Array{Any}((3,))
                1: LineNumberNode
                2: Module Base.Enums
                3: LineNumberNode
            2: Expr
              head: Symbol hygienic-scope
              args: Array{Any}((3,))
                1: Expr
                2: Module Base.Enums
                3: LineNumberNode
            3: Expr
              head: Symbol hygienic-scope
              args: Array{Any}((3,))
                1: LineNumberNode
                2: Module Base.Enums
                3: LineNumberNode
            4: Expr
              head: Symbol hygienic-scope
              args: Array{Any}((3,))
                1: Expr
                2: Module Base.Enums
                3: LineNumberNode
 ...
```

Currently fails during bootstrap with:
```
LoadError("sysimg.jl", 3, LoadError("Base.jl", 542, ErrorException("cannot document the following expression:\n\n#= mpfr.jl:65 =# @enum MPFRRoundingMode begin\n        #= mpfr.jl:66 =#\n        MPFRRoundNearest\n        #= mpfr.jl:67 =#\n        MPFRRoundToZero\n        #= mpfr.jl:68 =#\n        MPFRRoundUp\n        #= mpfr.jl:69 =#\n        MPFRRoundDown\n        #= mpfr.jl:70 =#\n        MPFRRoundFromZero\n        #= mpfr.jl:71 =#\n        MPFRRoundFaithful\n    end\n\n'@enum' not documentable. See 'Base.@__doc__' docs for details.\n")))
```

Perhaps we can do better than wrapping each `Expr(:toplevel, ...)` arg
individually, or I should be filtering out the LineNumberNodes?

---------

Co-authored-by: Keno Fischer <keno@juliacomputing.com>
Co-authored-by: Keno Fischer <keno@juliahub.com>
mkitti pushed a commit to mkitti/julia that referenced this pull request Apr 13, 2024
…aLang#53535)

The following is currently an error:
```
julia> module MyMacroModule
           macro mymacro end
       end
Main.MyMacroModule

julia> macro MyMacroModule.mymacro()
           1
       end
ERROR: syntax: invalid macro definition around REPL[2]:1
Stacktrace:
 [1] top-level scope
   @ REPL[2]:1
```

Discussing with Jeff, we didn't think there was any good reason not to
allow this, just a missing case in lowering. It's probably not
particularly useful (unlike the corresponding case for functions that is
used all the time), but it came up in writing a test case for JuliaLang#53515.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants