Add cron jobs to service

This commit is contained in:
dwrz
2026-06-02 12:04:02 +00:00
parent e5238e4081
commit 6fb63c8c90
84 changed files with 3022 additions and 2452 deletions

View File

@@ -100,6 +100,7 @@ var (
// Type constants.
tBool = types.Typ[types.Bool]
tByte = types.Typ[types.Byte]
tRune = types.Universe.Lookup("rune").Type() // prints as "rune" (Typ[Rune] is same as Int32)
tInt = types.Typ[types.Int]
tInvalid = types.Typ[types.Invalid]
tString = types.Typ[types.String]
@@ -892,6 +893,10 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
bound := createBound(fn.Prog, obj)
b.enqueue(bound)
// The assignment may widen a type parameter to its
// interface bound (case #3 of go.dev/issue.78110).
v = emitConv(fn, v, bound.FreeVars[0].Type())
c := &MakeClosure{
Fn: bound,
Bindings: []Value{v},
@@ -1270,7 +1275,7 @@ func (b *builder) arrayLen(fn *Function, elts []ast.Expr) int64 {
// x := T{a: 1}
// x = T{a: x.a}
//
// all the reads must occur before all the writes. Thus all stores to
// all the reads must occur before all the writes. Thus all stores to
// loc are emitted to the storebuf sb for later execution.
//
// A CompositeLit may have pointer type only in the recursive (nested)
@@ -1287,28 +1292,35 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero
sb.store(&address{addr, e.Lbrace, nil}, zeroConst(zt))
isZero = true
}
var fIndices []int
for i, e := range e.Elts {
fieldIndex := i
pos := e.Pos()
if kv, ok := e.(*ast.KeyValueExpr); ok {
var (
pos token.Pos
fType types.Type
)
if kv, ok := e.(*ast.KeyValueExpr); ok { // tagged field
fname := kv.Key.(*ast.Ident).Name
for i, n := 0, t.NumFields(); i < n; i++ {
sf := t.Field(i)
if sf.Name() == fname {
fieldIndex = i
pos = kv.Colon
e = kv.Value
break
}
}
obj, index, _ := types.LookupFieldOrMethod(t, true, fn.declaredPackage().Pkg, fname)
fIndices = append(fIndices[:0], index...)
pos = kv.Colon
e = kv.Value
fType = obj.Type()
} else { // untagged field
fIndices = append(fIndices[:0], i)
pos = e.Pos()
fType = t.Field(i).Type()
}
sf := t.Field(fieldIndex)
last := len(fIndices) - 1
v := emitImplicitSelections(fn, addr, fIndices[:last], pos)
faddr := &FieldAddr{
X: addr,
Field: fieldIndex,
X: v,
Field: fIndices[last],
}
faddr.setPos(pos)
faddr.setType(types.NewPointer(sf.Type()))
faddr.setType(types.NewPointer(fType))
fn.emit(faddr)
b.assign(fn, &address{addr: faddr, pos: pos, expr: e}, e, isZero, sb)
}
@@ -1467,13 +1479,14 @@ func (b *builder) switchStmt(fn *Function, s *ast.SwitchStmt, label *lblock) {
var nextCond *BasicBlock
for _, cond := range cc.List {
nextCond = fn.newBasicBlock("switch.next")
// TODO(adonovan): opt: when tag==vTrue, we'd
// get better code if we use b.cond(cond)
// instead of BinOp(EQL, tag, b.expr(cond))
// followed by If. Don't forget conversions
// though.
cond := emitCompare(fn, token.EQL, tag, b.expr(fn, cond), cond.Pos())
emitIf(fn, cond, body, nextCond)
// For boolean switches, emit short-circuit control flow,
// just like an if/else-chain.
if tag == vTrue && !isNonTypeParamInterface(fn.info.Types[cond].Type) {
b.cond(fn, cond, body, nextCond)
} else {
c := emitCompare(fn, token.EQL, tag, b.expr(fn, cond), cond.Pos())
emitIf(fn, c, body, nextCond)
}
fn.currentBlock = nextCond
}
fn.currentBlock = body
@@ -2149,13 +2162,6 @@ func (b *builder) rangeIter(fn *Function, x Value, tk, tv types.Type, pos token.
// done: (target of break)
//
if tk == nil {
tk = tInvalid
}
if tv == nil {
tv = tInvalid
}
rng := &Range{X: x}
rng.setPos(pos)
rng.setType(tRangeIter)
@@ -2165,14 +2171,29 @@ func (b *builder) rangeIter(fn *Function, x Value, tk, tv types.Type, pos token.
emitJump(fn, loop)
fn.currentBlock = loop
var ak, av types.Type
isString := false
if m, ok := typeparams.CoreType(x.Type()).(*types.Map); ok {
ak, av = m.Key(), m.Elem()
} else {
isString = true
ak, av = tInt, tRune
}
if tk == nil {
ak = tInvalid
}
if tv == nil {
av = tInvalid
}
okv := &Next{
Iter: it,
IsString: isBasic(typeparams.CoreType(x.Type())),
IsString: isString,
}
okv.setType(types.NewTuple(
varOk,
newVar("k", tk),
newVar("v", tv),
newVar("k", ak),
newVar("v", av),
))
fn.emit(okv)
@@ -2181,11 +2202,14 @@ func (b *builder) rangeIter(fn *Function, x Value, tk, tv types.Type, pos token.
emitIf(fn, emitExtract(fn, okv, 0), body, done)
fn.currentBlock = body
if tk != tInvalid {
k = emitExtract(fn, okv, 1)
// The assignment may widen a map or string
// key/value to a variable's interface type
// (cases #1 and #2 of go.dev/issue/78110).
if tk != nil {
k = emitConv(fn, emitExtract(fn, okv, 1), tk)
}
if tv != tInvalid {
v = emitExtract(fn, okv, 2)
if tv != nil {
v = emitConv(fn, emitExtract(fn, okv, 2), tv)
}
return
}

View File

@@ -16,6 +16,8 @@ import (
"os"
"slices"
"strings"
"golang.org/x/tools/internal/typeparams"
)
type sanity struct {
@@ -154,12 +156,17 @@ func (s *sanity) checkInstr(idx int, instr Instruction) {
case *Lookup:
case *MakeChan:
case *MakeClosure:
numFree := len(instr.Fn.(*Function).FreeVars)
numBind := len(instr.Bindings)
if numFree != numBind {
fn := instr.Fn.(*Function)
if numFree, numBind := len(fn.FreeVars), len(instr.Bindings); numFree != numBind {
s.errorf("MakeClosure has %d Bindings for function %s with %d free vars",
numBind, instr.Fn, numFree)
} else {
for i, fv := range fn.FreeVars {
if !types.Identical(instr.Bindings[i].Type(), fv.Type()) {
s.errorf("MakeClosure binding %d for %s has type %s, expected %s",
i, fv.Name(), instr.Bindings[i].Type(), fv.Type())
}
}
}
if recv := instr.Type().(*types.Signature).Recv(); recv != nil {
s.errorf("MakeClosure's type includes receiver %s", recv.Type())
@@ -170,12 +177,42 @@ func (s *sanity) checkInstr(idx int, instr Instruction) {
case *MakeSlice:
case *MapUpdate:
case *Next:
rng, ok := instr.Iter.(*Range)
if !ok {
s.errorf("Next: Iter is %T, not *Range", instr.Iter)
}
if rng.Type() != tRangeIter {
s.errorf("Next: Iter has type %s, expected %s", rng.Type(), tRangeIter)
}
var ek, ev types.Type
switch xt := typeparams.CoreType(rng.X.Type()).(type) {
case *types.Basic:
if types.Default(xt) != tString {
s.errorf("Next: basic operand of Next.Iter (Range) is %s, want string or untyped string", xt)
}
ek, ev = tInt, tRune
case *types.Map:
ek, ev = xt.Key(), xt.Elem()
}
res := instr.Type().(*types.Tuple) // (ok bool, k K, v V), but K or V may be invalid if unused
if !types.Identical(res.At(1).Type(), ek) && res.At(1).Type() != tInvalid {
s.errorf("Next: key type %s does not match map key type %s", res.At(1).Type(), ek)
}
if !types.Identical(res.At(2).Type(), ev) && res.At(2).Type() != tInvalid {
s.errorf("Next: value type %s does not match map value type %s", res.At(2).Type(), ev)
}
case *Range:
case *RunDefers:
case *Select:
case *Send:
case *Slice:
case *Store:
if !types.Identical(instr.Val.Type(), typeparams.CoreType(instr.Addr.Type()).(*types.Pointer).Elem()) {
s.errorf("Store: value type %s does not match address type %s",
instr.Val.Type(), instr.Addr.Type())
}
case *TypeAssert:
case *UnOp:
case *DebugRef:

View File

@@ -319,10 +319,10 @@ func (subst *subster) interface_(iface *types.Interface) *types.Interface {
func (subst *subster) alias(t *types.Alias) types.Type {
// See subster.named. This follows the same strategy.
tparams := aliases.TypeParams(t)
targs := aliases.TypeArgs(t)
tparams := t.TypeParams()
targs := t.TypeArgs()
tname := t.Obj()
torigin := aliases.Origin(t)
torigin := t.Origin()
if !declaredWithin(tname, subst.origin) {
// t is declared outside of the function origin. So t is a package level type alias.
@@ -361,15 +361,10 @@ func (subst *subster) alias(t *types.Alias) types.Type {
}
// Substitute rhs.
rhs := subst.typ(aliases.Rhs(t))
rhs := subst.typ(t.Rhs())
// Create the fresh alias.
//
// Until 1.27, the result of aliases.NewAlias(...).Type() cannot guarantee it is a *types.Alias.
// However, as t is an *alias.Alias and t is well-typed, then aliases must have been enabled.
// Follow this decision, and always enable aliases here.
const enabled = true
obj := aliases.NewAlias(enabled, tname.Pos(), tname.Pkg(), tname.Name(), rhs, newTParams)
obj := aliases.New(tname.Pos(), tname.Pkg(), tname.Name(), rhs, newTParams)
// Substitute into all of the constraints after they are created.
for i, ntp := range newTParams {