* feat: generate go1.21 files
* chore: update CI
* feat: add support for generic symbols in standard library packages
This is necessary to fully support go1.21 and beyond, which now
provide some generic packages such as `cmp`, `maps` or `slices`
in the standard library.
The principle is to embed the generic symbols in source form (as
strings) so they can be instantiated as required during interpretation.
Extract() has been modified to skip the generic types, functions and
constraint interfaces which can't be represented as reflect.Values.
A new stdlib/generic package has been added to provide the corresponding
source files as embedded strings.
The `Use()` function has been changed to pre-parse generic symbols as
doing lazy parsing was causing cyclic dependencies issues at compiling.
This is something we may improve in the future.
A unit test using `cmp` has been added.
For now, there are still some issues with generic stdlib packages
inter-dependencies, for example `slices` importing `cmp`, or when
generic types or function signatures depends on pre-compiled types
in the same package, which we will support shortly.
* fixup
* fixup
* fixup
* fixup
* fixup
* fixup
* fixes for go1.20
* fix previous
* update unsafe2 for go1.21, skip faky tests
In go1.21, the reflect rtype definition has been move to internal/abi.
We follow this change for maintainability, even if there is no layout
change (the go1.20 unsafe2 is compatible with go1.21).
We have isolated a few problematic tests which are failing sometimes
in go1.21, but work in go1.20, and also in go1.22. Those tests are
skipped if in go1.21. A preliminary investigation can not confirm that
something is wrong in yaegi, and the problem disappears with go1.22.
* add new wrapper for go1.21 package testing/slogtest
* add missing wrapper for go/doc/comment
* add support for slices generic package
---------
Co-authored-by: Marc Vertes <mvertes@free.fr>
For a long time, there was a confusion between aliased types and named types (due to my misunderstanding of alias types in Go at that time). The type category `aliasT` has been renamed into `linkedT`, which is correct semantically.
Aliased types are only declared using `typeSpecAssign`, and its processing is now distinct from `typeSpec` statement, used for named types.
A `linkedT` type is obtained by a statement like `type A uint32`, where `A` type category is therefore `linkedT`.
An aliased type is obtained by a statement like `type A = uint32` (notice the `=` sign, translating into `typeSpecAssign`).
The semantic difference is that in the first linkedT form, `A` and `uint32` are 2 distinct types, instead of being strictly equivalent in the `typeSpecAssign` form (the 2 names lead to one type definition).
Fixes#1416.
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.
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.
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.
As the unsafe and pointer methods in `reflect` are to be depreciated, and seeing no replacement functions, it is now forced that some unsafe is needed to replace this as when and interface is dereferenced it is made unsettable by reflect.
With this in mind, this adds real recursive types by hot swapping the struct field type on the fly. This removes a lot of compensation code, simplifying all previous cases.
**Note:** While the struct field type is swapped for the real type, the type string is not changed. Due to this, unsafe will recreate the same type.
When operating on map elements, result of assign operators were not
written to the map entry. Now check if the destination of an assign
operator is in a map, and if so, set the result to it.
Fixes#1194.
This is a follow-up of #1017, generalizing the use of reflect.Set
method to set, and possibly overwrite, the concrete value of
interface objects all accross the implementation of operators.
Previous optimized implementation for non-interface objects is
preserved.
The empty interface (interface{}), and its variants (such as []interface{} and map[string]interface{}), are commonly used in Go to (json) Unmarshal arbitrary data. Within Yaegi, all interface types are wrapped in a valueInterface struct in order to retain all the information needed for a consistent internal state (as reflect is not enough to achieve that). However, this wrapping ends up being problematic when it comes to the type assertions related to the aforementioned Unmarshaling.
Therefore, this PR is an attempt to consider the empty interface (and its variants) as an exception within Yaegi, that should never be wrapped within a valueInterface, and to treat it similarly to the other basic Go types. The assumption is that the wrapping should not be needed, as there is no information about implemented methods to maintain.
Fixes#984Fixes#829Fixes#1015
Always attempt to obtain an integer constant value for operators
expecting so. It allows to use '/' in integer constant defintions,
instead of default big.Rat.
Fixes#1005
In unary constant operations, the test for unsigned was defeated by
testing for int first, which is true also for unsigned. Make sure that
testing for unsigned precedes testing for int.
Fixes#907.
When working with an untyped const expression involving a division, if
the default type of the result should be an int (for example because the
default types of all the operands are ints as well), then we should make
sure that the operation that is applied is indeed an integer division,
and that the type of the result is not a float.
This is achieved by using the QUO_ASSIGN operator, instead of the QUO
operator.
This should fix several problems lurking around, and it notably fixes
one of the visible consequences, which is a systematic panic when using
the REPL as a "calculator".
This incidentally also allows us to revert what was done in
5dfc3b86dc since it now turns out it was
just a hack to fix one of the symptoms.
Fixes#864
This adds type checking to CallExpr (excluding builtin type checking, as that is a PR in its own right) as well as handling any required constant type conversion.
This also changes constant strings and runes to be represented as `constant.Value`. Runes change `rval` type at CFG typing time to avoid having to type at AST time. There are also changes to importSpecs and `stdlib` to account for the string change. With this all `untyped` types should now be `constant.Value`s, although errors are still not returned if this is not the case to be sure we do not break things.
This also fixed a bug in `itype.methods` that would panic if the type was recursive.