Commit Graph

66 Commits

Author SHA1 Message Date
Marc Vertes
8efc4f0735 interp: improve handling of methods defined on interfaces
For methods defined on interfaces (vs concrete methods), the resolution of the method is necessarily delayed at the run time and can not be completed at compile time.

The selectorExpr processing has been changed to correctly identify calls on interface methods which were confused as fields rather than methods (due to the fact that in a interface definition, methods are fields of the interface).

Then at runtime, method lookup has been fixed to correctly recurse in nested valueInterface wrappers and to find embedded interface fields in case of struct or pointer to struct.

Finally, remove receiver processing in `call()`.The receiver is already processed at method resolution and in genFunctionWrapper. Removing redundant processing in call fixes handling of variadic method, simplifies the code and makes it faster.

With those fixes, it is now possible to load and run `go.uber.org/zap` in yaegi. In turn, it makes possible for yaegi to run plugins dependent on zap, such as coraza-waf.

Fixes #1515, 
Fixes #1172,
Fixes #1275,
Fixes #1485.
2023-03-06 16:46:06 +01:00
Marc Vertes
e003140c6e interp: improve internal handling of functions
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.
2022-10-19 17:54:08 +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
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
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
d64563edee interp: improve handling values and comparisons in interfaces
Fixes #1347.
2022-05-23 10:30: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
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
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
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
d3bbe01d5c interp: improve support of composed interfaces
Fixes #1260.
2021-10-07 16:28:05 +02:00
Nicholas Wiersma
3eb2c79fd8 interp: fix nil funcs in composite literals
When a nil are used in a func composite literal, the nil type is a `func` not a `*node`. This handles this case.

Fixes #1249
2021-09-13 16:32:12 +02:00
Nicholas Wiersma
c33caeb573 interp: improve handling of wrapped interface values
This test (assert2.go) display 2 separate issues:
1. assert2.go L28: Type assert tries to set an `interface{}` to a `valueInterface`. The typing here is complex, we have a valueT(strings.Builder) wrapped in a ptrT wrapped in a src iface wrapped in a valueT(interface{}). Type assert fails to realise that the `valueT` `interface{}` is wrapping the `valueInterface`.
2. assert2.go L29: `genValueBinMethodOnInterface` does not try and get the bin method, as the `typ.node` (`ptrT` or a `valueT`(`string.Builder`)) is set. In this case the src iface is called with a receiver argument. To fix this the method is looked for first if possible, and only if not found does it fall back to the `defaultGen`.

Fixes #1227
2021-09-06 17:16:11 +02:00
Nicholas Wiersma
4af992bccb interp: create real recursive types with unsafe type swapping
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.
2021-08-30 18:38:12 +02:00
Nicholas Wiersma
da922ce90b interp: build type strings on the fly
This adds `itype.str` which is a string representation of the type built when the type is built. The goal is to make type comparison simpler and centralise the creation of types just to constructors and `nodeType`. `nodeType` continues to build types in parts so to reuse underlying types better.
2021-08-27 19:44:05 +02:00
Marc Vertes
c80c605ab9 interp: support wrapping of nested interfaces
Add getConcreteType to retrieve the concrete type of a nested interface
value implementing a specific interface for which a wrapper exists.

If method resolution fails at runtime, a panic is now issued instead
of an error message and continue.

Fixes #1187.
2021-07-26 19:12:11 +02:00
Marc Vertes
8f9eccdd61 interp: fix assign of function values with binary methods
In typecheck.go, detect binary methods so we know when to skip the receiver as first parameter when checking function signatures. The signature check is not yet performed, we just avoid a false error.

In cfg.go, take care to label types with isBinMethod field to true whenever a binary method is resolved.

Also, do not attempt to wrap node in functions if the node value is already a binary function.

Fixes #1145.
2021-06-18 12:56:05 +02:00
Marc Vertes
dd03989709 interp: fix handing nil when appending to a slice
Fixes #1147.
2021-06-18 12:44:07 +02:00
Marc Vertes
b19afbfe93 interp: avoid panic in output value generation for recursive types
Fixes #1134.
2021-06-11 17:44:12 +02:00
Marc Vertes
c86436afa6 interp: fix litteral map containing binary functions
The case of assigning a binary function to a funcT object was
solved elsewhere. Factor the case in genDestValue to apply it
at multiple places.

Fixes #1100.
2021-05-27 12:04:11 +02:00
Marc Vertes
7d8fdbc1fc interp: fix closure in a struct field
Functions in a struct fields are always wrapped (as potentially
used by the runtime), so generate a function wrapper also for
closure when assigned to a struct field.

When such a function is called from the interpreter, ensure that
interface arguments are also wrapped so method and receiver resolution
can be performed.

Fixes partially #1043.
2021-03-11 15:26:04 +01:00
mpl
2e17cfab4f interp: do not wrap empty interface
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 #984 
Fixes #829 
Fixes #1015
2021-02-04 12:08:04 +01:00
Marc Vertes
24b5375636 interp: fix memory handling of global values
In some cases, the global character of a value was lost, leading to
undefined behaviour. Now a node level field of -1 means that the value
is global, and that it should be accessed from the root data frame.

Fixes #993.
2021-01-05 17:28:03 +01:00
Marc Vertes
9e1da978b0 interp: fix handling interface types in wrapped functions
The interpreter interface type was replaced by a reflect.Value in
objects passed or return to function wrappers, losing the ability
to retrieve methods.

The valueInterface is now preserved, and correctly accessed if
wrapped multiple times.

Fixes #977.
2020-12-15 16:14:05 +01:00
mpl
1e0f6ece6e interp: support more type assertion cases
Fixes #955
2020-11-30 18:00:04 +01:00
Marc Vertes
d0a34d467b interp: fix getting unsigned constant value
The function vUint, used to get the unsigned integer value of a value,
variable (frame) or constant, was broken for constant.Value expression.

Fixes #948.
2020-11-09 17:40:04 +01:00
Nicholas Wiersma
913680d1ed feat: add call expression (not builtin) type checking
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.
2020-08-14 12:02:04 +02:00
Nicholas Wiersma
cdc352cee2 feat: add index and composite literal type checking
This adds type checking to both `IndexExpr` and `CompositeLitExpr` as well as handling any required constant type conversion.

This includes a change to the type propagation to the children of a composite literal. Previously in most cases the composite literal type was propagated to its children. This does not work with type checking as the actual child type is needed.
2020-08-11 15:58:04 +02:00
Marc Vertes
25c681c1e6 fix: regression on range following #787 2020-07-30 10:52:05 +02:00
Marc Vertes
9c51f6bb69 fix: correct range on arrays of interface objects 2020-07-23 12:25:04 +02:00
Nicholas Wiersma
a15ecb7176 feature: handle nested recursion
* fix: copy the type in recursion

In more advanced recursive cases, setting the rtype to interface may interfear with typeing. To stop this from happening, instead of setting t.val.rtype to interface in the hope it will be set correctly later, a copy if the type is made, and the rtype of the copy is set to interface{}.

* fix: detect intermediate recursive structs

In the case of a nested recussion, each symbol can have
a different perspective on the recursion. In this case,
it is impossible to move from one struct to the next.
To keep the perspectives the same, any intermediate struct
that contains a recursion should also be set to interface{}.
so that all perspectives are the same.

* fix: handle arb recursion

* chore: refactor dref to be consistent

* fix: invalid recursive struct issue

* fix: handle checkptr issue

* fix: move unsafe into function to stop ptr check

* fix: handle deref in assign
2020-07-02 23:20:03 +02:00
Marc Vertes
9977ef6fc6 Revert "fix: make interpreter methods discoverable by runtime (#722)" (#732)
This reverts commit a3b2737b5c.
2020-07-01 16:16:26 +02:00
Marc Vertes
a3b2737b5c fix: make interpreter methods discoverable by runtime (#722)
* fix: make interpreter methods discoverable by runtime

When generating an interface wrapper, lookup existing wrappers by method
to get the one with the biggest set of methods implemented by interpreter.

A string method is also added to wrappers, in order to provide a string
representation of the interpreter value rather than the wrapper itself
(at least for %s and %v verbs).

This allows the runtime to pickup an interpreter method automatically
even if the conversion to the interface is not specified in the script. As
in Go spec, it is enough for the type to implement the required methods.

A current limitation is that only single wrappers can be instantiated,
not allowing to compose interfaces.

This limitation can be removed when the Go reflect issue
https://github.com/golang/go/issues/15924 is fixed.

Fixes #435.

* test: add a simpler test
2020-06-29 14:25:14 +02:00
Nicholas Wiersma
1fe91be882 feature: refactor numeric constants and detect overflow 2020-06-18 09:20:04 +02:00
Nicholas Wiersma
eb25c84797 fix: handle call ellipsis 2020-06-03 16:42:04 +02:00
Nicholas Wiersma
01e4cdea70 fix: recursive struct function call 2020-06-03 00:18:04 +02:00
Marc Vertes
7d56fb067e fix: improve setting of interface objects 2020-04-30 17:44:04 +02:00
Marc Vertes
1feece61ce fix: improve handling of function return values 2020-04-30 10:32:04 +02:00
Marc Vertes
7b2d91bcb5 fix: handling values in map of interfaces 2020-04-22 10:34:05 +02:00
Marc Vertes
c7c1bea7ef fix: do not attempt to store data in _ var 2020-03-09 13:22:04 +01:00
Marc Vertes
681f2f9c40 fix: correctly handle constant init for further type declarations 2020-02-12 12:32:03 +01:00
Marc Vertes
23dfef0ac8 fix: define a correct zero value for an not initialized interface{} 2020-02-04 18:04:05 +01:00
Marc Vertes
786ea366ab fix: handle nil function closure 2019-11-25 23:36:03 +01:00
Marc Vertes
e506969172 fix: correct handling of dynamic type for interface values 2019-11-25 23:20:04 +01:00
Marc Vertes
3969ab16c4 fix: improve handling of untyped complex numbers 2019-10-29 18:14:05 +01:00
Dan Kortschak
714253c1e6 interp: add eval cancelation by semaphore 2019-10-29 16:18:04 +01:00
Marc Vertes
15686873e0 fix: assign binary func to func type var 2019-10-20 04:52:03 +02:00
Dan Kortschak
bb2921b42f interp: fix range expression handling 2019-09-30 22:44:04 +02:00
Marc Vertes
ec1ee5f5b6 fix: support array operations on array pointers 2019-09-18 23:32:04 +02:00