Skip to content

Commit e47a34a

Browse files
committed
Implement into modifier on parameter types
Source input: From Scala 3: `(x: into T)` From Scala 2: `(@allowConversions x: T)` Gets translated to (x: <into>[T]) where `<into>` is a new synthetic alias marker type defined as type <into>[T] = T `into` is not accessible from user programs.
1 parent 9d574ce commit e47a34a

29 files changed

+278
-55
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import core._
66
import util.Spans._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._
77
import Symbols._, StdNames._, Trees._, ContextOps._
88
import Decorators._, transform.SymUtils._
9+
import Annotations.Annotation
910
import NameKinds.{UniqueName, EvidenceParamName, DefaultGetterName, WildcardParamName}
1011
import typer.{Namer, Checking}
1112
import util.{Property, SourceFile, SourcePosition, Chars}
@@ -165,32 +166,41 @@ object desugar {
165166
*
166167
* Generate setter where needed
167168
*/
168-
def valDef(vdef0: ValDef)(using Context): Tree = {
169+
def valDef(vdef0: ValDef)(using Context): Tree =
169170
val vdef @ ValDef(_, tpt, rhs) = vdef0
170-
val mods = vdef.mods
171-
172171
val valName = normalizeName(vdef, tpt).asTermName
173-
val vdef1 = cpy.ValDef(vdef)(name = valName)
174172

175-
if (isSetterNeeded(vdef)) {
176-
// TODO: copy of vdef as getter needed?
177-
// val getter = ValDef(mods, name, tpt, rhs) withPos vdef.pos?
178-
// right now vdef maps via expandedTree to a thicket which concerns itself.
179-
// I don't see a problem with that but if there is one we can avoid it by making a copy here.
173+
var mods1 = vdef.mods
174+
def dropInto(tpt: Tree): Tree = tpt match
175+
case Into(tpt1) =>
176+
mods1 = vdef.mods.withAddedAnnotation(
177+
TypedSplice(
178+
Annotation(defn.AllowConversionsAnnot).tree.withSpan(tpt.span.startPos)))
179+
tpt1
180+
case ByNameTypeTree(tpt1) =>
181+
cpy.ByNameTypeTree(tpt)(dropInto(tpt1))
182+
case PostfixOp(tpt1, op) if op.name == tpnme.raw.STAR =>
183+
cpy.PostfixOp(tpt)(dropInto(tpt1), op)
184+
case _ =>
185+
tpt
186+
187+
val vdef1 = cpy.ValDef(vdef)(name = valName, tpt = dropInto(tpt))
188+
.withMods(mods1)
189+
190+
if isSetterNeeded(vdef) then
180191
val setterParam = makeSyntheticParameter(tpt = SetterParamTree().watching(vdef))
181192
// The rhs gets filled in later, when field is generated and getter has parameters (see Memoize miniphase)
182193
val setterRhs = if (vdef.rhs.isEmpty) EmptyTree else unitLiteral
183194
val setter = cpy.DefDef(vdef)(
184-
name = valName.setterName,
185-
paramss = (setterParam :: Nil) :: Nil,
186-
tpt = TypeTree(defn.UnitType),
187-
rhs = setterRhs
188-
).withMods((mods | Accessor) &~ (CaseAccessor | GivenOrImplicit | Lazy))
189-
.dropEndMarker() // the end marker should only appear on the getter definition
195+
name = valName.setterName,
196+
paramss = (setterParam :: Nil) :: Nil,
197+
tpt = TypeTree(defn.UnitType),
198+
rhs = setterRhs
199+
).withMods((vdef.mods | Accessor) &~ (CaseAccessor | GivenOrImplicit | Lazy))
200+
.dropEndMarker() // the end marker should only appear on the getter definition
190201
Thicket(vdef1, setter)
191-
}
192202
else vdef1
193-
}
203+
end valDef
194204

195205
def makeImplicitParameters(tpts: List[Tree], implicitFlag: FlagSet, forPrimaryConstructor: Boolean = false)(using Context): List[ValDef] =
196206
for (tpt <- tpts) yield {

compiler/src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
117117
case class ContextBounds(bounds: TypeBoundsTree, cxBounds: List[Tree])(implicit @constructorOnly src: SourceFile) extends TypTree
118118
case class PatDef(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree)(implicit @constructorOnly src: SourceFile) extends DefTree
119119
case class ExtMethods(paramss: List[ParamClause], methods: List[Tree])(implicit @constructorOnly src: SourceFile) extends Tree
120+
case class Into(tpt: Tree)(implicit @constructorOnly src: SourceFile) extends Tree
120121
case class MacroTree(expr: Tree)(implicit @constructorOnly src: SourceFile) extends Tree
121122

122123
case class ImportSelector(imported: Ident, renamed: Tree = EmptyTree, bound: Tree = EmptyTree)(implicit @constructorOnly src: SourceFile) extends Tree {
@@ -646,6 +647,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
646647
def ExtMethods(tree: Tree)(paramss: List[ParamClause], methods: List[Tree])(using Context): Tree = tree match
647648
case tree: ExtMethods if (paramss eq tree.paramss) && (methods == tree.methods) => tree
648649
case _ => finalize(tree, untpd.ExtMethods(paramss, methods)(tree.source))
650+
def Into(tree: Tree)(tpt: Tree)(using Context): Tree = tree match
651+
case tree: Into if tpt eq tree.tpt => tree
652+
case _ => finalize(tree, untpd.Into(tpt)(tree.source))
649653
def ImportSelector(tree: Tree)(imported: Ident, renamed: Tree, bound: Tree)(using Context): Tree = tree match {
650654
case tree: ImportSelector if (imported eq tree.imported) && (renamed eq tree.renamed) && (bound eq tree.bound) => tree
651655
case _ => finalize(tree, untpd.ImportSelector(imported, renamed, bound)(tree.source))
@@ -715,6 +719,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
715719
cpy.PatDef(tree)(mods, transform(pats), transform(tpt), transform(rhs))
716720
case ExtMethods(paramss, methods) =>
717721
cpy.ExtMethods(tree)(transformParamss(paramss), transformSub(methods))
722+
case Into(tpt) =>
723+
cpy.Into(tree)(transform(tpt))
718724
case ImportSelector(imported, renamed, bound) =>
719725
cpy.ImportSelector(tree)(transformSub(imported), transform(renamed), transform(bound))
720726
case Number(_, _) | TypedSplice(_) =>
@@ -774,6 +780,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
774780
this(this(this(x, pats), tpt), rhs)
775781
case ExtMethods(paramss, methods) =>
776782
this(paramss.foldLeft(x)(apply), methods)
783+
case Into(tpt) =>
784+
this(x, tpt)
777785
case ImportSelector(imported, renamed, bound) =>
778786
this(this(this(x, imported), renamed), bound)
779787
case Number(_, _) =>

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

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ object Decorators {
7474
/** Implements filterConserve, zipWithConserve methods
7575
* on lists that avoid duplication of list nodes where feasible.
7676
*/
77-
implicit class ListDecorator[T](val xs: List[T]) extends AnyVal {
77+
extension [T](xs: List[T])
7878

7979
final def mapconserve[U](f: T => U): List[U] = {
8080
@tailrec
@@ -203,11 +203,7 @@ object Decorators {
203203
}
204204

205205
/** Union on lists seen as sets */
206-
def | (ys: List[T]): List[T] = xs ::: (ys filterNot (xs contains _))
207-
208-
/** Intersection on lists seen as sets */
209-
def & (ys: List[T]): List[T] = xs filter (ys contains _)
210-
}
206+
def setUnion (ys: List[T]): List[T] = xs ::: ys.filterNot(xs contains _)
211207

212208
extension [T, U](xss: List[List[T]])
213209
def nestedMap(f: T => U): List[List[U]] = xss match

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,8 @@ class Definitions {
644644

645645
@tu lazy val RepeatedParamClass: ClassSymbol = enterSpecialPolyClass(tpnme.REPEATED_PARAM_CLASS, Covariant, Seq(ObjectType, SeqType))
646646

647+
@tu lazy val IntoType: TypeSymbol = enterAliasType(tpnme.INTO, HKTypeLambda(TypeBounds.empty :: Nil)(_.paramRefs(0)))
648+
647649
// fundamental classes
648650
@tu lazy val StringClass: ClassSymbol = requiredClass("java.lang.String")
649651
def StringType: Type = StringClass.typeRef
@@ -967,6 +969,7 @@ class Definitions {
967969
@tu lazy val RefiningAnnotationClass: ClassSymbol = requiredClass("scala.annotation.RefiningAnnotation")
968970

969971
// Annotation classes
972+
@tu lazy val AllowConversionsAnnot: ClassSymbol = requiredClass("scala.annotation.allowConversions")
970973
@tu lazy val AnnotationDefaultAnnot: ClassSymbol = requiredClass("scala.annotation.internal.AnnotationDefault")
971974
@tu lazy val BeanPropertyAnnot: ClassSymbol = requiredClass("scala.beans.BeanProperty")
972975
@tu lazy val BooleanBeanPropertyAnnot: ClassSymbol = requiredClass("scala.beans.BooleanBeanProperty")
@@ -1956,6 +1959,7 @@ class Definitions {
19561959
orType,
19571960
RepeatedParamClass,
19581961
ByNameParamClass2x,
1962+
IntoType,
19591963
AnyValClass,
19601964
NullClass,
19611965
NothingClass,

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import scala.annotation.internal.sharable
1515
object Names {
1616
import NameKinds._
1717

18-
/** Things that can be turned into names with `totermName` and `toTypeName`
19-
* Decorators defines implements these as extension methods for strings.
18+
/** Things that can be turned into names with `toTermName` and `toTypeName`.
19+
* Decorators implements these as extension methods for strings.
2020
*/
2121
type PreName = Name | String
2222

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
418418
case param: TypeParamRef if contains(param) =>
419419
param :: (if (isUpper) upper(param) else lower(param))
420420
case tp: AndType if isUpper =>
421-
dependentParams(tp.tp1, isUpper) | (dependentParams(tp.tp2, isUpper))
421+
dependentParams(tp.tp1, isUpper).setUnion(dependentParams(tp.tp2, isUpper))
422422
case tp: OrType if !isUpper =>
423423
dependentParams(tp.tp1, isUpper).intersect(dependentParams(tp.tp2, isUpper))
424424
case EtaExpansion(tycon) =>

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ object StdNames {
128128
val EXCEPTION_RESULT_PREFIX: N = "exceptionResult"
129129
val EXPAND_SEPARATOR: N = str.EXPAND_SEPARATOR
130130
val IMPORT: N = "<import>"
131+
val INTO: N = "<into>"
131132
val MODULE_SUFFIX: N = str.MODULE_SUFFIX
132133
val OPS_PACKAGE: N = "<special-ops>"
133134
val OVERLOADED: N = "<overloaded>"
@@ -498,6 +499,7 @@ object StdNames {
498499
val info: N = "info"
499500
val inlinedEquals: N = "inlinedEquals"
500501
val internal: N = "internal"
502+
val into: N = "into"
501503
val isArray: N = "isArray"
502504
val isDefinedAt: N = "isDefinedAt"
503505
val isDefinedAtImpl: N = "$isDefinedAt"

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

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,10 @@ object Types {
397397
def isRepeatedParam(using Context): Boolean =
398398
typeSymbol eq defn.RepeatedParamClass
399399

400+
/** Is this a parameter type that allows implicit argument converson? */
401+
def isConvertibleParam(using Context): Boolean =
402+
typeSymbol eq defn.IntoType
403+
400404
/** Is this the type of a method that has a repeated parameter type as
401405
* last parameter type?
402406
*/
@@ -544,7 +548,7 @@ object Types {
544548
case tp: ClassInfo =>
545549
tp.cls :: Nil
546550
case AndType(l, r) =>
547-
l.parentSymbols(include) | r.parentSymbols(include)
551+
l.parentSymbols(include).setUnion(r.parentSymbols(include))
548552
case OrType(l, r) =>
549553
l.parentSymbols(include) intersect r.parentSymbols(include) // TODO does not conform to spec
550554
case _ =>
@@ -1879,6 +1883,11 @@ object Types {
18791883

18801884
def dropRepeatedAnnot(using Context): Type = dropAnnot(defn.RepeatedAnnot)
18811885

1886+
/** A translation from types of original parameter ValDefs to the types
1887+
* of parameters in MethodTypes.
1888+
* Translates `Seq[T] @repeated` or `Array[T] @repeated` to `<repeated>[T]`.
1889+
* That way, repeated arguments are made manifest without risk of dropped annotations.
1890+
*/
18821891
def annotatedToRepeated(using Context): Type = this match {
18831892
case tp @ ExprType(tp1) => tp.derivedExprType(tp1.annotatedToRepeated)
18841893
case AnnotatedType(tp, annot) if annot matches defn.RepeatedAnnot =>
@@ -3949,27 +3958,45 @@ object Types {
39493958
* and inline parameters:
39503959
* - replace @repeated annotations on Seq or Array types by <repeated> types
39513960
* - add @inlineParam to inline parameters
3952-
*/
3953-
def fromSymbols(params: List[Symbol], resultType: Type)(using Context): MethodType = {
3954-
def translateInline(tp: Type): Type = tp match {
3955-
case ExprType(resType) => ExprType(AnnotatedType(resType, Annotation(defn.InlineParamAnnot)))
3956-
case _ => AnnotatedType(tp, Annotation(defn.InlineParamAnnot))
3957-
}
3958-
def translateErased(tp: Type): Type = tp match {
3959-
case ExprType(resType) => ExprType(AnnotatedType(resType, Annotation(defn.ErasedParamAnnot)))
3960-
case _ => AnnotatedType(tp, Annotation(defn.ErasedParamAnnot))
3961-
}
3962-
def paramInfo(param: Symbol) = {
3961+
* - add @erasedParam to erased parameters
3962+
* - wrap types of parameters that have an @allowConversions annotation with Into[_]
3963+
*/
3964+
def fromSymbols(params: List[Symbol], resultType: Type)(using Context): MethodType =
3965+
def addAnnotation(tp: Type, cls: ClassSymbol): Type = tp match
3966+
case ExprType(resType) => ExprType(addAnnotation(resType, cls))
3967+
case _ => AnnotatedType(tp, Annotation(cls))
3968+
3969+
def wrapConvertible(tp: Type) =
3970+
AppliedType(defn.IntoType.typeRef, tp :: Nil)
3971+
3972+
def addInto(tp: Type): Type = tp match
3973+
case tp @ AppliedType(tycon, args) if tycon.typeSymbol == defn.RepeatedParamClass =>
3974+
tp.derivedAppliedType(tycon, addInto(args.head) :: Nil)
3975+
case tp @ AppliedType(tycon, args) if defn.isFunctionType(tp) =>
3976+
wrapConvertible(tp.derivedAppliedType(tycon, args.init :+ addInto(args.last)))
3977+
case tp @ RefinedType(parent, rname, rinfo) if defn.isFunctionType(tp) =>
3978+
wrapConvertible(tp.derivedRefinedType(parent, rname, addInto(rinfo)))
3979+
case tp: MethodType =>
3980+
tp.derivedLambdaType(resType = addInto(tp.resType))
3981+
case ExprType(resType) =>
3982+
ExprType(addInto(resType))
3983+
case _ =>
3984+
wrapConvertible(tp)
3985+
3986+
def paramInfo(param: Symbol) =
39633987
var paramType = param.info.annotatedToRepeated
3964-
if (param.is(Inline)) paramType = translateInline(paramType)
3965-
if (param.is(Erased)) paramType = translateErased(paramType)
3988+
if param.is(Inline) then
3989+
paramType = addAnnotation(paramType, defn.InlineParamAnnot)
3990+
if param.is(Erased) then
3991+
paramType = addAnnotation(paramType, defn.ErasedParamAnnot)
3992+
if param.hasAnnotation(defn.AllowConversionsAnnot) then
3993+
paramType = addInto(paramType)
39663994
paramType
3967-
}
39683995

39693996
apply(params.map(_.name.asTermName))(
39703997
tl => params.map(p => tl.integrate(params, paramInfo(p))),
39713998
tl => tl.integrate(params, resultType))
3972-
}
3999+
end fromSymbols
39734000

39744001
final def apply(paramNames: List[TermName])(paramInfosExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(using Context): MethodType =
39754002
checkValid(unique(new CachedMethodType(paramNames)(paramInfosExp, resultTypeExp, self)))

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,6 +1906,11 @@ object Parsers {
19061906
else
19071907
core()
19081908

1909+
private def maybeInto(tp: () => Tree) =
1910+
if in.isIdent(nme.into) && canStartTypeTokens.contains(in.lookahead.token)
1911+
then atSpan(in.skipToken()) { Into(tp()) }
1912+
else tp()
1913+
19091914
/** FunArgType ::= Type
19101915
* | `=>' Type
19111916
* | [CaptureSet] `->' Type
@@ -1918,10 +1923,10 @@ object Parsers {
19181923
*/
19191924
def paramType(): Tree = paramTypeOf(paramValueType)
19201925

1921-
/** ParamValueType ::= Type [`*']
1926+
/** ParamValueType ::= [`into`] Type [`*']
19221927
*/
19231928
def paramValueType(): Tree = {
1924-
val t = toplevelTyp()
1929+
val t = maybeInto(toplevelTyp)
19251930
if (isIdent(nme.raw.STAR)) {
19261931
in.nextToken()
19271932
atSpan(startOffset(t)) { PostfixOp(t, Ident(tpnme.raw.STAR)) }

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@ object Tokens extends TokensCommon {
231231
final val canStartInfixTypeTokens: TokenSet = literalTokens | identifierTokens | BitSet(
232232
THIS, SUPER, USCORE, LPAREN, LBRACE, AT)
233233

234+
final val canStartTypeTokens: TokenSet = canStartInfixTypeTokens | BitSet(LBRACE)
235+
234236
final val templateIntroTokens: TokenSet = BitSet(CLASS, TRAIT, OBJECT, ENUM, CASECLASS, CASEOBJECT)
235237

236238
final val dclIntroTokens: TokenSet = BitSet(DEF, VAL, VAR, TYPE, GIVEN)
@@ -287,7 +289,7 @@ object Tokens extends TokensCommon {
287289

288290
final val closingParens = BitSet(RPAREN, RBRACKET, RBRACE)
289291

290-
final val softModifierNames = Set(nme.inline, nme.opaque, nme.open, nme.transparent, nme.infix)
292+
final val softModifierNames = Set(nme.inline, nme.into, nme.opaque, nme.open, nme.transparent, nme.infix)
291293

292294
def showTokenDetailed(token: Int): String = debugString(token)
293295

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
219219
case _ =>
220220
val tsym = tycon.typeSymbol
221221
if tycon.isRepeatedParam then toTextLocal(args.head) ~ "*"
222+
else if tp.isConvertibleParam then "into " ~ toText(args.head)
222223
else if defn.isFunctionSymbol(tsym) then
223224
toTextFunction(args, tsym.name.isContextFunction, tsym.name.isErasedFunction,
224225
isPure = ctx.settings.Ycc.value && !tsym.name.isImpureFunction)

compiler/src/dotty/tools/dotc/transform/TypeUtils.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ object TypeUtils {
7676
case AndType(tp1, tp2) =>
7777
// We assume that we have the following property:
7878
// (T1, T2, ..., Tn) & (U1, U2, ..., Un) = (T1 & U1, T2 & U2, ..., Tn & Un)
79-
tp1.tupleElementTypes.zip(tp2.tupleElementTypes).map { case (t1, t2) => t1 & t2 }
79+
tp1.tupleElementTypes.zip(tp2.tupleElementTypes).map { case (t1, t2) => t1.intersect(t2) }
8080
case OrType(tp1, tp2) =>
8181
None // We can't combine the type of two tuples
8282
case _ =>

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -977,14 +977,15 @@ trait Checking {
977977
sym.srcPos)
978978

979979
/** If `tree` is an application of a new-style implicit conversion (using the apply
980-
* method of a `scala.Conversion` instance), check that implicit conversions are
981-
* enabled.
980+
* method of a `scala.Conversion` instance), check that the expected type is
981+
* a convertible formal parameter type or that implicit conversions are enabled.
982982
*/
983-
def checkImplicitConversionUseOK(tree: Tree)(using Context): Unit =
983+
def checkImplicitConversionUseOK(tree: Tree, expected: Type)(using Context): Unit =
984984
val sym = tree.symbol
985985
if sym.name == nme.apply
986986
&& sym.owner.derivesFrom(defn.ConversionClass)
987987
&& !sym.info.isErroneous
988+
&& !expected.isConvertibleParam
988989
then
989990
def conv = methPart(tree) match
990991
case Select(qual, _) => qual.symbol.orElse(sym.owner)
@@ -1515,7 +1516,7 @@ trait NoChecking extends ReChecking {
15151516
override def checkStable(tp: Type, pos: SrcPos, kind: String)(using Context): Unit = ()
15161517
override def checkClassType(tp: Type, pos: SrcPos, traitReq: Boolean, stablePrefixReq: Boolean)(using Context): Type = tp
15171518
override def checkImplicitConversionDefOK(sym: Symbol)(using Context): Unit = ()
1518-
override def checkImplicitConversionUseOK(tree: Tree)(using Context): Unit = ()
1519+
override def checkImplicitConversionUseOK(tree: Tree, expected: Type)(using Context): Unit = ()
15191520
override def checkFeasibleParent(tp: Type, pos: SrcPos, where: => String = "")(using Context): Type = tp
15201521
override def checkAnnotArgs(tree: Tree)(using Context): tree.type = tree
15211522
override def checkNoTargetNameConflict(stats: List[Tree])(using Context): Unit = ()

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1621,12 +1621,14 @@ class Namer { typer: Typer =>
16211621
def typedAheadAnnotation(tree: Tree)(using Context): tpd.Tree =
16221622
typedAheadExpr(tree, defn.AnnotationClass.typeRef)
16231623

1624-
def typedAheadAnnotationClass(tree: Tree)(using Context): Symbol = tree match {
1624+
def typedAheadAnnotationClass(tree: Tree)(using Context): Symbol = tree match
16251625
case Apply(fn, _) => typedAheadAnnotationClass(fn)
16261626
case TypeApply(fn, _) => typedAheadAnnotationClass(fn)
16271627
case Select(qual, nme.CONSTRUCTOR) => typedAheadAnnotationClass(qual)
16281628
case New(tpt) => typedAheadType(tpt).tpe.classSymbol
1629-
}
1629+
case TypedSplice(_) =>
1630+
val sym = tree.symbol
1631+
if sym.isConstructor then sym.owner else sym
16301632

16311633
/** Enter and typecheck parameter list */
16321634
def completeParams(params: List[MemberDef])(using Context): Unit = {

0 commit comments

Comments
 (0)