Skip to content

fix[lang]: improve error message for exprs in type position#4898

Open
rafael-abuawad wants to merge 22 commits into
vyperlang:masterfrom
rafael-abuawad:fix/lang-varinfo-type-annotation-4865
Open

fix[lang]: improve error message for exprs in type position#4898
rafael-abuawad wants to merge 22 commits into
vyperlang:masterfrom
rafael-abuawad:fix/lang-varinfo-type-annotation-4865

Conversation

@rafael-abuawad
Copy link
Copy Markdown
Contributor

@rafael-abuawad rafael-abuawad commented Mar 27, 2026

What I did

Fixed a compiler panic when a name in a type position resolves to a VarInfo. The compiler now raises InvalidType with the existing '…' is not a type! message for that case, and keeps CompilerPanic for other unexpected non-VyperType namespace values.

How I did it

In _type_from_annotation in vyper/semantics/types/utils.py, after resolving a Name through the namespace and unwrapping ModuleInfo, the code now checks isinstance(typ_, VarInfo) before the fallthrough CompilerPanic. If it is a VarInfo, it raises InvalidType(err_msg, node) using the existing error message; otherwise the CompilerPanic is preserved for truly unexpected values.

How to verify it

  1. Minimal repro using GH 4865
  2. Local compiler

Commit message

when a name used in a type position resolves to `VarInfo` (e.g.
`empty(MAX_MESSAGES)` where `MAX_MESSAGES` is a constant, or using a
constant as a type annotation like `x: N`), the compiler raised
`CompilerPanic`. the namespace can legitimately contain `VarInfo`
entries — constants, immutables, state variables, and function
parameters all resolve to `VarInfo` — so hitting this branch is a
user error, not a compiler bug.

raise `InvalidType` with the existing "not a type" message for
`VarInfo`, and keep `CompilerPanic` for other unexpected non-type
namespace values.

Description for the changelog

Semantics: treat VarInfo in type position as InvalidType, not CompilerPanic (GH 4865).

Cute Animal Picture

Put a link to a cute animal picture inside the parenthesis-->

Resolving a name to VarInfo (e.g. a constant passed to empty()) is a user/type error, not an internal compiler failure. Raise InvalidType with the existing message; preserve CompilerPanic for unexpected values.

Fixes vyperlang#4865

Made-with: Cursor
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.06%. Comparing base (eab4648) to head (1625cb7).

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #4898   +/-   ##
=======================================
  Coverage   92.06%   92.06%           
=======================================
  Files         187      187           
  Lines       27132    27135    +3     
  Branches     4758     4759    +1     
=======================================
+ Hits        24978    24981    +3     
  Misses       1437     1437           
  Partials      717      717           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@charles-cooper charles-cooper requested a review from Sporarum April 8, 2026 09:23
Comment thread vyper/semantics/types/utils.py
Comment thread tests/unit/semantics/types/test_type_from_annotation.py Outdated
Copy link
Copy Markdown
Member

@charles-cooper charles-cooper left a comment

Choose a reason for hiding this comment

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

thanks for the submission, looks fine overall, requested style changes

@Sporarum
Copy link
Copy Markdown
Collaborator

Sporarum commented Apr 8, 2026

I'm not sure this is the right fix, it seems to me like a better error for

MAX_MESSAGES: constant(uint256) = 64

@external
def parse_blob(blob: Bytes[4096]):
    starts: DynArray[uint16, MAX_MESSAGES] = empty(MAX_MESSAGES)

would be something like:
"Only literal constants and expressions (10, 1 + 1) are allowed as lengths for DynArray"

Because 2 is not a type either, but DynArray[uint16, 2] is valid !

There's also the question of whether we should just allow the above, since MAX_MESSAGES is a compile-time constant

@rafael-abuawad
Copy link
Copy Markdown
Contributor Author

@Sporarum The error is not that they are using a constant for the length of the DynArray. The issue is that they are calling empty(<CONSTANT>) and the compiler panics

@Sporarum
Copy link
Copy Markdown
Collaborator

Sporarum commented Apr 9, 2026

@rafael-abuawad oh, of course

Then I think it would make sense to add a couple more tests (if they don't already exist) of similar cases, for example:

convert(something, MAX_MESSAGES)

(and every other spot where a type can be)

@rafael-abuawad
Copy link
Copy Markdown
Contributor Author

@Sporarum im going to add a few more tests maybe 2 or 3 to see how it handles that. And going to remove the compile panic line

Comment thread tests/functional/builtins/codegen/test_empty.py Outdated
Comment thread vyper/semantics/types/utils.py Outdated
Comment thread vyper/semantics/types/utils.py Outdated
rafael-abuawad and others added 2 commits April 14, 2026 13:44
Co-authored-by: Charles Cooper <cooper.charles.m@gmail.com>
@Sporarum
Copy link
Copy Markdown
Collaborator

@rafael-abuawad did you get around to add more tests ?

@rafael-abuawad
Copy link
Copy Markdown
Contributor Author

@rafael-abuawad did you get around to add more tests ?

Hey @Sporarum , no, not yet I'm going to do so this weekend hopefully

@rafael-abuawad
Copy link
Copy Markdown
Contributor Author

@Sporarum I've added more tests, but I don't know if that's enough

@Sporarum
Copy link
Copy Markdown
Collaborator

@rafael-abuawad
My idea was more to test more breadth of errors than more cases of specifically empty(<something which is not a type>)

For example:

x: <not a type>
convert(x, <not a type>)
x: <not a type>[10]
def foo(x: <not a type>)
def foo() -> <not a type>

But it's also something I can do myself if you prefer

@rafael-abuawad
Copy link
Copy Markdown
Contributor Author

My idea was more to test more breadth of errors than more cases of specifically empty(<something which is not a type>)

@Sporarum understood, I’ve added more tests. Sorry, I became too short-sighted. I didn’t want to go overboard with the tests, but I think this list covers enough

@Sporarum
Copy link
Copy Markdown
Collaborator

Very nice, thanks !

@rafael-abuawad
Copy link
Copy Markdown
Contributor Author

@Sporarum @charles-cooper do you need anything else from my side to have this merged?

@Sporarum Sporarum requested a review from charles-cooper May 4, 2026 07:51
@charles-cooper
Copy link
Copy Markdown
Member

Looks good, will merge shortly

@charles-cooper charles-cooper changed the title fix[lang]: use InvalidType when annotation names bind to VarInfo fix[lang]: improve error message for exprs in type position May 4, 2026
@charles-cooper
Copy link
Copy Markdown
Member

@rafael-abuawad looks like there is something not resolving correctly on initialization, can you fix? probably if you get lint passing it should be good

UnknownType,
)
from vyper.semantics.analysis.levenshtein_utils import get_levenshtein_error_suggestions
from vyper.semantics.analysis.base import VarInfo
@rafael-abuawad
Copy link
Copy Markdown
Contributor Author

@charles-cooper I think that was it, I was able to run the lint properly, but I don't know how to re-run the checks

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.

4 participants