Skip to content

Commit d913218

Browse files
authored
Merge pull request #1667 from swiftwasm/release/5.3
[pull] swiftwasm-release/5.3 from release/5.3
2 parents 1992afe + 7e770fd commit d913218

16 files changed

+628
-77
lines changed

include/swift/Parse/Parser.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -1357,8 +1357,7 @@ class Parser {
13571357
ParserResult<Pattern> parsePatternTuple();
13581358

13591359
ParserResult<Pattern>
1360-
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> P,
1361-
bool isOptional);
1360+
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> P);
13621361
ParserResult<Pattern> parseMatchingPattern(bool isExprBasic);
13631362
ParserResult<Pattern> parseMatchingPatternAsLetOrVar(bool isLet,
13641363
SourceLoc VarLoc,

lib/AST/ASTPrinter.cpp

+2-10
Original file line numberDiff line numberDiff line change
@@ -2642,18 +2642,10 @@ void PrintAST::visitVarDecl(VarDecl *decl) {
26422642
Printer << ": ";
26432643
TypeLoc tyLoc;
26442644
if (auto *repr = decl->getTypeReprOrParentPatternTypeRepr()) {
2645-
// Workaround for if-let statements. The parser creates a `OptionalTypeRepr`
2646-
// even though the user-written declared type for the if-let variable
2647-
// is non-optional. Get the non-optional type so we can print it correctly.
2648-
if (auto *optRepr = dyn_cast<OptionalTypeRepr>(repr)) {
2649-
if (type && !isa<OptionalType>(type.getPointer())) {
2650-
repr = optRepr->getBase();
2651-
}
2652-
}
26532645
tyLoc = TypeLoc(repr, type);
2654-
} else
2646+
} else {
26552647
tyLoc = TypeLoc::withoutLoc(type);
2656-
2648+
}
26572649
Printer.printDeclResultTypePre(decl, tyLoc);
26582650

26592651
// HACK: When printing result types for vars with opaque result types,

lib/Parse/ParsePattern.cpp

+1-11
Original file line numberDiff line numberDiff line change
@@ -1110,8 +1110,7 @@ ParserResult<Pattern> Parser::parsePatternTuple() {
11101110
/// pattern-type-annotation ::= (':' type)?
11111111
///
11121112
ParserResult<Pattern> Parser::
1113-
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> result,
1114-
bool isOptional) {
1113+
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> result) {
11151114
if (!Tok.is(tok::colon))
11161115
return result;
11171116

@@ -1138,15 +1137,6 @@ parseOptionalPatternTypeAnnotation(ParserResult<Pattern> result,
11381137
if (!repr)
11391138
repr = new (Context) ErrorTypeRepr(PreviousLoc);
11401139

1141-
// In an if-let, the actual type of the expression is Optional of whatever
1142-
// was written.
1143-
// FIXME: This is not good, `TypeRepr`s are supposed to represent what the
1144-
// user actually wrote in source (that's why they don't have any `isImplicit`
1145-
// bit). This synthesized `OptionalTypeRepr` leads to workarounds in other
1146-
// parts where we want to reason about the types as perceived by the user.
1147-
if (isOptional)
1148-
repr = new (Context) OptionalTypeRepr(repr, SourceLoc());
1149-
11501140
return makeParserResult(status, new (Context) TypedPattern(P, repr));
11511141
}
11521142

lib/Parse/ParseStmt.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -1498,8 +1498,7 @@ Parser::parseStmtConditionElement(SmallVectorImpl<StmtConditionElement> &result,
14981498
P->setImplicit();
14991499
}
15001500

1501-
ThePattern = parseOptionalPatternTypeAnnotation(ThePattern,
1502-
BindingKindStr != "case");
1501+
ThePattern = parseOptionalPatternTypeAnnotation(ThePattern);
15031502
if (ThePattern.hasCodeCompletion()) {
15041503
Status.setHasCodeCompletion();
15051504

@@ -2121,7 +2120,7 @@ ParserResult<Stmt> Parser::parseStmtForEach(LabeledStmtInfo LabelInfo) {
21212120
llvm::SaveAndRestore<decltype(InVarOrLetPattern)>
21222121
T(InVarOrLetPattern, Parser::IVOLP_InMatchingPattern);
21232122
pattern = parseMatchingPattern(/*isExprBasic*/true);
2124-
pattern = parseOptionalPatternTypeAnnotation(pattern, /*isOptional*/false);
2123+
pattern = parseOptionalPatternTypeAnnotation(pattern);
21252124
} else if (!IsCStyleFor || Tok.is(tok::kw_var)) {
21262125
// Change the parser state to know that the pattern we're about to parse is
21272126
// implicitly mutable. Bound variables can be changed to mutable explicitly

lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h

+5
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,11 @@ class DIMemoryObjectInfo {
176176
MemoryInst->isDerivedClassSelfOnly();
177177
}
178178

179+
/// True if this memory object is the 'self' of a root class init method.
180+
bool isRootClassSelf() const {
181+
return isClassInitSelf() && MemoryInst->isRootSelf();
182+
}
183+
179184
/// True if this memory object is the 'self' of a non-root class init method.
180185
bool isNonRootClassSelf() const {
181186
return isClassInitSelf() && !MemoryInst->isRootSelf();

lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp

+111-35
Original file line numberDiff line numberDiff line change
@@ -1071,7 +1071,13 @@ void LifetimeChecker::handleStoreUse(unsigned UseID) {
10711071
// it for later. Once we've collected all of the conditional init/assigns,
10721072
// we can insert a single control variable for the memory object for the
10731073
// whole function.
1074-
if (!Use.onlyTouchesTrivialElements(TheMemory))
1074+
//
1075+
// For root class initializers, we must keep track of initializations of
1076+
// trivial stored properties also, since we need to know when the object
1077+
// has been fully initialized when deciding if a strong_release should
1078+
// lower to a partial_dealloc_ref.
1079+
if (TheMemory.isRootClassSelf() ||
1080+
!Use.onlyTouchesTrivialElements(TheMemory))
10751081
HasConditionalInitAssign = true;
10761082
return;
10771083
}
@@ -2177,12 +2183,12 @@ static void updateControlVariable(SILLocation Loc,
21772183
}
21782184

21792185
/// Test a bit in the control variable at the current insertion point.
2180-
static SILValue testControlVariable(SILLocation Loc,
2181-
unsigned Elt,
2182-
SILValue ControlVariableAddr,
2183-
Identifier &ShiftRightFn,
2184-
Identifier &TruncateFn,
2185-
SILBuilder &B) {
2186+
static SILValue testControlVariableBit(SILLocation Loc,
2187+
unsigned Elt,
2188+
SILValue ControlVariableAddr,
2189+
Identifier &ShiftRightFn,
2190+
Identifier &TruncateFn,
2191+
SILBuilder &B) {
21862192
SILValue ControlVariable =
21872193
B.createLoad(Loc, ControlVariableAddr, LoadOwnershipQualifier::Trivial);
21882194

@@ -2215,6 +2221,32 @@ static SILValue testControlVariable(SILLocation Loc,
22152221
{}, CondVal);
22162222
}
22172223

2224+
/// Test if all bits in the control variable are set at the current
2225+
/// insertion point.
2226+
static SILValue testAllControlVariableBits(SILLocation Loc,
2227+
SILValue ControlVariableAddr,
2228+
Identifier &CmpEqFn,
2229+
SILBuilder &B) {
2230+
SILValue ControlVariable =
2231+
B.createLoad(Loc, ControlVariableAddr, LoadOwnershipQualifier::Trivial);
2232+
2233+
SILValue CondVal = ControlVariable;
2234+
CanBuiltinIntegerType IVType = CondVal->getType().castTo<BuiltinIntegerType>();
2235+
2236+
if (IVType->getFixedWidth() == 1)
2237+
return CondVal;
2238+
2239+
SILValue AllBitsSet = B.createIntegerLiteral(Loc, CondVal->getType(), -1);
2240+
if (!CmpEqFn.get())
2241+
CmpEqFn = getBinaryFunction("cmp_eq", CondVal->getType(),
2242+
B.getASTContext());
2243+
SILValue Args[] = { CondVal, AllBitsSet };
2244+
2245+
return B.createBuiltin(Loc, CmpEqFn,
2246+
SILType::getBuiltinIntegerType(1, B.getASTContext()),
2247+
{}, Args);
2248+
}
2249+
22182250
/// handleConditionalInitAssign - This memory object has some stores
22192251
/// into (some element of) it that is either an init or an assign based on the
22202252
/// control flow path through the function, or have a destroy event that happens
@@ -2276,7 +2308,13 @@ SILValue LifetimeChecker::handleConditionalInitAssign() {
22762308
// If this ambiguous store is only of trivial types, then we don't need to
22772309
// do anything special. We don't even need keep the init bit for the
22782310
// element precise.
2279-
if (Use.onlyTouchesTrivialElements(TheMemory))
2311+
//
2312+
// For root class initializers, we must keep track of initializations of
2313+
// trivial stored properties also, since we need to know when the object
2314+
// has been fully initialized when deciding if a strong_release should
2315+
// lower to a partial_dealloc_ref.
2316+
if (!TheMemory.isRootClassSelf() &&
2317+
Use.onlyTouchesTrivialElements(TheMemory))
22802318
continue;
22812319

22822320
B.setInsertionPoint(Use.Inst);
@@ -2315,9 +2353,9 @@ SILValue LifetimeChecker::handleConditionalInitAssign() {
23152353
// initialization.
23162354
for (unsigned Elt = Use.FirstElement, e = Elt+Use.NumElements;
23172355
Elt != e; ++Elt) {
2318-
auto CondVal = testControlVariable(Loc, Elt, ControlVariableAddr,
2319-
ShiftRightFn, TruncateFn,
2320-
B);
2356+
auto CondVal = testControlVariableBit(Loc, Elt, ControlVariableAddr,
2357+
ShiftRightFn, TruncateFn,
2358+
B);
23212359

23222360
SILBasicBlock *TrueBB, *FalseBB, *ContBB;
23232361
InsertCFGDiamond(CondVal, Loc, B,
@@ -2386,7 +2424,7 @@ SILValue LifetimeChecker::handleConditionalInitAssign() {
23862424
void LifetimeChecker::
23872425
handleConditionalDestroys(SILValue ControlVariableAddr) {
23882426
SILBuilderWithScope B(TheMemory.getUninitializedValue());
2389-
Identifier ShiftRightFn, TruncateFn;
2427+
Identifier ShiftRightFn, TruncateFn, CmpEqFn;
23902428

23912429
unsigned NumMemoryElements = TheMemory.getNumElements();
23922430

@@ -2456,9 +2494,9 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
24562494

24572495
// Insert a load of the liveness bitmask and split the CFG into a diamond
24582496
// right before the destroy_addr, if we haven't already loaded it.
2459-
auto CondVal = testControlVariable(Loc, Elt, ControlVariableAddr,
2460-
ShiftRightFn, TruncateFn,
2461-
B);
2497+
auto CondVal = testControlVariableBit(Loc, Elt, ControlVariableAddr,
2498+
ShiftRightFn, TruncateFn,
2499+
B);
24622500

24632501
SILBasicBlock *ReleaseBlock, *DeallocBlock, *ContBlock;
24642502

@@ -2477,11 +2515,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
24772515
// depending on if the self box was initialized or not.
24782516
auto emitReleaseOfSelfWhenNotConsumed = [&](SILLocation Loc,
24792517
SILInstruction *Release) {
2480-
auto CondVal = testControlVariable(Loc, SelfInitializedElt,
2481-
ControlVariableAddr,
2482-
ShiftRightFn,
2483-
TruncateFn,
2484-
B);
2518+
auto CondVal = testControlVariableBit(Loc, SelfInitializedElt,
2519+
ControlVariableAddr,
2520+
ShiftRightFn,
2521+
TruncateFn,
2522+
B);
24852523

24862524
SILBasicBlock *ReleaseBlock, *ConsumedBlock, *ContBlock;
24872525

@@ -2513,12 +2551,50 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
25132551
// Just conditionally destroy each memory element, and for classes,
25142552
// also free the partially initialized object.
25152553
if (!TheMemory.isNonRootClassSelf()) {
2516-
destroyMemoryElements(Loc, Availability);
2517-
processUninitializedRelease(Release, false, B.getInsertionPoint());
2554+
assert(!Availability.isAllYes() &&
2555+
"Should not end up here if fully initialized");
2556+
2557+
// For root class initializers, we check if all proeprties were
2558+
// dynamically initialized, and if so, treat this as a release of
2559+
// an initialized 'self', instead of tearing down the fields
2560+
// one by one and deallocating memory.
2561+
//
2562+
// This is required for correctness, since the condition that
2563+
// allows 'self' to escape is that all stored properties were
2564+
// initialized. So we cannot deallocate the memory if 'self' may
2565+
// have escaped.
2566+
//
2567+
// This also means the deinitializer will run if all stored
2568+
// properties were initialized.
2569+
if (TheMemory.isClassInitSelf() &&
2570+
Availability.hasAny(DIKind::Partial)) {
2571+
auto CondVal = testAllControlVariableBits(Loc, ControlVariableAddr,
2572+
CmpEqFn, B);
2573+
2574+
SILBasicBlock *ReleaseBlock, *DeallocBlock, *ContBlock;
2575+
2576+
InsertCFGDiamond(CondVal, Loc, B,
2577+
ReleaseBlock, DeallocBlock, ContBlock);
2578+
2579+
// If true, self was fully initialized and must be released.
2580+
B.setInsertionPoint(ReleaseBlock->begin());
2581+
B.setCurrentDebugScope(ReleaseBlock->begin()->getDebugScope());
2582+
Release->moveBefore(&*B.getInsertionPoint());
2583+
2584+
// If false, self is uninitialized and must be freed.
2585+
B.setInsertionPoint(DeallocBlock->begin());
2586+
B.setCurrentDebugScope(DeallocBlock->begin()->getDebugScope());
2587+
destroyMemoryElements(Loc, Availability);
2588+
processUninitializedRelease(Release, false, B.getInsertionPoint());
2589+
} else {
2590+
destroyMemoryElements(Loc, Availability);
2591+
processUninitializedRelease(Release, false, B.getInsertionPoint());
2592+
2593+
// The original strong_release or destroy_addr instruction is
2594+
// always dead at this point.
2595+
deleteDeadRelease(CDElt.ReleaseID);
2596+
}
25182597

2519-
// The original strong_release or destroy_addr instruction is
2520-
// always dead at this point.
2521-
deleteDeadRelease(CDElt.ReleaseID);
25222598
continue;
25232599
}
25242600

@@ -2564,11 +2640,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
25642640
// self.init or super.init may or may not have been called.
25652641
// We have not yet stored 'self' into the box.
25662642

2567-
auto CondVal = testControlVariable(Loc, SuperInitElt,
2568-
ControlVariableAddr,
2569-
ShiftRightFn,
2570-
TruncateFn,
2571-
B);
2643+
auto CondVal = testControlVariableBit(Loc, SuperInitElt,
2644+
ControlVariableAddr,
2645+
ShiftRightFn,
2646+
TruncateFn,
2647+
B);
25722648

25732649
SILBasicBlock *ConsumedBlock, *DeallocBlock, *ContBlock;
25742650

@@ -2598,11 +2674,11 @@ handleConditionalDestroys(SILValue ControlVariableAddr) {
25982674
// self.init or super.init may or may not have been called.
25992675
// We may or may have stored 'self' into the box.
26002676

2601-
auto CondVal = testControlVariable(Loc, SuperInitElt,
2602-
ControlVariableAddr,
2603-
ShiftRightFn,
2604-
TruncateFn,
2605-
B);
2677+
auto CondVal = testControlVariableBit(Loc, SuperInitElt,
2678+
ControlVariableAddr,
2679+
ShiftRightFn,
2680+
TruncateFn,
2681+
B);
26062682

26072683
SILBasicBlock *LiveBlock, *DeallocBlock, *ContBlock;
26082684

lib/SILOptimizer/Transforms/CSE.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,14 @@ static bool isLazyPropertyGetter(ApplyInst *ai) {
834834
!callee->isLazyPropertyGetter())
835835
return false;
836836

837+
// Only handle classes, but not structs.
838+
// Lazy property getters of structs have an indirect inout self parameter.
839+
// We don't know if the whole struct is overwritten between two getter calls.
840+
// In such a case, the lazy property could be reset to an Optional.none.
841+
// TODO: We could check this case with AliasAnalysis.
842+
if (ai->getArgument(0)->getType().isAddress())
843+
return false;
844+
837845
// Check if the first block has a switch_enum of an Optional.
838846
// We don't handle getters of generic types, which have a switch_enum_addr.
839847
// This will be obsolete with opaque values anyway.

lib/Sema/ConstraintSystem.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -4295,7 +4295,7 @@ SolutionApplicationTarget SolutionApplicationTarget::forInitialization(
42954295
bool bindPatternVarsOneWay) {
42964296
// Determine the contextual type for the initialization.
42974297
TypeLoc contextualType;
4298-
if (!isa<OptionalSomePattern>(pattern) &&
4298+
if (!(isa<OptionalSomePattern>(pattern) && !pattern->isImplicit()) &&
42994299
patternType && !patternType->isHole()) {
43004300
contextualType = TypeLoc::withoutLoc(patternType);
43014301

lib/Sema/ConstraintSystem.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -1455,7 +1455,8 @@ class SolutionApplicationTarget {
14551455
bool isOptionalSomePatternInit() const {
14561456
return kind == Kind::expression &&
14571457
expression.contextualPurpose == CTP_Initialization &&
1458-
isa<OptionalSomePattern>(expression.pattern);
1458+
isa<OptionalSomePattern>(expression.pattern) &&
1459+
!expression.pattern->isImplicit();
14591460
}
14601461

14611462
/// Whether to bind the types of any variables within the pattern via

lib/Sema/MiscDiagnostics.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -3791,10 +3791,9 @@ checkImplicitPromotionsInCondition(const StmtConditionElement &cond,
37913791
// checking for a type, which forced it to be promoted to a double optional
37923792
// type.
37933793
if (auto ooType = subExpr->getType()->getOptionalObjectType()) {
3794-
if (auto TP = dyn_cast<TypedPattern>(p))
3794+
if (auto OSP = dyn_cast<OptionalSomePattern>(p)) {
37953795
// Check for 'if let' to produce a tuned diagnostic.
3796-
if (isa<OptionalSomePattern>(TP->getSubPattern()) &&
3797-
TP->getSubPattern()->isImplicit()) {
3796+
if (auto *TP = dyn_cast<TypedPattern>(OSP->getSubPattern())) {
37983797
ctx.Diags.diagnose(cond.getIntroducerLoc(),
37993798
diag::optional_check_promotion,
38003799
subExpr->getType())
@@ -3803,6 +3802,7 @@ checkImplicitPromotionsInCondition(const StmtConditionElement &cond,
38033802
ooType->getString());
38043803
return;
38053804
}
3805+
}
38063806
ctx.Diags.diagnose(cond.getIntroducerLoc(),
38073807
diag::optional_pattern_match_promotion,
38083808
subExpr->getType(), cond.getInitializer()->getType())

0 commit comments

Comments
 (0)