diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 0b5f16945308a..c686c8be53a9f 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -1559,7 +1559,7 @@ class SolutionApplicationTarget { stmtCondition, caseLabelItem, patternBinding, - uninitializedWrappedVar, + uninitializedVar, } kind; private: @@ -1631,9 +1631,15 @@ class SolutionApplicationTarget { DeclContext *dc; } caseLabelItem; - PatternBindingDecl *patternBinding; + struct { + /// Index into pattern binding declaration (if any). + unsigned index; + PointerUnion declaration; + /// Type associated with the declaration. + Type type; + } uninitializedVar; - VarDecl *uninitializedWrappedVar; + PatternBindingDecl *patternBinding; }; // If the pattern contains a single variable that has an attached @@ -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. @@ -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( @@ -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"); @@ -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()) + return wrappedVar->getDeclContext(); + + return patternBinding->getInitContext(uninitializedVar.index); + } } llvm_unreachable("invalid decl context type"); } @@ -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(); + assert(kind == Kind::expression); assert(expression.contextualPurpose == CTP_Initialization); return expression.pattern; @@ -1903,6 +1945,12 @@ class SolutionApplicationTarget { } void setPattern(Pattern *pattern) { + if (kind == Kind::uninitializedVar) { + assert(uninitializedVar.declaration.is()); + uninitializedVar.declaration = pattern; + return; + } + assert(kind == Kind::expression); assert(expression.contextualPurpose == CTP_Initialization || expression.contextualPurpose == CTP_ForEachStmt); @@ -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: @@ -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: @@ -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: @@ -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: @@ -1978,8 +2026,68 @@ class SolutionApplicationTarget { case Kind::patternBinding: return nullptr; - case Kind::uninitializedWrappedVar: - return uninitializedWrappedVar; + case Kind::uninitializedVar: + return uninitializedVar.declaration.dyn_cast(); + } + 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(); + } + 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"); } @@ -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()) { + return wrappedVar->getSourceRange(); + } + return uninitializedVar.declaration.get()->getSourceRange(); + } } llvm_unreachable("invalid target type"); } @@ -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()) { + return wrappedVar->getLoc(); + } + return uninitializedVar.declaration.get()->getLoc(); + } } llvm_unreachable("invalid target type"); } diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 45ed189b7e505..e2dca80da774c 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -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; @@ -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)) @@ -9086,7 +9104,7 @@ SolutionApplicationTarget SolutionApplicationTarget::walk(ASTWalker &walker) { case Kind::patternBinding: return *this; - case Kind::uninitializedWrappedVar: + case Kind::uninitializedVar: return *this; } diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 3dd3546ba9c05..b0e779065e576 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -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; @@ -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; + } } } } diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index e63242fcd9531..db5437fd9403d 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -5419,11 +5419,6 @@ SolutionApplicationTarget SolutionApplicationTarget::forForEachStmt( return target; } -SolutionApplicationTarget -SolutionApplicationTarget::forUninitializedWrappedVar(VarDecl *wrappedVar) { - return SolutionApplicationTarget(wrappedVar); -} - SolutionApplicationTarget SolutionApplicationTarget::forPropertyWrapperInitializer( VarDecl *wrappedVar, DeclContext *dc, Expr *initializer) { @@ -5443,6 +5438,12 @@ SolutionApplicationTarget::forPropertyWrapperInitializer( ContextualPattern SolutionApplicationTarget::getContextualPattern() const { + if (kind == Kind::uninitializedVar) { + assert(patternBinding); + return ContextualPattern::forPatternBindingDecl(patternBinding, + uninitializedVar.index); + } + assert(kind == Kind::expression); assert(expression.contextualPurpose == CTP_Initialization || expression.contextualPurpose == CTP_ForEachStmt); @@ -5558,6 +5559,8 @@ void ConstraintSystem::diagnoseFailureFor(SolutionApplicationTarget target) { nominal->diagnose(diag::property_wrapper_declared_here, nominal->getName()); } + } else if (auto *var = target.getAsUninitializedVar()) { + DE.diagnose(target.getLoc(), diag::failed_to_produce_diagnostic); } else { // Emit a poor fallback message. DE.diagnose(target.getAsFunction()->getLoc(), diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index a9a82c7b5407d..241311b8c1ce3 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -295,7 +295,7 @@ void constraints::performSyntacticDiagnosticsForTarget( case SolutionApplicationTarget::Kind::stmtCondition: case SolutionApplicationTarget::Kind::caseLabelItem: case SolutionApplicationTarget::Kind::patternBinding: - case SolutionApplicationTarget::Kind::uninitializedWrappedVar: + case SolutionApplicationTarget::Kind::uninitializedVar: // Nothing to do for these. return; }