Skip to content

[ConstraintSystem] Generalize uninitialized wrapped variable targets #38912

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

Merged
merged 4 commits into from
Aug 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
160 changes: 139 additions & 21 deletions include/swift/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -1559,7 +1559,7 @@ class SolutionApplicationTarget {
stmtCondition,
caseLabelItem,
patternBinding,
uninitializedWrappedVar,
uninitializedVar,
} kind;

private:
Expand Down Expand Up @@ -1631,9 +1631,15 @@ class SolutionApplicationTarget {
DeclContext *dc;
} caseLabelItem;

PatternBindingDecl *patternBinding;
struct {
/// Index into pattern binding declaration (if any).
unsigned index;
PointerUnion<VarDecl *, Pattern *> declaration;
/// Type associated with the declaration.
Type type;
} uninitializedVar;

VarDecl *uninitializedWrappedVar;
PatternBindingDecl *patternBinding;
};

// If the pattern contains a single variable that has an attached
Expand Down Expand Up @@ -1679,9 +1685,29 @@ class SolutionApplicationTarget {
this->patternBinding = patternBinding;
}

SolutionApplicationTarget(VarDecl *wrappedVar) {
kind = Kind::uninitializedWrappedVar;
this->uninitializedWrappedVar= wrappedVar;
SolutionApplicationTarget(VarDecl *uninitializedWrappedVar)
: kind(Kind::uninitializedVar) {
if (auto *PDB = uninitializedWrappedVar->getParentPatternBinding()) {
patternBinding = PDB;
uninitializedVar.index =
PDB->getPatternEntryIndexForVarDecl(uninitializedWrappedVar);
} else {
uninitializedVar.index = 0;
}

uninitializedVar.declaration = uninitializedWrappedVar;
uninitializedVar.type = Type();
}

SolutionApplicationTarget(PatternBindingDecl *binding, unsigned index,
Pattern *var, Type patternTy)
: kind(Kind::uninitializedVar) {
assert(patternBinding);

patternBinding = binding;
uninitializedVar.index = index;
uninitializedVar.declaration = var;
uninitializedVar.type = patternTy;
}

/// Form a target for the initialization of a pattern from an expression.
Expand All @@ -1703,8 +1729,16 @@ class SolutionApplicationTarget {

/// Form a target for a property with an attached property wrapper that is
/// initialized out-of-line.
static SolutionApplicationTarget forUninitializedWrappedVar(
VarDecl *wrappedVar);
static SolutionApplicationTarget
forUninitializedWrappedVar(VarDecl *wrappedVar) {
return {wrappedVar};
}

static SolutionApplicationTarget
forUninitializedVar(PatternBindingDecl *binding, unsigned index, Pattern *var,
Type patternTy) {
return {binding, index, var, patternTy};
}

/// Form a target for a synthesized property wrapper initializer.
static SolutionApplicationTarget forPropertyWrapperInitializer(
Expand All @@ -1719,7 +1753,7 @@ class SolutionApplicationTarget {
case Kind::stmtCondition:
case Kind::caseLabelItem:
case Kind::patternBinding:
case Kind::uninitializedWrappedVar:
case Kind::uninitializedVar:
return nullptr;
}
llvm_unreachable("invalid expression type");
Expand All @@ -1742,8 +1776,13 @@ class SolutionApplicationTarget {
case Kind::patternBinding:
return patternBinding->getDeclContext();

case Kind::uninitializedWrappedVar:
return uninitializedWrappedVar->getDeclContext();
case Kind::uninitializedVar: {
if (auto *wrappedVar =
uninitializedVar.declaration.dyn_cast<VarDecl *>())
return wrappedVar->getDeclContext();

return patternBinding->getInitContext(uninitializedVar.index);
}
}
llvm_unreachable("invalid decl context type");
}
Expand Down Expand Up @@ -1799,6 +1838,9 @@ class SolutionApplicationTarget {

/// For a pattern initialization target, retrieve the pattern.
Pattern *getInitializationPattern() const {
if (kind == Kind::uninitializedVar)
return uninitializedVar.declaration.get<Pattern *>();

assert(kind == Kind::expression);
assert(expression.contextualPurpose == CTP_Initialization);
return expression.pattern;
Expand Down Expand Up @@ -1903,6 +1945,12 @@ class SolutionApplicationTarget {
}

void setPattern(Pattern *pattern) {
if (kind == Kind::uninitializedVar) {
assert(uninitializedVar.declaration.is<Pattern *>());
uninitializedVar.declaration = pattern;
return;
}

assert(kind == Kind::expression);
assert(expression.contextualPurpose == CTP_Initialization ||
expression.contextualPurpose == CTP_ForEachStmt);
Expand All @@ -1915,7 +1963,7 @@ class SolutionApplicationTarget {
case Kind::stmtCondition:
case Kind::caseLabelItem:
case Kind::patternBinding:
case Kind::uninitializedWrappedVar:
case Kind::uninitializedVar:
return None;

case Kind::function:
Expand All @@ -1930,7 +1978,7 @@ class SolutionApplicationTarget {
case Kind::function:
case Kind::caseLabelItem:
case Kind::patternBinding:
case Kind::uninitializedWrappedVar:
case Kind::uninitializedVar:
return None;

case Kind::stmtCondition:
Expand All @@ -1945,7 +1993,7 @@ class SolutionApplicationTarget {
case Kind::function:
case Kind::stmtCondition:
case Kind::patternBinding:
case Kind::uninitializedWrappedVar:
case Kind::uninitializedVar:
return None;

case Kind::caseLabelItem:
Expand All @@ -1960,7 +2008,7 @@ class SolutionApplicationTarget {
case Kind::function:
case Kind::stmtCondition:
case Kind::caseLabelItem:
case Kind::uninitializedWrappedVar:
case Kind::uninitializedVar:
return nullptr;

case Kind::patternBinding:
Expand All @@ -1978,8 +2026,68 @@ class SolutionApplicationTarget {
case Kind::patternBinding:
return nullptr;

case Kind::uninitializedWrappedVar:
return uninitializedWrappedVar;
case Kind::uninitializedVar:
return uninitializedVar.declaration.dyn_cast<VarDecl *>();
}
llvm_unreachable("invalid case label type");
}

Pattern *getAsUninitializedVar() const {
switch (kind) {
case Kind::expression:
case Kind::function:
case Kind::stmtCondition:
case Kind::caseLabelItem:
case Kind::patternBinding:
return nullptr;

case Kind::uninitializedVar:
return uninitializedVar.declaration.dyn_cast<Pattern *>();
}
llvm_unreachable("invalid case label type");
}

Type getTypeOfUninitializedVar() const {
switch (kind) {
case Kind::expression:
case Kind::function:
case Kind::stmtCondition:
case Kind::caseLabelItem:
case Kind::patternBinding:
return nullptr;

case Kind::uninitializedVar:
return uninitializedVar.type;
}
llvm_unreachable("invalid case label type");
}

PatternBindingDecl *getPatternBindingOfUninitializedVar() const {
switch (kind) {
case Kind::expression:
case Kind::function:
case Kind::stmtCondition:
case Kind::caseLabelItem:
case Kind::patternBinding:
return nullptr;

case Kind::uninitializedVar:
return patternBinding;
}
llvm_unreachable("invalid case label type");
}

unsigned getIndexOfUninitializedVar() const {
switch (kind) {
case Kind::expression:
case Kind::function:
case Kind::stmtCondition:
case Kind::caseLabelItem:
case Kind::patternBinding:
return 0;

case Kind::uninitializedVar:
return uninitializedVar.index;
}
llvm_unreachable("invalid case label type");
}
Expand Down Expand Up @@ -2013,8 +2121,13 @@ class SolutionApplicationTarget {
case Kind::patternBinding:
return patternBinding->getSourceRange();

case Kind::uninitializedWrappedVar:
return uninitializedWrappedVar->getSourceRange();
case Kind::uninitializedVar: {
if (auto *wrappedVar =
uninitializedVar.declaration.dyn_cast<VarDecl *>()) {
return wrappedVar->getSourceRange();
}
return uninitializedVar.declaration.get<Pattern *>()->getSourceRange();
}
}
llvm_unreachable("invalid target type");
}
Expand All @@ -2037,8 +2150,13 @@ class SolutionApplicationTarget {
case Kind::patternBinding:
return patternBinding->getLoc();

case Kind::uninitializedWrappedVar:
return uninitializedWrappedVar->getLoc();
case Kind::uninitializedVar: {
if (auto *wrappedVar =
uninitializedVar.declaration.dyn_cast<VarDecl *>()) {
return wrappedVar->getLoc();
}
return uninitializedVar.declaration.get<Pattern *>()->getLoc();
}
}
llvm_unreachable("invalid target type");
}
Expand Down
22 changes: 20 additions & 2 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8795,7 +8795,10 @@ ExprWalker::rewriteTarget(SolutionApplicationTarget target) {
patternBinding->setPattern(
index, resultTarget->getInitializationPattern(),
resultTarget->getDeclContext());
patternBinding->setInit(index, resultTarget->getAsExpr());

if (patternBinding->getInit(index)) {
patternBinding->setInit(index, resultTarget->getAsExpr());
}
}

return target;
Expand All @@ -8810,6 +8813,21 @@ ExprWalker::rewriteTarget(SolutionApplicationTarget target) {
wrappedVar, backingType->mapTypeOutOfContext());

return target;
} else if (auto *pattern = target.getAsUninitializedVar()) {
auto contextualPattern = target.getContextualPattern();
auto patternType = target.getTypeOfUninitializedVar();

TypeResolutionOptions options = TypeResolverContext::PatternBindingDecl;
options |= TypeResolutionFlags::OverrideType;

if (auto coercedPattern = TypeChecker::coercePatternToType(
contextualPattern, patternType, options)) {
auto resultTarget = target;
resultTarget.setPattern(coercedPattern);
return resultTarget;
}

return None;
} else {
auto fn = *target.getAsFunction();
if (rewriteFunction(fn))
Expand Down Expand Up @@ -9086,7 +9104,7 @@ SolutionApplicationTarget SolutionApplicationTarget::walk(ASTWalker &walker) {
case Kind::patternBinding:
return *this;

case Kind::uninitializedWrappedVar:
case Kind::uninitializedVar:
return *this;
}

Expand Down
44 changes: 31 additions & 13 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3934,15 +3934,19 @@ bool ConstraintSystem::generateConstraints(
if (!patternType || patternType->hasError())
return true;

auto init = patternBinding->getInit(index);
if (!init) {
llvm_unreachable("Unsupported pattern binding entry");
if (!patternBinding->isInitialized(index) &&
patternBinding->isDefaultInitializable(index) &&
pattern->hasStorage()) {
llvm_unreachable("default initialization is unsupported");
}

// Generate constraints for the initialization.
auto target = SolutionApplicationTarget::forInitialization(
init, dc, patternType, pattern,
/*bindPatternVarsOneWay=*/true);
auto init = patternBinding->getInit(index);
auto target = init ? SolutionApplicationTarget::forInitialization(
init, dc, patternType, pattern,
/*bindPatternVarsOneWay=*/true)
: SolutionApplicationTarget::forUninitializedVar(
patternBinding, index, pattern, patternType);

if (generateConstraints(target, FreeTypeVariableBinding::Disallow)) {
hadError = true;
continue;
Expand All @@ -3955,14 +3959,28 @@ bool ConstraintSystem::generateConstraints(
return hadError;
}

case SolutionApplicationTarget::Kind::uninitializedWrappedVar: {
auto *wrappedVar = target.getAsUninitializedWrappedVar();
auto propertyType = getVarType(wrappedVar);
if (propertyType->hasError())
return true;
case SolutionApplicationTarget::Kind::uninitializedVar: {
if (auto *wrappedVar = target.getAsUninitializedWrappedVar()) {
auto propertyType = getVarType(wrappedVar);
if (propertyType->hasError())
return true;

return generateWrappedPropertyTypeConstraints(
return generateWrappedPropertyTypeConstraints(
*this, /*initializerType=*/Type(), wrappedVar, propertyType);
} else {
auto pattern = target.getAsUninitializedVar();
auto locator = getConstraintLocator(
pattern, LocatorPathElt::ContextualType(CTP_Initialization));

// Generate constraints to bind all of the internal declarations
// and verify the pattern.
Type patternType = generateConstraints(
pattern, locator, /*shouldBindPatternVarsOneWay*/ true,
target.getPatternBindingOfUninitializedVar(),
target.getIndexOfUninitializedVar());

return !patternType;
}
}
}
}
Expand Down
Loading