@@ -315,6 +315,85 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
315315 private def checkInlTraitPrivateMemberIsLocal (tree : Tree )(using Context ): Unit =
316316 if tree.symbol.owner.isInlineTrait && tree.symbol.isAllOf(Private , butNot = Local ) then
317317 report.error(em " implementation restriction: inline traits cannot have non-local private members. This also means no retained inline methods. " , tree.srcPos)
318+
319+ private def checkFunctionContextBounds (ddef : DefDef )(using Context ): Unit = {
320+ val symbol = ddef.symbol
321+
322+ val isConstructorOfNonInlineType = ddef.symbol.isConstructor && ! ddef.symbol.owner.is(Flags .Inline )
323+ val isRegularDefDef = ! ddef.symbol.isConstructor && ! ddef.symbol.is(Flags .Inline )
324+ if isConstructorOfNonInlineType || isRegularDefDef then
325+ ddef.paramss.flatten.foreach {
326+ param => if SpecializedEvidence .unapply(param.tpe.widen.dealias).nonEmpty then
327+ report.error(s " Only inline traits and inline functions may take Specialized type parameters " , param.srcPos)
328+
329+ }
330+ }
331+
332+ private def checkForIllegalUseOfSpecialized (tdef : TypeDef )(using Context ): Unit = {
333+ val containUseOfSpecialized =
334+ tdef.rhs.tpe.existsPart(t => t.typeSymbol == defn.SpecializedClass .asType)
335+ if containUseOfSpecialized && (tdef.symbol ne defn.SpecializedClass )then
336+ report.error(IllegalUseOfSpecialized (), tdef.srcPos)
337+ }
338+
339+ private def checkValidAnonymousSpecialization (tree : Block )(using Context ): Unit = tree match {
340+ case AnonymousClassInstance (anon) =>
341+ def deandify (tp : Type ): Iterator [Type ] = tp match {
342+ case AndType (l, r) => deandify(l) ++ deandify(r)
343+ case _ => Iterator .single(tp)
344+ }
345+ anon.typeTree.tpe match {
346+ case a : AndType => /* Multiple mixed in traits will be typed as an AndType */
347+ deandify(a) foreach {
348+ Specialization .unapply(_, anon.typeTree.span) foreach {
349+ spec => if spec.hasSpecializedParams then
350+ report.error(
351+ """
352+ Anonymous classes acting as instances of Specialized traits may not mix in other traits;
353+ You can make a named object instead if you like.
354+ """ ,
355+ anon.srcPos
356+ )
357+ }
358+ }
359+
360+ case tpe =>
361+ Specialization
362+ .unapply(tpe, anon.typeTree.span)
363+ .foreach(spec =>
364+ if spec.hasSpecializedParams then
365+ // Only allowed to contain evidence parameters
366+ if anon.body.filterNot(x => x.symbol.name.is(ContextBoundParamName )).nonEmpty then
367+ report.error(
368+ """
369+ Anonymous classes acting as instances of Specialized traits may not have additional members;
370+ you can make a named object instead if you like.
371+ """ ,
372+ anon.srcPos
373+ )
374+
375+ def hasOnlyValidParents : Boolean = anon.parentCalls match {
376+ case (obj :: parentsOfSpecTrait) :+ (app@ Apply (_, _)) =>
377+ val isFirstParentObject = obj.symbol.owner == ctx.definitions.ObjectClass
378+ val validOtherParents =
379+ parentsOfSpecTrait.forall(x => spec.symbol.asClass.baseClasses.exists(p => p == x.symbol.owner))
380+
381+ isFirstParentObject && validOtherParents
382+ case _ => false
383+ }
384+
385+ if ! hasOnlyValidParents then
386+ report.error(
387+ """
388+ Anonymous classes acting as instances of Specialized traits may not mix in other traits;
389+ you can make a named object instead if you like.""" ,
390+ anon.srcPos
391+ )
392+ )
393+ }
394+ case _ =>
395+ }
396+
318397
319398 private def transformSelect (tree : Select , targs : List [Tree ])(using Context ): Tree = {
320399 val qual = tree.qualifier
@@ -581,6 +660,7 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
581660 if tree.symbol == defn.SpecializedModule && (ctx.owner ne defn.SpecializedModule .moduleClass) then
582661 report.error(IllegalUseOfSpecialized (), tree.srcPos)
583662 registerNeedsInlining(tree)
663+ registerIfHasSpecializations(tree)
584664 val tree1 = checkUsableAsValue(tree)
585665 tree1.tpe match {
586666 case tpe : ThisType => This (tpe.cls).withSpan(tree.span)
@@ -678,14 +758,13 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
678758 case tree : DefDef =>
679759 registerIfHasMacroAnnotations(tree)
680760 Checking .checkPolyFunctionType(tree.tpt)
761+ checkFunctionContextBounds(tree)
681762 annotateContextResults(tree)
682763 val tree1 = cpy.DefDef (tree)(tpt = explicifyTpt(tree))
683764 processValOrDefDef(superAcc.wrapDefDef(tree1)(super .transform(tree1).asInstanceOf [DefDef ]))
684765 case tree : TypeDef =>
685- if tree.symbol.isInlineTrait then
686- ctx.compilationUnit.needsInlining = true // Check and transform inline traits
687- if tree.rhs.tpe.existsPart(t => t.typeSymbol == defn.SpecializedClass .asType) && (tree.symbol ne defn.SpecializedClass ) then
688- report.error(IllegalUseOfSpecialized (), tree.srcPos)
766+ registerIfHasSpecializations(tree)
767+ checkForIllegalUseOfSpecialized(tree)
689768 registerIfHasMacroAnnotations(tree)
690769 val sym = tree.symbol
691770 if (sym.isClass)
@@ -696,9 +775,8 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
696775 sym.keepAnnotationsCarrying(thisPhase, Set (defn.CompanionClassMetaAnnot ), orNoneOf = defn.MetaAnnots )
697776 tree.rhs match
698777 case impl : Template =>
778+ registerIfHasSpecializations(impl)
699779 for parent <- impl.parents do
700- if Inlines .symbolFromParent(parent).isInlineTrait then
701- ctx.compilationUnit.needsInlining = true
702780 Checking .checkTraitInheritance(parent.tpe.classSymbol, sym.asClass, parent.srcPos)
703781 // Constructor parameters are in scope when typing a parent.
704782 // While they can safely appear in a parent tree, to preserve
@@ -789,6 +867,9 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
789867 )
790868 case Block (_, Closure (_, _, tpt)) if ExpandSAMs .needsWrapperClass(tpt.tpe) =>
791869 superAcc.withInvalidCurrentClass(super .transform(tree))
870+ case block : Block =>
871+ checkValidAnonymousSpecialization(block)
872+ super .transform(tree)
792873 case tree : RefinedTypeTree =>
793874 Checking .checkPolyFunctionType(tree)
794875 super .transform(tree)
@@ -814,6 +895,18 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
814895 if tree.symbol.is(Inline ) && ! Inlines .inInlineMethod && ! ctx.mode.is(Mode .NoInline ) then
815896 ctx.compilationUnit.needsInlining = true
816897
898+ private def registerIfHasSpecializations (tree : Tree )(using Context ): Unit = {
899+ val hasSpecializations = tree match
900+ case tree : Ident => tree.symbol == defn.SpecializedModule_apply
901+ case tree : TypeDef => tree.symbol.isInlineTrait
902+ case tree : Template => tree.parents.exists(parent => Inlines .symbolFromParent(parent).isInlineTrait)
903+ case _ => false
904+
905+ if hasSpecializations then
906+ ctx.compilationUnit.needsInlining = true
907+ ctx.compilationUnit.hasSpecializations = true
908+ }
909+
817910 /** Check if the definition has macro annotation and sets `compilationUnit.hasMacroAnnotations` if needed. */
818911 private def registerIfHasMacroAnnotations (tree : DefTree )(using Context ) =
819912 if ! Inlines .inInlineMethod && tree.symbol.hasMacroAnnotation then
0 commit comments