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

     1  // Copyright 2009 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 typecheck
     6  
     7  import (
     8  	"cmd/compile/internal/base"
     9  	"cmd/compile/internal/ir"
    10  	"cmd/compile/internal/types"
    11  	"cmd/internal/src"
    12  	"internal/types/errors"
    13  )
    14  
    15  func RangeExprType(t *types.Type) *types.Type {
    16  	if t.IsPtr() && t.Elem().IsArray() {
    17  		return t.Elem()
    18  	}
    19  	return t
    20  }
    21  
    22  // type check assignment.
    23  // if this assignment is the definition of a var on the left side,
    24  // fill in the var's type.
    25  func tcAssign(n *ir.AssignStmt) {
    26  	if base.EnableTrace && base.Flag.LowerT {
    27  		defer tracePrint("tcAssign", n)(nil)
    28  	}
    29  
    30  	if n.Y == nil {
    31  		n.X = AssignExpr(n.X)
    32  		return
    33  	}
    34  
    35  	lhs, rhs := []ir.Node{n.X}, []ir.Node{n.Y}
    36  	assign(n, lhs, rhs)
    37  	n.X, n.Y = lhs[0], rhs[0]
    38  
    39  	// TODO(mdempsky): This seems out of place.
    40  	if !ir.IsBlank(n.X) {
    41  		types.CheckSize(n.X.Type()) // ensure width is calculated for backend
    42  	}
    43  }
    44  
    45  func tcAssignList(n *ir.AssignListStmt) {
    46  	if base.EnableTrace && base.Flag.LowerT {
    47  		defer tracePrint("tcAssignList", n)(nil)
    48  	}
    49  
    50  	assign(n, n.Lhs, n.Rhs)
    51  }
    52  
    53  func assign(stmt ir.Node, lhs, rhs []ir.Node) {
    54  	// delicate little dance.
    55  	// the definition of lhs may refer to this assignment
    56  	// as its definition, in which case it will call tcAssign.
    57  	// in that case, do not call typecheck back, or it will cycle.
    58  	// if the variable has a type (ntype) then typechecking
    59  	// will not look at defn, so it is okay (and desirable,
    60  	// so that the conversion below happens).
    61  
    62  	checkLHS := func(i int, typ *types.Type) {
    63  		if n := lhs[i]; typ != nil && ir.DeclaredBy(n, stmt) && n.Type() == nil {
    64  			base.Assertf(typ.Kind() == types.TNIL, "unexpected untyped nil")
    65  			n.SetType(defaultType(typ))
    66  		}
    67  		if lhs[i].Typecheck() == 0 {
    68  			lhs[i] = AssignExpr(lhs[i])
    69  		}
    70  		checkassign(lhs[i])
    71  	}
    72  
    73  	assignType := func(i int, typ *types.Type) {
    74  		checkLHS(i, typ)
    75  		if typ != nil {
    76  			checkassignto(typ, lhs[i])
    77  		}
    78  	}
    79  
    80  	cr := len(rhs)
    81  	if len(rhs) == 1 {
    82  		rhs[0] = typecheck(rhs[0], ctxExpr|ctxMultiOK)
    83  		if rtyp := rhs[0].Type(); rtyp != nil && rtyp.IsFuncArgStruct() {
    84  			cr = rtyp.NumFields()
    85  		}
    86  	} else {
    87  		Exprs(rhs)
    88  	}
    89  
    90  	// x, ok = y
    91  assignOK:
    92  	for len(lhs) == 2 && cr == 1 {
    93  		stmt := stmt.(*ir.AssignListStmt)
    94  		r := rhs[0]
    95  
    96  		switch r.Op() {
    97  		case ir.OINDEXMAP:
    98  			stmt.SetOp(ir.OAS2MAPR)
    99  		case ir.ORECV:
   100  			stmt.SetOp(ir.OAS2RECV)
   101  		case ir.ODOTTYPE:
   102  			r := r.(*ir.TypeAssertExpr)
   103  			stmt.SetOp(ir.OAS2DOTTYPE)
   104  			r.SetOp(ir.ODOTTYPE2)
   105  		case ir.ODYNAMICDOTTYPE:
   106  			r := r.(*ir.DynamicTypeAssertExpr)
   107  			stmt.SetOp(ir.OAS2DOTTYPE)
   108  			r.SetOp(ir.ODYNAMICDOTTYPE2)
   109  		default:
   110  			break assignOK
   111  		}
   112  
   113  		assignType(0, r.Type())
   114  		assignType(1, types.UntypedBool)
   115  		return
   116  	}
   117  
   118  	if len(lhs) != cr {
   119  		if r, ok := rhs[0].(*ir.CallExpr); ok && len(rhs) == 1 {
   120  			if r.Type() != nil {
   121  				base.ErrorfAt(stmt.Pos(), errors.WrongAssignCount, "assignment mismatch: %d variable%s but %v returns %d value%s", len(lhs), plural(len(lhs)), r.Fun, cr, plural(cr))
   122  			}
   123  		} else {
   124  			base.ErrorfAt(stmt.Pos(), errors.WrongAssignCount, "assignment mismatch: %d variable%s but %v value%s", len(lhs), plural(len(lhs)), len(rhs), plural(len(rhs)))
   125  		}
   126  
   127  		for i := range lhs {
   128  			checkLHS(i, nil)
   129  		}
   130  		return
   131  	}
   132  
   133  	// x,y,z = f()
   134  	if cr > len(rhs) {
   135  		stmt := stmt.(*ir.AssignListStmt)
   136  		stmt.SetOp(ir.OAS2FUNC)
   137  		r := rhs[0].(*ir.CallExpr)
   138  		rtyp := r.Type()
   139  
   140  		mismatched := false
   141  		failed := false
   142  		for i := range lhs {
   143  			result := rtyp.Field(i).Type
   144  			assignType(i, result)
   145  
   146  			if lhs[i].Type() == nil || result == nil {
   147  				failed = true
   148  			} else if lhs[i] != ir.BlankNode && !types.Identical(lhs[i].Type(), result) {
   149  				mismatched = true
   150  			}
   151  		}
   152  		if mismatched && !failed {
   153  			RewriteMultiValueCall(stmt, r)
   154  		}
   155  		return
   156  	}
   157  
   158  	for i, r := range rhs {
   159  		checkLHS(i, r.Type())
   160  		if lhs[i].Type() != nil {
   161  			rhs[i] = AssignConv(r, lhs[i].Type(), "assignment")
   162  		}
   163  	}
   164  }
   165  
   166  func plural(n int) string {
   167  	if n == 1 {
   168  		return ""
   169  	}
   170  	return "s"
   171  }
   172  
   173  // tcCheckNil typechecks an OCHECKNIL node.
   174  func tcCheckNil(n *ir.UnaryExpr) ir.Node {
   175  	n.X = Expr(n.X)
   176  	if !n.X.Type().IsPtrShaped() {
   177  		base.FatalfAt(n.Pos(), "%L is not pointer shaped", n.X)
   178  	}
   179  	return n
   180  }
   181  
   182  // tcFor typechecks an OFOR node.
   183  func tcFor(n *ir.ForStmt) ir.Node {
   184  	Stmts(n.Init())
   185  	n.Cond = Expr(n.Cond)
   186  	n.Cond = DefaultLit(n.Cond, nil)
   187  	if n.Cond != nil {
   188  		t := n.Cond.Type()
   189  		if t != nil && !t.IsBoolean() {
   190  			base.Errorf("non-bool %L used as for condition", n.Cond)
   191  		}
   192  	}
   193  	n.Post = Stmt(n.Post)
   194  	Stmts(n.Body)
   195  	return n
   196  }
   197  
   198  // tcGoDefer typechecks (normalizes) an OGO/ODEFER statement.
   199  func tcGoDefer(n *ir.GoDeferStmt) {
   200  	call := normalizeGoDeferCall(n.Pos(), n.Op(), n.Call, n.PtrInit())
   201  	call.GoDefer = true
   202  	n.Call = call
   203  }
   204  
   205  // normalizeGoDeferCall normalizes call into a normal function call
   206  // with no arguments and no results, suitable for use in an OGO/ODEFER
   207  // statement.
   208  //
   209  // For example, it normalizes:
   210  //
   211  //	f(x, y)
   212  //
   213  // into:
   214  //
   215  //	x1, y1 := x, y          // added to init
   216  //	func() { f(x1, y1) }()  // result
   217  func normalizeGoDeferCall(pos src.XPos, op ir.Op, call ir.Node, init *ir.Nodes) *ir.CallExpr {
   218  	init.Append(ir.TakeInit(call)...)
   219  
   220  	if call, ok := call.(*ir.CallExpr); ok && call.Op() == ir.OCALLFUNC {
   221  		if sig := call.Fun.Type(); sig.NumParams()+sig.NumResults() == 0 {
   222  			return call // already in normal form
   223  		}
   224  	}
   225  
   226  	// Create a new wrapper function without parameters or results.
   227  	wrapperFn := ir.NewClosureFunc(pos, pos, op, types.NewSignature(nil, nil, nil), ir.CurFunc, Target)
   228  	wrapperFn.DeclareParams(true)
   229  	wrapperFn.SetWrapper(true)
   230  
   231  	// argps collects the list of operands within the call expression
   232  	// that must be evaluated at the go/defer statement.
   233  	var argps []*ir.Node
   234  
   235  	var visit func(argp *ir.Node)
   236  	visit = func(argp *ir.Node) {
   237  		arg := *argp
   238  		if arg == nil {
   239  			return
   240  		}
   241  
   242  		// Recognize a few common expressions that can be evaluated within
   243  		// the wrapper, so we don't need to allocate space for them within
   244  		// the closure.
   245  		switch arg.Op() {
   246  		case ir.OLITERAL, ir.ONIL, ir.OMETHEXPR, ir.ONEW:
   247  			return
   248  		case ir.ONAME:
   249  			arg := arg.(*ir.Name)
   250  			if arg.Class == ir.PFUNC {
   251  				return // reference to global function
   252  			}
   253  		case ir.OADDR:
   254  			arg := arg.(*ir.AddrExpr)
   255  			if arg.X.Op() == ir.OLINKSYMOFFSET {
   256  				return // address of global symbol
   257  			}
   258  
   259  		case ir.OCONVNOP:
   260  			arg := arg.(*ir.ConvExpr)
   261  
   262  			// For unsafe.Pointer->uintptr conversion arguments, save the
   263  			// unsafe.Pointer argument. This is necessary to handle cases
   264  			// like fixedbugs/issue24491a.go correctly.
   265  			//
   266  			// TODO(mdempsky): Limit to static callees with
   267  			// //go:uintptr{escapes,keepalive}?
   268  			if arg.Type().IsUintptr() && arg.X.Type().IsUnsafePtr() {
   269  				visit(&arg.X)
   270  				return
   271  			}
   272  
   273  		case ir.OARRAYLIT, ir.OSLICELIT, ir.OSTRUCTLIT:
   274  			// TODO(mdempsky): For very large slices, it may be preferable
   275  			// to construct them at the go/defer statement instead.
   276  			list := arg.(*ir.CompLitExpr).List
   277  			for i, el := range list {
   278  				switch el := el.(type) {
   279  				case *ir.KeyExpr:
   280  					visit(&el.Value)
   281  				case *ir.StructKeyExpr:
   282  					visit(&el.Value)
   283  				default:
   284  					visit(&list[i])
   285  				}
   286  			}
   287  			return
   288  		}
   289  
   290  		argps = append(argps, argp)
   291  	}
   292  
   293  	visitList := func(list []ir.Node) {
   294  		for i := range list {
   295  			visit(&list[i])
   296  		}
   297  	}
   298  
   299  	switch call.Op() {
   300  	default:
   301  		base.Fatalf("unexpected call op: %v", call.Op())
   302  
   303  	case ir.OCALLFUNC:
   304  		call := call.(*ir.CallExpr)
   305  
   306  		// If the callee is a named function, link to the original callee.
   307  		if wrapped := ir.StaticCalleeName(call.Fun); wrapped != nil {
   308  			wrapperFn.WrappedFunc = wrapped.Func
   309  		}
   310  
   311  		visit(&call.Fun)
   312  		visitList(call.Args)
   313  
   314  	case ir.OCALLINTER:
   315  		call := call.(*ir.CallExpr)
   316  		argps = append(argps, &call.Fun.(*ir.SelectorExpr).X) // must be first for OCHECKNIL; see below
   317  		visitList(call.Args)
   318  
   319  	case ir.OAPPEND, ir.ODELETE, ir.OPRINT, ir.OPRINTLN, ir.ORECOVER:
   320  		call := call.(*ir.CallExpr)
   321  		visitList(call.Args)
   322  		visit(&call.RType)
   323  
   324  	case ir.OCOPY:
   325  		call := call.(*ir.BinaryExpr)
   326  		visit(&call.X)
   327  		visit(&call.Y)
   328  		visit(&call.RType)
   329  
   330  	case ir.OCLEAR, ir.OCLOSE, ir.OPANIC:
   331  		call := call.(*ir.UnaryExpr)
   332  		visit(&call.X)
   333  	}
   334  
   335  	if len(argps) != 0 {
   336  		// Found one or more operands that need to be evaluated upfront
   337  		// and spilled to temporary variables, which can be captured by
   338  		// the wrapper function.
   339  
   340  		stmtPos := base.Pos
   341  		callPos := base.Pos
   342  
   343  		as := ir.NewAssignListStmt(callPos, ir.OAS2, make([]ir.Node, len(argps)), make([]ir.Node, len(argps)))
   344  		for i, argp := range argps {
   345  			arg := *argp
   346  
   347  			pos := callPos
   348  			if ir.HasUniquePos(arg) {
   349  				pos = arg.Pos()
   350  			}
   351  
   352  			// tmp := arg
   353  			tmp := TempAt(pos, ir.CurFunc, arg.Type())
   354  			init.Append(Stmt(ir.NewDecl(pos, ir.ODCL, tmp)))
   355  			tmp.Defn = as
   356  			as.Lhs[i] = tmp
   357  			as.Rhs[i] = arg
   358  
   359  			// Rewrite original expression to use/capture tmp.
   360  			*argp = ir.NewClosureVar(pos, wrapperFn, tmp)
   361  		}
   362  		init.Append(Stmt(as))
   363  
   364  		// For "go/defer iface.M()", if iface is nil, we need to panic at
   365  		// the point of the go/defer statement.
   366  		if call.Op() == ir.OCALLINTER {
   367  			iface := as.Lhs[0]
   368  			init.Append(Stmt(ir.NewUnaryExpr(stmtPos, ir.OCHECKNIL, ir.NewUnaryExpr(iface.Pos(), ir.OITAB, iface))))
   369  		}
   370  	}
   371  
   372  	// Move call into the wrapper function, now that it's safe to
   373  	// evaluate there.
   374  	wrapperFn.Body = []ir.Node{call}
   375  
   376  	// Finally, construct a call to the wrapper.
   377  	return Call(call.Pos(), wrapperFn.OClosure, nil, false).(*ir.CallExpr)
   378  }
   379  
   380  // tcIf typechecks an OIF node.
   381  func tcIf(n *ir.IfStmt) ir.Node {
   382  	Stmts(n.Init())
   383  	n.Cond = Expr(n.Cond)
   384  	n.Cond = DefaultLit(n.Cond, nil)
   385  	if n.Cond != nil {
   386  		t := n.Cond.Type()
   387  		if t != nil && !t.IsBoolean() {
   388  			base.Errorf("non-bool %L used as if condition", n.Cond)
   389  		}
   390  	}
   391  	Stmts(n.Body)
   392  	Stmts(n.Else)
   393  	return n
   394  }
   395  
   396  // range
   397  func tcRange(n *ir.RangeStmt) {
   398  	n.X = Expr(n.X)
   399  
   400  	// delicate little dance.  see tcAssignList
   401  	if n.Key != nil {
   402  		if !ir.DeclaredBy(n.Key, n) {
   403  			n.Key = AssignExpr(n.Key)
   404  		}
   405  		checkassign(n.Key)
   406  	}
   407  	if n.Value != nil {
   408  		if !ir.DeclaredBy(n.Value, n) {
   409  			n.Value = AssignExpr(n.Value)
   410  		}
   411  		checkassign(n.Value)
   412  	}
   413  
   414  	// second half of dance
   415  	n.SetTypecheck(1)
   416  	if n.Key != nil && n.Key.Typecheck() == 0 {
   417  		n.Key = AssignExpr(n.Key)
   418  	}
   419  	if n.Value != nil && n.Value.Typecheck() == 0 {
   420  		n.Value = AssignExpr(n.Value)
   421  	}
   422  
   423  	Stmts(n.Body)
   424  }
   425  
   426  // tcReturn typechecks an ORETURN node.
   427  func tcReturn(n *ir.ReturnStmt) ir.Node {
   428  	if ir.CurFunc == nil {
   429  		base.FatalfAt(n.Pos(), "return outside function")
   430  	}
   431  
   432  	typecheckargs(n)
   433  	if len(n.Results) != 0 {
   434  		typecheckaste(ir.ORETURN, nil, false, ir.CurFunc.Type().Results(), n.Results, func() string { return "return argument" })
   435  	}
   436  	return n
   437  }
   438  
   439  // select
   440  func tcSelect(sel *ir.SelectStmt) {
   441  	var def *ir.CommClause
   442  	lno := ir.SetPos(sel)
   443  	Stmts(sel.Init())
   444  	for _, ncase := range sel.Cases {
   445  		if ncase.Comm == nil {
   446  			// default
   447  			if def != nil {
   448  				base.ErrorfAt(ncase.Pos(), errors.DuplicateDefault, "multiple defaults in select (first at %v)", ir.Line(def))
   449  			} else {
   450  				def = ncase
   451  			}
   452  		} else {
   453  			n := Stmt(ncase.Comm)
   454  			ncase.Comm = n
   455  			oselrecv2 := func(dst, recv ir.Node, def bool) {
   456  				selrecv := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
   457  				selrecv.Def = def
   458  				selrecv.SetTypecheck(1)
   459  				selrecv.SetInit(n.Init())
   460  				ncase.Comm = selrecv
   461  			}
   462  			switch n.Op() {
   463  			default:
   464  				pos := n.Pos()
   465  				if n.Op() == ir.ONAME {
   466  					// We don't have the right position for ONAME nodes (see #15459 and
   467  					// others). Using ncase.Pos for now as it will provide the correct
   468  					// line number (assuming the expression follows the "case" keyword
   469  					// on the same line). This matches the approach before 1.10.
   470  					pos = ncase.Pos()
   471  				}
   472  				base.ErrorfAt(pos, errors.InvalidSelectCase, "select case must be receive, send or assign recv")
   473  
   474  			case ir.OAS:
   475  				// convert x = <-c into x, _ = <-c
   476  				// remove implicit conversions; the eventual assignment
   477  				// will reintroduce them.
   478  				n := n.(*ir.AssignStmt)
   479  				if r := n.Y; r.Op() == ir.OCONVNOP || r.Op() == ir.OCONVIFACE {
   480  					r := r.(*ir.ConvExpr)
   481  					if r.Implicit() {
   482  						n.Y = r.X
   483  					}
   484  				}
   485  				if n.Y.Op() != ir.ORECV {
   486  					base.ErrorfAt(n.Pos(), errors.InvalidSelectCase, "select assignment must have receive on right hand side")
   487  					break
   488  				}
   489  				oselrecv2(n.X, n.Y, n.Def)
   490  
   491  			case ir.OAS2RECV:
   492  				n := n.(*ir.AssignListStmt)
   493  				if n.Rhs[0].Op() != ir.ORECV {
   494  					base.ErrorfAt(n.Pos(), errors.InvalidSelectCase, "select assignment must have receive on right hand side")
   495  					break
   496  				}
   497  				n.SetOp(ir.OSELRECV2)
   498  
   499  			case ir.ORECV:
   500  				// convert <-c into _, _ = <-c
   501  				n := n.(*ir.UnaryExpr)
   502  				oselrecv2(ir.BlankNode, n, false)
   503  
   504  			case ir.OSEND:
   505  				break
   506  			}
   507  		}
   508  
   509  		Stmts(ncase.Body)
   510  	}
   511  
   512  	base.Pos = lno
   513  }
   514  
   515  // tcSend typechecks an OSEND node.
   516  func tcSend(n *ir.SendStmt) ir.Node {
   517  	n.Chan = Expr(n.Chan)
   518  	n.Value = Expr(n.Value)
   519  	n.Chan = DefaultLit(n.Chan, nil)
   520  	t := n.Chan.Type()
   521  	if t == nil {
   522  		return n
   523  	}
   524  	if !t.IsChan() {
   525  		base.Errorf("invalid operation: %v (send to non-chan type %v)", n, t)
   526  		return n
   527  	}
   528  
   529  	if !t.ChanDir().CanSend() {
   530  		base.Errorf("invalid operation: %v (send to receive-only type %v)", n, t)
   531  		return n
   532  	}
   533  
   534  	n.Value = AssignConv(n.Value, t.Elem(), "send")
   535  	if n.Value.Type() == nil {
   536  		return n
   537  	}
   538  	return n
   539  }
   540  
   541  // tcSwitch typechecks a switch statement.
   542  func tcSwitch(n *ir.SwitchStmt) {
   543  	Stmts(n.Init())
   544  	if n.Tag != nil && n.Tag.Op() == ir.OTYPESW {
   545  		tcSwitchType(n)
   546  	} else {
   547  		tcSwitchExpr(n)
   548  	}
   549  }
   550  
   551  func tcSwitchExpr(n *ir.SwitchStmt) {
   552  	t := types.Types[types.TBOOL]
   553  	if n.Tag != nil {
   554  		n.Tag = Expr(n.Tag)
   555  		n.Tag = DefaultLit(n.Tag, nil)
   556  		t = n.Tag.Type()
   557  	}
   558  
   559  	var nilonly string
   560  	if t != nil {
   561  		switch {
   562  		case t.IsMap():
   563  			nilonly = "map"
   564  		case t.Kind() == types.TFUNC:
   565  			nilonly = "func"
   566  		case t.IsSlice():
   567  			nilonly = "slice"
   568  
   569  		case !types.IsComparable(t):
   570  			if t.IsStruct() {
   571  				base.ErrorfAt(n.Pos(), errors.InvalidExprSwitch, "cannot switch on %L (struct containing %v cannot be compared)", n.Tag, types.IncomparableField(t).Type)
   572  			} else {
   573  				base.ErrorfAt(n.Pos(), errors.InvalidExprSwitch, "cannot switch on %L", n.Tag)
   574  			}
   575  			t = nil
   576  		}
   577  	}
   578  
   579  	var defCase ir.Node
   580  	for _, ncase := range n.Cases {
   581  		ls := ncase.List
   582  		if len(ls) == 0 { // default:
   583  			if defCase != nil {
   584  				base.ErrorfAt(ncase.Pos(), errors.DuplicateDefault, "multiple defaults in switch (first at %v)", ir.Line(defCase))
   585  			} else {
   586  				defCase = ncase
   587  			}
   588  		}
   589  
   590  		for i := range ls {
   591  			ir.SetPos(ncase)
   592  			ls[i] = Expr(ls[i])
   593  			ls[i] = DefaultLit(ls[i], t)
   594  			n1 := ls[i]
   595  			if t == nil || n1.Type() == nil {
   596  				continue
   597  			}
   598  
   599  			if nilonly != "" && !ir.IsNil(n1) {
   600  				base.ErrorfAt(ncase.Pos(), errors.MismatchedTypes, "invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Tag)
   601  			} else if t.IsInterface() && !n1.Type().IsInterface() && !types.IsComparable(n1.Type()) {
   602  				base.ErrorfAt(ncase.Pos(), errors.UndefinedOp, "invalid case %L in switch (incomparable type)", n1)
   603  			} else {
   604  				op1, _ := assignOp(n1.Type(), t)
   605  				op2, _ := assignOp(t, n1.Type())
   606  				if op1 == ir.OXXX && op2 == ir.OXXX {
   607  					if n.Tag != nil {
   608  						base.ErrorfAt(ncase.Pos(), errors.MismatchedTypes, "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Tag, n1.Type(), t)
   609  					} else {
   610  						base.ErrorfAt(ncase.Pos(), errors.MismatchedTypes, "invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type())
   611  					}
   612  				}
   613  			}
   614  		}
   615  
   616  		Stmts(ncase.Body)
   617  	}
   618  }
   619  
   620  func tcSwitchType(n *ir.SwitchStmt) {
   621  	guard := n.Tag.(*ir.TypeSwitchGuard)
   622  	guard.X = Expr(guard.X)
   623  	t := guard.X.Type()
   624  	if t != nil && !t.IsInterface() {
   625  		base.ErrorfAt(n.Pos(), errors.InvalidTypeSwitch, "cannot type switch on non-interface value %L", guard.X)
   626  		t = nil
   627  	}
   628  
   629  	// We don't actually declare the type switch's guarded
   630  	// declaration itself. So if there are no cases, we won't
   631  	// notice that it went unused.
   632  	if v := guard.Tag; v != nil && !ir.IsBlank(v) && len(n.Cases) == 0 {
   633  		base.ErrorfAt(v.Pos(), errors.UnusedVar, "%v declared but not used", v.Sym())
   634  	}
   635  
   636  	var defCase, nilCase ir.Node
   637  	var ts typeSet
   638  	for _, ncase := range n.Cases {
   639  		ls := ncase.List
   640  		if len(ls) == 0 { // default:
   641  			if defCase != nil {
   642  				base.ErrorfAt(ncase.Pos(), errors.DuplicateDefault, "multiple defaults in switch (first at %v)", ir.Line(defCase))
   643  			} else {
   644  				defCase = ncase
   645  			}
   646  		}
   647  
   648  		for i := range ls {
   649  			ls[i] = typecheck(ls[i], ctxExpr|ctxType)
   650  			n1 := ls[i]
   651  			if t == nil || n1.Type() == nil {
   652  				continue
   653  			}
   654  
   655  			if ir.IsNil(n1) { // case nil:
   656  				if nilCase != nil {
   657  					base.ErrorfAt(ncase.Pos(), errors.DuplicateCase, "multiple nil cases in type switch (first at %v)", ir.Line(nilCase))
   658  				} else {
   659  					nilCase = ncase
   660  				}
   661  				continue
   662  			}
   663  			if n1.Op() == ir.ODYNAMICTYPE {
   664  				continue
   665  			}
   666  			if n1.Op() != ir.OTYPE {
   667  				base.ErrorfAt(ncase.Pos(), errors.NotAType, "%L is not a type", n1)
   668  				continue
   669  			}
   670  			if !n1.Type().IsInterface() {
   671  				why := ImplementsExplain(n1.Type(), t)
   672  				if why != "" {
   673  					base.ErrorfAt(ncase.Pos(), errors.ImpossibleAssert, "impossible type switch case: %L cannot have dynamic type %v (%s)", guard.X, n1.Type(), why)
   674  				}
   675  				continue
   676  			}
   677  
   678  			ts.add(ncase.Pos(), n1.Type())
   679  		}
   680  
   681  		if ncase.Var != nil {
   682  			// Assign the clause variable's type.
   683  			vt := t
   684  			if len(ls) == 1 {
   685  				if ls[0].Op() == ir.OTYPE || ls[0].Op() == ir.ODYNAMICTYPE {
   686  					vt = ls[0].Type()
   687  				} else if !ir.IsNil(ls[0]) {
   688  					// Invalid single-type case;
   689  					// mark variable as broken.
   690  					vt = nil
   691  				}
   692  			}
   693  
   694  			nvar := ncase.Var
   695  			nvar.SetType(vt)
   696  			if vt != nil {
   697  				nvar = AssignExpr(nvar).(*ir.Name)
   698  			} else {
   699  				// Clause variable is broken; prevent typechecking.
   700  				nvar.SetTypecheck(1)
   701  			}
   702  			ncase.Var = nvar
   703  		}
   704  
   705  		Stmts(ncase.Body)
   706  	}
   707  }
   708  
   709  type typeSet struct {
   710  	m map[string]src.XPos
   711  }
   712  
   713  func (s *typeSet) add(pos src.XPos, typ *types.Type) {
   714  	if s.m == nil {
   715  		s.m = make(map[string]src.XPos)
   716  	}
   717  
   718  	ls := typ.LinkString()
   719  	if prev, ok := s.m[ls]; ok {
   720  		base.ErrorfAt(pos, errors.DuplicateCase, "duplicate case %v in type switch\n\tprevious case at %s", typ, base.FmtPos(prev))
   721  		return
   722  	}
   723  	s.m[ls] = pos
   724  }
   725  

View as plain text