...

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

Documentation: cmd/compile/internal/typecheck

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

View as plain text