diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index 0f08e470103e..0c3fffe87887 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -283,7 +283,7 @@ object NameKinds { val ProtectedAccessorName = new PrefixNameKind(PROTECTEDACCESSOR, "protected$") val ProtectedSetterName = new PrefixNameKind(PROTECTEDSETTER, "protected$set") // dubious encoding, kept for Scala2 compatibility val AvoidClashName = new SuffixNameKind(AVOIDCLASH, "$_avoid_name_clash_$") - val DirectName = new SuffixNameKind(DIRECT, "$direct") + val DirectMethodName = new SuffixNameKind(DIRECT, "$direct") { override def definesNewName = true } val FieldName = new SuffixNameKind(FIELD, "$$local") val ExtMethName = new SuffixNameKind(EXTMETH, "$extension") val ModuleVarName = new SuffixNameKind(OBJECTVAR, "$module") diff --git a/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala b/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala index 2fea1984730f..ec82b5d33b74 100644 --- a/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala +++ b/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala @@ -11,7 +11,7 @@ import core.Decorators._ import core.StdNames.nme import core.Names._ import core.NameOps._ -import core.NameKinds.DirectName +import core.NameKinds.DirectMethodName import ast.Trees._ import ast.tpd import collection.mutable @@ -77,6 +77,7 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisTr private def shouldBeSpecialized(sym: Symbol)(implicit ctx: Context) = sym.is(Method, butNot = Accessor) && defn.isImplicitFunctionType(sym.info.finalResultType) && + !sym.isAnonymousFunction && (specializeMonoTargets || !sym.isEffectivelyFinal || sym.allOverriddenSymbols.nonEmpty) /** @pre The type's final result type is an implicit function type `implicit Ts => R`. @@ -92,7 +93,7 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisTr /** A new `m$direct` method to accompany the given method `m` */ private def newDirectMethod(sym: Symbol)(implicit ctx: Context): Symbol = { val direct = sym.copy( - name = DirectName(sym.name.asTermName).asInstanceOf[sym.ThisName], + name = DirectMethodName(sym.name.asTermName).asInstanceOf[sym.ThisName], flags = sym.flags | Synthetic, info = directInfo(sym.info)) if (direct.allOverriddenSymbols.isEmpty) direct.resetFlag(Override) @@ -104,14 +105,13 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisTr */ private def directMethod(sym: Symbol)(implicit ctx: Context): Symbol = if (sym.owner.isClass) { - val direct = sym.owner.info.member(DirectName(sym.name.asTermName)) + val direct = sym.owner.info.member(DirectMethodName(sym.name.asTermName)) .suchThat(_.info matches directInfo(sym.info)).symbol if (direct.maybeOwner == sym.owner) direct else newDirectMethod(sym).enteredAfter(thisTransform) } else directMeth.getOrElseUpdate(sym, newDirectMethod(sym)) - /** Transform `qual.apply` occurrences according to rewrite rule (2) above */ override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo) = if (tree.name == nme.apply && @@ -122,7 +122,7 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisTr case TypeApply(fn, args) => cpy.TypeApply(tree)(directQual(fn), args) case Block(stats, expr) => cpy.Block(tree)(stats, directQual(expr)) case tree: RefTree => - cpy.Ref(tree)(DirectName(tree.name.asTermName)) + cpy.Ref(tree)(DirectMethodName(tree.name.asTermName)) .withType(directMethod(tree.symbol).termRef) } directQual(tree.qualifier) @@ -157,8 +157,8 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisTr val (remappedCore, fwdClosure) = splitClosure(mdef.rhs) val originalDef = cpy.DefDef(mdef)(rhs = fwdClosure) - val directDef = polyDefDef(direct.asTerm, remappedCore) - Thicket(originalDef, directDef) + val directDef = transformDefDef(polyDefDef(direct.asTerm, remappedCore)) + flatTree(List(originalDef, directDef)) } else mdef } diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 398a7a17e69e..e5a9ab8ffafc 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -422,8 +422,8 @@ object ProtoTypes { /** The normalized form of a type * - unwraps polymorphic types, tracking their parameters in the current constraint - * - skips implicit parameters; if result type depends on implicit parameter, - * replace with Wildcard. + * - skips implicit parameters of methods and functions; + * if result type depends on implicit parameter, replace with fresh type dependent parameter. * - converts non-dependent method types to the corresponding function types * - dereferences parameterless method types * - dereferences nullary method types provided the corresponding function type @@ -437,9 +437,10 @@ object ProtoTypes { */ def normalize(tp: Type, pt: Type)(implicit ctx: Context): Type = Stats.track("normalize") { tp.widenSingleton match { - case poly: PolyType => normalize(constrained(poly).resultType, pt) + case poly: PolyType => + normalize(constrained(poly).resultType, pt) case mt: MethodType => - if (mt.isImplicit) resultTypeApprox(mt) + if (mt.isImplicit) normalize(resultTypeApprox(mt), pt) else if (mt.isDependent) tp else { val rt = normalize(mt.resultType, pt) @@ -451,8 +452,11 @@ object ProtoTypes { if (mt.paramInfos.nonEmpty || ft <:< pt) ft else rt } } - case et: ExprType => et.resultType - case _ => tp + case et: ExprType => + normalize(et.resultType, pt) + case wtp => + if (defn.isImplicitFunctionType(wtp)) normalize(wtp.dealias.argInfos.last, pt) + else tp } } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 4bf938fd4344..a5e6b238e98a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1582,7 +1582,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit 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") - typedUnadapted(ifun) + typed(ifun, pt) } def typed(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = /*>|>*/ ctx.traceIndented (i"typing $tree", typr, show = true) /*<|<*/ { diff --git a/tests/neg/i2146.scala b/tests/neg/i2146.scala new file mode 100644 index 000000000000..13ecf1e7b680 --- /dev/null +++ b/tests/neg/i2146.scala @@ -0,0 +1,8 @@ +object Test { + case class A() + case class B() + + def foo[A, B]: implicit A => implicit B => Int = { implicit b: B => + 42 // error: found Int, required: implicit A => implicit B => Int + } +} diff --git a/tests/pos/i2146.check b/tests/pos/i2146.check new file mode 100644 index 000000000000..b9303dd2be3c --- /dev/null +++ b/tests/pos/i2146.check @@ -0,0 +1,9 @@ +(A(),B()) +(A(),B()) +(A(),B()) +A() +(A(),B()) +(A(),B()) +(A(),B()) +(A(),B()) +(A(),B()) \ No newline at end of file diff --git a/tests/pos/i2146.scala b/tests/pos/i2146.scala new file mode 100644 index 000000000000..8bb08de86e58 --- /dev/null +++ b/tests/pos/i2146.scala @@ -0,0 +1,32 @@ +object Test { + case class A() + case class B() + + def simple[A]: implicit A => A = implicitly[A] + + def foo[A, B]: implicit A => implicit B => (A, B) = + (implicitly[A], implicitly[B]) + + def bar[A, B]: implicit A => implicit B => (A, B) = { implicit a: A => + (implicitly[A], implicitly[B]) + } + + implicit val a: A = A() + implicit val b: B = B() + + def main(args: Array[String]) = { + println(foo[A, B]) + println(foo[A, B](a)) + println(foo(a)(b)) + val s: implicit A => A = simple[A] + println(s) + val x0: implicit A => implicit B => (A, B) = foo[A, B] + println(x0) + val x1: implicit B => (A, B) = foo[A, B] + println(x1) + + println(bar[A, B]) + println(bar[A, B](a)) + println(bar(a)(b)) + } +}