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

Add dependent function types #3464

Merged
merged 13 commits into from Nov 27, 2017

Implement implicit dependent function types

  • Loading branch information...
odersky committed Nov 14, 2017
commit 9b6d0c08f77379f8c4be793747a28f3f6e1f89b1
@@ -1328,10 +1328,7 @@ object Types {
val funType = defn.FunctionOf(
formals1 mapConserve (_.underlyingIfRepeated(mt.isJavaMethod)),
mt.nonDependentResultApprox, mt.isImplicitMethod && !ctx.erasedTypes)
if (mt.isDependent) {
assert(!mt.isImplicitMethod)
RefinedType(funType, nme.apply, mt)
}
if (mt.isDependent) RefinedType(funType, nme.apply, mt)
else funType
}
@@ -719,12 +719,10 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
completeParams(params)
val params1 = params.map(typedExpr(_).asInstanceOf[ValDef])
val resultTpt = typed(body)
val mt = MethodType.fromSymbols(params1.map(_.symbol), resultTpt.tpe)
val companion = if (isImplicit) ImplicitMethodType else MethodType
val mt = companion.fromSymbols(params1.map(_.symbol), resultTpt.tpe)
if (mt.isParamDependent)
ctx.error(i"$mt is an illegal function type because it has inter-parameter dependencies", tree.pos)
if (isImplicit)
ctx.error(i"dependent function type $mt may not be implicit", tree.pos)
val resTpt = TypeTree(mt.nonDependentResultApprox).withPos(body.pos)
val typeArgs = params1.map(_.tpt) :+ resTpt
val tycon = TypeTree(funCls.typeRef)
@@ -1723,7 +1721,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
protected def makeImplicitFunction(tree: untpd.Tree, pt: Type)(implicit ctx: Context): Tree = {
val defn.FunctionOf(formals, resType, true) = pt.dealias
val defn.FunctionOf(formals, _, true) = pt.dealias.dropDependentRefinement

This comment has been minimized.

@OlivierBlanvillain

OlivierBlanvillain Nov 14, 2017

Contributor

Since .dropDependentRefinement is always used after .dealias I guess the dealias could be pushed inside

@OlivierBlanvillain

OlivierBlanvillain Nov 14, 2017

Contributor

Since .dropDependentRefinement is always used after .dealias I guess the dealias could be pushed inside

val paramTypes = formals.map(fullyDefinedType(_, "implicit function parameter", tree.pos))
val ifun = desugar.makeImplicitFunction(paramTypes, tree)
typr.println(i"make implicit function $tree / $pt ---> $ifun")
@@ -38,4 +38,5 @@ object DottyPredef {
final def assertFail(): Unit = throw new java.lang.AssertionError("assertion failed")
final def assertFail(message: => Any): Unit = throw new java.lang.AssertionError("assertion failed: " + message)
@inline final def implicitly[T](implicit ev: T): T = ev
}
View
@@ -15,4 +15,21 @@ object Test {
val d: C = c
val z = depfun3(d)
val z1: d.M = z
// Reproduced here because the one from DottyPredef is lacking a Tasty tree and
// therefore can't be inlined when testing non-bootstrapped.
// But inlining `implicitly` is vital to make the definition of `ifun` below work.
inline final def implicitly[T](implicit ev: T): T = ev

This comment has been minimized.

@OlivierBlanvillain

OlivierBlanvillain Nov 14, 2017

Contributor

Would changing implicitly to return ev.type instead of T help here?

@OlivierBlanvillain

OlivierBlanvillain Nov 14, 2017

Contributor

Would changing implicitly to return ev.type instead of T help here?

This comment has been minimized.

@smarter

smarter Nov 14, 2017

Member

The fact that adding inline changes how a method is typechecked doesn't seem like a great thing. I think @OlivierBlanvillain has some examples where it breaks working code.

@smarter

smarter Nov 14, 2017

Member

The fact that adding inline changes how a method is typechecked doesn't seem like a great thing. I think @OlivierBlanvillain has some examples where it breaks working code.

This comment has been minimized.

@odersky

odersky Nov 15, 2017

Contributor

I am a bit nervous about changing it to ev.type. The inferencer has to do major acrobatics to deal with implicit method types. It might interfere with something else. The current type of implicitly is simpler and clearer.

@odersky

odersky Nov 15, 2017

Contributor

I am a bit nervous about changing it to ev.type. The inferencer has to do major acrobatics to deal with implicit method types. It might interfere with something else. The current type of implicitly is simpler and clearer.

type IDF = implicit (x: C) => x.M
implicit val ic: C = ???
val ifun: IDF = implicitly[C].m
val u = ifun(c)
val u1: Int = u
val v = ifun(d)
val v1: d.M = v
}
ProTip! Use n and p to navigate between commits in a pull request.