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 }