summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/transform/Fields.scala
Commit message (Collapse)AuthorAgeFilesLines
* Fix typos in compiler and reflectJanek Bogucki2017-02-131-1/+1
| | | | | | | | | | | | Miscellania: Miscellania is a small island off the northernmost part of the Fremennik Isles - RunScape Wiki Miscellanea: A collection of miscellaneous objects or writings - Merriam-Webster
* SI-10075 annotations go to lazy val's underlying fieldAdriaan Moors2016-12-051-13/+30
| | | | | | | | | | | | | 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
* Fix more compiler crashes with fields, refinement typesJason Zaugg2016-11-211-14/+15
| | | | | | | | | | | 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
* Detect clash of mixedin val and existing member.Adriaan Moors2016-10-121-7/+7
| | | | | | | | | Before, we looked only at the result type, which was silly. This was originally motivated by a hack to get to the error about conflicting paramaccessors. The error detection for that can now be formulated more directly. Fixes scala/scala-dev#244
* SI-9946 don't null field in lazy accessors that turn out to be liveJason Zaugg2016-10-071-8/+2
| | | | | | | | | | | | | | | | | | If a non-transient lazy val is the only user of a private field in a class, the field is nulled out at the end of the lazy initializer. This is tested in the existing test `run/lazy-leaks.scala`. The analysis of which fields could be nulled out was recently moved from `mixin` to the new `fields` phase. This introduced a regression as a reference from an inner- or companion-classes had not yet been processed by `explicitouter` to publicise private fields. This commit delays the analysis to mixin (after explicit outer has done its work.) Navigating from `foo$lzycompute()` to `foo()` to `foo` is a little dirty now. I'm not sure whether there is a more robust way to structure things.
* Clarify docs, variable nameAdriaan Moors2016-09-291-11/+12
| | | | A local lazy val and a local object are expanded in the same way.
* Emit local module like lazy valAdriaan Moors2016-09-291-22/+20
| | | | | | | | | The motivation is to use the new fine-grained lock scoping that local lazies have since #5294. Fixes scala/scala-dev#235 Co-Authored-By: Jason Zaugg <jzaugg@gmail.com>
* Merge pull request #5412 from retronym/ticket/SD-226Adriaan Moors2016-09-281-1/+8
|\ | | | | | | | | Be lazier in Fields info transform for better performance Fix scala-dev#226
| * Make isSeparateCompiled... robust against rogue phase time travelJason Zaugg2016-09-271-2/+2
| | | | | | | | | | | | | | | | | | We don't hit this code path during bootstrapping, but we could conceivably hit it with macros or compiler plugins peering into the future through atPhase before refchecks as run. Also rename a method to reflect the generality of the info transform (it does more than mixin, now.)
| * SD-226 Be lazier in Fields info transform for better performanceJason Zaugg2016-09-211-1/+8
| | | | | | | | | | | | | | | | Only mixin fields + accessors into class infos of classes that are either in the current run, or appear in a superclass chain of a class in the current run. This is analagous to what happens in the mixin phase.
* | Cast more pro-actively in synthetic accessor trees.Adriaan Moors2016-09-261-51/+62
| | | | | | | | Also narrow scope of afterOwnPhase.
* | Avoid mismatched symbols in fields phaseAdriaan Moors2016-09-261-2/+15
|/ | | | | | | | | | | | | | | | | | | | | The info of the var that stores a trait's lazy val's computed value is expressed in terms of symbols that exist before the fields phase. When we're implementing the lazy val in a subclass of that trait, we now see symbols created by the fields phase, which results in mismatches between the types of the lhs and rhs in the assignment of `lazyVar = super.lazyImpl`. So, type check the super-call to the trait's lazy accessor before our own phase. If the lazy var's info depends on a val that is now implemented by an accessor synthesize by our info transformer, we'll get a mismatch when assigning `rhs` to `lazyVarOf(getter)`, unless we also run before our own phase (like when we were creating the info for the lazy var). This was revealed by Hanns Holger Rutz's efforts in compiling scala-refactoring's test suite (reported on scala-internals). Fixes scala/scala-dev#219
* Merge pull request #5395 from retronym/pr/5394Jason Zaugg2016-09-151-1/+1
|\ | | | | Avoid omitting constant typed vals in constructors
| * Avoid omitting constant typed vals in constructorsJason Zaugg2016-09-121-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | Fix for regression in 2.12.0-RC1 compiling shapeless tests. They were given the same treatment as vals that are members of classes on the definition side without the requisite transformation of references to the val to fold the constant into references. This commit limits the transform to members of classes. Co-Authored-By: Miles Sabin <miles@milessabin.com>
* | Merge pull request #5398 from retronym/ticket/SD-225Jason Zaugg2016-09-151-2/+4
|\ \ | | | | | | SD-225 Use a "lzycompute" method for module initialization
| * | SD-225 Use a "lzycompute" method for module initializationJason Zaugg2016-09-141-2/+4
| |/ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The monitors and module instantation were inliuned into the module accessor method in b2e0911. However, this seems to have had a detrimental impact on performance. This might be because the module accessors are now above the "always inline" HotSpot threshold of 35 bytes, or perhaps because they contain monitor-entry/exit and exception handlers. This commit returns to the the 2.11.8 appraoch of factoring the the second check of the doublecheck locking into a method. I've done this by declaring a nested method within the accessor; this will be lifted out to the class level by lambdalift. This represents a slight deviation from the implementation strategy used for lazy accessors, which create a symbol for the slowpath method in the info transform and generate the corresponding DefDef as a class member. I don't believe this deviation is particular worrisome, though. I have bootstrapped the compiler through this commit and found that the drastic regression in compiling the shapeless test suite is solved.
* / SI-9918 object in trait mixed into package objectAdriaan Moors2016-09-101-1/+1
|/
* More elegant holders for local lazy vals.Adriaan Moors2016-09-021-24/+18
|
* Lazy val without local.Adriaan Moors2016-09-011-10/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Now `synchronized` is erased specially to avoid boxing, we can drop that work around. Note that this does add an extra cast and getter call on the slow path, but that likely doesn't matter. ``` class C { def foo = {lazy val x = {println("a"); "A" }; x } } ``` becomes ``` def foo(): String = { lazy <artifact> val x$lzy: scala.runtime.LazyRef[String] = new scala.runtime.LazyRef[String](); <artifact> private def x$lzycompute(): String = x$lzy.synchronized[String]{ if (x$lzy.initialized()) x$lzy.value() // NOTE: gets an `.asInstanceOf[String]` after erasure else { x$lzy.value_=({ scala.Predef.println("a"); "A" }); x$lzy.initialized_=(true); x$lzy.value() // NOTE: gets an `.asInstanceOf[String]` after erasure } } lazy def x(): String = if (x$lzy.initialized()) x$lzy.value() // NOTE: gets an `.asInstanceOf[String]` after erasure else x$lzycompute(); x() } ```
* Cleanups after integrating lazyvals into fields.Adriaan Moors2016-09-011-60/+71
| | | | | | | | | | Mostly refactorings and catching up with doc updates. Some changes to flag handling, removing some redundancy, and making lazy fields and modules a bit more consistent in their flags. They now uniformly carry LAZY or MODULEVAR. Before, LAZY was dropped because mixin had some lazy val logic. No longer.
* Local lazy vals: avoid boxing and mutable captureAdriaan Moors2016-08-291-13/+32
|
* Double-checked locking for local lazy vals.Adriaan Moors2016-08-291-27/+36
|
* Double-checked locking for modules.Adriaan Moors2016-08-291-11/+26
| | | | Inline `mkSynchronizedCheck`, whose abstraction obscured rather than clarified.
* Ensure access from subclass to trait lazy valAdriaan Moors2016-08-291-0/+5
| | | | | | | | | | | Since we need to refer to a trait lazy val's accessor using a super call in a subclass (when the field and bitmap are added), we must ensure that access is allowed. If the lazy val has an access boundary (e.g., `private[somePkg]`), make sure the `PROTECTED` flag is set, which widens access to `protected[somePkg]`. (As `member.hasAccessBoundary` implies `!member.hasFlag(PRIVATE)`, we don't have to `resetFlag PRIVATE`.)
* Fields does bitmaps & synch for lazy vals & modulesAdriaan Moors2016-08-291-95/+151
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Essentially, we fuse mixin and lazyvals into the fields phase. With fields mixing in trait members into subclasses, we have all info needed to compute bitmaps, and thus we can synthesize the synchronisation logic as well. By doing this before erasure we get better signatures, and before specialized means specialized lazy vals work now. Mixins is now almost reduced to its essence: implementing super accessors and forwarders. It still synthesizes accessors for param accessors and early init trait vals. Concretely, trait lazy vals are mixed into subclasses with the needed synchronization logic in place, as do lazy vals in classes and methods. Similarly, modules are initialized using double checked locking. Since the code to initialize a module is short, we do not emit compute methods for modules (anymore). For simplicity, local lazy vals do not get a compute method either. The strange corner case of constant-typed final lazy vals is resolved in favor of laziness, by no longer assigning a constant type to a lazy val (see widenIfNecessary in namers). If you explicitly ask for something lazy, you get laziness; with the constant-typedness implicit, it yields to the conflicting `lazy` modifier because it is explicit. Co-Authored-By: Lukas Rytz <lukas@lightbend.com> Fixes scala/scala-dev#133 Inspired by dotc, desugar a local `lazy val x = rhs` into ``` val x$lzy = new scala.runtime.LazyInt() def x(): Int = { x$lzy.synchronized { if (!x$lzy.initialized) { x$lzy.initialized = true x$lzy.value = rhs } x$lzy.value } } ``` Note that the 2.11 decoding (into a local variable and a bitmap) also creates boxes for local lazy vals, in fact two for each lazy val: ``` def f = { lazy val x = 0 x } ``` desugars to ``` public int f() { IntRef x$lzy = IntRef.zero(); VolatileByteRef bitmap$0 = VolatileByteRef.create((byte)0); return this.x$1(x$lzy, bitmap$0); } private final int x$lzycompute$1(IntRef x$lzy$1, VolatileByteRef bitmap$0$1) { C c = this; synchronized (c) { if ((byte)(bitmap$0$1.elem & 1) == 0) { x$lzy$1.elem = 0; bitmap$0$1.elem = (byte)(bitmap$0$1.elem | 1); } return x$lzy$1.elem; } } private final int x$1(IntRef x$lzy$1, VolatileByteRef bitmap$0$1) { return (byte)(bitmap$0$1.elem & 1) == 0 ? this.x$lzycompute$1(x$lzy$1, bitmap$0$1) : x$lzy$1.elem; } ``` An additional problem with the above encoding is that the `lzycompute` method synchronizes on `this`. In connection with the new lambda encoding that no longer generates anonymous classes, captured lazy vals no longer synchronize on the lambda object. The new encoding solves this problem (scala/scala-dev#133) by synchronizing on the lazy holder. Currently, we don't exploit the fact that the initialized field is `@volatile`, because it's not clear the performance is needed for local lazy vals (as they are not contended, and as soon as the VM warms up, biased locking should deal with that) Note, be very very careful when moving to double-checked locking, as this needs a different variation than the one we use for class-member lazy vals. A read of a volatile field of a class does not necessarily impart any knowledge about a "subsequent" read of another non-volatile field of the same object. A pair of volatile reads and write can be used to implement a lock, but it's not clear if the complexity is worth an unproven performance gain. (Once the performance gain is proven, let's change the encoding.) - don't explicitly init bitmap in bytecode - must apply method to () explicitly after uncurry
* Fields phase expands lazy vals like modulesAdriaan Moors2016-08-291-25/+113
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | They remain ValDefs until then. - remove lazy accessor logic now that we have a single ValDef for lazy vals, with the underlying machinery being hidden until the fields phase leave a `@deprecated def lazyAccessor` for scala-refactoring - don't skolemize in purely synthetic getters, but *do* skolemize in lazy accessor during typers Lazy accessors have arbitrary user code, so have to skolemize. We exempt the purely synthetic accessors (`isSyntheticAccessor`) for strict vals, and lazy accessors emitted by the fields phase to avoid spurious type mismatches due to issues with existentials (That bug is tracked as https://github.com/scala/scala-dev/issues/165) When we're past typer, lazy accessors are synthetic, but before they are user-defined to make this hack less hacky, we could rework our flag usage to allow for requiring both the ACCESSOR and the SYNTHETIC bits to identify synthetic accessors and trigger the exemption. see also https://github.com/scala/scala-dev/issues/165 ok 7 - pos/existentials-harmful.scala ok 8 - pos/t2435.scala ok 9 - pos/existentials.scala previous attempt: skolemize type of val inside the private[this] val because its type is only observed from inside the accessor methods (inside the method scope its existentials are skolemized) - bean accessors have regular method types, not nullary method types - must re-infer type for param accessor some weirdness with scoping of param accessor vals and defs? - tailcalls detect lazy vals, which are defdefs after fields - can inline constant lazy val from trait - don't mix in fields etc for an overridden lazy val - need try-lift in lazy vals: the assign is not seen in uncurry because fields does the transform (see run/t2333.scala) - ensure field members end up final in bytecode - implicit class companion method: annot filter in completer - update check: previous error message was tangled up with unrelated field definitions (`var s` and `val s_scope`), now it behaves consistently whether those are val/vars or defs - analyzer plugin check update seems benign, but no way to know... - error message gen: there is no underlying symbol for a deferred var look for missing getter/setter instead - avoid retypechecking valdefs while duplicating for specialize see pos/spec-private - Scaladoc uniformly looks to field/accessor symbol - test updates to innerClassAttribute by Lukas
* Make fewer trait methods not-{private, protected}Adriaan Moors2016-08-111-10/+8
| | | | | | | | | | | | | No longer making trait methods not-protected. (The backend only does public/private because of the poor mapping between visibility from Scala to the JVM). Note that protected trait members will not receive static forwarders in module classes (when mixed into objects). Historic note: we used to `makeNotPrivate` during explicitouter, now we do it later, which means more private methods must be excluded (e.g., lambdaLIFTED ones).
* Mixed in getter needs NullaryMethodType tooAdriaan Moors2016-08-111-1/+3
| | | | | Clone at uncurry to preserve it in its info history. Discovered by the scala-js test suite.
* Simplify erasure + mixinAdriaan Moors2016-08-111-0/+3
| | | | | | | | | | | Remove some old, obsolete & untested hacks from ExplicitOuter. Added a test for one of them to show this is now fine. There are a lot of `makeNotPrivate` invocations sprinkled around the codebase. Lets see if we can centralize the ones dealing with trait methods that need implementations in the phase that emits them. For example Fields (accessors for fields/modules) or SuperAccessors.
* Reduce flag fiddlingAdriaan Moors2016-08-111-4/+4
| | | | | | | | | | | | | | | There isn't much point to the late* flags in a world where we're mutating flags left and right in tree and info transformers... So, lets get rid of the indirection until we can include flags in a symbol's type history, like we do for its info. This retires lateDEFERRED (redundant with SYNTHESIZE_IMPL_IN_SUBCLASS). Since it's introduced so late, it makes little sense to have these synthetic members go back to DEFERRED. Instead, just set DEFERRED directly. Also remove unused late* and not* flags. notPRIVATE subsumes lateFINAL for effective finality (scala/scala-dev#126)
* Address lrytz's review feedbackAdriaan Moors2016-08-111-8/+8
| | | | | | | | | | | | | Remove obsolete hack for BeanSetter's RHS Use currentOwner.isClass instead of exprOwner.isLocalDummy Refactor: shortest branches first in if/else Fix comments from when the prototype ran before refchecks Also, store `isScala212` as a `val` in `Namer` since the `def` on `settings` parses the version each time...
* Fields phase synthesizes modulesAdriaan Moors2016-08-111-104/+204
| | | | | | | | | For now, keep the info transform in refchecks. Ultimately, refchecks should only check, not transform trees/infos. Fixes https://github.com/scala/scala-dev/issues/126: the accessor for a module in a trait is correctly marked non-final (it's deferred).
* Fields phaseAdriaan Moors2016-08-111-0/+449
One step towards teasing apart the mixin phase, making each phase that adds members to traits responsible for mixing in those members into subclasses of said traits. Another design tenet is to not emit symbols or trees only to later remove them. Therefore, we model a val in a trait as its accessor. The underlying field is an implementation detail. It must be mixed into subclasses, but has no business in a trait (an interface). Also trying to reduce tree creation by changing less in subtrees during tree transforms. A lot of nice fixes fall out from this rework: - Correct bridges and more precise generic signatures for mixed in accessors, since they are now created before erasure. - Correct enclosing method attribute for classes nested in trait fields. Trait fields are now created as MethodSymbol (no longer TermSymbol). This symbol shows up in the `originalOwner` chain of a class declared within the field initializer. This promoted the field getter to being the enclosing method of the nested class, which it is not (the EnclosingMethod attribute is a source-level property). - Signature inference is now more similar between vals and defs - No more field for constant-typed vals, or mixed in accessors for subclasses. A constant val can be fully implemented in a trait. TODO: - give same treatment to trait lazy vals (only accessors, no fields) - remove support for presuper vals in traits (they don't have the right init semantics in traits anyway) - lambdalift should emit accessors for captured vals in traits, not a field Assorted notes from the full git history before squashing below. Unit-typed vals: don't suppress field it affects the memory model -- even a write of unit to a field is relevant... unit-typed lazy vals should never receive a field this need was unmasked by test/files/run/t7843-jsr223-service.scala, which no longer printed the output expected from the `0 to 10 foreach` Use getter.referenced to track traitsetter reify's toolbox compiler changes the name of the trait that owns the accessor between fields and constructors (`$` suffix), so that the trait setter cannot be found when doing mkAssign in constructors this could be solved by creating the mkAssign tree immediately during fields anyway, first experiment: use `referenced` now that fields runs closer to the constructors phase (I tried this before and something broke) Infer result type for `val`s, like we do for `def`s The lack of result type inference caused pos/t6780 to fail in the new field encoding for traits, as there is no separate accessor, and method synthesis computes the type signature based on the ValDef tree. This caused a cyclic error in implicit search, because now the implicit val's result type was not inferred from the super member, and inferring it from the RHS would cause implicit search to consider the member in question, so that a cycle is detected and type checking fails... Regardless of the new encoding, we should consistently infer result types for `def`s and `val`s. Removed test/files/run/t4287inferredMethodTypes.scala and test/files/presentation/t4287c, since they were relying on inferring argument types from "overridden" constructors in a test for range positions of default arguments. Constructors don't override, so that was a mis-feature of -Yinfer-argument-types. Had to slightly refactor test/files/presentation/doc, as it was relying on scalac inferring a big intersection type to approximate the anonymous class that's instantiated for `override lazy val analyzer`. Now that we infer `Global` as the expected type based on the overridden val, we make `getComment` private in navigating between good old Skylla and Charybdis. I'm not sure why we need this restriction for anonymous classes though; only structural calls are restricted in the way that we're trying to avoid. The old behavior is maintained nder -Xsource:2.11. Tests: - test/files/{pos,neg}/val_infer.scala - test/files/neg/val_sig_infer_match.scala - test/files/neg/val_sig_infer_struct.scala need NMT when inferring sig for accessor Q: why are we calling valDefSig and not methodSig? A: traits use defs for vals, but still use valDefSig... keep accessor and field info in synch