Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2de8b62

Browse files
authored
Merge pull request #6559 from som-snytt/issue/post-postfix
Prepare to make postfixOps syntax an error (not just a warning) unless the feature is explicitly enabled
2 parents 6ff29f9 + b9e039c commit 2de8b62

File tree

15 files changed

+95
-68
lines changed

15 files changed

+95
-68
lines changed

src/compiler/scala/tools/nsc/Global.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,6 +1434,7 @@ class Global(var currentSettings: Settings, reporter0: LegacyReporter)
14341434
units foreach addUnit
14351435
reporter.reset()
14361436
warnDeprecatedAndConflictingSettings()
1437+
checkGoldenUnits(units)
14371438
globalPhase = fromPhase
14381439

14391440
val timePhases = statistics.areStatisticsLocallyEnabled
@@ -1518,6 +1519,16 @@ class Global(var currentSettings: Settings, reporter0: LegacyReporter)
15181519
perRunCaches.clearAll()
15191520
}
15201521

1522+
// special dispensations for golden units
1523+
def checkGoldenUnits(units: List[CompilationUnit]): Unit = {
1524+
units match {
1525+
case u :: Nil if u.source.file.path.endsWith("xsbt/Compat.scala") =>
1526+
val ss = settings
1527+
ss.language.enable(ss.languageFeatures.postfixOps)
1528+
case _ =>
1529+
}
1530+
}
1531+
15211532
/** Compile list of abstract files. */
15221533
def compileFiles(files: List[AbstractFile]): Unit = {
15231534
try {

src/compiler/scala/tools/nsc/settings/ScalaSettings.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@ trait ScalaSettings extends AbsScalaSettings
6060
// The two requirements: delay error checking until you have symbols, and let compiler command build option-specific help.
6161
object languageFeatures extends MultiChoiceEnumeration {
6262
val dynamics = Choice("dynamics", "Allow direct or indirect subclasses of scala.Dynamic")
63-
val postfixOps = Choice("postfixOps", "Allow postfix operator notation, such as `1 to 10 toList'")
64-
val reflectiveCalls = Choice("reflectiveCalls", "Allow reflective access to members of structural types")
65-
val implicitConversions = Choice("implicitConversions", "Allow definition of implicit functions called views")
66-
val higherKinds = Choice("higherKinds", "Allow higher-kinded types")
6763
val existentials = Choice("existentials", "Existential types (besides wildcard types) can be written and inferred")
64+
val higherKinds = Choice("higherKinds", "Allow higher-kinded types")
65+
val implicitConversions = Choice("implicitConversions", "Allow definition of implicit functions called views")
66+
val postfixOps = Choice("postfixOps", "Allow postfix operator notation, such as `1 to 10 toList` (not recommended)")
67+
val reflectiveCalls = Choice("reflectiveCalls", "Allow reflective access to members of structural types")
6868
val macros = Choice("experimental.macros", "Allow macro definition (besides implementation and application)")
6969
}
7070
val language = {

src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,10 +188,10 @@ trait AccessorSynthesis extends Transform with ast.TreeDSL {
188188
bitmapSyms
189189
}
190190

191-
fields groupBy bitmapCategory flatMap {
191+
fields.groupBy(bitmapCategory).flatMap {
192192
case (category, fields) if category != nme.NO_NAME && fields.nonEmpty => allocateBitmaps(fields, category): Iterable[Symbol]
193193
case _ => Nil
194-
} toList
194+
}.toList
195195
}
196196

197197
def slowPathFor(lzyVal: Symbol): Symbol = _slowPathFor(lzyVal)

src/compiler/scala/tools/nsc/transform/Fields.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
423423

424424
// afterOwnPhase, so traits receive trait setters for vals (needs to be at finest grain to avoid looping)
425425
val synthInSubclass =
426-
clazz.mixinClasses.flatMap(mixin => afterOwnPhase{mixin.info}.decls.toList.filter(accessorImplementedInSubclass))
426+
clazz.mixinClasses.flatMap(mixin => afterOwnPhase(mixin.info).decls.toList.filter(accessorImplementedInSubclass))
427427

428428
// mixin field accessors --
429429
// invariant: (accessorsMaybeNeedingImpl, mixedInAccessorAndFields).zipped.forall(case (acc, clone :: _) => `clone` is clone of `acc` case _ => true)
@@ -679,14 +679,14 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
679679
synthAccessorInClass.expandLazyClassMember(lazyVar, getter, rhs)
680680
}
681681

682-
(afterOwnPhase { clazz.info.decls }.toList) filter checkAndClearNeedsTrees map {
682+
afterOwnPhase(clazz.info.decls).toList.filter(checkAndClearNeedsTrees).map {
683683
case module if module hasAllFlags (MODULE | METHOD) => moduleAccessorBody(module)
684684
case getter if getter hasAllFlags (LAZY | METHOD) => superLazy(getter)
685685
case setter if setter.isSetter => setterBody(setter)
686686
case getter if getter.hasFlag(ACCESSOR) => getterBody(getter)
687687
case field if !(field hasFlag METHOD) => mkTypedValDef(field) // vals/vars and module vars (cannot have flags PACKAGE | JAVA since those never receive NEEDS_TREES)
688688
case _ => EmptyTree
689-
} filterNot (_ == EmptyTree) // there will likely be many EmptyTrees, but perhaps no thicket blocks that need expanding
689+
}.filterNot(_ == EmptyTree) // there will likely be many EmptyTrees, but perhaps no thicket blocks that need expanding
690690
}
691691

692692
def rhsAtOwner(stat: ValOrDefDef, newOwner: Symbol): Tree =

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -727,21 +727,19 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
727727
* if feature check is delayed or suppressed because we are past typer: true
728728
*/
729729
def checkFeature(pos: Position, featureTrait: Symbol, construct: => String = "", immediate: Boolean = false): Boolean =
730-
if (isPastTyper) true
731-
else {
730+
isPastTyper || {
732731
val nestedOwners =
733732
featureTrait.owner.ownerChain.takeWhile(_ != languageFeatureModule.moduleClass).reverse
734733
val featureName = (nestedOwners map (_.name + ".")).mkString + featureTrait.name
735734
def action(): Boolean = {
736735
def hasImport = inferImplicitByType(featureTrait.tpe, context).isSuccess
737736
def hasOption = settings.language contains featureName
738-
val OK = hasImport || hasOption
739-
if (!OK) {
737+
hasOption || hasImport || {
740738
val Some(AnnotationInfo(_, List(Literal(Constant(featureDesc: String)), Literal(Constant(required: Boolean))), _)) =
741739
featureTrait getAnnotation LanguageFeatureAnnot
742740
context.featureWarning(pos, featureName, featureDesc, featureTrait, construct, required)
741+
false
743742
}
744-
OK
745743
}
746744
if (immediate) {
747745
action()

src/library/scala/language.scala

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ package scala
2222
*
2323
* The language features are:
2424
* - [[dynamics `dynamics`]] enables defining calls rewriting using the [[scala.Dynamic `Dynamic`]] trait
25-
* - [[postfixOps `postfixOps`]] enables postfix operators
26-
* - [[reflectiveCalls `reflectiveCalls`]] enables using structural types
27-
* - [[implicitConversions `implicitConversions`]] enables defining implicit methods and members
28-
* - [[higherKinds `higherKinds`]] enables writing higher-kinded types
2925
* - [[existentials `existentials`]] enables writing existential types
26+
* - [[higherKinds `higherKinds`]] enables writing higher-kinded types
27+
* - [[implicitConversions `implicitConversions`]] enables defining implicit methods and members
28+
* - [[postfixOps `postfixOps`]] enables postfix operators (not recommended)
29+
* - [[reflectiveCalls `reflectiveCalls`]] enables using structural types
3030
* - [[experimental `experimental`]] contains newer features that have not yet been tested in production
3131
*
3232
* @groupname production Language Features
@@ -37,10 +37,11 @@ object language {
3737

3838
import languageFeature._
3939

40-
/** Where enabled, direct or indirect subclasses of trait scala.Dynamic can
41-
* be defined. Unless dynamics is enabled, a definition of a class, trait,
42-
* or object that has Dynamic as a base trait is rejected. Dynamic member
43-
* selection of existing subclasses of trait Dynamic are unaffected;
40+
/** Only where this feature is enabled, can direct or indirect subclasses of trait scala.Dynamic
41+
* be defined. If `dynamics` is not enabled, a definition of a class, trait,
42+
* or object that has `Dynamic` as a base trait is rejected by the compiler.
43+
*
44+
* Selections of dynamic members of existing subclasses of trait `Dynamic` are unaffected;
4445
* they can be used anywhere.
4546
*
4647
* '''Why introduce the feature?''' To enable flexible DSLs and convenient interfacing
@@ -54,19 +55,28 @@ object language {
5455
*/
5556
implicit lazy val dynamics: dynamics = languageFeature.dynamics
5657

57-
/** Only where enabled, postfix operator notation `(expr op)` will be allowed.
58+
/** Only where this feature is enabled, is postfix operator notation `(expr op)` permitted.
59+
* If `postfixOps` is not enabled, an expression using postfix notation is rejected by the compiler.
5860
*
59-
* '''Why keep the feature?''' Several DSLs written in Scala need the notation.
61+
* '''Why keep the feature?''' Postfix notation is preserved for backward
62+
* compatibility only. Historically, several DSLs written in Scala need the notation.
6063
*
6164
* '''Why control it?''' Postfix operators interact poorly with semicolon inference.
62-
* Most programmers avoid them for this reason.
65+
* Most programmers avoid them for this reason alone. Postfix syntax is
66+
* associated with an abuse of infix notation, `a op1 b op2 c op3`,
67+
* that can be harder to read than ordinary method invocation with judicious
68+
* use of parentheses. It is recommended not to enable this feature except for
69+
* legacy code.
6370
*
6471
* @group production
6572
*/
6673
implicit lazy val postfixOps: postfixOps = languageFeature.postfixOps
6774

68-
/** Only where enabled, accesses to members of structural types that need
69-
* reflection are supported. Reminder: A structural type is a type of the form
75+
/** Where this feature is enabled, accesses to members of structural types that need
76+
* reflection are supported. If `reflectiveCalls` is not enabled, an expression
77+
* requiring reflection will trigger a warning from the compiler.
78+
*
79+
* A structural type is a type of the form
7080
* `Parents { Decls }` where `Decls` contains declarations of new members that do
7181
* not override any member in `Parents`. To access one of these members, a
7282
* reflective call is needed.
@@ -83,8 +93,11 @@ object language {
8393
*/
8494
implicit lazy val reflectiveCalls: reflectiveCalls = languageFeature.reflectiveCalls
8595

86-
/** Only where enabled, definitions of implicit conversions are allowed. An
87-
* implicit conversion is an implicit value of unary function type `A => B`,
96+
/** Where this feature is enabled, definitions of implicit conversions are allowed.
97+
* If `implicitConversions` is not enabled, the definition of an implicit
98+
* conversion will trigger a warning from the compiler.
99+
*
100+
* An implicit conversion is an implicit value of unary function type `A => B`,
88101
* or an implicit method that has in its first parameter section a single,
89102
* non-implicit parameter. Examples:
90103
*
@@ -94,8 +107,8 @@ object language {
94107
* implicit def listToX(xs: List[T])(implicit f: T => X): X = ...
95108
* }}}
96109
*
97-
* implicit values of other types are not affected, and neither are implicit
98-
* classes.
110+
* Implicit classes and implicit values of other types are not governed by this
111+
* language feature.
99112
*
100113
* '''Why keep the feature?''' Implicit conversions are central to many aspects
101114
* of Scala’s core libraries.
@@ -110,7 +123,9 @@ object language {
110123
*/
111124
implicit lazy val implicitConversions: implicitConversions = languageFeature.implicitConversions
112125

113-
/** Only where this flag is enabled, higher-kinded types can be written.
126+
/** Where this feature is enabled, higher-kinded types can be written.
127+
* If `higherKinds` is not enabled, a higher-kinded type such as `F[A]`
128+
* will trigger a warning from the compiler.
114129
*
115130
* '''Why keep the feature?''' Higher-kinded types enable the definition of very general
116131
* abstractions such as functor, monad, or arrow. A significant set of advanced
@@ -133,9 +148,12 @@ object language {
133148
*/
134149
implicit lazy val higherKinds: higherKinds = languageFeature.higherKinds
135150

136-
/** Only where enabled, existential types that cannot be expressed as wildcard
151+
/** Where this feature is enabled, existential types that cannot be expressed as wildcard
137152
* types can be written and are allowed in inferred types of values or return
138-
* types of methods. Existential types with wildcard type syntax such as `List[_]`,
153+
* types of methods. If `existentials` is not enabled, those cases will trigger
154+
* a warning from the compiler.
155+
*
156+
* Existential types with wildcard type syntax such as `List[_]`,
139157
* or `Map[String, _]` are not affected.
140158
*
141159
* '''Why keep the feature?''' Existential types are needed to make sense of Java’s wildcard
@@ -151,8 +169,8 @@ object language {
151169
*/
152170
implicit lazy val existentials: existentials = languageFeature.existentials
153171

154-
/** The experimental object contains features that have been recently added but have not
155-
* been thoroughly tested in production yet.
172+
/** The experimental object contains features that are known to have unstable API or
173+
* behavior that may change in future releases.
156174
*
157175
* Experimental features '''may undergo API changes''' in future releases, so production
158176
* code should not rely on them.
@@ -167,8 +185,11 @@ object language {
167185

168186
import languageFeature.experimental._
169187

170-
/** Where enabled, macro definitions are allowed. Macro implementations and
171-
* macro applications are unaffected; they can be used anywhere.
188+
/** Only where this feature is enabled, are macro definitions allowed.
189+
* If `macros` is not enabled, macro definitions are rejected by the compiler.
190+
*
191+
* Macro implementations and macro applications are not governed by this
192+
* language feature; they can be used anywhere.
172193
*
173194
* '''Why introduce the feature?''' Macros promise to make the language more regular,
174195
* replacing ad-hoc language constructs with a general powerful abstraction

src/repl-frontend/scala/tools/nsc/interpreter/shell/InteractiveReader.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,11 @@ class SplashLoop(in: InteractiveReader, prompt: String) extends Runnable {
8686
var help = f"// Entering paste mode (ctrl-D to finish)%n%n"
8787

8888
val text =
89-
try Iterator.continually(in.readLine(help))
90-
.takeWhile { x => help = ""
91-
x != null && running }
92-
.mkString(EOL)
93-
.trim
89+
try
90+
Iterator.continually(in.readLine(help)).takeWhile { x =>
91+
help = ""
92+
x != null && running
93+
}.mkString(EOL).trim
9494
catch { case ie: InterruptedException => "" } // TODO let the exception bubble up, or at least signal the interrupt happened?
9595

9696
val next =

src/repl-frontend/scala/tools/nsc/interpreter/shell/Pasted.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ abstract class Pasted(prompt: String, continuePrompt: String, continueText: Stri
5353
private val resAssign = """^val (res\d+).*""".r
5454

5555
private class PasteAnalyzer(val lines: List[String]) {
56-
val referenced = lines.flatMap(resReference findAllIn _.trim.stripPrefix("res")).toSet
57-
val ActualPromptString = lines find matchesPrompt map (s =>
58-
if (matchesString(s, PromptString)) PromptString else AltPromptString) getOrElse PromptString
59-
val cmds = (lines reduceLeft append split ActualPromptString filterNot(_.trim == "")).toList
56+
val referenced = lines.flatMap(s => resReference.findAllIn(s.trim.stripPrefix("res"))).toSet
57+
val ActualPromptString = lines.find(matchesPrompt).map(s =>
58+
if (matchesString(s, PromptString)) PromptString else AltPromptString).getOrElse(PromptString)
59+
val cmds = lines.reduceLeft(append).split(ActualPromptString).filterNot(_.trim == "").toList
6060

6161
/** If it's a prompt or continuation line, strip the formatting bits and
6262
* assemble the code. Otherwise ship it off to be analyzed for res references

src/repl/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,22 @@ class AbstractOrMissingHandler[T](onError: String => Unit, value: T) extends Par
1616
case _ => false
1717
}
1818
def apply(t: Throwable) = t match {
19-
case x @ (_: AbstractMethodError | _: NoSuchMethodError | _: NoClassDefFoundError) =>
20-
onError("""
21-
|Failed to initialize compiler: %s.
19+
case e @ (_: AbstractMethodError | _: NoSuchMethodError | _: NoClassDefFoundError) =>
20+
onError(s"""
21+
|Failed to initialize compiler: ${e.getClass.getName.split('.').last}.
2222
|This is most often remedied by a full clean and recompile.
2323
|Otherwise, your classpath may continue bytecode compiled by
2424
|different and incompatible versions of scala.
25-
|""".stripMargin.format(x.getClass.getName.split('.').last)
25+
|""".stripMargin
2626
)
27-
x.printStackTrace()
27+
e.printStackTrace()
2828
value
29-
case x: MissingRequirementError =>
30-
onError("""
31-
|Failed to initialize compiler: %s not found.
29+
case e: MissingRequirementError =>
30+
onError(s"""
31+
|Failed to initialize compiler: ${e.req} not found.
3232
|** Note that as of 2.8 scala does not assume use of the java classpath.
3333
|** For the old behavior pass -usejavacp to scala, or if using a Settings
34-
|** object programmatically, settings.usejavacp.value = true.""".stripMargin.format(x.req)
34+
|** object programmatically, settings.usejavacp.value = true.""".stripMargin
3535
)
3636
value
3737
}

src/repl/scala/tools/nsc/interpreter/Imports.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,7 @@ trait Imports {
4444
* scope twiddling which should be swept away in favor of digging
4545
* into the compiler scopes.
4646
*/
47-
def sessionWildcards: List[Type] = {
48-
importHandlers filter (_.importsWildcard) map (_.targetType) distinct
49-
}
47+
def sessionWildcards: List[Type] = importHandlers.filter(_.importsWildcard).map(_.targetType).distinct
5048

5149
def languageSymbols = languageWildcardSyms flatMap membersAtPickler
5250
def sessionImportedSymbols = importHandlers flatMap (_.importedSymbols)

0 commit comments

Comments
 (0)