mirror of
https://github.com/dlang/dmd.git
synced 2025-04-28 14:10:11 +03:00
Allow default arguments in the middle (#14879)
This commit is contained in:
parent
eb57825c7c
commit
1d19f710b2
5 changed files with 38 additions and 14 deletions
|
@ -4146,9 +4146,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||||
else if (dim == 0 && tf.parameterList.varargs != VarArg.none) // allow varargs only ctor
|
else if (dim == 0 && tf.parameterList.varargs != VarArg.none) // allow varargs only ctor
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
else if (dim && tf.parameterList[0].defaultArg)
|
else if (dim && !tf.parameterList.hasArgsWithoutDefault)
|
||||||
{
|
{
|
||||||
// if the first parameter has a default argument, then the rest does as well
|
|
||||||
if (ctd.storage_class & STC.disable)
|
if (ctd.storage_class & STC.disable)
|
||||||
{
|
{
|
||||||
ctd.error("is marked `@disable`, so it cannot have default "~
|
ctd.error("is marked `@disable`, so it cannot have default "~
|
||||||
|
|
|
@ -4683,7 +4683,7 @@ extern (C++) final class TypeFunction : TypeNext
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://issues.dlang.org/show_bug.cgi?id=22997
|
// https://issues.dlang.org/show_bug.cgi?id=22997
|
||||||
if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList[argumentList.length].defaultArg)
|
if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs)
|
||||||
{
|
{
|
||||||
OutBuffer buf;
|
OutBuffer buf;
|
||||||
buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length);
|
buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length);
|
||||||
|
@ -6631,6 +6631,28 @@ extern (C++) struct ParameterList
|
||||||
// Ensure no remaining parameters in `other`
|
// Ensure no remaining parameters in `other`
|
||||||
return !diff && other[idx] is null;
|
return !diff && other[idx] is null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns: `true` if any parameter has a default argument
|
||||||
|
extern(D) bool hasDefaultArgs()
|
||||||
|
{
|
||||||
|
foreach (oidx, oparam, eidx, eparam; this)
|
||||||
|
{
|
||||||
|
if (eparam.defaultArg)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns: `true` if any parameter doesn't have a default argument
|
||||||
|
extern(D) bool hasArgsWithoutDefault()
|
||||||
|
{
|
||||||
|
foreach (oidx, oparam, eidx, eparam; this)
|
||||||
|
{
|
||||||
|
if (!eparam.defaultArg)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1333,7 +1333,6 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
||||||
// extended index), as we need to run semantic when `oidx` changes.
|
// extended index), as we need to run semantic when `oidx` changes.
|
||||||
size_t tupleOrigIdx = size_t.max;
|
size_t tupleOrigIdx = size_t.max;
|
||||||
size_t tupleExtIdx = size_t.max;
|
size_t tupleExtIdx = size_t.max;
|
||||||
bool hasDefault;
|
|
||||||
foreach (oidx, oparam, eidx, eparam; tf.parameterList)
|
foreach (oidx, oparam, eidx, eparam; tf.parameterList)
|
||||||
{
|
{
|
||||||
// oparam (original param) will always have the default arg
|
// oparam (original param) will always have the default arg
|
||||||
|
@ -1342,7 +1341,6 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
||||||
// position to get the offset in it later on.
|
// position to get the offset in it later on.
|
||||||
if (oparam.defaultArg)
|
if (oparam.defaultArg)
|
||||||
{
|
{
|
||||||
hasDefault = true;
|
|
||||||
// Get the obvious case out of the way
|
// Get the obvious case out of the way
|
||||||
if (oparam is eparam)
|
if (oparam is eparam)
|
||||||
errors |= !defaultArgSemantic(eparam, argsc);
|
errors |= !defaultArgSemantic(eparam, argsc);
|
||||||
|
@ -1369,11 +1367,6 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
||||||
eparam.defaultArg = (*te.exps)[eidx - tupleExtIdx];
|
eparam.defaultArg = (*te.exps)[eidx - tupleExtIdx];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (hasDefault)
|
|
||||||
{
|
|
||||||
.error(loc, "default argument expected for `%s`", oparam.toChars());
|
|
||||||
errors = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to know the default argument to resolve `auto ref`,
|
// We need to know the default argument to resolve `auto ref`,
|
||||||
// hence why this has to take place as the very last step.
|
// hence why this has to take place as the very last step.
|
||||||
|
|
|
@ -12,6 +12,18 @@ static assert(fun(y: "y", "z", x: "x") == "xyzW");
|
||||||
static assert(fun( "x", "y", w: "w") == "xyZw");
|
static assert(fun( "x", "y", w: "w") == "xyZw");
|
||||||
static assert(fun(x: "x", "y", z: "z") == "xyzW");
|
static assert(fun(x: "x", "y", z: "z") == "xyzW");
|
||||||
|
|
||||||
|
// Default arguments need not all be at the end anymore
|
||||||
|
string fun2(string x = "x", string y, string z = "z")
|
||||||
|
{
|
||||||
|
return x ~ y ~ z;
|
||||||
|
}
|
||||||
|
|
||||||
|
static assert(fun2(y: "y") == "xyz");
|
||||||
|
|
||||||
|
// The assumption that first parameter having a default implies all parameters have a default is no longer valid,
|
||||||
|
// so this struct constructor shouldn't be mistaken for a default constructor.
|
||||||
|
struct SD { this(int x = 1, int y) { } }
|
||||||
|
|
||||||
// UFCS
|
// UFCS
|
||||||
static assert("x".fun("y", w: "w") == "xyZw");
|
static assert("x".fun("y", w: "w") == "xyZw");
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ fail_compilation/diag3438.d(20): Error: constructor `diag3438.F5.this` is marked
|
||||||
fail_compilation/diag3438.d(20): Use `@disable this();` if you want to disable default initialization.
|
fail_compilation/diag3438.d(20): Use `@disable this();` if you want to disable default initialization.
|
||||||
fail_compilation/diag3438.d(21): Error: constructor `diag3438.F6.this` is marked `@disable`, so it cannot have default arguments for all parameters.
|
fail_compilation/diag3438.d(21): Error: constructor `diag3438.F6.this` is marked `@disable`, so it cannot have default arguments for all parameters.
|
||||||
fail_compilation/diag3438.d(21): Use `@disable this();` if you want to disable default initialization.
|
fail_compilation/diag3438.d(21): Use `@disable this();` if you want to disable default initialization.
|
||||||
fail_compilation/diag3438.d(24): Error: default argument expected for `y`
|
fail_compilation/diag3438.d(22): Error: constructor `diag3438.F7.this` all parameters have default arguments, but structs cannot have default constructors.
|
||||||
---
|
---
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -19,6 +19,4 @@ struct F3 { this(...) { } } // ok
|
||||||
struct F4 { this(int[] x...) { } } // ok
|
struct F4 { this(int[] x...) { } } // ok
|
||||||
struct F5 { @disable this(int x = 1); }
|
struct F5 { @disable this(int x = 1); }
|
||||||
struct F6 { @disable this(int x = 1) { } }
|
struct F6 { @disable this(int x = 1) { } }
|
||||||
|
struct F7 { this(int x = 1, int y = 2) { } }
|
||||||
// Make sure the deprecation doesn't interfere w/ the check for default arguments
|
|
||||||
struct S { this(int x = 1, int y) { } }
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue