aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools
diff options
context:
space:
mode:
authorodersky <odersky@gmail.com>2016-08-26 18:39:41 +0300
committerGitHub <noreply@github.com>2016-08-26 18:39:41 +0300
commit959ea0cad3a2ffe441b5e406d26cddbd6cc431ee (patch)
tree7470c7a2f049cb2722d662a983389cbd91825611 /src/dotty/tools
parentfb19d0bd248c01f29c9e217170e20f46d84e3028 (diff)
parente61ff6f4cfb632b11b7e54e2904706d382634eda (diff)
downloaddotty-959ea0cad3a2ffe441b5e406d26cddbd6cc431ee.tar.gz
dotty-959ea0cad3a2ffe441b5e406d26cddbd6cc431ee.tar.bz2
dotty-959ea0cad3a2ffe441b5e406d26cddbd6cc431ee.zip
Merge pull request #1461 from dotty-staging/fixes-gadts
Fixes of GADTs and test recategorization.
Diffstat (limited to 'src/dotty/tools')
-rw-r--r--src/dotty/tools/dotc/ast/Desugar.scala16
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala27
-rw-r--r--src/dotty/tools/dotc/transform/TreeChecker.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala5
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala27
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala26
6 files changed, 77 insertions, 26 deletions
diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala
index 346af42b8..500b28233 100644
--- a/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/src/dotty/tools/dotc/ast/Desugar.scala
@@ -8,6 +8,7 @@ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._
import Decorators._
import language.higherKinds
import collection.mutable.ListBuffer
+import util.Attachment
import config.Printers._
object desugar {
@@ -17,6 +18,11 @@ object desugar {
import untpd._
+ /** Tags a .withFilter call generated by desugaring a for expression.
+ * Such calls can alternatively be rewritten to use filter.
+ */
+ val MaybeFilter = new Attachment.Key[Unit]
+
/** Info of a variable in a pattern: The named tree and its type */
private type VarInfo = (NameTree, Tree)
@@ -773,6 +779,12 @@ object desugar {
(Bind(name, pat), Ident(name))
}
+ /** Add MaybeFilter attachment */
+ def orFilter(tree: Tree): tree.type = {
+ tree.putAttachment(MaybeFilter, ())
+ tree
+ }
+
/** Make a pattern filter:
* rhs.withFilter { case pat => true case _ => false }
*
@@ -803,7 +815,7 @@ object desugar {
val cases = List(
CaseDef(pat, EmptyTree, Literal(Constant(true))),
CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false))))
- Apply(Select(rhs, nme.withFilter), makeCaseLambda(cases))
+ Apply(orFilter(Select(rhs, nme.withFilter)), makeCaseLambda(cases))
}
/** Is pattern `pat` irrefutable when matched against `rhs`?
@@ -858,7 +870,7 @@ object desugar {
val vfrom1 = new IrrefutableGenFrom(makeTuple(allpats), rhs1)
makeFor(mapName, flatMapName, vfrom1 :: rest1, body)
case (gen: GenFrom) :: test :: rest =>
- val filtered = Apply(rhsSelect(gen, nme.withFilter), makeLambda(gen.pat, test))
+ val filtered = Apply(orFilter(rhsSelect(gen, nme.withFilter)), makeLambda(gen.pat, test))
val genFrom =
if (isIrrefutableGenFrom(gen)) new IrrefutableGenFrom(gen.pat, filtered)
else GenFrom(gen.pat, filtered)
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index 8d7e9d164..538a74198 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -76,6 +76,19 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
myNothingType
}
+ /** Indicates whether a previous subtype check used GADT bounds */
+ var GADTused = false
+
+ /** Record that GADT bounds of `sym` were used in a subtype check.
+ * But exclude constructor type parameters, as these are aliased
+ * to the corresponding class parameters, which does not constitute
+ * a true usage of a GADT symbol.
+ */
+ private def GADTusage(sym: Symbol) = {
+ if (!sym.owner.isConstructor) GADTused = true
+ true
+ }
+
// Subtype testing `<:<`
def topLevelSubType(tp1: Type, tp2: Type): Boolean = {
@@ -325,7 +338,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
val gbounds2 = ctx.gadt.bounds(tp2.symbol)
(gbounds2 != null) &&
(isSubTypeWhenFrozen(tp1, gbounds2.lo) ||
- narrowGADTBounds(tp2, tp1, isUpper = false))
+ narrowGADTBounds(tp2, tp1, isUpper = false)) &&
+ GADTusage(tp2.symbol)
}
((frozenConstraint || !isCappable(tp1)) && isSubType(tp1, lo2) ||
compareGADT ||
@@ -507,7 +521,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
val gbounds1 = ctx.gadt.bounds(tp1.symbol)
(gbounds1 != null) &&
(isSubTypeWhenFrozen(gbounds1.hi, tp2) ||
- narrowGADTBounds(tp1, tp2, isUpper = true))
+ narrowGADTBounds(tp1, tp2, isUpper = true)) &&
+ GADTusage(tp1.symbol)
}
isSubType(hi1, tp2) || compareGADT
case _ =>
@@ -846,11 +861,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
// special case for situations like:
// class C { type T }
// val foo: C
- // foo.type <: C { type T = foo.T }
+ // foo.type <: C { type T {= , <: , >:} foo.T }
def selfReferentialMatch = tp1.isInstanceOf[SingletonType] && {
rinfo2 match {
- case rinfo2: TypeAlias =>
- !defn.isBottomType(tp1.widen) && (tp1 select name) =:= rinfo2.alias
+ case rinfo2: TypeBounds =>
+ val mbr1 = tp1.select(name)
+ !defn.isBottomType(tp1.widen) &&
+ (mbr1 =:= rinfo2.hi || (rinfo2.hi ne rinfo2.lo) && mbr1 =:= rinfo2.lo)
case _ => false
}
}
diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala
index ce160d7b0..18e3a6c8a 100644
--- a/src/dotty/tools/dotc/transform/TreeChecker.scala
+++ b/src/dotty/tools/dotc/transform/TreeChecker.scala
@@ -258,7 +258,7 @@ class TreeChecker extends Phase with SymTransformer {
}
override def typed(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): tpd.Tree = {
- val tpdTree = super.typed(tree)
+ val tpdTree = super.typed(tree, pt)
checkIdentNotJavaClass(tpdTree)
tpdTree
}
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index 45ed4d938..099105de3 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -775,14 +775,13 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
* The generalizations of a type T are the smallest set G such that
*
* - T is in G
- * - If a typeref R in G represents a trait, R's superclass is in G.
+ * - If a typeref R in G represents a class or trait, R's superclass is in G.
* - If a type proxy P is not a reference to a class, P's supertype is in G
*/
def isSubTypeOfParent(subtp: Type, tp: Type)(implicit ctx: Context): Boolean =
if (subtp <:< tp) true
else tp match {
- case tp: TypeRef if tp.symbol.isClass =>
- tp.symbol.is(Trait) && isSubTypeOfParent(subtp, tp.firstParent)
+ case tp: TypeRef if tp.symbol.isClass => isSubTypeOfParent(subtp, tp.firstParent)
case tp: TypeProxy => isSubTypeOfParent(subtp, tp.superType)
case _ => false
}
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index 3c0a45e94..d90f37860 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -726,7 +726,7 @@ class Namer { typer: Typer =>
// the parent types are elaborated.
index(constr)
symbolOfTree(constr).ensureCompleted()
-
+
index(rest)(inClassContext(selfInfo))
val tparamAccessors = decls.filter(_ is TypeParamAccessor).toList
@@ -807,20 +807,27 @@ class Namer { typer: Typer =>
lazy val schema = paramFn(WildcardType)
val site = sym.owner.thisType
((NoType: Type) /: sym.owner.info.baseClasses.tail) { (tp, cls) =>
- val iRawInfo =
- cls.info.nonPrivateDecl(sym.name).matchingDenotation(site, schema).info
- val iInstInfo = iRawInfo match {
- case iRawInfo: PolyType =>
- if (iRawInfo.paramNames.length == typeParams.length)
- iRawInfo.instantiate(typeParams map (_.typeRef))
+ def instantiatedResType(info: Type, tparams: List[Symbol], paramss: List[List[Symbol]]): Type = info match {
+ case info: PolyType =>
+ if (info.paramNames.length == typeParams.length)
+ instantiatedResType(info.instantiate(tparams.map(_.typeRef)), Nil, paramss)
else NoType
+ case info: MethodType =>
+ paramss match {
+ case params :: paramss1 if info.paramNames.length == params.length =>
+ instantiatedResType(info.instantiate(params.map(_.termRef)), tparams, paramss1)
+ case _ =>
+ NoType
+ }
case _ =>
- if (typeParams.isEmpty) iRawInfo
+ if (tparams.isEmpty && paramss.isEmpty) info.widenExpr
else NoType
}
- val iResType = iInstInfo.finalResultType.asSeenFrom(site, cls)
+ val iRawInfo =
+ cls.info.nonPrivateDecl(sym.name).matchingDenotation(site, schema).info
+ val iResType = instantiatedResType(iRawInfo, typeParams, paramss).asSeenFrom(site, cls)
if (iResType.exists)
- typr.println(i"using inherited type for ${mdef.name}; raw: $iRawInfo, inst: $iInstInfo, inherited: $iResType")
+ typr.println(i"using inherited type for ${mdef.name}; raw: $iRawInfo, inherited: $iResType")
tp & iResType
}
}
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 7eb022b51..f0086b0ab 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -346,11 +346,17 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
}
- if (ctx.compilationUnit.isJava && tree.name.isTypeName) {
+ def selectWithFallback(fallBack: => Tree) =
+ tryEither(tryCtx => asSelect(tryCtx))((_, _) => fallBack)
+
+ if (ctx.compilationUnit.isJava && tree.name.isTypeName)
// SI-3120 Java uses the same syntax, A.B, to express selection from the
// value A and from the type A. We have to try both.
- tryEither(tryCtx => asSelect(tryCtx))((_, _) => asJavaSelectFromTypeTree(ctx))
- } else asSelect(ctx)
+ selectWithFallback(asJavaSelectFromTypeTree(ctx))
+ else if (tree.name == nme.withFilter && tree.getAttachment(desugar.MaybeFilter).isDefined)
+ selectWithFallback(typedSelect(untpd.cpy.Select(tree)(tree.qualifier, nme.filter), pt))
+ else
+ asSelect(ctx)
}
def typedSelectFromTypeTree(tree: untpd.SelectFromTypeTree, pt: Type)(implicit ctx: Context): Tree = track("typedSelectFromTypeTree") {
@@ -1066,8 +1072,9 @@ 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(_.tree)
+ val annotCtx = ctx.outersIterator.dropWhile(_.owner == sym).next
// necessary in order to mark the typed ahead annotations as definitely typed:
- untpd.modsDeco(mdef).mods.annotations.foreach(typedAnnotation)
+ untpd.modsDeco(mdef).mods.annotations.foreach(typedAnnotation(_)(annotCtx))
}
def typedAnnotation(annot: untpd.Tree)(implicit ctx: Context): Tree = track("typedAnnotation") {
@@ -1715,6 +1722,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
else
missingArgs
case _ =>
+ ctx.typeComparer.GADTused = false
if (ctx.mode is Mode.Pattern) {
tree match {
case _: RefTree | _: Literal if !isVarPattern(tree) =>
@@ -1723,7 +1731,15 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
tree
}
- else if (tree.tpe <:< pt) tree
+ else if (tree.tpe <:< pt)
+ if (ctx.typeComparer.GADTused && pt.isValueType)
+ // Insert an explicit cast, so that -Ycheck in later phases succeeds.
+ // I suspect, but am not 100% sure that this might affect inferred types,
+ // if the expected type is a supertype of the GADT bound. It would be good to come
+ // up with a test case for this.
+ tree.asInstance(pt)
+ else
+ tree
else if (wtp.isInstanceOf[MethodType]) missingArgs
else {
typr.println(i"adapt to subtype ${tree.tpe} !<:< $pt")