Skip to content

[NFC] Rename Type::is{,Non}NullableRef - #9286

Merged
tlively merged 1 commit into
mainfrom
is-nullable-ref-nfc
Oct 20, 2026
Merged

tlively merged 1 commit into
mainfrom
is-nullable-ref-nfc

Conversation

@tlively

@tlively tlively commented Oct 20, 2026

Copy link
Copy Markdown
Member

Rename Type::isNullable and Type::isNonNullable to Type::isNullableRef and Type::isNonNullableRef to make it clear that they already check that the type is a reference, and remove redundant isRef() checks at call sites.

Rename Type::isNullable and Type::isNonNullable to Type::isNullableRef and Type::isNonNullableRef to make it clear that they already check that the type is a reference, and remove redundant isRef() checks at call sites.
@tlively
tlively requested a review from a team as a code owner October 20, 2026 18:34
@tlively
tlively requested review from stevenfontanella and removed request for a team October 20, 2026 18:34

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request renames isNullable() to isNullableRef() and isNonNullable() to isNonNullableRef() across the codebase to clarify that these methods check reference types. Two critical issues were identified in the review: first, a logical contradiction in DeadArgumentElimination.cpp where a return type is checked for being both null and non-nullable, which always evaluates to false; second, an unsafe call to getHeapType() in wasm-validator.cpp that could cause a crash on invalid modules if the type is not first verified to be a reference type.

Comment on lines 553 to +554
bool wasReturnUninhabitable =
func->getResults().isNull() && func->getResults().isNonNullable();
func->getResults().isNull() && func->getResults().isNonNullableRef();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There is a logical contradiction in this check. func->getResults().isNull() checks if the type is the null type (which is a nullable reference type), while func->getResults().isNonNullableRef() checks if it is non-nullable. A type cannot be both null and non-nullable, so wasReturnUninhabitable will always evaluate to false. Based on the comment, you likely want to check if the return type is a non-nullable reference.

Suggested change
bool wasReturnUninhabitable =
func->getResults().isNull() && func->getResults().isNonNullable();
func->getResults().isNull() && func->getResults().isNonNullableRef();
bool wasReturnUninhabitable =
func->getResults().isNonNullableRef();

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not correct, but also points to a good renaming we could do. I'll also rename "isNull" to "isBottomRef".


if (!shouldBeTrue(curr->type.isRef() &&
curr->type.getHeapType().isContinuation(),
if (!shouldBeTrue(curr->type.getHeapType().isContinuation(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Calling curr->type.getHeapType() directly is unsafe here because curr->type is not guaranteed to be a reference type if the module being validated is invalid (e.g., if it is annotated with a basic type like i32). This will cause an assertion failure or crash in getHeapType(). You should restore the curr->type.isRef() check to ensure short-circuiting protects the getHeapType() call.

Suggested change
if (!shouldBeTrue(curr->type.getHeapType().isContinuation(),
if (!shouldBeTrue(curr->type.isRef() &&
curr->type.getHeapType().isContinuation(),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a false positive since we'll early return if it's not a ref

@kripken

kripken commented Oct 20, 2026

Copy link
Copy Markdown
Member

Isn't isNonNullable already clear enough about implying it is a reference? Only a reference can be nullable or non-nullable. That is, the longer names seem a little unnecessary to me.

@tlively

tlively commented Oct 20, 2026

Copy link
Copy Markdown
Member Author

Since it's a negative, it's arguably ambiguous whether isNonNullable() it means isRef() && !isNullable() or just !isNullable(). This makes it unambiguous, so I think it's a worthwhile change.

// if it is null.
void notePossibleTrap(Expression* expr) {
if (!expr->type.isRef() || expr->type.isNonNullable()) {
if (!expr->type.isNullableRef()) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks equivalent to !isRef || !isNullable while the original code is !isRef || isNonNullable. Is !isNullable the same as isNonNullable? I guess this is only in the case when isRef so yes?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think this should be good.

Non-refs: take the branch before and after.
nullable refs: do not take the branch before and after.
non-nullable refs: take the branch before and after.

@kripken

kripken commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

@tlively I suppose that is arguable... but have you ever read "this is a non-nullable type" and thought "well that might be an i32"..? 🤔

@stevenfontanella

Copy link
Copy Markdown
Member

@tlively I suppose that is arguable... but have you ever read "this is a non-nullable type" and thought "well that might be an i32"..? 🤔

Some code paths make this mistake and add a redundant check for isRef e.g. here

@tlively

tlively commented Oct 20, 2026

Copy link
Copy Markdown
Member Author

I've been uncertain about this in the past. And Gemini Code Assist was certainly confused about it here: #9282 (comment).

@tlively
tlively requested a review from kripken October 20, 2026 20:37
@kripken

kripken commented Oct 20, 2026

Copy link
Copy Markdown
Member

@stevenfontanella that code you linked to could be shortened, but it would need to be reordered (so it is safe to call getHeapType) - maybe that is the reason it is more verbose? Anyhow, we can fix such code paths.

@tlively If this is an AI issue, can we fix it with docs for the AI? If it is really an issue for you, I'd like to understand this better.

I think using longer, excessively-verbose names makes the code harder to read and less fun, as I wrote in the other PR. But I'll change my mind if we have a nice and short option to switch to, or if there is a real (non-AI) problem of understanding here.

@tlively

tlively commented Oct 20, 2026

Copy link
Copy Markdown
Member Author

isNNRef()?

@kripken

kripken commented Oct 20, 2026

Copy link
Copy Markdown
Member

I can live with isNNRef.

@tlively

tlively commented Oct 20, 2026

Copy link
Copy Markdown
Member Author

There were lots of redundant code paths, and I think that points to a real problem with the existing names. Both authors and reviewers are currently missing the redundancy.

Here are all 15 locations across the two commits where a redundant isRef() check was removed:

1. From Type::is{,Non}NullableRef (3203196)

  1. LocalStructuralDominance::Scanner (LocalStructuralDominance.cpp:81)
  2. TNHOracle::scan (possible-contents.cpp:1767)
  3. Inhabitator::markBottomRefsNullable (heap-types.cpp:1030)
  4. Inhabitator::markExternRefsNullable (heap-types.cpp:1051-1052)
  5. Inhabitator::breakNonNullableCycles (heap-types.cpp:1182)
  6. isUninhabitable (heap-types.cpp:1403)
  7. FunctionValidator::visitContNew (wasm-validator.cpp:4457-4468)
  8. FunctionValidator::visitContBind (wasm-validator.cpp:4505-4509)

2. From Type::isBottomRef (f250db9)

  1. Literal::operator== (literal.cpp:505-508)
  2. FunctionValidator::visitArrayGet (wasm-validator.cpp:3949-3951)
  3. FunctionValidator::visitArraySet (wasm-validator.cpp:3973-3975)
  4. FunctionValidator::visitArrayLoad (wasm-validator.cpp:4006-4008)
  5. FunctionValidator::visitArrayStore (wasm-validator.cpp:4034-4036)
  6. FunctionValidator::visitArrayFill (wasm-validator.cpp:4128-4130)
  7. FunctionValidator::visitArrayInit (wasm-validator.cpp:4161-4163)

@tlively

tlively commented Oct 20, 2026

Copy link
Copy Markdown
Member Author

Just to add my 2 cents to the bikeshed, I would prefer isNonNullableRef over isNNRef for symmetry with isNullableRef. I don't think the verbosity is a problem because (IMO) it carries its weight in improved clarity.

@stevenfontanella

Copy link
Copy Markdown
Member

Just to add my 2 cents to the bikeshed, I would prefer isNonNullableRef over isNNRef for symmetry with isNullableRef. I don't think the verbosity is a problem because (IMO) it carries its weight in improved clarity.

I agree FWIW

@kripken

kripken commented Oct 20, 2026

Copy link
Copy Markdown
Member

Ok, fair enough, I don't disagree that strongly. sgtm

@tlively
tlively merged commit fffd195 into main Oct 20, 2026
16 checks passed
@tlively
tlively deleted the is-nullable-ref-nfc branch October 20, 2026 21:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants