diff options
Diffstat (limited to 'src/cmd/compile/internal/typecheck/typecheck.go')
-rw-r--r-- | src/cmd/compile/internal/typecheck/typecheck.go | 243 |
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 { |