aboutsummaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/sjs/backend/sjs/JSCodeGen.scala64
-rw-r--r--compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/ast/Trees.scala8
-rw-r--r--compiler/src/dotty/tools/dotc/config/PathResolver.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/core/SymDenotations.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeComparer.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeErasure.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/core/Types.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/Parsers.scala14
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/Scanners.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/transform/Erasure.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala8
-rw-r--r--compiler/src/dotty/tools/dotc/transform/TreeChecker.scala7
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ValueClasses.scala10
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Applications.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Checking.scala49
-rw-r--r--compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala8
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Inliner.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Namer.scala13
-rw-r--r--compiler/src/dotty/tools/dotc/typer/RefChecks.scala35
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Typer.scala6
22 files changed, 140 insertions, 108 deletions
diff --git a/compiler/sjs/backend/sjs/JSCodeGen.scala b/compiler/sjs/backend/sjs/JSCodeGen.scala
index 401e01784..69a5651fc 100644
--- a/compiler/sjs/backend/sjs/JSCodeGen.scala
+++ b/compiler/sjs/backend/sjs/JSCodeGen.scala
@@ -127,7 +127,7 @@ class JSCodeGen()(implicit ctx: Context) {
/* Finally, we emit true code for the remaining class defs. */
for (td <- allTypeDefs) {
val sym = td.symbol
- implicit val pos: Position = sym.pos
+ implicit val pos = sym.pos
/* Do not actually emit code for primitive types nor scala.Array. */
val isPrimitive =
@@ -203,7 +203,7 @@ class JSCodeGen()(implicit ctx: Context) {
*/
private def genScalaClass(td: TypeDef): js.ClassDef = {
val sym = td.symbol.asClass
- implicit val pos: Position = sym.pos
+ implicit val pos = sym.pos
assert(!sym.is(Trait),
"genScalaClass() must be called only for normal classes: "+sym)
@@ -336,7 +336,7 @@ class JSCodeGen()(implicit ctx: Context) {
*/
private def genRawJSClassData(td: TypeDef): js.ClassDef = {
val sym = td.symbol.asClass
- implicit val pos: Position = sym.pos
+ implicit val pos = sym.pos
val classIdent = encodeClassFullNameIdent(sym)
val superClass =
@@ -358,7 +358,7 @@ class JSCodeGen()(implicit ctx: Context) {
*/
private def genInterface(td: TypeDef): js.ClassDef = {
val sym = td.symbol.asClass
- implicit val pos: Position = sym.pos
+ implicit val pos = sym.pos
val classIdent = encodeClassFullNameIdent(sym)
@@ -408,7 +408,7 @@ class JSCodeGen()(implicit ctx: Context) {
f <- classSym.info.decls
if !f.is(Method) && f.isTerm
} yield {
- implicit val pos: Position = f.pos
+ implicit val pos = f.pos
val name =
/*if (isExposed(f)) js.StringLiteral(jsNameOf(f))
@@ -479,7 +479,7 @@ class JSCodeGen()(implicit ctx: Context) {
* Other (normal) methods are emitted with `genMethodBody()`.
*/
private def genMethodWithCurrentLocalNameScope(dd: DefDef): Option[js.MethodDef] = {
- implicit val pos: Position = dd.pos
+ implicit val pos = dd.pos
val sym = dd.symbol
val vparamss = dd.vparamss
val rhs = dd.rhs
@@ -501,7 +501,7 @@ class JSCodeGen()(implicit ctx: Context) {
val methodName: js.PropertyName = encodeMethodSym(sym)
def jsParams = for (param <- params) yield {
- implicit val pos: Position = param.pos
+ implicit val pos = param.pos
js.ParamDef(encodeLocalSym(param), toIRType(param.info),
mutable = false, rest = false)
}
@@ -574,13 +574,13 @@ class JSCodeGen()(implicit ctx: Context) {
private def genMethodDef(static: Boolean, methodName: js.PropertyName,
paramsSyms: List[Symbol], resultIRType: jstpe.Type,
tree: Tree, optimizerHints: OptimizerHints): js.MethodDef = {
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
ctx.debuglog("genMethod " + methodName.name)
ctx.debuglog("")
val jsParams = for (param <- paramsSyms) yield {
- implicit val pos: Position = param.pos
+ implicit val pos = param.pos
js.ParamDef(encodeLocalSym(param), toIRType(param.info),
mutable = false, rest = false)
}
@@ -621,7 +621,7 @@ class JSCodeGen()(implicit ctx: Context) {
/* Any JavaScript expression is also a statement, but at least we get rid
* of some pure expressions that come from our own codegen.
*/
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
tree match {
case js.Block(stats :+ expr) => js.Block(stats :+ exprToStat(expr))
case _:js.Literal | js.This() => js.Skip()
@@ -644,7 +644,7 @@ class JSCodeGen()(implicit ctx: Context) {
* is transformed into an equivalent portion of the JS AST.
*/
private def genStatOrExpr(tree: Tree, isStat: Boolean): js.Tree = {
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
ctx.debuglog(" " + tree)
ctx.debuglog("")
@@ -902,7 +902,7 @@ class JSCodeGen()(implicit ctx: Context) {
* primitives, JS calls, etc. They are further dispatched in here.
*/
private def genApply(tree: Apply, isStat: Boolean): js.Tree = {
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
val args = tree.args
val sym = tree.fun.symbol
@@ -951,7 +951,7 @@ class JSCodeGen()(implicit ctx: Context) {
* irrelevant.
*/
private def genSuperCall(tree: Apply, isStat: Boolean): js.Tree = {
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
val Apply(fun @ Select(sup @ Super(_, mix), _), args) = tree
val sym = fun.symbol
@@ -987,7 +987,7 @@ class JSCodeGen()(implicit ctx: Context) {
* * regular new
*/
private def genApplyNew(tree: Apply): js.Tree = {
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
val Apply(fun @ Select(New(tpt), nme.CONSTRUCTOR), args) = tree
val ctor = fun.symbol
@@ -1023,7 +1023,7 @@ class JSCodeGen()(implicit ctx: Context) {
private def genPrimitiveOp(tree: Apply, isStat: Boolean): js.Tree = {
import scala.tools.nsc.backend.ScalaPrimitives._
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
val Apply(fun, args) = tree
val receiver = qualifierOf(fun)
@@ -1063,7 +1063,7 @@ class JSCodeGen()(implicit ctx: Context) {
private def genSimpleUnaryOp(tree: Apply, arg: Tree, code: Int): js.Tree = {
import scala.tools.nsc.backend.ScalaPrimitives._
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
val genArg = genExpr(arg)
val resultIRType = toIRType(tree.tpe)
@@ -1118,7 +1118,7 @@ class JSCodeGen()(implicit ctx: Context) {
}
import OpTypes._
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
val lhsIRType = toIRType(lhs.tpe)
val rhsIRType = toIRType(rhs.tpe)
@@ -1374,7 +1374,7 @@ class JSCodeGen()(implicit ctx: Context) {
*/
private def genStringConcat(tree: Apply, receiver: Tree,
args: List[Tree]): js.Tree = {
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
val arg = args.head
@@ -1401,7 +1401,7 @@ class JSCodeGen()(implicit ctx: Context) {
/** Gen JS code for a call to Any.## */
private def genScalaHash(tree: Apply, receiver: Tree): js.Tree = {
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
genModuleApplyMethod(defn.ScalaRuntimeModule.requiredMethod(nme.hash_),
List(genExpr(receiver)))
@@ -1411,7 +1411,7 @@ class JSCodeGen()(implicit ctx: Context) {
private def genArrayOp(tree: Tree, code: Int): js.Tree = {
import scala.tools.nsc.backend.ScalaPrimitives._
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
val Apply(fun, args) = tree
val arrayObj = qualifierOf(fun)
@@ -1462,7 +1462,7 @@ class JSCodeGen()(implicit ctx: Context) {
// common case for which there is no side-effect nor NPE
genArg
case _ =>
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
/* TODO Check for a null receiver?
* In theory, it's UB, but that decision should be left for link time.
*/
@@ -1474,7 +1474,7 @@ class JSCodeGen()(implicit ctx: Context) {
private def genCoercion(tree: Apply, receiver: Tree, code: Int): js.Tree = {
import scala.tools.nsc.backend.ScalaPrimitives._
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
val source = genExpr(receiver)
@@ -1544,7 +1544,7 @@ class JSCodeGen()(implicit ctx: Context) {
/** Gen a call to the special `throw` method. */
private def genThrow(tree: Apply, args: List[Tree]): js.Tree = {
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
val exception = args.head
val genException = genExpr(exception)
js.Throw {
@@ -1568,7 +1568,7 @@ class JSCodeGen()(implicit ctx: Context) {
* * Regular method call
*/
private def genNormalApply(tree: Apply, isStat: Boolean): js.Tree = {
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
val fun = tree.fun match {
case fun: Ident => desugarIdent(fun).get
@@ -1616,7 +1616,7 @@ class JSCodeGen()(implicit ctx: Context) {
superIn: Option[Symbol] = None)(
implicit pos: Position): js.Tree = {
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
def noSpread = !args.exists(_.isInstanceOf[js.JSSpread])
val argc = args.size // meaningful only for methods that don't have varargs
@@ -1775,7 +1775,7 @@ class JSCodeGen()(implicit ctx: Context) {
* primitive instead.)
*/
private def genTypeApply(tree: TypeApply): js.Tree = {
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
val TypeApply(fun, targs) = tree
@@ -1803,7 +1803,7 @@ class JSCodeGen()(implicit ctx: Context) {
/** Gen JS code for a Java Seq literal. */
private def genJavaSeqLiteral(tree: JavaSeqLiteral): js.Tree = {
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
val genElems = tree.elems.map(genExpr)
val arrayType = toReferenceType(tree.tpe).asInstanceOf[jstpe.ArrayType]
@@ -1852,7 +1852,7 @@ class JSCodeGen()(implicit ctx: Context) {
* available in the `body`.
*/
private def genClosure(tree: Closure): js.Tree = {
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
val Closure(env, call, functionalInterface) = tree
val envSize = env.size
@@ -1868,7 +1868,7 @@ class JSCodeGen()(implicit ctx: Context) {
val allCaptureValues = qualifier :: env
val (formalCaptures, actualCaptures) = allCaptureValues.map { value =>
- implicit val pos: Position = value.pos
+ implicit val pos = value.pos
val formalIdent = value match {
case Ident(name) => freshLocalIdent(name.toString)
case This(_) => freshLocalIdent("this")
@@ -1988,7 +1988,7 @@ class JSCodeGen()(implicit ctx: Context) {
/** Gen JS code for an isInstanceOf test (for reference types only) */
private def genIsInstanceOf(tree: Tree, value: js.Tree, to: Type): js.Tree = {
- implicit val pos: Position = tree.pos
+ implicit val pos = tree.pos
val sym = to.widenDealias.typeSymbol
if (sym == defn.ObjectClass) {
@@ -2242,7 +2242,7 @@ class JSCodeGen()(implicit ctx: Context) {
* to perform the conversion to js.Array, then wrap in a Spread
* operator.
*/
- implicit val pos: Position = arg.pos
+ implicit val pos = arg.pos
val jsArrayArg = genModuleApplyMethod(
jsdefn.RuntimePackage_genTraversableOnce2jsArray,
List(genExpr(arg)))
@@ -2259,7 +2259,7 @@ class JSCodeGen()(implicit ctx: Context) {
*/
private def tryGenRepeatedParamAsJSArray(arg: Tree,
handleNil: Boolean): Option[List[js.Tree]] = {
- implicit val pos: Position = arg.pos
+ implicit val pos = arg.pos
// Given a method `def foo(args: T*)`
arg match {
diff --git a/compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala b/compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala
index 0027defa7..eb4da5400 100644
--- a/compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala
+++ b/compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala
@@ -125,7 +125,7 @@ class DottyPrimitives(ctx: Context) {
/** Initialize the primitive map */
private def init: immutable.Map[Symbol, Int] = {
- implicit val ctx: Context = this.ctx
+ implicit val ctx = this.ctx
import core.Symbols.defn
val primitives = new mutable.HashMap[Symbol, Int]()
diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala
index c4b2b2122..20273eb85 100644
--- a/compiler/src/dotty/tools/dotc/ast/Trees.scala
+++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala
@@ -1224,7 +1224,7 @@ object Trees {
case AppliedTypeTree(tpt, args) =>
this(this(x, tpt), args)
case PolyTypeTree(tparams, body) =>
- implicit val ctx: Context = localCtx
+ implicit val ctx = localCtx
this(this(x, tparams), body)
case ByNameTypeTree(result) =>
this(x, result)
@@ -1237,13 +1237,13 @@ object Trees {
case UnApply(fun, implicits, patterns) =>
this(this(this(x, fun), implicits), patterns)
case tree @ ValDef(name, tpt, _) =>
- implicit val ctx: Context = localCtx
+ implicit val ctx = localCtx
this(this(x, tpt), tree.rhs)
case tree @ DefDef(name, tparams, vparamss, tpt, _) =>
- implicit val ctx: Context = localCtx
+ implicit val ctx = localCtx
this(this((this(x, tparams) /: vparamss)(apply), tpt), tree.rhs)
case TypeDef(name, rhs) =>
- implicit val ctx: Context = localCtx
+ implicit val ctx = localCtx
this(x, rhs)
case tree @ Template(constr, parents, self, _) =>
this(this(this(this(x, constr), parents), self), tree.body)
diff --git a/compiler/src/dotty/tools/dotc/config/PathResolver.scala b/compiler/src/dotty/tools/dotc/config/PathResolver.scala
index aa4d8aeb0..8df9a8c0e 100644
--- a/compiler/src/dotty/tools/dotc/config/PathResolver.scala
+++ b/compiler/src/dotty/tools/dotc/config/PathResolver.scala
@@ -143,7 +143,7 @@ object PathResolver {
println(Defaults)
}
else {
- implicit val ctx: Context = (new ContextBase).initialCtx // Dotty deviation: implicits need explicit type
+ implicit val ctx = (new ContextBase).initialCtx
val ArgsSummary(sstate, rest, errors) =
ctx.settings.processArguments(args.toList, true)
errors.foreach(println)
diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
index 8b7c28e19..e2bb0ac1a 100644
--- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -75,7 +75,7 @@ trait SymDenotations { this: Context =>
def explainSym(msg: String) = explain(s"$msg\n defined = ${denot.definedPeriodsString}")
if (denot.is(ValidForever) || denot.isRefinementClass) true
else {
- implicit val ctx: Context = this
+ implicit val ctx = this
val initial = denot.initial
if ((initial ne denot) || ctx.phaseId != initial.validFor.firstPhaseId) {
ctx.withPhase(initial.validFor.firstPhaseId).traceInvalid(initial)
diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
index f8c0cdac9..743220f55 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -16,7 +16,7 @@ import scala.util.control.NonFatal
/** Provides methods to compare types.
*/
class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
- implicit val ctx: Context = initctx
+ implicit val ctx = initctx
val state = ctx.typerState
import state.constraint
@@ -156,7 +156,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
private def firstTry(tp1: Type, tp2: Type): Boolean = tp2 match {
case tp2: NamedType =>
def compareNamed(tp1: Type, tp2: NamedType): Boolean = {
- implicit val ctx: Context = this.ctx
+ implicit val ctx = this.ctx
tp2.info match {
case info2: TypeAlias => isSubType(tp1, info2.alias)
case _ => tp1 match {
diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
index 57397a8bc..82943377a 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
@@ -438,7 +438,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
private def eraseDerivedValueClassRef(tref: TypeRef)(implicit ctx: Context): Type = {
val cls = tref.symbol.asClass
val underlying = underlyingOfValueClass(cls)
- if (underlying.exists) ErasedValueType(tref, valueErasure(underlying))
+ if (underlying.exists && !isCyclic(cls)) ErasedValueType(tref, valueErasure(underlying))
else NoType
}
diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala
index 7e6620f8e..4dffc4542 100644
--- a/compiler/src/dotty/tools/dotc/core/Types.scala
+++ b/compiler/src/dotty/tools/dotc/core/Types.scala
@@ -3378,7 +3378,7 @@ object Types {
/** Map this function over given type */
def mapOver(tp: Type): Type = {
- implicit val ctx: Context = this.ctx // Dotty deviation: implicits need explicit type
+ implicit val ctx = this.ctx
tp match {
case tp: NamedType =>
if (stopAtStatic && tp.symbol.isStatic) tp
diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
index 51dafc928..704f399ca 100644
--- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -597,7 +597,7 @@ object Parsers {
val isNegated = negOffset < in.offset
atPos(negOffset) {
if (in.token == SYMBOLLIT) atPos(in.skipToken()) { SymbolLit(in.strVal) }
- else if (in.token == INTERPOLATIONID) interpolatedString()
+ else if (in.token == INTERPOLATIONID) interpolatedString(inPattern)
else finish(in.token match {
case CHARLIT => in.charVal
case INTLIT => in.intVal(isNegated).toInt
@@ -621,10 +621,14 @@ object Parsers {
in.nextToken()
while (in.token == STRINGPART) {
segmentBuf += Thicket(
- literal(),
+ literal(inPattern = inPattern),
atPos(in.offset) {
if (in.token == IDENTIFIER)
termIdent()
+ else if (in.token == USCORE && inPattern) {
+ in.nextToken()
+ Ident(nme.WILDCARD)
+ }
else if (in.token == THIS) {
in.nextToken()
This(EmptyTypeIdent)
@@ -633,12 +637,12 @@ object Parsers {
if (inPattern) Block(Nil, inBraces(pattern()))
else expr()
else {
- ctx.error(InterpolatedStringError())
+ ctx.error(InterpolatedStringError(), source atPos Position(in.offset))
EmptyTree
}
})
}
- if (in.token == STRINGLIT) segmentBuf += literal()
+ if (in.token == STRINGLIT) segmentBuf += literal(inPattern = inPattern)
InterpolatedString(interpolator, segmentBuf.toList)
}
@@ -1444,7 +1448,7 @@ object Parsers {
case XMLSTART =>
xmlLiteralPattern()
case _ =>
- if (isLiteral) literal()
+ if (isLiteral) literal(inPattern = true)
else {
syntaxErrorOrIncomplete(IllegalStartOfSimplePattern())
errorTermTree
diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala
index 60003d098..101be167e 100644
--- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala
+++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala
@@ -758,7 +758,7 @@ object Scanners {
finishStringPart()
nextRawChar()
next.token = LBRACE
- } else if (Character.isUnicodeIdentifierStart(ch)) {
+ } else if (Character.isUnicodeIdentifierStart(ch) || ch == '_') {
finishStringPart()
do {
putChar(ch)
diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala
index 7fd50bfdc..c27644ad9 100644
--- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala
+++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala
@@ -14,7 +14,7 @@ object MessageContainer {
implicit class MessageContext(val c: Context) extends AnyVal {
def shouldExplain(cont: MessageContainer): Boolean = {
- implicit val ctx: Context = c
+ implicit val ctx = c
cont.contained.explanation match {
case "" => false
case _ => ctx.settings.explain.value
diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala
index 5c880c7bd..7595e5f2e 100644
--- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala
@@ -575,7 +575,7 @@ object Erasure extends TypeTestsCasts{
val bridge = ctx.newSymbol(ctx.owner, nme.ANON_FUN, Flags.Synthetic | Flags.Method, sam.info)
val bridgeCtx = ctx.withOwner(bridge)
Closure(bridge, bridgeParamss => {
- implicit val ctx: Context = bridgeCtx
+ implicit val ctx = bridgeCtx
val List(bridgeParams) = bridgeParamss
val rhs = Apply(meth, (bridgeParams, implParamTypes).zipped.map(adapt(_, _)))
@@ -691,7 +691,7 @@ object Erasure extends TypeTestsCasts{
val bridgeCtx = ctx.withOwner(bridge)
tpd.DefDef(bridge, { paramss: List[List[tpd.Tree]] =>
- implicit val ctx: Context = bridgeCtx
+ implicit val ctx = bridgeCtx
val rhs = paramss.foldLeft(sel)((fun, vparams) =>
fun.tpe.widen match {
diff --git a/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala b/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala
index 5ae4e8a54..925ec08b2 100644
--- a/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala
+++ b/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala
@@ -135,14 +135,6 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful
// TODO: this is state and should be per-run
// todo: check that when transformation finished map is empty
- private def checkNonCyclic(pos: Position, seen: Set[Symbol], clazz: ClassSymbol)(implicit ctx: Context): Unit =
- if (seen contains clazz)
- ctx.error("value class may not unbox to itself", pos)
- else {
- val unboxed = underlyingOfValueClass(clazz).typeSymbol
- if (isDerivedValueClass(unboxed)) checkNonCyclic(pos, seen + clazz, unboxed.asClass)
- }
-
override def transformTemplate(tree: tpd.Template)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
if (isDerivedValueClass(ctx.owner)) {
/* This is currently redundant since value classes may not
diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
index aa4eefe43..eee429a87 100644
--- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
+++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
@@ -129,17 +129,20 @@ class TreeChecker extends Phase with SymTransformer {
try checker.typedExpr(ctx.compilationUnit.tpdTree)(checkingCtx)
catch {
case NonFatal(ex) => //TODO CHECK. Check that we are bootstrapped
- implicit val ctx: Context = checkingCtx
+ implicit val ctx = checkingCtx
println(i"*** error while checking ${ctx.compilationUnit} after phase ${checkingCtx.phase.prev} ***")
throw ex
}
}
- class Checker(phasesToCheck: Seq[Phase]) extends ReTyper {
+ class Checker(phasesToCheck: Seq[Phase]) extends ReTyper with Checking {
val nowDefinedSyms = new mutable.HashSet[Symbol]
val everDefinedSyms = new mutable.HashMap[Symbol, Tree]
+ // don't check value classes after typer, as the constraint about constructors doesn't hold after transform
+ override def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(implicit ctx: Context) = ()
+
def withDefinedSym[T](tree: untpd.Tree)(op: => T)(implicit ctx: Context): T = tree match {
case tree: DefTree =>
val sym = tree.symbol
diff --git a/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala b/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala
index 93005c57a..b16d05644 100644
--- a/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala
+++ b/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala
@@ -53,4 +53,14 @@ object ValueClasses {
def underlyingOfValueClass(d: ClassDenotation)(implicit ctx: Context): Type =
valueClassUnbox(d).info.resultType
+ /** Whether a value class wraps itself */
+ def isCyclic(cls: ClassSymbol)(implicit ctx: Context): Boolean = {
+ def recur(seen: Set[Symbol], clazz: ClassSymbol)(implicit ctx: Context): Boolean =
+ (seen contains clazz) || {
+ val unboxed = underlyingOfValueClass(clazz).typeSymbol
+ (isDerivedValueClass(unboxed)) && recur(seen + clazz, unboxed.asClass)
+ }
+
+ recur(Set[Symbol](), cls)
+ }
}
diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala
index d34804865..4203ab9b2 100644
--- a/compiler/src/dotty/tools/dotc/typer/Applications.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala
@@ -1026,7 +1026,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
val nestedCtx = ctx.fresh.setExploreTyperState
{
- implicit val ctx: Context = nestedCtx
+ implicit val ctx = nestedCtx
isAsSpecificValueType(tp1, constrained(tp2).resultType)
}
case _ => // (3b)
diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala
index d80dfe7c0..f5f7bdbaa 100644
--- a/compiler/src/dotty/tools/dotc/typer/Checking.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala
@@ -29,6 +29,7 @@ import ErrorReporting.{err, errorType}
import config.Printers.typr
import collection.mutable
import SymDenotations.NoCompleter
+import dotty.tools.dotc.transform.ValueClasses._
object Checking {
import tpd._
@@ -56,7 +57,7 @@ object Checking {
checkBounds(args, poly.paramBounds, _.substParams(poly, _))
/** Check applied type trees for well-formedness. This means
- * - all arguments are within their corresponding bounds
+ * - all arguments are within their corresponding bounds
* - if type is a higher-kinded application with wildcard arguments,
* check that it or one of its supertypes can be reduced to a normal application.
* Unreducible applications correspond to general existentials, and we
@@ -88,12 +89,12 @@ object Checking {
checkWildcardHKApply(tp.superType, pos)
}
case _ =>
- }
+ }
def checkValidIfHKApply(implicit ctx: Context): Unit =
checkWildcardHKApply(tycon.tpe.appliedTo(args.map(_.tpe)), tree.pos)
checkValidIfHKApply(ctx.addMode(Mode.AllowLambdaWildcardApply))
}
-
+
/** Check that `tp` refers to a nonAbstract class
* and that the instance conforms to the self type of the created class.
*/
@@ -406,6 +407,43 @@ object Checking {
notPrivate.errors.foreach { case (msg, pos) => ctx.errorOrMigrationWarning(msg, pos) }
info
}
+
+ /** Verify classes extending AnyVal meet the requirements */
+ def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(implicit ctx: Context) = {
+ def checkValueClassMember(stat: Tree) = stat match {
+ case _: ValDef if !stat.symbol.is(ParamAccessor) =>
+ ctx.error(s"value class may not define non-parameter field", stat.pos)
+ case d: DefDef if d.symbol.isConstructor =>
+ ctx.error(s"value class may not define secondary constructor", stat.pos)
+ case _: MemberDef | _: Import | EmptyTree =>
+ // ok
+ case _ =>
+ ctx.error(s"value class may not contain initialization statements", stat.pos)
+ }
+ if (isDerivedValueClass(clazz)) {
+ if (clazz.is(Trait))
+ ctx.error("Only classes (not traits) are allowed to extend AnyVal", clazz.pos)
+ if (clazz.is(Abstract))
+ ctx.error("`abstract' modifier cannot be used with value classes", clazz.pos)
+ if (!clazz.isStatic)
+ ctx.error(s"value class may not be a ${if (clazz.owner.isTerm) "local class" else "member of another class"}", clazz.pos)
+ if (isCyclic(clazz.asClass))
+ ctx.error("value class cannot wrap itself", clazz.pos)
+ else {
+ val clParamAccessors = clazz.asClass.paramAccessors.filter(_.isTerm)
+ clParamAccessors match {
+ case List(param) =>
+ if (param.is(Mutable))
+ ctx.error("value class parameter must not be a var", param.pos)
+
+ case _ =>
+ ctx.error("value class needs to have exactly one val parameter", clazz.pos)
+ }
+ }
+ stats.foreach(checkValueClassMember)
+ }
+
+ }
}
trait Checking {
@@ -553,6 +591,10 @@ trait Checking {
errorTree(tpt, ex"Singleton type ${tpt.tpe} is not allowed $where")
}
else tpt
+
+ /** Verify classes extending AnyVal meet the requirements */
+ def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(implicit ctx: Context) =
+ Checking.checkDerivedValueClass(clazz, stats)
}
trait NoChecking extends Checking {
@@ -568,4 +610,5 @@ trait NoChecking extends Checking {
override def checkParentCall(call: Tree, caller: ClassSymbol)(implicit ctx: Context) = ()
override def checkSimpleKinded(tpt: Tree)(implicit ctx: Context): Tree = tpt
override def checkNotSingleton(tpt: Tree, where: String)(implicit ctx: Context): Tree = tpt
+ override def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(implicit ctx: Context) = ()
}
diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala
index a18c83ff8..a066fc04a 100644
--- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala
+++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala
@@ -46,7 +46,13 @@ object ErrorReporting {
errorMsg(msg, cx.outer)
}
} else msg
- errorMsg(ex.show, ctx)
+
+ if (cycleSym.is(Implicit, butNot = Method) && cycleSym.owner.isTerm)
+ em"""cyclic reference involving implicit $cycleSym
+ |This happens when the right hand-side of $cycleSym's definition involves an implicit search.
+ |To avoid the error, give $cycleSym an explicit type."""
+ else
+ errorMsg(ex.show, ctx)
}
def wrongNumberOfArgs(fntpe: Type, kind: String, expectedArgs: List[TypeParamInfo], actual: List[untpd.Tree], pos: Position)(implicit ctx: Context) =
diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala
index 3931fcaf4..09487570d 100644
--- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala
@@ -189,7 +189,7 @@ object Inliner {
if (!ctx.isAfterTyper) {
val inlineCtx = ctx
sym.updateAnnotation(LazyBodyAnnotation { _ =>
- implicit val ctx: Context = inlineCtx
+ implicit val ctx = inlineCtx
ctx.withNoError(treeExpr(ctx))(makeInlineable)
})
}
diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala
index b8fe46745..4bcdd5071 100644
--- a/compiler/src/dotty/tools/dotc/typer/Namer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala
@@ -683,7 +683,7 @@ class Namer { typer: Typer =>
//println(i"completing type params of $sym in ${sym.owner}")
nestedCtx = localContext(sym).setNewScope
myTypeParams = {
- implicit val ctx: Context = nestedCtx
+ implicit val ctx = nestedCtx
val tparams = original.rhs match {
case PolyTypeTree(tparams, _) => tparams
case _ => Nil
@@ -998,11 +998,16 @@ class Namer { typer: Typer =>
lhsType // keep constant types that fill in for a non-constant (to be revised when inline has landed).
else inherited
else {
- if (sym is Implicit) {
- val resStr = if (mdef.isInstanceOf[DefDef]) "result " else ""
- ctx.error(s"${resStr}type of implicit definition needs to be given explicitly", mdef.pos)
+ def missingType(modifier: String) = {
+ ctx.error(s"${modifier}type of implicit definition needs to be given explicitly", mdef.pos)
sym.resetFlag(Implicit)
}
+ if (sym is Implicit)
+ mdef match {
+ case _: DefDef => missingType("result")
+ case _: ValDef if sym.owner.isType => missingType("")
+ case _ =>
+ }
lhsType orElse WildcardType
}
}
diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala
index 46bdbf3b3..dcbd444f9 100644
--- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala
+++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala
@@ -18,7 +18,6 @@ import config.{ScalaVersion, NoScalaVersion}
import Decorators._
import typer.ErrorReporting._
import DenotTransformers._
-import ValueClasses.isDerivedValueClass
object RefChecks {
import tpd._
@@ -688,39 +687,6 @@ object RefChecks {
}
}
- /** Verify classes extending AnyVal meet the requirements */
- private def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(implicit ctx: Context) = {
- def checkValueClassMember(stat: Tree) = stat match {
- case _: ValDef if !stat.symbol.is(ParamAccessor) =>
- ctx.error(s"value class may not define non-parameter field", stat.pos)
- case _: DefDef if stat.symbol.isConstructor =>
- ctx.error(s"value class may not define secondary constructor", stat.pos)
- case _: MemberDef | _: Import | EmptyTree =>
- // ok
- case _ =>
- ctx.error(s"value class may not contain initialization statements", stat.pos)
- }
- if (isDerivedValueClass(clazz)) {
- if (clazz.is(Trait))
- ctx.error("Only classes (not traits) are allowed to extend AnyVal", clazz.pos)
- if (clazz.is(Abstract))
- ctx.error("`abstract' modifier cannot be used with value classes", clazz.pos)
- if (!clazz.isStatic)
- ctx.error(s"value class may not be a ${if (clazz.owner.isTerm) "local class" else "member of another class"}", clazz.pos)
- else {
- val clParamAccessors = clazz.asClass.paramAccessors.filter(sym => sym.isTerm && !sym.is(Method))
- clParamAccessors match {
- case List(param) =>
- if (param.is(Mutable))
- ctx.error("value class parameter must not be a var", param.pos)
- case _ =>
- ctx.error("value class needs to have exactly one val parameter", clazz.pos)
- }
- }
- stats.foreach(checkValueClassMember)
- }
- }
-
type LevelAndIndex = immutable.Map[Symbol, (LevelInfo, Int)]
class OptLevelInfo extends DotClass {
@@ -836,7 +802,6 @@ class RefChecks extends MiniPhase { thisTransformer =>
checkParents(cls)
checkCompanionNameClashes(cls)
checkAllOverrides(cls)
- checkDerivedValueClass(cls, tree.body)
tree
} catch {
case ex: MergeError =>
diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala
index ae6b719e4..eec3859f9 100644
--- a/compiler/src/dotty/tools/dotc/typer/Typer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala
@@ -1293,6 +1293,10 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
ctx.featureWarning(nme.dynamics.toString, "extension of type scala.Dynamic", isScala2Feature = true,
cls, isRequired, cdef.pos)
}
+
+ // check value class constraints
+ checkDerivedValueClass(cls, body1)
+
cdef1
// todo later: check that
@@ -1638,7 +1642,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
tryInsertImplicitOnQualifier(tree, pt).getOrElse(fallBack)
if (isApplyProto(pt)) tryImplicit
- else tryEither(tryApply(_))((_, _) => tryImplicit)
+ else tryEither(tryApply(_))((_, _) => tryImplicit)
}
/** If this tree is a select node `qual.name`, try to insert an implicit conversion