On Friday, November 8, 2019 at 7:16:42 PM UTC+1, Ian Lance Taylor wrote: > > On Fri, Nov 8, 2019 at 10:06 AM André Eriksson <ean...@gmail.com > <javascript:>> wrote: > > > > Interesting. Do you have a reference to where that happens? > > The method (*Package).rewriteCall in cmd/cgo/gcc.go. But more useful > might be to experiment with some cgo code and build with `go build > -work` and look in the $WORK directory to see the generated files. > > > > If i understand you correctly, however, it doesn't appear to solve the > case where the called function fn lives in a different package, and takes > an argument which is a private type. That is: > > > > -- a/a.go -- > > package a > > > > type myString string > > > > func Fn(str myString) { } > > > > -- b/b.go -- > > package b > > > > import "a" > > > > func rewrite() { > > go a.Fn("some string") > > } > > > > In this example knowing the desired type from the function signature > does not help, I would think? > > That is correct. > > Fortunately for a case like that you don't need to use a temporary > variable at all, since the argument is a constant. > > Ian >
That makes sense. I did some more research and came across another case where even this might not work. It appears that there is a distinction between an untyped value and an untyped constant. I hadn't appreciated this distinction until now. According to the spec (https://golang.org/ref/spec#Comparison_operators), "Comparison operators compare two operands and yield an untyped boolean value." As a result, it's possible to get untyped, non-constant values from non-constant expressions. So we could have fn(a() == b()) passed to fn(b myBool) with no ability to store this argument in a temporary variable without coercing the type to a regular typed bool. > > > On Friday, November 8, 2019 at 6:58:02 PM UTC+1, Ian Lance Taylor wrote: > >> > >> On Fri, Nov 8, 2019 at 9:08 AM André Eriksson <ean...@gmail.com> > wrote: > >> > > >> > That works in simple cases, but does not work when the expression is > an untyped constant, like 1 or nil. In the case of 1 the variable will get > a concrete type of int, while fn may accept a float32, or even a private > type that cannot be named in the current package. > >> > >> You might want to look at the rewriting that cmd/cgo does, as it > >> handles this exact kind of case. Basically, for untyped constants, > >> you know the desired type, because it's in the function signature. So > >> use that. > >> > >> It does get kind of complicated, though. > >> > >> Ian > >> > >> > >> > On Friday, November 8, 2019 at 5:51:10 PM UTC+1, Michael Jones wrote: > >> >> > >> >> If expr was evaluable in the original code then why not rewrite in > place after assigning temporaries? > >> >> > >> >> go fn(e1,e2) > >> >> > >> >> { > >> >> t1,t2 := e1,e2 > >> >> go func() { > >> >> defer instrument() > >> >> fn(t1,t2) > >> >> } > >> >> > >> >> > >> >> On Fri, Nov 8, 2019 at 8:38 AM André Eriksson <ean...@gmail.com> > wrote: > >> >>> > >> >>> I am working on a type of Go preprocessor that rewrites source code > to add additional instrumentation to certain types of statements. > >> >>> > >> >>> One such statement is the go statement. I would like to instrument > the newly created goroutine, injecting some instrumentation code at the > start and finish of the goroutine. > >> >>> > >> >>> In the simple case, the rewrite is straightforward: > >> >>> > >> >>> go fn() > >> >>> > >> >>> becomes > >> >>> > >> >>> go func() { > >> >>> defer instrument()() > >> >>> fn() > >> >>> }() > >> >>> > >> >>> However this approach does not work when fn takes parameters. > >> >>> If we were to rewrite go fn(expr) into the equivalent form above: > >> >>> > >> >>> go func() { > >> >>> defer instrument()() > >> >>> fn(expr) > >> >>> }() > >> >>> > >> >>> > >> >>> the semantics change, since in the rewrite expr gets evaluated > inside the newly created goroutine, which can change the behavior and > introduce data races. > >> >>> > >> >>> My attempts to address this have not been particularly fruitful. > >> >>> > >> >>> One cannot pass in expr as an argument to the closure, because the > type of the expression may not have a valid name in the current package > (for example if expr evaluates to a private type in some other package). > >> >>> > >> >>> Similarly, if expr is a constant expression (like 1 or nil) the > type may depend on the corresponding parameter in fn’s signature. > >> >>> > >> >>> The only semantics-preserving rewrite I can think of revolves > around using package reflect, and rewriting like so: > >> >>> > >> >>> go func(fn reflect.Value, vals …reflect.Value) { > >> >>> defer instrument() > >> >>> fn.Call(vals) > >> >>> }(reflect.ValueOf(fn), reflect.ValueOf(expr)) > >> >>> > >> >>> As far as I understand, this should be semantics-preserving, > although with a slight performance cost. (Though I imagine the cost of a > reflection-based call is dwarfed by the cost of spawning a goroutine.) > >> >>> > >> >>> Unfortunately this also comes with a major downside: the rewritten > code does not typecheck identically to the original code. Ideally I would > like the rewritten form to cause identical typechecking failures to the old > code, so that these errors are caught at compile time without requiring a > separate typechecking pass for the original code. > >> >>> > >> >>> Am I correct in the above reasoning? Can anyone think of a way to > do this sort of rewrite in a semantics-preserving and > typechecking-preserving way? > >> >>> > >> >>> -- > >> >>> You received this message because you are subscribed to the Google > Groups "golang-nuts" group. > >> >>> To unsubscribe from this group and stop receiving emails from it, > send an email to golan...@googlegroups.com. > >> >>> To view this discussion on the web visit > https://groups.google.com/d/msgid/golang-nuts/a92641f3-2eda-4d4a-ab02-d2b40e3bde75%40googlegroups.com. > > > >> >> > >> >> > >> >> > >> >> -- > >> >> Michael T. Jones > >> >> michae...@gmail.com > >> > > >> > -- > >> > You received this message because you are subscribed to the Google > Groups "golang-nuts" group. > >> > To unsubscribe from this group and stop receiving emails from it, > send an email to golan...@googlegroups.com. > >> > To view this discussion on the web visit > https://groups.google.com/d/msgid/golang-nuts/ec41a345-163f-4a8a-a24f-b868def081a0%40googlegroups.com. > > > > > > -- > > You received this message because you are subscribed to the Google > Groups "golang-nuts" group. > > To unsubscribe from this group and stop receiving emails from it, send > an email to golan...@googlegroups.com <javascript:>. > > To view this discussion on the web visit > https://groups.google.com/d/msgid/golang-nuts/0ff39043-4699-4f0b-a1c0-6c4ebc5eb208%40googlegroups.com. > > > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/afb22234-ecb2-46b7-a5af-7a2ee4525774%40googlegroups.com.