Skip to content

Commit b81cc98

Browse files
committed
Move currentPeriod back to Context
1 parent 9b99a46 commit b81cc98

25 files changed

+109
-112
lines changed

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

+5-5
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
414414
ref(NamedType(sym.owner.thisType, sym.name, sym.denot))
415415

416416
private def followOuterLinks(t: Tree)(using Context) = t match {
417-
case t: This if currentlyAfterErasure && !(t.symbol == ctx.owner.enclosingClass || t.symbol.isStaticOwner) =>
417+
case t: This if ctx.erasedTypes && !(t.symbol == ctx.owner.enclosingClass || t.symbol.isStaticOwner) =>
418418
// after erasure outer paths should be respected
419419
ExplicitOuter.OuterOps(ctx).path(toCls = t.tpe.widen.classSymbol)
420420
case t =>
@@ -458,7 +458,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
458458
def newArr =
459459
ref(defn.DottyArraysModule).select(defn.newArrayMethod).withSpan(span)
460460

461-
if (!currentlyAfterErasure) {
461+
if (!ctx.erasedTypes) {
462462
assert(!TypeErasure.isGeneric(elemTpe), elemTpe) //needs to be done during typer. See Applications.convertNewGenericArray
463463
newArr.appliedToTypeTrees(TypeTree(returnTpe) :: Nil).appliedToArgs(clsOf(elemTpe) :: clsOf(returnTpe) :: dims :: Nil).withSpan(span)
464464
}
@@ -962,7 +962,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
962962
/** cast tree to `tp`, assuming no exception is raised, i.e the operation is pure */
963963
def cast(tp: Type)(using Context): Tree = {
964964
assert(tp.isValueType, i"bad cast: $tree.asInstanceOf[$tp]")
965-
tree.select(if (currentlyAfterErasure) defn.Any_asInstanceOf else defn.Any_typeCast)
965+
tree.select(if (ctx.erasedTypes) defn.Any_asInstanceOf else defn.Any_typeCast)
966966
.appliedToType(tp)
967967
}
968968

@@ -972,7 +972,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
972972
*/
973973
def ensureConforms(tp: Type)(using Context): Tree =
974974
if (tree.tpe <:< tp) tree
975-
else if (!currentlyAfterErasure) cast(tp)
975+
else if (!ctx.erasedTypes) cast(tp)
976976
else Erasure.Boxing.adaptToType(tree, tp)
977977

978978
/** `tree ne null` (might need a cast to be type correct) */
@@ -1156,7 +1156,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
11561156

11571157
/** A tree that corresponds to `Predef.classOf[$tp]` in source */
11581158
def clsOf(tp: Type)(using Context): Tree =
1159-
if currentlyAfterErasure then
1159+
if ctx.erasedTypes then
11601160
def TYPE(module: TermSymbol) = ref(module).select(nme.TYPE_)
11611161
defn.scalaClassName(tp) match
11621162
case tpnme.Boolean => TYPE(defn.BoxedBooleanModule)

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

+4-7
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,6 @@ object Contexts {
8080
inline def atPhaseNoEarlier[T](limit: Phase)(inline op: Context ?=> T)(using Context): T =
8181
op(using if !limit.exists || limit <= ctx.phase then ctx else ctx.withPhase(limit))
8282

83-
inline def currentPeriod(using ctx: Context): Period = ctx.period
84-
85-
def currentlyAfterTyper(using Context): Boolean = ctx.base.isAfterTyper(ctx.phase)
86-
87-
/** Does current phase use an erased types interpretation? */
88-
def currentlyAfterErasure(using Context): Boolean = ctx.phase.erasedTypes
89-
9083
inline def inMode[T](mode: Mode)(inline op: Context ?=> T)(using ctx: Context): T =
9184
op(using if mode != ctx.mode then ctx.fresh.setMode(mode) else ctx)
9285

@@ -366,7 +359,11 @@ object Contexts {
366359
final def phase: Phase = base.phases(period.firstPhaseId)
367360
final def runId = period.runId
368361
final def phaseId = period.phaseId
362+
363+
/** Does current phase use an erased types interpretation? */
369364
final def erasedTypes = phase.erasedTypes
365+
366+
/** Is current phase after FrontEnd? */
370367
final def isAfterTyper = base.isAfterTyper(phase)
371368

372369
/** Is this a context for the members of a class definition? */

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -905,7 +905,7 @@ class Definitions {
905905

906906
object ArrayOf {
907907
def apply(elem: Type)(using Context): Type =
908-
if (currentlyAfterErasure) JavaArrayType(elem)
908+
if (ctx.erasedTypes) JavaArrayType(elem)
909909
else ArrayType.appliedTo(elem :: Nil)
910910
def unapply(tp: Type)(using Context): Option[Type] = tp.dealias match {
911911
case AppliedType(at, arg :: Nil) if at.isRef(ArrayType.symbol) => Some(arg)
@@ -1020,7 +1020,7 @@ class Definitions {
10201020
@tu lazy val Function0_apply: Symbol = ImplementedFunctionType(0).symbol.requiredMethod(nme.apply)
10211021

10221022
def FunctionType(n: Int, isContextual: Boolean = false, isErased: Boolean = false)(using Context): TypeRef =
1023-
if (n <= MaxImplementedFunctionArity && (!isContextual || currentlyAfterErasure) && !isErased) ImplementedFunctionType(n)
1023+
if (n <= MaxImplementedFunctionArity && (!isContextual || ctx.erasedTypes) && !isErased) ImplementedFunctionType(n)
10241024
else FunctionClass(n, isContextual, isErased).typeRef
10251025

10261026
lazy val PolyFunctionClass = requiredClass("scala.PolyFunction")
@@ -1285,7 +1285,7 @@ class Definitions {
12851285
*/
12861286
object ContextFunctionType:
12871287
def unapply(tp: Type)(using Context): Option[(List[Type], Type, Boolean)] =
1288-
if currentlyAfterErasure then
1288+
if ctx.erasedTypes then
12891289
atPhase(erasurePhase)(unapply(tp))
12901290
else
12911291
val tp1 = tp.dealias

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

+8-8
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,10 @@ object Denotations {
131131
/** The denotation with info(s) as seen from prefix type */
132132
final def asSeenFrom(pre: Type)(using Context): AsSeenFromResult =
133133
if (Config.cacheAsSeenFrom) {
134-
if ((cachedPrefix ne pre) || currentPeriod != validAsSeenFrom) {
134+
if ((cachedPrefix ne pre) || ctx.period != validAsSeenFrom) {
135135
cachedAsSeenFrom = computeAsSeenFrom(pre)
136136
cachedPrefix = pre
137-
validAsSeenFrom = if (pre.isProvisional) Nowhere else currentPeriod
137+
validAsSeenFrom = if (pre.isProvisional) Nowhere else ctx.period
138138
}
139139
cachedAsSeenFrom
140140
}
@@ -693,7 +693,7 @@ object Denotations {
693693
s"denotation $this invalid in run ${ctx.runId}. ValidFor: $validFor")
694694
var d: SingleDenotation = this
695695
while ({
696-
d.validFor = Period(currentPeriod.runId, d.validFor.firstPhaseId, d.validFor.lastPhaseId)
696+
d.validFor = Period(ctx.runId, d.validFor.firstPhaseId, d.validFor.lastPhaseId)
697697
d.invalidateInheritedInfo()
698698
d = d.nextInRun
699699
d ne this
@@ -746,7 +746,7 @@ object Denotations {
746746
if (myValidFor.code <= 0) nextDefined else this
747747

748748
/** Produce a denotation that is valid for the given context.
749-
* Usually called when !(validFor contains currentPeriod)
749+
* Usually called when !(validFor contains ctx.period)
750750
* (even though this is not a precondition).
751751
* If the runId of the context is the same as runId of this denotation,
752752
* the right flock member is located, or, if it does not exist yet,
@@ -758,7 +758,7 @@ object Denotations {
758758
* the symbol is stale, which constitutes an internal error.
759759
*/
760760
def current(using Context): SingleDenotation = {
761-
val currentPeriod = Contexts.currentPeriod
761+
val currentPeriod = ctx.period
762762
val valid = myValidFor
763763
if (valid.code <= 0) {
764764
// can happen if we sit on a stale denotation which has been replaced
@@ -919,7 +919,7 @@ object Denotations {
919919
case denot: SymDenotation => s"in ${denot.owner}"
920920
case _ => ""
921921
}
922-
s"stale symbol; $this#${symbol.id} $ownerMsg, defined in ${myValidFor}, is referred to in run ${currentPeriod}"
922+
s"stale symbol; $this#${symbol.id} $ownerMsg, defined in ${myValidFor}, is referred to in run ${ctx.period}"
923923
}
924924

925925
/** The period (interval of phases) for which there exists
@@ -977,10 +977,10 @@ object Denotations {
977977
true
978978
case MethodNotAMethodMatch =>
979979
// Java allows defining both a field and a zero-parameter method with the same name
980-
!currentlyAfterErasure && !(symbol.is(JavaDefined) && other.symbol.is(JavaDefined))
980+
!ctx.erasedTypes && !(symbol.is(JavaDefined) && other.symbol.is(JavaDefined))
981981
case ParamMatch =>
982982
// The signatures do not tell us enough to be sure about matching
983-
!currentlyAfterErasure && info.matches(other.info)
983+
!ctx.erasedTypes && info.matches(other.info)
984984
case noMatch =>
985985
false
986986
end matches

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ object Periods {
1919

2020
/** Are all base types in the current period guaranteed to be the same as in period `p`? */
2121
def currentHasSameBaseTypesAs(p: Period)(using Context): Boolean =
22-
val period = currentPeriod
22+
val period = ctx.period
2323
period == p ||
2424
period.runId == p.runId &&
2525
unfusedPhases(period.phaseId).sameBaseTypesStartId ==

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ object Phases {
308308
/** Is this phase the standard typerphase? True for FrontEnd, but
309309
* not for other first phases (such as FromTasty). The predicate
310310
* is tested in some places that perform checks and corrections. It's
311-
* different from currentlyAfterTyper (and cheaper to test).
311+
* different from ctx.isAfterTyper (and cheaper to test).
312312
*/
313313
def isTyper: Boolean = false
314314

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

+14-14
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,7 @@ object SymDenotations {
862862
def membersNeedAsSeenFrom(pre: Type)(using Context): Boolean =
863863
!( this.isTerm
864864
|| this.isStaticOwner && !this.seesOpaques
865-
|| currentlyAfterErasure
865+
|| ctx.erasedTypes
866866
|| (pre eq NoPrefix)
867867
|| (pre eq thisType)
868868
)
@@ -875,7 +875,7 @@ object SymDenotations {
875875
* Default parameters are recognized until erasure.
876876
*/
877877
def hasDefaultParams(using Context): Boolean =
878-
if currentlyAfterErasure then false
878+
if ctx.erasedTypes then false
879879
else if is(HasDefaultParams) then true
880880
else if is(NoDefaultParams) then false
881881
else
@@ -1450,7 +1450,7 @@ object SymDenotations {
14501450
// simulate default parameters, while also passing implicit context ctx to the default values
14511451
val initFlags1 = (if (initFlags != UndefinedFlags) initFlags else this.flags)
14521452
val info1 = if (info != null) info else this.info
1453-
if (currentlyAfterTyper && changedClassParents(info, info1, completersMatter = false))
1453+
if (ctx.isAfterTyper && changedClassParents(info, info1, completersMatter = false))
14541454
assert(ctx.phase.changesParents, i"undeclared parent change at ${ctx.phase} for $this, was: $info, now: $info1")
14551455
val privateWithin1 = if (privateWithin != null) privateWithin else this.privateWithin
14561456
val annotations1 = if (annotations != null) annotations else this.annotations
@@ -1567,17 +1567,17 @@ object SymDenotations {
15671567
private var memberNamesCache: MemberNames = MemberNames.None
15681568

15691569
private def memberCache(using Context): LRUCache[Name, PreDenotation] = {
1570-
if (myMemberCachePeriod != currentPeriod) {
1570+
if (myMemberCachePeriod != ctx.period) {
15711571
myMemberCache = new LRUCache
1572-
myMemberCachePeriod = currentPeriod
1572+
myMemberCachePeriod = ctx.period
15731573
}
15741574
myMemberCache
15751575
}
15761576

15771577
private def baseTypeCache(using Context): BaseTypeMap = {
15781578
if !currentHasSameBaseTypesAs(myBaseTypeCachePeriod) then
15791579
myBaseTypeCache = new BaseTypeMap
1580-
myBaseTypeCachePeriod = currentPeriod
1580+
myBaseTypeCachePeriod = ctx.period
15811581
myBaseTypeCache
15821582
}
15831583

@@ -1641,7 +1641,7 @@ object SymDenotations {
16411641
override final def typeParams(using Context): List[TypeSymbol] = {
16421642
if (myTypeParams == null)
16431643
myTypeParams =
1644-
if (currentlyAfterErasure || is(Module)) Nil // fast return for modules to avoid scanning package decls
1644+
if (ctx.erasedTypes || is(Module)) Nil // fast return for modules to avoid scanning package decls
16451645
else {
16461646
val di = initial
16471647
if (this ne di) di.typeParams
@@ -1729,7 +1729,7 @@ object SymDenotations {
17291729

17301730
def computeBaseData(implicit onBehalf: BaseData, ctx: Context): (List[ClassSymbol], BaseClassSet) = {
17311731
def emptyParentsExpected =
1732-
is(Package) || (symbol == defn.AnyClass) || currentlyAfterErasure && (symbol == defn.ObjectClass)
1732+
is(Package) || (symbol == defn.AnyClass) || ctx.erasedTypes && (symbol == defn.ObjectClass)
17331733
if (classParents.isEmpty && !emptyParentsExpected)
17341734
onBehalf.signalProvisional()
17351735
val builder = new BaseDataBuilder
@@ -1825,7 +1825,7 @@ object SymDenotations {
18251825
*/
18261826
def ensureTypeParamsInCorrectOrder()(using Context): Unit = {
18271827
val tparams = typeParams
1828-
if (!currentlyAfterErasure && !typeParamsFromDecls.corresponds(tparams)(_.name == _.name)) {
1828+
if (!ctx.erasedTypes && !typeParamsFromDecls.corresponds(tparams)(_.name == _.name)) {
18291829
val decls = info.decls
18301830
val decls1 = newScope
18311831
for (tparam <- typeParams) decls1.enter(decls.lookup(tparam.name))
@@ -2372,7 +2372,7 @@ object SymDenotations {
23722372
def traceInvalid(denot: Denotation)(using Context): Boolean = {
23732373
def show(d: Denotation) = s"$d#${d.symbol.id}"
23742374
def explain(msg: String) = {
2375-
println(s"${show(denot)} is invalid at ${currentPeriod} because $msg")
2375+
println(s"${show(denot)} is invalid at ${ctx.period} because $msg")
23762376
false
23772377
}
23782378
denot match {
@@ -2535,7 +2535,7 @@ object SymDenotations {
25352535
implicit val None: MemberNames = new InvalidCache with MemberNames {
25362536
def apply(keepOnly: NameFilter, clsd: ClassDenotation)(implicit onBehalf: MemberNames, ctx: Context) = ???
25372537
}
2538-
def newCache()(using Context): MemberNames = new MemberNamesImpl(currentPeriod)
2538+
def newCache()(using Context): MemberNames = new MemberNamesImpl(ctx.period)
25392539
}
25402540

25412541
/** A cache for baseclasses, as a sequence in linearization order and as a set that
@@ -2552,7 +2552,7 @@ object SymDenotations {
25522552
def apply(clsd: ClassDenotation)(implicit onBehalf: BaseData, ctx: Context) = ???
25532553
def signalProvisional() = ()
25542554
}
2555-
def newCache()(using Context): BaseData = new BaseDataImpl(currentPeriod)
2555+
def newCache()(using Context): BaseData = new BaseDataImpl(ctx.period)
25562556
}
25572557

25582558
private abstract class InheritedCacheImpl(val createdAt: Period) extends InheritedCache {
@@ -2575,11 +2575,11 @@ object SymDenotations {
25752575
}
25762576

25772577
def isValidAt(phase: Phase)(using Context) =
2578-
checkedPeriod == currentPeriod ||
2578+
checkedPeriod == ctx.period ||
25792579
createdAt.runId == ctx.runId &&
25802580
createdAt.phaseId < unfusedPhases.length &&
25812581
sameGroup(unfusedPhases(createdAt.phaseId), phase) &&
2582-
{ checkedPeriod = currentPeriod; true }
2582+
{ checkedPeriod = ctx.period; true }
25832583
}
25842584

25852585
private class InvalidCache extends InheritedCache {

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,13 @@ object Symbols {
102102
final def denot(using Context): SymDenotation = {
103103
util.Stats.record("Symbol.denot")
104104
val lastd = lastDenot
105-
if (checkedPeriod == currentPeriod) lastd
105+
if (checkedPeriod == ctx.period) lastd
106106
else computeDenot(lastd)
107107
}
108108

109109
private def computeDenot(lastd: SymDenotation)(using Context): SymDenotation = {
110110
util.Stats.record("Symbol.computeDenot")
111-
val now = currentPeriod
111+
val now = ctx.period
112112
checkedPeriod = now
113113
if (lastd.validFor contains now) lastd else recomputeDenot(lastd)
114114
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ class TypeApplications(val self: Type) extends AnyVal {
287287
val typParams = self.typeParams
288288
val stripped = self.stripTypeVar
289289
val dealiased = stripped.safeDealias
290-
if (args.isEmpty || currentlyAfterErasure) self
290+
if (args.isEmpty || ctx.erasedTypes) self
291291
else dealiased match {
292292
case dealiased: HKTypeLambda =>
293293
def tryReduce =

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

+6-6
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
261261
// This is safe because X$ self-type is X.type
262262
sym1 = sym1.companionModule
263263
if ((sym1 ne NoSymbol) && (sym1 eq sym2))
264-
currentlyAfterErasure ||
264+
ctx.erasedTypes ||
265265
sym1.isStaticOwner ||
266266
isSubPrefix(tp1.prefix, tp2.prefix) ||
267267
thirdTryNamed(tp2)
@@ -1312,7 +1312,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
13121312
*/
13131313
def compareCaptured(arg1: TypeBounds, arg2: Type) = tparam match {
13141314
case tparam: Symbol =>
1315-
if (leftRoot.isStable || (currentlyAfterTyper || ctx.mode.is(Mode.TypevarsMissContext))
1315+
if (leftRoot.isStable || (ctx.isAfterTyper || ctx.mode.is(Mode.TypevarsMissContext))
13161316
&& leftRoot.member(tparam.name).exists) {
13171317
val captured = TypeRef(leftRoot, tparam)
13181318
try isSubArg(captured, arg2)
@@ -1862,7 +1862,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
18621862
final def glb(tps: List[Type]): Type = tps.foldLeft(AnyType: Type)(glb)
18631863

18641864
def widenInUnions(using Context): Boolean =
1865-
migrateTo3 || currentlyAfterErasure
1865+
migrateTo3 || ctx.erasedTypes
18661866

18671867
/** The least upper bound of two types
18681868
* @param canConstrain If true, new constraints might be added to simplify the lub.
@@ -2021,7 +2021,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
20212021
}
20222022

20232023
private def andTypeGen(tp1: Type, tp2: Type, op: (Type, Type) => Type,
2024-
original: (Type, Type) => Type = _ & _, isErased: Boolean = currentlyAfterErasure): Type = trace(s"glb(${tp1.show}, ${tp2.show})", subtyping, show = true) {
2024+
original: (Type, Type) => Type = _ & _, isErased: Boolean = ctx.erasedTypes): Type = trace(s"glb(${tp1.show}, ${tp2.show})", subtyping, show = true) {
20252025
val t1 = distributeAnd(tp1, tp2)
20262026
if (t1.exists) t1
20272027
else {
@@ -2049,7 +2049,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
20492049
* Finally, refined types with the same refined name are
20502050
* opportunistically merged.
20512051
*/
2052-
final def andType(tp1: Type, tp2: Type, isErased: Boolean = currentlyAfterErasure): Type =
2052+
final def andType(tp1: Type, tp2: Type, isErased: Boolean = ctx.erasedTypes): Type =
20532053
andTypeGen(tp1, tp2, AndType(_, _), isErased = isErased)
20542054

20552055
final def simplifyAndTypeWithFallback(tp1: Type, tp2: Type, fallback: Type): Type =
@@ -2064,7 +2064,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
20642064
* @param isErased Apply erasure semantics. If erased is true, instead of creating
20652065
* an OrType, the lub will be computed using TypeCreator#erasedLub.
20662066
*/
2067-
final def orType(tp1: Type, tp2: Type, isErased: Boolean = currentlyAfterErasure): Type = {
2067+
final def orType(tp1: Type, tp2: Type, isErased: Boolean = ctx.erasedTypes): Type = {
20682068
val t1 = distributeOr(tp1, tp2)
20692069
if (t1.exists) t1
20702070
else {

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ object TypeErasure {
132132

133133
/** The current context with a phase no later than erasure */
134134
def preErasureCtx(using Context) =
135-
if (currentlyAfterErasure) ctx.withPhase(erasurePhase) else ctx
135+
if (ctx.erasedTypes) ctx.withPhase(erasurePhase) else ctx
136136

137137
/** The standard erasure of a Scala type. Value classes are erased as normal classes.
138138
*
@@ -608,7 +608,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
608608
else
609609
val cls = normalizeClass(sym.asClass)
610610
val fullName =
611-
if !currentlyAfterErasure then
611+
if !ctx.erasedTypes then
612612
// It's important to use the initial symbol to compute the full name
613613
// because the current symbol might have a different name or owner
614614
// and signatures are required to be stable before erasure.

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ object TypeOps:
193193
val accu1 = if (accu exists (_ derivesFrom c)) accu else c :: accu
194194
if (cs == c.baseClasses) accu1 else dominators(rest, accu1)
195195
case Nil => // this case can happen because after erasure we do not have a top class anymore
196-
assert(currentlyAfterErasure || ctx.reporter.errorsReported)
196+
assert(ctx.erasedTypes || ctx.reporter.errorsReported)
197197
defn.ObjectClass :: Nil
198198
}
199199

0 commit comments

Comments
 (0)