Skip to content

Inline traits for specialization in Scala 3 #17329

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 106 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
56c508b
Allow parsing of inline trait, update printer
timotheeandres Feb 24, 2023
5ffb63e
Implement phase 1 of inlining
timotheeandres Feb 28, 2023
966f12d
Implement phase 2 of inlining
timotheeandres Feb 28, 2023
3c4b310
Use inlining capabilities to inline body of defs
timotheeandres Mar 2, 2023
810dcb6
Improve inlining of traits
timotheeandres Mar 9, 2023
7531239
Add atomic tests for inline traits
timotheeandres Mar 23, 2023
f01f90d
Import Nicolas' work
timotheeandres Mar 28, 2023
567d555
Avoid generating accessor fields for inline traits
timotheeandres Mar 28, 2023
e572676
Use parent span for inlined code
timotheeandres Mar 30, 2023
61516a1
Blacklist inline trait tests due to pickling
timotheeandres Mar 30, 2023
2a077cc
Add benchmark for toy version of Numeric
timotheeandres Apr 3, 2023
8b3437f
Delete by-name parameter tests
timotheeandres Apr 4, 2023
b53f142
Revert "Use parent span for inlined code"
timotheeandres Apr 4, 2023
cd14169
Forbid var in inline traits for now
timotheeandres Apr 4, 2023
e167b96
Add override modifier to param accessors
timotheeandres Apr 4, 2023
e382e75
Forbid using/implicit parameters for now
timotheeandres Apr 4, 2023
ab2c439
Fix typo in type bound
timotheeandres Apr 4, 2023
fdfbe26
Multiple files tests, quick fix of span
timotheeandres Apr 6, 2023
e4e42ae
Improve benchmark, make adding implementations easier
timotheeandres Apr 6, 2023
5866057
Add specialized and inline trait matrices for benchmark
timotheeandres Apr 13, 2023
8c84089
Fix issue with generic type in signature
timotheeandres Apr 13, 2023
4d981af
Import modifications by Nicolas
nicolasstucki Apr 13, 2023
6b02d82
Rework and fix tests
timotheeandres Apr 14, 2023
67173de
Make fields private again
timotheeandres Apr 14, 2023
a516748
Fix type issue between untpd and tpd
timotheeandres Apr 14, 2023
f568ef8
Add tests with manual override
timotheeandres Apr 14, 2023
bd94dc6
Simplify type argument substitution in inline methods
nicolasstucki Apr 14, 2023
fd14025
Refactor creation of inlined symbols
nicolasstucki Apr 14, 2023
c06a501
Only call `inline` on rhs
nicolasstucki Apr 14, 2023
fa53620
Perform misc. changes on tests
timotheeandres Apr 17, 2023
59feb3f
Only allow override final if member is synthetic
timotheeandres Apr 17, 2023
2804dfd
Prevent generation of setters in inline traits
timotheeandres Apr 17, 2023
8b4741b
Don't generate members if they are overridden by user
timotheeandres Apr 17, 2023
59d6221
Fix type params not being replaced in RHS
timotheeandres Apr 18, 2023
b762cc9
Clean up InlineParentTrait
timotheeandres Apr 18, 2023
4bf1c76
Compute overriden symbols only once
timotheeandres Apr 20, 2023
e92c7b5
Factorize code to know what to inline from inline trait
timotheeandres Apr 21, 2023
c676689
Allow inlining of deferred defs
timotheeandres Apr 21, 2023
b9a81b1
Clean up example 4, make version without inner class
timotheeandres Apr 21, 2023
026212f
Update inner class tests
timotheeandres Apr 21, 2023
76e5e9a
Move special expansion cases in inlining methods
timotheeandres Apr 24, 2023
a4fd776
Create InlineTreeMap, make helper function for param accessors
timotheeandres Apr 24, 2023
334b5d3
Make accessor values functions tailrec
timotheeandres Apr 24, 2023
f1aa33e
Implement grandparent inline traits, fix parameters shadowing
timotheeandres Apr 24, 2023
2d20a79
Clean up code to get defs to inline
timotheeandres Apr 26, 2023
fcb2279
Start moving code from Typer
timotheeandres Apr 26, 2023
84a1682
Fix tests/pos/inline-trait-multiple-stages-generic-defs
nicolasstucki Apr 26, 2023
e13a71f
Pass overridden decls when expanding
timotheeandres Apr 26, 2023
59bee43
Remove pickling test blacklist
timotheeandres Apr 26, 2023
845c00b
Move trait inlining into Inlining phase
timotheeandres Apr 26, 2023
3d162cb
Implement ancestors inline traits without term args
timotheeandres Apr 27, 2023
50b6743
Disable test with inner class
timotheeandres Apr 27, 2023
34f77f6
Ensure inline traits have same extends precedence as normal traits
timotheeandres Apr 27, 2023
d605bc5
Partially implement inner traits
timotheeandres Apr 28, 2023
9e26b35
Use typeRef on ctx.owner
timotheeandres Apr 28, 2023
6523fcc
Split symbol inlining method by case
timotheeandres May 8, 2023
bcb6702
Improve checks in phases
timotheeandres May 10, 2023
e3e5582
Remove RHS of definitions in inline traits
timotheeandres May 10, 2023
c9ec223
Add tests with macros (unstable)
timotheeandres May 10, 2023
08e2689
Fix owner of bodies to their rightful symbols
timotheeandres May 10, 2023
5348868
Add more tests
timotheeandres May 10, 2023
060f5ab
Inline code of thisType at sole call site
timotheeandres May 10, 2023
ffe94e8
Forbid defining inline traits inside inline traits
timotheeandres May 11, 2023
67d8b1e
Enable inheritance tests
timotheeandres May 11, 2023
fde0c55
Check if owner is inline trait last
timotheeandres May 12, 2023
086f0b9
Use proper thisType, add coords to inlinedSym
timotheeandres May 12, 2023
2fc66ac
Extract param accessors code into helper class
timotheeandres May 16, 2023
686aac0
Move trait-related code to InlineParentTrait
timotheeandres May 16, 2023
78077a4
Add missing context to expandStat, refactor code
timotheeandres May 23, 2023
2172d03
Refactor Inlining for clarity
timotheeandres May 23, 2023
3f749f1
Factorize code for new inner class names
timotheeandres May 23, 2023
5570b25
Remove last refs to inline trait from Inliner
timotheeandres May 23, 2023
829f9eb
Call super before matching in Tree-/TypeMap
timotheeandres May 23, 2023
a1bc61f
Improve class symbol inlining
timotheeandres May 23, 2023
5226450
Prevent creating new accessor names for inner class' params
timotheeandres May 23, 2023
728d837
Do not add override flag to inner class-like type params
timotheeandres May 23, 2023
2392575
Remove incorrect parent, TODO add correct one
timotheeandres May 23, 2023
c4f13af
Add proper type bound to generated type
timotheeandres May 23, 2023
0b6ec5e
Register class-like symbol to be replaced by inliner
timotheeandres May 23, 2023
6075cd3
Forbid term params for inline traits
timotheeandres May 24, 2023
74aaba9
Create vals for child type and child tree
timotheeandres May 25, 2023
9514ccd
Add proper parent to inner class info
timotheeandres May 25, 2023
a5b53f8
Make function to inline just rhs
timotheeandres May 25, 2023
6fc5bd9
Handle inlining of statements in inline trait body
timotheeandres May 25, 2023
8a756d2
Add tests for inner traits
timotheeandres May 30, 2023
39e57f2
Remove FIXME along with info mapping
timotheeandres May 31, 2023
d7ada60
Add test for anonymous class extending inline trait
timotheeandres Jun 1, 2023
4b99869
Rename param for clarity
timotheeandres Jun 1, 2023
746e677
Create helper methods for inline trait rewriting
timotheeandres Jun 1, 2023
d896688
Strip parents of inner class from concrete elements
timotheeandres Jun 1, 2023
b1eec85
Add Synthetic flag to new trait and type
timotheeandres Jun 1, 2023
e13d3c4
Adapt body of child to point to inlined members
timotheeandres Jun 1, 2023
34a5567
Use wildcard for default var value in benchmark
timotheeandres Jun 5, 2023
5a0339b
Add Pair to benchmark
timotheeandres Jun 5, 2023
b1e16ab
Manual specialization, remove unused toTuple
timotheeandres Jun 6, 2023
cb95383
Add boxing benchmark for report
timotheeandres Jun 14, 2023
2784d54
Move inline trait inlining to its own phase
timotheeandres Jun 5, 2023
5c82ee0
Add simple test for inner class
timotheeandres Jun 16, 2023
6e8a489
Rework benchmark files for report
timotheeandres Jul 4, 2023
7c82e3d
Remove target name for inlined inner class
timotheeandres Jul 4, 2023
fd737ea
Restrict non-local private fields
timotheeandres Jul 4, 2023
7e2952c
Forbid user from overriding vars
timotheeandres Jul 4, 2023
f6e171b
Add tests for constructor arguments with side effects
timotheeandres Jul 4, 2023
102269e
Improve error message, remove unused method
timotheeandres Jul 4, 2023
a557940
Allow overriding opaque aliases for inline traits
timotheeandres Jul 4, 2023
17e17bc
Let compiler complain if deferred member isn't implemented
timotheeandres Jul 4, 2023
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
Prev Previous commit
Next Next commit
Import modifications by Nicolas
  • Loading branch information
nicolasstucki authored and timotheeandres committed Jun 16, 2023
commit 4d981af4719497523343aa5ef8d986d325f8b72c
17 changes: 17 additions & 0 deletions compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1050,10 +1050,27 @@ class TreeUnpickler(reader: TastyReader,
.map(_.changeOwner(localDummy, constr.symbol)))
else parents

val statsStart = currentAddr
val lazyStats = readLater(end, rdr => {
val stats = rdr.readIndexedStats(localDummy, end)
tparams ++ vparams ++ stats
})
if cls.isInlineTrait then
cls.addAnnotation(LazyBodyAnnotation { (ctx0: Context) ?=>
val ctx1 = localContext(cls)(using ctx0).addMode(Mode.ReadPositions)
inContext(sourceChangeContext(Addr(0))(using ctx1)) {
// avoids space leaks by not capturing the current context

val fork = forkAt(statsStart)
val stats = fork.readIndexedStats(localDummy, end)
val inlinedMembers = (tparams ++ vparams ++ stats).filter { stat =>
!(stat.isInstanceOf[TypeDef] && cls.typeParams.contains(stat.symbol)) // !isConstructor
&& !stat.symbol.is(Deferred)
&& !stat.symbol.isAllOf(Inline)
}
Block(inlinedMembers, unitLiteral).withSpan(cls.span)
}
})
defn.patchStdLibClass(cls)
NamerOps.addConstructorProxies(cls)
setSpan(start,
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/inlines/Inliner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ class Inliner(val call: tpd.Tree)(using Context):
case thistpe: ThisType =>
val cls = thistpe.cls
if cls.isInlineTrait then
integrate(This(ctx.owner.asClass), cls)
integrate(This(ctx.owner.asClass).withSpan(call.span), cls)
else thisProxy.get(cls) match {
case Some(t) =>
val thisRef = ref(t).withSpan(call.span)
Expand Down
96 changes: 39 additions & 57 deletions compiler/src/dotty/tools/dotc/inlines/Inlines.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ package dotc
package inlines

import ast.*, core.*
import Flags.*, Symbols.*, Types.*, Decorators.*, Constants.*, Contexts.*
import Flags.*, Symbols.*, Types.*, Decorators.*, Constants.*, Contexts.*, TypeOps.*
import Names.Name
import StdNames.{str, nme, tpnme}
import transform.SymUtils._
import typer.*
Expand Down Expand Up @@ -471,8 +472,7 @@ object Inlines:

def expandDefs(): List[Tree] =
val Block(stats, _) = Inlines.bodyToInline(parentSym): @unchecked
val s = stats.map(expandStat)
s.map(inlined(_)._2)
stats.map(expandStat).map(inlined(_)._2)
end expandDefs

override protected def registerType(tpe: Type): Unit = tpe match {
Expand All @@ -483,51 +483,30 @@ object Inlines:
case _ => super.registerType(tpe)
}

private val argsMap: Map[Names.Name, untpd.Tree] =
/*
* Consider the parent `new A[String](1)("A")` with signature `inline trait A[T](x: Int)(y: T)`.
* The `parent` tree is "right-to-left": Apply(Apply(TypeApply(..., String), 1), "A")
* The `info` tree is "left-to-right": PolyType(T, ..., MethodType(x, Int, MethodType(y, T, ...)))
* This recursive solution goes as deep as possible in the tree, then matches arguments with their
* names in a bottom-up fashion.
*/
def rec(tree: Tree, info: Type, acc: Map[Names.Name, untpd.Tree]): (Option[Type], Map[Names.Name, untpd.Tree]) =
tree match {
case Apply(tree1, args) => rec(tree1, info, acc) match {
case (Some(info1), acc1) => info1 match {
case MethodTpe(paramNames, _, info2) if paramNames.length == args.length =>
(Some(info2), acc1 ++ paramNames.zip(args).toMap)
case _ =>
report.error(s"mismatch between Apply ${tree.show} and info ${info1}", parent.srcPos)
(None, acc1)
}
case res => res
}
case TypeApply(tree1, tpes) => rec(tree1, info, acc) match {
case (Some(info1), acc1) => info1 match {
case PolyType(lambdaParams, info2) if lambdaParams.length == tpes.length =>
(Some(info2), acc1)
case _ =>
report.error(s"mismatch between TypeApply ${tree.show} and info ${info1}", parent.srcPos)
(None, acc1)
}
case res => res
}
case _ => (Some(info), acc)
}

parent match {
case _: GenericApply =>
val (remainingInfo, map) = rec(parent, parent.symbol.info, Map.empty)
remainingInfo match {
case Some(MethodType(paramNames)) =>
report.error(s"could not match the following parameters with their values: ${paramNames.map(_.show).mkString(", ")}", parent.srcPos)
case _ =>
}
map
case _ => Map.empty
}
end argsMap
private val argsMap: Map[Name, Tree] =
def allArgs(tree: Tree): List[List[Tree]] = tree match
case Apply(fun, args) => args :: allArgs(fun)
case TypeApply(fun, targs) => targs :: allArgs(fun)
case AppliedTypeTree(_, targs) => targs :: Nil
case _ => Nil
def allParams(info: Type): List[List[Name]] = info match
case mt: MethodType => mt.paramNames :: allParams(mt.resultType)
case pt: PolyType => pt.paramNames :: allParams(pt.resultType)
case _ => Nil
val info =
if parent.symbol.isClass then parent.symbol.primaryConstructor.info
else parent.symbol.info
allParams(info).flatten.zip(allArgs(parent).reverse.flatten).toMap

private val substituteTypeParams = new TypeMap {
override def apply(t: Type): Type = t match
case TypeRef(ths: ThisType, sym: Symbol) if ths.cls == parentSym =>
argsMap(sym.name).tpe
case t => mapOver(t)
}
private val substituteTypeParamsInTree = new TreeTypeMap(
typeMap = substituteTypeParams
)

private def expandStat(stat: untpd.Tree): untpd.Tree =
val sym = stat.symbol
Expand All @@ -537,22 +516,21 @@ object Inlines:
stat
case stat: ValDef =>
val vdef = cloneValDef(stat)
vdef.symbol.info = substituteTypeParams(sym.info)
if !sym.is(Private) then
vdef.symbol.setFlag(Override)
val vdef1 =
if sym.is(ParamAccessor) then
vdef.symbol.resetFlag(ParamAccessor)
cpy.ValDef(vdef)(rhs = argsMap(sym.name.asTermName))
else
vdef
if !sym.is(Private) then
vdef1.symbol.setFlag(Override)
vdef1 // TODO keep rhs? Can we do a single ValOrDefDef case using cloneStat?
substituteTypeParamsInTree(vdef1)
case stat: DefDef =>
val ddef = cloneDefDef(stat)
if !sym.is(Private) then
ddef.symbol.setFlag(Override)
if sym.is(Mutable) then
report.error("implementation restriction: inline traits cannot have mutable variables", stat.srcPos)
ddef
ddef.symbol.info = substituteTypeParams(sym.info)
if !sym.is(Private) then ddef.symbol.setFlag(Override)
substituteTypeParamsInTree(ddef)
case stat @ TypeDef(_, impl: Template) =>
report.error("inline traits do not handle inner classes yet", stat.srcPos)
cloneClass(stat, impl)
Expand All @@ -574,7 +552,7 @@ object Inlines:
val inlinedInfo = ClassInfo(prefix, cls, declaredParents, Scopes.newScope, selfInfo) // TODO adapt parents
clDef.symbol.copy(owner = ctx.owner, info = inlinedInfo, coord = spanCoord(parent.span)).entered.asClass
val (constr, body) = inContext(ctx.withOwner(inlinedCls)) {
(cloneDefDef(impl.constr), impl.body.map(cloneStat))
(clonePrimaryConstructorDefDef(impl.constr), impl.body.map(cloneStat))
}
tpd.ClassDefWithParents(inlinedCls, constr, impl.parents, body).withSpan(clDef.span) // TODO adapt parents

Expand All @@ -592,6 +570,10 @@ object Inlines:
inlinedRhs(ddef.rhs.subst(oldParamSyms, newParamSyms)) // TODO clone local classes?
tpd.DefDef(inlinedSym.asTerm, rhsFun).withSpan(parent.span)

private def clonePrimaryConstructorDefDef(ddef: DefDef)(using Context): DefDef =
val constr = cloneDefDef(ddef)
cpy.DefDef(constr)(tpt = TypeTree(defn.UnitType), rhs = EmptyTree)

private def cloneValDef(vdef: ValDef)(using Context): ValDef =
val inlinedSym = vdef.symbol.copy(owner = ctx.owner, coord = spanCoord(parent.span)).entered
tpd.ValDef(inlinedSym.asTerm, inlinedRhs(vdef.rhs)).withSpan(parent.span) // TODO clone local classes?
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/Mixin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>

def setters(mixin: ClassSymbol): List[Tree] =
val mixinSetters = mixin.info.decls.filter { sym =>
sym.isSetter && (!wasOneOf(sym, Deferred) || sym.name.is(TraitSetterName))
sym.isSetter && (!wasOneOf(sym, Deferred) || sym.name.is(TraitSetterName)) && !sym.owner.isAllOf(InlineTrait)
}
for (setter <- mixinSetters)
yield transformFollowing(DefDef(mkForwarderSym(setter.asTerm), unitLiteral.withSpan(cls.span)))
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/RefChecks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ object RefChecks {
overrideError("needs `override` modifier")
else if (other.is(AbsOverride) && other.isIncompleteIn(clazz) && !member.is(AbsOverride))
overrideError("needs `abstract override` modifiers")
else if member.is(Override) && other.is(Mutable) then
else if member.is(Override) && other.is(Mutable) && !other.owner.isAllOf(InlineTrait) then
overrideError("cannot override a mutable variable")
else if (member.isAnyOverride &&
!(member.owner.thisType.baseClasses exists (_ isSubClass other.owner)) &&
Expand Down
12 changes: 8 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2673,10 +2673,14 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
val body1 = addAccessorDefs(cls, typedStats(impl.body, dummy)(using ctx.inClassContext(self1.symbol))._1) ::: inlineTraitDefs

if !ctx.isAfterTyper && cls.isInlineTrait then
def isConstructorType(t: Tree) =
t.isInstanceOf[TypeDef] && cls.typeParams.contains(t.symbol)
val inlineTraitMembers = Block(body1.filter(t => !isConstructorType(t)), unitLiteral)
PrepareInlineable.registerInlineInfo(cls, inlineTraitMembers)
def isConstructorType(t: Tree) = t.isInstanceOf[TypeDef] && cls.typeParams.contains(t.symbol)
val membersToInline = body1.filter { t =>
!isConstructorType(t)
&& !t.symbol.is(Deferred)
&& !t.symbol.isAllOf(Inline)
}
val wrappedMembersToInline = Block(membersToInline, unitLiteral).withSpan(cdef.span)
PrepareInlineable.registerInlineInfo(cls, wrappedMembersToInline)

checkNoDoubleDeclaration(cls)
val impl1 = cpy.Template(impl)(constr1, parents1, Nil, self1, body1)
Expand Down
9 changes: 4 additions & 5 deletions tests/pos/inline-trait-body-def-curried-params.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
inline trait A:
def x(foo: Int)(bar: Unit) =
bar
foo
def x(foo: Int)(bar: Int) =
foo + bar

def y(foo: Int) = x(foo)
def y(foo: Int) = x(foo)(foo)

class B extends A:
def f = x
def f = x(1)(2)
5 changes: 5 additions & 0 deletions tests/pos/inline-trait-body-def-lambda.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
inline trait A:
def f = (i: Int) => i

class B extends A:
def g = f
2 changes: 1 addition & 1 deletion tests/pos/inline-trait-body-var.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ class B extends A:
def f =
val old = x
x += 1
old
old
10 changes: 10 additions & 0 deletions tests/pos/inline-trait-multiple-stages-defs/A_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
inline trait A(x: Int):
def f: Int = 1
def g(a: Int): Int = 2
def h: Int
val i: Int = 3
val j: Int
var k: Int = 4

inline val a = 5
inline def b(a: Int): Int = 6
3 changes: 3 additions & 0 deletions tests/pos/inline-trait-multiple-stages-defs/B_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class B extends A(10):
def h: Int = 11
val j: Int = 12
9 changes: 9 additions & 0 deletions tests/pos/inline-trait-multiple-stages-generic-defs/A_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
inline trait A[T](x: T):
def f: T = x
def g(a: T): T = a
def h: T
val i: T = x
val j: T
var k: T = x

inline def b(a: T): T = x
3 changes: 3 additions & 0 deletions tests/pos/inline-trait-multiple-stages-generic-defs/B_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class B extends A[Int](10):
def h: Int = 11
val j: Int = 12
2 changes: 1 addition & 1 deletion tests/pos/inline-trait-multiple-stages/A_1.scala
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
inline trait A:
val i: Int = 1
val i: Int = 1
2 changes: 1 addition & 1 deletion tests/pos/inline-trait-multiple-stages/B_2.scala
Original file line number Diff line number Diff line change
@@ -1 +1 @@
class B extends A
class B extends A
9 changes: 6 additions & 3 deletions tests/pos/inline-trait-signature-generic-inferred-type.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
inline trait A[T](val x: T)
inline trait A[T](val x: T):
def f: T = x

class B extends A(1)
val y: Int = f
class B extends A(1):
val y: Int = f

class C extends A[Int](1):
val z: Int = f