-
Notifications
You must be signed in to change notification settings - Fork 734
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix reference type processing #2571
base: main
Are you sure you want to change the base?
Conversation
This is another bugfix patch extracted from #2562. The list of changes are above, these constructs should work even in the main branch. |
@@ -973,11 +1008,16 @@ Result WastParser::ParseValueTypeList( | |||
CHECK_RESULT(ParseValueType(&type)); | |||
|
|||
if (type.is_index()) { | |||
out_type_list->push_back(Type(type.index())); | |||
// TODO: Temporary fix. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The full fix is in #2562. It is unlikely that close to UINT32_MAX number of types are defined, so this is good as a temporary change.
func->GetNumParams(), | ||
decl->sig.param_type_names, errors); | ||
|
||
func->local_types.Set(func->local_type_list); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a delayed processing of locals. The reasion is that otherwise we cannot tell that (ref $t)
and (ref 0)
refers to the same or different locals, so they can be merged or not.
src/ir.cc
Outdated
@@ -181,7 +181,7 @@ void LocalTypes::Set(const TypeVector& types) { | |||
Type type = types[0]; | |||
Index count = 1; | |||
for (Index i = 1; i < types.size(); ++i) { | |||
if (types[i] != type) { | |||
if (!types[i].IsSame(type)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name might not be the best. Anyway, the purpose is that ==
only compares the enum, while the index is also important for references.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this.
Mostly LGTM, just trying to page in how this stuff all works.
include/wabt/ir.h
Outdated
@@ -259,8 +259,8 @@ struct FuncSignature { | |||
// So to use this type we need to translate its name into | |||
// a proper index from the module type section. | |||
// This is the mapping from parameter/result index to its name. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment needs updating maybe?
include/wabt/type.h
Outdated
@@ -79,6 +79,11 @@ class Type { | |||
return IsRef(); | |||
} | |||
|
|||
// The == comparison only compares the enum_ member. | |||
bool IsSame(const Type& rhs) const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we instead update operator==
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately I get errors such as error: ambiguous overload for ‘operator==’ (operand types are ‘const wabt::Type’ and ‘wabt::Type::Enum’)
The reason is the Type has a constexpr operator Enum() const { return enum_; }
, and this confuses the compiler.
I am open to any ideas.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how much would break if you made that explicit
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to work for me locally:
constexpr operator Enum() const { return enum_; }
+ // TODO(sbc) Use =default here once we have C++20
+ bool operator==(const Type& other) const {
+ return enum_ == other.enum_ && type_index_ == other.type_index_;
+ }
+
+ bool operator==(const Enum& other) const { return enum_ == other; }
I tried the explicit
route too and that seems to break a bunch of places.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I change it. Thank you
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw it might fix another bug. Currently if we have two types which are the same except the ref part:
(type $t0 (func (param (ref $t0))))
(type $t1 (func (param (ref $t1))))
(func $f (param (ref $t1)) )
$f gets type 0, instead of type 1. The index is simply ignored.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems it does not work :(
if (types[i] != type) {
still uses the enum auto conversion.
if (!types[i].operator==(type)) {
works but does not look nice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What shall I do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess removing the implicit cast is the way to go.. although as you say it might require a bunch of downstream changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to move the operator== before the Enum casting, and the auto casting still takes precedence. I will never understand c++.
Removing the casting might have many side effects which is too big risk for this patch, so I move back to the original code for now, and we can try it later.
include/wabt/wast-parser.h
Outdated
@@ -137,7 +137,8 @@ class WastParser { | |||
Result ParseValueType(Var* out_type); | |||
Result ParseValueTypeList( | |||
TypeVector* out_type_list, | |||
std::unordered_map<uint32_t, std::string>* type_names); | |||
std::unordered_map<uint32_t, Var>* type_names, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe should be renamed? type_vars
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All ...type_names are renamed to ...type_vars.
test/typecheck/missing-ref.txt
Outdated
out/test/typecheck/missing-ref.txt:5:24: error: Unknown reference: $first_type | ||
(func $f (param (ref $first_type)) | ||
^^^^^^^^^^^ | ||
out/test/typecheck/missing-ref.txt:6:25: error: Unknown reference: $second_type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the errors that come from resolve-names.cc
It looks like this should be undefined reference type variable \"%s\""
.. or something like that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed it to undefined reference type name %s
@@ -457,7 +474,7 @@ class ResolveFuncTypesExprVisitorDelegate : public ExprVisitor::DelegateNop { | |||
: module_(module), errors_(errors) {} | |||
|
|||
void ResolveBlockDeclaration(const Location& loc, BlockDeclaration* decl) { | |||
ResolveTypeNames(*module_, decl); | |||
ResolveTypeNames(*module_, decl->sig, errors_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is this different to the code in src/wast-parser.cc
that does name resolving?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure I understand this question. ResolveTypeNames is reworked to support error throwing.
1207345
to
a4e230c
Compare
test/typecheck/missing-ref.txt
Outdated
out/test/typecheck/missing-ref.txt:5:24: error: undefined reference type name $first_type | ||
(func $f (param (ref $first_type)) | ||
^^^^^^^^^^^ | ||
out/test/typecheck/missing-ref.txt:6:25: error: undefined reference type name $second_type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a note: the error is thrown twice. The reason is that the references are resolved as func type and as a function signature. I don't think it is a problem, but we could fix it (could be later) by removing the items of param_type_vars / result_type_vars, if somebody does not like it.
946e527
to
74078be
Compare
Did some code improvements. The unordered_map is replaced by a vector, because it is a simpler structure. Furthermore, when a reference is resolved, its index is set to |
d403868
to
3fe420e
Compare
Parse (ref index) form, not just (ref $name) form Resolve references in types and locals Display location when a named reference is not found
Parse (ref index) form, not just (ref $name) form
Resolve references in types and locals
Display location when a named reference is not found