Skip to content

Commit c97685d

Browse files
Remove synthetic record constructor if the user has written one manually
Co-authored-by: Guillaume Martres <[email protected]>
1 parent 7220dd8 commit c97685d

File tree

5 files changed

+33
-13
lines changed

5 files changed

+33
-13
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,7 @@ class Definitions {
688688
@tu lazy val JavaCalendarClass: ClassSymbol = requiredClass("java.util.Calendar")
689689
@tu lazy val JavaDateClass: ClassSymbol = requiredClass("java.util.Date")
690690
@tu lazy val JavaFormattableClass: ClassSymbol = requiredClass("java.util.Formattable")
691+
@tu lazy val JavaRecordClass: Symbol = getClassIfDefined("java.lang.Record")
691692

692693
@tu lazy val JavaEnumClass: ClassSymbol = {
693694
val cls = requiredClass("java.lang.Enum")

compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -852,7 +852,7 @@ object JavaParsers {
852852

853853
// generate the canonical constructor
854854
val canonicalConstructor =
855-
DefDef(nme.CONSTRUCTOR, joinParams(tparams, List(header)), TypeTree(), EmptyTree).withMods(Modifiers(Flags.JavaDefined, mods.privateWithin))
855+
DefDef(nme.CONSTRUCTOR, joinParams(tparams, List(header)), TypeTree(), EmptyTree).withMods(Modifiers(Flags.JavaDefined | Flags.Synthetic, mods.privateWithin))
856856

857857
// return the trees, probably with addCompanionObject (like classDecl)
858858
val recordTypeDef = atSpan(start, nameOffset) {
@@ -863,7 +863,7 @@ object JavaParsers {
863863
tparams = tparams,
864864
true
865865
)
866-
)
866+
).withMods(mods)
867867
}
868868
addCompanionObject(statics, recordTypeDef)
869869
end recordDecl

compiler/src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -879,10 +879,18 @@ class Namer { typer: Typer =>
879879
!sd.symbol.is(Deferred) && sd.matches(denot)))
880880

881881
val isClashingSynthetic =
882-
denot.is(Synthetic, butNot = ConstructorProxy)
883-
&& desugar.isRetractableCaseClassMethodName(denot.name)
884-
&& isCaseClassOrCompanion(denot.owner)
885-
&& (definesMember || inheritsConcreteMember)
882+
denot.is(Synthetic, butNot = ConstructorProxy) &&
883+
(
884+
(desugar.isRetractableCaseClassMethodName(denot.name)
885+
&& isCaseClassOrCompanion(denot.owner)
886+
&& (definesMember || inheritsConcreteMember))
887+
||
888+
// remove synthetic constructor of a java Record if it clashes with a non-synthetic constructor
889+
(denot.isConstructor
890+
&& denot.owner.is(JavaDefined) && denot.owner.derivesFrom(defn.JavaRecordClass)
891+
&& denot.owner.unforcedDecls.lookupAll(denot.name).exists(c => c != denot.symbol && c.info.matches(denot.info))
892+
)
893+
)
886894

887895
if isClashingSynthetic then
888896
typr.println(i"invalidating clashing $denot in ${denot.owner}")
@@ -1734,7 +1742,7 @@ class Namer { typer: Typer =>
17341742
}
17351743

17361744
/** The type signature of a DefDef with given symbol */
1737-
def defDefSig(ddef: DefDef, sym: Symbol, completer: Namer#Completer)(using Context): Type = {
1745+
def defDefSig(ddef: DefDef, sym: Symbol, completer: Namer#Completer)(using Context): ErrorType | Type = {
17381746
// Beware: ddef.name need not match sym.name if sym was freshened!
17391747
val isConstructor = sym.name == nme.CONSTRUCTOR
17401748

@@ -1776,7 +1784,18 @@ class Namer { typer: Typer =>
17761784
if isConstructor then
17771785
// set result type tree to unit, but take the current class as result type of the symbol
17781786
typedAheadType(ddef.tpt, defn.UnitType)
1779-
wrapMethType(effectiveResultType(sym, paramSymss))
1787+
val res = wrapMethType(effectiveResultType(sym, paramSymss))
1788+
res
1789+
/* val unlink = sym.owner.is(JavaDefined) && sym.is(Synthetic) && sym.owner.derivesFrom(defn.JavaRecordClass) &&
1790+
sym.owner.unforcedDecls.lookupAll(sym.name).exists(c => c != sym && c.info.matches(res))
1791+
1792+
//println(s"sym: $sym, sym.owner ${sym.owner.flagsUNSAFE.flagsString}, sym ${sym.flagsUNSAFE.flagsString}")
1793+
//if sym.owner.is(JavaDefined) && sym.is(Synthetic) && sym.owner.derivesFrom(defn.JavaRecordClass) then
1794+
// println(s"unlink: $unlink -- ${sym.owner.info.decl(sym.name).alternatives}")
1795+
if unlink then
1796+
sym.markAbsent()
1797+
NoType
1798+
else res*/
17801799
else
17811800
valOrDefDefSig(ddef, sym, paramSymss, wrapMethType)
17821801
}

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2360,7 +2360,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
23602360

23612361
def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(using Context): Tree = {
23622362
if (!sym.info.exists) { // it's a discarded synthetic case class method, drop it
2363-
assert(sym.is(Synthetic) && desugar.isRetractableCaseClassMethodName(sym.name))
2363+
assert(sym.is(Synthetic) /*&& desugar.isRetractableCaseClassMethodName(sym.name)*/, s"$sym -- ${sym.flags.flagsString}")
23642364
sym.owner.info.decls.openForMutations.unlink(sym)
23652365
return EmptyTree
23662366
}

tests/pos-java16+/java-records/R2.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ public int getInt() {
55
}
66

77
// Canonical constructor
8-
// public R(int i, java.lang.String s) {
9-
// this.i = i;
10-
// this.s = s.intern();
11-
// }
8+
public R(int i, java.lang.String s) {
9+
this.i = i;
10+
this.s = s.intern();
11+
}
1212
}
1313
}

0 commit comments

Comments
 (0)