]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile: refactor top-level typechecking in unified IR
authorMatthew Dempsky <mdempsky@google.com>
Thu, 1 Jul 2021 02:20:28 +0000 (19:20 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Thu, 1 Jul 2021 03:34:49 +0000 (03:34 +0000)
This CL is a first step towards incremental typechecking during IR
construction within unified IR. Namely, all top-level declarations are
now typechecked as they're constructed, except for assignments (which
aren't really declarations anyway).

Change-Id: I65763a7659bf2e0f5e89dfe9e709d60e0fa4c631
Reviewed-on: https://go-review.googlesource.com/c/go/+/332097
Trust: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
src/cmd/compile/internal/noder/reader.go
src/cmd/compile/internal/noder/unified.go

index 4b42ae1ec3818629ccea7cd16535686c5dce03ba..24977ed7f0e0a8b9cffd8723452433a77efde55d 100644 (file)
@@ -784,6 +784,8 @@ func (r *reader) funcExt(name *ir.Name) {
        fn.Pragma = r.pragmaFlag()
        r.linkname(name)
 
+       typecheck.Func(fn)
+
        if r.bool() {
                fn.ABI = obj.ABI(r.uint64())
 
@@ -2124,7 +2126,7 @@ func (r *reader) methodWrapper(derefs int, tbase *types.Type, method *types.Fiel
        // TODO(mdempsky): Use method.Pos instead?
        pos := base.AutogeneratedPos
 
-       fn := r.newWrapperFunc(pos, sym, wrapper, method, target)
+       fn := r.newWrapperFunc(pos, sym, wrapper, method)
 
        var recv ir.Node = fn.Nname.Type().Recv().Nname.(*ir.Name)
 
@@ -2143,6 +2145,8 @@ func (r *reader) methodWrapper(derefs int, tbase *types.Type, method *types.Fiel
        }
 
        addTailCall(pos, fn, recv, method)
+
+       r.finishWrapperFunc(fn, target)
 }
 
 func (r *reader) methodValueWrapper(tbase *types.Type, method *types.Field, target *ir.Package) {
@@ -2167,7 +2171,7 @@ func (r *reader) methodValueWrapper(tbase *types.Type, method *types.Field, targ
        // TODO(mdempsky): Use method.Pos instead?
        pos := base.AutogeneratedPos
 
-       fn := r.newWrapperFunc(pos, sym, nil, method, target)
+       fn := r.newWrapperFunc(pos, sym, nil, method)
        fn.SetNeedctxt(true)
        sym.Def = fn
 
@@ -2181,9 +2185,11 @@ func (r *reader) methodValueWrapper(tbase *types.Type, method *types.Field, targ
        fn.ClosureVars = append(fn.ClosureVars, recv)
 
        addTailCall(pos, fn, recv, method)
+
+       r.finishWrapperFunc(fn, target)
 }
 
-func (r *reader) newWrapperFunc(pos src.XPos, sym *types.Sym, wrapper *types.Type, method *types.Field, target *ir.Package) *ir.Func {
+func (r *reader) newWrapperFunc(pos src.XPos, sym *types.Sym, wrapper *types.Type, method *types.Field) *ir.Func {
        fn := ir.NewFunc(pos)
        fn.SetDupok(true) // TODO(mdempsky): Leave unset for local, non-generic wrappers?
 
@@ -2214,11 +2220,19 @@ func (r *reader) newWrapperFunc(pos src.XPos, sym *types.Sym, wrapper *types.Typ
        defParams(ir.PPARAM, sig.Params())
        defParams(ir.PPARAMOUT, sig.Results())
 
-       target.Decls = append(target.Decls, fn)
-
        return fn
 }
 
+func (r *reader) finishWrapperFunc(fn *ir.Func, target *ir.Package) {
+       typecheck.Func(fn)
+
+       ir.WithFunc(fn, func() {
+               typecheck.Stmts(fn.Body)
+       })
+
+       target.Decls = append(target.Decls, fn)
+}
+
 // newWrapperType returns a copy of the given signature type, but with
 // the receiver parameter type substituted with recvType.
 // If recvType is nil, newWrapperType returns a signature
index 8397f14be83afd5e3d43f35af6b93483828b37c3..03bcb2755b23a36a7f5876fb8d5d94e901a778f1 100644 (file)
@@ -109,6 +109,16 @@ func unified(noders []*noder) {
        r.ext = r
        r.pkgInit(types.LocalPkg, target)
 
+       // Type-check any top-level assignments. We ignore non-assignments
+       // here because other declarations are typechecked as they're
+       // constructed.
+       for i, ndecls := 0, len(target.Decls); i < ndecls; i++ {
+               switch n := target.Decls[i]; n.Op() {
+               case ir.OAS, ir.OAS2:
+                       target.Decls[i] = typecheck.Stmt(n)
+               }
+       }
+
        // Don't use range--bodyIdx can add closures to todoBodies.
        for len(todoBodies) > 0 {
                // The order we expand bodies doesn't matter, so pop from the end
@@ -122,22 +132,12 @@ func unified(noders []*noder) {
 
                // Instantiated generic function: add to Decls for typechecking
                // and compilation.
-               if pri.dict != nil && len(pri.dict.targs) != 0 && fn.OClosure == nil {
+               if fn.OClosure == nil && len(pri.dict.targs) != 0 {
                        target.Decls = append(target.Decls, fn)
                }
        }
        todoBodies = nil
 
-       if !quirksMode() {
-               // TODO(mdempsky): Investigate generating wrappers in quirks mode too.
-               r.wrapTypes(target)
-       }
-
-       // Don't use range--typecheck can add closures to Target.Decls.
-       for i := 0; i < len(target.Decls); i++ {
-               target.Decls[i] = typecheck.Stmt(target.Decls[i])
-       }
-
        // Don't use range--typecheck can add closures to Target.Decls.
        for i := 0; i < len(target.Decls); i++ {
                if fn, ok := target.Decls[i].(*ir.Func); ok {
@@ -145,8 +145,9 @@ func unified(noders []*noder) {
                                s := fmt.Sprintf("\nbefore typecheck %v", fn)
                                ir.Dump(s, fn)
                        }
-                       ir.CurFunc = fn
-                       typecheck.Stmts(fn.Body)
+                       ir.WithFunc(fn, func() {
+                               typecheck.Stmts(fn.Body)
+                       })
                        if base.Flag.W > 1 {
                                s := fmt.Sprintf("\nafter typecheck %v", fn)
                                ir.Dump(s, fn)
@@ -154,6 +155,26 @@ func unified(noders []*noder) {
                }
        }
 
+       if !quirksMode() {
+               // TODO(mdempsky): Investigate generating wrappers in quirks mode too.
+               r.wrapTypes(target)
+       }
+
+       // Check that nothing snuck past typechecking.
+       for _, n := range target.Decls {
+               if n.Typecheck() == 0 {
+                       base.FatalfAt(n.Pos(), "missed typecheck: %v", n)
+               }
+
+               // For functions, check that at least their first statement (if
+               // any) was typechecked too.
+               if fn, ok := n.(*ir.Func); ok && len(fn.Body) != 0 {
+                       if stmt := fn.Body[0]; stmt.Typecheck() == 0 {
+                               base.FatalfAt(stmt.Pos(), "missed typecheck: %v", stmt)
+                       }
+               }
+       }
+
        base.ExitIfErrors() // just in case
 }