Skip to content

Commit 6bff9f0

Browse files
authored
Update local bindings on function with type use (#1466)
When a function is specified like this: (func (type $t) ...) the type can have any sequence of params and results, but it is not known what that signature is until it is resolved. However, locals that are parsed will be given a binding index under the assumption that the signature is empty, e.g. (func (type $t) (local $v0 i32) (local $v1 i32) ... ) So `$v0` will have index 0, and `$v1` will have index 1. If it turns out later that type `$t` has any parameters, then these indexes need to be updated.
1 parent 3239018 commit 6bff9f0

File tree

2 files changed

+32
-3
lines changed

2 files changed

+32
-3
lines changed

src/wast-parser.cc

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,17 +243,18 @@ bool IsEmptySignature(const FuncSignature& sig) {
243243
return sig.result_types.empty() && sig.param_types.empty();
244244
}
245245

246-
void ResolveFuncTypeWithEmptySignature(const Module& module,
246+
bool ResolveFuncTypeWithEmptySignature(const Module& module,
247247
FuncDeclaration* decl) {
248248
// Resolve func type variables where the signature was not specified
249249
// explicitly, e.g.: (func (type 1) ...)
250250
if (decl->has_func_type && IsEmptySignature(decl->sig)) {
251251
const FuncType* func_type = module.GetFuncType(decl->type_var);
252252
if (func_type) {
253253
decl->sig = func_type->sig;
254+
return true;
254255
}
255256
}
256-
257+
return false;
257258
}
258259

259260
void ResolveImplicitlyDefinedFunctionType(const Location& loc,
@@ -419,14 +420,28 @@ Result ResolveFuncTypes(Module* module, Errors* errors) {
419420
continue;
420421
}
421422

423+
bool has_func_type_and_empty_signature = false;
424+
422425
if (decl) {
423-
ResolveFuncTypeWithEmptySignature(*module, decl);
426+
has_func_type_and_empty_signature =
427+
ResolveFuncTypeWithEmptySignature(*module, decl);
424428
ResolveImplicitlyDefinedFunctionType(field.loc, module, *decl);
425429
result |=
426430
CheckFuncTypeVarMatchesExplicit(field.loc, *module, *decl, errors);
427431
}
428432

429433
if (func) {
434+
if (has_func_type_and_empty_signature) {
435+
// The call to ResolveFuncTypeWithEmptySignature may have updated the
436+
// function signature so there are parameters. Since parameters and
437+
// local variables share the same index space, we need to increment the
438+
// local indexes bound to a given name by the number of parameters in
439+
// the function.
440+
for (auto& pair: func->bindings) {
441+
pair.second.index += func->GetNumParams();
442+
}
443+
}
444+
430445
ResolveFuncTypesExprVisitorDelegate delegate(module, errors);
431446
ExprVisitor visitor(&delegate);
432447
result |= visitor.VisitFunc(func);

test/desugar/locals.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
;;; TOOL: wat-desugar
2+
(module
3+
(type (func (param i32) (result i32)))
4+
(func (type 0) (local $var i32)
5+
(local.get 0)
6+
(local.tee $var)))
7+
(;; STDOUT ;;;
8+
(module
9+
(type (;0;) (func (param i32) (result i32)))
10+
(func (;0;) (type 0) (param i32) (result i32)
11+
(local $var i32)
12+
local.get 0
13+
local.tee 0))
14+
;;; STDOUT ;;)

0 commit comments

Comments
 (0)