Skip to content

Commit

Permalink
Work around compiler bugs that cause linker errors
Browse files Browse the repository at this point in the history
  • Loading branch information
andralex committed Nov 6, 2021
1 parent 3d8d873 commit baa968f
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 91 deletions.
127 changes: 72 additions & 55 deletions std/algorithm/comparison.d
Expand Up @@ -58,13 +58,21 @@ T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
*/
module std.algorithm.comparison;

import std.functional : unaryFun, binaryFun, lessThan, greaterThan;
import std.range.primitives;
import std.traits;
import std.meta : allSatisfy, anySatisfy;
import std.typecons : tuple, Tuple, Flag, Yes;

import std.internal.attributes : betterC;

// Expose all symbols from canon!"std" into the std namespace.
static foreach (s; __traits(allMembers, canon!"std"))
{
mixin("alias "~s~" = canon!`std`."~s~";");
}

/// $(CANON_DESCRIPTION)
/// CANON_DESCRIPTION
template canon(string v)
{
// @@@TODO@@@: this is clowny, must add language support
Expand Down Expand Up @@ -829,7 +837,6 @@ static:
}

/// Example predicate that compares individual elements in reverse lexical order
static if (v == "std") // differences in spec
pure @safe unittest
{
int result;
Expand Down Expand Up @@ -904,39 +911,6 @@ static:
assert(ctr == a.length, "opCmp should be called exactly once per pair of items!");
}

version(none) // @@@BUG@@@ this code results in linker error
nothrow pure @safe @nogc unittest
{
import std.array : staticArray;
// Test cmp when opCmp returns float.
struct F
{
float value;
float opCmp(const ref F rhs) const
{
return value - rhs.value;
}
bool opEquals(T)(T o) const { return false; }
size_t toHash() const { return 0; }
}
auto result = cmp([F(1), F(2), F(3)].staticArray[], [F(1), F(2), F(3)].staticArray[]);
assert(result == 0);
assert(is(typeof(result) == float));
result = cmp([F(1), F(3), F(2)].staticArray[], [F(1), F(2), F(3)].staticArray[]);
assert(result > 0);
result = cmp([F(1), F(2), F(3)].staticArray[], [F(1), F(2), F(3), F(4)].staticArray[]);
assert(result < 0);
result = cmp([F(1), F(2), F(3)].staticArray[], [F(1), F(2)].staticArray[]);
assert(result > 0);
}

nothrow pure @safe unittest
{
// Parallelism (was broken by inferred return type "immutable int")
import std.parallelism : task;
auto t = task!cmp("foo", "bar");
}

// levenshteinDistance
/**
Encodes $(HTTP realityinteractive.com/rgrzywinski/archives/000249.html,
Expand Down Expand Up @@ -1562,8 +1536,16 @@ static:
}
assert(min(A(1, "first"), A(1, "second")) == A(1, "first"));
}

// mismatch
static Tuple!Ranges
/**
Sequentially compares elements in `rs` in lockstep, and
stops at the first mismatch (according to `pred`, by default
equality). Returns a tuple with the reduced ranges that start with the
two mismatched values. Performs $(BIGOH min(r[0].length, r[1].length, ...))
evaluations of `pred`.
*/
Tuple!(Ranges)
mismatch(alias pred = (a, b) => a == b, Ranges...)(Ranges rs)
if (rs.length >= 2 && allSatisfy!(isInputRange, Ranges))
{
Expand Down Expand Up @@ -1638,7 +1620,7 @@ static:
SwitchError) is also thrown if a void return expression was executed without
throwing anything.
*/
auto predSwitch(alias pred = (a, b) => a == b, T, R ...)(T switchExpression, lazy R choices)
auto predSwitch(alias pred = "a == b", T, R ...)(T switchExpression, lazy R choices)
{
import core.exception : SwitchError;
alias predicate = binaryFun!(pred);
Expand Down Expand Up @@ -1683,7 +1665,6 @@ static:
}

///
static if (v == "std") // no more string literals
@safe unittest
{
string res = 2.predSwitch!"a < b"(
Expand Down Expand Up @@ -1711,7 +1692,6 @@ static:
assertThrown!Exception(factorial(-9));
}

static if (v == "std") // no more string literals
@system unittest
{
import core.exception : SwitchError;
Expand Down Expand Up @@ -1992,7 +1972,7 @@ static:
}

/// ditto
bool isPermutation(alias pred = (a, b) => a == b, Range1, Range2)
bool isPermutation(alias pred = "a == b", Range1, Range2)
(Range1 r1, Range2 r2)
if (is(typeof(binaryFun!(pred))) &&
isForwardRange!Range1 &&
Expand Down Expand Up @@ -2093,7 +2073,6 @@ static:
assert(!isPermutation(arr3, arr4));
}

static if (v == "std")
@safe pure unittest
{
import std.internal.test.dummyrange;
Expand Down Expand Up @@ -2121,13 +2100,6 @@ static:
DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random) r11;
DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random) r12;
assert(isPermutation!(Yes.allocateGC)(r11, r12));

alias mytuple = Tuple!(int, int);

assert(isPermutation!"a[0] == b[0]"(
[mytuple(1, 4), mytuple(2, 5)],
[mytuple(2, 3), mytuple(1, 2)]
));
}

/**
Expand Down Expand Up @@ -2220,7 +2192,7 @@ static:
static assert(!__traits(compiles, either(1.0, "a")));
static assert(!__traits(compiles, either('a', "a")));
}
}
} // canon

/*
@@@BUG@@@
Expand All @@ -2232,7 +2204,6 @@ std/container/rbtree.d(1089): `__lambda5` declared here
std/algorithm/comparison.d(2330): Error: template instance `std.container.rbtree.__unittest_L2223_C12.RedBlackTree!(int, delegate (a, b) => a > b, false).RedBlackTree.opEquals.equalLoop!(RBRange!(RBNode!int*), RBRange!(RBNode!int*))` error instantiating
std/container/rbtree.d(1090): instantiated from here: `equal!(RBRange!(RBNode!int*), RBRange!(RBNode!int*))`
std/container/rbtree.d(2227): instantiated from here: `RedBlackTree!(int, delegate (a, b) => a > b, false)`
*/

// equal
Expand All @@ -2242,11 +2213,6 @@ Compares two or more ranges for equality, as defined by predicate `pred`
*/
template equal(alias pred = "a == b")
{
import std.functional : binaryFun;
import std.range.primitives;
import std.traits;
import std.meta : allSatisfy, anySatisfy;

/++
Compares two or more ranges for equality. The ranges may have
different element types, as long as all are comparable by means of
Expand Down Expand Up @@ -2531,3 +2497,54 @@ range of range (of range...) comparisons.
assert(!E().equal("foo"));
assert(!"bar".equal(E()));
}

/*
@@@BUG@@@ Link-time error when putting any of these unittest inside canon
Command to reproduce(run in the phobos dir):
../dmd/generated/linux/release/64/dmd -run ../dlang.org/tools/dspec_tester.d \
--compiler=../dmd/generated/linux/release/64/dmd
*/
nothrow pure @safe @nogc unittest
{
import std.array : staticArray;
// Test cmp when opCmp returns float.
struct F
{
float value;
float opCmp(const ref F rhs) const
{
return value - rhs.value;
}
bool opEquals(T)(T o) const { return false; }
size_t toHash() const { return 0; }
}
auto result = cmp([F(1), F(2), F(3)].staticArray[], [F(1), F(2), F(3)].staticArray[]);
assert(result == 0);
assert(is(typeof(result) == float));
result = cmp([F(1), F(3), F(2)].staticArray[], [F(1), F(2), F(3)].staticArray[]);
assert(result > 0);
result = cmp([F(1), F(2), F(3)].staticArray[], [F(1), F(2), F(3), F(4)].staticArray[]);
assert(result < 0);
result = cmp([F(1), F(2), F(3)].staticArray[], [F(1), F(2)].staticArray[]);
assert(result > 0);
}

// ditto @@@BUG@@@ above
nothrow pure @safe unittest
{
// Parallelism (was broken by inferred return type "immutable int")
import std.parallelism : task;
auto t = task!cmp("foo", "bar");
}

// ditto @@@BUG@@@ above
unittest
{
alias mytuple = Tuple!(int, int);

assert(isPermutation!"a[0] == b[0]"(
[mytuple(1, 4), mytuple(2, 5)],
[mytuple(2, 3), mytuple(1, 2)]
));
}

60 changes: 30 additions & 30 deletions std2xalpha/functional.d
@@ -1,30 +1,30 @@
module std2xalpha.functional;

static import std.functional;

// Pull all symbols from std.functional into the stdxalpha namespace.
static foreach (s; __traits(allMembers, std.functional))
{
static if (__traits(compiles, mixin("{ alias "~s~" = std.functional."~s~"; }")))
{
mixin("alias "~s~" = std.functional."~s~";");
}
}

/**
@@@TODO@@@: std2x `unaryFun` does not support string lambdas. Use function literals instead.
*/
//alias unaryFun(alias func) = func;

/**
@@@TODO@@@: std2x `unaryFun` does not support string lambdas. Use function literals instead.
*/
//alias binaryFun(alias func) = func;

///
unittest
{
// string literals not supported
// assert(binaryFun!"a + b"(1, 1) == 2); // no longer compiles
assert(binaryFun!((a, b) => a + b)(1, 1) == 2); // works
}
module std2xalpha.functional;

static import std.functional;

// Pull all symbols from std.functional into the stdxalpha namespace.
static foreach (s; __traits(allMembers, std.functional))
{
static if (__traits(compiles, mixin("{ alias "~s~" = std.functional."~s~"; }")))
{
mixin("alias "~s~" = std.functional."~s~";");
}
}

/**
@@@TODO@@@: std2x `unaryFun` does not support string lambdas. Use function literals instead.
*/
//alias unaryFun(alias func) = func;

/**
@@@TODO@@@: std2x `unaryFun` does not support string lambdas. Use function literals instead.
*/
//alias binaryFun(alias func) = func;

///
unittest
{
// string literals not supported
// assert(binaryFun!"a + b"(1, 1) == 2); // no longer compiles
assert(binaryFun!((a, b) => a + b)(1, 1) == 2); // works
}
6 changes: 3 additions & 3 deletions std2xalpha/traits.d
@@ -1,3 +1,3 @@
module std2xalpha.traits;

public import std.traits;
module std2xalpha.traits;

public import std.traits;
6 changes: 3 additions & 3 deletions std2xalpha/typecons.d
@@ -1,3 +1,3 @@
module std2xalpha.typecons;

public import std.typecons;
module std2xalpha.typecons;

public import std.typecons;

0 comments on commit baa968f

Please sign in to comment.