This is an automated email from the ASF dual-hosted git repository.
chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory.git
The following commit(s) were added to refs/heads/main by this push:
new f5d72ab0e fix(compiler): allow qualified nested types in FDL rpc
signatures (#3518)
f5d72ab0e is described below
commit f5d72ab0e6392d11b36bb9da4a97301b15fad09a
Author: 邓伟键 <[email protected]>
AuthorDate: Fri Mar 27 10:51:26 2026 +0800
fix(compiler): allow qualified nested types in FDL rpc signatures (#3518)
## Why?
FDL already supports qualified nested names like `Outer.Inner` in the
normal type system, and schema validation can resolve those names.
However, FDL service RPC parsing still only accepts a simple identifier
in request/response type positions.
That makes the FDL service parser inconsistent with:
- the rest of the FDL type system
- the existing protobuf service parser
- the existing FlatBuffers service parser
## What does this PR do?
- allows FDL RPC request/response types to parse a named type reference
such as `Request` or `Outer.Inner`
- adds a regression test for qualified request/response type names in
service parsing
- keeps the existing validator test for simple known types and adds a
separate validator test for qualified known types
This change is intentionally small and limited to the FDL service parser
path and its direct tests.
## Related issues
- [Open #<3517>](https://github.com/apache/fory/issues/3517)
## AI Contribution Checklist
- [x] Substantial AI assistance was used in this PR: `yes`
- [x] If `yes`, I included a completed [AI Contribution
Checklist](https://github.com/apache/fory/blob/main/AI_POLICY.md#9-contributor-checklist-for-ai-assisted-prs)
in this PR description and the required `AI Usage Disclosure`.
- [x] If `yes`, I can explain and defend all important changes without
AI help.
- [x] If `yes`, I reviewed AI-assisted code changes line by line before
submission.
- [x] If `yes`, I ran adequate human verification and recorded evidence.
- [x] If `yes`, I added or updated tests and docs where required.
- [x] If `yes`, I validated protocol or performance impacts with
evidence when applicable.
- [x] If `yes`, I verified licensing and provenance compliance.
AI Usage Disclosure
- substantial_ai_assistance: yes
- scope: limited assistance for a small parser/test change and PR
wording after manual reproduction and verification
- affected_files_or_subsystems: FDL parser, compiler service tests
- human_verification:
- reviewed all changes line by line
- from `/home/dwj/Project/apache-fory-prA/compiler` ran:
- `PYTHONPATH=/home/dwj/Project/apache-fory-prA/compiler
/home/dwj/miniconda3/bin/python3 -m pytest
fory_compiler/tests/test_fdl_service.py -q` -> `14 passed`
- `PYTHONPATH=/home/dwj/Project/apache-fory-prA/compiler
/home/dwj/miniconda3/bin/python3 -m pytest
fory_compiler/tests/test_proto_service.py -q` -> `5 passed`
- `PYTHONPATH=/home/dwj/Project/apache-fory-prA/compiler
/home/dwj/miniconda3/bin/python3 -m pytest
fory_compiler/tests/test_fbs_service.py -q` -> `5 passed`
- performance_verification: N/A
- provenance_license_confirmation: Apache-2.0-compatible provenance
confirmed; no incompatible third-party code introduced
## Does this PR introduce any user-facing change?
This introduces a small compiler-frontend behavior change: FDL service
RPC request/response type positions now accept qualified nested names
such as `Outer.Inner`.
- [ ] Does this PR introduce any public API change?
- [ ] Does this PR introduce any binary protocol compatibility change?
---
compiler/fory_compiler/frontend/fdl/parser.py | 24 +++++++++----
compiler/fory_compiler/tests/test_fdl_service.py | 44 ++++++++++++++++++++++++
2 files changed, 61 insertions(+), 7 deletions(-)
diff --git a/compiler/fory_compiler/frontend/fdl/parser.py
b/compiler/fory_compiler/frontend/fdl/parser.py
index 56b8285c7..00f0a8243 100644
--- a/compiler/fory_compiler/frontend/fdl/parser.py
+++ b/compiler/fory_compiler/frontend/fdl/parser.py
@@ -890,10 +890,7 @@ class Parser:
self.advance()
client_streaming = True
- req_type_token = self.consume(TokenType.IDENT, "Expected request
message type")
- request_type = NamedType(
- name=req_type_token.value,
location=self.make_location(req_type_token)
- )
+ request_type = self.parse_named_type_reference("Expected request
message type")
self.consume(TokenType.RPAREN, "Expected ')' after request type")
# Parse return type
@@ -904,9 +901,8 @@ class Parser:
self.advance()
server_streaming = True
- res_type_token = self.consume(TokenType.IDENT, "Expected response
message type")
- response_type = NamedType(
- name=res_type_token.value,
location=self.make_location(res_type_token)
+ response_type = self.parse_named_type_reference(
+ "Expected response message type"
)
self.consume(TokenType.RPAREN, "Expected ')' after response type")
@@ -945,6 +941,20 @@ class Parser:
location=self.make_location(start),
)
+ def parse_named_type_reference(self, message: str) -> NamedType:
+ """Parse a named type reference such as Request or Outer.Inner."""
+ type_token = self.consume(TokenType.IDENT, message)
+ type_name = type_token.value
+
+ while self.check(TokenType.DOT):
+ self.advance()
+ type_name += (
+ "."
+ + self.consume(TokenType.IDENT, "Expected identifier after
'.'").value
+ )
+
+ return NamedType(name=type_name,
location=self.make_location(type_token))
+
def parse_type_options(
self, type_name: str, known_options: Set[str], allow_zero_id: bool =
False
) -> dict:
diff --git a/compiler/fory_compiler/tests/test_fdl_service.py
b/compiler/fory_compiler/tests/test_fdl_service.py
index 78bf889b0..c84092311 100644
--- a/compiler/fory_compiler/tests/test_fdl_service.py
+++ b/compiler/fory_compiler/tests/test_fdl_service.py
@@ -67,6 +67,29 @@ def test_unary_rpc():
assert not method.server_streaming
+def test_rpc_with_qualified_request_and_response_types():
+ source = """
+ package test;
+
+ message Outer {
+ message HelloRequest {}
+ }
+
+ message ReplyEnvelope {
+ message HelloReply {}
+ }
+
+ service Greeter {
+ rpc SayHello (Outer.HelloRequest) returns (ReplyEnvelope.HelloReply);
+ }
+ """
+ schema = parse(source)
+ service = schema.services[0]
+ method = service.methods[0]
+ assert method.request_type.name == "Outer.HelloRequest"
+ assert method.response_type.name == "ReplyEnvelope.HelloReply"
+
+
def test_client_streaming_rpc():
source = """
package test;
@@ -232,3 +255,24 @@ def test_service_known_types_pass_validation():
schema = parse(source)
validator = SchemaValidator(schema)
assert validator.validate()
+
+
+def test_service_qualified_known_types_pass_validation():
+ source = """
+ package test;
+
+ message Outer {
+ message HelloRequest {}
+ }
+
+ message ReplyEnvelope {
+ message HelloReply {}
+ }
+
+ service Greeter {
+ rpc SayHello (Outer.HelloRequest) returns (ReplyEnvelope.HelloReply);
+ }
+ """
+ schema = parse(source)
+ validator = SchemaValidator(schema)
+ assert validator.validate()
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]