require "../../spec_helper" describe "Semantic: named args" do it "errors if named arg not found" do assert_error <<-CRYSTAL, "no parameter named 'w'" def foo(x, y = 1, z = 2) end foo 1, w: 3 CRYSTAL end it "errors if named arg already specified" do assert_error <<-CRYSTAL, "argument for parameter 'x' already specified" def foo(x, y = 1, z = 2) end foo 1, x: 1 CRYSTAL end it "errors if named arg already specified, but multiple overloads (#7281)" do assert_error <<-CRYSTAL, "no overload matches" def foo(x : String, y = 1, z = 2) end def foo(x : Int32, y : Int32) end foo 1, x: 1 CRYSTAL end it "errors if named arg not found in new" do assert_error <<-CRYSTAL, "no parameter named 'w'" class Foo def initialize(x, y = 1, z = 2) end end Foo.new 1, w: 3 CRYSTAL end it "errors if named arg already specified" do assert_error <<-CRYSTAL, "argument for parameter 'x' already specified" class Foo def initialize(x, y = 1, z = 2) end end Foo.new 1, x: 1 CRYSTAL end it "errors if doesn't pass named arg restriction" do assert_error <<-CRYSTAL, "expected argument 'x' to 'foo' to be Int32, not Float64" def foo(x : Int32 = 1) end foo x: 1.5 CRYSTAL end it "errors if named arg already specified but in same position" do assert_error <<-CRYSTAL, "argument for parameter 'headers' already specified" def foo(headers = nil) end foo 1, headers: 2 CRYSTAL end it "sends one regular argument as named argument" do assert_type(<<-CRYSTAL) { int32 } def foo(x) x end foo x: 1 CRYSTAL end it "sends two regular arguments as named arguments" do assert_type(<<-CRYSTAL, inject_primitives: true) { int32 } def foo(x, y) x + y end foo x: 1, y: 2 CRYSTAL end it "sends two regular arguments as named arguments in inverted position (1)" do assert_type(<<-CRYSTAL) { string } def foo(x, y) x end foo y: 1, x: "foo" CRYSTAL end it "sends two regular arguments as named arguments in inverted position (2)" do assert_type(<<-CRYSTAL) { int32 } def foo(x, y) y end foo y: 1, x: "foo" CRYSTAL end it "errors if named arg matches single splat argument" do assert_error <<-CRYSTAL, "no parameter named 'x'" def foo(*y) end foo x: 1, y: 2 CRYSTAL end it "errors if named arg matches splat argument" do assert_error <<-CRYSTAL, "no overload matches" def foo(x, *y) end foo x: 1, y: 2 CRYSTAL end it "allows named arg if there's a splat" do assert_type(<<-CRYSTAL) { tuple_of([char, tuple_of([int32])]) } def foo(*y, x) { x, y } end foo 1, x: 'a' CRYSTAL end it "errors if missing one argument" do assert_error <<-CRYSTAL, "missing argument: z" def foo(x, y, z) end foo x: 1, y: 2 CRYSTAL end it "errors if missing two arguments" do assert_error <<-CRYSTAL, "missing arguments: x, z" def foo(x, y, z) end foo y: 2 CRYSTAL end it "doesn't include arguments with default values in missing arguments error" do assert_error <<-CRYSTAL, "missing argument: z" def foo(x, z, y = 1) end foo(x: 1) CRYSTAL end it "says no overload matches with named arg" do assert_error <<-CRYSTAL, "missing argument: y" def foo(x, y) end def foo(x, y, z) end foo(x: 2) CRYSTAL end it "gives correct error message for missing args after *" do assert_error <<-CRYSTAL, "missing arguments: x, y" def foo(*, x, y) end foo CRYSTAL end it "overloads based on required named args" do assert_type(<<-CRYSTAL) { tuple_of([int32, char]) } def foo(x, *, y) 1 end def foo(x, *, z) 'a' end a = foo(1, y: 2) b = foo(1, z: 2) {a, b} CRYSTAL end it "overloads based on required named args, with restrictions" do assert_type(<<-CRYSTAL) { tuple_of([int32, char]) } def foo(x, *, z : Int32) 1 end def foo(x, *, z : Float64) 'a' end a = foo(1, z: 1) b = foo(1, z: 1.5) {a, b} CRYSTAL end it "uses bare splat in new" do assert_type(<<-CRYSTAL) { types["Foo"] } class Foo def initialize(*, y = nil) end end Foo.new CRYSTAL end it "passes #2696" do assert_type(<<-CRYSTAL) { types["Bar"] } class Bar def bar yield self end end module Foo def self.foo(count = 5) Bar.new end end Foo.foo(count: 3).bar { } CRYSTAL end it "matches specific overload with named arguments (#2753)" do assert_type(<<-CRYSTAL, inject_primitives: true) { bool } def foo(x : Nil, y) foo 1, y true end def foo(x, y) x + 2 'a' end foo nil, y: 2 CRYSTAL end it "matches specific overload with named arguments (2) (#2753)" do assert_type(<<-CRYSTAL, inject_primitives: true) { bool } def foo(x : Nil, y, z) foo 1, y, z true end def foo(x, y, z) x + 2 'a' end foo nil, z: 1, y: 2 CRYSTAL end it "gives correct error message with external names (#3934)" do assert_error <<-CRYSTAL, "no overload matches" def foo(*, arg a : String) a end foo(arg: 10) CRYSTAL end it "says correct error when forwarding named args (#7491)" do assert_error <<-CRYSTAL, "no parameter named 'baz'" def bar(foo = false) end bar(**{foo: true, baz: true}) CRYSTAL end it "doesn't fail on named argument with NoReturn type (#7760)" do assert_type(<<-CRYSTAL) { no_return } lib LibC fun exit : NoReturn end def foo(x : Int32) 'a' end x = 1 LibC.exit if x.is_a?(Int32) foo(x: x) CRYSTAL end end