diff options
Diffstat (limited to 'src/dotty/tools')
-rw-r--r-- | src/dotty/tools/dotc/ast/Desugar.scala | 16 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TypeComparer.scala | 27 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/TreeChecker.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Applications.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Namer.scala | 27 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 26 |
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") |