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/go2go: assignment type checking does not work correctly #39930

Closed
tdakkota opened this issue Jun 29, 2020 · 4 comments
Closed

cmd/go2go: assignment type checking does not work correctly #39930

tdakkota opened this issue Jun 29, 2020 · 4 comments
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@tdakkota
Copy link

What version of Go are you using (go version)?

$ go version
go version devel +71c7be55eb Mon Jun 29 16:07:10 2020 +0000 windows/amd64

Does this issue reproduce with the latest release?

n/a

What operating system and processor architecture are you using (go env)?

  • windows/amd64
  • playground

What did you do?

https://go2goplay.golang.org/p/jmaTevSNW0X

What did you expect to see?

Successful compilation.

What did you see instead?

type checking failed for main
prog.go2:36:13: cannot use New(a, b) (value of type Tuple(IA, IB)) as I value in argument

Unrelated bug from #39754 (comment)

@ianlancetaylor
Copy link
Contributor

CC @griesemer

I'm not sure the type checker is wrong here. You have a type parameter I with a constraint Tuple(IA, IB). You have a function of type func(I) R. You are calling that function with a value of type Tuple(IA, IB). The type checker is saying that the value of type Tuple(IA, IB) is not the same as the value I. I think that is correct. It's true that I implements Tuple(IA, IB), but that doesn't mean that a value of type Tuple(IA, IB) is the same as I.

@ianlancetaylor ianlancetaylor added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Jun 29, 2020
@ianlancetaylor ianlancetaylor added this to the Unreleased milestone Jun 29, 2020
@tdakkota
Copy link
Author

tdakkota commented Jun 29, 2020

The problem is here

go/src/go/types/operand.go

Lines 233 to 234 in 71c7be5

Vu := optype(V.Under())
Tu := optype(T.Under())

	Vu := optype(V.Under()) // V represents type of a result of New function, so Vu is *types.Interface bound by three methods 
	Tu := optype(T.Under()) // T represents type param I, so optype function returns types.top

That's what happens when optype(T.Under()) called

func optype(typ Type) Type { 
	if t := typ.TypeParam(); t != nil { // I is a type param
		if u := t.Bound().allTypes; u != nil && u != typ { // t bound only by method list, not by type list, so allTypes is nil
			return u.Under()
		}
		return theTop // here function returns
	}
	return typ
}

I tried to fix it changing optype's body to

func optype(typ Type) Type {
	if t := typ.TypeParam(); t != nil {
		// If the optype is typ, return the top type as we have
		// no information. It also prevents infinite recursion
		// via the TypeParam converter methods. This can happen
		// for a type parameter list of the form:
		// (type T interface { type T }).
		// See also issue #39680.
		bound := t.Bound()
		if u := bound.allTypes; u != nil && u != typ {
			// u != typ and u is a type parameter => u.Under() != typ, so this is ok
			return u.Under()
		}

		if u := bound.allMethods; u != nil  {
			return bound
		}

		return theTop
	}
	return typ
}

then code compiles, but it breaks some standard libraries in testdata directory.

@tdakkota
Copy link
Author

@ianlancetaylor

This example does not compile too, it's literally Tuple(IA, IB) != Tuple(IA, IB)

func curry(type
	IA, IB, RA, RB interface{},
	I Tuple(IA, IB),
	R Tuple(RA, RB),
)(a IA, fn func(t I) R) func(IB) R {
	return func(b IB) R {
		return fn(New(IA, IB)(a, b))
	}
}

@griesemer griesemer self-assigned this Jun 29, 2020
@griesemer
Copy link
Contributor

This is not a bug; @ianlancetaylor has explained the reason already.

Here's a simplified version of the code, hopefully making this more clear:

package p

type Tuple interface {}

type tuple struct {}

func _(type I Tuple) () {
	var v I
	var t Tuple
	v = t // <<<< ERROR: cannot use t (variable of type Tuple) as I value in assignment
	_ = v
}

Passing the result of New to fn in your example is equivalent to assigning the variable t of type Tuple to the variable v of type I in this example, and that is not permitted.

The point is that the type of v is I which is not the same at all as Tuple. The Tuple type is a constraint describing the properties of type I, but it cannot be that type (if it were, then it wouldn't make sense to instantiate the enclosing function with some arbitrary type that happens to implement Tuple).

In summary, this is working as intended. Closing.

@golang golang locked and limited conversation to collaborators Jun 30, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

4 participants