| Commit message (Collapse) | Author | Age | Files | Lines |
... | |
|\ \ \ \ \ \ \ \
| | | | | | | | |
| | | | | | | | | |
SI-8607 Fix erasure for value class inheriting from private class
|
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | | |
In the previous commit, we avoided an awkward chain of casts
by exploiting the knowledge that Scala defined classes will
by JVM accessible, and as such immune to `LinkageError`s when
used as the target of a cast.
This commit generalized this to the entire fix for SI-4283,
rather than just for derived value classes.
|
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | | |
The fix for SI-4283 added a pre-emptive cast of the qualifier of
a selection `qual.a` to avoid later casting to the owner of `a`
if that owner might be inaccessible at the call site. This fixed
a `LinkageError`.
In the enclosed test, this cast led to the following diff in the
tree shapes (with respect to a version with a public base class).
[erasure]
- new p1.C.<init>(c.$asInstanceOf[scala.this.Int]()).a();
+ new p1.C.<init>(new p1.C.<init>(c.$asInstanceOf[scala.this.Int]()).$asInstanceOf[ErasedValueType( class C, scala.this.Int)]().$asInstanceOf[scala.this.Int]()).a();
[posterasure]
- new p1.C.<init>(c).a();
+ new p1.C.<init>(new p1.C.<init>(c).$asInstanceOf[scala.this.Int]().$asInstanceOf[scala.this.Int]()) .a();
()
What we really wanted to end up with is:
new p1.C.<init>(c).$asInstanceOf[C]().a();
The stray cast leads to the crash:
error: should have been unboxed by erasure: new p1.C.<init>(c).$asInstanceOf[scala.this.Int]()
Rather than trying to fix this in erasure/posterasure, this commit
instead relies on the fact the owner of `a` cannot be Java defined
if `qual`s type is a derived value class. This follows from the
restrictions we place on value classes.
With this knowledge, we elide the cast altogether in this case.
|
|\ \ \ \ \ \ \ \ \
| |_|_|/ / / / / /
|/| | | | | | | | |
SI-8346 Rebuild invariant sets in #toSet, avoiding CCE
|
| | |/ / / / / /
| |/| | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
SI-3953 caused several types of sets' operations to trivially throw
`ClassCastException` after using inherited covariant #toSet method, by
doing an unchecked cast that is only safe for intrinsically covariant
set data structures like `HashSet`, but totally unsafe for others like
`TreeSet` or `Enumeration.ValueSet`.
This change moves the cast to the leaves of the class hierarchy where
that is safe, and incidentally undeprecates overriding Set#toSet.
|
|\ \ \ \ \ \ \ \
| | | | | | | | |
| | | | | | | | | |
SI-8475 Fix off by one in GroupedIterator when Streaming
|
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | | |
This also affected sliding and grouped since they defer to GroupedIterator
|
|\ \ \ \ \ \ \ \ \
| | | | | | | | | |
| | | | | | | | | | |
SI-8625 fix unreachability analysis for boolean expressions
|
| | | | | | | | | | |
|
|\ \ \ \ \ \ \ \ \ \
| |/ / / / / / / / /
|/| | | | | | | | | |
Compiler optimizations for Scopes, checkDoubleDefs, Namer
|
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | | |
We can copy the hash table from the parent scope, rather
than constructing it from scratch.
This takes us to:
% rm -rf /tmp/pkg; (for i in {1..50}; do for j in {1..100}; do echo "package pkg { class A_${i}_${j}___(val a: Int, val b: Int) }"; done; done) > sandbox/A1.scala && time qbin/scalac -Ybackend:GenASM -J-Xmx1G -J-XX:MaxPermSize=400M -d /tmp sandbox/A1.scala;
real 0m19.639s // head~1 was 0m35.662s
user 0m41.683s // head~1 was 0m58.275s
sys 0m1.886s
In more detail, this commit:
- Removes the unused `fingerprint` constructor parameter from
scopes. This is a remnant from a previous optimization attempt
- Leave only one constructor on Scope which creates an empty
scope
- Update the factory method, `newNestedScope`, to copy the hash
table from the parent if it exists. We can rely on the invariant
that `outer.hashTable != null || outer.size < MIN_HASH)`, so we
don't need `if (size >= MIN_HASH) createHash()` anymore. This
used to be needed in `Scope#<init>`, which accepted an aribitrary
`initElems: ScopeEntry`.
- Update subclasses and factories of `Scope` in runtime reflection
to accomodate the change. Pleasingly, we could actually remove
the override for `newNestedScope`.
- Unit tests the functionality I'm touching
|
| | |/ / / / / / /
| |/| | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | | |
Where N is the number of members of the enclosing package.
Double definition errors for top level classes/objects are issued
elsewhere, as demonstrated by the enclosed test. So we can
omit the call to `checkNoDoubleDefs` in this content.
We can't omit the call to `addSynthetics` for package
class owners (case- and value-class synthetic companions
are added here), but we can make the process cheaper by
moving the expensive-but-usually-true call to `shouldAdd`.
Here's an example of the improvement.
% rm -rf /tmp/pkg; (for i in {1..50}; do for j in {1..100}; do echo "package pkg { class A_${i}_${j}___(val a: Int, val b: Int) }"; done; done) > sandbox/A1.scala && time scalac-hash v2.11.0 -Ybackend:GenASM -J-Xmx1G -J-XX:MaxPermSize=400M -d /tmp sandbox/A1.scala;
real 0m49.762s
user 1m12.376s
sys 0m2.371s
% rm -rf /tmp/pkg; (for i in {1..50}; do for j in {1..100}; do echo "package pkg { class A_${i}_${j}___(val a: Int, val b: Int) }"; done; done) > sandbox/A1.scala && time qbin/scalac -Ybackend:GenASM -J-Xmx1G -J-XX:MaxPermSize=400M -d /tmp sandbox/A1.scala;
real 0m35.662s
user 0m58.275s
sys 0m2.355s
We've still got another source of pathological performance in
creating nested scopes that I'll fix in the next commit.
|
|/ / / / / / / /
| | | | | | | |
| | | | | | | |
| | | | | | | | |
The tree to create a `NoManifest` was unpositioned.
|
| |/ / / / / /
|/| | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | | |
This commit is a squashed version of all commits in PR #3747.
For future upgrades, consult the README and check the commits in
https://github.com/scala/scala/pull/3747/commits
There's one bug in ASM 5.0.2 that breaks scalac:
http://forge.ow2.org/tracker/?func=detail&aid=317200&group_id=23&atid=100023
This bug is fixed in ASM trunk, the patch has been merged into this
commit. A future upgrade of ASM should contain the fix.
|
|\ \ \ \ \ \ \
| | | | | | | |
| | | | | | | | |
SI-8507 Avoid lazy val in StringContext
|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
This mild refactor eliminates the lazy val StringBuilder
and arguably makes the code easier to read.
There is a small unit test but no benchmark to prove
anything useful about performance. The ticket notes
contention due to lazy implementation.
|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
This test fails under 2.11.0, and works now that DCE treats
static loads as useful instructions.
|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
As part of my sweep through the side-effecting byte code instructions.
|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
Otherwise we lose the side effect of a `NegativeArraySizeException`.
|
| | | | | | | | |
|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
It can NPE or trigger static class initilization, we can't elimiate
it without changing semantics.
To make sure we don't thwart closure elimination, I've allowed DCE
to eliminate a non-static LOAD_FIELD of a member of a closure class.
It would be more general to track nullity of the reciever (e.g, `this`
or `new Foo` cannot be null), but that would require more
infrastructure in this phase.
I've added a test for closure inlining based on a a suggestion by
@dragos. This actually passes if we remove the (LOAD_FIELD, DROP)
peephole optimization for `closelim` altogether. But I chose to
adapt that optimization (only allow it for non-static, closure
fields), rather then remove it alogether, in the interests of
treading lightly.
|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
`{i, l}div` and `{i, l}rem` throw an `ArithmeticException` if the
divisor is 0.
`arraylength` throws a `NullPointerException` on a null reference.
JVM Spec:
> The only integer operations that can throw an exception are the
> integer divide instructions (idiv and ldiv) and the integer
> remainder instructions (irem and lrem), which throw an
> ArithmeticException if the divisor is zero.
> The Java virtual machine's floating-point operators do not throw
> runtime exceptions
> If the arrayref is null, the arraylength instruction throws a
> NullPointerException.
I checked the other primitives in `ICode` to see if anything else
should be considered as live code.
Pure:
// jvm : {i, l, f, d}neg
case class Negation(kind: TypeKind) extends Primitive
// jvm : if{eq, ne, lt, ge, le, gt}, if{null, nonnull}
// if_icmp{eq, ne, lt, ge, le, gt}, if_acmp{eq,ne}
case class Test(op: TestOp, kind: TypeKind, zero: Boolean) extends Primitive
// jvm : lcmp, {f, d}cmp{l, g}
case class Comparison(op: ComparisonOp, kind: TypeKind) extends Primitive
Impure: {i, l}{div, rem}, otherwise pure
// jvm : {i, l, f, d}{add, sub, mul, div, rem}
case class Arithmetic(op: ArithmeticOp, kind: TypeKind) extends Primitive
Pure (overflow is silent, NaN.toInt is defined):
// jvm : {i, l}{and, or, xor}
case class Logical(op: LogicalOp, kind: TypeKind) extends Primitive
// jvm : {i, l}{shl, ushl, shr}
case class Shift(op: ShiftOp, kind: TypeKind) extends Primitive
// jvm : i2{l, f, d}, l2{i, f, d}, f2{i, l, d}, d2{i, l, f}, i2{b, c, s}
case class Conversion(src: TypeKind, dst: TypeKind) extends Primitive
Impure! May NPE!
// jvm : arraylength
case class ArrayLength(kind: TypeKind) extends Primitive
Pure (we know that StringBuilder.{<init>, append, toString} are pure
and `append` is null safe.)
// jvm : It should call the appropiate 'append' method on StringBuffer
case class StringConcat(el: TypeKind) extends Primitive
// jvm: it should create a new StringBuffer
case object StartConcat extends Primitive
// jvm: convert StringBuffer to a String
case object EndConcat extends Primitive
|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
This reverts commit ee611cd76c29fedd416162e482c7ab3f15b831ca.
|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
This reverts commit 0b432f9cd22b6e9770852e5b331a15f0534a312c.
|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
This reverts commit 99b4ef8d8472f154d73160f5fe72daf081abb24e.
|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
This reverts commit 70b912a87433c9589af33e4f8b33dca39abb66e5.
|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
This reverts commit dcade51d751b389fb5137040f7e1006b4bc633c6.
|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
As part of my sweep through the side-effecting byte code instructions.
|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
Otherwise we lose the side effect of a `NegativeArraySizeException`.
|
| | | | | | | | |
|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
It can NPE or trigger static class initilization, we can't elimiate
it without changing semantics.
|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
`{i, l}div` and `{i, l}rem` throw an `ArithmeticException` if the
divisor is 0.
`arraylength` throws a `NullPointerException` on a null reference.
JVM Spec:
> The only integer operations that can throw an exception are the
> integer divide instructions (idiv and ldiv) and the integer
> remainder instructions (irem and lrem), which throw an
> ArithmeticException if the divisor is zero.
> The Java virtual machine's floating-point operators do not throw
> runtime exceptions
> If the arrayref is null, the arraylength instruction throws a
> NullPointerException.
I checked the other primitives in `ICode` to see if anything else
should be considered as live code.
Pure:
// jvm : {i, l, f, d}neg
case class Negation(kind: TypeKind) extends Primitive
// jvm : if{eq, ne, lt, ge, le, gt}, if{null, nonnull}
// if_icmp{eq, ne, lt, ge, le, gt}, if_acmp{eq,ne}
case class Test(op: TestOp, kind: TypeKind, zero: Boolean) extends Primitive
// jvm : lcmp, {f, d}cmp{l, g}
case class Comparison(op: ComparisonOp, kind: TypeKind) extends Primitive
Impure: {i, l}{div, rem}, otherwise pure
// jvm : {i, l, f, d}{add, sub, mul, div, rem}
case class Arithmetic(op: ArithmeticOp, kind: TypeKind) extends Primitive
Pure (overflow is silent, NaN.toInt is defined):
// jvm : {i, l}{and, or, xor}
case class Logical(op: LogicalOp, kind: TypeKind) extends Primitive
// jvm : {i, l}{shl, ushl, shr}
case class Shift(op: ShiftOp, kind: TypeKind) extends Primitive
// jvm : i2{l, f, d}, l2{i, f, d}, f2{i, l, d}, d2{i, l, f}, i2{b, c, s}
case class Conversion(src: TypeKind, dst: TypeKind) extends Primitive
Impure! May NPE!
// jvm : arraylength
case class ArrayLength(kind: TypeKind) extends Primitive
Pure (we know that StringBuilder.{<init>, append, toString} are pure
and `append` is null safe.)
// jvm : It should call the appropiate 'append' method on StringBuffer
case class StringConcat(el: TypeKind) extends Primitive
// jvm: it should create a new StringBuffer
case object StartConcat extends Primitive
// jvm: convert StringBuffer to a String
case object EndConcat extends Primitive
|
|\ \ \ \ \ \ \ \
| |_|_|_|_|_|/ /
|/| | | | | | | |
SI-8574 Copy @SerialVersionUID, etc, to specialized subclasses
|
| | |_|/ / / /
| |/| | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | | |
The test case demonstrates that this is important for serialization
and for strictfp. (Although the latter is still pretty broken,
see SI-7954.)
Now that the synthetic subclass of `Tuple2[Int, Int]` also has the
`@deprecatedInheritance` annotation, I had to change the spot that
issues this warning to be silent after the typer phase. Otherwise,
we get two warnings in `run/t3888.scala`. This also remedies double
warnings that were incurred in `neg/t6162-inheritance`.
|
| | | | | | | |
|
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | | |
I removed the `-bcode` test since we have a build that passes
`-Ybackend:GenBCode` to all tests.
Short intro do the [`InnerClass` attribute][1]:
- A class needs one `InnerClass` attribute for each of its nested
classes
- A class needs the `InnerClass` attribute for all (nested) classes
that are mentioned in its constant pool
The attribute for a nested class `A$B$C` consists of the long name of
the outer class `A$B`, the short name of the inner class `C`, and
an access flag set describig the visibility.
The attribute seems to be used for reflection.
[1]: http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.6
|
| |/ / / / /
|/| | | | | |
|
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
As seen in a runtime reflection failure in Slick during a GenBCode
enabled run of our beloved Community Build.
|
| |_|/ / /
|/| | | |
| | | | |
| | | | |
| | | | | |
It is important to append the fresh 'N' after '$'. Otherwise, we
find out the hard way that ("foo$11" + "1") == ("foo$1" + "11").
|
|/ / / /
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Parts of this test fail if testing a library built with -Xcheckinit.
The failures seem to be in two categories:
- A component of the serialized structure does not have a
declared SerialVersionUID, meaning that the extra field
added to track initialization results in a different ID.
This manifests as a `java.io.InvalidClassException` when
deserializing the blobs of data saved in the test case.
- Spurious `UnitializedFieldErrors` when calling methods on
the object that has been serialized and then deserialized.
Until we figure out the right course of action (more @SerialVersionUID
annotations / weaker tests / ...), this commit disabled those tests.
|
|\ \ \ \
| | | | |
| | | | | |
Fix checkinit build
|
| | | | | |
|
| | | | |
| | | | |
| | | | |
| | | | | |
Fix only, refactoring in subsequent commit.
|
| | | | | |
|
| | | | | |
|
|\ \ \ \ \
| |_|_|_|/
|/| | | | |
|
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
This reverts commit 78bd175afcc89878ca1c00cce69d0517909c6ff3.
See discussion:
https://github.com/scala/scala/pull/3597#commitcomment-6270375
|
| |\ \ \ \
| | | | | |
| | | | | | |
SI-5905 Sanity check -language options
|
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
The language feature options are discovered reflectively, but it
is nice to enforce that expected options are supplied.
Short of that, the code string includes a rowdy postfix operator.
It still does enforce that at least one option was discovered.
Delete -nowarn flags file. Let's see if that was to suppress
a warning in the standard build.
|
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Underscore means all.
-x:c,b,a,_ results in value c,b,a,a,b,c,d,...
Currently, -Xprint does not present phases as a closed
set of choices; there is ad hoc checking in Global.
That would be a nice unification. (You don't know the
list of choices until after global is constructed.)
|