aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/typecheck/typecheck.go
diff options
context:
space:
mode:
authorMatthew Dempsky <mdempsky@google.com>2020-12-31 21:48:27 -0800
committerMatthew Dempsky <mdempsky@google.com>2021-01-01 10:52:19 +0000
commit0f1d2129c4c294a895480b79eeab8d22c07ac573 (patch)
treec17b8efff81852a140d69a8da18dd62e51641918 /src/cmd/compile/internal/typecheck/typecheck.go
parentb8fd3440cd3973a16184c4c878b557cf6c6703e4 (diff)
downloadgo-0f1d2129c4c294a895480b79eeab8d22c07ac573.tar.gz
go-0f1d2129c4c294a895480b79eeab8d22c07ac573.zip
[dev.regabi] cmd/compile: reshuffle type-checking code [generated]
This commit splits up typecheck.Package and moves the code elsewhere. The type-checking code is moved into noder, so that it can eventually be interleaved with the noding process. The non-type-checking code is moved back into package gc, so that it can be incorporated into appropriate compiler backend phases. While here, deadcode removal is moved into its own package. Passes toolstash -cmp. [git-generate] cd src/cmd/compile/internal/typecheck : Split into two functions. sed -i -e '/Phase 6/i}\n\nfunc postTypecheck() {' typecheck.go rf ' # Export needed identifiers. mv deadcode Deadcode mv loadsys InitRuntime mv declareUniverse DeclareUniverse mv dirtyAddrtaken DirtyAddrtaken mv computeAddrtaken ComputeAddrtaken mv incrementalAddrtaken IncrementalAddrtaken # Move into new package. mv Deadcode deadcodeslice deadcodeexpr deadcode.go mv deadcode.go cmd/compile/internal/deadcode # Move top-level type-checking code into noder. # Move DeclVars there too, now that nothing else uses it. mv DeclVars Package noder.go mv noder.go cmd/compile/internal/noder # Move non-type-checking code back into gc. mv postTypecheck main.go mv main.go cmd/compile/internal/gc ' cd ../deadcode rf ' # Destutter names. mv Deadcode Func mv deadcodeslice stmts mv deadcodeexpr expr ' cd ../noder rf ' # Move functions up, next to their related code. mv noder.go:/func Package/-1,$ \ noder.go:/makeSrcPosBase translates/-1 mv noder.go:/func DeclVars/-3,$ \ noder.go:/constState tracks/-1 ' cd ../gc rf ' # Inline postTypecheck code back into gc.Main. mv main.go:/func postTypecheck/+0,/AllImportedBodies/+1 \ main.go:/Build init task/-1 rm postTypecheck ' Change-Id: Ie5e992ece4a42204cce6aa98dd6eb52112d098c8 Reviewed-on: https://go-review.googlesource.com/c/go/+/280974 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>
Diffstat (limited to 'src/cmd/compile/internal/typecheck/typecheck.go')
-rw-r--r--src/cmd/compile/internal/typecheck/typecheck.go243
1 files changed, 1 insertions, 242 deletions
diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go
index 4b5c3198ca..4c6ac21fc6 100644
--- a/src/cmd/compile/internal/typecheck/typecheck.go
+++ b/src/cmd/compile/internal/typecheck/typecheck.go
@@ -35,110 +35,7 @@ func Init() {
initUniverse()
DeclContext = ir.PEXTERN
base.Timer.Start("fe", "loadsys")
- loadsys()
-}
-
-func Package() {
- declareUniverse()
-
- TypecheckAllowed = true
-
- // Process top-level declarations in phases.
-
- // Phase 1: const, type, and names and types of funcs.
- // This will gather all the information about types
- // and methods but doesn't depend on any of it.
- //
- // We also defer type alias declarations until phase 2
- // to avoid cycles like #18640.
- // TODO(gri) Remove this again once we have a fix for #25838.
-
- // Don't use range--typecheck can add closures to Target.Decls.
- base.Timer.Start("fe", "typecheck", "top1")
- for i := 0; i < len(Target.Decls); i++ {
- n := Target.Decls[i]
- if op := n.Op(); op != ir.ODCL && op != ir.OAS && op != ir.OAS2 && (op != ir.ODCLTYPE || !n.(*ir.Decl).X.Alias()) {
- Target.Decls[i] = Stmt(n)
- }
- }
-
- // Phase 2: Variable assignments.
- // To check interface assignments, depends on phase 1.
-
- // Don't use range--typecheck can add closures to Target.Decls.
- base.Timer.Start("fe", "typecheck", "top2")
- for i := 0; i < len(Target.Decls); i++ {
- n := Target.Decls[i]
- if op := n.Op(); op == ir.ODCL || op == ir.OAS || op == ir.OAS2 || op == ir.ODCLTYPE && n.(*ir.Decl).X.Alias() {
- Target.Decls[i] = Stmt(n)
- }
- }
-
- // Phase 3: Type check function bodies.
- // Don't use range--typecheck can add closures to Target.Decls.
- base.Timer.Start("fe", "typecheck", "func")
- var fcount int64
- for i := 0; i < len(Target.Decls); i++ {
- n := Target.Decls[i]
- if n.Op() == ir.ODCLFUNC {
- FuncBody(n.(*ir.Func))
- fcount++
- }
- }
-
- // Phase 4: Check external declarations.
- // TODO(mdempsky): This should be handled when type checking their
- // corresponding ODCL nodes.
- base.Timer.Start("fe", "typecheck", "externdcls")
- for i, n := range Target.Externs {
- if n.Op() == ir.ONAME {
- Target.Externs[i] = Expr(Target.Externs[i])
- }
- }
-
- // Phase 5: With all user code type-checked, it's now safe to verify map keys.
- CheckMapKeys()
-
- // Phase 6: Compute Addrtaken for names.
- // We need to wait until typechecking is done so that when we see &x[i]
- // we know that x has its address taken if x is an array, but not if x is a slice.
- // We compute Addrtaken in bulk here.
- // After this phase, we maintain Addrtaken incrementally.
- if dirtyAddrtaken {
- computeAddrtaken(Target.Decls)
- dirtyAddrtaken = false
- }
- incrementalAddrtaken = true
-
- // Phase 7: Eliminate some obviously dead code.
- // Must happen after typechecking.
- for _, n := range Target.Decls {
- if n.Op() == ir.ODCLFUNC {
- deadcode(n.(*ir.Func))
- }
- }
-
- // Phase 8: Decide how to capture closed variables.
- // This needs to run before escape analysis,
- // because variables captured by value do not escape.
- base.Timer.Start("fe", "capturevars")
- for _, n := range Target.Decls {
- if n.Op() == ir.ODCLFUNC {
- n := n.(*ir.Func)
- if n.OClosure != nil {
- ir.CurFunc = n
- CaptureVars(n)
- }
- }
- }
- CaptureVarsComplete = true
- ir.CurFunc = nil
-
- if base.Debug.TypecheckInl != 0 {
- // Typecheck imported function bodies if Debug.l > 1,
- // otherwise lazily when used or re-exported.
- AllImportedBodies()
- }
+ InitRuntime()
}
func AssignExpr(n ir.Node) ir.Node { return typecheck(n, ctxExpr|ctxAssign) }
@@ -2247,144 +2144,6 @@ func CheckReturn(fn *ir.Func) {
}
}
-func deadcode(fn *ir.Func) {
- deadcodeslice(&fn.Body)
-
- if len(fn.Body) == 0 {
- return
- }
-
- for _, n := range fn.Body {
- if len(n.Init()) > 0 {
- return
- }
- switch n.Op() {
- case ir.OIF:
- n := n.(*ir.IfStmt)
- if !ir.IsConst(n.Cond, constant.Bool) || len(n.Body) > 0 || len(n.Else) > 0 {
- return
- }
- case ir.OFOR:
- n := n.(*ir.ForStmt)
- if !ir.IsConst(n.Cond, constant.Bool) || ir.BoolVal(n.Cond) {
- return
- }
- default:
- return
- }
- }
-
- fn.Body.Set([]ir.Node{ir.NewBlockStmt(base.Pos, nil)})
-}
-
-func deadcodeslice(nn *ir.Nodes) {
- var lastLabel = -1
- for i, n := range *nn {
- if n != nil && n.Op() == ir.OLABEL {
- lastLabel = i
- }
- }
- for i, n := range *nn {
- // Cut is set to true when all nodes after i'th position
- // should be removed.
- // In other words, it marks whole slice "tail" as dead.
- cut := false
- if n == nil {
- continue
- }
- if n.Op() == ir.OIF {
- n := n.(*ir.IfStmt)
- n.Cond = deadcodeexpr(n.Cond)
- if ir.IsConst(n.Cond, constant.Bool) {
- var body ir.Nodes
- if ir.BoolVal(n.Cond) {
- n.Else = ir.Nodes{}
- body = n.Body
- } else {
- n.Body = ir.Nodes{}
- body = n.Else
- }
- // If "then" or "else" branch ends with panic or return statement,
- // it is safe to remove all statements after this node.
- // isterminating is not used to avoid goto-related complications.
- // We must be careful not to deadcode-remove labels, as they
- // might be the target of a goto. See issue 28616.
- if body := body; len(body) != 0 {
- switch body[(len(body) - 1)].Op() {
- case ir.ORETURN, ir.ORETJMP, ir.OPANIC:
- if i > lastLabel {
- cut = true
- }
- }
- }
- }
- }
-
- deadcodeslice(n.PtrInit())
- switch n.Op() {
- case ir.OBLOCK:
- n := n.(*ir.BlockStmt)
- deadcodeslice(&n.List)
- case ir.OFOR:
- n := n.(*ir.ForStmt)
- deadcodeslice(&n.Body)
- case ir.OIF:
- n := n.(*ir.IfStmt)
- deadcodeslice(&n.Body)
- deadcodeslice(&n.Else)
- case ir.ORANGE:
- n := n.(*ir.RangeStmt)
- deadcodeslice(&n.Body)
- case ir.OSELECT:
- n := n.(*ir.SelectStmt)
- for _, cas := range n.Cases {
- deadcodeslice(&cas.Body)
- }
- case ir.OSWITCH:
- n := n.(*ir.SwitchStmt)
- for _, cas := range n.Cases {
- deadcodeslice(&cas.Body)
- }
- }
-
- if cut {
- nn.Set((*nn)[:i+1])
- break
- }
- }
-}
-
-func deadcodeexpr(n ir.Node) ir.Node {
- // Perform dead-code elimination on short-circuited boolean
- // expressions involving constants with the intent of
- // producing a constant 'if' condition.
- switch n.Op() {
- case ir.OANDAND:
- n := n.(*ir.LogicalExpr)
- n.X = deadcodeexpr(n.X)
- n.Y = deadcodeexpr(n.Y)
- if ir.IsConst(n.X, constant.Bool) {
- if ir.BoolVal(n.X) {
- return n.Y // true && x => x
- } else {
- return n.X // false && x => false
- }
- }
- case ir.OOROR:
- n := n.(*ir.LogicalExpr)
- n.X = deadcodeexpr(n.X)
- n.Y = deadcodeexpr(n.Y)
- if ir.IsConst(n.X, constant.Bool) {
- if ir.BoolVal(n.X) {
- return n.X // true || x => true
- } else {
- return n.Y // false || x => x
- }
- }
- }
- return n
-}
-
// getIotaValue returns the current value for "iota",
// or -1 if not within a ConstSpec.
func getIotaValue() int64 {