From 372b31273539b988fe887d7b7cc2ed14439278e6 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 30 Jun 2021 19:20:28 -0700 Subject: [PATCH] [dev.typeparams] cmd/compile: refactor top-level typechecking in unified IR 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 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/noder/reader.go | 24 +++++++++--- src/cmd/compile/internal/noder/unified.go | 47 ++++++++++++++++------- 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 4b42ae1ec3..24977ed7f0 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -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 diff --git a/src/cmd/compile/internal/noder/unified.go b/src/cmd/compile/internal/noder/unified.go index 8397f14be8..03bcb2755b 100644 --- a/src/cmd/compile/internal/noder/unified.go +++ b/src/cmd/compile/internal/noder/unified.go @@ -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 }