From fdf3496fccfd5c5593ac9e03804ffc8feeb59dbc Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Tue, 9 Feb 2021 15:13:19 -0800 Subject: [dev.typeparams] cmd/compile: make type conversions by type parameters work When doing a type conversion using a type param, delay the transformation to OCONV/OCONVNOP until stenciling, since the nodes created depend on the actual type. Re-enable the fact.go test. Change-Id: I3d5861aab3dd0e781d767f67435afaf951dfe451 Reviewed-on: https://go-review.googlesource.com/c/go/+/290752 Trust: Dan Scales Trust: Robert Griesemer Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/noder/helpers.go | 5 ++++ src/cmd/compile/internal/noder/stencil.go | 40 ++++++++++++++++++------------- 2 files changed, 28 insertions(+), 17 deletions(-) (limited to 'src/cmd/compile/internal/noder') diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go index 2bf125bdd8..4cb6bc3eab 100644 --- a/src/cmd/compile/internal/noder/helpers.go +++ b/src/cmd/compile/internal/noder/helpers.go @@ -84,6 +84,11 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool) if fun.Op() == ir.OTYPE { // Actually a type conversion, not a function call. n := ir.NewCallExpr(pos, ir.OCALL, fun, args) + if fun.Type().Kind() == types.TTYPEPARAM { + // For type params, don't typecheck until we actually know + // the type. + return typed(typ, n) + } return typecheck.Expr(n) } diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 64320237d9..2995496da1 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -174,30 +174,36 @@ func (subst *subster) node(n ir.Node) ir.Node { } ir.EditChildren(m, edit) - // A method value/call via a type param will have been left as an - // OXDOT. When we see this during stenciling, finish the - // typechecking, now that we have the instantiated receiver type. - // We need to do this now, since the access/selection to the - // method for the real type is very different from the selection - // for the type param. if x.Op() == ir.OXDOT { - // Will transform to an OCALLPART + // A method value/call via a type param will have been left as an + // OXDOT. When we see this during stenciling, finish the + // typechecking, now that we have the instantiated receiver type. + // We need to do this now, since the access/selection to the + // method for the real type is very different from the selection + // for the type param. m.SetTypecheck(0) + // m will transform to an OCALLPART typecheck.Expr(m) } if x.Op() == ir.OCALL { call := m.(*ir.CallExpr) - if call.X.Op() != ir.OCALLPART { - base.FatalfAt(call.Pos(), "Expecting OXDOT with CALL") + if call.X.Op() == ir.OTYPE { + // Do typechecking on a conversion, now that we + // know the type argument. + m.SetTypecheck(0) + m = typecheck.Expr(m) + } else if call.X.Op() == ir.OCALLPART { + // Redo the typechecking, now that we know the method + // value is being called. + call.X.(*ir.SelectorExpr).SetOp(ir.OXDOT) + call.X.SetTypecheck(0) + call.X.SetType(nil) + typecheck.Callee(call.X) + m.SetTypecheck(0) + typecheck.Call(m.(*ir.CallExpr)) + } else { + base.FatalfAt(call.Pos(), "Expecting OCALLPART or OTYPE with CALL") } - // Redo the typechecking, now that we know the method - // value is being called - call.X.(*ir.SelectorExpr).SetOp(ir.OXDOT) - call.X.SetTypecheck(0) - call.X.SetType(nil) - typecheck.Callee(call.X) - m.SetTypecheck(0) - typecheck.Call(m.(*ir.CallExpr)) } if x.Op() == ir.OCLOSURE { -- cgit v1.3