From 1656cb2a1f1688a322142c3798f1c33d8a9b6e17 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Wed, 27 Apr 2022 15:41:21 -0500 Subject: [PATCH] Let constant tuple indexers work with constants (#12012) --- spec/compiler/semantic/tuple_spec.cr | 10 ++++++++++ src/compiler/crystal/semantic/call.cr | 28 +++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/spec/compiler/semantic/tuple_spec.cr b/spec/compiler/semantic/tuple_spec.cr index 20e46c9e1537..0c04053fd936 100644 --- a/spec/compiler/semantic/tuple_spec.cr +++ b/spec/compiler/semantic/tuple_spec.cr @@ -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 diff --git a/src/compiler/crystal/semantic/call.cr b/src/compiler/crystal/semantic/call.cr index a5f74f22c17d..e376eccb2dca 100644 --- a/src/compiler/crystal/semantic/call.cr +++ b/src/compiler/crystal/semantic/call.cr @@ -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 @@ -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)