diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
index 057a93196154..8fd06ddc3933 100644
--- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
@@ -783,7 +783,7 @@ object desugar {
DefDef(
className.toTermName, joinParams(constrTparams, defParamss),
classTypeRef, creatorExpr)
- .withMods(companionMods | mods.flags.toTermFlags & GivenOrImplicit | Synthetic | Final)
+ .withMods(companionMods | mods.flags.toTermFlags & GivenOrImplicit | Final)
.withSpan(cdef.span) :: Nil
}
@@ -809,7 +809,7 @@ object desugar {
Nil
}
}
- val classMods = if mods.is(Given) then mods &~ Given | Synthetic else mods
+ val classMods = if mods.is(Given) then mods | Synthetic else mods
cpy.TypeDef(cdef: TypeDef)(
name = className,
rhs = cpy.Template(impl)(constr, parents1, clsDerived, self1,
diff --git a/compiler/src/dotty/tools/dotc/ast/TreeMapWithImplicits.scala b/compiler/src/dotty/tools/dotc/ast/TreeMapWithImplicits.scala
index 9e5b7f036aa0..359f5d5c2580 100644
--- a/compiler/src/dotty/tools/dotc/ast/TreeMapWithImplicits.scala
+++ b/compiler/src/dotty/tools/dotc/ast/TreeMapWithImplicits.scala
@@ -63,7 +63,7 @@ class TreeMapWithImplicits extends tpd.TreeMap {
private def nestedScopeCtx(defs: List[Tree])(using Context): Context = {
val nestedCtx = ctx.fresh.setNewScope
defs foreach {
- case d: DefTree if d.symbol.isOneOf(GivenOrImplicit) => nestedCtx.enter(d.symbol)
+ case d: DefTree if d.symbol.isOneOf(GivenOrImplicitVal) => nestedCtx.enter(d.symbol)
case _ =>
}
nestedCtx
@@ -74,7 +74,7 @@ class TreeMapWithImplicits extends tpd.TreeMap {
new TreeTraverser {
def traverse(tree: Tree)(using Context): Unit = {
tree match {
- case d: DefTree if d.symbol.isOneOf(GivenOrImplicit) =>
+ case d: DefTree if d.symbol.isOneOf(GivenOrImplicitVal) =>
nestedCtx.enter(d.symbol)
case _ =>
}
diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala
index 3c5adcba3aec..0b1646e23620 100644
--- a/compiler/src/dotty/tools/dotc/core/Contexts.scala
+++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala
@@ -13,7 +13,6 @@ import Scopes._
import Uniques._
import ast.Trees._
import ast.untpd
-import Flags.GivenOrImplicit
import util.{NoSource, SimpleIdentityMap, SourceFile, HashSet, ReusableInstance}
import typer.{Implicits, ImportInfo, Inliner, SearchHistory, SearchRoot, TypeAssigner, Typer, Nullables}
import Nullables._
diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala
index 890a0763938e..cb590e2384a0 100644
--- a/compiler/src/dotty/tools/dotc/core/Flags.scala
+++ b/compiler/src/dotty/tools/dotc/core/Flags.scala
@@ -233,7 +233,7 @@ object Flags {
val (Param @ _, TermParam @ _, TypeParam @ _) = newFlags(8, "")
/** Labeled with `implicit` modifier (implicit value) */
- val (Implicit @ _, ImplicitTerm @ _, _) = newFlags(9, "implicit")
+ val (Implicit @ _, ImplicitVal @ _, _) = newFlags(9, "implicit")
/** Labeled with `lazy` (a lazy val) / a trait */
val (LazyOrTrait @ _, Lazy @ _, Trait @ _) = newFlags(10, "lazy", "")
@@ -321,7 +321,7 @@ object Flags {
val (Extension @ _, ExtensionMethod @ _, _) = newFlags(28, "")
/** An inferable (`given`) parameter */
- val (Given @ _, _, _) = newFlags(29, "given")
+ val (Given @ _, GivenVal @ _, _) = newFlags(29, "given")
/** Symbol is defined by a Java class */
val (JavaDefined @ _, JavaDefinedVal @ _, _) = newFlags(30, "")
@@ -568,6 +568,7 @@ object Flags {
val FinalOrSealed: FlagSet = Final | Sealed
val GivenOrImplicit: FlagSet = Given | Implicit
val GivenOrImplicitVal: FlagSet = GivenOrImplicit.toTermFlags
+ val GivenMethod: FlagSet = Given | Method
val InlineOrProxy: FlagSet = Inline | InlineProxy // An inline method or inline argument proxy */
val InlineMethod: FlagSet = Inline | Method
val InlineParam: FlagSet = Inline | Param
@@ -600,7 +601,6 @@ object Flags {
val Scala2Trait: FlagSet = Scala2x | Trait
val SyntheticArtifact: FlagSet = Synthetic | Artifact
val SyntheticCase: FlagSet = Synthetic | Case
- val SyntheticGivenMethod: FlagSet = Synthetic | Given | Method
val SyntheticModule: FlagSet = Synthetic | Module
val SyntheticOpaque: FlagSet = Synthetic | Opaque
val SyntheticParam: FlagSet = Synthetic | Param
diff --git a/compiler/src/dotty/tools/dotc/core/Scopes.scala b/compiler/src/dotty/tools/dotc/core/Scopes.scala
index b22ce84849c1..5dc7ce168c24 100644
--- a/compiler/src/dotty/tools/dotc/core/Scopes.scala
+++ b/compiler/src/dotty/tools/dotc/core/Scopes.scala
@@ -411,7 +411,7 @@ object Scopes {
var irefs = new mutable.ListBuffer[TermRef]
var e = lastEntry
while (e ne null) {
- if (e.sym.isOneOf(GivenOrImplicit)) {
+ if (e.sym.isOneOf(GivenOrImplicitVal)) {
val d = e.sym.denot
irefs += TermRef(NoPrefix, d.symbol.asTerm).withDenot(d)
}
diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
index a7d45abd7a41..fcfbba208eb9 100644
--- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -711,6 +711,19 @@ 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 =
+ is(Method) && isOneOf(GivenOrImplicit)
+ && ( is(Synthetic) // previous scheme used in 3.0
+ || cls.isOneOf(GivenOrImplicit) // new scheme from 3.1
+ )
+ && 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.
@@ -2231,7 +2244,7 @@ object SymDenotations {
if (keepOnly eq implicitFilter)
if (this.is(Package)) Iterator.empty
// implicits in package objects are added by the overriding `memberNames` in `PackageClassDenotation`
- else info.decls.iterator.filter(_.isOneOf(GivenOrImplicit))
+ else info.decls.iterator.filter(_.isOneOf(GivenOrImplicitVal))
else info.decls.iterator
for (sym <- ownSyms) maybeAdd(sym.name)
names
diff --git a/compiler/src/dotty/tools/dotc/core/TypeErrors.scala b/compiler/src/dotty/tools/dotc/core/TypeErrors.scala
index 950963497fbc..c9ca98f65f5e 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeErrors.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeErrors.scala
@@ -141,7 +141,7 @@ class CyclicReference private (val denot: SymDenotation) extends TypeError {
}
// Give up and give generic errors.
- else if (cycleSym.isOneOf(GivenOrImplicit, butNot = Method) && cycleSym.owner.isTerm)
+ else if (cycleSym.isOneOf(GivenOrImplicitVal, butNot = Method) && cycleSym.owner.isTerm)
CyclicReferenceInvolvingImplicit(cycleSym)
else
CyclicReferenceInvolving(denot)
diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
index 59047c22403d..18db42f9e276 100644
--- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
+++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
@@ -722,9 +722,9 @@ class TreePickler(pickler: TastyPickler) {
if flags.is(Invisible) then writeModTag(INVISIBLE)
if (flags.is(Erased)) writeModTag(ERASED)
if (flags.is(Exported)) writeModTag(EXPORTED)
+ if (flags.is(Given)) writeModTag(GIVEN)
+ if (flags.is(Implicit)) writeModTag(IMPLICIT)
if (isTerm) {
- if (flags.is(Implicit)) writeModTag(IMPLICIT)
- if (flags.is(Given)) writeModTag(GIVEN)
if (flags.is(Lazy, butNot = Module)) writeModTag(LAZY)
if (flags.is(AbsOverride)) { writeModTag(ABSTRACT); writeModTag(OVERRIDE) }
if (flags.is(Mutable)) writeModTag(MUTABLE)
diff --git a/compiler/src/dotty/tools/dotc/interactive/Completion.scala b/compiler/src/dotty/tools/dotc/interactive/Completion.scala
index 8c19671293e0..bc63b958f1f0 100644
--- a/compiler/src/dotty/tools/dotc/interactive/Completion.scala
+++ b/compiler/src/dotty/tools/dotc/interactive/Completion.scala
@@ -323,7 +323,7 @@ object Completion {
val extMethodsFromImplicitScope = extractMemberExtensionMethods(implicitScopeCompanions)
// 4. The reference is of the form r.m and the extension method is defined in some given instance in the implicit scope of the type of r.
- val givensInImplicitScope = implicitScopeCompanions.flatMap(_.membersBasedOnFlags(required = Given, excluded = EmptyFlags)).map(_.info)
+ val givensInImplicitScope = implicitScopeCompanions.flatMap(_.membersBasedOnFlags(required = GivenVal, excluded = EmptyFlags)).map(_.info)
val extMethodsFromGivensInImplicitScope = extractMemberExtensionMethods(givensInImplicitScope)
val availableExtMethods = extMethodsFromGivensInImplicitScope ++ extMethodsFromImplicitScope ++ extMethodsFromGivensInScope ++ extMethodsInScope
diff --git a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala
index e3d6711af97f..aa1d7b102fb5 100644
--- a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala
+++ b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala
@@ -79,6 +79,8 @@ class ExtractSemanticDB extends Phase:
|| sym.isLocalDummy
|| sym.is(Synthetic)
|| sym.isSetter
+ || sym.isOldStyleImplicitConversion(forImplicitClassOnly = true)
+ || sym.owner.isGivenInstanceSummoner
|| excludeDefOrUse(sym)
private def excludeDefOrUse(sym: Symbol)(using Context): Boolean =
@@ -102,6 +104,7 @@ class ExtractSemanticDB extends Phase:
private def excludeChildren(sym: Symbol)(using Context): Boolean =
!sym.exists
|| sym.is(Param) && sym.info.bounds.hi.isInstanceOf[Types.HKTypeLambda]
+ || sym.isOldStyleImplicitConversion(forImplicitClassOnly = true)
/** Uses of this symbol where the reference has given span should be excluded from semanticdb */
private def excludeUse(qualifier: Option[Symbol], sym: Symbol)(using Context): Boolean =
diff --git a/compiler/src/dotty/tools/dotc/semanticdb/Tools.scala b/compiler/src/dotty/tools/dotc/semanticdb/Tools.scala
index a7bfdcefc047..ec427523195e 100644
--- a/compiler/src/dotty/tools/dotc/semanticdb/Tools.scala
+++ b/compiler/src/dotty/tools/dotc/semanticdb/Tools.scala
@@ -41,6 +41,11 @@ object Tools:
document.copy(text = text)
end loadTextDocument
+ def loadTextDocumentUnsafe(scalaAbsolutePath: Path, semanticdbAbsolutePath: Path): TextDocument =
+ val docs = parseTextDocuments(semanticdbAbsolutePath).documents
+ assert(docs.length == 1)
+ docs.head.copy(text = new String(Files.readAllBytes(scalaAbsolutePath), StandardCharsets.UTF_8))
+
/** Parses SemanticDB text documents from an absolute path to a `*.semanticdb` file. */
private def parseTextDocuments(path: Path): TextDocuments =
val bytes = Files.readAllBytes(path) // NOTE: a semanticdb file is a TextDocuments message, not TextDocument
diff --git a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala
index 353ebee25c29..acfb4be5c022 100644
--- a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala
+++ b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala
@@ -87,6 +87,31 @@ object SymUtils:
def isGenericProduct(using Context): Boolean = whyNotGenericProduct.isEmpty
+ /** Is this an old style implicit conversion?
+ * @param directOnly only consider explicitly written methods
+ * @param forImplicitClassOnly only consider methods generated from implicit classes
+ */
+ def isOldStyleImplicitConversion(directOnly: Boolean = false, forImplicitClassOnly: Boolean = false)(using Context): Boolean =
+ self.is(Implicit) && self.info.stripPoly.match
+ case mt @ MethodType(_ :: Nil) if !mt.isImplicitMethod =>
+ if self.isCoDefinedGiven(mt.finalResultType.typeSymbol)
+ then !directOnly
+ else !forImplicitClassOnly
+ case _ =>
+ false
+
+ /** Is this the method that summons a structural given instance? */
+ def isGivenInstanceSummoner(using Context): Boolean =
+ def isCodefined(info: Type): Boolean = info.stripPoly match
+ case mt: MethodType =>
+ // given summoner can only have contextual params
+ mt.isImplicitMethod && isCodefined(mt.resultType)
+ case mt: ExprType =>
+ isCodefined(mt.resultType)
+ case res =>
+ self.isCoDefinedGiven(res.typeSymbol)
+ self.isAllOf(Given | Method) && isCodefined(self.info)
+
def useCompanionAsMirror(using Context): Boolean = self.linkedClass.exists && !self.is(Scala2x)
/** Is this a sealed class or trait for which a sum mirror is generated?
diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala
index 9a83f9da4f02..2f34caf0e2f7 100644
--- a/compiler/src/dotty/tools/dotc/typer/Applications.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala
@@ -1631,7 +1631,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
*
@@ -1641,7 +1641,7 @@ trait Applications extends Compatibility {
* To compare specificity we should compare with `T`, not with its implementation `I[X]`.
* No such widening is performed for given aliases, which are not synthetic. E.g.
*
- * given J[X] as T = rhs
+ * given J[X]: T = rhs
*
* already has the right result type `T`. Neither is widening performed for given
* objects, since these are anyway taken to be more specific than methods
@@ -1652,8 +1652,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
}
diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala
index 5534d0c795fc..0f838ac20755 100644
--- a/compiler/src/dotty/tools/dotc/typer/Checking.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala
@@ -473,7 +473,7 @@ object Checking {
if (sym.is(Implicit)) {
if (sym.owner.is(Package))
fail(TopLevelCantBeImplicit(sym))
- if (sym.isType)
+ if sym.isType && (!sym.isClass || sym.is(Trait)) then
fail(TypesAndTraitsCantBeImplicit())
}
if sym.is(Transparent) then
@@ -861,22 +861,14 @@ trait Checking {
/** If `sym` is an old-style implicit conversion, check that implicit conversions are enabled.
* @pre sym.is(GivenOrImplicit)
*/
- def checkImplicitConversionDefOK(sym: Symbol)(using Context): Unit = {
- def check(): Unit =
+ def checkImplicitConversionDefOK(sym: Symbol)(using Context): Unit =
+ if sym.isOldStyleImplicitConversion(directOnly = true) then
checkFeature(
nme.implicitConversions,
i"Definition of implicit conversion $sym",
ctx.owner.topLevelClass,
sym.srcPos)
- sym.info.stripPoly match {
- case mt @ MethodType(_ :: Nil)
- if !mt.isImplicitMethod && !sym.is(Synthetic) => // it's an old-styleconversion
- check()
- case _ =>
- }
- }
-
/** If `tree` is an application of a new-style implicit conversion (using the apply
* method of a `scala.Conversion` instance), check that implicit conversions are
* enabled.
diff --git a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala
index a975dd206d22..e8a923427b38 100644
--- a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala
+++ b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala
@@ -151,7 +151,7 @@ class ImportInfo(symf: Context ?=> Symbol,
else
for
renamed <- reverseMapping.keys
- denot <- pre.member(reverseMapping(renamed)).altsWith(_.isOneOf(GivenOrImplicit))
+ denot <- pre.member(reverseMapping(renamed)).altsWith(_.isOneOf(GivenOrImplicitVal))
yield
val original = reverseMapping(renamed)
val ref = TermRef(pre, original, denot)
diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala
index 29a6da138e6c..1eb6c47bce4a 100644
--- a/compiler/src/dotty/tools/dotc/typer/Namer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala
@@ -241,7 +241,7 @@ class Namer { typer: Typer =>
tree match {
case tree: TypeDef if tree.isClassDef =>
- val flags = checkFlags(tree.mods.flags &~ Implicit)
+ val flags = checkFlags(tree.mods.flags)
val name = checkNoConflict(tree.name, flags.is(Private), tree.span).asTypeName
val cls =
createOrRefine[ClassSymbol](tree, name, flags, ctx.owner,
diff --git a/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala b/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala
index ac11d819b24d..919469529cb5 100644
--- a/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala
+++ b/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala
@@ -326,7 +326,7 @@ trait QuotesAndSplices {
tdef.symbol.addAnnotation(Annotation(New(ref(defn.QuotedRuntimePatterns_fromAboveAnnot.typeRef)).withSpan(tdef.span)))
val bindingType = getBinding(tdef.symbol).symbol.typeRef
val bindingTypeTpe = AppliedType(defn.QuotedTypeClass.typeRef, bindingType :: Nil)
- val sym = newPatternBoundSymbol(nameOfSyntheticGiven, bindingTypeTpe, tdef.span, flags = ImplicitTerm)(using ctx0)
+ val sym = newPatternBoundSymbol(nameOfSyntheticGiven, bindingTypeTpe, tdef.span, flags = ImplicitVal)(using ctx0)
buff += Bind(sym, untpd.Ident(nme.WILDCARD).withType(bindingTypeTpe)).withSpan(tdef.span)
super.transform(tdef)
}
diff --git a/compiler/test-resources/repl/i1374 b/compiler/test-resources/repl/i1374
index a56b15df2818..3d117fdb4ff9 100644
--- a/compiler/test-resources/repl/i1374
+++ b/compiler/test-resources/repl/i1374
@@ -1,5 +1,6 @@
scala> implicit class Padder(val sb: StringBuilder) extends AnyVal { def pad2(width: Int) = { 1 to width - sb.length foreach { sb append '*' }; sb } }
// defined class Padder
+def Padder(sb: StringBuilder): Padder
scala> val greeting = new StringBuilder("Hello, kitteh!")
val greeting: StringBuilder = Hello, kitteh!
scala> val a = greeting pad2 20
diff --git a/compiler/test/dotty/tools/dotc/semanticdb/SemanticdbTests.scala b/compiler/test/dotty/tools/dotc/semanticdb/SemanticdbTests.scala
index 5deeaed114a8..d1f58bf52a91 100644
--- a/compiler/test/dotty/tools/dotc/semanticdb/SemanticdbTests.scala
+++ b/compiler/test/dotty/tools/dotc/semanticdb/SemanticdbTests.scala
@@ -25,6 +25,30 @@ import dotty.tools.dotc.util.SourceFile
@main def updateExpect =
SemanticdbTests().runExpectTest(updateExpectFiles = true)
+/** Useful for printing semanticdb metac output for one file
+ *
+ * @param root the output directory containing semanticdb output,
+ * only 1 semanticdb file should be present
+ * @param source the single source file producing the semanticdb
+ */
+@main def metac(root: String, source: String) =
+ val rootSrc = Paths.get(root)
+ val sourceSrc = Paths.get(source)
+ val semanticFile = FileSystems.getDefault.getPathMatcher("glob:**.semanticdb")
+ def inputFile(): Path =
+ val ls = Files.walk(rootSrc.resolve("META-INF").resolve("semanticdb"))
+ val files =
+ try ls.filter(p => semanticFile.matches(p)).collect(Collectors.toList).asScala
+ finally ls.close()
+ require(files.sizeCompare(1) == 0, s"No semanticdb files! $rootSrc")
+ files.head
+ val metacSb: StringBuilder = StringBuilder(5000)
+ val semanticdbPath = inputFile()
+ val doc = Tools.loadTextDocumentUnsafe(sourceSrc.toAbsolutePath, semanticdbPath)
+ Tools.metac(doc, Paths.get(doc.uri))(using metacSb)
+ Files.write(rootSrc.resolve("metac.expect"), metacSb.toString.getBytes(StandardCharsets.UTF_8))
+
+
@Category(Array(classOf[BootstrappedOnlyTests]))
class SemanticdbTests:
val javaFile = FileSystems.getDefault.getPathMatcher("glob:**.java")
diff --git a/tests/pos/i12949.scala b/tests/pos/i12949.scala
new file mode 100644
index 000000000000..5a886aa894b3
--- /dev/null
+++ b/tests/pos/i12949.scala
@@ -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
diff --git a/tests/semanticdb/expect/InventedNames.expect.scala b/tests/semanticdb/expect/InventedNames.expect.scala
index 131d4304da31..7c5b008209c2 100644
--- a/tests/semanticdb/expect/InventedNames.expect.scala
+++ b/tests/semanticdb/expect/InventedNames.expect.scala
@@ -39,4 +39,4 @@ val f/*<-givens::InventedNames$package.f.*/ = given_Float/*->givens::InventedNam
val g/*<-givens::InventedNames$package.g.*/ = `* *`/*->givens::InventedNames$package.`* *`.*/
val x/*<-givens::InventedNames$package.x.*/ = given_X/*->givens::InventedNames$package.given_X.*/
val y/*<-givens::InventedNames$package.y.*/ = given_Y/*->givens::InventedNames$package.given_Y().*/
-val z/*<-givens::InventedNames$package.z.*/ = given_Z_T/*->givens::InventedNames$package.given_Z_T().*/[String/*->scala::Predef.String#*/]
\ No newline at end of file
+val z/*<-givens::InventedNames$package.z.*/ = given_Z_T/*->givens::InventedNames$package.given_Z_T().*/[String/*->scala::Predef.String#*/]
diff --git a/tests/semanticdb/expect/InventedNames.scala b/tests/semanticdb/expect/InventedNames.scala
index 3858f22c8331..42c14c90e370 100644
--- a/tests/semanticdb/expect/InventedNames.scala
+++ b/tests/semanticdb/expect/InventedNames.scala
@@ -39,4 +39,4 @@ val f = given_Float
val g = `* *`
val x = given_X
val y = given_Y
-val z = given_Z_T[String]
\ No newline at end of file
+val z = given_Z_T[String]
diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect
index c367bf48e8d4..d66bf1dc17dd 100644
--- a/tests/semanticdb/metac.expect
+++ b/tests/semanticdb/metac.expect
@@ -484,7 +484,7 @@ classes/C12#foo2Impl().(context) => param context: Context
classes/C12#foo2Impl().(x) => param x: context.Expr[Int]
classes/C12#foo2Impl().(y) => param y: context.Expr[String]
classes/M. => final object M extends Object { self: M.type => +3 decls }
-classes/M.C5# => class C5 extends Object { self: C5 => +2 decls }
+classes/M.C5# => implicit class C5 extends Object { self: C5 => +2 decls }
classes/M.C5#``(). => primary ctor (param x: Int): C5
classes/M.C5#``().(x) => param x: Int
classes/M.C5#x. => private[this] val method x Int
@@ -1519,7 +1519,7 @@ example/ImplicitConversion#string2Number().(string) => param string: String
example/ImplicitConversion#tuple. => val method tuple Tuple2[Int, Int]
example/ImplicitConversion#x. => val method x Int
example/ImplicitConversion. => final object ImplicitConversion extends Object { self: ImplicitConversion.type => +6 decls }
-example/ImplicitConversion.newAny2stringadd# => final class newAny2stringadd [typeparam A ] extends AnyVal { self: newAny2stringadd[A] => +4 decls }
+example/ImplicitConversion.newAny2stringadd# => final implicit class newAny2stringadd [typeparam A ] extends AnyVal { self: newAny2stringadd[A] => +4 decls }
example/ImplicitConversion.newAny2stringadd#[A] => typeparam A
example/ImplicitConversion.newAny2stringadd#`+`(). => method + (param other: String): String
example/ImplicitConversion.newAny2stringadd#`+`().(other) => param other: String
@@ -1705,14 +1705,14 @@ givens/InventedNames$package.given_List_T().[T] => typeparam T
givens/InventedNames$package.given_String. => final implicit lazy val given method given_String String
givens/InventedNames$package.given_X. => final implicit given object given_X extends Object with X { self: given_X.type => +2 decls }
givens/InventedNames$package.given_X.doX(). => method doX => Int <: givens/X#doX().
-givens/InventedNames$package.given_Y# => class given_Y extends Object with Y { self: given_Y => +3 decls }
+givens/InventedNames$package.given_Y# => implicit given class given_Y extends Object with Y { self: given_Y => +3 decls }
givens/InventedNames$package.given_Y#``(). => primary ctor ()(implicit val given param x$1: X): given_Y
givens/InventedNames$package.given_Y#``().(x$1) => implicit val given param x$1: X
givens/InventedNames$package.given_Y#doY(). => method doY => String <: givens/Y#doY().
givens/InventedNames$package.given_Y#x$1. => protected implicit val given method x$1 X
givens/InventedNames$package.given_Y(). => final implicit given method given_Y (implicit given param x$1: X): given_Y
givens/InventedNames$package.given_Y().(x$1) => implicit given param x$1: X
-givens/InventedNames$package.given_Z_T# => class given_Z_T [typeparam T ] extends Object with Z[T] { self: given_Z_T[T] => +3 decls }
+givens/InventedNames$package.given_Z_T# => implicit given class given_Z_T [typeparam T ] extends Object with Z[T] { self: given_Z_T[T] => +3 decls }
givens/InventedNames$package.given_Z_T#[T] => typeparam T
givens/InventedNames$package.given_Z_T#``(). => primary ctor [typeparam T ](): given_Z_T[T]
givens/InventedNames$package.given_Z_T#doZ(). => method doZ => List[T] <: givens/Z#doZ().