Compare commits

...

78 Commits

Author SHA1 Message Date
Marc Vertes
79747f3d6f interp: fix redeclarations containing a blank variable
In [short variable declarations](https://go.dev/ref/spec#Short_variable_declarations),
The reuse of existing symbols is possible only if a new variable is defined,
otherwise a new symbol must be created, which was not the case in the issue.

Search for new symbols and correctly ignore blank variables.

Fixes #1434.
2022-09-02 16:44:07 +02:00
Marc Vertes
63825e7201 interp: fix use of interfaces in composite types
The representation of non empty interfaces defined in the interpreter is now identical between refType() and frameType() functions, which are used to generate interpreter objects.

Fixes #1447 and #1426.
2022-09-01 12:18:08 +02:00
Marc Vertes
03ccda1a69 interp: fix type switch on arbitrary expressions
If the value on which to type-switch was already set (i.e. a variable),
there was no problem. But if it had to be obtained through a complex
expression (func call, array index, etc...), then the code to retrieve
the value prior type-switch was not scheduled. This is now fixed.

This issue is nasty because the behavior is silently changed,
leading potentially to further unrelated issues or runtime panics.

Fixes #1444.
2022-08-25 12:04:08 +02:00
Marc Vertes
e02621577f interp: improve handling of composed interfaces wrappers
This change implements a workaround to better support composed
interfaces in yaegi and let the interpreter define objects which
implement multiple interfaces at once.

We use the existing MapTypes to store what possible composed interface
wrapper could be used for some interfaces. When generating an interface
wrapper, the wrapper with the highest number of implemented methods is
chosen.

This is still an imperfect solution but it improves the accuracy of
interpreter in some critical cases.

This workaround could be removed in future if/when golang/go#15924
is resolved.

Fixes #1425.
2022-08-25 10:44:11 +02:00
Marc Vertes
ab869c8d20 interp: improve method resolution for embedded interfaces
The function `getMethodByName()` is now able to look for
embedded `valueInterface` field for matching methods in interface
struct fields.
    
Fixes #1439 and #1427.
2022-08-17 18:14:10 +02:00
Marc Vertes
b2aa636ea0 interp: fix spurious variable declaration loop
The variable dependency check function was confused by a dependency
variable with the same name but in an external package.

This change is necessary to address #1427.
2022-08-10 16:10:08 +02:00
Marc Vertes
ae725fb3d9 interp: fix generic check on nil function
Related to issue https://github.com/traefik/traefik/issues/9231
2022-08-05 18:20:08 +02:00
Marc Vertes
14bc3b56b8 interp: add support of Go generics in interpreter
Status:
* [x] parsing code with generics
* [x] instantiate generics from concrete types
* [x] automatic type inference
* [x] support of generic recursive types 
* [x] support of generic methods
* [x] support of generic receivers in methods
* [x] support of multiple type parameters
* [x] support of generic constraints
* [x] tests (see _test/gen*.go)

Fixes #1363.
2022-08-03 15:18:08 +02:00
Marc Vertes
255b1cf1de interp: do not allow function declaration without body
Such function declaration denotes either a linkname (an access to
an arbitrary, typically unexported symbol, solved by go compiler),
or a foreign C or assembly implementation of the body.

Those cases are not supported (or planned to be) by the interpreter.

Fixes #1431.
2022-08-03 10:06:06 +02:00
Marc Vertes
d3fc5e990e chore: upgrade to go1.19
* chore: upgrade to go1.19

* review

Co-authored-by: Fernandez Ludovic <ldez@users.noreply.github.com>
2022-08-03 09:44:07 +02:00
Marc Vertes
dc082b5ded stdlib: support of go1.18 and go1.19, remove go1.16 and go1.17
In addition:
- extract commmand now skips exported generics in runtime wrappers
- interp_consistent_test.go fixed for go1.18 and go1.19
- move minimal version of go compiler to go1.18

Note that this version is incompatible with go1.17 and before due
to the major changes in the stdlib go parser.

To be merged once go1.19 is officially released (not before).
2022-07-20 17:10:08 +02:00
Marc Vertes
d9c402e20d interp: fix unit testing for go1.18
Some tests are not passing when using go1.18, due to a change of
content in error messages compared to go1.17. We simply skip them
while we support go1.17. It concerns a small number of tests
regarding error detection.
2022-07-20 11:04:09 +02:00
ttoad
09a1617640 interp: improve support of alias types
I expect the following code to be supported.
```go
type TT http.Header

func (t TT) Set(key, val string) {

}

func (t TT) Get(key string) string {

}
```
So, I pushed this PR. 
Do I need to add some test cases?  I don't see the relevant test files ....
2022-07-14 19:38:07 +02:00
Luo Peng
cb642c44ba interp: improve type checking when comparing aliased types
Fixes #1421.
2022-06-30 10:22:12 +02:00
Marc Vertes
f76db27c77 interp: fix resolution of methods on aliased types
The type.val field was always pointing to the final underlying type
for aliased types, defeating a possible match if a method was
attached to a type in between. Now the complete chain of aliases
is always preserved.

We have added an underlying() itype method which returns the underlying
type of a defined type (aliasT), even in the presence of multiple
indirections.

We have added a definedType function which checks if type t1 is
defined from type t2 or t2 defined from t1, required when checking
assignability of aliasT types.

Fixes #1411.

PS: this is the 2nd attempt, as the first version #1412 wasn't passing
_test/issue-1408.go as well. This PR does pass and supersedes #1412.
2022-06-14 16:42:09 +02:00
mpl
996b1e33c8 interp: catch mismatched types for other comparisons
The check for mismatched types was already added recently for ==  and != comparisons.
This PR now adds it for other comparisons ( < , <=, > , >=).
2022-06-14 10:52:08 +02:00
Marc Vertes
236a0effaf interp: improve the behaviour of interface{} function parameters
We finally address a long standing limitation of the interpreter:
the capacity to generate the correct interface wrapper for an
anonymous interface{} function parameter of a binary function.

It allows for example fmt.Printf to invoke the String method
of an object defined within the interpreter, or json.Marshal
to invoke a textMarshaler method if it exists and if there is
no Marshaler method already defined for the passed interpreter
object.

To achieve that, we add a new mapType part of the "Used" symbols
to describe what not empty interfaces are expected and in which
priority order. This information can not be guessed and is found
in the related package documentation, then captured in stdlib/maptypes.go.

Then, at compile time and/or during execution, a lookup on mapTypes
is performed to allow the correct wrapper to be generated.

This change adds a new MapType type to the stdlib package.

Fixes #435.
2022-06-14 10:18:08 +02:00
Marc Vertes
eaeb445e17 interp: create interpreter interface value with new
In that case, the interface must be wrapped in an valueInterface
at creation.

With that fix, it is now possible to import
github.com/google/go-querystring/query. Not tested beyond that.

Fixes #1123.
2022-06-13 11:36:09 +02:00
Marc Vertes
6933ba2b4e interp: improve type checking for defined types
Fixes #1408.
2022-06-13 11:24:09 +02:00
Marc Vertes
a61a7d5bcd interp: avoid panic when defining a label in incremental parsing mode
In REPL mode, a panic (stack overflow) could be triggered by:

	$ yaegi
	> a:
	runtime: goroutine stack exceeds 1000000000-byte limit
	runtime: sp=0x14020760330 stack=[0x14020760000, 0x14040760000]
	fatal error: stack overflow
	[...]

This issue occurs in incremental parsing mode only, and not when the parser
is in file mode. We avoid it by being more defensive when generating
values.

Fixes #982.
2022-06-13 11:10:09 +02:00
Marc Vertes
259f64cfd4 interp: fix redeclaration of an interface variable
Fixes #1404.
2022-06-13 10:56:09 +02:00
Marc Vertes
6c74ab7bec interp: allow conversions of untyped complex
For untyped numerical types, conversions to different numerical
types can be allowed if there is no overflow (not checked here).

Fixes #1402.
2022-06-13 10:42:08 +02:00
Marc Vertes
d64563edee interp: improve handling values and comparisons in interfaces
Fixes #1347.
2022-05-23 10:30:08 +02:00
Marc Vertes
07039262a0 interp: implements detection of packages with no Go files
This avoids panic during import, and print a proper diagnostic
instead.

Fixes #1394.
2022-05-19 18:34:08 +02:00
Marc Vertes
4ed9ccb5c4 interp: fix retrieving the string value of an interface
Thanks to @bailsman for providing first insight, in addition to
raising the issue.

Fixes #1342.
2022-05-19 18:20:09 +02:00
Marc Vertes
25edcfee7a interp: fix handling of empty interfaces in map index expressions
There should be no need now to wrap empty interfaces in order to
retrieve its value.

Fixes #1344.
2022-05-19 18:08:09 +02:00
Marc Vertes
d183f4205e interp: improve handling of empty interface values (#1393)
At variable, function parameter, slice, map or field element assign,
if the destination type is an empty interface, the value was never
wrapped into a valueInterface (to preserve type mutability in case
of re-assign). Now we wrap it in a valueInterface if the source
type has a non empty set of methods, to allow a future use as a non
empty interface.

There are still corner cases, but it extends notably the support
of interfaces within the interpreter.

Fixes #1355.
2022-05-19 17:53:56 +02:00
Marc Vertes
821e9ee006 interp: recover interpreter internal panics in EvalWithContext 2022-05-19 17:30:09 +02:00
Marc Vertes
00e3f924c1 interp: fix the behaviour of goto, continue and break (#1392)
The logic of goto was false due to mixing break label and goto
label, despite being opposite. In case of break, jump to node (the
exit point) instead of node.start. Also always define label symbols
before their use is parsed.

* Fix continue label, detect invalid labels for break and continue

* fix multiple goto, break, continue to the same label

Fixes #1354.
2022-05-19 11:23:30 +02:00
Marc Vertes
2248851d77 interp: fix creation of binary composite types (#1391)
* interp: fix creation of binary composite types

Use direct assignment instead of reflect.Value Set method to
initialize a binary composite type, as for non binary types.
It ensures that a new reflect.Value is stored in the frame
instead of modifying a possibly existing one, which can defeat
the purpose of initializing variables in a body loop.

While there, remove the need to have and use a mutex on types.

Fixes #1381.

* review: rework a bit the test

Co-authored-by: mpl <mathieu.lonjaret@gmail.com>
2022-05-05 21:31:10 +02:00
Marc Vertes
f74d1ea6d8 interp: detect invalid uses of _ as value
We now detect the use of special identifier _ (blank) during parsing in order to abort compiling early. It allows to not panic later during execution. We must catch all the cases where blank is used as a value, but still preserve the cases where it is assigned, used as a struct field or for import side effects.

Fixes #1386.
2022-05-04 18:51:09 +02:00
Marc Vertes
606b4c3a37 interp: fix import of binary type symbols in current scope (#1380)
Fixes #1360.
2022-05-04 17:27:11 +02:00
Ethan Reesor
4e77fc9436 interp: delete incomplete type on pkg import
When a package is imported, it creates a symbol with a name like "errors/_.go". If a statement such as x := errors.New(...) is executed before import "errors", it creates an incomplete type symbol with a name like "errors". Importing the package after the incomplete type symbol has been created does not fix the compile issue because the incomplete type still exists.

To fix this, this PR deletes the incomplete type symbol, if one exists.

Closes #1388.
2022-04-26 11:04:13 +02:00
Ethan Reesor
ad9db379e7 interp: add a function to get globals (#1387)
Co-authored-by: Marc Vertes <mvertes@free.fr>
2022-04-25 16:11:18 +02:00
Ethan Reesor
7be17d393f interp: expose fset to fix CompileAST issue
The interpreter has its own internal fileset and expects all code to have been parsed using that fileset. If a user creates a fileset, calls `go/parser.Parse*`, then passes the result to `interp.CompileAST`, strange things can happen.

The solutions I can see are:

1. Expose the fileset so the user can use it when parsing source.
2. Add the fileset as an option (input to New) so that the user can tell the interpreter to use a specific fileset.
3. Pass the fileset into `CompileAST`

There are two ways to implement option 3. One is to add a field to nodes and update every reference to `interp.fset` to use `node.fset`. The other is to add a parameter to every function that references `interp.fset` or calls a function that does. Both of these are significant changes and involve an extra pointer for every node or most function calls.

Options 1 and 2 are easy. Option 2 involves adding an option so I went with option 1. I can imagine situations where option 2 could be necessary, but I can open another issue/PR if and when I need that.

Fixes #1383
2022-04-22 11:48:08 +02:00
cclerget
5665c9a410 interp: fix redeclaration scope issue
Fixes #1378
2022-04-09 15:28:07 +02:00
cclerget
1cf9d345aa Ignore private methods for binary types during type assertion
Fixes #1373
2022-04-07 18:16:08 +02:00
Marc Vertes
f07f25f1ba interp: handle struct with multiple recursive fields (#1372)
* interp: handle struct with multiple recursive fields

In case of a recursive struct with several recursive fields of
different type, only the first one was properly fixed when
constructing the corresponding reflect type. We now memorize and
process all fields at the same depth level.

Fixes #1371.

* Update interp/type.go

Co-authored-by: mpl <mathieu.lonjaret@gmail.com>

* fix lint

* fix comment

Co-authored-by: mpl <mathieu.lonjaret@gmail.com>
2022-04-07 14:53:23 +02:00
cclerget
c93b836c77 Prevent variadic arguments from being wrapped as function
Fixes #1375
2022-04-07 14:24:07 +02:00
Marc Vertes
371103f0d1 interp: fix switch expression (#1370)
The control flow graph was incorrect for the initial clause.

Fixes #1368.
2022-04-06 22:07:51 +02:00
Marc Vertes
8bd7afbe62 interp: fix handling of redeclaration in multi-assign expression (#1367)
* interp: fix handling of redeclaration in multi-assign expression

In a statement like `a, b := f()` if `a` was previously declared,
its symbol must be reused, a new symbol must not override its
previous value. This is now fixed.

* In case of redeclaration, reuse the existing only if the redeclared
variable has the same type. Add _test/var16.go to check this use
case.

Fixes #1365.
2022-04-06 20:01:25 +02:00
Marc Vertes
8ea3a493f4 interp: fix interface conversion from binary call (#1366)
Fixes #1364.
2022-04-06 19:51:12 +02:00
Marc Vertes
f2abd346c0 interp: fix passing binary function as parameter
Wrap binary function values in a node if passing it
as a parameter to an interperter defined function.

Fixes #1361.
2022-04-05 17:34:08 +02:00
Marc Vertes
c784713aca interp: make methods passed as value preserve receiver
Fixes #1332.
2022-04-05 16:58:09 +02:00
Marc Vertes
14acf618af interp: improve type switch on binary interfaces
Fixes #1337.
2022-01-04 10:50:08 +01:00
Marc Vertes
fbee2baf9d interp: fix wrapping of returned closure passed to runtime
Fixes #1333.
2021-12-21 17:44:06 +01:00
Marc Vertes
2819b4167b interp: fix derivation of type of slice expression of binary object
Fixes #1328.
2021-12-20 15:46:05 +01:00
Marc Vertes
2af660cb1f interp: improve method resolution on embedded fields
The capability to dereference pointers has been added to
methodByName(), improving method lookup on binary values.

Wrapping to valueInterface is performed in a missing use case at
return of function calls. It was done in the nested call, but not
at assign.

Fixes #1330.
2021-12-20 15:06:11 +01:00
Marc Vertes
8323068414 interp: fix nested calls with variadic interfaces
Fixes #1326
2021-12-08 17:16:05 +01:00
Marc Vertes
5b62f9fdb6 interp: fix setting of interface value from nested function calls
Fixes #1320 and #1294.
2021-11-30 15:44:05 +01:00
Marc Vertes
4f66e3fe6c interp: fix type switch when the case type is an interpreted interface
Fixes #1315.

With this PR, the package gopkg.in/yaml.v3 works in yaegi (fixes #1296).
2021-11-26 12:24:07 +01:00
Marc Vertes
1335b4c64f stdlib: add wrappers for go/build/constraint package 2021-11-26 12:10:08 +01:00
Marc Vertes
da03c922ca interp: get rid of deprecated stdlib package ioutil
No functional change.
2021-11-26 11:58:07 +01:00
Marc Vertes
9620116c30 interp: replace value.Type().Kind() by value.Kind()
No functional change. Just simpler and faster.
2021-11-26 11:42:07 +01:00
Marc Vertes
dd7197f2a2 interp: fix assign of multiple return function call
A runtime builtin assignFromCall is added to handle multiple values returned at once. It is necessary if some of the values require to be set to interface values in the caller space, which is performed by reflect.Set in assignFromCall.
 
Fixes #1311.
2021-11-19 15:30:05 +01:00
Marc Vertes
9214806342 interp: fix populating array of interfaces
Fixes #1308.
2021-11-09 11:26:11 +01:00
Marc Vertes
348e713a8e interp: avoid collision between type and variable names in assign
Fixes #1306
2021-11-09 11:14:09 +01:00
Marc Vertes
cb81fe41ab interp: fix type processing to support multiple recursive fields
Fixes #1304
2021-11-08 20:46:12 +01:00
Marc Vertes
a876bb3673 interp: virtualize environment in restricted mode
In restricted mode, replace environment related symbols in
stdlib os package by a version which operates on a private copy
per interpreter context.

It allows to have concurrent interpreters in the same process
operating each in their own environment without affecting each
other or the host.

If unrestricted opt is set, this behaviour is disabled, and the
default symbols from stdlib are used.

Note also that no modification is done for syscall package, as it
should be not used in restricted mode.
2021-11-08 09:58:10 +01:00
Marc Vertes
afa46daccd interp: fix assignment to a dereferenced struct pointer
disable the optimization of skipping assign operation in that case,
as this step is necessary in case of writing to a pointer.

Fixes #1300.
2021-11-02 15:56:13 +01:00
Marc Vertes
3c00da291e stdlib: add wrappers for standard lib runtime/metrics package
This package was forgotten. No reason to not include it.
2021-11-02 15:20:06 +01:00
Marc Vertes
c847481184 interp: fix comparison operators in if statement
At generation of operator closures, the comparison expression
was hard-coded instead of being derived from the operator name,
leading to a wrong result.

Fixes #1297.
2021-11-02 15:02:07 +01:00
Marc Vertes
f46ef67180 interp: fix computation of ellipsis array length
Fixes #1287.
2021-10-20 14:36:05 +02:00
Marc Vertes
229ddfdae1 interp: fix use of builtins in type definitions
Make len() and cap() work on pointers. Preserve scope in case of
nested calls of cfg.

Fixes #1285.
2021-10-18 10:50:14 +02:00
Marc Vertes
aa7f0849e3 interp: fix goto to a label with no statement
Fixes #1288.
2021-10-18 10:36:12 +02:00
Bai-Yingjie
7617b8a090 interp: add args option to let each interpreter have seperate args
In some cases, we use many yaegi instances in one process, each interpreter will expect its own os.Args. This is done in interp.go as an option in interp.Options besides Stdin Stdout and Stderr.
2021-10-11 16:58:07 +02:00
Marc Vertes
4e06abe002 interp: fix unsafe2 to work on 32 bits architectures
Fixes #1279.
2021-10-11 11:38:12 +02:00
Bai-Yingjie
b1a758dd5a extract: add an option to be able to set build tag to the created file
Add a tag option in the extract program to optionally give an opportunity to tailor some packages in for example the stdlib, for people who is interested in keeping the final binary size as smaller as possible.
Below go generate
```
//go:generate ../cmd/extract/extract -name stdlib -tag stdmime mime mime/multipart mime/quotedprintable
```
produces a header to stdlib/mime-multipart.go
```
// Code generated by 'yaegi extract mime/multipart'. DO NOT EDIT.

// +build go1.16,!go1.17,stdmime
```
2021-10-11 10:50:11 +02:00
Marc Vertes
5bf4daef2d interp: fix type check of methods with a receiver of interface kind
Fixes #1280.
2021-10-08 17:44:09 +02:00
Marc Vertes
e56db3b82e interp: improve interface wrappers when used by reflect
When an interpreter type implementing an interface is
used by the runtime, the runtime can extract its type
and create new values using reflect, and call methods
on it. The problem is that there will be no interpreted
method counterpart in this case, which makes wrapper panic.

Allow the String() method wrapper to always succeed and
return an empty string if no interpreted method is present.

This allows scripts to define custom flag.Value types on
which the runtime internally instantiates values using
reflect (see isZeroValue in Go src/flag/flag.go).

This workaround could be generalized to all wrappers if
necessary. At this moment, it is convenient to keep the
default behavior of expecting instantiated interpreter
methods, in order to catch interpreter bugs related to
interfaces.

Fixes #1276.
2021-10-08 15:56:06 +02:00
Marc Vertes
d3bbe01d5c interp: improve support of composed interfaces
Fixes #1260.
2021-10-07 16:28:05 +02:00
Nicholas Wiersma
286d6c6359 interp: handle recursive and incomplete seen types in nodeType
This comes from experiments looking into #1259 where incomplete twice seen types are marked as complete. To mitigate the problem instead of a map of seen types in `nodeType` a slice is used as a cheap way to keep track of our current path through the node tree.
2021-09-27 10:20:13 +02:00
Nicholas Wiersma
84424b52bc interp: handle alias of an alias
When dealing with an alias of an alias, the actual underlying type of the source alias should be used.
2021-09-27 10:08:11 +02:00
Marc Vertes
98c2dcd3e5 interp: fix interface wrapper for struct types
This change fixes a regression introduced by PR #1192 in a program using
https://github.com/NYTimes/gziphandler which defines several types
implementing stdlib interfaces. We do not implement a wrapper
if we see that a type already implements an interface, except that
it can be falsly reported by reflect in case of a struct with
embedded interface field. We need to force the wrapper generation
in this case.
The problem occurs only for wrappers on struct, not on pointers or
other indirection types.
2021-09-24 13:20:12 +02:00
Ethan Reesor
808f0bde9d interp: add a function to directly compile Go AST
Adds CompileAST, which can be used to compile Go AST directly. This
allows users to delegate parsing of source to their own code instead of
relying on the interpreter.

CLoses #1251
2021-09-23 12:34:12 +02:00
Nicholas Wiersma
c5c6012947 interp: support type spec assign
This supports type spec assign types which disallows the attachment of methods onto the alias type as per the Go spec.

Fixes #1154
2021-09-23 12:16:11 +02:00
Nicholas Wiersma
836060c8ad interp: allow GTA revisit for unresolved define statements
When a define statement relies on a selector or type that may exist in another file it should revisit once GTA is complete. This allows that revisit.

**Note:** In order to keep the original GTA error for the define statement, so the error received is correct and meaningful, I have added a node `meta` property. I decided to make it generic as it may be useful in future. There may be a better way to stash errors across the GTA runs and am open to suggestion here.

Fixes #1253
2021-09-20 12:04:06 +02:00
Nicholas Wiersma
7a54353c7b chore: update linter to v1.42.1
* chore: update linter to v1.42.1

* fix: linter issues
2021-09-20 10:18:14 +02:00
681 changed files with 19018 additions and 8426 deletions

View File

@@ -17,7 +17,7 @@ jobs:
strategy:
matrix:
go-version: [ 1.16, 1.17 ]
go-version: [ 1.18, 1.19 ]
os: [ubuntu-latest, macos-latest, windows-latest]
include:
@@ -34,6 +34,7 @@ jobs:
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}
stable: true
# https://github.com/marketplace/actions/checkout
- name: Checkout code

View File

@@ -7,8 +7,8 @@ on:
pull_request:
env:
GO_VERSION: 1.17
GOLANGCI_LINT_VERSION: v1.41.1
GO_VERSION: 1.18
GOLANGCI_LINT_VERSION: v1.47.1
jobs:
@@ -45,12 +45,13 @@ jobs:
needs: linting
strategy:
matrix:
go-version: [ 1.16, 1.17 ]
go-version: [ 1.18, 1.19 ]
steps:
- name: Set up Go ${{ matrix.go-version }}
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}
stable: true
- name: Check out code
uses: actions/checkout@v2
@@ -75,13 +76,14 @@ jobs:
working-directory: ${{ github.workspace }}/go/src/github.com/traefik/yaegi
strategy:
matrix:
go-version: [ 1.16, 1.17 ]
go-version: [ 1.18, 1.19 ]
steps:
- name: Set up Go ${{ matrix.go-version }}
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}
stable: true
- name: Check out code
uses: actions/checkout@v2

View File

@@ -6,7 +6,7 @@ on:
- v[0-9]+.[0-9]+*
env:
GO_VERSION: 1.17
GO_VERSION: 1.19
jobs:

View File

@@ -27,6 +27,7 @@
"scopelint", # deprecated
"interfacer", # deprecated
"maligned", # deprecated
"exhaustivestruct", # deprecated
"lll",
"gas",
"dupl",
@@ -49,10 +50,15 @@
"wrapcheck",
"nestif",
"exhaustive",
"exhaustivestruct",
"exhaustruct",
"forbidigo",
"ifshort",
"forcetypeassert",
"varnamelen",
"nosnakecase",
"nonamedreturns",
"nilnil",
"maintidx",
"errorlint", # TODO: must be reactivate before fixes
]
@@ -75,6 +81,12 @@
[[issues.exclude-rules]]
path = "interp/interp.go"
text = "`out` can be `io.Writer`"
[[issues.exclude-rules]]
path = "interp/interp.go"
text = "`Panic` should conform to the `XxxError` format"
[[issues.exclude-rules]]
path = "interp/interp_eval_test.go"
linters = ["thelper"]
[[issues.exclude-rules]]
path = "interp/debugger.go"
linters = ["containedctx"]

View File

@@ -18,7 +18,7 @@ It powers executable Go scripts and plugins, in embedded interpreters or interac
* Works everywhere Go works
* All Go & runtime resources accessible from script (with control)
* Security: `unsafe` and `syscall` packages neither used nor exported by default
* Support Go 1.16 and Go 1.17 (the latest 2 major releases)
* Support Go 1.18 and Go 1.19 (the latest 2 major releases)
## Install

View File

@@ -6,16 +6,18 @@ const (
zero = iota
one
two
three
)
func main() {
a := [...]string{
zero: "zero",
one: "one",
two: "two",
zero: "zero",
one: "one",
three: "three",
three + 2: "five",
}
fmt.Printf("%v %T\n", a, a)
}
// Output:
// [zero one two] [3]string
// [zero one three five] [6]string

View File

@@ -1,5 +1,10 @@
package alias3
import (
"fmt"
"net/http"
)
type T struct {
A string
}
@@ -7,3 +12,20 @@ type T struct {
func (t *T) Print() {
println(t.A)
}
type A http.Header
func (a A) ForeachKey() error {
for k, vals := range a {
for _, v := range vals {
fmt.Println(k, v)
}
}
return nil
}
func (a A) Set(k string, v []string) {
a[k] = v
}

39
_test/alias4.go Normal file
View File

@@ -0,0 +1,39 @@
package main
import (
"fmt"
"net/http"
)
type A http.Header
func (a A) Test1() {
fmt.Println("test1")
}
type B A
func (b B) Test2() {
fmt.Println("test2")
}
func (b B) Test3() {
for k, vals := range b {
for _, v := range vals {
fmt.Println(k, v)
}
}
}
func main() {
b := B{}
b.Test2()
b["test"] = []string{"a", "b"}
b.Test3()
}
// Output:
// test2
// test a
// test b

View File

@@ -5,8 +5,8 @@ import (
"sync"
)
// Defined an interface of stringBuilder that compatible with
// strings.Builder(go 1.10) and bytes.Buffer(< go 1.10)
// Define an interface of stringBuilder that is compatible with
// strings.Builder(go 1.10) and bytes.Buffer(< go 1.10).
type stringBuilder interface {
WriteRune(r rune) (n int, err error)
WriteString(s string) (int, error)

21
_test/assign17.go Normal file
View File

@@ -0,0 +1,21 @@
package main
func main() {
s := make([]map[string]string, 0)
m := make(map[string]string)
m["m1"] = "m1"
m["m2"] = "m2"
s = append(s, m)
tmpStr := "start"
println(tmpStr)
for _, v := range s {
tmpStr, ok := v["m1"]
println(tmpStr, ok)
}
println(tmpStr)
}
// Output:
// start
// m1 true
// start

21
_test/assign18.go Normal file
View File

@@ -0,0 +1,21 @@
package main
func main() {
s := make([]map[string]string, 0)
m := make(map[string]string)
m["m1"] = "m1"
m["m2"] = "m2"
s = append(s, m)
tmpStr := "start"
println(tmpStr)
for _, v := range s {
tmpStr, _ := v["m1"]
println(tmpStr)
}
println(tmpStr)
}
// Output:
// start
// m1
// start

24
_test/break0.go Normal file
View File

@@ -0,0 +1,24 @@
package main
func main() {
n := 2
m := 2
foo := true
OuterLoop:
println("Boo")
for i := 0; i < n; i++ {
println("I: ", i)
for j := 0; j < m; j++ {
switch foo {
case true:
println(foo)
break OuterLoop
case false:
println(foo)
}
}
}
}
// Error:
// 15:5: invalid break label OuterLoop

24
_test/break1.go Normal file
View File

@@ -0,0 +1,24 @@
package main
func main() {
n := 2
m := 2
foo := true
OuterLoop:
for i := 0; i < n; i++ {
println("I: ", i)
for j := 0; j < m; j++ {
switch foo {
case true:
println(foo)
break OuterLoop
case false:
println(foo)
}
}
}
}
// Output:
// I: 0
// true

25
_test/break2.go Normal file
View File

@@ -0,0 +1,25 @@
package main
func main() {
n := 2
m := 2
foo := true
OuterLoop:
for i := 0; i < n; i++ {
println("I: ", i)
for j := 0; j < m; j++ {
switch foo {
case true:
println(foo)
break OuterLoop
case false:
println(foo)
continue OuterLoop
}
}
}
}
// Output:
// I: 0
// true

27
_test/break3.go Normal file
View File

@@ -0,0 +1,27 @@
package main
func main() {
n := 2
m := 2
foo := true
goto OuterLoop
println("Boo")
OuterLoop:
for i := 0; i < n; i++ {
println("I: ", i)
for j := 0; j < m; j++ {
switch foo {
case true:
println(foo)
break OuterLoop
case false:
println(foo)
goto OuterLoop
}
}
}
}
// Output:
// I: 0
// true

View File

@@ -2,7 +2,7 @@ package main
import (
"fmt"
"io/ioutil"
"io"
"log"
"net"
"net/http"
@@ -13,7 +13,7 @@ func client(uri string) {
if err != nil {
log.Fatal(err)
}
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}

View File

@@ -2,7 +2,7 @@ package main
import (
"fmt"
"io/ioutil"
"io"
"log"
"net"
"net/http"
@@ -21,7 +21,7 @@ func client(uri string) {
if err != nil {
log.Fatal(err)
}
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}

View File

@@ -2,7 +2,7 @@ package main
import (
"fmt"
"io/ioutil"
"io"
"log"
"net/http"
"net/http/httptest"
@@ -13,7 +13,7 @@ func client(uri string) {
if err != nil {
log.Fatal(err)
}
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}

View File

@@ -2,7 +2,7 @@ package main
import (
"fmt"
"io/ioutil"
"io"
"log"
"net/http"
"net/http/httptest"
@@ -40,7 +40,7 @@ func client(uri string) {
if err != nil {
log.Fatal(err)
}
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}

View File

@@ -2,7 +2,7 @@ package main
import (
"fmt"
"io/ioutil"
"io"
"log"
"net/http"
"net/http/httptest"
@@ -40,7 +40,7 @@ func client(uri string) {
if err != nil {
log.Fatal(err)
}
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}

View File

@@ -2,7 +2,7 @@ package main
import (
"fmt"
"io/ioutil"
"io"
"log"
"net/http"
"net/http/httptest"
@@ -41,7 +41,7 @@ func client(uri string) {
if err != nil {
log.Fatal(err)
}
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}

26
_test/cont2.go Normal file
View File

@@ -0,0 +1,26 @@
package main
func main() {
n := 2
m := 2
foo := true
OuterLoop:
for i := 0; i < n; i++ {
println("I: ", i)
for j := 0; j < m; j++ {
switch foo {
case true:
println(foo)
continue OuterLoop
case false:
println(foo)
}
}
}
}
// Output:
// I: 0
// true
// I: 1
// true

24
_test/cont3.go Normal file
View File

@@ -0,0 +1,24 @@
package main
func main() {
n := 2
m := 2
foo := true
OuterLoop:
println("boo")
for i := 0; i < n; i++ {
println("I: ", i)
for j := 0; j < m; j++ {
switch foo {
case true:
println(foo)
continue OuterLoop
case false:
println(foo)
}
}
}
}
// Error:
// 15:5: invalid continue label OuterLoop

View File

@@ -2,12 +2,11 @@ package main
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
file, err := ioutil.TempFile("", "yeagibench")
file, err := os.CreateTemp("", "yeagibench")
if err != nil {
panic(err)
}
@@ -23,7 +22,7 @@ func main() {
panic(err)
}
b, err := ioutil.ReadFile(file.Name())
b, err := os.ReadFile(file.Name())
if err != nil {
panic(err)
}

39
_test/gen1.go Normal file
View File

@@ -0,0 +1,39 @@
package main
import "fmt"
// SumInts adds together the values of m.
func SumInts(m map[string]int64) int64 {
var s int64
for _, v := range m {
s += v
}
return s
}
// SumFloats adds together the values of m.
func SumFloats(m map[string]float64) float64 {
var s float64
for _, v := range m {
s += v
}
return s
}
func main() {
// Initialize a map for the integer values
ints := map[string]int64{
"first": 34,
"second": 12,
}
// Initialize a map for the float values
floats := map[string]float64{
"first": 35.98,
"second": 26.99,
}
fmt.Printf("Non-Generic Sums: %v and %v\n",
SumInts(ints),
SumFloats(floats))
}

12
_test/gen10.go Normal file
View File

@@ -0,0 +1,12 @@
package main
func genFunc() (f func()) {
return f
}
func main() {
println(genFunc() == nil)
}
// Output:
// true

34
_test/gen2.go Normal file
View File

@@ -0,0 +1,34 @@
package main
import "fmt"
// SumIntsOrFloats sums the values of map m. It supports both int64 and float64
// as types for map values.
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {
var s V
for _, v := range m {
s += v
}
return s
}
func main() {
// Initialize a map for the integer values
ints := map[string]int64{
"first": 34,
"second": 12,
}
// Initialize a map for the float values
floats := map[string]float64{
"first": 35.98,
"second": 26.99,
}
fmt.Printf("Generic Sums: %v and %v\n",
SumIntsOrFloats[string, int64](ints),
SumIntsOrFloats[string, float64](floats))
}
// Output:
// Generic Sums: 46 and 62.97

22
_test/gen3.go Normal file
View File

@@ -0,0 +1,22 @@
package main
type Number interface {
int | int64 | ~float64
}
func Sum[T Number](numbers []T) T {
var total T
for _, x := range numbers {
total += x
}
return total
}
func main() {
xs := []int{3, 5, 10}
total := Sum(xs)
println(total)
}
// Output:
// 18

42
_test/gen4.go Normal file
View File

@@ -0,0 +1,42 @@
package main
import "fmt"
type List[T any] struct {
head, tail *element[T]
}
// A recursive generic type.
type element[T any] struct {
next *element[T]
val T
}
func (lst *List[T]) Push(v T) {
if lst.tail == nil {
lst.head = &element[T]{val: v}
lst.tail = lst.head
} else {
lst.tail.next = &element[T]{val: v}
lst.tail = lst.tail.next
}
}
func (lst *List[T]) GetAll() []T {
var elems []T
for e := lst.head; e != nil; e = e.next {
elems = append(elems, e.val)
}
return elems
}
func main() {
lst := List[int]{}
lst.Push(10)
lst.Push(13)
lst.Push(23)
fmt.Println("list:", lst.GetAll())
}
// Output:
// list: [10 13 23]

24
_test/gen5.go Normal file
View File

@@ -0,0 +1,24 @@
package main
import "fmt"
type Set[Elem comparable] struct {
m map[Elem]struct{}
}
func Make[Elem comparable]() Set[Elem] {
return Set[Elem]{m: make(map[Elem]struct{})}
}
func (s Set[Elem]) Add(v Elem) {
s.m[v] = struct{}{}
}
func main() {
s := Make[int]()
s.Add(1)
fmt.Println(s)
}
// Output:
// {map[1:{}]}

19
_test/gen6.go Normal file
View File

@@ -0,0 +1,19 @@
package main
func MapKeys[K comparable, V any](m map[K]V) []K {
r := make([]K, 0, len(m))
for k := range m {
r = append(r, k)
}
return r
}
func main() {
var m = map[int]string{1: "2", 2: "4", 4: "8"}
// Test type inference
println(len(MapKeys(m)))
}
// Output:
// 3

19
_test/gen7.go Normal file
View File

@@ -0,0 +1,19 @@
package main
func MapKeys[K comparable, V any](m map[K]V) []K {
r := make([]K, 0, len(m))
for k := range m {
r = append(r, k)
}
return r
}
func main() {
var m = map[int]string{1: "2", 2: "4", 4: "8"}
// Test type inference
println(len(MapKeys))
}
// Error:
// invalid argument for len

15
_test/gen8.go Normal file
View File

@@ -0,0 +1,15 @@
package main
type Float interface {
~float32 | ~float64
}
func add[T Float](a, b T) float64 { return float64(a) + float64(b) }
func main() {
var x, y int = 1, 2
println(add(x, y))
}
// Error:
// int does not implement main.Float

14
_test/gen9.go Normal file
View File

@@ -0,0 +1,14 @@
package main
type Float interface {
~float32 | ~float64
}
func add[T Float](a, b T) float64 { return float64(a) + float64(b) }
func main() {
println(add(1, 2))
}
// Error:
// untyped int does not implement main.Float

View File

@@ -2,7 +2,7 @@ package main
import (
"fmt"
"io/ioutil"
"io"
"log"
"strings"
)
@@ -10,7 +10,7 @@ import (
func main() {
r := strings.NewReader("Go is a general-purpose language designed with systems programming in mind.")
b, err := ioutil.ReadAll(r)
b, err := io.ReadAll(r)
if err != nil {
log.Fatal(err)
}

View File

@@ -2,7 +2,6 @@ package main
import (
"io"
"io/ioutil"
"os"
)
@@ -13,7 +12,7 @@ type sink interface {
func newSink() sink {
// return os.Stdout // Stdout is special in yaegi tests
file, err := ioutil.TempFile("", "yaegi-test.*")
file, err := os.CreateTemp("", "yaegi-test.*")
if err != nil {
panic(err)
}

67
_test/issue-1260.go Normal file
View File

@@ -0,0 +1,67 @@
package main
import (
"fmt"
"io"
"os"
)
type WriteSyncer interface {
io.Writer
Sync() error
}
type Sink interface {
WriteSyncer
io.Closer
}
func newFileSink(path string) (Sink, error) {
return os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
}
type Sink1 struct{ name string }
func (s Sink1) Write(b []byte) (int, error) { println("in Write"); return 0, nil }
func (s Sink1) Sync() error { println("in Sync"); return nil }
func (s Sink1) Close() error { println("in Close", s.name); return nil }
func newS1(name string) Sink { return Sink1{name} }
func newS1p(name string) Sink { return &Sink1{name} }
type Sink2 struct{ name string }
func (s *Sink2) Write(b []byte) (int, error) { println("in Write"); return 0, nil }
func (s *Sink2) Sync() error { println("in Sync"); return nil }
func (s *Sink2) Close() error { println("in Close", s.name); return nil }
func newS2(name string) Sink { return Sink1{name} }
func main() {
tmpfile, err := os.CreateTemp("", "xxx")
if err != nil {
panic(err)
}
defer os.Remove(tmpfile.Name())
closers := []io.Closer{}
sink, err := newFileSink(tmpfile.Name())
if err != nil {
panic(err)
}
closers = append(closers, sink)
s1p := newS1p("ptr")
s1 := newS1("struct")
s2 := newS2("ptr2")
closers = append(closers, s1p, s1, s2)
for _, closer := range closers {
fmt.Println(closer.Close())
}
}
// Output:
// <nil>
// in Close ptr
// <nil>
// in Close struct
// <nil>
// in Close ptr2
// <nil>

24
_test/issue-1276.go Normal file
View File

@@ -0,0 +1,24 @@
package main
import (
"flag"
)
type customFlag struct{}
func (cf customFlag) String() string {
return "custom flag"
}
func (cf customFlag) Set(string) error {
return nil
}
func main() {
flag.Var(customFlag{}, "cf", "custom flag")
flag.Parse()
println("Hello, playground")
}
// Output:
// Hello, playground

30
_test/issue-1280.go Normal file
View File

@@ -0,0 +1,30 @@
package main
import (
"io"
"log"
"os"
)
type DBReader interface {
io.ReadCloser
io.ReaderAt
}
type DB struct {
f DBReader
}
func main() {
f, err := os.Open("/dev/null")
if err != nil {
log.Fatal(err)
}
d := &DB{f}
data := make([]byte, 1)
_, _ = d.f.ReadAt(data, 0)
println("bye")
}
// Output:
// bye

25
_test/issue-1285.go Normal file
View File

@@ -0,0 +1,25 @@
package main
type (
T1 struct{ Path [12]int8 }
T2 struct{ Path *[12]int8 }
)
var (
t11 = &T1{}
t21 = &T2{}
)
func main() {
b := [12]byte{}
t12 := &T1{}
t22 := &T2{}
b11 := (*[len(t11.Path)]byte)(&b)
b12 := (*[len(t12.Path)]byte)(&b)
b21 := (*[len(t21.Path)]byte)(&b)
b22 := (*[len(t22.Path)]byte)(&b)
println(len(b11), len(b12), len(b21), len(b22))
}
// Output:
// 12 12 12 12

10
_test/issue-1288.go Normal file
View File

@@ -0,0 +1,10 @@
package main
func main() {
println("Hi")
goto done
done:
}
// Output:
// Hi

20
_test/issue-1300.go Normal file
View File

@@ -0,0 +1,20 @@
package main
const buflen = 512
type T struct {
buf []byte
}
func f(t *T) { *t = T{buf: make([]byte, 0, buflen)} }
func main() {
s := T{}
println(cap(s.buf))
f(&s)
println(cap(s.buf))
}
// Output:
// 0
// 512

16
_test/issue-1304.go Normal file
View File

@@ -0,0 +1,16 @@
package main
type Node struct {
Name string
Alias *Node
Child []*Node
}
func main() {
n := &Node{Name: "parent"}
n.Child = append(n.Child, &Node{Name: "child"})
println(n.Name, n.Child[0].Name)
}
// Output:
// parent child

15
_test/issue-1306.go Normal file
View File

@@ -0,0 +1,15 @@
package main
import "fmt"
func check() (result bool, err error) {
return true, nil
}
func main() {
result, error := check()
fmt.Println(result, error)
}
// Output:
// true <nil>

27
_test/issue-1308.go Normal file
View File

@@ -0,0 +1,27 @@
package main
import "fmt"
type test struct {
v interface{}
s string
}
type T struct {
name string
}
func main() {
t := []test{
{
v: []interface{}{
T{"hello"},
},
s: "world",
},
}
fmt.Println(t)
}
// Output:
// [{[{hello}] world}]

19
_test/issue-1311.go Normal file
View File

@@ -0,0 +1,19 @@
package main
type T struct {
v interface{}
}
func f() (ret int64, err error) {
ret += 2
return
}
func main() {
t := &T{}
t.v, _ = f()
println(t.v.(int64))
}
// Output:
// 2

32
_test/issue-1315.go Normal file
View File

@@ -0,0 +1,32 @@
package main
type Intf interface {
M()
}
type T struct {
s string
}
func (t *T) M() { println("in M") }
func f(i interface{}) {
switch j := i.(type) {
case Intf:
j.M()
default:
println("default")
}
}
func main() {
var i Intf
var k interface{} = 1
i = &T{"hello"}
f(i)
f(k)
}
// Output:
// in M
// default

29
_test/issue-1320.go Normal file
View File

@@ -0,0 +1,29 @@
package main
type Pooler interface {
Get() string
}
type baseClient struct {
connPool Pooler
}
type connPool struct {
name string
}
func (c *connPool) Get() string { return c.name }
func newBaseClient(i int, p Pooler) *baseClient {
return &baseClient{connPool: p}
}
func newConnPool() *connPool { return &connPool{name: "connPool"} }
func main() {
b := newBaseClient(0, newConnPool())
println(b.connPool.(*connPool).name)
}
// Output:
// connPool

42
_test/issue-1326.go Normal file
View File

@@ -0,0 +1,42 @@
package main
type Option interface {
apply(*T)
}
type T struct {
s string
}
type opt struct {
name string
}
func (o *opt) apply(t *T) {
println(o.name)
}
func BuildOptions() []Option {
return []Option{
&opt{"opt1"},
&opt{"opt2"},
}
}
func NewT(name string, options ...Option) *T {
t := &T{name}
for _, opt := range options {
opt.apply(t)
}
return t
}
func main() {
t := NewT("hello", BuildOptions()...)
println(t.s)
}
// Output:
// opt1
// opt2
// hello

16
_test/issue-1328.go Normal file
View File

@@ -0,0 +1,16 @@
package main
import (
"crypto/sha1"
"encoding/hex"
)
func main() {
script := "hello"
sumRaw := sha1.Sum([]byte(script))
sum := hex.EncodeToString(sumRaw[:])
println(sum)
}
// Output:
// aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d

42
_test/issue-1330.go Normal file
View File

@@ -0,0 +1,42 @@
package main
import (
"fmt"
"io"
"net"
)
type wrappedConn struct {
net.Conn
}
func main() {
_, err := net.Listen("tcp", "127.0.0.1:49153")
if err != nil {
panic(err)
}
dialer := &net.Dialer{
LocalAddr: &net.TCPAddr{
IP: net.ParseIP("127.0.0.1"),
Port: 0,
},
}
conn, err := dialer.Dial("tcp", "127.0.0.1:49153")
if err != nil {
panic(err)
}
defer conn.Close()
t := &wrappedConn{conn}
var w io.Writer = t
if n, err := w.Write([]byte("hello")); err != nil {
fmt.Println(err)
} else {
fmt.Println(n)
}
}
// Output:
// 5

17
_test/issue-1332.go Normal file
View File

@@ -0,0 +1,17 @@
package main
func run(fn func(name string)) { fn("test") }
type T2 struct {
name string
}
func (t *T2) f(s string) { println(s, t.name) }
func main() {
t2 := &T2{"foo"}
run(t2.f)
}
// Output:
// test foo

37
_test/issue-1333.go Normal file
View File

@@ -0,0 +1,37 @@
package main
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
)
func mock(name string) http.HandlerFunc {
return func(rw http.ResponseWriter, req *http.Request) {
fmt.Fprint(rw, "Hello ", name)
}
}
func client(uri string) {
resp, err := http.Get(uri)
if err != nil {
panic(err)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Println(string(body))
}
func main() {
mux := http.NewServeMux()
server := httptest.NewServer(mux)
defer server.Close()
mux.Handle("/", mock("foo"))
client(server.URL)
}
// Output:
// Hello foo

26
_test/issue-1337.go Normal file
View File

@@ -0,0 +1,26 @@
package main
import (
"io"
"os"
)
func f(i interface{}) {
switch at := i.(type) {
case int, int8:
println("integer", at)
case io.Reader:
println("reader")
}
println("bye")
}
func main() {
var fd *os.File
var r io.Reader = fd
f(r)
}
// Output:
// reader
// bye

12
_test/issue-1342.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
var a interface{}
a = "a"
fmt.Println(a, a == "a")
}
// Output:
// a true

13
_test/issue-1344.go Normal file
View File

@@ -0,0 +1,13 @@
package main
import "fmt"
func main() {
var m = map[string]interface{}{"a": "a"}
a, _ := m["a"]
b, ok := a.(string)
fmt.Println("a:", a, ", b:", b, ", ok:", ok)
}
// Output:
// a: a , b: a , ok: true

21
_test/issue-1354.go Normal file
View File

@@ -0,0 +1,21 @@
package main
func main() {
println(test()) // Go prints true, Yaegi false
}
func test() bool {
if true {
goto label
}
goto label
label:
println("Go continues here")
return true
println("Yaegi goes straight to this return (this line is never printed)")
return false
}
// Output:
// Go continues here
// true

22
_test/issue-1355.go Normal file
View File

@@ -0,0 +1,22 @@
package main
import "github.com/traefik/yaegi/_test/p2"
func f(i interface{}) {
_, ok := i.(p2.I)
println("ok:", ok)
}
func main() {
var v *p2.T
var i interface{}
i = v
_, ok := i.(p2.I)
println("ok:", ok)
f(v)
}
// Output:
// ok: true
// ok: true

14
_test/issue-1360.go Normal file
View File

@@ -0,0 +1,14 @@
package main
import (
"fmt"
. "net"
)
func main() {
v := IP{}
fmt.Println(v)
}
// Output:
// <nil>

27
_test/issue-1361.go Normal file
View File

@@ -0,0 +1,27 @@
package main
import (
"fmt"
"math"
)
type obj struct {
num float64
}
type Fun func(o *obj) (r *obj, err error)
func numFun(fn func(f float64) float64) Fun {
return func(o *obj) (*obj, error) {
return &obj{fn(o.num)}, nil
}
}
func main() {
f := numFun(math.Cos)
r, err := f(&obj{})
fmt.Println(r, err)
}
// Output:
// &{1} <nil>

16
_test/issue-1364.go Normal file
View File

@@ -0,0 +1,16 @@
package main
import (
"fmt"
"strconv"
)
func main() {
var value interface{}
var err error
value, err = strconv.ParseFloat("123", 64)
fmt.Println(value, err)
}
// Output:
// 123 <nil>

18
_test/issue-1365.go Normal file
View File

@@ -0,0 +1,18 @@
package main
func genInt() (int, error) { return 3, nil }
func getInt() (value int) {
value, err := genInt()
if err != nil {
panic(err)
}
return
}
func main() {
println(getInt())
}
// Output:
// 3

16
_test/issue-1368.go Normal file
View File

@@ -0,0 +1,16 @@
package main
const dollar byte = 36
func main() {
var c byte = 36
switch true {
case c == dollar:
println("ok")
default:
println("not ok")
}
}
// Output:
// ok

18
_test/issue-1371.go Normal file
View File

@@ -0,0 +1,18 @@
package main
import "fmt"
type node struct {
parent *node
child []*node
key string
}
func main() {
root := &node{key: "root"}
root.child = nil
fmt.Println("root:", root)
}
// Output:
// root: &{<nil> [] root}

17
_test/issue-1373.go Normal file
View File

@@ -0,0 +1,17 @@
package main
import (
"fmt"
"go/ast"
)
func NewBadExpr() ast.Expr {
return &ast.BadExpr{}
}
func main() {
fmt.Printf("%T\n", NewBadExpr().(*ast.BadExpr))
}
// Output:
// *ast.BadExpr

38
_test/issue-1375.go Normal file
View File

@@ -0,0 +1,38 @@
package main
import "fmt"
type Option func(*Struct)
func WithOption(opt string) Option {
return func(s *Struct) {
s.opt = opt
}
}
type Struct struct {
opt string
}
func New(opts ...Option) *Struct {
s := new(Struct)
for _, opt := range opts {
opt(s)
}
return s
}
func (s *Struct) ShowOption() {
fmt.Println(s.opt)
}
func main() {
opts := []Option{
WithOption("test"),
}
s := New(opts...)
s.ShowOption()
}
// Output:
// test

21
_test/issue-1378.go Normal file
View File

@@ -0,0 +1,21 @@
package main
import (
"fmt"
"time"
)
func main() {
t, err := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
if err != nil {
panic(err)
}
fn := func() error {
_, err := t.GobEncode()
return err
}
fmt.Println(fn())
}
// Output:
// <nil>

58
_test/issue-1381.go Normal file
View File

@@ -0,0 +1,58 @@
package main
import (
"bytes"
"fmt"
)
func main() {
var bufPtrOne *bytes.Buffer
var bufPtrTwo *bytes.Buffer
var bufPtrThree *bytes.Buffer
var bufPtrFour *bytes.Buffer
for i := 0; i < 2; i++ {
bufOne := bytes.Buffer{}
bufTwo := &bytes.Buffer{}
var bufThree bytes.Buffer
bufFour := new(bytes.Buffer)
if bufPtrOne == nil {
bufPtrOne = &bufOne
} else if bufPtrOne == &bufOne {
fmt.Println("bufOne was not properly redeclared")
} else {
fmt.Println("bufOne is properly redeclared")
}
if bufPtrTwo == nil {
bufPtrTwo = bufTwo
} else if bufPtrTwo == bufTwo {
fmt.Println("bufTwo was not properly redeclared")
} else {
fmt.Println("bufTwo is properly redeclared")
}
if bufPtrThree == nil {
bufPtrThree = &bufThree
} else if bufPtrThree == &bufThree {
fmt.Println("bufThree was not properly redeclared")
} else {
fmt.Println("bufThree is properly redeclared")
}
if bufPtrFour == nil {
bufPtrFour = bufFour
} else if bufPtrFour == bufFour {
fmt.Println("bufFour was not properly redeclared")
} else {
fmt.Println("bufFour is properly redeclared")
}
}
}
// Output:
// bufOne is properly redeclared
// bufTwo is properly redeclared
// bufThree is properly redeclared
// bufFour is properly redeclared

22
_test/issue-1404.go Normal file
View File

@@ -0,0 +1,22 @@
package main
type I interface {
inI()
}
type T struct {
name string
}
func (t *T) inI() {}
func main() {
var i I = &T{name: "foo"}
if i, ok := i.(*T); ok {
println(i.name)
}
}
// Output:
// foo

16
_test/issue-1408.go Normal file
View File

@@ -0,0 +1,16 @@
package main
type (
Number = int32
Number2 = Number
)
func f(n Number2) { println(n) }
func main() {
var n Number = 5
f(n)
}
// Output:
// 5

16
_test/issue-1411.go Normal file
View File

@@ -0,0 +1,16 @@
package main
type Number int32
func (n Number) IsValid() bool { return true }
type Number1 = Number
type Number2 = Number1
func main() {
a := Number2(5)
println(a.IsValid())
}
// Output: true

9
_test/issue-1421.go Normal file
View File

@@ -0,0 +1,9 @@
package main
type Number = int
func main() {
println(Number(1) < int(2))
}
// Output: true

44
_test/issue-1425.go Normal file
View File

@@ -0,0 +1,44 @@
package main
import (
"io"
"log"
"os"
"strings"
)
type WrappedReader struct {
reader io.Reader
}
func (wr WrappedReader) Read(p []byte) (n int, err error) {
return wr.reader.Read(p)
}
// Of course, this implementation is completely stupid because it does not write
// to the intended writer, as any honest WriteTo implementation should. its
// implemtion is just to make obvious the divergence of behaviour with yaegi.
func (wr WrappedReader) WriteTo(w io.Writer) (n int64, err error) {
// Ignore w, send to Stdout to prove whether this WriteTo is used.
data, err := io.ReadAll(wr)
if err != nil {
return 0, err
}
nn, err := os.Stdout.Write(data)
return int64(nn), err
}
func main() {
f := strings.NewReader("hello world")
wr := WrappedReader{reader: f}
// behind the scenes, io.Copy is supposed to use wr.WriteTo if the implementation exists.
// With Go, it works as expected, i.e. the output is sent to os.Stdout.
// With Yaegi, it doesn't, i.e. the output is sent to io.Discard.
if _, err := io.Copy(io.Discard, wr); err != nil {
log.Fatal(err)
}
}
// Output:
// hello world

25
_test/issue-1439.go Normal file
View File

@@ -0,0 +1,25 @@
package main
type Transformer interface {
Reset()
}
type Encoder struct {
Transformer
}
type nop struct{}
func (nop) Reset() { println("Reset") }
func f(e Transformer) {
e.Reset()
}
func main() {
e := Encoder{Transformer: nop{}}
f(e)
}
// Output:
// Reset

20
_test/issue-1447.go Normal file
View File

@@ -0,0 +1,20 @@
package main
import "fmt"
type I interface {
Name() string
}
type S struct {
iMap map[string]I
}
func main() {
s := S{}
s.iMap = map[string]I{}
fmt.Println(s)
}
// Output:
// {map[]}

25
_test/issue-435.go Normal file
View File

@@ -0,0 +1,25 @@
package main
import (
"fmt"
"strconv"
)
type Foo int
func (f Foo) String() string {
return "foo-" + strconv.Itoa(int(f))
}
func print1(arg interface{}) {
fmt.Println(arg)
}
func main() {
var arg Foo = 3
var f = print1
f(arg)
}
// Output:
// foo-3

View File

@@ -3,7 +3,6 @@ package main
import (
"fmt"
"io"
"io/ioutil"
"log"
"strings"
)
@@ -36,7 +35,7 @@ type pipe struct {
func newReadAutoCloser(r io.Reader) readAutoCloser {
if _, ok := r.(io.Closer); !ok {
return readAutoCloser{ioutil.NopCloser(r)}
return readAutoCloser{io.NopCloser(r)}
}
return readAutoCloser{r.(io.ReadCloser)}
}
@@ -44,7 +43,7 @@ func newReadAutoCloser(r io.Reader) readAutoCloser {
func main() {
p := &pipe{}
p.Reader = newReadAutoCloser(strings.NewReader("test"))
b, err := ioutil.ReadAll(p.Reader)
b, err := io.ReadAll(p.Reader)
if err != nil {
log.Fatal(err)
}

14
_test/method38.go Normal file
View File

@@ -0,0 +1,14 @@
package main
import (
"fmt"
"github.com/traefik/yaegi/_test/method38"
)
func main() {
fmt.Println(method38.Get())
}
// Output:
// &{[] {<nil>}}

19
_test/method38/a.go Normal file
View File

@@ -0,0 +1,19 @@
package method38
import "sync"
func NewPool() Pool { return Pool{} }
type Buffer struct {
bs []byte
pool Pool
}
type Pool struct {
p *sync.Pool
}
var (
_pool = NewPool()
Get = _pool.Get
)

3
_test/method38/b.go Normal file
View File

@@ -0,0 +1,3 @@
package method38
func (p Pool) Get() *Buffer { return &Buffer{} }

32
_test/method39.go Normal file
View File

@@ -0,0 +1,32 @@
package main
import (
"fmt"
"sync"
"github.com/traefik/yaegi/_test/method38"
)
func NewPool() Pool { return Pool{} }
type Buffer struct {
bs []byte
pool Pool
}
type Pool struct {
p *sync.Pool
}
var (
_pool = NewPool()
Get = _pool.Get
)
func main() {
fmt.Println(Get())
}
// Error:
// 17:11: undefined selector Get

View File

@@ -2,11 +2,11 @@ package main
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
_, err := ioutil.ReadFile("__NotExisting__")
_, err := os.ReadFile("__NotExisting__")
if err != nil {
fmt.Println(err.Error())
}

9
_test/p2/p2.go Normal file
View File

@@ -0,0 +1,9 @@
package p2
type I interface {
isI()
}
type T struct{}
func (t *T) isI() {}

0
_test/p3/empty Normal file
View File

3
_test/p4/p4.go Normal file
View File

@@ -0,0 +1,3 @@
package p4
var Value1 = "value1"

10
_test/p5.go Normal file
View File

@@ -0,0 +1,10 @@
package main
import "github.com/traefik/yaegi/_test/p5"
func main() {
println(*p5.Value1)
}
// Output:
// value1

8
_test/p5/p5.go Normal file
View File

@@ -0,0 +1,8 @@
package p5
import "github.com/traefik/yaegi/_test/p4"
var (
Value1 = &val1
val1 = p4.Value1
)

View File

@@ -8,6 +8,7 @@ type A struct {
}
type D struct {
F *A
E *A
}

22
_test/struct61.go Normal file
View File

@@ -0,0 +1,22 @@
package main
import "fmt"
type A struct {
B string
D
}
type D struct {
*A
E *A
}
func main() {
a := &A{B: "b"}
a.D = D{E: a}
fmt.Println(a.D.E.B)
}
// Output:
// b

11
_test/struct62.go Normal file
View File

@@ -0,0 +1,11 @@
package main
func main() {
type A struct{ *A }
v := &A{}
v.A = v
println("v.A.A = v", v.A.A == v)
}
// Output:
// v.A.A = v true

17
_test/switch39.go Normal file
View File

@@ -0,0 +1,17 @@
package main
func f(params ...interface{}) {
switch p0 := params[0].(type) {
case string:
println("string:", p0)
default:
println("not a string")
}
}
func main() {
f("Hello")
}
// Output:
// string: Hello

17
_test/switch40.go Normal file
View File

@@ -0,0 +1,17 @@
package main
func f(params ...interface{}) {
switch params[0].(type) {
case string:
println("a string")
default:
println("not a string")
}
}
func main() {
f("Hello")
}
// Output:
// a string

17
_test/type27.go Normal file
View File

@@ -0,0 +1,17 @@
package main
import "fmt"
type Foo = int
func (f Foo) Bar() int {
return f * f
}
func main() {
x := Foo(1)
fmt.Println(x.Bar())
}
// Error:
// 7:1: cannot define new methods on non-local type int

17
_test/type28.go Normal file
View File

@@ -0,0 +1,17 @@
package main
import "fmt"
type Foo = int
func (f *Foo) Bar() int {
return *f * *f
}
func main() {
x := Foo(1)
fmt.Println(x.Bar())
}
// Error:
// 7:1: cannot define new methods on non-local type int

12
_test/type29.go Normal file
View File

@@ -0,0 +1,12 @@
package main
var Foo int
func (f Foo) Bar() int {
return 1
}
func main() {}
// Error:
// 5:1: cannot define new methods on non-local type int

12
_test/type30.go Normal file
View File

@@ -0,0 +1,12 @@
package main
var Foo *int
func (f Foo) Bar() int {
return 1
}
func main() {}
// Error:
// 5:1: cannot define new methods on non-local type int

17
_test/type31.go Normal file
View File

@@ -0,0 +1,17 @@
package main
import "fmt"
func (f Foo) Bar() int {
return f * f
}
type Foo = int
func main() {
x := Foo(1)
fmt.Println(x.Bar())
}
// Error:
// 5:1: cannot define new methods on non-local type int

17
_test/type32.go Normal file
View File

@@ -0,0 +1,17 @@
package main
import "fmt"
func (f *Foo) Bar() int {
return *f * *f
}
type Foo = int
func main() {
x := Foo(1)
fmt.Println(x.Bar())
}
// Error:
// 5:1: cannot define new methods on non-local type int

11
_test/type33.go Normal file
View File

@@ -0,0 +1,11 @@
package main
func (f *Foo) Bar() int {
return *f * *f
}
func main() {
}
// Error:
// 3:1: undefined: Foo

19
_test/var16.go Normal file
View File

@@ -0,0 +1,19 @@
package main
func getArray() ([]int, error) { println("getArray"); return []int{1, 2}, nil }
func getNum() (int, error) { println("getNum"); return 3, nil }
func main() {
if a, err := getNum(); err != nil {
println("#1", a)
} else if a, err := getArray(); err != nil {
println("#2", a)
}
println("#3")
}
// Output:
// getNum
// getArray
// #3

Some files were not shown because too many files have changed in this diff Show More