Skip to content

Commit de6cbda

Browse files
committed
fix #12949: export synthetic given co-defined with class
1 parent 8a6703f commit de6cbda

File tree

5 files changed

+54
-15
lines changed

5 files changed

+54
-15
lines changed

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,17 @@ object SymDenotations {
711711
}
712712
)
713713

714+
/** Do this symbol and `cls` represent a pair of a given or implicit method and
715+
* its associated class that were defined by a single definition?
716+
* This can mean one of two things:
717+
* - the method and class are defined in a structural given instance, or
718+
* - the class is an implicit class and the method is its implicit conversion.
719+
*/
720+
final def isCoDefinedGiven(cls: Symbol)(using Context): Boolean =
721+
isAllOf(Method | Synthetic)
722+
&& isOneOf(GivenOrImplicit)
723+
&& name == cls.name.toTermName && owner == cls.owner
724+
714725
/** Is this a denotation of a stable term (or an arbitrary type)?
715726
* Terms are stable if they are idempotent (as in TreeInfo.Idempotent): that is, they always return the same value,
716727
* if any.

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,7 +1627,7 @@ trait Applications extends Compatibility {
16271627
/** Widen the result type of synthetic given methods from the implementation class to the
16281628
* type that's implemented. Example
16291629
*
1630-
* given I[X] as T { ... }
1630+
* given I[X]: T with { ... }
16311631
*
16321632
* This desugars to
16331633
*
@@ -1648,8 +1648,8 @@ trait Applications extends Compatibility {
16481648
mt.derivedLambdaType(mt.paramNames, mt.paramInfos, widenGiven(mt.resultType, alt))
16491649
case pt: PolyType =>
16501650
pt.derivedLambdaType(pt.paramNames, pt.paramInfos, widenGiven(pt.resultType, alt))
1651-
case _ =>
1652-
if (alt.symbol.isAllOf(SyntheticGivenMethod)) tp.widenToParents
1651+
case rt =>
1652+
if alt.symbol.isCoDefinedGiven(rt.typeSymbol) then tp.widenToParents
16531653
else tp
16541654
}
16551655

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -847,7 +847,8 @@ trait Checking {
847847

848848
sym.info.stripPoly match {
849849
case mt @ MethodType(_ :: Nil)
850-
if !mt.isImplicitMethod && !sym.is(Synthetic) => // it's an old-styleconversion
850+
if !mt.isImplicitMethod && !sym.isCoDefinedGiven(mt.finalResultType.typeSymbol) =>
851+
// it's an old-style conversion
851852
check()
852853
case _ =>
853854
}

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

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,17 +1101,25 @@ class Namer { typer: Typer =>
11011101

11021102
def addWildcardForwarders(seen: List[TermName], span: Span): Unit =
11031103
val nonContextual = mutable.HashSet(seen: _*)
1104-
for mbr <- path.tpe.membersBasedOnFlags(required = EmptyFlags, excluded = PrivateOrSynthetic) do
1105-
if !mbr.symbol.isSuperAccessor then
1106-
// Scala 2 superaccessors have neither Synthetic nor Artfact set, so we
1107-
// need to filter them out here (by contrast, Scala 3 superaccessors are Artifacts)
1108-
val alias = mbr.name.toTermName
1109-
if mbr.symbol.is(Given) then
1110-
if !seen.contains(alias) && mbr.matchesImportBound(givenBound) then
1111-
addForwarder(alias, mbr, span)
1112-
else if !nonContextual.contains(alias) && mbr.matchesImportBound(wildcardBound) then
1113-
nonContextual += alias
1114-
addWildcardForwardersNamed(alias, span)
1104+
for
1105+
mbr <- path.tpe.membersBasedOnFlags(required = EmptyFlags, excluded = Artifact|Private)
1106+
if !mbr.symbol.isSuperAccessor
1107+
do
1108+
val alias = mbr.name.toTermName
1109+
val isSynthetic = mbr.filterWithFlags(required = Synthetic, excluded = EmptyFlags).exists
1110+
// Scala 2 superaccessors have neither Synthetic nor Artfact set, so we
1111+
// need to filter them out here (by contrast, Scala 3 superaccessors are Artifacts)
1112+
if mbr.symbol.is(Given) then
1113+
val eligable = !seen.contains(alias) && mbr.matchesImportBound(givenBound)
1114+
if
1115+
eligable && (!isSynthetic || mbr.symbol.exists
1116+
&& mbr.symbol.isCoDefinedGiven(mbr.info.finalResultType.typeSymbol)
1117+
)
1118+
then
1119+
addForwarder(alias, mbr, span)
1120+
else if !isSynthetic && !nonContextual.contains(alias) && mbr.matchesImportBound(wildcardBound) then
1121+
nonContextual += alias
1122+
addWildcardForwardersNamed(alias, span)
11151123

11161124
def addForwarders(sels: List[untpd.ImportSelector], seen: List[TermName]): Unit = sels match
11171125
case sel :: sels1 =>

tests/pos/i12949.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
object Catch22:
2+
trait TC[V]
3+
object TC:
4+
export Hodor.TC.given
5+
6+
object Hodor:
7+
object TC:
8+
import Catch22.TC
9+
given fromString[V <: String]: TC[V] = ???
10+
transparent inline given fromDouble[V <: Double]: TC[V] =
11+
new TC[V]:
12+
type Out = Double
13+
given fromInt[V <: Int]: TC[V] with
14+
type Out = Int
15+
16+
object Test:
17+
summon[Catch22.TC["hi"]] //works
18+
summon[Catch22.TC[7.7]] //works
19+
summon[Catch22.TC[1]] //error

0 commit comments

Comments
 (0)