Skip to content

fix #12949: export synthetic given co-defined with class #12999

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

Closed
wants to merge 1 commit into from
Closed
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
11 changes: 11 additions & 0 deletions compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,17 @@ object SymDenotations {
}
)

/** Do this symbol and `cls` represent a pair of a given or implicit method and
* its associated class that were defined by a single definition?
* This can mean one of two things:
* - the method and class are defined in a structural given instance, or
* - the class is an implicit class and the method is its implicit conversion.
*/
final def isCoDefinedGiven(cls: Symbol)(using Context): Boolean =
isAllOf(Method | Synthetic)
&& isOneOf(GivenOrImplicit)
&& name == cls.name.toTermName && owner == cls.owner

/** Is this a denotation of a stable term (or an arbitrary type)?
* Terms are stable if they are idempotent (as in TreeInfo.Idempotent): that is, they always return the same value,
* if any.
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1627,7 +1627,7 @@ trait Applications extends Compatibility {
/** Widen the result type of synthetic given methods from the implementation class to the
* type that's implemented. Example
*
* given I[X] as T { ... }
* given I[X]: T with { ... }
*
* This desugars to
*
Expand All @@ -1648,8 +1648,8 @@ trait Applications extends Compatibility {
mt.derivedLambdaType(mt.paramNames, mt.paramInfos, widenGiven(mt.resultType, alt))
case pt: PolyType =>
pt.derivedLambdaType(pt.paramNames, pt.paramInfos, widenGiven(pt.resultType, alt))
case _ =>
if (alt.symbol.isAllOf(SyntheticGivenMethod)) tp.widenToParents
case rt =>
if alt.symbol.isCoDefinedGiven(rt.typeSymbol) then tp.widenToParents
else tp
}

Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,8 @@ trait Checking {

sym.info.stripPoly match {
case mt @ MethodType(_ :: Nil)
if !mt.isImplicitMethod && !sym.is(Synthetic) => // it's an old-styleconversion
if !mt.isImplicitMethod && !sym.isCoDefinedGiven(mt.finalResultType.typeSymbol) =>
// it's an old-style conversion
check()
case _ =>
}
Expand Down
30 changes: 19 additions & 11 deletions compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1101,17 +1101,25 @@ class Namer { typer: Typer =>

def addWildcardForwarders(seen: List[TermName], span: Span): Unit =
val nonContextual = mutable.HashSet(seen: _*)
for mbr <- path.tpe.membersBasedOnFlags(required = EmptyFlags, excluded = PrivateOrSynthetic) do
if !mbr.symbol.isSuperAccessor then
// Scala 2 superaccessors have neither Synthetic nor Artfact set, so we
// need to filter them out here (by contrast, Scala 3 superaccessors are Artifacts)
val alias = mbr.name.toTermName
if mbr.symbol.is(Given) then
if !seen.contains(alias) && mbr.matchesImportBound(givenBound) then
addForwarder(alias, mbr, span)
else if !nonContextual.contains(alias) && mbr.matchesImportBound(wildcardBound) then
nonContextual += alias
addWildcardForwardersNamed(alias, span)
for
mbr <- path.tpe.membersBasedOnFlags(required = EmptyFlags, excluded = Artifact|Private)
if !mbr.symbol.isSuperAccessor
do
val alias = mbr.name.toTermName
val isSynthetic = mbr.filterWithFlags(required = Synthetic, excluded = EmptyFlags).exists
// Scala 2 superaccessors have neither Synthetic nor Artfact set, so we
// need to filter them out here (by contrast, Scala 3 superaccessors are Artifacts)
if mbr.symbol.is(Given) then
val eligable = !seen.contains(alias) && mbr.matchesImportBound(givenBound)
if
eligable && (!isSynthetic || mbr.symbol.exists
&& mbr.symbol.isCoDefinedGiven(mbr.info.finalResultType.typeSymbol)
)
then
addForwarder(alias, mbr, span)
else if !isSynthetic && !nonContextual.contains(alias) && mbr.matchesImportBound(wildcardBound) then
nonContextual += alias
addWildcardForwardersNamed(alias, span)

def addForwarders(sels: List[untpd.ImportSelector], seen: List[TermName]): Unit = sels match
case sel :: sels1 =>
Expand Down
19 changes: 19 additions & 0 deletions tests/pos/i12949.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
object Catch22:
trait TC[V]
object TC:
export Hodor.TC.given

object Hodor:
object TC:
import Catch22.TC
given fromString[V <: String]: TC[V] = ???
transparent inline given fromDouble[V <: Double]: TC[V] =
new TC[V]:
type Out = Double
given fromInt[V <: Int]: TC[V] with
type Out = Int

object Test:
summon[Catch22.TC["hi"]] //works
summon[Catch22.TC[7.7]] //works
summon[Catch22.TC[1]] //error