Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions IDEHelper/Compiler/BfCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -523,15 +523,20 @@ bool BfCompiler::IsTypeAccessible(BfType* checkType, BfProject* curProject)
BfTypeInstance* typeInst = checkType->ToTypeInstance();
if (typeInst != NULL)
{
if (checkType->IsTuple())
// A closure's type is its delegate's, from the delegate's project, so what it captures decides who can see it
if ((checkType->IsTuple()) || (checkType->IsClosure()))
{
for (auto&& fieldInst : typeInst->mFieldInstances)
{
if (!IsTypeAccessible(fieldInst.mResolvedType, curProject))
if ((fieldInst.mResolvedType != NULL) && (!IsTypeAccessible(fieldInst.mResolvedType, curProject)))
return false;
}
}

// Nor does a closure carry its delegate's signature: that is its source delegate's
if ((checkType->IsClosure()) && (((BfClosureType*)typeInst)->mSrcDelegate != NULL) && (!IsTypeAccessible(((BfClosureType*)typeInst)->mSrcDelegate, curProject)))
return false;

auto genericTypeInst = typeInst->ToGenericTypeInstance();
if (genericTypeInst != NULL)
{
Expand Down Expand Up @@ -587,15 +592,18 @@ bool BfCompiler::IsTypeUsed(BfType* checkType, BfProject* curProject, bool conse
if (checkType->IsUnspecializedType())
return typeInst->mIsReified || conservativeCheck;

if (checkType->IsTuple())
if ((checkType->IsTuple()) || (checkType->IsClosure()))
{
for (auto&& fieldInst : typeInst->mFieldInstances)
{
if (!IsTypeUsed(fieldInst.mResolvedType, curProject, true))
if ((fieldInst.mResolvedType != NULL) && (!IsTypeUsed(fieldInst.mResolvedType, curProject, true)))
return false;
}
}

if ((checkType->IsClosure()) && (((BfClosureType*)typeInst)->mSrcDelegate != NULL) && (!IsTypeUsed(((BfClosureType*)typeInst)->mSrcDelegate, curProject, true)))
return false;

auto genericTypeInst = typeInst->ToGenericTypeInstance();
if (genericTypeInst != NULL)
{
Expand Down
9 changes: 9 additions & 0 deletions IDEHelper/Tests/LibA/src/LibA0.bf
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,12 @@ static
return 1;
}
}

namespace SharedGlobals
{
// LibA's part of the globals LibC also has globals in; TestsB calls it
static
{
public static int32 LibAGlobal() => 3;
}
}
21 changes: 21 additions & 0 deletions IDEHelper/Tests/LibC/src/LibCClosures.bf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;

namespace SharedGlobals
{
// Globals of a namespace LibA has globals in too: one globals type, its LibC part in a module
// of its own. TestsB, which uses LibA's part but does not reference LibC, must not take this
// part (and the closure in it, capturing a LibC type) into its link
struct LibCCaptured
{
public int32 mValue;
}

static
{
public static int32 LibCCaptures(LibCCaptured captured)
{
delegate int32() get = scope () => captured.mValue;
return get();
}
}
}
4 changes: 4 additions & 0 deletions IDEHelper/Tests/TestsB/src/TestsB0.bf
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ namespace TestsB
int la0a = la0.GetA();
Test.Assert(la0a == 2);

// LibA's part of globals LibC has a part of too: LibC's part (a closure capturing a LibC type)
// must stay out of this executable, which does not reference LibC
Test.Assert(SharedGlobals.LibAGlobal() == 3);

// Same LibA5_Derived.GetVal body the Tests project links, but this executable sees no
// extension of LibA5, so the same 'base.GetVal()' has to resolve to the original
LibA.LibA5_Derived la5d = scope .();
Expand Down
10 changes: 10 additions & 0 deletions IDEHelper/Tests/src/Lambdas.bf
Original file line number Diff line number Diff line change
Expand Up @@ -160,5 +160,15 @@ namespace Tests
Test.Assert((getNewer() == 20) && (getOlder() == 10));
Test.Assert(CallWith(() => @y) == 20);
}

// LibC's part of the SharedGlobals globals holds a closure capturing a LibC type; TestsB, which
// uses LibA's part but does not reference LibC, links only if it leaves LibC's part out
[Test]
public static void TestClosuresOfAnotherProjectsTypes()
{
SharedGlobals.LibCCaptured captured = .() { mValue = 7 };
Test.Assert(SharedGlobals.LibCCaptures(captured) == 7);
Test.Assert(SharedGlobals.LibAGlobal() == 3);
}
}
}
Loading