// Copyright 2023 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.

package p

// The type parameter P is not used in interface T1.
// T1 is a defined parameterized interface type which
// can be assigned to any other interface with the same
// methods. We cannot infer a type argument in this case
// because any type would do.

type T1[P any] interface{ m() }

func g[P any](T1[P]) {}

func _() {
	var x T1[int]
	g /* ERROR "cannot infer P" */ (x)
	g[int](x)    // int is ok for P
	g[string](x) // string is also ok for P!
}

// This is analogous to the above example,
// but uses two interface types of the same structure.

type T2[P any] interface{ m() }

func _() {
	var x T2[int]
	g /* ERROR "cannot infer P" */ (x)
	g[int](x)    // int is ok for P
	g[string](x) // string is also ok for P!
}

// Analogous to the T2 example but using an unparameterized interface T3.

type T3 interface{ m() }

func _() {
	var x T3
	g /* ERROR "cannot infer P" */ (x)
	g[int](x)    // int is ok for P
	g[string](x) // string is also ok for P!
}

// The type parameter P is not used in struct S.
// S is a defined parameterized (non-interface) type which can only
// be assigned to another type S with the same type argument.
// Therefore we can infer a type argument in this case.

type S[P any] struct{}

func g4[P any](S[P]) {}

func _() {
	var x S[int]
	g4(x)      // we can infer int for P
	g4[int](x) // int is the correct type argument
	g4[string](x /* ERROR "cannot use x (variable of struct type S[int]) as S[string] value in argument to g4[string]" */)
}

// This is similar to the first example but here T1 is a component
// of a func type. In this case types must match exactly: P must
// match int.

func g5[P any](func(T1[P])) {}

func _() {
	var f func(T1[int])
	g5(f)
	g5[int](f)
	g5[string](f /* ERROR "cannot use f (variable of type func(T1[int])) as func(T1[string]) value in argument to g5[string]" */)
}

// This example would fail if we were to infer the type argument int for P
// exactly because any type argument would be ok for the first argument.
// Choosing the wrong type would cause the second argument to not match.

type T[P any] interface{}

func g6[P any](T[P], P) {}

func _() {
	var x T[int]
	g6(x, 1.2)
	g6(x, "")
}
