aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDmitry Petrashko <dark@d-d.me>2015-11-02 18:46:15 +0100
committerDmitry Petrashko <dark@d-d.me>2015-11-02 18:46:15 +0100
commit432689d1a38cf65da88a1e72e0c0f425850c340e (patch)
tree066f9574bc6d1665fb14d6fd7b6e6db4e210c074 /src
parentf58acd171105487984a1d8df2646246aab43e5e1 (diff)
parent4b1d08928bd008a23fa40490d2998e58a6f06c4d (diff)
downloaddotty-432689d1a38cf65da88a1e72e0c0f425850c340e.tar.gz
dotty-432689d1a38cf65da88a1e72e0c0f425850c340e.tar.bz2
dotty-432689d1a38cf65da88a1e72e0c0f425850c340e.zip
Merge pull request #860 from dotty-staging/change-allow-ex-in-hk
Change allow ex in hk
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala6
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala66
-rw-r--r--src/dotty/tools/dotc/core/Types.scala44
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreePickler.scala35
-rw-r--r--src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala9
-rw-r--r--src/dotty/tools/dotc/transform/PostTyper.scala2
-rw-r--r--src/dotty/tools/dotc/transform/TypeTestsCasts.scala1
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala4
-rw-r--r--src/dotty/tools/dotc/typer/TypeAssigner.scala3
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala29
10 files changed, 105 insertions, 94 deletions
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index 0dde5de95..1271d7f6a 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -227,6 +227,8 @@ object Flags {
/** A trait */
final val Trait = typeFlag(10, "<trait>")
+ final val LazyOrTrait = Lazy.toCommonFlags
+
/** A value or variable accessor (getter or setter) */
final val Accessor = termFlag(11, "<accessor>")
@@ -315,6 +317,8 @@ object Flags {
/** An unpickled Scala 2.x class */
final val Scala2x = typeFlag(26, "<scala-2.x>")
+ final val SuperAccessorOrScala2x = SuperAccessor.toCommonFlags
+
/** A method that has default params */
final val DefaultParameterized = termFlag(27, "<defaultparam>")
@@ -440,7 +444,7 @@ object Flags {
AccessFlags | Module | Package | Deferred | Final | MethodOrHKCommon | Param | ParamAccessor | Scala2ExistentialCommon |
InSuperCall | Touched | JavaStatic | CovariantOrOuter | ContravariantOrLabel | ExpandedName | AccessorOrSealed |
CaseAccessorOrTypeArgument | Fresh | Frozen | Erroneous | ImplicitCommon | Permanent |
- SelfNameOrImplClass
+ LazyOrTrait | SuperAccessorOrScala2x | SelfNameOrImplClass
assert(FromStartFlags.isTermFlags && FromStartFlags.isTypeFlags)
// TODO: Should check that FromStartFlags do not change in completion
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index 47935f79e..7274c1f70 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -48,33 +48,43 @@ class TypeApplications(val self: Type) extends AnyVal {
* For a typeref referring to a class, the type parameters of the class.
* For a typeref referring to a Lambda class, the type parameters of
* its right hand side or upper bound.
- * For a refinement type, the type parameters of its parent, unless the refinement
- * re-binds the type parameter with a type-alias.
- * For any other non-singleton type proxy, the type parameters of its underlying type.
- * For any other type, the empty list.
+ * For a refinement type, the type parameters of its parent, dropping
+ * any type parameter that is-rebound by the refinement. "Re-bind" means:
+ * The refinement contains a TypeAlias for the type parameter, or
+ * it introduces bounds for the type parameter, and we are not in the
+ * special case of a type Lambda, where a LambdaTrait gets refined
+ * with the bounds on its hk args. See `LambdaAbstract`, where these
+ * types get introduced, and see `isBoundedLambda` below for the test.
*/
final def typeParams(implicit ctx: Context): List[TypeSymbol] = /*>|>*/ track("typeParams") /*<|<*/ {
self match {
- case tp: ClassInfo =>
- tp.cls.typeParams
- case tp: TypeRef =>
- val tsym = tp.typeSymbol
+ case self: ClassInfo =>
+ self.cls.typeParams
+ case self: TypeRef =>
+ val tsym = self.typeSymbol
if (tsym.isClass) tsym.typeParams
- else if (tsym.isAliasType) tp.underlying.typeParams
+ else if (tsym.isAliasType) self.underlying.typeParams
else {
val lam = LambdaClass(forcing = false)
if (lam.exists) lam.typeParams else Nil
}
- case tp: RefinedType =>
- val tparams = tp.parent.typeParams
- tp.refinedInfo match {
- case rinfo: TypeAlias => tparams.filterNot(_.name == tp.refinedName)
- case _ => tparams
+ case self: RefinedType =>
+ def isBoundedLambda(tp: Type): Boolean = tp match {
+ case tp: TypeRef => tp.typeSymbol.isLambdaTrait
+ case tp: RefinedType => tp.refinedName.isLambdaArgName && isBoundedLambda(tp.parent)
+ case _ => false
+ }
+ val tparams = self.parent.typeParams
+ self.refinedInfo match {
+ case rinfo: TypeBounds if rinfo.isAlias || isBoundedLambda(self) =>
+ tparams.filterNot(_.name == self.refinedName)
+ case _ =>
+ tparams
}
- case tp: SingletonType =>
+ case self: SingletonType =>
Nil
- case tp: TypeProxy =>
- tp.underlying.typeParams
+ case self: TypeProxy =>
+ self.underlying.typeParams
case _ =>
Nil
}
@@ -91,23 +101,23 @@ class TypeApplications(val self: Type) extends AnyVal {
*/
final def rawTypeParams(implicit ctx: Context): List[TypeSymbol] = {
self match {
- case tp: ClassInfo =>
- tp.cls.typeParams
- case tp: TypeRef =>
- val tsym = tp.typeSymbol
+ case self: ClassInfo =>
+ self.cls.typeParams
+ case self: TypeRef =>
+ val tsym = self.typeSymbol
if (tsym.isClass) tsym.typeParams
- else if (tsym.isAliasType) tp.underlying.rawTypeParams
+ else if (tsym.isAliasType) self.underlying.rawTypeParams
else Nil
case _: BoundType | _: SingletonType =>
Nil
- case tp: TypeProxy =>
- tp.underlying.rawTypeParams
+ case self: TypeProxy =>
+ self.underlying.rawTypeParams
case _ =>
Nil
}
}
- /** If type `tp` is equal, aliased-to, or upperbounded-by a type of the form
+ /** If type `self` is equal, aliased-to, or upperbounded-by a type of the form
* `LambdaXYZ { ... }`, the class symbol of that type, otherwise NoSymbol.
* symbol of that type, otherwise NoSymbol.
* @param forcing if set, might force completion. If not, never forces
@@ -125,7 +135,7 @@ class TypeApplications(val self: Type) extends AnyVal {
NoSymbol
}}
- /** Is type `tp` equal, aliased-to, or upperbounded-by a type of the form
+ /** Is type `self` equal, aliased-to, or upperbounded-by a type of the form
* `LambdaXYZ { ... }`?
*/
def isLambda(implicit ctx: Context): Boolean =
@@ -137,7 +147,7 @@ class TypeApplications(val self: Type) extends AnyVal {
def isSafeLambda(implicit ctx: Context): Boolean =
LambdaClass(forcing = false).exists
- /** Is type `tp` a Lambda with all hk$i fields fully instantiated? */
+ /** Is type `self` a Lambda with all hk$i fields fully instantiated? */
def isInstantiatedLambda(implicit ctx: Context): Boolean =
isSafeLambda && typeParams.isEmpty
@@ -225,7 +235,7 @@ class TypeApplications(val self: Type) extends AnyVal {
}
/** Same as isHK, except we classify all abstract types as HK,
- * (they must be, because the are applied). This avoids some forcing and
+ * (they must be, because they are applied). This avoids some forcing and
* CyclicReference errors of the standard isHK.
*/
def isKnownHK(tp: Type): Boolean = tp match {
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 58a6d226d..3fe5afb33 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -846,14 +846,16 @@ object Types {
* (*) normalizes means: follow instantiated typevars and aliases.
*/
def lookupRefined(name: Name)(implicit ctx: Context): Type = {
- def loop(pre: Type, resolved: List[Name]): Type = pre.stripTypeVar match {
+ def loop(pre: Type): Type = pre.stripTypeVar match {
case pre: RefinedType =>
object instantiate extends TypeMap {
var isSafe = true
def apply(tp: Type): Type = tp match {
case TypeRef(RefinedThis(`pre`), name) if name.isLambdaArgName =>
- val TypeAlias(alias) = member(name).info
- alias
+ member(name).info match {
+ case TypeAlias(alias) => alias
+ case _ => isSafe = false; tp
+ }
case tp: TypeVar if !tp.inst.exists =>
isSafe = false
tp
@@ -861,23 +863,37 @@ object Types {
mapOver(tp)
}
}
- def betaReduce(tp: Type) = {
- val lam = pre.parent.LambdaClass(forcing = false)
- if (lam.exists && lam.typeParams.forall(tparam => resolved.contains(tparam.name))) {
- val reduced = instantiate(tp)
+ def instArg(tp: Type): Type = tp match {
+ case tp @ TypeAlias(TypeRef(RefinedThis(`pre`), name)) if name.isLambdaArgName =>
+ member(name).info match {
+ case TypeAlias(alias) => tp.derivedTypeAlias(alias) // needed to keep variance
+ case bounds => bounds
+ }
+ case _ =>
+ instantiate(tp)
+ }
+ def instTop(tp: Type): Type = tp.stripTypeVar match {
+ case tp: RefinedType =>
+ tp.derivedRefinedType(instTop(tp.parent), tp.refinedName, instArg(tp.refinedInfo))
+ case _ =>
+ instantiate(tp)
+ }
+ /** Reduce rhs of $hkApply to make it stand alone */
+ def betaReduce(tp: Type) =
+ if (pre.parent.isSafeLambda) {
+ val reduced = instTop(tp)
if (instantiate.isSafe) reduced else NoType
}
else NoType
- }
pre.refinedInfo match {
case TypeAlias(alias) =>
- if (pre.refinedName ne name) loop(pre.parent, pre.refinedName :: resolved)
+ if (pre.refinedName ne name) loop(pre.parent)
else if (!pre.refinementRefersToThis) alias
else alias match {
case TypeRef(RefinedThis(`pre`), aliasName) => lookupRefined(aliasName) // (1)
case _ => if (name == tpnme.hkApply) betaReduce(alias) else NoType // (2)
}
- case _ => loop(pre.parent, resolved)
+ case _ => loop(pre.parent)
}
case RefinedThis(binder) =>
binder.lookupRefined(name)
@@ -887,14 +903,14 @@ object Types {
WildcardType
case pre: TypeRef =>
pre.info match {
- case TypeAlias(alias) => loop(alias, resolved)
+ case TypeAlias(alias) => loop(alias)
case _ => NoType
}
case _ =>
NoType
}
- loop(this, Nil)
+ loop(this)
}
/** The type <this . name> , reduced if possible */
@@ -1886,6 +1902,10 @@ object Types {
s"variance mismatch for $this, $cls, ${cls.typeParams}, ${cls.typeParams.apply(refinedName.LambdaArgIndex).variance}, ${refinedInfo.variance}")
case _ =>
}
+ if (Config.checkProjections &&
+ (refinedName == tpnme.hkApply || refinedName.isLambdaArgName) &&
+ parent.noHK)
+ assert(false, s"illegal refinement of first-order type: $this")
this
}
diff --git a/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/src/dotty/tools/dotc/core/tasty/TreePickler.scala
index 58697c196..86bbc893f 100644
--- a/src/dotty/tools/dotc/core/tasty/TreePickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreePickler.scala
@@ -148,27 +148,32 @@ class TreePickler(pickler: TastyPickler) {
pickleType(tpe.info.bounds.hi)
case tpe: WithFixedSym =>
val sym = tpe.symbol
+ def pickleRef() =
+ if (tpe.prefix == NoPrefix) {
+ writeByte(if (tpe.isType) TYPEREFdirect else TERMREFdirect)
+ pickleSymRef(sym)
+ }
+ else {
+ assert(tpe.symbol.isClass)
+ assert(tpe.symbol.is(Flags.Scala2x), tpe.symbol.showLocated)
+ writeByte(TYPEREF) // should be changed to a new entry that keeps track of prefix, symbol & owner
+ pickleName(tpe.name)
+ pickleType(tpe.prefix)
+ }
if (sym.is(Flags.Package)) {
writeByte(if (tpe.isType) TYPEREFpkg else TERMREFpkg)
pickleName(qualifiedName(sym))
}
- else {
- assert(tpe.prefix == NoPrefix)
- def pickleRef() = {
- writeByte(if (tpe.isType) TYPEREFdirect else TERMREFdirect)
- pickleSymRef(sym)
- }
- if (sym is Flags.BindDefinedType) {
- registerDef(sym)
- writeByte(BIND)
- withLength {
- pickleName(sym.name)
- pickleType(sym.info)
- pickleRef()
- }
+ else if (sym is Flags.BindDefinedType) {
+ registerDef(sym)
+ writeByte(BIND)
+ withLength {
+ pickleName(sym.name)
+ pickleType(sym.info)
+ pickleRef()
}
- else pickleRef()
}
+ else pickleRef()
case tpe: TermRefWithSignature =>
if (tpe.symbol.is(Flags.Package)) picklePackageRef(tpe.symbol)
else {
diff --git a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
index 6e405d5f8..cdb733efa 100644
--- a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
+++ b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
@@ -451,6 +451,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
}
def finishSym(sym: Symbol): Symbol = {
+ if (sym.isClass) sym.setFlag(Scala2x)
val owner = sym.owner
if (owner.isClass &&
!( isUnpickleRoot(sym)
@@ -536,7 +537,6 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
case denot: ClassDenotation =>
val selfInfo = if (atEnd) NoType else readTypeRef()
setClassInfo(denot, tp, selfInfo)
- denot setFlag Scala2x
case denot =>
val tp1 = depoly(tp, denot)
denot.info =
@@ -621,7 +621,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
tp.derivedRefinedType(parent1, name, info)
}
case tp @ TypeRef(pre, tpnme.hkApply) =>
- elim(pre)
+ tp.derivedSelect(elim(pre))
case _ =>
tp
}
@@ -687,7 +687,10 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
case _ =>
}
val tycon =
- if (isLocal(sym) || pre == NoPrefix) {
+ if (sym.isClass && sym.is(Scala2x) && !sym.owner.is(Package))
+ // used fixed sym for Scala 2 inner classes, because they might be shadowed
+ TypeRef.withFixedSym(pre, sym.name.asTypeName, sym.asType)
+ else if (isLocal(sym) || pre == NoPrefix) {
val pre1 = if ((pre eq NoPrefix) && (sym is TypeParam)) sym.owner.thisType else pre
pre1 select sym
}
diff --git a/src/dotty/tools/dotc/transform/PostTyper.scala b/src/dotty/tools/dotc/transform/PostTyper.scala
index 7a25a9870..fc4427277 100644
--- a/src/dotty/tools/dotc/transform/PostTyper.scala
+++ b/src/dotty/tools/dotc/transform/PostTyper.scala
@@ -71,7 +71,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
/** Check bounds of AppliedTypeTrees.
* Replace type trees with TypeTree nodes.
* Replace constant expressions with Literal nodes.
- * Note: Demanding idempotency instead of purityin literalize is strictly speaking too loose.
+ * Note: Demanding idempotency instead of purity in literalize is strictly speaking too loose.
* Example
*
* object O { final val x = 42; println("43") }
diff --git a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
index 98b8357b9..b2d45b661 100644
--- a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
+++ b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
@@ -27,7 +27,6 @@ import ValueClasses._
* Unfortunately this phase ended up being not Y-checkable unless types are erased. A cast to an ConstantType(3) or x.type
* cannot be rewritten before erasure.
*/
-
trait TypeTestsCasts {
import ast.tpd._
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index fa417beec..b8b4c89b4 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -398,9 +398,7 @@ trait Checking {
if (tpt.tpe.isHK && !ctx.compilationUnit.isJava) {
// be more lenient with missing type params in Java,
// needed to make pos/java-interop/t1196 work.
- val alias = tpt.tpe.dealias
- if (alias.isHK) errorTree(tpt, d"missing type parameter for ${tpt.tpe}")
- else tpt.withType(alias)
+ errorTree(tpt, d"missing type parameter for ${tpt.tpe}")
}
else tpt
}
diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala
index 7225ede14..25030012c 100644
--- a/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -344,10 +344,9 @@ trait TypeAssigner {
def assignType(tree: untpd.Return)(implicit ctx: Context) =
tree.withType(defn.NothingType)
- def assignType(tree: untpd.Try, expr: Tree, cases: List[CaseDef])(implicit ctx: Context) = {
+ def assignType(tree: untpd.Try, expr: Tree, cases: List[CaseDef])(implicit ctx: Context) =
if (cases.isEmpty) tree.withType(expr.tpe)
else tree.withType(ctx.typeComparer.lub(expr.tpe :: cases.tpes))
- }
def assignType(tree: untpd.SeqLiteral, elems: List[Tree])(implicit ctx: Context) = tree match {
case tree: JavaSeqLiteral =>
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 4637eed51..60ecaac0b 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -851,34 +851,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
val args1 = args.zipWithConserve(tparams)(typedArg(_, _)).asInstanceOf[List[Tree]]
// check that arguments conform to bounds is done in phase PostTyper
- val tree1 = assignType(cpy.AppliedTypeTree(tree)(tpt1, args1), tpt1, args1)
- if (tree1.tpe.isHKApply)
- for (arg @ TypeBoundsTree(_, _) <- args1)
- ctx.error("illegal wildcard type argument; does not correspond to type parameter of a class", arg.pos)
- // The reason for outlawing such arguments is illustrated by the following example.
- // Say we have
- //
- // type RMap[A, B] = Map[B, A]
- //
- // Then
- //
- // Rmap[_, Int]
- //
- // translates to
- //
- // Lambda$I { type hk$0; type hk$1 = Int; type $apply = Map[$hk1, $hk0] } # $apply
- //
- // Let's call the last type T. You would expect that
- //
- // Map[Int, String] <: RMap[_, Int]
- //
- // But that's not the case given the standard subtyping rules. In fact, the rhs reduces to
- //
- // Map[Int, T # $hk0]
- //
- // That means the second argument to `Map` is unknown and String is certainly not a subtype of it.
- // To avoid the surprise we outlaw problematic wildcard arguments from the start.
- tree1
+ assignType(cpy.AppliedTypeTree(tree)(tpt1, args1), tpt1, args1)
}
}