Skip to content
This repository has been archived by the owner on Nov 16, 2023. It is now read-only.

Can't get conjunction type resolution to work #370

Closed
catchmareck opened this issue Nov 18, 2020 · 1 comment · Fixed by #371
Closed

Can't get conjunction type resolution to work #370

catchmareck opened this issue Nov 18, 2020 · 1 comment · Fixed by #371

Comments

@catchmareck
Copy link
Contributor

catchmareck commented Nov 18, 2020

Describe the bug
So I've been experimenting with the conjunction type resolution for 2 days and couldn't get it working. I'm referring to Section 5.3 and Section 5.7 from the language docs. I tried to implement it in various ways and couldn't achieve the expected result. I am always getting one of two errors:

  1. "Constant value not defined for type 'NSMain::TypeA&NSMain::TypeB'"

I did some debugging here, and I think I know where the error may come from. I'm not sure if I understand everything correctly but from what I can see, there is something wrong in the Assembly#ensureSingleDecl(opts: OOMemberLookupInfo[]) method. When I try to call a static function from a conjunction type, at some point the TypeChecker#checkCallStaticFunctionExpression(env, exp, trgt, refok) method gets called and inside this method, the Assembly#tryGetOOMemberDeclUnique(...) gets called which then calls the mentioned ensureSingleDecl(...) which returns undefined. And that undefined value causes the error to appear. In this method, for me, the opts.every() check is firing and this is where false is being returned. And this is because of this condition:

if (opt1.contiainingType.ns !== opt.contiainingType.ns || opt1.contiainingType.name !== opt.contiainingType.name) {
    return false;
}

I'm a bit confused here. How the second condition (opt1.contiainingType.name !== opt.contiainingType.name) can be ever false here? I'm creating two concept types with different names so how this can return false? 🧐

  1. Error -- TypeError: Cannot read property 'trkey' of undefined

I have tracked the second error and this is the stack trace:

TypeError: Cannot read property 'trkey' of undefined
    at MIRAssembly.subtypeOf ([...]\bin\compiler\mir_assembly.js:563:38)
    at [...]\bin\tooling\aot\cpptype_emitter.js:644:127
    at Array.filter (<anonymous>)
    at [...]\bin\tooling\aot\cpptype_emitter.js:644:98
    at Map.forEach (<anonymous>)
    at CPPTypeEmitter.initializeConceptSubtypeRelation ([...]\bin\tooling\aot\cpptype_emitter.js:642:36)
    at Function.emit ([...]\bin\tooling\aot\cppdecls_emitter.js:66:21)
    at Immediate._onImmediate ([...]\bin\runtimes\exegen\exegen.js:73:55)

You probably know the codebase better so this may tell you more than me, but from my understanding, something is wrong with the MIRAssembly#typeMap initialization and as a result, the CPPTypeEmitter#getMIRType() returns undefined but I'm not sure if that's the correct conclusion.

To Reproduce
Let me list my attempts and the errors I get:

concept Foo {
    static ala(a: Int): Int {
        _debug("Called Bar::ala");
        return a;
    }
}

concept Bar {
    static ala(a: Int): Int {
        _debug("Called Baz::ala");
        return a;
    }
}
...
(Foo & Bar)::ala(1);

This results in the error 1.

  1. The two concepts above + this one:
concept Baz provides Foo & Bar {}
...
Baz::ala(1);

This results in the error 2.

  1. Pretty similar to the previous one but slightly modified
typedef Abd = Foo & Bar;
concept Baz provides Abd {}
...
Baz::ala(1);

This results in the error 2.

  1. A modification of the previous one
typedef Abd = Foo & Bar;
...
Abd::ala(1);

This results in the error 1.

Expected behavior
I expect it to work as described in the docs.

Desktop (please complete the following information):

  • OS: Windows
  • Bosque Version: master

Additional context
It's likely that I don't understand the concept of conjunction types in Bosque and how that is supposed to work but it seems to me that something is not right here. Also, could you please show an example of how this could be used in a real app? Like, how this feature is useful? I don't get it really :(

@mrkmarron
Copy link
Contributor

Thanks for the very useful bug report. There were a couple of things going on here. One of them was fixed in PR #371 and there is a parser issues I opened bug #372.

The expected result of your example is the type error since you have 2 possible resolutions of the static call -- Foo::ala and Bar::ala. We check that there is only 1 unique resolution of the call. So, the following would be ok:

concept Foo {
    static ala(a: Int): Int {
        _debug("Called Foo::ala");
        return a;
    }
}

concept Bar {
}

entrypoint function main(): Int {
   return Foo&Bar::ala(1);
}

In this case there is only 1 possible resolution -- namely Foo::ala.

This isn't too useful when dealing with explicit types since you could just write Foo::ala instead. However, it can be very convenient when dealing with template instantiation:

function baz<T>(a: Int): Int {
   return T::ala(a);
}

In this case we want to be able to call baz<Foo&Bar>(3) instead of having to ensure that each template type that may be used in a static resolution is unique. Similarly we should also allow cases like:

entity E provides Foo {
}

entrypoint function main(): Int {
   return E::ala(1);
}

In this case we resolve the correct static member from the derived type instead of requiring the developer to use the exact concept type that specifies the static member.

I am merging PR #371 which should get this working but please repoen if there are other issues or questions.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants