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

renthraysk opened this issue Nov 4, 2021 · 3 comments


Copy link

@renthraysk 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)
Copy link

@randall77 randall77 commented Nov 4, 2021

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.

Copy link

@renthraysk renthraysk commented Nov 4, 2021

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

package main

import (

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]())

Copy link

@ALTree 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
None yet

No branches or pull requests

3 participants