Skip to content
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

"could not find type" inside struct #944

Open
Classes123 opened this issue Feb 7, 2024 · 1 comment
Open

"could not find type" inside struct #944

Classes123 opened this issue Feb 7, 2024 · 1 comment

Comments

@Classes123
Copy link

Compiler version: 1.12.0.7107
Code to reproduce the issue:

Map g_map; //OK

public void OnPluginStart()
{
    Map map = view_as<Map>(1); //OK

    {
        Map n_map; //OK
    }
}

enum struct t
{
    Map map; //error 139: could not find type "Map"
}

methodmap Map 
{
    property Map2 map //OK
    {
        public get()
        {
            Map2 map; //OK
            return map;
        }
    }
}

methodmap Map2 
{}
@dvander
Copy link
Member

dvander commented Feb 28, 2024

tl;dr explanation: Name binding happens in two passes. The first pass is a quick skim of top-level declarations. During this pass, global variables are skipped, type declarations are registered in the type system, and function names (but NOT their arguments or return types) are bound. The second name-binding pass will bind everything we skipped in the first pass.

So it's easy to see what's going wrong: we're binding the fields of enum struct t in the first pass, when it should be done in the second. The first pass only needs to register that t exists, not fill out its complete type.

Unfortunately this exposes a pretty big hole in an idea I've been toying with, which is collapsing all passes in the compiler into a single pipeline. For example Map g_map would be parsed, bound, type checked, and AST generated before proceeding with the next statement. This is how clang works, by having the Parser call into the Semantics class to generate AST nodes. It would greatly simplify the compiler, make type checking/coercion straightforward, and compilation would be much more efficient both in speed and memory use.

Your example makes me think I have to toss this idea in the rubbish bin. How could we type check Map g_map if the type declaration hasn't even been lexed yet? We'd have to toss out the ability to declare types in any order. Caching the tokens and replaying them later would work, except... it'd mean we can never have cyclic reference support.

Anyway, the fix here, I think, is to delay binding of struct fields until the second name binding phase. Eventually, someone would find a loophole to this too. Like void f(int [sizeof(t.map)]) would still not work if f was defined before t. I'm ok with that, it's very esoteric. But we could consider binding types recursively if we really, really, really wanted.

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

No branches or pull requests

2 participants