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]

Reply via email to