Skip to content

Fix #2152: Instantiate dependent result type parameters #2209

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/NameKinds.scala
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ object NameKinds {
val InlineAccessorName = new UniqueNameKind("$_inlineAccessor_$")
val TempResultName = new UniqueNameKind("ev$")
val EvidenceParamName = new UniqueNameKind("evidence$")
val DepParamName = new UniqueNameKind("<param>")
val DepParamName = new UniqueNameKind("(param)")
val LazyImplicitName = new UniqueNameKind("$_lazy_implicit_$")
val LazyLocalName = new UniqueNameKind("$lzy")
val LazyLocalInitName = new UniqueNameKind("$lzyINIT")
Expand Down
7 changes: 6 additions & 1 deletion compiler/src/dotty/tools/dotc/core/TypeOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import SymDenotations._, Denotations.SingleDenotation
import config.Printers.typr
import util.Positions._
import NameOps._
import NameKinds.DepParamName
import Decorators._
import StdNames._
import Annotations._
Expand Down Expand Up @@ -158,7 +159,11 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
case tp1 => tp1
}
case tp: TypeParamRef =>
typerState.constraint.typeVarOfParam(tp) orElse tp
if (tp.paramName.is(DepParamName)) {
val bounds = ctx.typeComparer.bounds(tp)
if (bounds.lo.isRef(defn.NothingClass)) bounds.hi else bounds.lo
}
else typerState.constraint.typeVarOfParam(tp) orElse tp
case _: ThisType | _: BoundType | NoPrefix =>
tp
case tp: RefinedType =>
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3509,7 +3509,7 @@ object Types {

def apply(tp: Type): Type

protected var variance = 1
protected[core] var variance = 1

protected def derivedSelect(tp: NamedType, pre: Type): Type =
tp.derivedSelect(pre)
Expand Down
17 changes: 9 additions & 8 deletions compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -377,9 +377,10 @@ object ProtoTypes {
* Also, if `owningTree` is non-empty, add a type variable for each parameter.
* @return The added type lambda, and the list of created type variables.
*/
def constrained(tl: TypeLambda, owningTree: untpd.Tree)(implicit ctx: Context): (TypeLambda, List[TypeTree]) = {
def constrained(tl: TypeLambda, owningTree: untpd.Tree, alwaysAddTypeVars: Boolean = false)(implicit ctx: Context): (TypeLambda, List[TypeTree]) = {
val state = ctx.typerState
assert(!(ctx.typerState.isCommittable && owningTree.isEmpty),
val addTypeVars = alwaysAddTypeVars || !owningTree.isEmpty
assert(!(ctx.typerState.isCommittable && !addTypeVars),
s"inconsistent: no typevars were added to committable constraint ${state.constraint}")

def newTypeVars(tl: TypeLambda): List[TypeTree] =
Expand All @@ -392,21 +393,21 @@ object ProtoTypes {
val added =
if (state.constraint contains tl) tl.newLikeThis(tl.paramNames, tl.paramInfos, tl.resultType)
else tl
val tvars = if (owningTree.isEmpty) Nil else newTypeVars(added)
val tvars = if (addTypeVars) newTypeVars(added) else Nil
ctx.typeComparer.addToConstraint(added, tvars.tpes.asInstanceOf[List[TypeVar]])
(added, tvars)
}

/** Same as `constrained(tl, EmptyTree)`, but returns just the created type lambda */
def constrained(tl: TypeLambda)(implicit ctx: Context): TypeLambda = constrained(tl, EmptyTree)._1

/** Create a new TypeParamRef that represents a dependent method parameter singleton */
def newDepTypeParamRef(tp: Type)(implicit ctx: Context): TypeParamRef = {
/** Create a new TypeVar that represents a dependent method parameter singleton */
def newDepTypeVar(tp: Type)(implicit ctx: Context): TypeVar = {
val poly = PolyType(DepParamName.fresh().toTypeName :: Nil)(
pt => TypeBounds.upper(AndType(tp, defn.SingletonType)) :: Nil,
pt => defn.AnyType)
ctx.typeComparer.addToConstraint(poly, Nil)
TypeParamRef(poly, 0)
constrained(poly, untpd.EmptyTree, alwaysAddTypeVars = true)
._2.head.tpe.asInstanceOf[TypeVar]
}

/** The result type of `mt`, where all references to parameters of `mt` are
Expand All @@ -415,7 +416,7 @@ object ProtoTypes {
def resultTypeApprox(mt: MethodType)(implicit ctx: Context): Type =
if (mt.isDependent) {
def replacement(tp: Type) =
if (ctx.mode.is(Mode.TypevarsMissContext)) WildcardType else newDepTypeParamRef(tp)
if (ctx.mode.is(Mode.TypevarsMissContext)) WildcardType else newDepTypeVar(tp)
mt.resultType.substParams(mt, mt.paramInfos.map(replacement))
}
else mt.resultType
Expand Down
7 changes: 7 additions & 0 deletions tests/pos/i2152.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class Contra[-D](task: AnyRef)
object Test {
def narrow(task: AnyRef): Contra[task.type] = new Contra(task)
def ident[Before](elems: Contra[Before]): Contra[Before] = elems
val foo = null
ident(narrow(foo))
}