aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/Compiler.scala9
-rw-r--r--src/dotty/tools/dotc/ast/Desugar.scala36
-rw-r--r--src/dotty/tools/dotc/config/ScalaSettings.scala1
-rw-r--r--src/dotty/tools/dotc/core/Contexts.scala16
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala4
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala6
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala7
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala66
-rw-r--r--src/dotty/tools/dotc/core/TypeOps.scala10
-rw-r--r--src/dotty/tools/dotc/core/Types.scala49
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreePickler.scala35
-rw-r--r--src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala23
-rw-r--r--src/dotty/tools/dotc/parsing/JavaParsers.scala2
-rw-r--r--src/dotty/tools/dotc/parsing/Parsers.scala30
-rw-r--r--src/dotty/tools/dotc/reporting/Reporter.scala6
-rw-r--r--src/dotty/tools/dotc/transform/PostTyper.scala7
-rw-r--r--src/dotty/tools/dotc/transform/TypeTestsCasts.scala1
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala19
-rw-r--r--src/dotty/tools/dotc/typer/FrontEnd.scala7
-rw-r--r--src/dotty/tools/dotc/typer/Implicits.scala34
-rw-r--r--src/dotty/tools/dotc/typer/ProtoTypes.scala3
-rw-r--r--src/dotty/tools/dotc/typer/RefChecks.scala4
-rw-r--r--src/dotty/tools/dotc/typer/TypeAssigner.scala3
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala58
-rw-r--r--src/dotty/tools/dotc/typer/VarianceChecker.scala12
26 files changed, 284 insertions, 166 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index a36743b59..bf3dbb232 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -9,11 +9,10 @@ import Scopes._
import typer.{FrontEnd, Typer, Mode, ImportInfo, RefChecks}
import reporting.{Reporter, ConsoleReporter}
import Phases.Phase
-import dotty.tools.dotc.transform._
-import dotty.tools.dotc.transform.TreeTransforms.{TreeTransform, TreeTransformer}
-import dotty.tools.dotc.core.DenotTransformers.DenotTransformer
-import dotty.tools.dotc.core.Denotations.SingleDenotation
-
+import transform._
+import transform.TreeTransforms.{TreeTransform, TreeTransformer}
+import core.DenotTransformers.DenotTransformer
+import core.Denotations.SingleDenotation
import dotty.tools.backend.jvm.{LabelDefs, GenBCode}
diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala
index d1f101283..33205dfd4 100644
--- a/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/src/dotty/tools/dotc/ast/Desugar.scala
@@ -132,7 +132,7 @@ object desugar {
case tparam @ TypeDef(_, ContextBounds(tbounds, cxbounds)) =>
for (cxbound <- cxbounds) {
val paramFlags: FlagSet = if (isPrimaryConstructor) PrivateLocalParamAccessor else Param
- val epname = (nme.EVIDENCE_PARAM_PREFIX.toString + epbuf.length).toTermName
+ val epname = ctx.freshName(nme.EVIDENCE_PARAM_PREFIX).toTermName
epbuf += ValDef(epname, cxbound, EmptyTree).withFlags(paramFlags | Implicit)
}
cpy.TypeDef(tparam)(rhs = tbounds)
@@ -236,10 +236,12 @@ object desugar {
// prefixed by type or val). `tparams` and `vparamss` are the type parameters that
// go in `constr`, the constructor after desugaring.
+ val isCaseClass = mods.is(Case) && !mods.is(Module)
+
val constrTparams = constr1.tparams map toDefParam
val constrVparamss =
if (constr1.vparamss.isEmpty) { // ensure parameter list is non-empty
- if (mods is Case)
+ if (isCaseClass)
ctx.error("case class needs to have at least one parameter list", cdef.pos)
ListOfNil
}
@@ -287,7 +289,7 @@ object desugar {
// neg/t1843-variances.scala for a test case. The test would give
// two errors without @uncheckedVariance, one of them spurious.
val caseClassMeths =
- if (mods is Case) {
+ if (isCaseClass) {
def syntheticProperty(name: TermName, rhs: Tree) =
DefDef(name, Nil, Nil, TypeTree(), rhs).withMods(synthetic)
val isDefinedMeth = syntheticProperty(nme.isDefined, Literal(Constant(true)))
@@ -326,9 +328,9 @@ object desugar {
if (targs.isEmpty) tycon else AppliedTypeTree(tycon, targs)
}
- // Case classes get a ProductN parent
+ // Case classes and case objects get a ProductN parent
var parents1 = parents
- if ((mods is Case) && arity <= Definitions.MaxTupleArity)
+ if (mods.is(Case) && arity <= Definitions.MaxTupleArity)
parents1 = parents1 :+ productConstr(arity)
// The thicket which is the desugared version of the companion object
@@ -350,7 +352,7 @@ object desugar {
// (T11, ..., T1N) => ... => (TM1, ..., TMN) => C
// For all other classes, the parent is AnyRef.
val companions =
- if (mods is Case) {
+ if (isCaseClass) {
val parent =
if (constrTparams.nonEmpty ||
constrVparamss.length > 1 ||
@@ -386,7 +388,7 @@ object desugar {
ctx.error("implicit classes may not be toplevel", cdef.pos)
Nil
}
- else if (mods is Case) {
+ else if (isCaseClass) {
ctx.error("implicit classes may not be case classes", cdef.pos)
Nil
}
@@ -407,7 +409,7 @@ object desugar {
val originalTparams = constr1.tparams.toIterator
val originalVparams = constr1.vparamss.toIterator.flatten
val tparamAccessors = derivedTparams.map(_.withMods(originalTparams.next.mods))
- val caseAccessor = if (mods is Case) CaseAccessor else EmptyFlags
+ val caseAccessor = if (isCaseClass) CaseAccessor else EmptyFlags
val vparamAccessors = derivedVparamss.flatten.map(_.withMods(originalVparams.next.mods | caseAccessor))
cpy.TypeDef(cdef)(
rhs = cpy.Template(impl)(constr, parents1, self1,
@@ -453,7 +455,7 @@ object desugar {
.withPos(tmpl.self.pos orElse tmpl.pos.startPos)
val clsTmpl = cpy.Template(tmpl)(self = clsSelf, body = tmpl.body)
val cls = TypeDef(clsName, clsTmpl)
- .withMods(mods.toTypeFlags & AccessOrSynthetic | ModuleClassCreationFlags)
+ .withMods(mods.toTypeFlags & RetainedModuleClassFlags | ModuleClassCreationFlags)
Thicket(modul, classDef(cls))
}
}
@@ -556,14 +558,20 @@ object desugar {
DefDef(nme.ANON_FUN, Nil, params :: Nil, tpt, body).withMods(synthetic),
Closure(Nil, Ident(nme.ANON_FUN), EmptyTree))
- /** Expand partial function
+ /** If `nparams` == 1, expand partial function
+ *
* { cases }
* ==>
- * x$0 => x$0 match { cases }
+ * x$1 => x$1 match { cases }
+ *
+ * If `nparams` != 1, expand instead to
+ *
+ * (x$1, ..., x$n) => (x$0, ..., x${n-1}) match { cases }
*/
- def makeCaseLambda(cases: List[CaseDef])(implicit ctx: Context) = {
- val param = makeSyntheticParameter()
- Function(param :: Nil, Match(Ident(param.name), cases))
+ def makeCaseLambda(cases: List[CaseDef], nparams: Int = 1)(implicit ctx: Context) = {
+ val params = (1 to nparams).toList.map(makeSyntheticParameter(_))
+ val selector = makeTuple(params.map(p => Ident(p.name)))
+ Function(params, Match(selector, cases))
}
/** Add annotation with class `cls` to tree:
diff --git a/src/dotty/tools/dotc/config/ScalaSettings.scala b/src/dotty/tools/dotc/config/ScalaSettings.scala
index 05fefc8b4..62b071372 100644
--- a/src/dotty/tools/dotc/config/ScalaSettings.scala
+++ b/src/dotty/tools/dotc/config/ScalaSettings.scala
@@ -18,6 +18,7 @@ class ScalaSettings extends Settings.SettingGroup {
*/
val dependencyfile = StringSetting("-dependencyfile", "file", "Set dependency tracking file.", ".scala_dependencies")
val deprecation = BooleanSetting("-deprecation", "Emit warning and location for usages of deprecated APIs.")
+ val migration = BooleanSetting("-migration", "Emit warning and location for migration issues from Scala 2.")
val encoding = StringSetting("-encoding", "encoding", "Specify character encoding used by source files.", Properties.sourceEncoding)
val explaintypes = BooleanSetting("-explaintypes", "Explain type errors in more detail.")
val feature = BooleanSetting("-feature", "Emit warning and location for usages of features that should be imported explicitly.")
diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala
index d5fdba1af..522240b0f 100644
--- a/src/dotty/tools/dotc/core/Contexts.scala
+++ b/src/dotty/tools/dotc/core/Contexts.scala
@@ -153,6 +153,14 @@ object Contexts {
protected def gadt_=(gadt: GADTMap) = _gadt = gadt
def gadt: GADTMap = _gadt
+ /**The current fresh name creator */
+ private[this] var _freshNames: FreshNameCreator = _
+ protected def freshNames_=(freshNames: FreshNameCreator) = _freshNames = freshNames
+ def freshNames: FreshNameCreator = _freshNames
+
+ def freshName(prefix: String = ""): String = freshNames.newName(prefix)
+ def freshName(prefix: Name): String = freshName(prefix.toString)
+
/** A map in which more contextual properties can be stored */
private var _moreProperties: Map[String, Any] = _
protected def moreProperties_=(moreProperties: Map[String, Any]) = _moreProperties = moreProperties
@@ -423,6 +431,7 @@ object Contexts {
def setDiagnostics(diagnostics: Option[StringBuilder]): this.type = { this.diagnostics = diagnostics; this }
def setTypeComparerFn(tcfn: Context => TypeComparer): this.type = { this.typeComparer = tcfn(this); this }
def setSearchHistory(searchHistory: SearchHistory): this.type = { this.searchHistory = searchHistory; this }
+ def setFreshNames(freshNames: FreshNameCreator): this.type = { this.freshNames = freshNames; this }
def setMoreProperties(moreProperties: Map[String, Any]): this.type = { this.moreProperties = moreProperties; this }
def setProperty(prop: (String, Any)): this.type = setMoreProperties(moreProperties + prop)
@@ -468,6 +477,7 @@ object Contexts {
typeAssigner = TypeAssigner
runInfo = new RunInfo(this)
diagnostics = None
+ freshNames = new FreshNameCreator.Default
moreProperties = Map.empty
typeComparer = new TypeComparer(this)
searchHistory = new SearchHistory(0, Map())
@@ -498,12 +508,6 @@ object Contexts {
/** The platform */
val platform: Platform = new JavaPlatform
- /** The standard fresh name creator */
- val freshNames = new FreshNameCreator.Default
-
- def freshName(prefix: String = ""): String = freshNames.newName(prefix)
- def freshName(prefix: Name): String = freshName(prefix.toString)
-
/** The loader that loads the members of _root_ */
def rootLoader(root: TermSymbol)(implicit ctx: Context): SymbolLoader = platform.rootLoader(root)
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index a503a2d23..6f322904e 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -192,6 +192,9 @@ class Definitions {
ScalaPackageClass, tpnme.Null, AbstractFinal, List(ObjectClass.typeRef))
lazy val ScalaPredefModule = ctx.requiredModule("scala.Predef")
+
+ lazy val Predef_conforms = ctx.requiredMethod(ScalaPredefModule.moduleClass.asClass, "$conforms")
+
lazy val ScalaRuntimeModule = ctx.requiredModule("scala.runtime.ScalaRunTime")
lazy val ScalaRuntimeClass = ScalaRuntimeModule.moduleClass.asClass
@@ -210,7 +213,6 @@ class Definitions {
def newRefArrayMethod = ctx.requiredMethod(DottyArraysModule.moduleClass.asClass, "newRefArray")
lazy val NilModule = ctx.requiredModule("scala.collection.immutable.Nil")
- lazy val PredefConformsClass = ctx.requiredClass("scala.Predef." + tpnme.Conforms)
// lazy val FunctionClass: ClassSymbol = ctx.requiredClass("scala.Function")
lazy val SingletonClass: ClassSymbol =
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index 0dde5de95..1271d7f6a 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -227,6 +227,8 @@ object Flags {
/** A trait */
final val Trait = typeFlag(10, "<trait>")
+ final val LazyOrTrait = Lazy.toCommonFlags
+
/** A value or variable accessor (getter or setter) */
final val Accessor = termFlag(11, "<accessor>")
@@ -315,6 +317,8 @@ object Flags {
/** An unpickled Scala 2.x class */
final val Scala2x = typeFlag(26, "<scala-2.x>")
+ final val SuperAccessorOrScala2x = SuperAccessor.toCommonFlags
+
/** A method that has default params */
final val DefaultParameterized = termFlag(27, "<defaultparam>")
@@ -440,7 +444,7 @@ object Flags {
AccessFlags | Module | Package | Deferred | Final | MethodOrHKCommon | Param | ParamAccessor | Scala2ExistentialCommon |
InSuperCall | Touched | JavaStatic | CovariantOrOuter | ContravariantOrLabel | ExpandedName | AccessorOrSealed |
CaseAccessorOrTypeArgument | Fresh | Frozen | Erroneous | ImplicitCommon | Permanent |
- SelfNameOrImplClass
+ LazyOrTrait | SuperAccessorOrScala2x | SelfNameOrImplClass
assert(FromStartFlags.isTermFlags && FromStartFlags.isTypeFlags)
// TODO: Should check that FromStartFlags do not change in completion
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index 126af9259..20d674b86 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -176,7 +176,7 @@ object SymDenotations {
// completions.println(s"completed ${this.debugString}")
}
- protected[dotc] final def info_=(tp: Type) = {
+ protected[dotc] def info_=(tp: Type) = {
/* // DEBUG
def illegal: String = s"illegal type for $this: $tp"
if (this is Module) // make sure module invariants that allow moduleClass and sourceModule to work are kept.
@@ -1177,6 +1177,11 @@ object SymDenotations {
myTypeParams
}
+ override protected[dotc] final def info_=(tp: Type) = {
+ super.info_=(tp)
+ myTypeParams = null // changing the info might change decls, and with it typeParams
+ }
+
/** The denotations of all parents in this class. */
def classParents(implicit ctx: Context): List[TypeRef] = info match {
case classInfo: ClassInfo => classInfo.classParents
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index 47935f79e..7274c1f70 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -48,33 +48,43 @@ class TypeApplications(val self: Type) extends AnyVal {
* For a typeref referring to a class, the type parameters of the class.
* For a typeref referring to a Lambda class, the type parameters of
* its right hand side or upper bound.
- * For a refinement type, the type parameters of its parent, unless the refinement
- * re-binds the type parameter with a type-alias.
- * For any other non-singleton type proxy, the type parameters of its underlying type.
- * For any other type, the empty list.
+ * For a refinement type, the type parameters of its parent, dropping
+ * any type parameter that is-rebound by the refinement. "Re-bind" means:
+ * The refinement contains a TypeAlias for the type parameter, or
+ * it introduces bounds for the type parameter, and we are not in the
+ * special case of a type Lambda, where a LambdaTrait gets refined
+ * with the bounds on its hk args. See `LambdaAbstract`, where these
+ * types get introduced, and see `isBoundedLambda` below for the test.
*/
final def typeParams(implicit ctx: Context): List[TypeSymbol] = /*>|>*/ track("typeParams") /*<|<*/ {
self match {
- case tp: ClassInfo =>
- tp.cls.typeParams
- case tp: TypeRef =>
- val tsym = tp.typeSymbol
+ case self: ClassInfo =>
+ self.cls.typeParams
+ case self: TypeRef =>
+ val tsym = self.typeSymbol
if (tsym.isClass) tsym.typeParams
- else if (tsym.isAliasType) tp.underlying.typeParams
+ else if (tsym.isAliasType) self.underlying.typeParams
else {
val lam = LambdaClass(forcing = false)
if (lam.exists) lam.typeParams else Nil
}
- case tp: RefinedType =>
- val tparams = tp.parent.typeParams
- tp.refinedInfo match {
- case rinfo: TypeAlias => tparams.filterNot(_.name == tp.refinedName)
- case _ => tparams
+ case self: RefinedType =>
+ def isBoundedLambda(tp: Type): Boolean = tp match {
+ case tp: TypeRef => tp.typeSymbol.isLambdaTrait
+ case tp: RefinedType => tp.refinedName.isLambdaArgName && isBoundedLambda(tp.parent)
+ case _ => false
+ }
+ val tparams = self.parent.typeParams
+ self.refinedInfo match {
+ case rinfo: TypeBounds if rinfo.isAlias || isBoundedLambda(self) =>
+ tparams.filterNot(_.name == self.refinedName)
+ case _ =>
+ tparams
}
- case tp: SingletonType =>
+ case self: SingletonType =>
Nil
- case tp: TypeProxy =>
- tp.underlying.typeParams
+ case self: TypeProxy =>
+ self.underlying.typeParams
case _ =>
Nil
}
@@ -91,23 +101,23 @@ class TypeApplications(val self: Type) extends AnyVal {
*/
final def rawTypeParams(implicit ctx: Context): List[TypeSymbol] = {
self match {
- case tp: ClassInfo =>
- tp.cls.typeParams
- case tp: TypeRef =>
- val tsym = tp.typeSymbol
+ case self: ClassInfo =>
+ self.cls.typeParams
+ case self: TypeRef =>
+ val tsym = self.typeSymbol
if (tsym.isClass) tsym.typeParams
- else if (tsym.isAliasType) tp.underlying.rawTypeParams
+ else if (tsym.isAliasType) self.underlying.rawTypeParams
else Nil
case _: BoundType | _: SingletonType =>
Nil
- case tp: TypeProxy =>
- tp.underlying.rawTypeParams
+ case self: TypeProxy =>
+ self.underlying.rawTypeParams
case _ =>
Nil
}
}
- /** If type `tp` is equal, aliased-to, or upperbounded-by a type of the form
+ /** If type `self` is equal, aliased-to, or upperbounded-by a type of the form
* `LambdaXYZ { ... }`, the class symbol of that type, otherwise NoSymbol.
* symbol of that type, otherwise NoSymbol.
* @param forcing if set, might force completion. If not, never forces
@@ -125,7 +135,7 @@ class TypeApplications(val self: Type) extends AnyVal {
NoSymbol
}}
- /** Is type `tp` equal, aliased-to, or upperbounded-by a type of the form
+ /** Is type `self` equal, aliased-to, or upperbounded-by a type of the form
* `LambdaXYZ { ... }`?
*/
def isLambda(implicit ctx: Context): Boolean =
@@ -137,7 +147,7 @@ class TypeApplications(val self: Type) extends AnyVal {
def isSafeLambda(implicit ctx: Context): Boolean =
LambdaClass(forcing = false).exists
- /** Is type `tp` a Lambda with all hk$i fields fully instantiated? */
+ /** Is type `self` a Lambda with all hk$i fields fully instantiated? */
def isInstantiatedLambda(implicit ctx: Context): Boolean =
isSafeLambda && typeParams.isEmpty
@@ -225,7 +235,7 @@ class TypeApplications(val self: Type) extends AnyVal {
}
/** Same as isHK, except we classify all abstract types as HK,
- * (they must be, because the are applied). This avoids some forcing and
+ * (they must be, because they are applied). This avoids some forcing and
* CyclicReference errors of the standard isHK.
*/
def isKnownHK(tp: Type): Boolean = tp match {
diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala
index 77c6805f0..aa643256c 100644
--- a/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/src/dotty/tools/dotc/core/TypeOps.scala
@@ -5,6 +5,7 @@ package core
import Contexts._, Types._, Symbols._, Names._, Flags._, Scopes._
import SymDenotations._, Denotations.Denotation
import config.Printers._
+import util.Positions._
import Decorators._
import StdNames._
import util.SimpleMap
@@ -572,6 +573,15 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
/** Is auto-tupling enabled? */
def canAutoTuple =
!featureEnabled(defn.LanguageModuleClass, nme.noAutoTupling)
+
+ def scala2Mode =
+ featureEnabled(defn.LanguageModuleClass, nme.Scala2)
+
+ def testScala2Mode(msg: String, pos: Position) = {
+ if (scala2Mode) migrationWarning(msg, pos)
+ scala2Mode
+ }
+
}
object TypeOps {
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 58a6d226d..bfff1a448 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -606,7 +606,7 @@ object Types {
}
/** Is this type a primitive value type which can be widened to the primitive value type `that`? */
- def isValueSubType(that: Type)(implicit ctx: Context) = widenExpr match {
+ def isValueSubType(that: Type)(implicit ctx: Context) = widen match {
case self: TypeRef if defn.ScalaValueClasses contains self.symbol =>
that.widenExpr match {
case that: TypeRef if defn.ScalaValueClasses contains that.symbol =>
@@ -618,6 +618,9 @@ object Types {
false
}
+ def relaxed_<:<(that: Type)(implicit ctx: Context) =
+ (this <:< that) || (this isValueSubType that)
+
/** Is this type a legal type for a member that overrides another
* member of type `that`? This is the same as `<:<`, except that
* the types ()T and => T are identified, and T is seen as overriding
@@ -846,14 +849,16 @@ object Types {
* (*) normalizes means: follow instantiated typevars and aliases.
*/
def lookupRefined(name: Name)(implicit ctx: Context): Type = {
- def loop(pre: Type, resolved: List[Name]): Type = pre.stripTypeVar match {
+ def loop(pre: Type): Type = pre.stripTypeVar match {
case pre: RefinedType =>
object instantiate extends TypeMap {
var isSafe = true
def apply(tp: Type): Type = tp match {
case TypeRef(RefinedThis(`pre`), name) if name.isLambdaArgName =>
- val TypeAlias(alias) = member(name).info
- alias
+ member(name).info match {
+ case TypeAlias(alias) => alias
+ case _ => isSafe = false; tp
+ }
case tp: TypeVar if !tp.inst.exists =>
isSafe = false
tp
@@ -861,23 +866,37 @@ object Types {
mapOver(tp)
}
}
- def betaReduce(tp: Type) = {
- val lam = pre.parent.LambdaClass(forcing = false)
- if (lam.exists && lam.typeParams.forall(tparam => resolved.contains(tparam.name))) {
- val reduced = instantiate(tp)
+ def instArg(tp: Type): Type = tp match {
+ case tp @ TypeAlias(TypeRef(RefinedThis(`pre`), name)) if name.isLambdaArgName =>
+ member(name).info match {
+ case TypeAlias(alias) => tp.derivedTypeAlias(alias) // needed to keep variance
+ case bounds => bounds
+ }
+ case _ =>
+ instantiate(tp)
+ }
+ def instTop(tp: Type): Type = tp.stripTypeVar match {
+ case tp: RefinedType =>
+ tp.derivedRefinedType(instTop(tp.parent), tp.refinedName, instArg(tp.refinedInfo))
+ case _ =>
+ instantiate(tp)
+ }
+ /** Reduce rhs of $hkApply to make it stand alone */
+ def betaReduce(tp: Type) =
+ if (pre.parent.isSafeLambda) {
+ val reduced = instTop(tp)
if (instantiate.isSafe) reduced else NoType
}
else NoType
- }
pre.refinedInfo match {
case TypeAlias(alias) =>
- if (pre.refinedName ne name) loop(pre.parent, pre.refinedName :: resolved)
+ if (pre.refinedName ne name) loop(pre.parent)
else if (!pre.refinementRefersToThis) alias
else alias match {
case TypeRef(RefinedThis(`pre`), aliasName) => lookupRefined(aliasName) // (1)
case _ => if (name == tpnme.hkApply) betaReduce(alias) else NoType // (2)
}
- case _ => loop(pre.parent, resolved)
+ case _ => loop(pre.parent)
}
case RefinedThis(binder) =>
binder.lookupRefined(name)
@@ -887,14 +906,14 @@ object Types {
WildcardType
case pre: TypeRef =>
pre.info match {
- case TypeAlias(alias) => loop(alias, resolved)
+ case TypeAlias(alias) => loop(alias)
case _ => NoType
}
case _ =>
NoType
}
- loop(this, Nil)
+ loop(this)
}
/** The type <this . name> , reduced if possible */
@@ -1886,6 +1905,10 @@ object Types {
s"variance mismatch for $this, $cls, ${cls.typeParams}, ${cls.typeParams.apply(refinedName.LambdaArgIndex).variance}, ${refinedInfo.variance}")
case _ =>
}
+ if (Config.checkProjections &&
+ (refinedName == tpnme.hkApply || refinedName.isLambdaArgName) &&
+ parent.noHK)
+ assert(false, s"illegal refinement of first-order type: $this")
this
}
diff --git a/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/src/dotty/tools/dotc/core/tasty/TreePickler.scala
index 58697c196..86bbc893f 100644
--- a/src/dotty/tools/dotc/core/tasty/TreePickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreePickler.scala
@@ -148,27 +148,32 @@ class TreePickler(pickler: TastyPickler) {
pickleType(tpe.info.bounds.hi)
case tpe: WithFixedSym =>
val sym = tpe.symbol
+ def pickleRef() =
+ if (tpe.prefix == NoPrefix) {
+ writeByte(if (tpe.isType) TYPEREFdirect else TERMREFdirect)
+ pickleSymRef(sym)
+ }
+ else {
+ assert(tpe.symbol.isClass)
+ assert(tpe.symbol.is(Flags.Scala2x), tpe.symbol.showLocated)
+ writeByte(TYPEREF) // should be changed to a new entry that keeps track of prefix, symbol & owner
+ pickleName(tpe.name)
+ pickleType(tpe.prefix)
+ }
if (sym.is(Flags.Package)) {
writeByte(if (tpe.isType) TYPEREFpkg else TERMREFpkg)
pickleName(qualifiedName(sym))
}
- else {
- assert(tpe.prefix == NoPrefix)
- def pickleRef() = {
- writeByte(if (tpe.isType) TYPEREFdirect else TERMREFdirect)
- pickleSymRef(sym)
- }
- if (sym is Flags.BindDefinedType) {
- registerDef(sym)
- writeByte(BIND)
- withLength {
- pickleName(sym.name)
- pickleType(sym.info)
- pickleRef()
- }
+ else if (sym is Flags.BindDefinedType) {
+ registerDef(sym)
+ writeByte(BIND)
+ withLength {
+ pickleName(sym.name)
+ pickleType(sym.info)
+ pickleRef()
}
- else pickleRef()
}
+ else pickleRef()
case tpe: TermRefWithSignature =>
if (tpe.symbol.is(Flags.Package)) picklePackageRef(tpe.symbol)
else {
diff --git a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
index 6e405d5f8..9269109ad 100644
--- a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
+++ b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
@@ -130,8 +130,18 @@ object Scala2Unpickler {
} else {
registerCompanionPair(scalacCompanion, denot.classSymbol)
}
+ val declsTypeParams = denot.typeParams
+ val declsInRightOrder =
+ if (declsTypeParams.corresponds(tparams)(_.name == _.name)) decls
+ else { // create new scope with type parameters in right order
+ val decls1 = newScope
+ for (tparam <- tparams) decls1.enter(decls.lookup(tparam.name))
+ for (sym <- decls) if (!declsTypeParams.contains(sym)) decls1.enter(sym)
+ decls1
+ }
- denot.info = ClassInfo(denot.owner.thisType, denot.classSymbol, parentRefs, decls, ost)
+ denot.info = ClassInfo(
+ denot.owner.thisType, denot.classSymbol, parentRefs, declsInRightOrder, ost)
}
}
@@ -405,6 +415,8 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
// println(owner.info.decls.toList.map(_.debugString).mkString("\n ")) // !!! DEBUG
// }
// (5) Create a stub symbol to defer hard failure a little longer.
+ println(i"***** missing reference, looking for $name in $owner")
+ println(i"decls = ${owner.info.decls}")
new Exception().printStackTrace()
ctx.newStubSymbol(owner, name, source)
}
@@ -451,6 +463,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
}
def finishSym(sym: Symbol): Symbol = {
+ if (sym.isClass) sym.setFlag(Scala2x)
val owner = sym.owner
if (owner.isClass &&
!( isUnpickleRoot(sym)
@@ -536,7 +549,6 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
case denot: ClassDenotation =>
val selfInfo = if (atEnd) NoType else readTypeRef()
setClassInfo(denot, tp, selfInfo)
- denot setFlag Scala2x
case denot =>
val tp1 = depoly(tp, denot)
denot.info =
@@ -621,7 +633,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
tp.derivedRefinedType(parent1, name, info)
}
case tp @ TypeRef(pre, tpnme.hkApply) =>
- elim(pre)
+ tp.derivedSelect(elim(pre))
case _ =>
tp
}
@@ -687,7 +699,10 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
case _ =>
}
val tycon =
- if (isLocal(sym) || pre == NoPrefix) {
+ if (sym.isClass && sym.is(Scala2x) && !sym.owner.is(Package))
+ // used fixed sym for Scala 2 inner classes, because they might be shadowed
+ TypeRef.withFixedSym(pre, sym.name.asTypeName, sym.asType)
+ else if (isLocal(sym) || pre == NoPrefix) {
val pre1 = if ((pre eq NoPrefix) && (sym is TypeParam)) sym.owner.thisType else pre
pre1 select sym
}
diff --git a/src/dotty/tools/dotc/parsing/JavaParsers.scala b/src/dotty/tools/dotc/parsing/JavaParsers.scala
index 7b9d29ce3..52bcdb965 100644
--- a/src/dotty/tools/dotc/parsing/JavaParsers.scala
+++ b/src/dotty/tools/dotc/parsing/JavaParsers.scala
@@ -114,7 +114,7 @@ object JavaParsers {
def makeTemplate(parents: List[Tree], stats: List[Tree], tparams: List[TypeDef], needsDummyConstr: Boolean) = {
def pullOutFirstConstr(stats: List[Tree]): (Tree, List[Tree]) = stats match {
- case (meth: DefDef) :: rest if meth.name.isConstructorName => (meth, rest)
+ case (meth: DefDef) :: rest if meth.name == CONSTRUCTOR => (meth, rest)
case first :: rest =>
val (constr, tail) = pullOutFirstConstr(rest)
(constr, first :: tail)
diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala
index 4b22eac95..71a03b9e2 100644
--- a/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -259,7 +259,11 @@ object Parsers {
}
/** Cannot use ctx.featureEnabled because accessing the context would force too much */
- private def scala2mode = ctx.settings.language.value.contains(nme.Scala2.toString)
+ private def testScala2Mode(msg: String, pos: Position = Position(in.offset)) = {
+ val s2 = ctx.settings.language.value.contains(nme.Scala2.toString)
+ if (s2) ctx.migrationWarning(msg, source atPos pos)
+ s2
+ }
/* ---------- TREE CONSTRUCTION ------------------------------------------- */
@@ -322,6 +326,7 @@ object Parsers {
case Ident(name1) => placeholderParams.nonEmpty && name1 == placeholderParams.head.name
case Typed(t1, _) => isWildcard(t1)
case Annotated(t1, _) => isWildcard(t1)
+ case Parens(t1) => isWildcard(t1)
case _ => false
}
@@ -1725,12 +1730,13 @@ object Parsers {
* DefSig ::= id [DefTypeParamClause] ParamClauses
*/
def defDefOrDcl(mods: Modifiers): Tree = atPos(tokenRange) {
- def atScala2Brace = scala2mode && in.token == LBRACE
+ def scala2ProcedureSyntax =
+ testScala2Mode("Procedure syntax no longer supported; `=' should be inserted here")
if (in.token == THIS) {
in.nextToken()
val vparamss = paramClauses(nme.CONSTRUCTOR)
val rhs = {
- if (!atScala2Brace) accept(EQUALS)
+ if (!(in.token == LBRACE && scala2ProcedureSyntax)) accept(EQUALS)
atPos(in.offset) { constrExpr() }
}
makeConstructor(Nil, vparamss, rhs).withMods(mods)
@@ -1741,10 +1747,22 @@ object Parsers {
val vparamss = paramClauses(name)
var tpt = fromWithinReturnType(typedOpt())
val rhs =
- if (tpt.isEmpty || in.token == EQUALS) {
- if (atScala2Brace) tpt = scalaUnit else accept(EQUALS)
+ if (in.token == EQUALS) {
+ in.nextToken()
+ expr
+ }
+ else if (!tpt.isEmpty)
+ EmptyTree
+ else if (scala2ProcedureSyntax) {
+ tpt = scalaUnit
+ if (in.token == LBRACE) expr()
+ else EmptyTree
+ }
+ else {
+ if (!isExprIntro) syntaxError("missing return type", in.lastOffset)
+ accept(EQUALS)
expr()
- } else EmptyTree
+ }
DefDef(name, tparams, vparamss, tpt, rhs).withMods(mods1)
}
}
diff --git a/src/dotty/tools/dotc/reporting/Reporter.scala b/src/dotty/tools/dotc/reporting/Reporter.scala
index 0358f71f6..4a72c2066 100644
--- a/src/dotty/tools/dotc/reporting/Reporter.scala
+++ b/src/dotty/tools/dotc/reporting/Reporter.scala
@@ -66,6 +66,9 @@ object Reporter {
class DeprecationWarning(msgFn: => String, pos: SourcePosition) extends ConditionalWarning(msgFn, pos) {
def enablingOption(implicit ctx: Context) = ctx.settings.deprecation
}
+ class MigrationWarning(msgFn: => String, pos: SourcePosition) extends ConditionalWarning(msgFn, pos) {
+ def enablingOption(implicit ctx: Context) = ctx.settings.migration
+ }
}
import Reporter._
@@ -82,6 +85,9 @@ trait Reporting { this: Context =>
def deprecationWarning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
reporter.report(new DeprecationWarning(msg, pos))
+ def migrationWarning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
+ reporter.report(new MigrationWarning(msg, pos))
+
def uncheckedWarning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
reporter.report(new UncheckedWarning(msg, pos))
diff --git a/src/dotty/tools/dotc/transform/PostTyper.scala b/src/dotty/tools/dotc/transform/PostTyper.scala
index 7a25a9870..221d097f9 100644
--- a/src/dotty/tools/dotc/transform/PostTyper.scala
+++ b/src/dotty/tools/dotc/transform/PostTyper.scala
@@ -68,10 +68,10 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
// TODO fill in
}
- /** Check bounds of AppliedTypeTrees.
+ /** Check bounds of AppliedTypeTrees and TypeApplys.
* Replace type trees with TypeTree nodes.
* Replace constant expressions with Literal nodes.
- * Note: Demanding idempotency instead of purityin literalize is strictly speaking too loose.
+ * Note: Demanding idempotency instead of purity in literalize is strictly speaking too loose.
* Example
*
* object O { final val x = 42; println("43") }
@@ -114,6 +114,9 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
tparam.info.asSeenFrom(tycon.tpe.normalizedPrefix, tparam.owner.owner).bounds)
Checking.checkBounds(args, bounds, _.substDealias(tparams, _))
norm(tree)
+ case TypeApply(fn, args) =>
+ Checking.checkBounds(args, fn.tpe.widen.asInstanceOf[PolyType])
+ norm(tree)
case _ =>
norm(tree)
}
diff --git a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
index 98b8357b9..b2d45b661 100644
--- a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
+++ b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
@@ -27,7 +27,6 @@ import ValueClasses._
* Unfortunately this phase ended up being not Y-checkable unless types are erased. A cast to an ConstantType(3) or x.type
* cannot be rewritten before erasure.
*/
-
trait TypeTestsCasts {
import ast.tpd._
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index 0fee17bcd..87bed8895 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -607,7 +607,7 @@ trait Applications extends Compatibility { self: Typer =>
case pt: PolyType =>
if (typedArgs.length <= pt.paramBounds.length)
typedArgs = typedArgs.zipWithConserve(pt.paramBounds)(adaptTypeArg)
- checkBounds(typedArgs, pt)
+ Checking.checkBounds(typedArgs, pt)
case _ =>
}
assignType(cpy.TypeApply(tree)(typedFn, typedArgs), typedFn, typedArgs)
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index fa417beec..3dc7b67df 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -41,6 +41,13 @@ object Checking {
d"Type argument ${arg.tpe} does not conform to $which bound $bound ${err.whyNoMatchStr(arg.tpe, bound)}",
arg.pos)
+ /** Check that type arguments `args` conform to corresponding bounds in `poly`
+ * Note: This does not check the bounds of AppliedTypeTrees. These
+ * are handled by method checkBounds in FirstTransform
+ */
+ def checkBounds(args: List[tpd.Tree], poly: PolyType)(implicit ctx: Context): Unit =
+ checkBounds(args, poly.paramBounds, _.substParams(poly, _))
+
/** Check that `tp` refers to a nonAbstract class
* and that the instance conforms to the self type of the created class.
*/
@@ -295,13 +302,6 @@ trait Checking {
tree
}
- /** Check that type arguments `args` conform to corresponding bounds in `poly`
- * Note: This does not check the bounds of AppliedTypeTrees. These
- * are handled by method checkBounds in FirstTransform
- */
- def checkBounds(args: List[tpd.Tree], poly: PolyType)(implicit ctx: Context): Unit =
- Checking.checkBounds(args, poly.paramBounds, _.substParams(poly, _))
-
/** Check that type `tp` is stable. */
def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit =
if (!tp.isStable && !tp.isErroneous)
@@ -398,9 +398,7 @@ trait Checking {
if (tpt.tpe.isHK && !ctx.compilationUnit.isJava) {
// be more lenient with missing type params in Java,
// needed to make pos/java-interop/t1196 work.
- val alias = tpt.tpe.dealias
- if (alias.isHK) errorTree(tpt, d"missing type parameter for ${tpt.tpe}")
- else tpt.withType(alias)
+ errorTree(tpt, d"missing type parameter for ${tpt.tpe}")
}
else tpt
}
@@ -409,7 +407,6 @@ trait NoChecking extends Checking {
import tpd._
override def checkNonCyclic(sym: Symbol, info: TypeBounds, reportErrors: Boolean)(implicit ctx: Context): Type = info
override def checkValue(tree: Tree, proto: Type)(implicit ctx: Context): tree.type = tree
- override def checkBounds(args: List[tpd.Tree], poly: PolyType)(implicit ctx: Context): Unit = ()
override def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit = ()
override def checkClassTypeWithStablePrefix(tp: Type, pos: Position, traitReq: Boolean)(implicit ctx: Context): Type = tp
override def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = ()
diff --git a/src/dotty/tools/dotc/typer/FrontEnd.scala b/src/dotty/tools/dotc/typer/FrontEnd.scala
index f417448bd..e8a0adf19 100644
--- a/src/dotty/tools/dotc/typer/FrontEnd.scala
+++ b/src/dotty/tools/dotc/typer/FrontEnd.scala
@@ -9,6 +9,7 @@ import parsing.Parsers.Parser
import config.Printers._
import util.Stats._
import scala.util.control.NonFatal
+import util.FreshNameCreator
class FrontEnd extends Phase {
@@ -28,7 +29,8 @@ class FrontEnd extends Phase {
unit.untpdTree =
if (unit.isJava) new JavaParser(unit.source).parse()
else new Parser(unit.source).parse()
- typr.println("parsed:\n" + unit.untpdTree.show)
+ val printer = if (ctx.settings.Xprint.value.contains("parser")) default else typr
+ printer.println("parsed:\n" + unit.untpdTree.show)
}
def enterSyms(implicit ctx: Context) = monitor("indexing") {
@@ -46,7 +48,8 @@ class FrontEnd extends Phase {
}
override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
- val unitContexts = units map (unit => ctx.fresh.setCompilationUnit(unit))
+ val unitContexts = for (unit <- units) yield
+ ctx.fresh.setCompilationUnit(unit).setFreshNames(new FreshNameCreator.Default)
unitContexts foreach (parse(_))
record("parsedTrees", ast.Trees.ntrees)
unitContexts foreach (enterSyms(_))
diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala
index e3626fe20..280cc40e9 100644
--- a/src/dotty/tools/dotc/typer/Implicits.scala
+++ b/src/dotty/tools/dotc/typer/Implicits.scala
@@ -44,19 +44,19 @@ object Implicits {
/** Return those references in `refs` that are compatible with type `pt`. */
protected def filterMatching(pt: Type)(implicit ctx: Context): List[TermRef] = track("filterMatching") {
- def refMatches(ref: TermRef)(implicit ctx: Context) = {
+ def refMatches(ref: TermRef)(implicit ctx: Context) = /*ctx.traceIndented(i"refMatches $ref $pt")*/ {
def discardForView(tpw: Type, argType: Type): Boolean = tpw match {
case mt: MethodType =>
mt.isImplicit ||
mt.paramTypes.length != 1 ||
- !(argType <:< mt.paramTypes.head)(ctx.fresh.setExploreTyperState)
+ !(argType relaxed_<:< mt.paramTypes.head)(ctx.fresh.setExploreTyperState)
case poly: PolyType =>
poly.resultType match {
case mt: MethodType =>
mt.isImplicit ||
mt.paramTypes.length != 1 ||
- !(argType <:< wildApprox(mt.paramTypes.head)(ctx.fresh.setExploreTyperState))
+ !(argType relaxed_<:< wildApprox(mt.paramTypes.head)(ctx.fresh.setExploreTyperState))
case rtp =>
discardForView(wildApprox(rtp), argType)
}
@@ -65,7 +65,9 @@ object Implicits {
case tpw =>
//if (ctx.typer.isApplicable(tp, argType :: Nil, resultType))
// println(i"??? $tp is applicable to $this / typeSymbol = ${tpw.typeSymbol}")
- !tpw.derivesFrom(defn.FunctionClass(1)) || tpw.isRef(defn.PredefConformsClass)
+ !tpw.derivesFrom(defn.FunctionClass(1)) ||
+ ref.symbol == defn.Predef_conforms //
+ // as an implicit conversion, Predef.$conforms is a no-op, so exclude it
}
def discardForValueType(tpw: Type): Boolean = tpw match {
@@ -530,6 +532,25 @@ trait Implicits { self: Typer =>
case nil => acc
}
+ /** If the (result types of) the expected type, and both alternatives
+ * are all numeric value types, return the alternative which has
+ * the smaller numeric subtype as result type, if it exists.
+ * (This alternative is then discarded).
+ */
+ def numericValueTieBreak(alt1: SearchSuccess, alt2: SearchSuccess): SearchResult = {
+ def isNumeric(tp: Type) = tp.typeSymbol.isNumericValueClass
+ def isProperSubType(tp1: Type, tp2: Type) =
+ tp1.isValueSubType(tp2) && !tp2.isValueSubType(tp1)
+ val rpt = pt.resultType
+ val rt1 = alt1.ref.widen.resultType
+ val rt2 = alt2.ref.widen.resultType
+ if (isNumeric(rpt) && isNumeric(rt1) && isNumeric(rt2))
+ if (isProperSubType(rt1, rt2)) alt1
+ else if (isProperSubType(rt2, rt1)) alt2
+ else NoImplicitMatches
+ else NoImplicitMatches
+ }
+
/** Convert a (possibly empty) list of search successes into a single search result */
def condense(hits: List[SearchSuccess]): SearchResult = hits match {
case best :: alts =>
@@ -539,7 +560,10 @@ trait Implicits { self: Typer =>
println(i"ambiguous refs: ${hits map (_.ref) map (_.show) mkString ", "}")
isAsGood(best.ref, alt.ref, explain = true)(ctx.fresh.withExploreTyperState)
*/
- new AmbiguousImplicits(best.ref, alt.ref, pt, argument)
+ numericValueTieBreak(best, alt) match {
+ case eliminated: SearchSuccess => condense(hits.filter(_ ne eliminated))
+ case _ => new AmbiguousImplicits(best.ref, alt.ref, pt, argument)
+ }
case None =>
ctx.runInfo.useCount(best.ref) += 1
best
diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala
index 40e919ee5..2b19d9db3 100644
--- a/src/dotty/tools/dotc/typer/ProtoTypes.scala
+++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala
@@ -32,9 +32,10 @@ object ProtoTypes {
* 1. `tp` is a subtype of `pt`
* 2. `pt` is by name parameter type, and `tp` is compatible with its underlying type
* 3. there is an implicit conversion from `tp` to `pt`.
+ * 4. `tp` is a numeric subtype of `pt` (this case applies even if implicit conversions are disabled)
*/
def isCompatible(tp: Type, pt: Type)(implicit ctx: Context): Boolean =
- tp.widenExpr <:< pt.widenExpr || viewExists(tp, pt)
+ (tp.widenExpr relaxed_<:< pt.widenExpr) || viewExists(tp, pt)
/** Test compatibility after normalization in a fresh typerstate. */
def normalizedCompatible(tp: Type, pt: Type)(implicit ctx: Context) = {
diff --git a/src/dotty/tools/dotc/typer/RefChecks.scala b/src/dotty/tools/dotc/typer/RefChecks.scala
index ae854ed9a..3ffbb8079 100644
--- a/src/dotty/tools/dotc/typer/RefChecks.scala
+++ b/src/dotty/tools/dotc/typer/RefChecks.scala
@@ -287,7 +287,9 @@ object RefChecks {
!member.isAnyOverride) {
// (*) Exclusion for default getters, fixes SI-5178. We cannot assign the Override flag to
// the default getter: one default getter might sometimes override, sometimes not. Example in comment on ticket.
- if (member.owner != clazz && other.owner != clazz && !(other.owner derivesFrom member.owner))
+ if (member.name == nme.isDefined && member.is(Synthetic)) // isDefined methods are added automatially, can't have an override preset.
+ member.setFlag(Override)
+ else if (member.owner != clazz && other.owner != clazz && !(other.owner derivesFrom member.owner))
emitOverrideError(
clazz + " inherits conflicting members:\n "
+ infoStringWithLocation(other) + " and\n " + infoStringWithLocation(member)
diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala
index 7225ede14..25030012c 100644
--- a/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -344,10 +344,9 @@ trait TypeAssigner {
def assignType(tree: untpd.Return)(implicit ctx: Context) =
tree.withType(defn.NothingType)
- def assignType(tree: untpd.Try, expr: Tree, cases: List[CaseDef])(implicit ctx: Context) = {
+ def assignType(tree: untpd.Try, expr: Tree, cases: List[CaseDef])(implicit ctx: Context) =
if (cases.isEmpty) tree.withType(expr.tpe)
else tree.withType(ctx.typeComparer.lub(expr.tpe :: cases.tpes))
- }
def assignType(tree: untpd.SeqLiteral, elems: List[Tree])(implicit ctx: Context) = tree match {
case tree: JavaSeqLiteral =>
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 569e4f7d5..c621d96c4 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -220,8 +220,10 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
val found =
if (isSelfDenot(defDenot)) curOwner.enclosingClass.thisType
else curOwner.thisType.select(name, defDenot)
- if (!(curOwner is Package) || (defDenot.symbol is Package) || isDefinedInCurrentUnit(defDenot))
+ if (!(curOwner is Package) || isDefinedInCurrentUnit(defDenot))
return checkNewOrShadowed(found, definition) // no need to go further out, we found highest prec entry
+ else if (defDenot.symbol is Package)
+ return checkNewOrShadowed(previous orElse found, packageClause)
else if (prevPrec < packageClause)
return findRef(found, packageClause, ctx)(outer)
}
@@ -502,6 +504,16 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
assignType(cpy.If(tree)(cond1, thenp2, elsep2), thenp2, elsep2)
}
+ private def decomposeProtoFunction(pt: Type, defaultArity: Int)(implicit ctx: Context): (List[Type], Type) = pt match {
+ case _ if defn.isFunctionType(pt) =>
+ (pt.dealias.argInfos.init, pt.dealias.argInfos.last)
+ case SAMType(meth) =>
+ val mt @ MethodType(_, paramTypes) = meth.info
+ (paramTypes, mt.resultType)
+ case _ =>
+ (List.range(0, defaultArity) map alwaysWildcardType, WildcardType)
+ }
+
def typedFunction(tree: untpd.Function, pt: Type)(implicit ctx: Context) = track("typedFunction") {
val untpd.Function(args, body) = tree
if (ctx.mode is Mode.Type)
@@ -509,15 +521,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
untpd.TypeTree(defn.FunctionClass(args.length).typeRef), args :+ body), pt)
else {
val params = args.asInstanceOf[List[untpd.ValDef]]
- val (protoFormals, protoResult): (List[Type], Type) = pt match {
- case _ if defn.isFunctionType(pt) =>
- (pt.dealias.argInfos.init, pt.dealias.argInfos.last)
- case SAMType(meth) =>
- val mt @ MethodType(_, paramTypes) = meth.info
- (paramTypes, mt.resultType)
- case _ =>
- (params map alwaysWildcardType, WildcardType)
- }
+ val (protoFormals, protoResult) = decomposeProtoFunction(pt, params.length)
def refersTo(arg: untpd.Tree, param: untpd.ValDef): Boolean = arg match {
case Ident(name) => name == param.name
@@ -629,7 +633,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def typedMatch(tree: untpd.Match, pt: Type)(implicit ctx: Context) = track("typedMatch") {
tree.selector match {
case EmptyTree =>
- typed(desugar.makeCaseLambda(tree.cases) withPos tree.pos, pt)
+ val (protoFormals, _) = decomposeProtoFunction(pt, 1)
+ typed(desugar.makeCaseLambda(tree.cases, protoFormals.length) withPos tree.pos, pt)
case _ =>
val sel1 = typedExpr(tree.selector)
val selType = widenForMatchSelector(
@@ -848,34 +853,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
val args1 = args.zipWithConserve(tparams)(typedArg(_, _)).asInstanceOf[List[Tree]]
// check that arguments conform to bounds is done in phase PostTyper
- val tree1 = assignType(cpy.AppliedTypeTree(tree)(tpt1, args1), tpt1, args1)
- if (tree1.tpe.isHKApply)
- for (arg @ TypeBoundsTree(_, _) <- args1)
- ctx.error("illegal wildcard type argument; does not correspond to type parameter of a class", arg.pos)
- // The reason for outlawing such arguments is illustrated by the following example.
- // Say we have
- //
- // type RMap[A, B] = Map[B, A]
- //
- // Then
- //
- // Rmap[_, Int]
- //
- // translates to
- //
- // Lambda$I { type hk$0; type hk$1 = Int; type $apply = Map[$hk1, $hk0] } # $apply
- //
- // Let's call the last type T. You would expect that
- //
- // Map[Int, String] <: RMap[_, Int]
- //
- // But that's not the case given the standard subtyping rules. In fact, the rhs reduces to
- //
- // Map[Int, T # $hk0]
- //
- // That means the second argument to `Map` is unknown and String is certainly not a subtype of it.
- // To avoid the surprise we outlaw problematic wildcard arguments from the start.
- tree1
+ assignType(cpy.AppliedTypeTree(tree)(tpt1, args1), tpt1, args1)
}
}
@@ -888,8 +866,6 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
val TypeBoundsTree(lo, hi) = desugar.typeBoundsTree(tree)
val lo1 = typed(lo)
val hi1 = typed(hi)
- if (!(lo1.tpe <:< hi1.tpe))
- ctx.error(d"lower bound ${lo1.tpe} does not conform to upper bound ${hi1.tpe}", tree.pos)
assignType(cpy.TypeBoundsTree(tree)(lo1, hi1), lo1, hi1)
}
diff --git a/src/dotty/tools/dotc/typer/VarianceChecker.scala b/src/dotty/tools/dotc/typer/VarianceChecker.scala
index 1d3ceaa57..5d3bd4f20 100644
--- a/src/dotty/tools/dotc/typer/VarianceChecker.scala
+++ b/src/dotty/tools/dotc/typer/VarianceChecker.scala
@@ -110,16 +110,20 @@ class VarianceChecker()(implicit ctx: Context) {
private object Traverser extends TreeTraverser {
def checkVariance(sym: Symbol) = Validator.validateDefinition(sym) match {
case Some(VarianceError(tvar, required)) =>
- ctx.error(
- i"${varianceString(tvar.flags)} $tvar occurs in ${varianceString(required)} position in type ${sym.info} of $sym",
- sym.pos)
+ def msg = i"${varianceString(tvar.flags)} $tvar occurs in ${varianceString(required)} position in type ${sym.info} of $sym"
+ if (ctx.scala2Mode && sym.owner.isConstructor)
+ ctx.migrationWarning(s"According to new variance rules, this is no longer accepted; need to annotate with @uncheckedVariance:\n$msg", sym.pos)
+ else ctx.error(msg, sym.pos)
case None =>
}
override def traverse(tree: Tree)(implicit ctx: Context) = {
def sym = tree.symbol
// No variance check for private/protected[this] methods/values.
- def skip = !sym.exists || sym.is(Local)
+ def skip =
+ !sym.exists ||
+ sym.is(Local) || // !!! watch out for protected local!
+ sym.is(TypeParam) && sym.owner.isClass // already taken care of in primary constructor of class
tree match {
case defn: MemberDef if skip =>
ctx.debuglog(s"Skipping variance check of ${sym.showDcl}")