diff --git a/src/variables.jl b/src/variables.jl index df70cf9e9a3..203722e9e00 100644 --- a/src/variables.jl +++ b/src/variables.jl @@ -1750,6 +1750,27 @@ function _moi_add_variable( return var_ref end +_to_value(::Type{T}, value::T, ::String) where {T} = value + +function _to_value(::Type{T}, value, msg::String) where {T} + try + return convert(T, value) + catch + error( + "Unable to use `$value::$(typeof(value))` as the $msg of a " * + "variable because it is not convertable to type `::$T`.", + ) + end +end + +function _to_value(::Type{T}, value::AbstractJuMPScalar, msg::String) where {T} + return error( + "Unable to use `$value::$(typeof(value))` as the $msg of a variable. " * + "The $msg must be a constant value of type `::$T`. You cannot use " * + "JuMP variables or expressions.", + ) +end + function _moi_constrain_variable( moi_backend::MOI.ModelLike, index, @@ -1762,21 +1783,21 @@ function _moi_constrain_variable( _moi_add_constraint( moi_backend, index, - MOI.GreaterThan{T}(info.lower_bound), + MOI.GreaterThan{T}(_to_value(T, info.lower_bound, "lower bound")), ) end if info.has_ub _moi_add_constraint( moi_backend, index, - MOI.LessThan{T}(info.upper_bound), + MOI.LessThan{T}(_to_value(T, info.upper_bound, "upper bound")), ) end if info.has_fix _moi_add_constraint( moi_backend, index, - MOI.EqualTo{T}(info.fixed_value), + MOI.EqualTo{T}(_to_value(T, info.fixed_value, "fixed value")), ) end if info.binary @@ -1790,7 +1811,7 @@ function _moi_constrain_variable( moi_backend, MOI.VariablePrimalStart(), index, - convert(T, info.start), + _to_value(T, info.start, "start value"), ) end end diff --git a/test/test_variable.jl b/test/test_variable.jl index 4e4a2221f91..6f3f50205ae 100644 --- a/test/test_variable.jl +++ b/test/test_variable.jl @@ -1569,4 +1569,36 @@ function test_variable_ref_type_unsupported() return end +function test_bad_bound_types() + T = Int + model = GenericModel{T}() + function err(value, msg, T) + return ErrorException( + "Unable to use `$value::$(typeof(value))` as the $msg of a " * + "variable because it is not convertable to type `::$T`.", + ) + end + for v in (1.2, "abc", :d) + @test_throws err(v, "upper bound", T) @variable(model, x <= v) + @test_throws err(v, "lower bound", T) @variable(model, x >= v) + @test_throws err(v, "fixed value", T) @variable(model, x == v) + @test_throws err(v, "start value", T) @variable(model, x, start = v) + end + function err2(value, msg, T) + return ErrorException( + "Unable to use `$value::$(typeof(value))` as the $msg of a variable. " * + "The $msg must be a constant value of type `::$T`. You cannot use " * + "JuMP variables or expressions.", + ) + end + @variable(model, y) + for v in (y, T(2) * y, sin(y)) + @test_throws err2(v, "upper bound", T) @variable(model, x <= v) + @test_throws err2(v, "lower bound", T) @variable(model, x >= v) + @test_throws err2(v, "fixed value", T) @variable(model, x == v) + @test_throws err2(v, "start value", T) @variable(model, x, start = v) + end + return +end + end # module TestVariable