parent
8afdb1c3ef
commit
b6058bfd6e
|
@ -1069,13 +1069,6 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
||||||
left_type := c.expr(node.left)
|
left_type := c.expr(node.left)
|
||||||
c.expected_type = left_type
|
c.expected_type = left_type
|
||||||
mut is_generic := left_type.has_flag(.generic)
|
mut is_generic := left_type.has_flag(.generic)
|
||||||
// x is Bar<T>, x.foo() -> x.foo<T>()
|
|
||||||
if is_generic && node.concrete_types.len == 0 {
|
|
||||||
rec_sym := c.table.sym(left_type)
|
|
||||||
if rec_sym.info is ast.Struct {
|
|
||||||
node.concrete_types = rec_sym.info.generic_types
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node.left_type = left_type
|
node.left_type = left_type
|
||||||
// Set default values for .return_type & .receiver_type too,
|
// Set default values for .return_type & .receiver_type too,
|
||||||
// or there will be hard tRo diagnose 0 type panics in cgen.
|
// or there will be hard tRo diagnose 0 type panics in cgen.
|
||||||
|
@ -1113,19 +1106,6 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
||||||
// c.error('`void` type has no methods', node.left.pos())
|
// c.error('`void` type has no methods', node.left.pos())
|
||||||
return ast.void_type
|
return ast.void_type
|
||||||
}
|
}
|
||||||
mut concrete_types := []ast.Type{}
|
|
||||||
for concrete_type in node.concrete_types {
|
|
||||||
if concrete_type.has_flag(.generic) {
|
|
||||||
concrete_types << c.unwrap_generic(concrete_type)
|
|
||||||
} else {
|
|
||||||
concrete_types << concrete_type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if concrete_types.len > 0 {
|
|
||||||
if c.table.register_fn_concrete_types(node.fkey(), concrete_types) {
|
|
||||||
c.need_recheck_generic_fns = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: remove this for actual methods, use only for compiler magic
|
// TODO: remove this for actual methods, use only for compiler magic
|
||||||
// FIXME: Argument count != 1 will break these
|
// FIXME: Argument count != 1 will break these
|
||||||
if left_sym.kind == .array && method_name in array_builtin_methods {
|
if left_sym.kind == .array && method_name in array_builtin_methods {
|
||||||
|
@ -1239,6 +1219,33 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if has_method {
|
if has_method {
|
||||||
|
// x is Bar<T>, x.foo() -> x.foo<T>()
|
||||||
|
rec_sym := c.table.sym(node.left_type)
|
||||||
|
rec_is_generic := left_type.has_flag(.generic)
|
||||||
|
if rec_sym.info is ast.Struct {
|
||||||
|
if rec_is_generic && node.concrete_types.len == 0 {
|
||||||
|
node.concrete_types = rec_sym.info.generic_types
|
||||||
|
} else if !rec_is_generic && rec_sym.info.concrete_types.len > 0
|
||||||
|
&& node.concrete_types.len > 0
|
||||||
|
&& rec_sym.info.concrete_types.len + node.concrete_types.len == method.generic_names.len {
|
||||||
|
t_concrete_types := node.concrete_types.clone()
|
||||||
|
node.concrete_types = rec_sym.info.concrete_types
|
||||||
|
node.concrete_types << t_concrete_types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mut concrete_types := []ast.Type{}
|
||||||
|
for concrete_type in node.concrete_types {
|
||||||
|
if concrete_type.has_flag(.generic) {
|
||||||
|
concrete_types << c.unwrap_generic(concrete_type)
|
||||||
|
} else {
|
||||||
|
concrete_types << concrete_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if concrete_types.len > 0 {
|
||||||
|
if c.table.register_fn_concrete_types(node.fkey(), concrete_types) {
|
||||||
|
c.need_recheck_generic_fns = true
|
||||||
|
}
|
||||||
|
}
|
||||||
node.is_noreturn = method.is_noreturn
|
node.is_noreturn = method.is_noreturn
|
||||||
node.is_ctor_new = method.is_ctor_new
|
node.is_ctor_new = method.is_ctor_new
|
||||||
if !method.is_pub && !c.pref.is_test && method.mod != c.mod {
|
if !method.is_pub && !c.pref.is_test && method.mod != c.mod {
|
||||||
|
|
|
@ -352,8 +352,9 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||||
if is_method && rec.typ.has_flag(.generic) {
|
if is_method && rec.typ.has_flag(.generic) {
|
||||||
sym := p.table.sym(rec.typ)
|
sym := p.table.sym(rec.typ)
|
||||||
if sym.info is ast.Struct {
|
if sym.info is ast.Struct {
|
||||||
rec_generic_names := sym.info.generic_types.map(p.table.sym(it).name)
|
fn_generic_names := generic_names.clone()
|
||||||
for gname in rec_generic_names {
|
generic_names = sym.info.generic_types.map(p.table.sym(it).name)
|
||||||
|
for gname in fn_generic_names {
|
||||||
if gname !in generic_names {
|
if gname !in generic_names {
|
||||||
generic_names << gname
|
generic_names << gname
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
struct Outer<T> {
|
||||||
|
mut:
|
||||||
|
inner Inner<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Inner<T> {
|
||||||
|
val T
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut i Inner<T>) next<S>(input S) f64 {
|
||||||
|
$if S is f32 {
|
||||||
|
return 32
|
||||||
|
} $else {
|
||||||
|
panic('"$S.name" is not supported')
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_generics_method_on_nested_struct() {
|
||||||
|
mut outer := Outer<f64>{
|
||||||
|
inner: Inner<f64>{
|
||||||
|
val: 1.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r1 := outer.inner.next<f32>(99.0)
|
||||||
|
println(r1)
|
||||||
|
assert r1 == 32.0
|
||||||
|
|
||||||
|
r2 := outer.inner.next<f64, f32>(99.0)
|
||||||
|
println(r2)
|
||||||
|
assert r2 == 32.0
|
||||||
|
|
||||||
|
r3 := outer.inner.next(f32(99.0))
|
||||||
|
println(r3)
|
||||||
|
assert r3 == 32.0
|
||||||
|
}
|
Loading…
Reference in New Issue