From 5daae278392ed6fabd45c9fa55aded970ca2a348 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 29 Jun 2016 19:12:29 +0200 Subject: Multiple fixes - Swap order of tests in lookupRefined - Change joins of BindingKinds. A type parameter joint with a normal refinement represents a type parameter that has been filled in. So the Binding attribute should be removed. - Fix printing of type lambdas under new hk scheme - refine isRef for hk type The new definition avoids that a higher-kinded type "isRef" of an underlying class. I.e. `[X] -> Any` is not longer a ref to `Any`. - Fix withBindingKind for type aliases Old definition converted aliases to type bounds. - Multiple fixes to BetaReduce - Fix logic for hk subtype tests - Make isHK more precise --- src/dotty/tools/dotc/core/TypeApplications.scala | 84 +++++++++++++++++++----- 1 file changed, 67 insertions(+), 17 deletions(-) (limited to 'src/dotty/tools/dotc/core/TypeApplications.scala') diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index 9ceae6e5f..dfd1caf62 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -285,17 +285,18 @@ object TypeApplications { TypeLambda.applyOBS(variances, bounds, body) } - private class InstMap(fullType: Type)(implicit ctx: Context) extends TypeMap { + private class InstMap(fullType: Type, shortLived: Boolean)(implicit ctx: Context) extends TypeMap { var localRecs: Set[RecType] = Set.empty var keptRefs: Set[Name] = Set.empty var isSafe: Boolean = true + var tyconIsHK: Boolean = true def apply(tp: Type): Type = tp match { case tp @ TypeRef(RecThis(rt), sel) if sel.isHkArgName && localRecs.contains(rt) => fullType.member(sel).info match { case TypeAlias(alias) => apply(alias) case _ => keptRefs += sel; tp } - case tp: TypeVar if !tp.inst.exists => + case tp: TypeVar if !tp.inst.exists && !shortLived => isSafe = false tp case _ => @@ -451,8 +452,10 @@ class TypeApplications(val self: Type) extends AnyVal { def isHK(implicit ctx: Context): Boolean = self.dealias match { case self: TypeRef => self.info.isHK case self: RefinedType => self.refinedName == tpnme.hkApplyOBS || self.isTypeParam - case self: RecType => self.parent.isHK - case TypeBounds(_, hi) => hi.isHK + case self: SingletonType => false + case self: TypeVar => self.origin.isHK + case self: WildcardType => self.optBounds.isHK + case self: TypeProxy => self.underlying.isHK case _ => false } @@ -552,20 +555,55 @@ class TypeApplications(val self: Type) extends AnyVal { assert(!isHK, self) self match { case self: TypeAlias => - self.derivedTypeAlias(expand(self.alias.BetaReduce)) + self.derivedTypeAlias(expand(self.alias.BetaReduce())) case self @ TypeBounds(lo, hi) => if (Config.newHK) - self.derivedTypeBounds(lo, expand(hi.BetaReduce)) + self.derivedTypeBounds(lo, expand(hi.BetaReduce())) else - self.derivedTypeBounds(lo, expand(TypeBounds.upper(hi.BetaReduce))) + self.derivedTypeBounds(lo, expand(TypeBounds.upper(hi.BetaReduce()))) case _ => expand(self) } } - def BetaReduce(implicit ctx: Context): Type = self.dealias match { - case self1 @ RefinedType(_, rname, _) if Config.newHK && rname.isHkArgName => - val inst = new InstMap(self) - def instTop(tp: Type): Type = { + /** If `self` is a * type, perform the following rewritings: + * + * 1. For every occurrence of `z.$hk_i`, where `z` is a RecThis type that refers + * to some recursive type in `self`, if the member of `self.hk$i` has an alias + * type `= U`: + * + * z.$hk_i --> U + * + * 2. For every top-level binding `type A = z.$hk_i$, where `z` is a RecThis type that refers + * to some recursive type in `self`, if the member of `self` has bounds `S..U`: + * + * type A = z.$hk_i --> type A >: S <: U + * + * 3. If the type constructor preceding all bindings is a * type, delete every top-level + * binding `{ type $hk_i ... }` where `$hk_i` does not appear in the prefix of the binding. + * I.e. + * + * T { type $hk_i ... } --> T + * + * If `$hk_i` does not appear in `T`. + * + * A binding is top-level if it can be reached by + * + * - following aliases + * - dropping refinements and rec-types + * - going from a wildcard type to its upper bound + * + * @param shortLived If `false` suppresses all rewritings where a type variable with + * an unknown or uncommitted instance is rewritten. Reason: If the + * type variable is finally instantiated to something else, the + * reduction might not be valid anymore. However, when reducing + * during `<:<` tests `shortLived` is true and the reduction + * is never suppressed, because then we are only interested + * in subtyping relative to the current context. + */ + def BetaReduce(shortLived: Boolean = false)(implicit ctx: Context): Type = self.dealias match { + case self1 @ RefinedType(_, rname, _) if Config.newHK && rname.isHkArgName && self1.typeParams.isEmpty => + val inst = new InstMap(self, shortLived) + def instTop(tp: Type): Type = if (!inst.isSafe) tp else tp.dealias match { case tp: RecType => @@ -574,18 +612,30 @@ class TypeApplications(val self: Type) extends AnyVal { case tp @ RefinedType(parent, rname, rinfo) => rinfo match { case TypeAlias(TypeRef(RecThis(rt), sel)) if sel.isHkArgName && inst.localRecs.contains(rt) => - instTop(tp.derivedRefinedType(parent, rname, self.member(sel).info)) + val bounds @ TypeBounds(_, _) = self.member(sel).info + instTop(tp.derivedRefinedType(parent, rname, bounds.withBindingKind(NoBinding))) case _ => val parent1 = instTop(parent) - if (rname.isHkArgName && !inst.keptRefs.contains(rname)) parent1 + if (rname.isHkArgName && + !inst.tyconIsHK && + !inst.keptRefs.contains(rname)) parent1 else tp.derivedRefinedType(parent1, rname, inst(rinfo)) } + case tp @ WildcardType(bounds @ TypeBounds(lo, hi)) => + tp.derivedWildcardType(bounds.derivedTypeBounds(inst(lo), instTop(hi))) case tp => - inst(tp) - }} + inst.tyconIsHK = tp.isHK + val res = inst(tp) + tp match { + case tp: WildcardType => + println(s"inst $tp --> $res") + case _ => + } + res + } val reduced = instTop(self) if (inst.isSafe) reduced else self - case self1 => self1 + case _ => self } /** A type ref is eta expandable if it refers to a non-lambda class. @@ -761,7 +811,7 @@ class TypeApplications(val self: Type) extends AnyVal { matchParams(RefinedType(t, tparam.memberName, arg.toBounds(tparam)), tparams1, args1) } catch { case ex: MatchError => - println(s"applied type mismatch: $self $args, typeParams = $typParams") // !!! DEBUG + println(s"applied type mismatch: $self with underlying ${self.underlyingIfProxy}, args = $args, typeParams = $typParams") // !!! DEBUG //println(s"precomplete decls = ${self.typeSymbol.unforcedDecls.toList.map(_.denot).mkString("\n ")}") throw ex } -- cgit v1.2.3