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: gotip generic conversion rules too strict for integer types #49353

Closed
renthraysk opened this issue Nov 4, 2021 · 3 comments
Closed

Comments

@renthraysk
Copy link

renthraysk commented Nov 4, 2021

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

$ go version
go version devel go1.18-00d6d2037e Thu Nov 4 14:54:46 2021 +0000 linux/amd64

What did you do?

This is similar to #49295 in that it falls afoul to the recently enforced rule, but worked in previous heads.
The conversion rule seems too strict on integer types.

package main

import "constraints"

func SizeOf[T constraints.Integer]() int {
	return 1 + int(T(1<<8))>>8 + int(T(2<<16))>>16 + int(T(4<<32))>>32
}

func IsSigned[T constraints.Integer]() bool {
	return T(-1) < 0
}

What did you expect to see?

Successful compilation

What did you see instead?

# command-line-arguments
./main.go:6:19: cannot convert 1 << 16 (untyped int value) to T
	cannot convert 1 << 16 (untyped int constant 65536) to int8 (in T)
./main.go:6:38: cannot convert 2 << 16 (untyped int value) to T
	cannot convert 2 << 16 (untyped int constant 131072) to int8 (in T)
./main.go:6:58: cannot convert 4 << 32 (untyped int value) to T
	cannot convert 4 << 32 (untyped int constant 17179869184) to int8 (in T)
@randall77
Copy link
Contributor

This looks like it is working as intended. You can't use constants outside the range of an int8 if int8 is in the type set of the type parameter.

https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#untyped-constants

@renthraysk
Copy link
Author

Perhaps I'm not understanding the need for the strictness with constants, when so easily bypassed with variables.

package main

import (
	"constraints"
	"fmt"
)

func SizeOf[T constraints.Integer]() int {
	var x uint16 = 1 << 8
	var y uint32 = 2 << 16
	var z uint64 = 4 << 32
	return 1 + int(T(x))>>8 + int(T(y))>>16 + int(T(z))>>32
}

func main() {
	fmt.Printf("uint8: %d\n", SizeOf[uint8]())
	fmt.Printf("uint16: %d\n", SizeOf[uint16]())
	fmt.Printf("uint32: %d\n", SizeOf[uint32]())
	fmt.Printf("uint64: %d\n", SizeOf[uint64]())
	fmt.Printf("uint: %d\n", SizeOf[uint]())
	fmt.Printf("int8: %d\n", SizeOf[int8]())
	fmt.Printf("int16: %d\n", SizeOf[int16]())
	fmt.Printf("int32: %d\n", SizeOf[int32]())
	fmt.Printf("int64: %d\n", SizeOf[int64]())
	fmt.Printf("int: %d\n", SizeOf[int]())
}

@ALTree
Copy link
Member

ALTree commented Nov 4, 2021

easily bypassed with variables.

It's not a typesets thing, this is already true. var u uint8 = 256 does not compile, but var u uint8 = 1; println(u<<16) does.

@golang golang locked and limited conversation to collaborators Nov 4, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants