From a4937916037f74b414c9bab1819681ed2ecd7fdc Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 27 Jan 2015 15:13:23 +0100 Subject: Fixups taking into account reviewer's comments. --- src/dotty/tools/dotc/core/Constraint.scala | 6 ++++-- src/dotty/tools/dotc/core/ConstraintHandling.scala | 3 ++- src/dotty/tools/dotc/core/OrderingConstraint.scala | 12 ++++++------ src/dotty/tools/dotc/core/TypeComparer.scala | 18 +++++++++++------- src/dotty/tools/dotc/core/Types.scala | 2 +- src/dotty/tools/dotc/typer/Implicits.scala | 6 ++---- src/dotty/tools/dotc/typer/ProtoTypes.scala | 2 +- 7 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/dotty/tools/dotc/core/Constraint.scala b/src/dotty/tools/dotc/core/Constraint.scala index d6e1589e0..bc0d476a9 100644 --- a/src/dotty/tools/dotc/core/Constraint.scala +++ b/src/dotty/tools/dotc/core/Constraint.scala @@ -92,11 +92,13 @@ abstract class Constraint extends Showable { */ def updateEntry(param: PolyParam, tp: Type)(implicit ctx: Context): This - /** A constraint that includes the relationship `p1 <: p2` + /** A constraint that includes the relationship `p1 <: p2`. + * `<:` relationships between parameters ("edges") are propagated, but + * non-parameter bounds are left alone. */ def addLess(p1: PolyParam, p2: PolyParam)(implicit ctx: Context): This - /** A constraint resulting by adding p2 = p1 to this constraint, and at the same + /** A constraint resulting from adding p2 = p1 to this constraint, and at the same * time transferring all bounds of p2 to p1 */ def unify(p1: PolyParam, p2: PolyParam)(implicit ctx: Context): This diff --git a/src/dotty/tools/dotc/core/ConstraintHandling.scala b/src/dotty/tools/dotc/core/ConstraintHandling.scala index 02f5bf87f..478fc5740 100644 --- a/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -218,7 +218,8 @@ trait ConstraintHandling { * `bound` is assumed to be in normalized form, as specified in `firstTry` and * `secondTry` of `TypeComparer`. In particular, it should not be an alias type, * lazy ref, typevar, wildcard type, error type. In addition, upper bounds may - * not be AndTypes and lower bounds may not be OrTypes. + * not be AndTypes and lower bounds may not be OrTypes. This is assured by the + * way isSubType is organized. */ protected def addConstraint(param: PolyParam, bound: Type, fromBelow: Boolean): Boolean = { def description = i"constr $param ${if (fromBelow) ">:" else "<:"} $bound:\n$constraint" diff --git a/src/dotty/tools/dotc/core/OrderingConstraint.scala b/src/dotty/tools/dotc/core/OrderingConstraint.scala index ec2a65416..e265c0b98 100644 --- a/src/dotty/tools/dotc/core/OrderingConstraint.scala +++ b/src/dotty/tools/dotc/core/OrderingConstraint.scala @@ -14,10 +14,10 @@ import reflect.ClassTag object OrderingConstraint { - /** The type of `Constraint#boundsMap` */ + /** The type of `OrderingConstraint#boundsMap` */ type ParamBounds = SimpleMap[PolyType, Array[Type]] - /** The type of `Constraint#lowerMap`, `Constraint#upperMap` */ + /** The type of `OrderingConstraint#lowerMap`, `OrderingConstraint#upperMap` */ type ParamOrdering = SimpleMap[PolyType, Array[List[PolyParam]]] /** A new constraint with given maps */ @@ -117,10 +117,10 @@ import OrderingConstraint._ * * @param lowerMap a map from PolyTypes to arrays. Each array entry corresponds * to a parameter P of the polytype; it contains all constrained parameters - * Q that are known to be smaller than P, i.e. P <: Q. + * Q that are known to be smaller than P, i.e. Q <: P. * @param upperMap a map from PolyTypes to arrays. Each array entry corresponds * to a parameter P of the polytype; it contains all constrained parameters - * Q that are known to be greater than P, i.e. Q <: P. + * Q that are known to be greater than P, i.e. P <: Q. */ class OrderingConstraint(private val boundsMap: ParamBounds, private val lowerMap : ParamOrdering, @@ -272,8 +272,8 @@ class OrderingConstraint(private val boundsMap: ParamBounds, // ---------- Updates ------------------------------------------------------------ - /** An updated partial order matrix that incorporates `less` and also reflects that `param` relates - * to `p2` wrt <:< if `inOrder` is true, `>:>` otherwise. + /** Add the fact `param1 <: param2` to the constraint `current` and propagate + * `<:<` relationships between parameters ("edges") but not bounds. */ private def order(current: This, param1: PolyParam, param2: PolyParam)(implicit ctx: Context): This = if (param1 == param2 || current.isLess(param1, param2)) this diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 6d5d78448..06f03b9f9 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -299,7 +299,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi val gbounds2 = ctx.gadt.bounds(tp2.symbol) (gbounds2 != null) && (isSubTypeWhenFrozen(tp1, gbounds2.lo) || - narrowGADTBounds(tp2, tp1, isLowerBound = true)) + narrowGADTBounds(tp2, tp1, isUpper = false)) } ((frozenConstraint || !isCappable(tp1)) && isSubType(tp1, lo2) || compareGADT || @@ -414,7 +414,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi val gbounds1 = ctx.gadt.bounds(tp1.symbol) (gbounds1 != null) && (isSubTypeWhenFrozen(gbounds1.hi, tp2) || - narrowGADTBounds(tp1, tp2, isLowerBound = false)) + narrowGADTBounds(tp1, tp2, isUpper = true)) } isSubType(hi1, tp2) || compareGADT case _ => @@ -616,16 +616,20 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi //}) } - private def narrowGADTBounds(tr: NamedType, bound: Type, isLowerBound: Boolean): Boolean = + /** Narrow gadt.bounds for the type parameter referenced by `tr` to include + * `bound` as an upper or lower bound (which depends on `isUpper`). + * Test that the resulting bounds are still satisfiable. + */ + private def narrowGADTBounds(tr: NamedType, bound: Type, isUpper: Boolean): Boolean = ctx.mode.is(Mode.GADTflexible) && { val tparam = tr.symbol - val bound1 = deSkolemize(bound, toSuper = isLowerBound) - typr.println(s"narrow gadt bound of $tparam: ${tparam.info} from ${if (isLowerBound) "below" else "above"} to $bound1 ${bound1.isRef(tparam)}") + val bound1 = deSkolemize(bound, toSuper = !isUpper) + typr.println(s"narrow gadt bound of $tparam: ${tparam.info} from ${if (isUpper) "above" else "below"} to $bound1 ${bound1.isRef(tparam)}") !bound1.isRef(tparam) && { val oldBounds = ctx.gadt.bounds(tparam) val newBounds = - if (isLowerBound) TypeBounds(oldBounds.lo | bound1, oldBounds.hi) - else TypeBounds(oldBounds.lo, oldBounds.hi & bound1) + if (isUpper) TypeBounds(oldBounds.lo, oldBounds.hi & bound1) + else TypeBounds(oldBounds.lo | bound1, oldBounds.hi) isSubType(newBounds.lo, newBounds.hi) && { ctx.gadt.setBounds(tparam, newBounds); true } } diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 30e394941..e986e680d 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -761,7 +761,7 @@ object Types { * a reference to the "this" of the current refined type. But does follow * aliases in order to avoid such references. Example: * - * Lambda$I { type $hk$Arg0 = String, type Apply = this<0>.$hk$Arg0 } # Apply + * Lambda$I { type $hk$Arg0 = String, type Apply = Lambda$I{...}.$hk$Arg0 } # Apply * * Here, the refinement for `Apply` has a refined this node, yet dereferencing ones more * yields `String` as the result of lookupRefined. diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index 24d9ebf6d..5111f10bd 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -450,10 +450,8 @@ trait Implicits { self: Typer => private def nestedContext = ctx.fresh.setMode(ctx.mode &~ Mode.ImplicitsEnabled) private def implicitProto(resultType: Type, f: Type => Type) = - if (argument.isEmpty) f(resultType) else ViewProto(f(argument.tpe/*.widen*/), f(resultType)) - // !!! TODO: check performance implications - // If we do the widen, SyntheticMethods, line 66 fails to compile - // val synthetic = sym.copy(...) + if (argument.isEmpty) f(resultType) else ViewProto(f(argument.tpe.widen), f(resultType)) + // Not clear whether we need to drop the `.widen` here. All tests pass with it in place, though. assert(argument.isEmpty || argument.tpe.isValueType || argument.tpe.isInstanceOf[ExprType], d"found: ${argument.tpe}, expected: $pt") diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala index 521f0deaa..e4d58cb19 100644 --- a/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -376,7 +376,7 @@ object ProtoTypes { tp.derivedRefinedType(wildApprox(tp.parent, theMap), tp.refinedName, wildApprox(tp.refinedInfo, theMap)) case tp: TypeAlias => // default case, inlined for speed tp.derivedTypeAlias(wildApprox(tp.alias, theMap)) - case tp @ PolyParam(poly, pnum) => // !!! todo adapt to TrackingConstraint + case tp @ PolyParam(poly, pnum) => ctx.typerState.constraint.entry(tp) match { case bounds: TypeBounds => wildApprox(WildcardType(bounds)) case NoType => WildcardType(wildApprox(poly.paramBounds(pnum)).bounds) -- cgit v1.2.3