@@ 0,0 1,23 @@
+interface I {
+ fn foo()
+}
+
+struct S {
+ var i: int
+ ref fn foo() {
+ i = i + 1
+ }
+}
+
+fn main() {
+ let s = S(i: 0)
+ # this shouldn't even work as s is immutable, can't get its ref method
+ let iface: I = s
+ iface.foo()
+ println(s.i)
+}
+
+@extern(import: "fmt", symbol: "Println")
+fn println(v: int)
+
+#=1
@@ 396,6 396,12 @@ type Ident struct {
// type.
type ImplicitConv struct {
Value Expr
+ // MethodMapping is set when the ImplicitConv targets an interface. It maps
+ // the methods of the target interface as keys to the methods of the Value
+ // expression (which has necessarily either a *StructType or an *InterfaceType
+ // at the moment) as values.
+ MethodMapping map[*Fn]*Fn
+
commonExpr
}
@@ 189,7 189,7 @@ func (t *typecheckVisitor) Visit(n Node) Visitor {
return nil
}
if !T.IdenticalTo(n.Type()) {
- n.Value = createImplicitConv(n.Value, n.Type())
+ n.Value = t.createImplicitConv(n.Value, n.Type())
}
}
var T Type
@@ 262,7 262,7 @@ func (t *typecheckVisitor) Visit(n Node) Visitor {
}
// insert implicit conversion if required
if !valt.IdenticalTo(retType) {
- n.Value = createImplicitConv(n.Value, retType)
+ n.Value = t.createImplicitConv(n.Value, retType)
}
return nil
}
@@ 297,7 297,7 @@ func (t *typecheckVisitor) Visit(n Node) Visitor {
}
// insert implicit conversion if required
if !rt.IdenticalTo(lt) {
- n.Right = createImplicitConv(n.Right, lt)
+ n.Right = t.createImplicitConv(n.Right, lt)
}
case *ExprStmt:
@@ 373,9 373,9 @@ func (t *typecheckVisitor) Visit(n Node) Visitor {
// converted operand is always the smaller one
lsz, rsz := basicKindSizes[lt.Kind], basicKindSizes[rt.Kind]
if lsz < rsz {
- n.Left = createImplicitConv(n.Left, rt)
+ n.Left = t.createImplicitConv(n.Left, rt)
} else if rsz < lsz {
- n.Right = createImplicitConv(n.Right, lt)
+ n.Right = t.createImplicitConv(n.Right, lt)
}
case *Unary:
@@ 654,7 654,7 @@ func (t *typecheckVisitor) typecheckStructInit(n *Call) {
}
// insert implicit conversion if required
if !argt.IdenticalTo(typ) {
- n.Args[i] = createImplicitConv(arg, typ)
+ n.Args[i] = t.createImplicitConv(arg, typ)
}
}
@@ 734,7 734,7 @@ func (t *typecheckVisitor) typecheckFnCall(n *Call) {
}
// insert implicit conversion if required
if !argt.IdenticalTo(st.Params[i]) {
- n.Args[i] = createImplicitConv(arg, st.Params[i])
+ n.Args[i] = t.createImplicitConv(arg, st.Params[i])
}
}
@@ 780,12 780,24 @@ func asIdentDeclRef(expr Expr) Decl {
return ref
}
-func createImplicitConv(expr Expr, toType Type) *ImplicitConv {
+func (t *typecheckVisitor) createImplicitConv(expr Expr, toType Type) *ImplicitConv {
+ // TODO: store the mapping of methods when converting to an interface type
+ // TODO: this might be a good place too to typecheck e.g. that expr has the right
+ // type context to access a ref method.
+ // TODO: maybe have `mightBeSatisfiedBy` when checking AssignableTo, and then here
+ // use the more thorough isSatisfiedBy, which builds the method mapping, and then here
+ // we can check with the type context if it is ok.
+ var ms map[*Fn]*Fn
+ if it := AsInterfaceType(toType); it != nil {
+ ms = make(map[*Fn]*Fn, len(it.Decl.Methods))
+ }
+
var ic ImplicitConv
ic.pos = expr.Pos()
ic.scope = expr.Scope()
ic.Value = expr
ic.typ = toType
ic.ctx = Value
+ ic.MethodMapping = ms
return &ic
}