Skip to content

Commit

Permalink
Let constant tuple indexers work with constants (#12012)
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite authored Apr 27, 2022
1 parent 8bf1ab7 commit 1656cb2
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 4 deletions.
10 changes: 10 additions & 0 deletions spec/compiler/semantic/tuple_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,16 @@ describe "Semantic: tuples" do
end
end

describe "#[](Path)" do
it "works for tuple indexer" do
assert_type("A = 0; {1, 'a'}[A]") { int32 }
end

it "works for named tuple indexer" do
assert_type("A = :a; {a: 1, b: 'a'}[A]") { int32 }
end
end

it "can name a tuple type" do
assert_type("Tuple(Int32, Float64)") { tuple_of([int32, float64]).metaclass }
end
Expand Down
28 changes: 24 additions & 4 deletions src/compiler/crystal/semantic/call.cr
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,22 @@ class Crystal::Call
end

def tuple_indexer_helper(args, arg_types, owner, instance_type, nilable)
index = tuple_indexer_helper_index(args.first, owner, instance_type, nilable)
return unless index

indexer_def = yield instance_type, index
indexer_match = Match.new(indexer_def, arg_types, MatchContext.new(owner, owner))
Matches.new([indexer_match] of Match, true)
end

private def tuple_indexer_helper_index(arg, owner, instance_type, nilable)
arg = args.first

# Make it work with constants too
while arg.is_a?(Path) && (target_const = arg.target_const)
arg = target_const.value
end

if arg.is_a?(NumberLiteral) && arg.kind.i32?
index = arg.value.to_i
index += instance_type.size if index < 0
Expand Down Expand Up @@ -547,13 +562,18 @@ class Crystal::Call
return nil
end

indexer_def = yield instance_type, index
indexer_match = Match.new(indexer_def, arg_types, MatchContext.new(owner, owner))
Matches.new([indexer_match] of Match, true)
index
end

def named_tuple_indexer_helper(args, arg_types, owner, instance_type, nilable)
case arg = args.first
arg = args.first

# Make it work with constants too
while arg.is_a?(Path) && (target_const = arg.target_const)
arg = target_const.value
end

case arg
when SymbolLiteral, StringLiteral
name = arg.value
index = instance_type.name_index(name)
Expand Down

0 comments on commit 1656cb2

Please sign in to comment.