Skip to content

Commit

Permalink
Fix #184: Support for DIP1000 (#296)
Browse files Browse the repository at this point in the history
* Emitter: Make EmitterFunction use a scope parameter

Because we're giving it the address of this,
and DIP1000 isn't happy about this.

* Emitter: Do not use `with` statement

Besides lowering readability, it seems that the lowering sometimes
conflict with `-preview=dip1000` and triggers a false positive,
as the compiler sees the address of a `scope` struct being taken.

* Use a vendored version of std.sumtype

Since we had to fix it upstream for things to work, we either neeed
to wait for v2.101.0 (not yet released as of July 13th) to be the latest
supported version, which should take 10 releases, or go the vendoring route.

* Make D-YAML compile with `-preview=dip1000`

It's time to join the cool kids.
  • Loading branch information
Geod24 authored Jul 13, 2022
1 parent 339d0c6 commit 5c791b9
Show file tree
Hide file tree
Showing 8 changed files with 2,717 additions and 50 deletions.
1 change: 1 addition & 0 deletions .github/workflows/d.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ jobs:
compiler: ${{ matrix.dc }}
- name: 'Test'
run: |
dub test -c unittest-dip1000
dub test --build=unittest-cov
bash <(curl -s https://codecov.io/bash)
examples:
Expand Down
11 changes: 11 additions & 0 deletions dub.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@
},
"homepage": "https://github.com/dlang-community/D-YAML",
"copyright": "Copyright © 2011-2018, Ferdinand Majerech",
"configurations": [
{ "name": "library" },
{ "name": "unittest" },
{
"name": "unittest-dip1000",
"dflags": [ "-preview=dip1000" ],
"dependencies": {
"tinyendian": { "version": "*", "dflags" : [ "-preview=dip1000" ] },
}
}
],
"subPackages": [
"examples/constructor",
"examples/getting_started",
Expand Down
14 changes: 7 additions & 7 deletions source/dyaml/emitter.d
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ struct Emitter(Range, CharType) if (isOutputRange!(Range, CharType))
Range stream_;

/// Type used for upcoming emitter steps
alias EmitterFunction = void function(typeof(this)*) @safe;
alias EmitterFunction = void function(scope typeof(this)*) @safe;

///Stack of states.
Appender!(EmitterFunction[]) states_;
Expand Down Expand Up @@ -732,14 +732,14 @@ struct Emitter(Range, CharType) if (isOutputRange!(Range, CharType))
//}
auto writer = ScalarWriter!(Range, CharType)(&this, analysis_.scalar,
context_ != Context.mappingSimpleKey);
with(writer) final switch(style_)
final switch(style_)
{
case ScalarStyle.invalid: assert(false);
case ScalarStyle.doubleQuoted: writeDoubleQuoted(); break;
case ScalarStyle.singleQuoted: writeSingleQuoted(); break;
case ScalarStyle.folded: writeFolded(); break;
case ScalarStyle.literal: writeLiteral(); break;
case ScalarStyle.plain: writePlain(); break;
case ScalarStyle.doubleQuoted: writer.writeDoubleQuoted(); break;
case ScalarStyle.singleQuoted: writer.writeSingleQuoted(); break;
case ScalarStyle.folded: writer.writeFolded(); break;
case ScalarStyle.literal: writer.writeLiteral(); break;
case ScalarStyle.plain: writer.writePlain(); break;
}
analysis_.flags.isNull = true;
style_ = ScalarStyle.invalid;
Expand Down
17 changes: 12 additions & 5 deletions source/dyaml/exception.d
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,14 @@ struct Mark
return column_;
}

/// Duplicate a mark
Mark dup () const scope @safe pure nothrow
{
return Mark(this.name_.idup, this.line_, this.column_);
}

/// Get a string representation of the mark.
string toString() @safe pure nothrow const
string toString() const scope @safe pure nothrow
{
// Line/column numbers start at zero internally, make them start at 1.
static string clamped(ushort v) @safe pure nothrow
Expand All @@ -84,23 +90,24 @@ abstract class MarkedYAMLException : YAMLException
Mark mark;

// Construct a MarkedYAMLException with specified context and problem.
this(string context, const Mark contextMark, string problem, const Mark problemMark,
this(string context, scope const Mark contextMark,
string problem, scope const Mark problemMark,
string file = __FILE__, size_t line = __LINE__) @safe pure nothrow
{
const msg = context ~ '\n' ~
(contextMark != problemMark ? contextMark.toString() ~ '\n' : "") ~
problem ~ '\n' ~ problemMark.toString() ~ '\n';
super(msg, file, line);
mark = problemMark;
mark = problemMark.dup;
}

// Construct a MarkedYAMLException with specified problem.
this(string problem, const Mark problemMark,
this(string problem, scope const Mark problemMark,
string file = __FILE__, size_t line = __LINE__)
@safe pure nothrow
{
super(problem ~ '\n' ~ problemMark.toString(), file, line);
mark = problemMark;
mark = problemMark.dup;
}

/// Construct a MarkedYAMLException from a struct storing constructor parameters.
Expand Down
85 changes: 50 additions & 35 deletions source/dyaml/node.d
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ import std.math;
import std.meta : AliasSeq;
import std.range;
import std.string;
import std.sumtype;
import std.traits;
import std.typecons;

// FIXME: Switch back to upstream's when v2.101 is the oldest
// supported version (recommended: after v2.111 release).
import dyaml.stdsumtype;

import dyaml.event;
import dyaml.exception;
import dyaml.style;
Expand All @@ -35,7 +38,8 @@ class NodeException : MarkedYAMLException
//
// Params: msg = Error message.
// start = Start position of the node.
this(string msg, Mark start, string file = __FILE__, size_t line = __LINE__)
this(string msg, const scope Mark start,
string file = __FILE__, size_t line = __LINE__)
@safe pure nothrow
{
super(msg, start, file, line);
Expand Down Expand Up @@ -83,13 +87,13 @@ private struct Pair
}

/// Equality test with another Pair.
bool opEquals(const ref Pair rhs) const @safe
bool opEquals(const ref Pair rhs) const scope @safe
{
return key == rhs.key && value == rhs.value;
}

// Comparison with another Pair.
int opCmp(ref const(Pair) rhs) const @safe
int opCmp(const scope ref Pair rhs) const scope @safe
{
const keyCmp = key.opCmp(rhs.key);
return keyCmp != 0 ? keyCmp
Expand All @@ -100,7 +104,10 @@ private struct Pair
public void toString (scope void delegate(scope const(char)[]) @safe sink)
const scope @safe
{
formattedWrite(sink, "%s: %s", this.key, this.value);
// formattedWrite does not accept `scope` parameters
() @trusted {
formattedWrite(sink, "%s: %s", this.key, this.value);
}();
}
}

Expand Down Expand Up @@ -403,19 +410,19 @@ struct Node
}

/// Is this node valid (initialized)?
@property bool isValid() const @safe pure nothrow
@property bool isValid() const scope @safe pure nothrow @nogc
{
return value_.match!((const YAMLInvalid _) => false, _ => true);
}

/// Return tag of the node.
@property string tag() const @safe nothrow
@property string tag() const return scope @safe pure nothrow @nogc
{
return tag_;
}

/// Return the start position of the node.
@property Mark startMark() const @safe pure nothrow
@property Mark startMark() const return scope @safe pure nothrow @nogc
{
return startMark_;
}
Expand All @@ -434,11 +441,11 @@ struct Node
*
* Returns: true if equal, false otherwise.
*/
bool opEquals(const Node rhs) const @safe
bool opEquals(const scope Node rhs) const scope @safe
{
return opCmp(rhs) == 0;
}
bool opEquals(T)(const auto ref T rhs) const
bool opEquals(T)(const scope auto ref T rhs) const @safe
{
try
{
Expand Down Expand Up @@ -509,7 +516,7 @@ struct Node
* Throws: NodeException if unable to convert to specified type, or if
* the value is out of range of requested type.
*/
inout(T) get(T, Flag!"stringConversion" stringConversion = Yes.stringConversion)() inout
inout(T) get(T, Flag!"stringConversion" stringConversion = Yes.stringConversion)() inout @safe return scope
{
static assert (allowed!(Unqual!T) ||
hasNodeConstructor!(inout(Unqual!T)) ||
Expand Down Expand Up @@ -564,7 +571,7 @@ struct Node
// Try to convert to string.
try
{
return coerceValue!T();
return coerceValue!T().dup;
}
catch (MatchException e)
{
Expand Down Expand Up @@ -661,9 +668,11 @@ struct Node
this.z = z;
}

this(Node node) @safe
this(scope const Node node) @safe
{
auto parts = node.as!string().split(":");
// `std.array.split` is not marked as taking a `scope` range,
// but we don't escape a reference.
scope parts = () @trusted { return node.as!string().split(":"); }();
x = parts[0].to!int;
y = parts[1].to!int;
z = parts[2].to!int;
Expand Down Expand Up @@ -785,9 +794,11 @@ struct Node
this.z = z;
}

this(Node node) @safe inout
this(scope const Node node) @safe inout
{
auto parts = node.as!string().split(":");
// `std.array.split` is not marked as taking a `scope` range,
// but we don't escape a reference.
scope parts = () @trusted { return node.as!string().split(":"); }();
x = parts[0].to!int;
y = parts[1].to!int;
z = parts[2].to!int;
Expand Down Expand Up @@ -936,7 +947,7 @@ struct Node
* non-integral index is used with a sequence or the node is
* not a collection.
*/
ref inout(Node) opIndex(T)(T index) inout @safe
ref inout(Node) opIndex(T)(T index) inout return scope @safe
{
final switch (nodeID)
{
Expand Down Expand Up @@ -1377,7 +1388,7 @@ struct Node

string[int] test;
foreach (pair; n.mapping)
test[pair.key.as!int] = pair.value.as!string;
test[pair.key.as!int] = pair.value.as!string.idup;

assert(test[1] == "foo");
assert(test[2] == "bar");
Expand Down Expand Up @@ -1680,7 +1691,7 @@ struct Node
Pair(k3, Node(cast(real)1.0)),
Pair(k4, Node("yarly"))]);

foreach(string key, Node value; nmap2)
foreach(scope string key, scope Node value; nmap2)
{
switch(key)
{
Expand Down Expand Up @@ -1972,7 +1983,7 @@ struct Node
}

/// Compare with another _node.
int opCmp(const ref Node rhs) const @safe
int opCmp(const scope ref Node rhs) const scope @safe
{
const bool hasNullTag = this.tag_ is null;
// Only one of them is null: we can order nodes
Expand All @@ -1998,7 +2009,7 @@ struct Node
if (const typeCmp = cmp(type, rhs.type))
return typeCmp;

static int compareCollections(T)(const ref Node lhs, const ref Node rhs)
static int compareCollections(T)(const scope ref Node lhs, const scope ref Node rhs)
{
const c1 = lhs.getValue!T;
const c2 = rhs.getValue!T;
Expand Down Expand Up @@ -2145,7 +2156,7 @@ struct Node
// Params: level = Level of the node in the tree.
//
// Returns: String representing the node tree.
@property string debugString(uint level = 0) const @safe
@property string debugString(uint level = 0) const scope @safe
{
string indent;
foreach(i; 0 .. level){indent ~= " ";}
Expand Down Expand Up @@ -2396,7 +2407,8 @@ struct Node

// Get index of pair with key (or value, if key is false) matching index.
// Cannot be inferred @safe due to https://issues.dlang.org/show_bug.cgi?id=16528
sizediff_t findPair(T, Flag!"key" key = Yes.key)(const ref T index) const @safe
sizediff_t findPair(T, Flag!"key" key = Yes.key)(const scope ref T index)
const scope @safe
{
const pairs = getValue!(Pair[])();
const(Node)* node;
Expand All @@ -2420,7 +2432,7 @@ struct Node
}

// Check if index is integral and in range.
void checkSequenceIndex(T)(T index) const
void checkSequenceIndex(T)(T index) const scope @safe
{
assert(nodeID == NodeID.sequence,
"checkSequenceIndex() called on a " ~ nodeTypeString ~ " node");
Expand All @@ -2437,13 +2449,13 @@ struct Node
}
}
// Safe wrapper for getting a value out of the variant.
inout(T) getValue(T)() @safe inout
inout(T) getValue(T)() @safe return scope inout
{
alias RType = typeof(return);
return value_.tryMatch!((RType r) => r);
}
// Safe wrapper for coercing a value out of the variant.
inout(T) coerceValue(T)() @safe inout
inout(T) coerceValue(T)() @trusted scope return inout
{
alias RType = typeof(return);
static if (is(typeof({ RType rt = T.init; T t = RType.init; })))
Expand All @@ -2463,15 +2475,15 @@ struct Node
// }
// Doesn't compile with DMD v2.100.0
return this.value_.tryMatch!(
(inout bool v ) => v.to!TType,
(inout long v) => v.to!TType,
(inout bool v) @safe => v.to!TType,
(inout long v) @safe => v.to!TType,
(inout Node[] v) @trusted => v.to!TType,
(inout ubyte[] v) => v.to!TType,
(inout string v) => v.to!TType,
(inout ubyte[] v) @safe => v.to!TType,
(inout string v) @safe => v.to!TType,
(inout Node.Pair[] v) @trusted => v.to!TType,
(inout SysTime v) => v.to!TType,
(inout real v) => v.to!TType,
(inout YAMLNull v) => null.to!TType,
(inout SysTime v) @trusted => v.to!TType,
(inout real v) @safe => v.to!TType,
(inout YAMLNull v) @safe => null.to!TType,
);
}
// Safe wrapper for setting a value for the variant.
Expand Down Expand Up @@ -2521,7 +2533,10 @@ package:
// toMerge = Pairs to merge.
void merge(ref Appender!(Node.Pair[]) pairs, Node.Pair[] toMerge) @safe
{
bool eq(ref Node.Pair a, ref Node.Pair b){return a.key == b.key;}
bool eq(ref Node.Pair a, ref Node.Pair b) @safe
{
return a.key == b.key;
}

foreach(ref pair; toMerge) if(!canFind!eq(pairs.data, pair))
{
Expand Down Expand Up @@ -2568,7 +2583,7 @@ enum castableToNode(T) = (is(T == struct) || is(T == class)) && is(typeof(T.opCa
{
foreach(value; node["bars"].sequence)
{
bars ~= value.as!string;
bars ~= value.as!string.idup;
}
}
}
Expand Down
10 changes: 8 additions & 2 deletions source/dyaml/resolver.d
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ struct Resolver
*
* Returns: Resolved tag.
*/
string resolve(const NodeID kind, const string tag, const string value,
string resolve(const NodeID kind, const string tag, scope string value,
const bool implicit) @safe
{
import std.array : empty, front;
Expand All @@ -189,7 +189,13 @@ struct Resolver
//If regexp matches, return tag.
foreach(resolver; resolvers)
{
if(!(match(value, resolver[1]).empty))
// source/dyaml/resolver.d(192,35): Error: scope variable `__tmpfordtorXXX`
// assigned to non-scope parameter `this` calling
// `std.regex.RegexMatch!string.RegexMatch.~this`
bool isEmpty = () @trusted {
return match(value, resolver[1]).empty;
}();
if(!isEmpty)
{
return resolver[0];
}
Expand Down
Loading

0 comments on commit 5c791b9

Please sign in to comment.