Repository navigation
Type-check pins when creating a link - #473
Merged
Merged
Conversation
TryCreateLink validated direction, duplicates, connection limits and self-links, but never compared the pins' declared types, so a string output fed an int input and the result reported Success. The graph then held a link whose value cannot survive the trip, and a host had nothing to surface. PinTypeUtilities.CanConnect already implements the compatibility rules and Pin already carries DataType, so the check is a use of both rather than a new policy. It sits with the direction check, ahead of the graph's own state, because an incompatible pair is refused on its own terms; the message names both types and both pin names so a host can say which end is wrong. Only a pair that both declare a type is checked. A null DataType is an untyped pin, which PinSpec documents as a supported way to describe one, and CanConnect answers false for a null rather than "unknown" - so asking it about an untyped pin would refuse every link that pin appears in, including every caller of the name-only CreateNode overloads. Four tests: the reported string-to-int case and execution flow into a data pin both fail without the change; a widening numeric conversion and an untyped pin are no-regression guards that pass either way, and are what a fix refusing all typed pairs would break. The check also caught two miswired links in CleanImNodesDemo, which fed a Make node's NumberData straight into Add's double parameters. They are routed through a Split now, so the demo graph is type-correct rather than silently unconnected. Fixes #472 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J9LhTGkoRSYpyGzriwfeZd
|
This was referenced Sep 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Fixes #472
The defect
NodeEditorEngine.TryCreateLinkvalidated direction, duplicates, connection limits and self-links, but never compared the pins'DataType. A string output connected to an int input and the result reportedSuccess, leaving the graph holding a link whose value cannot survive the trip — and leaving a host with nothing to surface, since the message said the link was created.The issue is accurate about the pieces already existing:
PinTypeUtilities.CanConnect(Type, Type)inktsu.NodeGraphimplements the rules (exact match, assignability, numeric conversion, string),Pinalready carriesType? DataType, andImGui.NodeEditoralready project-referencesNodeGraph. So this is a use of both rather than a new policy.The change
One check, placed with the direction check and ahead of the graph's own state, because an incompatible pair is refused on its own terms rather than because of what the graph currently holds:
The message names both types and both pin names, which is what the issue asks for — a host can say which end is wrong, not merely that the drag failed. Measured against the library's own nodes:
NodeEditorHistory.TryCreateLinkdelegates to this method, so the undo/redo path is covered without a second change.Only a pair that both declare a type is checked
This is the one judgement worth arguing, so the reasoning in full.
CanConnectanswers false for a null argument rather than "unknown".Pin.DataTypeisType?andPinSpec's own doc comment describes null as "an untyped pin" — a supported way to describe one, not a defect. So handing an untyped pin toCanConnectwould refuse every link that pin appears in: that is most of the existing test suite and every caller of the name-onlyCreateNodeoverloads, which is the entire untyped API.Hence the
is Typepattern on both ends. Untyped stays permissive; a declared pair is checked. A fix that skipped this reads as smaller and breaks 200+ call sites.Tests
Four, in
NodeEditorEngineTestsbeside the existingTryCreateLinkcases.TryCreateLink_RefusesPinsWhoseDeclaredTypesCannotConnectTryCreateLink_RefusesExecutionFlowIntoADataPinvoidexecution pin into a data input, whichCanConnectallows only against anothervoidTryCreateLink_ConnectsPinsWhoseDeclaredTypesAreCompatibleTryCreateLink_DoesNotTypeCheckAnUntypedPinDataTypereasoning above, one end declared and neither end declaredThe split matters: the last two pass in both configurations, which is correct for no-regression guards. They are what a fix refusing every typed pair, or one passing nulls straight to
CanConnect, would fail.Proved failing without the fix. Reverting only
ImGui.NodeEditor/NodeEditorEngine.csand keeping the tests:Both fail on the reported symptom — the link being created — not on a message that merely changed shape.
Verification
dotnet build ImGui.sln -c Release— succeeded, 0 warnings, 0 errors (this repo runs analyzers as errors)dotnet test tests/ImGui.NodeEditor.Tests -c Release— 266 total, 266 passed, 0 failed, 0 skippeddotnet test tests/NodeGraph.Tests -c Release— 106 total, 106 passed, 0 failedNodeEditorEngine.cs— 2 of 266 failed, as aboveBaseline on unmodified
mainwas 262 passed for the NodeEditor suite, so the 262 pre-existing tests are unaffected in both directions. Run on .NET SDK 10.0.401, Linux.The check caught two miswired demo links
Worth reading before reviewing the third file in the diff, because it is a behaviour change rather than a tidy-up.
CleanImNodesDemofedmakeNumber1/makeNumber2's output — aNumberDatastructure — straight intoMathOperations.Add(double a, double b). Those two links previously succeeded and now do not:They were wrong before this change; nothing reported it. Leaving them would ship a demo whose graph is silently missing two edges, so each operand is routed through a
Split(whoseValueoutput is adouble), which is the Make → Split → Operate pattern the surrounding comments already describe. That needed one addedSplitNumberNodeformakeNumber2's chain, sinceMakeNumberNodeexposes no scalar output.I verified the rest of the demo graph rather than assuming: the vector chain is unaffected, because
float→doubleanddouble→floatare both allowed numeric conversions, and everyVector2Dataedge is an exact match. The demo UI tests assert no link counts, and the full solution builds clean.Tagged
[minor]on the commit subject: a caller whose typed pins were incompatible got a link before and gets a refusal now.Not in this change
Nothing widens
CanConnectitself.typeof(object)outputs, whichAttributeBasedNodeFactoryproduces for an attribute-declared pin with no explicit type, are only assignable toobjectandstringunder the existing rules — so such a pin is now narrower than an untyped one. That asymmetry is pre-existing inCanConnectand is a policy question for the type system rather than for this wiring; nothing in the repository currently produces it on a connected pin.Type coercion at execution time is also untouched. This refuses the link; it does not convert a value that crosses a compatible-but-not-identical edge.
🤖 Generated with Claude Code
https://claude.ai/code/session_01J9LhTGkoRSYpyGzriwfeZd
Generated by Claude Code