Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/compile/internal/noder/stmt.go

Documentation: cmd/compile/internal/noder

     1  // Copyright 2021 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package noder
     6  
     7  import (
     8  	"cmd/compile/internal/ir"
     9  	"cmd/compile/internal/syntax"
    10  	"cmd/compile/internal/typecheck"
    11  	"cmd/compile/internal/types"
    12  	"cmd/internal/src"
    13  )
    14  
    15  func (g *irgen) stmts(stmts []syntax.Stmt) []ir.Node {
    16  	var nodes []ir.Node
    17  	for _, stmt := range stmts {
    18  		switch s := g.stmt(stmt).(type) {
    19  		case nil: // EmptyStmt
    20  		case *ir.BlockStmt:
    21  			nodes = append(nodes, s.List...)
    22  		default:
    23  			nodes = append(nodes, s)
    24  		}
    25  	}
    26  	return nodes
    27  }
    28  
    29  func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
    30  	switch stmt := stmt.(type) {
    31  	case nil, *syntax.EmptyStmt:
    32  		return nil
    33  	case *syntax.LabeledStmt:
    34  		return g.labeledStmt(stmt)
    35  	case *syntax.BlockStmt:
    36  		return ir.NewBlockStmt(g.pos(stmt), g.blockStmt(stmt))
    37  	case *syntax.ExprStmt:
    38  		x := g.expr(stmt.X)
    39  		if call, ok := x.(*ir.CallExpr); ok {
    40  			call.Use = ir.CallUseStmt
    41  		}
    42  		return x
    43  	case *syntax.SendStmt:
    44  		n := ir.NewSendStmt(g.pos(stmt), g.expr(stmt.Chan), g.expr(stmt.Value))
    45  		if n.Chan.Type().HasTParam() || n.Value.Type().HasTParam() {
    46  			// Delay transforming the send if the channel or value
    47  			// have a type param.
    48  			n.SetTypecheck(3)
    49  			return n
    50  		}
    51  		transformSend(n)
    52  		n.SetTypecheck(1)
    53  		return n
    54  	case *syntax.DeclStmt:
    55  		return ir.NewBlockStmt(g.pos(stmt), g.decls(stmt.DeclList))
    56  
    57  	case *syntax.AssignStmt:
    58  		if stmt.Op != 0 && stmt.Op != syntax.Def {
    59  			op := g.op(stmt.Op, binOps[:])
    60  			var n *ir.AssignOpStmt
    61  			if stmt.Rhs == nil {
    62  				n = IncDec(g.pos(stmt), op, g.expr(stmt.Lhs))
    63  			} else {
    64  				n = ir.NewAssignOpStmt(g.pos(stmt), op, g.expr(stmt.Lhs), g.expr(stmt.Rhs))
    65  			}
    66  			if n.X.Typecheck() == 3 {
    67  				n.SetTypecheck(3)
    68  				return n
    69  			}
    70  			transformAsOp(n)
    71  			n.SetTypecheck(1)
    72  			return n
    73  		}
    74  
    75  		names, lhs := g.assignList(stmt.Lhs, stmt.Op == syntax.Def)
    76  		rhs := g.exprList(stmt.Rhs)
    77  
    78  		// We must delay transforming the assign statement if any of the
    79  		// lhs or rhs nodes are also delayed, since transformAssign needs
    80  		// to know the types of the left and right sides in various cases.
    81  		delay := false
    82  		for _, e := range lhs {
    83  			if e.Typecheck() == 3 {
    84  				delay = true
    85  				break
    86  			}
    87  		}
    88  		for _, e := range rhs {
    89  			if e.Typecheck() == 3 {
    90  				delay = true
    91  				break
    92  			}
    93  		}
    94  
    95  		if len(lhs) == 1 && len(rhs) == 1 {
    96  			n := ir.NewAssignStmt(g.pos(stmt), lhs[0], rhs[0])
    97  			n.Def = initDefn(n, names)
    98  
    99  			if delay {
   100  				n.SetTypecheck(3)
   101  				return n
   102  			}
   103  
   104  			lhs, rhs := []ir.Node{n.X}, []ir.Node{n.Y}
   105  			transformAssign(n, lhs, rhs)
   106  			n.X, n.Y = lhs[0], rhs[0]
   107  			n.SetTypecheck(1)
   108  			return n
   109  		}
   110  
   111  		n := ir.NewAssignListStmt(g.pos(stmt), ir.OAS2, lhs, rhs)
   112  		n.Def = initDefn(n, names)
   113  		if delay {
   114  			n.SetTypecheck(3)
   115  			return n
   116  		}
   117  		transformAssign(n, n.Lhs, n.Rhs)
   118  		n.SetTypecheck(1)
   119  		return n
   120  
   121  	case *syntax.BranchStmt:
   122  		return ir.NewBranchStmt(g.pos(stmt), g.tokOp(int(stmt.Tok), branchOps[:]), g.name(stmt.Label))
   123  	case *syntax.CallStmt:
   124  		return ir.NewGoDeferStmt(g.pos(stmt), g.tokOp(int(stmt.Tok), callOps[:]), g.expr(stmt.Call))
   125  	case *syntax.ReturnStmt:
   126  		n := ir.NewReturnStmt(g.pos(stmt), g.exprList(stmt.Results))
   127  		for _, e := range n.Results {
   128  			if e.Type().HasTParam() {
   129  				// Delay transforming the return statement if any of the
   130  				// return values have a type param.
   131  				n.SetTypecheck(3)
   132  				return n
   133  			}
   134  		}
   135  		transformReturn(n)
   136  		n.SetTypecheck(1)
   137  		return n
   138  	case *syntax.IfStmt:
   139  		return g.ifStmt(stmt)
   140  	case *syntax.ForStmt:
   141  		return g.forStmt(stmt)
   142  	case *syntax.SelectStmt:
   143  		n := g.selectStmt(stmt)
   144  		transformSelect(n.(*ir.SelectStmt))
   145  		n.SetTypecheck(1)
   146  		return n
   147  	case *syntax.SwitchStmt:
   148  		return g.switchStmt(stmt)
   149  
   150  	default:
   151  		g.unhandled("statement", stmt)
   152  		panic("unreachable")
   153  	}
   154  }
   155  
   156  // TODO(mdempsky): Investigate replacing with switch statements or dense arrays.
   157  
   158  var branchOps = [...]ir.Op{
   159  	syntax.Break:       ir.OBREAK,
   160  	syntax.Continue:    ir.OCONTINUE,
   161  	syntax.Fallthrough: ir.OFALL,
   162  	syntax.Goto:        ir.OGOTO,
   163  }
   164  
   165  var callOps = [...]ir.Op{
   166  	syntax.Defer: ir.ODEFER,
   167  	syntax.Go:    ir.OGO,
   168  }
   169  
   170  func (g *irgen) tokOp(tok int, ops []ir.Op) ir.Op {
   171  	// TODO(mdempsky): Validate.
   172  	return ops[tok]
   173  }
   174  
   175  func (g *irgen) op(op syntax.Operator, ops []ir.Op) ir.Op {
   176  	// TODO(mdempsky): Validate.
   177  	return ops[op]
   178  }
   179  
   180  func (g *irgen) assignList(expr syntax.Expr, def bool) ([]*ir.Name, []ir.Node) {
   181  	if !def {
   182  		return nil, g.exprList(expr)
   183  	}
   184  
   185  	var exprs []syntax.Expr
   186  	if list, ok := expr.(*syntax.ListExpr); ok {
   187  		exprs = list.ElemList
   188  	} else {
   189  		exprs = []syntax.Expr{expr}
   190  	}
   191  
   192  	var names []*ir.Name
   193  	res := make([]ir.Node, len(exprs))
   194  	for i, expr := range exprs {
   195  		expr := expr.(*syntax.Name)
   196  		if expr.Value == "_" {
   197  			res[i] = ir.BlankNode
   198  			continue
   199  		}
   200  
   201  		if obj, ok := g.info.Uses[expr]; ok {
   202  			res[i] = g.obj(obj)
   203  			continue
   204  		}
   205  
   206  		name, _ := g.def(expr)
   207  		names = append(names, name)
   208  		res[i] = name
   209  	}
   210  
   211  	return names, res
   212  }
   213  
   214  // initDefn marks the given names as declared by defn and populates
   215  // its Init field with ODCL nodes. It then reports whether any names
   216  // were so declared, which can be used to initialize defn.Def.
   217  func initDefn(defn ir.InitNode, names []*ir.Name) bool {
   218  	if len(names) == 0 {
   219  		return false
   220  	}
   221  
   222  	init := make([]ir.Node, len(names))
   223  	for i, name := range names {
   224  		name.Defn = defn
   225  		init[i] = ir.NewDecl(name.Pos(), ir.ODCL, name)
   226  	}
   227  	defn.SetInit(init)
   228  	return true
   229  }
   230  
   231  func (g *irgen) blockStmt(stmt *syntax.BlockStmt) []ir.Node {
   232  	return g.stmts(stmt.List)
   233  }
   234  
   235  func (g *irgen) ifStmt(stmt *syntax.IfStmt) ir.Node {
   236  	init := g.stmt(stmt.Init)
   237  	n := ir.NewIfStmt(g.pos(stmt), g.expr(stmt.Cond), g.blockStmt(stmt.Then), nil)
   238  	if stmt.Else != nil {
   239  		e := g.stmt(stmt.Else)
   240  		if e.Op() == ir.OBLOCK {
   241  			e := e.(*ir.BlockStmt)
   242  			n.Else = e.List
   243  		} else {
   244  			n.Else = []ir.Node{e}
   245  		}
   246  	}
   247  	return g.init(init, n)
   248  }
   249  
   250  // unpackTwo returns the first two nodes in list. If list has fewer
   251  // than 2 nodes, then the missing nodes are replaced with nils.
   252  func unpackTwo(list []ir.Node) (fst, snd ir.Node) {
   253  	switch len(list) {
   254  	case 0:
   255  		return nil, nil
   256  	case 1:
   257  		return list[0], nil
   258  	default:
   259  		return list[0], list[1]
   260  	}
   261  }
   262  
   263  func (g *irgen) forStmt(stmt *syntax.ForStmt) ir.Node {
   264  	if r, ok := stmt.Init.(*syntax.RangeClause); ok {
   265  		names, lhs := g.assignList(r.Lhs, r.Def)
   266  		key, value := unpackTwo(lhs)
   267  		n := ir.NewRangeStmt(g.pos(r), key, value, g.expr(r.X), g.blockStmt(stmt.Body))
   268  		n.Def = initDefn(n, names)
   269  		return n
   270  	}
   271  
   272  	return ir.NewForStmt(g.pos(stmt), g.stmt(stmt.Init), g.expr(stmt.Cond), g.stmt(stmt.Post), g.blockStmt(stmt.Body))
   273  }
   274  
   275  func (g *irgen) selectStmt(stmt *syntax.SelectStmt) ir.Node {
   276  	body := make([]*ir.CommClause, len(stmt.Body))
   277  	for i, clause := range stmt.Body {
   278  		body[i] = ir.NewCommStmt(g.pos(clause), g.stmt(clause.Comm), g.stmts(clause.Body))
   279  	}
   280  	return ir.NewSelectStmt(g.pos(stmt), body)
   281  }
   282  
   283  func (g *irgen) switchStmt(stmt *syntax.SwitchStmt) ir.Node {
   284  	pos := g.pos(stmt)
   285  	init := g.stmt(stmt.Init)
   286  
   287  	var expr ir.Node
   288  	switch tag := stmt.Tag.(type) {
   289  	case *syntax.TypeSwitchGuard:
   290  		var ident *ir.Ident
   291  		if tag.Lhs != nil {
   292  			ident = ir.NewIdent(g.pos(tag.Lhs), g.name(tag.Lhs))
   293  		}
   294  		expr = ir.NewTypeSwitchGuard(pos, ident, g.expr(tag.X))
   295  	default:
   296  		expr = g.expr(tag)
   297  	}
   298  
   299  	body := make([]*ir.CaseClause, len(stmt.Body))
   300  	for i, clause := range stmt.Body {
   301  		// Check for an implicit clause variable before
   302  		// visiting body, because it may contain function
   303  		// literals that reference it, and then it'll be
   304  		// associated to the wrong function.
   305  		//
   306  		// Also, override its position to the clause's colon, so that
   307  		// dwarfgen can find the right scope for it later.
   308  		// TODO(mdempsky): We should probably just store the scope
   309  		// directly in the ir.Name.
   310  		var cv *ir.Name
   311  		if obj, ok := g.info.Implicits[clause]; ok {
   312  			cv = g.obj(obj)
   313  			cv.SetPos(g.makeXPos(clause.Colon))
   314  		}
   315  		body[i] = ir.NewCaseStmt(g.pos(clause), g.exprList(clause.Cases), g.stmts(clause.Body))
   316  		body[i].Var = cv
   317  	}
   318  
   319  	return g.init(init, ir.NewSwitchStmt(pos, expr, body))
   320  }
   321  
   322  func (g *irgen) labeledStmt(label *syntax.LabeledStmt) ir.Node {
   323  	sym := g.name(label.Label)
   324  	lhs := ir.NewLabelStmt(g.pos(label), sym)
   325  	ls := g.stmt(label.Stmt)
   326  
   327  	// Attach label directly to control statement too.
   328  	switch ls := ls.(type) {
   329  	case *ir.ForStmt:
   330  		ls.Label = sym
   331  	case *ir.RangeStmt:
   332  		ls.Label = sym
   333  	case *ir.SelectStmt:
   334  		ls.Label = sym
   335  	case *ir.SwitchStmt:
   336  		ls.Label = sym
   337  	}
   338  
   339  	l := []ir.Node{lhs}
   340  	if ls != nil {
   341  		if ls.Op() == ir.OBLOCK {
   342  			ls := ls.(*ir.BlockStmt)
   343  			l = append(l, ls.List...)
   344  		} else {
   345  			l = append(l, ls)
   346  		}
   347  	}
   348  	return ir.NewBlockStmt(src.NoXPos, l)
   349  }
   350  
   351  func (g *irgen) init(init ir.Node, stmt ir.InitNode) ir.InitNode {
   352  	if init != nil {
   353  		stmt.SetInit([]ir.Node{init})
   354  	}
   355  	return stmt
   356  }
   357  
   358  func (g *irgen) name(name *syntax.Name) *types.Sym {
   359  	if name == nil {
   360  		return nil
   361  	}
   362  	return typecheck.Lookup(name.Value)
   363  }
   364  

View as plain text