-
Notifications
You must be signed in to change notification settings - Fork 18.5k
Description
Currently, a statement like a = b may require an implicit conversion of b to a's type before the assignment can happen. In particular, for conversions to interface type, these generally require a run-time operation to change the value representation. (An implicit conversion can also happen for assignments between defined types and their underlying type literal or assignments from unrestricted channel types to send/receive-only channel types; but these are more of a formality, since Go implementations in practice use identical value representations for these cases.)
go/types provides enough information for users to infer/reconstruct these implicit conversions, but go/types already has to handle this as part of type checking anyway. So we might as well surface the information to users, so they don't have to remember all of the cases where implicit conversions happen.
My thoughts were along the lines of either:
- Add a
types.Info.ImplicitTypesmap of typemap[ast.Expr]types.Type, which will record the type that the expression needs to be implicitly converted, if it differs fromtypes.Info.Types[e].Type. (E.g., forvar x int = int(42),int(42)would not need an entry in this map, becauseint(42)is already the same type as it's assigned to; butvar x interface{} = int(42)would have an entry.) - Same idea, but extend
types.TypeAndValuewith an extraImplicit Typefield. Might be simpler/cleaner in some use cases, but it also implies more memory consumption (which I think at least gopls is very sensitive to).
Further, for N:1 assignments, I'd suggest the ImplicitTypes be present and a synthesized Tuple type if any of the respective tuple elements need implicit conversion. For example:
type MyBool bool
var f func() (int, int)
var g func(interface{}, interface{})
var a int
var b interface{}
var x MyBool
a, b = f() // 'f()' has Type (int, int); but ImplicitType (int, interface{}), due to assignment to a,b
g(f()) // 'f()' has Type (int, int); but ImplicitType (interface{}, interface{}), due to passing to g()
b, x = b.(int) // 'b.(int)' has Type (int, MyBool†); but ImplicitType (interface{}, MyBool), due to assignment to b,x
// † cmd/compile's legacy typechecker produces 'MyBool' in this case, but I think 'bool' or 'untyped bool' would be okay too
Incidentally, I think having a way to record separate types for the expression in isolation vs expression in context could help with cases like #13061.
/cc @griesemer @findleyr
Metadata
Metadata
Assignees
Labels
Type
Projects
Status