Black Lives Matter. Support the Equal Justice Initiative.

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  )
    13  
    14  func RangeExprType(t *types.Type) *types.Type {
    15  	if t.IsPtr() && t.Elem().IsArray() {
    16  		return t.Elem()
    17  	}
    18  	return t
    19  }
    20  
    21  func typecheckrangeExpr(n *ir.RangeStmt) {
    22  	n.X = Expr(n.X)
    23  	if n.X.Type() == nil {
    24  		return
    25  	}
    26  
    27  	t := RangeExprType(n.X.Type())
    28  	// delicate little dance.  see tcAssignList
    29  	if n.Key != nil && !ir.DeclaredBy(n.Key, n) {
    30  		n.Key = AssignExpr(n.Key)
    31  	}
    32  	if n.Value != nil && !ir.DeclaredBy(n.Value, n) {
    33  		n.Value = AssignExpr(n.Value)
    34  	}
    35  
    36  	var tk, tv *types.Type
    37  	toomany := false
    38  	switch t.Kind() {
    39  	default:
    40  		base.ErrorfAt(n.Pos(), "cannot range over %L", n.X)
    41  		return
    42  
    43  	case types.TARRAY, types.TSLICE:
    44  		tk = types.Types[types.TINT]
    45  		tv = t.Elem()
    46  
    47  	case types.TMAP:
    48  		tk = t.Key()
    49  		tv = t.Elem()
    50  
    51  	case types.TCHAN:
    52  		if !t.ChanDir().CanRecv() {
    53  			base.ErrorfAt(n.Pos(), "invalid operation: range %v (receive from send-only type %v)", n.X, n.X.Type())
    54  			return
    55  		}
    56  
    57  		tk = t.Elem()
    58  		tv = nil
    59  		if n.Value != nil {
    60  			toomany = true
    61  		}
    62  
    63  	case types.TSTRING:
    64  		tk = types.Types[types.TINT]
    65  		tv = types.RuneType
    66  	}
    67  
    68  	if toomany {
    69  		base.ErrorfAt(n.Pos(), "too many variables in range")
    70  	}
    71  
    72  	do := func(nn ir.Node, t *types.Type) {
    73  		if nn != nil {
    74  			if ir.DeclaredBy(nn, n) {
    75  				nn.SetType(t)
    76  			} else if nn.Type() != nil {
    77  				if op, why := Assignop(t, nn.Type()); op == ir.OXXX {
    78  					base.ErrorfAt(n.Pos(), "cannot assign type %v to %L in range%s", t, nn, why)
    79  				}
    80  			}
    81  			checkassign(n, nn)
    82  		}
    83  	}
    84  	do(n.Key, tk)
    85  	do(n.Value, tv)
    86  }
    87  
    88  // type check assignment.
    89  // if this assignment is the definition of a var on the left side,
    90  // fill in the var's type.
    91  func tcAssign(n *ir.AssignStmt) {
    92  	if base.EnableTrace && base.Flag.LowerT {
    93  		defer tracePrint("tcAssign", n)(nil)
    94  	}
    95  
    96  	if n.Y == nil {
    97  		n.X = AssignExpr(n.X)
    98  		return
    99  	}
   100  
   101  	lhs, rhs := []ir.Node{n.X}, []ir.Node{n.Y}
   102  	assign(n, lhs, rhs)
   103  	n.X, n.Y = lhs[0], rhs[0]
   104  
   105  	// TODO(mdempsky): This seems out of place.
   106  	if !ir.IsBlank(n.X) {
   107  		types.CheckSize(n.X.Type()) // ensure width is calculated for backend
   108  	}
   109  }
   110  
   111  func tcAssignList(n *ir.AssignListStmt) {
   112  	if base.EnableTrace && base.Flag.LowerT {
   113  		defer tracePrint("tcAssignList", n)(nil)
   114  	}
   115  
   116  	assign(n, n.Lhs, n.Rhs)
   117  }
   118  
   119  func assign(stmt ir.Node, lhs, rhs []ir.Node) {
   120  	// delicate little dance.
   121  	// the definition of lhs may refer to this assignment
   122  	// as its definition, in which case it will call tcAssign.
   123  	// in that case, do not call typecheck back, or it will cycle.
   124  	// if the variable has a type (ntype) then typechecking
   125  	// will not look at defn, so it is okay (and desirable,
   126  	// so that the conversion below happens).
   127  
   128  	checkLHS := func(i int, typ *types.Type) {
   129  		lhs[i] = Resolve(lhs[i])
   130  		if n := lhs[i]; typ != nil && ir.DeclaredBy(n, stmt) && n.Name().Ntype == nil {
   131  			if typ.Kind() != types.TNIL {
   132  				n.SetType(defaultType(typ))
   133  			} else {
   134  				base.Errorf("use of untyped nil")
   135  			}
   136  		}
   137  		if lhs[i].Typecheck() == 0 {
   138  			lhs[i] = AssignExpr(lhs[i])
   139  		}
   140  		checkassign(stmt, lhs[i])
   141  	}
   142  
   143  	assignType := func(i int, typ *types.Type) {
   144  		checkLHS(i, typ)
   145  		if typ != nil {
   146  			checkassignto(typ, lhs[i])
   147  		}
   148  	}
   149  
   150  	cr := len(rhs)
   151  	if len(rhs) == 1 {
   152  		rhs[0] = typecheck(rhs[0], ctxExpr|ctxMultiOK)
   153  		if rtyp := rhs[0].Type(); rtyp != nil && rtyp.IsFuncArgStruct() {
   154  			cr = rtyp.NumFields()
   155  		}
   156  	} else {
   157  		Exprs(rhs)
   158  	}
   159  
   160  	// x, ok = y
   161  assignOK:
   162  	for len(lhs) == 2 && cr == 1 {
   163  		stmt := stmt.(*ir.AssignListStmt)
   164  		r := rhs[0]
   165  
   166  		switch r.Op() {
   167  		case ir.OINDEXMAP:
   168  			stmt.SetOp(ir.OAS2MAPR)
   169  		case ir.ORECV:
   170  			stmt.SetOp(ir.OAS2RECV)
   171  		case ir.ODOTTYPE:
   172  			r := r.(*ir.TypeAssertExpr)
   173  			stmt.SetOp(ir.OAS2DOTTYPE)
   174  			r.SetOp(ir.ODOTTYPE2)
   175  		default:
   176  			break assignOK
   177  		}
   178  
   179  		assignType(0, r.Type())
   180  		assignType(1, types.UntypedBool)
   181  		return
   182  	}
   183  
   184  	if len(lhs) != cr {
   185  		if r, ok := rhs[0].(*ir.CallExpr); ok && len(rhs) == 1 {
   186  			if r.Type() != nil {
   187  				base.ErrorfAt(stmt.Pos(), "assignment mismatch: %d variable%s but %v returns %d value%s", len(lhs), plural(len(lhs)), r.X, cr, plural(cr))
   188  			}
   189  		} else {
   190  			base.ErrorfAt(stmt.Pos(), "assignment mismatch: %d variable%s but %v value%s", len(lhs), plural(len(lhs)), len(rhs), plural(len(rhs)))
   191  		}
   192  
   193  		for i := range lhs {
   194  			checkLHS(i, nil)
   195  		}
   196  		return
   197  	}
   198  
   199  	// x,y,z = f()
   200  	if cr > len(rhs) {
   201  		stmt := stmt.(*ir.AssignListStmt)
   202  		stmt.SetOp(ir.OAS2FUNC)
   203  		r := rhs[0].(*ir.CallExpr)
   204  		r.Use = ir.CallUseList
   205  		rtyp := r.Type()
   206  
   207  		mismatched := false
   208  		failed := false
   209  		for i := range lhs {
   210  			result := rtyp.Field(i).Type
   211  			assignType(i, result)
   212  
   213  			if lhs[i].Type() == nil || result == nil {
   214  				failed = true
   215  			} else if lhs[i] != ir.BlankNode && !types.Identical(lhs[i].Type(), result) {
   216  				mismatched = true
   217  			}
   218  		}
   219  		if mismatched && !failed {
   220  			rewriteMultiValueCall(stmt, r)
   221  		}
   222  		return
   223  	}
   224  
   225  	for i, r := range rhs {
   226  		checkLHS(i, r.Type())
   227  		if lhs[i].Type() != nil {
   228  			rhs[i] = AssignConv(r, lhs[i].Type(), "assignment")
   229  		}
   230  	}
   231  }
   232  
   233  func plural(n int) string {
   234  	if n == 1 {
   235  		return ""
   236  	}
   237  	return "s"
   238  }
   239  
   240  // tcFor typechecks an OFOR node.
   241  func tcFor(n *ir.ForStmt) ir.Node {
   242  	Stmts(n.Init())
   243  	n.Cond = Expr(n.Cond)
   244  	n.Cond = DefaultLit(n.Cond, nil)
   245  	if n.Cond != nil {
   246  		t := n.Cond.Type()
   247  		if t != nil && !t.IsBoolean() {
   248  			base.Errorf("non-bool %L used as for condition", n.Cond)
   249  		}
   250  	}
   251  	n.Post = Stmt(n.Post)
   252  	if n.Op() == ir.OFORUNTIL {
   253  		Stmts(n.Late)
   254  	}
   255  	Stmts(n.Body)
   256  	return n
   257  }
   258  
   259  func tcGoDefer(n *ir.GoDeferStmt) {
   260  	what := "defer"
   261  	if n.Op() == ir.OGO {
   262  		what = "go"
   263  	}
   264  
   265  	switch n.Call.Op() {
   266  	// ok
   267  	case ir.OCALLINTER,
   268  		ir.OCALLMETH,
   269  		ir.OCALLFUNC,
   270  		ir.OCLOSE,
   271  		ir.OCOPY,
   272  		ir.ODELETE,
   273  		ir.OPANIC,
   274  		ir.OPRINT,
   275  		ir.OPRINTN,
   276  		ir.ORECOVER:
   277  		return
   278  
   279  	case ir.OAPPEND,
   280  		ir.OCAP,
   281  		ir.OCOMPLEX,
   282  		ir.OIMAG,
   283  		ir.OLEN,
   284  		ir.OMAKE,
   285  		ir.OMAKESLICE,
   286  		ir.OMAKECHAN,
   287  		ir.OMAKEMAP,
   288  		ir.ONEW,
   289  		ir.OREAL,
   290  		ir.OLITERAL: // conversion or unsafe.Alignof, Offsetof, Sizeof
   291  		if orig := ir.Orig(n.Call); orig.Op() == ir.OCONV {
   292  			break
   293  		}
   294  		base.ErrorfAt(n.Pos(), "%s discards result of %v", what, n.Call)
   295  		return
   296  	}
   297  
   298  	// type is broken or missing, most likely a method call on a broken type
   299  	// we will warn about the broken type elsewhere. no need to emit a potentially confusing error
   300  	if n.Call.Type() == nil || n.Call.Type().Broke() {
   301  		return
   302  	}
   303  
   304  	if !n.Diag() {
   305  		// The syntax made sure it was a call, so this must be
   306  		// a conversion.
   307  		n.SetDiag(true)
   308  		base.ErrorfAt(n.Pos(), "%s requires function call, not conversion", what)
   309  	}
   310  }
   311  
   312  // tcIf typechecks an OIF node.
   313  func tcIf(n *ir.IfStmt) ir.Node {
   314  	Stmts(n.Init())
   315  	n.Cond = Expr(n.Cond)
   316  	n.Cond = DefaultLit(n.Cond, nil)
   317  	if n.Cond != nil {
   318  		t := n.Cond.Type()
   319  		if t != nil && !t.IsBoolean() {
   320  			base.Errorf("non-bool %L used as if condition", n.Cond)
   321  		}
   322  	}
   323  	Stmts(n.Body)
   324  	Stmts(n.Else)
   325  	return n
   326  }
   327  
   328  // range
   329  func tcRange(n *ir.RangeStmt) {
   330  	// Typechecking order is important here:
   331  	// 0. first typecheck range expression (slice/map/chan),
   332  	//	it is evaluated only once and so logically it is not part of the loop.
   333  	// 1. typecheck produced values,
   334  	//	this part can declare new vars and so it must be typechecked before body,
   335  	//	because body can contain a closure that captures the vars.
   336  	// 2. decldepth++ to denote loop body.
   337  	// 3. typecheck body.
   338  	// 4. decldepth--.
   339  	typecheckrangeExpr(n)
   340  
   341  	// second half of dance, the first half being typecheckrangeExpr
   342  	n.SetTypecheck(1)
   343  	if n.Key != nil && n.Key.Typecheck() == 0 {
   344  		n.Key = AssignExpr(n.Key)
   345  	}
   346  	if n.Value != nil && n.Value.Typecheck() == 0 {
   347  		n.Value = AssignExpr(n.Value)
   348  	}
   349  
   350  	Stmts(n.Body)
   351  }
   352  
   353  // tcReturn typechecks an ORETURN node.
   354  func tcReturn(n *ir.ReturnStmt) ir.Node {
   355  	typecheckargs(n)
   356  	if ir.CurFunc == nil {
   357  		base.Errorf("return outside function")
   358  		n.SetType(nil)
   359  		return n
   360  	}
   361  
   362  	if ir.HasNamedResults(ir.CurFunc) && len(n.Results) == 0 {
   363  		return n
   364  	}
   365  	typecheckaste(ir.ORETURN, nil, false, ir.CurFunc.Type().Results(), n.Results, func() string { return "return argument" })
   366  	return n
   367  }
   368  
   369  // select
   370  func tcSelect(sel *ir.SelectStmt) {
   371  	var def *ir.CommClause
   372  	lno := ir.SetPos(sel)
   373  	Stmts(sel.Init())
   374  	for _, ncase := range sel.Cases {
   375  		if ncase.Comm == nil {
   376  			// default
   377  			if def != nil {
   378  				base.ErrorfAt(ncase.Pos(), "multiple defaults in select (first at %v)", ir.Line(def))
   379  			} else {
   380  				def = ncase
   381  			}
   382  		} else {
   383  			n := Stmt(ncase.Comm)
   384  			ncase.Comm = n
   385  			oselrecv2 := func(dst, recv ir.Node, def bool) {
   386  				n := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
   387  				n.Def = def
   388  				n.SetTypecheck(1)
   389  				ncase.Comm = n
   390  			}
   391  			switch n.Op() {
   392  			default:
   393  				pos := n.Pos()
   394  				if n.Op() == ir.ONAME {
   395  					// We don't have the right position for ONAME nodes (see #15459 and
   396  					// others). Using ncase.Pos for now as it will provide the correct
   397  					// line number (assuming the expression follows the "case" keyword
   398  					// on the same line). This matches the approach before 1.10.
   399  					pos = ncase.Pos()
   400  				}
   401  				base.ErrorfAt(pos, "select case must be receive, send or assign recv")
   402  
   403  			case ir.OAS:
   404  				// convert x = <-c into x, _ = <-c
   405  				// remove implicit conversions; the eventual assignment
   406  				// will reintroduce them.
   407  				n := n.(*ir.AssignStmt)
   408  				if r := n.Y; r.Op() == ir.OCONVNOP || r.Op() == ir.OCONVIFACE {
   409  					r := r.(*ir.ConvExpr)
   410  					if r.Implicit() {
   411  						n.Y = r.X
   412  					}
   413  				}
   414  				if n.Y.Op() != ir.ORECV {
   415  					base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
   416  					break
   417  				}
   418  				oselrecv2(n.X, n.Y, n.Def)
   419  
   420  			case ir.OAS2RECV:
   421  				n := n.(*ir.AssignListStmt)
   422  				if n.Rhs[0].Op() != ir.ORECV {
   423  					base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
   424  					break
   425  				}
   426  				n.SetOp(ir.OSELRECV2)
   427  
   428  			case ir.ORECV:
   429  				// convert <-c into _, _ = <-c
   430  				n := n.(*ir.UnaryExpr)
   431  				oselrecv2(ir.BlankNode, n, false)
   432  
   433  			case ir.OSEND:
   434  				break
   435  			}
   436  		}
   437  
   438  		Stmts(ncase.Body)
   439  	}
   440  
   441  	base.Pos = lno
   442  }
   443  
   444  // tcSend typechecks an OSEND node.
   445  func tcSend(n *ir.SendStmt) ir.Node {
   446  	n.Chan = Expr(n.Chan)
   447  	n.Value = Expr(n.Value)
   448  	n.Chan = DefaultLit(n.Chan, nil)
   449  	t := n.Chan.Type()
   450  	if t == nil {
   451  		return n
   452  	}
   453  	if !t.IsChan() {
   454  		base.Errorf("invalid operation: %v (send to non-chan type %v)", n, t)
   455  		return n
   456  	}
   457  
   458  	if !t.ChanDir().CanSend() {
   459  		base.Errorf("invalid operation: %v (send to receive-only type %v)", n, t)
   460  		return n
   461  	}
   462  
   463  	n.Value = AssignConv(n.Value, t.Elem(), "send")
   464  	if n.Value.Type() == nil {
   465  		return n
   466  	}
   467  	return n
   468  }
   469  
   470  // tcSwitch typechecks a switch statement.
   471  func tcSwitch(n *ir.SwitchStmt) {
   472  	Stmts(n.Init())
   473  	if n.Tag != nil && n.Tag.Op() == ir.OTYPESW {
   474  		tcSwitchType(n)
   475  	} else {
   476  		tcSwitchExpr(n)
   477  	}
   478  }
   479  
   480  func tcSwitchExpr(n *ir.SwitchStmt) {
   481  	t := types.Types[types.TBOOL]
   482  	if n.Tag != nil {
   483  		n.Tag = Expr(n.Tag)
   484  		n.Tag = DefaultLit(n.Tag, nil)
   485  		t = n.Tag.Type()
   486  	}
   487  
   488  	var nilonly string
   489  	if t != nil {
   490  		switch {
   491  		case t.IsMap():
   492  			nilonly = "map"
   493  		case t.Kind() == types.TFUNC:
   494  			nilonly = "func"
   495  		case t.IsSlice():
   496  			nilonly = "slice"
   497  
   498  		case !types.IsComparable(t):
   499  			if t.IsStruct() {
   500  				base.ErrorfAt(n.Pos(), "cannot switch on %L (struct containing %v cannot be compared)", n.Tag, types.IncomparableField(t).Type)
   501  			} else {
   502  				base.ErrorfAt(n.Pos(), "cannot switch on %L", n.Tag)
   503  			}
   504  			t = nil
   505  		}
   506  	}
   507  
   508  	var defCase ir.Node
   509  	var cs constSet
   510  	for _, ncase := range n.Cases {
   511  		ls := ncase.List
   512  		if len(ls) == 0 { // default:
   513  			if defCase != nil {
   514  				base.ErrorfAt(ncase.Pos(), "multiple defaults in switch (first at %v)", ir.Line(defCase))
   515  			} else {
   516  				defCase = ncase
   517  			}
   518  		}
   519  
   520  		for i := range ls {
   521  			ir.SetPos(ncase)
   522  			ls[i] = Expr(ls[i])
   523  			ls[i] = DefaultLit(ls[i], t)
   524  			n1 := ls[i]
   525  			if t == nil || n1.Type() == nil {
   526  				continue
   527  			}
   528  
   529  			if nilonly != "" && !ir.IsNil(n1) {
   530  				base.ErrorfAt(ncase.Pos(), "invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Tag)
   531  			} else if t.IsInterface() && !n1.Type().IsInterface() && !types.IsComparable(n1.Type()) {
   532  				base.ErrorfAt(ncase.Pos(), "invalid case %L in switch (incomparable type)", n1)
   533  			} else {
   534  				op1, _ := Assignop(n1.Type(), t)
   535  				op2, _ := Assignop(t, n1.Type())
   536  				if op1 == ir.OXXX && op2 == ir.OXXX {
   537  					if n.Tag != nil {
   538  						base.ErrorfAt(ncase.Pos(), "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Tag, n1.Type(), t)
   539  					} else {
   540  						base.ErrorfAt(ncase.Pos(), "invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type())
   541  					}
   542  				}
   543  			}
   544  
   545  			// Don't check for duplicate bools. Although the spec allows it,
   546  			// (1) the compiler hasn't checked it in the past, so compatibility mandates it, and
   547  			// (2) it would disallow useful things like
   548  			//       case GOARCH == "arm" && GOARM == "5":
   549  			//       case GOARCH == "arm":
   550  			//     which would both evaluate to false for non-ARM compiles.
   551  			if !n1.Type().IsBoolean() {
   552  				cs.add(ncase.Pos(), n1, "case", "switch")
   553  			}
   554  		}
   555  
   556  		Stmts(ncase.Body)
   557  	}
   558  }
   559  
   560  func tcSwitchType(n *ir.SwitchStmt) {
   561  	guard := n.Tag.(*ir.TypeSwitchGuard)
   562  	guard.X = Expr(guard.X)
   563  	t := guard.X.Type()
   564  	if t != nil && !t.IsInterface() {
   565  		base.ErrorfAt(n.Pos(), "cannot type switch on non-interface value %L", guard.X)
   566  		t = nil
   567  	}
   568  
   569  	// We don't actually declare the type switch's guarded
   570  	// declaration itself. So if there are no cases, we won't
   571  	// notice that it went unused.
   572  	if v := guard.Tag; v != nil && !ir.IsBlank(v) && len(n.Cases) == 0 {
   573  		base.ErrorfAt(v.Pos(), "%v declared but not used", v.Sym())
   574  	}
   575  
   576  	var defCase, nilCase ir.Node
   577  	var ts typeSet
   578  	for _, ncase := range n.Cases {
   579  		ls := ncase.List
   580  		if len(ls) == 0 { // default:
   581  			if defCase != nil {
   582  				base.ErrorfAt(ncase.Pos(), "multiple defaults in switch (first at %v)", ir.Line(defCase))
   583  			} else {
   584  				defCase = ncase
   585  			}
   586  		}
   587  
   588  		for i := range ls {
   589  			ls[i] = typecheck(ls[i], ctxExpr|ctxType)
   590  			n1 := ls[i]
   591  			if t == nil || n1.Type() == nil {
   592  				continue
   593  			}
   594  
   595  			var missing, have *types.Field
   596  			var ptr int
   597  			if ir.IsNil(n1) { // case nil:
   598  				if nilCase != nil {
   599  					base.ErrorfAt(ncase.Pos(), "multiple nil cases in type switch (first at %v)", ir.Line(nilCase))
   600  				} else {
   601  					nilCase = ncase
   602  				}
   603  				continue
   604  			}
   605  			if n1.Op() != ir.OTYPE {
   606  				base.ErrorfAt(ncase.Pos(), "%L is not a type", n1)
   607  				continue
   608  			}
   609  			if !n1.Type().IsInterface() && !implements(n1.Type(), t, &missing, &have, &ptr) && !missing.Broke() {
   610  				if have != nil && !have.Broke() {
   611  					base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
   612  						" (wrong type for %v method)\n\thave %v%S\n\twant %v%S", guard.X, n1.Type(), missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
   613  				} else if ptr != 0 {
   614  					base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
   615  						" (%v method has pointer receiver)", guard.X, n1.Type(), missing.Sym)
   616  				} else {
   617  					base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
   618  						" (missing %v method)", guard.X, n1.Type(), missing.Sym)
   619  				}
   620  				continue
   621  			}
   622  
   623  			ts.add(ncase.Pos(), n1.Type())
   624  		}
   625  
   626  		if ncase.Var != nil {
   627  			// Assign the clause variable's type.
   628  			vt := t
   629  			if len(ls) == 1 {
   630  				if ls[0].Op() == ir.OTYPE {
   631  					vt = ls[0].Type()
   632  				} else if !ir.IsNil(ls[0]) {
   633  					// Invalid single-type case;
   634  					// mark variable as broken.
   635  					vt = nil
   636  				}
   637  			}
   638  
   639  			nvar := ncase.Var
   640  			nvar.SetType(vt)
   641  			if vt != nil {
   642  				nvar = AssignExpr(nvar).(*ir.Name)
   643  			} else {
   644  				// Clause variable is broken; prevent typechecking.
   645  				nvar.SetTypecheck(1)
   646  				nvar.SetWalkdef(1)
   647  			}
   648  			ncase.Var = nvar
   649  		}
   650  
   651  		Stmts(ncase.Body)
   652  	}
   653  }
   654  
   655  type typeSet struct {
   656  	m map[string][]typeSetEntry
   657  }
   658  
   659  type typeSetEntry struct {
   660  	pos src.XPos
   661  	typ *types.Type
   662  }
   663  
   664  func (s *typeSet) add(pos src.XPos, typ *types.Type) {
   665  	if s.m == nil {
   666  		s.m = make(map[string][]typeSetEntry)
   667  	}
   668  
   669  	// LongString does not uniquely identify types, so we need to
   670  	// disambiguate collisions with types.Identical.
   671  	// TODO(mdempsky): Add a method that *is* unique.
   672  	ls := typ.LongString()
   673  	prevs := s.m[ls]
   674  	for _, prev := range prevs {
   675  		if types.Identical(typ, prev.typ) {
   676  			base.ErrorfAt(pos, "duplicate case %v in type switch\n\tprevious case at %s", typ, base.FmtPos(prev.pos))
   677  			return
   678  		}
   679  	}
   680  	s.m[ls] = append(prevs, typeSetEntry{pos, typ})
   681  }
   682  

View as plain text