// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file implements initialization and assignment checks.

package types

import (
	
	
	
)

// assignment reports whether x can be assigned to a variable of type T,
// if necessary by attempting to convert untyped values to the appropriate
// type. context describes the context in which the assignment takes place.
// Use T == nil to indicate assignment to an untyped blank identifier.
// x.mode is set to invalid if the assignment failed.
func ( *Checker) ( *operand,  Type,  string) {
	.singleValue()

	switch .mode {
	case invalid:
		return // error reported before
	case constant_, variable, mapindex, value, commaok, commaerr:
		// ok
	default:
		// we may get here because of other problems (issue #39634, crash 12)
		.errorf(, 0, "cannot assign %s to %s in %s", , , )
		return
	}

	if isUntyped(.typ) {
		 := 
		// spec: "If an untyped constant is assigned to a variable of interface
		// type or the blank identifier, the constant is first converted to type
		// bool, rune, int, float64, complex128 or string respectively, depending
		// on whether the value is a boolean, rune, integer, floating-point,
		// complex, or string constant."
		if  == nil || IsInterface() && !isTypeParam() {
			if  == nil && .typ == Typ[UntypedNil] {
				.errorf(, _UntypedNil, "use of untyped nil in %s", )
				.mode = invalid
				return
			}
			 = Default(.typ)
		}
		, ,  := .implicitTypeAndValue(, )
		if  != 0 {
			 := .sprintf("cannot use %s as %s value in %s", , , )
			switch  {
			case _TruncatedFloat:
				 += " (truncated)"
			case _NumericOverflow:
				 += " (overflows)"
			default:
				 = _IncompatibleAssign
			}
			.error(, , )
			.mode = invalid
			return
		}
		if  != nil {
			.val = 
			.updateExprVal(.expr, )
		}
		if  != .typ {
			.typ = 
			.updateExprType(.expr, , false)
		}
	}

	// A generic (non-instantiated) function value cannot be assigned to a variable.
	if ,  := under(.typ).(*Signature);  != nil && .TypeParams().Len() > 0 {
		.errorf(, _WrongTypeArgCount, "cannot use generic function %s without instantiation in %s", , )
	}

	// spec: "If a left-hand side is the blank identifier, any typed or
	// non-constant value except for the predeclared identifier nil may
	// be assigned to it."
	if  == nil {
		return
	}

	 := ""
	if ,  := .assignableTo(, , &); ! {
		if compilerErrorMessages {
			if  != "" {
				.errorf(, , "cannot use %s as type %s in %s:\n\t%s", , , , )
			} else {
				.errorf(, , "cannot use %s as type %s in %s", , , )
			}
		} else {
			if  != "" {
				.errorf(, , "cannot use %s as %s value in %s: %s", , , , )
			} else {
				.errorf(, , "cannot use %s as %s value in %s", , , )
			}
		}
		.mode = invalid
	}
}

func ( *Checker) ( *Const,  *operand) {
	if .mode == invalid || .typ == Typ[Invalid] || .typ == Typ[Invalid] {
		if .typ == nil {
			.typ = Typ[Invalid]
		}
		return
	}

	// rhs must be a constant
	if .mode != constant_ {
		.errorf(, _InvalidConstInit, "%s is not constant", )
		if .typ == nil {
			.typ = Typ[Invalid]
		}
		return
	}
	assert(isConstType(.typ))

	// If the lhs doesn't have a type yet, use the type of x.
	if .typ == nil {
		.typ = .typ
	}

	.assignment(, .typ, "constant declaration")
	if .mode == invalid {
		return
	}

	.val = .val
}

func ( *Checker) ( *Var,  *operand,  string) Type {
	if .mode == invalid || .typ == Typ[Invalid] || .typ == Typ[Invalid] {
		if .typ == nil {
			.typ = Typ[Invalid]
		}
		return nil
	}

	// If the lhs doesn't have a type yet, use the type of x.
	if .typ == nil {
		 := .typ
		if isUntyped() {
			// convert untyped types to default types
			if  == Typ[UntypedNil] {
				.errorf(, _UntypedNil, "use of untyped nil in %s", )
				.typ = Typ[Invalid]
				return nil
			}
			 = Default()
		}
		.typ = 
	}

	.assignment(, .typ, )
	if .mode == invalid {
		return nil
	}

	return .typ
}

func ( *Checker) ( ast.Expr,  *operand) Type {
	if .mode == invalid || .typ == Typ[Invalid] {
		.useLHS()
		return nil
	}

	// Determine if the lhs is a (possibly parenthesized) identifier.
	,  := unparen().(*ast.Ident)

	// Don't evaluate lhs if it is the blank identifier.
	if  != nil && .Name == "_" {
		.recordDef(, nil)
		.assignment(, nil, "assignment to _ identifier")
		if .mode == invalid {
			return nil
		}
		return .typ
	}

	// If the lhs is an identifier denoting a variable v, this assignment
	// is not a 'use' of v. Remember current value of v.used and restore
	// after evaluating the lhs via check.expr.
	var  *Var
	var  bool
	if  != nil {
		if  := .lookup(.Name);  != nil {
			// It's ok to mark non-local variables, but ignore variables
			// from other packages to avoid potential race conditions with
			// dot-imported variables.
			if ,  := .(*Var);  != nil && .pkg == .pkg {
				 = 
				 = .used
			}
		}
	}

	var  operand
	.expr(&, )
	if  != nil {
		.used =  // restore v.used
	}

	if .mode == invalid || .typ == Typ[Invalid] {
		return nil
	}

	// spec: "Each left-hand side operand must be addressable, a map index
	// expression, or the blank identifier. Operands may be parenthesized."
	switch .mode {
	case invalid:
		return nil
	case variable, mapindex:
		// ok
	default:
		if ,  := .expr.(*ast.SelectorExpr);  {
			var  operand
			.expr(&, .X)
			if .mode == mapindex {
				.errorf(&, _UnaddressableFieldAssign, "cannot assign to struct field %s in map", ExprString(.expr))
				return nil
			}
		}
		.errorf(&, _UnassignableOperand, "cannot assign to %s", &)
		return nil
	}

	.assignment(, .typ, "assignment")
	if .mode == invalid {
		return nil
	}

	return .typ
}

// operandTypes returns the list of types for the given operands.
func ( []*operand) ( []Type) {
	for ,  := range  {
		 = append(, .typ)
	}
	return 
}

// varTypes returns the list of types for the given variables.
func ( []*Var) ( []Type) {
	for ,  := range  {
		 = append(, .typ)
	}
	return 
}

// typesSummary returns a string of the form "(t1, t2, ...)" where the
// ti's are user-friendly string representations for the given types.
// If variadic is set and the last type is a slice, its string is of
// the form "...E" where E is the slice's element type.
func ( *Checker) ( []Type,  bool) string {
	var  []string
	for ,  := range  {
		var  string
		switch {
		case  == nil:
			fallthrough // should not happen but be cautious
		case  == Typ[Invalid]:
			 = "<T>"
		case isUntyped():
			if isNumeric() {
				// Do not imply a specific type requirement:
				// "have number, want float64" is better than
				// "have untyped int, want float64" or
				// "have int, want float64".
				 = "number"
			} else {
				// If we don't have a number, omit the "untyped" qualifier
				// for compactness.
				 = strings.Replace(.(*Basic).name, "untyped ", "", -1)
			}
		case  &&  == len()-1:
			 = .sprintf("...%s", .(*Slice).elem)
		}
		if  == "" {
			 = .sprintf("%s", )
		}
		 = append(, )
	}
	return "(" + strings.Join(, ", ") + ")"
}

func ( int,  string) string {
	if  != 1 {
		 += "s"
	}
	return fmt.Sprintf("%d %s", , )
}

func ( *Checker) ( []ast.Expr, ,  int) {
	 := measure(, "variable")
	 := measure(, "value")
	 := [0]

	if len() == 1 {
		if ,  := unparen().(*ast.CallExpr);  != nil {
			.errorf(, _WrongAssignCount, "assignment mismatch: %s but %s returns %s", , .Fun, )
			return
		}
	}
	.errorf(, _WrongAssignCount, "assignment mismatch: %s but %s", , )
}

// If returnStmt != nil, initVars is called to type-check the assignment
// of return expressions, and returnStmt is the return statement.
func ( *Checker) ( []*Var,  []ast.Expr,  ast.Stmt) {
	,  := .exprList(, len() == 2 &&  == nil)

	if len() != len() {
		// invalidate lhs
		for ,  := range  {
			.used = true // avoid declared but not used errors
			if .typ == nil {
				.typ = Typ[Invalid]
			}
		}
		// don't report an error if we already reported one
		for ,  := range  {
			if .mode == invalid {
				return
			}
		}
		if  != nil {
			var  positioner = 
			 := "not enough"
			if len() > len() {
				 = [len()].expr // report at first extra value
				 = "too many"
			} else if len() > 0 {
				 = [len()-1].expr // report at last value
			}
			.errorf(, _WrongResultCount, "%s return values\n\thave %s\n\twant %s",
				,
				.typesSummary(operandTypes(), false),
				.typesSummary(varTypes(), false),
			)
			return
		}
		if compilerErrorMessages {
			.assignError(, len(), len())
		} else {
			.errorf([0], _WrongAssignCount, "cannot initialize %d variables with %d values", len(), len())
		}
		return
	}

	 := "assignment"
	if  != nil {
		 = "return statement"
	}

	if  {
		var  [2]Type
		for  := range  {
			[] = .initVar([], [], )
		}
		.recordCommaOkTypes([0], )
		return
	}

	for ,  := range  {
		.initVar(, [], )
	}
}

func ( *Checker) (,  []ast.Expr) {
	,  := .exprList(, len() == 2)

	if len() != len() {
		.useLHS(...)
		// don't report an error if we already reported one
		for ,  := range  {
			if .mode == invalid {
				return
			}
		}
		if compilerErrorMessages {
			.assignError(, len(), len())
		} else {
			.errorf([0], _WrongAssignCount, "cannot assign %d values to %d variables", len(), len())
		}
		return
	}

	if  {
		var  [2]Type
		for  := range  {
			[] = .assignVar([], [])
		}
		.recordCommaOkTypes([0], )
		return
	}

	for ,  := range  {
		.assignVar(, [])
	}
}

func ( *Checker) ( positioner, ,  []ast.Expr) {
	 := len(.delayed)
	 := .scope

	// collect lhs variables
	 := make(map[string]bool, len())
	 := make([]*Var, len())
	 := make([]*Var, 0, len())
	 := false
	for ,  := range  {
		,  := .(*ast.Ident)
		if  == nil {
			.useLHS()
			// TODO(rFindley) this is redundant with a parser error. Consider omitting?
			.errorf(, _BadDecl, "non-name %s on left side of :=", )
			 = true
			continue
		}

		 := .Name
		if  != "_" {
			if [] {
				.errorf(, _RepeatedDecl, "%s repeated on left side of :=", )
				 = true
				continue
			}
			[] = true
		}

		// Use the correct obj if the ident is redeclared. The
		// variable's scope starts after the declaration; so we
		// must use Scope.Lookup here and call Scope.Insert
		// (via check.declare) later.
		if  := .Lookup();  != nil {
			.recordUse(, )
			// redeclared object must be a variable
			if ,  := .(*Var);  != nil {
				[] = 
			} else {
				.errorf(, _UnassignableOperand, "cannot assign to %s", )
				 = true
			}
			continue
		}

		// declare new variable
		 := NewVar(.Pos(), .pkg, , nil)
		[] = 
		if  != "_" {
			 = append(, )
		}
		.recordDef(, )
	}

	// create dummy variables where the lhs is invalid
	for ,  := range  {
		if  == nil {
			[] = NewVar([].Pos(), .pkg, "_", nil)
		}
	}

	.initVars(, , nil)

	// process function literals in rhs expressions before scope changes
	.processDelayed()

	if len() == 0 && ! {
		.softErrorf(, _NoNewVar, "no new variables on left side of :=")
		return
	}

	// declare new variables
	// spec: "The scope of a constant or variable identifier declared inside
	// a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
	// for short variable declarations) and ends at the end of the innermost
	// containing block."
	 := [len()-1].End()
	for ,  := range  {
		.declare(, nil, , ) // id = nil: recordDef already called
	}
}