Skip to content
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

Make apply proxies work with overloaded ctors #19464

Merged
merged 2 commits into from
Jan 30, 2024
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
47 changes: 30 additions & 17 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4297,8 +4297,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) =>
Expand All @@ -4309,17 +4313,27 @@ 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))),
nme.CONSTRUCTOR),
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
Expand All @@ -4333,7 +4347,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 =>
Expand All @@ -4342,22 +4356,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 _ =>
Expand Down
12 changes: 12 additions & 0 deletions tests/pos/i19201.scala
Original file line number Diff line number Diff line change
@@ -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")
Loading