Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/graph_engine.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2061,6 +2061,26 @@ make_node!(materialize::True, node_type::Composite, behaviour::Stochastic, model
Composite(), model, ctx, options, fform, lhs_interface, rhs_interfaces, static(length(rhs_interfaces) + length(lhs_interface))
)

# A multi-output submodel call must provide exactly as many outputs on the left-hand side as there are
# interfaces left unspecified on the right-hand side. When it does not, the total arity does not match the
# `StaticInt{N}` of any generated `make_node!` method and dispatch fails with a `MethodError` that says
# nothing about the real problem, so this less specific fallback reports it instead.
function make_node!(
::Composite,
model::Model,
ctx::Context,
options::NodeCreationOptions,
fform::F,
lhs_interface::Union{Tuple, NamedTuple},
rhs_interfaces::NamedTuple,
::StaticInt{N}
) where {F, N}
n = "\n"
error(
lazy"Node '$(fform)' cannot be called with $(length(lhs_interface)) output(s) on the left-hand side and $(length(rhs_interfaces)) interface(s) on the right-hand side, $(N) in total.$(n)$(n)The number of outputs on the left-hand side must be equal to the number of interfaces of '$(fform)' that are left unspecified on the right-hand side. Currently specified interfaces are: $(keys(rhs_interfaces)), but check the documentation to see the specification options."
)
end

"""
make_node!

Expand Down
28 changes: 27 additions & 1 deletion test/multi_and_zero_output_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,33 @@ end
(p, q) ~ two_iface_sub(x = x, b = b)
end

@test_throws "no method matching make_node!" create_model(main_mismatch()) do model, ctx
# Too many outputs on the LHS: only `a` is missing, but two are provided
@test_throws "cannot be called with 2 output(s) on the left-hand side" create_model(main_mismatch()) do model, ctx
x = datalabel(model, ctx, NodeCreationOptions(kind = :data), :x, 1.0)
return (x = x,)
end
@test_throws "must be equal to the number of interfaces" create_model(main_mismatch()) do model, ctx
x = datalabel(model, ctx, NodeCreationOptions(kind = :data), :x, 1.0)
return (x = x,)
end

# Too few outputs on the LHS: both `a` and `b` are missing, but only one is provided
@model function main_too_few(x)
(p,) ~ two_iface_sub(x = x)
end

@test_throws "cannot be called with 1 output(s) on the left-hand side" create_model(main_too_few()) do model, ctx
x = datalabel(model, ctx, NodeCreationOptions(kind = :data), :x, 1.0)
return (x = x,)
end

# The same applies to the named-output (NamedTuple LHS) form
@model function main_named_mismatch(x)
b ~ Normal(0, 1)
(a = p, b = q) ~ two_iface_sub(x = x, b = b)
end

@test_throws "cannot be called with 2 output(s) on the left-hand side" create_model(main_named_mismatch()) do model, ctx
x = datalabel(model, ctx, NodeCreationOptions(kind = :data), :x, 1.0)
return (x = x,)
end
Expand Down
Loading