Skip to content

Commit 44ace21

Browse files
committed
Raise UnsupportedSyntax if a proc object is given as block-pass-argument
At present, users will see BlockTypeMismatch diagnostic when a proc object is passed as block-pass-argument. We'll usually see the diagnostic with `&method` idiom. ```ruby [1, 2, 3].map(&method(:puts)) ``` But there is nothing to do from the user side because such a call is not invalid. It seems like a false positive. This changes the diagnostic type for the case to UnsupportedSyntax. It notifies users that the source code is valid and that change is unnecessary. refs: #149
1 parent 8ebbb39 commit 44ace21

File tree

3 files changed

+153
-122
lines changed

3 files changed

+153
-122
lines changed

lib/steep/type_construction.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4190,6 +4190,16 @@ def try_method_type(node, receiver_type:, method_name:, method_overload:, argume
41904190
method_type: method_type
41914191
)
41924192
else
4193+
if node_type.is_a?(AST::Types::Name::Instance) && node_type.name.to_s == '::Proc'
4194+
errors << Diagnostic::Ruby::UnsupportedSyntax.new(
4195+
node: arg.node,
4196+
message: "Unsupported block-pass-argument given `#{node_type}`"
4197+
)
4198+
4199+
type = Interface::Function.new(params: nil, return_type: AST::Builtin.any_type, location: nil)
4200+
node_type = AST::Types::Proc.new(type: type, self_type: nil, block: nil)
4201+
end
4202+
41934203
# non-nil value is given
41944204
constr.check_relation(sub_type: node_type, super_type: arg.node_type, constraints: constraints).else do |result|
41954205
errors << Diagnostic::Ruby::BlockTypeMismatch.new(

smoke/block/test_expectations.yml

Lines changed: 120 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,131 @@
11
---
22
- file: a.rb
33
diagnostics:
4-
- range:
5-
start:
6-
line: 8
7-
character: 0
8-
end:
9-
line: 8
10-
character: 9
11-
severity: ERROR
12-
message: |-
13-
Cannot assign a value of type `::Integer` to a variable of type `::String`
14-
::Integer <: ::String
15-
::Numeric <: ::String
16-
::Object <: ::String
17-
::BasicObject <: ::String
18-
code: Ruby::IncompatibleAssignment
19-
- range:
20-
start:
21-
line: 10
22-
character: 0
23-
end:
24-
line: 10
25-
character: 17
26-
severity: ERROR
27-
message: |-
28-
Cannot assign a value of type `::String` to a variable of type `::Integer`
29-
::String <: ::Integer
30-
::Object <: ::Integer
31-
::BasicObject <: ::Integer
32-
code: Ruby::IncompatibleAssignment
33-
- file: b.rb
34-
diagnostics:
35-
- range:
36-
start:
37-
line: 5
38-
character: 2
39-
end:
40-
line: 5
41-
character: 9
42-
severity: ERROR
43-
message: |-
44-
Cannot break with a value of type `::Integer` because type `::Symbol` is assumed
45-
::Integer <: ::Symbol
46-
::Numeric <: ::Symbol
47-
::Object <: ::Symbol
48-
::BasicObject <: ::Symbol
49-
code: Ruby::BreakTypeMismatch
50-
- range:
51-
start:
52-
line: 10
53-
character: 0
54-
end:
55-
line: 13
56-
character: 3
57-
severity: ERROR
58-
message: |-
59-
Cannot assign a value of type `(::Integer | ::Symbol)` to a variable of type `::String`
60-
(::Integer | ::Symbol) <: ::String
4+
- range:
5+
start:
6+
line: 8
7+
character: 0
8+
end:
9+
line: 8
10+
character: 9
11+
severity: ERROR
12+
message: |-
13+
Cannot assign a value of type `::Integer` to a variable of type `::String`
6114
::Integer <: ::String
6215
::Numeric <: ::String
6316
::Object <: ::String
6417
::BasicObject <: ::String
65-
code: Ruby::IncompatibleAssignment
18+
code: Ruby::IncompatibleAssignment
19+
- range:
20+
start:
21+
line: 10
22+
character: 0
23+
end:
24+
line: 10
25+
character: 17
26+
severity: ERROR
27+
message: |-
28+
Cannot assign a value of type `::String` to a variable of type `::Integer`
29+
::String <: ::Integer
30+
::Object <: ::Integer
31+
::BasicObject <: ::Integer
32+
code: Ruby::IncompatibleAssignment
33+
- file: b.rb
34+
diagnostics:
35+
- range:
36+
start:
37+
line: 5
38+
character: 2
39+
end:
40+
line: 5
41+
character: 9
42+
severity: ERROR
43+
message: |-
44+
Cannot break with a value of type `::Integer` because type `::Symbol` is assumed
45+
::Integer <: ::Symbol
46+
::Numeric <: ::Symbol
47+
::Object <: ::Symbol
48+
::BasicObject <: ::Symbol
49+
code: Ruby::BreakTypeMismatch
50+
- range:
51+
start:
52+
line: 10
53+
character: 0
54+
end:
55+
line: 13
56+
character: 3
57+
severity: ERROR
58+
message: |-
59+
Cannot assign a value of type `(::Integer | ::Symbol)` to a variable of type `::String`
60+
(::Integer | ::Symbol) <: ::String
61+
::Integer <: ::String
62+
::Numeric <: ::String
63+
::Object <: ::String
64+
::BasicObject <: ::String
65+
code: Ruby::IncompatibleAssignment
6666
- file: d.rb
6767
diagnostics:
68-
- range:
69-
start:
70-
line: 6
71-
character: 0
72-
end:
73-
line: 6
74-
character: 19
75-
severity: ERROR
76-
message: |-
77-
Cannot assign a value of type `::Array[::String]` to a variable of type `::Array[::Float]`
78-
::Array[::String] <: ::Array[::Float]
79-
::String <: ::Float
80-
::Object <: ::Float
81-
::BasicObject <: ::Float
82-
code: Ruby::IncompatibleAssignment
83-
- range:
84-
start:
85-
line: 8
86-
character: 0
87-
end:
88-
line: 8
89-
character: 23
90-
severity: ERROR
91-
message: |-
92-
Cannot assign a value of type `::Array[::String]` to a variable of type `::Array[::Float]`
93-
::Array[::String] <: ::Array[::Float]
94-
::String <: ::Float
95-
::Object <: ::Float
96-
::BasicObject <: ::Float
97-
code: Ruby::IncompatibleAssignment
98-
- range:
99-
start:
100-
line: 10
101-
character: 12
102-
end:
103-
line: 10
104-
character: 28
105-
severity: ERROR
106-
message: |-
107-
Cannot pass a value of type `::Proc` as a block-pass-argument of type `^(::Integer) -> U(3)`
108-
::Proc <: ^(::Integer) -> U(3)
109-
code: Ruby::BlockTypeMismatch
110-
- range:
111-
start:
112-
line: 11
113-
character: 12
114-
end:
115-
line: 11
116-
character: 20
117-
severity: ERROR
118-
message: |-
119-
Cannot pass a value of type `::Proc` as a block-pass-argument of type `^(::Integer) -> U(4)`
120-
::Proc <: ^(::Integer) -> U(4)
121-
code: Ruby::BlockTypeMismatch
68+
- range:
69+
start:
70+
line: 6
71+
character: 0
72+
end:
73+
line: 6
74+
character: 19
75+
severity: ERROR
76+
message: |-
77+
Cannot assign a value of type `::Array[::String]` to a variable of type `::Array[::Float]`
78+
::Array[::String] <: ::Array[::Float]
79+
::String <: ::Float
80+
::Object <: ::Float
81+
::BasicObject <: ::Float
82+
code: Ruby::IncompatibleAssignment
83+
- range:
84+
start:
85+
line: 8
86+
character: 0
87+
end:
88+
line: 8
89+
character: 23
90+
severity: ERROR
91+
message: |-
92+
Cannot assign a value of type `::Array[::String]` to a variable of type `::Array[::Float]`
93+
::Array[::String] <: ::Array[::Float]
94+
::String <: ::Float
95+
::Object <: ::Float
96+
::BasicObject <: ::Float
97+
code: Ruby::IncompatibleAssignment
98+
- range:
99+
start:
100+
line: 10
101+
character: 12
102+
end:
103+
line: 10
104+
character: 28
105+
severity: ERROR
106+
message: |-
107+
Unsupported block-pass-argument given `::Proc`
108+
code: Ruby::UnsupportedSyntax
109+
- range:
110+
start:
111+
line: 11
112+
character: 12
113+
end:
114+
line: 11
115+
character: 20
116+
severity: ERROR
117+
message: |-
118+
Unsupported block-pass-argument given `::Proc`
119+
code: Ruby::UnsupportedSyntax
122120
- file: e.rb
123121
diagnostics:
124-
- range:
125-
start:
126-
line: 11
127-
character: 2
128-
end:
129-
line: 11
130-
character: 5
131-
severity: ERROR
132-
message: Type `(::Integer | ::String)` does not have method `foo`
133-
code: Ruby::NoMethod
122+
- range:
123+
start:
124+
line: 11
125+
character: 2
126+
end:
127+
line: 11
128+
character: 5
129+
severity: ERROR
130+
message: Type `(::Integer | ::String)` does not have method `foo`
131+
code: Ruby::NoMethod

test/type_construction_test.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7529,6 +7529,29 @@ def test_proc_with_block_annotation
75297529
end
75307530
end
75317531

7532+
def test_proc_for_block_pass_argument
7533+
with_checker() do |checker|
7534+
source = parse_ruby(<<-'RUBY')
7535+
# @type var f: Proc
7536+
f = _ = nil
7537+
r = [1, 2, 3].map(&f)
7538+
RUBY
7539+
7540+
with_standard_construction(checker, source) do |construction, typing|
7541+
type, _, context = construction.synthesize(source.node)
7542+
7543+
assert_typing_error(typing, size: 1) do |errors|
7544+
assert_any!(errors) do |error|
7545+
assert_instance_of Diagnostic::Ruby::UnsupportedSyntax, error
7546+
assert_equal "Unsupported block-pass-argument given `::Proc`", error.message
7547+
end
7548+
end
7549+
assert_equal parse_type("::Array[untyped]"), context.type_env[:r]
7550+
end
7551+
end
7552+
end
7553+
7554+
75327555
def test_next_with_next_type
75337556
with_checker(<<RBS) do |checker|
75347557
class NextTest

0 commit comments

Comments
 (0)