Skip to content

Commit 8a85696

Browse files
authored
Merge pull request #2903 from swiftwasm/main
[pull] swiftwasm from main
2 parents 08be6b2 + 58f03e8 commit 8a85696

File tree

8 files changed

+275
-104
lines changed

8 files changed

+275
-104
lines changed

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 85 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,79 @@ static bool getPositionInArgs(DeclContext &DC, Expr *Args, Expr *CCExpr,
745745
return false;
746746
}
747747

748+
/// Get index of \p CCExpr in \p Params. Note that the position in \p Params may
749+
/// be different than the position in \p Args if there are defaulted arguments
750+
/// in \p Params which don't occur in \p Args.
751+
///
752+
/// \returns \c true if success, \c false if \p CCExpr is not a part of \p Args.
753+
static bool getPositionInParams(DeclContext &DC, Expr *Args, Expr *CCExpr,
754+
ArrayRef<AnyFunctionType::Param> Params,
755+
unsigned &PosInParams) {
756+
if (isa<ParenExpr>(Args)) {
757+
PosInParams = 0;
758+
return true;
759+
}
760+
761+
auto *tuple = dyn_cast<TupleExpr>(Args);
762+
if (!tuple) {
763+
return false;
764+
}
765+
766+
auto &SM = DC.getASTContext().SourceMgr;
767+
PosInParams = 0;
768+
unsigned PosInArgs = 0;
769+
bool LastParamWasVariadic = false;
770+
// We advance PosInArgs until we find argument that is after the code
771+
// completion token, which is when we stop.
772+
// For each argument, we try to find a matching parameter either by matching
773+
// argument labels, in which case PosInParams may be advanced by more than 1,
774+
// or by advancing PosInParams and PosInArgs both by 1.
775+
for (; PosInArgs < tuple->getNumElements(); ++PosInArgs) {
776+
if (!SM.isBeforeInBuffer(tuple->getElement(PosInArgs)->getEndLoc(),
777+
CCExpr->getStartLoc())) {
778+
// The arg is after the code completion position. Stop.
779+
break;
780+
}
781+
782+
auto ArgName = tuple->getElementName(PosInArgs);
783+
// If the last parameter we matched was variadic, we claim all following
784+
// unlabeled arguments for that variadic parameter -> advance PosInArgs but
785+
// not PosInParams.
786+
if (LastParamWasVariadic && ArgName.empty()) {
787+
continue;
788+
} else {
789+
LastParamWasVariadic = false;
790+
}
791+
792+
// Look for a matching parameter label.
793+
bool FoundLabelMatch = false;
794+
for (unsigned i = PosInParams; i < Params.size(); ++i) {
795+
if (Params[i].getLabel() == ArgName) {
796+
// We have found a label match. Advance the position in the params
797+
// to point to the param after the one with this label.
798+
PosInParams = i + 1;
799+
FoundLabelMatch = true;
800+
if (Params[i].isVariadic()) {
801+
LastParamWasVariadic = true;
802+
}
803+
break;
804+
}
805+
}
806+
807+
if (!FoundLabelMatch) {
808+
// We haven't found a matching argument label. Assume the current one is
809+
// named incorrectly and advance by one.
810+
++PosInParams;
811+
}
812+
}
813+
if (PosInArgs < tuple->getNumElements() && PosInParams < Params.size()) {
814+
// We didn't search until the end, so we found a position in Params. Success
815+
return true;
816+
} else {
817+
return false;
818+
}
819+
}
820+
748821
/// Given an expression and its context, the analyzer tries to figure out the
749822
/// expected type of the expression by analyzing its context.
750823
class ExprContextAnalyzer {
@@ -791,14 +864,12 @@ class ExprContextAnalyzer {
791864
PossibleCallees.assign(Candidates.begin(), Candidates.end());
792865

793866
// Determine the position of code completion token in call argument.
794-
unsigned Position;
867+
unsigned PositionInArgs;
795868
bool HasName;
796-
if (!getPositionInArgs(*DC, Arg, ParsedExpr, Position, HasName))
869+
if (!getPositionInArgs(*DC, Arg, ParsedExpr, PositionInArgs, HasName))
797870
return false;
798871

799872
// Collect possible types (or labels) at the position.
800-
// FIXME: Take variadic and optional parameters into account. We need to do
801-
// something equivalent to 'constraints::matchCallArguments'
802873
{
803874
bool MayNeedName = !HasName && !E->isImplicit() &&
804875
(isa<CallExpr>(E) | isa<SubscriptExpr>(E) ||
@@ -811,13 +882,22 @@ class ExprContextAnalyzer {
811882
memberDC = typeAndDecl.Decl->getInnermostDeclContext();
812883

813884
auto Params = typeAndDecl.Type->getParams();
885+
unsigned PositionInParams;
886+
if (!getPositionInParams(*DC, Arg, ParsedExpr, Params,
887+
PositionInParams)) {
888+
// If the argument doesn't have a matching position in the parameters,
889+
// indicate that with optional nullptr param.
890+
if (seenArgs.insert({Identifier(), CanType()}).second)
891+
recordPossibleParam(nullptr, /*isRequired=*/false);
892+
continue;
893+
}
814894
ParameterList *paramList = nullptr;
815895
if (auto VD = typeAndDecl.Decl) {
816896
paramList = getParameterList(VD);
817897
if (paramList && paramList->size() != Params.size())
818898
paramList = nullptr;
819899
}
820-
for (auto Pos = Position; Pos < Params.size(); ++Pos) {
900+
for (auto Pos = PositionInParams; Pos < Params.size(); ++Pos) {
821901
const auto &paramType = Params[Pos];
822902
Type ty = paramType.getPlainType();
823903
if (memberDC && ty->hasTypeParameter())
@@ -843,12 +923,6 @@ class ExprContextAnalyzer {
843923
if (!canSkip)
844924
break;
845925
}
846-
// If the argument position is out of expeceted number, indicate that
847-
// with optional nullptr param.
848-
if (Position >= Params.size()) {
849-
if (seenArgs.insert({Identifier(), CanType()}).second)
850-
recordPossibleParam(nullptr, /*isRequired=*/false);
851-
}
852926
}
853927
}
854928
return !PossibleTypes.empty() || !PossibleParams.empty();

lib/Sema/TypeCheckDecl.cpp

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2503,13 +2503,38 @@ NamingPatternRequest::evaluate(Evaluator &evaluator, VarDecl *VD) const {
25032503
}
25042504

25052505
if (!namingPattern) {
2506-
// Try type checking parent control statement.
25072506
if (auto parentStmt = VD->getParentPatternStmt()) {
2508-
if (auto CS = dyn_cast<CaseStmt>(parentStmt))
2509-
parentStmt = CS->getParentStmt();
2510-
ASTNode node(parentStmt);
2511-
TypeChecker::typeCheckASTNode(node, VD->getDeclContext(),
2512-
/*LeaveBodyUnchecked=*/true);
2507+
// Try type checking parent control statement.
2508+
if (auto condStmt = dyn_cast<LabeledConditionalStmt>(parentStmt)) {
2509+
// The VarDecl is defined inside a condition of a `if` or `while` stmt.
2510+
// Only type check the condition we care about: the one with the VarDecl
2511+
bool foundVarDecl = false;
2512+
for (auto &condElt : condStmt->getCond()) {
2513+
if (auto pat = condElt.getPatternOrNull()) {
2514+
if (!pat->containsVarDecl(VD)) {
2515+
continue;
2516+
}
2517+
// We found the condition that declares the variable. Type check it
2518+
// and stop the loop. The variable can only be declared once.
2519+
2520+
// We don't care about isFalsable
2521+
bool isFalsable = false;
2522+
TypeChecker::typeCheckStmtConditionElement(condElt, isFalsable,
2523+
VD->getDeclContext());
2524+
2525+
foundVarDecl = true;
2526+
break;
2527+
}
2528+
}
2529+
assert(foundVarDecl && "VarDecl not declared in its parent?");
2530+
} else {
2531+
// We have some other parent stmt. Type check it completely.
2532+
if (auto CS = dyn_cast<CaseStmt>(parentStmt))
2533+
parentStmt = CS->getParentStmt();
2534+
ASTNode node(parentStmt);
2535+
TypeChecker::typeCheckASTNode(node, VD->getDeclContext(),
2536+
/*LeaveBodyUnchecked=*/true);
2537+
}
25132538
namingPattern = VD->getCanonicalVarDecl()->NamingPattern;
25142539
}
25152540
}

lib/Sema/TypeCheckStmt.cpp

Lines changed: 85 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,89 @@ static LabeledStmt *findBreakOrContinueStmtTarget(
419419
return nullptr;
420420
}
421421

422+
bool TypeChecker::typeCheckStmtConditionElement(StmtConditionElement &elt,
423+
bool &isFalsable,
424+
DeclContext *dc) {
425+
auto &Context = dc->getASTContext();
426+
if (elt.getKind() == StmtConditionElement::CK_Availability) {
427+
isFalsable = true;
428+
429+
// Reject inlinable code using availability macros.
430+
PoundAvailableInfo *info = elt.getAvailability();
431+
if (auto *decl = dc->getAsDecl()) {
432+
if (decl->getAttrs().hasAttribute<InlinableAttr>() ||
433+
decl->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>())
434+
for (auto queries : info->getQueries())
435+
if (auto availSpec =
436+
dyn_cast<PlatformVersionConstraintAvailabilitySpec>(queries))
437+
if (availSpec->getMacroLoc().isValid()) {
438+
Context.Diags.diagnose(
439+
availSpec->getMacroLoc(),
440+
swift::diag::availability_macro_in_inlinable,
441+
decl->getDescriptiveKind());
442+
break;
443+
}
444+
}
445+
446+
return false;
447+
}
448+
449+
if (auto E = elt.getBooleanOrNull()) {
450+
assert(!E->getType() && "the bool condition is already type checked");
451+
bool hadError = TypeChecker::typeCheckCondition(E, dc);
452+
elt.setBoolean(E);
453+
isFalsable = true;
454+
return hadError;
455+
}
456+
assert(elt.getKind() != StmtConditionElement::CK_Boolean);
457+
458+
// This is cleanup goop run on the various paths where type checking of the
459+
// pattern binding fails.
460+
auto typeCheckPatternFailed = [&] {
461+
elt.getPattern()->setType(ErrorType::get(Context));
462+
elt.getInitializer()->setType(ErrorType::get(Context));
463+
464+
elt.getPattern()->forEachVariable([&](VarDecl *var) {
465+
// Don't change the type of a variable that we've been able to
466+
// compute a type for.
467+
if (var->hasInterfaceType() && !var->isInvalid())
468+
return;
469+
var->setInvalid();
470+
});
471+
};
472+
473+
// Resolve the pattern.
474+
assert(!elt.getPattern()->hasType() &&
475+
"the pattern binding condition is already type checked");
476+
auto *pattern = TypeChecker::resolvePattern(elt.getPattern(), dc,
477+
/*isStmtCondition*/ true);
478+
if (!pattern) {
479+
typeCheckPatternFailed();
480+
return true;
481+
}
482+
elt.setPattern(pattern);
483+
484+
TypeChecker::diagnoseDuplicateBoundVars(pattern);
485+
486+
// Check the pattern, it allows unspecified types because the pattern can
487+
// provide type information.
488+
auto contextualPattern = ContextualPattern::forRawPattern(pattern, dc);
489+
Type patternType = TypeChecker::typeCheckPattern(contextualPattern);
490+
if (patternType->hasError()) {
491+
typeCheckPatternFailed();
492+
return true;
493+
}
494+
495+
// If the pattern didn't get a type, it's because we ran into some
496+
// unknown types along the way. We'll need to check the initializer.
497+
auto init = elt.getInitializer();
498+
bool hadError = TypeChecker::typeCheckBinding(pattern, init, dc, patternType);
499+
elt.setPattern(pattern);
500+
elt.setInitializer(init);
501+
isFalsable |= pattern->isRefutablePattern();
502+
return hadError;
503+
}
504+
422505
/// Type check the given 'if', 'while', or 'guard' statement condition.
423506
///
424507
/// \param stmt The conditional statement to type-check, which will be modified
@@ -427,88 +510,12 @@ static LabeledStmt *findBreakOrContinueStmtTarget(
427510
/// \returns true if an error occurred, false otherwise.
428511
static bool typeCheckConditionForStatement(LabeledConditionalStmt *stmt,
429512
DeclContext *dc) {
430-
auto &Context = dc->getASTContext();
431513
bool hadError = false;
432514
bool hadAnyFalsable = false;
433515
auto cond = stmt->getCond();
434516
for (auto &elt : cond) {
435-
if (elt.getKind() == StmtConditionElement::CK_Availability) {
436-
hadAnyFalsable = true;
437-
438-
// Reject inlinable code using availability macros.
439-
PoundAvailableInfo *info = elt.getAvailability();
440-
if (auto *decl = dc->getAsDecl()) {
441-
if (decl->getAttrs().hasAttribute<InlinableAttr>() ||
442-
decl->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>())
443-
for (auto queries : info->getQueries())
444-
if (auto availSpec =
445-
dyn_cast<PlatformVersionConstraintAvailabilitySpec>(queries))
446-
if (availSpec->getMacroLoc().isValid()) {
447-
Context.Diags.diagnose(
448-
availSpec->getMacroLoc(),
449-
swift::diag::availability_macro_in_inlinable,
450-
decl->getDescriptiveKind());
451-
break;
452-
}
453-
}
454-
455-
continue;
456-
}
457-
458-
if (auto E = elt.getBooleanOrNull()) {
459-
assert(!E->getType() && "the bool condition is already type checked");
460-
hadError |= TypeChecker::typeCheckCondition(E, dc);
461-
elt.setBoolean(E);
462-
hadAnyFalsable = true;
463-
continue;
464-
}
465-
assert(elt.getKind() != StmtConditionElement::CK_Boolean);
466-
467-
// This is cleanup goop run on the various paths where type checking of the
468-
// pattern binding fails.
469-
auto typeCheckPatternFailed = [&] {
470-
hadError = true;
471-
elt.getPattern()->setType(ErrorType::get(Context));
472-
elt.getInitializer()->setType(ErrorType::get(Context));
473-
474-
elt.getPattern()->forEachVariable([&](VarDecl *var) {
475-
// Don't change the type of a variable that we've been able to
476-
// compute a type for.
477-
if (var->hasInterfaceType() && !var->isInvalid())
478-
return;
479-
var->setInvalid();
480-
});
481-
};
482-
483-
// Resolve the pattern.
484-
assert(!elt.getPattern()->hasType() &&
485-
"the pattern binding condition is already type checked");
486-
auto *pattern = TypeChecker::resolvePattern(elt.getPattern(), dc,
487-
/*isStmtCondition*/ true);
488-
if (!pattern) {
489-
typeCheckPatternFailed();
490-
continue;
491-
}
492-
elt.setPattern(pattern);
493-
494-
TypeChecker::diagnoseDuplicateBoundVars(pattern);
495-
496-
// Check the pattern, it allows unspecified types because the pattern can
497-
// provide type information.
498-
auto contextualPattern = ContextualPattern::forRawPattern(pattern, dc);
499-
Type patternType = TypeChecker::typeCheckPattern(contextualPattern);
500-
if (patternType->hasError()) {
501-
typeCheckPatternFailed();
502-
continue;
503-
}
504-
505-
// If the pattern didn't get a type, it's because we ran into some
506-
// unknown types along the way. We'll need to check the initializer.
507-
auto init = elt.getInitializer();
508-
hadError |= TypeChecker::typeCheckBinding(pattern, init, dc, patternType);
509-
elt.setPattern(pattern);
510-
elt.setInitializer(init);
511-
hadAnyFalsable |= pattern->isRefutablePattern();
517+
hadError |=
518+
TypeChecker::typeCheckStmtConditionElement(elt, hadAnyFalsable, dc);
512519
}
513520

514521
// If the binding is not refutable, and there *is* an else, reject it as

lib/Sema/TypeChecker.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,13 @@ bool typesSatisfyConstraint(Type t1, Type t2, bool openArchetypes,
423423
/// of the function, set the result type of the expression to that sugar type.
424424
Expr *substituteInputSugarTypeForResult(ApplyExpr *E);
425425

426+
/// Type check a \c StmtConditionElement.
427+
/// Sets \p isFalsable to \c true if the condition might evaluate to \c false,
428+
/// otherwise leaves \p isFalsable untouched.
429+
/// \returns \c true if there was an error type checking, \c false otherwise.
430+
bool typeCheckStmtConditionElement(StmtConditionElement &elt, bool &isFalsable,
431+
DeclContext *dc);
432+
426433
void typeCheckASTNode(ASTNode &node, DeclContext *DC,
427434
bool LeaveBodyUnchecked = false);
428435

test/Concurrency/Runtime/cancellation_handler.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %target-run-simple-swift(-Xfrontend -enable-experimental-concurrency %import-libdispatch)
2+
// REQUIRES: concurrency
23

34
class Canary {
45
deinit {

0 commit comments

Comments
 (0)