diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 53ad330eea35..f5f35a995cdb 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -292,23 +292,58 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def TypeDef(sym: TypeSymbol)(using Context): TypeDef = ta.assignType(untpd.TypeDef(sym.name, TypeTree(sym.info)), sym) - def ClassDef(cls: ClassSymbol, constr: DefDef, body: List[Tree], superArgs: List[Tree] = Nil)(using Context): TypeDef = { + def ClassDef(cls: ClassSymbol, constrDef: DefDef, body: List[Tree])(using Context): TypeDef = { val firstParent :: otherParents = cls.info.parents: @unchecked val superRef = if (cls.is(Trait)) TypeTree(firstParent) else { - def isApplicable(ctpe: Type): Boolean = ctpe match { - case ctpe: PolyType => - isApplicable(ctpe.instantiate(firstParent.argTypes)) - case ctpe: MethodType => - (superArgs corresponds ctpe.paramInfos)(_.tpe <:< _) + def fromRepeated(tpe: Type): Type = tpe match { + case AnnotatedType(AppliedType(base, List(tparam)), annot) if annot.symbol == defn.RepeatedAnnot => + tparam case _ => - false + NoType } - val constr = firstParent.decl(nme.CONSTRUCTOR).suchThat(constr => isApplicable(constr.info)) - New(firstParent, constr.symbol.asTerm, superArgs) + + def canConstructMethod(constrSym: Symbol): Boolean = constrSym.info match { + case ctpe: MethodOrPoly => + constrSym.paramSymss.flatten.filter(_.isTerm).forall { paramSym => + paramSym.flags.is(Flags.HasDefault) || (fromRepeated(paramSym.info) != NoType) + } + case _ => false + } + + def constructParent(constr: Tree): Tree = { + constr.symbol.paramSymss.filter(!_.exists(_.isType)).foldLeft(constr) { (acc, paramList) => + acc.appliedToTermArgs(paramList.zipWithIndex.collect { + case (paramSym, idx) if paramSym.flags.is(Flags.HasDefault) => + typer.Applications.defaultArgument(acc, idx, false) + case (paramSym, idx) if fromRepeated(paramSym.info) != NoType => + tpd.ref(defn.NilModule) + }) + } + } + + val tycon = firstParent.typeConstructor + val newTree = New(tycon) + .withSpan(cls.span) + val constr = firstParent + .decl(nme.CONSTRUCTOR) + .suchThat{ constr => + canConstructMethod(constr) + } + + if constr.exists then + constructParent( + newTree + .select(TermRef(tycon, constr.symbol.asTerm)) + .appliedToTypes(firstParent.argTypes) + ) + else + val msg = em"not enough arguments for constructor ${firstParent.dealias.typeSymbol.primaryConstructor.info}" + report.error(msg, cls.sourcePos) + EmptyTree } - ClassDefWithParents(cls, constr, superRef :: otherParents.map(TypeTree(_)), body) + ClassDefWithParents(cls, constrDef, superRef :: otherParents.map(TypeTree(_)), body) } def ClassDefWithParents(cls: ClassSymbol, constr: DefDef, parents: List[Tree], body: List[Tree])(using Context): TypeDef = { diff --git a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala index 63bac2fb0f2a..157c729c1cf7 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala @@ -182,4 +182,5 @@ class ExpandSAMs extends MiniPhase: case tpe => tpe } + end ExpandSAMs diff --git a/tests/neg/i15855.scala b/tests/neg/i15855.scala new file mode 100644 index 000000000000..fa333a655077 --- /dev/null +++ b/tests/neg/i15855.scala @@ -0,0 +1,7 @@ +class MyFunction(arg: String) + +trait MyFun[+R] extends MyFunction { + def apply(i: Int): R +} + +val myFun: MyFun[Int] = (i: Int) => 1 // error diff --git a/tests/run/i15855.check b/tests/run/i15855.check new file mode 100644 index 000000000000..3343fff53e31 --- /dev/null +++ b/tests/run/i15855.check @@ -0,0 +1,11 @@ +default +List() +other +asdf +420 +21.37 +1 +2 +3 +4 +5 diff --git a/tests/run/i15855.scala b/tests/run/i15855.scala new file mode 100644 index 000000000000..fda7a76d42f3 --- /dev/null +++ b/tests/run/i15855.scala @@ -0,0 +1,82 @@ +class MyFunction1() + +trait MyFun1[+R] extends MyFunction1 { + def apply(i: Int): R +} + +val myFun1: MyFun1[Int] = (i: Int) => 1 + +// + +class MyFunction2(arg: String = "default") { + println(arg) +} + +trait MyFun2[+R] extends MyFunction2 { + def apply(i: Int): R +} + +val myFun2: MyFun2[Int] = (i: Int) => 2 + +// + +class MyFunction3(arg: String*) { + println(arg) +} + +trait MyFun3[+R] extends MyFunction3 { + def apply(i: Int): R +} + +val myFun3: MyFun3[Int] = (i: Int) => 3 + +// + +class MyFunction4(arg: String) { + println(arg) + def this() = { + this("other") + } +} + +trait MyFun4[+R] extends MyFunction4 { + def apply(i: Int): R +} + +val myFun4: MyFun4[Int] = (i: Int) => 4 + +// + +class MyFunction5(arg: String = "asdf")(arg1: Int = 420, arg2: Double = 21.37) { + println(arg) + println(arg1) + println(arg2) +} + +trait MyFun5[+R] extends MyFunction5 { + def apply(i: Int): R +} + +val myFun5: MyFun5[Int] = (i: Int) => 5 + +// + +trait Equiv[T] extends Any with Serializable { + def equiv(x: T, y: T): Boolean +} + +def reference[T <: AnyRef]: Equiv[T] = { _ eq _ } +def universal[T]: Equiv[T] = { _ == _ } +def fromFunction[T](cmp: (T, T) => Boolean): Equiv[T] = { + (x, y) => cmp(x, y) +} + +// + +object Test extends App { + println(myFun1(1)) + println(myFun2(1)) + println(myFun3(1)) + println(myFun4(1)) + println(myFun5(1)) +}