Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 0897027

Browse files
committed
Take default parameters into account
1 parent 11a2539 commit 0897027

File tree

1 file changed

+218
-6
lines changed

1 file changed

+218
-6
lines changed

src/core/internal/traits.d

Lines changed: 218 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,12 +206,16 @@ template hasElaborateCopyConstructor(S)
206206
{
207207
static foreach (f; __traits(getOverloads, S, "__ctor"))
208208
{{
209-
static if (Parameters!f.length == 1)
209+
enum isVoid(alias T) = is (T == void);
210+
static if (Parameters!f.length == 1 ||
211+
(Parameters!f.length > 1 && !anySatisfy!(isVoid, ParameterDefaults!f[1 .. $])))
210212
{
211-
Parameters!f tmp;
212-
bool r = (Parameters!f x) {
213-
return __traits(isRef, x) && is (Parameters!f[0] : S);
214-
}(tmp);
213+
bool r = is (typeof((Parameters!f x) {
214+
static if (!(__traits(isRef, x[0]) && is (Parameters!f[0] : S)))
215+
{
216+
static assert(0);
217+
}
218+
}));
215219
if (r) return true;
216220
}
217221
}}
@@ -225,7 +229,7 @@ template hasElaborateCopyConstructor(S)
225229
}
226230
}
227231

228-
unittest
232+
@safe unittest
229233
{
230234
static struct S
231235
{
@@ -243,6 +247,15 @@ unittest
243247
}
244248

245249
static assert(!hasElaborateCopyConstructor!S2);
250+
251+
static struct S3
252+
{
253+
int x;
254+
this(return scope ref typeof(this) rhs, int x = 42) { }
255+
this(int x, int y) {}
256+
}
257+
258+
static assert(hasElaborateCopyConstructor!S3);
246259
}
247260

248261
template hasElaborateAssign(S)
@@ -263,6 +276,205 @@ template hasElaborateAssign(S)
263276
}
264277
}
265278

279+
// std.traits.isFunctionPointer
280+
/**
281+
Detect whether symbol or type `T` is a function pointer.
282+
*/
283+
template isFunctionPointer(T...)
284+
if (T.length == 1)
285+
{
286+
static if (is(T[0] U) || is(typeof(T[0]) U))
287+
{
288+
static if (is(U F : F*) && is(F == function))
289+
enum bool isFunctionPointer = true;
290+
else
291+
enum bool isFunctionPointer = false;
292+
}
293+
else
294+
enum bool isFunctionPointer = false;
295+
}
296+
297+
///
298+
@safe unittest
299+
{
300+
static void foo() {}
301+
void bar() {}
302+
303+
auto fpfoo = &foo;
304+
static assert( isFunctionPointer!fpfoo);
305+
static assert( isFunctionPointer!(void function()));
306+
307+
auto dgbar = &bar;
308+
static assert(!isFunctionPointer!dgbar);
309+
static assert(!isFunctionPointer!(void delegate()));
310+
static assert(!isFunctionPointer!foo);
311+
static assert(!isFunctionPointer!bar);
312+
313+
static assert( isFunctionPointer!((int a) {}));
314+
}
315+
316+
// std.traits.isDelegate
317+
/**
318+
Detect whether symbol or type `T` is a delegate.
319+
*/
320+
template isDelegate(T...)
321+
if (T.length == 1)
322+
{
323+
static if (is(typeof(& T[0]) U : U*) && is(typeof(& T[0]) U == delegate))
324+
{
325+
// T is a (nested) function symbol.
326+
enum bool isDelegate = true;
327+
}
328+
else static if (is(T[0] W) || is(typeof(T[0]) W))
329+
{
330+
// T is an expression or a type. Take the type of it and examine.
331+
enum bool isDelegate = is(W == delegate);
332+
}
333+
else
334+
enum bool isDelegate = false;
335+
}
336+
337+
///
338+
@safe unittest
339+
{
340+
static void sfunc() { }
341+
int x;
342+
void func() { x++; }
343+
344+
int delegate() dg;
345+
assert(isDelegate!dg);
346+
assert(isDelegate!(int delegate()));
347+
assert(isDelegate!(typeof(&func)));
348+
349+
int function() fp;
350+
assert(!isDelegate!fp);
351+
assert(!isDelegate!(int function()));
352+
assert(!isDelegate!(typeof(&sfunc)));
353+
}
354+
355+
// std.traits.ParameterIdentifierTuple
356+
/**
357+
Get, as a tuple, the identifiers of the parameters to a function symbol.
358+
*/
359+
template ParameterIdentifierTuple(func...)
360+
if (func.length == 1/* && isCallable!func*/)
361+
{
362+
static if (is(FunctionTypeOf!func PT == __parameters))
363+
{
364+
template Get(size_t i)
365+
{
366+
static if (!isFunctionPointer!func && !isDelegate!func
367+
// Unnamed parameters yield CT error.
368+
&& is(typeof(__traits(identifier, PT[i .. i+1])))
369+
// Filter out unnamed args, which look like (Type) instead of (Type name).
370+
&& PT[i].stringof != PT[i .. i+1].stringof[1..$-1])
371+
{
372+
enum Get = __traits(identifier, PT[i .. i+1]);
373+
}
374+
else
375+
{
376+
enum Get = "";
377+
}
378+
}
379+
}
380+
else
381+
{
382+
static assert(0, func[0].stringof ~ "is not a function");
383+
384+
// Define dummy entities to avoid pointless errors
385+
template Get(size_t i) { enum Get = ""; }
386+
alias PT = AliasSeq!();
387+
}
388+
389+
template Impl(size_t i = 0)
390+
{
391+
static if (i == PT.length)
392+
alias Impl = AliasSeq!();
393+
else
394+
alias Impl = AliasSeq!(Get!i, Impl!(i+1));
395+
}
396+
397+
alias ParameterIdentifierTuple = Impl!();
398+
}
399+
400+
///
401+
@safe unittest
402+
{
403+
int foo(int num, string name, int);
404+
static assert([ParameterIdentifierTuple!foo] == ["num", "name", ""]);
405+
}
406+
407+
// std.traits.ParameterDefaults
408+
/**
409+
Get, as a tuple, the default value of the parameters to a function symbol.
410+
If a parameter doesn't have the default value, `void` is returned instead.
411+
*/
412+
template ParameterDefaults(func...)
413+
if (func.length == 1/* && isCallable!func*/)
414+
{
415+
alias param_names = ParameterIdentifierTuple!func;
416+
static if (is(FunctionTypeOf!(func[0]) PT == __parameters))
417+
{
418+
template Get(size_t i)
419+
{
420+
// `PT[i .. i+1]` declares a parameter with an arbitrary name.
421+
// To avoid a name clash, generate local names that are distinct
422+
// from the parameter name, and mix them in.
423+
enum name = param_names[i];
424+
enum args = "args" ~ (name == "args" ? "_" : "");
425+
enum val = "val" ~ (name == "val" ? "_" : "");
426+
enum ptr = "ptr" ~ (name == "ptr" ? "_" : "");
427+
mixin("
428+
// workaround scope escape check, see
429+
// https://issues.dlang.org/show_bug.cgi?id=16582
430+
// should use return scope once available
431+
enum get = (PT[i .. i+1] " ~ args ~ ") @trusted
432+
{
433+
// If the parameter is lazy, we force it to be evaluated
434+
// like this.
435+
auto " ~ val ~ " = " ~ args ~ "[0];
436+
auto " ~ ptr ~ " = &" ~ val ~ ";
437+
// workaround Bugzilla 16582
438+
return *" ~ ptr ~ ";
439+
};
440+
");
441+
static if (is(typeof(get())))
442+
enum Get = get();
443+
else
444+
alias Get = void;
445+
// If default arg doesn't exist, returns void instead.
446+
}
447+
}
448+
else
449+
{
450+
static assert(0, func[0].stringof ~ "is not a function");
451+
452+
// Define dummy entities to avoid pointless errors
453+
template Get(size_t i) { enum Get = ""; }
454+
alias PT = AliasSeq!();
455+
}
456+
457+
template Impl(size_t i = 0)
458+
{
459+
static if (i == PT.length)
460+
alias Impl = AliasSeq!();
461+
else
462+
alias Impl = AliasSeq!(Get!i, Impl!(i+1));
463+
}
464+
465+
alias ParameterDefaults = Impl!();
466+
}
467+
468+
///
469+
@safe unittest
470+
{
471+
int foo(int num, string name = "hello", int[] = [1,2,3], lazy int x = 0);
472+
static assert(is(ParameterDefaults!foo[0] == void));
473+
static assert( ParameterDefaults!foo[1] == "hello");
474+
static assert( ParameterDefaults!foo[2] == [1,2,3]);
475+
static assert( ParameterDefaults!foo[3] == 0);
476+
}
477+
266478
// std.meta.Filter
267479
template Filter(alias pred, TList...)
268480
{

0 commit comments

Comments
 (0)