From c2e799237fe66134b015442bc6db181319bef0c1 Mon Sep 17 00:00:00 2001 From: Aleksandr Nogikh Date: Thu, 5 Oct 2023 17:45:03 +0200 Subject: pkg/compiler: prohibit not DirIn resources inside fmt The problem mentioned in the previous commit is actually not only ANY-specific, it's only by a happy coincidence that all our descriptions already avoided such situations. Enforce this rule at the compilation stage. --- pkg/compiler/check.go | 16 +++++++++++----- pkg/compiler/testdata/errors2.txt | 4 ++++ pkg/compiler/types.go | 2 ++ 3 files changed, 17 insertions(+), 5 deletions(-) (limited to 'pkg/compiler') diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go index 5f7bb7108..44c354606 100644 --- a/pkg/compiler/check.go +++ b/pkg/compiler/check.go @@ -672,10 +672,10 @@ func (comp *compiler) checkConstructors() { switch n := decl.(type) { case *ast.Call: for _, arg := range n.Args { - comp.checkTypeCtors(arg.Type, prog.DirIn, true, true, ctors, inputs, checked) + comp.checkTypeCtors(arg.Type, prog.DirIn, true, true, ctors, inputs, checked, nil) } if n.Ret != nil { - comp.checkTypeCtors(n.Ret, prog.DirOut, true, true, ctors, inputs, checked) + comp.checkTypeCtors(n.Ret, prog.DirOut, true, true, ctors, inputs, checked, nil) } } } @@ -699,17 +699,23 @@ func (comp *compiler) checkConstructors() { } func (comp *compiler) checkTypeCtors(t *ast.Type, dir prog.Dir, isArg, canCreate bool, - ctors, inputs map[string]bool, checked map[structDir]bool) { + ctors, inputs map[string]bool, checked map[structDir]bool, neverOutAt *ast.Pos) { desc, args, base := comp.getArgsBase(t, isArg) if base.IsOptional { canCreate = false } + if desc.CantHaveOut { + neverOutAt = &t.Pos + } if desc == typeResource { // TODO(dvyukov): consider changing this to "dir == prog.DirOut". // We have few questionable cases where resources can be created // only by inout struct fields. These structs should be split // into two different structs: one is in and second is out. // But that will require attaching dir to individual fields. + if dir != prog.DirIn && neverOutAt != nil { + comp.error(*neverOutAt, "resource %s cannot be created in fmt", t.Ident) + } if canCreate && dir != prog.DirIn { r := comp.resources[t.Ident] for r != nil && !ctors[r.Name.Name] { @@ -742,7 +748,7 @@ func (comp *compiler) checkTypeCtors(t *ast.Type, dir prog.Dir, isArg, canCreate if !fldHasDir { fldDir = dir } - comp.checkTypeCtors(fld.Type, fldDir, false, canCreate, ctors, inputs, checked) + comp.checkTypeCtors(fld.Type, fldDir, false, canCreate, ctors, inputs, checked, neverOutAt) } return } @@ -751,7 +757,7 @@ func (comp *compiler) checkTypeCtors(t *ast.Type, dir prog.Dir, isArg, canCreate } for i, arg := range args { if desc.Args[i].Type == typeArgType { - comp.checkTypeCtors(arg, dir, desc.Args[i].IsArg, canCreate, ctors, inputs, checked) + comp.checkTypeCtors(arg, dir, desc.Args[i].IsArg, canCreate, ctors, inputs, checked, neverOutAt) } } } diff --git a/pkg/compiler/testdata/errors2.txt b/pkg/compiler/testdata/errors2.txt index 3cd63ebd2..e99610c58 100644 --- a/pkg/compiler/testdata/errors2.txt +++ b/pkg/compiler/testdata/errors2.txt @@ -421,3 +421,7 @@ foo$non_generatable(a compressed_image) (no_minimize) ### call foo$non_generatab foo$non_minimizable(a compressed_image) (no_generate) ### call foo$non_minimizable refers to type compressed_image and so must be marked no_minimize foo$non_generatable_via_struct(a ptr[in, struct_non_generatable]) (no_minimize) ### call foo$non_generatable_via_struct refers to type compressed_image and so must be marked no_generate foo$non_minimizable_via_union(a ptr[in, union_non_minimizable]) (no_generate) ### call foo$non_minimizable_via_union refers to type compressed_image and so must be marked no_minimize + +resource for_fmt[int32] +foo$fmt_copyin(a ptr[in, fmt[dec, for_fmt]]) +foo$fmt_copyout(a ptr[out, fmt[dec, for_fmt]]) ### resource for_fmt cannot be created in fmt diff --git a/pkg/compiler/types.go b/pkg/compiler/types.go index 099ab0009..a55a6c50d 100644 --- a/pkg/compiler/types.go +++ b/pkg/compiler/types.go @@ -20,6 +20,7 @@ type typeDesc struct { CanBeTypedef bool // can be type alias target? CantBeOpt bool // can't be marked as opt? CantBeOut bool // can't be used as an explicitly output argument? + CantHaveOut bool // everything inside can only be in NeedBase bool // needs base type when used as field? MaxColon int // max number of colons (int8:2) on fields OptArgs int // number of optional arguments in Args array @@ -764,6 +765,7 @@ var typeFmt = &typeDesc{ CanBeTypedef: true, CantBeOpt: true, CantBeOut: true, + CantHaveOut: true, Args: []namedArg{ {Name: "format", Type: typeFmtFormat}, {Name: "value", Type: typeArgType, IsArg: true}, -- cgit mrf-deployment