Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/compile: type inference could be less strict when there are interface arguments #40055

Open
rogpeppe opened this issue Jul 5, 2020 · 7 comments
Labels
NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. TypeInference Issue is related to generic type inference
Milestone

Comments

@rogpeppe
Copy link
Contributor

rogpeppe commented Jul 5, 2020

The following program fails:

func Equal(type T comparable)(x, y T) bool {
	return x == y
} 

func main() {
	var x interface{} = 5
	var y = 5

	fmt.Println(Equal(x, y))
}

The error is:

prog.go2:15:23: type int of y does not match inferred type interface{} for T

Although it's true that the types don't match exactly, it seems to me that it might be nice
to allow the type argument to unify to interface{} in the same way that we allow
a concrete type to be passed to an interface type.

@mmaedel
Copy link

mmaedel commented Jul 5, 2020

hi @rogpeppe
i am with you and if with a 'comparable', it would be nice to even have it in basic types...

this:

func main() {
var x interface{} = 5
var y = 6.1

fmt.Println(Equal(x, interface{}(y)))

}

should also work for:

func main() {
var x = 5
var y = 6.1

fmt.Println(Equal(x, y))

}

@ianlancetaylor
Copy link
Contributor

I am very concerned about avoiding any possible confusion in which type inference does not act as people expect. This is based on the complexity of the C++ equivalent to type inference, which observably confuses people. I would rather say that if there is any confusion, the programmer must explicitly state the desired type.

@cagedmantis cagedmantis added this to the Unplanned milestone Jul 6, 2020
@dmitshur dmitshur added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Jul 7, 2020
@bcmills
Copy link
Contributor

bcmills commented Jul 17, 2020

I too would like to see better type inference here, but I think this is the sort of refinement that can (and should!) wait until after the initial implementation and release of generics, so that we can gather empirical evidence to weigh the cost (of more difficulty reasoning about inference) against the benefit (of avoiding the verbosity and distraction of “obvious” annotations).

@griesemer griesemer added the TypeInference Issue is related to generic type inference label Mar 7, 2023
@griesemer griesemer changed the title cmd/go2go: type inference could be less strict when there are interface arguments cmd/compile: type inference could be less strict when there are interface arguments Mar 8, 2023
@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Mar 8, 2023
@griesemer
Copy link
Contributor

Updated playground link (new syntax).

The idea here in its simple-most form is that if multiple function arguments have the same type parameter type, the "most general" type parameter type should be chosen.

In this example, x and y have the same type parameter type T and the argument types are interface{} and int. Since int values can be assigned to interface{} variables, T should be inferred to be interface{}.

It gets complicated very quickly (e.g., argument types are different interface types that build a type hierarchy, or channel types with different directions, etc.).

In any case, this needs a concrete proposal describing what's in scope.

@griesemer griesemer added NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. and removed NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. labels May 19, 2023
@griesemer
Copy link
Contributor

If we say that a non-interface type V unifies with an interface type T if V implements T under unification, this code will work. (If V is a type parameter that doesn't have a type inferred for it yet, then we infer T for V, of course.)

@griesemer
Copy link
Contributor

A simple experiment shows that the suggested approach does indeed work for simple cases. But it falls apart in more complex situations. Example:

func f[T any](x T, _ ...T) T { return x }

func _() {
        var x any
        var i int
        var s string

        x = f(x)
        x = f(x, i)
        x = f(i, x)

        x = f(x, i, s)
        x = f(x, s, i)
        x = f(i, x, s)
        x = f(i, x, x)
        x = f(s, x, i)
        x = f(s, i, x) // ERROR "type int of i does not match inferred type string for T"
}

This code works but for the last assignment: because x (of interface type) is checked at the end (not as first or second argument), the inferred type for T is already string and we get an error when we check i. In all other cases, either we infer the interface right away, or we can correct to the interface.

In order to do this truly correctly, unification would have to build a type set whenever we unify two types: unification of two types x, y would need to union x and y. At the end, if we end up with simple types or type sets (interfaces), that a) may be valid Go types (or not => inference fails), b) may satisfy constraints (or not => instantiation fails), or we may end up with the empty set (=> inference fails).

We're not set up for computing unions during unification at this point. This will have to wait a bit.

@griesemer
Copy link
Contributor

Quick follow-up: What we can do relatively easily is to check if a union is possible in the first place. For instance, if we try to unify two interfaces, or an interface with a non-interface type, methods that exist with both types must unify. If they don't, a union is not possible (methods with the same name that have different signatures are in conflict). That check will allow the inference of type parameters that occur in the signatures of corresponding methods.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. TypeInference Issue is related to generic type inference
Projects
None yet
Development

No branches or pull requests

8 participants