aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--docs/CNAME1
-rw-r--r--docs/_config.yml2
-rw-r--r--docs/docs/index.md2
-rw-r--r--project/Build.scala3
-rw-r--r--sandbox/scalajs/src/main/scala/hello.scala (renamed from sandbox/scalajs/hello.scala)0
-rw-r--r--src/dotty/Pair.scala5
-rw-r--r--src/dotty/Singleton.scala5
-rw-r--r--src/dotty/tools/dotc/ast/Desugar.scala10
-rw-r--r--src/dotty/tools/dotc/ast/untpd.scala50
-rw-r--r--src/dotty/tools/dotc/core/Comments.scala3
-rw-r--r--src/dotty/tools/dotc/core/ConstraintHandling.scala24
-rw-r--r--src/dotty/tools/dotc/core/Decorators.scala2
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala39
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala3
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala43
-rw-r--r--src/dotty/tools/dotc/core/Types.scala23
-rw-r--r--src/dotty/tools/dotc/core/tasty/NameBuffer.scala18
-rw-r--r--src/dotty/tools/dotc/parsing/JavaParsers.scala5
-rw-r--r--src/dotty/tools/dotc/parsing/Parsers.scala114
-rw-r--r--src/dotty/tools/dotc/reporting/diagnostic/messages.scala502
-rw-r--r--src/dotty/tools/dotc/transform/ExtensionMethods.scala20
-rw-r--r--src/dotty/tools/dotc/transform/PatternMatcher.scala22
-rw-r--r--src/dotty/tools/dotc/transform/PostTyper.scala13
-rw-r--r--src/dotty/tools/dotc/transform/TailRec.scala6
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala11
-rw-r--r--src/dotty/tools/dotc/typer/ErrorReporting.scala4
-rw-r--r--src/dotty/tools/dotc/typer/Implicits.scala4
-rw-r--r--src/dotty/tools/dotc/typer/Inferencing.scala57
-rw-r--r--src/dotty/tools/dotc/typer/RefChecks.scala2
-rw-r--r--src/dotty/tools/dotc/typer/TypeAssigner.scala6
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala12
-rw-r--r--src/dotty/tools/dotc/util/SourcePosition.scala2
-rw-r--r--src/scala/annotation/internal/Alias.scala (renamed from src/dotty/annotation/internal/Alias.scala)2
-rw-r--r--src/scala/annotation/internal/AnnotationDefault.scala (renamed from src/dotty/annotation/internal/AnnotationDefault.scala)2
-rw-r--r--src/scala/annotation/internal/Body.scala (renamed from src/dotty/annotation/internal/Body.scala)2
-rw-r--r--src/scala/annotation/internal/Child.scala (renamed from src/dotty/annotation/internal/Child.scala)4
-rw-r--r--src/scala/annotation/internal/InlineParam.scala (renamed from src/dotty/annotation/internal/InlineParam.scala)2
-rw-r--r--src/scala/annotation/internal/Repeated.scala (renamed from src/dotty/annotation/internal/Repeated.scala)2
-rw-r--r--src/scala/annotation/internal/SourceFile.scala (renamed from src/dotty/annotation/internal/SourceFile.scala)2
-rw-r--r--src/scala/annotation/internal/UnsafeNonvariant.scala (renamed from src/dotty/annotation/internal/UnsafeNonvariant.scala)2
-rw-r--r--src/scalaShadowing/language.scala198
-rw-r--r--test/test/ModifiersParsingTest.scala162
-rw-r--r--tests/neg/i1286.scala16
-rw-r--r--tests/neg/i1531.scala6
-rw-r--r--tests/pos/1567/PosZInt_1.scala6
-rw-r--r--tests/pos/1567/Test_2.scala3
-rw-r--r--tests/pos/i1500.scala19
-rw-r--r--tests/pos/i1515.scala16
-rw-r--r--tests/pos/i1540.scala14
-rw-r--r--tests/pos/i1540b.scala14
-rw-r--r--tests/pos/i1544.scala4
-rw-r--r--tests/pos/i1570.scala4
-rw-r--r--tests/pos/i1590.scala10
-rw-r--r--tests/pos/java-interop/1576/TagAnnotation.java3
-rw-r--r--tests/pos/java-interop/1576/Test.scala5
-rw-r--r--tests/pos/tailcall/i1614.scala9
-rw-r--r--tests/repl/imports.check10
58 files changed, 1336 insertions, 196 deletions
diff --git a/.gitignore b/.gitignore
index 9536d0ebc..7c5baf8f8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,8 @@ project/boot/
project/plugins/project/
project/local-plugins.sbt
.history
+.ensime
+.ensime_cache/
# Scala-IDE specific
.scala_dependencies
diff --git a/docs/CNAME b/docs/CNAME
new file mode 100644
index 000000000..ed5ff1bc5
--- /dev/null
+++ b/docs/CNAME
@@ -0,0 +1 @@
+dotty.epfl.ch \ No newline at end of file
diff --git a/docs/_config.yml b/docs/_config.yml
index d32781d9a..51578256b 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -1,5 +1,5 @@
title: Dotty Documentation
-baseurl: "/dotty"
+baseurl: ""
theme: minima
gems:
- jekyll-toc
diff --git a/docs/docs/index.md b/docs/docs/index.md
index b8c5e9c20..6fc2b2739 100644
--- a/docs/docs/index.md
+++ b/docs/docs/index.md
@@ -11,9 +11,9 @@ pages.
Index
-----
-* [Blog](blog/)
* Usage
- [Migrating from Scala 2](usage/migrating.md)
+ - [Using Dotty with cbt](usage/cbt-projects.md)
- [Using Dotty with sbt](usage/sbt-projects.md)
* Contributing
- [Getting Started](contributing/getting-started.md) details on how to run
diff --git a/project/Build.scala b/project/Build.scala
index 5ee082800..7c57bd862 100644
--- a/project/Build.scala
+++ b/project/Build.scala
@@ -64,9 +64,6 @@ object DottyBuild extends Build {
lazy val dotty = project.in(file(".")).
dependsOn(`dotty-interfaces`).
settings(
- // Disable scaladoc generation, makes publishLocal much faster
- publishArtifact in packageDoc := false,
-
overrideScalaVersionSetting,
// set sources to src/, tests to test/ and resources to resources/
diff --git a/sandbox/scalajs/hello.scala b/sandbox/scalajs/src/main/scala/hello.scala
index bd4aa8cc5..bd4aa8cc5 100644
--- a/sandbox/scalajs/hello.scala
+++ b/sandbox/scalajs/src/main/scala/hello.scala
diff --git a/src/dotty/Pair.scala b/src/dotty/Pair.scala
deleted file mode 100644
index 2322fe169..000000000
--- a/src/dotty/Pair.scala
+++ /dev/null
@@ -1,5 +0,0 @@
-package dotty
-
-class Pair[T, U](x: T, y: U) {
-
-}
diff --git a/src/dotty/Singleton.scala b/src/dotty/Singleton.scala
deleted file mode 100644
index 4ba57a12d..000000000
--- a/src/dotty/Singleton.scala
+++ /dev/null
@@ -1,5 +0,0 @@
-package dotty
-
-class Singleton {
-
-}
diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala
index af34164dc..639dac930 100644
--- a/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/src/dotty/tools/dotc/ast/Desugar.scala
@@ -433,11 +433,11 @@ object desugar {
if (!mods.is(Implicit))
Nil
else if (ctx.owner is Package) {
- ctx.error("implicit classes may not be toplevel", cdef.pos)
+ ctx.error(TopLevelImplicitClass(cdef), cdef.pos)
Nil
}
else if (isCaseClass) {
- ctx.error("implicit classes may not be case classes", cdef.pos)
+ ctx.error(ImplicitCaseClass(cdef), cdef.pos)
Nil
}
else
@@ -497,7 +497,7 @@ object desugar {
.withPos(mdef.pos)
val ValDef(selfName, selfTpt, _) = tmpl.self
val selfMods = tmpl.self.mods
- if (!selfTpt.isEmpty) ctx.error("object definition may not have a self type", tmpl.self.pos)
+ if (!selfTpt.isEmpty) ctx.error(ObjectMayNotHaveSelfType(mdef), tmpl.self.pos)
val clsSelf = ValDef(selfName, SingletonTypeTree(Ident(name)), tmpl.self.rhs)
.withMods(selfMods)
.withPos(tmpl.self.pos orElse tmpl.pos.startPos)
@@ -931,7 +931,7 @@ object desugar {
val arity = ts.length
def tupleTypeRef = defn.TupleType(arity)
if (arity > Definitions.MaxTupleArity) {
- ctx.error(s"tuple too long (max allowed: ${Definitions.MaxTupleArity})", tree.pos)
+ ctx.error(TupleTooLong(ts), tree.pos)
unitLiteral
} else if (arity == 1) ts.head
else if (ctx.mode is Mode.Type) AppliedTypeTree(ref(tupleTypeRef), ts)
@@ -1051,7 +1051,7 @@ object desugar {
elems foreach collect
case Alternative(trees) =>
for (tree <- trees; (vble, _) <- getVariables(tree))
- ctx.error("illegal variable in pattern alternative", vble.pos)
+ ctx.error(IllegalVariableInPatternAlternative(), vble.pos)
case Annotated(arg, _) =>
collect(arg)
case InterpolatedString(_, segments) =>
diff --git a/src/dotty/tools/dotc/ast/untpd.scala b/src/dotty/tools/dotc/ast/untpd.scala
index 7fd818c25..ac3beaff4 100644
--- a/src/dotty/tools/dotc/ast/untpd.scala
+++ b/src/dotty/tools/dotc/ast/untpd.scala
@@ -94,9 +94,42 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
class InfixOpBlock(leftOperand: Tree, rightOp: Tree) extends Block(leftOperand :: Nil, rightOp)
// ----- Modifiers -----------------------------------------------------
+ /** Mod is intended to record syntactic information about modifiers, it's
+ * NOT a replacement of FlagSet.
+ *
+ * For any query about semantic information, check `flags` instead.
+ */
+ sealed abstract class Mod(val flags: FlagSet) extends Positioned
- /** Modifiers and annotations for definitions
- * @param flags The set flags
+ object Mod {
+ case class Private() extends Mod(Flags.Private)
+
+ case class Protected() extends Mod(Flags.Protected)
+
+ case class Val() extends Mod(Flags.EmptyFlags)
+
+ case class Var() extends Mod(Flags.Mutable)
+
+ case class Implicit(flag: FlagSet = Flags.ImplicitCommon) extends Mod(flag)
+
+ case class Final() extends Mod(Flags.Final)
+
+ case class Sealed() extends Mod(Flags.Sealed)
+
+ case class Override() extends Mod(Flags.Override)
+
+ case class Abstract() extends Mod(Flags.Abstract)
+
+ case class Lazy() extends Mod(Flags.Lazy)
+
+ case class Inline() extends Mod(Flags.Inline)
+
+ case class Type() extends Mod(Flags.EmptyFlags)
+ }
+
+ /** Modifiers and annotations for definitions
+ *
+ * @param flags The set flags
* @param privateWithin If a private or protected has is followed by a
* qualifier [q], the name q, "" as a typename otherwise.
* @param annotations The annotations preceding the modifiers
@@ -104,7 +137,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
case class Modifiers (
flags: FlagSet = EmptyFlags,
privateWithin: TypeName = tpnme.EMPTY,
- annotations: List[Tree] = Nil) extends Positioned with Cloneable {
+ annotations: List[Tree] = Nil,
+ mods: List[Mod] = Nil) extends Positioned with Cloneable {
def is(fs: FlagSet): Boolean = flags is fs
def is(fc: FlagConjunction): Boolean = flags is fc
@@ -120,7 +154,15 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
if (this.flags == flags) this
else copy(flags = flags)
- def withAddedAnnotation(annot: Tree): Modifiers =
+ def withAddedMod(mod: Mod): Modifiers =
+ if (mods.exists(_ eq mod)) this
+ else withMods(mods :+ mod)
+
+ def withMods(ms: List[Mod]): Modifiers =
+ if (mods eq ms) this
+ else copy(mods = ms)
+
+ def withAddedAnnotation(annot: Tree): Modifiers =
if (annotations.exists(_ eq annot)) this
else withAnnotations(annotations :+ annot)
diff --git a/src/dotty/tools/dotc/core/Comments.scala b/src/dotty/tools/dotc/core/Comments.scala
index 1cf5aec38..1e623db4d 100644
--- a/src/dotty/tools/dotc/core/Comments.scala
+++ b/src/dotty/tools/dotc/core/Comments.scala
@@ -9,6 +9,7 @@ import util.Positions._
import util.CommentParsing._
import util.Property.Key
import parsing.Parsers.Parser
+import reporting.diagnostic.messages.ProperDefinitionNotFound
object Comments {
val ContextDoc = new Key[ContextDocstrings]
@@ -125,7 +126,7 @@ object Comments {
val newName = (tree.name.show + "$" + codePos + "$doc").toTermName
untpd.DefDef(newName, tree.tparams, tree.vparamss, tree.tpt, tree.rhs)
case _ =>
- ctx.error("proper definition was not found in `@usecase`", codePos)
+ ctx.error(ProperDefinitionNotFound(), codePos)
tree
}
}
diff --git a/src/dotty/tools/dotc/core/ConstraintHandling.scala b/src/dotty/tools/dotc/core/ConstraintHandling.scala
index 3835d553c..0e155b9e1 100644
--- a/src/dotty/tools/dotc/core/ConstraintHandling.scala
+++ b/src/dotty/tools/dotc/core/ConstraintHandling.scala
@@ -162,7 +162,8 @@ trait ConstraintHandling {
/** Solve constraint set for given type parameter `param`.
* If `fromBelow` is true the parameter is approximated by its lower bound,
* otherwise it is approximated by its upper bound. However, any occurrences
- * of the parameter in a refinement somewhere in the bound are removed.
+ * of the parameter in a refinement somewhere in the bound are removed. Also
+ * wildcard types in bounds are approximated by their upper or lower bounds.
* (Such occurrences can arise for F-bounded types).
* The constraint is left unchanged.
* @return the instantiating type
@@ -174,6 +175,27 @@ trait ConstraintHandling {
def apply(tp: Type) = mapOver {
tp match {
case tp: RefinedType if param occursIn tp.refinedInfo => tp.parent
+ case tp: WildcardType =>
+ val bounds = tp.optBounds.orElse(TypeBounds.empty).bounds
+ // Try to instantiate the wildcard to a type that is known to conform to it.
+ // This means:
+ // If fromBelow is true, we minimize the type overall
+ // Hence, if variance < 0, pick the maximal safe type: bounds.lo
+ // (i.e. the whole bounds range is over the type)
+ // if variance > 0, pick the minimal safe type: bounds.hi
+ // (i.e. the whole bounds range is under the type)
+ // if variance == 0, pick bounds.lo anyway (this is arbitrary but in line with
+ // the principle that we pick the smaller type when in doubt).
+ // If fromBelow is false, we maximize the type overall and reverse the bounds
+ // if variance != 0. For variance == 0, we still minimize.
+ // In summary we pick the bound given by this table:
+ //
+ // variance | -1 0 1
+ // ------------------------
+ // from below | lo lo hi
+ // from above | hi lo lo
+ //
+ if (variance == 0 || fromBelow == (variance < 0)) bounds.lo else bounds.hi
case _ => tp
}
}
diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala
index b0f1f0c98..a105741f5 100644
--- a/src/dotty/tools/dotc/core/Decorators.scala
+++ b/src/dotty/tools/dotc/core/Decorators.scala
@@ -179,7 +179,7 @@ object Decorators {
/** Formatter that adds syntax highlighting to all interpolated values */
def hl(args: Any*)(implicit ctx: Context): String =
- new SyntaxFormatter(sc).assemble(args)
+ new SyntaxFormatter(sc).assemble(args).stripMargin
}
}
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 50746c61d..541d66306 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -140,6 +140,16 @@ class Definitions {
lazy val Sys_errorR = SysPackage.moduleClass.requiredMethodRef(nme.error)
def Sys_error(implicit ctx: Context) = Sys_errorR.symbol
+ /** The `scalaShadowing` package is used to safely modify classes and
+ * objects in scala so that they can be used from dotty. They will
+ * be visible as members of the `scala` package, replacing any objects
+ * or classes with the same name. But their binary artifacts are
+ * in `scalaShadowing` so they don't clash with the same-named `scala`
+ * members at runtime.
+ */
+ lazy val ScalaShadowingPackageVal = ctx.requiredPackage("scalaShadowing")
+ lazy val ScalaShadowingPackageClass = ScalaShadowingPackageVal.moduleClass.asClass
+
/** Note: We cannot have same named methods defined in Object and Any (and AnyVal, for that matter)
* because after erasure the Any and AnyVal references get remapped to the Object methods
* which would result in a double binding assertion failure.
@@ -410,8 +420,6 @@ class Definitions {
lazy val StringAdd_plusR = StringAddClass.requiredMethodRef(nme.raw.PLUS)
def StringAdd_+(implicit ctx: Context) = StringAdd_plusR.symbol
- lazy val PairType: TypeRef = ctx.requiredClassRef("dotty.Pair")
- def PairClass(implicit ctx: Context) = PairType.symbol.asClass
lazy val PartialFunctionType: TypeRef = ctx.requiredClassRef("scala.PartialFunction")
def PartialFunctionClass(implicit ctx: Context) = PartialFunctionType.symbol.asClass
lazy val AbstractPartialFunctionType: TypeRef = ctx.requiredClassRef("scala.runtime.AbstractPartialFunction")
@@ -450,17 +458,17 @@ class Definitions {
def StaticAnnotationClass(implicit ctx: Context) = StaticAnnotationType.symbol.asClass
// Annotation classes
- lazy val AliasAnnotType = ctx.requiredClassRef("dotty.annotation.internal.Alias")
+ lazy val AliasAnnotType = ctx.requiredClassRef("scala.annotation.internal.Alias")
def AliasAnnot(implicit ctx: Context) = AliasAnnotType.symbol.asClass
- lazy val AnnotationDefaultAnnotType = ctx.requiredClassRef("dotty.annotation.internal.AnnotationDefault")
+ lazy val AnnotationDefaultAnnotType = ctx.requiredClassRef("scala.annotation.internal.AnnotationDefault")
def AnnotationDefaultAnnot(implicit ctx: Context) = AnnotationDefaultAnnotType.symbol.asClass
- lazy val BodyAnnotType = ctx.requiredClassRef("dotty.annotation.internal.Body")
+ lazy val BodyAnnotType = ctx.requiredClassRef("scala.annotation.internal.Body")
def BodyAnnot(implicit ctx: Context) = BodyAnnotType.symbol.asClass
- lazy val ChildAnnotType = ctx.requiredClassRef("dotty.annotation.internal.Child")
+ lazy val ChildAnnotType = ctx.requiredClassRef("scala.annotation.internal.Child")
def ChildAnnot(implicit ctx: Context) = ChildAnnotType.symbol.asClass
- lazy val CovariantBetweenAnnotType = ctx.requiredClassRef("dotty.annotation.internal.CovariantBetween")
+ lazy val CovariantBetweenAnnotType = ctx.requiredClassRef("scala.annotation.internal.CovariantBetween")
def CovariantBetweenAnnot(implicit ctx: Context) = CovariantBetweenAnnotType.symbol.asClass
- lazy val ContravariantBetweenAnnotType = ctx.requiredClassRef("dotty.annotation.internal.ContravariantBetween")
+ lazy val ContravariantBetweenAnnotType = ctx.requiredClassRef("scala.annotation.internal.ContravariantBetween")
def ContravariantBetweenAnnot(implicit ctx: Context) = ContravariantBetweenAnnotType.symbol.asClass
lazy val DeprecatedAnnotType = ctx.requiredClassRef("scala.deprecated")
def DeprecatedAnnot(implicit ctx: Context) = DeprecatedAnnotType.symbol.asClass
@@ -468,9 +476,9 @@ class Definitions {
def ImplicitNotFoundAnnot(implicit ctx: Context) = ImplicitNotFoundAnnotType.symbol.asClass
lazy val InlineAnnotType = ctx.requiredClassRef("scala.inline")
def InlineAnnot(implicit ctx: Context) = InlineAnnotType.symbol.asClass
- lazy val InlineParamAnnotType = ctx.requiredClassRef("dotty.annotation.internal.InlineParam")
+ lazy val InlineParamAnnotType = ctx.requiredClassRef("scala.annotation.internal.InlineParam")
def InlineParamAnnot(implicit ctx: Context) = InlineParamAnnotType.symbol.asClass
- lazy val InvariantBetweenAnnotType = ctx.requiredClassRef("dotty.annotation.internal.InvariantBetween")
+ lazy val InvariantBetweenAnnotType = ctx.requiredClassRef("scala.annotation.internal.InvariantBetween")
def InvariantBetweenAnnot(implicit ctx: Context) = InvariantBetweenAnnotType.symbol.asClass
lazy val MigrationAnnotType = ctx.requiredClassRef("scala.annotation.migration")
def MigrationAnnot(implicit ctx: Context) = MigrationAnnotType.symbol.asClass
@@ -478,9 +486,9 @@ class Definitions {
def NativeAnnot(implicit ctx: Context) = NativeAnnotType.symbol.asClass
lazy val RemoteAnnotType = ctx.requiredClassRef("scala.remote")
def RemoteAnnot(implicit ctx: Context) = RemoteAnnotType.symbol.asClass
- lazy val RepeatedAnnotType = ctx.requiredClassRef("dotty.annotation.internal.Repeated")
+ lazy val RepeatedAnnotType = ctx.requiredClassRef("scala.annotation.internal.Repeated")
def RepeatedAnnot(implicit ctx: Context) = RepeatedAnnotType.symbol.asClass
- lazy val SourceFileAnnotType = ctx.requiredClassRef("dotty.annotation.internal.SourceFile")
+ lazy val SourceFileAnnotType = ctx.requiredClassRef("scala.annotation.internal.SourceFile")
def SourceFileAnnot(implicit ctx: Context) = SourceFileAnnotType.symbol.asClass
lazy val ScalaSignatureAnnotType = ctx.requiredClassRef("scala.reflect.ScalaSignature")
def ScalaSignatureAnnot(implicit ctx: Context) = ScalaSignatureAnnotType.symbol.asClass
@@ -510,7 +518,7 @@ class Definitions {
def UncheckedStableAnnot(implicit ctx: Context) = UncheckedStableAnnotType.symbol.asClass
lazy val UncheckedVarianceAnnotType = ctx.requiredClassRef("scala.annotation.unchecked.uncheckedVariance")
def UncheckedVarianceAnnot(implicit ctx: Context) = UncheckedVarianceAnnotType.symbol.asClass
- lazy val UnsafeNonvariantAnnotType = ctx.requiredClassRef("dotty.annotation.internal.UnsafeNonvariant")
+ lazy val UnsafeNonvariantAnnotType = ctx.requiredClassRef("scala.annotation.internal.UnsafeNonvariant")
def UnsafeNonvariantAnnot(implicit ctx: Context) = UnsafeNonvariantAnnotType.symbol.asClass
lazy val VolatileAnnotType = ctx.requiredClassRef("scala.volatile")
def VolatileAnnot(implicit ctx: Context) = VolatileAnnotType.symbol.asClass
@@ -781,6 +789,11 @@ class Definitions {
if (!_isInitialized) {
// force initialization of every symbol that is synthesized or hijacked by the compiler
val forced = syntheticCoreClasses ++ syntheticCoreMethods ++ ScalaValueClasses()
+
+ // Enter all symbols from the scalaShadowing package in the scala package
+ for (m <- ScalaShadowingPackageClass.info.decls)
+ ScalaPackageClass.enter(m)
+
_isInitialized = true
}
}
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index 3f4433708..63fbc98dc 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -544,6 +544,9 @@ object Flags {
/** An inline method */
final val InlineMethod = allOf(Inline, Method)
+ /** An inline parameter */
+ final val InlineParam = allOf(Inline, Param)
+
/** A parameter or parameter accessor */
final val ParamOrAccessor = Param | ParamAccessor
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index b495f00d0..1980fe50d 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -965,28 +965,29 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
* Test that the resulting bounds are still satisfiable.
*/
private def narrowGADTBounds(tr: NamedType, bound: Type, isUpper: Boolean): Boolean =
- ctx.mode.is(Mode.GADTflexible) && {
- val tparam = tr.symbol
- typr.println(i"narrow gadt bound of $tparam: ${tparam.info} from ${if (isUpper) "above" else "below"} to $bound ${bound.isRef(tparam)}")
- if (bound.isRef(tparam)) false
- else bound match {
- case bound: TypeRef
- if bound.symbol.is(BindDefinedType) && ctx.gadt.bounds.contains(bound.symbol) &&
- !tr.symbol.is(BindDefinedType) =>
- // Avoid having pattern-bound types in gadt bounds,
- // as these might be eliminated once the pattern is typechecked.
- // Pattern-bound type symbols should be narrowed first, only if that fails
- // should symbols in the environment be constrained.
- narrowGADTBounds(bound, tr, !isUpper)
- case _ =>
- val oldBounds = ctx.gadt.bounds(tparam)
- val newBounds =
- if (isUpper) TypeBounds(oldBounds.lo, oldBounds.hi & bound)
- else TypeBounds(oldBounds.lo | bound, oldBounds.hi)
- isSubType(newBounds.lo, newBounds.hi) &&
- { ctx.gadt.setBounds(tparam, newBounds); true }
+ ctx.mode.is(Mode.GADTflexible) && !frozenConstraint && {
+ val tparam = tr.symbol
+ typr.println(i"narrow gadt bound of $tparam: ${tparam.info} from ${if (isUpper) "above" else "below"} to $bound ${bound.isRef(tparam)}")
+ if (bound.isRef(tparam)) false
+ else bound match {
+ case bound: TypeRef
+ if bound.symbol.is(BindDefinedType) &&
+ ctx.gadt.bounds.contains(bound.symbol) &&
+ !tr.symbol.is(BindDefinedType) =>
+ // Avoid having pattern-bound types in gadt bounds,
+ // as these might be eliminated once the pattern is typechecked.
+ // Pattern-bound type symbols should be narrowed first, only if that fails
+ // should symbols in the environment be constrained.
+ narrowGADTBounds(bound, tr, !isUpper)
+ case _ =>
+ val oldBounds = ctx.gadt.bounds(tparam)
+ val newBounds =
+ if (isUpper) TypeBounds(oldBounds.lo, oldBounds.hi & bound)
+ else TypeBounds(oldBounds.lo | bound, oldBounds.hi)
+ isSubType(newBounds.lo, newBounds.hi) &&
+ { ctx.gadt.setBounds(tparam, newBounds); true }
+ }
}
- }
// Tests around `matches`
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index d242843e5..38913a7d0 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -239,9 +239,14 @@ object Types {
/** The parts of this type which are type or term refs and which
* satisfy predicate `p`.
+ *
+ * @param p The predicate to satisfy
+ * @param excludeLowerBounds If set to true, the lower bounds of abstract
+ * types will be ignored.
*/
- def namedPartsWith(p: NamedType => Boolean)(implicit ctx: Context): collection.Set[NamedType] =
- new NamedPartsAccumulator(p).apply(mutable.LinkedHashSet(), this)
+ def namedPartsWith(p: NamedType => Boolean, excludeLowerBounds: Boolean = false)
+ (implicit ctx: Context): collection.Set[NamedType] =
+ new NamedPartsAccumulator(p, excludeLowerBounds).apply(mutable.LinkedHashSet(), this)
/** Map function `f` over elements of an AndType, rebuilding with function `g` */
def mapReduceAnd[T](f: Type => T)(g: (T, T) => T)(implicit ctx: Context): T = stripTypeVar match {
@@ -615,13 +620,13 @@ object Types {
/** The set of abstract term members of this type. */
final def abstractTermMembers(implicit ctx: Context): Seq[SingleDenotation] = track("abstractTermMembers") {
memberDenots(abstractTermNameFilter,
- (name, buf) => buf ++= member(name).altsWith(_ is Deferred))
+ (name, buf) => buf ++= nonPrivateMember(name).altsWith(_ is Deferred))
}
/** The set of abstract type members of this type. */
final def abstractTypeMembers(implicit ctx: Context): Seq[SingleDenotation] = track("abstractTypeMembers") {
memberDenots(abstractTypeNameFilter,
- (name, buf) => buf += member(name).asSingleDenotation)
+ (name, buf) => buf += nonPrivateMember(name).asSingleDenotation)
}
/** The set of abstract type members of this type. */
@@ -3710,7 +3715,8 @@ object Types {
def apply(x: Boolean, tp: Type) = x || tp.isUnsafeNonvariant || foldOver(x, tp)
}
- class NamedPartsAccumulator(p: NamedType => Boolean)(implicit ctx: Context) extends TypeAccumulator[mutable.Set[NamedType]] {
+ class NamedPartsAccumulator(p: NamedType => Boolean, excludeLowerBounds: Boolean = false)
+ (implicit ctx: Context) extends TypeAccumulator[mutable.Set[NamedType]] {
override def stopAtStatic = false
def maybeAdd(x: mutable.Set[NamedType], tp: NamedType) = if (p(tp)) x += tp else x
val seen: mutable.Set[Type] = mutable.Set()
@@ -3723,7 +3729,8 @@ object Types {
apply(foldOver(maybeAdd(x, tp), tp), tp.underlying)
case tp: TypeRef =>
foldOver(maybeAdd(x, tp), tp)
- case TypeBounds(_, hi) =>
+ case TypeBounds(lo, hi) =>
+ if (!excludeLowerBounds) apply(x, lo)
apply(x, hi)
case tp: ThisType =>
apply(x, tp.tref)
@@ -3756,7 +3763,7 @@ object Types {
object abstractTypeNameFilter extends NameFilter {
def apply(pre: Type, name: Name)(implicit ctx: Context): Boolean =
name.isTypeName && {
- val mbr = pre.member(name)
+ val mbr = pre.nonPrivateMember(name)
(mbr.symbol is Deferred) && mbr.info.isInstanceOf[RealTypeBounds]
}
}
@@ -3773,7 +3780,7 @@ object Types {
/** A filter for names of deferred term definitions of a given type */
object abstractTermNameFilter extends NameFilter {
def apply(pre: Type, name: Name)(implicit ctx: Context): Boolean =
- name.isTermName && (pre member name).hasAltWith(_.symbol is Deferred)
+ name.isTermName && pre.nonPrivateMember(name).hasAltWith(_.symbol is Deferred)
}
object typeNameFilter extends NameFilter {
diff --git a/src/dotty/tools/dotc/core/tasty/NameBuffer.scala b/src/dotty/tools/dotc/core/tasty/NameBuffer.scala
index 69fd63805..3ff7298ce 100644
--- a/src/dotty/tools/dotc/core/tasty/NameBuffer.scala
+++ b/src/dotty/tools/dotc/core/tasty/NameBuffer.scala
@@ -12,6 +12,7 @@ import TastyName._
import TastyFormat._
class NameBuffer extends TastyBuffer(10000) {
+ import NameBuffer._
private val nameRefs = new mutable.LinkedHashMap[TastyName, NameRef]
@@ -40,13 +41,12 @@ class NameBuffer extends TastyBuffer(10000) {
nameIndex(name)
}
- private def withLength(op: => Unit): Unit = {
+ private def withLength(op: => Unit, lengthWidth: Int = 1): Unit = {
val lengthAddr = currentAddr
- writeByte(0)
+ for (i <- 0 until lengthWidth) writeByte(0)
op
val length = currentAddr.index - lengthAddr.index - 1
- assert(length < 128)
- putNat(lengthAddr, length, 1)
+ putNat(lengthAddr, length, lengthWidth)
}
def writeNameRef(ref: NameRef) = writeNat(ref.index)
@@ -64,7 +64,9 @@ class NameBuffer extends TastyBuffer(10000) {
withLength { writeNameRef(qualified); writeNameRef(selector) }
case Signed(original, params, result) =>
writeByte(SIGNED)
- withLength { writeNameRef(original); writeNameRef(result); params.foreach(writeNameRef) }
+ withLength(
+ { writeNameRef(original); writeNameRef(result); params.foreach(writeNameRef) },
+ if ((params.length + 2) * maxIndexWidth <= maxNumInByte) 1 else 2)
case Expanded(prefix, original) =>
writeByte(EXPANDED)
withLength { writeNameRef(prefix); writeNameRef(original) }
@@ -91,3 +93,9 @@ class NameBuffer extends TastyBuffer(10000) {
}
}
}
+
+object NameBuffer {
+ private val maxIndexWidth = 3 // allows name indices up to 2^21.
+ private val payloadBitsPerByte = 7 // determined by nat encoding in TastyBuffer
+ private val maxNumInByte = (1 << payloadBitsPerByte) - 1
+}
diff --git a/src/dotty/tools/dotc/parsing/JavaParsers.scala b/src/dotty/tools/dotc/parsing/JavaParsers.scala
index ed7cf9e3f..b6a423dc7 100644
--- a/src/dotty/tools/dotc/parsing/JavaParsers.scala
+++ b/src/dotty/tools/dotc/parsing/JavaParsers.scala
@@ -21,6 +21,7 @@ import Symbols._
import ast.Trees._
import Decorators._
import StdNames._
+import dotty.tools.dotc.reporting.diagnostic.messages.IdentifierExpected
import dotty.tools.dotc.util.SourceFile
import util.Positions._
import annotation.switch
@@ -131,7 +132,7 @@ object JavaParsers {
def makeSyntheticParam(count: Int, tpt: Tree): ValDef =
makeParam(nme.syntheticParamName(count), tpt)
def makeParam(name: TermName, tpt: Tree): ValDef =
- ValDef(name, tpt, EmptyTree).withMods(Modifiers(Flags.JavaDefined | Flags.PrivateLocalParamAccessor))
+ ValDef(name, tpt, EmptyTree).withMods(Modifiers(Flags.JavaDefined | Flags.ParamAccessor))
def makeConstructor(formals: List[Tree], tparams: List[TypeDef], flags: FlagSet = Flags.JavaDefined) = {
val vparams = mapWithIndex(formals)((p, i) => makeSyntheticParam(i + 1, p))
@@ -230,7 +231,7 @@ object JavaParsers {
case AppliedTypeTree(_, _) | Select(_, _) =>
tree
case _ =>
- syntaxError("identifier expected", tree.pos)
+ syntaxError(IdentifierExpected(tree.show), tree.pos)
errorTypeTree
}
}
diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala
index 507a2e80c..8768466a2 100644
--- a/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -316,7 +316,7 @@ object Parsers {
case id @ Select(qual, name) =>
cpy.Select(id)(qual, name.toTypeName)
case _ =>
- syntaxError("identifier expected", tree.pos)
+ syntaxError(IdentifierExpected(tree.show), tree.pos)
tree
}
@@ -334,7 +334,7 @@ object Parsers {
try op
finally {
placeholderParams match {
- case vd :: _ => syntaxError("unbound placeholder parameter", vd.pos)
+ case vd :: _ => syntaxError(UnboundPlaceholderParameter(), vd.pos)
case _ =>
}
placeholderParams = savedPlaceholderParams
@@ -623,7 +623,7 @@ object Parsers {
if (inPattern) Block(Nil, inBraces(pattern()))
else expr()
else {
- syntaxErrorOrIncomplete("error in interpolated string: identifier or block expected")
+ ctx.error(InterpolatedStringError())
EmptyTree
}
})
@@ -692,7 +692,7 @@ object Parsers {
else {
for (t <- ts)
if (t.isInstanceOf[ByNameTypeTree])
- syntaxError("no by-name parameter type allowed here", t.pos)
+ syntaxError(ByNameParameterNotSupported())
val tuple = atPos(start) { makeTupleOrParens(ts) }
infixTypeRest(refinedTypeRest(withTypeRest(simpleTypeRest(tuple))))
}
@@ -1079,7 +1079,8 @@ object Parsers {
if (in.token != RPAREN) syntaxError("`_*' can be used only for last argument", uscoreStart)
Typed(t, atPos(uscoreStart) { Ident(tpnme.WILDCARD_STAR) })
} else {
- syntaxErrorOrIncomplete("`*' expected"); t
+ syntaxErrorOrIncomplete(IncorrectRepeatedParameterSyntax())
+ t
}
case AT if location != Location.InPattern =>
(t /: annotations())(Annotated)
@@ -1097,8 +1098,9 @@ object Parsers {
/** Expr ::= implicit Id `=>' Expr
* BlockResult ::= implicit Id [`:' InfixType] `=>' Block
*/
- def implicitClosure(start: Int, location: Location.Value): Tree = {
- val mods = atPos(start) { Modifiers(Implicit) }
+ def implicitClosure(start: Int, location: Location.Value, implicitMod: Option[Mod] = None): Tree = {
+ var mods = atPos(start) { Modifiers(Implicit) }
+ if (implicitMod.nonEmpty) mods = mods.withAddedMod(implicitMod.get)
val id = termIdent()
val paramExpr =
if (location == Location.InBlock && in.token == COLON)
@@ -1177,7 +1179,7 @@ object Parsers {
case _ =>
if (isLiteral) literal()
else {
- syntaxErrorOrIncomplete("illegal start of simple expression")
+ syntaxErrorOrIncomplete(IllegalStartSimpleExpr(tokenString(in.token)))
errorTermTree
}
}
@@ -1326,7 +1328,7 @@ object Parsers {
if (in.token == YIELD) { in.nextToken(); ForYield(enums, expr()) }
else if (in.token == DO) { in.nextToken(); ForDo(enums, expr()) }
else {
- if (!wrappedEnums) syntaxErrorOrIncomplete("`yield' or `do' expected")
+ if (!wrappedEnums) syntaxErrorOrIncomplete(YieldOrDoExpectedInForComprehension())
ForDo(enums, expr())
}
}
@@ -1464,19 +1466,19 @@ object Parsers {
/* -------- MODIFIERS and ANNOTATIONS ------------------------------------------- */
- private def flagOfToken(tok: Int): FlagSet = tok match {
- case ABSTRACT => Abstract
- case FINAL => Final
- case IMPLICIT => ImplicitCommon
- case INLINE => Inline
- case LAZY => Lazy
- case OVERRIDE => Override
- case PRIVATE => Private
- case PROTECTED => Protected
- case SEALED => Sealed
+ private def modOfToken(tok: Int): Mod = tok match {
+ case ABSTRACT => Mod.Abstract()
+ case FINAL => Mod.Final()
+ case IMPLICIT => Mod.Implicit(ImplicitCommon)
+ case INLINE => Mod.Inline()
+ case LAZY => Mod.Lazy()
+ case OVERRIDE => Mod.Override()
+ case PRIVATE => Mod.Private()
+ case PROTECTED => Mod.Protected()
+ case SEALED => Mod.Sealed()
}
- /** Drop `private' modifier when followed by a qualifier.
+ /** Drop `private' modifier when followed by a qualifier.
* Contract `abstract' and `override' to ABSOVERRIDE
*/
private def normalize(mods: Modifiers): Modifiers =
@@ -1488,11 +1490,11 @@ object Parsers {
mods
private def addModifier(mods: Modifiers): Modifiers = {
- val flag = flagOfToken(in.token)
- if (mods is flag) syntaxError("repeated modifier")
- val res = addFlag(mods, flag)
- in.nextToken()
- res
+ val tok = in.token
+ val mod = atPos(in.skipToken()) { modOfToken(tok) }
+
+ if (mods is mod.flags) syntaxError(RepeatedModifier(mod.flags.toString))
+ addMod(mods, mod)
}
private def compatible(flags1: FlagSet, flags2: FlagSet): Boolean = (
@@ -1518,6 +1520,11 @@ object Parsers {
}
}
+ /** Always add the syntactic `mod`, but check and conditionally add semantic `mod.flags`
+ */
+ def addMod(mods: Modifiers, mod: Mod): Modifiers =
+ addFlag(mods, mod.flags).withAddedMod(mod)
+
/** AccessQualifier ::= "[" (Id | this) "]"
*/
def accessQualifierOpt(mods: Modifiers): Modifiers =
@@ -1614,10 +1621,10 @@ object Parsers {
mods =
atPos(start, in.offset) {
if (in.token == TYPE) {
- in.nextToken()
- mods | Param | ParamAccessor
+ val mod = atPos(in.skipToken()) { Mod.Type() }
+ (mods | Param | ParamAccessor).withAddedMod(mod)
} else {
- if (mods.hasFlags) syntaxError("`type' expected")
+ if (mods.hasFlags) syntaxError(TypeParamsTypeExpected(mods, ident()))
mods | Param | PrivateLocal
}
}
@@ -1659,7 +1666,7 @@ object Parsers {
* Param ::= id `:' ParamType [`=' Expr]
*/
def paramClauses(owner: Name, ofCaseClass: Boolean = false): List[List[ValDef]] = {
- var implicitFlag = EmptyFlags
+ var implicitMod: Mod = null
var firstClauseOfCaseClass = ofCaseClass
var implicitOffset = -1 // use once
def param(): ValDef = {
@@ -1670,11 +1677,11 @@ object Parsers {
mods =
atPos(start, in.offset) {
if (in.token == VAL) {
- in.nextToken()
- mods
+ val mod = atPos(in.skipToken()) { Mod.Val() }
+ mods.withAddedMod(mod)
} else if (in.token == VAR) {
- in.nextToken()
- addFlag(mods, Mutable)
+ val mod = atPos(in.skipToken()) { Mod.Var() }
+ addMod(mods, mod)
} else {
if (!(mods.flags &~ (ParamAccessor | Inline)).isEmpty)
syntaxError("`val' or `var' expected")
@@ -1696,7 +1703,7 @@ object Parsers {
if (in.token == ARROW) {
if (owner.isTypeName && !(mods is Local))
syntaxError(s"${if (mods is Mutable) "`var'" else "`val'"} parameters may not be call-by-name")
- else if (!implicitFlag.isEmpty)
+ else if (implicitMod != null)
syntaxError("implicit parameters may not be call-by-name")
}
paramType()
@@ -1708,15 +1715,16 @@ object Parsers {
mods = mods.withPos(mods.pos.union(Position(implicitOffset, implicitOffset)))
implicitOffset = -1
}
- ValDef(name, tpt, default).withMods(addFlag(mods, implicitFlag))
+ if (implicitMod != null) mods = addMod(mods, implicitMod)
+ ValDef(name, tpt, default).withMods(mods)
}
}
def paramClause(): List[ValDef] = inParens {
if (in.token == RPAREN) Nil
else {
if (in.token == IMPLICIT) {
- implicitOffset = in.skipToken()
- implicitFlag = Implicit
+ implicitOffset = in.offset
+ implicitMod = atPos(in.skipToken()) { Mod.Implicit(Implicit) }
}
commaSeparated(param)
}
@@ -1726,7 +1734,7 @@ object Parsers {
if (in.token == LPAREN)
paramClause() :: {
firstClauseOfCaseClass = false
- if (implicitFlag.isEmpty) clauses() else Nil
+ if (implicitMod == null) clauses() else Nil
}
else Nil
}
@@ -1735,8 +1743,8 @@ object Parsers {
if (owner == nme.CONSTRUCTOR && (result.isEmpty || (result.head take 1 exists (_.mods is Implicit)))) {
in.token match {
case LBRACKET => syntaxError("no type parameters allowed here")
- case EOF => incompleteInputError("auxiliary constructor needs non-implicit parameter list")
- case _ => syntaxError("auxiliary constructor needs non-implicit parameter list", start)
+ case EOF => incompleteInputError(AuxConstructorNeedsNonImplicitParameter())
+ case _ => syntaxError(AuxConstructorNeedsNonImplicitParameter(), start)
}
}
result
@@ -1819,9 +1827,13 @@ object Parsers {
*/
def defOrDcl(start: Int, mods: Modifiers): Tree = in.token match {
case VAL =>
- patDefOrDcl(start, posMods(start, mods), in.getDocComment(start))
+ val mod = atPos(in.skipToken()) { Mod.Val() }
+ val mods1 = mods.withAddedMod(mod)
+ patDefOrDcl(start, mods1, in.getDocComment(start))
case VAR =>
- patDefOrDcl(start, posMods(start, addFlag(mods, Mutable)), in.getDocComment(start))
+ val mod = atPos(in.skipToken()) { Mod.Var() }
+ val mod1 = addMod(mods, mod)
+ patDefOrDcl(start, mod1, in.getDocComment(start))
case DEF =>
defDefOrDcl(start, posMods(start, mods), in.getDocComment(start))
case TYPE =>
@@ -1898,7 +1910,7 @@ object Parsers {
else EmptyTree
}
else {
- if (!isExprIntro) syntaxError("missing return type", in.lastOffset)
+ if (!isExprIntro) syntaxError(MissingReturnType(), in.lastOffset)
accept(EQUALS)
expr()
}
@@ -2061,7 +2073,7 @@ object Parsers {
def templateBody(): (ValDef, List[Tree]) = {
val r = inDefScopeBraces { templateStatSeq() }
if (in.token == WITH) {
- syntaxError("early definitions are not supported; use trait parameters instead")
+ syntaxError(EarlyDefinitionsNotSupported())
in.nextToken()
template(emptyConstructor)
}
@@ -2184,8 +2196,11 @@ object Parsers {
stats.toList
}
- def localDef(start: Int, implicitFlag: FlagSet): Tree =
- defOrDcl(start, addFlag(defAnnotsMods(localModifierTokens), implicitFlag))
+ def localDef(start: Int, implicitFlag: FlagSet, implicitMod: Option[Mod] = None): Tree = {
+ var mods = addFlag(defAnnotsMods(localModifierTokens), implicitFlag)
+ if (implicitMod.nonEmpty) mods = mods.withAddedMod(implicitMod.get)
+ defOrDcl(start, mods)
+ }
/** BlockStatSeq ::= { BlockStat semi } [ResultExpr]
* BlockStat ::= Import
@@ -2205,9 +2220,10 @@ object Parsers {
stats += expr(Location.InBlock)
else if (isDefIntro(localModifierTokens))
if (in.token == IMPLICIT) {
- val start = in.skipToken()
- if (isIdent) stats += implicitClosure(start, Location.InBlock)
- else stats += localDef(start, ImplicitCommon)
+ val start = in.offset
+ val mod = atPos(in.skipToken()) { Mod.Implicit(ImplicitCommon) }
+ if (isIdent) stats += implicitClosure(start, Location.InBlock, Some(mod))
+ else stats += localDef(start, ImplicitCommon, Some(mod))
} else {
stats += localDef(in.offset, EmptyFlags)
}
diff --git a/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/src/dotty/tools/dotc/reporting/diagnostic/messages.scala
index 9cfac4801..b986b3cc8 100644
--- a/src/dotty/tools/dotc/reporting/diagnostic/messages.scala
+++ b/src/dotty/tools/dotc/reporting/diagnostic/messages.scala
@@ -4,12 +4,12 @@ package reporting
package diagnostic
import dotc.core._
-import Contexts.Context, Decorators._, Symbols._, Names._, Types._
+import Contexts.Context, Decorators._, Symbols._, Names._, NameOps._, Types._
import util.{SourceFile, NoSource}
import util.{SourcePosition, NoSourcePosition}
import config.Settings.Setting
import interfaces.Diagnostic.{ERROR, WARNING, INFO}
-import printing.SyntaxHighlighting._
+import printing.Highlighting._
import printing.Formatting
object messages {
@@ -77,8 +77,15 @@ object messages {
* EmptyCatchBlock(tree).warning(pos) // res: Warning
* ```
*/
- import dotc.ast.Trees._
- import dotc.ast.untpd
+ import ast.Trees._
+ import ast.untpd
+ import ast.tpd
+
+ /** Helper methods for messages */
+ def implicitClassRestrictionsText(implicit ctx: Context) =
+ hl"""|${NoColor("For a full list of restrictions on implicit classes visit")}
+ |${Blue("http://docs.scala-lang.org/overviews/core/implicit-classes.html")}"""
+
// Syntax Errors ---------------------------------------------------------- //
abstract class EmptyCatchOrFinallyBlock(tryBody: untpd.Tree, errNo: Int)(implicit ctx: Context)
@@ -113,7 +120,7 @@ object messages {
|$code2
|
|It is recommended to use the ${"NonFatal"} extractor to catch all exceptions as it
- |correctly handles transfer functions like ${"return"}.""".stripMargin
+ |correctly handles transfer functions like ${"return"}."""
}
}
@@ -122,7 +129,7 @@ object messages {
val kind = "Syntax"
val msg =
hl"""|The ${"catch"} block does not contain a valid expression, try
- |adding a case like - `${"case e: Exception =>"}` to the block""".stripMargin
+ |adding a case like - `${"case e: Exception =>"}` to the block"""
}
case class EmptyCatchAndFinallyBlock(tryBody: untpd.Tree)(implicit ctx: Context)
@@ -130,7 +137,7 @@ object messages {
val kind = "Syntax"
val msg =
hl"""|A ${"try"} without ${"catch"} or ${"finally"} is equivalent to putting
- |its body in a block; no exceptions are handled.""".stripMargin
+ |its body in a block; no exceptions are handled."""
}
case class DeprecatedWithOperator()(implicit ctx: Context)
@@ -141,7 +148,7 @@ object messages {
val explanation =
hl"""|Dotty introduces intersection types - `&' types. These replace the
|use of the ${"with"} keyword. There are a few differences in
- |semantics between intersection types and using `${"with"}'.""".stripMargin
+ |semantics between intersection types and using `${"with"}'."""
}
case class CaseClassMissingParamList(cdef: untpd.TypeDef)(implicit ctx: Context)
@@ -153,7 +160,7 @@ object messages {
val explanation =
hl"""|${cdef.name} must have at least one parameter list, if you would rather
|have a singleton representation of ${cdef.name}, use a "${"case object"}".
- |Or, add an explicit `()' as a parameter list to ${cdef.name}.""".stripMargin
+ |Or, add an explicit `()' as a parameter list to ${cdef.name}."""
}
@@ -181,7 +188,7 @@ object messages {
|
|$caseDef
|
- |`${bind.name}` is not unique. Rename one of the bound variables!""".stripMargin
+ |`${bind.name}` is not unique. Rename one of the bound variables!"""
}
}
@@ -192,7 +199,7 @@ object messages {
val explanation = {
hl"""|An identifier for `$treeKind$name` is missing. This means that something
- |has either been misspelt or you're forgetting an import""".stripMargin
+ |has either been misspelt or you're forgetting an import"""
}
}
@@ -274,4 +281,477 @@ object messages {
val explanation = ""
}
+
+ case class EarlyDefinitionsNotSupported()(implicit ctx:Context)
+ extends Message(9) {
+ val kind = "Syntax"
+ val msg = "early definitions are not supported; use trait parameters instead"
+
+ val explanation = {
+ val code1 =
+ """|trait Logging {
+ | val f: File
+ | f.open()
+ | onExit(f.close())
+ | def log(msg: String) = f.write(msg)
+ |}
+ |
+ |class B extends Logging {
+ | val f = new File("log.data") // triggers a NullPointerException
+ |}
+ |
+ |// early definition gets around the NullPointerException
+ |class C extends {
+ | val f = new File("log.data")
+ |} with Logging""".stripMargin
+
+ val code2 =
+ """|trait Logging(f: File) {
+ | f.open()
+ | onExit(f.close())
+ | def log(msg: String) = f.write(msg)
+ |}
+ |
+ |class C extends Logging(new File("log.data"))""".stripMargin
+
+ hl"""|Earlier versions of Scala did not support trait parameters and "early
+ |definitions" (also known as "early initializers") were used as an alternative.
+ |
+ |Example of old syntax:
+ |
+ |$code1
+ |
+ |The above code can now be written as:
+ |
+ |$code2
+ |"""
+ }
+ }
+
+ case class TopLevelImplicitClass(cdef: untpd.TypeDef)(implicit ctx: Context)
+ extends Message(10) {
+ val kind = "Syntax"
+ val msg = hl"""An ${"implicit class"} may not be top-level"""
+
+ val explanation = {
+ val TypeDef(name, impl @ Template(constr0, parents, self, _)) = cdef
+ val exampleArgs =
+ constr0.vparamss(0).map(_.withMods(untpd.Modifiers()).show).mkString(", ")
+ def defHasBody[T] = impl.body.exists(!_.isEmpty)
+ val exampleBody = if (defHasBody) "{\n ...\n }" else ""
+ hl"""|There may not be any method, member or object in scope with the same name as
+ |the implicit class and a case class automatically gets a companion object with
+ |the same name created by the compiler which would cause a naming conflict if it
+ |were allowed.
+ |
+ |""" + implicitClassRestrictionsText + hl"""|
+ |
+ |To resolve the conflict declare ${cdef.name} inside of an ${"object"} then import the class
+ |from the object at the use site if needed, for example:
+ |
+ |object Implicits {
+ | implicit class ${cdef.name}($exampleArgs)$exampleBody
+ |}
+ |
+ |// At the use site:
+ |import Implicits.${cdef.name}"""
+ }
+ }
+
+ case class ImplicitCaseClass(cdef: untpd.TypeDef)(implicit ctx: Context)
+ extends Message(11) {
+ val kind = "Syntax"
+ val msg = hl"""A ${"case class"} may not be defined as ${"implicit"}"""
+
+ val explanation =
+ hl"""|implicit classes may not be case classes. Instead use a plain class:
+ |
+ |implicit class ${cdef.name}...
+ |
+ |""" + implicitClassRestrictionsText
+ }
+
+ case class ObjectMayNotHaveSelfType(mdef: untpd.ModuleDef)(implicit ctx: Context)
+ extends Message(12) {
+ val kind = "Syntax"
+ val msg = hl"""${"object"}s must not have a self ${"type"}"""
+
+ val explanation = {
+ val untpd.ModuleDef(name, tmpl) = mdef
+ val ValDef(_, selfTpt, _) = tmpl.self
+ hl"""|${"object"}s must not have a self ${"type"}:
+ |
+ |Consider these alternative solutions:
+ | - Create a trait or a class instead of an object
+ | - Let the object extend a trait containing the self type:
+ |
+ | object $name extends ${selfTpt.show}"""
+ }
+ }
+
+ case class TupleTooLong(ts: List[untpd.Tree])(implicit ctx: Context)
+ extends Message(13) {
+ import Definitions.MaxTupleArity
+ val kind = "Syntax"
+ val msg = hl"""A ${"tuple"} cannot have more than ${MaxTupleArity} members"""
+
+ val explanation = {
+ val members = ts.map(_.showSummary).grouped(MaxTupleArity)
+ val nestedRepresentation = members.map(_.mkString(", ")).mkString(")(")
+ hl"""|This restriction will be removed in the future.
+ |Currently it is possible to use nested tuples when more than $MaxTupleArity are needed, for example:
+ |
+ |((${nestedRepresentation}))"""
+ }
+ }
+
+ case class RepeatedModifier(modifier: String)(implicit ctx:Context)
+ extends Message(14) {
+ val kind = "Syntax"
+ val msg = hl"""repeated modifier $modifier"""
+
+ val explanation = {
+ val code1 = hl"""private private val Origin = Point(0, 0)"""
+ val code2 = hl"""private final val Origin = Point(0, 0)"""
+ hl"""This happens when you accidentally specify the same modifier twice.
+ |
+ |Example:
+ |
+ |$code1
+ |
+ |instead of
+ |
+ |$code2
+ |
+ |"""
+ }
+ }
+
+ case class InterpolatedStringError()(implicit ctx:Context)
+ extends Message(15) {
+ val kind = "Syntax"
+ val msg = "error in interpolated string: identifier or block expected"
+ val explanation = {
+ val code1 = "s\"$new Point(0, 0)\""
+ val code2 = "s\"${new Point(0, 0)}\""
+ hl"""|This usually happens when you forget to place your expressions inside curly braces.
+ |
+ |$code1
+ |
+ |should be written as
+ |
+ |$code2
+ |"""
+ }
+ }
+
+ case class UnboundPlaceholderParameter()(implicit ctx:Context)
+ extends Message(16) {
+ val kind = "Syntax"
+ val msg = "unbound placeholder parameter; incorrect use of `_`"
+ val explanation =
+ hl"""|The `_` placeholder syntax was used where it could not be bound.
+ |Consider explicitly writing the variable binding.
+ |
+ |This can be done by replacing `_` with a variable (eg. `x`)
+ |and adding ${"x =>"} where applicable.
+ |
+ |Example before:
+ |
+ |${"{ _ }"}
+ |
+ |Example after:
+ |
+ |${"x => { x }"}
+ |
+ |Another common occurrence for this error is defining a val with `_`:
+ |
+ |${"val a = _"}
+ |
+ |But this val definition isn't very useful, it can never be assigned
+ |another value. And thus will always remain uninitialized.
+ |Consider replacing the ${"val"} with ${"var"}:
+ |
+ |${"var a = _"}
+ |
+ |Note that this use of `_` is not placeholder syntax,
+ |but an uninitialized var definition"""
+ }
+
+ case class IllegalStartSimpleExpr(illegalToken: String)(implicit ctx: Context)
+ extends Message(17) {
+ val kind = "Syntax"
+ val msg = "illegal start of simple expression"
+ val explanation = {
+ hl"""|An expression yields a value. In the case of the simple expression, this error
+ |commonly occurs when there's a missing parenthesis or brace. The reason being
+ |that a simple expression is one of the following:
+ |
+ |- Block
+ |- Expression in parenthesis
+ |- Identifier
+ |- Object creation
+ |- Literal
+ |
+ |which cannot start with ${Red(illegalToken)}."""
+ }
+ }
+
+ case class MissingReturnType()(implicit ctx:Context) extends Message(18) {
+ val kind = "Syntax"
+ val msg = "missing return type"
+ val explanation =
+ hl"""|An abstract declaration must have a return type. For example:
+ |
+ |trait Shape {
+ | def area: Double // abstract declaration returning a ${"Double"}
+ |}"""
+ }
+
+ case class YieldOrDoExpectedInForComprehension()(implicit ctx: Context)
+ extends Message(19) {
+ val kind = "Syntax"
+ val msg = hl"${"yield"} or ${"do"} expected"
+
+ val explanation =
+ hl"""|When the enumerators in a for comprehension are not placed in parentheses or
+ |braces, a ${"do"} or ${"yield"} statement is required after the enumerators
+ |section of the comprehension.
+ |
+ |You can save some keystrokes by omitting the parentheses and writing
+ |
+ |${"val numbers = for i <- 1 to 3 yield i"}
+ |
+ | instead of
+ |
+ |${"val numbers = for (i <- 1 to 3) yield i"}
+ |
+ |but the ${"yield"} keyword is still required.
+ |
+ |For comprehensions that simply perform a side effect without yielding anything
+ |can also be written without parentheses but a ${"do"} keyword has to be
+ |included. For example,
+ |
+ |${"for (i <- 1 to 3) println(i)"}
+ |
+ |can be written as
+ |
+ |${"for i <- 1 to 3 do println(i) // notice the 'do' keyword"}
+ |
+ |"""
+ }
+
+ case class ProperDefinitionNotFound()(implicit ctx: Context)
+ extends Message(20) {
+ val kind = "Definition Not Found"
+ val msg = hl"""Proper definition was not found in ${"@usecase"}"""
+
+ val explanation = {
+ val noUsecase =
+ "def map[B, That](f: A => B)(implicit bf: CanBuildFrom[List[A], B, That]): That"
+
+ val usecase =
+ """|/** Map from List[A] => List[B]
+ | *
+ | * @usecase def map[B](f: A => B): List[B]
+ | */
+ |def map[B, That](f: A => B)(implicit bf: CanBuildFrom[List[A], B, That]): That
+ |""".stripMargin
+
+ hl"""|Usecases are only supported for ${"def"}s. They exist because with Scala's
+ |advanced type-system, we sometimes end up with seemingly scary signatures.
+ |The usage of these methods, however, needs not be - for instance the `map`
+ |function
+ |
+ |${"List(1, 2, 3).map(2 * _) // res: List(2, 4, 6)"}
+ |
+ |is easy to understand and use - but has a rather bulky signature:
+ |
+ |$noUsecase
+ |
+ |to mitigate this and ease the usage of such functions we have the ${"@usecase"}
+ |annotation for docstrings. Which can be used like this:
+ |
+ |$usecase
+ |
+ |When creating the docs, the signature of the method is substituted by the
+ |usecase and the compiler makes sure that it is valid. Because of this, you're
+ |only allowed to use ${"def"}s when defining usecases."""
+ }
+ }
+
+ case class ByNameParameterNotSupported()(implicit ctx: Context)
+ extends Message(21) {
+ val kind = "Syntax"
+ val msg = "By-name parameter type not allowed here."
+
+ val explanation =
+ hl"""|By-name parameters act like functions that are only evaluated when referenced,
+ |allowing for lazy evaluation of a parameter.
+ |
+ |An example of using a by-name parameter would look like:
+ |${"def func(f: => Boolean) = f // 'f' is evaluated when referenced within the function"}
+ |
+ |An example of the syntax of passing an actual function as a parameter:
+ |${"def func(f: (Boolean => Boolean)) = f(true)"}
+ |
+ |or:
+ |
+ |${"def func(f: Boolean => Boolean) = f(true)"}
+ |
+ |And the usage could be as such:
+ |${"func(bool => // do something...)"}
+ |"""
+ }
+
+ case class WrongNumberOfArgs(fntpe: Type, argKind: String, expectedArgs: List[TypeParamInfo], actual: List[untpd.Tree])(implicit ctx: Context)
+ extends Message(22) {
+ val kind = "Syntax"
+
+ private val expectedCount = expectedArgs.length
+ private val actualCount = actual.length
+ private val msgPrefix = if (actualCount > expectedCount) "Too many" else "Not enough"
+
+ //TODO add def simpleParamName to TypeParamInfo
+ private val expectedArgString = fntpe
+ .widen.typeParams
+ .map(_.paramName.unexpandedName.show)
+ .mkString("[", ", ", "]")
+
+ private val actualArgString = actual.map(_.show).mkString("[", ", ", "]")
+
+ private val prettyName = fntpe.termSymbol match {
+ case NoSymbol => fntpe.show
+ case symbol => symbol.showFullName
+ }
+
+ val msg =
+ hl"""|${NoColor(msgPrefix)} ${argKind} arguments for $prettyName$expectedArgString
+ |expected: $expectedArgString
+ |actual: $actualArgString""".stripMargin
+
+ val explanation = {
+ val tooManyTypeParams =
+ """|val tuple2: (Int, String) = (1, "one")
+ |val list: List[(Int, String)] = List(tuple2)""".stripMargin
+
+ if (actualCount > expectedCount)
+ hl"""|You have supplied too many type parameters
+ |
+ |For example List takes a single type parameter (List[A])
+ |If you need to hold more types in a list then you need to combine them
+ |into another data type that can contain the number of types you need,
+ |In this example one solution would be to use a Tuple:
+ |
+ |${tooManyTypeParams}"""
+ else
+ hl"""|You have not supplied enough type parameters
+ |If you specify one type parameter then you need to specify every type parameter."""
+ }
+ }
+
+ case class IllegalVariableInPatternAlternative()(implicit ctx: Context)
+ extends Message(23) {
+ val kind = "Syntax"
+ val msg = "Variables are not allowed in alternative patterns"
+ val explanation = {
+ val varInAlternative =
+ """|def g(pair: (Int,Int)): Int = pair match {
+ | case (1, n) | (n, 1) => n
+ | case _ => 0
+ |}""".stripMargin
+
+ val fixedVarInAlternative =
+ """|def g(pair: (Int,Int)): Int = pair match {
+ | case (1, n) => n
+ | case (n, 1) => n
+ | case _ => 0
+ |}""".stripMargin
+
+ hl"""|Variables are not allowed within alternate pattern matches. You can workaround
+ |this issue by adding additional cases for each alternative. For example, the
+ |illegal function:
+ |
+ |$varInAlternative
+ |could be implemented by moving each alternative into a separate case:
+ |
+ |$fixedVarInAlternative"""
+ }
+ }
+
+ case class TypeParamsTypeExpected(mods: untpd.Modifiers, identifier: TermName)(implicit ctx: Context)
+ extends Message(24) {
+ val kind = "Syntax"
+ val msg = hl"""Expected ${"type"} keyword for type parameter $identifier"""
+ val explanation =
+ hl"""|This happens when you add modifiers like ${"private"} or ${"protected"}
+ |to your type parameter definition without adding the ${"type"} keyword.
+ |
+ |Add ${"type"} to your code, e.g.:
+ |${s"trait A[${mods.flags} type $identifier]"}
+ |"""
+ }
+
+ case class IdentifierExpected(identifier: String)(implicit ctx: Context)
+ extends Message(25) {
+ val kind = "Syntax"
+ val msg = "identifier expected"
+ val explanation = {
+ val wrongIdentifier = s"def foo: $identifier = {...}"
+ val validIdentifier = s"def foo = {...}"
+ hl"""|An identifier expected, but `$identifier` found. This could be because
+ |`$identifier` is not a valid identifier. As a workaround, the compiler could
+ |infer the type for you. For example, instead of:
+ |
+ |$wrongIdentifier
+ |
+ |Write your code like:
+ |
+ |$validIdentifier
+ |
+ |"""
+ }
+ }
+
+ case class AuxConstructorNeedsNonImplicitParameter()(implicit ctx:Context)
+ extends Message(26) {
+ val kind = "Syntax"
+ val msg = "auxiliary constructor needs non-implicit parameter list"
+ val explanation =
+ hl"""|Only the primary constructor is allowed an ${"implicit"} parameter list;
+ |auxiliary constructors need non-implicit parameter lists. When a primary
+ |constructor has an implicit argslist, auxiliary constructors that call the
+ |primary constructor must specify the implicit value.
+ |
+ |To resolve this issue check for:
+ | - forgotten parenthesis on ${"this"} (${"def this() = { ... }"})
+ | - auxiliary constructors specify the implicit value
+ |"""
+ }
+
+ case class IncorrectRepeatedParameterSyntax()(implicit ctx: Context) extends Message(27) {
+ val kind = "Syntax"
+ val msg = "'*' expected"
+ val explanation =
+ hl"""|Expected * in '_*' operator.
+ |
+ |The '_*' operator can be used to supply a sequence-based argument
+ |to a method with a variable-length or repeated parameter. It is used
+ |to expand the sequence to a variable number of arguments, such that:
+ |func(args: _*) would expand to func(arg1, arg2 ... argN).
+ |
+ |Below is an example of how a method with a variable-length
+ |parameter can be declared and used.
+ |
+ |Squares the arguments of a variable-length parameter:
+ |${"def square(args: Int*) = args.map(a => a * a)"}
+ |
+ |Usage:
+ |${"square(1, 2, 3) // res0: List[Int] = List(1, 4, 9)"}
+ |
+ |Secondary Usage with '_*':
+ |${"val ints = List(2, 3, 4) // ints: List[Int] = List(2, 3, 4)"}
+ |${"square(ints: _*) // res1: List[Int] = List(4, 9, 16)"}
+ |""".stripMargin
+ }
}
diff --git a/src/dotty/tools/dotc/transform/ExtensionMethods.scala b/src/dotty/tools/dotc/transform/ExtensionMethods.scala
index 62a21198d..5ae4e8a54 100644
--- a/src/dotty/tools/dotc/transform/ExtensionMethods.scala
+++ b/src/dotty/tools/dotc/transform/ExtensionMethods.scala
@@ -32,6 +32,9 @@ import SymUtils._
* in [[ElimErasedValueType]].
* This is different from the implementation of value classes in Scala 2
* (see SIP-15) which uses `asInstanceOf` which does not typecheck.
+ *
+ * Finally, if the constructor of a value class is private pr protected
+ * it is widened to public.
*/
class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with FullParameterization { thisTransformer =>
@@ -96,11 +99,18 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful
case _ =>
moduleClassSym
}
- case ref: SymDenotation
- if isMethodWithExtension(ref) && ref.hasAnnotation(defn.TailrecAnnot) =>
- val ref1 = ref.copySymDenotation()
- ref1.removeAnnotation(defn.TailrecAnnot)
- ref1
+ case ref: SymDenotation =>
+ if (isMethodWithExtension(ref) && ref.hasAnnotation(defn.TailrecAnnot)) {
+ val ref1 = ref.copySymDenotation()
+ ref1.removeAnnotation(defn.TailrecAnnot)
+ ref1
+ }
+ else if (ref.isConstructor && isDerivedValueClass(ref.owner) && ref.is(AccessFlags)) {
+ val ref1 = ref.copySymDenotation()
+ ref1.resetFlag(AccessFlags)
+ ref1
+ }
+ else ref
case _ =>
ref
}
diff --git a/src/dotty/tools/dotc/transform/PatternMatcher.scala b/src/dotty/tools/dotc/transform/PatternMatcher.scala
index 49c0eabec..8636d5084 100644
--- a/src/dotty/tools/dotc/transform/PatternMatcher.scala
+++ b/src/dotty/tools/dotc/transform/PatternMatcher.scala
@@ -240,17 +240,21 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {
val isDefined = extractorMemberType(prev.tpe, nme.isDefined)
if ((isDefined isRef defn.BooleanClass) && getTp.exists) {
- val tmpSym = freshSym(prev.pos, prev.tpe, "o")
- val prevValue = ref(tmpSym).select("get".toTermName).ensureApplied
+ // isDefined and get may be overloaded
+ val getDenot = prev.tpe.member(nme.get).suchThat(_.info.isParameterless)
+ val isDefinedDenot = prev.tpe.member(nme.isDefined).suchThat(_.info.isParameterless)
- Block(
- List(ValDef(tmpSym, prev)),
- // must be isEmpty and get as we don't control the target of the call (prev is an extractor call)
- ifThenElseZero(
- ref(tmpSym).select(nme.isDefined),
- Block(List(ValDef(b.asTerm, prevValue)), next)
- )
+ val tmpSym = freshSym(prev.pos, prev.tpe, "o")
+ val prevValue = ref(tmpSym).select(getDenot.symbol).ensureApplied
+
+ Block(
+ List(ValDef(tmpSym, prev)),
+ // must be isEmpty and get as we don't control the target of the call (prev is an extractor call)
+ ifThenElseZero(
+ ref(tmpSym).select(isDefinedDenot.symbol),
+ Block(List(ValDef(b.asTerm, prevValue)), next)
)
+ )
} else {
assert(defn.isProductSubType(prev.tpe))
val nullCheck: Tree = prev.select(defn.Object_ne).appliedTo(Literal(Constant(null)))
diff --git a/src/dotty/tools/dotc/transform/PostTyper.scala b/src/dotty/tools/dotc/transform/PostTyper.scala
index 49727e70b..7e51635e5 100644
--- a/src/dotty/tools/dotc/transform/PostTyper.scala
+++ b/src/dotty/tools/dotc/transform/PostTyper.scala
@@ -261,6 +261,19 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
case tpe => tpe
}
)
+ case Import(expr, selectors) =>
+ val exprTpe = expr.tpe
+ def checkIdent(ident: Ident): Unit = {
+ val name = ident.name.asTermName.encode
+ if (name != nme.WILDCARD && !exprTpe.member(name).exists && !exprTpe.member(name.toTypeName).exists)
+ ctx.error(s"${ident.name} is not a member of ${expr.show}", ident.pos)
+ }
+ selectors.foreach {
+ case ident: Ident => checkIdent(ident)
+ case Thicket((ident: Ident) :: _) => checkIdent(ident)
+ case _ =>
+ }
+ super.transform(tree)
case tree =>
super.transform(tree)
}
diff --git a/src/dotty/tools/dotc/transform/TailRec.scala b/src/dotty/tools/dotc/transform/TailRec.scala
index a7a8ac177..dc4454439 100644
--- a/src/dotty/tools/dotc/transform/TailRec.scala
+++ b/src/dotty/tools/dotc/transform/TailRec.scala
@@ -143,7 +143,11 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
newOwners = label :: Nil
).transform(rhsSemiTransformed)
})
- Block(List(labelDef), ref(label).appliedToArgss(vparamss0.map(_.map(x=> ref(x.symbol)))))
+ val callIntoLabel = (
+ if (dd.tparams.isEmpty) ref(label)
+ else ref(label).appliedToTypes(dd.tparams.map(_.tpe))
+ ).appliedToArgss(vparamss0.map(_.map(x=> ref(x.symbol))))
+ Block(List(labelDef), callIntoLabel)
}} else {
if (mandatory) ctx.error(
"TailRec optimisation not applicable, method not tail recursive",
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index 753475d84..dbfc89f6c 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -469,10 +469,13 @@ trait Checking {
/** Check that `tree` is a pure expression of constant type */
def checkInlineConformant(tree: Tree, what: => String)(implicit ctx: Context): Unit =
- tree.tpe.widenTermRefExpr match {
- case tp: ConstantType if isPureExpr(tree) => // ok
- case tp if defn.isFunctionType(tp) && isPureExpr(tree) => // ok
- case _ => ctx.error(em"$what must be a constant expression or a function", tree.pos)
+ tree.tpe match {
+ case tp: TermRef if tp.symbol.is(InlineParam) => // ok
+ case tp => tp.widenTermRefExpr match {
+ case tp: ConstantType if isPureExpr(tree) => // ok
+ case tp if defn.isFunctionType(tp) && isPureExpr(tree) => // ok
+ case _ => ctx.error(em"$what must be a constant expression or a function", tree.pos)
+ }
}
/** Check that class does not define same symbol twice */
diff --git a/src/dotty/tools/dotc/typer/ErrorReporting.scala b/src/dotty/tools/dotc/typer/ErrorReporting.scala
index 1d22dc646..a18c83ff8 100644
--- a/src/dotty/tools/dotc/typer/ErrorReporting.scala
+++ b/src/dotty/tools/dotc/typer/ErrorReporting.scala
@@ -49,8 +49,8 @@ object ErrorReporting {
errorMsg(ex.show, ctx)
}
- def wrongNumberOfArgs(fntpe: Type, kind: String, expected: Int, pos: Position)(implicit ctx: Context) =
- errorType(em"wrong number of ${kind}arguments for $fntpe, expected: $expected", pos)
+ def wrongNumberOfArgs(fntpe: Type, kind: String, expectedArgs: List[TypeParamInfo], actual: List[untpd.Tree], pos: Position)(implicit ctx: Context) =
+ errorType(WrongNumberOfArgs(fntpe, kind, expectedArgs, actual)(ctx), pos)
class Errors(implicit ctx: Context) {
diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala
index d6cf7fb2b..f3dceea71 100644
--- a/src/dotty/tools/dotc/typer/Implicits.scala
+++ b/src/dotty/tools/dotc/typer/Implicits.scala
@@ -343,7 +343,9 @@ trait ImplicitRunInfo { self: RunInfo =>
}
tp.classSymbols(liftingCtx) foreach addClassScope
case _ =>
- for (part <- tp.namedPartsWith(_.isType))
+ // We exclude lower bounds to conform to SLS 7.2:
+ // "The parts of a type T are: [...] if T is an abstract type, the parts of its upper bound"
+ for (part <- tp.namedPartsWith(_.isType, excludeLowerBounds = true))
comps ++= iscopeRefs(part)
}
comps
diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala
index 9a1a42e44..aede4974a 100644
--- a/src/dotty/tools/dotc/typer/Inferencing.scala
+++ b/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -223,7 +223,6 @@ object Inferencing {
constr.println(s"qualifying undet vars: ${constraint.uninstVars filter qualifies map (tvar => s"$tvar / ${tvar.show}")}, constraint: ${constraint.show}")
val vs = variances(tp, qualifies)
- var changed = false
val hasUnreportedErrors = ctx.typerState.reporter match {
case r: StoreReporter if r.hasErrors => true
case _ => false
@@ -253,17 +252,13 @@ object Inferencing {
if (v != 0) {
typr.println(s"interpolate ${if (v == 1) "co" else "contra"}variant ${tvar.show} in ${tp.show}")
tvar.instantiate(fromBelow = v == 1)
- changed = true
}
}
- if (changed) // instantiations might have uncovered new typevars to interpolate
- interpolateUndetVars(tree, ownedBy)
- else
- for (tvar <- constraint.uninstVars)
- if (!(vs contains tvar) && qualifies(tvar)) {
- typr.println(s"instantiating non-occurring ${tvar.show} in ${tp.show}")
- tvar.instantiate(fromBelow = true)
- }
+ for (tvar <- constraint.uninstVars)
+ if (!(vs contains tvar) && qualifies(tvar)) {
+ typr.println(s"instantiating non-occurring ${tvar.show} in ${tp.show} / $tp")
+ tvar.instantiate(fromBelow = true)
+ }
}
if (constraint.uninstVars exists qualifies) interpolate()
}
@@ -306,12 +301,16 @@ object Inferencing {
* we want to instantiate U to x.type right away. No need to wait further.
*/
private def variances(tp: Type, include: TypeVar => Boolean)(implicit ctx: Context): VarianceMap = Stats.track("variances") {
- val accu = new TypeAccumulator[VarianceMap] {
+ val constraint = ctx.typerState.constraint
+
+ object accu extends TypeAccumulator[VarianceMap] {
+ def setVariance(v: Int) = variance = v
def apply(vmap: VarianceMap, t: Type): VarianceMap = t match {
- case t: TypeVar if !t.isInstantiated && (ctx.typerState.constraint contains t) && include(t) =>
+ case t: TypeVar
+ if !t.isInstantiated && (ctx.typerState.constraint contains t) && include(t) =>
val v = vmap(t)
if (v == null) vmap.updated(t, variance)
- else if (v == variance) vmap
+ else if (v == variance || v == 0) vmap
else vmap.updated(t, 0)
case _ =>
foldOver(vmap, t)
@@ -319,7 +318,37 @@ object Inferencing {
override def applyToPrefix(vmap: VarianceMap, t: NamedType) =
apply(vmap, t.prefix)
}
- accu(SimpleMap.Empty, tp)
+
+ /** Include in `vmap` type variables occurring in the constraints of type variables
+ * already in `vmap`. Specifically:
+ * - if `tvar` is covariant in `vmap`, include all variables in its lower bound
+ * (because they influence the minimal solution of `tvar`),
+ * - if `tvar` is contravariant in `vmap`, include all variables in its upper bound
+ * at flipped variances (because they influence the maximal solution of `tvar`),
+ * - if `tvar` is nonvariant in `vmap`, include all variables in its upper and lower
+ * bounds as non-variant.
+ * Do this in a fixpoint iteration until `vmap` stabilizes.
+ */
+ def propagate(vmap: VarianceMap): VarianceMap = {
+ var vmap1 = vmap
+ def traverse(tp: Type) = { vmap1 = accu(vmap1, tp) }
+ vmap.foreachBinding { (tvar, v) =>
+ val param = tvar.origin
+ val e = constraint.entry(param)
+ accu.setVariance(v)
+ if (v >= 0) {
+ traverse(e.bounds.lo)
+ constraint.lower(param).foreach(p => traverse(constraint.typeVarOfParam(p)))
+ }
+ if (v <= 0) {
+ traverse(e.bounds.hi)
+ constraint.upper(param).foreach(p => traverse(constraint.typeVarOfParam(p)))
+ }
+ }
+ if (vmap1 eq vmap) vmap else propagate(vmap1)
+ }
+
+ propagate(accu(SimpleMap.Empty, tp))
}
}
diff --git a/src/dotty/tools/dotc/typer/RefChecks.scala b/src/dotty/tools/dotc/typer/RefChecks.scala
index a2bb9b8d0..026015d1d 100644
--- a/src/dotty/tools/dotc/typer/RefChecks.scala
+++ b/src/dotty/tools/dotc/typer/RefChecks.scala
@@ -487,7 +487,7 @@ object RefChecks {
// abstract method, and a cursory examination of the difference reveals
// something obvious to us, let's make it more obvious to them.
val abstractParams = underlying.info.firstParamTypes
- val matchingName = clazz.info.member(underlying.name).alternatives
+ val matchingName = clazz.info.nonPrivateMember(underlying.name).alternatives
val matchingArity = matchingName filter { m =>
!m.symbol.is(Deferred) &&
m.info.firstParamTypes.length == abstractParams.length
diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala
index 861847b11..b1fed308c 100644
--- a/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -314,7 +314,7 @@ trait TypeAssigner {
val ownType = fn.tpe.widen match {
case fntpe @ MethodType(_, ptypes) =>
if (sameLength(ptypes, args) || ctx.phase.prev.relaxedTyping) fntpe.instantiate(args.tpes)
- else wrongNumberOfArgs(fn.tpe, "", ptypes.length, tree.pos)
+ else wrongNumberOfArgs(fn.tpe, "", fntpe.typeParams, args, tree.pos)
case t =>
errorType(i"${err.exprStr(fn)} does not take parameters", tree.pos)
}
@@ -369,7 +369,7 @@ trait TypeAssigner {
else {
val argTypes = args.tpes
if (sameLength(argTypes, paramNames) || ctx.phase.prev.relaxedTyping) pt.instantiate(argTypes)
- else wrongNumberOfArgs(fn.tpe, "type ", pt.paramNames.length, tree.pos)
+ else wrongNumberOfArgs(fn.tpe, "type", pt.typeParams, args, tree.pos)
}
case _ =>
errorType(i"${err.exprStr(fn)} does not take type parameters", tree.pos)
@@ -451,7 +451,7 @@ trait TypeAssigner {
val ownType =
if (hasNamedArg(args)) (tycon.tpe /: args)(refineNamed)
else if (sameLength(tparams, args)) tycon.tpe.appliedTo(args.tpes)
- else wrongNumberOfArgs(tycon.tpe, "type ", tparams.length, tree.pos)
+ else wrongNumberOfArgs(tycon.tpe, "type", tparams, args, tree.pos)
tree.withType(ownType)
}
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index f6d53f1e2..c283f43cf 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -577,16 +577,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
def escapingRefs(block: Tree, localSyms: => List[Symbol])(implicit ctx: Context): collection.Set[NamedType] = {
- var hoisted: Set[Symbol] = Set()
lazy val locals = localSyms.toSet
- def leakingTypes(tp: Type): collection.Set[NamedType] =
- tp namedPartsWith (tp => locals.contains(tp.symbol))
- def typeLeaks(tp: Type): Boolean = leakingTypes(tp).nonEmpty
- def classLeaks(sym: ClassSymbol): Boolean =
- (ctx.owner is Method) || // can't hoist classes out of method bodies
- (sym.info.parents exists typeLeaks) ||
- (sym.info.decls.toList exists (t => typeLeaks(t.info)))
- leakingTypes(block.tpe)
+ block.tpe namedPartsWith (tp => locals.contains(tp.symbol))
}
/** Check that expression's type can be expressed without references to locally defined
@@ -1038,7 +1030,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
if (hasNamedArg(args)) typedNamedArgs(args)
else {
if (args.length != tparams.length) {
- wrongNumberOfArgs(tpt1.tpe, "type ", tparams.length, tree.pos)
+ wrongNumberOfArgs(tpt1.tpe, "type", tparams, args, tree.pos)
args = args.take(tparams.length)
}
def typedArg(arg: untpd.Tree, tparam: TypeParamInfo) = {
diff --git a/src/dotty/tools/dotc/util/SourcePosition.scala b/src/dotty/tools/dotc/util/SourcePosition.scala
index 595ea34ca..aad4995d8 100644
--- a/src/dotty/tools/dotc/util/SourcePosition.scala
+++ b/src/dotty/tools/dotc/util/SourcePosition.scala
@@ -29,7 +29,7 @@ extends interfaces.SourcePosition {
source.lineContent(source.lineToOffset(lineNumber))
def beforeAndAfterPoint: (List[Int], List[Int]) =
- lineOffsets.partition(_ < point)
+ lineOffsets.partition(_ <= point)
/** The column of the position, starting at 0 */
def column: Int = source.column(point)
diff --git a/src/dotty/annotation/internal/Alias.scala b/src/scala/annotation/internal/Alias.scala
index 8be83960f..e3f56e70c 100644
--- a/src/dotty/annotation/internal/Alias.scala
+++ b/src/scala/annotation/internal/Alias.scala
@@ -1,4 +1,4 @@
-package dotty.annotation.internal
+package scala.annotation.internal
import scala.annotation.Annotation
diff --git a/src/dotty/annotation/internal/AnnotationDefault.scala b/src/scala/annotation/internal/AnnotationDefault.scala
index 7409b2f96..5280d091c 100644
--- a/src/dotty/annotation/internal/AnnotationDefault.scala
+++ b/src/scala/annotation/internal/AnnotationDefault.scala
@@ -1,4 +1,4 @@
-package dotty.annotation.internal
+package scala.annotation.internal
import scala.annotation.Annotation
diff --git a/src/dotty/annotation/internal/Body.scala b/src/scala/annotation/internal/Body.scala
index 7e26b02f2..b6aa0c0fb 100644
--- a/src/dotty/annotation/internal/Body.scala
+++ b/src/scala/annotation/internal/Body.scala
@@ -1,4 +1,4 @@
-package dotty.annotation.internal
+package scala.annotation.internal
import scala.annotation.Annotation
diff --git a/src/dotty/annotation/internal/Child.scala b/src/scala/annotation/internal/Child.scala
index 9295de73e..c90871945 100644
--- a/src/dotty/annotation/internal/Child.scala
+++ b/src/scala/annotation/internal/Child.scala
@@ -1,4 +1,4 @@
-package dotty.annotation.internal
+package scala.annotation.internal
import scala.annotation.Annotation
@@ -9,7 +9,7 @@ import scala.annotation.Annotation
* case class B() extends A
* case class C() extends A
*
- * Then the class symbol `A` would carry the annotations
+ * Then the class symbol `A` would carry the annotations
* `@Child[Bref] @Child[Cref]` where `Bref`, `Cref` are TypeRefs
* referring to the class symbols of `B` and `C`
*/
diff --git a/src/dotty/annotation/internal/InlineParam.scala b/src/scala/annotation/internal/InlineParam.scala
index a144f9edb..0b3649e89 100644
--- a/src/dotty/annotation/internal/InlineParam.scala
+++ b/src/scala/annotation/internal/InlineParam.scala
@@ -1,4 +1,4 @@
-package dotty.annotation.internal
+package scala.annotation.internal
import scala.annotation.Annotation
diff --git a/src/dotty/annotation/internal/Repeated.scala b/src/scala/annotation/internal/Repeated.scala
index 24adc051f..75eb3bc25 100644
--- a/src/dotty/annotation/internal/Repeated.scala
+++ b/src/scala/annotation/internal/Repeated.scala
@@ -1,4 +1,4 @@
-package dotty.annotation.internal
+package scala.annotation.internal
import scala.annotation.Annotation
diff --git a/src/dotty/annotation/internal/SourceFile.scala b/src/scala/annotation/internal/SourceFile.scala
index c49fc2c8d..b203869cf 100644
--- a/src/dotty/annotation/internal/SourceFile.scala
+++ b/src/scala/annotation/internal/SourceFile.scala
@@ -1,4 +1,4 @@
-package dotty.annotation.internal
+package scala.annotation.internal
import scala.annotation.Annotation
diff --git a/src/dotty/annotation/internal/UnsafeNonvariant.scala b/src/scala/annotation/internal/UnsafeNonvariant.scala
index 43a0a114b..b33df65d6 100644
--- a/src/dotty/annotation/internal/UnsafeNonvariant.scala
+++ b/src/scala/annotation/internal/UnsafeNonvariant.scala
@@ -1,4 +1,4 @@
-package dotty.annotation.internal
+package scala.annotation.internal
import scala.annotation.Annotation
diff --git a/src/scalaShadowing/language.scala b/src/scalaShadowing/language.scala
new file mode 100644
index 000000000..a74c9c671
--- /dev/null
+++ b/src/scalaShadowing/language.scala
@@ -0,0 +1,198 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2015, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+package scalaShadowing
+
+/**
+ * The `scala.language` object controls the language features available to the programmer, as proposed in the
+ * [[https://docs.google.com/document/d/1nlkvpoIRkx7at1qJEZafJwthZ3GeIklTFhqmXMvTX9Q/edit '''SIP-18 document''']].
+ *
+ * Each of these features has to be explicitly imported into the current scope to become available:
+ * {{{
+ * import language.postfixOps // or language._
+ * List(1, 2, 3) reverse
+ * }}}
+ *
+ * The language features are:
+ * - [[dynamics `dynamics`]] enables defining calls rewriting using the [[scala.Dynamic `Dynamic`]] trait
+ * - [[postfixOps `postfixOps`]] enables postfix operators
+ * - [[reflectiveCalls `reflectiveCalls`]] enables using structural types
+ * - [[implicitConversions `implicitConversions`]] enables defining implicit methods and members
+ * - [[higherKinds `higherKinds`]] enables writing higher-kinded types
+ * - [[existentials `existentials`]] enables writing existential types
+ * - [[experimental `experimental`]] contains newer features that have not yet been tested in production
+ *
+ * and, for dotty:
+ *
+ * - [[Scala2 `Scala2`] backwards compatibility mode for Scala2
+ * - [[noAtoTupling `noAutoTupling`]] disable auto-tupling
+ *
+ * @groupname production Language Features
+ * @groupname experimental Experimental Language Features
+ * @groupprio experimental 10
+ *
+ * Dotty-specific features come at the end.
+ *
+ * Note: Due to the more restricted language import mechanism in dotty (only
+ * imports count, implicits are disregarded) we don't need the constructions
+ * of the inherited language features. A simple object for each feature is
+ * sufficient.
+ */
+object language {
+
+ import languageFeature._
+
+ /** Where enabled, direct or indirect subclasses of trait scala.Dynamic can
+ * be defined. Unless dynamics is enabled, a definition of a class, trait,
+ * or object that has Dynamic as a base trait is rejected. Dynamic member
+ * selection of existing subclasses of trait Dynamic are unaffected;
+ * they can be used anywhere.
+ *
+ * '''Why introduce the feature?''' To enable flexible DSLs and convenient interfacing
+ * with dynamic languages.
+ *
+ * '''Why control it?''' Dynamic member selection can undermine static checkability
+ * of programs. Furthermore, dynamic member selection often relies on reflection,
+ * which is not available on all platforms.
+ *
+ * @group production
+ */
+ @volatile implicit lazy val dynamics: dynamics = languageFeature.dynamics
+
+ /** Only where enabled, postfix operator notation `(expr op)` will be allowed.
+ *
+ * '''Why keep the feature?''' Several DSLs written in Scala need the notation.
+ *
+ * '''Why control it?''' Postfix operators interact poorly with semicolon inference.
+ * Most programmers avoid them for this reason.
+ *
+ * @group production
+ */
+ @volatile implicit lazy val postfixOps: postfixOps = languageFeature.postfixOps
+
+ /** Only where enabled, accesses to members of structural types that need
+ * reflection are supported. Reminder: A structural type is a type of the form
+ * `Parents { Decls }` where `Decls` contains declarations of new members that do
+ * not override any member in `Parents`. To access one of these members, a
+ * reflective call is needed.
+ *
+ * '''Why keep the feature?''' Structural types provide great flexibility because
+ * they avoid the need to define inheritance hierarchies a priori. Besides,
+ * their definition falls out quite naturally from Scala’s concept of type refinement.
+ *
+ * '''Why control it?''' Reflection is not available on all platforms. Popular tools
+ * such as ProGuard have problems dealing with it. Even where reflection is available,
+ * reflective dispatch can lead to surprising performance degradations.
+ *
+ * @group production
+ */
+ @volatile implicit lazy val reflectiveCalls: reflectiveCalls = languageFeature.reflectiveCalls
+
+ /** Only where enabled, definitions of implicit conversions are allowed. An
+ * implicit conversion is an implicit value of unary function type `A => B`,
+ * or an implicit method that has in its first parameter section a single,
+ * non-implicit parameter. Examples:
+ *
+ * {{{
+ * implicit def stringToInt(s: String): Int = s.length
+ * implicit val conv = (s: String) => s.length
+ * implicit def listToX(xs: List[T])(implicit f: T => X): X = ...
+ * }}}
+ *
+ * implicit values of other types are not affected, and neither are implicit
+ * classes.
+ *
+ * '''Why keep the feature?''' Implicit conversions are central to many aspects
+ * of Scala’s core libraries.
+ *
+ * '''Why control it?''' Implicit conversions are known to cause many pitfalls
+ * if over-used. And there is a tendency to over-use them because they look
+ * very powerful and their effects seem to be easy to understand. Also, in
+ * most situations using implicit parameters leads to a better design than
+ * implicit conversions.
+ *
+ * @group production
+ */
+ @volatile implicit lazy val implicitConversions: implicitConversions = languageFeature.implicitConversions
+
+ /** Only where this flag is enabled, higher-kinded types can be written.
+ *
+ * '''Why keep the feature?''' Higher-kinded types enable the definition of very general
+ * abstractions such as functor, monad, or arrow. A significant set of advanced
+ * libraries relies on them. Higher-kinded types are also at the core of the
+ * scala-virtualized effort to produce high-performance parallel DSLs through staging.
+ *
+ * '''Why control it?''' Higher kinded types in Scala lead to a Turing-complete
+ * type system, where compiler termination is no longer guaranteed. They tend
+ * to be useful mostly for type-level computation and for highly generic design
+ * patterns. The level of abstraction implied by these design patterns is often
+ * a barrier to understanding for newcomers to a Scala codebase. Some syntactic
+ * aspects of higher-kinded types are hard to understand for the uninitiated and
+ * type inference is less effective for them than for normal types. Because we are
+ * not completely happy with them yet, it is possible that some aspects of
+ * higher-kinded types will change in future versions of Scala. So an explicit
+ * enabling also serves as a warning that code involving higher-kinded types
+ * might have to be slightly revised in the future.
+ *
+ * @group production
+ */
+ @volatile implicit lazy val higherKinds: higherKinds = languageFeature.higherKinds
+
+ /** Only where enabled, existential types that cannot be expressed as wildcard
+ * types can be written and are allowed in inferred types of values or return
+ * types of methods. Existential types with wildcard type syntax such as `List[_]`,
+ * or `Map[String, _]` are not affected.
+ *
+ * '''Why keep the feature?''' Existential types are needed to make sense of Java’s wildcard
+ * types and raw types and the erased types of run-time values.
+ *
+ * '''Why control it?''' Having complex existential types in a code base usually makes
+ * application code very brittle, with a tendency to produce type errors with
+ * obscure error messages. Therefore, going overboard with existential types
+ * is generally perceived not to be a good idea. Also, complicated existential types
+ * might be no longer supported in a future simplification of the language.
+ *
+ * @group production
+ */
+ @volatile implicit lazy val existentials: existentials = languageFeature.existentials
+
+ /** The experimental object contains features that have been recently added but have not
+ * been thoroughly tested in production yet.
+ *
+ * Experimental features '''may undergo API changes''' in future releases, so production
+ * code should not rely on them.
+ *
+ * Programmers are encouraged to try out experimental features and
+ * [[http://issues.scala-lang.org report any bugs or API inconsistencies]]
+ * they encounter so they can be improved in future releases.
+ *
+ * @group experimental
+ */
+ object experimental {
+
+ import languageFeature.experimental._
+
+ /** Where enabled, macro definitions are allowed. Macro implementations and
+ * macro applications are unaffected; they can be used anywhere.
+ *
+ * '''Why introduce the feature?''' Macros promise to make the language more regular,
+ * replacing ad-hoc language constructs with a general powerful abstraction
+ * capability that can express them. Macros are also a more disciplined and
+ * powerful replacement for compiler plugins.
+ *
+ * '''Why control it?''' For their very power, macros can lead to code that is hard
+ * to debug and understand.
+ */
+ @volatile implicit lazy val macros: macros = languageFeature.experimental.macros
+ }
+
+ /** Where imported, a backwards compatibility mode for Scala2 is enabled */
+ object Scala2
+
+ /** Where imported, auto-tupling is disabled */
+ object noAutoTupling
+}
diff --git a/test/test/ModifiersParsingTest.scala b/test/test/ModifiersParsingTest.scala
new file mode 100644
index 000000000..82aa33281
--- /dev/null
+++ b/test/test/ModifiersParsingTest.scala
@@ -0,0 +1,162 @@
+package test
+
+import org.junit.Test
+import org.junit.Assert._
+
+import dotty.tools.dotc.ast.untpd.modsDeco
+import dotty.tools.dotc.ast.untpd._
+import dotty.tools.dotc.ast.{ Trees => d }
+import dotty.tools.dotc.parsing.Parsers.Parser
+import dotty.tools.dotc.util.SourceFile
+import dotty.tools.dotc.core.Contexts.ContextBase
+import dotty.tools.dotc.core.Flags
+
+object ModifiersParsingTest {
+ implicit val ctx = (new ContextBase).initialCtx
+
+ implicit def parse(code: String): Tree = {
+ val (_, stats) = new Parser(new SourceFile("<meta>", code.toCharArray)).templateStatSeq()
+ stats match { case List(stat) => stat; case stats => Thicket(stats) }
+ }
+
+ implicit class TreeDeco(val code: Tree) extends AnyVal {
+ def firstConstrValDef: ValDef = code match {
+ case d.TypeDef(_, d.Template(constr, _, _, _)) =>
+ constr.vparamss.head.head
+ }
+
+ def firstTypeParam: TypeDef = code match {
+ case d.TypeDef(_, d.Template(constr, _, _, _)) =>
+ constr.tparams.head
+ }
+
+ def defParam(i: Int): ValDef = code match {
+ case d.DefDef(_, _, vparamss, _, _) =>
+ vparamss.head.toArray.apply(i)
+ }
+
+ def defParam(i: Int, j: Int): ValDef = code match {
+ case d.DefDef(_, _, vparamss, _, _) =>
+ vparamss.toArray.apply(i).toArray.apply(j)
+ }
+
+ def funParam(i: Int): Tree = code match {
+ case Function(params, _) =>
+ params.toArray.apply(i)
+ }
+
+ def field(i: Int): Tree = code match {
+ case d.TypeDef(_, t: Template) =>
+ t.body.toArray.apply(i)
+ }
+
+ def field(name: String): Tree = code match {
+ case d.TypeDef(_, t: Template) =>
+ t.body.find({
+ case m: MemberDef => m.name.show == name
+ case _ => false
+ }).get
+ }
+
+ def stat(i: Int): Tree = code match {
+ case d.Block(stats, expr) =>
+ if (i < stats.length) stats.toArray.apply(i)
+ else expr
+ }
+
+ def modifiers: List[Mod] = code match {
+ case t: MemberDef => t.mods.mods
+ }
+ }
+}
+
+
+class ModifiersParsingTest {
+ import ModifiersParsingTest._
+
+
+ @Test def valDef = {
+ var source: Tree = "class A(var a: Int)"
+ assert(source.firstConstrValDef.modifiers == List(Mod.Var()))
+
+ source = "class A(val a: Int)"
+ assert(source.firstConstrValDef.modifiers == List(Mod.Val()))
+
+ source = "class A(private val a: Int)"
+ assert(source.firstConstrValDef.modifiers == List(Mod.Private(), Mod.Val()))
+
+ source = "class A(protected var a: Int)"
+ assert(source.firstConstrValDef.modifiers == List(Mod.Protected(), Mod.Var()))
+
+ source = "class A(protected implicit val a: Int)"
+ assert(source.firstConstrValDef.modifiers == List(Mod.Protected(), Mod.Implicit(), Mod.Val()))
+
+ source = "class A[T]"
+ assert(source.firstTypeParam.modifiers == List())
+
+ source = "class A[type T]"
+ assert(source.firstTypeParam.modifiers == List(Mod.Type()))
+ }
+
+ @Test def typeDef = {
+ var source: Tree = "class A"
+ assert(source.modifiers == List())
+
+ source = "sealed class A"
+ assert(source.modifiers == List(Mod.Sealed()))
+
+ source = "implicit class A"
+ assert(source.modifiers == List(Mod.Implicit()))
+
+ source = "abstract sealed class A"
+ assert(source.modifiers == List(Mod.Abstract(), Mod.Sealed()))
+ }
+
+ @Test def fieldDef = {
+ val source: Tree =
+ """
+ | class A {
+ | lazy var a = ???
+ | lazy private val b = ???
+ | final val c = ???
+ |
+ | abstract override def f: Boolean
+ | inline def g(n: Int) = ???
+ | }
+ """.stripMargin
+
+ assert(source.field("a").modifiers == List(Mod.Lazy(), Mod.Var()))
+ assert(source.field("b").modifiers == List(Mod.Lazy(), Mod.Private(), Mod.Val()))
+ assert(source.field("c").modifiers == List(Mod.Final(), Mod.Val()))
+ assert(source.field("f").modifiers == List(Mod.Abstract(), Mod.Override()))
+ assert(source.field("g").modifiers == List(Mod.Inline()))
+ }
+
+ @Test def paramDef = {
+ var source: Tree = "def f(inline a: Int) = ???"
+ assert(source.defParam(0).modifiers == List(Mod.Inline()))
+
+ source = "def f(implicit a: Int, b: Int) = ???"
+ println(source.defParam(0).modifiers)
+ assert(source.defParam(0).modifiers == List(Mod.Implicit(Flags.Implicit)))
+ assert(source.defParam(1).modifiers == List(Mod.Implicit(Flags.Implicit)))
+
+ source = "def f(x: Int, y: Int)(implicit a: Int, b: Int) = ???"
+ assert(source.defParam(0, 0).modifiers == List())
+ assert(source.defParam(1, 0).modifiers == List(Mod.Implicit(Flags.Implicit)))
+ }
+
+ @Test def blockDef = {
+ var source: Tree = "implicit val x : A = ???"
+ assert(source.modifiers == List(Mod.Implicit(), Mod.Val()))
+
+ source = "implicit var x : A = ???"
+ assert(source.modifiers == List(Mod.Implicit(), Mod.Var()))
+
+ source = "{ implicit var x : A = ??? }"
+ assert(source.stat(0).modifiers == List(Mod.Implicit(), Mod.Var()))
+
+ source = "{ implicit x => x * x }"
+ assert(source.stat(0).funParam(0).modifiers == List(Mod.Implicit()))
+ }
+}
diff --git a/tests/neg/i1286.scala b/tests/neg/i1286.scala
new file mode 100644
index 000000000..40db9ab1d
--- /dev/null
+++ b/tests/neg/i1286.scala
@@ -0,0 +1,16 @@
+import scala.idontexist // error
+import scala.io.Idontexist // error
+
+import scala.io
+import io.Idontexist2 // error
+
+import scala.io.{ AnsiColor, Idontexist3 } // error
+
+import scala.io.{ Idontexist4 => Foo } // error
+import scala.io.{ Idontexist5 => _ } // error
+
+import scala.language.dynamics
+import scala.language.noAutoTupling
+import scala.language.idontexist // error
+
+object Test
diff --git a/tests/neg/i1531.scala b/tests/neg/i1531.scala
new file mode 100644
index 000000000..3c05e9509
--- /dev/null
+++ b/tests/neg/i1531.scala
@@ -0,0 +1,6 @@
+trait T {
+ def f: Int
+}
+
+class A(f: Int) extends T // error: class A needs to be abstract
+
diff --git a/tests/pos/1567/PosZInt_1.scala b/tests/pos/1567/PosZInt_1.scala
new file mode 100644
index 000000000..60b4061e6
--- /dev/null
+++ b/tests/pos/1567/PosZInt_1.scala
@@ -0,0 +1,6 @@
+final class PosZInt private (val value: Int) extends AnyVal
+
+object PosZInt {
+ def from(value: Int): Option[PosZInt] =
+ if (value >= 0) Some(new PosZInt(value)) else None
+}
diff --git a/tests/pos/1567/Test_2.scala b/tests/pos/1567/Test_2.scala
new file mode 100644
index 000000000..db6ca7070
--- /dev/null
+++ b/tests/pos/1567/Test_2.scala
@@ -0,0 +1,3 @@
+object Test {
+ scala.util.Try(PosZInt.from(1).get)
+}
diff --git a/tests/pos/i1500.scala b/tests/pos/i1500.scala
new file mode 100644
index 000000000..713d06689
--- /dev/null
+++ b/tests/pos/i1500.scala
@@ -0,0 +1,19 @@
+sealed trait HList
+sealed trait HNil extends HList
+sealed trait ::[+H, +T <: HList] extends HList
+
+case class Size[L <: HList](value: Int)
+
+object Size {
+ implicit val caseHNil: Size[HNil] = Size(0)
+ implicit def caseHCons[H, T <: HList](implicit e: Size[T]): Size[H :: T] = Size(e.value + 1)
+}
+
+object HListTest {
+ def main(args: Array[String]): Unit = {
+ assert(implicitly[Size[HNil]].value == 0)
+ assert(implicitly[Size[Int :: HNil]].value == 1)
+ assert(implicitly[Size[Int :: Int :: HNil]].value == 2)
+ assert(implicitly[Size[Int :: Int :: Int :: HNil]].value == 3)
+ }
+}
diff --git a/tests/pos/i1515.scala b/tests/pos/i1515.scala
new file mode 100644
index 000000000..fb3ad78ee
--- /dev/null
+++ b/tests/pos/i1515.scala
@@ -0,0 +1,16 @@
+sealed trait Trait[T]
+
+final case class Case[T](e: T) extends Trait[T]
+
+object Demo {
+ def main(args: Array[String]): Unit = {
+
+ def f[H](t: Trait[H]): Unit =
+ t match {
+ case Case(e) => println(Some(e))
+ }
+
+ f(Case(1))
+
+ }
+}
diff --git a/tests/pos/i1540.scala b/tests/pos/i1540.scala
new file mode 100644
index 000000000..7aa24f459
--- /dev/null
+++ b/tests/pos/i1540.scala
@@ -0,0 +1,14 @@
+class Casey1(val a: Int) {
+ def isDefined: Boolean = true
+ def isDefined(x: Int): Boolean = ???
+ def get: Int = a
+ def get(x: Int): String = ???
+}
+object Casey1 { def unapply(a: Casey1) = a }
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ val c @ Casey1(x) = new Casey1(0)
+ assert(x == c.get)
+ }
+}
diff --git a/tests/pos/i1540b.scala b/tests/pos/i1540b.scala
new file mode 100644
index 000000000..2b4c5408e
--- /dev/null
+++ b/tests/pos/i1540b.scala
@@ -0,0 +1,14 @@
+class Casey1[T](val a: T) {
+ def isDefined: Boolean = true
+ def isDefined(x: T): Boolean = ???
+ def get: T = a
+ def get(x: T): String = ???
+}
+object Casey1 { def unapply[T](a: Casey1[T]) = a }
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ val c @ Casey1(x) = new Casey1(0)
+ assert(x == c.get)
+ }
+}
diff --git a/tests/pos/i1544.scala b/tests/pos/i1544.scala
new file mode 100644
index 000000000..f98d346e8
--- /dev/null
+++ b/tests/pos/i1544.scala
@@ -0,0 +1,4 @@
+object Foo {
+ def foo(p1: Int, p2: Int, p3: Int, p4: Int, p5: Int, p6: Int, p7: Int, p8: Int, p9: Int, p10: Int, p11: Int, p12: Int, p13: Int, p14: Int, p15: Int, p16: Int, p17: Int, p18: Int, p19: Int, p20: Int, p21: Int, p22: Int, p23: Int, p24: Int, p25: Int, p26: Int, p27: Int, p28: Int, p29: Int, p30: Int, p31: Int, p32: Int, p33: Int, p34: Int, p35: Int, p36: Int, p37: Int, p38: Int, p39: Int, p40: Int, p41: Int, p42: Int, p43: Int, p44: Int, p45: Int, p46: Int, p47: Int, p48: Int, p49: Int, p50: Int, p51: Int, p52: Int, p53: Int, p54: Int, p55: Int, p56: Int, p57: Int, p58: Int, p59: Int, p60: Int, p61: Int, p62: Int, p63: Int, p64: Int, p65: Int, p66: Int, p67: Int, p68: Int, p69: Int, p70: Int, p71: Int, p72: Int, p73: Int, p74: Int, p75: Int, p76: Int, p77: Int, p78: Int, p79: Int, p80: Int, p81: Int, p82: Int, p83: Int, p84: Int, p85: Int, p86: Int, p87: Int, p88: Int, p89: Int, p90: Int, p91: Int, p92: Int, p93: Int, p94: Int, p95: Int, p96: Int, p97: Int, p98: Int, p99: Int, p100: Int, p101: Int, p102: Int, p103: Int, p104: Int, p105: Int, p106: Int, p107: Int, p108: Int, p109: Int): Int = 42
+ foo(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109)
+}
diff --git a/tests/pos/i1570.scala b/tests/pos/i1570.scala
new file mode 100644
index 000000000..c2e4fd01b
--- /dev/null
+++ b/tests/pos/i1570.scala
@@ -0,0 +1,4 @@
+object Test {
+ inline def foo(inline n: Int) = bar(n)
+ inline def bar(inline n: Int) = n
+}
diff --git a/tests/pos/i1590.scala b/tests/pos/i1590.scala
new file mode 100644
index 000000000..ab922c218
--- /dev/null
+++ b/tests/pos/i1590.scala
@@ -0,0 +1,10 @@
+case class W[T](seq: Option[Option[T]] = Option.empty)
+object W {
+ def apply[T] = new W[T]()
+}
+
+case class V[T](vv: W[W[T]] = W.apply)
+object Test {
+ W[Int]()
+ // V[Int]() fails in scalac and dotty: both instantiate the vv-default to W[Nothing]
+}
diff --git a/tests/pos/java-interop/1576/TagAnnotation.java b/tests/pos/java-interop/1576/TagAnnotation.java
new file mode 100644
index 000000000..3034a1a2d
--- /dev/null
+++ b/tests/pos/java-interop/1576/TagAnnotation.java
@@ -0,0 +1,3 @@
+public @interface TagAnnotation {
+ public String value();
+} \ No newline at end of file
diff --git a/tests/pos/java-interop/1576/Test.scala b/tests/pos/java-interop/1576/Test.scala
new file mode 100644
index 000000000..ea3d06a83
--- /dev/null
+++ b/tests/pos/java-interop/1576/Test.scala
@@ -0,0 +1,5 @@
+object Test {
+ val v: TagAnnotation = null
+ println(v.value) // error: value value in class TagAnnotation cannot be accessed as a
+ // member of TagAnnotation(Test.v) from module class Test$.
+}
diff --git a/tests/pos/tailcall/i1614.scala b/tests/pos/tailcall/i1614.scala
new file mode 100644
index 000000000..4c10e963d
--- /dev/null
+++ b/tests/pos/tailcall/i1614.scala
@@ -0,0 +1,9 @@
+object Foobar {
+ def apply(): Option[String] = {
+ def foobar[A](f: (String, String) => A): List[A] = List[String]() match {
+ case _ :: ls => foobar(f)
+ }
+ foobar((a1, a2) => (a1 + a2)).headOption
+ }
+}
+
diff --git a/tests/repl/imports.check b/tests/repl/imports.check
index 26b725637..b6d9ae8a7 100644
--- a/tests/repl/imports.check
+++ b/tests/repl/imports.check
@@ -15,4 +15,14 @@ scala> buf += xs
|
scala> buf ++= xs
res1: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3)
+scala> import util.foo
+-- Error: <console> ----------------------------------------------------------------------------------------------------
+8 |import util.foo
+ | ^^^
+ | foo is not a member of util
+scala> import util.foo.bar
+-- [E008] Member Not Found Error: <console> ----------------------------------------------------------------------------
+8 |import util.foo.bar
+ | ^^^^^^^^
+ | value `foo` is not a member of util.type - did you mean `util.Left`?
scala> :quit