mirror of
https://github.com/golang/go
synced 2024-11-20 11:24:47 -07:00
exp/types/staging: support for typechecking (most) builtins
This code relies on some functions that are not yet in staging, but it get's harder to keep all this in sync in a piece-meal fashion. R=rsc CC=golang-dev https://golang.org/cl/6492124
This commit is contained in:
parent
f5483fb801
commit
ebf56e086d
349
src/pkg/exp/types/staging/builtins.go
Normal file
349
src/pkg/exp/types/staging/builtins.go
Normal file
@ -0,0 +1,349 @@
|
|||||||
|
// Copyright 2012 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.
|
||||||
|
|
||||||
|
// This file implements typechecking of builtin function calls.
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/ast"
|
||||||
|
"go/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// builtin typechecks a built-in call. The built-in type is bin, and iota is the current
|
||||||
|
// value of iota or -1 if iota doesn't have a value in the current context. The result
|
||||||
|
// of the call is returned via x. If the call has type errors, the returned x is marked
|
||||||
|
// as invalid (x.mode == invalid).
|
||||||
|
//
|
||||||
|
func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota int) {
|
||||||
|
args := call.Args
|
||||||
|
id := bin.id
|
||||||
|
|
||||||
|
// declare before goto's
|
||||||
|
var arg0 ast.Expr
|
||||||
|
var typ0 Type
|
||||||
|
|
||||||
|
// check argument count
|
||||||
|
n := len(args)
|
||||||
|
msg := ""
|
||||||
|
if n < bin.nargs {
|
||||||
|
msg = "not enough"
|
||||||
|
} else if !bin.isVariadic && n > bin.nargs {
|
||||||
|
msg = "too many"
|
||||||
|
}
|
||||||
|
if msg != "" {
|
||||||
|
check.invalidOp(call.Pos(), msg+"arguments for %s (expected %d, found %d)", call, bin.nargs, n)
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// common case: evaluate first argument if present;
|
||||||
|
// if it is an expression, x has the expression value
|
||||||
|
if n > 0 {
|
||||||
|
arg0 = args[0]
|
||||||
|
switch id {
|
||||||
|
case _Make, _New:
|
||||||
|
// argument must be a type
|
||||||
|
typ0 = underlying(check.typ(arg0, false))
|
||||||
|
if typ0 == Typ[Invalid] {
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
case _Trace:
|
||||||
|
// _Trace implementation does the work
|
||||||
|
default:
|
||||||
|
// argument must be an expression
|
||||||
|
check.expr(x, arg0, nil, iota)
|
||||||
|
if x.mode == invalid {
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
typ0 = underlying(x.typ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch id {
|
||||||
|
case _Append:
|
||||||
|
s, ok := typ0.(*Slice)
|
||||||
|
if !ok {
|
||||||
|
check.invalidArg(x.pos(), "%s is not a typed slice", x)
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
for _, arg := range args[1:] {
|
||||||
|
check.expr(x, arg, nil, iota)
|
||||||
|
if x.mode == invalid {
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
// TODO(gri) check assignability
|
||||||
|
}
|
||||||
|
x.mode = value
|
||||||
|
x.typ = s
|
||||||
|
|
||||||
|
case _Cap, _Len:
|
||||||
|
mode := invalid
|
||||||
|
var val interface{}
|
||||||
|
switch typ := implicitDeref(typ0).(type) {
|
||||||
|
case *Basic:
|
||||||
|
if isString(typ) && id == _Len {
|
||||||
|
if x.mode == constant {
|
||||||
|
mode = constant
|
||||||
|
val = int64(len(x.val.(string)))
|
||||||
|
} else {
|
||||||
|
mode = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case *Array:
|
||||||
|
mode = value
|
||||||
|
if !containsCallsOrReceives(arg0) {
|
||||||
|
mode = constant
|
||||||
|
val = typ.Len
|
||||||
|
}
|
||||||
|
|
||||||
|
case *Slice, *Chan:
|
||||||
|
mode = value
|
||||||
|
|
||||||
|
case *Map:
|
||||||
|
if id == _Len {
|
||||||
|
mode = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if mode == invalid {
|
||||||
|
check.invalidArg(x.pos(), "%s for %s", x, bin.name)
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
x.mode = mode
|
||||||
|
x.typ = Typ[Int]
|
||||||
|
x.val = val
|
||||||
|
|
||||||
|
case _Close:
|
||||||
|
ch, ok := typ0.(*Chan)
|
||||||
|
if !ok {
|
||||||
|
check.invalidArg(x.pos(), "%s is not a channel", x)
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
if ch.Dir&ast.SEND == 0 {
|
||||||
|
check.invalidArg(x.pos(), "%s must not be a receive-only channel", x)
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
x.mode = novalue
|
||||||
|
|
||||||
|
case _Complex:
|
||||||
|
var y operand
|
||||||
|
check.expr(&y, args[1], nil, iota)
|
||||||
|
if y.mode == invalid {
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
// TODO(gri) handle complex(a, b) like (a + toImag(b))
|
||||||
|
unimplemented()
|
||||||
|
|
||||||
|
case _Copy:
|
||||||
|
// TODO(gri) implements checks
|
||||||
|
unimplemented()
|
||||||
|
x.mode = value
|
||||||
|
x.typ = Typ[Int]
|
||||||
|
|
||||||
|
case _Delete:
|
||||||
|
m, ok := typ0.(*Map)
|
||||||
|
if !ok {
|
||||||
|
check.invalidArg(x.pos(), "%s is not a map", x)
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
check.expr(x, args[1], nil, iota)
|
||||||
|
if x.mode == invalid {
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
if !x.isAssignable(m.Key) {
|
||||||
|
check.invalidArg(x.pos(), "%s is not assignable to %s", x, m.Key)
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
x.mode = novalue
|
||||||
|
|
||||||
|
case _Imag, _Real:
|
||||||
|
if !isComplex(typ0) {
|
||||||
|
check.invalidArg(x.pos(), "%s must be a complex number", x)
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
if x.mode == constant {
|
||||||
|
// nothing to do for x.val == 0
|
||||||
|
if !isZeroConst(x.val) {
|
||||||
|
c := x.val.(complex)
|
||||||
|
if id == _Real {
|
||||||
|
x.val = c.re
|
||||||
|
} else {
|
||||||
|
x.val = c.im
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
x.mode = value
|
||||||
|
}
|
||||||
|
k := Invalid
|
||||||
|
switch typ0.(*Basic).Kind {
|
||||||
|
case Complex64:
|
||||||
|
k = Float32
|
||||||
|
case Complex128:
|
||||||
|
k = Float64
|
||||||
|
case UntypedComplex:
|
||||||
|
k = UntypedFloat
|
||||||
|
default:
|
||||||
|
unreachable()
|
||||||
|
}
|
||||||
|
x.typ = Typ[k]
|
||||||
|
|
||||||
|
case _Make:
|
||||||
|
var min int // minimum number of arguments
|
||||||
|
switch typ0.(type) {
|
||||||
|
case *Slice:
|
||||||
|
min = 2
|
||||||
|
case *Map, *Chan:
|
||||||
|
min = 1
|
||||||
|
default:
|
||||||
|
check.invalidArg(arg0.Pos(), "cannot make %s; type must be slice, map, or channel", arg0)
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
if n := len(args); n < min || min+1 < n {
|
||||||
|
check.errorf(call.Pos(), "%s expects %d or %d arguments; found %d", call, min, min+1, n)
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
for _, arg := range args[1:] {
|
||||||
|
check.expr(x, arg, nil, iota)
|
||||||
|
if !x.isInteger() {
|
||||||
|
check.invalidArg(x.pos(), "%s must be an integer", x)
|
||||||
|
// safe to continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x.mode = variable
|
||||||
|
x.typ = typ0
|
||||||
|
|
||||||
|
case _New:
|
||||||
|
x.mode = variable
|
||||||
|
x.typ = &Pointer{Base: typ0}
|
||||||
|
|
||||||
|
case _Panic, _Print, _Println:
|
||||||
|
x.mode = novalue
|
||||||
|
|
||||||
|
case _Recover:
|
||||||
|
x.mode = value
|
||||||
|
x.typ = emptyInterface
|
||||||
|
|
||||||
|
case _Alignof:
|
||||||
|
x.mode = constant
|
||||||
|
x.typ = Typ[Uintptr]
|
||||||
|
// For now we return 1 always as it satisfies the spec's alignment guarantees.
|
||||||
|
// TODO(gri) Extend typechecker API so that platform-specific values can be
|
||||||
|
// provided.
|
||||||
|
x.val = int64(1)
|
||||||
|
|
||||||
|
case _Offsetof:
|
||||||
|
if _, ok := unparen(x.expr).(*ast.SelectorExpr); !ok {
|
||||||
|
check.invalidArg(x.pos(), "%s is not a selector", x)
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
x.mode = constant
|
||||||
|
x.typ = Typ[Uintptr]
|
||||||
|
// because of the size guarantees for basic types (> 0 for some),
|
||||||
|
// returning 0 is only correct if two distinct non-zero size
|
||||||
|
// structs can have the same address (the spec permits that)
|
||||||
|
x.val = int64(0)
|
||||||
|
|
||||||
|
case _Sizeof:
|
||||||
|
// basic types with specified sizes have size guarantees; for all others we use 0
|
||||||
|
var size int64
|
||||||
|
if typ, ok := typ0.(*Basic); ok {
|
||||||
|
size = typ.Size
|
||||||
|
}
|
||||||
|
x.mode = constant
|
||||||
|
x.typ = Typ[Uintptr]
|
||||||
|
x.val = size
|
||||||
|
|
||||||
|
case _Assert:
|
||||||
|
// assert(pred) causes a typechecker error if pred is false.
|
||||||
|
// The result of assert is the value of pred if there is no error.
|
||||||
|
// Note: assert is only available in self-test mode.
|
||||||
|
if x.mode != constant || !isBoolean(typ0) {
|
||||||
|
check.invalidArg(x.pos(), "%s is not a boolean constant", x)
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
pred, ok := x.val.(bool)
|
||||||
|
if !ok {
|
||||||
|
check.errorf(x.pos(), "internal error: value of %s should be a boolean constant", x)
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
if !pred {
|
||||||
|
check.errorf(call.Pos(), "%s failed", call)
|
||||||
|
// compile-time assertion failure - safe to continue
|
||||||
|
}
|
||||||
|
|
||||||
|
case _Trace:
|
||||||
|
// trace(x, y, z, ...) dumps the positions, expressions, and
|
||||||
|
// values of its arguments. The result of trace is the value
|
||||||
|
// of the first argument.
|
||||||
|
// Note: trace is only available in self-test mode.
|
||||||
|
if len(args) == 0 {
|
||||||
|
check.dump("%s: trace() without arguments", call.Pos())
|
||||||
|
x.mode = novalue
|
||||||
|
x.expr = call
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var t operand
|
||||||
|
x1 := x
|
||||||
|
for _, arg := range args {
|
||||||
|
check.exprOrType(x1, arg, nil, iota, true) // permit trace for types, e.g.: new(trace(T))
|
||||||
|
check.dump("%s: %s", x1.pos(), x1)
|
||||||
|
x1 = &t // use incoming x only for first argument
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
check.invalidAST(call.Pos(), "unknown builtin id %d", id)
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
|
||||||
|
x.expr = call
|
||||||
|
return
|
||||||
|
|
||||||
|
Error:
|
||||||
|
x.mode = invalid
|
||||||
|
x.expr = call
|
||||||
|
}
|
||||||
|
|
||||||
|
// implicitDeref returns A if typ is of the form *A and A is an array;
|
||||||
|
// otherwise it returns typ.
|
||||||
|
//
|
||||||
|
func implicitDeref(typ Type) Type {
|
||||||
|
if p, ok := typ.(*Pointer); ok {
|
||||||
|
if a, ok := underlying(p.Base).(*Array); ok {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return typ
|
||||||
|
}
|
||||||
|
|
||||||
|
// containsCallsOrReceives returns true if the expression x contains
|
||||||
|
// function calls or channel receives; it returns false otherwise.
|
||||||
|
//
|
||||||
|
func containsCallsOrReceives(x ast.Expr) bool {
|
||||||
|
res := false
|
||||||
|
ast.Inspect(x, func(x ast.Node) bool {
|
||||||
|
switch x := x.(type) {
|
||||||
|
case *ast.CallExpr:
|
||||||
|
res = true
|
||||||
|
return false
|
||||||
|
case *ast.UnaryExpr:
|
||||||
|
if x.Op == token.ARROW {
|
||||||
|
res = true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// unparen removes any parentheses surrounding an expression and returns
|
||||||
|
// the naked expression.
|
||||||
|
//
|
||||||
|
func unparen(x ast.Expr) ast.Expr {
|
||||||
|
if p, ok := x.(*ast.ParenExpr); ok {
|
||||||
|
return unparen(p.X)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
258
src/pkg/exp/types/staging/testdata/builtins.src
vendored
Normal file
258
src/pkg/exp/types/staging/testdata/builtins.src
vendored
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
// Copyright 2012 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.
|
||||||
|
|
||||||
|
// builtin calls
|
||||||
|
|
||||||
|
package builtins
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
func _append() {
|
||||||
|
var x int
|
||||||
|
var s []byte
|
||||||
|
_0 := append /* ERROR "argument" */ ()
|
||||||
|
_1 := append("foo" /* ERROR "not a typed slice" */)
|
||||||
|
_2 := append(nil /* ERROR "not a typed slice" */, s)
|
||||||
|
_3 := append(x /* ERROR "not a typed slice" */, s)
|
||||||
|
_4 := append(s)
|
||||||
|
append /* ERROR "not used" */ (s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _cap() {
|
||||||
|
var a [10]bool
|
||||||
|
var p *[20]int
|
||||||
|
var s []int
|
||||||
|
var c chan string
|
||||||
|
_0 := cap /* ERROR "argument" */ ()
|
||||||
|
_1 := cap /* ERROR "argument" */ (1, 2)
|
||||||
|
_2 := cap(42 /* ERROR "invalid" */)
|
||||||
|
const _3 = cap(a)
|
||||||
|
assert(_3 == 10)
|
||||||
|
const _4 = cap(p)
|
||||||
|
assert(_4 == 20)
|
||||||
|
_5 := cap(c)
|
||||||
|
cap /* ERROR "not used" */ (c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _close() {
|
||||||
|
var c chan int
|
||||||
|
var r <-chan int
|
||||||
|
close /* ERROR "argument" */ ()
|
||||||
|
close /* ERROR "argument" */ (1, 2)
|
||||||
|
close(42 /* ERROR "not a channel" */)
|
||||||
|
close(r /* ERROR "receive-only channel" */)
|
||||||
|
close(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _complex() {
|
||||||
|
_0 := complex /* ERROR "argument" */ ()
|
||||||
|
_1 := complex /* ERROR "argument" */ (1)
|
||||||
|
_2 := complex(1, 2)
|
||||||
|
// TODO(gri) add tests checking types
|
||||||
|
complex /* ERROR "not used" */ (1, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _delete() {
|
||||||
|
var m map[string]int
|
||||||
|
var s string
|
||||||
|
delete /* ERROR "argument" */ ()
|
||||||
|
delete /* ERROR "argument" */ (1)
|
||||||
|
delete /* ERROR "argument" */ (1, 2, 3)
|
||||||
|
delete(m, 0 /* ERROR "not assignable" */)
|
||||||
|
delete(m, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _imag() {
|
||||||
|
var f32 float32
|
||||||
|
var f64 float64
|
||||||
|
var c64 complex64
|
||||||
|
var c128 complex128
|
||||||
|
_0 := imag /* ERROR "argument" */ ()
|
||||||
|
_1 := imag /* ERROR "argument" */ (1, 2)
|
||||||
|
_2 := imag(10 /* ERROR "must be a complex number" */)
|
||||||
|
_3 := imag(2.7182818 /* ERROR "must be a complex number" */)
|
||||||
|
_4 := imag("foo" /* ERROR "must be a complex number" */)
|
||||||
|
const _5 = imag(1 + 2i)
|
||||||
|
assert(_5 == 2)
|
||||||
|
f32 = _5
|
||||||
|
f64 = _5
|
||||||
|
const _6 = imag(0i)
|
||||||
|
assert(_6 == 0)
|
||||||
|
f32 = imag(c64)
|
||||||
|
f64 = imag(c128)
|
||||||
|
f32 = imag /* ERROR "cannot assign" */ (c128)
|
||||||
|
f64 = imag /* ERROR "cannot assign" */ (c64)
|
||||||
|
imag /* ERROR "not used" */ (c64)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _len() {
|
||||||
|
const c = "foobar"
|
||||||
|
var a [10]bool
|
||||||
|
var p *[20]int
|
||||||
|
var s []int
|
||||||
|
var m map[string]complex128
|
||||||
|
_0 := len /* ERROR "argument" */ ()
|
||||||
|
_1 := len /* ERROR "argument" */ (1, 2)
|
||||||
|
_2 := len(42 /* ERROR "invalid" */)
|
||||||
|
const _3 = len(c)
|
||||||
|
assert(_3 == 6)
|
||||||
|
const _4 = len(a)
|
||||||
|
assert(_4 == 10)
|
||||||
|
const _5 = len(p)
|
||||||
|
assert(_5 == 20)
|
||||||
|
_6 := len(m)
|
||||||
|
len /* ERROR "not used" */ (c)
|
||||||
|
|
||||||
|
// esoteric case
|
||||||
|
var t string
|
||||||
|
var hash map[interface{}][]*[10]int
|
||||||
|
const n = len /* ERROR "not constant" */ (hash[recover()][len(t)])
|
||||||
|
assert /* ERROR "failed" */ (n == 10)
|
||||||
|
var ch <-chan int
|
||||||
|
const nn = len /* ERROR "not constant" */ (hash[<-ch][len(t)])
|
||||||
|
_7 := nn // TODO(gri) remove this once unused constants get type-checked
|
||||||
|
}
|
||||||
|
|
||||||
|
func _make() {
|
||||||
|
n := 0
|
||||||
|
|
||||||
|
_0 := make /* ERROR "argument" */ ()
|
||||||
|
_1 := make(1 /* ERROR "not a type" */)
|
||||||
|
_2 := make(int /* ERROR "cannot make" */)
|
||||||
|
|
||||||
|
// slices
|
||||||
|
_3 := make/* ERROR "arguments" */ ([]int)
|
||||||
|
_4 := make/* ERROR "arguments" */ ([]int, 2, 3, 4)
|
||||||
|
_5 := make([]int, int /* ERROR "not an expression" */)
|
||||||
|
_6 := make([]int, 10, float32 /* ERROR "not an expression" */)
|
||||||
|
_7 := make([]int, "foo" /* ERROR "must be an integer" */)
|
||||||
|
_8 := make([]int, 10, 2.3 /* ERROR "must be an integer" */)
|
||||||
|
_9 := make([]int, 5, 10.0)
|
||||||
|
_10 := make([]int, 0i)
|
||||||
|
_11 := make([]int, -1, 1<<100) // out-of-range constants lead to run-time errors
|
||||||
|
|
||||||
|
// maps
|
||||||
|
_12 := make /* ERROR "arguments" */ (map[int]string, 10, 20)
|
||||||
|
_13 := make(map[int]float32, int /* ERROR "not an expression" */)
|
||||||
|
_14 := make(map[int]float32, "foo" /* ERROR "must be an integer" */)
|
||||||
|
_15 := make(map[int]float32, 10)
|
||||||
|
_16 := make(map[int]float32, n)
|
||||||
|
_17 := make(map[int]float32, int64(n))
|
||||||
|
|
||||||
|
// channels
|
||||||
|
_22 := make /* ERROR "arguments" */ (chan int, 10, 20)
|
||||||
|
_23 := make(chan int, int /* ERROR "not an expression" */)
|
||||||
|
_24 := make(chan<- int, "foo" /* ERROR "must be an integer" */)
|
||||||
|
_25 := make(<-chan float64, 10)
|
||||||
|
_26 := make(chan chan int, n)
|
||||||
|
_27 := make(chan string, int64(n))
|
||||||
|
|
||||||
|
make /* ERROR "not used" */ ([]int, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _new() {
|
||||||
|
_0 := new /* ERROR "argument" */ ()
|
||||||
|
_1 := new /* ERROR "argument" */ (1, 2)
|
||||||
|
_3 := new("foo" /* ERROR "not a type" */)
|
||||||
|
_4 := new(float64)
|
||||||
|
_5 := new(struct{ x, y int })
|
||||||
|
_6 := new(*float64)
|
||||||
|
_7 := *_4 == **_6
|
||||||
|
new /* ERROR "not used" */ (int)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _real() {
|
||||||
|
var f32 float32
|
||||||
|
var f64 float64
|
||||||
|
var c64 complex64
|
||||||
|
var c128 complex128
|
||||||
|
_0 := real /* ERROR "argument" */ ()
|
||||||
|
_1 := real /* ERROR "argument" */ (1, 2)
|
||||||
|
_2 := real(10 /* ERROR "must be a complex number" */)
|
||||||
|
_3 := real(2.7182818 /* ERROR "must be a complex number" */)
|
||||||
|
_4 := real("foo" /* ERROR "must be a complex number" */)
|
||||||
|
const _5 = real(1 + 2i)
|
||||||
|
assert(_5 == 1)
|
||||||
|
f32 = _5
|
||||||
|
f64 = _5
|
||||||
|
const _6 = real(0i)
|
||||||
|
assert(_6 == 0)
|
||||||
|
f32 = real(c64)
|
||||||
|
f64 = real(c128)
|
||||||
|
f32 = real /* ERROR "cannot assign" */ (c128)
|
||||||
|
f64 = real /* ERROR "cannot assign" */ (c64)
|
||||||
|
real /* ERROR "not used" */ (c64)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _recover() {
|
||||||
|
_0 := recover()
|
||||||
|
_1 := recover /* ERROR "argument" */ (10)
|
||||||
|
recover()
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Alignof() {
|
||||||
|
var x int
|
||||||
|
_0 := unsafe /* ERROR "argument" */ .Alignof()
|
||||||
|
_1 := unsafe /* ERROR "argument" */ .Alignof(1, 2)
|
||||||
|
_3 := unsafe.Alignof(int /* ERROR "not an expression" */)
|
||||||
|
_4 := unsafe.Alignof(42)
|
||||||
|
_5 := unsafe.Alignof(new(struct{}))
|
||||||
|
unsafe /* ERROR "not used" */ .Alignof(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Offsetof() {
|
||||||
|
var x struct{ f int }
|
||||||
|
_0 := unsafe /* ERROR "argument" */ .Offsetof()
|
||||||
|
_1 := unsafe /* ERROR "argument" */ .Offsetof(1, 2)
|
||||||
|
_2 := unsafe.Offsetof(int /* ERROR "not an expression" */)
|
||||||
|
_3 := unsafe.Offsetof(x /* ERROR "not a selector" */)
|
||||||
|
_4 := unsafe.Offsetof(x.f)
|
||||||
|
_5 := unsafe.Offsetof((x.f))
|
||||||
|
_6 := unsafe.Offsetof((((((((x))).f)))))
|
||||||
|
unsafe /* ERROR "not used" */ .Offsetof(x.f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Sizeof() {
|
||||||
|
var x int
|
||||||
|
_0 := unsafe /* ERROR "argument" */ .Sizeof()
|
||||||
|
_1 := unsafe /* ERROR "argument" */ .Sizeof(1, 2)
|
||||||
|
_2 := unsafe.Sizeof(int /* ERROR "not an expression" */)
|
||||||
|
_3 := unsafe.Sizeof(42)
|
||||||
|
_4 := unsafe.Sizeof(new(complex128))
|
||||||
|
unsafe /* ERROR "not used" */ .Sizeof(x)
|
||||||
|
|
||||||
|
// basic types have size guarantees
|
||||||
|
assert(unsafe.Sizeof(byte(0)) == 1)
|
||||||
|
assert(unsafe.Sizeof(uint8(0)) == 1)
|
||||||
|
assert(unsafe.Sizeof(int8(0)) == 1)
|
||||||
|
assert(unsafe.Sizeof(uint16(0)) == 2)
|
||||||
|
assert(unsafe.Sizeof(int16(0)) == 2)
|
||||||
|
assert(unsafe.Sizeof(uint32(0)) == 4)
|
||||||
|
assert(unsafe.Sizeof(int32(0)) == 4)
|
||||||
|
assert(unsafe.Sizeof(float32(0)) == 4)
|
||||||
|
assert(unsafe.Sizeof(uint64(0)) == 8)
|
||||||
|
assert(unsafe.Sizeof(int64(0)) == 8)
|
||||||
|
assert(unsafe.Sizeof(float64(0)) == 8)
|
||||||
|
assert(unsafe.Sizeof(complex64(0)) == 8)
|
||||||
|
assert(unsafe.Sizeof(complex128(0)) == 16)
|
||||||
|
}
|
||||||
|
|
||||||
|
// self-testing only
|
||||||
|
func _assert() {
|
||||||
|
var x int
|
||||||
|
assert /* ERROR "argument" */ ()
|
||||||
|
assert /* ERROR "argument" */ (1, 2)
|
||||||
|
assert("foo" /* ERROR "boolean constant" */ )
|
||||||
|
assert(x /* ERROR "boolean constant" */)
|
||||||
|
assert(true)
|
||||||
|
assert /* ERROR "failed" */ (false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// self-testing only
|
||||||
|
func _trace() {
|
||||||
|
// Uncomment the code below to test trace - will produce console output
|
||||||
|
// _0 := trace /* ERROR "no value" */ ()
|
||||||
|
// _1 := trace(1)
|
||||||
|
// _2 := trace(true, 1.2, '\'', "foo", 42i, "foo" <= "bar")
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user