oracle/graal · error · RuleParseError

Captured node "%s" has differing types

Error message

Captured node "%s" has differing types

What it means

Thrown by RuleParser.parseType when the same captured name (lowercase identifier after '=') is bound to two different node types within one rule. Captured names are how a @MatchRule communicates matched nodes to the generated method parameters, so one name must consistently denote one type; reusing it for a different node type is rejected.

Source

Thrown at compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/core/match/processor/MatchProcessor.java:209

                    next();
                    name = next();
                }
                originatingElements.addAll(type.originatingElements);
            } else if (Character.isLowerCase(peek("name").charAt(0))) {
                name = next();
                type = valueType;
            } else {
                throw new RuleParseError("Unexpected token \"%s\" when looking for name or node type", peek(null));
            }
            requiredPackages.add(type.nodePackage);
            if (name != null) {
                if (!capturedNames.contains(name)) {
                    capturedNames.add(name);
                    capturedTypes.add(type);
                } else {
                    int index = capturedNames.indexOf(name);
                    if (capturedTypes.get(index) != type) {
                        throw new RuleParseError("Captured node \"%s\" has differing types", name);
                    }
                }
            }
            return new MatchDescriptor(type, name, forExpression);
        }

        List<String> generateVariants() {
            return matchDescriptor.generateVariants();
        }

        /**
         * Recursively accumulate any required Position declarations.
         */
        void generatePositionDeclarations(Set<String> declarations) {
            matchDescriptor.generatePositionDeclarations(declarations);
        }

        /**

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Rename one of the captures so each name maps to exactly one node type (x = a, x = b).
  2. If both captures genuinely refer to the same node position, bind the name once and reuse it only for the identical type.
  3. Adopt unique, descriptive capture names per rule to avoid collisions.

Example fix

// before
@MatchRule("Add(x = v, Mul(x = w))")

// after
@MatchRule("Add(x = v, Mul(y = w))")
Defensive patterns

Strategy: try-catch

Try / catch

Compile-time only; the diagnostic names the conflicting capture. No runtime handling possible.

Prevention

When it happens

Trigger: A rule like "Add(x = value, Mul(x = other))" where 'x' binds first to an Add input type and then to a Mul type differing by reference equality (capturedTypes.get(index) != type). Note the check is exact TypeDescriptor identity, not name compatibility.

Common situations: Copy-pasting a sub-pattern and forgetting to rename its capture; rules grown organically where 'x'/'y' get reused; introducing a new sub-match that accidentally reuses an existing short name with a different node type.

Related errors


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/f2fa68c4d5dc4ed5. Report an issue: GitHub.