| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
[Most of this comment and the initial fix were implemented by Jason Zaugg.
I just cleaned it up a bit.]
After a soundness fix in SI-3873, instantiation of dependent
method type results behaved differently depending on whether the argument
from which we were propagating information had a stable type
or not. This is particular to substitution into singleton types
over the parameter in question.
If the argument was stable, it was substituted into singleton
types, such as the one below in the prefix in `a.type#B`
(which is the longhand version of `a.B`)
scala> class A { type B >: Null <: AnyRef }
defined class A
scala> object AA extends A { type B = String }
defined object AA
scala> def foo(a: A): a.B = null
foo: (a: A)a.B
scala> foo(AA)
res0: AA.B = null
But what if it isn't stable?
scala> foo({def a = AA; a: A { type B <: String}})
res1: a.B = null
This commit changes that to:
scala> foo({def a = AA; a: A { type B <: String}})
res1: A{type B <: String}#B = null
|
|\
| |
| | |
SI-8177 co-evolve more than just RefinedTypes
|
| |
| |
| |
| |
| |
| |
| |
| |
| | |
We look for any prefix that has a refinement class for a type symbol.
This includes ThisTypes, which were not considered before.
pos/t8177g.scala, neg/t0764*scala now compile, as they should
Additional test cases contributed by Jason & Paul.
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
`asSeenFrom` produced a typeref of the shape `T'#A` where `A` referred to a symbol
defined in a `T` of times past.
More precisely, the `TypeRef` case of `TypeMap`'s `mapOver` correctly modified a prefix
from having an underlying type of `{ type A = AIn }` to `{ type A = Int }`,
with a new symbol for `A` (now with info `Int`), but the symbol in the outer
`TypeRef` wasn't co-evolved (so it still referred to the `A` in `{ type A = AIn }`
underlying the old prefix).
`coEvolveSym` used to only look at prefixes that were directly `RefinedType`s,
but this bug shows they could also be `SingleType`s with an underlying `RefinedType`.
|
|\ \
| |/
|/| |
Avoid SOE in logicallyEnclosingMember
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
We've started calling this method during higher-kinded subtyping
to ensure that variances of higher order type params in overriding
as soundly aligned.
Turns out that running this over the expansion of the SBT task
macro leads to a SOE due to a corrupt owner chain.
I've fixed that in SBT (https://github.com/sbt/sbt/pull/1113),
but we ought not crash like this.
This commit considers NoSymbol to be its own enclosing member and
logs a -Xdev warning. This is analagous to the handling of
`NoSymbol.owner`.
|
|\ \
| | |
| | | |
SI-6736 Range.contains is wrong
|
| | |
| | |
| | |
| | |
| | |
| | | |
Operations are reasonable when they don't require indexing or conversion into a collection. These include head, tail, init, last, drop, take, dropWhile, takeWhile, dropRight, takeRight, span.
Tests added also to verify the new behavior.
|
| | |
| | |
| | |
| | | |
Removed once-used private method that was calculating ranges in error and corrected the contains method (plus improved performance).
|
|\ \ \
| | | |
| | | | |
SI-7475 Private members aren't inheritable, findMember overhaul
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
- comment the cases in `isNewMember`
- check both sides for privacy (doesn't influence behaviour of
any tests, but it means that method can be understood without
understanding the order of traversal of members.)
- hoist `findAll`
- break out of the loop in `FindMembers` as soon as we determine
that the candidate member is matched by an already-found member
and can be discarded.
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
It turns out `findMembers` has been a bit sloppy in recent
years and has returned private members from *anywhere* up the
base class sequence. Access checks usually pick up the slack
and eliminate the unwanted privates.
But, in concert with the "concrete beats abstract" rule in
`findMember`, the following mishap appeared:
scala> :paste
// Entering paste mode (ctrl-D to finish)
trait T { def a: Int }
trait B { private def a: Int = 0 }
trait C extends T with B { a }
// Exiting paste mode, now interpreting.
<console>:9: error: method a in trait B cannot be accessed in C
trait C extends T with B { a }
^
I noticed this when compiling Akka against JDK 8; a new private method
in the bowels of the JDK was enough to break the build!
It turns out that some finesse in needed to interpret SLS 5.2:
> The private modifier can be used with any definition or declaration
> in a template. They are not inherited by subclasses [...]
So, can we simply exclude privates from all but the first base class?
No, as that might be a refinement class! The following must be
allowed:
trait A { private def foo = 0; trait T { self: A => this.foo } }
This commit:
- tracks when the walk up the base class sequence passes the
first non-refinement class, and excludes private members
- ... except, if we are at a direct parent of a refinement
class itself
- Makes a corresponding change to OverridingPairs, to only consider
private members if they are owned by the `base` Symbol under
consideration. We don't need to deal with the subtleties of
refinements there as that code is only used for bona-fide classes.
- replaces use of `hasTransOwner` when considering whether a
private[this] symbol is a member.
The last condition was not grounded in the spec at all. The change
is visible in cases like:
// Old
scala> trait A { private[this] val x = 0; class B extends A { this.x } }
<console>:7: error: value x in trait A cannot be accessed in A.this.B
trait A { private[this] val x = 0; class B extends A { this.x } }
^
// New
scala> trait A { private[this] val x = 0; class B extends A { this.x } }
<console>:8: error: value x is not a member of A.this.B
trait A { private[this] val x = 0; class B extends A { this.x } }
^
Furthermore, we no longer give a `private[this]` member a free pass
if it is sourced from the very first base class.
trait Cake extends Slice {
private[this] val bippy = ()
}
trait Slice { self: Cake =>
bippy // BCS: Cake, Slice, AnyRef, Any
}
The different handling between `private` and `private[this]`
still seems a bit dubious.
The spec says:
> An different form of qualification is private[this]. A member M
> marked with this modifier can be accessed only from within the
> object in which it is defined. That is, a selection p.M is only
> legal if the prefix is this or O.this, for some class O enclosing
> the reference. In addition, the restrictions for unqualified
> private apply.
This sounds like a question of access, not membership. If so, we
should admit `private[this]` members from parents of refined types
in `FindMember`.
AFAICT, not too much rests on the distinction: do we get a
"no such member", or "member foo inaccessible" error? I welcome
scrutinee of the checkfile of `neg/t7475f.scala` to help put
this last piece into the puzzle.
One more thing: findMember does not have *any* code the corresponds
to the last sentence of:
> SLS 5.2 The modifier can be qualified with an identifier C
> (e.g. private[C]) that must denote a class or package enclosing
> the definition. Members labeled with such a modifier are accessible
> respectively only from code inside the package C or only from code
> inside the class C and its companion module (ยง5.4).
> Such members are also inherited only from templates inside C.
When I showed Martin this, he suggested it was an error in the
spec, and we should leave the access checking to callers of
that inherited qualified-private member.
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Swathes of important logic are duplicated between `findMember`
and `findMembers` after they separated on grounds of irreconcilable
differences about how fast they should run:
d905558 Variation #10 to optimze findMember
fcb0c01 Attempt #9 to opimize findMember.
71d2ceb Attempt #8 to opimize findMember.
77e5692 Attempty #7 to optimize findMember
275115e Fixing problem that caused fingerprints to fail in
e94252e Attemmpt #6 to optimize findMember
73e61b8 Attempt #5 to optimize findMember.
04f0b65 Attempt #4 to optimize findMember
0e3c70f Attempt #3 to optimize findMember
41f4497 Attempt #2 to optimize findMember
1a73aa0 Attempt #1 to optimize findMember
This didn't actually bear fruit, and the intervening years have
seen the implementations drift.
Now is the time to reunite them under the banner of `FindMemberBase`.
Each has a separate subclass to customise the behaviour. This is
primarily used by `findMember` to cache member types and to assemble
the resulting list of symbols in an low-allocation manner.
While there I have introduced some polymorphic calls, the call sites
are only bi-morphic, and our typical pattern of compilation involves
far more `findMember` calls, so I expect that JIT will keep the
virtual call cost to an absolute minimum.
Test results have been updated now that `findMembers` correctly
excludes constructors and doesn't inherit privates.
Coming up next: we can actually fix SI-7475!
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
This affords us:
- a better chance to share code with `findMembers` again
- the ability to break up the logic into smaller methods for
scrutability and JIT-tability.
The cost is the use of the heap rather than the stack for the
working area of the computation. But I didn't notice a difference
between `locker.lib` and `quick.lib` after this change.
I've left the old implementation in place with an assertion to
verify identical results. In the next commit, this stepping stone
will be removed, and we'll update `findMembers` to share the code.
Some problem areas have been highlighted and will be addressed
after the refactoring phase is complete.
|
|\ \ \ \
| | | | |
| | | | | |
Revert "SI-1786 incorporate defined bounds in inference"
|
| | |_|/
| |/| |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Have to revert because the stricter bounds that it inferred break e.g., slick.
(Backstop for that added as pos/t1786-counter.scala, as minimized by Jason)
Worse, the fix was compilation order-dependent.
There's a less invasive fix (SI-6169) that could be generalized
in `sharpenQuantifierBounds` (used in `skolemizeExistential`),
but I'd rather not mess with existentials at this point.
This reverts commit e28c3edda4dd405ed382227d2a688b799bf33c72.
Conflicts:
src/compiler/scala/tools/nsc/typechecker/Typers.scala
test/files/pos/t1786.scala
|
|\ \ \ \
| |/ / /
|/| | | |
SI-5994 battling implicits for String.lines
|
| |/ /
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
Deprecated ProcessBuilder's lines method and renamed it lineStream.
stream was another possibility, but that seemed more likely to cause conflicts.
streaming was also tried, but feedback was in favor of lineStream.
Also updated tutorial in ProcessBuilder.
I am sure this will break some tests, but because of the name conflict it's hard to be sure where they are. So Jenkins gets to find the problems for me.
Changed name to lineStream.
|
|\ \ \
| | | |
| | | | |
changes the order of whitebox typechecks. yes, again.
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
My first attempt at SI-6992 was about having whitebox expansions first
typecheck against outerPt and only then verify that the result is compatible
with innerPt.
That was a nice try, but soon after it went live in 2.11.0-M8, we've got
multiple reports with problems - both shapeless and then in a week specs2
started having issues with their whitebox macros.
In shapeless, typecheck against outerPt screwed up type inference, which
was more or less fixable by explicit type annotations, so I decided to
wait a bit before jumping to conclusions.
However, in specs2 the problem was more insidious. After being typechecked
against outerPt, expansions were being implicitly converted to a type
that became incompatible with innerPt. This revealed a fatal flaw of the
implemented approach - if allowed to typecheck against outerPt first,
whitebox macros could never be robust.
Now realizing that "outerPt > innerPt" doesn't work, I nevertheless wasn't
looking forward to rolling that back to "innerPt > outerPt", because that
would revive SI-6992 and SI-8048 that are highly unintuitive, especially
the latter one.
Therefore, this commit combines the permissiveness of "... > innerPt"
approaches with the robustness of "innerPt > outerPt", introducing
"WildcardType > innerPt > outerPt".
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Previously pq used pattern1 which required parens to be used in
alternative pattern. This commit tweaks it to allow pq"a | b"
syntax. Also adds some tests for alternative syntax.
|
|\ \ \ \
| | | | |
| | | | | |
SI-8226 Deduplicate JavaTokens/ScalaTokens
|
| | | | | |
|
| |_|/ /
|/| | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
As reported on scala-user:
> Using `scala.Predef.readLine(text: String, args: Any*)`
> on Windows causes strange behavior. If I am leaving some
> part of `text` unforced to be flushed (say, "---\nEnter new
> expression >") then "Enter new expression >" flushed only
> after Enter press. Still, it works fine on Ubuntu and (seems like)
> on MacOS.
>
> My workaround is to force `java.lang.System.out` (that readLine
> depends on to write welcome string) to flush output like
> "---\nEnter new expression >\n".
|
|\ \ \ \
| | | | |
| | | | | |
Make Object#== override Any#==
|
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
- Typer is created with Context.
- Typer creates an Inferencer with said Context.
- Typer mutates Typer#context after each import statement
- Typer mutates its current Context (e.g to disable implicits.)
- Typer asks a question of Inferencer
- Inferencer, looking at the old context, thinks that implicits
are allowed
- Inferencer saves implicit ambiguities into the wrong Context.
Because of this bug, overload resolution in blocks or template
bodies for applications that follow an import have been
considering implicit coercions in the first try at static overload
resolution, and, in the rare case that it encounters an ambigous
implicit in the process, leaking an unpositioned ambiguout error.
This commit ensures coherency between `typer.context` and
`typer.infer.context` by making the latter delegate to the former.
|
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
And the same for !=
If we tried to declare these signatures in non-fictional classes,
we would be chastised about collapsing into the "same signature after
erasure".
This will have an influence of typing, as the typechecking of
arguments is sensitive to overloading: if multiple variants are
feasible, the argument will be typechecked with a wildcard expected
type. So people inspecting the types of the arguments to `==` before
this change might have seen an interesting type for
`if (true) x else y`, but now the `If` will have type `Any`, as we
don't need to calculate the LUB.
I've left a TODO to note that we should really make `Any#{==, !=}`
non-final and include a final override in `AnyVal`. But I don't think
that is particularly urgent.
|
|\ \ \ \ \
| |/ / / /
|/| | | | |
Fix regression for using Scala IDE on scala-library
|
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
If the class path is incomplete, the presentation compiler might crash during construction.
If the PC thread was already started, it will never get the chance to shutdown, and the
thread leaks. In the IDE, where the PC is started when needed, this can lead to a very
quick depletion of JVM threads.
See Scala IDE #1002016.
|
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
This reverts commit 66904556ef34dc81cbb7c09257b013b3ddb76f78.
Conflicts:
src/reflect/scala/reflect/internal/TreeInfo.scala
As evidenced by the highlights of the stack trace in Scala IDE,
my assertion in the 66904556e wasn't universally true.
The change was only motivated by removing a special case, not in
order to fix some other problem. So the revert is the most straight
forward course of action for now.
I haven't pinned this down with a test outside of Eclipse, and
given the lateness of the hour wrt 2.11.0, I'll have to submit
without one.
2013-03-10 08:38:04,690 ERROR [main] - org.scala-ide.sdt.core - org.scala-ide.sdt.core - org.scala-ide.sdt.core - 0 - Error during askOption
scala.reflect.internal.Symbols$CyclicReference: illegal cyclic reference involving object Predef
...
at scala.reflect.internal.Symbols$Symbol.lock(Symbols.scala:482)
at scala.reflect.internal.Symbols$Symbol.info(Symbols.scala:1216)
at scala.reflect.internal.Symbols$Symbol.tpe(Symbols.scala:1200)
at scala.reflect.internal.Symbols$Symbol.tpeHK(Symbols.scala:1201)
at scala.reflect.internal.Types$Type.computeMemberType(Types.scala:784)
at scala.reflect.internal.Types$Type.memberType(Types.scala:781)
at scala.reflect.internal.TreeGen.mkAttributedSelect(TreeGen.scala:203)
...
at scala.reflect.internal.TreeGen.mkAttributedStableRef(TreeGen.scala:162)
at scala.tools.nsc.ast.TreeGen.mkWildcardImport(TreeGen.scala:39)
at scala.tools.nsc.typechecker.Contexts$Context.makeNewImport(Contexts.scala:308)
at scala.tools.nsc.typechecker.Contexts$class.rootContext(Contexts.scala:69)
at scala.tools.nsc.Global$$anon$1.rootContext(Global.scala:492)
at scala.tools.nsc.typechecker.Contexts$class.rootContext(Contexts.scala:64)
at scala.tools.nsc.Global$$anon$1.rootContext(Global.scala:492)
at scala.tools.nsc.typechecker.Analyzer$namerFactory$$anon$1.apply(Analyzer.scala:43)
at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:463)
...
at scala.tools.nsc.Global$Run.compileLate(Global.scala:1681)
at scala.tools.nsc.Global$Run.compileLate(Global.scala:1671)
at scala.tools.nsc.symtab.SymbolLoaders$SourcefileLoader.doComplete(SymbolLoaders.scala:284)
at scala.tools.nsc.symtab.SymbolLoaders$SymbolLoader.complete(SymbolLoaders.scala:187)
at scala.reflect.internal.Symbols$Symbol.info(Symbols.scala:1229)
at scala.reflect.internal.Symbols$Symbol.tpe(Symbols.scala:1200)
at scala.reflect.internal.Symbols$Symbol.tpeHK(Symbols.scala:1201)
at scala.reflect.internal.Types$Type.computeMemberType(Types.scala:784)
at scala.reflect.internal.Types$Type.memberType(Types.scala:781)
at scala.reflect.internal.TreeGen.mkAttributedSelect(TreeGen.scala:203)
at scala.reflect.internal.TreeGen.mkAttributedRef(TreeGen.scala:124)
at scala.reflect.internal.TreeGen.mkAttributedRef(TreeGen.scala:130)
at scala.reflect.internal.TreeGen.mkAttributedStableRef(TreeGen.scala:162)
at scala.tools.nsc.ast.TreeGen.mkWildcardImport(TreeGen.scala:39)
...
at scala.tools.nsc.Global$$anon$1.rootContext(Global.scala:492)
at scala.tools.nsc.typechecker.Analyzer$namerFactory$$anon$1.apply(Analyzer.scala:43)
at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:463)
...
at scala.tools.nsc.Global$Run.compileLate(Global.scala:1671)
at scala.tools.nsc.symtab.SymbolLoaders$SourcefileLoader.doComplete(SymbolLoaders.scala:284)
at scala.tools.nsc.symtab.SymbolLoaders$SymbolLoader.complete(SymbolLoaders.scala:187)
at scala.reflect.internal.Symbols$Symbol.info(Symbols.scala:1229)
at scala.reflect.internal.Symbols$Symbol.initialize(Symbols.scala:1365)
...
at scala.collection.immutable.HashSet$HashSet1.foreach(HashSet.scala:153)
at scala.collection.immutable.HashSet$HashTrieSet.foreach(HashSet.scala:306)
at scala.tools.eclipse.javaelements.ScalaJavaMapper$class.initializeRequiredSymbols(ScalaJavaMapper.scala:29)
...
at scala.tools.nsc.util.InterruptReq.execute(InterruptReq.scala:26)
at scala.tools.nsc.interactive.Global.pollForWork(Global.scala:340)
|
|\ \ \ \ \
| | | | | |
| | | | | | |
Make the Abstract* classes public.
|
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Several weaknesses in the implementation converge and force multiply.
1) Type constructor inference is not persistent. During implicit search
it will give up after the first seen parent even if some deeper base type
(even another direct parent) would satisfy the search.
2) Type inference is not aware of access restrictions. Inferred types are
calculated with disregard for whether the inferred type is visible at
the point of inference. That means that package-private types - which may be
private for any number of good reasons, such as not wanting them to appear in
bytecode thus creating binary compatibility obligations - are not private.
There is no such thing as a qualified private type.
package p {
trait PublicInterface[T] { def foo(): Int }
private[p] trait ImplementationOnly[T] extends PublicInterface[T] { def foo(): Int = 1 }
class PublicClass extends ImplementationOnly[PublicClass]
}
package q {
object Test {
def f[A, CC[X]](xs: CC[A]): CC[A] = xs
def g = f(new p.PublicClass) // inferred type: p.ImplementationOnly[p.PublicClass]
def h = g.foo()
// Bytecode contains:
// public p.ImplementationOnly<p.PublicClass> g();
// public int h();
// 0: aload_0
// 1: invokevirtual #30 // Method g:()Lp/ImplementationOnly;
// 4: invokeinterface #33, 1 // InterfaceMethod p/ImplementationOnly.foo:()I
// 9: ireturn
}
}
3) The trait encoding leads to a proliferation of forwarder methods, so much so that
1.5 Mb of bytecode was taken off of the standard library size by creating abstract classes
which act as central mixin points so that leaf classes can inherit some methods the
old fashioned way rather than each receiving their own copy of every trait defined method.
This was done for 2.10 through the creation of the Abstract* classes, all of which were
given reduced visibility to keep them out of the API.
private[collection] class AbstractSeq extends ...
This achieved its intended goal very nicely, but also some unintended ones.
In combination with 1) above:
scala> val rand = new scala.util.Random()
rand: scala.util.Random = scala.util.Random@7f85a53b
// this works
scala> rand.shuffle(0 to 5)
res1: scala.collection.immutable.IndexedSeq[Int] = Vector(4, 0, 1, 2, 5, 3)
// and this doesn't! good luck reasoning that one out
scala> rand.shuffle(0 until 5)
<console>:9: error: Cannot construct a collection of type scala.collection.AbstractSeq[Int]
with elements of type Int based on a collection of type scala.collection.AbstractSeq[Int].
rand.shuffle(0 until 5)
^
// Somewhat comically, in scala 2.9 it was flipped: to failed (differently), until worked.
scala> scala.util.Random.shuffle(0 to 5)
<console>:8: error: type mismatch;
found : scala.collection.immutable.Range.Inclusive
required: ?CC[?T]
scala> scala.util.Random.shuffle(0 until 5)
res2: scala.collection.immutable.IndexedSeq[Int] = Vector(4, 3, 1, 2, 0)
In combination with 2) above:
scala> def f[A, CC[X]](xs: CC[A]): CC[A] = xs
f: [A, CC[X]](xs: CC[A])CC[A]
scala> var x = f(1 until 10)
x: scala.collection.AbstractSeq[Int] = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)
// It has inferred a type for our value which it will not allow us to use or even to reference.
scala> var y: scala.collection.AbstractSeq[Int] = x
<console>:10: error: class AbstractSeq in package collection cannot be accessed in package collection
var y: scala.collection.AbstractSeq[Int] = x
^
// This one is a straight regression - in scala 2.9,
scala> var x = f(1 until 10)
x: scala.collection.immutable.IndexedSeq[Int] = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)
Since 1) and 2) are essentially unfixable - at least by me - I propose
to ameliorate these regressions by attacking the symptoms at the leaves.
That means making all the Abstract* classes public - keeping in mind that
they must already be assumed to be in the binary compatibility footprint,
since they have been leaking throughout their existence. This only impacts
the inference of inaccessible collections types - it doesn't help with the
more serious issue with type inference.
|
|\ \ \ \ \ \
| | | | | | |
| | | | | | | |
SI-6169 TODO: consolidate with fix for SI-1786 (#2518)
|
| | | | | | | |
|
|\ \ \ \ \ \ \
| | | | | | | |
| | | | | | | | |
Optimization: use AnyRef map for Namer -> Typer tree handoff
|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
These are a hotspot in the backend.
|
| | |_|_|_|_|/
| |/| | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | | |
And uses a map per-compilation unit, rather than one per Typer.
One small change required: we now need to clear this map in the
the interactive compiler which reuses compilation units, rather
than in the call to `Typer#reset`.
|
|\ \ \ \ \ \ \
| | | | | | | |
| | | | | | | | |
SI-6260 Avoid double-def error with lambdas over value classes
|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
- fix typo
- remove BRIDGE flag from the method that we promote from
a bridge to a bona-fide method
- note possibility for delambdafy to avoid the bridge method
creation in *all* cases.
- note inconsistency with anonymous class naming between
`-Ydelamdafy:{inline,method}`
|
| |/ / / / / /
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | | |
Post-erasure of value classs in method signatures to the underlying
type wreaks havoc when the erased signature overlaps with the
generic signature from an overriden method. There just isn't room
for both. But we *really* need both; callers to the interface method
will be passing boxed values that the bridge needs to unbox and
pass to the specific method that accepts unboxed values.
This most commonly turns up with value classes that erase to
Object that are used as the parameter or the return type of
an anonymous function.
This was thought to have been intractable, unless we chose
a different name for the unboxed, specific method in the
subclass. But that sounds like a big task that would require
call-site rewriting, ala specialization.
But there is an important special case in which we don't need
to rewrite call sites. If the class defining the method is
anonymous, there is actually no need for the unboxed method;
it will *only* ever be called via the generic method.
I came to this realisation when looking at how Java 8 lambdas
are handled. I was expecting bridge methods, but found none.
The lambda body is placed directly in a method exactly matching
the generic signature.
This commit detects the clash between bridge and target,
and recovers for anonymous classes by mangling the name
of the target method's symbol. This is used as the bytecode
name. The generic bridge forward to that, as before, with
the requisite box/unbox operations.
|
|\ \ \ \ \ \ \
| |_|_|_|_|/ /
|/| | | | | | |
SI-7570 top-level codegen for toolboxes
|
| | | | | | | |
|
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | | |
Provides a way to inject top-level classes, traits and modules into
toolbox universes.
Previously that was impossible, because compile and eval both wrap their
arguments into an enclosing method of a synthetic module, which makes it
impossible to later on refer to any definitions from the outside.
|
|\ \ \ \ \ \ \
| | | | | | | |
| | | | | | | | |
SI-6411 SI-7328 value class fixes for runtime reflection
|
| | | | | | | | |
|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
This automatically brings performance fixes and correct handling of
values class / by-name params into the constructor land.
|
| |/ / / / / /
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | | |
The `transformedType` method, which is used to bring Scala types to Java
world, was written in pre-valueclass times. Therefore, this method only
called transforms from erasure, uncurry and refChecks.
Now runtime reflection becomes aware of posterasure and as a consequence
methods, which have value classes in their signatures, can be called
without having to wrap them in catch-a-crash clause.
Another facet to this fix was the realization that value classes need
to be unwrapped, e.g. C(2) needs to be transformed to just 2, when they
are used naked in method signatures (i.e. `c` in `def foo(c: C)` needs
to be unwrapped, whereas `cs: List[C]`, `cs: C*` and even `cs: Array[C]`
do not).
|
|\ \ \ \ \ \ \
| |_|_|/ / / /
|/| | | | | | |
fix typo
|
| | | | | | | |
|
|\ \ \ \ \ \ \
| | | | | | | |
| | | | | | | | |
SI-7933 REPL javax.script eval is cached result
|