diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 7728ab06d089..e3f1f99e1bb5 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -4237,8 +4237,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer case _ => } - /** Convert constructor proxy reference to a new expression */ - def newExpr = + /** If `tree` is a constructor proxy reference, convert it to a `new` expression, + * otherwise return EmptyTree. + */ + def newExpr(tree: Tree): Tree = + val ctorResultType = applyProxyResultType(tree) + if !ctorResultType.exists then return EmptyTree val qual = qualifier(tree) val tpt = qual match case Ident(name) => @@ -4249,7 +4253,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer cpy.Ident(qual)(qual.symbol.name.sourceModuleName.toTypeName) case _ => errorTree(tree, em"cannot convert from $tree to an instance creation expression") - val tycon = tree.tpe.widen.finalResultType.underlyingClassRef(refinementOK = false) + val tycon = ctorResultType.underlyingClassRef(refinementOK = false) typed( untpd.Select( untpd.New(untpd.TypedSplice(tpt.withType(tycon))), @@ -4257,9 +4261,19 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer pt) .showing(i"convert creator $tree -> $result", typr) - def isApplyProxy(tree: Tree) = tree match - case Select(_, nme.apply) => tree.symbol.isAllOf(ApplyProxyFlags) - case _ => false + /** If `tree` is a constructor proxy reference, return the type it constructs, + * otherwise return NoType. + */ + def applyProxyResultType(tree: Tree): Type = tree match + case Select(_, nme.apply) => + // can't use tree.symbol and tree.tpe.widen.finalResultType, because when overloaded + // tree.symbol is NoSymbol (via MultiDenotation.symbol) and tree.tpe won't widen. + tree.denot.altsWith(_.isAllOf(ApplyProxyFlags)) match + case denot :: _ => + // any of the constructors will do, in order to get the result type, so using the first one + denot.info.widen.finalResultType + case _ => NoType + case _ => NoType tree match { case _: MemberDef | _: PackageDef | _: Import | _: WithoutTypeOrPos[?] | _: Closure => tree @@ -4273,7 +4287,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer if needsTupledDual(ref, pt) && Feature.autoTuplingEnabled => adapt(tree, pt.tupledDual, locked) case _ => - adaptOverloaded(ref) + newExpr(tree).orElse(adaptOverloaded(ref)) } case poly: PolyType if !(ctx.mode is Mode.Type) && dummyTreeOfType.unapply(tree).isEmpty => @@ -4282,22 +4296,21 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer // Test case was but i18695.scala, but it got fixed by a different tweak in #18719. // We leave test for this condition in as a defensive measure in case // it arises somewhere else. - if isApplyProxy(tree) then newExpr - else if pt.isInstanceOf[PolyProto] then tree - else - var typeArgs = tree match - case Select(qual, nme.CONSTRUCTOR) => qual.tpe.widenDealias.argTypesLo.map(TypeTree(_)) - case _ => Nil - if typeArgs.isEmpty then typeArgs = constrained(poly, tree)._2.map(_.wrapInTypeTree(tree)) - convertNewGenericArray(readapt(tree.appliedToTypeTrees(typeArgs))) + newExpr(tree).orElse: + if pt.isInstanceOf[PolyProto] then tree + else + var typeArgs = tree match + case Select(qual, nme.CONSTRUCTOR) => qual.tpe.widenDealias.argTypesLo.map(TypeTree(_)) + case _ => Nil + if typeArgs.isEmpty then typeArgs = constrained(poly, tree)._2.map(_.wrapInTypeTree(tree)) + convertNewGenericArray(readapt(tree.appliedToTypeTrees(typeArgs))) case wtp => val isStructuralCall = wtp.isValueType && isStructuralTermSelectOrApply(tree) if (isStructuralCall) readaptSimplified(handleStructural(tree)) else pt match { case pt: FunProto => - if isApplyProxy(tree) then newExpr - else adaptToArgs(wtp, pt) + newExpr(tree).orElse(adaptToArgs(wtp, pt)) case pt: PolyProto if !wtp.isImplicitMethod => tryInsertApplyOrImplicit(tree, pt, locked)(tree) // error will be reported in typedTypeApply case _ => diff --git a/tests/pos/i19201.scala b/tests/pos/i19201.scala new file mode 100644 index 000000000000..4d9fa7bf3df1 --- /dev/null +++ b/tests/pos/i19201.scala @@ -0,0 +1,12 @@ +class Person( + val firstName: String, + val lastName: String, + val birthYear: Int = -1, + val address: String = "" +): + // Works if remove this constructor + def this() = this("John", "Doe") + +class Test: + def p1 = Person("First", "Last") // was: Type Error: none of the overloads.. match arguments + def p2 = Person("Josh", "Joe", 1912, "Main Street")