forked from OSchip/llvm-project
[llgo] llgoi: separate evaluation from printing
Summary: Separate the evaluation of expressions from printing of results. This is in preparation for splitting the core of the interpreter out for use in alternative interpreter frontends. At the same time, the output is made less noisy in response to comments on the golang-nuts announcement. We would ideally print out values using Go syntax, but this is impractical until we have libgo based on Go 1.5. When that happens, fmt's %#v will handle reflect.Value better, and so we can fix/filter type names to remove automatically generated package names. Reviewers: pcc Subscribers: llvm-commits, axw Differential Revision: http://reviews.llvm.org/D13761 llvm-svn: 267374
This commit is contained in:
parent
61a14911b2
commit
bfb1679603
|
@ -83,8 +83,9 @@ type interp struct {
|
||||||
imports []*types.Package
|
imports []*types.Package
|
||||||
scope map[string]types.Object
|
scope map[string]types.Object
|
||||||
|
|
||||||
pkgmap map[string]*types.Package
|
modules map[string]llvm.Module
|
||||||
pkgnum int
|
pkgmap map[string]*types.Package
|
||||||
|
pkgnum int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in *interp) makeCompilerOptions() error {
|
func (in *interp) makeCompilerOptions() error {
|
||||||
|
@ -119,6 +120,7 @@ func (in *interp) init() error {
|
||||||
in.liner = liner.NewLiner()
|
in.liner = liner.NewLiner()
|
||||||
in.scope = make(map[string]types.Object)
|
in.scope = make(map[string]types.Object)
|
||||||
in.pkgmap = make(map[string]*types.Package)
|
in.pkgmap = make(map[string]*types.Package)
|
||||||
|
in.modules = make(map[string]llvm.Module)
|
||||||
|
|
||||||
err := in.makeCompilerOptions()
|
err := in.makeCompilerOptions()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -139,23 +141,21 @@ func (in *interp) loadSourcePackageFromCode(pkgcode, pkgpath string, copts irgen
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
files := []*ast.File{file}
|
files := []*ast.File{file}
|
||||||
|
|
||||||
return in.loadSourcePackage(fset, files, pkgpath, copts)
|
return in.loadSourcePackage(fset, files, pkgpath, copts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in *interp) loadSourcePackage(fset *token.FileSet, files []*ast.File, pkgpath string, copts irgen.CompilerOptions) (pkg *types.Package, err error) {
|
func (in *interp) loadSourcePackage(fset *token.FileSet, files []*ast.File, pkgpath string, copts irgen.CompilerOptions) (_ *types.Package, resultErr error) {
|
||||||
compiler, err := irgen.NewCompiler(copts)
|
compiler, err := irgen.NewCompiler(copts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
module, err := compiler.Compile(fset, files, pkgpath)
|
module, err := compiler.Compile(fset, files, pkgpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil, err
|
||||||
}
|
}
|
||||||
pkg = module.Package
|
in.modules[pkgpath] = module.Module
|
||||||
|
|
||||||
if in.engine.C != nil {
|
if in.engine.C != nil {
|
||||||
in.engine.AddModule(module.Module)
|
in.engine.AddModule(module.Module)
|
||||||
|
@ -163,25 +163,33 @@ func (in *interp) loadSourcePackage(fset *token.FileSet, files []*ast.File, pkgp
|
||||||
options := llvm.NewMCJITCompilerOptions()
|
options := llvm.NewMCJITCompilerOptions()
|
||||||
in.engine, err = llvm.NewMCJITCompiler(module.Module, options)
|
in.engine, err = llvm.NewMCJITCompiler(module.Module, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
importname := irgen.ManglePackagePath(pkgpath) + "..import$descriptor"
|
var importFunc func()
|
||||||
importglobal := module.Module.NamedGlobal(importname)
|
importAddress := in.getPackageSymbol(pkgpath, ".import$descriptor")
|
||||||
|
*(*unsafe.Pointer)(unsafe.Pointer(&importFunc)) = importAddress
|
||||||
var importfunc func()
|
|
||||||
*(*unsafe.Pointer)(unsafe.Pointer(&importfunc)) = in.engine.PointerToGlobal(importglobal)
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
p := recover()
|
p := recover()
|
||||||
if p != nil {
|
if p != nil {
|
||||||
err = fmt.Errorf("panic: %v\n%v", p, string(debug.Stack()))
|
resultErr = fmt.Errorf("panic: %v\n%v", p, string(debug.Stack()))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
importfunc()
|
importFunc()
|
||||||
in.pkgmap[pkgpath] = pkg
|
in.pkgmap[pkgpath] = module.Package
|
||||||
return
|
|
||||||
|
return module.Package, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (in *interp) getPackageSymbol(pkgpath, name string) unsafe.Pointer {
|
||||||
|
symbolName := irgen.ManglePackagePath(pkgpath) + "." + name
|
||||||
|
global := in.modules[pkgpath].NamedGlobal(symbolName)
|
||||||
|
if global.IsNil() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return in.engine.PointerToGlobal(global)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in *interp) augmentPackageScope(pkg *types.Package) {
|
func (in *interp) augmentPackageScope(pkg *types.Package) {
|
||||||
|
@ -246,19 +254,17 @@ func (l *line) ready() bool {
|
||||||
return l.parens <= 0 && l.bracks <= 0 && l.braces <= 0
|
return l.parens <= 0 && l.bracks <= 0 && l.braces <= 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in *interp) readExprLine(str string, assigns []string) error {
|
func (in *interp) readExprLine(str string, assigns []string) ([]interface{}, error) {
|
||||||
in.pendingLine.append(str, assigns)
|
in.pendingLine.append(str, assigns)
|
||||||
|
if !in.pendingLine.ready() {
|
||||||
if in.pendingLine.ready() {
|
return nil, nil
|
||||||
err := in.interpretLine(in.pendingLine)
|
|
||||||
in.pendingLine = line{}
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
results, err := in.interpretLine(in.pendingLine)
|
||||||
|
in.pendingLine = line{}
|
||||||
|
return results, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in *interp) interpretLine(l line) error {
|
func (in *interp) interpretLine(l line) ([]interface{}, error) {
|
||||||
pkgname := fmt.Sprintf("input%05d", in.pkgnum)
|
pkgname := fmt.Sprintf("input%05d", in.pkgnum)
|
||||||
in.pkgnum++
|
in.pkgnum++
|
||||||
|
|
||||||
|
@ -277,14 +283,12 @@ func (in *interp) interpretLine(l line) error {
|
||||||
var err error
|
var err error
|
||||||
tv, err = types.Eval(l.line, pkg, scope)
|
tv, err = types.Eval(l.line, pkg, scope)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var code bytes.Buffer
|
var code bytes.Buffer
|
||||||
fmt.Fprintf(&code, "package %s", pkgname)
|
fmt.Fprintf(&code, "package %s\n", pkgname)
|
||||||
code.WriteString("\n\nimport __fmt__ \"fmt\"\n")
|
|
||||||
code.WriteString("import __os__ \"os\"\n")
|
|
||||||
|
|
||||||
for _, pkg := range in.imports {
|
for _, pkg := range in.imports {
|
||||||
fmt.Fprintf(&code, "import %q\n", pkg.Path())
|
fmt.Fprintf(&code, "import %q\n", pkg.Path())
|
||||||
|
@ -306,7 +310,7 @@ func (in *interp) interpretLine(l line) error {
|
||||||
typs = append(typs, types.Typ[types.Bool])
|
typs = append(typs, types.Typ[types.Bool])
|
||||||
}
|
}
|
||||||
if len(l.assigns) != 0 && len(l.assigns) != len(typs) {
|
if len(l.assigns) != 0 && len(l.assigns) != len(typs) {
|
||||||
return errors.New("return value mismatch")
|
return nil, errors.New("return value mismatch")
|
||||||
}
|
}
|
||||||
|
|
||||||
code.WriteString("var ")
|
code.WriteString("var ")
|
||||||
|
@ -324,31 +328,34 @@ func (in *interp) interpretLine(l line) error {
|
||||||
fmt.Fprintf(&code, "__llgoiV%d", i)
|
fmt.Fprintf(&code, "__llgoiV%d", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Fprintf(&code, " = %s\n\n", l.line)
|
fmt.Fprintf(&code, " = %s\n", l.line)
|
||||||
|
|
||||||
code.WriteString("func init() {\n\t")
|
code.WriteString("func init() {\n")
|
||||||
for i, t := range typs {
|
varnames := make([]string, len(typs))
|
||||||
var varname, prefix string
|
for i := range typs {
|
||||||
|
var varname string
|
||||||
if len(l.assigns) != 0 && l.assigns[i] != "" {
|
if len(l.assigns) != 0 && l.assigns[i] != "" {
|
||||||
if _, ok := in.scope[l.assigns[i]]; ok {
|
if _, ok := in.scope[l.assigns[i]]; ok {
|
||||||
fmt.Fprintf(&code, "\t%s = __llgoiV%d\n", l.assigns[i], i)
|
fmt.Fprintf(&code, "\t%s = __llgoiV%d\n", l.assigns[i], i)
|
||||||
}
|
}
|
||||||
varname = l.assigns[i]
|
varname = l.assigns[i]
|
||||||
prefix = l.assigns[i]
|
|
||||||
} else {
|
} else {
|
||||||
varname = fmt.Sprintf("__llgoiV%d", i)
|
varname = fmt.Sprintf("__llgoiV%d", i)
|
||||||
prefix = fmt.Sprintf("#%d", i)
|
|
||||||
}
|
|
||||||
if _, ok := t.Underlying().(*types.Interface); ok {
|
|
||||||
fmt.Fprintf(&code, "\t__fmt__.Printf(\"%s %s (%%T) = %%+v\\n\", %s, %s)\n", prefix, t.String(), varname, varname)
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(&code, "\t__fmt__.Printf(\"%s %s = %%+v\\n\", %s)\n", prefix, t.String(), varname)
|
|
||||||
}
|
}
|
||||||
|
varnames[i] = varname
|
||||||
}
|
}
|
||||||
code.WriteString("}")
|
code.WriteString("}\n\n")
|
||||||
|
|
||||||
|
code.WriteString("func __llgoiResults() []interface{} {\n")
|
||||||
|
code.WriteString("\treturn []interface{}{\n")
|
||||||
|
for _, varname := range varnames {
|
||||||
|
fmt.Fprintf(&code, "\t\t%s,\n", varname)
|
||||||
|
}
|
||||||
|
code.WriteString("\t}\n")
|
||||||
|
code.WriteString("}\n")
|
||||||
} else {
|
} else {
|
||||||
if len(l.assigns) != 0 {
|
if len(l.assigns) != 0 {
|
||||||
return errors.New("return value mismatch")
|
return nil, errors.New("return value mismatch")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(&code, "func init() {\n\t%s}", l.line)
|
fmt.Fprintf(&code, "func init() {\n\t%s}", l.line)
|
||||||
|
@ -359,11 +366,18 @@ func (in *interp) interpretLine(l line) error {
|
||||||
copts.DisableUnusedImportCheck = true
|
copts.DisableUnusedImportCheck = true
|
||||||
pkg, err := in.loadSourcePackageFromCode(code.String(), pkgname, copts)
|
pkg, err := in.loadSourcePackageFromCode(code.String(), pkgname, copts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
in.imports = append(in.imports, pkg)
|
in.imports = append(in.imports, pkg)
|
||||||
|
|
||||||
|
var results []interface{}
|
||||||
|
llgoiResultsAddress := in.getPackageSymbol(pkgname, "__llgoiResults$descriptor")
|
||||||
|
if llgoiResultsAddress != nil {
|
||||||
|
var resultsFunc func() []interface{}
|
||||||
|
*(*unsafe.Pointer)(unsafe.Pointer(&resultsFunc)) = llgoiResultsAddress
|
||||||
|
results = resultsFunc()
|
||||||
|
}
|
||||||
|
|
||||||
for _, assign := range l.assigns {
|
for _, assign := range l.assigns {
|
||||||
if assign != "" {
|
if assign != "" {
|
||||||
if _, ok := in.scope[assign]; !ok {
|
if _, ok := in.scope[assign]; !ok {
|
||||||
|
@ -376,7 +390,7 @@ func (in *interp) interpretLine(l line) error {
|
||||||
in.scope[l.declName] = pkg.Scope().Lookup(l.declName)
|
in.scope[l.declName] = pkg.Scope().Lookup(l.declName)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in *interp) maybeReadAssignment(line string, s *scanner.Scanner, initial string, base int) (bool, error) {
|
func (in *interp) maybeReadAssignment(line string, s *scanner.Scanner, initial string, base int) (bool, error) {
|
||||||
|
@ -404,7 +418,9 @@ func (in *interp) maybeReadAssignment(line string, s *scanner.Scanner, initial s
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, in.readExprLine(line[int(pos)-base+2:], assigns)
|
// It's an assignment statement, there are no results.
|
||||||
|
_, err := in.readExprLine(line[int(pos)-base+2:], assigns)
|
||||||
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in *interp) loadPackage(pkgpath string) (*types.Package, error) {
|
func (in *interp) loadPackage(pkgpath string) (*types.Package, error) {
|
||||||
|
@ -428,8 +444,6 @@ func (in *interp) loadPackage(pkgpath string) (*types.Package, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("# %s\n", pkgpath)
|
|
||||||
|
|
||||||
inputs := make([]string, len(buildpkg.GoFiles))
|
inputs := make([]string, len(buildpkg.GoFiles))
|
||||||
for i, file := range buildpkg.GoFiles {
|
for i, file := range buildpkg.GoFiles {
|
||||||
inputs[i] = filepath.Join(buildpkg.Dir, file)
|
inputs[i] = filepath.Join(buildpkg.Dir, file)
|
||||||
|
@ -446,7 +460,7 @@ func (in *interp) loadPackage(pkgpath string) (*types.Package, error) {
|
||||||
|
|
||||||
// readLine accumulates lines of input, including trailing newlines,
|
// readLine accumulates lines of input, including trailing newlines,
|
||||||
// executing statements as they are completed.
|
// executing statements as they are completed.
|
||||||
func (in *interp) readLine(line string) error {
|
func (in *interp) readLine(line string) ([]interface{}, error) {
|
||||||
if !in.pendingLine.ready() {
|
if !in.pendingLine.ready() {
|
||||||
return in.readExprLine(line, nil)
|
return in.readExprLine(line, nil)
|
||||||
}
|
}
|
||||||
|
@ -459,33 +473,32 @@ func (in *interp) readLine(line string) error {
|
||||||
_, tok, lit := s.Scan()
|
_, tok, lit := s.Scan()
|
||||||
switch tok {
|
switch tok {
|
||||||
case token.EOF:
|
case token.EOF:
|
||||||
return nil
|
return nil, nil
|
||||||
|
|
||||||
case token.IMPORT:
|
case token.IMPORT:
|
||||||
_, tok, lit = s.Scan()
|
_, tok, lit = s.Scan()
|
||||||
if tok != token.STRING {
|
if tok != token.STRING {
|
||||||
return errors.New("expected string literal")
|
return nil, errors.New("expected string literal")
|
||||||
}
|
}
|
||||||
pkgpath, err := strconv.Unquote(lit)
|
pkgpath, err := strconv.Unquote(lit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
pkg, err := in.loadPackage(pkgpath)
|
pkg, err := in.loadPackage(pkgpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
in.imports = append(in.imports, pkg)
|
in.imports = append(in.imports, pkg)
|
||||||
return nil
|
return nil, nil
|
||||||
|
|
||||||
case token.IDENT:
|
case token.IDENT:
|
||||||
ok, err := in.maybeReadAssignment(line, &s, lit, file.Base())
|
ok, err := in.maybeReadAssignment(line, &s, lit, file.Base())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
if ok {
|
if ok {
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fallthrough
|
fallthrough
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -493,6 +506,14 @@ func (in *interp) readLine(line string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// printResult prints a value that was the result of an expression evaluated
|
||||||
|
// by the interpreter.
|
||||||
|
func printResult(w io.Writer, v interface{}) {
|
||||||
|
// TODO the result should be formatted in Go syntax, without
|
||||||
|
// package qualifiers for types defined within the interpreter.
|
||||||
|
fmt.Fprintf(w, "%+v", v)
|
||||||
|
}
|
||||||
|
|
||||||
// formatHistory reformats the provided Go source by collapsing all lines
|
// formatHistory reformats the provided Go source by collapsing all lines
|
||||||
// and adding semicolons where required, suitable for adding to line history.
|
// and adding semicolons where required, suitable for adding to line history.
|
||||||
func formatHistory(input []byte) string {
|
func formatHistory(input []byte) string {
|
||||||
|
@ -560,10 +581,14 @@ func main() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
buf.WriteString(line + "\n")
|
buf.WriteString(line + "\n")
|
||||||
err = in.readLine(line + "\n")
|
results, err := in.readLine(line + "\n")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
for _, result := range results {
|
||||||
|
printResult(os.Stdout, result)
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if liner.TerminalSupported() {
|
if liner.TerminalSupported() {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// RUN: llgoi < %s | FileCheck %s
|
// RUN: llgoi < %s | FileCheck %s
|
||||||
|
|
||||||
1 + 1
|
1 + 1
|
||||||
// CHECK: #0 untyped int = 2
|
// CHECK: 2
|
||||||
|
|
|
@ -4,17 +4,15 @@
|
||||||
Answer := 1
|
Answer := 1
|
||||||
|
|
||||||
import "foo"
|
import "foo"
|
||||||
// CHECK: # bar
|
|
||||||
// CHECK: # foo
|
|
||||||
|
|
||||||
// Test that importing binary after source works.
|
// Test that importing binary after source works.
|
||||||
import "strconv"
|
import "strconv"
|
||||||
|
|
||||||
foo.Answer()
|
foo.Answer()
|
||||||
// CHECK: #0 int = 42
|
// CHECK: 42
|
||||||
|
|
||||||
strconv.FormatBool(true)
|
strconv.FormatBool(true)
|
||||||
// CHECK: #0 string = true
|
// CHECK: true
|
||||||
|
|
||||||
var v1 strconv.NumError
|
var v1 strconv.NumError
|
||||||
var v2 strconv.NumError
|
var v2 strconv.NumError
|
||||||
|
|
|
@ -4,11 +4,9 @@
|
||||||
import "strconv"
|
import "strconv"
|
||||||
|
|
||||||
import "foo"
|
import "foo"
|
||||||
// CHECK: # bar
|
|
||||||
// CHECK: # foo
|
|
||||||
|
|
||||||
foo.Answer()
|
foo.Answer()
|
||||||
// CHECK: #0 int = 42
|
// CHECK: 42
|
||||||
|
|
||||||
strconv.FormatBool(true)
|
strconv.FormatBool(true)
|
||||||
// CHECK: #0 string = true
|
// CHECK: true
|
||||||
|
|
|
@ -2,18 +2,21 @@
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
err := errors.New("foo")
|
err := errors.New("foo")
|
||||||
// CHECK: err error {{.*}} = foo
|
err
|
||||||
|
// CHECK: foo
|
||||||
|
|
||||||
err.(interface{Foo()})
|
err.(interface{Foo()})
|
||||||
// CHECK: panic: interface conversion
|
// CHECK: panic: interface conversion
|
||||||
|
|
||||||
_, _ := err.(interface{Foo()})
|
_, ok := err.(interface{Foo()})
|
||||||
// CHECK: #0 interface{Foo()} (<nil>) = <nil>
|
ok
|
||||||
// CHECK: #1 bool = false
|
// CHECK: false
|
||||||
|
|
||||||
err.(interface{Error() string})
|
err.(interface{Error() string})
|
||||||
// CHECK: #0 interface{Error() string} {{.*}} = foo
|
// CHECK: foo
|
||||||
|
|
||||||
_, _ := err.(interface{Error() string})
|
iface, ok := err.(interface{Error() string})
|
||||||
// CHECK: #0 interface{Error() string} {{.*}} = foo
|
iface
|
||||||
// CHECK: #1 bool = true
|
// CHECK: foo
|
||||||
|
ok
|
||||||
|
// CHECK: true
|
||||||
|
|
|
@ -1,22 +1,27 @@
|
||||||
// RUN: llgoi < %s | FileCheck %s
|
// RUN: llgoi < %s | FileCheck %s
|
||||||
|
|
||||||
m := make(map[int]int)
|
m := make(map[int]int)
|
||||||
// CHECK: m map[int]int = map[]
|
m
|
||||||
|
// CHECK: map[]
|
||||||
|
|
||||||
m[0]
|
m[0]
|
||||||
// CHECK: #0 int = 0
|
// CHECK: 0
|
||||||
|
|
||||||
_, _ := m[0]
|
m0, ok := m[0]
|
||||||
// CHECK: #0 int = 0
|
m0
|
||||||
// CHECK: #1 bool = false
|
// CHECK: 0
|
||||||
|
ok
|
||||||
|
// CHECK: false
|
||||||
|
|
||||||
func() {
|
func() {
|
||||||
m[0] = 1
|
m[0] = 1
|
||||||
}()
|
}()
|
||||||
|
|
||||||
m[0]
|
m[0]
|
||||||
// CHECK: #0 int = 1
|
// CHECK: 1
|
||||||
|
|
||||||
_, _ := m[0]
|
m0, ok = m[0]
|
||||||
// CHECK: #0 int = 1
|
m0
|
||||||
// CHECK: #1 bool = true
|
// CHECK: 1
|
||||||
|
ok
|
||||||
|
// CHECK: true
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
// RUN: llgoi < %s 2>&1 | FileCheck %s
|
// RUN: llgoi < %s 2>&1 | FileCheck %s
|
||||||
|
|
||||||
x := 3
|
x := 3
|
||||||
// CHECK: x untyped int = 3
|
x
|
||||||
|
// CHECK: 3
|
||||||
|
|
||||||
x + x
|
x + x
|
||||||
// CHECK: #0 int = 6
|
// CHECK: 6
|
||||||
|
|
||||||
x * x
|
x * x
|
||||||
// CHECK: #0 int = 9
|
// CHECK: 9
|
||||||
|
|
||||||
x = 4
|
x = 4
|
||||||
x + x
|
x + x
|
||||||
// CHECK: #0 int = 8
|
// CHECK: 8
|
||||||
|
|
||||||
x := true
|
x := true
|
||||||
// CHECK: cannot assign {{.*}} to x (variable of type int)
|
// CHECK: cannot assign {{.*}} to x (variable of type int)
|
||||||
|
@ -19,11 +20,11 @@ x := true
|
||||||
x, y := func() (int, int) {
|
x, y := func() (int, int) {
|
||||||
return 1, 2
|
return 1, 2
|
||||||
}()
|
}()
|
||||||
// CHECK: x int = 1
|
// CHECK: 1
|
||||||
// CHECK: y int = 2
|
// CHECK: 2
|
||||||
|
|
||||||
x, _ = func() (int, int) {
|
x, _ = func() (int, int) {
|
||||||
return 3, 4
|
return 3, 4
|
||||||
}()
|
}()
|
||||||
x
|
x
|
||||||
// CHECK: #0 int = 3
|
// CHECK: 3
|
||||||
|
|
Loading…
Reference in New Issue