// 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 typechecking of call and selector expressions.

package types

import (
	
	
	
	. 
	
	
)

// funcInst type-checks a function instantiation inst and returns the result in x.
// The operand x must be the evaluation of inst.X and its type must be a signature.
func ( *Checker) ( *operand,  *typeparams.IndexExpr) {
	if !.allowVersion(.pkg, 1, 18) {
		.softErrorf(inNode(.Orig, .Lbrack), UnsupportedFeature, "function instantiation requires go1.18 or later")
	}

	 := .typeList(.Indices)
	if  == nil {
		.mode = invalid
		.expr = .Orig
		return
	}
	assert(len() == len(.Indices))

	// check number of type arguments (got) vs number of type parameters (want)
	 := .typ.(*Signature)
	,  := len(), .TypeParams().Len()
	if  >  {
		.errorf(.Indices[-1], WrongTypeArgCount, "got %d type arguments but want %d", , )
		.mode = invalid
		.expr = .Orig
		return
	}

	if  <  {
		 = .infer(.Orig, .TypeParams().list(), , nil, nil)
		if  == nil {
			// error was already reported
			.mode = invalid
			.expr = .Orig
			return
		}
		 = len()
	}
	assert( == )

	// instantiate function signature
	 = .instantiateSignature(.Pos(), , , .Indices)
	assert(.TypeParams().Len() == 0) // signature is not generic anymore
	.recordInstance(.Orig, , )
	.typ = 
	.mode = value
	.expr = .Orig
}

func ( *Checker) ( token.Pos,  *Signature,  []Type,  []ast.Expr) ( *Signature) {
	assert( != nil)
	assert(len() == .TypeParams().Len())

	if trace {
		.trace(, "-- instantiating signature %s with %s", , )
		.indent++
		defer func() {
			.indent--
			.trace(, "=> %s (under = %s)", , .Underlying())
		}()
	}

	 := .instance(, , , nil, .context()).(*Signature)
	assert(len() <= len())

	// verify instantiation lazily (was issue #50450)
	.later(func() {
		 := .TypeParams().list()
		if ,  := .verify(, , , .context());  != nil {
			// best position for error reporting
			 := 
			if  < len() {
				 = [].Pos()
			}
			.softErrorf(atPos(), InvalidTypeArg, "%s", )
		} else {
			.mono.recordInstance(.pkg, , , , )
		}
	}).describef(atPos(), "verify instantiation")

	return 
}

func ( *Checker) ( *operand,  *ast.CallExpr) exprKind {
	 := typeparams.UnpackIndexExpr(.Fun)
	if  != nil {
		if .indexExpr(, ) {
			// Delay function instantiation to argument checking,
			// where we combine type and value arguments for type
			// inference.
			assert(.mode == value)
		} else {
			 = nil
		}
		.expr = .Fun
		.record()
	} else {
		.exprOrType(, .Fun, true)
	}
	// x.typ may be generic

	switch .mode {
	case invalid:
		.use(.Args...)
		.expr = 
		return statement

	case typexpr:
		// conversion
		.nonGeneric()
		if .mode == invalid {
			return conversion
		}
		 := .typ
		.mode = invalid
		switch  := len(.Args);  {
		case 0:
			.errorf(inNode(, .Rparen), WrongArgCount, "missing argument in conversion to %s", )
		case 1:
			.expr(, .Args[0])
			if .mode != invalid {
				if .Ellipsis.IsValid() {
					.errorf(.Args[0], BadDotDotDotSyntax, "invalid use of ... in conversion to %s", )
					break
				}
				if ,  := under().(*Interface);  != nil && !isTypeParam() {
					if !.IsMethodSet() {
						.errorf(, MisplacedConstraintIface, "cannot use interface %s in conversion (contains specific type constraints or is comparable)", )
						break
					}
				}
				.conversion(, )
			}
		default:
			.use(.Args...)
			.errorf(.Args[-1], WrongArgCount, "too many arguments in conversion to %s", )
		}
		.expr = 
		return conversion

	case builtin:
		// no need to check for non-genericity here
		 := .id
		if !.builtin(, , ) {
			.mode = invalid
		}
		.expr = 
		// a non-constant result implies a function call
		if .mode != invalid && .mode != constant_ {
			.hasCallOrRecv = true
		}
		return predeclaredFuncs[].kind
	}

	// ordinary function/method call
	// signature may be generic
	 := .mode == cgofunc

	// a type parameter may be "called" if all types have the same signature
	,  := coreType(.typ).(*Signature)
	if  == nil {
		.errorf(, InvalidCall, invalidOp+"cannot call non-function %s", )
		.mode = invalid
		.expr = 
		return statement
	}

	// Capture wasGeneric before sig is potentially instantiated below.
	 := .TypeParams().Len() > 0

	// evaluate type arguments, if any
	var  []ast.Expr
	var  []Type
	if  != nil {
		 = .Indices
		 = .typeList()
		if  == nil {
			.use(.Args...)
			.mode = invalid
			.expr = 
			return statement
		}
		assert(len() == len())

		// check number of type arguments (got) vs number of type parameters (want)
		,  := len(), .TypeParams().Len()
		if  >  {
			.errorf([], WrongTypeArgCount, "got %d type arguments but want %d", , )
			.use(.Args...)
			.mode = invalid
			.expr = 
			return statement
		}

		// If sig is generic and all type arguments are provided, preempt function
		// argument type inference by explicitly instantiating the signature. This
		// ensures that we record accurate type information for sig, even if there
		// is an error checking its arguments (for example, if an incorrect number
		// of arguments is supplied).
		if  ==  &&  > 0 {
			if !.allowVersion(.pkg, 1, 18) {
				.softErrorf(inNode(.Fun, .Lbrack), UnsupportedFeature, "function instantiation requires go1.18 or later")
			}

			 = .instantiateSignature(.Pos(), , , )
			assert(.TypeParams().Len() == 0) // signature is not generic anymore
			.recordInstance(.Orig, , )

			// targs have been consumed; proceed with checking arguments of the
			// non-generic signature.
			 = nil
			 = nil
		}
	}

	// evaluate arguments
	,  := .exprList(.Args, false)
	 = .arguments(, , , , )

	if  && .TypeParams().Len() == 0 {
		// Update the recorded type of call.Fun to its instantiated type.
		.recordTypeAndValue(.Fun, value, , nil)
	}

	// determine result
	switch .results.Len() {
	case 0:
		.mode = novalue
	case 1:
		if  {
			.mode = commaerr
		} else {
			.mode = value
		}
		.typ = .results.vars[0].typ // unpack tuple
	default:
		.mode = value
		.typ = .results
	}
	.expr = 
	.hasCallOrRecv = true

	// if type inference failed, a parametrized result must be invalidated
	// (operands cannot have a parametrized type)
	if .mode == value && .TypeParams().Len() > 0 && isParameterized(.TypeParams().list(), .typ) {
		.mode = invalid
	}

	return statement
}

func ( *Checker) ( []ast.Expr,  bool) ( []*operand,  bool) {
	switch len() {
	case 0:
		// nothing to do

	case 1:
		// single (possibly comma-ok) value, or function returning multiple values
		 := [0]
		var  operand
		.multiExpr(&, )
		if ,  := .typ.(*Tuple);  && .mode != invalid {
			// multiple values
			 = make([]*operand, .Len())
			for ,  := range .vars {
				[] = &operand{mode: value, expr: , typ: .typ}
			}
			break
		}

		// exactly one (possibly invalid or comma-ok) value
		 = []*operand{&}
		if  && (.mode == mapindex || .mode == commaok || .mode == commaerr) {
			 := &operand{mode: value, expr: , typ: Typ[UntypedBool]}
			if .mode == commaerr {
				.typ = universeError
			}
			 = append(, )
			 = true
		}

	default:
		// multiple (possibly invalid) values
		 = make([]*operand, len())
		for ,  := range  {
			var  operand
			.expr(&, )
			[] = &
		}
	}

	return
}

// xlist is the list of type argument expressions supplied in the source code.
func ( *Checker) ( *ast.CallExpr,  *Signature,  []Type,  []*operand,  []ast.Expr) ( *Signature) {
	 = 

	// TODO(gri) try to eliminate this extra verification loop
	for ,  := range  {
		switch .mode {
		case typexpr:
			.errorf(, NotAnExpr, "%s used as value", )
			return
		case invalid:
			return
		}
	}

	// Function call argument/parameter count requirements
	//
	//               | standard call    | dotdotdot call |
	// --------------+------------------+----------------+
	// standard func | nargs == npars   | invalid        |
	// --------------+------------------+----------------+
	// variadic func | nargs >= npars-1 | nargs == npars |
	// --------------+------------------+----------------+

	 := len()
	 := .params.Len()
	 := .Ellipsis.IsValid()

	// set up parameters
	 := .params // adjusted for variadic functions (may be nil for empty parameter lists!)
	 := false       // indicates if sigParams is different from t.params
	if .variadic {
		if  {
			// variadic_func(a, b, c...)
			if len(.Args) == 1 &&  > 1 {
				// f()... is not permitted if f() is multi-valued
				.errorf(inNode(, .Ellipsis), InvalidDotDotDot, "cannot use ... with %d-valued %s", , .Args[0])
				return
			}
		} else {
			// variadic_func(a, b, c)
			if  >= -1 {
				// Create custom parameters for arguments: keep
				// the first npars-1 parameters and add one for
				// each argument mapping to the ... parameter.
				 := make([]*Var, -1) // npars > 0 for variadic functions
				copy(, .params.vars)
				 := .params.vars[-1]
				 := .typ.(*Slice).elem
				for len() <  {
					 = append(, NewParam(.pos, .pkg, .name, ))
				}
				 = NewTuple(...) // possibly nil!
				 = true
				 = 
			} else {
				// nargs < npars-1
				-- // for correct error message below
			}
		}
	} else {
		if  {
			// standard_func(a, b, c...)
			.errorf(inNode(, .Ellipsis), NonVariadicDotDotDot, "cannot use ... in call to non-variadic %s", .Fun)
			return
		}
		// standard_func(a, b, c)
	}

	// check argument count
	if  !=  {
		var  positioner = 
		 := "not enough"
		if  >  {
			 = [].expr // report at first extra argument
			 = "too many"
		} else {
			 = atPos(.Rparen) // report at closing )
		}
		// take care of empty parameter lists represented by nil tuples
		var  []*Var
		if .params != nil {
			 = .params.vars
		}
		 := newErrorf(, WrongArgCount, "%s arguments in call to %s", , .Fun)
		.errorf(token.NoPos, "have %s", .typesSummary(operandTypes(), false))
		.errorf(token.NoPos, "want %s", .typesSummary(varTypes(), .variadic))
		.report()
		return
	}

	// infer type arguments and instantiate signature if necessary
	if .TypeParams().Len() > 0 {
		if !.allowVersion(.pkg, 1, 18) {
			switch .Fun.(type) {
			case *ast.IndexExpr, *ast.IndexListExpr:
				 := typeparams.UnpackIndexExpr(.Fun)
				.softErrorf(inNode(.Fun, .Lbrack), UnsupportedFeature, "function instantiation requires go1.18 or later")
			default:
				.softErrorf(inNode(, .Lparen), UnsupportedFeature, "implicit function instantiation requires go1.18 or later")
			}
		}
		 := .infer(, .TypeParams().list(), , , )
		if  == nil {
			return // error already reported
		}

		// compute result signature
		 = .instantiateSignature(.Pos(), , , )
		assert(.TypeParams().Len() == 0) // signature is not generic anymore
		.recordInstance(.Fun, , )

		// Optimization: Only if the parameter list was adjusted do we
		// need to compute it from the adjusted list; otherwise we can
		// simply use the result signature's parameter list.
		if  {
			 = .subst(.Pos(), , makeSubstMap(.TypeParams().list(), ), nil, .context()).(*Tuple)
		} else {
			 = .params
		}
	}

	// check arguments
	if len() > 0 {
		 := .sprintf("argument to %s", .Fun)
		for ,  := range  {
			.assignment(, .vars[].typ, )
		}
	}

	return
}

var cgoPrefixes = [...]string{
	"_Ciconst_",
	"_Cfconst_",
	"_Csconst_",
	"_Ctype_",
	"_Cvar_", // actually a pointer to the var
	"_Cfpvar_fp_",
	"_Cfunc_",
	"_Cmacro_", // function to evaluate the expanded expression
}

func ( *Checker) ( *operand,  *ast.SelectorExpr,  *Named) {
	// these must be declared before the "goto Error" statements
	var (
		      Object
		    []int
		 bool
	)

	 := .Sel.Name
	// If the identifier refers to a package, handle everything here
	// so we don't need a "package" mode for operands: package names
	// can only appear in qualified identifiers which are mapped to
	// selector expressions.
	if ,  := .X.(*ast.Ident);  {
		 := .lookup(.Name)
		if ,  := .(*PkgName);  != nil {
			assert(.pkg == .pkg)
			.recordUse(, )
			.used = true
			 := .imported

			var  Object
			 := value
			if .cgo {
				// cgo special cases C.malloc: it's
				// rewritten to _CMalloc and does not
				// support two-result calls.
				if  == "malloc" {
					 = "_CMalloc"
				} else {
					 = cgofunc
				}
				for ,  := range cgoPrefixes {
					// cgo objects are part of the current package (in file
					// _cgo_gotypes.go). Use regular lookup.
					_,  = .scope.LookupParent(+, .pos)
					if  != nil {
						break
					}
				}
				if  == nil {
					.errorf(.Sel, UndeclaredImportedName, "undefined: %s", ast.Expr()) // cast to ast.Expr to silence vet
					goto 
				}
				.objDecl(, nil)
			} else {
				 = .scope.Lookup()
				if  == nil {
					if !.fake {
						.errorf(.Sel, UndeclaredImportedName, "undefined: %s", ast.Expr())
					}
					goto 
				}
				if !.Exported() {
					.errorf(.Sel, UnexportedName, "%s not exported by package %s", , .name)
					// ok to continue
				}
			}
			.recordUse(.Sel, )

			// Simplified version of the code for *ast.Idents:
			// - imported objects are always fully initialized
			switch exp := .(type) {
			case *Const:
				assert(.Val() != nil)
				.mode = constant_
				.typ = .typ
				.val = .val
			case *TypeName:
				.mode = typexpr
				.typ = .typ
			case *Var:
				.mode = variable
				.typ = .typ
				if .cgo && strings.HasPrefix(.name, "_Cvar_") {
					.typ = .typ.(*Pointer).base
				}
			case *Func:
				.mode = 
				.typ = .typ
				if .cgo && strings.HasPrefix(.name, "_Cmacro_") {
					.mode = value
					.typ = .typ.(*Signature).results.vars[0].typ
				}
			case *Builtin:
				.mode = builtin
				.typ = .typ
				.id = .id
			default:
				.dump("%v: unexpected object %v", .Sel.Pos(), )
				unreachable()
			}
			.expr = 
			return
		}
	}

	.exprOrType(, .X, false)
	switch .mode {
	case typexpr:
		// don't crash for "type T T.x" (was issue #51509)
		if  != nil && .typ ==  {
			.cycleError([]Object{.obj})
			goto 
		}
	case builtin:
		// types2 uses the position of '.' for the error
		.errorf(.Sel, UncalledBuiltin, "cannot select on %s", )
		goto 
	case invalid:
		goto 
	}

	, ,  = LookupFieldOrMethod(.typ, .mode == variable, .pkg, )
	if  == nil {
		// Don't report another error if the underlying type was invalid (issue #49541).
		if under(.typ) == Typ[Invalid] {
			goto 
		}

		if  != nil {
			// TODO(gri) should provide actual type where the conflict happens
			.errorf(.Sel, AmbiguousSelector, "ambiguous selector %s.%s", .expr, )
			goto 
		}

		if  {
			if .mode == typexpr {
				.errorf(.Sel, InvalidMethodExpr, "invalid method expression %s.%s (needs pointer receiver (*%s).%s)", .typ, , .typ, )
			} else {
				.errorf(.Sel, InvalidMethodExpr, "cannot call pointer method %s on %s", , .typ)
			}
			goto 
		}

		var  string
		if isInterfacePtr(.typ) {
			 = .interfacePtrError(.typ)
		} else {
			 = .sprintf("type %s has no field or method %s", .typ, )
			// Check if capitalization of sel matters and provide better error message in that case.
			// TODO(gri) This code only looks at the first character but LookupFieldOrMethod should
			//           have an (internal) mechanism for case-insensitive lookup that we should use
			//           instead (see types2).
			if len() > 0 {
				var  string
				if  := rune([0]); unicode.IsUpper() {
					 = string(unicode.ToLower()) + [1:]
				} else {
					 = string(unicode.ToUpper()) + [1:]
				}
				if , _, _ = LookupFieldOrMethod(.typ, .mode == variable, .pkg, );  != nil {
					 += ", but does have " + 
				}
			}
		}
		.errorf(.Sel, MissingFieldOrMethod, "%s.%s undefined (%s)", .expr, , )
		goto 
	}

	// methods may not have a fully set up signature yet
	if ,  := .(*Func);  != nil {
		.objDecl(, nil)
	}

	if .mode == typexpr {
		// method expression
		,  := .(*Func)
		if  == nil {
			// TODO(gri) should check if capitalization of sel matters and provide better error message in that case
			.errorf(.Sel, MissingFieldOrMethod, "%s.%s undefined (type %s has no method %s)", .expr, , .typ, )
			goto 
		}

		.recordSelection(, MethodExpr, .typ, , , )

		 := .typ.(*Signature)
		if .recv == nil {
			.error(, InvalidDeclCycle, "illegal cycle in method declaration")
			goto 
		}

		// the receiver type becomes the type of the first function
		// argument of the method expression's function type
		var  []*Var
		if .params != nil {
			 = .params.vars
		}
		// Be consistent about named/unnamed parameters. This is not needed
		// for type-checking, but the newly constructed signature may appear
		// in an error message and then have mixed named/unnamed parameters.
		// (An alternative would be to not print parameter names in errors,
		// but it's useful to see them; this is cheap and method expressions
		// are rare.)
		 := ""
		if len() > 0 && [0].name != "" {
			// name needed
			 = .recv.name
			if  == "" {
				 = "_"
			}
		}
		 = append([]*Var{NewVar(.recv.pos, .recv.pkg, , .typ)}, ...)
		.mode = value
		.typ = &Signature{
			tparams:  .tparams,
			params:   NewTuple(...),
			results:  .results,
			variadic: .variadic,
		}

		.addDeclDep()

	} else {
		// regular selector
		switch obj := .(type) {
		case *Var:
			.recordSelection(, FieldVal, .typ, , , )
			if .mode == variable ||  {
				.mode = variable
			} else {
				.mode = value
			}
			.typ = .typ

		case *Func:
			// TODO(gri) If we needed to take into account the receiver's
			// addressability, should we report the type &(x.typ) instead?
			.recordSelection(, MethodVal, .typ, , , )

			// TODO(gri) The verification pass below is disabled for now because
			//           method sets don't match method lookup in some cases.
			//           For instance, if we made a copy above when creating a
			//           custom method for a parameterized received type, the
			//           method set method doesn't match (no copy there). There
			///          may be other situations.
			 := true
			if ! && debug {
				// Verify that LookupFieldOrMethod and MethodSet.Lookup agree.
				// TODO(gri) This only works because we call LookupFieldOrMethod
				// _before_ calling NewMethodSet: LookupFieldOrMethod completes
				// any incomplete interfaces so they are available to NewMethodSet
				// (which assumes that interfaces have been completed already).
				 := .typ
				if .mode == variable {
					// If typ is not an (unnamed) pointer or an interface,
					// use *typ instead, because the method set of *typ
					// includes the methods of typ.
					// Variables are addressable, so we can always take their
					// address.
					if ,  := .(*Pointer); ! && !IsInterface() {
						 = &Pointer{base: }
					}
				}
				// If we created a synthetic pointer type above, we will throw
				// away the method set computed here after use.
				// TODO(gri) Method set computation should probably always compute
				// both, the value and the pointer receiver method set and represent
				// them in a single structure.
				// TODO(gri) Consider also using a method set cache for the lifetime
				// of checker once we rely on MethodSet lookup instead of individual
				// lookup.
				 := NewMethodSet()
				if  := .Lookup(.pkg, );  == nil || .obj !=  {
					.dump("%v: (%s).%v -> %s", .Pos(), , .name, )
					.dump("%s\n", )
					// Caution: MethodSets are supposed to be used externally
					// only (after all interface types were completed). It's
					// now possible that we get here incorrectly. Not urgent
					// to fix since we only run this code in debug mode.
					// TODO(gri) fix this eventually.
					panic("method sets and lookup don't agree")
				}
			}

			.mode = value

			// remove receiver
			 := *.typ.(*Signature)
			.recv = nil
			.typ = &

			.addDeclDep()

		default:
			unreachable()
		}
	}

	// everything went well
	.expr = 
	return

:
	.mode = invalid
	.expr = 
}

// use type-checks each argument.
// Useful to make sure expressions are evaluated
// (and variables are "used") in the presence of other errors.
// The arguments may be nil.
func ( *Checker) ( ...ast.Expr) {
	var  operand
	for ,  := range  {
		// The nil check below is necessary since certain AST fields
		// may legally be nil (e.g., the ast.SliceExpr.High field).
		if  != nil {
			.rawExpr(&, , nil, false)
		}
	}
}

// useLHS is like use, but doesn't "use" top-level identifiers.
// It should be called instead of use if the arguments are
// expressions on the lhs of an assignment.
// The arguments must not be nil.
func ( *Checker) ( ...ast.Expr) {
	var  operand
	for ,  := range  {
		// 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.rawExpr.
		var  *Var
		var  bool
		if ,  := unparen().(*ast.Ident);  != nil {
			// never type-check the blank name on the lhs
			if .Name == "_" {
				continue
			}
			if ,  := .scope.LookupParent(.Name, token.NoPos);  != 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
				}
			}
		}
		.rawExpr(&, , nil, false)
		if  != nil {
			.used =  // restore v.used
		}
	}
}