diff --git a/src/Containers/macro.jl b/src/Containers/macro.jl index c62bf345a6e..b4f3f444b75 100644 --- a/src/Containers/macro.jl +++ b/src/Containers/macro.jl @@ -79,13 +79,23 @@ function parse_macro_arguments( end """ - _explicit_oneto(index_set) + _explicit_oneto(error_fn, index_set) If the `index_set` matches the form of `1:N`, then return `Base.OneTo(index_set)`. """ -function _explicit_oneto(index_set) +function _explicit_oneto(error_fn, index_set) s = Meta.isexpr(index_set, :escape) ? index_set.args[1] : index_set + index_set = quote + try + $index_set + catch + $error_fn( + "unexpected error parsing reference set: ", + $(Meta.quot(_drop_esc(index_set))), + ) + end + end if Meta.isexpr(s, :call, 3) && s.args[1] == :(:) && s.args[2] == 1 return :(Base.OneTo($index_set)) else @@ -316,6 +326,8 @@ function build_error_fn(macro_name, args, source) return error_fn end +_drop_esc(x) = Meta.isexpr(x, :escape) ? x.args[1] : x + """ build_ref_sets(error_fn::Function, expr) @@ -331,7 +343,7 @@ function build_ref_sets(error_fn::Function, expr) end if !_has_dependent_sets(index_vars, index_sets) && condition == :() # Convert any 1:N to Base.OneTo(N) - new_index_sets = _explicit_oneto.(index_sets) + new_index_sets = _explicit_oneto.(error_fn, index_sets) indices = :(Containers.vectorized_product($(new_index_sets...))) return index_vars, indices end @@ -340,11 +352,29 @@ function build_ref_sets(error_fn::Function, expr) for i in 1:length(index_vars) push!( indices.args, - :(($(esc_index_vars[1:(i-1)]...),) -> $(index_sets[i])), + quote + ($(esc_index_vars[1:(i-1)]...),) -> try + $(index_sets[i]) + catch + $error_fn( + "unexpected error parsing reference set: ", + $(Meta.quot(_drop_esc(index_sets[i]))), + ) + end + end, ) end if condition != :() - f = :(($(esc_index_vars...),) -> $(esc(condition))) + f = quote + ($(esc_index_vars...),) -> try + $(esc(condition)) + catch + $error_fn( + "unexpected error parsing condition: ", + $(Meta.quot(condition)), + ) + end + end args = indices.args[2:end] indices = :(Containers.nested($(args...); condition = $f)) end diff --git a/test/test_macros.jl b/test/test_macros.jl index 5183deb4bc6..1a4e0aca7c0 100644 --- a/test/test_macros.jl +++ b/test/test_macros.jl @@ -2254,4 +2254,82 @@ function test_escaping_of_set_kwarg() return end +function test_error_parsing_reference_sets() + model = Model() + @variable(model, a) + @test_throws_runtime( + ErrorException( + "In `@variable(model, b[1:a])`: unexpected error parsing reference set: 1:a", + ), + @variable(model, b[1:a]), + ) + @test_throws_runtime( + ErrorException( + "In `@variable(model, b[1:2, 1:a])`: unexpected error parsing reference set: 1:a", + ), + @variable(model, b[1:2, 1:a]), + ) + @test_throws_runtime( + ErrorException( + "In `@variable(model, b[i = 1:a, 1:i])`: unexpected error parsing reference set: 1:a", + ), + @variable(model, b[i = 1:a, 1:i]), + ) + @test_throws_runtime( + ErrorException( + "In `@variable(model, b[i = 1:2, a:i])`: unexpected error parsing reference set: a:i", + ), + @variable(model, b[i = 1:2, a:i]), + ) + @test_throws_runtime( + ErrorException( + "In `@variable(model, b[i = 1:2; i < a])`: unexpected error parsing condition: i < a", + ), + @variable(model, b[i = 1:2; i < a]), + ) + @test_throws_runtime( + ErrorException( + "In `@expression(model, b[1:a], a + 1)`: unexpected error parsing reference set: 1:a", + ), + @expression(model, b[1:a], a + 1), + ) + @test_throws_runtime( + ErrorException( + "In `@expression(model, b[1:2, 1:a], a + 1)`: unexpected error parsing reference set: 1:a", + ), + @expression(model, b[1:2, 1:a], a + 1), + ) + @test_throws_runtime( + ErrorException( + "In `@expression(model, b[i = 1:a, 1:i], a + 1)`: unexpected error parsing reference set: 1:a", + ), + @expression(model, b[i = 1:a, 1:i], a + 1), + ) + @test_throws_runtime( + ErrorException( + "In `@expression(model, b[i = 1:2, a:i], a + 1)`: unexpected error parsing reference set: a:i", + ), + @expression(model, b[i = 1:2, a:i], a + 1), + ) + @test_throws_runtime( + ErrorException( + "In `@expression(model, b[i = 1:2; i < a], a + 1)`: unexpected error parsing condition: i < a", + ), + @expression(model, b[i = 1:2; i < a], a + 1), + ) + @test_throws_runtime( + ErrorException( + "In `@constraint(model, b[i = 1:a], a <= 1)`: unexpected error parsing reference set: 1:a", + ), + @constraint(model, b[i = 1:a], a <= 1), + ) + @test_throws_runtime( + ErrorException( + "In `@constraint(model, b[i = 1:2; i < a], a <= 1)`: unexpected error parsing condition: i < a", + ), + @constraint(model, b[i = 1:2; i < a], a <= 1), + ) + return +end + end # module