aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/src/dotty/tools/dotc')
-rw-r--r--compiler/src/dotty/tools/dotc/ast/Desugar.scala23
-rw-r--r--compiler/src/dotty/tools/dotc/ast/Trees.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/core/Contexts.scala20
-rw-r--r--compiler/src/dotty/tools/dotc/core/Definitions.scala221
-rw-r--r--compiler/src/dotty/tools/dotc/core/Denotations.scala22
-rw-r--r--compiler/src/dotty/tools/dotc/core/NameOps.scala6
-rw-r--r--compiler/src/dotty/tools/dotc/core/Periods.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/core/Phases.scala5
-rw-r--r--compiler/src/dotty/tools/dotc/core/Scopes.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/core/StdNames.scala1
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeComparer.scala11
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeErasure.scala17
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeOps.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/core/Types.scala6
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/Parsers.scala90
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/Scanners.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala8
-rw-r--r--compiler/src/dotty/tools/dotc/repl/CompilingInterpreter.scala76
-rw-r--r--compiler/src/dotty/tools/dotc/repl/InterpreterLoop.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/reporting/Reporter.scala9
-rw-r--r--compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala8
-rw-r--r--compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala1
-rw-r--r--compiler/src/dotty/tools/dotc/transform/Erasure.scala84
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala18
-rw-r--r--compiler/src/dotty/tools/dotc/transform/Memoize.scala8
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Applications.scala35
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Checking.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/typer/FrontEnd.scala11
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Implicits.scala104
-rw-r--r--compiler/src/dotty/tools/dotc/typer/ImportInfo.scala16
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Inferencing.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Namer.scala109
-rw-r--r--compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala11
-rw-r--r--compiler/src/dotty/tools/dotc/typer/ReTyper.scala5
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Typer.scala148
-rw-r--r--compiler/src/dotty/tools/dotc/util/Chars.scala9
38 files changed, 785 insertions, 322 deletions
diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
index 4b2ff1bc3..15cb0b665 100644
--- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
@@ -142,16 +142,21 @@ object desugar {
val DefDef(name, tparams, vparamss, tpt, rhs) = meth
val mods = meth.mods
val epbuf = new ListBuffer[ValDef]
- val tparams1 = tparams mapConserve {
- case tparam @ TypeDef(_, ContextBounds(tbounds, cxbounds)) =>
+ def desugarContextBounds(rhs: Tree): Tree = rhs match {
+ case ContextBounds(tbounds, cxbounds) =>
for (cxbound <- cxbounds) {
val paramFlags: FlagSet = if (isPrimaryConstructor) PrivateLocalParamAccessor else Param
val epname = ctx.freshName(nme.EVIDENCE_PARAM_PREFIX).toTermName
epbuf += ValDef(epname, cxbound, EmptyTree).withFlags(paramFlags | Implicit)
}
- cpy.TypeDef(tparam)(rhs = tbounds)
- case tparam =>
- tparam
+ tbounds
+ case PolyTypeTree(tparams, body) =>
+ cpy.PolyTypeTree(rhs)(tparams, desugarContextBounds(body))
+ case _ =>
+ rhs
+ }
+ val tparams1 = tparams mapConserve { tdef =>
+ cpy.TypeDef(tdef)(rhs = desugarContextBounds(tdef.rhs))
}
val meth1 = addEvidenceParams(cpy.DefDef(meth)(tparams = tparams1), epbuf.toList)
@@ -916,7 +921,11 @@ object desugar {
val elems = segments flatMap {
case ts: Thicket => ts.trees.tail
case t => Nil
+ } map {
+ case Block(Nil, expr) => expr // important for interpolated string as patterns, see i1773.scala
+ case t => t
}
+
Apply(Select(Apply(Ident(nme.StringContext), strs), id), elems)
case InfixOp(l, op, r) =>
if (ctx.mode is Mode.Type)
@@ -1079,6 +1088,10 @@ object desugar {
collect(tree)
case Tuple(trees) =>
trees foreach collect
+ case Thicket(trees) =>
+ trees foreach collect
+ case Block(Nil, expr) =>
+ collect(expr)
case _ =>
}
collect(tree)
diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala
index 2801bcae2..c4b2b2122 100644
--- a/compiler/src/dotty/tools/dotc/ast/Trees.scala
+++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala
@@ -32,7 +32,7 @@ object Trees {
/** Property key for trees with documentation strings attached */
val DocComment = new Property.Key[Comment]
- @sharable private var nextId = 0 // for debugging
+ @sharable private var nextId = 0 // for debugging
type LazyTree = AnyRef /* really: Tree | Lazy[Tree] */
type LazyTreeList = AnyRef /* really: List[Tree] | Lazy[List[Tree]] */
diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala
index 639c4d111..a1b99d16d 100644
--- a/compiler/src/dotty/tools/dotc/core/Contexts.scala
+++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala
@@ -216,8 +216,8 @@ object Contexts {
else if (isNonEmptyScopeContext) scope.implicitDecls
else Nil
val outerImplicits =
- if (isImportContext && importInfo.hiddenRoot.exists)
- outer.implicits exclude importInfo.hiddenRoot
+ if (isImportContext && importInfo.unimported.exists)
+ outer.implicits exclude importInfo.unimported
else
outer.implicits
if (implicitRefs.isEmpty) outerImplicits
@@ -422,9 +422,18 @@ object Contexts {
final def withOwner(owner: Symbol): Context =
if (owner ne this.owner) fresh.setOwner(owner) else this
- override def toString =
+ final def withProperty[T](key: Key[T], value: Option[T]): Context =
+ if (property(key) == value) this
+ else value match {
+ case Some(v) => fresh.setProperty(key, v)
+ case None => fresh.dropProperty(key)
+ }
+
+ override def toString = {
+ def iinfo(implicit ctx: Context) = if (ctx.importInfo == null) "" else i"${ctx.importInfo.selectors}%, %"
"Context(\n" +
- (outersIterator map ( ctx => s" owner = ${ctx.owner}, scope = ${ctx.scope}") mkString "\n")
+ (outersIterator map ( ctx => s" owner = ${ctx.owner}, scope = ${ctx.scope}, import = ${iinfo(ctx)}") mkString "\n")
+ }
}
/** A condensed context provides only a small memory footprint over
@@ -468,6 +477,9 @@ object Contexts {
def setProperty[T](key: Key[T], value: T): this.type =
setMoreProperties(moreProperties.updated(key, value))
+ def dropProperty(key: Key[_]): this.type =
+ setMoreProperties(moreProperties - key)
+
def setPhase(pid: PhaseId): this.type = setPeriod(Period(runId, pid))
def setPhase(phase: Phase): this.type = setPeriod(Period(runId, phase.start, phase.end))
diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala
index 4b090d9b1..e4e5761b2 100644
--- a/compiler/src/dotty/tools/dotc/core/Definitions.scala
+++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala
@@ -12,13 +12,20 @@ import collection.mutable
import scala.reflect.api.{ Universe => ApiUniverse }
object Definitions {
- val MaxTupleArity, MaxAbstractFunctionArity = 22
- val MaxFunctionArity = 30
- // Awaiting a definite solution that drops the limit altogether, 30 gives a safety
- // margin over the previous 22, so that treecopiers in miniphases are allowed to
- // temporarily create larger closures. This is needed in lambda lift where large closures
- // are first formed by treecopiers before they are split apart into parameters and
- // environment in the lambdalift transform itself.
+
+ /** The maximum number of elements in a tuple or product.
+ * This should be removed once we go to hlists.
+ */
+ val MaxTupleArity = 22
+
+ /** The maximum arity N of a function type that's implemented
+ * as a trait `scala.FunctionN`. Functions of higher arity are possible,
+ * but are mapped in erasure to functions taking a single parameter of type
+ * Object[].
+ * The limit 22 is chosen for Scala2x interop. It could be something
+ * else without affecting the set of programs that can be compiled.
+ */
+ val MaxImplementedFunctionArity = 22
}
/** A class defining symbols and types of standard definitions
@@ -45,32 +52,29 @@ class Definitions {
ctx.newSymbol(owner, name, flags | Permanent, info)
private def newClassSymbol(owner: Symbol, name: TypeName, flags: FlagSet, infoFn: ClassSymbol => Type) =
- ctx.newClassSymbol(owner, name, flags | Permanent, infoFn).entered
+ ctx.newClassSymbol(owner, name, flags | Permanent, infoFn)
- private def newCompleteClassSymbol(owner: Symbol, name: TypeName, flags: FlagSet, parents: List[TypeRef], decls: Scope = newScope) =
+ private def enterCompleteClassSymbol(owner: Symbol, name: TypeName, flags: FlagSet, parents: List[TypeRef], decls: Scope = newScope) =
ctx.newCompleteClassSymbol(owner, name, flags | Permanent, parents, decls).entered
- private def newTopClassSymbol(name: TypeName, flags: FlagSet, parents: List[TypeRef]) =
- completeClass(newCompleteClassSymbol(ScalaPackageClass, name, flags, parents))
-
- private def newTypeField(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) =
+ private def enterTypeField(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) =
scope.enter(newSymbol(cls, name, flags, TypeBounds.empty))
- private def newTypeParam(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) =
- newTypeField(cls, name, flags | ClassTypeParamCreationFlags, scope)
+ private def enterTypeParam(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) =
+ enterTypeField(cls, name, flags | ClassTypeParamCreationFlags, scope)
- private def newSyntheticTypeParam(cls: ClassSymbol, scope: MutableScope, paramFlags: FlagSet, suffix: String = "T0") =
- newTypeParam(cls, suffix.toTypeName.expandedName(cls), ExpandedName | paramFlags, scope)
+ private def enterSyntheticTypeParam(cls: ClassSymbol, paramFlags: FlagSet, scope: MutableScope, suffix: String = "T0") =
+ enterTypeParam(cls, suffix.toTypeName.expandedName(cls), ExpandedName | paramFlags, scope)
// NOTE: Ideally we would write `parentConstrs: => Type*` but SIP-24 is only
// implemented in Dotty and not in Scala 2.
// See <http://docs.scala-lang.org/sips/pending/repeated-byname.html>.
- private def specialPolyClass(name: TypeName, paramFlags: FlagSet, parentConstrs: => Seq[Type]): ClassSymbol = {
+ private def enterSpecialPolyClass(name: TypeName, paramFlags: FlagSet, parentConstrs: => Seq[Type]): ClassSymbol = {
val completer = new LazyType {
def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
val cls = denot.asClass.classSymbol
val paramDecls = newScope
- val typeParam = newSyntheticTypeParam(cls, paramDecls, paramFlags)
+ val typeParam = enterSyntheticTypeParam(cls, paramFlags, paramDecls)
def instantiate(tpe: Type) =
if (tpe.typeParams.nonEmpty) tpe.appliedTo(typeParam.typeRef)
else tpe
@@ -79,31 +83,54 @@ class Definitions {
denot.info = ClassInfo(ScalaPackageClass.thisType, cls, parentRefs, paramDecls)
}
}
- newClassSymbol(ScalaPackageClass, name, EmptyFlags, completer)
+ newClassSymbol(ScalaPackageClass, name, EmptyFlags, completer).entered
+ }
+
+ /** The trait FunctionN, for some N */
+ private def newFunctionNTrait(n: Int) = {
+ val completer = new LazyType {
+ def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
+ val cls = denot.asClass.classSymbol
+ val decls = newScope
+ val argParams =
+ for (i <- List.range(0, n)) yield
+ enterTypeParam(cls, s"T$i".toTypeName, Contravariant, decls)
+ val resParam = enterTypeParam(cls, s"R".toTypeName, Covariant, decls)
+ val applyMeth =
+ decls.enter(
+ newMethod(cls, nme.apply,
+ MethodType(argParams.map(_.typeRef), resParam.typeRef), Deferred))
+ denot.info = ClassInfo(ScalaPackageClass.thisType, cls, ObjectType :: Nil, decls)
+ }
+ }
+ newClassSymbol(ScalaPackageClass, s"Function$n".toTypeName, Trait, completer)
}
private def newMethod(cls: ClassSymbol, name: TermName, info: Type, flags: FlagSet = EmptyFlags): TermSymbol =
- newSymbol(cls, name.encode, flags | Method, info).entered.asTerm
+ newSymbol(cls, name.encode, flags | Method, info).asTerm
+
+ private def enterMethod(cls: ClassSymbol, name: TermName, info: Type, flags: FlagSet = EmptyFlags): TermSymbol =
+ newMethod(cls, name, info, flags).entered
- private def newAliasType(name: TypeName, tpe: Type, flags: FlagSet = EmptyFlags): TypeSymbol = {
+ private def enterAliasType(name: TypeName, tpe: Type, flags: FlagSet = EmptyFlags): TypeSymbol = {
val sym = newSymbol(ScalaPackageClass, name, flags, TypeAlias(tpe))
ScalaPackageClass.currentPackageDecls.enter(sym)
sym
}
- private def newPolyMethod(cls: ClassSymbol, name: TermName, typeParamCount: Int,
+ private def enterPolyMethod(cls: ClassSymbol, name: TermName, typeParamCount: Int,
resultTypeFn: PolyType => Type, flags: FlagSet = EmptyFlags) = {
val tparamNames = tpnme.syntheticTypeParamNames(typeParamCount)
val tparamBounds = tparamNames map (_ => TypeBounds.empty)
val ptype = PolyType(tparamNames)(_ => tparamBounds, resultTypeFn)
- newMethod(cls, name, ptype, flags)
+ enterMethod(cls, name, ptype, flags)
}
- private def newT1ParameterlessMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) =
- newPolyMethod(cls, name, 1, resultTypeFn, flags)
+ private def enterT1ParameterlessMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) =
+ enterPolyMethod(cls, name, 1, resultTypeFn, flags)
- private def newT1EmptyParamsMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) =
- newPolyMethod(cls, name, 1, pt => MethodType(Nil, resultTypeFn(pt)), flags)
+ private def enterT1EmptyParamsMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) =
+ enterPolyMethod(cls, name, 1, pt => MethodType(Nil, resultTypeFn(pt)), flags)
private def mkArityArray(name: String, arity: Int, countFrom: Int): Array[TypeRef] = {
val arr = new Array[TypeRef](arity + 1)
@@ -172,20 +199,20 @@ class Definitions {
* def getClass: java.lang.Class[T] = ???
* }
*/
- lazy val AnyClass: ClassSymbol = completeClass(newCompleteClassSymbol(ScalaPackageClass, tpnme.Any, Abstract, Nil))
+ lazy val AnyClass: ClassSymbol = completeClass(enterCompleteClassSymbol(ScalaPackageClass, tpnme.Any, Abstract, Nil))
def AnyType = AnyClass.typeRef
- lazy val AnyValClass: ClassSymbol = completeClass(newCompleteClassSymbol(ScalaPackageClass, tpnme.AnyVal, Abstract, List(AnyClass.typeRef)))
+ lazy val AnyValClass: ClassSymbol = completeClass(enterCompleteClassSymbol(ScalaPackageClass, tpnme.AnyVal, Abstract, List(AnyClass.typeRef)))
def AnyValType = AnyValClass.typeRef
- lazy val Any_== = newMethod(AnyClass, nme.EQ, methOfAny(BooleanType), Final)
- lazy val Any_!= = newMethod(AnyClass, nme.NE, methOfAny(BooleanType), Final)
- lazy val Any_equals = newMethod(AnyClass, nme.equals_, methOfAny(BooleanType))
- lazy val Any_hashCode = newMethod(AnyClass, nme.hashCode_, MethodType(Nil, IntType))
- lazy val Any_toString = newMethod(AnyClass, nme.toString_, MethodType(Nil, StringType))
- lazy val Any_## = newMethod(AnyClass, nme.HASHHASH, ExprType(IntType), Final)
- lazy val Any_getClass = newMethod(AnyClass, nme.getClass_, MethodType(Nil, ClassClass.typeRef.appliedTo(TypeBounds.empty)), Final)
- lazy val Any_isInstanceOf = newT1ParameterlessMethod(AnyClass, nme.isInstanceOf_, _ => BooleanType, Final)
- lazy val Any_asInstanceOf = newT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, PolyParam(_, 0), Final)
+ lazy val Any_== = enterMethod(AnyClass, nme.EQ, methOfAny(BooleanType), Final)
+ lazy val Any_!= = enterMethod(AnyClass, nme.NE, methOfAny(BooleanType), Final)
+ lazy val Any_equals = enterMethod(AnyClass, nme.equals_, methOfAny(BooleanType))
+ lazy val Any_hashCode = enterMethod(AnyClass, nme.hashCode_, MethodType(Nil, IntType))
+ lazy val Any_toString = enterMethod(AnyClass, nme.toString_, MethodType(Nil, StringType))
+ lazy val Any_## = enterMethod(AnyClass, nme.HASHHASH, ExprType(IntType), Final)
+ lazy val Any_getClass = enterMethod(AnyClass, nme.getClass_, MethodType(Nil, ClassClass.typeRef.appliedTo(TypeBounds.empty)), Final)
+ lazy val Any_isInstanceOf = enterT1ParameterlessMethod(AnyClass, nme.isInstanceOf_, _ => BooleanType, Final)
+ lazy val Any_asInstanceOf = enterT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, PolyParam(_, 0), Final)
def AnyMethods = List(Any_==, Any_!=, Any_equals, Any_hashCode,
Any_toString, Any_##, Any_getClass, Any_isInstanceOf, Any_asInstanceOf)
@@ -205,37 +232,37 @@ class Definitions {
}
def ObjectType = ObjectClass.typeRef
- lazy val AnyRefAlias: TypeSymbol = newAliasType(tpnme.AnyRef, ObjectType)
+ lazy val AnyRefAlias: TypeSymbol = enterAliasType(tpnme.AnyRef, ObjectType)
def AnyRefType = AnyRefAlias.typeRef
- lazy val Object_eq = newMethod(ObjectClass, nme.eq, methOfAnyRef(BooleanType), Final)
- lazy val Object_ne = newMethod(ObjectClass, nme.ne, methOfAnyRef(BooleanType), Final)
- lazy val Object_synchronized = newPolyMethod(ObjectClass, nme.synchronized_, 1,
+ lazy val Object_eq = enterMethod(ObjectClass, nme.eq, methOfAnyRef(BooleanType), Final)
+ lazy val Object_ne = enterMethod(ObjectClass, nme.ne, methOfAnyRef(BooleanType), Final)
+ lazy val Object_synchronized = enterPolyMethod(ObjectClass, nme.synchronized_, 1,
pt => MethodType(List(PolyParam(pt, 0)), PolyParam(pt, 0)), Final)
- lazy val Object_clone = newMethod(ObjectClass, nme.clone_, MethodType(Nil, ObjectType), Protected)
- lazy val Object_finalize = newMethod(ObjectClass, nme.finalize_, MethodType(Nil, UnitType), Protected)
- lazy val Object_notify = newMethod(ObjectClass, nme.notify_, MethodType(Nil, UnitType))
- lazy val Object_notifyAll = newMethod(ObjectClass, nme.notifyAll_, MethodType(Nil, UnitType))
- lazy val Object_wait = newMethod(ObjectClass, nme.wait_, MethodType(Nil, UnitType))
- lazy val Object_waitL = newMethod(ObjectClass, nme.wait_, MethodType(LongType :: Nil, UnitType))
- lazy val Object_waitLI = newMethod(ObjectClass, nme.wait_, MethodType(LongType :: IntType :: Nil, UnitType))
+ lazy val Object_clone = enterMethod(ObjectClass, nme.clone_, MethodType(Nil, ObjectType), Protected)
+ lazy val Object_finalize = enterMethod(ObjectClass, nme.finalize_, MethodType(Nil, UnitType), Protected)
+ lazy val Object_notify = enterMethod(ObjectClass, nme.notify_, MethodType(Nil, UnitType))
+ lazy val Object_notifyAll = enterMethod(ObjectClass, nme.notifyAll_, MethodType(Nil, UnitType))
+ lazy val Object_wait = enterMethod(ObjectClass, nme.wait_, MethodType(Nil, UnitType))
+ lazy val Object_waitL = enterMethod(ObjectClass, nme.wait_, MethodType(LongType :: Nil, UnitType))
+ lazy val Object_waitLI = enterMethod(ObjectClass, nme.wait_, MethodType(LongType :: IntType :: Nil, UnitType))
def ObjectMethods = List(Object_eq, Object_ne, Object_synchronized, Object_clone,
Object_finalize, Object_notify, Object_notifyAll, Object_wait, Object_waitL, Object_waitLI)
/** Dummy method needed by elimByName */
- lazy val dummyApply = newPolyMethod(
+ lazy val dummyApply = enterPolyMethod(
OpsPackageClass, nme.dummyApply, 1,
pt => MethodType(List(FunctionOf(Nil, PolyParam(pt, 0))), PolyParam(pt, 0)))
/** Method representing a throw */
- lazy val throwMethod = newMethod(OpsPackageClass, nme.THROWkw,
+ lazy val throwMethod = enterMethod(OpsPackageClass, nme.THROWkw,
MethodType(List(ThrowableType), NothingType))
- lazy val NothingClass: ClassSymbol = newCompleteClassSymbol(
+ lazy val NothingClass: ClassSymbol = enterCompleteClassSymbol(
ScalaPackageClass, tpnme.Nothing, AbstractFinal, List(AnyClass.typeRef))
def NothingType = NothingClass.typeRef
- lazy val NullClass: ClassSymbol = newCompleteClassSymbol(
+ lazy val NullClass: ClassSymbol = enterCompleteClassSymbol(
ScalaPackageClass, tpnme.Null, AbstractFinal, List(ObjectClass.typeRef))
def NullType = NullClass.typeRef
@@ -281,7 +308,7 @@ class Definitions {
lazy val SingletonClass: ClassSymbol =
// needed as a synthetic class because Scala 2.x refers to it in classfiles
// but does not define it as an explicit class.
- newCompleteClassSymbol(
+ enterCompleteClassSymbol(
ScalaPackageClass, tpnme.Singleton, PureInterfaceCreationFlags | Final,
List(AnyClass.typeRef), EmptyScope)
@@ -387,17 +414,17 @@ class Definitions {
lazy val BoxedDoubleModule = ctx.requiredModule("java.lang.Double")
lazy val BoxedUnitModule = ctx.requiredModule("java.lang.Void")
- lazy val ByNameParamClass2x = specialPolyClass(tpnme.BYNAME_PARAM_CLASS, Covariant, Seq(AnyType))
- lazy val EqualsPatternClass = specialPolyClass(tpnme.EQUALS_PATTERN, EmptyFlags, Seq(AnyType))
+ lazy val ByNameParamClass2x = enterSpecialPolyClass(tpnme.BYNAME_PARAM_CLASS, Covariant, Seq(AnyType))
+ lazy val EqualsPatternClass = enterSpecialPolyClass(tpnme.EQUALS_PATTERN, EmptyFlags, Seq(AnyType))
- lazy val RepeatedParamClass = specialPolyClass(tpnme.REPEATED_PARAM_CLASS, Covariant, Seq(ObjectType, SeqType))
+ lazy val RepeatedParamClass = enterSpecialPolyClass(tpnme.REPEATED_PARAM_CLASS, Covariant, Seq(ObjectType, SeqType))
// fundamental classes
lazy val StringClass = ctx.requiredClass("java.lang.String")
def StringType: Type = StringClass.typeRef
lazy val StringModule = StringClass.linkedClass
- lazy val String_+ = newMethod(StringClass, nme.raw.PLUS, methOfAny(StringType), Final)
+ lazy val String_+ = enterMethod(StringClass, nme.raw.PLUS, methOfAny(StringType), Final)
lazy val String_valueOf_Object = StringModule.info.member(nme.valueOf).suchThat(_.info.firstParamTypes match {
case List(pt) => (pt isRef AnyClass) || (pt isRef ObjectClass)
case _ => false
@@ -431,6 +458,9 @@ class Definitions {
def PartialFunctionClass(implicit ctx: Context) = PartialFunctionType.symbol.asClass
lazy val AbstractPartialFunctionType: TypeRef = ctx.requiredClassRef("scala.runtime.AbstractPartialFunction")
def AbstractPartialFunctionClass(implicit ctx: Context) = AbstractPartialFunctionType.symbol.asClass
+ lazy val FunctionXXLType: TypeRef = ctx.requiredClassRef("scala.FunctionXXL")
+ def FunctionXXLClass(implicit ctx: Context) = FunctionXXLType.symbol.asClass
+
lazy val SymbolType: TypeRef = ctx.requiredClassRef("scala.Symbol")
def SymbolClass(implicit ctx: Context) = SymbolType.symbol.asClass
lazy val DynamicType: TypeRef = ctx.requiredClassRef("scala.Dynamic")
@@ -562,14 +592,15 @@ class Definitions {
object FunctionOf {
def apply(args: List[Type], resultType: Type)(implicit ctx: Context) =
FunctionType(args.length).appliedTo(args ::: resultType :: Nil)
- def unapply(ft: Type)(implicit ctx: Context)/*: Option[(List[Type], Type)]*/ = {
- // -language:keepUnions difference: unapply needs result type because inferred type
- // is Some[(List[Type], Type)] | None, which is not a legal unapply type.
+ def unapply(ft: Type)(implicit ctx: Context) = {
val tsym = ft.typeSymbol
- lazy val targs = ft.argInfos
- val numArgs = targs.length - 1
- if (numArgs >= 0 && numArgs <= MaxFunctionArity &&
- (FunctionType(numArgs).symbol == tsym)) Some(targs.init, targs.last)
+ if (isFunctionClass(tsym)) {
+ lazy val targs = ft.argInfos
+ val numArgs = targs.length - 1
+ if (numArgs >= 0 && FunctionType(numArgs).symbol == tsym)
+ Some(targs.init, targs.last)
+ else None
+ }
else None
}
}
@@ -612,19 +643,26 @@ class Definitions {
// ----- Symbol sets ---------------------------------------------------
- lazy val AbstractFunctionType = mkArityArray("scala.runtime.AbstractFunction", MaxAbstractFunctionArity, 0)
+ lazy val AbstractFunctionType = mkArityArray("scala.runtime.AbstractFunction", MaxImplementedFunctionArity, 0)
val AbstractFunctionClassPerRun = new PerRun[Array[Symbol]](implicit ctx => AbstractFunctionType.map(_.symbol.asClass))
def AbstractFunctionClass(n: Int)(implicit ctx: Context) = AbstractFunctionClassPerRun()(ctx)(n)
- lazy val FunctionType = mkArityArray("scala.Function", MaxFunctionArity, 0)
- def FunctionClassPerRun = new PerRun[Array[Symbol]](implicit ctx => FunctionType.map(_.symbol.asClass))
- def FunctionClass(n: Int)(implicit ctx: Context) = FunctionClassPerRun()(ctx)(n)
- lazy val Function0_applyR = FunctionType(0).symbol.requiredMethodRef(nme.apply)
- def Function0_apply(implicit ctx: Context) = Function0_applyR.symbol
+ private lazy val ImplementedFunctionType = mkArityArray("scala.Function", MaxImplementedFunctionArity, 0)
+ def FunctionClassPerRun = new PerRun[Array[Symbol]](implicit ctx => ImplementedFunctionType.map(_.symbol.asClass))
lazy val TupleType = mkArityArray("scala.Tuple", MaxTupleArity, 2)
lazy val ProductNType = mkArityArray("scala.Product", MaxTupleArity, 0)
- private lazy val FunctionTypes: Set[TypeRef] = FunctionType.toSet
+ def FunctionClass(n: Int)(implicit ctx: Context) =
+ if (n < MaxImplementedFunctionArity) FunctionClassPerRun()(ctx)(n)
+ else ctx.requiredClass("scala.Function" + n.toString)
+
+ lazy val Function0_applyR = ImplementedFunctionType(0).symbol.requiredMethodRef(nme.apply)
+ def Function0_apply(implicit ctx: Context) = Function0_applyR.symbol
+
+ def FunctionType(n: Int)(implicit ctx: Context): TypeRef =
+ if (n < MaxImplementedFunctionArity) ImplementedFunctionType(n)
+ else FunctionClass(n).typeRef
+
private lazy val TupleTypes: Set[TypeRef] = TupleType.toSet
private lazy val ProductTypes: Set[TypeRef] = ProductNType.toSet
@@ -646,10 +684,19 @@ class Definitions {
tp.derivesFrom(NothingClass) || tp.derivesFrom(NullClass)
def isFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.Function)
+ def isUnimplementedFunctionClass(cls: Symbol) =
+ isFunctionClass(cls) && cls.name.functionArity > MaxImplementedFunctionArity
def isAbstractFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.AbstractFunction)
def isTupleClass(cls: Symbol) = isVarArityClass(cls, tpnme.Tuple)
def isProductClass(cls: Symbol) = isVarArityClass(cls, tpnme.Product)
+ val predefClassNames: Set[Name] =
+ Set("Predef$", "DeprecatedPredef", "LowPriorityImplicits").map(_.toTypeName)
+
+ /** Is `cls` the predef module class, or a class inherited by Predef? */
+ def isPredefClass(cls: Symbol) =
+ (cls.owner eq ScalaPackageClass) && predefClassNames.contains(cls.name)
+
val StaticRootImportFns = List[() => TermRef](
() => JavaLangPackageVal.termRef,
() => ScalaPackageVal.termRef
@@ -688,10 +735,11 @@ class Definitions {
def isProductSubType(tp: Type)(implicit ctx: Context) =
(tp derivesFrom ProductType.symbol) && tp.baseClasses.exists(isProductClass)
- def isFunctionType(tp: Type)(implicit ctx: Context) = {
- val arity = functionArity(tp)
- 0 <= arity && arity <= MaxFunctionArity && (tp isRef FunctionType(arity).symbol)
- }
+ def isFunctionType(tp: Type)(implicit ctx: Context) =
+ isFunctionClass(tp.dealias.typeSymbol) && {
+ val arity = functionArity(tp)
+ arity >= 0 && tp.isRef(FunctionType(functionArity(tp)).typeSymbol)
+ }
def functionArity(tp: Type)(implicit ctx: Context) = tp.dealias.argInfos.length - 1
@@ -767,6 +815,23 @@ class Definitions {
// ----- Initialization ---------------------------------------------------
+ /** Give the scala package a scope where a FunctionN trait is automatically
+ * added when someone looks for it.
+ */
+ private def makeScalaSpecial()(implicit ctx: Context) = {
+ val oldInfo = ScalaPackageClass.classInfo
+ val oldDecls = oldInfo.decls
+ val newDecls = new MutableScope(oldDecls) {
+ override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = {
+ val res = super.lookupEntry(name)
+ if (res == null && name.functionArity > 0)
+ newScopeEntry(newFunctionNTrait(name.functionArity))
+ else res
+ }
+ }
+ ScalaPackageClass.info = oldInfo.derivedClassInfo(decls = newDecls)
+ }
+
/** Lists core classes that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
lazy val syntheticScalaClasses = List(
AnyClass,
@@ -794,6 +859,8 @@ class Definitions {
def init()(implicit ctx: Context) = {
this.ctx = ctx
if (!_isInitialized) {
+ makeScalaSpecial()
+
// force initialization of every symbol that is synthesized or hijacked by the compiler
val forced = syntheticCoreClasses ++ syntheticCoreMethods ++ ScalaValueClasses()
diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala
index 6a39c5787..99c688d50 100644
--- a/compiler/src/dotty/tools/dotc/core/Denotations.scala
+++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala
@@ -132,7 +132,7 @@ object Denotations {
def atSignature(sig: Signature, site: Type = NoPrefix, relaxed: Boolean = false)(implicit ctx: Context): Denotation
/** The variant of this denotation that's current in the given context.
- * If no such denotation exists, returns the denotation with each alternative
+ * If no such denotation exists, returns the denotation with each alternative
* at its first point of definition.
*/
def current(implicit ctx: Context): Denotation
@@ -744,6 +744,20 @@ object Denotations {
else NoDenotation
}
+ /** The next defined denotation (following `nextInRun`) or an arbitrary
+ * undefined denotation, if all denotations in a `nextinRun` cycle are
+ * undefined.
+ */
+ private def nextDefined: SingleDenotation = {
+ var p1 = this
+ var p2 = nextInRun
+ while (p1.validFor == Nowhere && (p1 ne p2)) {
+ p1 = p1.nextInRun
+ p2 = p2.nextInRun.nextInRun
+ }
+ p1
+ }
+
/** Produce a denotation that is valid for the given context.
* Usually called when !(validFor contains ctx.period)
* (even though this is not a precondition).
@@ -763,8 +777,9 @@ object Denotations {
// can happen if we sit on a stale denotation which has been replaced
// wholesale by an installAfter; in this case, proceed to the next
// denotation and try again.
- if (validFor == Nowhere && nextInRun.validFor != Nowhere) return nextInRun.current
- assert(false)
+ val nxt = nextDefined
+ if (nxt.validFor != Nowhere) return nxt
+ assert(false, this)
}
if (valid.runId != currentPeriod.runId)
@@ -905,6 +920,7 @@ object Denotations {
prev.nextInRun = this
this.nextInRun = old.nextInRun
old.validFor = Nowhere
+ old.nextInRun = this
}
def staleSymbolError(implicit ctx: Context) = {
diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala
index 4c7f5b0a9..7a4fc0512 100644
--- a/compiler/src/dotty/tools/dotc/core/NameOps.scala
+++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala
@@ -229,6 +229,12 @@ object NameOps {
}
}
+ def functionArity: Int =
+ if (name.startsWith(tpnme.Function))
+ try name.drop(tpnme.Function.length).toString.toInt
+ catch { case ex: NumberFormatException => -1 }
+ else -1
+
/** The name of the generic runtime operation corresponding to an array operation */
def genericArrayOp: TermName = name match {
case nme.apply => nme.array_apply
diff --git a/compiler/src/dotty/tools/dotc/core/Periods.scala b/compiler/src/dotty/tools/dotc/core/Periods.scala
index 6efadab7f..29d9d208f 100644
--- a/compiler/src/dotty/tools/dotc/core/Periods.scala
+++ b/compiler/src/dotty/tools/dotc/core/Periods.scala
@@ -153,7 +153,7 @@ object Periods {
final val FirstPhaseId = 1
/** The number of bits needed to encode a phase identifier. */
- final val PhaseWidth = 6
+ final val PhaseWidth = 7
final val PhaseMask = (1 << PhaseWidth) - 1
final val MaxPossiblePhaseId = PhaseMask
}
diff --git a/compiler/src/dotty/tools/dotc/core/Phases.scala b/compiler/src/dotty/tools/dotc/core/Phases.scala
index 222e2235d..6a53e1b30 100644
--- a/compiler/src/dotty/tools/dotc/core/Phases.scala
+++ b/compiler/src/dotty/tools/dotc/core/Phases.scala
@@ -26,7 +26,10 @@ trait Phases {
def phasesStack: List[Phase] =
if ((this eq NoContext) || !phase.exists) Nil
- else phase :: outersIterator.dropWhile(_.phase == phase).next.phasesStack
+ else {
+ val rest = outersIterator.dropWhile(_.phase == phase)
+ phase :: (if (rest.hasNext) rest.next.phasesStack else Nil)
+ }
/** Execute `op` at given phase */
def atPhase[T](phase: Phase)(op: Context => T): T =
diff --git a/compiler/src/dotty/tools/dotc/core/Scopes.scala b/compiler/src/dotty/tools/dotc/core/Scopes.scala
index 3daa8117e..6090079e5 100644
--- a/compiler/src/dotty/tools/dotc/core/Scopes.scala
+++ b/compiler/src/dotty/tools/dotc/core/Scopes.scala
@@ -309,7 +309,7 @@ object Scopes {
/** Lookup a symbol entry matching given name.
*/
- override final def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = {
+ override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = {
var e: ScopeEntry = null
if (hashTable ne null) {
e = hashTable(name.hashCode & (hashTable.length - 1))
diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala
index c2a14b36f..741ff8b1f 100644
--- a/compiler/src/dotty/tools/dotc/core/StdNames.scala
+++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala
@@ -265,6 +265,7 @@ object StdNames {
val THIS: N = "_$this"
val TRAIT_CONSTRUCTOR: N = "$init$"
val U2EVT: N = "u2evt$"
+ val ALLARGS: N = "$allArgs"
final val Nil: N = "Nil"
final val Predef: N = "Predef"
diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
index f78820fff..f8c0cdac9 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -260,6 +260,11 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
secondTry(tp1, tp2)
}
compareErasedValueType
+ case ConstantType(v2) =>
+ tp1 match {
+ case ConstantType(v1) => v1.value == v2.value
+ case _ => secondTry(tp1, tp2)
+ }
case ErrorType =>
true
case _ =>
@@ -541,9 +546,11 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
/** if `tp2 == p.type` and `p: q.type` then try `tp1 <:< q.type` as a last effort.*/
def comparePaths = tp2 match {
case tp2: TermRef =>
- tp2.info.widenExpr match {
+ tp2.info.widenExpr.dealias match {
case tp2i: SingletonType =>
- isSubType(tp1, tp2i) // see z1720.scala for a case where this can arise even in typer.
+ isSubType(tp1, tp2i)
+ // see z1720.scala for a case where this can arise even in typer.
+ // Also, i1753.scala, to show why the dealias above is necessary.
case _ => false
}
case _ =>
diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
index 28dbed8f6..82943377a 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
@@ -7,6 +7,7 @@ import Uniques.unique
import dotc.transform.ExplicitOuter._
import dotc.transform.ValueClasses._
import util.DotClass
+import Definitions.MaxImplementedFunctionArity
/** Erased types are:
*
@@ -38,7 +39,10 @@ object TypeErasure {
case _: ErasedValueType =>
true
case tp: TypeRef =>
- tp.symbol.isClass && tp.symbol != defn.AnyClass && tp.symbol != defn.ArrayClass
+ val sym = tp.symbol
+ sym.isClass &&
+ sym != defn.AnyClass && sym != defn.ArrayClass &&
+ !defn.isUnimplementedFunctionClass(sym)
case _: TermRef =>
true
case JavaArrayType(elem) =>
@@ -176,8 +180,13 @@ object TypeErasure {
else if (sym.isAbstractType) TypeAlias(WildcardType)
else if (sym.isConstructor) outer.addParam(sym.owner.asClass, erase(tp)(erasureCtx))
else erase.eraseInfo(tp, sym)(erasureCtx) match {
- case einfo: MethodType if sym.isGetter && einfo.resultType.isRef(defn.UnitClass) =>
- MethodType(Nil, defn.BoxedUnitType)
+ case einfo: MethodType =>
+ if (sym.isGetter && einfo.resultType.isRef(defn.UnitClass))
+ MethodType(Nil, defn.BoxedUnitType)
+ else if (sym.isAnonymousFunction && einfo.paramTypes.length > MaxImplementedFunctionArity)
+ MethodType(nme.ALLARGS :: Nil, JavaArrayType(defn.ObjectType) :: Nil, einfo.resultType)
+ else
+ einfo
case einfo =>
einfo
}
@@ -317,6 +326,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
* - For a term ref p.x, the type <noprefix> # x.
* - For a typeref scala.Any, scala.AnyVal or scala.Singleton: |java.lang.Object|
* - For a typeref scala.Unit, |scala.runtime.BoxedUnit|.
+ * - For a typeref scala.FunctionN, where N > MaxImplementedFunctionArity, scala.FunctionXXL
* - For a typeref P.C where C refers to a class, <noprefix> # C.
* - For a typeref P.C where C refers to an alias type, the erasure of C's alias.
* - For a typeref P.C where C refers to an abstract type, the erasure of C's upper bound.
@@ -345,6 +355,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
if (!sym.isClass) this(tp.info)
else if (semiEraseVCs && isDerivedValueClass(sym)) eraseDerivedValueClassRef(tp)
else if (sym == defn.ArrayClass) apply(tp.appliedTo(TypeBounds.empty)) // i966 shows that we can hit a raw Array type.
+ else if (defn.isUnimplementedFunctionClass(sym)) defn.FunctionXXLType
else eraseNormalClassRef(tp)
case tp: RefinedType =>
val parent = tp.parent
diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala
index 92e5f9d57..39214dd0c 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala
@@ -197,6 +197,9 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
case c :: rest =>
val accu1 = if (accu exists (_ derivesFrom c)) accu else c :: accu
if (cs == c.baseClasses) accu1 else dominators(rest, accu1)
+ case Nil => // this case can happen because after erasure we do not have a top class anymore
+ assert(ctx.erasedTypes)
+ defn.ObjectClass :: Nil
}
def mergeRefined(tp1: Type, tp2: Type): Type = {
diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala
index 89bc21929..7e6620f8e 100644
--- a/compiler/src/dotty/tools/dotc/core/Types.scala
+++ b/compiler/src/dotty/tools/dotc/core/Types.scala
@@ -2862,14 +2862,14 @@ object Types {
*
* @param origin The parameter that's tracked by the type variable.
* @param creatorState The typer state in which the variable was created.
- * @param owningTree The function part of the TypeApply tree tree that introduces
- * the type variable.
+ * @param bindingTree The TypeTree which introduces the type variable, or EmptyTree
+ * if the type variable does not correspond to a source term.
* @paran owner The current owner if the context where the variable was created.
*
* `owningTree` and `owner` are used to determine whether a type-variable can be instantiated
* at some given point. See `Inferencing#interpolateUndetVars`.
*/
- final class TypeVar(val origin: PolyParam, creatorState: TyperState, val owningTree: untpd.Tree, val owner: Symbol) extends CachedProxyType with ValueType {
+ final class TypeVar(val origin: PolyParam, creatorState: TyperState, val bindingTree: untpd.Tree, val owner: Symbol) extends CachedProxyType with ValueType {
/** The permanent instance type of the variable, or NoType is none is given yet */
private[core] var inst: Type = NoType
diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
index fa0576c7a..704f399ca 100644
--- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -83,6 +83,15 @@ object Parsers {
def atPos[T <: Positioned](start: Offset)(t: T): T =
atPos(start, start)(t)
+ def startOffset(t: Positioned): Int =
+ if (t.pos.exists) t.pos.start else in.offset
+
+ def pointOffset(t: Positioned): Int =
+ if (t.pos.exists) t.pos.point else in.offset
+
+ def endOffset(t: Positioned): Int =
+ if (t.pos.exists) t.pos.end else in.lastOffset
+
def nameStart: Offset =
if (in.token == BACKQUOTED_IDENT) in.offset + 1 else in.offset
@@ -448,7 +457,7 @@ object Parsers {
val topInfo = opStack.head
opStack = opStack.tail
val od = reduceStack(base, topInfo.operand, 0, true)
- return atPos(od.pos.start, topInfo.offset) {
+ return atPos(startOffset(od), topInfo.offset) {
PostfixOp(od, topInfo.operator)
}
}
@@ -492,7 +501,7 @@ object Parsers {
/** Accept identifier acting as a selector on given tree `t`. */
def selector(t: Tree): Tree =
- atPos(t.pos.start, in.offset) { Select(t, ident()) }
+ atPos(startOffset(t), in.offset) { Select(t, ident()) }
/** Selectors ::= ident { `.' ident()
*
@@ -588,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
@@ -612,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)
@@ -624,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)
}
@@ -728,7 +741,7 @@ object Parsers {
def refinedTypeRest(t: Tree): Tree = {
newLineOptWhenFollowedBy(LBRACE)
- if (in.token == LBRACE) refinedTypeRest(atPos(t.pos.start) { RefinedTypeTree(t, refinement()) })
+ if (in.token == LBRACE) refinedTypeRest(atPos(startOffset(t)) { RefinedTypeTree(t, refinement()) })
else t
}
@@ -749,7 +762,7 @@ object Parsers {
def annotType(): Tree = annotTypeRest(simpleType())
def annotTypeRest(t: Tree): Tree =
- if (in.token == AT) annotTypeRest(atPos(t.pos.start) { Annotated(t, annot()) })
+ if (in.token == AT) annotTypeRest(atPos(startOffset(t)) { Annotated(t, annot()) })
else t
/** SimpleType ::= SimpleType TypeArgs
@@ -780,19 +793,19 @@ object Parsers {
val handleSingletonType: Tree => Tree = t =>
if (in.token == TYPE) {
in.nextToken()
- atPos(t.pos.start) { SingletonTypeTree(t) }
+ atPos(startOffset(t)) { SingletonTypeTree(t) }
} else t
private def simpleTypeRest(t: Tree): Tree = in.token match {
case HASH => simpleTypeRest(typeProjection(t))
- case LBRACKET => simpleTypeRest(atPos(t.pos.start) { AppliedTypeTree(t, typeArgs(namedOK = true)) })
+ case LBRACKET => simpleTypeRest(atPos(startOffset(t)) { AppliedTypeTree(t, typeArgs(namedOK = true)) })
case _ => t
}
private def typeProjection(t: Tree): Tree = {
accept(HASH)
val id = typeIdent()
- atPos(t.pos.start, id.pos.start) { Select(t, id.name) }
+ atPos(startOffset(t), startOffset(id)) { Select(t, id.name) }
}
/** NamedTypeArg ::= id `=' Type
@@ -846,7 +859,7 @@ object Parsers {
val t = toplevelTyp()
if (isIdent(nme.raw.STAR)) {
in.nextToken()
- atPos(t.pos.start) { PostfixOp(t, nme.raw.STAR) }
+ atPos(startOffset(t)) { PostfixOp(t, nme.raw.STAR) }
} else t
}
@@ -971,7 +984,7 @@ object Parsers {
val t = expr1(location)
if (in.token == ARROW) {
placeholderParams = saved
- closureRest(t.pos.start, location, convertToParams(t))
+ closureRest(startOffset(t), location, convertToParams(t))
}
else if (isWildcard(t)) {
placeholderParams = placeholderParams ::: saved
@@ -1025,7 +1038,7 @@ object Parsers {
assert(handlerStart != -1)
syntaxError(
new EmptyCatchBlock(body),
- Position(handlerStart, handler.pos.end)
+ Position(handlerStart, endOffset(handler))
)
case _ =>
}
@@ -1035,7 +1048,7 @@ object Parsers {
else {
if (handler.isEmpty) warning(
EmptyCatchAndFinallyBlock(body),
- source atPos Position(tryOffset, body.pos.end)
+ source atPos Position(tryOffset, endOffset(body))
)
EmptyTree
}
@@ -1057,21 +1070,21 @@ object Parsers {
case EQUALS =>
t match {
case Ident(_) | Select(_, _) | Apply(_, _) =>
- atPos(t.pos.start, in.skipToken()) { Assign(t, expr()) }
+ atPos(startOffset(t), in.skipToken()) { Assign(t, expr()) }
case _ =>
t
}
case COLON =>
ascription(t, location)
case MATCH =>
- atPos(t.pos.start, in.skipToken()) {
+ atPos(startOffset(t), in.skipToken()) {
inBraces(Match(t, caseClauses()))
}
case _ =>
t
}
- def ascription(t: Tree, location: Location.Value) = atPos(t.pos.start, in.skipToken()) {
+ def ascription(t: Tree, location: Location.Value) = atPos(startOffset(t), in.skipToken()) {
in.token match {
case USCORE =>
val uscoreStart = in.skipToken()
@@ -1105,7 +1118,7 @@ object Parsers {
val id = termIdent()
val paramExpr =
if (location == Location.InBlock && in.token == COLON)
- atPos(id.pos.start, in.skipToken()) { Typed(id, infixType()) }
+ atPos(startOffset(id), in.skipToken()) { Typed(id, infixType()) }
else
id
closureRest(start, location, convertToParam(paramExpr, mods) :: Nil)
@@ -1194,13 +1207,13 @@ object Parsers {
in.nextToken()
simpleExprRest(selector(t), canApply = true)
case LBRACKET =>
- val tapp = atPos(t.pos.start, in.offset) { TypeApply(t, typeArgs(namedOK = true)) }
+ val tapp = atPos(startOffset(t), in.offset) { TypeApply(t, typeArgs(namedOK = true)) }
simpleExprRest(tapp, canApply = true)
case LPAREN | LBRACE if canApply =>
- val app = atPos(t.pos.start, in.offset) { Apply(t, argumentExprs()) }
+ val app = atPos(startOffset(t), in.offset) { Apply(t, argumentExprs()) }
simpleExprRest(app, canApply = true)
case USCORE =>
- atPos(t.pos.start, in.skipToken()) { PostfixOp(t, nme.WILDCARD) }
+ atPos(startOffset(t), in.skipToken()) { PostfixOp(t, nme.WILDCARD) }
case _ =>
t
}
@@ -1284,7 +1297,7 @@ object Parsers {
if (in.token == IF) guard()
else {
val pat = pattern1()
- if (in.token == EQUALS) atPos(pat.pos.start, in.skipToken()) { GenAlias(pat, expr()) }
+ if (in.token == EQUALS) atPos(startOffset(pat), in.skipToken()) { GenAlias(pat, expr()) }
else generatorRest(pat)
}
@@ -1293,7 +1306,7 @@ object Parsers {
def generator(): Tree = generatorRest(pattern1())
def generatorRest(pat: Tree) =
- atPos(pat.pos.start, accept(LARROW)) { GenFrom(pat, expr()) }
+ atPos(startOffset(pat), accept(LARROW)) { GenFrom(pat, expr()) }
/** ForExpr ::= `for' (`(' Enumerators `)' | `{' Enumerators `}')
* {nl} [`yield'] Expr
@@ -1357,7 +1370,7 @@ object Parsers {
val pattern = () => {
val pat = pattern1()
if (isIdent(nme.raw.BAR))
- atPos(pat.pos.start) { Alternative(pat :: patternAlts()) }
+ atPos(startOffset(pat)) { Alternative(pat :: patternAlts()) }
else pat
}
@@ -1383,15 +1396,15 @@ object Parsers {
// compatibility for Scala2 `x @ _*` syntax
infixPattern() match {
case pt @ Ident(tpnme.WILDCARD_STAR) =>
- migrationWarningOrError("The syntax `x @ _*' is no longer supported; use `x : _*' instead", p.pos.start)
- atPos(p.pos.start, offset) { Typed(p, pt) }
+ migrationWarningOrError("The syntax `x @ _*' is no longer supported; use `x : _*' instead", startOffset(p))
+ atPos(startOffset(p), offset) { Typed(p, pt) }
case p =>
- atPos(p.pos.start, offset) { Bind(name, p) }
+ atPos(startOffset(p), offset) { Bind(name, p) }
}
case p @ Ident(tpnme.WILDCARD_STAR) =>
// compatibility for Scala2 `_*` syntax
- migrationWarningOrError("The syntax `_*' is no longer supported; use `x : _*' instead", p.pos.start)
- atPos(p.pos.start) { Typed(Ident(nme.WILDCARD), p) }
+ migrationWarningOrError("The syntax `_*' is no longer supported; use `x : _*' instead", startOffset(p))
+ atPos(startOffset(p)) { Typed(Ident(nme.WILDCARD), p) }
case p =>
p
}
@@ -1415,7 +1428,7 @@ object Parsers {
val simplePattern = () => in.token match {
case IDENTIFIER | BACKQUOTED_IDENT | THIS =>
path(thisOK = true) match {
- case id @ Ident(nme.raw.MINUS) if isNumericLit => literal(id.pos.start)
+ case id @ Ident(nme.raw.MINUS) if isNumericLit => literal(startOffset(id))
case t => simplePatternRest(t)
}
case USCORE =>
@@ -1435,7 +1448,7 @@ object Parsers {
case XMLSTART =>
xmlLiteralPattern()
case _ =>
- if (isLiteral) literal()
+ if (isLiteral) literal(inPattern = true)
else {
syntaxErrorOrIncomplete(IllegalStartOfSimplePattern())
errorTermTree
@@ -1445,9 +1458,9 @@ object Parsers {
def simplePatternRest(t: Tree): Tree = {
var p = t
if (in.token == LBRACKET)
- p = atPos(t.pos.start, in.offset) { TypeApply(p, typeArgs()) }
+ p = atPos(startOffset(t), in.offset) { TypeApply(p, typeArgs()) }
if (in.token == LPAREN)
- p = atPos(t.pos.start, in.offset) { Apply(p, argumentPatterns()) }
+ p = atPos(startOffset(t), in.offset) { Apply(p, argumentPatterns()) }
p
}
@@ -1573,7 +1586,8 @@ object Parsers {
case Select(qual, name) => cpy.Select(tree)(adjustStart(start)(qual), name)
case _ => tree
}
- if (start < tree1.pos.start) tree1.withPos(tree1.pos.withStart(start))
+ if (tree1.pos.exists && start < tree1.pos.start)
+ tree1.withPos(tree1.pos.withStart(start))
else tree1
}
@@ -1771,7 +1785,7 @@ object Parsers {
case imp: Import =>
imp
case sel @ Select(qual, name) =>
- val selector = atPos(sel.pos.point) { Ident(name) }
+ val selector = atPos(pointOffset(sel)) { Ident(name) }
cpy.Import(sel)(qual, selector :: Nil)
case t =>
accept(DOT)
@@ -1804,7 +1818,7 @@ object Parsers {
def importSelector(): Tree = {
val from = termIdentOrWildcard()
if (from.name != nme.WILDCARD && in.token == ARROW)
- atPos(from.pos.start, in.skipToken()) {
+ atPos(startOffset(from), in.skipToken()) {
Thicket(from, termIdentOrWildcard())
}
else from
@@ -2085,7 +2099,7 @@ object Parsers {
/** Create a tree representing a packaging */
def makePackaging(start: Int, pkg: Tree, stats: List[Tree]): PackageDef = pkg match {
- case x: RefTree => atPos(start, pkg.pos.point)(PackageDef(x, stats))
+ case x: RefTree => atPos(start, pointOffset(pkg))(PackageDef(x, stats))
}
/** Packaging ::= package QualId [nl] `{' TopStatSeq `}'
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/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index 00627fc28..1ddf3cd6d 100644
--- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -614,14 +614,12 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
(sym.allOverriddenSymbols exists (_ is TypeParam))
override def toText(sym: Symbol): Text = {
- if (sym.isImport) {
- def importString(tree: untpd.Tree) = s"import ${tree.show}"
+ if (sym.isImport)
sym.infoOrCompleter match {
- case info: Namer#Completer => return importString(info.original)
- case info: ImportType => return importString(info.expr)
+ case info: Namer#Completer => return info.original.show
+ case info: ImportType => return s"import $info.expr.show"
case _ =>
}
- }
if (sym.is(ModuleClass))
kindString(sym) ~~ (nameString(sym.name.stripModuleClassSuffix) + idString(sym))
else
diff --git a/compiler/src/dotty/tools/dotc/repl/CompilingInterpreter.scala b/compiler/src/dotty/tools/dotc/repl/CompilingInterpreter.scala
index 5b3669d5e..65c64f708 100644
--- a/compiler/src/dotty/tools/dotc/repl/CompilingInterpreter.scala
+++ b/compiler/src/dotty/tools/dotc/repl/CompilingInterpreter.scala
@@ -6,7 +6,7 @@ import java.io.{
File, PrintWriter, PrintStream, StringWriter, Writer, OutputStream,
ByteArrayOutputStream => ByteOutputStream
}
-import java.lang.{Class, ClassLoader}
+import java.lang.{Class, ClassLoader, Thread, System, StringBuffer}
import java.net.{URL, URLClassLoader}
import scala.collection.immutable.ListSet
@@ -443,7 +443,10 @@ class CompilingInterpreter(
}
// the types are all =>T; remove the =>
- val cleanedType = rawType.widenExpr
+ val cleanedType = rawType.widenExpr match {
+ case tp: MethodType => tp.resultType
+ case tp => tp
+ }
map + (name ->
ctx.atPhase(ctx.typerPhase.next) { implicit ctx =>
@@ -680,15 +683,49 @@ class CompilingInterpreter(
code.print(resultExtractors.mkString(""))
}
+ private val ListReg = """^.*List\[(\w+)\]$""".r
+ private val MapReg = """^.*Map\[(\w+),[ ]*(\w+)\]$""".r
+ private val LitReg = """^.*\((.+)\)$""".r
+
private def resultExtractor(req: Request, varName: Name): String = {
val prettyName = varName.decode
- val varType = string2code(req.typeOf(varName))
+ // FIXME: `varType` is prettified to abbreviate common types where
+ // appropriate, and to also prettify literal types
+ //
+ // This should be rewritten to use the actual types once we have a
+ // semantic representation available to the REPL
+ val varType = string2code(req.typeOf(varName)) match {
+ // Extract List's paremeter from full path
+ case ListReg(param) => s"List[$param]"
+ // Extract Map's paremeters from full path
+ case MapReg(k, v) => s"Map[$k, $v]"
+ // Extract literal type from literal type representation. Example:
+ //
+ // ```
+ // scala> val x: 42 = 42
+ // val x: Int(42) = 42
+ // scala> val y: "hello" = "hello"
+ // val y: String("hello") = "hello"
+ // ```
+ case LitReg(lit) => lit
+ // When the type is a singleton value like None, don't show `None$`
+ // instead show `None.type`.
+ case x if x.lastOption == Some('$') => x.init + ".type"
+ case x => x
+ }
val fullPath = req.fullPath(varName)
- s""" + "$prettyName: $varType = " + {
+ val varOrVal = statement match {
+ case v: ValDef if v.mods is Flags.Mutable => "var"
+ case _ => "val"
+ }
+
+ s""" + "$varOrVal $prettyName: $varType = " + {
| if ($fullPath.asInstanceOf[AnyRef] != null) {
- | (if ($fullPath.toString().contains('\\n')) "\\n" else "") +
- | $fullPath.toString() + "\\n"
+ | (if ($fullPath.toString().contains('\\n')) "\\n" else "") + {
+ | import dotty.Show._
+ | $fullPath.show /*toString()*/ + "\\n"
+ | }
| } else {
| "null\\n"
| }
@@ -735,9 +772,30 @@ class CompilingInterpreter(
override def defNames = boundNames
override def resultExtractionCode(req: Request, code: PrintWriter): Unit = {
- if (!defDef.mods.is(Flags.AccessFlags))
- code.print("+\"" + string2code(defDef.name.toString) + ": " +
- string2code(req.typeOf(defDef.name)) + "\\n\"")
+ /** TODO: This is the result of the state of the REPL - this would be
+ * entirely unnecessary with a better structure where we could just
+ * use the type printer
+ *
+ * @see `def findTypes` for an explanation of what should be done
+ */
+ if (!defDef.mods.is(Flags.AccessFlags)) {
+ // Take the DefDef and remove the `rhs` and ascribed type `tpt`
+ val copy = ast.untpd.cpy.DefDef(defDef)(
+ rhs = EmptyTree,
+ tpt = TypeTree
+ )
+
+ val tpt = defDef.tpt match {
+ // ascribed TypeExpr e.g: `def foo: Int = 5`
+ case Ident(tpt) if defDef.vparamss.isEmpty =>
+ ": " + tpt.show
+ case tpt =>
+ ": " + req.typeOf(defDef.name)
+ }
+ code.print {
+ "+\"" + string2code(copy.show) + tpt + "\\n\""
+ }
+ }
}
}
diff --git a/compiler/src/dotty/tools/dotc/repl/InterpreterLoop.scala b/compiler/src/dotty/tools/dotc/repl/InterpreterLoop.scala
index b3ac41c55..cfe8d892d 100644
--- a/compiler/src/dotty/tools/dotc/repl/InterpreterLoop.scala
+++ b/compiler/src/dotty/tools/dotc/repl/InterpreterLoop.scala
@@ -4,7 +4,7 @@ package repl
import java.io.{BufferedReader, File, FileReader, PrintWriter}
import java.io.IOException
-import java.lang.{ClassLoader, System}
+import java.lang.{ClassLoader, System, Thread}
import scala.concurrent.{Future, Await}
import scala.concurrent.duration.Duration
import reporting.Reporter
diff --git a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala
index 8477cfe28..26c1e5ebc 100644
--- a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala
+++ b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala
@@ -286,11 +286,16 @@ abstract class Reporter extends interfaces.ReporterResult {
}
/** Should this diagnostic not be reported at all? */
- def isHidden(m: MessageContainer)(implicit ctx: Context): Boolean = ctx.mode.is(Mode.Printing)
+ def isHidden(m: MessageContainer)(implicit ctx: Context): Boolean =
+ ctx.mode.is(Mode.Printing)
/** Does this reporter contain not yet reported errors or warnings? */
def hasPending: Boolean = false
+ /** If this reporter buffers messages, remove and return all buffered messages. */
+ def removeBufferedMessages(implicit ctx: Context): List[MessageContainer] = Nil
+
/** Issue all error messages in this reporter to next outer one, or make sure they are written. */
- def flush()(implicit ctx: Context): Unit = {}
+ def flush()(implicit ctx: Context): Unit =
+ removeBufferedMessages.foreach(ctx.reporter.report)
}
diff --git a/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala b/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala
index 586273c2e..34b109882 100644
--- a/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala
+++ b/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala
@@ -36,11 +36,9 @@ class StoreReporter(outer: Reporter) extends Reporter {
}
}
- override def flush()(implicit ctx: Context) =
- if (infos != null) {
- infos.foreach(ctx.reporter.report(_))
- infos = null
- }
+ override def removeBufferedMessages(implicit ctx: Context): List[MessageContainer] =
+ if (infos != null) try infos.toList finally infos = null
+ else Nil
override def errorsReported = hasErrors || outer.errorsReported
}
diff --git a/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala b/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala
index 714255962..331fce46a 100644
--- a/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala
+++ b/compiler/src/dotty/tools/dotc/transform/CollectEntryPoints.scala
@@ -9,7 +9,6 @@ import dotty.tools.dotc.core.Symbols.NoSymbol
import scala.annotation.tailrec
import dotty.tools.dotc.core._
import Symbols._
-import scala.Some
import dotty.tools.dotc.transform.TreeTransforms.{NXTransformations, TransformerInfo, TreeTransform, TreeTransformer}
import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Contexts.Context
diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala
index 069176111..5c880c7bd 100644
--- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala
@@ -13,6 +13,7 @@ import core.StdNames._
import core.NameOps._
import core.Decorators._
import core.Constants._
+import core.Definitions._
import typer.NoChecking
import typer.ProtoTypes._
import typer.ErrorReporting._
@@ -36,9 +37,17 @@ class Erasure extends Phase with DenotTransformer { thisTransformer =>
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match {
case ref: SymDenotation =>
+ def isCompacted(sym: Symbol) =
+ sym.isAnonymousFunction && {
+ sym.info(ctx.withPhase(ctx.phase.next)) match {
+ case MethodType(nme.ALLARGS :: Nil, _) => true
+ case _ => false
+ }
+ }
+
assert(ctx.phase == this, s"transforming $ref at ${ctx.phase}")
if (ref.symbol eq defn.ObjectClass) {
- // Aftre erasure, all former Any members are now Object members
+ // After erasure, all former Any members are now Object members
val ClassInfo(pre, _, ps, decls, selfInfo) = ref.info
val extendedScope = decls.cloneScope
for (decl <- defn.AnyClass.classInfo.decls)
@@ -59,7 +68,10 @@ class Erasure extends Phase with DenotTransformer { thisTransformer =>
val oldInfo = ref.info
val newInfo = transformInfo(ref.symbol, oldInfo)
val oldFlags = ref.flags
- val newFlags = ref.flags &~ Flags.HasDefaultParams // HasDefaultParams needs to be dropped because overriding might become overloading
+ val newFlags =
+ if (oldSymbol.is(Flags.TermParam) && isCompacted(oldSymbol.owner)) oldFlags &~ Flags.Param
+ else oldFlags &~ Flags.HasDefaultParams // HasDefaultParams needs to be dropped because overriding might become overloading
+
// TODO: define derivedSymDenotation?
if ((oldSymbol eq newSymbol) && (oldOwner eq newOwner) && (oldInfo eq newInfo) && (oldFlags == newFlags)) ref
else {
@@ -82,7 +94,7 @@ class Erasure extends Phase with DenotTransformer { thisTransformer =>
assertErased(tree)
tree match {
case res: tpd.This =>
- assert(!ExplicitOuter.referencesOuter(ctx.owner.enclosingClass, res),
+ assert(!ExplicitOuter.referencesOuter(ctx.owner.lexicallyEnclosingClass, res),
i"Reference to $res from ${ctx.owner.showLocated}")
case ret: tpd.Return =>
// checked only after erasure, as checking before erasure is complicated
@@ -331,8 +343,23 @@ object Erasure extends TypeTestsCasts{
* e.m -> e.[]m if `m` is an array operation other than `clone`.
*/
override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = {
- val sym = tree.symbol
- assert(sym.exists, tree.show)
+
+ def mapOwner(sym: Symbol): Symbol = {
+ val owner = sym.owner
+ if ((owner eq defn.AnyClass) || (owner eq defn.AnyValClass)) {
+ assert(sym.isConstructor, s"${sym.showLocated}")
+ defn.ObjectClass
+ }
+ else if (defn.isUnimplementedFunctionClass(owner))
+ defn.FunctionXXLClass
+ else
+ owner
+ }
+
+ var sym = tree.symbol
+ val owner = mapOwner(sym)
+ if (owner ne sym.owner) sym = owner.info.decl(sym.name).symbol
+ assert(sym.exists, owner)
def select(qual: Tree, sym: Symbol): Tree = {
val name = tree.typeOpt match {
@@ -366,11 +393,7 @@ object Erasure extends TypeTestsCasts{
def recur(qual: Tree): Tree = {
val qualIsPrimitive = qual.tpe.widen.isPrimitiveValueType
val symIsPrimitive = sym.owner.isPrimitiveValueClass
- if ((sym.owner eq defn.AnyClass) || (sym.owner eq defn.AnyValClass)) {
- assert(sym.isConstructor, s"${sym.showLocated}")
- select(qual, defn.ObjectClass.info.decl(sym.name).symbol)
- }
- else if (qualIsPrimitive && !symIsPrimitive || qual.tpe.widenDealias.isErasedValueType)
+ if (qualIsPrimitive && !symIsPrimitive || qual.tpe.widenDealias.isErasedValueType)
recur(box(qual))
else if (!qualIsPrimitive && symIsPrimitive)
recur(unbox(qual, sym.owner.typeRef))
@@ -389,7 +412,7 @@ object Erasure extends TypeTestsCasts{
}
override def typedThis(tree: untpd.This)(implicit ctx: Context): Tree =
- if (tree.symbol == ctx.owner.enclosingClass || tree.symbol.isStaticOwner) promote(tree)
+ if (tree.symbol == ctx.owner.lexicallyEnclosingClass || tree.symbol.isStaticOwner) promote(tree)
else {
ctx.log(i"computing outer path from ${ctx.owner.ownersIterator.toList}%, % to ${tree.symbol}, encl class = ${ctx.owner.enclosingClass}")
outer.path(tree.symbol)
@@ -423,6 +446,9 @@ object Erasure extends TypeTestsCasts{
}
}
+ /** Besides normal typing, this method collects all arguments
+ * to a compacted function into a single argument of array type.
+ */
override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
val Apply(fun, args) = tree
if (fun.symbol == defn.dummyApply)
@@ -434,7 +460,13 @@ object Erasure extends TypeTestsCasts{
fun1.tpe.widen match {
case mt: MethodType =>
val outers = outer.args(fun.asInstanceOf[tpd.Tree]) // can't use fun1 here because its type is already erased
- val args1 = (outers ::: args ++ protoArgs(pt)).zipWithConserve(mt.paramTypes)(typedExpr)
+ var args0 = outers ::: args ++ protoArgs(pt)
+ if (args0.length > MaxImplementedFunctionArity && mt.paramTypes.length == 1) {
+ val bunchedArgs = untpd.JavaSeqLiteral(args0, TypeTree(defn.ObjectType))
+ .withType(defn.ArrayOf(defn.ObjectType))
+ args0 = bunchedArgs :: Nil
+ }
+ val args1 = args0.zipWithConserve(mt.paramTypes)(typedExpr)
untpd.cpy.Apply(tree)(fun1, args1) withType mt.resultType
case _ =>
throw new MatchError(i"tree $tree has unexpected type of function ${fun1.tpe.widen}, was ${fun.typeOpt.widen}")
@@ -470,18 +502,36 @@ object Erasure extends TypeTestsCasts{
super.typedValDef(untpd.cpy.ValDef(vdef)(
tpt = untpd.TypedSplice(TypeTree(sym.info).withPos(vdef.tpt.pos))), sym)
+ /** Besides normal typing, this function also compacts anonymous functions
+ * with more than `MaxImplementedFunctionArity` parameters to ise a single
+ * parameter of type `[]Object`.
+ */
override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = {
val restpe =
if (sym.isConstructor) defn.UnitType
else sym.info.resultType
+ var vparamss1 = (outer.paramDefs(sym) ::: ddef.vparamss.flatten) :: Nil
+ var rhs1 = ddef.rhs match {
+ case id @ Ident(nme.WILDCARD) => untpd.TypedSplice(id.withType(restpe))
+ case _ => ddef.rhs
+ }
+ if (sym.isAnonymousFunction && vparamss1.head.length > MaxImplementedFunctionArity) {
+ val bunchedParam = ctx.newSymbol(sym, nme.ALLARGS, Flags.TermParam, JavaArrayType(defn.ObjectType))
+ def selector(n: Int) = ref(bunchedParam)
+ .select(defn.Array_apply)
+ .appliedTo(Literal(Constant(n)))
+ val paramDefs = vparamss1.head.zipWithIndex.map {
+ case (paramDef, idx) =>
+ assignType(untpd.cpy.ValDef(paramDef)(rhs = selector(idx)), paramDef.symbol)
+ }
+ vparamss1 = (tpd.ValDef(bunchedParam) :: Nil) :: Nil
+ rhs1 = untpd.Block(paramDefs, rhs1)
+ }
val ddef1 = untpd.cpy.DefDef(ddef)(
tparams = Nil,
- vparamss = (outer.paramDefs(sym) ::: ddef.vparamss.flatten) :: Nil,
+ vparamss = vparamss1,
tpt = untpd.TypedSplice(TypeTree(restpe).withPos(ddef.tpt.pos)),
- rhs = ddef.rhs match {
- case id @ Ident(nme.WILDCARD) => untpd.TypedSplice(id.withType(restpe))
- case _ => ddef.rhs
- })
+ rhs = rhs1)
super.typedDefDef(ddef1, sym)
}
diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
index 3fec47e9f..a32e1c921 100644
--- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
+++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
@@ -330,7 +330,7 @@ object ExplicitOuter {
/** The path of outer accessors that references `toCls.this` starting from
* the context owner's this node.
*/
- def path(toCls: Symbol, start: Tree = This(ctx.owner.enclosingClass.asClass)): Tree = try {
+ def path(toCls: Symbol, start: Tree = This(ctx.owner.lexicallyEnclosingClass.asClass)): Tree = try {
def loop(tree: Tree): Tree = {
val treeCls = tree.tpe.widen.classSymbol
val outerAccessorCtx = ctx.withPhaseNoLater(ctx.lambdaLiftPhase) // lambdalift mangles local class names, which means we cannot reliably find outer acessors anymore
diff --git a/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala b/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala
index 7c60e8d72..21ca8dbfd 100644
--- a/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala
+++ b/compiler/src/dotty/tools/dotc/transform/InterceptedMethods.scala
@@ -96,14 +96,24 @@ class InterceptedMethods extends MiniPhaseTransform {
s"that means the intercepted methods set doesn't match the code")
tree
}
- lazy val Select(qual, _) = tree.fun
+ lazy val qual = tree.fun match {
+ case Select(qual, _) => qual
+ case ident @ Ident(_) =>
+ ident.tpe match {
+ case TermRef(prefix: TermRef, _) =>
+ tpd.ref(prefix)
+ case TermRef(prefix: ThisType, _) =>
+ tpd.This(prefix.cls)
+ }
+
+ }
val Any_## = this.Any_##
val Any_!= = defn.Any_!=
val rewrite: Tree = tree.fun.symbol match {
case Any_## =>
- poundPoundValue(qual)
+ poundPoundValue(qual)
case Any_!= =>
- qual.select(defn.Any_==).appliedToArgs(tree.args).select(defn.Boolean_!)
+ qual.select(defn.Any_==).appliedToArgs(tree.args).select(defn.Boolean_!)
/*
/* else if (isPrimitiveValueClass(qual.tpe.typeSymbol)) {
// todo: this is needed to support value classes
@@ -121,7 +131,7 @@ class InterceptedMethods extends MiniPhaseTransform {
// we get a primitive form of _getClass trying to target a boxed value
// so we need replace that method name with Object_getClass to get correct behavior.
// See SI-5568.
- qual.selectWithSig(defn.Any_getClass).appliedToNone
+ qual.selectWithSig(defn.Any_getClass).appliedToNone
case _ =>
tree
}
diff --git a/compiler/src/dotty/tools/dotc/transform/Memoize.scala b/compiler/src/dotty/tools/dotc/transform/Memoize.scala
index 01c240e3a..0314d4ec4 100644
--- a/compiler/src/dotty/tools/dotc/transform/Memoize.scala
+++ b/compiler/src/dotty/tools/dotc/transform/Memoize.scala
@@ -47,7 +47,9 @@ import Decorators._
}
tree match {
case ddef: DefDef
- if !ddef.symbol.is(Deferred) && ddef.rhs == EmptyTree =>
+ if !ddef.symbol.is(Deferred) &&
+ !ddef.symbol.isConstructor && // constructors bodies are added later at phase Constructors
+ ddef.rhs == EmptyTree =>
errorLackImplementation(ddef)
case tdef: TypeDef
if tdef.symbol.isClass && !tdef.symbol.is(Deferred) && tdef.rhs == EmptyTree =>
@@ -89,10 +91,10 @@ import Decorators._
}
lazy val field = sym.field.orElse(newField).asTerm
-
+
def adaptToField(tree: Tree) =
if (tree.isEmpty) tree else tree.ensureConforms(field.info.widen)
-
+
if (sym.is(Accessor, butNot = NoFieldNeeded))
if (sym.isGetter) {
def skipBlocks(t: Tree): Tree = t match {
diff --git a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala
index 9571c387b..a72e10681 100644
--- a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala
+++ b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala
@@ -55,7 +55,9 @@ class ParamForwarding(thisTransformer: DenotTransformer) {
stat match {
case stat: ValDef =>
val sym = stat.symbol.asTerm
- if (sym is (ParamAccessor, butNot = Mutable)) {
+ if (sym.is(ParamAccessor, butNot = Mutable) && !sym.info.isInstanceOf[ExprType]) {
+ // ElimByName gets confused with methods returning an ExprType,
+ // so avoid param forwarding if parameter is by name. See i1766.scala
val idx = superArgs.indexWhere(_.symbol == sym)
if (idx >= 0 && superParamNames(idx) == stat.name) { // supercall to like-named parameter
val alias = inheritedAccessor(sym)
diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala
index 6c398cd72..11121e1f3 100644
--- a/compiler/src/dotty/tools/dotc/typer/Applications.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala
@@ -250,8 +250,37 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
/** Splice new method reference into existing application */
def spliceMeth(meth: Tree, app: Tree): Tree = app match {
- case Apply(fn, args) => Apply(spliceMeth(meth, fn), args)
- case TypeApply(fn, targs) => TypeApply(spliceMeth(meth, fn), targs)
+ case Apply(fn, args) =>
+ spliceMeth(meth, fn).appliedToArgs(args)
+ case TypeApply(fn, targs) =>
+ // Note: It is important that the type arguments `targs` are passed in new trees
+ // instead of being spliced in literally. Otherwise, a type argument to a default
+ // method could be constructed as the definition site of the type variable for
+ // that default constructor. This would interpolate type variables too early,
+ // causing lots of tests (among them tasty_unpickleScala2) to fail.
+ //
+ // The test case is in i1757.scala. Here we have a variable `s` and a method `cpy`
+ // defined like this:
+ //
+ // var s
+ // def cpy[X](b: List[Int] = b): B[X] = new B[X](b)
+ //
+ // The call `s.cpy()` then gets expanded to
+ //
+ // { val $1$: B[Int] = this.s
+ // $1$.cpy[X']($1$.cpy$default$1[X']
+ // }
+ //
+ // A type variable gets interpolated if it does not appear in the type
+ // of the current tree and the current tree contains the variable's "definition".
+ // Previously, the polymorphic function tree to which the variable was first added
+ // was taken as the variable's definition. But that fails here because that
+ // tree was `s.cpy` but got transformed into `$1$.cpy`. We now take the type argument
+ // [X'] of the variable as its definition tree, which is more robust. But then
+ // it's crucial that the type tree is not copied directly as argument to
+ // `cpy$default$1`. If it was, the variable `X'` would already be interpolated
+ // when typing the default argument, which is too early.
+ spliceMeth(meth, fn).appliedToTypes(targs.tpes)
case _ => meth
}
@@ -333,7 +362,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
val getter = findDefaultGetter(n + numArgs(normalizedFun))
if (getter.isEmpty) missingArg(n)
else {
- addTyped(treeToArg(spliceMeth(getter withPos appPos, normalizedFun)), formal)
+ addTyped(treeToArg(spliceMeth(getter withPos normalizedFun.pos, normalizedFun)), formal)
matchArgs(args1, formals1, n + 1)
}
}
diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala
index 5e1d8622a..f5f7bdbaa 100644
--- a/compiler/src/dotty/tools/dotc/typer/Checking.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala
@@ -456,7 +456,7 @@ trait Checking {
/** Check that Java statics and packages can only be used in selections.
*/
def checkValue(tree: Tree, proto: Type)(implicit ctx: Context): tree.type = {
- if (!proto.isInstanceOf[SelectionProto]) {
+ if (!proto.isInstanceOf[SelectionProto] && !proto.isInstanceOf[ApplyingProto]) {
val sym = tree.tpe.termSymbol
// The check is avoided inside Java compilation units because it always fails
// on the singleton type Module.type.
diff --git a/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala b/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala
index c444631ae..cd374e32c 100644
--- a/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala
+++ b/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala
@@ -44,6 +44,12 @@ class FrontEnd extends Phase {
typr.println("entered: " + unit.source)
}
+ def enterAnnotations(implicit ctx: Context) = monitor("annotating") {
+ val unit = ctx.compilationUnit
+ ctx.typer.annotate(unit.untpdTree :: Nil)
+ typr.println("annotated: " + unit.source)
+ }
+
def typeCheck(implicit ctx: Context) = monitor("typechecking") {
val unit = ctx.compilationUnit
unit.tpdTree = ctx.typer.typedExpr(unit.untpdTree)
@@ -69,8 +75,9 @@ class FrontEnd extends Phase {
}
unitContexts foreach (parse(_))
record("parsedTrees", ast.Trees.ntrees)
- unitContexts foreach (enterSyms(_))
- unitContexts foreach (typeCheck(_))
+ unitContexts.foreach(enterSyms(_))
+ unitContexts.foreach(enterAnnotations(_))
+ unitContexts.foreach(typeCheck(_))
record("total trees after typer", ast.Trees.ntrees)
unitContexts.map(_.compilationUnit).filterNot(discardAfterTyper)
}
diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala
index f3dceea71..1a9a8f64c 100644
--- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala
@@ -24,6 +24,7 @@ import Constants._
import Applications._
import ProtoTypes._
import ErrorReporting._
+import reporting.diagnostic.MessageContainer
import Inferencing.fullyDefinedType
import Trees._
import Hashable._
@@ -212,6 +213,8 @@ object Implicits {
/** A "no matching implicit found" failure */
case object NoImplicitMatches extends SearchFailure
+ case object DivergingImplicit extends SearchFailure
+
/** A search failure that can show information about the cause */
abstract class ExplainedSearchFailure extends SearchFailure {
protected def pt: Type
@@ -233,9 +236,35 @@ object Implicits {
"\n " + explanation
}
- class NonMatchingImplicit(ref: TermRef, val pt: Type, val argument: tpd.Tree) extends ExplainedSearchFailure {
- def explanation(implicit ctx: Context): String =
- em"${err.refStr(ref)} does not $qualify"
+ class NonMatchingImplicit(ref: TermRef,
+ val pt: Type,
+ val argument: tpd.Tree,
+ trail: List[MessageContainer]) extends ExplainedSearchFailure {
+ private val separator = "\n**** because ****\n"
+
+ /** Replace repeated parts beginning with `separator` by ... */
+ private def elideRepeated(str: String): String = {
+ val startIdx = str.indexOfSlice(separator)
+ val nextIdx = str.indexOfSlice(separator, startIdx + separator.length)
+ if (nextIdx < 0) str
+ else {
+ val prefix = str.take(startIdx)
+ val first = str.slice(startIdx, nextIdx)
+ var rest = str.drop(nextIdx)
+ if (rest.startsWith(first)) {
+ rest = rest.drop(first.length)
+ val dots = "\n\n ...\n"
+ if (!rest.startsWith(dots)) rest = dots ++ rest
+ }
+ prefix ++ first ++ rest
+ }
+ }
+
+ def explanation(implicit ctx: Context): String = {
+ val headMsg = em"${err.refStr(ref)} does not $qualify"
+ val trailMsg = trail.map(mc => i"$separator ${mc.message}").mkString
+ elideRepeated(headMsg ++ trailMsg)
+ }
}
class ShadowedImplicit(ref: TermRef, shadowing: Type, val pt: Type, val argument: tpd.Tree) extends ExplainedSearchFailure {
@@ -273,9 +302,10 @@ trait ImplicitRunInfo { self: RunInfo =>
* a type variable, we need the current context, the current
* runinfo context does not do.
*/
- def implicitScope(tp: Type, liftingCtx: Context): OfTypeImplicits = {
+ def implicitScope(rootTp: Type, liftingCtx: Context): OfTypeImplicits = {
val seen: mutable.Set[Type] = mutable.Set()
+ val incomplete: mutable.Set[Type] = mutable.Set()
/** Replace every typeref that does not refer to a class by a conjunction of class types
* that has the same implicit scope as the original typeref. The motivation for applying
@@ -309,16 +339,23 @@ trait ImplicitRunInfo { self: RunInfo =>
}
}
- def iscopeRefs(tp: Type): TermRefSet =
- if (seen contains tp) EmptyTermRefSet
- else {
- seen += tp
- iscope(tp).companionRefs
- }
-
// todo: compute implicits directly, without going via companionRefs?
def collectCompanions(tp: Type): TermRefSet = track("computeImplicitScope") {
ctx.traceIndented(i"collectCompanions($tp)", implicits) {
+
+ def iscopeRefs(t: Type): TermRefSet = implicitScopeCache.get(t) match {
+ case Some(is) =>
+ is.companionRefs
+ case None =>
+ if (seen contains t) {
+ incomplete += tp // all references to rootTo will be accounted for in `seen` so we return `EmptySet`.
+ EmptyTermRefSet // on the other hand, the refs of `tp` are now not accurate, so `tp` is marked incomplete.
+ } else {
+ seen += t
+ iscope(t).companionRefs
+ }
+ }
+
val comps = new TermRefSet
tp match {
case tp: NamedType =>
@@ -356,7 +393,8 @@ trait ImplicitRunInfo { self: RunInfo =>
* @param isLifted Type `tp` is the result of a `liftToClasses` application
*/
def iscope(tp: Type, isLifted: Boolean = false): OfTypeImplicits = {
- def computeIScope(cacheResult: Boolean) = {
+ val canCache = Config.cacheImplicitScopes && tp.hash != NotCached
+ def computeIScope() = {
val savedEphemeral = ctx.typerState.ephemeral
ctx.typerState.ephemeral = false
try {
@@ -367,33 +405,23 @@ trait ImplicitRunInfo { self: RunInfo =>
else
collectCompanions(tp)
val result = new OfTypeImplicits(tp, refs)(ctx)
- if (ctx.typerState.ephemeral) record("ephemeral cache miss: implicitScope")
- else if (cacheResult) implicitScopeCache(tp) = result
+ if (ctx.typerState.ephemeral)
+ record("ephemeral cache miss: implicitScope")
+ else if (canCache &&
+ ((tp eq rootTp) || // first type traversed is always cached
+ !incomplete.contains(tp) && // other types are cached if they are not incomplete
+ result.companionRefs.forall( // and all their companion refs are cached
+ implicitScopeCache.contains)))
+ implicitScopeCache(tp) = result
result
}
finally ctx.typerState.ephemeral |= savedEphemeral
}
-
- if (tp.hash == NotCached || !Config.cacheImplicitScopes)
- computeIScope(cacheResult = false)
- else implicitScopeCache get tp match {
- case Some(is) => is
- case None =>
- // Implicit scopes are tricky to cache because of loops. For example
- // in `tests/pos/implicit-scope-loop.scala`, the scope of B contains
- // the scope of A which contains the scope of B. We break the loop
- // by returning EmptyTermRefSet in `collectCompanions` for types
- // that we have already seen, but this means that we cannot cache
- // the computed scope of A, it is incomplete.
- // Keeping track of exactly where these loops happen would require a
- // lot of book-keeping, instead we choose to be conservative and only
- // cache scopes before any type has been seen. This is unfortunate
- // because loops are very common for types in scala.collection.
- computeIScope(cacheResult = seen.isEmpty)
- }
+ if (canCache) implicitScopeCache.getOrElse(tp, computeIScope())
+ else computeIScope()
}
- iscope(tp)
+ iscope(rootTp)
}
/** A map that counts the number of times an implicit ref was picked */
@@ -587,7 +615,7 @@ trait Implicits { self: Typer =>
val wildProto = implicitProto(pt, wildApprox(_))
/** Search failures; overridden in ExplainedImplicitSearch */
- protected def nonMatchingImplicit(ref: TermRef): SearchFailure = NoImplicitMatches
+ protected def nonMatchingImplicit(ref: TermRef, trail: List[MessageContainer]): SearchFailure = NoImplicitMatches
protected def divergingImplicit(ref: TermRef): SearchFailure = NoImplicitMatches
protected def shadowedImplicit(ref: TermRef, shadowing: Type): SearchFailure = NoImplicitMatches
protected def failedSearch: SearchFailure = NoImplicitMatches
@@ -628,7 +656,7 @@ trait Implicits { self: Typer =>
{ implicits.println(i"invalid eqAny[$tp1, $tp2]"); false }
}
if (ctx.reporter.hasErrors)
- nonMatchingImplicit(ref)
+ nonMatchingImplicit(ref, ctx.reporter.removeBufferedMessages)
else if (contextual && !ctx.mode.is(Mode.ImplicitShadowing) &&
!shadowing.tpe.isError && !refMatches(shadowing)) {
implicits.println(i"SHADOWING $ref in ${ref.termSymbol.owner} is shadowed by $shadowing in ${shadowing.symbol.owner}")
@@ -637,7 +665,7 @@ trait Implicits { self: Typer =>
else generated1 match {
case TypeApply(fn, targs @ (arg1 :: arg2 :: Nil))
if fn.symbol == defn.Predef_eqAny && !validEqAnyArgs(arg1.tpe, arg2.tpe) =>
- nonMatchingImplicit(ref)
+ nonMatchingImplicit(ref, Nil)
case _ =>
SearchSuccess(generated1, ref, ctx.typerState)
}
@@ -743,8 +771,8 @@ trait Implicits { self: Typer =>
fail
}
def failures = myFailures.toList
- override def nonMatchingImplicit(ref: TermRef) =
- record(new NonMatchingImplicit(ref, pt, argument))
+ override def nonMatchingImplicit(ref: TermRef, trail: List[MessageContainer]) =
+ record(new NonMatchingImplicit(ref, pt, argument, trail))
override def divergingImplicit(ref: TermRef) =
record(new DivergingImplicit(ref, pt, argument))
override def shadowedImplicit(ref: TermRef, shadowing: Type): SearchFailure =
diff --git a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala
index 3aa289181..b4ec3390e 100644
--- a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala
+++ b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala
@@ -95,14 +95,22 @@ class ImportInfo(symf: => Symbol, val selectors: List[untpd.Tree], val isRootImp
/** The root import symbol hidden by this symbol, or NoSymbol if no such symbol is hidden.
* Note: this computation needs to work even for un-initialized import infos, and
* is not allowed to force initialization.
+ *
+ * TODO: Once we have fully bootstrapped, I would prefer if we expressed
+ * unimport with an `override` modifier, and generalized it to all imports.
+ * I believe this would be more transparent than the curren set of conditions. E.g.
+ *
+ * override import Predef.{any2stringAdd => _, StringAdd => _, _} // disables String +
+ * override import java.lang.{} // disables all imports
*/
- lazy val hiddenRoot: Symbol = {
- val sym = site.termSymbol
- def hasMaskingSelector = selectors exists {
+ lazy val unimported: Symbol = {
+ lazy val sym = site.termSymbol
+ val hasMaskingSelector = selectors exists {
case Thicket(_ :: Ident(nme.WILDCARD) :: Nil) => true
case _ => false
}
- if ((defn.RootImportTypes exists (_.symbol == sym)) && hasMaskingSelector) sym else NoSymbol
+ if (hasMaskingSelector && defn.RootImportTypes.exists(_.symbol == sym)) sym
+ else NoSymbol
}
override def toString = {
diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala
index aede4974a..1cb86dd72 100644
--- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -216,10 +216,10 @@ object Inferencing {
def interpolateUndetVars(tree: Tree, ownedBy: Symbol)(implicit ctx: Context): Unit = {
val constraint = ctx.typerState.constraint
val qualifies = (tvar: TypeVar) =>
- (tree contains tvar.owningTree) || ownedBy.exists && tvar.owner == ownedBy
+ (tree contains tvar.bindingTree) || ownedBy.exists && tvar.owner == ownedBy
def interpolate() = Stats.track("interpolateUndetVars") {
val tp = tree.tpe.widen
- constr.println(s"interpolate undet vars in ${tp.show}, pos = ${tree.pos}, mode = ${ctx.mode}, undets = ${constraint.uninstVars map (tvar => s"${tvar.show}@${tvar.owningTree.pos}")}")
+ constr.println(s"interpolate undet vars in ${tp.show}, pos = ${tree.pos}, mode = ${ctx.mode}, undets = ${constraint.uninstVars map (tvar => s"${tvar.show}@${tvar.bindingTree.pos}")}")
constr.println(s"qualifying undet vars: ${constraint.uninstVars filter qualifies map (tvar => s"$tvar / ${tvar.show}")}, constraint: ${constraint.show}")
val vs = variances(tp, qualifies)
diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala
index 148cf1da7..b8fe46745 100644
--- a/compiler/src/dotty/tools/dotc/typer/Namer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala
@@ -528,18 +528,96 @@ class Namer { typer: Typer =>
}
}
- stats foreach expand
+ stats.foreach(expand)
mergeCompanionDefs()
val ctxWithStats = (ctx /: stats) ((ctx, stat) => indexExpanded(stat)(ctx))
createCompanionLinks(ctxWithStats)
ctxWithStats
}
+ /** Add all annotations of definitions in `stats` to the defined symbols */
+ def annotate(stats: List[Tree])(implicit ctx: Context): Unit = {
+ def recur(stat: Tree): Unit = stat match {
+ case pcl: PackageDef =>
+ annotate(pcl.stats)
+ case stat: untpd.MemberDef =>
+ stat.getAttachment(SymOfTree) match {
+ case Some(sym) =>
+ sym.infoOrCompleter match {
+ case info: Completer if !defn.isPredefClass(sym.owner) =>
+ // Annotate Predef methods only when they are completed;
+ // This is necessary to break a cyclic dependence between `Predef`
+ // and `deprecated` in test `compileStdLib`.
+ addAnnotations(sym, stat)(info.creationContext)
+ case _ =>
+ // Annotations were already added as part of the symbol's completion
+ }
+ case none =>
+ assert(stat.typeOpt.exists, i"no symbol for $stat")
+ }
+ case stat: untpd.Thicket =>
+ stat.trees.foreach(recur)
+ case _ =>
+ }
+
+ for (stat <- stats) recur(expanded(stat))
+ }
+
+ /** Add annotations of `stat` to `sym`.
+ * This method can be called twice on a symbol (e.g. once
+ * during the `annotate` phase and then again during completion).
+ * Therefore, care needs to be taken not to add annotations again
+ * that are already added to the symbol.
+ */
+ def addAnnotations(sym: Symbol, stat: MemberDef)(implicit ctx: Context) = {
+ // (1) The context in which an annotation of a top-level class or module is evaluated
+ // is the closest enclosing context which has the enclosing package as owner.
+ // (2) The context in which an annotation for any other symbol is evaluated is the
+ // closest enclosing context which has the owner of the class enclosing the symbol as owner.
+ // E.g in
+ //
+ // package p
+ // import a.b
+ // class C {
+ // import d.e
+ // @ann m() ...
+ // }
+ //
+ // `@ann` is evaluated in the context just outside `C`, where the `a.b`
+ // import is visible but the `d.e` import is forgotten. This measure is necessary
+ // in order to avoid cycles.
+ lazy val annotCtx = {
+ var target = sym.owner.lexicallyEnclosingClass
+ if (!target.is(PackageClass)) target = target.owner
+ var c = ctx
+ while (c.owner != target) c = c.outer
+ c
+ }
+ for (annotTree <- untpd.modsDeco(stat).mods.annotations) {
+ val cls = typedAheadAnnotation(annotTree)(annotCtx)
+ if (sym.unforcedAnnotation(cls).isEmpty) {
+ val ann = Annotation.deferred(cls, implicit ctx => typedAnnotation(annotTree))
+ sym.addAnnotation(ann)
+ if (cls == defn.InlineAnnot && sym.is(Method, butNot = Accessor))
+ sym.setFlag(Inline)
+ }
+ }
+ }
+
+ def indexAndAnnotate(stats: List[Tree])(implicit ctx: Context): Context = {
+ val localCtx = index(stats)
+ annotate(stats)
+ localCtx
+ }
+
/** The completer of a symbol defined by a member def or import (except ClassSymbols) */
class Completer(val original: Tree)(implicit ctx: Context) extends LazyType {
protected def localContext(owner: Symbol) = ctx.fresh.setOwner(owner).setTree(original)
+ /** The context with which this completer was created */
+ def creationContext = ctx
+
protected def typeSig(sym: Symbol): Type = original match {
case original: ValDef =>
if (sym is Module) moduleValSig(sym)
@@ -572,19 +650,6 @@ class Namer { typer: Typer =>
completeInCreationContext(denot)
}
- protected def addAnnotations(denot: SymDenotation): Unit = original match {
- case original: untpd.MemberDef =>
- var hasInlineAnnot = false
- for (annotTree <- untpd.modsDeco(original).mods.annotations) {
- val cls = typedAheadAnnotation(annotTree)
- val ann = Annotation.deferred(cls, implicit ctx => typedAnnotation(annotTree))
- denot.addAnnotation(ann)
- if (cls == defn.InlineAnnot && denot.is(Method, butNot = Accessor))
- denot.setFlag(Inline)
- }
- case _ =>
- }
-
private def addInlineInfo(denot: SymDenotation) = original match {
case original: untpd.DefDef if denot.isInlineMethod =>
Inliner.registerInlineInfo(
@@ -598,7 +663,10 @@ class Namer { typer: Typer =>
* to pick up the context at the point where the completer was created.
*/
def completeInCreationContext(denot: SymDenotation): Unit = {
- addAnnotations(denot)
+ original match {
+ case original: MemberDef => addAnnotations(denot.symbol, original)
+ case _ =>
+ }
addInlineInfo(denot)
denot.info = typeSig(denot.symbol)
Checking.checkWellFormed(denot.symbol)
@@ -742,7 +810,7 @@ class Namer { typer: Typer =>
ok
}
- addAnnotations(denot)
+ addAnnotations(denot.symbol, original)
val selfInfo =
if (self.isEmpty) NoType
@@ -765,9 +833,10 @@ class Namer { typer: Typer =>
// accessors, that's why the constructor needs to be completed before
// the parent types are elaborated.
index(constr)
+ annotate(constr :: params)
symbolOfTree(constr).ensureCompleted()
- index(rest)(inClassContext(selfInfo))
+ indexAndAnnotate(rest)(inClassContext(selfInfo))
val tparamAccessors = decls.filter(_ is TypeParamAccessor).toList
val parentTypes = ensureFirstIsClass(parents.map(checkedParentType(_, tparamAccessors)))
@@ -790,7 +859,7 @@ class Namer { typer: Typer =>
case Some(ttree) => ttree
case none =>
val ttree = typer.typed(tree, pt)
- xtree.pushAttachment(TypedAhead, ttree)
+ xtree.putAttachment(TypedAhead, ttree)
ttree
}
}
@@ -810,7 +879,7 @@ class Namer { typer: Typer =>
/** Enter and typecheck parameter list */
def completeParams(params: List[MemberDef])(implicit ctx: Context) = {
- index(params)
+ indexAndAnnotate(params)
for (param <- params) typedAheadExpr(param)
}
@@ -990,7 +1059,7 @@ class Namer { typer: Typer =>
// 3. Info of CP is computed (to be copied to DP).
// 4. CP is completed.
// 5. Info of CP is copied to DP and DP is completed.
- index(tparams)
+ indexAndAnnotate(tparams)
if (isConstructor) sym.owner.typeParams.foreach(_.ensureCompleted())
for (tparam <- tparams) typedAheadExpr(tparam)
diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
index 9a20a452e..ed6b95c3b 100644
--- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
+++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
@@ -353,20 +353,23 @@ object ProtoTypes {
* Also, if `owningTree` is non-empty, add a type variable for each parameter.
* @return The added polytype, and the list of created type variables.
*/
- def constrained(pt: PolyType, owningTree: untpd.Tree)(implicit ctx: Context): (PolyType, List[TypeVar]) = {
+ def constrained(pt: PolyType, owningTree: untpd.Tree)(implicit ctx: Context): (PolyType, List[TypeTree]) = {
val state = ctx.typerState
assert(!(ctx.typerState.isCommittable && owningTree.isEmpty),
s"inconsistent: no typevars were added to committable constraint ${state.constraint}")
- def newTypeVars(pt: PolyType): List[TypeVar] =
+ def newTypeVars(pt: PolyType): List[TypeTree] =
for (n <- (0 until pt.paramNames.length).toList)
- yield new TypeVar(PolyParam(pt, n), state, owningTree, ctx.owner)
+ yield {
+ val tt = new TypeTree().withPos(owningTree.pos)
+ tt.withType(new TypeVar(PolyParam(pt, n), state, tt, ctx.owner))
+ }
val added =
if (state.constraint contains pt) pt.newLikeThis(pt.paramNames, pt.paramBounds, pt.resultType)
else pt
val tvars = if (owningTree.isEmpty) Nil else newTypeVars(added)
- ctx.typeComparer.addToConstraint(added, tvars)
+ ctx.typeComparer.addToConstraint(added, tvars.tpes.asInstanceOf[List[TypeVar]])
(added, tvars)
}
diff --git a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala
index 2413c0c22..3252ead47 100644
--- a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala
+++ b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala
@@ -72,9 +72,10 @@ class ReTyper extends Typer {
override def localTyper(sym: Symbol) = this
override def index(trees: List[untpd.Tree])(implicit ctx: Context) = ctx
+ override def annotate(trees: List[untpd.Tree])(implicit ctx: Context) = ()
- override def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: (Tree, TyperState) => Tree)(implicit ctx: Context): Tree =
- fallBack(tree, ctx.typerState)
+ override def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: => Tree)(implicit ctx: Context): Tree =
+ fallBack
override def completeAnnotations(mdef: untpd.MemberDef, sym: Symbol)(implicit ctx: Context): Unit = ()
diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala
index bc335299b..78c479433 100644
--- a/compiler/src/dotty/tools/dotc/typer/Typer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala
@@ -27,7 +27,7 @@ import EtaExpansion.etaExpand
import dotty.tools.dotc.transform.Erasure.Boxing
import util.Positions._
import util.common._
-import util.SourcePosition
+import util.{SourcePosition, Property}
import collection.mutable
import annotation.tailrec
import Implicits._
@@ -57,6 +57,8 @@ object Typer {
def assertPositioned(tree: untpd.Tree)(implicit ctx: Context) =
if (!tree.isEmpty && !tree.isInstanceOf[untpd.TypedSplice] && ctx.typerState.isGlobalCommittable)
assert(tree.pos.exists, s"position not set for $tree # ${tree.uniqueId}")
+
+ private val ExprOwner = new Property.Key[Symbol]
}
class Typer extends Namer with TypeAssigner with Applications with Implicits with Dynamic with Checking with Docstrings {
@@ -74,7 +76,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
* Note: It would be more proper to move importedFromRoot into typedIdent.
* We should check that this has no performance degradation, however.
*/
- private var importedFromRoot: Set[Symbol] = Set()
+ private var unimported: Set[Symbol] = Set()
/** Temporary data item for single call to typed ident:
* This symbol would be found under Scala2 mode, but is not
@@ -102,15 +104,6 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
*/
def error(msg: => Message, pos: Position) = ctx.error(msg, pos)
- /** Is this import a root import that has been shadowed by an explicit
- * import in the same program?
- */
- def isDisabled(imp: ImportInfo, site: Type): Boolean = {
- if (imp.isRootImport && (importedFromRoot contains site.termSymbol)) return true
- if (imp.hiddenRoot.exists) importedFromRoot += imp.hiddenRoot
- false
- }
-
/** Does this identifier appear as a constructor of a pattern? */
def isPatternConstr =
if (ctx.mode.isExpr && (ctx.outer.mode is Mode.Pattern))
@@ -188,32 +181,44 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
/** The type representing a named import with enclosing name when imported
* from given `site` and `selectors`.
*/
- def namedImportRef(site: Type, selectors: List[untpd.Tree])(implicit ctx: Context): Type = {
- def checkUnambiguous(found: Type) = {
- val other = namedImportRef(site, selectors.tail)
- if (other.exists && found.exists && (found != other))
- error(em"reference to `$name` is ambiguous; it is imported twice in ${ctx.tree}",
- tree.pos)
- found
- }
+ def namedImportRef(imp: ImportInfo)(implicit ctx: Context): Type = {
val Name = name.toTermName.decode
- selectors match {
+ def recur(selectors: List[untpd.Tree]): Type = selectors match {
case selector :: rest =>
+ def checkUnambiguous(found: Type) = {
+ val other = recur(selectors.tail)
+ if (other.exists && found.exists && (found != other))
+ error(em"reference to `$name` is ambiguous; it is imported twice in ${ctx.tree}",
+ tree.pos)
+ found
+ }
+
+ def selection(name: Name) =
+ if (imp.sym.isCompleting) {
+ ctx.warning(i"cyclic ${imp.sym}, ignored", tree.pos)
+ NoType
+ }
+ else if (unimported.nonEmpty && unimported.contains(imp.site.termSymbol))
+ NoType
+ else {
+ // Pass refctx so that any errors are reported in the context of the
+ // reference instead of the
+ checkUnambiguous(selectionType(imp.site, name, tree.pos)(refctx))
+ }
+
selector match {
case Thicket(fromId :: Ident(Name) :: _) =>
val Ident(from) = fromId
- val selName = if (name.isTypeName) from.toTypeName else from
- // Pass refctx so that any errors are reported in the context of the
- // reference instead of the context of the import.
- checkUnambiguous(selectionType(site, selName, tree.pos)(refctx))
+ selection(if (name.isTypeName) from.toTypeName else from)
case Ident(Name) =>
- checkUnambiguous(selectionType(site, name, tree.pos)(refctx))
+ selection(name)
case _ =>
- namedImportRef(site, rest)
+ recur(rest)
}
case nil =>
NoType
}
+ recur(imp.selectors)
}
/** The type representing a wildcard import with enclosing name when imported
@@ -222,7 +227,9 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def wildImportRef(imp: ImportInfo)(implicit ctx: Context): Type = {
if (imp.isWildcardImport) {
val pre = imp.site
- if (!isDisabled(imp, pre) && !(imp.excluded contains name.toTermName) && name != nme.CONSTRUCTOR) {
+ if (!unimported.contains(pre.termSymbol) &&
+ !imp.excluded.contains(name.toTermName) &&
+ name != nme.CONSTRUCTOR) {
val denot = pre.member(name).accessibleFrom(pre)(refctx)
if (reallyExists(denot)) return pre.select(name, denot)
}
@@ -279,19 +286,27 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
if (result.exists) result
else { // find import
val curImport = ctx.importInfo
+ def updateUnimported() =
+ if (curImport.unimported.exists) unimported += curImport.unimported
if (ctx.owner.is(Package) && curImport != null && curImport.isRootImport && previous.exists)
previous // no more conflicts possible in this case
- else if (isPossibleImport(namedImport) && (curImport ne outer.importInfo) && !curImport.sym.isCompleting) {
- val namedImp = namedImportRef(curImport.site, curImport.selectors)
+ else if (isPossibleImport(namedImport) && (curImport ne outer.importInfo)) {
+ val namedImp = namedImportRef(curImport)
if (namedImp.exists)
findRef(checkNewOrShadowed(namedImp, namedImport), namedImport, ctx)(outer)
- else if (isPossibleImport(wildImport)) {
+ else if (isPossibleImport(wildImport) && !curImport.sym.isCompleting) {
val wildImp = wildImportRef(curImport)
if (wildImp.exists)
findRef(checkNewOrShadowed(wildImp, wildImport), wildImport, ctx)(outer)
- else loop(outer)
+ else {
+ updateUnimported()
+ loop(outer)
+ }
+ }
+ else {
+ updateUnimported()
+ loop(outer)
}
- else loop(outer)
}
else loop(outer)
}
@@ -311,11 +326,10 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
return typed(desugar.patternVar(tree), pt)
}
-
val rawType = {
- val saved1 = importedFromRoot
+ val saved1 = unimported
val saved2 = foundUnderScala2
- importedFromRoot = Set.empty
+ unimported = Set.empty
foundUnderScala2 = NoType
try {
var found = findRef(NoType, BindingPrec.nothingBound, NoContext)
@@ -329,7 +343,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
found
}
finally {
- importedFromRoot = saved1
+ unimported = saved1
foundUnderScala2 = saved2
}
}
@@ -576,7 +590,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
def typedBlockStats(stats: List[untpd.Tree])(implicit ctx: Context): (Context, List[tpd.Tree]) =
- (index(stats), typedStats(stats, ctx.owner))
+ (indexAndAnnotate(stats), typedStats(stats, ctx.owner))
def typedBlock(tree: untpd.Block, pt: Type)(implicit ctx: Context) = track("typedBlock") {
val (exprCtx, stats1) = typedBlockStats(tree.stats)
@@ -1058,7 +1072,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def typedPolyTypeTree(tree: untpd.PolyTypeTree)(implicit ctx: Context): Tree = track("typedPolyTypeTree") {
val PolyTypeTree(tparams, body) = tree
- index(tparams)
+ indexAndAnnotate(tparams)
val tparams1 = tparams.mapconserve(typed(_).asInstanceOf[TypeDef])
val body1 = typedType(tree.body)
assignType(cpy.PolyTypeTree(tree)(tparams1, body1), tparams1, body1)
@@ -1121,7 +1135,17 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def completeAnnotations(mdef: untpd.MemberDef, sym: Symbol)(implicit ctx: Context): Unit = {
// necessary to force annotation trees to be computed.
sym.annotations.foreach(_.ensureCompleted)
- val annotCtx = ctx.outersIterator.dropWhile(_.owner == sym).next
+ lazy val annotCtx = {
+ val c = ctx.outersIterator.dropWhile(_.owner == sym).next
+ c.property(ExprOwner) match {
+ case Some(exprOwner) if c.owner.isClass =>
+ // We need to evaluate annotation arguments in an expression context, since
+ // classes defined in a such arguments should not be entered into the
+ // enclosing class.
+ c.exprContext(mdef, exprOwner)
+ case None => c
+ }
+ }
// necessary in order to mark the typed ahead annotations as definitely typed:
untpd.modsDeco(mdef).mods.annotations.foreach(typedAnnotation(_)(annotCtx))
}
@@ -1544,7 +1568,11 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
case nil =>
buf.toList
}
- traverse(stats)
+ val localCtx = {
+ val exprOwnerOpt = if (exprOwner == ctx.owner) None else Some(exprOwner)
+ ctx.withProperty(ExprOwner, exprOwnerOpt)
+ }
+ traverse(stats)(localCtx)
}
/** Given an inline method `mdef`, the method rewritten so that its body
@@ -1589,18 +1617,34 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
* `fallBack`.
*
* 1st strategy: Try to insert `.apply` so that the result conforms to prototype `pt`.
+ * This strategy is not tried if the prototype represents already
+ * another `.apply` or `.apply()` selection.
* 2nd strategy: If tree is a select `qual.name`, try to insert an implicit conversion
* around the qualifier part `qual` so that the result conforms to the expected type
* with wildcard result type.
*/
- def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: (Tree, TyperState) => Tree)(implicit ctx: Context): Tree =
- tryEither { implicit ctx =>
+ def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: => Tree)(implicit ctx: Context): Tree = {
+
+ /** Is `pt` a prototype of an `apply` selection, or a parameterless function yielding one? */
+ def isApplyProto(pt: Type): Boolean = pt match {
+ case pt: SelectionProto => pt.name == nme.apply
+ case pt: FunProto => pt.args.isEmpty && isApplyProto(pt.resultType)
+ case pt: IgnoredProto => isApplyProto(pt.ignored)
+ case _ => false
+ }
+
+ def tryApply(implicit ctx: Context) = {
val sel = typedSelect(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt)
if (sel.tpe.isError) sel else adapt(sel, pt)
- } { (failedTree, failedState) =>
- tryInsertImplicitOnQualifier(tree, pt).getOrElse(fallBack(failedTree, failedState))
}
+ def tryImplicit =
+ tryInsertImplicitOnQualifier(tree, pt).getOrElse(fallBack)
+
+ if (isApplyProto(pt)) tryImplicit
+ else tryEither(tryApply(_))((_, _) => tryImplicit)
+ }
+
/** If this tree is a select node `qual.name`, try to insert an implicit conversion
* `c` around `qual` so that `c(qual).name` conforms to `pt`.
*/
@@ -1692,7 +1736,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def hasEmptyParams(denot: SingleDenotation) = denot.info.paramTypess == ListOfNil
pt match {
case pt: FunProto =>
- tryInsertApplyOrImplicit(tree, pt)((_, _) => noMatches)
+ tryInsertApplyOrImplicit(tree, pt)(noMatches)
case _ =>
if (altDenots exists (_.info.paramTypess == ListOfNil))
typed(untpd.Apply(untpd.TypedSplice(tree), Nil), pt)
@@ -1731,7 +1775,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
case Apply(_, _) => " more"
case _ => ""
}
- (_, _) => errorTree(tree, em"$methodStr does not take$more parameters")
+ errorTree(tree, em"$methodStr does not take$more parameters")
}
}
@@ -1834,7 +1878,9 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
ctx.typeComparer.GADTused = false
if (ctx.mode is Mode.Pattern) {
tree match {
- case _: RefTree | _: Literal if !isVarPattern(tree) =>
+ case _: RefTree | _: Literal
+ if !isVarPattern(tree) &&
+ !(tree.tpe <:< pt)(ctx.addMode(Mode.GADTflexible)) =>
checkCanEqual(pt, wtp, tree.pos)(ctx.retractMode(Mode.Pattern))
case _ =>
}
@@ -1936,21 +1982,19 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
if (pt.isInstanceOf[PolyProto]) tree
else {
var typeArgs = tree match {
- case Select(qual, nme.CONSTRUCTOR) => qual.tpe.widenDealias.argTypesLo
+ case Select(qual, nme.CONSTRUCTOR) => qual.tpe.widenDealias.argTypesLo.map(TypeTree)
case _ => Nil
}
if (typeArgs.isEmpty) typeArgs = constrained(poly, tree)._2
convertNewGenericArray(
- adaptInterpolated(tree.appliedToTypes(typeArgs), pt, original))
+ adaptInterpolated(tree.appliedToTypeTrees(typeArgs), pt, original))
}
case wtp =>
pt match {
case pt: FunProto =>
adaptToArgs(wtp, pt)
case pt: PolyProto =>
- tryInsertApplyOrImplicit(tree, pt) {
- (_, _) => tree // error will be reported in typedTypeApply
- }
+ tryInsertApplyOrImplicit(tree, pt)(tree) // error will be reported in typedTypeApply
case _ =>
if (ctx.mode is Mode.Type) adaptType(tree.tpe)
else adaptNoArgs(wtp)
diff --git a/compiler/src/dotty/tools/dotc/util/Chars.scala b/compiler/src/dotty/tools/dotc/util/Chars.scala
index bae3b4732..6f95b87c4 100644
--- a/compiler/src/dotty/tools/dotc/util/Chars.scala
+++ b/compiler/src/dotty/tools/dotc/util/Chars.scala
@@ -6,7 +6,6 @@ package dotty.tools.dotc
package util
import scala.annotation.switch
-import java.lang.{ Character => JCharacter }
import java.lang.{Character => JCharacter}
import java.lang.Character.LETTER_NUMBER
import java.lang.Character.LOWERCASE_LETTER
@@ -66,16 +65,16 @@ object Chars {
/** Can character start an alphanumeric Scala identifier? */
def isIdentifierStart(c: Char): Boolean =
- (c == '_') || (c == '$') || Character.isUnicodeIdentifierStart(c)
+ (c == '_') || (c == '$') || JCharacter.isUnicodeIdentifierStart(c)
/** Can character form part of an alphanumeric Scala identifier? */
def isIdentifierPart(c: Char) =
- (c == '$') || Character.isUnicodeIdentifierPart(c)
+ (c == '$') || JCharacter.isUnicodeIdentifierPart(c)
/** Is character a math or other symbol in Unicode? */
def isSpecial(c: Char) = {
- val chtp = Character.getType(c)
- chtp == Character.MATH_SYMBOL.toInt || chtp == Character.OTHER_SYMBOL.toInt
+ val chtp = JCharacter.getType(c)
+ chtp == JCharacter.MATH_SYMBOL.toInt || chtp == JCharacter.OTHER_SYMBOL.toInt
}
private final val otherLetters = Set[Char]('\u0024', '\u005F') // '$' and '_'