Issue 20008 - __traits(allMembers) of packages is complete nonsense
Summary: __traits(allMembers) of packages is complete nonsense
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: x86_64 Linux
: P3 normal
Assignee: No Owner
URL:
Keywords: pull
: 11595 (view as issue list)
Depends on:
Blocks:
 
Reported: 2019-06-26 11:33 UTC by FeepingCreature
Modified: 2023-06-27 06:45 UTC (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description FeepingCreature 2019-06-26 11:33:20 UTC
Consider this code: https://run.dlang.io/is/ANydDv

import std.meta;

void main()
{
    alias module_ = __traits(parent, main);
    
    static assert(anySatisfy!(isSame!main, allMembers!module_));
    static assert(anySatisfy!(isSame!std, allMembers!module_));
    pragma(msg, __traits(allMembers, std));
    // static assert(anySatisfy!(isSame!(std.meta), allMembers!std));
}

alias allMembers(alias Sym) = staticMap!(getMember!Sym, __traits(allMembers, Sym));

template getMember(alias Sym) {
    alias getMember(string ident) = __traits(getMember, Sym, ident);
}

template isSame(alias Sym1) {
    enum isSame(alias Sym2) = __traits(isSame, Sym1, Sym2);
}

As can be seen by the pragma(msg) and the spectacular errors when you comment in the commented-out line, the contents of __traits(allMembers, std) are not at all things that can be written in the form "std.<member>".

Expected: tuple("meta")

Got: tuple("object", "AliasSeq", "Alias", "OldAlias", "staticIndexOf", "genericIndexOf", "Erase", "GenericErase", "EraseAll", "GenericEraseAll", "EraseAllN", "NoDuplicates", "Replace", "GenericReplace", "ReplaceAll", "GenericReplaceAll", "Reverse", "MostDerived", "DerivedToFront", "staticMap", "allSatisfy", "anySatisfy", "Filter", "templateNot", "templateAnd", "templateOr", "aliasSeqOf", "ApplyLeft", "ApplyRight", "SmartAlias", "Repeat", "staticSort", "staticMerge", "isLessEq", "staticIsSorted", "Stride", "Instantiate", "isSame", "expectType", "expectBool", "Pack")

This means it is still impossible to walk all transitive imports.
Comment 1 basile-z 2020-08-25 04:16:28 UTC
One problem is that "std" as member of the module is actually "std.meta". It appears like that by accident and could lead to what I call symbol leaks.
The allmembers traits actually always takes the ident of a symbol but for imports this should be a FQN.
Comment 2 basile-z 2020-08-25 04:47:12 UTC
with the patch for the FQN in allMembers, this code

---
void allMembers(string p)()
{
    alias P = mixin(p);
    static if (is(P == module) || is(P == package))
    {
        enum members = [__traits(allMembers, P)];
        pragma(msg, p, " ", members);
        static foreach (m; members)
            static if (m != "object")
                static if (is(mixin(m) == module) || is(mixin(m) == package))
                    allMembers!(m);
    }
}

import std.algorithm;
void main(string[] args)
{
    allMembers!("std.algorithm");
} 
---

outputs:
---
std.algorithm ["object", "std.algorithm.comparison", "std.algorithm.iteration", "std.algorithm.mutation", "std.algorithm.searching", "std.algorithm.setops", "std.algorithm.sorting", "std.functional"]
std.algorithm.comparison ["object", "std.functional", "std.range.primitives", "std.traits", "std.meta", "std.typecons", "std.internal.attributes", "among", "indexOfFirstOvershadowingChoiceOnLast", "castSwitch", "clamp", "cmp", "equal", "MaxType", "EditOp", "Levenshtein", "levenshteinDistance", "levenshteinDistanceAndPath", "max", "MinType", "min", "mismatch", "predSwitch", "isSameLength", "AllocateGC", "isPermutation", "either"]
std.algorithm.iteration ["object", "std.functional", "std.range.primitives", "std.traits", "std.typecons", "aggregate", "cache", "cacheBidirectional", "_Cache", "map", "MapResult", "each", "filter", "FilterResult", "filterBidirectional", "FilterBidiResult", "group", "Group", "ChunkByChunkImpl", "ChunkByImplIsUnary", "ChunkByImpl", "chunkBy", "joiner", "reduce", "ReduceSeedType", "fold", "cumulativeFold", "splitter", "SplitterResult", "hasDifferentAutodecoding", "substitute", "sum", "sumPairwise", "sumPairwise16", "sumPair", "sumPairwiseN", "sumKahan", "mean", "uniq", "UniqResult", "permutations", "Permutations"]
std.algorithm.mutation ["object", "std.range.primitives", "std.traits", "std.meta", "std.typecons", "bringToFront", "bringToFrontImpl", "areCopyCompatibleArrays", "copy", "fill", "initializeAll", "move", "moveImpl", "trustedMoveImpl", "moveEmplaceImpl", "moveEmplace", "moveAll", "moveEmplaceAll", "moveAllImpl", "moveSome", "moveEmplaceSome", "moveSomeImpl", "SwapStrategy", "isValidIntegralTuple", "remove", "removeImpl", "removeUnstable", "removeStable", "removeStableString", "removePredUnstable", "removePredStable", "removePredString", "reverse", "strip", "stripLeft", "stripRight", "swap", "swapAt", "swapFront", "swapRanges", "uninitializedFill"]
std.algorithm.searching ["object", "std.functional", "std.range.primitives", "std.traits", "std.typecons", "all", "any", "balancedParens", "BoyerMooreFinder", "boyerMooreFinder", "commonPrefix", "count", "countUntil", "endsWith", "hasConstEmptyMember", "RebindableOrUnqual", "extremum", "find", "simpleMindedFind", "canFind", "findAdjacent", "findAmong", "findSkip", "findSplit", "findSplitBefore", "findSplitAfter", "minCount", "maxCount", "minElement", "maxElement", "minPos", "maxPos", "minIndex", "maxIndex", "skipOver", "startsWith", "skipAll", "OpenRight", "until", "Until"]
std.algorithm.setops ["object", "std.range.primitives", "std.functional", "std.traits", "std.meta", "std.algorithm.sorting", "std.typecons", "cartesianProduct", "largestPartialIntersection", "std.algorithm.sorting", "largestPartialIntersectionWeighted", "MultiwayMerge", "multiwayMerge", "nWayUnion", "NWayUnion", "multiwayUnion", "SetDifference", "setDifference", "SetIntersection", "setIntersection", "SetSymmetricDifference", "setSymmetricDifference"]
std.algorithm.sorting ["object", "std.algorithm.mutation", "std.functional", "std.range.primitives", "std.typecons", "std.meta", "std.range", "std.traits", "SortOutput", "completeSort", "isSorted", "isStrictlyMonotonic", "ordered", "strictlyOrdered", "partition", "pivotPartition", "isPartitioned", "partition3", "makeIndex", "Merge", "merge", "validPredicates", "multiSort", "multiSortPredFun", "multiSortImpl", "getPivot", "shortSort", "trustedMoveEmplace", "sort5", "sort", "quickSortImpl", "HeapOps", "TimSortImpl", "schwartzSort", "partialSort", "topN", "topNImpl", "topNPartition", "p3", "p4", "topNPartitionOffMedian", "expandPartition", "topNCopy", "topNIndex", "medianOf", "nextPermutation", "nextEvenPermutation", "nthPermutation", "nthPermutationImpl"]
---

but apparently not all imports are handled.. for example std.typecons has not its line.
Comment 3 Dennis 2022-09-29 14:23:21 UTC
*** Issue 11595 has been marked as a duplicate of this issue. ***
Comment 4 Dlang Bot 2023-06-20 22:17:21 UTC
@dkorpel created dlang/dmd pull request #15335 "Fix 20008 - __traits(allMembers) of packages is complete nonsense" fixing this issue:

- Fix 20008 - __traits(allMembers) of packages is complete nonsense

https://github.com/dlang/dmd/pull/15335
Comment 5 Dlang Bot 2023-06-27 06:45:08 UTC
dlang/dmd pull request #15335 "Fix 20008 - __traits(allMembers) of packages is complete nonsense" was merged into master:

- cf7ac3326918c83ca819ee061b2f65f6fbf0de63 by Dennis Korpel:
  Fix 20008 - __traits(allMembers) of packages is complete nonsense

https://github.com/dlang/dmd/pull/15335