Up to now functions could be stored as node values in frame (as for interpreter defined functions) or function values, directly callable by the Go runtime. We now always store functions in the later form, making the processing of functions, anonymous closures and methods simpler and more robust. All functions, once compiled are always directly callable, with no further wrapping necessary.
Fixes#1459.
Although empty interfaces are usually not wrapped, for compatibility with the runtime, we may have to wrap them sometime into `valueInterface` type.
It allows to preserve interpreter type metadata for interface values exchanged with the runtime. It is necessary to resolve methods and receivers in the absence of reflect support.
During type assertions on empty interfaces, we now handle a possible valueInterface and dereference the original value to pursue the type assertion.
In the same change, we have improved the format of some panic messages at runtime to give location of offending source at interpreter level.
This change will allow to fixtraefik/traefik#9362.
Those declarations involve the indexListExpr AST token, which was not handled in type.go. The same processing as for a single type parameter is applied.
Fixes#1460.
In type assertion at compile time, compare signatures between function types only.
Make `itype.numOut()` return the correct value for Go builtins (this was not strictly necessary due to above fix, but it is correct and improves maintainability).
Fixes#1454.
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.
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.
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.
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.
The function `getMethodByName()` is now able to look for
embedded `valueInterface` field for matching methods in interface
struct fields.
Fixes#1439 and #1427.
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.
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.
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.
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).
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.
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 ....
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.
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.
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.
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.
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.
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.
* 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>
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.
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.
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
* 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>
* 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.