M pkg/parser/parser.go => pkg/parser/parser.go +3 -0
@@ 807,6 807,9 @@ func (p *parser) parseInterfaceDecl() *ast.InterfaceDecl {
if fn.Ref.IsValid() {
p.error(fn.Pos(), "interface method cannot be marked as ref")
}
+ if fn.GenericParams != nil {
+ p.error(fn.Pos(), "interface method cannot have a generic clause (the interface itself can)")
+ }
if fn.Body != nil {
p.error(fn.Pos(), "interface method cannot have a body")
}
M pkg/parser/testdata/invalid_interface.snow => pkg/parser/testdata/invalid_interface.snow +2 -0
@@ 5,4 5,6 @@ interface I {
fn bar() {
foo()
}
+
+ fn quz[$T](t: $T)
}
M pkg/parser/testdata/invalid_interface.snow.err => pkg/parser/testdata/invalid_interface.snow.err +1 -0
@@ 1,2 1,3 @@
testdata/invalid_interface.snow:2:3: interface method cannot have attributes
testdata/invalid_interface.snow:5:3: interface method cannot have a body
+testdata/invalid_interface.snow:9:3: interface method cannot have a generic clause (the interface itself can)
M pkg/parser/testdata/invalid_interface.snow.want => pkg/parser/testdata/invalid_interface.snow.want +11 -2
@@ 1,5 1,5 @@
-file [1, #0] [0:80]
- interface [2] [0:80]
+file [1, #0] [0:101]
+ interface [3] [0:101]
ident [I] [10:11]
fn [16:50]
@ [2] [16:39]
@@ 19,3 19,12 @@ file [1, #0] [0:80]
expr [69:74]
call [0] [69:74]
ident [foo] [69:72]
+ fn [82:99]
+ ident [quz] [85:88]
+ generic [88:92]
+ param [89:91]
+ ident [$T] [89:91]
+ sig [1->0] [92:99]
+ param [93:98]
+ ident [t] [93:94]
+ ident [$T] [96:98]
A pkg/semantic/testdata/check/fn_generic_interface.snow.err => pkg/semantic/testdata/check/fn_generic_interface.snow.err +1 -0
@@ 0,0 1,1 @@
+testdata/fn_generic_interface.snow:23:14: cannot assign type struct G[bool] to variable of type interface I[int]
A pkg/semantic/testdata/check/fn_generic_interface.snow.want => pkg/semantic/testdata/check/fn_generic_interface.snow.want +82 -0
@@ 0,0 1,82 @@
+file testdata/fn_generic_interface.snow [0, 1, 2, 1]
+ fn main [let: () -> void]
+ block [10]
+ var:= ifaceInt [var: interface I[int]]
+ generic inst [1] [type: interface I[int]]
+ ident I [type: interface I]
+ ident int [type: int]
+ implicit conv [value: interface I[int]]
+ call [0] [value: struct S]
+ ident S [type: struct S]
+ var= res [var: int]
+ call [1] [value: int]
+ select [let: (int) -> int]
+ ident ifaceInt [var: interface I[int]]
+ ident foo [let: (int) -> int]
+ int [1] [const: int]
+ var: gInt [var: struct G[int]]
+ generic inst [1] [type: struct G[int]]
+ ident G [type: struct G]
+ ident int [type: int]
+ var= gres [var: int]
+ call [1] [value: int]
+ select [let: (int) -> int]
+ ident gInt [var: struct G[int]]
+ ident foo [let: (int) -> int]
+ int [1] [const: int]
+ assign
+ ident ifaceInt [var: interface I[int]]
+ implicit conv [value: interface I[int]]
+ call [0] [value: struct G[int]]
+ generic inst [1] [type: struct G[int]]
+ ident G [type: struct G]
+ ident int [type: int]
+ assign
+ ident res [var: int]
+ call [1] [value: int]
+ select [let: (int) -> int]
+ ident ifaceInt [var: interface I[int]]
+ ident foo [let: (int) -> int]
+ int [2] [const: int]
+ assign
+ ident ifaceInt [var: interface I[int]]
+ call [0] [value: struct G[bool]]
+ generic inst [1] [type: struct G[bool]]
+ ident G [type: struct G]
+ ident bool [type: bool]
+ var: ifaceString [var: interface I[string]]
+ generic inst [1] [type: interface I[string]]
+ ident I [type: interface I]
+ ident string [type: string]
+ assign
+ ident ifaceString [var: interface I[string]]
+ implicit conv [value: interface I[string]]
+ call [0] [value: struct G[string]]
+ generic inst [1] [type: struct G[string]]
+ ident G [type: struct G]
+ ident string [type: string]
+ expr
+ call [1] [value: string]
+ select [let: (string) -> string]
+ ident ifaceString [var: interface I[string]]
+ ident foo [let: (string) -> string]
+ string ["a"] [const: string]
+ struct S [0, 1, 0, 0] [type: struct S]
+ fn foo [let: (int) -> int]
+ let: i [let: int]
+ ident int [type: int]
+ ident int [type: int]
+ block [0]
+ struct G [0, 1, 0, 0, $1] [type: struct G]
+ generic type $T [type: $T]
+ fn foo [let: ($T) -> $T]
+ let: t [let: $T]
+ ident $T [type: $T]
+ ident $T [type: $T]
+ block [0]
+ interface I [1, $1] [type: interface I]
+ generic type $T [type: $T]
+ fn foo [let: ($T) -> $T]
+ let: t [let: $T]
+ ident $T [type: $T]
+ ident $T [type: $T]
A pkg/semantic/testdata/fn_generic_interface.snow => pkg/semantic/testdata/fn_generic_interface.snow +29 -0
@@ 0,0 1,29 @@
+interface I[$T] {
+ fn foo(t: $T) -> $T
+}
+
+struct S {
+ fn foo(i: int) -> int {}
+}
+
+struct G[$T] {
+ fn foo(t: $T) -> $T {}
+}
+
+fn main() {
+ var ifaceInt: I[int] = S()
+ var res = ifaceInt.foo(1)
+ var gInt: G[int]
+ var gres = gInt.foo(1)
+
+ ifaceInt = G[int]()
+ res = ifaceInt.foo(2)
+
+ # this should fail
+ ifaceInt = G[bool]()
+
+ # this should work
+ var ifaceString: I[string]
+ ifaceString = G[string]()
+ ifaceString.foo("a")
+}
A pkg/semantic/testdata/scopes/fn_generic_interface.snow.err => pkg/semantic/testdata/scopes/fn_generic_interface.snow.err +0 -0
A pkg/semantic/testdata/scopes/fn_generic_interface.snow.want => pkg/semantic/testdata/scopes/fn_generic_interface.snow.want +61 -0
@@ 0,0 1,61 @@
+1 *semantic.Unit {
+. bool
+. extern
+. f32
+. f64
+. false
+. float
+. i16
+. i32
+. i64
+. i8
+. int
+. string
+. true
+. u16
+. u32
+. u64
+. u8
+. uint
+. void
+. 2 *semantic.Struct {
+. . import
+. . pkg
+. . symbol
+. }
+. 3 *semantic.File {
+. . G
+. . I
+. . S
+. . main
+. . 4 *semantic.Interface {
+. . . $T
+. . . foo
+. . . 5 *semantic.Fn {
+. . . . t
+. . . }
+. . }
+. . 6 *semantic.Struct {
+. . . foo
+. . . 7 *semantic.Fn {
+. . . . i
+. . . . self
+. . . }
+. . }
+. . 8 *semantic.Struct {
+. . . $T
+. . . foo
+. . . 9 *semantic.Fn {
+. . . . self
+. . . . t
+. . . }
+. . }
+. . 10 *semantic.Fn {
+. . . gInt
+. . . gres
+. . . ifaceInt
+. . . ifaceString
+. . . res
+. . }
+. }
+}
A pkg/semantic/testdata/static/fn_generic_interface.snow.err => pkg/semantic/testdata/static/fn_generic_interface.snow.err +1 -0
@@ 0,0 1,1 @@
+testdata/fn_generic_interface.snow:23:14: cannot assign type struct G[bool] to variable of type interface I[int]
A pkg/semantic/testdata/static/fn_generic_interface.snow.want => pkg/semantic/testdata/static/fn_generic_interface.snow.want +15 -0
@@ 0,0 1,15 @@
+testdata/fn_generic_interface.snow:14:26: S
+testdata/fn_generic_interface.snow:15:13: ifaceInt
+testdata/fn_generic_interface.snow:15:22: foo
+testdata/fn_generic_interface.snow:17:14: gInt
+testdata/fn_generic_interface.snow:17:19: foo
+testdata/fn_generic_interface.snow:19:14: G
+testdata/fn_generic_interface.snow:19:16: int
+testdata/fn_generic_interface.snow:20:9: ifaceInt
+testdata/fn_generic_interface.snow:20:18: foo
+testdata/fn_generic_interface.snow:23:14: G
+testdata/fn_generic_interface.snow:23:16: bool
+testdata/fn_generic_interface.snow:27:17: G
+testdata/fn_generic_interface.snow:27:19: string
+testdata/fn_generic_interface.snow:28:3: ifaceString
+testdata/fn_generic_interface.snow:28:15: foo
A pkg/semantic/testdata/types/fn_generic_interface.snow.err => pkg/semantic/testdata/types/fn_generic_interface.snow.err +0 -0
A pkg/semantic/testdata/types/fn_generic_interface.snow.want => pkg/semantic/testdata/types/fn_generic_interface.snow.want +79 -0
@@ 0,0 1,79 @@
+file testdata/fn_generic_interface.snow [0, 1, 2, 1]
+ fn main [let: () -> void]
+ block [10]
+ var:= ifaceInt [var: interface I[int]]
+ generic inst [1] [type: interface I[int]]
+ ident I [type: interface I]
+ ident int [type: int]
+ call [0] [value: struct S]
+ ident S [type: struct S]
+ var= res [var: int]
+ call [1] [value: int]
+ select [let: (int) -> int]
+ ident ifaceInt [var: interface I[int]]
+ ident foo [let: (int) -> int]
+ int [1] [const: int]
+ var: gInt [var: struct G[int]]
+ generic inst [1] [type: struct G[int]]
+ ident G [type: struct G]
+ ident int [type: int]
+ var= gres [var: int]
+ call [1] [value: int]
+ select [let: (int) -> int]
+ ident gInt [var: struct G[int]]
+ ident foo [let: (int) -> int]
+ int [1] [const: int]
+ assign
+ ident ifaceInt [var: interface I[int]]
+ call [0] [value: struct G[int]]
+ generic inst [1] [type: struct G[int]]
+ ident G [type: struct G]
+ ident int [type: int]
+ assign
+ ident res [var: int]
+ call [1] [value: int]
+ select [let: (int) -> int]
+ ident ifaceInt [var: interface I[int]]
+ ident foo [let: (int) -> int]
+ int [2] [const: int]
+ assign
+ ident ifaceInt [var: interface I[int]]
+ call [0] [value: struct G[bool]]
+ generic inst [1] [type: struct G[bool]]
+ ident G [type: struct G]
+ ident bool [type: bool]
+ var: ifaceString [var: interface I[string]]
+ generic inst [1] [type: interface I[string]]
+ ident I [type: interface I]
+ ident string [type: string]
+ assign
+ ident ifaceString [var: interface I[string]]
+ call [0] [value: struct G[string]]
+ generic inst [1] [type: struct G[string]]
+ ident G [type: struct G]
+ ident string [type: string]
+ expr
+ call [1] [value: string]
+ select [let: (string) -> string]
+ ident ifaceString [var: interface I[string]]
+ ident foo [let: (string) -> string]
+ string ["a"] [const: string]
+ struct S [0, 1, 0, 0] [type: struct S]
+ fn foo [let: (int) -> int]
+ let: i [let: int]
+ ident int [type: int]
+ ident int [type: int]
+ block [0]
+ struct G [0, 1, 0, 0, $1] [type: struct G]
+ generic type $T [type: $T]
+ fn foo [let: ($T) -> $T]
+ let: t [let: $T]
+ ident $T [type: $T]
+ ident $T [type: $T]
+ block [0]
+ interface I [1, $1] [type: interface I]
+ generic type $T [type: $T]
+ fn foo [let: ($T) -> $T]
+ let: t [let: $T]
+ ident $T [type: $T]
+ ident $T [type: $T]