Skip to content

Commit df35f33

Browse files
authored
[SilOpt] Add new layout _BridgeObject and add pre-specialization support for it (#70239)
rdar://119048001
1 parent 201a5d0 commit df35f33

19 files changed

+131
-42
lines changed

docs/ABI/Mangling.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,7 @@ now codified into the ABI; the index 0 is therefore reserved.
947947
LAYOUT-CONSTRAINT ::= 'M' LAYOUT-SIZE-AND-ALIGNMENT // Trivial of size at most N bits
948948
LAYOUT-CONSTRAINT ::= 'm' LAYOUT-SIZE // Trivial of size at most N bits
949949
LAYOUT-CONSTRAINT ::= 'U' // Unknown layout
950+
LAYOUT-CONSTRAINT ::= 'B' // BridgeObject
950951

951952
LAYOUT-SIZE ::= INDEX // Size only
952953
LAYOUT-SIZE-AND-ALIGNMENT ::= INDEX INDEX // Size followed by alignment

include/swift/AST/KnownIdentifiers.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ IDENTIFIER_WITH_NAME(RefCountedObjectLayout, "_RefCountedObject")
177177
IDENTIFIER_WITH_NAME(NativeRefCountedObjectLayout, "_NativeRefCountedObject")
178178
IDENTIFIER_WITH_NAME(ClassLayout, "_Class")
179179
IDENTIFIER_WITH_NAME(NativeClassLayout, "_NativeClass")
180+
IDENTIFIER_WITH_NAME(BridgeObjectLayout, "_BridgeObject")
180181

181182
// Operators
182183
IDENTIFIER_WITH_NAME(MatchOperator, "~=")

include/swift/AST/LayoutConstraint.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ class LayoutConstraintInfo
112112
return isNativeRefCounted(Kind);
113113
}
114114

115+
bool isBridgeObject() const { return isBridgeObject(Kind); }
116+
115117
unsigned getTrivialSizeInBytes() const {
116118
assert(isKnownSizeTrivial());
117119
return (SizeInBits + 7) / 8;
@@ -200,6 +202,8 @@ class LayoutConstraintInfo
200202

201203
static bool isNativeRefCounted(LayoutConstraintKind Kind);
202204

205+
static bool isBridgeObject(LayoutConstraintKind Kind);
206+
203207
/// Uniquing for the LayoutConstraintInfo.
204208
void Profile(llvm::FoldingSetNodeID &ID) {
205209
Profile(ID, Kind, SizeInBits, Alignment);
@@ -217,6 +221,7 @@ class LayoutConstraintInfo
217221
static LayoutConstraintInfo ClassConstraintInfo;
218222
static LayoutConstraintInfo NativeClassConstraintInfo;
219223
static LayoutConstraintInfo TrivialConstraintInfo;
224+
static LayoutConstraintInfo BridgeObjectConstraintInfo;
220225
};
221226

222227
/// A wrapper class containing a reference to the actual LayoutConstraintInfo

include/swift/AST/LayoutConstraintKind.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ enum class LayoutConstraintKind : uint8_t {
3939
RefCountedObject,
4040
// It is a layout constraint representing a native reference counted object.
4141
NativeRefCountedObject,
42-
LastLayout = NativeRefCountedObject,
42+
// It is a layout constraint representing a bridge object
43+
BridgeObject,
44+
LastLayout = BridgeObject,
4345
};
4446

4547
#endif

include/swift/Demangling/TypeDecoder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@ void decodeRequirement(NodePointer node,
427427
.Case("C", LayoutConstraintKind::Class)
428428
.Case("D", LayoutConstraintKind::NativeClass)
429429
.Case("T", LayoutConstraintKind::Trivial)
430+
.Case("B", LayoutConstraintKind::BridgeObject)
430431
.Cases("E", "e", LayoutConstraintKind::TrivialOfExactSize)
431432
.Cases("M", "m", LayoutConstraintKind::TrivialOfAtMostSize)
432433
.Default(llvm::None);

include/swift/SIL/SILType.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,8 @@ class SILType {
284284
return is<BuiltinVectorType>();
285285
}
286286

287+
bool isBuiltinBridgeObject() const { return is<BuiltinBridgeObjectType>(); }
288+
287289
SWIFT_IMPORT_UNSAFE
288290
SILType getBuiltinVectorElementType() const {
289291
auto vector = castTo<BuiltinVectorType>();

lib/AST/ASTMangler.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3801,6 +3801,9 @@ void ASTMangler::appendOpParamForLayoutConstraint(LayoutConstraint layout) {
38013801
appendOperatorParam("M", Index(layout->getTrivialSizeInBits()),
38023802
Index(layout->getAlignmentInBits()));
38033803
break;
3804+
case LayoutConstraintKind::BridgeObject:
3805+
appendOperatorParam("B");
3806+
break;
38043807
}
38053808
}
38063809

lib/AST/ASTPrinter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7683,6 +7683,7 @@ void LayoutConstraintInfo::print(ASTPrinter &Printer,
76837683
case LayoutConstraintKind::Class:
76847684
case LayoutConstraintKind::NativeClass:
76857685
case LayoutConstraintKind::Trivial:
7686+
case LayoutConstraintKind::BridgeObject:
76867687
return; // non-parameterized cases
76877688
case LayoutConstraintKind::TrivialOfAtMostSize:
76887689
case LayoutConstraintKind::TrivialOfExactSize:

lib/AST/GenericSignature.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -511,10 +511,18 @@ GenericSignature GenericSignature::typeErased(ArrayRef<Type> typeErasedParams) c
511511
auto other = req.getFirstType();
512512
return t->isEqual(other);
513513
});
514-
if (found) {
515-
requirementsErased.push_back(Requirement(RequirementKind::SameType,
516-
req.getFirstType(),
517-
Ptr->getASTContext().getAnyObjectType()));
514+
if (found && req.getKind() == RequirementKind::Layout) {
515+
if (req.getLayoutConstraint()->isClass()) {
516+
requirementsErased.push_back(
517+
Requirement(RequirementKind::SameType, req.getFirstType(),
518+
Ptr->getASTContext().getAnyObjectType()));
519+
} else if (req.getLayoutConstraint()->isBridgeObject()) {
520+
requirementsErased.push_back(
521+
Requirement(RequirementKind::SameType, req.getFirstType(),
522+
Ptr->getASTContext().TheBridgeObjectType));
523+
} else {
524+
requirementsErased.push_back(req);
525+
}
518526
} else {
519527
requirementsErased.push_back(req);
520528
}

lib/AST/LayoutConstraint.cpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ LayoutConstraint getLayoutConstraint(Identifier ID, ASTContext &Ctx) {
4747
return LayoutConstraint::getLayoutConstraint(
4848
LayoutConstraintKind::NativeClass, Ctx);
4949

50+
if (ID == Ctx.Id_BridgeObjectLayout)
51+
return LayoutConstraint::getLayoutConstraint(
52+
LayoutConstraintKind::BridgeObject, Ctx);
53+
5054
return LayoutConstraint::getLayoutConstraint(
5155
LayoutConstraintKind::UnknownLayout, Ctx);
5256
}
@@ -73,6 +77,8 @@ StringRef LayoutConstraintInfo::getName(LayoutConstraintKind Kind, bool internal
7377
return "_TrivialAtMost";
7478
case LayoutConstraintKind::TrivialOfExactSize:
7579
return "_Trivial";
80+
case LayoutConstraintKind::BridgeObject:
81+
return "_BridgeObject";
7682
}
7783

7884
llvm_unreachable("Unhandled LayoutConstraintKind in switch.");
@@ -132,14 +138,18 @@ bool LayoutConstraintInfo::isNativeClass(LayoutConstraintKind Kind) {
132138
}
133139

134140
bool LayoutConstraintInfo::isRefCounted(LayoutConstraintKind Kind) {
135-
return isAnyRefCountedObject(Kind) || isClass(Kind);
141+
return isAnyRefCountedObject(Kind) || isClass(Kind) || isBridgeObject(Kind);
136142
}
137143

138144
bool LayoutConstraintInfo::isNativeRefCounted(LayoutConstraintKind Kind) {
139145
return Kind == LayoutConstraintKind::NativeRefCountedObject ||
140146
Kind == LayoutConstraintKind::NativeClass;
141147
}
142148

149+
bool LayoutConstraintInfo::isBridgeObject(LayoutConstraintKind Kind) {
150+
return Kind == LayoutConstraintKind::BridgeObject;
151+
}
152+
143153
SourceRange LayoutConstraintLoc::getSourceRange() const { return getLoc(); }
144154

145155
#define MERGE_LOOKUP(lhs, rhs) \
@@ -170,50 +180,55 @@ static LayoutConstraintKind mergeTable[unsigned(E(LastLayout)) +
170180
E(/* TrivialOfAtMostSize */ TrivialOfAtMostSize), E(/* Trivial */ Trivial),
171181
E(/* Class */ Class), E(/* NativeClass */ NativeClass),
172182
E(/* RefCountedObject*/ RefCountedObject),
173-
E(/* NativeRefCountedObject */ NativeRefCountedObject)},
183+
E(/* NativeRefCountedObject */ NativeRefCountedObject), MERGE_CONFLICT},
174184

175185
// Initialize the row for TrivialOfExactSize.
176186
{E(/* UnknownLayout */ TrivialOfExactSize),
177187
E(/* TrivialOfExactSize */ TrivialOfExactSize), MERGE_CONFLICT,
178188
E(/* Trivial */ TrivialOfExactSize), MERGE_CONFLICT, MERGE_CONFLICT,
179-
MERGE_CONFLICT, MERGE_CONFLICT},
189+
MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT},
180190

181191
// Initialize the row for TrivialOfAtMostSize.
182192
{E(/* UnknownLayout */ TrivialOfAtMostSize), MERGE_CONFLICT,
183193
E(/* TrivialOfAtMostSize */ TrivialOfAtMostSize),
184194
E(/* Trivial */ TrivialOfAtMostSize), MERGE_CONFLICT, MERGE_CONFLICT,
185-
MERGE_CONFLICT, MERGE_CONFLICT},
195+
MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT},
186196

187197
// Initialize the row for Trivial.
188198
{E(/* UnknownLayout */ Trivial),
189199
E(/* TrivialOfExactSize */ TrivialOfExactSize),
190200
E(/* TrivialOfAtMostSize */ TrivialOfAtMostSize), E(/* Trivial */ Trivial),
191-
MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT},
201+
MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT,
202+
MERGE_CONFLICT},
192203

193204
// Initialize the row for Class.
194205
{E(/* UnknownLayout*/ Class), MERGE_CONFLICT, MERGE_CONFLICT,
195206
MERGE_CONFLICT, E(/* Class */ Class), E(/* NativeClass */ NativeClass),
196207
E(/* RefCountedObject */ Class),
197-
E(/* NativeRefCountedObject */ NativeClass)},
208+
E(/* NativeRefCountedObject */ NativeClass), MERGE_CONFLICT},
198209

199210
// Initialize the row for NativeClass.
200211
{E(/* UnknownLayout */ NativeClass), MERGE_CONFLICT, MERGE_CONFLICT,
201212
MERGE_CONFLICT, E(/* Class */ NativeClass),
202213
E(/* NativeClass */ NativeClass), E(/* RefCountedObject */ NativeClass),
203-
E(/* NativeRefCountedObject */ NativeClass)},
214+
E(/* NativeRefCountedObject */ NativeClass), MERGE_CONFLICT},
204215

205216
// Initialize the row for RefCountedObject.
206217
{E(/* UnknownLayout */ RefCountedObject), MERGE_CONFLICT, MERGE_CONFLICT,
207218
MERGE_CONFLICT, E(/* Class */ Class), E(/* NativeClass */ NativeClass),
208219
E(/* RefCountedObject */ RefCountedObject),
209-
E(/* NativeRefCountedObject */ NativeRefCountedObject)},
220+
E(/* NativeRefCountedObject */ NativeRefCountedObject), MERGE_CONFLICT},
210221

211222
// Initialize the row for NativeRefCountedObject.
212223
{E(/* UnknownLayout */ NativeRefCountedObject), MERGE_CONFLICT,
213224
MERGE_CONFLICT, MERGE_CONFLICT, E(/* Class */ NativeClass),
214225
E(/* NativeClass */ NativeClass),
215226
E(/* RefCountedObject */ NativeRefCountedObject),
216-
E(/* NativeRefCountedObject*/ NativeRefCountedObject)},
227+
E(/* NativeRefCountedObject*/ NativeRefCountedObject), MERGE_CONFLICT},
228+
229+
{E(BridgeObject), MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT,
230+
MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT,
231+
E(/*BridgeObject*/ BridgeObject)},
217232
};
218233

219234
#undef E
@@ -324,6 +339,8 @@ LayoutConstraint::getLayoutConstraint(LayoutConstraintKind Kind) {
324339
&LayoutConstraintInfo::RefCountedObjectConstraintInfo);
325340
case LayoutConstraintKind::UnknownLayout:
326341
return LayoutConstraint(&LayoutConstraintInfo::UnknownLayoutConstraintInfo);
342+
case LayoutConstraintKind::BridgeObject:
343+
return LayoutConstraint(&LayoutConstraintInfo::BridgeObjectConstraintInfo);
327344
case LayoutConstraintKind::TrivialOfAtMostSize:
328345
case LayoutConstraintKind::TrivialOfExactSize:
329346
llvm_unreachable("Wrong layout constraint kind");
@@ -352,6 +369,9 @@ LayoutConstraintInfo LayoutConstraintInfo::NativeClassConstraintInfo(
352369
LayoutConstraintInfo LayoutConstraintInfo::TrivialConstraintInfo(
353370
LayoutConstraintKind::Trivial);
354371

372+
LayoutConstraintInfo LayoutConstraintInfo::BridgeObjectConstraintInfo(
373+
LayoutConstraintKind::BridgeObject);
374+
355375
int LayoutConstraint::compare(LayoutConstraint rhs) const {
356376
if (Ptr->getKind() != rhs->getKind())
357377
return int(rhs->getKind()) - int(Ptr->getKind());

lib/Demangling/Demangler.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4028,6 +4028,8 @@ NodePointer Demangler::demangleGenericRequirement() {
40284028
name = "D";
40294029
} else if (c == 'T') {
40304030
name = "T";
4031+
} else if (c == 'B') {
4032+
name = "B";
40314033
} else if (c == 'E') {
40324034
size = demangleIndexAsNode();
40334035
if (!size)

lib/Demangling/OldDemangler.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1633,6 +1633,9 @@ class OldDemangler {
16331633
} else if (Mangled.nextIf('T')) {
16341634
kind = Node::Kind::Identifier;
16351635
name = "T";
1636+
} else if (Mangled.nextIf('B')) {
1637+
kind = Node::Kind::Identifier;
1638+
name = "B";
16361639
} else if (Mangled.nextIf('E')) {
16371640
kind = Node::Kind::Identifier;
16381641
if (!demangleNatural(size, depth + 1))

lib/SIL/IR/AbstractionPattern.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2238,6 +2238,7 @@ class SubstFunctionTypePatternVisitor
22382238
// Keep these layout constraints as is.
22392239
case LayoutConstraintKind::RefCountedObject:
22402240
case LayoutConstraintKind::TrivialOfAtMostSize:
2241+
case LayoutConstraintKind::BridgeObject:
22412242
break;
22422243

22432244
case LayoutConstraintKind::UnknownLayout:

lib/SILOptimizer/Utils/Generics.cpp

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -316,14 +316,25 @@ void SpecializedFunction::computeTypeReplacements(const ApplySite &apply) {
316316
auto resultType =
317317
fn->getConventions().getSILResultType(fn->getTypeExpansionContext());
318318
SmallVector<SILResultInfo, 4> indirectResults(substConv.getIndirectSILResults());
319+
SmallVector<SILResultInfo, 4> targetIndirectResults(
320+
fn->getConventions().getIndirectSILResults());
319321

320322
for (auto pair : llvm::enumerate(apply.getArgumentOperands())) {
321323
if (pair.index() < substConv.getSILArgIndexOfFirstParam()) {
322324
auto formalIndex = substConv.getIndirectFormalResultIndexForSILArg(pair.index());
323325
auto fnResult = indirectResults[formalIndex];
324326
if (fnResult.isFormalIndirect()) {
325-
// FIXME: properly get the type
326-
auto indirectResultTy = M.getASTContext().getAnyObjectType(); //fnResult.getReturnValueType(M, fnType, expansion);
327+
CanType indirectResultTy;
328+
if (targetIndirectResults.size() > formalIndex) {
329+
indirectResultTy =
330+
targetIndirectResults[formalIndex].getReturnValueType(
331+
M, fnType, expansion);
332+
} else {
333+
indirectResultTy =
334+
fnType->getResults()[formalIndex].getReturnValueType(M, fnType,
335+
expansion);
336+
}
337+
327338
addIndirectResultType(formalIndex, indirectResultTy);
328339
}
329340

@@ -2967,7 +2978,7 @@ bool usePrespecialized(
29672978

29682979
if (specializedReInfo.getSpecializedType() != reInfo.getSpecializedType()) {
29692980
SmallVector<Type, 4> newSubs;
2970-
auto specializedSig = SA->getSpecializedSignature();
2981+
auto specializedSig = SA->getUnerasedSpecializedSignature();
29712982

29722983
auto erasedParams = SA->getTypeErasedParams();
29732984
if(!ctxt.LangOpts.hasFeature(Feature::LayoutPrespecialization) || erasedParams.empty()) {
@@ -2985,8 +2996,12 @@ bool usePrespecialized(
29852996
});
29862997

29872998
auto layout = specializedSig->getLayoutConstraint(genericParam);
2999+
if (!specializedSig->getRequiredProtocols(genericParam).empty()) {
3000+
llvm::report_fatal_error("Unexpected protocol requirements");
3001+
}
29883002

2989-
if (!erased || !layout || !layout->isClass()) {
3003+
if (!erased || !layout ||
3004+
(!layout->isClass() && !layout->isBridgeObject())) {
29903005
newSubs.push_back(entry.value());
29913006
continue;
29923007
}
@@ -2997,17 +3012,19 @@ bool usePrespecialized(
29973012
lowered = singleton;
29983013
}
29993014

3000-
if (!lowered.hasRetainablePointerRepresentation()) {
3001-
// non-reference type can't be applied
3002-
break;
3003-
} else if (!specializedSig->getRequiredProtocols(genericParam)
3004-
.empty()) {
3005-
llvm::report_fatal_error("Unexpected protocol requirements");
3006-
} else if (layout->isNativeClass()) {
3007-
newSubs.push_back(genericParam->getASTContext().TheNativeObjectType);
3008-
score += 1;
3015+
if (lowered.isBuiltinBridgeObject() && layout->isBridgeObject()) {
3016+
newSubs.push_back(genericParam->getASTContext().TheBridgeObjectType);
3017+
} else if (lowered.hasRetainablePointerRepresentation()) {
3018+
if (layout->isNativeClass()) {
3019+
newSubs.push_back(
3020+
genericParam->getASTContext().TheNativeObjectType);
3021+
score += 1;
3022+
} else {
3023+
newSubs.push_back(genericParam->getASTContext().getAnyObjectType());
3024+
}
30093025
} else {
3010-
newSubs.push_back(genericParam->getASTContext().getAnyObjectType());
3026+
// no match
3027+
break;
30113028
}
30123029
}
30133030

lib/Serialization/Deserialization.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,7 @@ getActualLayoutConstraintKind(uint64_t rawKind) {
11841184
CASE(Class)
11851185
CASE(NativeClass)
11861186
CASE(UnknownLayout)
1187+
CASE(BridgeObject)
11871188
}
11881189
#undef CASE
11891190

lib/Serialization/ModuleFormat.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5858
/// describe what change you made. The content of this comment isn't important;
5959
/// it just ensures a conflict if two people change the module format.
6060
/// Don't worry about adhering to the 80-column limit for this line.
61-
const uint16_t SWIFTMODULE_VERSION_MINOR = 823; // _resultDependsOn
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 824; // LayoutRequirementKindField
6262

6363
/// A standard hash seed used for all string hashes in a serialized module.
6464
///
@@ -482,9 +482,10 @@ enum LayoutRequirementKind : uint8_t {
482482
RefCountedObject = 4,
483483
NativeRefCountedObject = 5,
484484
Class = 6,
485-
NativeClass = 7
485+
NativeClass = 7,
486+
BridgeObject = 8,
486487
};
487-
using LayoutRequirementKindField = BCFixed<3>;
488+
using LayoutRequirementKindField = BCFixed<4>;
488489

489490
// These IDs must \em not be renumbered or reordered without incrementing
490491
// the module version.

lib/Serialization/Serialization.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1507,6 +1507,9 @@ void Serializer::serializeGenericRequirements(
15071507
case LayoutConstraintKind::UnknownLayout:
15081508
rawKind = LayoutRequirementKind::UnknownLayout;
15091509
break;
1510+
case LayoutConstraintKind::BridgeObject:
1511+
rawKind = LayoutRequirementKind::BridgeObject;
1512+
break;
15101513
}
15111514
scratch.push_back(rawKind);
15121515
scratch.push_back(addTypeRef(req.getFirstType()));

test/SILOptimizer/Inputs/pre_specialized_module_layouts.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public class SomeClass {
1010
@_specialize(exported: true, where T == Int)
1111
@_specialize(exported: true, where T == Double)
1212
@_specialize(exported: true, where @_noMetadata T : _Class)
13+
@_specialize(exported: true, where @_noMetadata T : _BridgeObject)
1314
@_specialize(exported: true, availability: macOS 10.50, *; where T == SomeData)
1415
public func publicPrespecialized<T>(_ t: T) {
1516
}
@@ -131,6 +132,7 @@ public func useInternalThing<T>(_ t: T) {
131132
}
132133

133134
@_specialize(exported: true, where @_noMetadata T : _Class, @_noMetadata V : _Class)
135+
@_specialize(exported: true, where @_noMetadata T : _BridgeObject, @_noMetadata V : _BridgeObject)
134136
public func publicPresepcializedMultipleIndirectResults<T, V>(_ t: T, _ v: V, _ x: Int64)-> (V, Int64, T) {
135137
return (v, x, t)
136-
}
138+
}

0 commit comments

Comments
 (0)