summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--spec/05-classes-and-objects.md4
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala18
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala10
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala7
-rw-r--r--src/compiler/scala/tools/nsc/transform/AddInterfaces.scala6
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala197
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Fields.scala449
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala132
-rw-r--r--src/compiler/scala/tools/nsc/transform/OverridingPairs.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/Statics.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala23
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala60
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala395
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala84
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala16
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala8
-rw-r--r--src/library/scala/deprecatedInheritance.scala3
-rw-r--r--src/library/scala/deprecatedOverriding.scala3
-rw-r--r--src/reflect/scala/reflect/internal/AnnotationInfos.scala11
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala12
-rw-r--r--src/reflect/scala/reflect/internal/Flags.scala12
-rw-r--r--src/reflect/scala/reflect/internal/Phase.scala2
-rw-r--r--src/reflect/scala/reflect/internal/ReificationSupport.scala1
-rw-r--r--src/reflect/scala/reflect/internal/SymbolPairs.scala28
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala121
-rw-r--r--test/files/neg/overloaded-unapply.check4
-rw-r--r--test/files/neg/t1960.check2
-rw-r--r--test/files/neg/t200.check4
-rw-r--r--test/files/neg/t2779.check4
-rw-r--r--test/files/neg/t278.check4
-rw-r--r--test/files/neg/t3871.check2
-rw-r--r--test/files/neg/t4541.check2
-rw-r--r--test/files/neg/t4541b.check2
-rw-r--r--test/files/neg/t5429.check2
-rw-r--r--test/files/neg/t591.check4
-rw-r--r--test/files/neg/t591.scala3
-rw-r--r--test/files/neg/t6335.check8
-rw-r--r--test/files/neg/t6446-additional.check31
-rw-r--r--test/files/neg/t6446-missing.check29
-rw-r--r--test/files/neg/t6446-show-phases.check29
-rw-r--r--test/files/neg/t6666.check4
-rw-r--r--test/files/neg/t7494-no-options.check31
-rw-r--r--test/files/neg/t7602.check4
-rw-r--r--test/files/neg/t7622-cyclic-dependency.check2
-rw-r--r--test/files/neg/t800.check12
-rw-r--r--test/files/neg/t8849.check2
-rw-r--r--test/files/neg/trait_fields_conflicts.check273
-rw-r--r--test/files/neg/trait_fields_conflicts.scala87
-rw-r--r--test/files/neg/trait_fields_deprecated_overriding.check6
-rw-r--r--test/files/neg/trait_fields_deprecated_overriding.flags1
-rw-r--r--test/files/neg/trait_fields_deprecated_overriding.scala11
-rw-r--r--test/files/neg/val_infer.check6
-rw-r--r--test/files/neg/val_infer.scala4
-rw-r--r--test/files/neg/val_sig_infer_match.check4
-rw-r--r--test/files/neg/val_sig_infer_match.scala22
-rw-r--r--test/files/neg/val_sig_infer_struct.check4
-rw-r--r--test/files/neg/val_sig_infer_struct.scala8
-rw-r--r--test/files/neg/warn-unused-privates.check7
-rw-r--r--test/files/pos/infer_override_def_args.flags (renamed from test/files/presentation/t4287c.flags)0
-rw-r--r--test/files/pos/infer_override_def_args.scala5
-rw-r--r--test/files/pos/trait_fields_dependent_conflict.scala20
-rw-r--r--test/files/pos/trait_fields_dependent_rebind.scala15
-rw-r--r--test/files/pos/trait_fields_inherit_double_def.scala20
-rw-r--r--test/files/pos/trait_fields_lambdalift.scala22
-rw-r--r--test/files/pos/trait_fields_nested_private_object.scala8
-rw-r--r--test/files/pos/trait_fields_nested_public_object.scala5
-rw-r--r--test/files/pos/trait_fields_owners.scala19
-rw-r--r--test/files/pos/trait_fields_private_this.scala5
-rw-r--r--test/files/pos/trait_fields_static_fwd.scala10
-rw-r--r--test/files/pos/val_infer.scala5
-rw-r--r--test/files/presentation/doc/doc.scala2
-rw-r--r--test/files/presentation/scope-completion-3.check14
-rw-r--r--test/files/presentation/t4287c.check11
-rw-r--r--test/files/presentation/t4287c/Test.scala3
-rw-r--r--test/files/presentation/t4287c/src/Foo.scala9
-rw-r--r--test/files/run/SymbolsTest.scala18
-rw-r--r--test/files/run/analyzerPlugins.check37
-rw-r--r--test/files/run/programmatic-main.check29
-rw-r--r--test/files/run/reflection-fieldsymbol-navigation.check6
-rw-r--r--test/files/run/repl-colon-type.check2
-rw-r--r--test/files/run/showdecl.check2
-rw-r--r--test/files/run/showdecl/Macros_1.scala2
-rw-r--r--test/files/run/showraw_mods.check2
-rw-r--r--test/files/run/t4287inferredMethodTypes.check30
-rw-r--r--test/files/run/t4287inferredMethodTypes.scala25
-rw-r--r--test/files/run/t6733.check15
-rw-r--r--test/files/run/t7533.check51
-rw-r--r--test/files/run/t7533.scala34
-rw-r--r--test/files/run/t8549.scala6
-rw-r--r--test/files/run/trait_fields_bytecode.scala23
-rw-r--r--test/files/run/trait_fields_final.scala21
-rw-r--r--test/files/run/trait_fields_init.check21
-rw-r--r--test/files/run/trait_fields_init.scala55
-rw-r--r--test/files/run/trait_fields_repl.check11
-rw-r--r--test/files/run/trait_fields_repl.scala10
-rw-r--r--test/files/run/trait_fields_three_layer_overrides.check2
-rw-r--r--test/files/run/trait_fields_three_layer_overrides.scala25
-rw-r--r--test/files/run/trait_fields_volatile.scala13
-rw-r--r--test/junit/scala/reflect/internal/PrintersTest.scala6
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala3
-rw-r--r--test/pending/run/origins.check6
103 files changed, 2064 insertions, 794 deletions
diff --git a/spec/05-classes-and-objects.md b/spec/05-classes-and-objects.md
index 69828ec7fe..f92e88788a 100644
--- a/spec/05-classes-and-objects.md
+++ b/spec/05-classes-and-objects.md
@@ -344,8 +344,8 @@ $M'$:
- If $M$ and $M'$ are both concrete value definitions, then either none
of them is marked `lazy` or both must be marked `lazy`.
-A stable member can only be overridden by a stable member.
-For example, this is not allowed:
+- A stable member can only be overridden by a stable member.
+ For example, this is not allowed:
```scala
class X { val stable = 1}
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index d4c2896c5c..c2d92ce7f9 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -476,10 +476,22 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
val runsRightAfter = None
} with TailCalls
+ // phaseName = "fields"
+ object fields extends {
+ val global: Global.this.type = Global.this
+ // after refchecks, so it doesn't have to make weird exceptions for synthetic accessors
+ // after uncurry as it produces more work for the fields phase as well as being confused by it:
+ // - sam expansion synthesizes classes, which may need trait fields mixed in
+ // - the fields phase adds synthetic abstract methods to traits that should not disqualify them from being a SAM type
+ // before erasure: correct signatures & bridges for accessors
+ val runsAfter = List("uncurry")
+ val runsRightAfter = None
+ } with Fields
+
// phaseName = "explicitouter"
object explicitOuter extends {
val global: Global.this.type = Global.this
- val runsAfter = List("tailcalls")
+ val runsAfter = List("fields")
val runsRightAfter = None
} with ExplicitOuter
@@ -595,7 +607,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
* This implementation creates a description map at the same time.
*/
protected def computeInternalPhases(): Unit = {
- // Note: this fits -Xshow-phases into 80 column width, which it is
+ // Note: this fits -Xshow-phases into 80 column width, which is
// desirable to preserve.
val phs = List(
syntaxAnalyzer -> "parse source into ASTs, perform simple desugaring",
@@ -608,6 +620,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
pickler -> "serialize symbol tables",
refChecks -> "reference/override checking, translate nested objects",
uncurry -> "uncurry, translate function values to anonymous classes",
+ fields -> "synthesize accessors and fields",
tailCalls -> "replace tail calls by jumps",
specializeTypes -> "@specialized-driven class and method specialization",
explicitOuter -> "this refs to outer pointers",
@@ -1239,6 +1252,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
val picklerPhase = phaseNamed("pickler")
val refchecksPhase = phaseNamed("refchecks")
val uncurryPhase = phaseNamed("uncurry")
+ // val fieldsPhase = phaseNamed("fields")
// val tailcallsPhase = phaseNamed("tailcalls")
val specializePhase = phaseNamed("specialize")
val explicitouterPhase = phaseNamed("explicitouter")
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index bb695500cc..5dddf30c96 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -290,6 +290,16 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
}
+ // the result type of a function or corresponding SAM type
+ private def functionResultType(tp: Type): Type = {
+ val dealiased = tp.dealiasWiden
+ if (isFunctionTypeDirect(dealiased)) dealiased.typeArgs.last
+ else samOf(tp) match {
+ case samSym if samSym.exists => tp.memberInfo(samSym).resultType.deconst
+ case _ => NoType
+ }
+ }
+
/**
* Lift a Function's body to a method. For use during Uncurry, where Function nodes have type FunctionN[T1, ..., Tn, R]
*
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
index d779490ba8..27a4cbd134 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
@@ -164,7 +164,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
def enclosingMethod(sym: Symbol): Option[Symbol] = {
if (sym.isClass || sym == NoSymbol) None
- else if (sym.isMethod) {
+ else if (sym.isMethod && !sym.isGetter) {
if (doesNotExist(sym)) None else Some(sym)
}
else enclosingMethod(nextEnclosing(sym))
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
index 383347a0d3..836893a98b 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
@@ -549,7 +549,10 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
if (classSym.isEffectivelyFinal) None
else {
// Phase travel necessary. For example, nullary methods (getter of an abstract val) get an
- // empty parameter list in later phases and would therefore be picked as SAM.
+ // empty parameter list in uncurry and would therefore be picked as SAM.
+ // Similarly, the fields phases adds abstract trait setters, which should not be considered
+ // abstract for SAMs (they do disqualify the SAM from LMF treatment,
+ // but an anonymous subclasss can be spun up by scalac after making just the single abstract method concrete)
val samSym = exitingPickler(definitions.samOf(classSym.tpe))
if (samSym == NoSymbol) None
else Some(samSym.javaSimpleName.toString + methodBTypeFromSymbol(samSym).descriptor)
@@ -724,7 +727,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
(((sym.rawflags & symtab.Flags.FINAL) != 0) || isTopLevelModuleClass(sym))
&& !sym.enclClass.isTrait
&& !sym.isClassConstructor
- && !sym.isMutable // lazy vals and vars both
+ && (!sym.isMutable || nme.isTraitSetterName(sym.name)) // lazy vals and vars and their setters cannot be final, but trait setters are
)
// Primitives are "abstract final" to prohibit instantiation
diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
index 9a8eca152f..104e2e8c93 100644
--- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
+++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
@@ -50,12 +50,6 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
}
}
- private def mkAssign(clazz: Symbol, assignSym: Symbol, rhs: Tree): Tree = {
- val qual = Select(This(clazz), assignSym)
- if (assignSym.isSetter) Apply(qual, List(rhs))
- else Assign(qual, rhs)
- }
-
/** Add calls to supermixin constructors
* `super[mix].$init$()`
* to tree, which is assumed to be the body of a constructor of class clazz.
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index 971a55f763..ec8dc68834 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -13,7 +13,7 @@ import symtab.Flags._
/** This phase converts classes with parameters into Java-like classes with
* fields, which are assigned to from constructors.
*/
-abstract class Constructors extends Statics with Transform with ast.TreeDSL {
+abstract class Constructors extends Statics with Transform with TypingTransformers with ast.TreeDSL {
import global._
import definitions._
@@ -26,7 +26,7 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
private val guardedCtorStats: mutable.Map[Symbol, List[Tree]] = perRunCaches.newMap[Symbol, List[Tree]]()
private val ctorParams: mutable.Map[Symbol, List[Symbol]] = perRunCaches.newMap[Symbol, List[Symbol]]()
- class ConstructorTransformer(unit: CompilationUnit) extends Transformer {
+ class ConstructorTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
/*
* Inspect for obvious out-of-order initialization; concrete, eager vals or vars, declared in this class,
* for which a reference to the member precedes its definition.
@@ -80,7 +80,10 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
else {
checkUninitializedReads(cd)
val tplTransformer = new TemplateTransformer(unit, impl0)
- treeCopy.ClassDef(cd, mods0, name0, tparams0, tplTransformer.transformed)
+ tplTransformer.localTyper = this.localTyper
+ tplTransformer.atOwner(impl0, cd.symbol) {
+ treeCopy.ClassDef(cd, mods0, name0, tparams0, tplTransformer.transformed)
+ }
}
case _ =>
super.transform(tree)
@@ -442,13 +445,14 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
} // GuardianOfCtorStmts
private class TemplateTransformer(val unit: CompilationUnit, val impl: Template)
- extends StaticsTransformer
+ extends TypingTransformer(unit)
+ with StaticsTransformer
with DelayedInitHelper
with OmittablesHelper
- with GuardianOfCtorStmts {
+ with GuardianOfCtorStmts
+ {
val clazz = impl.symbol.owner // the transformed class
- val localTyper = typer.atOwner(impl, clazz)
val isDelayedInitSubclass = clazz isSubClass DelayedInitClass
@@ -544,12 +548,15 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
else transform(tree.changeOwner(oldOwner -> newOwner))
}
- // Create an assignment to class field `to` with rhs `from`
- def mkAssign(to: Symbol, from: Tree): Tree =
- localTyper.typedPos(to.pos) {
- Assign(Select(This(clazz), to), from)
+ // Assign `rhs` to class field / trait setter `assignSym`
+ def mkAssign(assignSym: Symbol, rhs: Tree): Tree =
+ localTyper.typedPos(assignSym.pos) {
+ val qual = Select(This(clazz), assignSym)
+ if (assignSym.isSetter) Apply(qual, List(rhs))
+ else Assign(qual, rhs)
}
+
// Create code to copy parameter to parameter accessor field.
// If parameter is $outer, check that it is not null so that we NPE
// here instead of at some unknown future $outer access.
@@ -565,9 +572,6 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
}
}
- // Constant typed vals are not memoized.
- def memoizeValue(sym: Symbol) = !sym.info.resultType.isInstanceOf[ConstantType]
-
/** Triage definitions and statements in this template into the following categories.
* The primary constructor is treated separately, as it is assembled in part from these pieces.
*
@@ -577,84 +581,113 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
* - `constrStats`: statements that go into the constructor after and including the superclass constructor call
* - `classInitStats`: statements that go into the class initializer
*/
- def triageStats = {
- val defBuf, auxConstructorBuf, constrPrefixBuf, constrStatBuf, classInitStatBuf = new mutable.ListBuffer[Tree]
-
- // The early initialized field definitions of the class (these are the class members)
- val presupers = treeInfo.preSuperFields(stats)
-
- // generate code to copy pre-initialized fields
- for (stat <- primaryConstrBody.stats) {
- constrStatBuf += stat
- stat match {
- case ValDef(mods, name, _, _) if mods.hasFlag(PRESUPER) =>
- // stat is the constructor-local definition of the field value
- val fields = presupers filter (_.getterName == name)
- assert(fields.length == 1, s"expected exactly one field by name $name in $presupers of $clazz's early initializers")
- val to = fields.head.symbol
-
- if (memoizeValue(to)) constrStatBuf += mkAssign(to, Ident(stat.symbol))
- case _ =>
+ class Triage {
+ private val defBuf, auxConstructorBuf, constrPrefixBuf, constrStatBuf, classInitStatBuf = new mutable.ListBuffer[Tree]
+
+ triage()
+
+ val defs = defBuf.toList
+ val auxConstructors = auxConstructorBuf.toList
+ val constructorPrefix = constrPrefixBuf.toList
+ val constructorStats = constrStatBuf.toList
+ val classInitStats = classInitStatBuf.toList
+
+ private def triage() = {
+ // Constant typed vals are not memoized.
+ def memoizeValue(sym: Symbol) = !sym.info.resultType.isInstanceOf[ConstantType]
+
+ // The early initialized field definitions of the class (these are the class members)
+ val presupers = treeInfo.preSuperFields(stats)
+
+ // generate code to copy pre-initialized fields
+ for (stat <- primaryConstrBody.stats) {
+ constrStatBuf += stat
+ stat match {
+ case ValDef(mods, name, _, _) if mods.hasFlag(PRESUPER) => // TODO trait presupers
+ // stat is the constructor-local definition of the field value
+ val fields = presupers filter (_.getterName == name)
+ assert(fields.length == 1, s"expected exactly one field by name $name in $presupers of $clazz's early initializers")
+ val to = fields.head.symbol
+
+ if (memoizeValue(to)) constrStatBuf += mkAssign(to, Ident(stat.symbol))
+ case _ =>
+ }
}
- }
- for (stat <- stats) {
- val statSym = stat.symbol
-
- // Move the RHS of a ValDef to the appropriate part of the ctor.
- // If the val is an early initialized or a parameter accessor,
- // it goes before the superclass constructor call, otherwise it goes after.
- // A lazy val's effect is not moved to the constructor, as it is delayed.
- // Returns `true` when a `ValDef` is needed.
- def moveEffectToCtor(mods: Modifiers, rhs: Tree, assignSym: Symbol): Unit = {
- val initializingRhs =
- if ((assignSym eq NoSymbol) || statSym.isLazy) EmptyTree // not memoized, or effect delayed (for lazy val)
- else if (!mods.hasStaticFlag) intoConstructor(statSym, primaryConstr.symbol)(rhs)
- else rhs
-
- if (initializingRhs ne EmptyTree) {
- val initPhase =
- if (mods hasFlag STATIC) classInitStatBuf
- else if (mods hasFlag PRESUPER | PARAMACCESSOR) constrPrefixBuf
- else constrStatBuf
-
- initPhase += mkAssign(assignSym, initializingRhs)
+ val primaryConstrSym = primaryConstr.symbol
+
+ for (stat <- stats) {
+ val statSym = stat.symbol
+
+ // Move the RHS of a ValDef to the appropriate part of the ctor.
+ // If the val is an early initialized or a parameter accessor,
+ // it goes before the superclass constructor call, otherwise it goes after.
+ // A lazy val's effect is not moved to the constructor, as it is delayed.
+ // Returns `true` when a `ValDef` is needed.
+ def moveEffectToCtor(mods: Modifiers, rhs: Tree, assignSym: Symbol): Unit = {
+ val initializingRhs =
+ if ((assignSym eq NoSymbol) || statSym.isLazy) EmptyTree // not memoized, or effect delayed (for lazy val)
+ else if (!mods.hasStaticFlag) intoConstructor(statSym, primaryConstrSym)(rhs)
+ else rhs
+
+ if (initializingRhs ne EmptyTree) {
+ val initPhase =
+ if (mods hasFlag STATIC) classInitStatBuf
+ else if (mods hasFlag PRESUPER | PARAMACCESSOR) constrPrefixBuf
+ else constrStatBuf
+
+ initPhase += mkAssign(assignSym, initializingRhs)
+ }
}
- }
- stat match {
- // recurse on class definition, store in defBuf
- case _: ClassDef if !stat.symbol.isInterface => defBuf += new ConstructorTransformer(unit).transform(stat)
-
- // Triage methods -- they all end up in the template --
- // regular ones go to `defBuf`, secondary contructors go to `auxConstructorBuf`.
- // The primary constructor is dealt with separately (we're massaging it here).
- case _: DefDef if statSym.isPrimaryConstructor || statSym.isMixinConstructor => ()
- case _: DefDef if statSym.isConstructor => auxConstructorBuf += stat
- case _: DefDef => defBuf += stat
-
- // If a val needs a field, an empty valdef goes into the template.
- // Except for lazy and ConstantTyped vals, the field is initialized by an assignment in:
- // - the class initializer (static),
- // - the constructor, before the super call (early initialized or a parameter accessor),
- // - the constructor, after the super call (regular val).
- case ValDef(mods, _, _, rhs) =>
- if (rhs ne EmptyTree) {
- val emitField = memoizeValue(statSym)
- moveEffectToCtor(mods, rhs, if (emitField) statSym else NoSymbol)
- if (emitField) defBuf += deriveValDef(stat)(_ => EmptyTree)
- } else defBuf += stat
-
- // all other statements go into the constructor
- case _ => constrStatBuf += intoConstructor(impl.symbol, primaryConstr.symbol)(stat)
+ stat match {
+ // recurse on class definition, store in defBuf
+ case _: ClassDef if !statSym.isInterface =>
+ defBuf += new ConstructorTransformer(unit).transform(stat)
+
+ // primary constructor is already tracked as `primaryConstr`
+ // non-primary constructors go to auxConstructorBuf
+ // mixin constructors are suppressed (!?!?)
+ case _: DefDef if statSym.isConstructor =>
+ if ((statSym ne primaryConstrSym) && !statSym.isMixinConstructor) auxConstructorBuf += stat
+
+ // If a val needs a field, an empty valdef goes into the template.
+ // Except for lazy and ConstantTyped vals, the field is initialized by an assignment in:
+ // - the class initializer (static),
+ // - the constructor, before the super call (early initialized or a parameter accessor),
+ // - the constructor, after the super call (regular val).
+ case vd: ValDef =>
+ if (vd.rhs eq EmptyTree) { defBuf += vd }
+ else {
+ val emitField = memoizeValue(statSym)
+
+ if (emitField) {
+ moveEffectToCtor(vd.mods, vd.rhs, statSym)
+ defBuf += deriveValDef(stat)(_ => EmptyTree)
+ }
+ }
+
+ case dd: DefDef =>
+ // either move the RHS to ctor (for getter of stored field) or just drop it (for corresponding setter)
+ def shouldMoveRHS =
+ clazz.isTrait && statSym.isAccessor && !statSym.isLazy && (statSym.isSetter || memoizeValue(statSym))
+
+ if ((dd.rhs eq EmptyTree) || !shouldMoveRHS) { defBuf += dd }
+ else {
+ if (statSym.isGetter) moveEffectToCtor(dd.mods, dd.rhs, statSym.asTerm.referenced orElse statSym.setterIn(clazz))
+ defBuf += deriveDefDef(stat)(_ => EmptyTree)
+ }
+
+ // all other statements go into the constructor
+ case _ =>
+ constrStatBuf += intoConstructor(impl.symbol, primaryConstrSym)(stat)
+ }
}
}
-
- (defBuf.toList, auxConstructorBuf.toList, constrPrefixBuf.toList, constrStatBuf.toList, classInitStatBuf.toList)
}
def transformed = {
- val (defs, auxConstructors, constructorPrefix, constructorStats, classInitStats) = triageStats
+ val triage = new Triage; import triage._
// omit unused outers
val omittableAccessor: Set[Symbol] =
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index db8e203c1c..289ac0cc02 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -1156,6 +1156,8 @@ abstract class Erasure extends AddInterfaces
treeCopy.ArrayValue(
tree1, elemtpt setType specialScalaErasure.applyInArray(elemtpt.tpe), trees map transform).clearType()
case DefDef(_, _, _, _, tpt, _) =>
+ fields.dropFieldAnnotationsFromGetter(tree.symbol) // TODO: move this in some post-processing transform in the fields phase?
+
try super.transform(tree1).clearType()
finally tpt setType specialErasure(tree1.symbol)(tree1.symbol.tpe).resultType
case ApplyDynamic(qual, Literal(Constant(boostrapMethodRef: Symbol)) :: _) =>
diff --git a/src/compiler/scala/tools/nsc/transform/Fields.scala b/src/compiler/scala/tools/nsc/transform/Fields.scala
new file mode 100644
index 0000000000..0dd7b1fee0
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/transform/Fields.scala
@@ -0,0 +1,449 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2013 LAMP/EPFL
+ * @author
+ */
+
+package scala.tools.nsc
+package transform
+
+import scala.annotation.tailrec
+import symtab.Flags._
+
+
+/** Synthesize accessors and field for each (strict) val owned by a trait.
+ *
+ * For traits:
+ *
+ * - Namers translates a definition `val x = rhs` into a getter `def x = rhs` -- no underlying field is created.
+ * - This phase synthesizes accessors and fields for any vals mixed into a non-trait class.
+ * - Constructors will move the rhs to an assignment in the template body.
+ * and those statements then move to the template into the constructor,
+ * which means it will initialize the fields defined in this template (and execute the corresponding side effects).
+ * We need to maintain the connection between getter and rhs until after specialization so that it can duplicate vals.
+ *
+ * Runs before erasure (to get bridges), and thus before lambdalift/flatten, so that nested functions/definitions must be considered.
+ * We run after uncurry because it can introduce subclasses of traits with fields (SAMs with vals).
+ * Lambdalift also introduces new fields (paramaccessors for captured vals), but runs too late in the pipeline
+ * (mixins still synthesizes implementations for accessors that need to be mixed into subclasses of local traits that capture).
+ *
+ * In the future, would like to get closer to dotty, which lifts a val's RHS (a similar thing is done for template-level statements)
+ * to a method `$_initialize_$1$x` instead of a block, which is used in the constructor to initialize the val.
+ * This makes for a nice unification of strict and lazy vals, in that the RHS is lifted to a method for both,
+ * with the corresponding compute method called at the appropriate time.)
+ *
+ * This only reduces the required number of methods per field declaration in traits,
+ * if we encode the name (and place in initialisation order) of the field
+ * in the name of its initializing method, to allow separate compilation.
+ * (The name mangling must include ordering, and thus complicate incremental compilation:
+ * ideally, we'd avoid renumbering unchanged methods, but that would result in
+ * different bytecode between clean recompiles and incremental ones).
+ *
+ * In the even longer term (Scala 3?), I agree with @DarkDimius that it would make sense
+ * to hide the difference between strict and lazy vals. All vals are lazy,
+ * but the memoization overhead is removed when we statically know they are forced during initialiation.
+ * We could still expose the low-level field semantics through `private[this] val`s.
+ *
+ * In any case, the current behavior of overriding vals is pretty surprising.
+ * An overridden val's side-effect is still performed.
+ * The only change due to overriding is that its value is never written to the field
+ * (the overridden val's value is, of course, stored in the field in addition to its side-effect being performed).
+ */
+abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransformers {
+
+ import global._
+ import definitions._
+
+ /** the following two members override abstract members in Transform */
+ val phaseName: String = "fields"
+
+ protected def newTransformer(unit: CompilationUnit): Transformer = new FieldsTransformer(unit)
+ override def transformInfo(sym: Symbol, tp: Type): Type =
+ if (sym.isJavaDefined || sym.isPackageClass || !sym.isClass) tp
+ else synthFieldsAndAccessors(tp)
+
+ // we leave lazy vars/accessors and early-init vals alone for now
+ private def excludedAccessorOrFieldByFlags(statSym: Symbol): Boolean = statSym hasFlag LAZY | PRESUPER
+
+ // used for internal communication between info and tree transform of this phase -- not pickled, not in initialflags
+ // TODO: reuse MIXEDIN for NEEDS_TREES?
+ override def phaseNewFlags: Long = NEEDS_TREES | OVERRIDDEN_TRAIT_SETTER
+
+ private final val OVERRIDDEN_TRAIT_SETTER = TRANS_FLAG
+
+ final val TRAIT_SETTER_FLAGS = NEEDS_TREES | DEFERRED | ProtectedLocal
+
+ private def accessorImplementedInSubclass(accessor: Symbol) =
+ (accessor hasFlag SYNTHESIZE_IMPL_IN_SUBCLASS) && (accessor hasFlag (ACCESSOR))
+
+ private def concreteOrSynthImpl(sym: Symbol): Boolean = !(sym hasFlag DEFERRED) || (sym hasFlag SYNTHESIZE_IMPL_IN_SUBCLASS)
+
+ private def synthesizeImplInSubclasses(accessor: Symbol): Unit =
+ accessor setFlag lateDEFERRED | SYNTHESIZE_IMPL_IN_SUBCLASS
+
+ private def setClonedTraitSetterFlags(clazz: Symbol, correspondingGetter: Symbol, cloneInSubclass: Symbol): Unit = {
+ val overridden = isOverriddenAccessor(correspondingGetter, clazz)
+ if (overridden) cloneInSubclass setFlag OVERRIDDEN_TRAIT_SETTER
+ else if (correspondingGetter.isEffectivelyFinal) cloneInSubclass setFlag FINAL
+ }
+
+ // TODO: add MIXEDIN (see e.g., `accessed` on `Symbol`)
+ private def setMixedinAccessorFlags(orig: Symbol, cloneInSubclass: Symbol): Unit =
+ cloneInSubclass setFlag OVERRIDE | NEEDS_TREES resetFlag DEFERRED | lateDEFERRED | SYNTHESIZE_IMPL_IN_SUBCLASS
+
+ private def setFieldFlags(accessor: Symbol, fieldInSubclass: TermSymbol): Unit =
+ fieldInSubclass setFlag (NEEDS_TREES |
+ PrivateLocal
+ | (accessor getFlag MUTABLE | LAZY)
+ | (if (accessor hasFlag STABLE) 0 else MUTABLE)
+ )
+
+
+ def checkAndClearOverridden(setter: Symbol) = checkAndClear(OVERRIDDEN_TRAIT_SETTER)(setter)
+ def checkAndClearNeedsTrees(setter: Symbol) = checkAndClear(NEEDS_TREES)(setter)
+ def checkAndClear(flag: Long)(sym: Symbol) =
+ sym.hasFlag(flag) match {
+ case overridden =>
+ sym resetFlag flag
+ overridden
+ }
+
+
+ private def isOverriddenAccessor(member: Symbol, site: Symbol): Boolean = {
+ val pre = site.thisType
+ @tailrec def loop(bcs: List[Symbol]): Boolean = {
+ // println(s"checking ${bcs.head} for member overriding $member (of ${member.owner})")
+ bcs.nonEmpty && bcs.head != member.owner && (matchingAccessor(pre, member, bcs.head) != NoSymbol || loop(bcs.tail))
+ }
+
+ member.exists && loop(site.info.baseClasses)
+ }
+
+
+ def matchingAccessor(pre: Type, member: Symbol, clazz: Symbol) = {
+ val res = member.matchingSymbol(clazz, pre) filter (sym => (sym hasFlag ACCESSOR) && concreteOrSynthImpl(sym))
+ // if (res != NoSymbol) println(s"matching accessor for $member in $clazz = $res (under $pre)")
+ // else println(s"no matching accessor for $member in $clazz (under $pre) among ${clazz.info.decls}")
+ res
+ }
+
+
+ class FieldMemoization(accessorOrField: Symbol, site: Symbol) {
+ val tp = fieldTypeOfAccessorIn(accessorOrField, site.thisType)
+ // not stored, no side-effect
+ val pureConstant = tp.isInstanceOf[ConstantType]
+
+ // if !stored, may still have a side-effect
+ // (currently not distinguished -- used to think we could drop unit-typed vals,
+ // but the memory model cares about writes to unit-typed fields)
+ val stored = !pureConstant // || isUnitType(tp))
+ }
+
+ private def fieldTypeForGetterIn(getter: Symbol, pre: Type): Type = getter.info.finalResultType.asSeenFrom(pre, getter.owner)
+ private def fieldTypeForSetterIn(setter: Symbol, pre: Type): Type = setter.info.paramTypes.head.asSeenFrom(pre, setter.owner)
+
+ // TODO: is there a more elegant way?
+ def fieldTypeOfAccessorIn(accessor: Symbol, pre: Type) =
+ if (accessor.isSetter) fieldTypeForSetterIn(accessor, pre)
+ else fieldTypeForGetterIn(accessor, pre)
+
+
+ // Constant/unit typed vals are not memoized (their value is so cheap it doesn't make sense to store it in a field)
+ // for a unit-typed getter, we perform the effect at the appropriate time (constructor for eager ones, lzyCompute for lazy),
+ // and have the getter just return Unit (who does that!?)
+ // NOTE: this only considers type, filter on flags first!
+ def fieldMemoizationIn(accessorOrField: Symbol, site: Symbol) = new FieldMemoization(accessorOrField, site)
+
+ // drop field-targeting annotations from getters
+ // (in traits, getters must also hold annotations that target the underlying field,
+ // because the latter won't be created until the trait is mixed into a class)
+ // TODO do bean getters need special treatment to suppress field-targeting annotations in traits?
+ def dropFieldAnnotationsFromGetter(sym: Symbol) =
+ if (sym.isGetter && sym.owner.isTrait) {
+ sym setAnnotations (sym.annotations filter AnnotationInfo.mkFilter(GetterTargetClass, defaultRetention = false))
+ }
+
+ private object synthFieldsAndAccessors extends TypeMap {
+ private def newTraitSetter(getter: Symbol, clazz: Symbol) = {
+ // Add setter for an immutable, memoizing getter
+ // (can't emit during namers because we don't yet know whether it's going to be memoized or not)
+ val setterFlags = (getter.flags & ~(STABLE | PrivateLocal | OVERRIDE | IMPLICIT | FINAL)) | MUTABLE | ACCESSOR | TRAIT_SETTER_FLAGS
+ val setterName = nme.expandedSetterName(getter.name.setterName, clazz)
+ val setter = clazz.newMethod(setterName, getter.pos.focus, setterFlags)
+ val fieldTp = fieldTypeForGetterIn(getter, clazz.thisType)
+ // println(s"newTraitSetter in $clazz for $getter = $setterName : $fieldTp")
+
+ getter.asTerm.referenced = setter
+
+ setter setInfo MethodType(List(setter.newSyntheticValueParam(fieldTp)), UnitTpe)
+ setter
+ }
+
+ def apply(tp0: Type): Type = tp0 match {
+ // TODO: make less destructive (name changes, decl additions, flag setting --
+ // none of this is actually undone when travelling back in time using atPhase)
+ case tp@ClassInfoType(parents, decls, clazz) if clazz.isTrait =>
+ // setters for trait vars or module accessor
+ val newDecls = collection.mutable.ListBuffer[Symbol]()
+ val origDecls = decls.toList
+
+ // strict, memoized accessors will receive an implementation in first real class to extend this trait
+ origDecls.foreach { member =>
+ if (member hasFlag ACCESSOR) {
+ val fieldMemoization = fieldMemoizationIn(member, clazz)
+ // check flags before calling makeNotPrivate
+ val accessorUnderConsideration = !(member hasFlag (DEFERRED | LAZY))
+
+ // destructively mangle accessor's name (which may cause rehashing of decls), also sets flags
+ if (member hasFlag PRIVATE) member makeNotPrivate clazz
+
+ // Need to mark as notPROTECTED, so that it's carried over to the synthesized member in subclasses,
+ // since the trait member will receive this flag later in ExplicitOuter, but the synthetic subclass member will not.
+ // If we don't add notPROTECTED to the synthesized one, the member will not be seen as overriding the trait member.
+ // Therefore, addForwarders's call to membersBasedOnFlags would see the deferred member in the trait,
+ // instead of the concrete (desired) one in the class
+ // TODO: encapsulate as makeNotProtected, similar to makeNotPrivate (also do moduleClass, e.g.)
+ if (member hasFlag PROTECTED) member setFlag notPROTECTED
+
+ // must not reset LOCAL, as we must maintain protected[this]ness to allow that variance hole
+ // (not sure why this only problem only arose when we started setting the notPROTECTED flag)
+
+ // derive trait setter after calling makeNotPrivate (so that names are mangled consistently)
+ if (accessorUnderConsideration && fieldMemoization.stored) {
+ synthesizeImplInSubclasses(member)
+
+ if (member hasFlag STABLE) // TODO: check isGetter?
+ newDecls += newTraitSetter(member, clazz)
+ }
+ }
+ }
+
+ if (newDecls nonEmpty) {
+ val allDecls = newScope
+ origDecls foreach allDecls.enter
+ newDecls foreach allDecls.enter
+ ClassInfoType(parents, allDecls, clazz)
+ } else tp
+
+ // mix in fields & accessors for all mixed in traits
+
+ case tp@ClassInfoType(parents, oldDecls, clazz) if !clazz.isPackageClass =>
+ val site = clazz.thisType
+ // TODO (1): improve logic below, which is used to avoid mixing in anything that would result in an error in refchecks
+ // (a reason to run after refchecks? we should run before pickler, though, I think, so that the synthesized stats are pickled)
+
+ val membersNeedingSynthesis = clazz.mixinClasses.flatMap { mixin =>
+ // afterOwnPhase, so traits receive trait setters for vals
+ afterOwnPhase {mixin.info}.decls.toList.filter(accessorImplementedInSubclass)
+ }
+
+// println(s"mixing in for $clazz: $membersNeedingSynthesis from ${clazz.mixinClasses}")
+
+ // TODO: setter conflicts?
+ def accessorConflictsExistingVal(accessor: Symbol): Boolean = {
+ val existingGetter = oldDecls.lookup(accessor.name.getterName)
+ // println(s"$existingGetter from $accessor to ${accessor.name.getterName}")
+ val tp = fieldTypeOfAccessorIn(accessor, site)
+ (existingGetter ne NoSymbol) && (tp matches (site memberInfo existingGetter).resultType) // !existingGetter.isDeferred && -- see (3)
+ }
+
+ // mixin field accessors --
+ // invariant: (accessorsMaybeNeedingImpl, mixedInAccessorAndFields).zipped.forall(case (acc, clone :: _) => `clone` is clone of `acc` case _ => true)
+ val synthAccessorAndFields = membersNeedingSynthesis map { member =>
+ def cloneAccessor() = {
+ val clonedAccessor = (member cloneSymbol clazz) setPos clazz.pos
+ setMixedinAccessorFlags(member, clonedAccessor)
+
+ if (clonedAccessor.isGetter)
+ clonedAccessor setAnnotations (clonedAccessor.annotations filter AnnotationInfo.mkFilter(GetterTargetClass, defaultRetention = false))
+
+ // if we don't cloneInfo, method argument symbols are shared between trait and subclasses --> lambalift proxy crash
+ // TODO: use derive symbol variant?
+ // println(s"cloning accessor $accessor to $clazz / $clonedInfo -> $relativeInfo")
+ clonedAccessor setInfo ((clazz.thisType memberType member) cloneInfo clonedAccessor) // accessor.info.cloneInfo(clonedAccessor).asSeenFrom(clazz.thisType, accessor.owner)
+ }
+
+ // when considering whether to mix in the trait setter, forget about conflicts -- they will be reported for the getter
+ // a trait setter for an overridden val will receive a unit body in the tree transform
+ if (nme.isTraitSetterName(member.name)) {
+ val getter = member.getterIn(member.owner)
+ val clone = cloneAccessor()
+
+ setClonedTraitSetterFlags(clazz, getter, clone)
+ // println(s"mixed in trait setter ${clone.defString}")
+
+ List(clone)
+ }
+ // avoid creating early errors in case of conflicts (wait until refchecks);
+ // also, skip overridden accessors contributed by supertraits (only act on the last overriding one)
+ else if (accessorConflictsExistingVal(member) || isOverriddenAccessor(member, clazz)) Nil
+ else if (member.isGetter && fieldMemoizationIn(member, clazz).stored) {
+ // add field if needed
+ val field = clazz.newValue(member.localName, member.pos) setInfo fieldTypeForGetterIn(member, clazz.thisType)
+
+ setFieldFlags(member, field)
+
+ // filter getter's annotations to exclude those only meant for the field
+ // we must keep them around long enough to see them here, though, when we create the field
+ field setAnnotations (member.annotations filter AnnotationInfo.mkFilter(FieldTargetClass, defaultRetention = true))
+
+ List(cloneAccessor(), field)
+ } else List(cloneAccessor())
+ }
+
+ // println(s"new decls for $clazz: $mixedInAccessorAndFields")
+
+ // omit fields that are not memoized, retain all other members
+ def omittableField(sym: Symbol) = sym.isValue && !sym.isMethod && !fieldMemoizationIn(sym, clazz).stored
+
+ val newDecls =
+ if (synthAccessorAndFields.isEmpty) oldDecls.filterNot(omittableField)
+ else {
+ // must not alter `decls` directly
+ val newDecls = newScope
+ val enter = newDecls enter (_: Symbol)
+ val enterAll = (_: List[Symbol]) foreach enter
+
+ oldDecls foreach { d => if (!omittableField(d)) enter(d) }
+ synthAccessorAndFields foreach enterAll
+
+ newDecls
+ }
+
+ // println(s"new decls: $newDecls")
+
+ if (newDecls eq oldDecls) tp
+ else ClassInfoType(parents, newDecls, clazz)
+
+ case tp => mapOver(tp)
+ }
+ }
+
+
+
+ class FieldsTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
+ def mkTypedUnit(pos: Position) = localTyper.typedPos(pos)(CODE.UNIT)
+ def deriveUnitDef(stat: Tree) = deriveDefDef(stat)(_ => mkTypedUnit(stat.pos))
+
+ def mkAccessor(accessor: Symbol)(body: Tree) = localTyper.typedPos(accessor.pos)(DefDef(accessor, body)).asInstanceOf[DefDef]
+
+ def mkField(sym: Symbol) = localTyper.typedPos(sym.pos)(ValDef(sym)).asInstanceOf[ValDef]
+
+
+ // synth trees for accessors/fields and trait setters when they are mixed into a class
+ def fieldsAndAccessors(exprOwner: Symbol): List[ValOrDefDef] = {
+ if (exprOwner.isLocalDummy) {
+ val clazz = exprOwner.owner
+ def fieldAccess(accessor: Symbol): Option[Tree] = {
+ val fieldName = accessor.localName
+ val field = clazz.info.decl(fieldName)
+ // The `None` result denotes an error, but we defer to refchecks to report it.
+ // This is the result of overriding a val with a def, so that no field is found in the subclass.
+ if (field.exists) Some(Select(This(clazz), field))
+ else None
+ }
+
+ def getterBody(getter: Symbol): Option[Tree] = {
+ val fieldMemoization = fieldMemoizationIn(getter, clazz)
+ if (fieldMemoization.pureConstant) Some(gen.mkAttributedQualifier(fieldMemoization.tp)) // TODO: drop when we no longer care about producing identical bytecode
+ else fieldAccess(getter)
+ }
+
+ // println(s"accessorsAndFieldsNeedingTrees for $templateSym: $accessorsAndFieldsNeedingTrees")
+ def setterBody(setter: Symbol): Option[Tree] = {
+ // trait setter in trait
+ if (clazz.isTrait) Some(EmptyTree)
+ // trait setter for overridden val in class
+ else if (checkAndClearOverridden(setter)) Some(mkTypedUnit(setter.pos))
+ // trait val/var setter mixed into class
+ else fieldAccess(setter) map (fieldSel => Assign(fieldSel, Ident(setter.firstParam)))
+ }
+
+
+ clazz.info.decls.toList.filter(checkAndClearNeedsTrees) flatMap {
+ case setter if setter.isSetter => setterBody(setter) map mkAccessor(setter)
+ case getter if getter.isAccessor => getterBody(getter) map mkAccessor(getter)
+ case field if !(field hasFlag METHOD) => Some(mkField(field)) // vals/vars and module vars (cannot have flags PACKAGE | JAVA since those never receive NEEDS_TREES)
+ case _ => None
+ }
+ } else {
+// println(s"$exprOwner : ${exprOwner.info} --> ${exprOwner.info.decls}")
+ Nil
+ }
+ }
+
+ def rhsAtOwner(stat: ValOrDefDef, newOwner: Symbol): Tree =
+ atOwner(newOwner)(super.transform(stat.rhs.changeOwner(stat.symbol -> newOwner)))
+
+ private def transformStat(exprOwner: Symbol)(stat: Tree): List[Tree] = {
+ val clazz = currentOwner
+ val statSym = stat.symbol
+
+ // println(s"transformStat $statSym in ${exprOwner.ownerChain}")
+ // currentRun.trackerFactory.snapshot()
+
+ /*
+ For traits, the getter has the val's RHS, which is already constant-folded. There is no valdef.
+ For classes, we still have the classic scheme of private[this] valdef + getter & setter that read/assign to the field.
+
+ There are two axes: (1) is there a side-effect to the val (2) does the val need storage?
+ For a ConstantType, both answers are "no". (For a unit-typed field, there's a side-effect, but no storage needed.)
+
+ All others (getter for trait field, valdef for class field) have their rhs moved to an initialization statement.
+ Trait accessors for stored fields are made abstract (there can be no field in a trait).
+ (In some future version, accessors for non-stored, but effectful fields,
+ would receive a constant rhs, as the effect is performed by the initialization statement.
+ We could do this for unit-typed fields, but have chosen not to for backwards compatibility.)
+ */
+ stat match {
+ // TODO: consolidate with ValDef case
+ case stat@DefDef(_, _, _, _, _, rhs) if (statSym hasFlag ACCESSOR) && !excludedAccessorOrFieldByFlags(statSym) =>
+ /* TODO: defer replacing ConstantTyped tree by the corresponding constant until erasure
+ (until then, trees should not be constant-folded -- only their type tracks the resulting constant)
+ TODO: also remove ACCESSOR flag since there won't be an underlying field to access?
+ */
+ def statInlinedConstantRhs =
+ if (clazz.isTrait) stat // we've already done this for traits.. the asymmetry will be solved by the above todo
+ else deriveDefDef(stat)(_ => gen.mkAttributedQualifier(rhs.tpe))
+
+ if (rhs ne EmptyTree) {
+ val fieldMemoization = fieldMemoizationIn(statSym, clazz)
+
+ // if we decide to have non-stored fields with initialization effects, the stat's RHS should be replaced by unit
+ // if (!fieldMemoization.stored) deriveUnitDef(stat) else stat
+
+ if (fieldMemoization.pureConstant) statInlinedConstantRhs :: Nil
+ else super.transform(stat) :: Nil
+ } else {
+ stat :: Nil
+ }
+
+ case stat@ValDef(mods, _, _, rhs) if !excludedAccessorOrFieldByFlags(statSym) =>
+ if (rhs ne EmptyTree) {
+ val fieldMemoization = fieldMemoizationIn(statSym, clazz)
+
+ // drop the val for (a) constant (pure & not-stored) and (b) not-stored (but still effectful) fields
+ if (fieldMemoization.pureConstant) Nil // (a)
+ else super.transform(stat) :: Nil // if (fieldMemoization.stored)
+ // else rhsAtOwner(transformStat, exprOwner) :: Nil // (b) -- not used currently
+ } else {
+ stat :: Nil
+ }
+
+
+ case tree => List(
+ if (exprOwner != currentOwner && tree.isTerm) atOwner(exprOwner)(super.transform(tree))
+ else super.transform(tree)
+ )
+ }
+ }
+
+ // TODO flatMapConserve or something like it
+ // TODO use thicket encoding of multi-tree transformStat?
+ // if (!currentOwner.isClass || currentOwner.isPackageClass || currentOwner.isInterface) stats flatMap transformStat(exprOwner) // for the ModuleDef case, the only top-level case in that method
+ // else
+ override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] =
+ afterOwnPhase {
+ fieldsAndAccessors(exprOwner) ++ (stats flatMap transformStat(exprOwner))
+ }
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index b5084cffe1..d98daf0ffb 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -45,8 +45,8 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* methods in the impl class (because they can have arbitrary initializers)
*/
private def isImplementedStatically(sym: Symbol) = (
- sym.isMethod
- && (!sym.hasFlag(DEFERRED | SUPERACCESSOR) || (sym hasFlag lateDEFERRED))
+ sym.isMethod
+ && notDeferredOrLate(sym)
&& sym.owner.isTrait
&& (!sym.isModule || sym.hasFlag(PRIVATE | LIFTED))
&& (!(sym hasFlag (ACCESSOR | SUPERACCESSOR)) || sym.isLazy)
@@ -109,16 +109,16 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
// --------- type transformation -----------------------------------------------
- def isConcreteAccessor(member: Symbol) =
- member.hasAccessorFlag && (!member.isDeferred || (member hasFlag lateDEFERRED))
+ private def notDeferredOrLate(sym: Symbol) = !sym.hasFlag(DEFERRED) || sym.hasFlag(lateDEFERRED)
/** Is member overridden (either directly or via a bridge) in base class sequence `bcs`? */
def isOverriddenAccessor(member: Symbol, bcs: List[Symbol]): Boolean = beforeOwnPhase {
def hasOverridingAccessor(clazz: Symbol) = {
clazz.info.nonPrivateDecl(member.name).alternatives.exists(
sym =>
- isConcreteAccessor(sym) &&
+ sym.hasFlag(ACCESSOR) &&
!sym.hasFlag(MIXEDIN) &&
+ notDeferredOrLate(sym) &&
matchesType(sym.tpe, member.tpe, alwaysMatchSimple = true))
}
( bcs.head != member.owner
@@ -126,6 +126,8 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
)
}
+ private def isUnitGetter(sym: Symbol) = sym.tpe.resultType.typeSymbol == UnitClass
+
/** Add given member to given class, and mark member as mixed-in.
*/
def addMember(clazz: Symbol, member: Symbol): Symbol = {
@@ -202,6 +204,8 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
clazz.info // make sure info is up to date, so that implClass is set.
+ // TODO: is this needed? can there be fields in a class that don't have accessors yet but need them???
+ // can we narrow this down to just getters for lazy vals? param accessors?
for (member <- clazz.info.decls) {
if (!member.isMethod && !member.isModule && !member.isModuleVar) {
assert(member.isTerm && !member.isDeferred, member)
@@ -297,49 +301,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
def mixinTraitMembers(mixinClass: Symbol) {
// For all members of a trait's interface do:
for (mixinMember <- mixinClass.info.decls) {
- if (isConcreteAccessor(mixinMember)) {
- if (isOverriddenAccessor(mixinMember, clazz.info.baseClasses))
- devWarning(s"Overridden concrete accessor: ${mixinMember.fullLocationString}")
- else {
- // mixin field accessors
- val mixedInAccessor = cloneAndAddMixinMember(mixinClass, mixinMember)
- if (mixinMember.isLazy) {
- initializer(mixedInAccessor) = (
- mixinClass.info.decl(mixinMember.name)
- orElse abort("Could not find initializer for " + mixinMember.name)
- )
- }
- if (!mixinMember.isSetter)
- mixinMember.tpe match {
- case MethodType(Nil, ConstantType(_)) =>
- // mixinMember is a constant; only getter is needed
- ;
- case MethodType(Nil, TypeRef(_, UnitClass, _)) =>
- // mixinMember is a value of type unit. No field needed
- ;
- case _ => // otherwise mixin a field as well
- // enteringPhase: the private field is moved to the implementation class by erasure,
- // so it can no longer be found in the mixinMember's owner (the trait)
- val accessed = enteringPickler(mixinMember.accessed)
- // #3857, need to retain info before erasure when cloning (since cloning only
- // carries over the current entry in the type history)
- val sym = enteringErasure {
- // so we have a type history entry before erasure
- clazz.newValue(mixinMember.localName, mixinMember.pos).setInfo(mixinMember.tpe.resultType)
- }
- sym updateInfo mixinMember.tpe.resultType // info at current phase
-
- val newFlags = (
- ( PrivateLocal )
- | ( mixinMember getFlag MUTABLE | LAZY)
- | ( if (mixinMember.hasStableFlag) 0 else MUTABLE )
- )
-
- addMember(clazz, sym setFlag newFlags setAnnotations accessed.annotations)
- }
- }
- }
- else if (mixinMember.isSuperAccessor) { // mixin super accessors
+ if (mixinMember.hasFlag(SUPERACCESSOR)) { // mixin super accessors
val superAccessor = addMember(clazz, mixinMember.cloneSymbol(clazz)) setPos clazz.pos
assert(superAccessor.alias != NoSymbol, superAccessor)
@@ -355,10 +317,53 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
superAccessor.asInstanceOf[TermSymbol] setAlias alias1
}
}
- else if (mixinMember.isMethod && mixinMember.isModule && mixinMember.hasNoFlags(LIFTED | BRIDGE)) {
+ else if (mixinMember.hasAllFlags(METHOD | MODULE) && mixinMember.hasNoFlags(LIFTED | BRIDGE)) {
// mixin objects: todo what happens with abstract objects?
addMember(clazz, mixinMember.cloneSymbol(clazz, mixinMember.flags & ~(DEFERRED | lateDEFERRED)) setPos clazz.pos)
}
+ else if (mixinMember.hasFlag(ACCESSOR) && notDeferredOrLate(mixinMember)
+ && (mixinMember hasFlag (LAZY | PARAMACCESSOR))
+ && !isOverriddenAccessor(mixinMember, clazz.info.baseClasses)) {
+ // pick up where `fields` left off -- it already mixed in fields and accessors for regular vals.
+ // but has ignored lazy vals and constructor parameter accessors
+ // TODO: captures added by lambdalift for local traits?
+ //
+ // mixin accessor for lazy val or constructor parameter
+ // (note that a paramaccessor cannot have a constant type as it must have a user-defined type)
+ val mixedInAccessor = cloneAndAddMixinMember(mixinClass, mixinMember)
+ val name = mixinMember.name
+
+ if (mixinMember.isLazy)
+ initializer(mixedInAccessor) =
+ (mixinClass.info.decl(name) orElse abort(s"Could not find initializer for lazy val $name!"))
+
+ // Add field while we're mixing in the getter (unless it's a Unit-typed lazy val)
+ //
+ // lazy val of type Unit doesn't need a field -- the bitmap is enough.
+ // TODO: constant-typed lazy vals... it's an extreme corner case, but we could also suppress the field in:
+ // `trait T { final lazy val a = "a" }; class C extends T`, but who writes code like that!? :)
+ // we'd also have to change the lazyvals logic if we do this
+ if (!nme.isSetterName(name) && !(mixinMember.isLazy && isUnitGetter(mixinMember))) {
+ // enteringPhase: the private field is moved to the implementation class by erasure,
+ // so it can no longer be found in the mixinMember's owner (the trait)
+ val accessed = enteringPickler(mixinMember.accessed)
+ // #3857, need to retain info before erasure when cloning (since cloning only
+ // carries over the current entry in the type history)
+ val sym = enteringErasure {
+ // so we have a type history entry before erasure
+ clazz.newValue(mixinMember.localName, mixinMember.pos).setInfo(mixinMember.tpe.resultType)
+ }
+ sym updateInfo mixinMember.tpe.resultType // info at current phase
+
+ val newFlags = (
+ (PrivateLocal)
+ | (mixinMember getFlag MUTABLE | LAZY)
+ | (if (mixinMember.hasStableFlag) 0 else MUTABLE)
+ )
+
+ addMember(clazz, sym setFlag newFlags setAnnotations accessed.annotations)
+ }
+ }
}
}
@@ -478,8 +483,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
tree
- case _ =>
- tree
+ case _ => tree
}
}
@@ -763,13 +767,12 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
def addCheckedGetters(clazz: Symbol, stats: List[Tree]): List[Tree] = {
def dd(stat: DefDef) = {
val sym = stat.symbol
- def isUnit = sym.tpe.resultType.typeSymbol == UnitClass
def isEmpty = stat.rhs == EmptyTree
if (!clazz.isTrait && sym.isLazy && !isEmpty) {
assert(fieldOffset contains sym, sym)
deriveDefDef(stat) {
- case t if isUnit => mkLazyDef(clazz, sym, List(t), UNIT, fieldOffset(sym))
+ case t if isUnitGetter(sym) => mkLazyDef(clazz, sym, List(t), UNIT, fieldOffset(sym))
case Block(stats, res) =>
mkLazyDef(clazz, sym, stats, Select(This(clazz), res.symbol), fieldOffset(sym))
@@ -781,8 +784,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
assert(fieldOffset contains sym, sym)
deriveDefDef(stat)(rhs =>
(mkCheckedAccessor(clazz, _: Tree, fieldOffset(sym), stat.pos, sym))(
- if (sym.tpe.resultType.typeSymbol == UnitClass) UNIT
- else rhs
+ if (isUnitGetter(sym)) UNIT else rhs
)
)
}
@@ -908,7 +910,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
}
}
- def isUnitGetter(getter: Symbol) = getter.tpe.resultType.typeSymbol == UnitClass
def fieldAccess(accessor: Symbol) = Select(This(clazz), accessor.accessed)
def isOverriddenSetter(sym: Symbol) =
@@ -924,7 +925,12 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
addDefDef(sym)
} else {
// if class is not a trait add accessor definitions
- if (isConcreteAccessor(sym)) {
+ // used to include `sym` with `sym hasFlag lateDEFERRED` as not deferred,
+ // but I don't think MIXEDIN members ever get this flag
+ assert(!sym.hasFlag(lateDEFERRED), s"mixedin $sym from $clazz has lateDEFERRED flag?!")
+ if (sym.hasFlag(ACCESSOR) && !sym.hasFlag(DEFERRED)) {
+ assert(sym hasFlag (LAZY | PARAMACCESSOR), s"mixed in $sym from $clazz is not lazy/param?!?")
+
// add accessor definitions
addDefDef(sym, {
if (sym.isSetter) {
@@ -1006,20 +1012,14 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
val parents1 = currentOwner.info.parents map (t => TypeTree(t) setPos tree.pos)
// mark fields which can be nulled afterward
lazyValNullables = nullableFields(templ) withDefaultValue Set()
- // Remove bodies of accessors in traits - TODO: after PR #5141 (fields refactoring), this might be a no-op
- val bodyEmptyAccessors = if (!sym.enclClass.isTrait) body else body mapConserve {
- case dd: DefDef if dd.symbol.isAccessor && !dd.symbol.isLazy =>
- deriveDefDef(dd)(_ => EmptyTree)
- case tree => tree
- }
// add all new definitions to current class or interface
- val body1 = addNewDefs(currentOwner, bodyEmptyAccessors)
- body1 foreach {
+ val statsWithNewDefs = addNewDefs(currentOwner, body)
+ statsWithNewDefs foreach {
case dd: DefDef if isTraitMethodRequiringStaticImpl(dd) =>
dd.symbol.updateAttachment(NeedStaticImpl)
case _ =>
}
- treeCopy.Template(tree, parents1, self, body1)
+ treeCopy.Template(tree, parents1, self, statsWithNewDefs)
case Select(qual, name) if sym.owner.isTrait && !sym.isMethod =>
// refer to fields in some trait an abstract getter in the interface.
diff --git a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala
index e4082eb376..a861115cab 100644
--- a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala
+++ b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala
@@ -18,8 +18,6 @@ abstract class OverridingPairs extends SymbolPairs {
import global._
class Cursor(base: Symbol) extends super.Cursor(base) {
- lazy val relatively = new RelativeTo(base.thisType)
-
/** Symbols to exclude: Here these are constructors and private/artifact symbols,
* including bridges. But it may be refined in subclasses.
*/
@@ -37,7 +35,7 @@ abstract class OverridingPairs extends SymbolPairs {
(lo.owner != high.owner) // don't try to form pairs from overloaded members
&& !high.isPrivate // private or private[this] members never are overridden
&& !exclude(lo) // this admits private, as one can't have a private member that matches a less-private member.
- && relatively.matches(lo, high)
+ && ((self memberType lo) matches (self memberType high))
) // TODO we don't call exclude(high), should we?
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/Statics.scala b/src/compiler/scala/tools/nsc/transform/Statics.scala
index 9ab00f1a83..776805fd9f 100644
--- a/src/compiler/scala/tools/nsc/transform/Statics.scala
+++ b/src/compiler/scala/tools/nsc/transform/Statics.scala
@@ -4,7 +4,7 @@ package transform
abstract class Statics extends Transform with ast.TreeDSL {
import global._
- class StaticsTransformer extends Transformer {
+ trait StaticsTransformer extends Transformer {
/** generate a static constructor with symbol fields inits, or an augmented existing static ctor
*/
def staticConstructor(body: List[Tree], localTyper: analyzer.Typer, pos: Position)(newStaticInits: List[Tree]): Tree =
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index 81a465ef2f..fcfcc8feb9 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -13,6 +13,7 @@ import scala.reflect.macros.runtime.AbortMacroException
import scala.util.control.NonFatal
import scala.tools.nsc.util.stackTraceString
import scala.reflect.io.NoAbstractFile
+import scala.reflect.internal.util.NoSourceFile
trait ContextErrors {
self: Analyzer =>
@@ -757,22 +758,18 @@ trait ContextErrors {
}
def DefDefinedTwiceError(sym0: Symbol, sym1: Symbol) = {
+ val addPref = s";\n the conflicting $sym1 was defined"
+ val bugNote = "\n Note: this may be due to a bug in the compiler involving wildcards in package objects"
+
// Most of this hard work is associated with SI-4893.
val isBug = sym0.isAbstractType && sym1.isAbstractType && (sym0.name startsWith "_$")
- val addendums = List(
- if (sym0.associatedFile eq sym1.associatedFile)
- Some("conflicting symbols both originated in file '%s'".format(sym0.associatedFile.canonicalPath))
- else if ((sym0.associatedFile ne NoAbstractFile) && (sym1.associatedFile ne NoAbstractFile))
- Some("conflicting symbols originated in files '%s' and '%s'".format(sym0.associatedFile.canonicalPath, sym1.associatedFile.canonicalPath))
- else None ,
- if (isBug) Some("Note: this may be due to a bug in the compiler involving wildcards in package objects") else None
- )
- val addendum = addendums.flatten match {
- case Nil => ""
- case xs => xs.mkString("\n ", "\n ", "")
- }
+ val addendum = (
+ if (sym0.pos.source eq sym1.pos.source) s"$addPref at line ${sym1.pos.line}:${sym1.pos.column}"
+ else if (sym1.pos.source ne NoSourceFile) s"$addPref at line ${sym1.pos.line}:${sym1.pos.column} of '${sym1.pos.source.path}'"
+ else if (sym1.associatedFile ne NoAbstractFile) s"$addPref in '${sym1.associatedFile.canonicalPath}'"
+ else "") + (if (isBug) bugNote else "")
- issueSymbolTypeError(sym0, sym1+" is defined twice" + addendum)
+ issueSymbolTypeError(sym0, s"$sym0 is defined twice$addendum")
}
// cyclic errors
diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
index c03094bc6a..408b457d5b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
@@ -121,6 +121,7 @@ trait MethodSynthesis {
}
// TODO: see if we can link symbol creation & tree derivation by sharing the Field/Getter/Setter factories
+ // maybe we can at least reuse some variant of standardAccessors?
def enterGetterSetter(tree: ValDef): Unit = {
tree.symbol =
if (tree.mods.isLazy) {
@@ -131,15 +132,14 @@ trait MethodSynthesis {
val getterSym = getter.createAndEnterSymbol()
// Create the setter if necessary.
- if (getter.needsSetter)
- Setter(tree).createAndEnterSymbol()
+ if (getter.needsSetter) Setter(tree).createAndEnterSymbol()
- // If the getter's abstract the tree gets the getter's symbol,
- // otherwise, create a field (assume the getter requires storage).
+ // If the getter's abstract, the tree gets the getter's symbol,
+ // otherwise, create a field (we have to assume the getter requires storage for now).
// NOTE: we cannot look at symbol info, since we're in the process of deriving them
// (luckily, they only matter for lazy vals, which we've ruled out in this else branch,
// and `doNotDeriveField` will skip them if `!mods.isLazy`)
- if (Field.noFieldFor(tree)) getterSym setPos tree.pos
+ if (Field.noFieldFor(tree)) getterSym setPos tree.pos // TODO: why do setPos? `createAndEnterSymbol` already gave `getterSym` the position `tree.pos.focus`
else enterStrictVal(tree)
}
@@ -282,14 +282,15 @@ trait MethodSynthesis {
final def enclClass = basisSym.enclClass
- /* Explicit isSetter required for bean setters (beanSetterSym.isSetter is false) */
- final def completer(sym: Symbol) = namerOf(sym).accessorTypeCompleter(tree, isSetter)
+ // There's no reliable way to detect all kinds of setters from flags or name!!!
+ // A BeanSetter's name does not end in `_=` -- it does begin with "set", but so could the getter
+ // for a regular Scala field... TODO: can we add a flag to distinguish getter/setter accessors?
+ final def completer(sym: Symbol) = namerOf(sym).accessorTypeCompleter(tree, this.isInstanceOf[DerivedSetter])
final def fieldSelection = Select(This(enclClass), basisSym)
def derivedSym: Symbol = tree.symbol
def derivedTree: Tree = EmptyTree
- def isSetter = false
def isDeferred = mods.isDeferred
def validate() { }
def createAndEnterSymbol(): MethodSymbol = {
@@ -304,6 +305,7 @@ trait MethodSynthesis {
result
}
+
final def derive(initial: List[AnnotationInfo]): Tree = {
validate()
@@ -311,7 +313,9 @@ trait MethodSynthesis {
// Annotations on ValDefs can be targeted towards the following: field, getter, setter, beanGetter, beanSetter, param.
// The defaults are:
// - (`val`-, `var`- or plain) constructor parameter annotations end up on the parameter, not on any other entity.
- // - val/var member annotations solely end up on the underlying field.
+ // - val/var member annotations solely end up on the underlying field, except in traits (@since 2.12),
+ // where there is no field, and the getter thus holds annotations targetting both getter & field.
+ // As soon as there is a field/getter (in subclasses mixing in the trait), we triage the annotations.
//
// TODO: these defaults can be surprising for annotations not meant for accessors/fields -- should we revisit?
// (In order to have `@foo val X` result in the X getter being annotated with `@foo`, foo needs to be meta-annotated with @getter)
@@ -319,9 +323,11 @@ trait MethodSynthesis {
case _: Param => annotationFilter(ParamTargetClass, defaultRetention = true)
// By default annotations go to the field, except if the field is generated for a class parameter (PARAMACCESSOR).
case _: Field => annotationFilter(FieldTargetClass, defaultRetention = !mods.isParamAccessor)
+ case _: BaseGetter if owner.isTrait => annotationFilter(List(FieldTargetClass, GetterTargetClass), defaultRetention = true)
case _: BaseGetter => annotationFilter(GetterTargetClass, defaultRetention = false)
case _: Setter => annotationFilter(SetterTargetClass, defaultRetention = false)
case _: BeanSetter => annotationFilter(BeanSetterTargetClass, defaultRetention = false)
+ // TODO do bean getters need special treatment to collect field-targeting annotations in traits?
case _: AnyBeanGetter => annotationFilter(BeanGetterTargetClass, defaultRetention = false)
}
@@ -329,21 +335,23 @@ trait MethodSynthesis {
// should be propagated to this kind of accessor.
derivedSym setAnnotations (initial filter annotFilter)
+ if (derivedSym.isSetter && owner.isTrait && !isDeferred)
+ derivedSym addAnnotation TraitSetterAnnotationClass
+
logDerived(derivedTree)
}
}
+
sealed trait DerivedGetter extends DerivedFromValDef {
- // A getter must be accompanied by a setter if the ValDef is mutable.
def needsSetter = mods.isMutable
}
sealed trait DerivedSetter extends DerivedFromValDef {
- override def isSetter = true
- private def setterParam = derivedSym.paramss match {
+ protected def setterParam = derivedSym.paramss match {
case (p :: Nil) :: _ => p
case _ => NoSymbol
}
- private def setterRhs = {
+ protected def setterRhs = {
assert(!derivedSym.isOverloaded, s"Unexpected overloaded setter $derivedSym for $basisSym in $enclClass")
if (Field.noFieldFor(tree) || derivedSym.isOverloaded) EmptyTree
else Assign(fieldSelection, Ident(setterParam))
@@ -390,6 +398,7 @@ trait MethodSynthesis {
override def derivedSym = if (Field.noFieldFor(tree)) basisSym else basisSym.getterIn(enclClass)
private def derivedRhs = if (Field.noFieldFor(tree)) tree.rhs else fieldSelection
+ // TODO: more principled approach -- this is a bit bizarre
private def derivedTpt = {
// For existentials, don't specify a type for the getter, even one derived
// from the symbol! This leads to incompatible existentials for the field and
@@ -457,6 +466,7 @@ trait MethodSynthesis {
def flagsMask = SetterFlags
def flagsExtra = ACCESSOR
+ // TODO: double check logic behind need for name expansion in context of new fields phase
override def derivedSym = basisSym.setterIn(enclClass)
}
@@ -464,17 +474,25 @@ trait MethodSynthesis {
// No field for these vals (either never emitted or eliminated later on):
// - abstract vals have no value we could store (until they become concrete, potentially)
// - lazy vals of type Unit
- // - [Emitted, later removed during AddInterfaces/Mixins] concrete vals in traits can't have a field
- // - [Emitted, later removed during Constructors] a concrete val with a statically known value (Unit / ConstantType)
+ // - concrete vals in traits don't yield a field here either (their getter's RHS has the initial value)
+ // Constructors will move the assignment to the constructor, abstracting over the field using the field setter,
+ // and Fields will add a field to the class that mixes in the trait, implementing the accessors in terms of it
+ // - [Emitted, later removed during Constructors] a concrete val with a statically known value (ConstantType)
// performs its side effect according to lazy/strict semantics, but doesn't need to store its value
// each access will "evaluate" the RHS (a literal) again
// We would like to avoid emitting unnecessary fields, but the required knowledge isn't available until after typer.
// The only way to avoid emitting & suppressing, is to not emit at all until we are sure to need the field, as dotty does.
// NOTE: do not look at `vd.symbol` when called from `enterGetterSetter` (luckily, that call-site implies `!mods.isLazy`),
+ // similarly, the `def field` call-site breaks when you add `|| vd.symbol.owner.isTrait` (detected in test suite)
// as the symbol info is in the process of being created then.
// TODO: harmonize tree & symbol creation
- // TODO: the `def field` call-site breaks when you add `|| vd.symbol.owner.isTrait` (detected in test suite)
- def noFieldFor(vd: ValDef) = vd.mods.isDeferred || (vd.mods.isLazy && isUnitType(vd.symbol.info))
+ // the middle `&& !owner.isTrait` is needed after `isLazy` because non-unit-typed lazy vals in traits still get a field -- see neg/t5455.scala
+ def noFieldFor(vd: ValDef) = (vd.mods.isDeferred
+ || (vd.mods.isLazy && !owner.isTrait && isUnitType(vd.symbol.info))
+ || (owner.isTrait && !traitFieldFor(vd)))
+
+ // TODO: never emit any fields in traits -- only use getter for lazy/presuper ones as well
+ private def traitFieldFor(vd: ValDef): Boolean = vd.mods.hasFlag(PRESUPER | LAZY)
}
case class Field(tree: ValDef) extends DerivedFromValDef {
@@ -482,6 +500,9 @@ trait MethodSynthesis {
def flagsMask = FieldFlags
def flagsExtra = PrivateLocal
+ // TODO: override def createAndEnterSymbol (currently never called on Field)
+ // and do `enterStrictVal(tree)`, so that enterGetterSetter and addDerivedTrees can share some logic...
+
// handle lazy val first for now (we emit a Field even though we probably shouldn't...)
override def derivedTree =
if (mods.isLazy) copyValDef(tree)(mods = mods | flagsExtra, name = this.name, rhs = EmptyTree).setPos(tree.pos.focus)
@@ -528,7 +549,10 @@ trait MethodSynthesis {
}
case class BooleanBeanGetter(tree: ValDef) extends BeanAccessor("is") with AnyBeanGetter { }
case class BeanGetter(tree: ValDef) extends BeanAccessor("get") with AnyBeanGetter { }
- case class BeanSetter(tree: ValDef) extends BeanAccessor("set") with DerivedSetter
+ case class BeanSetter(tree: ValDef) extends BeanAccessor("set") with DerivedSetter {
+ // TODO: document, motivate
+ override protected def setterRhs = Apply(Ident(tree.name.setterName), List(Ident(setterParam)))
+ }
// No Symbols available.
private def beanAccessorsFromNames(tree: ValDef) = {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index caad4a907b..784b43ab84 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -6,6 +6,7 @@
package scala.tools.nsc
package typechecker
+import scala.annotation.tailrec
import scala.collection.mutable
import symtab.Flags._
import scala.language.postfixOps
@@ -116,10 +117,10 @@ trait Namers extends MethodSynthesis {
}
// All lazy vals need accessors, including those owned by terms (e.g., in method) or private[this] in a class
- def deriveAccessors(vd: ValDef) = vd.mods.isLazy || (owner.isClass && deriveAccessorsInClass(vd))
+ def deriveAccessors(vd: ValDef) = (vd.mods.isLazy || owner.isTrait || (owner.isClass && deriveAccessorsInClass(vd)))
private def deriveAccessorsInClass(vd: ValDef) =
- !vd.mods.isPrivateLocal && // note, private[this] lazy vals do get accessors -- see outer disjunction of deriveAccessors
+ !vd.mods.isPrivateLocal && // note, private[this] lazy vals do get accessors -- see outer disjunction of deriveAccessors
!(vd.name startsWith nme.OUTER) && // outer accessors are added later, in explicitouter
!isEnumConstant(vd) // enums can only occur in classes, so only check here
@@ -773,28 +774,31 @@ trait Namers extends MethodSynthesis {
// this accomplishes anything, but performance is a non-consideration
// on these flag checks so it can't hurt.
def needsCycleCheck = sym.isNonClassType && !sym.isParameter && !sym.isExistential
- logAndValidate(sym) {
- val tp = typeSig(tree)
-
- findCyclicalLowerBound(tp) andAlso { sym =>
- if (needsCycleCheck) {
- // neg/t1224: trait C[T] ; trait A { type T >: C[T] <: C[C[T]] }
- // To avoid an infinite loop on the above, we cannot break all cycles
- log(s"Reinitializing info of $sym to catch any genuine cycles")
- sym reset sym.info
- sym.initialize
- }
- }
- sym setInfo {
- if (sym.isJavaDefined) RestrictJavaArraysMap(tp)
- else tp
- }
+
+ // logDefinition(sym) {
+ val tp = typeSig(tree)
+
+ findCyclicalLowerBound(tp) andAlso { sym =>
if (needsCycleCheck) {
- log(s"Needs cycle check: ${sym.debugLocationString}")
- if (!typer.checkNonCyclic(tree.pos, tp))
- sym setInfo ErrorType
+ // neg/t1224: trait C[T] ; trait A { type T >: C[T] <: C[C[T]] }
+ // To avoid an infinite loop on the above, we cannot break all cycles
+ log(s"Reinitializing info of $sym to catch any genuine cycles")
+ sym reset sym.info
+ sym.initialize
}
}
+ sym setInfo {
+ if (sym.isJavaDefined) RestrictJavaArraysMap(tp)
+ else tp
+ }
+ if (needsCycleCheck) {
+ log(s"Needs cycle check: ${sym.debugLocationString}")
+ if (!typer.checkNonCyclic(tree.pos, tp))
+ sym setInfo ErrorType
+ }
+ //}
+
+ validate(sym)
}
def moduleClassTypeCompleter(tree: ModuleDef) = {
@@ -807,15 +811,18 @@ trait Namers extends MethodSynthesis {
/* Explicit isSetter required for bean setters (beanSetterSym.isSetter is false) */
def accessorTypeCompleter(tree: ValDef, isSetter: Boolean) = mkTypeCompleter(tree) { sym =>
- logAndValidate(sym) {
- sym setInfo {
- val tp = if (isSetter) MethodType(List(sym.newSyntheticValueParam(typeSig(tree))), UnitTpe)
- else NullaryMethodType(typeSig(tree))
- pluginsTypeSigAccessor(tp, typer, tree, sym)
- }
- }
+ // typeSig calls valDefSig (because tree: ValDef)
+ // sym is an accessor, while tree is the field (which may have the same symbol as the getter, or maybe it's the field)
+ val sig = accessorSigFromFieldTp(sym, isSetter, typeSig(tree))
+
+ sym setInfo pluginsTypeSigAccessor(sig, typer, tree, sym)
+
+ validate(sym)
}
+ private def accessorSigFromFieldTp(sym: global.Symbol, isSetter: Boolean, tp: global.Type): global.Type with Product with Serializable = {
+ if (isSetter) MethodType(List(sym.newSyntheticValueParam(tp)), UnitTpe) else NullaryMethodType(tp)
+ }
def selfTypeCompleter(tree: Tree) = mkTypeCompleter(tree) { sym =>
val selftpe = typer.typedType(tree).tpe
sym setInfo {
@@ -992,6 +999,19 @@ trait Namers extends MethodSynthesis {
clazz.tpe_*
}
+
+ // make a java method type if meth.isJavaDefined
+ private def methodTypeFor(meth: Symbol, vparamSymss: List[List[Symbol]], restpe: Type) = {
+ def makeJavaMethodType(vparams: List[Symbol], restpe: Type) = {
+ vparams foreach (p => p setInfo objToAny(p.tpe))
+ JavaMethodType(vparams, restpe)
+ }
+ if (vparamSymss.isEmpty) NullaryMethodType(restpe)
+ else if (meth.isJavaDefined) vparamSymss.foldRight(restpe)(makeJavaMethodType)
+ else vparamSymss.foldRight(restpe)(MethodType(_, _))
+ }
+
+
/**
* The method type for `ddef`.
*
@@ -1009,166 +1029,140 @@ trait Namers extends MethodSynthesis {
* to the non-skolems.
*/
private def methodSig(ddef: DefDef): Type = {
-
- // DEPMETTODO: do we need to skolemize value parameter symbols?
-
val DefDef(_, _, tparams, vparamss, tpt, _) = ddef
val meth = owner
val methOwner = meth.owner
- val site = methOwner.thisType
/* tparams already have symbols (created in enterDefDef/completerOf), namely the skolemized ones (created
* by the PolyTypeCompleter constructor, and assigned to tparams). reenterTypeParams enters the type skolems
* into scope and returns the non-skolems.
*/
val tparamSyms = typer.reenterTypeParams(tparams)
-
val tparamSkolems = tparams.map(_.symbol)
- /* since the skolemized tparams are in scope, the TypeRefs in types of vparamSymss refer to the type skolems
- * note that for parameters with missing types, `methodSig` reassigns types of these symbols (the parameter
- * types from the overridden method).
- */
- var vparamSymss = enterValueParams(vparamss)
-
/*
* Creates a method type using tparamSyms and vparamsSymss as argument symbols and `respte` as result type.
* All typeRefs to type skolems are replaced by references to the corresponding non-skolem type parameter,
* so the resulting type is a valid external method type, it does not contain (references to) skolems.
+ *
+ * tparamSyms are deskolemized symbols -- TODO: check that their infos don't refer to method args?
+ * vparamss refer (if they do) to skolemized tparams
*/
- def thisMethodType(restpe: Type) = {
- if (vparamSymss.lengthCompare(0) > 0) { // OPT fast path for methods of 0-1 parameter lists
- val checkDependencies = new DependentTypeChecker(context)(this)
- checkDependencies check vparamSymss
- }
-
- val makeMethodType = (vparams: List[Symbol], restpe: Type) => {
- // TODODEPMET: check that we actually don't need to do anything here
- // new dependent method types: probably OK already, since 'enterValueParams' above
- // enters them in scope, and all have a lazy type. so they may depend on other params. but: need to
- // check that params only depend on ones in earlier sections, not the same. (done by checkDependencies,
- // so re-use / adapt that)
- if (meth.isJavaDefined)
- // TODODEPMET necessary?? new dependent types: replace symbols in restpe with the ones in vparams
- JavaMethodType(vparams map (p => p setInfo objToAny(p.tpe)), restpe)
- else
- MethodType(vparams, restpe)
- }
+ def deskolemizedPolySig(vparamSymss: List[List[Symbol]], restpe: Type) =
+ GenPolyType(tparamSyms, methodTypeFor(meth, vparamSymss, restpe).substSym(tparamSkolems, tparamSyms))
- val res = GenPolyType(
- tparamSyms, // deSkolemized symbols -- TODO: check that their infos don't refer to method args?
- if (vparamSymss.isEmpty) NullaryMethodType(restpe)
- // vparamss refer (if they do) to skolemized tparams
- else (vparamSymss :\ restpe) (makeMethodType)
- )
- res.substSym(tparamSkolems, tparamSyms)
+ if (tpt.isEmpty && meth.name == nme.CONSTRUCTOR) {
+ tpt defineType context.enclClass.owner.tpe_*
+ tpt setPos meth.pos.focus
}
+ /* since the skolemized tparams are in scope, the TypeRefs in types of vparamSymss refer to the type skolems
+ * note that for parameters with missing types, `methodSig` reassigns types of these symbols (the parameter
+ * types from the overridden method).
+ */
+ val vparamSymss: List[List[Symbol]] = enterValueParams(vparamss)
+
+ val resTpGiven =
+ if (tpt.isEmpty) WildcardType
+ else typer.typedType(tpt).tpe
+
+
+ // ignore missing types unless we can look to overridden method to recover the missing information
+ val canOverride = methOwner.isClass && !meth.isConstructor
+ val inferResTp = canOverride && tpt.isEmpty
+ val inferArgTp = canOverride && settings.YmethodInfer && mexists(vparamss)(_.tpt.isEmpty)
+
+
/*
- * Creates a schematic method type which has WildcardTypes for non specified
- * return or parameter types. For instance, in `def f[T](a: T, b) = ...`, the
- * type schema is
+ * Find the overridden method that matches a schematic method type,
+ * which has WildcardTypes for unspecified return or parameter types.
+ * For instance, in `def f[T](a: T, b) = ...`, the type schema is
*
* PolyType(T, MethodType(List(a: T, b: WildcardType), WildcardType))
*
* where T are non-skolems.
+ *
+ * NOTE: mutates info of symbol of vparamss that don't specify a type
*/
- def methodTypeSchema(resTp: Type) = {
- // for all params without type set WildcaradType
- mforeach(vparamss)(v => if (v.tpt.isEmpty) v.symbol setInfo WildcardType)
- thisMethodType(resTp)
- }
-
- def overriddenSymbol(resTp: Type) = {
- lazy val schema: Type = methodTypeSchema(resTp) // OPT create once. Must be lazy to avoid cycles in neg/t5093.scala
- intersectionType(methOwner.info.parents).nonPrivateMember(meth.name).filter { sym =>
- sym != NoSymbol && (site.memberType(sym) matches schema)
+ val methodSigApproxUnknownArgs: () => Type =
+ if (!inferArgTp) () => deskolemizedPolySig(vparamSymss, resTpGiven)
+ else () => {
+ // for all params without type set WildcardType
+ mforeach(vparamss)(v => if (v.tpt.isEmpty) v.symbol setInfo WildcardType)
+ // must wait to call deskolemizedPolySig until we've temporarily set the WildcardType info for the vparamSymss
+ // (Otherwise, valDefSig will complain about missing argument types.)
+ deskolemizedPolySig(vparamSymss, resTpGiven)
}
- }
- // TODO: see whether this or something similar would work instead:
- // def overriddenSymbol = meth.nextOverriddenSymbol
+ // Must be lazy about the schema to avoid cycles in neg/t5093.scala
+ val overridden =
+ if (!canOverride) NoSymbol
+ else safeNextOverriddenSymbolLazySchema(meth, methodSigApproxUnknownArgs)
/*
- * If `meth` doesn't have an explicit return type, extracts the return type from the method
- * overridden by `meth` (if there's an unique one). This type is lateron used as the expected
+ * If `meth` doesn't have an explicit return type, extract the return type from the method
+ * overridden by `meth` (if there's an unique one). This type is later used as the expected
* type for computing the type of the rhs. The resulting type references type skolems for
* type parameters (consistent with the result of `typer.typedType(tpt).tpe`).
*
- * As a first side effect, this method assigns a MethodType constructed using this
- * return type to `meth`. This allows omitting the result type for recursive methods.
+ * If the result type is missing, assign a MethodType to `meth` that's constructed using this return type.
+ * This allows omitting the result type for recursive methods.
*
- * As another side effect, this method also assigns parameter types from the overridden
- * method to parameters of `meth` that have missing types (the parser accepts missing
- * parameter types under -Yinfer-argument-types).
+ * Missing parameter types are also recovered from the overridden method (by mutating the info of their symbols).
+ * (The parser accepts missing parameter types under -Yinfer-argument-types.)
*/
- def typesFromOverridden(methResTp: Type): Type = {
- val overridden = overriddenSymbol(methResTp)
- if (overridden == NoSymbol || overridden.isOverloaded) {
- methResTp
- } else {
+ val resTpFromOverride =
+ if (!(inferArgTp || inferResTp) || overridden == NoSymbol || overridden.isOverloaded) resTpGiven
+ else {
overridden.cookJavaRawInfo() // #3404 xform java rawtypes into existentials
- var overriddenTp = site.memberType(overridden) match {
- case PolyType(tparams, rt) => rt.substSym(tparams, tparamSkolems)
- case mt => mt
+
+ val (overriddenTparams, overriddenTp) =
+ methOwner.thisType.memberType(overridden) match {
+ case PolyType(tparams, mt) => (tparams, mt.substSym(tparams, tparamSkolems))
+ case mt => (Nil, mt)
}
- for (vparams <- vparamss) {
- var overriddenParams = overriddenTp.params
- for (vparam <- vparams) {
+
+ // try to derive empty parameter types from the overridden method's argument types
+ if (inferArgTp) {
+ val overriddenSyms = overriddenTparams ++ overridden.paramss.flatten
+ val ourSyms = tparamSkolems ++ vparamSymss.flatten
+ foreach2(vparamss, overridden.paramss) { foreach2(_, _) { (vparam, overriddenParam) =>
+ // println(s"infer ${vparam.symbol} from ${overriddenParam}? ${vparam.tpt}")
if (vparam.tpt.isEmpty) {
- val overriddenParamTp = overriddenParams.head.tpe
+ val overriddenParamTp = overriddenParam.tpe.substSym(overriddenSyms, ourSyms)
+ // println(s"inferred ${vparam.symbol} : $overriddenParamTp")
// references to type parameters in overriddenParamTp link to the type skolems, so the
// assigned type is consistent with the other / existing parameter types in vparamSymss.
vparam.symbol setInfo overriddenParamTp
vparam.tpt defineType overriddenParamTp setPos vparam.pos.focus
}
- overriddenParams = overriddenParams.tail
- }
- overriddenTp = overriddenTp.resultType
+ }}
}
- // SI-7668 Substitute parameters from the parent method with those of the overriding method.
- overriddenTp = overriddenTp.substSym(overridden.paramss.flatten, vparamss.flatten.map(_.symbol))
+ @tailrec @inline def applyFully(tp: Type, paramss: List[List[Symbol]]): Type =
+ if (paramss.isEmpty) tp match {
+ case NullaryMethodType(rtpe) => rtpe
+ case MethodType(Nil, rtpe) => rtpe
+ case tp => tp
+ }
+ else applyFully(tp.resultType(paramss.head.map(_.tpe)), paramss.tail)
- overriddenTp match {
- case NullaryMethodType(rtpe) => overriddenTp = rtpe
- case MethodType(List(), rtpe) => overriddenTp = rtpe
- case _ =>
- }
+ if (inferResTp) {
+ // SI-7668 Substitute parameters from the parent method with those of the overriding method.
+ val overriddenResTp = applyFully(overriddenTp, vparamSymss).substSym(overriddenTparams, tparamSkolems)
- if (tpt.isEmpty) {
// provisionally assign `meth` a method type with inherited result type
// that way, we can leave out the result type even if method is recursive.
- meth setInfo thisMethodType(overriddenTp)
- overriddenTp
- } else {
- methResTp
- }
+ meth setInfo deskolemizedPolySig(vparamSymss, overriddenResTp)
+ overriddenResTp
+ } else resTpGiven
}
- }
-
- if (tpt.isEmpty && meth.name == nme.CONSTRUCTOR) {
- tpt defineType context.enclClass.owner.tpe_*
- tpt setPos meth.pos.focus
- }
-
- val methResTp = if (tpt.isEmpty) WildcardType else typer.typedType(tpt).tpe
- val resTpFromOverride = if (methOwner.isClass && (tpt.isEmpty || mexists(vparamss)(_.tpt.isEmpty))) {
- typesFromOverridden(methResTp)
- } else {
- methResTp
- }
-
- // Add a () parameter section if this overrides some method with () parameters
- if (methOwner.isClass && vparamss.isEmpty &&
- overriddenSymbol(methResTp).alternatives.exists(_.info.isInstanceOf[MethodType])) {
- vparamSymss = ListOfNil
- }
// issue an error for missing parameter types
+ // (computing resTpFromOverride may have required inferring some, meanwhile)
mforeach(vparamss) { vparam =>
if (vparam.tpt.isEmpty) {
MissingParameterOrValTypeError(vparam)
@@ -1176,13 +1170,9 @@ trait Namers extends MethodSynthesis {
}
}
- val overridden = {
- val isConstr = meth.isConstructor
- if (isConstr || !methOwner.isClass) NoSymbol else overriddenSymbol(methResTp)
- }
- val hasDefaults = mexists(vparamss)(_.symbol.hasDefault) || mexists(overridden.paramss)(_.hasDefault)
- if (hasDefaults)
- addDefaultGetters(meth, ddef, vparamss, tparams, overridden)
+ // If we, or the overridden method has defaults, add getters for them
+ if (mexists(vparamss)(_.symbol.hasDefault) || mexists(overridden.paramss)(_.hasDefault))
+ addDefaultGetters(meth, ddef, vparamss, tparams, overridden)
// fast track macros, i.e. macros defined inside the compiler, are hardcoded
// hence we make use of that and let them have whatever right-hand side they need
@@ -1193,27 +1183,35 @@ trait Namers extends MethodSynthesis {
// because @macroImpl annotation only gets assigned during typechecking
// otherwise macro defs wouldn't be able to robustly coexist with their clients
// because a client could be typechecked before a macro def that it uses
- if (meth.isMacro) {
- typer.computeMacroDefType(ddef, resTpFromOverride)
+ if (meth.isMacro) typer.computeMacroDefType(ddef, resTpFromOverride) // note: `pt` argument ignored in `computeMacroDefType`
+
+ if (vparamSymss.lengthCompare(0) > 0) { // OPT fast path for methods of 0-1 parameter lists
+ val checkDependencies = new DependentTypeChecker(context)(this)
+ checkDependencies check vparamSymss
}
- val res = thisMethodType({
- val rt = (
- if (!tpt.isEmpty) {
- methResTp
- } else {
- // return type is inferred, we don't just use resTpFromOverride. Here, C.f has type String:
- // trait T { def f: Object }; class C <: T { def f = "" }
- // using resTpFromOverride as expected type allows for the following (C.f has type A):
- // trait T { def f: A }; class C <: T { implicit def b2a(t: B): A = ???; def f = new B }
- assignTypeToTree(ddef, typer, resTpFromOverride)
- })
+ val resTp = {
+ // When return type is inferred, we don't just use resTpFromOverride -- it must be packed and widened.
+ // Here, C.f has type String:
+ // trait T { def f: Object }; class C extends T { def f = "" }
+ // using resTpFromOverride as expected type allows for the following (C.f has type A):
+ // trait T { def f: A }; class C extends T { implicit def b2a(t: B): A = ???; def f = new B }
+ val resTpComputedUnlessGiven =
+ if (tpt.isEmpty) assignTypeToTree(ddef, typer, resTpFromOverride)
+ else resTpGiven
+
// #2382: return type of default getters are always @uncheckedVariance
- if (meth.hasDefault)
- rt.withAnnotation(AnnotationInfo(uncheckedVarianceClass.tpe, List(), List()))
- else rt
- })
- pluginsTypeSig(res, typer, ddef, methResTp)
+ if (meth.hasDefault) resTpComputedUnlessGiven.withAnnotation(AnnotationInfo(uncheckedVarianceClass.tpe, List(), List()))
+ else resTpComputedUnlessGiven
+ }
+
+ // Add a () parameter section if this overrides some method with () parameters
+ val vparamSymssOrEmptyParamsFromOverride =
+ if (overridden != NoSymbol && vparamSymss.isEmpty && overridden.alternatives.exists(_.info.isInstanceOf[MethodType])) ListOfNil // NOTEL must check `.info.isInstanceOf[MethodType]`, not `.isMethod`!
+ else vparamSymss
+
+ val methSig = deskolemizedPolySig(vparamSymssOrEmptyParamsFromOverride, resTp)
+ pluginsTypeSig(methSig, typer, ddef, resTpGiven)
}
/**
@@ -1369,19 +1367,76 @@ trait Namers extends MethodSynthesis {
private def valDefSig(vdef: ValDef) = {
val ValDef(_, _, tpt, rhs) = vdef
- val result = if (tpt.isEmpty) {
- if (rhs.isEmpty) {
- MissingParameterOrValTypeError(tpt)
- ErrorType
- }
- else assignTypeToTree(vdef, typer, WildcardType)
- } else {
- typer.typedType(tpt).tpe
- }
+ val result =
+ if (tpt.isEmpty) {
+ if (rhs.isEmpty) {
+ MissingParameterOrValTypeError(tpt)
+ ErrorType
+ } else {
+ // enterGetterSetter assigns the getter's symbol to a ValDef when there's no underlying field
+ // (a deferred val or most vals defined in a trait -- see Field.noFieldFor)
+ val isGetter = vdef.symbol hasFlag ACCESSOR
+
+ val pt = {
+ val valOwner = owner.owner
+ // there's no overriding outside of classes, and we didn't use to do this in 2.11, so provide opt-out
+ if (valOwner.isClass && settings.isScala212) {
+ // normalize to getter so that we correctly consider a val overriding a def
+ // (a val's name ends in a " ", so can't compare to def)
+ val overridingSym = if (isGetter) vdef.symbol else vdef.symbol.getterIn(valOwner)
+
+ // We're called from an accessorTypeCompleter, which is completing the info for the accessor's symbol,
+ // which may or may not be `vdef.symbol` (see isGetter above)
+ val overridden = safeNextOverriddenSymbol(overridingSym)
+
+ if (overridden == NoSymbol || overridden.isOverloaded) WildcardType
+ else valOwner.thisType.memberType(overridden).resultType
+ } else WildcardType
+ }
+
+ def patchSymInfo(tp: Type): Unit =
+ if (pt ne WildcardType) // no patching up to do if we didn't infer a prototype
+ vdef.symbol setInfo (if (isGetter) NullaryMethodType(tp) else tp)
+
+ patchSymInfo(pt)
+
+ // derives the val's result type from type checking its rhs under the expected type `pt`
+ // vdef.tpt is mutated, and `vdef.tpt.tpe` is `assignTypeToTree`'s result
+ val tptFromRhsUnderPt = assignTypeToTree(vdef, typer, pt)
+
+ // need to re-align with assignTypeToTree, as the type we're returning from valDefSig (tptFromRhsUnderPt)
+ // may actually go to the accessor, not the valdef (and if assignTypeToTree returns a subtype of `pt`,
+ // we would be out of synch between field and its accessors), and thus the type completer won't
+ // fix the symbol's info for us -- we set it to tmpInfo above, which may need to be improved to tptFromRhsUnderPt
+ if (!isGetter) patchSymInfo(tptFromRhsUnderPt)
+
+ tptFromRhsUnderPt
+ }
+ } else typer.typedType(tpt).tpe
+
+// println(s"val: $result / ${vdef.tpt.tpe} / ")
+
pluginsTypeSig(result, typer, vdef, if (tpt.isEmpty) WildcardType else result)
+ }
+ // Pretend we're an erroneous symbol, for now, so that we match while finding the overridden symbol,
+ // but are not considered during implicit search.
+ private def safeNextOverriddenSymbol(sym: Symbol, schema: Type = ErrorType): Symbol = {
+ val savedInfo = sym.rawInfo
+ val savedFlags = sym.rawflags
+ try {
+ sym setInfo schema
+ sym.nextOverriddenSymbol
+ } finally {
+ sym setInfo savedInfo // setInfo resets the LOCKED flag, so restore saved flags as well
+ sym.rawflags = savedFlags
+ }
}
+ private def safeNextOverriddenSymbolLazySchema(sym: Symbol, schema: () => Type): Symbol =
+ safeNextOverriddenSymbol(sym, new LazyType { override def complete(sym: Symbol): Unit = sym setInfo schema() })
+
+
//@M! an abstract type definition (abstract type member/type parameter)
// may take type parameters, which are in scope in its bounds
private def typeDefSig(tdef: TypeDef) = {
@@ -1560,10 +1615,6 @@ trait Namers extends MethodSynthesis {
sym => "[define] >> " + sym.flagString + " " + sym.fullLocationString,
sym => "[define] << " + sym
)
- private def logAndValidate(sym: Symbol)(body: => Unit) {
- logDefinition(sym)(body)
- validate(sym)
- }
/** Convert Java generic array type T[] to (T with Object)[]
* (this is necessary because such arrays have a representation which is incompatible
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index d1764ea482..0eae1ce419 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -298,16 +298,29 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
def infoString(sym: Symbol) = infoString0(sym, sym.owner != clazz)
def infoStringWithLocation(sym: Symbol) = infoString0(sym, true)
- def infoString0(sym: Symbol, showLocation: Boolean) = {
- val sym1 = analyzer.underlyingSymbol(sym)
- sym1.toString() +
+ def infoString0(member: Symbol, showLocation: Boolean) = {
+ val underlying = // not using analyzer.underlyingSymbol(member) because we should get rid of it
+ if (!(member hasFlag ACCESSOR)) member
+ else member.accessed match {
+ case field if field.exists => field
+ case _ if member.isSetter => member.getterIn(member.owner)
+ case _ => member
+ }
+
+ def memberInfo =
+ self.memberInfo(underlying) match {
+ case getterTp if underlying.isGetter => getterTp.resultType
+ case tp => tp
+ }
+
+ underlying.toString() +
(if (showLocation)
- sym1.locationString +
- (if (sym1.isAliasType) ", which equals "+self.memberInfo(sym1)
- else if (sym1.isAbstractType) " with bounds"+self.memberInfo(sym1)
- else if (sym1.isModule) ""
- else if (sym1.isTerm) " of type "+self.memberInfo(sym1)
- else "")
+ underlying.locationString +
+ (if (underlying.isAliasType) s", which equals $memberInfo"
+ else if (underlying.isAbstractType) s" with bounds$memberInfo"
+ else if (underlying.isModule) ""
+ else if (underlying.isTerm) s" of type $memberInfo"
+ else "")
else "")
}
@@ -321,7 +334,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
def memberTp = lowType
def otherTp = highType
- debuglog("Checking validity of %s overriding %s".format(member.fullLocationString, other.fullLocationString))
+// debuglog(s"Checking validity of ${member.fullLocationString} overriding ${other.fullLocationString}")
def noErrorType = !pair.isErroneous
def isRootOrNone(sym: Symbol) = sym != null && sym.isRoot || sym == NoSymbol
@@ -346,9 +359,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
analyzer.foundReqMsg(member.tpe, other.tpe)
else ""
- "overriding %s;\n %s %s%s".format(
- infoStringWithLocation(other), infoString(member), msg, addendum
- )
+ s"overriding ${infoStringWithLocation(other)};\n ${infoString(member)} $msg$addendum"
}
def emitOverrideError(fullmsg: String) {
if (member.owner == clazz) reporter.error(member.pos, fullmsg)
@@ -439,9 +450,11 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
} else if (other.isAbstractOverride && other.isIncompleteIn(clazz) && !member.isAbstractOverride) {
overrideError("needs `abstract override' modifiers")
}
- else if (member.isAnyOverride && (other hasFlag ACCESSOR) && other.accessed.isVariable && !other.accessed.isLazy) {
- // !?! this is not covered by the spec. We need to resolve this either by changing the spec or removing the test here.
- // !!! is there a !?! convention? I'm !!!ing this to make sure it turns up on my searches.
+ else if (member.isAnyOverride && (other hasFlag ACCESSOR) && !(other hasFlag STABLE)) {
+ // The check above used to look at `field` == `other.accessed`, ensuring field.isVariable && !field.isLazy,
+ // which I think is identical to the more direct `!(other hasFlag STABLE)` (given that `other` is a method).
+ // Also, we're moving away from (looking at) underlying fields (vals in traits no longer have them, to begin with)
+ // TODO: this is not covered by the spec. We need to resolve this either by changing the spec or removing the test here.
if (!settings.overrideVars)
overrideError("cannot override a mutable variable")
}
@@ -456,7 +469,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
} else if (member.isValue && member.isLazy &&
other.isValue && !other.isSourceMethod && !other.isDeferred && !other.isLazy) {
overrideError("cannot override a concrete non-lazy value")
- } else if (other.isValue && other.isLazy && !other.isSourceMethod && !other.isDeferred &&
+ } else if (other.isValue && other.isLazy && !other.isSourceMethod && !other.isDeferred && // !(other.hasFlag(MODULE) && other.hasFlag(PACKAGE | JAVA)) && other.hasFlag(LAZY) && (!other.isMethod || other.hasFlag(STABLE)) && !other.hasFlag(DEFERRED)
member.isValue && !member.isLazy) {
overrideError("must be declared lazy to override a concrete lazy value")
} else if (other.isDeferred && member.isTermMacro && member.extendedOverriddenSymbols.forall(_.isDeferred)) { // (1.9)
@@ -547,7 +560,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
}
def checkOverrideDeprecated() {
- if (other.hasDeprecatedOverridingAnnotation && !member.ownerChain.exists(x => x.isDeprecated || x.hasBridgeAnnotation)) {
+ if (other.hasDeprecatedOverridingAnnotation && !(member.hasDeprecatedOverridingAnnotation || member.ownerChain.exists(x => x.isDeprecated || x.hasBridgeAnnotation))) {
val version = other.deprecatedOverridingVersion.getOrElse("")
val since = if (version.isEmpty) version else s" (since $version)"
val message = other.deprecatedOverridingMessage map (msg => s": $msg") getOrElse ""
@@ -651,7 +664,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
for (member <- missing) {
def undefined(msg: String) = abstractClassError(false, infoString(member) + " is not defined" + msg)
- val underlying = analyzer.underlyingSymbol(member)
+ val underlying = analyzer.underlyingSymbol(member) // TODO: don't use this method
// Give a specific error message for abstract vars based on why it fails:
// It could be unimplemented, have only one accessor, or be uninitialized.
@@ -1133,22 +1146,16 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
case _ =>
}
- // SI-6276 warn for `def foo = foo` or `val bar: X = bar`, which come up more frequently than you might think.
- def checkInfiniteLoop(valOrDef: ValOrDefDef) {
- def callsSelf = valOrDef.rhs match {
- case t @ (Ident(_) | Select(This(_), _)) =>
- t hasSymbolWhich (_.accessedOrSelf == valOrDef.symbol)
- case _ => false
+ // SI-6276 warn for trivial recursion, such as `def foo = foo` or `val bar: X = bar`, which come up more frequently than you might think.
+ // TODO: Move to abide rule. Also, this does not check that the def is final or not overridden, for example
+ def checkInfiniteLoop(sym: Symbol, rhs: Tree): Unit =
+ if (!sym.isValueParameter && sym.paramss.isEmpty) {
+ rhs match {
+ case t@(Ident(_) | Select(This(_), _)) if t hasSymbolWhich (_.accessedOrSelf == sym) =>
+ reporter.warning(rhs.pos, s"${sym.fullLocationString} does nothing other than call itself recursively")
+ case _ =>
+ }
}
- val trivialInfiniteLoop = (
- !valOrDef.isErroneous
- && !valOrDef.symbol.isValueParameter
- && valOrDef.symbol.paramss.isEmpty
- && callsSelf
- )
- if (trivialInfiniteLoop)
- reporter.warning(valOrDef.rhs.pos, s"${valOrDef.symbol.fullLocationString} does nothing other than call itself recursively")
- }
// Transformation ------------------------------------------------------------
@@ -1659,16 +1666,19 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
// inside annotations.
applyRefchecksToAnnotations(tree)
var result: Tree = tree match {
- case vod: ValOrDefDef =>
+ // NOTE: a val in a trait is now a DefDef, with the RHS being moved to an Assign in Constructors
+ case tree: ValOrDefDef =>
checkDeprecatedOvers(tree)
- checkInfiniteLoop(vod)
+ if (!tree.isErroneous)
+ checkInfiniteLoop(tree.symbol, tree.rhs)
+
if (settings.warnNullaryUnit)
checkNullaryMethodReturnType(sym)
if (settings.warnInaccessible) {
if (!sym.isConstructor && !sym.isEffectivelyFinalOrNotOverridden && !sym.isSynthetic)
checkAccessibilityOfReferencedTypes(tree)
}
- vod match {
+ tree match {
case dd: DefDef =>
checkByNameRightAssociativeDef(dd)
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
index 5f2643cb25..bee327c760 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -133,12 +133,14 @@ trait TypeDiagnostics {
alternatives(tree) map (x => " " + methodTypeErrorString(x)) mkString ("", " <and>\n", "\n")
/** The symbol which the given accessor represents (possibly in part).
- * This is used for error messages, where we want to speak in terms
- * of the actual declaration or definition, not in terms of the generated setters
- * and getters.
- */
+ * This is used for error messages, where we want to speak in terms
+ * of the actual declaration or definition, not in terms of the generated setters
+ * and getters.
+ *
+ * TODO: is it wise to create new symbols simply to generate error message? is this safe in interactive/resident mode?
+ */
def underlyingSymbol(member: Symbol): Symbol =
- if (!member.hasAccessorFlag) member
+ if (!member.hasAccessorFlag || member.owner.isTrait) member
else if (!member.isDeferred) member.accessed
else {
val getter = if (member.isSetter) member.getterIn(member.owner) else member
@@ -532,8 +534,8 @@ trait TypeDiagnostics {
val what = (
if (sym.isDefaultGetter) "default argument"
else if (sym.isConstructor) "constructor"
- else if (sym.isVar || sym.isGetter && sym.accessed.isVar) "var"
- else if (sym.isVal || sym.isGetter && sym.accessed.isVal || sym.isLazy) "val"
+ else if (sym.isVar || sym.isGetter && (sym.accessed.isVar || (sym.owner.isTrait && !sym.hasFlag(STABLE)))) "var"
+ else if (sym.isVal || sym.isGetter && (sym.accessed.isVal || (sym.owner.isTrait && sym.hasFlag(STABLE))) || sym.isLazy) "val"
else if (sym.isSetter) "setter"
else if (sym.isMethod) "method"
else if (sym.isModule) "object"
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index ba104fb7a6..2bbf8ed74e 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1360,7 +1360,13 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
notAllowed(s"redefinition of $name method. See SIP-15, criterion 4.")
else if (stat.symbol != null && stat.symbol.isParamAccessor)
notAllowed("additional parameter")
+ // concrete accessor (getter) in trait corresponds to a field definition (neg/anytrait.scala)
+ // TODO: only reject accessors that actually give rise to field (e.g., a constant-type val is fine)
+ else if (!isValueClass && stat.symbol.isAccessor && !stat.symbol.isDeferred)
+ notAllowed("field definition")
checkEphemeralDeep.traverse(rhs)
+ // for value class or "exotic" vals in traits
+ // (traits don't receive ValDefs for regular vals until fields phase -- well, except for early initialized/lazy vals)
case _: ValDef =>
notAllowed("field definition")
case _: ModuleDef =>
@@ -4219,7 +4225,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// if (varsym.isVariable ||
// // setter-rewrite has been done above, so rule out methods here, but, wait a minute, why are we assigning to non-variables after erasure?!
// (phase.erasedTypes && varsym.isValue && !varsym.isMethod)) {
- if (varsym.isVariable || varsym.isValue && phase.erasedTypes) {
+ if (varsym.isVariable || varsym.isValue && phase.assignsFields) {
val rhs1 = typedByValueExpr(rhs, lhs1.tpe)
treeCopy.Assign(tree, lhs1, checkDead(rhs1)) setType UnitTpe
}
diff --git a/src/library/scala/deprecatedInheritance.scala b/src/library/scala/deprecatedInheritance.scala
index bd5daf5de0..994eac9ed8 100644
--- a/src/library/scala/deprecatedInheritance.scala
+++ b/src/library/scala/deprecatedInheritance.scala
@@ -8,6 +8,8 @@
package scala
+import scala.annotation.meta._
+
/** An annotation that designates that inheriting from a class is deprecated.
*
* This is usually done to warn about a non-final class being made final in a future version.
@@ -41,4 +43,5 @@ package scala
* @see [[scala.deprecatedOverriding]]
* @see [[scala.deprecatedName]]
*/
+@getter @setter @beanGetter @beanSetter
class deprecatedInheritance(message: String = "", since: String = "") extends scala.annotation.StaticAnnotation
diff --git a/src/library/scala/deprecatedOverriding.scala b/src/library/scala/deprecatedOverriding.scala
index 46639986c0..5be6830b27 100644
--- a/src/library/scala/deprecatedOverriding.scala
+++ b/src/library/scala/deprecatedOverriding.scala
@@ -8,6 +8,8 @@
package scala
+import scala.annotation.meta._
+
/** An annotation that designates that overriding a member is deprecated.
*
* Overriding such a member in a sub-class then generates a warning.
@@ -42,4 +44,5 @@ package scala
* @see [[scala.deprecatedInheritance]]
* @see [[scala.deprecatedName]]
*/
+@getter @setter @beanGetter @beanSetter
class deprecatedOverriding(message: String = "", since: String = "") extends scala.annotation.StaticAnnotation
diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
index fa19103d0c..d58cabf3d7 100644
--- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala
+++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
@@ -305,10 +305,13 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
}
/** The default kind of members to which this annotation is attached.
- * For instance, for scala.deprecated defaultTargets =
- * List(getter, setter, beanGetter, beanSetter).
- */
- def defaultTargets = symbol.annotations map (_.symbol) filter isMetaAnnotation
+ * For instance, for scala.deprecated defaultTargets =
+ * List(getter, setter, beanGetter, beanSetter).
+ *
+ * NOTE: have to call symbol.initialize, since we won't get any annotations if the symbol hasn't yet been completed
+ */
+ def defaultTargets = symbol.initialize.annotations map (_.symbol) filter isMetaAnnotation
+
// Test whether the typeSymbol of atp conforms to the given class.
def matches(clazz: Symbol) = !symbol.isInstanceOf[StubSymbol] && (symbol isNonBottomSubClass clazz)
// All subtrees of all args are considered.
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 3dec73da58..35ec80901e 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -674,8 +674,10 @@ trait Definitions extends api.StandardDefinitions {
// Note that these call .dealiasWiden and not .normalize, the latter of which
// tends to change the course of events by forcing types.
def isFunctionType(tp: Type) = isFunctionTypeDirect(tp.dealiasWiden)
+
// the number of arguments expected by the function described by `tp` (a FunctionN or SAM type),
// or `-1` if `tp` does not represent a function type or SAM
+ // for use during typers (after fields, samOf will be confused by abstract accessors for trait fields)
def functionArityFromType(tp: Type) = {
val dealiased = tp.dealiasWiden
if (isFunctionTypeDirect(dealiased)) dealiased.typeArgs.length - 1
@@ -685,16 +687,6 @@ trait Definitions extends api.StandardDefinitions {
}
}
- // the result type of a function or corresponding SAM type
- def functionResultType(tp: Type): Type = {
- val dealiased = tp.dealiasWiden
- if (isFunctionTypeDirect(dealiased)) dealiased.typeArgs.last
- else samOf(tp) match {
- case samSym if samSym.exists => tp.memberInfo(samSym).resultType.deconst
- case _ => NoType
- }
- }
-
// the SAM's parameters and the Function's formals must have the same length
// (varargs etc don't come into play, as we're comparing signatures, not checking an application)
def samMatchesFunctionBasedOnArity(sam: Symbol, formals: List[Any]): Boolean =
diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala
index e06decea6d..d088150db6 100644
--- a/src/reflect/scala/reflect/internal/Flags.scala
+++ b/src/reflect/scala/reflect/internal/Flags.scala
@@ -169,6 +169,11 @@ class Flags extends ModifierFlags {
final val SYNCHRONIZED = 1L << 45 // symbol is a method which should be marked ACC_SYNCHRONIZED
+ final val SYNTHESIZE_IMPL_IN_SUBCLASS = 1L << 50 // used in fields phase to indicate this accessor should receive an implementation in a subclass
+
+ // flags used strictly internally in the Fields phase (info/tree transform):
+ final val NEEDS_TREES = 1L << 59 // this symbol needs a tree. (distinct from SYNTHESIZE_IMPL_IN_SUBCLASS)
+
// ------- shift definitions -------------------------------------------------------
//
// Flags from 1L to (1L << 50) are normal flags.
@@ -257,7 +262,8 @@ class Flags extends ModifierFlags {
/** These modifiers appear in TreePrinter output. */
final val PrintableFlags =
ExplicitFlags | BridgeFlags | LOCAL | SYNTHETIC | STABLE | CASEACCESSOR | MACRO |
- ACCESSOR | SUPERACCESSOR | PARAMACCESSOR | STATIC | SPECIALIZED | SYNCHRONIZED | ARTIFACT
+ ACCESSOR | SUPERACCESSOR | PARAMACCESSOR | STATIC | SPECIALIZED | SYNCHRONIZED | ARTIFACT |
+ SYNTHESIZE_IMPL_IN_SUBCLASS | NEEDS_TREES
/** When a symbol for a field is created, only these flags survive
* from Modifiers. Others which may be applied at creation time are:
@@ -442,7 +448,7 @@ class Flags extends ModifierFlags {
case JAVA_DEFAULTMETHOD => "<defaultmethod>" // (1L << 47)
case JAVA_ENUM => "<enum>" // (1L << 48)
case JAVA_ANNOTATION => "<annotation>" // (1L << 49)
- case 0x4000000000000L => "" // (1L << 50)
+ case SYNTHESIZE_IMPL_IN_SUBCLASS => "<sub_synth>" // (1L << 50)
case `lateDEFERRED` => "<latedeferred>" // (1L << 51)
case `lateFINAL` => "<latefinal>" // (1L << 52)
case `lateMETHOD` => "<latemethod>" // (1L << 53)
@@ -451,7 +457,7 @@ class Flags extends ModifierFlags {
case `notPROTECTED` => "<notprotected>" // (1L << 56)
case `notOVERRIDE` => "<notoverride>" // (1L << 57)
case `notPRIVATE` => "<notprivate>" // (1L << 58)
- case 0x800000000000000L => "" // (1L << 59)
+ case NEEDS_TREES => "<needs_trees>" // (1L << 59)
case 0x1000000000000000L => "" // (1L << 60)
case 0x2000000000000000L => "" // (1L << 61)
case 0x4000000000000000L => "" // (1L << 62)
diff --git a/src/reflect/scala/reflect/internal/Phase.scala b/src/reflect/scala/reflect/internal/Phase.scala
index a761f686e6..f56c41d71c 100644
--- a/src/reflect/scala/reflect/internal/Phase.scala
+++ b/src/reflect/scala/reflect/internal/Phase.scala
@@ -47,6 +47,8 @@ abstract class Phase(val prev: Phase) {
final val specialized: Boolean = ((prev ne null) && (prev ne NoPhase)) && (prev.name == "specialize" || prev.specialized)
final val refChecked: Boolean = ((prev ne null) && (prev ne NoPhase)) && (prev.name == "refchecks" || prev.refChecked)
+ // are we past the fields phase, so that we should allow writing to vals (as part of type checking trait setters)
+ final val assignsFields: Boolean = ((prev ne null) && (prev ne NoPhase)) && (prev.name == "fields" || prev.assignsFields)
/** This is used only in unsafeTypeParams, and at this writing is
* overridden to false in parser, namer, typer, and erasure. (And NoPhase.)
diff --git a/src/reflect/scala/reflect/internal/ReificationSupport.scala b/src/reflect/scala/reflect/internal/ReificationSupport.scala
index 30f2efd7e3..33ca78b439 100644
--- a/src/reflect/scala/reflect/internal/ReificationSupport.scala
+++ b/src/reflect/scala/reflect/internal/ReificationSupport.scala
@@ -285,6 +285,7 @@ trait ReificationSupport { self: SymbolTable =>
val (gvdefs, etdefs) = rawEdefs.partition(treeInfo.isEarlyValDef)
val (fieldDefs, UnCtor(ctorMods, ctorVparamss, lvdefs) :: body) = rest.splitAt(indexOfCtor(rest))
val evdefs = gvdefs.zip(lvdefs).map {
+ // TODO: in traits, early val defs are defdefs
case (gvdef @ ValDef(_, _, tpt: TypeTree, _), ValDef(_, _, _, rhs)) =>
copyValDef(gvdef)(tpt = tpt.original, rhs = rhs)
case (tr1, tr2) =>
diff --git a/src/reflect/scala/reflect/internal/SymbolPairs.scala b/src/reflect/scala/reflect/internal/SymbolPairs.scala
index a52d2d8510..320c814696 100644
--- a/src/reflect/scala/reflect/internal/SymbolPairs.scala
+++ b/src/reflect/scala/reflect/internal/SymbolPairs.scala
@@ -30,27 +30,6 @@ abstract class SymbolPairs {
val global: SymbolTable
import global._
- /** Type operations relative to a prefix. All operations work on Symbols,
- * and the types are the member types of those symbols in the prefix.
- */
- class RelativeTo(val prefix: Type) {
- def this(clazz: Symbol) = this(clazz.thisType)
- import scala.language.implicitConversions // geez, it even has to hassle me when it's private
- private implicit def symbolToType(sym: Symbol): Type = prefix memberType sym
-
- def erasureOf(sym: Symbol): Type = erasure.erasure(sym)(sym: Type)
- def signature(sym: Symbol): String = sym defStringSeenAs (sym: Type)
- def erasedSignature(sym: Symbol): String = sym defStringSeenAs erasureOf(sym)
-
- def isSameType(sym1: Symbol, sym2: Symbol): Boolean = sym1 =:= sym2
- def isSubType(sym1: Symbol, sym2: Symbol): Boolean = sym1 <:< sym2
- def isSuperType(sym1: Symbol, sym2: Symbol): Boolean = sym2 <:< sym1
- def isSameErasure(sym1: Symbol, sym2: Symbol): Boolean = erasureOf(sym1) =:= erasureOf(sym2)
- def matches(sym1: Symbol, sym2: Symbol): Boolean = (sym1: Type) matches (sym2: Type)
-
- override def toString = s"RelativeTo($prefix)"
- }
-
/** Are types tp1 and tp2 equivalent seen from the perspective
* of `baseClass`? For instance List[Int] and Seq[Int] are =:=
* when viewed from IterableClass.
@@ -58,10 +37,11 @@ abstract class SymbolPairs {
def sameInBaseClass(baseClass: Symbol)(tp1: Type, tp2: Type) =
(tp1 baseType baseClass) =:= (tp2 baseType baseClass)
- case class SymbolPair(base: Symbol, low: Symbol, high: Symbol) {
+ final case class SymbolPair(base: Symbol, low: Symbol, high: Symbol) {
+ private[this] val self = base.thisType
+
def pos = if (low.owner == base) low.pos else if (high.owner == base) high.pos else base.pos
- def self: Type = base.thisType
- def rootType: Type = base.thisType
+ def rootType: Type = self
def lowType: Type = self memberType low
def lowErased: Type = erasure.specialErasure(base)(low.tpe)
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index ab52a875f8..af1cdafcda 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -96,8 +96,12 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def isByNameParam: Boolean = this.isValueParameter && (this hasFlag BYNAMEPARAM)
def isImplementationArtifact: Boolean = (this hasFlag BRIDGE) || (this hasFlag VBRIDGE) || (this hasFlag ARTIFACT)
def isJava: Boolean = isJavaDefined
- def isVal: Boolean = isTerm && !isModule && !isMethod && !isMutable
- def isVar: Boolean = isTerm && !isModule && !isMethod && !isLazy && isMutable
+
+ def isField: Boolean = isTerm && !isModule && (!isMethod || owner.isTrait && isAccessor)
+ def isMutableVal = if (owner.isTrait) !hasFlag(STABLE) else isMutable
+ def isVal: Boolean = isField && !isMutableVal
+ def isVar: Boolean = isField && !isLazy && isMutableVal
+
def isAbstract: Boolean = isAbstractClass || isDeferred || isAbstractType
def isPrivateThis = (this hasFlag PRIVATE) && (this hasFlag LOCAL)
def isProtectedThis = (this hasFlag PROTECTED) && (this hasFlag LOCAL)
@@ -1532,7 +1536,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def setInfo(info: Type): this.type = { info_=(info); this }
/** Modifies this symbol's info in place. */
def modifyInfo(f: Type => Type): this.type = setInfo(f(info))
- /** Substitute second list of symbols for first in current info. */
+ /** Substitute second list of symbols for first in current info.
+ *
+ * NOTE: this discards the type history (uses setInfo)
+ */
def substInfo(syms0: List[Symbol], syms1: List[Symbol]): this.type =
if (syms0.isEmpty) this
else modifyInfo(_.substSym(syms0, syms1))
@@ -2048,7 +2055,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
assert(hasAccessorFlag, this)
val localField = owner.info decl localName
- if (localField == NoSymbol && this.hasFlag(MIXEDIN)) {
+ if (localField == NoSymbol && this.hasFlag(MIXEDIN)) { // TODO: fields phase does not (yet?) add MIXEDIN in setMixedinAccessorFlags
// SI-8087: private[this] fields don't have a `localName`. When searching the accessed field
// for a mixin accessor of such a field, we need to look for `name` instead.
// The phase travel ensures that the field is found (`owner` is the trait class symbol, the
@@ -2088,8 +2095,15 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** If this is a lazy value, the lazy accessor; otherwise this symbol. */
def lazyAccessorOrSelf: Symbol = if (isLazy) lazyAccessor else this
- /** If this is an accessor, the accessed symbol. Otherwise, this symbol. */
- def accessedOrSelf: Symbol = if (hasAccessorFlag) accessed else this
+ /** `accessed`, if this is an accessor that should have an underlying field. Otherwise, `this`.
+ * Note that a "regular" accessor in a trait does not have a field, as an interface cannot define a field.
+ * "non-regular" vals are: early initialized or lazy vals.
+ * Eventually, we should delay introducing symbols for all val/vars until the fields (or lazyvals) phase,
+ * as they are an implementation detail that's irrelevant to type checking.
+ */
+ def accessedOrSelf: Symbol =
+ if (hasAccessorFlag && (!owner.isTrait || hasFlag(PRESUPER | LAZY))) accessed
+ else this
/** For an outer accessor: The class from which the outer originates.
* For all other symbols: NoSymbol
@@ -2532,30 +2546,34 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
private def symbolKind: SymbolKind = {
var kind =
- if (isTermMacro) ("term macro", "macro method", "MACM")
- else if (isInstanceOf[FreeTermSymbol]) ("free term", "free term", "FTE")
- else if (isInstanceOf[FreeTypeSymbol]) ("free type", "free type", "FTY")
- else if (isPackageClass) ("package class", "package", "PKC")
- else if (hasPackageFlag) ("package", "package", "PK")
- else if (isPackageObject) ("package object", "package", "PKO")
- else if (isPackageObjectClass) ("package object class", "package", "PKOC")
- else if (isAnonymousClass) ("anonymous class", "anonymous class", "AC")
- else if (isRefinementClass) ("refinement class", "", "RC")
- else if (isModule) ("module", "object", "MOD")
- else if (isModuleClass) ("module class", "object", "MODC")
- else if (isGetter) ("getter", if (isSourceMethod) "method" else "value", "GET")
- else if (isSetter) ("setter", if (isSourceMethod) "method" else "value", "SET")
- else if (isTerm && isLazy) ("lazy value", "lazy value", "LAZ")
- else if (isVariable) ("field", "variable", "VAR")
- else if (isTrait) ("trait", "trait", "TRT")
- else if (isClass) ("class", "class", "CLS")
- else if (isType) ("type", "type", "TPE")
- else if (isClassConstructor && (owner.hasCompleteInfo && isPrimaryConstructor)) ("primary constructor", "constructor", "PCTOR")
- else if (isClassConstructor) ("constructor", "constructor", "CTOR")
- else if (isSourceMethod) ("method", "method", "METH")
- else if (isTerm) ("value", "value", "VAL")
- else ("", "", "???")
+ if (isTermMacro) ("term macro", "macro method", "MACM")
+ else if (isInstanceOf[FreeTermSymbol]) ("free term", "free term", "FTE")
+ else if (isInstanceOf[FreeTypeSymbol]) ("free type", "free type", "FTY")
+ else if (isPackageClass) ("package class", "package", "PKC")
+ else if (hasPackageFlag) ("package", "package", "PK")
+ else if (isPackageObject) ("package object", "package", "PKO")
+ else if (isPackageObjectClass) ("package object class", "package", "PKOC")
+ else if (isAnonymousClass) ("anonymous class", "anonymous class", "AC")
+ else if (isRefinementClass) ("refinement class", "", "RC")
+ else if (isModule) ("module", "object", "MOD")
+ else if (isModuleClass) ("module class", "object", "MODC")
+ else if (isAccessor &&
+ !hasFlag(STABLE | LAZY)) ("setter", "variable", "SET")
+ else if (isAccessor && !hasFlag(LAZY)) ("getter", "value", "GET")
+ else if (isTerm && hasFlag(LAZY)) ("lazy value", "lazy value", "LAZ")
+ else if (isVariable) ("field", "variable", "VAR")
+ else if (isTrait) ("trait", "trait", "TRT")
+ else if (isClass) ("class", "class", "CLS")
+ else if (isType) ("type", "type", "TPE")
+ else if (isClassConstructor && (owner.hasCompleteInfo &&
+ isPrimaryConstructor)) ("primary constructor", "constructor", "PCTOR")
+ else if (isClassConstructor) ("constructor", "constructor", "CTOR")
+ else if (isMethod) ("method", "method", "METH")
+ else if (isTerm) ("value", "value", "VAL")
+ else ("", "", "???")
+
if (isSkolem) kind = (kind._1, kind._2, kind._3 + "#SKO")
+
SymbolKind(kind._1, kind._2, kind._3)
}
@@ -2623,12 +2641,17 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* If hasMeaninglessName is true, uses the owner's name to disambiguate identity.
*/
override def toString: String = {
- if (isPackageObjectOrClass && !settings.debug)
- s"package object ${owner.decodedName}"
- else compose(
- kindString,
- if (hasMeaninglessName) owner.decodedName + idString else nameString
- )
+ val simplifyNames = !settings.debug
+ if (isPackageObjectOrClass && simplifyNames) s"package object ${owner.decodedName}"
+ else {
+ val kind = kindString
+ val _name: String =
+ if (hasMeaninglessName) owner.decodedName + idString
+ else if (simplifyNames && (kind == "variable" || kind == "value")) unexpandedName.getterName.decode.toString // TODO: make condition less gross?
+ else nameString
+
+ compose(kind, _name)
+ }
}
/** String representation of location.
@@ -2764,18 +2787,21 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
)
***/
override def isValueParameter = this hasFlag PARAM
-
override def isSetterParameter = isValueParameter && owner.isSetter
- override def isAccessor = this hasFlag ACCESSOR
- override def isGetter = isAccessor && !isSetter
+
override def isDefaultGetter = name containsName nme.DEFAULT_GETTER_STRING
- override def isSetter = isAccessor && nme.isSetterName(name) // todo: make independent of name, as this can be forged.
+
+ override def isAccessor = this hasFlag ACCESSOR
+ override def isGetter = isAccessor && !nme.isSetterName(name) // TODO: make independent of name, as this can be forged.
+ override def isSetter = isAccessor && nme.isSetterName(name) // TODO: make independent of name, as this can be forged.
+
override def isLocalDummy = nme.isLocalDummyName(name)
+
override def isClassConstructor = name == nme.CONSTRUCTOR
override def isMixinConstructor = name == nme.MIXIN_CONSTRUCTOR
- override def isConstructor = nme.isConstructorName(name)
+ override def isConstructor = isClassConstructor || isMixinConstructor
- override def isPackageObject = isModule && (name == nme.PACKAGE)
+ override def isPackageObject = isModule && (name == nme.PACKAGE)
// The name in comments is what it is being disambiguated from.
// TODO - rescue CAPTURED from BYNAMEPARAM so we can see all the names.
@@ -2900,10 +2926,15 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def isVarargsMethod = this hasFlag VARARGS
override def isLiftedMethod = this hasFlag LIFTED
- // TODO - this seems a strange definition for "isSourceMethod", given that
- // it does not make any specific effort to exclude synthetics. Figure out what
- // this method is really for and what logic makes sense.
- override def isSourceMethod = !(this hasFlag STABLE) // exclude all accessors
+ // TODO: this definition of isSourceMethod makes no sense -- inline it and re-evaluate at each call site.
+ // I'm guessing it meant "method written by user, and not generated by the compiler"
+ // (And then assuming those generated by the compiler don't require certain transformations?)
+ // Use SYNTHETIC/ARTIFACT instead as an indicator? I don't see how it makes sense to only exclude getters.
+ // Note also that trait vals are modelled as getters, and thus that user-supplied code appears in their rhs.
+ // Originally, it may have been an optimization to skip methods that were not user-defined (getters),
+ // but it doesn't even exclude setters, contrary to its original comment (// exclude all accessors)
+ override def isSourceMethod = !(this hasFlag STABLE)
+
// unfortunately having the CASEACCESSOR flag does not actually mean you
// are a case accessor (you can also be a field.)
override def isCaseAccessorMethod = isCaseAccessor
diff --git a/test/files/neg/overloaded-unapply.check b/test/files/neg/overloaded-unapply.check
index 68a826bac2..3951166de5 100644
--- a/test/files/neg/overloaded-unapply.check
+++ b/test/files/neg/overloaded-unapply.check
@@ -7,8 +7,8 @@ match argument types (List[a])
overloaded-unapply.scala:22: error: cannot resolve overloaded unapply
case List(x, xs) => 7
^
-overloaded-unapply.scala:12: error: method unapply is defined twice
- conflicting symbols both originated in file 'overloaded-unapply.scala'
+overloaded-unapply.scala:12: error: method unapply is defined twice;
+ the conflicting method unapply was defined at line 7:7
def unapply[a](xs: List[a]): Option[Null] = xs match {
^
three errors found
diff --git a/test/files/neg/t1960.check b/test/files/neg/t1960.check
index 5238141c4e..de0907b4a9 100644
--- a/test/files/neg/t1960.check
+++ b/test/files/neg/t1960.check
@@ -1,4 +1,4 @@
-t1960.scala:5: error: parameter 'p' requires field but conflicts with method p in trait TBase
+t1960.scala:5: error: parameter 'p' requires field but conflicts with variable p in trait TBase
class Aclass (p: Int) extends TBase { def g() { f(p) } }
^
one error found
diff --git a/test/files/neg/t200.check b/test/files/neg/t200.check
index b6b1a32267..f0c5e77772 100644
--- a/test/files/neg/t200.check
+++ b/test/files/neg/t200.check
@@ -1,5 +1,5 @@
-t200.scala:7: error: method foo is defined twice
- conflicting symbols both originated in file 't200.scala'
+t200.scala:7: error: method foo is defined twice;
+ the conflicting method foo was defined at line 6:7
def foo: Int;
^
one error found
diff --git a/test/files/neg/t2779.check b/test/files/neg/t2779.check
index 0ab4c50d0f..9881d5182c 100644
--- a/test/files/neg/t2779.check
+++ b/test/files/neg/t2779.check
@@ -1,5 +1,5 @@
-t2779.scala:16: error: method f is defined twice
- conflicting symbols both originated in file 't2779.scala'
+t2779.scala:16: error: method f is defined twice;
+ the conflicting method f was defined at line 15:18
override def f = List(M1)
^
one error found
diff --git a/test/files/neg/t278.check b/test/files/neg/t278.check
index 405f7d225c..940b8edcef 100644
--- a/test/files/neg/t278.check
+++ b/test/files/neg/t278.check
@@ -4,8 +4,8 @@ t278.scala:5: error: overloaded method value a with alternatives:
does not take type parameters
println(a[A])
^
-t278.scala:4: error: method a is defined twice
- conflicting symbols both originated in file 't278.scala'
+t278.scala:4: error: method a is defined twice;
+ the conflicting method a was defined at line 3:7
def a = (p:A) => ()
^
two errors found
diff --git a/test/files/neg/t3871.check b/test/files/neg/t3871.check
index b920357ee6..c9667abfb6 100644
--- a/test/files/neg/t3871.check
+++ b/test/files/neg/t3871.check
@@ -1,5 +1,5 @@
t3871.scala:4: error: variable foo in class Sub2 cannot be accessed in Sub2
- Access to protected method foo not permitted because
+ Access to protected variable foo not permitted because
enclosing class Base is not a subclass of
class Sub2 where target is defined
s.foo = true
diff --git a/test/files/neg/t4541.check b/test/files/neg/t4541.check
index 7bd8ff78f9..7ee0cc6414 100644
--- a/test/files/neg/t4541.check
+++ b/test/files/neg/t4541.check
@@ -1,5 +1,5 @@
t4541.scala:11: error: variable data in class Sparse cannot be accessed in Sparse[Int]
- Access to protected method data not permitted because
+ Access to protected variable data not permitted because
prefix type Sparse[Int] does not conform to
class Sparse$mcI$sp where the access take place
that.data
diff --git a/test/files/neg/t4541b.check b/test/files/neg/t4541b.check
index 8a52fd97f4..2aae95f6b9 100644
--- a/test/files/neg/t4541b.check
+++ b/test/files/neg/t4541b.check
@@ -1,5 +1,5 @@
t4541b.scala:13: error: variable data in class SparseArray cannot be accessed in SparseArray[Int]
- Access to protected method data not permitted because
+ Access to protected variable data not permitted because
prefix type SparseArray[Int] does not conform to
class SparseArray$mcI$sp where the access take place
use(that.data.clone)
diff --git a/test/files/neg/t5429.check b/test/files/neg/t5429.check
index 4350696bc8..fb2d9c2e47 100644
--- a/test/files/neg/t5429.check
+++ b/test/files/neg/t5429.check
@@ -134,7 +134,7 @@ t5429.scala:87: error: overriding value value in class A0 of type Any;
lazy value value cannot override a concrete non-lazy value
override lazy val value = 0 // fail (strict over lazy)
^
-t5429.scala:91: error: value oneArg overrides nothing.
+t5429.scala:91: error: lazy value oneArg overrides nothing.
Note: the super classes of class F0 contain the following, non final members named oneArg:
def oneArg(x: String): Any
override lazy val oneArg = 15 // fail
diff --git a/test/files/neg/t591.check b/test/files/neg/t591.check
index d33f6d7a2f..c0bade0814 100644
--- a/test/files/neg/t591.check
+++ b/test/files/neg/t591.check
@@ -1,5 +1,5 @@
-t591.scala:38: error: method input_= is defined twice
- conflicting symbols both originated in file 't591.scala'
+t591.scala:40: error: method input_= is defined twice;
+ the conflicting variable input was defined at line 35:18
def input_=(in : Input) = {}
^
one error found
diff --git a/test/files/neg/t591.scala b/test/files/neg/t591.scala
index 0f0b02395c..14fb256a69 100644
--- a/test/files/neg/t591.scala
+++ b/test/files/neg/t591.scala
@@ -35,7 +35,8 @@ trait BaseFlow extends BaseList {
private var input : Input = _;
private var output : Output = _;
+ // the error message is a bit confusing, as it points here,
+ // but the symbol it reports is `input`'s actual setter (the one we synthesized)
def input_=(in : Input) = {}
-
}
}
diff --git a/test/files/neg/t6335.check b/test/files/neg/t6335.check
index 1727a05eb2..d118440f75 100644
--- a/test/files/neg/t6335.check
+++ b/test/files/neg/t6335.check
@@ -1,9 +1,9 @@
-t6335.scala:6: error: method Z is defined twice
- conflicting symbols both originated in file 't6335.scala'
+t6335.scala:6: error: method Z is defined twice;
+ the conflicting method Z was defined at line 5:7
implicit class Z[A](val i: A) { def zz = i }
^
-t6335.scala:3: error: method X is defined twice
- conflicting symbols both originated in file 't6335.scala'
+t6335.scala:3: error: method X is defined twice;
+ the conflicting method X was defined at line 2:7
implicit class X(val x: Int) { def xx = x }
^
two errors found
diff --git a/test/files/neg/t6446-additional.check b/test/files/neg/t6446-additional.check
index e56a67b28b..45db63317c 100644
--- a/test/files/neg/t6446-additional.check
+++ b/test/files/neg/t6446-additional.check
@@ -10,18 +10,19 @@ superaccessors 6 add super accessors in traits and nested classes
pickler 8 serialize symbol tables
refchecks 9 reference/override checking, translate nested objects
uncurry 10 uncurry, translate function values to anonymous classes
- tailcalls 11 replace tail calls by jumps
- specialize 12 @specialized-driven class and method specialization
- explicitouter 13 this refs to outer pointers
- erasure 14 erase types, add interfaces for traits
- posterasure 15 clean up erased inline classes
- lazyvals 16 allocate bitmaps, translate lazy vals into lazified defs
- lambdalift 17 move nested functions to top level
- constructors 18 move field definitions into constructors
- flatten 19 eliminate inner classes
- mixin 20 mixin composition
- cleanup 21 platform-specific cleanups, generate reflective calls
- delambdafy 22 remove lambdas
- jvm 23 generate JVM bytecode
- ploogin 24 A sample phase that does so many things it's kind of hard...
- terminal 25 the last phase during a compilation run
+ fields 11 synthesize accessors and fields
+ tailcalls 12 replace tail calls by jumps
+ specialize 13 @specialized-driven class and method specialization
+ explicitouter 14 this refs to outer pointers
+ erasure 15 erase types, add interfaces for traits
+ posterasure 16 clean up erased inline classes
+ lazyvals 17 allocate bitmaps, translate lazy vals into lazified defs
+ lambdalift 18 move nested functions to top level
+ constructors 19 move field definitions into constructors
+ flatten 20 eliminate inner classes
+ mixin 21 mixin composition
+ cleanup 22 platform-specific cleanups, generate reflective calls
+ delambdafy 23 remove lambdas
+ jvm 24 generate JVM bytecode
+ ploogin 25 A sample phase that does so many things it's kind of hard...
+ terminal 26 the last phase during a compilation run
diff --git a/test/files/neg/t6446-missing.check b/test/files/neg/t6446-missing.check
index 15f0ceb6e3..04523d18e6 100644
--- a/test/files/neg/t6446-missing.check
+++ b/test/files/neg/t6446-missing.check
@@ -11,17 +11,18 @@ superaccessors 6 add super accessors in traits and nested classes
pickler 8 serialize symbol tables
refchecks 9 reference/override checking, translate nested objects
uncurry 10 uncurry, translate function values to anonymous classes
- tailcalls 11 replace tail calls by jumps
- specialize 12 @specialized-driven class and method specialization
- explicitouter 13 this refs to outer pointers
- erasure 14 erase types, add interfaces for traits
- posterasure 15 clean up erased inline classes
- lazyvals 16 allocate bitmaps, translate lazy vals into lazified defs
- lambdalift 17 move nested functions to top level
- constructors 18 move field definitions into constructors
- flatten 19 eliminate inner classes
- mixin 20 mixin composition
- cleanup 21 platform-specific cleanups, generate reflective calls
- delambdafy 22 remove lambdas
- jvm 23 generate JVM bytecode
- terminal 24 the last phase during a compilation run
+ fields 11 synthesize accessors and fields
+ tailcalls 12 replace tail calls by jumps
+ specialize 13 @specialized-driven class and method specialization
+ explicitouter 14 this refs to outer pointers
+ erasure 15 erase types, add interfaces for traits
+ posterasure 16 clean up erased inline classes
+ lazyvals 17 allocate bitmaps, translate lazy vals into lazified defs
+ lambdalift 18 move nested functions to top level
+ constructors 19 move field definitions into constructors
+ flatten 20 eliminate inner classes
+ mixin 21 mixin composition
+ cleanup 22 platform-specific cleanups, generate reflective calls
+ delambdafy 23 remove lambdas
+ jvm 24 generate JVM bytecode
+ terminal 25 the last phase during a compilation run
diff --git a/test/files/neg/t6446-show-phases.check b/test/files/neg/t6446-show-phases.check
index 280a4f43d5..03f8273c17 100644
--- a/test/files/neg/t6446-show-phases.check
+++ b/test/files/neg/t6446-show-phases.check
@@ -10,17 +10,18 @@ superaccessors 6 add super accessors in traits and nested classes
pickler 8 serialize symbol tables
refchecks 9 reference/override checking, translate nested objects
uncurry 10 uncurry, translate function values to anonymous classes
- tailcalls 11 replace tail calls by jumps
- specialize 12 @specialized-driven class and method specialization
- explicitouter 13 this refs to outer pointers
- erasure 14 erase types, add interfaces for traits
- posterasure 15 clean up erased inline classes
- lazyvals 16 allocate bitmaps, translate lazy vals into lazified defs
- lambdalift 17 move nested functions to top level
- constructors 18 move field definitions into constructors
- flatten 19 eliminate inner classes
- mixin 20 mixin composition
- cleanup 21 platform-specific cleanups, generate reflective calls
- delambdafy 22 remove lambdas
- jvm 23 generate JVM bytecode
- terminal 24 the last phase during a compilation run
+ fields 11 synthesize accessors and fields
+ tailcalls 12 replace tail calls by jumps
+ specialize 13 @specialized-driven class and method specialization
+ explicitouter 14 this refs to outer pointers
+ erasure 15 erase types, add interfaces for traits
+ posterasure 16 clean up erased inline classes
+ lazyvals 17 allocate bitmaps, translate lazy vals into lazified defs
+ lambdalift 18 move nested functions to top level
+ constructors 19 move field definitions into constructors
+ flatten 20 eliminate inner classes
+ mixin 21 mixin composition
+ cleanup 22 platform-specific cleanups, generate reflective calls
+ delambdafy 23 remove lambdas
+ jvm 24 generate JVM bytecode
+ terminal 25 the last phase during a compilation run
diff --git a/test/files/neg/t6666.check b/test/files/neg/t6666.check
index 43c8252753..090ef72770 100644
--- a/test/files/neg/t6666.check
+++ b/test/files/neg/t6666.check
@@ -1,7 +1,7 @@
t6666.scala:23: error: Implementation restriction: access of method x$2 in object O1 from <$anon: Function0>, would require illegal premature access to object O1
F.byname(x)
^
-t6666.scala:30: error: Implementation restriction: access of value x$3 in object O2 from <$anon: Function0>, would require illegal premature access to object O2
+t6666.scala:30: error: Implementation restriction: access of method x$3 in object O2 from <$anon: Function0>, would require illegal premature access to object O2
F.byname(x)
^
t6666.scala:37: error: Implementation restriction: access of method x$4 in object O3 from <$anon: Function0>, would require illegal premature access to object O3
@@ -10,7 +10,7 @@ t6666.scala:37: error: Implementation restriction: access of method x$4 in objec
t6666.scala:50: error: Implementation restriction: access of method x$6 in class C1 from <$anon: Function0>, would require illegal premature access to the unconstructed `this` of class C1
F.byname(x)
^
-t6666.scala:54: error: Implementation restriction: access of value x$7 in class C2 from <$anon: Function0>, would require illegal premature access to the unconstructed `this` of class C2
+t6666.scala:54: error: Implementation restriction: access of method x$7 in class C2 from <$anon: Function0>, would require illegal premature access to the unconstructed `this` of class C2
F.byname(x)
^
t6666.scala:58: error: Implementation restriction: access of method x$8 in class C3 from <$anon: Function0>, would require illegal premature access to the unconstructed `this` of class C3
diff --git a/test/files/neg/t7494-no-options.check b/test/files/neg/t7494-no-options.check
index a4c4a1ad5b..bb143e8644 100644
--- a/test/files/neg/t7494-no-options.check
+++ b/test/files/neg/t7494-no-options.check
@@ -11,18 +11,19 @@ superaccessors 6 add super accessors in traits and nested classes
pickler 8 serialize symbol tables
refchecks 9 reference/override checking, translate nested objects
uncurry 10 uncurry, translate function values to anonymous classes
- tailcalls 11 replace tail calls by jumps
- specialize 12 @specialized-driven class and method specialization
- explicitouter 13 this refs to outer pointers
- erasure 14 erase types, add interfaces for traits
- posterasure 15 clean up erased inline classes
- lazyvals 16 allocate bitmaps, translate lazy vals into lazified defs
- lambdalift 17 move nested functions to top level
- constructors 18 move field definitions into constructors
- flatten 19 eliminate inner classes
- mixin 20 mixin composition
- cleanup 21 platform-specific cleanups, generate reflective calls
- delambdafy 22 remove lambdas
- jvm 23 generate JVM bytecode
- ploogin 24 A sample phase that does so many things it's kind of hard...
- terminal 25 the last phase during a compilation run
+ fields 11 synthesize accessors and fields
+ tailcalls 12 replace tail calls by jumps
+ specialize 13 @specialized-driven class and method specialization
+ explicitouter 14 this refs to outer pointers
+ erasure 15 erase types, add interfaces for traits
+ posterasure 16 clean up erased inline classes
+ lazyvals 17 allocate bitmaps, translate lazy vals into lazified defs
+ lambdalift 18 move nested functions to top level
+ constructors 19 move field definitions into constructors
+ flatten 20 eliminate inner classes
+ mixin 21 mixin composition
+ cleanup 22 platform-specific cleanups, generate reflective calls
+ delambdafy 23 remove lambdas
+ jvm 24 generate JVM bytecode
+ ploogin 25 A sample phase that does so many things it's kind of hard...
+ terminal 26 the last phase during a compilation run
diff --git a/test/files/neg/t7602.check b/test/files/neg/t7602.check
index 5bb1450d7d..5ce3776790 100644
--- a/test/files/neg/t7602.check
+++ b/test/files/neg/t7602.check
@@ -1,5 +1,5 @@
-t7602.scala:16: error: method foo is defined twice
- conflicting symbols both originated in file 't7602.scala'
+t7602.scala:16: error: method foo is defined twice;
+ the conflicting method foo was defined at line 15:7
def foo : Device
^
one error found
diff --git a/test/files/neg/t7622-cyclic-dependency.check b/test/files/neg/t7622-cyclic-dependency.check
index 3546964f5f..81e3ecc6a4 100644
--- a/test/files/neg/t7622-cyclic-dependency.check
+++ b/test/files/neg/t7622-cyclic-dependency.check
@@ -1 +1 @@
-error: Cycle in phase dependencies detected at cyclicdependency1, created phase-cycle.dot
+error: Cycle in phase dependencies detected at cyclicdependency2, created phase-cycle.dot
diff --git a/test/files/neg/t800.check b/test/files/neg/t800.check
index 8ba95fddde..238b8dd27d 100644
--- a/test/files/neg/t800.check
+++ b/test/files/neg/t800.check
@@ -1,16 +1,16 @@
t800.scala:4: error: qualification is already defined as value qualification
val qualification = false;
^
-t800.scala:8: error: method qualification is defined twice
- conflicting symbols both originated in file 't800.scala'
+t800.scala:8: error: value qualification is defined twice;
+ the conflicting variable qualification was defined at line 7:7
val qualification = false;
^
-t800.scala:12: error: value qualification is defined twice
- conflicting symbols both originated in file 't800.scala'
+t800.scala:12: error: variable qualification is defined twice;
+ the conflicting value qualification was defined at line 11:7
var qualification = false;
^
-t800.scala:16: error: method qualification is defined twice
- conflicting symbols both originated in file 't800.scala'
+t800.scala:16: error: variable qualification is defined twice;
+ the conflicting variable qualification was defined at line 15:7
var qualification = false;
^
four errors found
diff --git a/test/files/neg/t8849.check b/test/files/neg/t8849.check
index 15b00aee8b..1d5b4164b2 100644
--- a/test/files/neg/t8849.check
+++ b/test/files/neg/t8849.check
@@ -1,5 +1,5 @@
t8849.scala:8: error: ambiguous implicit values:
- both value global in object Implicits of type => scala.concurrent.ExecutionContext
+ both lazy value global in object Implicits of type => scala.concurrent.ExecutionContext
and value dummy of type scala.concurrent.ExecutionContext
match expected type scala.concurrent.ExecutionContext
require(implicitly[ExecutionContext] eq dummy)
diff --git a/test/files/neg/trait_fields_conflicts.check b/test/files/neg/trait_fields_conflicts.check
new file mode 100644
index 0000000000..696d0284c1
--- /dev/null
+++ b/test/files/neg/trait_fields_conflicts.check
@@ -0,0 +1,273 @@
+trait_fields_conflicts.scala:5: error: overriding value x in trait Val of type Int;
+ value x needs `override' modifier
+trait ValForVal extends Val { val x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:6: error: overriding value x in trait Val of type Int;
+ variable x needs `override' modifier
+trait VarForVal extends Val { var x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:7: error: overriding value x in trait Val of type Int;
+ method x needs `override' modifier
+trait DefForVal extends Val { def x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:8: error: overriding variable x in trait Var of type Int;
+ value x needs `override' modifier
+trait ValForVar extends Var { val x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:9: error: overriding variable x in trait Var of type Int;
+ variable x needs `override' modifier
+trait VarForVar extends Var { var x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:10: error: overriding variable x in trait Var of type Int;
+ method x needs `override' modifier
+trait DefForVar extends Var { def x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:11: error: overriding lazy value x in trait Lazy of type Int;
+ value x needs `override' modifier
+trait ValForLazy extends Lazy { val x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:12: error: overriding lazy value x in trait Lazy of type Int;
+ variable x needs `override' modifier
+trait VarForLazy extends Lazy { var x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:13: error: overriding lazy value x in trait Lazy of type Int;
+ method x needs `override' modifier
+trait DefForLazy extends Lazy { def x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:16: error: overriding value x in trait Val of type Int;
+ variable x needs to be a stable, immutable value
+trait VarForValOvr extends Val { override var x: Int = 1 } // bad override
+ ^
+trait_fields_conflicts.scala:17: error: overriding value x in trait Val of type Int;
+ method x needs to be a stable, immutable value
+trait DefForValOvr extends Val { override def x: Int = 1 } // bad override
+ ^
+trait_fields_conflicts.scala:18: error: overriding variable x in trait Var of type Int;
+ value x cannot override a mutable variable
+trait ValForVarOvr extends Var { override val x: Int = 1 } // bad override -- unsound if used in path and var changes
+ ^
+trait_fields_conflicts.scala:19: error: overriding variable x in trait Var of type Int;
+ variable x cannot override a mutable variable
+trait VarForVarOvr extends Var { override var x: Int = 1 } // bad override -- why?
+ ^
+trait_fields_conflicts.scala:20: error: overriding variable x in trait Var of type Int;
+ method x cannot override a mutable variable
+trait DefForVarOvr extends Var { override def x: Int = 1 } // bad override -- why?
+ ^
+trait_fields_conflicts.scala:21: error: overriding lazy value x in trait Lazy of type Int;
+ value x must be declared lazy to override a concrete lazy value
+trait ValForLazyOvr extends Lazy { override val x: Int = 1 } // bad override -- why?
+ ^
+trait_fields_conflicts.scala:22: error: overriding lazy value x in trait Lazy of type Int;
+ variable x needs to be a stable, immutable value
+trait VarForLazyOvr extends Lazy { override var x: Int = 1 } // bad override -- why?
+ ^
+trait_fields_conflicts.scala:23: error: overriding lazy value x in trait Lazy of type Int;
+ method x needs to be a stable, immutable value
+trait DefForLazyOvr extends Lazy { override def x: Int = 1 } // bad override -- why?
+ ^
+trait_fields_conflicts.scala:25: error: overriding value x in trait Val of type Int;
+ value x needs `override' modifier
+class CValForVal extends Val { val x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:26: error: overriding value x in trait Val of type Int;
+ variable x needs `override' modifier
+class CVarForVal extends Val { var x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:27: error: overriding value x in trait Val of type Int;
+ method x needs `override' modifier
+class CDefForVal extends Val { def x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:28: error: overriding variable x in trait Var of type Int;
+ value x needs `override' modifier
+class CValForVar extends Var { val x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:29: error: overriding variable x in trait Var of type Int;
+ variable x needs `override' modifier
+class CVarForVar extends Var { var x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:30: error: overriding variable x in trait Var of type Int;
+ method x needs `override' modifier
+class CDefForVar extends Var { def x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:31: error: overriding lazy value x in trait Lazy of type Int;
+ value x needs `override' modifier
+class CValForLazy extends Lazy { val x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:32: error: overriding lazy value x in trait Lazy of type Int;
+ variable x needs `override' modifier
+class CVarForLazy extends Lazy { var x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:33: error: overriding lazy value x in trait Lazy of type Int;
+ method x needs `override' modifier
+class CDefForLazy extends Lazy { def x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:36: error: overriding value x in trait Val of type Int;
+ variable x needs to be a stable, immutable value
+class CVarForValOvr extends Val { override var x: Int = 1 } // bad override
+ ^
+trait_fields_conflicts.scala:37: error: overriding value x in trait Val of type Int;
+ method x needs to be a stable, immutable value
+class CDefForValOvr extends Val { override def x: Int = 1 } // bad override
+ ^
+trait_fields_conflicts.scala:38: error: overriding variable x in trait Var of type Int;
+ value x cannot override a mutable variable
+class CValForVarOvr extends Var { override val x: Int = 1 } // bad override -- unsound if used in path and var changes
+ ^
+trait_fields_conflicts.scala:39: error: overriding variable x in trait Var of type Int;
+ variable x cannot override a mutable variable
+class CVarForVarOvr extends Var { override var x: Int = 1 } // bad override -- why?
+ ^
+trait_fields_conflicts.scala:40: error: overriding variable x in trait Var of type Int;
+ method x cannot override a mutable variable
+class CDefForVarOvr extends Var { override def x: Int = 1 } // bad override -- why?
+ ^
+trait_fields_conflicts.scala:41: error: overriding lazy value x in trait Lazy of type Int;
+ value x must be declared lazy to override a concrete lazy value
+class CValForLazyOvr extends Lazy { override val x: Int = 1 } // bad override -- why?
+ ^
+trait_fields_conflicts.scala:42: error: overriding lazy value x in trait Lazy of type Int;
+ variable x needs to be a stable, immutable value
+class CVarForLazyOvr extends Lazy { override var x: Int = 1 } // bad override -- why?
+ ^
+trait_fields_conflicts.scala:43: error: overriding lazy value x in trait Lazy of type Int;
+ method x needs to be a stable, immutable value
+class CDefForLazyOvr extends Lazy { override def x: Int = 1 } // bad override -- why?
+ ^
+trait_fields_conflicts.scala:49: error: overriding value x in class CVal of type Int;
+ value x needs `override' modifier
+trait ValForCVal extends CVal { val x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:50: error: overriding value x in class CVal of type Int;
+ variable x needs `override' modifier
+trait VarForCVal extends CVal { var x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:51: error: overriding value x in class CVal of type Int;
+ method x needs `override' modifier
+trait DefForCVal extends CVal { def x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:52: error: overriding variable x in class CVar of type Int;
+ value x needs `override' modifier
+trait ValForCVar extends CVar { val x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:53: error: overriding variable x in class CVar of type Int;
+ variable x needs `override' modifier
+trait VarForCVar extends CVar { var x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:54: error: overriding variable x in class CVar of type Int;
+ method x needs `override' modifier
+trait DefForCVar extends CVar { def x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:55: error: overriding lazy value x in class CLazy of type Int;
+ value x needs `override' modifier
+trait ValForCLazy extends CLazy { val x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:56: error: overriding lazy value x in class CLazy of type Int;
+ variable x needs `override' modifier
+trait VarForCLazy extends CLazy { var x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:57: error: overriding lazy value x in class CLazy of type Int;
+ method x needs `override' modifier
+trait DefForCLazy extends CLazy { def x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:60: error: overriding value x in class CVal of type Int;
+ variable x needs to be a stable, immutable value
+trait VarForCValOvr extends CVal { override var x: Int = 1 } // bad override
+ ^
+trait_fields_conflicts.scala:61: error: overriding value x in class CVal of type Int;
+ method x needs to be a stable, immutable value
+trait DefForCValOvr extends CVal { override def x: Int = 1 } // bad override
+ ^
+trait_fields_conflicts.scala:62: error: overriding variable x in class CVar of type Int;
+ value x cannot override a mutable variable
+trait ValForCVarOvr extends CVar { override val x: Int = 1 } // bad override -- unsound if used in path and var changes
+ ^
+trait_fields_conflicts.scala:63: error: overriding variable x in class CVar of type Int;
+ variable x cannot override a mutable variable
+trait VarForCVarOvr extends CVar { override var x: Int = 1 } // bad override -- why?
+ ^
+trait_fields_conflicts.scala:64: error: overriding variable x in class CVar of type Int;
+ method x cannot override a mutable variable
+trait DefForCVarOvr extends CVar { override def x: Int = 1 } // bad override -- why?
+ ^
+trait_fields_conflicts.scala:65: error: overriding lazy value x in class CLazy of type Int;
+ value x must be declared lazy to override a concrete lazy value
+trait ValForCLazyOvr extends CLazy { override val x: Int = 1 } // bad override -- why?
+ ^
+trait_fields_conflicts.scala:66: error: overriding lazy value x in class CLazy of type Int;
+ variable x needs to be a stable, immutable value
+trait VarForCLazyOvr extends CLazy { override var x: Int = 1 } // bad override -- why?
+ ^
+trait_fields_conflicts.scala:67: error: overriding lazy value x in class CLazy of type Int;
+ method x needs to be a stable, immutable value
+trait DefForCLazyOvr extends CLazy { override def x: Int = 1 } // bad override -- why?
+ ^
+trait_fields_conflicts.scala:69: error: overriding value x in class CVal of type Int;
+ value x needs `override' modifier
+class CValForCVal extends CVal { val x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:70: error: overriding value x in class CVal of type Int;
+ variable x needs `override' modifier
+class CVarForCVal extends CVal { var x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:71: error: overriding value x in class CVal of type Int;
+ method x needs `override' modifier
+class CDefForCVal extends CVal { def x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:72: error: overriding variable x in class CVar of type Int;
+ value x needs `override' modifier
+class CValForCVar extends CVar { val x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:73: error: overriding variable x in class CVar of type Int;
+ variable x needs `override' modifier
+class CVarForCVar extends CVar { var x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:74: error: overriding variable x in class CVar of type Int;
+ method x needs `override' modifier
+class CDefForCVar extends CVar { def x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:75: error: overriding lazy value x in class CLazy of type Int;
+ value x needs `override' modifier
+class CValForCLazy extends CLazy { val x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:76: error: overriding lazy value x in class CLazy of type Int;
+ variable x needs `override' modifier
+class CVarForCLazy extends CLazy { var x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:77: error: overriding lazy value x in class CLazy of type Int;
+ method x needs `override' modifier
+class CDefForCLazy extends CLazy { def x: Int = 1 } // needs override
+ ^
+trait_fields_conflicts.scala:80: error: overriding value x in class CVal of type Int;
+ variable x needs to be a stable, immutable value
+class CVarForCValOvr extends CVal { override var x: Int = 1 } // bad override
+ ^
+trait_fields_conflicts.scala:81: error: overriding value x in class CVal of type Int;
+ method x needs to be a stable, immutable value
+class CDefForCValOvr extends CVal { override def x: Int = 1 } // bad override
+ ^
+trait_fields_conflicts.scala:82: error: overriding variable x in class CVar of type Int;
+ value x cannot override a mutable variable
+class CValForCVarOvr extends CVar { override val x: Int = 1 } // bad override -- unsound if used in path and var changes
+ ^
+trait_fields_conflicts.scala:83: error: overriding variable x in class CVar of type Int;
+ variable x cannot override a mutable variable
+class CVarForCVarOvr extends CVar { override var x: Int = 1 } // bad override -- why?
+ ^
+trait_fields_conflicts.scala:84: error: overriding variable x in class CVar of type Int;
+ method x cannot override a mutable variable
+class CDefForCVarOvr extends CVar { override def x: Int = 1 } // bad override -- why?
+ ^
+trait_fields_conflicts.scala:85: error: overriding lazy value x in class CLazy of type Int;
+ value x must be declared lazy to override a concrete lazy value
+class CValForCLazyOvr extends CLazy { override val x: Int = 1 } // bad override -- why?
+ ^
+trait_fields_conflicts.scala:86: error: overriding lazy value x in class CLazy of type Int;
+ variable x needs to be a stable, immutable value
+class CVarForCLazyOvr extends CLazy { override var x: Int = 1 } // bad override -- why?
+ ^
+trait_fields_conflicts.scala:87: error: overriding lazy value x in class CLazy of type Int;
+ method x needs to be a stable, immutable value
+class CDefForCLazyOvr extends CLazy { override def x: Int = 1 } // bad override -- why?
+ ^
+68 errors found
diff --git a/test/files/neg/trait_fields_conflicts.scala b/test/files/neg/trait_fields_conflicts.scala
new file mode 100644
index 0000000000..92fc106e44
--- /dev/null
+++ b/test/files/neg/trait_fields_conflicts.scala
@@ -0,0 +1,87 @@
+trait Val { val x: Int = 123 }
+trait Var { var x: Int = 123 }
+trait Lazy { lazy val x: Int = 123 }
+
+trait ValForVal extends Val { val x: Int = 1 } // needs override
+trait VarForVal extends Val { var x: Int = 1 } // needs override
+trait DefForVal extends Val { def x: Int = 1 } // needs override
+trait ValForVar extends Var { val x: Int = 1 } // needs override
+trait VarForVar extends Var { var x: Int = 1 } // needs override
+trait DefForVar extends Var { def x: Int = 1 } // needs override
+trait ValForLazy extends Lazy { val x: Int = 1 } // needs override
+trait VarForLazy extends Lazy { var x: Int = 1 } // needs override
+trait DefForLazy extends Lazy { def x: Int = 1 } // needs override
+
+trait ValForValOvr extends Val { override val x: Int = 1 } // override ok
+trait VarForValOvr extends Val { override var x: Int = 1 } // bad override
+trait DefForValOvr extends Val { override def x: Int = 1 } // bad override
+trait ValForVarOvr extends Var { override val x: Int = 1 } // bad override -- unsound if used in path and var changes
+trait VarForVarOvr extends Var { override var x: Int = 1 } // bad override -- why?
+trait DefForVarOvr extends Var { override def x: Int = 1 } // bad override -- why?
+trait ValForLazyOvr extends Lazy { override val x: Int = 1 } // bad override -- why?
+trait VarForLazyOvr extends Lazy { override var x: Int = 1 } // bad override -- why?
+trait DefForLazyOvr extends Lazy { override def x: Int = 1 } // bad override -- why?
+
+class CValForVal extends Val { val x: Int = 1 } // needs override
+class CVarForVal extends Val { var x: Int = 1 } // needs override
+class CDefForVal extends Val { def x: Int = 1 } // needs override
+class CValForVar extends Var { val x: Int = 1 } // needs override
+class CVarForVar extends Var { var x: Int = 1 } // needs override
+class CDefForVar extends Var { def x: Int = 1 } // needs override
+class CValForLazy extends Lazy { val x: Int = 1 } // needs override
+class CVarForLazy extends Lazy { var x: Int = 1 } // needs override
+class CDefForLazy extends Lazy { def x: Int = 1 } // needs override
+
+class CValForValOvr extends Val { override val x: Int = 1 } // override ok
+class CVarForValOvr extends Val { override var x: Int = 1 } // bad override
+class CDefForValOvr extends Val { override def x: Int = 1 } // bad override
+class CValForVarOvr extends Var { override val x: Int = 1 } // bad override -- unsound if used in path and var changes
+class CVarForVarOvr extends Var { override var x: Int = 1 } // bad override -- why?
+class CDefForVarOvr extends Var { override def x: Int = 1 } // bad override -- why?
+class CValForLazyOvr extends Lazy { override val x: Int = 1 } // bad override -- why?
+class CVarForLazyOvr extends Lazy { override var x: Int = 1 } // bad override -- why?
+class CDefForLazyOvr extends Lazy { override def x: Int = 1 } // bad override -- why?
+
+class CVal { val x: Int = 123 }
+class CVar { var x: Int = 123 }
+class CLazy { lazy val x: Int = 123 }
+
+trait ValForCVal extends CVal { val x: Int = 1 } // needs override
+trait VarForCVal extends CVal { var x: Int = 1 } // needs override
+trait DefForCVal extends CVal { def x: Int = 1 } // needs override
+trait ValForCVar extends CVar { val x: Int = 1 } // needs override
+trait VarForCVar extends CVar { var x: Int = 1 } // needs override
+trait DefForCVar extends CVar { def x: Int = 1 } // needs override
+trait ValForCLazy extends CLazy { val x: Int = 1 } // needs override
+trait VarForCLazy extends CLazy { var x: Int = 1 } // needs override
+trait DefForCLazy extends CLazy { def x: Int = 1 } // needs override
+
+trait ValForCValOvr extends CVal { override val x: Int = 1 } // override ok
+trait VarForCValOvr extends CVal { override var x: Int = 1 } // bad override
+trait DefForCValOvr extends CVal { override def x: Int = 1 } // bad override
+trait ValForCVarOvr extends CVar { override val x: Int = 1 } // bad override -- unsound if used in path and var changes
+trait VarForCVarOvr extends CVar { override var x: Int = 1 } // bad override -- why?
+trait DefForCVarOvr extends CVar { override def x: Int = 1 } // bad override -- why?
+trait ValForCLazyOvr extends CLazy { override val x: Int = 1 } // bad override -- why?
+trait VarForCLazyOvr extends CLazy { override var x: Int = 1 } // bad override -- why?
+trait DefForCLazyOvr extends CLazy { override def x: Int = 1 } // bad override -- why?
+
+class CValForCVal extends CVal { val x: Int = 1 } // needs override
+class CVarForCVal extends CVal { var x: Int = 1 } // needs override
+class CDefForCVal extends CVal { def x: Int = 1 } // needs override
+class CValForCVar extends CVar { val x: Int = 1 } // needs override
+class CVarForCVar extends CVar { var x: Int = 1 } // needs override
+class CDefForCVar extends CVar { def x: Int = 1 } // needs override
+class CValForCLazy extends CLazy { val x: Int = 1 } // needs override
+class CVarForCLazy extends CLazy { var x: Int = 1 } // needs override
+class CDefForCLazy extends CLazy { def x: Int = 1 } // needs override
+
+class CValForCValOvr extends CVal { override val x: Int = 1 } // override ok
+class CVarForCValOvr extends CVal { override var x: Int = 1 } // bad override
+class CDefForCValOvr extends CVal { override def x: Int = 1 } // bad override
+class CValForCVarOvr extends CVar { override val x: Int = 1 } // bad override -- unsound if used in path and var changes
+class CVarForCVarOvr extends CVar { override var x: Int = 1 } // bad override -- why?
+class CDefForCVarOvr extends CVar { override def x: Int = 1 } // bad override -- why?
+class CValForCLazyOvr extends CLazy { override val x: Int = 1 } // bad override -- why?
+class CVarForCLazyOvr extends CLazy { override var x: Int = 1 } // bad override -- why?
+class CDefForCLazyOvr extends CLazy { override def x: Int = 1 } // bad override -- why?
diff --git a/test/files/neg/trait_fields_deprecated_overriding.check b/test/files/neg/trait_fields_deprecated_overriding.check
new file mode 100644
index 0000000000..89dfa5c295
--- /dev/null
+++ b/test/files/neg/trait_fields_deprecated_overriding.check
@@ -0,0 +1,6 @@
+trait_fields_deprecated_overriding.scala:8: warning: overriding value x in trait DeprecatedOverriding is deprecated
+ override val x = 2
+ ^
+error: No warnings can be incurred under -Xfatal-warnings.
+one warning found
+one error found
diff --git a/test/files/neg/trait_fields_deprecated_overriding.flags b/test/files/neg/trait_fields_deprecated_overriding.flags
new file mode 100644
index 0000000000..c6bfaf1f64
--- /dev/null
+++ b/test/files/neg/trait_fields_deprecated_overriding.flags
@@ -0,0 +1 @@
+-deprecation -Xfatal-warnings
diff --git a/test/files/neg/trait_fields_deprecated_overriding.scala b/test/files/neg/trait_fields_deprecated_overriding.scala
new file mode 100644
index 0000000000..e7d722c92f
--- /dev/null
+++ b/test/files/neg/trait_fields_deprecated_overriding.scala
@@ -0,0 +1,11 @@
+package scala
+
+trait DeprecatedOverriding {
+ @deprecatedOverriding val x = 1
+}
+
+class COverride extends DeprecatedOverriding {
+ override val x = 2
+}
+
+class CSynthImpl extends DeprecatedOverriding \ No newline at end of file
diff --git a/test/files/neg/val_infer.check b/test/files/neg/val_infer.check
new file mode 100644
index 0000000000..711450add9
--- /dev/null
+++ b/test/files/neg/val_infer.check
@@ -0,0 +1,6 @@
+val_infer.scala:3: error: type mismatch;
+ found : String("")
+ required: Int
+ trait Sub extends Base { def foo = "" }
+ ^
+one error found
diff --git a/test/files/neg/val_infer.scala b/test/files/neg/val_infer.scala
new file mode 100644
index 0000000000..7fe8393749
--- /dev/null
+++ b/test/files/neg/val_infer.scala
@@ -0,0 +1,4 @@
+class Test {
+ trait Base { def foo: Int }
+ trait Sub extends Base { def foo = "" }
+} \ No newline at end of file
diff --git a/test/files/neg/val_sig_infer_match.check b/test/files/neg/val_sig_infer_match.check
new file mode 100644
index 0000000000..704c99cf84
--- /dev/null
+++ b/test/files/neg/val_sig_infer_match.check
@@ -0,0 +1,4 @@
+val_sig_infer_match.scala:21: error: value y is not a member of A
+ def m = f.y // doesn't compile anymore
+ ^
+one error found
diff --git a/test/files/neg/val_sig_infer_match.scala b/test/files/neg/val_sig_infer_match.scala
new file mode 100644
index 0000000000..fb8aa66d56
--- /dev/null
+++ b/test/files/neg/val_sig_infer_match.scala
@@ -0,0 +1,22 @@
+class A
+
+class B extends A {
+ def y: Int = 0
+}
+
+class B1 extends B
+class B2 extends B
+
+class C {
+ def f: A = null
+}
+
+class D extends C {
+ def s = ""
+ override final val f = s match {
+ case "" => new B1
+ case _ => new B2
+ }
+
+ def m = f.y // doesn't compile anymore
+} \ No newline at end of file
diff --git a/test/files/neg/val_sig_infer_struct.check b/test/files/neg/val_sig_infer_struct.check
new file mode 100644
index 0000000000..26efbbc3f4
--- /dev/null
+++ b/test/files/neg/val_sig_infer_struct.check
@@ -0,0 +1,4 @@
+val_sig_infer_struct.scala:7: error: value foo is not a member of Object
+ def bar = f.foo
+ ^
+one error found
diff --git a/test/files/neg/val_sig_infer_struct.scala b/test/files/neg/val_sig_infer_struct.scala
new file mode 100644
index 0000000000..e88340337c
--- /dev/null
+++ b/test/files/neg/val_sig_infer_struct.scala
@@ -0,0 +1,8 @@
+class C {
+ def f: Object = this
+}
+
+class D extends C {
+ override val f = new Object { def foo = 1 }
+ def bar = f.foo
+} \ No newline at end of file
diff --git a/test/files/neg/warn-unused-privates.check b/test/files/neg/warn-unused-privates.check
index 4876ed8fc2..2e93f338bb 100644
--- a/test/files/neg/warn-unused-privates.check
+++ b/test/files/neg/warn-unused-privates.check
@@ -19,10 +19,7 @@ warn-unused-privates.scala:36: warning: private val in class Boppy is never used
warn-unused-privates.scala:43: warning: private var in trait Accessors is never used
private var v1: Int = 0 // warn
^
-warn-unused-privates.scala:43: warning: private setter in trait Accessors is never used
- private var v1: Int = 0 // warn
- ^
-warn-unused-privates.scala:44: warning: private setter in trait Accessors is never used
+warn-unused-privates.scala:44: warning: private var in trait Accessors is never used
private var v2: Int = 0 // warn, never set
^
warn-unused-privates.scala:45: warning: private var in trait Accessors is never used
@@ -65,5 +62,5 @@ warn-unused-privates.scala:103: warning: local type OtherThing is never used
type OtherThing = String // warn
^
error: No warnings can be incurred under -Xfatal-warnings.
-22 warnings found
+21 warnings found
one error found
diff --git a/test/files/presentation/t4287c.flags b/test/files/pos/infer_override_def_args.flags
index d1a8244169..d1a8244169 100644
--- a/test/files/presentation/t4287c.flags
+++ b/test/files/pos/infer_override_def_args.flags
diff --git a/test/files/pos/infer_override_def_args.scala b/test/files/pos/infer_override_def_args.scala
new file mode 100644
index 0000000000..ac10720c81
--- /dev/null
+++ b/test/files/pos/infer_override_def_args.scala
@@ -0,0 +1,5 @@
+abstract class A { def foo(a: Int): A }
+class B extends A {
+ implicit def spackle(x: Int): A = new B
+ def foo(a) = a
+} \ No newline at end of file
diff --git a/test/files/pos/trait_fields_dependent_conflict.scala b/test/files/pos/trait_fields_dependent_conflict.scala
new file mode 100644
index 0000000000..afb6f4b0c5
--- /dev/null
+++ b/test/files/pos/trait_fields_dependent_conflict.scala
@@ -0,0 +1,20 @@
+// derived from test/files/pos/S5.scala
+
+// compile with -uniqid to see a hint of the trouble
+trait N {
+ // the symbol for self does not get rebound when synthesizing members in C
+ val self: N = ???
+ val n: self.type = self
+}
+
+abstract class M {
+ val self: N
+ val n: self.type
+}
+
+abstract class MConflict extends N {
+ val self: N
+ val n: self.type
+}
+
+class C extends M with N
diff --git a/test/files/pos/trait_fields_dependent_rebind.scala b/test/files/pos/trait_fields_dependent_rebind.scala
new file mode 100644
index 0000000000..e2cf4c43c3
--- /dev/null
+++ b/test/files/pos/trait_fields_dependent_rebind.scala
@@ -0,0 +1,15 @@
+// derived from test/files/pos/S5.scala
+
+// compile with -uniqid to see a hint of the trouble
+trait N {
+ // the symbol for self does not get rebound when synthesizing members in C
+ val self: N = ???
+ val n: self.type = self
+}
+
+abstract class M {
+ val self: N
+ val n: self.type
+}
+
+class C extends M with N
diff --git a/test/files/pos/trait_fields_inherit_double_def.scala b/test/files/pos/trait_fields_inherit_double_def.scala
new file mode 100644
index 0000000000..8703d6312c
--- /dev/null
+++ b/test/files/pos/trait_fields_inherit_double_def.scala
@@ -0,0 +1,20 @@
+// done
+// test/files/trait-defaults/fields.scala:24: error: double definition:
+// def signalDelegate_=(x$1: Signalling): Unit at line 24 and
+// def signalDelegate_=(x$1: Signalling): Unit at line 24
+// have same type
+// class SUB extends IterableSplitter
+// ^
+// one error found
+
+trait Signalling
+
+trait DelegatedSignalling extends Signalling {
+ var signalDelegate: Signalling
+}
+
+trait IterableSplitter extends DelegatedSignalling {
+ var signalDelegate: Signalling = ???
+}
+
+class SUB extends IterableSplitter \ No newline at end of file
diff --git a/test/files/pos/trait_fields_lambdalift.scala b/test/files/pos/trait_fields_lambdalift.scala
new file mode 100644
index 0000000000..62304a5268
--- /dev/null
+++ b/test/files/pos/trait_fields_lambdalift.scala
@@ -0,0 +1,22 @@
+class Lift {
+ def foo = {
+ // this will be captured by the MouseHandler trait,
+ // which gives rise to a new trait field during LambdaLift
+ var Clicked = "Clicked"
+
+ def bar = Clicked
+
+ trait MouseHandler {
+ def mouseClicked = Clicked + bar
+ }
+
+ class CC extends MouseHandler
+
+ // new C {}
+ (new CC).mouseClicked
+ }
+}
+
+object O extends Lift with App {
+ println(foo)
+}
diff --git a/test/files/pos/trait_fields_nested_private_object.scala b/test/files/pos/trait_fields_nested_private_object.scala
new file mode 100644
index 0000000000..8efc1cb3fa
--- /dev/null
+++ b/test/files/pos/trait_fields_nested_private_object.scala
@@ -0,0 +1,8 @@
+trait NestedObj {
+ private object O { println("NO") }
+}
+
+
+class C extends NestedObj {
+ def O = ???
+} \ No newline at end of file
diff --git a/test/files/pos/trait_fields_nested_public_object.scala b/test/files/pos/trait_fields_nested_public_object.scala
new file mode 100644
index 0000000000..016487fb8a
--- /dev/null
+++ b/test/files/pos/trait_fields_nested_public_object.scala
@@ -0,0 +1,5 @@
+trait NestedObj {
+ object O { println("NO") }
+}
+
+class C extends NestedObj \ No newline at end of file
diff --git a/test/files/pos/trait_fields_owners.scala b/test/files/pos/trait_fields_owners.scala
new file mode 100644
index 0000000000..6aa5572171
--- /dev/null
+++ b/test/files/pos/trait_fields_owners.scala
@@ -0,0 +1,19 @@
+trait V {
+ // ok
+ // error: java.lang.IllegalArgumentException: Could not find proxy for val f: Function1 in List(value f, value v, trait V, package <empty>, package <root>) (currentOwner= value <local V$class> )
+ val v = { val f = (x: Int) => x + 1; f(2) }
+
+ // ok
+ // assertion failed:
+ // Trying to access the this of another class: tree.symbol = trait V, class symbol = object V$class compilation unit: fields.scala
+ val developmentVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if v endsWith "-SNAPSHOT"
+ ov <- scalaPropOrNone("version.number")
+ } yield ov
+
+ def scalaPropOrNone(name: String): Option[String] = ???
+}
+
+object O extends V \ No newline at end of file
diff --git a/test/files/pos/trait_fields_private_this.scala b/test/files/pos/trait_fields_private_this.scala
new file mode 100644
index 0000000000..8065cc89e6
--- /dev/null
+++ b/test/files/pos/trait_fields_private_this.scala
@@ -0,0 +1,5 @@
+trait Chars {
+ private[this] val char2uescapeArray: String = ???
+}
+
+object Chars extends Chars \ No newline at end of file
diff --git a/test/files/pos/trait_fields_static_fwd.scala b/test/files/pos/trait_fields_static_fwd.scala
new file mode 100644
index 0000000000..af2cdad9ff
--- /dev/null
+++ b/test/files/pos/trait_fields_static_fwd.scala
@@ -0,0 +1,10 @@
+trait T {
+ // Need to mark the synthesized member in the object's module class as notPROTECTED,
+ // since the trait member will receive this flag later.
+ // If we don't add notPROTECTED to the synthesized one, the member will not be seen as overriding the trait member.
+ // Therefore, addForwarders's call to membersBasedOnFlags would see the deferred member in the trait,
+ // instead of the concrete (desired) one in the class, and thus not create the static forwarder.
+ protected val propFilename: String = "/"
+}
+
+object P extends T
diff --git a/test/files/pos/val_infer.scala b/test/files/pos/val_infer.scala
new file mode 100644
index 0000000000..5f82da8393
--- /dev/null
+++ b/test/files/pos/val_infer.scala
@@ -0,0 +1,5 @@
+class Test {
+ implicit def s2i(s: String): Int = s.length
+ trait Base { def foo: Int }
+ trait Sub extends Base { val foo = "" }
+}
diff --git a/test/files/presentation/doc/doc.scala b/test/files/presentation/doc/doc.scala
index 8c60af557b..08c6ebf059 100644
--- a/test/files/presentation/doc/doc.scala
+++ b/test/files/presentation/doc/doc.scala
@@ -37,7 +37,7 @@ object Test extends InteractiveTest {
prepre + docComment(nTags) + prepost + post
}
- override lazy val compiler = {
+ override lazy val compiler: Global { def getComment(sym: Symbol, source: SourceFile, fragments: List[(Symbol,SourceFile)]): Option[Comment] } = {
prepareSettings(settings)
new Global(settings, compilerReporter) with MemberLookupBase with CommentFactoryBase with doc.ScaladocGlobalTrait {
outer =>
diff --git a/test/files/presentation/scope-completion-3.check b/test/files/presentation/scope-completion-3.check
index b70a7d5c6b..f2510127fb 100644
--- a/test/files/presentation/scope-completion-3.check
+++ b/test/files/presentation/scope-completion-3.check
@@ -3,7 +3,7 @@ reload: Completions.scala
askScopeCompletion at Completions.scala(75,2)
================================================================================
[response] askScopeCompletion at (75,2)
-retrieved 37 members
+retrieved 38 members
abstract class Base1 extends AnyRef
abstract trait Trait1 extends AnyRef
class Cb1 extends AnyRef
@@ -14,6 +14,8 @@ def <init>(): test.Completion1
def fb1: Int
def fc1: Int
def ft1: Int
+def rt1: Int
+def rt1_=(x$1: Int): Unit
object Completion2
object Ob1
object Oc1
@@ -30,23 +32,22 @@ private[this] val vb1: Int
private[this] val vb3: Int
private[this] val vc1: Int
private[this] val vc2: Int
-private[this] val vt1: Int
private[this] val vt3: Int
private[this] var rb1: Int
private[this] var rb3: Int
private[this] var rc1: Int
private[this] var rc2: Int
-private[this] var rt1: Int
private[this] var rt3: Int
type tb1 = Completion1.this.tb1
type tc1 = Completion1.this.tc1
type tt1 = Completion1.this.tt1
+val vt1: Int
================================================================================
askScopeCompletion at Completions.scala(104,2)
================================================================================
[response] askScopeCompletion at (104,2)
-retrieved 37 members
+retrieved 38 members
abstract class Base1 extends AnyRef
abstract trait Trait1 extends AnyRef
class Cb1 extends AnyRef
@@ -57,6 +58,8 @@ def <init>(): test.Completion2.type
def fb1: Int
def fo1: Int
def ft1: Int
+def rt1: Int
+def rt1_=(x$1: Int): Unit
object Completion2
object Ob1
object Oo1
@@ -73,15 +76,14 @@ private[this] val vb1: Int
private[this] val vb3: Int
private[this] val vo1: Int
private[this] val vo2: Int
-private[this] val vt1: Int
private[this] val vt3: Int
private[this] var rb1: Int
private[this] var rb3: Int
private[this] var ro1: Int
private[this] var ro2: Int
-private[this] var rt1: Int
private[this] var rt3: Int
type tb1 = test.Completion2.tb1
type to1 = test.Completion2.to1
type tt1 = test.Completion2.tt1
+val vt1: Int
================================================================================
diff --git a/test/files/presentation/t4287c.check b/test/files/presentation/t4287c.check
deleted file mode 100644
index 42fc30997d..0000000000
--- a/test/files/presentation/t4287c.check
+++ /dev/null
@@ -1,11 +0,0 @@
-reload: Foo.scala
-
-askHyperlinkPos for `A` at (1,18) Foo.scala
-================================================================================
-[response] found askHyperlinkPos for `A` at (3,8) Foo.scala
-================================================================================
-
-askHyperlinkPos for `a` at (1,25) Foo.scala
-================================================================================
-[response] found askHyperlinkPos for `a` at (4,7) Foo.scala
-================================================================================
diff --git a/test/files/presentation/t4287c/Test.scala b/test/files/presentation/t4287c/Test.scala
deleted file mode 100644
index bec1131c4c..0000000000
--- a/test/files/presentation/t4287c/Test.scala
+++ /dev/null
@@ -1,3 +0,0 @@
-import scala.tools.nsc.interactive.tests.InteractiveTest
-
-object Test extends InteractiveTest \ No newline at end of file
diff --git a/test/files/presentation/t4287c/src/Foo.scala b/test/files/presentation/t4287c/src/Foo.scala
deleted file mode 100644
index 26870b5021..0000000000
--- a/test/files/presentation/t4287c/src/Foo.scala
+++ /dev/null
@@ -1,9 +0,0 @@
-class A(a: Int = A/*#*/.a/*#*/)
-
-object A {
- val a = 2
-}
-
-class B extends A {
- def this(a) = this()
-} \ No newline at end of file
diff --git a/test/files/run/SymbolsTest.scala b/test/files/run/SymbolsTest.scala
index d5948ea168..7c185b0e09 100644
--- a/test/files/run/SymbolsTest.scala
+++ b/test/files/run/SymbolsTest.scala
@@ -137,16 +137,16 @@ object Test {
// }
// val an2 = () => {
// object nested {
- // val m = 'mfsa
+ // val m = 'mfsa
// }
// nested.m
// }
// val an3 = () => {
// object nested {
- // val f = () => {
- // 'layered
- // }
- // def gets = f()
+ // val f = () => {
+ // 'layered
+ // }
+ // def gets = f()
// }
// nested.gets
// }
@@ -204,8 +204,8 @@ object Test {
val s1 = 's1
def s2 = 's2
object inner {
- val s3 = 's3
- val s4 = 's4
+ val s3 = 's3
+ val s4 = 's4
}
}
@@ -223,8 +223,8 @@ object Test {
val s5 = 's5
def s6 = 's6
object inner2 {
- val s7 = 's7
- def s8 = 's8
+ val s7 = 's7
+ def s8 = 's8
}
}
assert(Local.s5 == 's5)
diff --git a/test/files/run/analyzerPlugins.check b/test/files/run/analyzerPlugins.check
index 1bb7c6ceab..ca0005ea4d 100644
--- a/test/files/run/analyzerPlugins.check
+++ b/test/files/run/analyzerPlugins.check
@@ -21,7 +21,6 @@ lub(List(Int @testAnn, Int)) [1]
pluginsPt(?, Trees$Annotated) [7]
pluginsPt(?, Trees$Apply) [11]
pluginsPt(?, Trees$ApplyImplicitView) [2]
-pluginsPt(?, Trees$Assign) [7]
pluginsPt(?, Trees$Block) [4]
pluginsPt(?, Trees$ClassDef) [2]
pluginsPt(?, Trees$DefDef) [14]
@@ -31,9 +30,9 @@ pluginsPt(?, Trees$Literal) [16]
pluginsPt(?, Trees$New) [5]
pluginsPt(?, Trees$PackageDef) [1]
pluginsPt(?, Trees$Return) [1]
-pluginsPt(?, Trees$Select) [50]
+pluginsPt(?, Trees$Select) [43]
pluginsPt(?, Trees$Super) [2]
-pluginsPt(?, Trees$This) [20]
+pluginsPt(?, Trees$This) [13]
pluginsPt(?, Trees$TypeApply) [3]
pluginsPt(?, Trees$TypeBoundsTree) [2]
pluginsPt(?, Trees$TypeDef) [1]
@@ -47,23 +46,19 @@ pluginsPt(Boolean @testAnn, Trees$Literal) [1]
pluginsPt(Boolean @testAnn, Trees$Select) [1]
pluginsPt(Boolean, Trees$Apply) [1]
pluginsPt(Boolean, Trees$Ident) [1]
-pluginsPt(Boolean, Trees$Literal) [1]
pluginsPt(Double, Trees$Select) [1]
pluginsPt(Int @testAnn, Trees$Literal) [1]
pluginsPt(Int, Trees$Apply) [1]
-pluginsPt(Int, Trees$Ident) [2]
-pluginsPt(Int, Trees$If) [1]
-pluginsPt(Int, Trees$Literal) [5]
+pluginsPt(Int, Trees$Ident) [1]
+pluginsPt(Int, Trees$Literal) [4]
pluginsPt(Int, Trees$Select) [3]
-pluginsPt(List, Trees$Apply) [1]
pluginsPt(List[Any], Trees$Select) [1]
pluginsPt(String @testAnn, Trees$Select) [1]
pluginsPt(String, Trees$Apply) [1]
pluginsPt(String, Trees$Block) [2]
-pluginsPt(String, Trees$Ident) [4]
+pluginsPt(String, Trees$Ident) [3]
pluginsPt(String, Trees$Literal) [1]
pluginsPt(String, Trees$Select) [1]
-pluginsPt(String, Trees$Typed) [1]
pluginsPt(Unit, Trees$Assign) [1]
pluginsPt(testAnn, Trees$Apply) [5]
pluginsTypeSig(<none>, Trees$Template) [2]
@@ -119,7 +114,7 @@ pluginsTyped(=> Int, Trees$TypeApply) [1]
pluginsTyped(=> String @testAnn, Trees$Select) [1]
pluginsTyped(A, Trees$Apply) [1]
pluginsTyped(A, Trees$Ident) [2]
-pluginsTyped(A, Trees$This) [8]
+pluginsTyped(A, Trees$This) [1]
pluginsTyped(A, Trees$TypeTree) [4]
pluginsTyped(A.super.type, Trees$Super) [1]
pluginsTyped(A.this.type, Trees$This) [11]
@@ -128,25 +123,23 @@ pluginsTyped(AnyRef, Trees$Select) [4]
pluginsTyped(Array[Any], Trees$ArrayValue) [1]
pluginsTyped(Boolean @testAnn, Trees$Select) [1]
pluginsTyped(Boolean @testAnn, Trees$TypeTree) [4]
-pluginsTyped(Boolean(false), Trees$Literal) [2]
+pluginsTyped(Boolean(false), Trees$Literal) [1]
pluginsTyped(Boolean, Trees$Apply) [1]
-pluginsTyped(Boolean, Trees$Select) [4]
+pluginsTyped(Boolean, Trees$Select) [3]
pluginsTyped(Char('c'), Trees$Literal) [2]
pluginsTyped(Double, Trees$Apply) [3]
pluginsTyped(Double, Trees$Select) [6]
pluginsTyped(Int @testAnn, Trees$TypeTree) [2]
pluginsTyped(Int @testAnn, Trees$Typed) [2]
-pluginsTyped(Int(0), Trees$Literal) [3]
+pluginsTyped(Int(0), Trees$Literal) [2]
pluginsTyped(Int(1) @testAnn, Trees$Typed) [1]
pluginsTyped(Int(1), Trees$Literal) [8]
pluginsTyped(Int(2), Trees$Literal) [1]
pluginsTyped(Int, Trees$Apply) [1]
-pluginsTyped(Int, Trees$Ident) [2]
-pluginsTyped(Int, Trees$If) [2]
-pluginsTyped(Int, Trees$Select) [15]
+pluginsTyped(Int, Trees$Ident) [1]
+pluginsTyped(Int, Trees$If) [1]
+pluginsTyped(Int, Trees$Select) [12]
pluginsTyped(Int, Trees$TypeTree) [13]
-pluginsTyped(List, Trees$Apply) [1]
-pluginsTyped(List, Trees$Select) [1]
pluginsTyped(List[Any], Trees$Apply) [1]
pluginsTyped(List[Any], Trees$Select) [1]
pluginsTyped(List[Any], Trees$TypeTree) [3]
@@ -159,15 +152,13 @@ pluginsTyped(String(""), Trees$Literal) [2]
pluginsTyped(String("huhu"), Trees$Literal) [1]
pluginsTyped(String("str") @testAnn, Trees$Typed) [1]
pluginsTyped(String("str"), Trees$Literal) [1]
-pluginsTyped(String("str"), Trees$Typed) [1]
pluginsTyped(String("two"), Trees$Literal) [2]
pluginsTyped(String, Trees$Apply) [2]
pluginsTyped(String, Trees$Block) [2]
-pluginsTyped(String, Trees$Ident) [1]
-pluginsTyped(String, Trees$Select) [9]
+pluginsTyped(String, Trees$Select) [7]
pluginsTyped(String, Trees$TypeTree) [7]
pluginsTyped(Unit, Trees$Apply) [2]
-pluginsTyped(Unit, Trees$Assign) [8]
+pluginsTyped(Unit, Trees$Assign) [1]
pluginsTyped(Unit, Trees$Block) [4]
pluginsTyped(Unit, Trees$If) [1]
pluginsTyped(Unit, Trees$Literal) [5]
diff --git a/test/files/run/programmatic-main.check b/test/files/run/programmatic-main.check
index 280a4f43d5..03f8273c17 100644
--- a/test/files/run/programmatic-main.check
+++ b/test/files/run/programmatic-main.check
@@ -10,17 +10,18 @@ superaccessors 6 add super accessors in traits and nested classes
pickler 8 serialize symbol tables
refchecks 9 reference/override checking, translate nested objects
uncurry 10 uncurry, translate function values to anonymous classes
- tailcalls 11 replace tail calls by jumps
- specialize 12 @specialized-driven class and method specialization
- explicitouter 13 this refs to outer pointers
- erasure 14 erase types, add interfaces for traits
- posterasure 15 clean up erased inline classes
- lazyvals 16 allocate bitmaps, translate lazy vals into lazified defs
- lambdalift 17 move nested functions to top level
- constructors 18 move field definitions into constructors
- flatten 19 eliminate inner classes
- mixin 20 mixin composition
- cleanup 21 platform-specific cleanups, generate reflective calls
- delambdafy 22 remove lambdas
- jvm 23 generate JVM bytecode
- terminal 24 the last phase during a compilation run
+ fields 11 synthesize accessors and fields
+ tailcalls 12 replace tail calls by jumps
+ specialize 13 @specialized-driven class and method specialization
+ explicitouter 14 this refs to outer pointers
+ erasure 15 erase types, add interfaces for traits
+ posterasure 16 clean up erased inline classes
+ lazyvals 17 allocate bitmaps, translate lazy vals into lazified defs
+ lambdalift 18 move nested functions to top level
+ constructors 19 move field definitions into constructors
+ flatten 20 eliminate inner classes
+ mixin 21 mixin composition
+ cleanup 22 platform-specific cleanups, generate reflective calls
+ delambdafy 23 remove lambdas
+ jvm 24 generate JVM bytecode
+ terminal 25 the last phase during a compilation run
diff --git a/test/files/run/reflection-fieldsymbol-navigation.check b/test/files/run/reflection-fieldsymbol-navigation.check
index ae0597a045..fd06c78a18 100644
--- a/test/files/run/reflection-fieldsymbol-navigation.check
+++ b/test/files/run/reflection-fieldsymbol-navigation.check
@@ -1,6 +1,6 @@
-method x
+variable x
false
variable x
true
-method x
-method x_=
+variable x
+variable x
diff --git a/test/files/run/repl-colon-type.check b/test/files/run/repl-colon-type.check
index 21fbe34d96..1217e8d8c2 100644
--- a/test/files/run/repl-colon-type.check
+++ b/test/files/run/repl-colon-type.check
@@ -35,7 +35,7 @@ Int
scala> :type protected lazy val f = 5
<console>:5: error: lazy value f cannot be accessed in object $iw
- Access to protected value f not permitted because
+ Access to protected lazy value f not permitted because
enclosing object $eval in package $line13 is not a subclass of
object $iw where target is defined
lazy val $result = f
diff --git a/test/files/run/showdecl.check b/test/files/run/showdecl.check
index b8d7f94c57..d431c36f6d 100644
--- a/test/files/run/showdecl.check
+++ b/test/files/run/showdecl.check
@@ -8,7 +8,7 @@ initialized y: lazy val y: Int
uninitialized z: def z: <?>
initialized z: def z: Int
uninitialized t: def t: <?>
-initialized t: def t[T <: Int](x: D)(y: x.W): Int
+initialized t: def t[T <: <?>](x: D)(y: x.W): Int
uninitialized W: type W = String
initialized W: type W = String
uninitialized C: class C extends
diff --git a/test/files/run/showdecl/Macros_1.scala b/test/files/run/showdecl/Macros_1.scala
index c68dd275de..89b8e8d3c2 100644
--- a/test/files/run/showdecl/Macros_1.scala
+++ b/test/files/run/showdecl/Macros_1.scala
@@ -9,7 +9,7 @@ object Macros {
import c.universe._
def test(sym: Symbol): Unit = {
println(s"uninitialized ${sym.name}: ${showDecl(sym)}")
- sym.info
+ sym.info // NOTE: not fullyInitializeSymbol, so some parts may still be LazyTypes
println(s"initialized ${sym.name}: ${showDecl(sym)}")
}
diff --git a/test/files/run/showraw_mods.check b/test/files/run/showraw_mods.check
index 4d34160422..ff77d22adf 100644
--- a/test/files/run/showraw_mods.check
+++ b/test/files/run/showraw_mods.check
@@ -1 +1 @@
-Block(List(ClassDef(Modifiers(ABSTRACT | DEFAULTPARAM/TRAIT), TypeName("C"), List(), Template(List(Ident(TypeName("AnyRef"))), noSelfType, List(DefDef(Modifiers(), TermName("$init$"), List(), List(List()), TypeTree(), Block(List(), Literal(Constant(())))), ValDef(Modifiers(PRIVATE | LOCAL), TermName("x"), TypeTree(), Literal(Constant(2))), ValDef(Modifiers(MUTABLE), TermName("y"), TypeTree(), Select(This(TypeName("C")), TermName("x"))), ValDef(Modifiers(LAZY), TermName("z"), TypeTree(), Select(This(TypeName("C")), TermName("y"))))))), Literal(Constant(())))
+Block(List(ClassDef(Modifiers(ABSTRACT | DEFAULTPARAM/TRAIT), TypeName("C"), List(), Template(List(Ident(TypeName("AnyRef"))), noSelfType, List(DefDef(Modifiers(), TermName("$init$"), List(), List(List()), TypeTree(), Block(List(), Literal(Constant(())))), DefDef(Modifiers(PRIVATE | METHOD | LOCAL | STABLE | ACCESSOR), TermName("x"), List(), List(), TypeTree(), Literal(Constant(2))), DefDef(Modifiers(METHOD | ACCESSOR), TermName("y"), List(), List(), TypeTree(), Select(This(TypeName("C")), TermName("x"))), DefDef(Modifiers(METHOD | ACCESSOR), TermName("y_$eq"), List(), List(List(ValDef(Modifiers(PARAM | SYNTHETIC), TermName("x$1"), TypeTree(), EmptyTree))), TypeTree(), EmptyTree), ValDef(Modifiers(LAZY), TermName("z"), TypeTree(), Select(This(TypeName("C")), TermName("y"))))))), Literal(Constant(())))
diff --git a/test/files/run/t4287inferredMethodTypes.check b/test/files/run/t4287inferredMethodTypes.check
deleted file mode 100644
index 56e9c097cc..0000000000
--- a/test/files/run/t4287inferredMethodTypes.check
+++ /dev/null
@@ -1,30 +0,0 @@
-[[syntax trees at end of typer]] // newSource1.scala
-[0:92]package [0:0]<empty> {
- [0:21]class A extends [7:21][23]scala.AnyRef {
- [8:16]<paramaccessor> private[this] val a: [8]Int = _;
- <8:20>def <init>(<8:20>a: [11]<type: [11]scala.Int> = [17:20]A.a): [7]A = <8:20>{
- <8:20><8:20><8:20>A.super.<init>();
- <8:20>()
- }
- };
- [23:47]object A extends [32:47][49]scala.AnyRef {
- [49]def <init>(): [32]A.type = [49]{
- [49][49][49]A.super.<init>();
- [32]()
- };
- [36:45]private[this] val a: [40]Int = [44:45]2;
- [40]<stable> <accessor> def a: [40]Int = [40][40]A.this.a;
- [8]<synthetic> def <init>$default$1: [8]Int = [19]A.a
- };
- [49:92]class B extends [57:92][65:66]A {
- [65]def <init>(): [57]B = [65]{
- [65][65][65]B.super.<init>([65]A.<init>$default$1);
- [57]()
- };
- [70:90]def <init>([79:80]a: [79]Int): [74]B = [84:90]{
- [84:90][84:90][84]B.this.<init>();
- [84]()
- }
- }
-}
-
diff --git a/test/files/run/t4287inferredMethodTypes.scala b/test/files/run/t4287inferredMethodTypes.scala
deleted file mode 100644
index f14e672da8..0000000000
--- a/test/files/run/t4287inferredMethodTypes.scala
+++ /dev/null
@@ -1,25 +0,0 @@
-import scala.tools.partest.DirectTest
-
-object Test extends DirectTest {
-
- override def extraSettings: String =
- s"-usejavacp -Yinfer-argument-types -Xprint-pos -Xprint:typer -Yrangepos -Ystop-after:typer -d ${testOutput.path}"
-
- override def code = """
-class A(a: Int = A.a)
-
-object A {
- val a = 2
-}
-
-class B extends A {
- def this(a) = this()
-}
- """.trim
-
- override def show(): Unit = {
- Console.withErr(System.out) {
- compile()
- }
- }
-} \ No newline at end of file
diff --git a/test/files/run/t6733.check b/test/files/run/t6733.check
index aeb595fbfd..7062301c56 100644
--- a/test/files/run/t6733.check
+++ b/test/files/run/t6733.check
@@ -2,23 +2,22 @@ method $init$: isPrivateThis = false, isProtectedThis = false
value pri1a: isPrivateThis = true, isProtectedThis = false
method pri2a: isPrivateThis = true, isProtectedThis = false
variable pri3a: isPrivateThis = true, isProtectedThis = false
-value pri4a: isPrivateThis = true, isProtectedThis = false
+variable pri3a: isPrivateThis = true, isProtectedThis = false
+lazy value pri4a: isPrivateThis = true, isProtectedThis = false
lazy value pri4a: isPrivateThis = true, isProtectedThis = false
type Pri5a: isPrivateThis = true, isProtectedThis = false
class Pri6: isPrivateThis = true, isProtectedThis = false
trait Pri7: isPrivateThis = true, isProtectedThis = false
object Pri8: isPrivateThis = true, isProtectedThis = false
value pro1a: isPrivateThis = false, isProtectedThis = true
-value pro1a: isPrivateThis = true, isProtectedThis = false
value pro1b: isPrivateThis = false, isProtectedThis = true
method pro2a: isPrivateThis = false, isProtectedThis = true
method pro2b: isPrivateThis = false, isProtectedThis = true
-method pro3a: isPrivateThis = false, isProtectedThis = true
-method pro3a_=: isPrivateThis = false, isProtectedThis = true
-variable pro3a: isPrivateThis = true, isProtectedThis = false
-method pro3b: isPrivateThis = false, isProtectedThis = true
-method pro3b_=: isPrivateThis = false, isProtectedThis = true
-value pro4a: isPrivateThis = false, isProtectedThis = true
+variable pro3a: isPrivateThis = false, isProtectedThis = true
+variable pro3a: isPrivateThis = false, isProtectedThis = true
+variable pro3b: isPrivateThis = false, isProtectedThis = true
+variable pro3b: isPrivateThis = false, isProtectedThis = true
+lazy value pro4a: isPrivateThis = false, isProtectedThis = true
lazy value pro4a: isPrivateThis = true, isProtectedThis = false
type Pro5a: isPrivateThis = false, isProtectedThis = true
type Pro5b: isPrivateThis = false, isProtectedThis = true
diff --git a/test/files/run/t7533.check b/test/files/run/t7533.check
index fa5b3edc8f..61fd4657bd 100644
--- a/test/files/run/t7533.check
+++ b/test/files/run/t7533.check
@@ -1,30 +1,29 @@
Testing Symbol.isAbstract...
=======class C=======
-class C => true
-constructor C => false
-value x1 => true
-value x2 => false
-value x2 => false
-method y1 => true
-method y2 => false
-type T1 => true
-type T2 => false
+class C => abstract
+constructor C => concrete
+value xAbs => abstract
+value x => concrete
+value x => concrete
+method yAbs => abstract
+method y => concrete
+type TAbs => abstract
+type T => concrete
=======trait T=======
-trait T => true
-method $init$ => false
-value z1 => true
-value z2 => false
-value z2 => false
-method w1 => true
-method w2 => false
-type U1 => true
-type U2 => false
-=======class D=======
-class D => false
-constructor D => false
-value x1 => false
-value x1 => false
-method y1 => false
+trait T => abstract
+method $init$ => concrete
+value zAbs => abstract
+value z => concrete
+method wAbs => abstract
+method w => concrete
+type UAbs => abstract
+type U => concrete
+=======class AllConcrete=======
+class AllConcrete => concrete
+constructor AllConcrete => concrete
+value xAbs => concrete
+value xAbs => concrete
+method yAbs => concrete
=======object M=======
-object M => false
-constructor M => false
+object M => concrete
+constructor M => concrete
diff --git a/test/files/run/t7533.scala b/test/files/run/t7533.scala
index c7bd8e8d43..65c5c26b42 100644
--- a/test/files/run/t7533.scala
+++ b/test/files/run/t7533.scala
@@ -1,24 +1,24 @@
import scala.reflect.runtime.universe._
abstract class C {
- val x1: Int
- val x2: Int = 2
- def y1: Int
- def y2: Int = 2
- type T1 <: Int
- type T2 = Int
+ val xAbs: Int
+ val x: Int = 2
+ def yAbs: Int
+ def y: Int = 2
+ type TAbs <: Int
+ type T = Int
}
trait T {
- val z1: Int
- val z2: Int = 2
- def w1: Int
- def w2: Int = 2
- type U1 <: Int
- type U2 = Int
+ val zAbs: Int
+ val z: Int = 2
+ def wAbs: Int
+ def w: Int = 2
+ type UAbs <: Int
+ type U = Int
}
-class D extends C {
- val x1 = 3
- def y1 = 3
+class AllConcrete extends C {
+ val xAbs = 3
+ def yAbs = 3
}
object M
@@ -27,12 +27,12 @@ object Test extends App {
def test[T: TypeTag] = {
val sym = typeOf[T].typeSymbol
println(s"=======$sym=======")
- def printAbstract(sym: Symbol) = println(s"$sym => ${sym.isAbstract}")
+ def printAbstract(sym: Symbol) = println(s"$sym => ${if (sym.isAbstract) "abstract" else "concrete"}")
printAbstract(sym)
sym.info.decls.sorted.foreach(printAbstract)
}
test[C]
test[T]
- test[D]
+ test[AllConcrete]
test[M.type]
} \ No newline at end of file
diff --git a/test/files/run/t8549.scala b/test/files/run/t8549.scala
index da7a731459..7a38491231 100644
--- a/test/files/run/t8549.scala
+++ b/test/files/run/t8549.scala
@@ -79,7 +79,7 @@ object Test extends App {
}
}
- // Generated on 20160715-08:27:53 with Scala version 2.12.0-20160715-012500-f5a80bd)
+ // Generated on 20160720-18:56:11 with Scala version 2.12.0-local-5815f9a)
overwrite.foreach(updateComment)
check(Some(1))("rO0ABXNyAApzY2FsYS5Tb21lESLyaV6hi3QCAAFMAAV2YWx1ZXQAEkxqYXZhL2xhbmcvT2JqZWN0O3hyAAxzY2FsYS5PcHRpb27+aTf92w5mdAIAAHhwc3IAEWphdmEubGFuZy5JbnRlZ2VyEuKgpPeBhzgCAAFJAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cAAAAAE=")
@@ -174,7 +174,7 @@ object Test extends App {
// check(mutable.ArraySeq(1, 2, 3))( "rO0ABXNyACFzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuQXJyYXlTZXEVPD3SKEkOcwIAAkkABmxlbmd0aFsABWFycmF5dAATW0xqYXZhL2xhbmcvT2JqZWN0O3hwAAAAA3VyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAANzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4ABQAAAAJzcQB+AAUAAAAD")
check(mutable.AnyRefMap("a" -> "A"))( "rO0ABXNyACJzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuQW55UmVmTWFwAAAAAAAAAAECAAdJAAVfc2l6ZUkAB192YWNhbnRJAARtYXNrTAAMZGVmYXVsdEVudHJ5dAARTHNjYWxhL0Z1bmN0aW9uMTtbACtzY2FsYSRjb2xsZWN0aW9uJG11dGFibGUkQW55UmVmTWFwJCRfaGFzaGVzdAACW0lbAClzY2FsYSRjb2xsZWN0aW9uJG11dGFibGUkQW55UmVmTWFwJCRfa2V5c3QAE1tMamF2YS9sYW5nL09iamVjdDtbACtzY2FsYSRjb2xsZWN0aW9uJG11dGFibGUkQW55UmVmTWFwJCRfdmFsdWVzcQB+AAN4cAAAAAEAAAAAAAAAB3NyADNzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuQW55UmVmTWFwJEV4Y2VwdGlvbkRlZmF1bHQAAAAAAAAAAQIAAHhwdXIAAltJTbpgJnbqsqUCAAB4cAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+UkA2AAAAAHVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAhwcHBwcHB0AAFhcHVxAH4ACQAAAAhwcHBwcHB0AAFBcA==")
check(mutable.ArrayStack(1, 2, 3))( "rO0ABXNyACNzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuQXJyYXlTdGFja3bdxXbcnLBeAgACSQAqc2NhbGEkY29sbGVjdGlvbiRtdXRhYmxlJEFycmF5U3RhY2skJGluZGV4WwAqc2NhbGEkY29sbGVjdGlvbiRtdXRhYmxlJEFycmF5U3RhY2skJHRhYmxldAATW0xqYXZhL2xhbmcvT2JqZWN0O3hwAAAAA3VyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAANzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAA3NxAH4ABQAAAAJzcQB+AAUAAAAB")
- check(mutable.DoubleLinkedList(1, 2, 3))( "rO0ABXNyAClzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuRG91YmxlTGlua2VkTGlzdI73LKsKRr1RAgADTAAEZWxlbXQAEkxqYXZhL2xhbmcvT2JqZWN0O0wABG5leHR0AB5Mc2NhbGEvY29sbGVjdGlvbi9tdXRhYmxlL1NlcTtMAARwcmV2cQB+AAJ4cHNyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3EAfgAAc3EAfgAEAAAAAnNxAH4AAHNxAH4ABAAAAANzcQB+AABwcQB+AAtxAH4ACXEAfgAHcQB+AANw")
+ check(mutable.DoubleLinkedList(1, 2, 3))( "rO0ABXNyAClzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuRG91YmxlTGlua2VkTGlzdI73LKsKRr1RAgADTAAEZWxlbXQAEkxqYXZhL2xhbmcvT2JqZWN0O0wABG5leHR0ACtMc2NhbGEvY29sbGVjdGlvbi9tdXRhYmxlL0RvdWJsZUxpbmtlZExpc3Q7TAAEcHJldnEAfgACeHBzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4AAHNxAH4ABAAAAAJzcQB+AABzcQB+AAQAAAADc3EAfgAAcHEAfgALcQB+AAlxAH4AB3EAfgADcA==")
check(mutable.HashMap())( "rO0ABXNyACBzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuSGFzaE1hcAAAAAAAAAABAwAAeHB3DQAAAu4AAAAAAAAABAB4")
check(mutable.HashMap(1 -> 1))( "rO0ABXNyACBzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuSGFzaE1hcAAAAAAAAAABAwAAeHB3DQAAAu4AAAABAAAABABzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXEAfgAEeA==")
@@ -189,7 +189,7 @@ object Test extends App {
// check(new mutable.History())( "rO0ABXNyACBzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuSGlzdG9yeUhuXxDIFJrsAgACSQAKbWF4SGlzdG9yeUwAA2xvZ3QAIExzY2FsYS9jb2xsZWN0aW9uL211dGFibGUvUXVldWU7eHAAAAPoc3IAHnNjYWxhLmNvbGxlY3Rpb24ubXV0YWJsZS5RdWV1ZbjMURVfOuHHAgAAeHIAJHNjYWxhLmNvbGxlY3Rpb24ubXV0YWJsZS5NdXRhYmxlTGlzdFJpnjJ+gFbAAgADSQADbGVuTAAGZmlyc3QwdAAlTHNjYWxhL2NvbGxlY3Rpb24vbXV0YWJsZS9MaW5rZWRMaXN0O0wABWxhc3QwcQB+AAV4cAAAAABzcgAjc2NhbGEuY29sbGVjdGlvbi5tdXRhYmxlLkxpbmtlZExpc3Sak+nGCZHaUQIAAkwABGVsZW10ABJMamF2YS9sYW5nL09iamVjdDtMAARuZXh0dAAeTHNjYWxhL2NvbGxlY3Rpb24vbXV0YWJsZS9TZXE7eHBwcQB+AApxAH4ACg==")
check(mutable.LinkedHashMap(1 -> 2))( "rO0ABXNyACZzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuTGlua2VkSGFzaE1hcAAAAAAAAAABAwAAeHB3DQAAAu4AAAABAAAABABzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4AAgAAAAJ4")
check(mutable.LinkedHashSet(1, 2, 3))( "rO0ABXNyACZzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuTGlua2VkSGFzaFNldAAAAAAAAAABAwAAeHB3DQAAAu4AAAADAAAABABzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4AAgAAAAJzcQB+AAIAAAADeA==")
- check(mutable.LinkedList(1, 2, 3))( "rO0ABXNyACNzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuTGlua2VkTGlzdJqT6cYJkdpRAgACTAAEZWxlbXQAEkxqYXZhL2xhbmcvT2JqZWN0O0wABG5leHR0AB5Mc2NhbGEvY29sbGVjdGlvbi9tdXRhYmxlL1NlcTt4cHNyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3EAfgAAc3EAfgAEAAAAAnNxAH4AAHNxAH4ABAAAAANzcQB+AABwcQB+AAs=")
+ check(mutable.LinkedList(1, 2, 3))( "rO0ABXNyACNzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuTGlua2VkTGlzdJqT6cYJkdpRAgACTAAEZWxlbXQAEkxqYXZhL2xhbmcvT2JqZWN0O0wABG5leHR0ACVMc2NhbGEvY29sbGVjdGlvbi9tdXRhYmxlL0xpbmtlZExpc3Q7eHBzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4AAHNxAH4ABAAAAAJzcQB+AABzcQB+AAQAAAADc3EAfgAAcHEAfgAL")
// TODO SI-8576 unstable under -Xcheckinit
// check(mutable.ListBuffer(1, 2, 3))( "rO0ABXNyACNzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuTGlzdEJ1ZmZlci9y9I7QyWzGAwAEWgAIZXhwb3J0ZWRJAANsZW5MAAVsYXN0MHQAKUxzY2FsYS9jb2xsZWN0aW9uL2ltbXV0YWJsZS8kY29sb24kY29sb247TAAqc2NhbGEkY29sbGVjdGlvbiRtdXRhYmxlJExpc3RCdWZmZXIkJHN0YXJ0dAAhTHNjYWxhL2NvbGxlY3Rpb24vaW1tdXRhYmxlL0xpc3Q7eHBzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4ABAAAAAJzcQB+AAQAAAADc3IALHNjYWxhLmNvbGxlY3Rpb24uaW1tdXRhYmxlLkxpc3RTZXJpYWxpemVFbmQkilxjW/dTC20CAAB4cHcFAAAAAAN4")
diff --git a/test/files/run/trait_fields_bytecode.scala b/test/files/run/trait_fields_bytecode.scala
new file mode 100644
index 0000000000..d87412f43e
--- /dev/null
+++ b/test/files/run/trait_fields_bytecode.scala
@@ -0,0 +1,23 @@
+trait TFinal { final val bla: Int = 123 }
+
+// bla should be final in C
+class CFinal extends TFinal
+
+
+trait TConst { final val C = "S" }
+// there should be a C method in `T$class`!
+class CConst extends TConst { }
+
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ val f1 = classOf[CFinal].getDeclaredMethod("bla")
+ import java.lang.reflect.Modifier._
+ assert(isFinal(f1.getModifiers), f1)
+
+ classOf[CConst].getMethod("C")
+
+ import language.reflectiveCalls
+ assert(new CConst().asInstanceOf[{def C: String}].C == "S")
+ }
+}
diff --git a/test/files/run/trait_fields_final.scala b/test/files/run/trait_fields_final.scala
new file mode 100644
index 0000000000..8b32e5b47d
--- /dev/null
+++ b/test/files/run/trait_fields_final.scala
@@ -0,0 +1,21 @@
+// TODO: clarify meaning of final in traits
+// In the new compiler, there's no final modifier after mixin for `meh`'s setter,
+// whereas 2.12.0-M3 makes meh's trait setter final.
+// NOTE: bytecode is identical, but the scalasignature is different
+trait Foo { self: Meh =>
+ def bar(x: String) = x == "a"
+ private final val meh = bar("a")
+}
+
+abstract class Meh extends Foo
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ val setter = classOf[Meh].getDeclaredMethod("Foo$_setter_$Foo$$meh_$eq", java.lang.Boolean.TYPE)
+ val getter = classOf[Meh].getDeclaredMethod("Foo$$meh")
+ import java.lang.reflect.Modifier._
+ assert(isFinal(setter.getModifiers), setter)
+ assert(isFinal(getter.getModifiers), getter)
+ }
+
+}
diff --git a/test/files/run/trait_fields_init.check b/test/files/run/trait_fields_init.check
new file mode 100644
index 0000000000..84c1a2ead9
--- /dev/null
+++ b/test/files/run/trait_fields_init.check
@@ -0,0 +1,21 @@
+x
+y
+z
+abstract
+public
+protected
+abstract protected
+private
+private[this]
+abstract
+public
+protected
+abstract protected
+private
+private[this]
+abstract
+public
+protected
+abstract protected
+private
+private[this]
diff --git a/test/files/run/trait_fields_init.scala b/test/files/run/trait_fields_init.scala
new file mode 100644
index 0000000000..496911d538
--- /dev/null
+++ b/test/files/run/trait_fields_init.scala
@@ -0,0 +1,55 @@
+trait T {
+ val abs: String
+ protected val protabs: String
+ val pub = "public"
+ protected val prot = "protected"
+ private val privvy = "private"
+ private[this] val privateThis = "private[this]"
+ // TODO:
+ // final val const = "const"
+
+ trait Nested { println(abs + privateThis) }
+
+ object NO {
+ println(abs)
+ println(pub)
+ println(prot)
+ println(protabs)
+ println(privvy)
+ println(privateThis)
+ }
+
+ trait NT {
+ println(abs)
+ println(pub)
+ println(prot)
+ println(protabs)
+ println(privvy)
+ println(privateThis)
+ }
+
+ class NC {
+ println(abs)
+ println(pub)
+ println(prot)
+ println(protabs)
+ println(privvy)
+ println(privateThis)
+ }
+}
+
+class C extends AnyRef with T {
+ println("x")
+ val abs = "abstract"
+ println("y")
+ val protabs = "abstract protected"
+ final val const = "const"
+ println("z")
+}
+
+object Test extends C {
+ def main(args: Array[String]): Unit = {
+ NO
+ new NT{}
+ new NC
+}} \ No newline at end of file
diff --git a/test/files/run/trait_fields_repl.check b/test/files/run/trait_fields_repl.check
new file mode 100644
index 0000000000..d03a565c7b
--- /dev/null
+++ b/test/files/run/trait_fields_repl.check
@@ -0,0 +1,11 @@
+
+scala> trait B { val y = "a" }
+defined trait B
+
+scala> trait T extends B { val x: y.type = y }
+defined trait T
+
+scala> println((new T{}).x)
+a
+
+scala> :quit
diff --git a/test/files/run/trait_fields_repl.scala b/test/files/run/trait_fields_repl.scala
new file mode 100644
index 0000000000..311477b7d2
--- /dev/null
+++ b/test/files/run/trait_fields_repl.scala
@@ -0,0 +1,10 @@
+// TODO: fix AME when this runs in REPL
+import scala.tools.partest.ReplTest
+
+object Test extends ReplTest {
+ def code = """
+trait B { val y = "a" }
+trait T extends B { val x: y.type = y }
+println((new T{}).x)
+"""
+}
diff --git a/test/files/run/trait_fields_three_layer_overrides.check b/test/files/run/trait_fields_three_layer_overrides.check
new file mode 100644
index 0000000000..8bb45803c5
--- /dev/null
+++ b/test/files/run/trait_fields_three_layer_overrides.check
@@ -0,0 +1,2 @@
+the real universe.TypeTag
+1
diff --git a/test/files/run/trait_fields_three_layer_overrides.scala b/test/files/run/trait_fields_three_layer_overrides.scala
new file mode 100644
index 0000000000..9d7aa94341
--- /dev/null
+++ b/test/files/run/trait_fields_three_layer_overrides.scala
@@ -0,0 +1,25 @@
+// interesting hierarchies/overrides distilled from reflect/compiler
+
+trait Aliases {
+ val TypeTag = "universe.TypeTag"
+}
+trait AliasesOverrides extends Aliases { // or self: Aliases =>
+ override val TypeTag = "the real universe.TypeTag"
+}
+class Context extends Aliases with AliasesOverrides
+
+
+
+trait SymbolTable {
+ def currentRunId: Int = -1
+}
+trait ReflectSetup extends SymbolTable {
+ override val currentRunId = 1
+}
+class G extends SymbolTable with ReflectSetup
+
+
+object Test extends App {
+ println((new Context).TypeTag)
+ println((new G).currentRunId)
+} \ No newline at end of file
diff --git a/test/files/run/trait_fields_volatile.scala b/test/files/run/trait_fields_volatile.scala
new file mode 100644
index 0000000000..eedb6de1c2
--- /dev/null
+++ b/test/files/run/trait_fields_volatile.scala
@@ -0,0 +1,13 @@
+// bytecode should reflect volatile annotation
+trait VolatileAbort {
+ @volatile private var abortflag = false
+}
+class DefaultSignalling extends VolatileAbort
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ val field = classOf[DefaultSignalling].getDeclaredFields.find(_.getName.contains("abortflag")).get
+ assert(java.lang.reflect.Modifier.isVolatile(field.getModifiers), field)
+ }
+
+}
diff --git a/test/junit/scala/reflect/internal/PrintersTest.scala b/test/junit/scala/reflect/internal/PrintersTest.scala
index d581ca8cf4..6f9b711b34 100644
--- a/test/junit/scala/reflect/internal/PrintersTest.scala
+++ b/test/junit/scala/reflect/internal/PrintersTest.scala
@@ -151,7 +151,7 @@ class BasePrintTest {
|else
| ((a.toString): String)""",
typedCode=sm"""
- |val a = 1;
+ |val a: Int = 1;
|if (PrintersContext.this.a.>(1))
| ((PrintersContext.this.a): scala.Int)
|else
@@ -864,7 +864,7 @@ class TraitPrintTest {
@Test def testTraitWithSelf2 = assertPrintedCode(sm"""
|trait X { self: scala.Cloneable with scala.Serializable =>
- | val x: scala.Int = 1
+ | val x: Int = 1
|}""")
@Test def testTraitTypeParams = assertPrintedCode("trait X[A, B]")
@@ -903,7 +903,7 @@ class TraitPrintTest {
| type Foo;
| type XString = scala.Predef.String
|} with scala.Serializable {
- | val z = 7
+ | val z: Int = 7
|}""")
@Test def testTraitWithSingletonTypeTree = assertPrintedCode(sm"""
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala
index 54f4c805c1..d24b4e518b 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala
@@ -104,6 +104,7 @@ class ScalaInlineInfoTest extends BytecodeTesting {
("x4()I", MethodInlineInfo(false,false,false)),
("x4$(LT;)I", MethodInlineInfo(true ,false,false)),
("x5()I", MethodInlineInfo(true, false,false)),
+ ("x5$(LT;)I", MethodInlineInfo(true ,false,false)),
("L$lzycompute$1(Lscala/runtime/VolatileObjectRef;)LT$L$2$;", MethodInlineInfo(true, false,false)),
("L$1(Lscala/runtime/VolatileObjectRef;)LT$L$2$;", MethodInlineInfo(true ,false,false)),
("nest$1()I", MethodInlineInfo(true, false,false)),
@@ -127,7 +128,7 @@ class ScalaInlineInfoTest extends BytecodeTesting {
"x3_$eq(I)V" -> MethodInlineInfo(false,false,false),
"x4$lzycompute()I" -> MethodInlineInfo(true ,false,false),
"x4()I" -> MethodInlineInfo(false,false,false),
- "x5()I" -> MethodInlineInfo(true ,false,false),
+// "x5()I" -> MethodInlineInfo(true ,false,false), -- there is no x5 in the class as it's implemented fully in the interface
"T$$super$toString()Ljava/lang/String;" -> MethodInlineInfo(true ,false,false),
"<init>()V" -> MethodInlineInfo(false,false,false)),
None)
diff --git a/test/pending/run/origins.check b/test/pending/run/origins.check
index b12cb6e38f..af94b549d3 100644
--- a/test/pending/run/origins.check
+++ b/test/pending/run/origins.check
@@ -1,6 +1,4 @@
->> Origins tag 'boop' logged 65 calls from 3 distinguished sources.
+>> Origins tag 'boop' logged 65 calls from 1 distinguished sources.
- 50 Test$$anonfun$f3$1.apply(origins.scala:16)
- 10 Test$$anonfun$f2$1.apply(origins.scala:15)
- 5 Test$$anonfun$f1$1.apply(origins.scala:14)
+ 65 null