| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|\
| |
| | |
SI-10069 Fix code gen errors with array updates, Nothing
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Crashes in ASM or VerifyErrors used to occur when assigning
an expression of type Nothing to an element of a primitive array.
This commit adapts the RHS of the assignment to the element
type to correct this. `adapt` contains logic to insert an
`ATHROW` of the slot of type `Nothing$`, which makes everything
line up. The subsequent array stores become dead code and are
dropped later on in code gen, so the test case compiles to:
public void foo0(double[]);
Code:
0: bipush 42
2: istore_2
3: aload_1
4: iconst_0
5: aload_0
6: invokevirtual #30 // Method throwExpected:()Lscala/runtime/Nothing$;
9: athrow
I found a similar bug in the emission of primitive unboxing and
fixed that too.
|
|\ \
| | |
| | | |
SI-3772 Fix detection of term-owned companions
|
| | | |
|
| |/
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Companion detection consults the scopes of enclosing Contexts during
typechecking to avoid the cycles that would ensue if we had to look
at into the info of enclosing class symbols. For example, this used
to typecheck:
object CC { val outer = 42 }
if ("".isEmpty) {
case class CC(c: Int)
CC.outer
}
This logic was not suitably hardened to find companions in exactly
the same nesting level.
After fixing this problem, a similar problem in `Namer::inCurrentScope`
could be solved to be more selective about synthesizing a companion
object. In particular, if a manually defined companion trails after
the case class, don't create an addiotional synthetic comanpanion object.
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
VarHandles bring a host of new "polymorphic signature" methods to
the Java 9 standard library. This commit updates the way we detect
such methods to look at the absense/presense of the
`PolymorphicSignature` annotation, so as to include these (and any
future additions.)
When we see applications of such methods, we disable adaptation
of argument and return types.
Tested manually with JDK9-ea:
```
Welcome to Scala 2.12.2-20161208-165912-3de1c0c (Java HotSpot(TM) 64-Bit Server VM, Java 9-ea).
Type in expressions for evaluation. Or try :help.
scala> import java.lang.invoke._, scala.runtime.IntRef
import java.lang.invoke._
import scala.runtime.IntRef
scala> val varHandle = MethodHandles.lookup().in(classOf[IntRef]).findVarHandle(classOf[IntRef], "elem", classOf[Int]);
varHandle: java.lang.invoke.VarHandle = java.lang.invoke.VarHandleInts$FieldInstanceReadWrite@7112ce6
scala> varHandle.getAndSet(ref, 1): Int
res5: Int = 0
scala> varHandle.getAndSet(ref, 1): Int
res6: Int = 1
```
Inspecting bytecode shows the absense of box/unboxing:
```
object Test {
import java.lang.invoke._, scala.runtime.IntRef
val varHandle = MethodHandles.lookup().in(classOf[IntRef]).findVarHandle(classOf[IntRef], "elem", classOf[Int]);
def main(args: Array[String]): Unit = {
val i : Int = varHandle.getAndSet(IntRef.zero, 1)
}
}
```
```
public void main(java.lang.String[]);
Code:
0: aload_0
1: invokevirtual #28 // Method varHandle:()Ljava/lang/invoke/VarHandle;
4: invokestatic #34 // Method scala/runtime/IntRef.zero:()Lscala/runtime/IntRef;
7: iconst_1
8: invokevirtual #40 // Method java/lang/invoke/VarHandle.getAndSet:(Lscala/runtime/IntRef;I)I
11: istore_2
12: return
```
|
|\ \
| | |
| | | |
SI-10075 propagate annotations to lazy val's underlying field
|
| | |
| | |
| | |
| | |
| | |
| | | |
Based on review suggestion by retronym.
See also scala/scala-dev#213
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
This likely regressed in #5294.
Review feedback from retronym:
- Tie annotation triaging a bit closer together
durban kindly provided initial version of test/files/run/t10075.scala
And pointed out you must force `lazy val`, since `null`-valued field
is serializable regardless of its type.
Test test/files/run/t10075b courtesy of retronym
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
http://openjdk.java.net/jeps/220 changes the layout of the
JDK to encapsulate the provided libraries with the new module
system.
This commit modifies the compiler's classpath implementation
to scan the new location of these, the `jrt://` virtual filesystem.
This might need to be adjusted once we provide a means for
users to specify the subset of modules that they want to
depend on, but for now reclaims the ground we lost.
```
⚡ (java_use 9-ea; qscala)
Welcome to Scala 2.12.0-20160908-223617-7e4ebda (Java HotSpot(TM) 64-Bit Server VM, Java 9-ea).
Type in expressions for evaluation. Or try :help.
scala> import StackWalker._, java.util.stream._, scala.collection.JavaConverters._
import StackWalker._
import java.util.stream._
import scala.collection.JavaConverters._
scala> (() => StackWalker.getInstance(java.util.EnumSet.of(Option.RETAIN_CLASS_REFERENCE)).walk[Seq[String]]((s: java.util.stream.Stream[StackFrame]) => s.iterator.asScala.take(3).map(_.toString).toList)).apply().mkString("\n")
res0: String =
.$anonfun$res0$1(<console>:21)
.<init>(<console>:21)
.<clinit>(<console>)
scala>
```
I've marked the new class, `NioFile` as `private[scala]` to justify
the forward compatibility whitelist entry.
In principle we could use NioFile more widely rather than `PlainFile`
I tried this out in https://github.com/retronym/scala/commit/b2d0a17a
which passed CI. But to be conservative, I'm not submitting that change
at this point.
|
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
In Java 9. we can no longer introspect the boot classpath with
a JVM provided system property. Instead, this commit passes
a custom property which will be found by PathResolver when it
constructs the compiler classpath.
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
This was not having the desired effect of placing the
Scala library on the JVM's regular classpath.
This commit honours this setting.
Note that the Windows scripts have never supported
the use of bootclasspath, so no changes are required.
The existing bug:
```
(java_use 1.8; ~/scala/2.11.8/bin/scala -nobootcp -debug -e 'print("")')
/Library/Java/JavaVirtualMachines/jdk1.8.0_102.jdk/Contents/Home/bin/java
-Xmx256M
-Xms32M
-Xbootclasspath/a:/Users/jason/scala/2.11.8/lib/akka-actor_2.11-2.3.10.jar:/Users/jason/scala/2.11.8/lib/config-1.2.1.jar:/Users/jason/scala/2.11.8/lib/jline-2.12.1.jar:/Users/jason/scala/2.11.8/lib/scala-actors-2.11.0.jar:/Users/jason/scala/2.11.8/lib/scala-actors-migration_2.11-1.1.0.jar:/Users/jason/scala/2.11.8/lib/scala-compiler.jar:/Users/jason/scala/2.11.8/lib/scala-continuations-library_2.11-1.0.2.jar:/Users/jason/scala/2.11.8/lib/scala-continuations-plugin_2.11.8-1.0.2.jar:/Users/jason/scala/2.11.8/lib/scala-library.jar:/Users/jason/scala/2.11.8/lib/scala-parser-combinators_2.11-1.0.4.jar:/Users/jason/scala/2.11.8/lib/scala-reflect.jar:/Users/jason/scala/2.11.8/lib/scala-swing_2.11-1.0.2.jar:/Users/jason/scala/2.11.8/lib/scala-xml_2.11-1.0.4.jar:/Users/jason/scala/2.11.8/lib/scalap-2.11.8.jar
-classpath
""
-Dscala.home=/Users/jason/scala/2.11.8
-Dscala.usejavacp=true
-Denv.emacs=
scala.tools.nsc.MainGenericRunner
print("")
```
Fixed by this patch:
```
⚡ (java_use 1.8; qscala -nobootcp -debug -e 'print("")')
/Library/Java/JavaVirtualMachines/jdk1.8.0_102.jdk/Contents/Home/bin/java
-Xmx256M
-Xms32M
-classpath
/Users/jason/code/scala/build/quick/classes/repl-jline-embedded:/Users/jason/code/scala/build/quick/classes/repl-jline:/Users/jason/code/scala/build/quick/classes/repl:/Users/jason/code/scala/build/quick/classes/compiler:/Users/jason/code/scala/build/quick/classes/library:/Users/jason/code/scala/build/quick/classes/reflect:/Users/jason/code/scala/build/quick/classes/interactive:/Users/jason/.ivy2/cache/org.apache.ant/ant/jars/ant-1.9.4.jar:/Users/jason/.ivy2/cache/org.apache.ant/ant-launcher/jars/ant-launcher-1.9.4.jar:/Users/jason/.ivy2/cache/org.scala-lang.modules/scala-asm/bundles/scala-asm-5.1.0-scala-1.jar:/Users/jason/.ivy2/cache/org.scala-lang.modules/scala-xml_2.12.0-RC1/bundles/scala-xml_2.12.0-RC1-1.0.5.jar:/Users/jason/.ivy2/cache/jline/jline/jars/jline-2.14.1.jar
-Dscala.home=/Users/jason/code/scala/build/quick
-Dscala.usejavacp=true
-Denv.emacs=
scala.tools.nsc.MainGenericRunner
-nc
print("")
```
|
|\ \ \
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
SI-7046 reflection doesn't see all knownDirectSubclasses
This appears to do the right thing in the most typical scenarios in which `knownDirectSubclasses` would be used. The missing 5% is that subclasses defined in local scopes might not be seen by `knownDirectSubclasses` (see `Local` and `Riddle` in the test below). In mitigation, though, it is almost certain that a local subclass would represent an error in any scenario where `knownDirectSubclasses` might be used.
Errors for such situations are reported by recording (via a symbol attachment) that `knownDirectSubclasses` has been called and reporting an error if any additional children are added subsequently.
Despite these limitations and caveats, I believe that this represents a huge improvement over the status quo, and would eliminate 100% of the failures that I've seen in practice with people using shapeless for type class derivation.
|
| | | | |
|
|\ \ \ \
| |_|/ /
|/| | | |
Clean up of code guarded by bare -Xexperimental
|
| | | | |
|
| |/ / |
|
|\ \ \
| | | |
| | | | |
Don't exclude super calls to trait methods from inlining
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
In 8020cd6, the inliner was changed to make sure trait methods bodies
are not duplicated into the static super accessors, and from there into
mixin forwarders.
The check for mixin forwarders was too wide. In `def t = super.m`, where
`m` is a trait method annotated `@inline`, we want to inline `m`. Note
that `super.m` is translated to an `invokestatic T.m$`. The current
check incorrectly identifies `t` as a mixin forwarder, and skip
inlining.
|
|\ \ \ \
| | | | |
| | | | | |
SI-10009 Fields survive untypecheck/retypecheck
|
| | |_|/
| |/| |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Some places in the compiler, and many places in macros, use
`untypecheck` (aka `resetAttrs`) to strip types and local symbols
from a tree before retypechecking it under some different context.
The refactoring of the desugaring of vals and vars in Scala 2.12.0
broke an assumption in this facility.
When a ValDef must be split into multiple members (e.g. a field and
a getter, or a perhaps also a setter), the ValDef that was parsed
assumes the role of the `field`, and the trees for other members are
stached by `Namer` to the `synthetics` map of the compilation unit,
in order to spliced into the right statement list by typechecking.
See `enterGetterSetter` for more details.
However, the parsed ValDef is now used verbatim, carrying the meaning
(ie, the symbol) of the `private[this]` field. This tree now had
an inconsistency between the flags in `tree.mods.flags` and
`tree.symbol.flags`. `tree.name` also differed from `tree.symbol.name`
(the latter was renamed to be a local name, ie one with a trailing space.)
When `ResetAttrs` stripped off the symbol and we retypechecked, we'd
end up with two symbols in scope with the same name.
In the first from the `run` test:
```
================================================================================
{
class a extends scala.AnyRef {
def <init>(): a = {
a.super.<init>();
()
};
private[this] val x: Int = 42;
<stable> <accessor> def x: Int = a.this.x
};
new a()
}
{
class a extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
val x = 42; // oops, the name is "x" rather than "x " and we've missing `private[this]`!
<stable> <accessor> def x: Int = a.this.x
};
new a()
}
scala.tools.reflect.ToolBoxError: reflective typecheck has failed: x is already defined as value x
```
This commit uses the flags and name of the symbol in `typedValDef`.
I've also had to modify the internals of `CodePrinter` to use the
implicit, override, and deferred flags from the modifiers of an
accessor when recovering pre-typer tree for a ValDef.
|
|\ \ \ \
| | | | |
| | | | | |
Fix more compiler crashes with fields, refinement types
|
| |/ / /
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
In the same manner as scala/scala-dev#219, the placement of the fields
phase after uncurry is presenting some challenges in keeping our trees
type correct.
This commit whacks a few more moles by adding a casts in the body of
synthetic methods.
Fixes scala/scala-dev#268
|
|\ \ \ \
| |_|/ /
|/| | | |
Avoid name table pollution with fresh existentials
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
During large compilations runs, the large numbers of globally unique
fresh names for existentials captured from prefixes of `asSeenFrom`.
is a) somewhat wasteful (all these names are interned in the name table)
, and, b) form a pathological case for the current implementation of
`Names#hashValue`, which leads to overfull hash-buckets in the name table.
`hashValue` should probably be improved, but my attempts to do so have
shown a small performance degradation in some benchmarks. So this commit
starts by being more frugal with these names, only uniquely naming
within an `asSeenFrom` operation.
References scala/scala-dev#246
|
|\ \ \ \
| | | | |
| | | | | |
SI-8779 Enable inlining of code within a REPL session
|
| | |_|/
| |/| |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
The REPL has a long running instance of Global which outputs
classfiles by default to a VirtualDirectory. The inliner did not find
any of these class files when compiling calls to methods defined in
previous runs (ie, previous lines of input.)
This commit:
- Adds a hook to augment the classpath that the optimizer searches,
and uses this in the REPL to add the output directory
- Fixes the implementation of `findClassFile` in VirtualDirectory,
which doesn't seem to have been used in anger before. I've factored out
some common code into a new method on `AbstractFile`.
- Fixes a similar problem getSubDir reported by Li Haoyi
- Adds missing unit test coverage.
This also fixes a bug in REPL autocompletion for types defined
in packages >= 2 level deep (with the `:paste -raw` command).
I've added a test for this case.
|
|\ \ \ \
| |/ / /
|/| | | |
Better inliner support for 2.12 trait encoding
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
One line per inline request, nested inlines are indented. Log when a
rollback happens. Examples:
```
Inline into scala/collection/SeqLike$$anon$2.andThen: inlined scala/collection/SeqLike$$anon$2.andThen. Before: 8 ins, inlined: 8 ins.
inlined scala/PartialFunction.andThen$. Before: 20 ins, inlined: 8 ins.
inlined scala/PartialFunction.andThen. Before: 31 ins, inlined: 10 ins.
```
and
```
Inline into scala/collection/IterableLike$$anon$1.takeWhile: inlined scala/collection/IterableLike$$anon$1.takeWhile. Before: 8 ins, inlined: 8 ins.
inlined scala/collection/TraversableViewLike.takeWhile$. Before: 20 ins, inlined: 8 ins.
failed scala/collection/TraversableViewLike.takeWhile. [...] would cause IllegalAccessError [...]
rolling back, nested inline failed.
```
|
| | | |
| | | |
| | | |
| | | |
| | | | |
Rename `undoLog.run` to `rollback`, use java ArrayList instead of
helper methods to copy to an array.
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Some changes to the trait encoding came late in the 2.12 cycle, and the
inliner was not adapted to support it in the best possible way.
In 2.12.0 concrete trait methods are encoded as
interface T {
default int m() { return 1 }
static int m$(T $this) { <invokespecial $this.m()> }
}
class C implements T {
public int m() { return T.m$(this) }
}
If a trait method is selected for inlining, the 2.12.0 inliner would
copy its body into the static super accessor `T.m$`, and from there into
the mixin forwarder `C.m`.
This commit special-cases the inliner:
- We don't inline into static super accessors and mixin forwarders.
- Insted, when inlining an invocation of a mixin forwarder, the
inliner also follows through the two forwarders and inlines the
trait method body.
There was a difficulty implementing this: inlining the static static
super accessor would copy an `invokespecial` instruction into a
different classfile, which is not legal / may change semantics. That
`invokespecial` is supposed to disappear when inlining the actual
default method body. However, this last step may fail, for example
because the trait method body itself contains instructions that are not
legal in a different classfile.
It is very difficult to perform all necessary checks ahead of time. So
instead, this commit implements the ability to speculatively inline a
callsite and roll back if necessary.
The commit also cleans up the implementation of inliner warnings a
little. The previous code would always emit a warning when a method
annotated `@inline` was not picked by the heuristics - this was a
problem when the callsite in the static super accessor was no longer
chosen.
|
|\ \ \ \
| |/ / /
|/| | | |
SI-10071 Separate compilation for varargs methods
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Make sure that methods annotated with varargs are properly mixed-in. This commit
splits the transformation into an info transformer (that works on all symbols, whether
they come from source or binary) and a tree transformer.
The gist of this is that the symbol-creation part of the code was moved to the UnCurry
info transformer, while tree operations remained in the tree transformer. The newly
created symbol is attached to the original method so that the tree transformer can still
retrieve the symbol.
A few fall outs:
- I removed a local map that was identical to TypeParamsVarargsAttachment
- moved the said attachment to StdAttachments so it’s visible between reflect.internal
and nsc.transform
- a couple more comments in UnCurry to honour the boy-scout rule
|
|\ \ \ \
| |/ / /
|/| | | |
SI-9814 Fix synchronized in specialized overrides
|
| | |/
| |/|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
Specialization creates a subclasses of a specializd class for each
type parameter combination. These contains copies of the methods from
the superclass.
However, before this transform, the pattern of self-synchronization
in a method body had been replace by flag Flag.SYNCHRONIZED on the
method symbol. This was not being propagated to the override, and
hence no locking occured.
This commit modifies the creation of the specialized overload symbol
to copy the SYNCHRONIZED flag, as was already done for ASBOVERRIDE.
I have also done the same for the `@strictfp` annotation.
|
|/ /
| |
| |
| | |
Scaladoc was prone to warning about java imports.
|
|\ \
| | |
| | | |
SI-9953 Any Any aborts warn on equals
|
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
Don't warn about equals if any `Any` is involved. cf SI-8965
The condition for warning is that both types lub to a supertype
of Object.
|
|\ \ \
| | | |
| | | | |
SI-9944 Scan after interp expr keeps CR
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
In an interpolated expression `s"""${ e }"""`, the scanner
advances input past the RBRACE. If a multiline string as
shown, get the next raw char, because CR is significant.
|
|\ \ \ \
| | | | |
| | | | | |
SI-10059 reset the `DEFERRED` flag for Java varargs forwarders
|
| | |_|/
| |/| |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
When an abstract method is annotated `@varargs`, make sure that the
generated synthetic Java varargs method does not have the `DEFERRED`
flag (`ACC_ABSTRACT` in bytecode).
The flag lead to an NPE in the code generator, because the ASM framework
leaves certain fields `null` for abstract methods (`localVariables` in
this case).
Interestingly this did not crash in 2.11.x: the reason is that the test
whether to emit a method body or not has changed in the 2.12 backend
(in c8e6050).
val isAbstractMethod = [..] methSymbol.isDeferred [..] // 2.11
val isAbstractMethod = rhs == EmptyTree // 2.12
So in 2.11, the varargs forwarder method was actually left abstract in
bytecode, leading to an `AbstractMethodError: T.m([I)I` at run-time.
|
|\ \ \ \
| | | | |
| | | | | |
SI-9915 Utf8_info are modified UTF8
|
| | |_|/
| |/| |
| | | |
| | | |
| | | |
| | | | |
Use DataInputStream.readUTF to read CONSTANT_Utf8_info.
This fixes reading embedded null char and supplementary chars.
|
| | | | |
|
|\ \ \ \
| | | | |
| | | | | |
SI-6978 No linting of Java parens
|
| |/ / /
| | | |
| | | |
| | | |
| | | | |
Don't lint overriding of nullary by non-nullary
when non-nullary is Java-defined. They can't help it.
|
|\ \ \ \
| | | | |
| | | | | |
SI-6734 Synthesize companion near case class
|
| | | | | |
|