Skip to content

Commit

Permalink
WIP [ci skip]
Browse files Browse the repository at this point in the history
  • Loading branch information
jmalloc committed Nov 2, 2024
1 parent cb4644c commit a34c844
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func resolveVariadic[
E any,
B configbuilder.EntityBuilder[T, E],
](
b B,
builderXXXXXXXXXXX B,
inst ssa.CallInstruction,
) iter.Seq[ssa.Value] {
return func(yield func(ssa.Value) bool) {
Expand All @@ -61,7 +61,7 @@ func resolveVariadic[

array, ok := findAllocation(variadics)
if !ok {
b.Partial()
builderXXXXXXXXXXX.Partial()
return
}

Expand Down
89 changes: 89 additions & 0 deletions config/staticconfig/internal/ssax/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,80 @@ func StaticValue(v ssa.Value) optional.Optional[ssa.Value] {
return optional.None[ssa.Value]()
}

// StaticValuesFromArguments returns the static value(s) used as arguments in
// the given function call.
func StaticValuesFromArguments(
inst ssa.CallInstruction,
) (
args []optional.Optional[ssa.Value],
varargs []SliceElem,
exhaustive bool,
) {
call := inst.Common()
sig := call.Signature()

n := sig.Params().Len()
if sig.Variadic() {
n--
}

args = make([]optional.Optional[ssa.Value], n)

for i, arg := range call.Args[:n] {
args[i] = StaticValue(arg)
}

if !sig.Variadic() {
return args, varargs, true
}

varargs, exhaustive = StaticValuesFromSlice(call.Args[n])
return args, varargs, exhaustive
}

// SliceElem represents an element within a slice.
type SliceElem struct {
Index optional.Optional[int]
Value optional.Optional[ssa.Value]
}

// StaticValuesFromSlice returns the static value(s) contained within a slice.
func StaticValuesFromSlice(
v ssa.Value,
) (elems []SliceElem, exhaustive bool) {
array, ok := findUnderlyingArrayAllocation(v)
if !ok {
return nil, false
}

vinst := v.(ssa.Instruction)

for b := range WalkBlock(array.Block()) {
if vinst != nil && !PathExists(b, vinst.Block()) {
continue
}

for inst := range InstructionsBefore(b, vinst) {
switch inst := inst.(type) {
case *ssa.Store:
if addr, ok := inst.Addr.(*ssa.IndexAddr); ok {
if addr.X == array {
elems = append(
elems,
SliceElem{
Index: AsInt(addr.Index),
Value: StaticValue(inst.Val),
},
)
}
}
}
}
}

return elems, true
}

// staticValuesFromInstruction returns the static value(s) that result from
// evaluating the given instruction.
//
Expand Down Expand Up @@ -135,3 +209,18 @@ func equal(a, b ssa.Value) bool {

return false
}

// findUnderlyingArrayAllocation returns the underlying array allocation of a
// slice.
func findUnderlyingArrayAllocation(v ssa.Value) (*ssa.Alloc, bool) {
switch v := v.(type) {
case *ssa.Alloc:
return v, true

case *ssa.Slice:
return findUnderlyingArrayAllocation(v.X)

default:
return nil, false
}
}
17 changes: 14 additions & 3 deletions config/staticconfig/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package staticconfig
import (
"github.com/dogmatiq/enginekit/config"
"github.com/dogmatiq/enginekit/config/internal/configbuilder"
"github.com/dogmatiq/enginekit/config/staticconfig/internal/ssax"
"github.com/dogmatiq/enginekit/internal/typename"
"golang.org/x/tools/go/ssa"
)
Expand All @@ -14,12 +15,22 @@ func analyzeRoutes[
](
ctx *configurerCallContext[T, H, B],
) {
for r := range resolveVariadic(ctx.Builder, ctx.Instruction) {
_, varargs, exhaustive := ssax.StaticValuesFromArguments(ctx.Instruction)
if !exhaustive {
ctx.Builder.Partial()
}

for _, elem := range varargs {
ctx.Builder.Route(func(b *configbuilder.RouteBuilder) {
if ctx.IsSpeculative {
if ctx.IsSpeculative || !elem.Index.IsPresent() {
b.Speculative() // TODO: is this correct?
}
analyzeRoute(ctx.context, b, r)

if r, ok := elem.Value.TryGet(); ok {
analyzeRoute(ctx.context, b, r)
} else {
b.Partial()
}
})
}
}
Expand Down

0 comments on commit a34c844

Please sign in to comment.