Skip to content

Propagate block return types to method return types#112

Closed
dak2 wants to merge 1 commit into
mainfrom
block-return-type-propagation
Closed

Propagate block return types to method return types#112
dak2 wants to merge 1 commit into
mainfrom
block-return-type-propagation

Conversation

@dak2
Copy link
Copy Markdown
Owner

@dak2 dak2 commented Apr 6, 2026

Motivation

Methods like map return generic types parameterized by block return values (e.g., [1,2].map { |x| x.to_s }Array[String]). Without this propagation, the type checker could not infer the element type of collections produced by block-yielding methods, causing false positives on subsequent method calls like .upcase.

Changes

  • Add BlockResult struct to return block body's last expression vertex from blocks.rs
  • Add BlockReturnTypeBox that observes block return type and substitutes type variables in method return types
  • Extend RbsTypeConverter::parse to handle generic types (e.g., Array[Elem], Hash[K, V])
  • Extract is_type_variable_name / is_block_type_variable_name as module-level functions and add resolve_return_type for shared type variable resolution
  • Remove unused SerializableMethodInfo::return_type() method (replaced by RbsTypeConverter::parse)

Checked

  • cargo test --lib passes
  • bundle exec rake test passes

🤖 Generated with Claude Code

@dak2 dak2 force-pushed the block-return-type-propagation branch from 8b77fcb to e1b6e44 Compare April 6, 2026 14:02
Methods like `map` return generic types parameterized by block return values
(e.g., `[1,2].map { |x| x.to_s }` → `Array[String]`). Without this, the
type checker could not infer the element type of collections produced by
block-yielding methods, causing false positives on subsequent method calls.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@dak2 dak2 force-pushed the block-return-type-propagation branch from e1b6e44 to d928289 Compare May 17, 2026 14:15
@dak2 dak2 requested a review from Copilot May 17, 2026 14:24
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves generic return inference for block-yielding methods so method results can reflect block body return types.

Changes:

  • Adds generic RBS type parsing and uses it when loading cached RBS method signatures.
  • Introduces BlockReturnTypeBox to substitute block return types into method return types.
  • Adds Ruby and Rust tests for generic parsing and block return propagation.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
test/range_test.rb Updates expected Range#to_a inference to resolved Array[Integer].
test/block_test.rb Adds coverage for map block return propagation and related cases.
core/src/rbs/converter.rs Adds parsing for generic RBS types and tests.
core/src/graph/mod.rs Re-exports BlockReturnTypeBox.
core/src/graph/box.rs Adds return type variable resolution and block return propagation box.
core/src/checker.rs Uses RbsTypeConverter::parse for cached return types.
core/src/cache/rbs_cache.rs Removes the old simple return type parser usage.
core/src/analyzer/dispatch.rs Wires block processing results into BlockReturnTypeBox.
core/src/analyzer/blocks.rs Returns block parameter vertices plus the block body’s last expression vertex.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread core/src/graph/box.rs
Comment on lines +497 to +505
for recv_ty in &recv_types {
let Some(info) = genv.resolve_method(recv_ty, &self.method_name) else {
continue;
};

// Reuse resolve_return_type with block_return_union to substitute
// both receiver type variables and block output type variables in one pass.
if let Some(resolved) =
resolve_return_type(&info.return_type, recv_ty, Some(&block_return_union))
Comment on lines +588 to +598
if let Some(body_vtx) = block_result.body_last_vtx {
let box_id = genv.alloc_box_id();
let ret_box = BlockReturnTypeBox::new(
box_id,
recv_vtx,
method_name,
body_vtx,
ret_vtx,
);
genv.register_box(box_id, Box::new(ret_box));
}
Comment thread core/src/graph/box.rs
type_args: resolved_args,
})
}
_ => Some(return_type.clone()),
Comment thread core/src/rbs/converter.rs
Comment on lines +56 to +59
let type_args: Vec<Type> = split_type_args(args_str)
.into_iter()
.map(Self::parse)
.collect();
@dak2 dak2 closed this May 17, 2026
@dak2 dak2 deleted the block-return-type-propagation branch May 17, 2026 14:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants