Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ccd0dd9

Browse files
committedOct 7, 2020
Tighten covariance rules wrt. in params with -preview=in
Require the `in` storage class on both sides, just like ref/out/lazy. Doing so makes sure the code compiles with all compilers and for all targets, independent from whether `in` means `const scope` or `const scope ref`.
1 parent f518a22 commit ccd0dd9

File tree

6 files changed

+32
-58
lines changed

6 files changed

+32
-58
lines changed
 

‎src/dmd/mtype.d

+4-4
Original file line numberDiff line numberDiff line change
@@ -6900,8 +6900,8 @@ extern (C++) final class Parameter : ASTNode
69006900
* Params:
69016901
* returnByRef = true if the function returns by ref
69026902
* p = Parameter to compare with
6903-
* previewIn = Whether `-previewIn` is being used, and thus if
6904-
* `in` means `scope`.
6903+
* previewIn = Whether `-preview=in` is being used, and thus if
6904+
* `in` means `scope [ref]`.
69056905
*
69066906
* Returns:
69076907
* true = `this` can be used in place of `p`
@@ -6921,8 +6921,8 @@ extern (C++) final class Parameter : ASTNode
69216921
otherSTC |= STC.scope_;
69226922
}
69236923

6924-
enum stc = STC.ref_ | STC.out_ | STC.lazy_;
6925-
if ((thisSTC & stc) != (otherSTC & stc))
6924+
const mask = STC.ref_ | STC.out_ | STC.lazy_ | (previewIn ? STC.in_ : 0);
6925+
if ((thisSTC & mask) != (otherSTC & mask))
69266926
return false;
69276927
return isCovariantScope(returnByRef, thisSTC, otherSTC);
69286928
}

‎src/dmd/mtype.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ class Parameter : public ASTNode
558558
static size_t dim(Parameters *parameters);
559559
static Parameter *getNth(Parameters *parameters, d_size_t nth);
560560
const char *toChars() const;
561-
bool isCovariant(bool returnByRef, const Parameter *p) const;
561+
bool isCovariant(bool returnByRef, const Parameter *p, bool previewIn) const;
562562
};
563563

564564
struct ParameterList

‎test/compilable/previewin.d

+5-6
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,13 @@ struct FooBar
2424
string toString() const
2525
{
2626
string result;
27+
// Type is const
28+
this.toString((in char[] buf) {
29+
static assert(is(typeof(buf) == const(char[])));
30+
result ~= buf;
31+
});
2732
// Type inference works
28-
this.toString((buf) { result ~= buf; });
29-
// Specifying the STC too
3033
this.toString((in buf) { result ~= buf; });
31-
// Some covariance
32-
this.toString((const scope buf) { result ~= buf; });
33-
this.toString((scope const(char)[] buf) { result ~= buf; });
34-
this.toString((scope const(char[]) buf) { result ~= buf; });
3534
return result;
3635
}
3736

‎test/fail_compilation/diagin.d

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
PERMUTE_ARGS: -preview=in
33
TEST_OUTPUT:
44
---
5-
fail_compilation/diagin.d(14): Error: function `diagin.foo(in string)` is not callable using argument types `()`
6-
fail_compilation/diagin.d(14): missing argument for parameter #1: `in string`
5+
fail_compilation/diagin.d(14): Error: function `diagin.foo(in int)` is not callable using argument types `()`
6+
fail_compilation/diagin.d(14): missing argument for parameter #1: `in int`
77
fail_compilation/diagin.d(16): Error: template `diagin.foo1` cannot deduce function from argument types `!()(bool[])`, candidates are:
88
fail_compilation/diagin.d(20): `foo1(T)(in T v, string)`
99
---
@@ -16,10 +16,10 @@ void main ()
1616
foo1(lvalue);
1717
}
1818

19-
void foo(in string) {}
19+
void foo(in int) {}
2020
void foo1(T)(in T v, string) {}
2121

2222
// Ensure that `in` has a unique mangling
23-
static assert(foo.mangleof == `_D6diagin3fooFIAyaZv`);
23+
static assert(foo.mangleof == `_D6diagin3fooFIiZv`);
2424
static assert(foo1!int.mangleof == `_D6diagin__T4foo1TiZQiFNaNbNiNfIiAyaZv`);
2525
static assert(foo1!char.mangleof == `_D6diagin__T4foo1TaZQiFNaNbNiNfIaAyaZv`);

‎test/fail_compilation/previewin.d

+17-43
Original file line numberDiff line numberDiff line change
@@ -2,59 +2,33 @@
22
REQUIRED_ARGS: -preview=in -preview=dip1000
33
TEST_OUTPUT:
44
---
5-
fail_compilation/previewin.d(3): Error: function `previewin.func1(void function(ulong[8]) dg)` is not callable using argument types `(void function(in ulong[8]))`
6-
fail_compilation/previewin.d(3): cannot pass argument `& func_byRef` of type `void function(in ulong[8])` to parameter `void function(ulong[8]) dg`
7-
fail_compilation/previewin.d(4): Error: function `previewin.func2(void function(ref ulong[8]) dg)` is not callable using argument types `(void function(in ulong[8]))`
8-
fail_compilation/previewin.d(4): cannot pass argument `& func_byRef` of type `void function(in ulong[8])` to parameter `void function(ref ulong[8]) dg`
9-
fail_compilation/previewin.d(7): Error: function `previewin.func4(void function(ref uint) dg)` is not callable using argument types `(void function(in uint))`
10-
fail_compilation/previewin.d(7): cannot pass argument `& func_byValue` of type `void function(in uint)` to parameter `void function(ref uint) dg`
11-
fail_compilation/previewin.d(41): Error: scope variable `arg` assigned to non-scope `myGlobal`
12-
fail_compilation/previewin.d(42): Error: scope variable `arg` assigned to non-scope `myGlobal`
13-
fail_compilation/previewin.d(43): Error: scope variable `arg` may not be returned
14-
fail_compilation/previewin.d(44): Error: scope variable `arg` assigned to `escape` with longer lifetime
15-
fail_compilation/previewin.d(48): Error: returning `arg` escapes a reference to parameter `arg`
16-
fail_compilation/previewin.d(48): perhaps annotate the parameter with `return`
5+
fail_compilation/previewin.d(4): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(real x) pure nothrow @nogc @safe)`
6+
fail_compilation/previewin.d(4): cannot pass argument `__lambda1` of type `void function(real x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
7+
fail_compilation/previewin.d(5): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(const(real) x) pure nothrow @nogc @safe)`
8+
fail_compilation/previewin.d(5): cannot pass argument `__lambda2` of type `void function(const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
9+
fail_compilation/previewin.d(6): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(ref const(real) x) pure nothrow @nogc @safe)`
10+
fail_compilation/previewin.d(6): cannot pass argument `__lambda3` of type `void function(ref const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
11+
fail_compilation/previewin.d(15): Error: scope variable `arg` assigned to non-scope `myGlobal`
12+
fail_compilation/previewin.d(16): Error: scope variable `arg` assigned to non-scope `myGlobal`
13+
fail_compilation/previewin.d(17): Error: scope variable `arg` may not be returned
14+
fail_compilation/previewin.d(18): Error: scope variable `arg` assigned to `escape` with longer lifetime
15+
fail_compilation/previewin.d(22): Error: returning `arg` escapes a reference to parameter `arg`
16+
fail_compilation/previewin.d(22): perhaps annotate the parameter with `return`
1717
---
1818
*/
1919

2020
#line 1
2121
void main ()
2222
{
23-
func1(&func_byRef); // No
24-
func2(&func_byRef); // No
25-
func3(&func_byRef); // Could be Yes, but currently No
26-
27-
func4(&func_byValue); // No
28-
func5(&func_byValue); // Yes
29-
30-
func6(&func_byValue2); // Yes
31-
func7(&func_byValue3); // Yes
23+
// No covariance without explicit `in`
24+
takeFunction((real x) {});
25+
takeFunction((const scope real x) {});
26+
takeFunction((const scope ref real x) {});
3227

3328
tryEscape("Hello World"); // Yes by `tryEscape` is NG
3429
}
3530

36-
// Takes by `scope ref const`
37-
void func_byRef(in ulong[8]) {}
38-
// Takes by `scope const`
39-
void func_byValue(in uint) {}
40-
41-
// Error: `ulong[8]` is passed by `ref`
42-
void func1(void function(scope ulong[8]) dg) {}
43-
// Error: Missing `scope` on a `ref`
44-
void func2(void function(ref ulong[8]) dg) {}
45-
// Works: `scope ref`
46-
void func3(void function(scope const ref ulong[8]) dg) {}
47-
48-
// Error: `uint` is passed by value
49-
void func4(void function(ref uint) dg) {}
50-
// Works: By value `scope const`
51-
void func5(void function(scope const uint) dg) {}
52-
53-
// This works for arrays:
54-
void func_byValue2(in char[]) {}
55-
void func6(void function(char[]) dg) {}
56-
void func_byValue3(scope const(char)[]) {}
57-
void func7(void function(in char[]) dg) {}
31+
void takeFunction(void function(in real) f);
5832

5933
// Make sure things cannot be escaped (`scope` is applied)
6034
const(char)[] myGlobal;

‎test/runnable/previewin.d

+1
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ void testin4(in RefT[4] p) { static assert(__traits(isRef, p)); }
166166

167167
// By ref because of non-copyability
168168
void testin5(in NonCopyable noncopy) { static assert(__traits(isRef, noncopy)); }
169+
static assert(testin5.mangleof == "_D9previewin7testin5FNaNbNiNfIKSQBe11NonCopyableZv"); // incl. `ref`
169170
// By ref because of postblit
170171
void testin6(in WithPostblit withpostblit) { static assert(__traits(isRef, withpostblit)); }
171172
// By ref because of copy ctor

0 commit comments

Comments
 (0)
Please sign in to comment.