src/go/types/call.go GO 1,056 lines View on github.com → Search inside
1// Copyright 2013 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.45// This file implements typechecking of call and selector expressions.67package types89import (10	"go/ast"11	"go/token"12	. "internal/types/errors"13	"strings"14)1516// funcInst type-checks a function instantiation.17// The incoming x must be a generic function.18// If ix != nil, it provides some or all of the type arguments (ix.Indices).19// If target != nil, it may be used to infer missing type arguments of x, if any.20// At least one of T or ix must be provided.21//22// There are two modes of operation:23//24//  1. If infer == true, funcInst infers missing type arguments as needed and25//     instantiates the function x. The returned results are nil.26//27//  2. If infer == false and inst provides all type arguments, funcInst28//     instantiates the function x. The returned results are nil.29//     If inst doesn't provide enough type arguments, funcInst returns the30//     available arguments; x remains unchanged.31//32// If an error (other than a version error) occurs in any case, it is reported33// and x.mode is set to invalid.34func (check *Checker) funcInst(T *target, pos token.Pos, x *operand, ix *indexedExpr, infer bool) []Type {35	assert(T != nil || ix != nil)3637	var instErrPos positioner38	if ix != nil {39		instErrPos = inNode(ix.orig, ix.lbrack)40		x.expr = ix.orig // if we don't have an index expression, keep the existing expression of x41	} else {42		instErrPos = atPos(pos)43	}44	versionErr := !check.verifyVersionf(instErrPos, go1_18, "function instantiation")4546	// targs and xlist are the type arguments and corresponding type expressions, or nil.47	var targs []Type48	var xlist []ast.Expr49	if ix != nil {50		xlist = ix.indices51		targs = check.typeList(xlist)52		if targs == nil {53			x.invalidate()54			return nil55		}56		assert(len(targs) == len(xlist))57	}5859	// Check the number of type arguments (got) vs number of type parameters (want).60	// Note that x is a function value, not a type expression, so we don't need to61	// call Underlying below.62	sig := x.typ().(*Signature)63	got, want := len(targs), sig.TypeParams().Len()64	if got > want {65		// Providing too many type arguments is always an error.66		check.errorf(ix.indices[got-1], WrongTypeArgCount, "got %d type arguments but want %d", got, want)67		x.invalidate()68		return nil69	}7071	if got < want {72		if !infer {73			return targs74		}7576		// If the uninstantiated or partially instantiated function x is used in77		// an assignment (tsig != nil), infer missing type arguments by treating78		// the assignment79		//80		//    var tvar tsig = x81		//82		// like a call g(tvar) of the synthetic generic function g83		//84		//    func g[type_parameters_of_x](func_type_of_x)85		//86		var args []*operand87		var params []*Var88		var reverse bool89		if T != nil && sig.tparams != nil {90			if !versionErr && !check.allowVersion(go1_21) {91				if ix != nil {92					check.versionErrorf(instErrPos, go1_21, "partially instantiated function in assignment")93				} else {94					check.versionErrorf(instErrPos, go1_21, "implicitly instantiated function in assignment")95				}96			}97			gsig := NewSignatureType(nil, nil, nil, sig.params, sig.results, sig.variadic)98			params = []*Var{NewParam(x.Pos(), check.pkg, "", gsig)}99			// The type of the argument operand is tsig, which is the type of the LHS in an assignment100			// or the result type in a return statement. Create a pseudo-expression for that operand101			// that makes sense when reported in error messages from infer, below.102			expr := ast.NewIdent(T.desc)103			expr.NamePos = x.Pos() // correct position104			args = []*operand{{mode_: value, expr: expr, typ_: T.sig}}105			reverse = true106		}107108		// Rename type parameters to avoid problems with recursive instantiations.109		// Note that NewTuple(params...) below is (*Tuple)(nil) if len(params) == 0, as desired.110		tparams, params2 := check.renameTParams(pos, sig.TypeParams().list(), NewTuple(params...))111112		err := check.newError(CannotInferTypeArgs)113		targs = check.infer(atPos(pos), tparams, targs, params2.(*Tuple), args, reverse, err)114		if targs == nil {115			if !err.empty() {116				err.report()117			}118			x.invalidate()119			return nil120		}121		got = len(targs)122	}123	assert(got == want)124125	// instantiate function signature126	sig = check.instantiateSignature(x.Pos(), x.expr, sig, targs, xlist)127	x.typ_ = sig128	x.mode_ = value129	return nil130}131132func (check *Checker) instantiateSignature(pos token.Pos, expr ast.Expr, typ *Signature, targs []Type, xlist []ast.Expr) (res *Signature) {133	assert(check != nil)134	assert(len(targs) == typ.TypeParams().Len())135136	if check.conf._Trace {137		check.trace(pos, "-- instantiating signature %s with %s", typ, targs)138		check.indent++139		defer func() {140			check.indent--141			check.trace(pos, "=> %s (under = %s)", res, res.Underlying())142		}()143	}144145	// For signatures, Checker.instance will always succeed because the type argument146	// count is correct at this point (see assertion above); hence the type assertion147	// to *Signature will always succeed.148	inst := check.instance(pos, typ, targs, nil, check.context()).(*Signature)149	assert(inst.TypeParams().Len() == 0) // signature is not generic anymore150	check.recordInstance(expr, targs, inst)151	assert(len(xlist) <= len(targs))152153	// verify instantiation lazily (was go.dev/issue/50450)154	check.later(func() {155		tparams := typ.TypeParams().list()156		// check type constraints157		if i, err := check.verify(pos, tparams, targs, check.context()); err != nil {158			// best position for error reporting159			pos := pos160			if i < len(xlist) {161				pos = xlist[i].Pos()162			}163			check.softErrorf(atPos(pos), InvalidTypeArg, "%s", err)164		} else {165			check.mono.recordInstance(check.pkg, pos, tparams, targs, xlist)166		}167	}).describef(atPos(pos), "verify instantiation")168169	return inst170}171172func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind {173	ix := unpackIndexedExpr(call.Fun)174	if ix != nil {175		if check.indexExpr(x, ix) {176			// Delay function instantiation to argument checking,177			// where we combine type and value arguments for type178			// inference.179			assert(x.mode() == value)180		} else {181			ix = nil182		}183		x.expr = call.Fun184		check.record(x)185	} else {186		check.exprOrType(x, call.Fun, true)187	}188	// x.typ may be generic189190	switch x.mode() {191	case invalid:192		check.use(call.Args...)193		x.expr = call194		return statement195196	case typexpr:197		// conversion198		check.nonGeneric(nil, x)199		if !x.isValid() {200			return conversion201		}202		T := x.typ()203		x.invalidate()204		// We cannot convert a value to an incomplete type; make sure it's complete.205		if !check.isComplete(T) {206			x.expr = call207			return conversion208		}209		switch n := len(call.Args); n {210		case 0:211			check.errorf(inNode(call, call.Rparen), WrongArgCount, "missing argument in conversion to %s", T)212		case 1:213			check.expr(newTarget(T, "conversion"), T, x, call.Args[0])214			if x.isValid() {215				if hasDots(call) {216					check.errorf(call.Args[0], BadDotDotDotSyntax, "invalid use of ... in conversion to %s", T)217					break218				}219				if t, _ := T.Underlying().(*Interface); t != nil && !isTypeParam(T) {220					if !t.IsMethodSet() {221						check.errorf(call, MisplacedConstraintIface, "cannot use interface %s in conversion (contains specific type constraints or is comparable)", T)222						break223					}224				}225				check.conversion(x, T)226			}227		default:228			check.use(call.Args...)229			check.errorf(call.Args[n-1], WrongArgCount, "too many arguments in conversion to %s", T)230		}231		x.expr = call232		return conversion233234	case builtin:235		// no need to check for non-genericity here236		id := x.id237		if !check.builtin(x, call, id) {238			x.invalidate()239		}240		x.expr = call241		// a non-constant result implies a function call242		if x.isValid() && x.mode() != constant_ {243			check.hasCallOrRecv = true244		}245		return predeclaredFuncs[id].kind246	}247248	// ordinary function/method call249	// signature may be generic250	cgocall := x.mode() == cgofunc251252	// If the operand type is a type parameter, all types in its type set253	// must have a common underlying type, which must be a signature.254	u, err := commonUnder(x.typ(), func(t, u Type) *typeError {255		if _, ok := u.(*Signature); u != nil && !ok {256			return typeErrorf("%s is not a function", t)257		}258		return nil259	})260	if err != nil {261		check.errorf(x, InvalidCall, invalidOp+"cannot call %s: %s", x, err.format(check))262		x.invalidate()263		x.expr = call264		return statement265	}266	sig := u.(*Signature) // u must be a signature per the commonUnder condition267268	// Capture wasGeneric before sig is potentially instantiated below.269	wasGeneric := sig.TypeParams().Len() > 0270271	// evaluate type arguments, if any272	var xlist []ast.Expr273	var targs []Type274	if ix != nil {275		xlist = ix.indices276		targs = check.typeList(xlist)277		if targs == nil {278			check.use(call.Args...)279			x.invalidate()280			x.expr = call281			return statement282		}283		assert(len(targs) == len(xlist))284285		// check number of type arguments (got) vs number of type parameters (want)286		got, want := len(targs), sig.TypeParams().Len()287		if got > want {288			check.errorf(xlist[want], WrongTypeArgCount, "got %d type arguments but want %d", got, want)289			check.use(call.Args...)290			x.invalidate()291			x.expr = call292			return statement293		}294295		// If sig is generic and all type arguments are provided, preempt function296		// argument type inference by explicitly instantiating the signature. This297		// ensures that we record accurate type information for sig, even if there298		// is an error checking its arguments (for example, if an incorrect number299		// of arguments is supplied).300		if got == want && want > 0 {301			check.verifyVersionf(atPos(ix.lbrack), go1_18, "function instantiation")302			sig = check.instantiateSignature(ix.Pos(), ix.orig, sig, targs, xlist)303			// targs have been consumed; proceed with checking arguments of the304			// non-generic signature.305			targs = nil306			xlist = nil307		}308	}309310	// evaluate arguments311	args, atargs := check.genericExprList(sig.argType, call.Args)312	sig = check.arguments(call, sig, targs, xlist, args, atargs)313314	if wasGeneric && sig.TypeParams().Len() == 0 {315		// Update the recorded type of call.Fun to its instantiated type.316		check.recordTypeAndValue(call.Fun, value, sig, nil)317	}318319	// determine result320	switch sig.results.Len() {321	case 0:322		x.mode_ = novalue323	case 1:324		if cgocall {325			x.mode_ = commaerr326		} else {327			x.mode_ = value328		}329		typ := sig.results.vars[0].typ // unpack tuple330		// We cannot return a value of an incomplete type; make sure it's complete.331		if !check.isComplete(typ) {332			x.invalidate()333			x.expr = call334			return statement335		}336		x.typ_ = typ337	default:338		x.mode_ = value339		x.typ_ = sig.results340	}341	x.expr = call342	check.hasCallOrRecv = true343344	// if type inference failed, a parameterized result must be invalidated345	// (operands cannot have a parameterized type)346	if x.mode() == value && sig.TypeParams().Len() > 0 && isParameterized(sig.TypeParams().list(), x.typ()) {347		x.invalidate()348	}349350	return statement351}352353// exprList evaluates a list of expressions and returns the corresponding operands.354// A single-element expression list may evaluate to multiple operands.355func (check *Checker) exprList(elist []ast.Expr) (xlist []*operand) {356	if n := len(elist); n == 1 {357		xlist, _ = check.multiExpr(elist[0], false)358	} else if n > 1 {359		// multiple (possibly invalid) values360		xlist = make([]*operand, n)361		for i, e := range elist {362			var x operand363			check.expr(nil, nil, &x, e)364			xlist[i] = &x365		}366	}367	return368}369370// genericExprList is like exprList but result operands may be uninstantiated or partially371// instantiated generic functions (where constraint information is insufficient to infer372// the missing type arguments) for Go 1.21 and later. Additionally, typeAt must return the373// corresponding target type for each operand, or nil if none exists.374// For each non-generic or uninstantiated generic operand, the corresponding targsList and375// elements do not exist (targsList is nil) or the elements are nil.376// For each partially instantiated generic function operand, the corresponding377// targsList elements are the operand's partial type arguments.378func (check *Checker) genericExprList(typeAt func(int) Type, elist []ast.Expr) (resList []*operand, targsList [][]Type) {379	if debug {380		defer func() {381			// type arguments must only exist for partially instantiated functions382			for i, x := range resList {383				if i < len(targsList) {384					if n := len(targsList[i]); n > 0 {385						// x must be a partially instantiated function386						assert(n < x.typ().(*Signature).TypeParams().Len())387					}388				}389			}390		}()391	}392393	// Before Go 1.21, uninstantiated or partially instantiated argument functions are394	// not permitted. Checker.funcInst must infer missing type arguments in that case.395	infer := true // for -lang < go1.21396	n := len(elist)397	if n > 0 && check.allowVersion(go1_21) {398		infer = false399	}400401	if n == 1 {402		// single value (possibly a partially instantiated function), or a multi-valued expression403		e := elist[0]404		var x operand405		if ix := unpackIndexedExpr(e); ix != nil && check.indexExpr(&x, ix) {406			// x is a generic function.407			targs := check.funcInst(nil, x.Pos(), &x, ix, infer)408			if targs != nil {409				// x was not instantiated: collect the (partial) type arguments.410				targsList = [][]Type{targs}411				// Update x.expr so that we can record the partially instantiated function.412				x.expr = ix.orig413			} else {414				// x was instantiated: we must record it here because we didn't415				// use the usual expression evaluators.416				check.record(&x)417			}418			resList = []*operand{&x}419		} else {420			// x is not a function instantiation (it may still be a generic function).421			check.rawExpr(nil, typeAt(0), &x, e, nil, true)422			check.exclude(&x, 1<<novalue|1<<builtin|1<<typexpr)423			if t, ok := x.typ().(*Tuple); ok && x.isValid() {424				// x is a function call returning multiple values; it cannot be generic.425				resList = make([]*operand, t.Len())426				for i, v := range t.vars {427					resList[i] = &operand{mode_: value, expr: e, typ_: v.typ}428				}429			} else {430				// x is exactly one value (possibly invalid or uninstantiated generic function).431				resList = []*operand{&x}432			}433		}434	} else if n > 1 {435		// multiple values436		resList = make([]*operand, n)437		targsList = make([][]Type, n)438		for i, e := range elist {439			var x operand440			if ix := unpackIndexedExpr(e); ix != nil && check.indexExpr(&x, ix) {441				// x is a generic function.442				targs := check.funcInst(nil, x.Pos(), &x, ix, infer)443				if targs != nil {444					// x was not instantiated: collect the (partial) type arguments.445					targsList[i] = targs446					// Update x.expr so that we can record the partially instantiated function.447					x.expr = ix.orig448				} else {449					// x was instantiated: we must record it here because we didn't450					// use the usual expression evaluators.451					check.record(&x)452				}453			} else {454				// x is exactly one value (possibly invalid or uninstantiated generic function).455				check.genericExpr(typeAt(i), &x, e, nil)456			}457			resList[i] = &x458		}459	}460461	return462}463464// arguments type-checks arguments passed to a function call with the given signature.465// The function and its arguments may be generic, and possibly partially instantiated.466// targs and xlist are the function's type arguments (and corresponding expressions).467// args are the function arguments. If an argument args[i] is a partially instantiated468// generic function, atargs[i] are the corresponding type arguments.469// If the callee is variadic, arguments adjusts its signature to match the provided470// arguments. The type parameters and arguments of the callee and all its arguments471// are used together to infer any missing type arguments, and the callee and argument472// functions are instantiated as necessary.473// The result signature is the (possibly adjusted and instantiated) function signature.474// If an error occurred, the result signature is the incoming sig.475func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type, xlist []ast.Expr, args []*operand, atargs [][]Type) (rsig *Signature) {476	rsig = sig477478	// Function call argument/parameter count requirements479	//480	//               | standard call    | dotdotdot call |481	// --------------+------------------+----------------+482	// standard func | nargs == npars   | invalid        |483	// --------------+------------------+----------------+484	// variadic func | nargs >= npars-1 | nargs == npars |485	// --------------+------------------+----------------+486487	nargs := len(args)488	npars := sig.params.Len()489	ddd := hasDots(call)490491	// set up parameters492	sigParams := sig.params // adjusted for variadic functions (may be nil for empty parameter lists!)493	adjusted := false       // indicates if sigParams is different from sig.params494	if sig.variadic {495		if ddd {496			// variadic_func(a, b, c...)497			if len(call.Args) == 1 && nargs > 1 {498				// f()... is not permitted if f() is multi-valued499				check.errorf(inNode(call, call.Ellipsis), InvalidDotDotDot, "cannot use ... with %d-valued %s", nargs, call.Args[0])500				return501			}502		} else {503			// variadic_func(a, b, c)504			if nargs >= npars-1 {505				// Create custom parameters for arguments: keep506				// the first npars-1 parameters and add one for507				// each argument mapping to the ... parameter.508				vars := make([]*Var, npars-1) // npars > 0 for variadic functions509				copy(vars, sig.params.vars)510				last := sig.params.vars[npars-1]511				typ := last.typ.(*Slice).elem512				for len(vars) < nargs {513					vars = append(vars, NewParam(last.pos, last.pkg, last.name, typ))514				}515				sigParams = NewTuple(vars...) // possibly nil!516				adjusted = true517				npars = nargs518			} else {519				// nargs < npars-1520				npars-- // for correct error message below521			}522		}523	} else {524		if ddd {525			// standard_func(a, b, c...)526			check.errorf(inNode(call, call.Ellipsis), NonVariadicDotDotDot, "cannot use ... in call to non-variadic %s", call.Fun)527			return528		}529		// standard_func(a, b, c)530	}531532	// check argument count533	if nargs != npars {534		var at positioner = call535		qualifier := "not enough"536		if nargs > npars {537			at = args[npars].expr // report at first extra argument538			qualifier = "too many"539		} else {540			at = atPos(call.Rparen) // report at closing )541		}542		// take care of empty parameter lists represented by nil tuples543		var params []*Var544		if sig.params != nil {545			params = sig.params.vars546		}547		err := check.newError(WrongArgCount)548		err.addf(at, "%s arguments in call to %s", qualifier, call.Fun)549		err.addf(noposn, "have %s", check.typesSummary(operandTypes(args), false, ddd))550		err.addf(noposn, "want %s", check.typesSummary(varTypes(params), sig.variadic, false))551		err.report()552		return553	}554555	// collect type parameters of callee and generic function arguments556	var tparams []*TypeParam557558	// collect type parameters of callee559	n := sig.TypeParams().Len()560	if n > 0 {561		if !check.allowVersion(go1_18) {562			switch call.Fun.(type) {563			case *ast.IndexExpr, *ast.IndexListExpr:564				ix := unpackIndexedExpr(call.Fun)565				check.versionErrorf(inNode(call.Fun, ix.lbrack), go1_18, "function instantiation")566			default:567				check.versionErrorf(inNode(call, call.Lparen), go1_18, "implicit function instantiation")568			}569		}570		// rename type parameters to avoid problems with recursive calls571		var tmp Type572		tparams, tmp = check.renameTParams(call.Pos(), sig.TypeParams().list(), sigParams)573		sigParams = tmp.(*Tuple)574		// make sure targs and tparams have the same length575		for len(targs) < len(tparams) {576			targs = append(targs, nil)577		}578	}579	assert(len(tparams) == len(targs))580581	// collect type parameters from generic function arguments582	var genericArgs []int // indices of generic function arguments583	if enableReverseTypeInference {584		for i, arg := range args {585			// generic arguments cannot have a defined (*Named) type - no need for underlying type below586			if asig, _ := arg.typ().(*Signature); asig != nil && asig.TypeParams().Len() > 0 {587				// The argument type is a generic function signature. This type is588				// pointer-identical with (it's copied from) the type of the generic589				// function argument and thus the function object.590				// Before we change the type (type parameter renaming, below), make591				// a clone of it as otherwise we implicitly modify the object's type592				// (go.dev/issues/63260).593				asig = clone(asig)594				// Rename type parameters for cases like f(g, g); this gives each595				// generic function argument a unique type identity (go.dev/issues/59956).596				// TODO(gri) Consider only doing this if a function argument appears597				//           multiple times, which is rare (possible optimization).598				atparams, tmp := check.renameTParams(call.Pos(), asig.TypeParams().list(), asig)599				asig = tmp.(*Signature)600				asig.tparams = &TypeParamList{atparams} // renameTParams doesn't touch associated type parameters601				arg.typ_ = asig                         // new type identity for the function argument602				tparams = append(tparams, atparams...)603				// add partial list of type arguments, if any604				if i < len(atargs) {605					targs = append(targs, atargs[i]...)606				}607				// make sure targs and tparams have the same length608				for len(targs) < len(tparams) {609					targs = append(targs, nil)610				}611				genericArgs = append(genericArgs, i)612			}613		}614	}615	assert(len(tparams) == len(targs))616617	// at the moment we only support implicit instantiations of argument functions618	_ = len(genericArgs) > 0 && check.verifyVersionf(args[genericArgs[0]], go1_21, "implicitly instantiated function as argument")619620	// tparams holds the type parameters of the callee and generic function arguments, if any:621	// the first n type parameters belong to the callee, followed by mi type parameters for each622	// of the generic function arguments, where mi = args[i].typ.(*Signature).TypeParams().Len().623624	// infer missing type arguments of callee and function arguments625	if len(tparams) > 0 {626		err := check.newError(CannotInferTypeArgs)627		targs = check.infer(call, tparams, targs, sigParams, args, false, err)628		if targs == nil {629			// TODO(gri) If infer inferred the first targs[:n], consider instantiating630			//           the call signature for better error messages/gopls behavior.631			//           Perhaps instantiate as much as we can, also for arguments.632			//           This will require changes to how infer returns its results.633			if !err.empty() {634				check.errorf(err.posn(), CannotInferTypeArgs, "in call to %s, %s", call.Fun, err.msg())635			}636			return637		}638639		// update result signature: instantiate if needed640		if n > 0 {641			rsig = check.instantiateSignature(call.Pos(), call.Fun, sig, targs[:n], xlist)642			// If the callee's parameter list was adjusted we need to update (instantiate)643			// it separately. Otherwise we can simply use the result signature's parameter644			// list.645			if adjusted {646				sigParams = check.subst(call.Pos(), sigParams, makeSubstMap(tparams[:n], targs[:n]), nil, check.context()).(*Tuple)647			} else {648				sigParams = rsig.params649			}650		}651652		// compute argument signatures: instantiate if needed653		j := n654		for _, i := range genericArgs {655			arg := args[i]656			asig := arg.typ().(*Signature)657			k := j + asig.TypeParams().Len()658			// targs[j:k] are the inferred type arguments for asig659			arg.typ_ = check.instantiateSignature(call.Pos(), arg.expr, asig, targs[j:k], nil) // TODO(gri) provide xlist if possible (partial instantiations)660			check.record(arg)                                                                  // record here because we didn't use the usual expr evaluators661			j = k662		}663	}664665	// check arguments666	if len(args) > 0 {667		context := check.sprintf("argument to %s", call.Fun)668		for i, a := range args {669			check.assignment(a, sigParams.vars[i].typ, context)670		}671	}672673	return674}675676var cgoPrefixes = [...]string{677	"_Ciconst_",678	"_Cfconst_",679	"_Csconst_",680	"_Ctype_",681	"_Cvar_", // actually a pointer to the var682	"_Cfpvar_fp_",683	"_Cfunc_",684	"_Cmacro_", // function to evaluate the expanded expression685}686687func (check *Checker) selector(x *operand, e *ast.SelectorExpr, wantType bool) {688	// these must be declared before the "goto Error" statements689	var (690		obj      Object691		index    []int692		indirect bool693	)694695	sel := e.Sel.Name696	// If the identifier refers to a package, handle everything here697	// so we don't need a "package" mode for operands: package names698	// can only appear in qualified identifiers which are mapped to699	// selector expressions.700	if ident, ok := e.X.(*ast.Ident); ok {701		obj := check.lookup(ident.Name)702		if pname, _ := obj.(*PkgName); pname != nil {703			assert(pname.pkg == check.pkg)704			check.recordUse(ident, pname)705			check.usedPkgNames[pname] = true706			pkg := pname.imported707708			var exp Object709			funcMode := value710			if pkg.cgo {711				// cgo special cases C.malloc: it's712				// rewritten to _CMalloc and does not713				// support two-result calls.714				if sel == "malloc" {715					sel = "_CMalloc"716				} else {717					funcMode = cgofunc718				}719				for _, prefix := range cgoPrefixes {720					// cgo objects are part of the current package (in file721					// _cgo_gotypes.go). Use regular lookup.722					exp = check.lookup(prefix + sel)723					if exp != nil {724						break725					}726				}727				if exp == nil {728					if isValidName(sel) {729						check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s", ast.Expr(e)) // cast to ast.Expr to silence vet730					}731					goto Error732				}733				check.objDecl(exp)734			} else {735				exp = pkg.scope.Lookup(sel)736				if exp == nil {737					if !pkg.fake && isValidName(sel) {738						// Try to give a better error message when selector matches an object name ignoring case.739						exps := pkg.scope.lookupIgnoringCase(sel, true)740						if len(exps) >= 1 {741							// report just the first one742							check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s (but have %s)", ast.Expr(e), exps[0].Name())743						} else {744							check.errorf(e.Sel, UndeclaredImportedName, "undefined: %s", ast.Expr(e))745						}746					}747					goto Error748				}749				if !exp.Exported() {750					check.errorf(e.Sel, UnexportedName, "name %s not exported by package %s", sel, pkg.name)751					// ok to continue752				}753			}754			check.recordUse(e.Sel, exp)755756			// Simplified version of the code for *ast.Idents:757			// - imported objects are always fully initialized758			switch exp := exp.(type) {759			case *Const:760				assert(exp.Val() != nil)761				x.mode_ = constant_762				x.typ_ = exp.typ763				x.val = exp.val764			case *TypeName:765				x.mode_ = typexpr766				x.typ_ = exp.typ767			case *Var:768				x.mode_ = variable769				x.typ_ = exp.typ770				if pkg.cgo && strings.HasPrefix(exp.name, "_Cvar_") {771					x.typ_ = x.typ().(*Pointer).base772				}773			case *Func:774				x.mode_ = funcMode775				x.typ_ = exp.typ776				if pkg.cgo && strings.HasPrefix(exp.name, "_Cmacro_") {777					x.mode_ = value778					x.typ_ = x.typ().(*Signature).results.vars[0].typ779				}780			case *Builtin:781				x.mode_ = builtin782				x.typ_ = exp.typ783				x.id = exp.id784			default:785				check.dump("%v: unexpected object %v", e.Sel.Pos(), exp)786				panic("unreachable")787			}788			x.expr = e789			return790		}791	}792793	check.exprOrType(x, e.X, false)794	switch x.mode() {795	case builtin:796		// types2 uses the position of '.' for the error797		check.errorf(e.Sel, UncalledBuiltin, "invalid use of %s in selector expression", x)798		goto Error799	case invalid:800		goto Error801	}802803	// We cannot select on an incomplete type; make sure it's complete.804	if !check.isComplete(x.typ()) {805		goto Error806	}807808	// Avoid crashing when checking an invalid selector in a method declaration.809	//810	//   type S[T any] struct{}811	//   type V = S[any]812	//   func (fs *S[T]) M(x V.M) {}813	//814	// All codepaths below return a non-type expression. If we get here while815	// expecting a type expression, it is an error.816	//817	// See go.dev/issue/57522 for more details.818	if wantType {819		check.errorf(e.Sel, NotAType, "%s is not a type", ast.Expr(e))820		goto Error821	}822823	// Additionally, if x.typ is a pointer type, selecting implicitly dereferences the value, meaning824	// its base type must also be complete.825	if p, ok := x.typ().Underlying().(*Pointer); ok && !check.isComplete(p.base) {826		goto Error827	}828829	obj, index, indirect = lookupFieldOrMethod(x.typ(), x.mode() == variable, check.pkg, sel, false)830	if obj == nil {831		// Don't report another error if the underlying type was invalid (go.dev/issue/49541).832		if !isValid(x.typ().Underlying()) {833			goto Error834		}835836		if index != nil {837			// TODO(gri) should provide actual type where the conflict happens838			check.errorf(e.Sel, AmbiguousSelector, "ambiguous selector %s.%s", x.expr, sel)839			goto Error840		}841842		if indirect {843			if x.mode() == typexpr {844				check.errorf(e.Sel, InvalidMethodExpr, "invalid method expression %s.%s (needs pointer receiver (*%s).%s)", x.typ(), sel, x.typ(), sel)845			} else {846				check.errorf(e.Sel, InvalidMethodExpr, "cannot call pointer method %s on %s", sel, x.typ())847			}848			goto Error849		}850851		var why string852		if isInterfacePtr(x.typ()) {853			why = check.interfacePtrError(x.typ())854		} else {855			alt, _, _ := lookupFieldOrMethod(x.typ(), x.mode() == variable, check.pkg, sel, true)856			why = check.lookupError(x.typ(), sel, alt, false)857		}858		check.errorf(e.Sel, MissingFieldOrMethod, "%s.%s undefined (%s)", x.expr, sel, why)859		goto Error860	}861	// obj != nil862863	switch obj := obj.(type) {864	case *Var:865		if x.mode() == typexpr {866			check.errorf(e.X, MissingFieldOrMethod, "operand for field selector %s must be value of type %s", sel, x.typ())867			goto Error868		}869870		// field value871		check.recordSelection(e, FieldVal, x.typ(), obj, index, indirect)872		if x.mode() == variable || indirect {873			x.mode_ = variable874		} else {875			x.mode_ = value876		}877		x.typ_ = obj.typ878879	case *Func:880		check.objDecl(obj) // ensure fully set-up signature881		check.addDeclDep(obj)882		// TODO(mark): Assert that sig.rparams is nil here?883884		if x.mode() == typexpr {885			// method expression886			check.recordSelection(e, MethodExpr, x.typ(), obj, index, indirect)887888			sig := obj.typ.(*Signature)889			if sig.recv == nil {890				check.error(e, InvalidDeclCycle, "illegal cycle in method declaration")891				goto Error892			}893894			// The receiver type becomes the type of the first function895			// argument of the method expression's function type.896			var params []*Var897			if sig.params != nil {898				params = sig.params.vars899			}900			// Be consistent about named/unnamed parameters. This is not needed901			// for type-checking, but the newly constructed signature may appear902			// in an error message and then have mixed named/unnamed parameters.903			// (An alternative would be to not print parameter names in errors,904			// but it's useful to see them; this is cheap and method expressions905			// are rare.)906			name := ""907			if len(params) > 0 && params[0].name != "" {908				// name needed909				name = sig.recv.name910				if name == "" {911					name = "_"912				}913			}914			params = append([]*Var{NewParam(sig.recv.pos, sig.recv.pkg, name, x.typ())}, params...)915			x.mode_ = value916			x.typ_ = &Signature{917				tparams:  sig.tparams,918				recvold:  methodExprSentinel,919				params:   NewTuple(params...),920				results:  sig.results,921				variadic: sig.variadic,922			}923		} else {924			// method value925926			// TODO(gri) If we needed to take into account the receiver's927			// addressability, should we report the type &(x.typ) instead?928			check.recordSelection(e, MethodVal, x.typ(), obj, index, indirect)929930			// TODO(gri) The verification pass below is disabled for now because931			//           method sets don't match method lookup in some cases.932			//           For instance, if we made a copy above when creating a933			//           custom method for a parameterized received type, the934			//           method set method doesn't match (no copy there). There935			///          may be other situations.936			disabled := true937			if !disabled && debug {938				// Verify that LookupFieldOrMethod and MethodSet.Lookup agree.939				// TODO(gri) This only works because we call LookupFieldOrMethod940				// _before_ calling NewMethodSet: LookupFieldOrMethod completes941				// any incomplete interfaces so they are available to NewMethodSet942				// (which assumes that interfaces have been completed already).943				typ := x.typ_944				if x.mode() == variable {945					// If typ is not an (unnamed) pointer or an interface,946					// use *typ instead, because the method set of *typ947					// includes the methods of typ.948					// Variables are addressable, so we can always take their949					// address.950					if _, ok := typ.(*Pointer); !ok && !IsInterface(typ) {951						typ = &Pointer{base: typ}952					}953				}954				// If we created a synthetic pointer type above, we will throw955				// away the method set computed here after use.956				// TODO(gri) Method set computation should probably always compute957				// both, the value and the pointer receiver method set and represent958				// them in a single structure.959				// TODO(gri) Consider also using a method set cache for the lifetime960				// of checker once we rely on MethodSet lookup instead of individual961				// lookup.962				mset := NewMethodSet(typ)963				if m := mset.Lookup(check.pkg, sel); m == nil || m.obj != obj {964					check.dump("%v: (%s).%v -> %s", e.Pos(), typ, obj.name, m)965					check.dump("%s\n", mset)966					// Caution: MethodSets are supposed to be used externally967					// only (after all interface types were completed). It's968					// now possible that we get here incorrectly. Not urgent969					// to fix since we only run this code in debug mode.970					// TODO(gri) fix this eventually.971					panic("method sets and lookup don't agree")972				}973			}974975			x.mode_ = value976977			// remove/stash receiver978			sig := *obj.typ.(*Signature)979			sig.recvold = sig.recv980			sig.recv = nil981			x.typ_ = &sig982		}983984	default:985		panic("unreachable")986	}987988	// everything went well989	x.expr = e990	return991992Error:993	x.invalidate()994	x.typ_ = Typ[Invalid]995	x.expr = e996}997998// use type-checks each argument.999// Useful to make sure expressions are evaluated1000// (and variables are "used") in the presence of1001// other errors. Arguments may be nil.1002// Reports if all arguments evaluated without error.1003func (check *Checker) use(args ...ast.Expr) bool { return check.useN(args, false) }10041005// useLHS is like use, but doesn't "use" top-level identifiers.1006// It should be called instead of use if the arguments are1007// expressions on the lhs of an assignment.1008func (check *Checker) useLHS(args ...ast.Expr) bool { return check.useN(args, true) }10091010func (check *Checker) useN(args []ast.Expr, lhs bool) bool {1011	ok := true1012	for _, e := range args {1013		if !check.use1(e, lhs) {1014			ok = false1015		}1016	}1017	return ok1018}10191020func (check *Checker) use1(e ast.Expr, lhs bool) bool {1021	var x operand1022	x.mode_ = value // anything but invalid1023	switch n := ast.Unparen(e).(type) {1024	case nil:1025		// nothing to do1026	case *ast.Ident:1027		// don't report an error evaluating blank1028		if n.Name == "_" {1029			break1030		}1031		// If the lhs is an identifier denoting a variable v, this assignment1032		// is not a 'use' of v. Remember current value of v.used and restore1033		// after evaluating the lhs via check.rawExpr.1034		var v *Var1035		var v_used bool1036		if lhs {1037			if obj := check.lookup(n.Name); obj != nil {1038				// It's ok to mark non-local variables, but ignore variables1039				// from other packages to avoid potential race conditions with1040				// dot-imported variables.1041				if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {1042					v = w1043					v_used = check.usedVars[v]1044				}1045			}1046		}1047		check.exprOrType(&x, n, true)1048		if v != nil {1049			check.usedVars[v] = v_used // restore v.used1050		}1051	default:1052		check.rawExpr(nil, nil, &x, e, nil, true)1053	}1054	return x.isValid()1055}

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.