aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--interfaces/src/main/java/dotty/tools/dotc/interfaces/SourceFile.java2
-rw-r--r--sandbox/scalajs/src/main/scala/hello.scala (renamed from sandbox/scalajs/hello.scala)0
-rw-r--r--src/dotty/tools/dotc/ast/Desugar.scala8
-rw-r--r--src/dotty/tools/dotc/ast/Trees.scala4
-rw-r--r--src/dotty/tools/dotc/core/ConstraintHandling.scala24
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala43
-rw-r--r--src/dotty/tools/dotc/core/TypeErasure.scala2
-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/Parsers.scala2
-rw-r--r--src/dotty/tools/dotc/reporting/diagnostic/messages.scala128
-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/TreeTransform.scala4
-rw-r--r--src/dotty/tools/dotc/typer/Implicits.scala4
-rw-r--r--src/dotty/tools/dotc/typer/ProtoTypes.scala7
-rw-r--r--src/dotty/tools/dotc/typer/RefChecks.scala2
-rw-r--r--src/dotty/tools/dotc/typer/TypeAssigner.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala10
-rw-r--r--src/strawman/collections/CollectionStrawMan4.scala4
-rw-r--r--test/test/ContextEscapeDetector.java6
-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/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/i1590.scala10
-rw-r--r--tests/run/i1543.check31
-rw-r--r--tests/run/i1543.scala41
-rw-r--r--tests/run/unit_erasure.scala16
33 files changed, 416 insertions, 82 deletions
diff --git a/.gitignore b/.gitignore
index 416a12eff..a34babd4f 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/interfaces/src/main/java/dotty/tools/dotc/interfaces/SourceFile.java b/interfaces/src/main/java/dotty/tools/dotc/interfaces/SourceFile.java
index 0e16d3ea4..6c72a5125 100644
--- a/interfaces/src/main/java/dotty/tools/dotc/interfaces/SourceFile.java
+++ b/interfaces/src/main/java/dotty/tools/dotc/interfaces/SourceFile.java
@@ -1,7 +1,5 @@
package dotty.tools.dotc.interfaces;
-import java.io.File;
-
/** A source file.
*
* User code should not implement this interface, but it may have to
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/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala
index af34164dc..8b8e0b318 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)
diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala
index 1fb3557db..2c02e7d1e 100644
--- a/src/dotty/tools/dotc/ast/Trees.scala
+++ b/src/dotty/tools/dotc/ast/Trees.scala
@@ -48,7 +48,7 @@ object Trees {
* the existing tree transparently, assigning its `tpe` field,
* provided it was `null` before.
* - It is impossible to embed untyped trees in typed ones.
- * - Typed trees can be embedded untyped ones provided they are rooted
+ * - Typed trees can be embedded in untyped ones provided they are rooted
* in a TypedSplice node.
* - Type checking an untyped tree should remove all embedded `TypedSplice`
* nodes.
@@ -853,7 +853,7 @@ object Trees {
val cpy: TreeCopier
- /** A class for copying trees. The copy methods avid creating a new tree
+ /** A class for copying trees. The copy methods avoid creating a new tree
* If all arguments stay the same.
*
* Note: Some of the copy methods take a context.
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/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/TypeErasure.scala b/src/dotty/tools/dotc/core/TypeErasure.scala
index fd5fcb921..254ea3277 100644
--- a/src/dotty/tools/dotc/core/TypeErasure.scala
+++ b/src/dotty/tools/dotc/core/TypeErasure.scala
@@ -417,7 +417,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
// See doc comment for ElimByName for speculation how we could improve this.
else MethodType(Nil, Nil, eraseResult(rt))
case tp: PolyType =>
- this(tp.resultType) match {
+ eraseResult(tp.resultType) match {
case rt: MethodType => rt
case rt => MethodType(Nil, Nil, rt)
}
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/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala
index 507a2e80c..46e7512f3 100644
--- a/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -2061,7 +2061,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)
}
diff --git a/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/src/dotty/tools/dotc/reporting/diagnostic/messages.scala
index 9cfac4801..633501295 100644
--- a/src/dotty/tools/dotc/reporting/diagnostic/messages.scala
+++ b/src/dotty/tools/dotc/reporting/diagnostic/messages.scala
@@ -5,11 +5,12 @@ package diagnostic
import dotc.core._
import Contexts.Context, Decorators._, Symbols._, Names._, Types._
+import ast.untpd.{Modifiers, ModuleDef}
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 {
@@ -274,4 +275,129 @@ 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 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 null pointer exception
+ |}
+ |
+ |class C extends {
+ | val f = new File("log.data") // early definition gets around the null pointer exception
+ |} 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
+
+ val explanation =
+ 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
+ |""".stripMargin
+ }
+
+ 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")}""".stripMargin
+
+ 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(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.
+ |
+ |""".stripMargin + 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}""".stripMargin
+ }
+ }
+
+ 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:
+ | example: implicit class ${cdef.name}...
+ |
+ |""".stripMargin + implicitClassRestrictionsText
+ }
+
+ case class ObjectMayNotHaveSelfType(mdef: untpd.ModuleDef)(implicit ctx: Context)
+ extends Message(12) {
+ val kind = "Syntax"
+
+ val msg = hl"""|${"objects"} must not have a ${"self type"}"""
+
+ val explanation = {
+ val ModuleDef(name, tmpl) = mdef
+ val ValDef(_, selfTpt, _) = tmpl.self
+ hl"""|objects 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:
+ | example: object $name extends ${selfTpt.show}""".stripMargin
+ }
+ }
+
+ 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}))""".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/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala
index 52a3ad94e..45fa3d607 100644
--- a/src/dotty/tools/dotc/transform/TreeTransform.scala
+++ b/src/dotty/tools/dotc/transform/TreeTransform.scala
@@ -42,7 +42,7 @@ object TreeTransforms {
* the general dispatch overhead as opposed to the concrete work done in transformations. So that leaves us with
* 0.2sec, or roughly 600M processor cycles.
*
- * Now, to the amount of work that needs to be done. The codebase produces of about 250'000 trees after typechecking.
+ * Now, to the amount of work that needs to be done. The codebase produces an average of about 250'000 trees after typechecking.
* Transformations are likely to make this bigger so let's assume 300K trees on average. We estimate to have about 100
* micro-transformations. Let's say 5 transformation groups of 20 micro-transformations each. (by comparison,
* scalac has in excess of 20 phases, and most phases do multiple transformations). There are then 30M visits
@@ -208,7 +208,7 @@ object TreeTransforms {
if (cls.getDeclaredMethods.exists(_.getName == name)) cls != classOf[TreeTransform]
else hasRedefinedMethod(cls.getSuperclass, name)
- /** Create an index array `next` of size one larger than teh size of `transforms` such that
+ /** Create an index array `next` of size one larger than the size of `transforms` such that
* for each index i, `next(i)` is the smallest index j such that
*
* i <= j
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/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala
index d451d6abd..08f566d49 100644
--- a/src/dotty/tools/dotc/typer/ProtoTypes.scala
+++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala
@@ -400,9 +400,10 @@ object ProtoTypes {
if (mt.isDependent) tp
else {
val rt = normalize(mt.resultType, pt)
- if (pt.isInstanceOf[ApplyingProto])
- mt.derivedMethodType(mt.paramNames, mt.paramTypes, rt)
- else {
+ pt match {
+ case pt: IgnoredProto => mt
+ case pt: ApplyingProto => mt.derivedMethodType(mt.paramNames, mt.paramTypes, rt)
+ case _ =>
val ft = defn.FunctionOf(mt.paramTypes, rt)
if (mt.paramTypes.nonEmpty || ft <:< pt) ft else rt
}
diff --git a/src/dotty/tools/dotc/typer/RefChecks.scala b/src/dotty/tools/dotc/typer/RefChecks.scala
index 4d82a2d12..834bb37a8 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 696ecfedb..861847b11 100644
--- a/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -416,7 +416,7 @@ trait TypeAssigner {
def assignType(tree: untpd.SeqLiteral, elems: List[Tree], elemtpt: Tree)(implicit ctx: Context) = {
val ownType = tree match {
- case tree: JavaSeqLiteral => defn.ArrayOf(elemtpt.tpe)
+ case tree: untpd.JavaSeqLiteral => defn.ArrayOf(elemtpt.tpe)
case _ => if (ctx.erasedTypes) defn.SeqType else defn.SeqType.appliedTo(elemtpt.tpe)
}
tree.withType(ownType)
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 6be119319..6fb0dd7c7 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
diff --git a/src/strawman/collections/CollectionStrawMan4.scala b/src/strawman/collections/CollectionStrawMan4.scala
index fb95ea59f..7e8de2c82 100644
--- a/src/strawman/collections/CollectionStrawMan4.scala
+++ b/src/strawman/collections/CollectionStrawMan4.scala
@@ -216,7 +216,7 @@ object CollectionStrawMan4 {
object ListBuffer extends IterableFactory[ListBuffer] {
def fromIterable[B](coll: Iterable[B]): ListBuffer[B] = coll match {
- case pd @ View.Partitioned(partition: View.Partition[B]) =>
+ case pd @ View.Partitioned(partition: View.Partition[B] @unchecked) =>
partition.distribute(new ListBuffer[B]())
new ListBuffer[B] ++= pd.forced.get
case _ =>
@@ -267,7 +267,7 @@ object CollectionStrawMan4 {
Array.copy(fst.elems, fst.start, elems, 0, fst.length)
Array.copy(snd.elems, snd.start, elems, fst.length, snd.length)
new ArrayBuffer(elems, elems.length)
- case pd @ View.Partitioned(partition: View.Partition[B]) =>
+ case pd @ View.Partitioned(partition: View.Partition[B] @unchecked) =>
partition.distribute(new ArrayBuffer[B]())
pd.forced.get.asInstanceOf[ArrayBuffer[B]]
case c if c.knownLength >= 0 =>
diff --git a/test/test/ContextEscapeDetector.java b/test/test/ContextEscapeDetector.java
index c7768fd57..78d293a5d 100644
--- a/test/test/ContextEscapeDetector.java
+++ b/test/test/ContextEscapeDetector.java
@@ -1,6 +1,5 @@
package test;
-import org.junit.runner.Description;
import org.junit.runner.Result;
import org.junit.runner.notification.RunListener;
import org.junit.Assert;
@@ -43,6 +42,7 @@ public class ContextEscapeDetector extends RunListener {
return count;
}
+ @SuppressWarnings("unused")
private static volatile Object o = null;
private static synchronized void forceGCHeuristic0() {
@@ -59,7 +59,7 @@ public class ContextEscapeDetector extends RunListener {
private static synchronized void forceGCHeuristic1() {
Object obj = new Object();
- WeakReference ref = new WeakReference<Object>(obj);
+ WeakReference<Object> ref = new WeakReference<>(obj);
obj = null;
while (ref.get() != null) {
System.gc();
@@ -69,7 +69,7 @@ public class ContextEscapeDetector extends RunListener {
private static synchronized void forceGCHeuristic2() {
try {
Object[] arr = new Object[1024]; // upto 8 GB
- WeakReference ref = new WeakReference<Object>(arr);
+ WeakReference<Object> ref = new WeakReference<>(arr);
o = arr; // make sure array isn't optimized away
Runtime runtime = Runtime.getRuntime();
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/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/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/run/i1543.check b/tests/run/i1543.check
new file mode 100644
index 000000000..10adcaf83
--- /dev/null
+++ b/tests/run/i1543.check
@@ -0,0 +1,31 @@
+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
diff --git a/tests/run/i1543.scala b/tests/run/i1543.scala
new file mode 100644
index 000000000..268bc717b
--- /dev/null
+++ b/tests/run/i1543.scala
@@ -0,0 +1,41 @@
+
+object Test extends dotty.runtime.LegacyApp {
+ new Bar().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)
+}
+
+
+class Bar {
+ 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): Unit = {
+ println(p1)
+ println(p2)
+ println(p3)
+ println(p4)
+ println(p5)
+ println(p6)
+ println(p7)
+ println(p8)
+ println(p9)
+ println(p10)
+ println(p11)
+ println(p12)
+ println(p13)
+ println(p14)
+ println(p15)
+ println(p16)
+ println(p17)
+ println(p18)
+ println(p19)
+ println(p20)
+ println(p21)
+ println(p22)
+ println(p23)
+ println(p24)
+ println(p25)
+ println(p26)
+ println(p27)
+ println(p28)
+ println(p29)
+ println(p30)
+ println(p31)
+ }
+}
diff --git a/tests/run/unit_erasure.scala b/tests/run/unit_erasure.scala
new file mode 100644
index 000000000..51ccf0a16
--- /dev/null
+++ b/tests/run/unit_erasure.scala
@@ -0,0 +1,16 @@
+class A {
+ def foo1[T]: Unit = {}
+ def foo2[T](): Unit = {}
+ def foo3[T]()(): Unit = {}
+ def foo4: Unit = {}
+ def foo5(): Unit = {}
+ def foo6()(): Unit = {}
+}
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ classOf[A].getMethods.toList.filter(_.getName.startsWith("foo")).foreach { m =>
+ assert(m.getGenericReturnType == Void.TYPE, s"Method does not return void: `${m}`")
+ }
+ }
+} \ No newline at end of file