From 782a5b433221013635854c452a23db6254581134 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Sun, 14 Sep 2025 11:33:29 +0100 Subject: [PATCH 1/5] [CS] Ensure we trap in `getOverloadChoice` if the overload is missing Using `*` previously meant we'd invoke undefined behavior. --- include/swift/Sema/ConstraintSystem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 4ddd6ce498f69..786fb1e33c9d4 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -1764,7 +1764,7 @@ class Solution { /// Retrieve the overload choice associated with the given /// locator. SelectedOverload getOverloadChoice(ConstraintLocator *locator) const { - return *getOverloadChoiceIfAvailable(locator); + return getOverloadChoiceIfAvailable(locator).value(); } /// Retrieve the overload choice for the callee associated with the given From cdf0bfbaf78234ab9c63db182dbc1810a46ca073 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Sun, 14 Sep 2025 11:33:29 +0100 Subject: [PATCH 2/5] [CS] Remove a couple uses of `recordAnyTypeVarAsPotentialHole` It's not actually clear these are necessary anymore, and in one case it actually makes a diagnostic worse. --- lib/Sema/CSSimplify.cpp | 11 ----------- .../type_checker_crashers_fixed/issue-65360.swift | 4 ++-- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index ad8c12c221404..0c6ffb49003e8 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -6683,12 +6683,6 @@ bool ConstraintSystem::repairFailures( if (rhs->isExistentialType()) break; - // If the types didn't line up, let's allow right-hand side - // of the conversion (or pattern match) to have holes. This - // helps when conversion if between a type and a tuple e.g. - // `Int` vs. `(_, _)`. - recordAnyTypeVarAsPotentialHole(rhs); - conversionsOrFixes.push_back(CollectionElementContextualMismatch::create( *this, lhs, rhs, getConstraintLocator(locator))); break; @@ -6782,9 +6776,6 @@ bool ConstraintSystem::repairFailures( case ConstraintLocator::TernaryBranch: case ConstraintLocator::SingleValueStmtResult: { - recordAnyTypeVarAsPotentialHole(lhs); - recordAnyTypeVarAsPotentialHole(rhs); - if (lhs->hasPlaceholder() || rhs->hasPlaceholder()) return true; @@ -6852,8 +6843,6 @@ bool ConstraintSystem::repairFailures( return true; if (isMemberMatch) { - recordAnyTypeVarAsPotentialHole(lhs); - recordAnyTypeVarAsPotentialHole(rhs); conversionsOrFixes.push_back(AllowAssociatedValueMismatch::create( *this, lhs, rhs, getConstraintLocator(locator))); break; diff --git a/validation-test/Sema/type_checker_crashers_fixed/issue-65360.swift b/validation-test/Sema/type_checker_crashers_fixed/issue-65360.swift index fd6652a85f4e4..df4c4ead1c2bc 100644 --- a/validation-test/Sema/type_checker_crashers_fixed/issue-65360.swift +++ b/validation-test/Sema/type_checker_crashers_fixed/issue-65360.swift @@ -9,13 +9,13 @@ let _: () -> Void = { let _: () -> Void = { for case (0)? in [a] {} - // expected-error@-1 {{pattern cannot match values of type 'Any?'}} + // expected-error@-1 {{cannot convert sequence element type 'Any?' to expected type 'Int?'}} if case (0, 0) = a {} } let _: () -> Void = { for case (0)? in [a] {} - // expected-error@-1 {{pattern cannot match values of type 'Any?'}} + // expected-error@-1 {{cannot convert sequence element type 'Any?' to expected type 'Int?'}} for case (0, 0) in [a] {} } From a7c046087707dde0391ce29a0b70d42732eff5f1 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Sun, 14 Sep 2025 11:33:29 +0100 Subject: [PATCH 3/5] [CS] Record `IgnoreInvalidASTNode` for invalid key path component And ensure we don't end up with invalid key paths in CSApply. --- lib/Sema/CSApply.cpp | 13 ++++++------- lib/Sema/CSGen.cpp | 1 + 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 5c20caac80278..df3343a44d9cc 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -5395,19 +5395,18 @@ namespace { } break; } - case KeyPathExpr::Component::Kind::Invalid: - case KeyPathExpr::Component::Kind::CodeCompletion: { - auto component = origComponent; - component.setComponentType(leafTy); - resolvedComponents.push_back(component); - break; - } case KeyPathExpr::Component::Kind::Identity: { auto component = origComponent; component.setComponentType(componentTy); resolvedComponents.push_back(component); break; } + case KeyPathExpr::Component::Kind::CodeCompletion: + llvm_unreachable("solver-based completion shouldn't do CSApply"); + break; + case KeyPathExpr::Component::Kind::Invalid: + llvm_unreachable("should have been diagnosed"); + break; case KeyPathExpr::Component::Kind::Member: case KeyPathExpr::Component::Kind::Subscript: case KeyPathExpr::Component::Kind::Apply: diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 0d1b17a189db8..8e16f3b25f437 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -3845,6 +3845,7 @@ namespace { switch (auto kind = component.getKind()) { case KeyPathExpr::Component::Kind::Invalid: + CS.recordFix(IgnoreInvalidASTNode::create(CS, memberLocator)); break; case KeyPathExpr::Component::Kind::CodeCompletion: // We don't know what the code completion might resolve to, so we are From 90bfc1676d16e7706664342593380ed9be90dbfc Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sun, 14 Sep 2025 11:33:29 +0100 Subject: [PATCH 4/5] Sema: Remove some unreachable code from CSApply I believe these code paths could only be reached by re-typechecking invalid code in the old CSDiag implementation. --- include/swift/AST/DiagnosticsSema.def | 7 -- include/swift/AST/Expr.h | 15 ---- include/swift/AST/ExprNodes.def | 1 - lib/AST/ASTDumper.cpp | 6 -- lib/AST/ASTPrinter.cpp | 3 - lib/AST/Expr.cpp | 3 - lib/SILGen/SILGenExpr.cpp | 8 -- lib/Sema/CSApply.cpp | 114 ++++++-------------------- 8 files changed, 25 insertions(+), 132 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 19d39a86bec97..2ae48f34ece4e 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -254,13 +254,6 @@ ERROR(cannot_apply_lvalue_binop_to_subelement,none, ERROR(cannot_apply_lvalue_binop_to_rvalue,none, "left side of mutating operator has immutable type %0", (Type)) -ERROR(cannot_subscript_base,none, - "cannot subscript a value of type %0", - (Type)) - -ERROR(cannot_subscript_ambiguous_base,none, - "cannot subscript a value of incorrect or ambiguous type", ()) - ERROR(cannot_subscript_nil_literal,none, "cannot subscript a nil literal value", ()) ERROR(conditional_cast_from_nil,none, diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 74f58a18c406a..ae80a3f70a27b 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -3348,24 +3348,9 @@ class ABISafeConversionExpr : public ImplicitConversionExpr { } }; -/// This is a conversion from an expression of UnresolvedType to an arbitrary -/// other type, and from an arbitrary type to UnresolvedType. This node does -/// not appear in valid code, only in code involving diagnostics. -class UnresolvedTypeConversionExpr : public ImplicitConversionExpr { -public: - UnresolvedTypeConversionExpr(Expr *subExpr, Type type) - : ImplicitConversionExpr(ExprKind::UnresolvedTypeConversion, subExpr, type) {} - - static bool classof(const Expr *E) { - return E->getKind() == ExprKind::UnresolvedTypeConversion; - } -}; - /// FunctionConversionExpr - Convert a function to another function type, /// which might involve renaming the parameters or handling substitutions /// of subtypes (in the return) or supertypes (in the input). -/// -/// FIXME: This should be a CapturingExpr. class FunctionConversionExpr : public ImplicitConversionExpr { public: FunctionConversionExpr(Expr *subExpr, Type type) diff --git a/include/swift/AST/ExprNodes.def b/include/swift/AST/ExprNodes.def index 6a2e250d865fb..a193b8d699ec0 100644 --- a/include/swift/AST/ExprNodes.def +++ b/include/swift/AST/ExprNodes.def @@ -161,7 +161,6 @@ ABSTRACT_EXPR(ImplicitConversion, Expr) EXPR(Load, ImplicitConversionExpr) EXPR(ABISafeConversion, ImplicitConversionExpr) EXPR(DestructureTuple, ImplicitConversionExpr) - EXPR(UnresolvedTypeConversion, ImplicitConversionExpr) EXPR(FunctionConversion, ImplicitConversionExpr) EXPR(CovariantFunctionConversion, ImplicitConversionExpr) EXPR(CovariantReturnConversion, ImplicitConversionExpr) diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 0ed2c08a21fe5..f53e1f7a096c4 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -3817,12 +3817,6 @@ class PrintExpr : public ExprVisitor, printFoot(); } - void visitUnresolvedTypeConversionExpr(UnresolvedTypeConversionExpr *E, - Label label) { - printCommon(E, "unresolvedtype_conversion_expr", label); - printRec(E->getSubExpr(), Label::optional("sub_expr")); - printFoot(); - } void visitFunctionConversionExpr(FunctionConversionExpr *E, Label label) { printCommon(E, "function_conversion_expr", label); printRec(E->getSubExpr(), Label::optional("sub_expr")); diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 8863947e78b8e..e11bb76a5607b 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -5558,9 +5558,6 @@ void PrintAST::visitMakeTemporarilyEscapableExpr(MakeTemporarilyEscapableExpr *e void PrintAST::visitProtocolMetatypeToObjectExpr(ProtocolMetatypeToObjectExpr *expr) { } -void PrintAST::visitUnresolvedTypeConversionExpr(UnresolvedTypeConversionExpr *expr) { -} - void PrintAST::visitConditionalBridgeFromObjCExpr(ConditionalBridgeFromObjCExpr *expr) { } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 85136687ead44..a8f3f57f8eefc 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -414,7 +414,6 @@ ConcreteDeclRef Expr::getReferencedDecl(bool stopAtParenExpr) const { PASS_THROUGH_REFERENCE(Load, getSubExpr); NO_REFERENCE(DestructureTuple); - NO_REFERENCE(UnresolvedTypeConversion); PASS_THROUGH_REFERENCE(ABISafeConversion, getSubExpr); PASS_THROUGH_REFERENCE(FunctionConversion, getSubExpr); PASS_THROUGH_REFERENCE(CovariantFunctionConversion, getSubExpr); @@ -783,7 +782,6 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const { case ExprKind::Load: case ExprKind::ABISafeConversion: case ExprKind::DestructureTuple: - case ExprKind::UnresolvedTypeConversion: case ExprKind::FunctionConversion: case ExprKind::CovariantFunctionConversion: case ExprKind::CovariantReturnConversion: @@ -993,7 +991,6 @@ bool Expr::isValidParentOfTypeExpr(Expr *typeExpr) const { case ExprKind::Binary: case ExprKind::Load: case ExprKind::DestructureTuple: - case ExprKind::UnresolvedTypeConversion: case ExprKind::ABISafeConversion: case ExprKind::FunctionConversion: case ExprKind::CovariantFunctionConversion: diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 0dd1b60351946..2886aebce6cab 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -481,8 +481,6 @@ namespace { RValue visitConditionalBridgeFromObjCExpr(ConditionalBridgeFromObjCExpr *E, SGFContext C); RValue visitArchetypeToSuperExpr(ArchetypeToSuperExpr *E, SGFContext C); - RValue visitUnresolvedTypeConversionExpr(UnresolvedTypeConversionExpr *E, - SGFContext C); RValue visitABISafeConversionExpr(ABISafeConversionExpr *E, SGFContext C) { llvm_unreachable("cannot appear in rvalue"); } @@ -1035,12 +1033,6 @@ RValue RValueEmitter::visitSuperRefExpr(SuperRefExpr *E, SGFContext C) { return RValue(SGF, E, result); } -RValue RValueEmitter:: -visitUnresolvedTypeConversionExpr(UnresolvedTypeConversionExpr *E, - SGFContext C) { - llvm_unreachable("invalid code made its way into SILGen"); -} - RValue RValueEmitter::visitOtherConstructorDeclRefExpr( OtherConstructorDeclRefExpr *E, SGFContext C) { // This should always be a child of an ApplyExpr and so will be emitted by diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index df3343a44d9cc..e5fbbaeeaf0a1 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -3268,8 +3268,7 @@ namespace { auto type = simplifyType(openedType); cs.setType(expr, type); - if (type->is()) - return expr; + assert(!type->is()); Type conformingType = type; if (auto baseType = conformingType->getOptionalObjectType()) { @@ -3288,14 +3287,11 @@ namespace { ConcreteDeclRef witness = conformance.getWitnessByName(constrName); - auto selectedOverload = solution.getOverloadChoiceIfAvailable( + auto selectedOverload = solution.getOverloadChoice( cs.getConstraintLocator(expr, ConstraintLocator::ConstructorMember)); - if (!selectedOverload) - return nullptr; - - auto fnType = - simplifyType(selectedOverload->adjustedOpenedType)->castTo(); + auto fnType = simplifyType(selectedOverload.adjustedOpenedType) + ->castTo(); auto newArgs = coerceCallArguments( expr->getArgs(), fnType, witness, /*applyExpr=*/nullptr, @@ -3628,18 +3624,8 @@ namespace { // Determine the declaration selected for this overloaded reference. auto memberLocator = cs.getConstraintLocator(expr, ConstraintLocator::Member); - auto selectedElt = solution.getOverloadChoiceIfAvailable(memberLocator); - - if (!selectedElt) { - // If constraint solving resolved this to an UnresolvedType, then we're - // in an ambiguity tolerant mode used for diagnostic generation. Just - // leave this as whatever type of member reference it already is. - Type resultTy = simplifyType(cs.getType(expr)); - cs.setType(expr, resultTy); - return expr; - } + auto selected = solution.getOverloadChoice(memberLocator); - auto selected = *selectedElt; if (!selected.choice.getBaseType()) { // This is one of the "outer alternatives", meaning the innermost // methods didn't work out. @@ -3958,39 +3944,17 @@ namespace { Expr *visitSubscriptExpr(SubscriptExpr *expr) { auto *memberLocator = cs.getConstraintLocator(expr, ConstraintLocator::SubscriptMember); - auto overload = solution.getOverloadChoiceIfAvailable(memberLocator); - - // Handles situation where there was a solution available but it didn't - // have a proper overload selected from subscript call, might be because - // solver was allowed to return free or unresolved types, which can - // happen while running diagnostics on one of the expressions. - if (!overload) { - auto *base = expr->getBase(); - auto &de = ctx.Diags; - auto baseType = cs.getType(base); - - if (auto errorType = baseType->getAs()) { - de.diagnose(base->getLoc(), diag::cannot_subscript_base, - errorType->getOriginalType()) - .highlight(base->getSourceRange()); - } else { - de.diagnose(base->getLoc(), diag::cannot_subscript_ambiguous_base) - .highlight(base->getSourceRange()); - } - - return nullptr; - } - - if (overload->choice.isKeyPathDynamicMemberLookup()) { + auto overload = solution.getOverloadChoice(memberLocator); + if (overload.choice.isKeyPathDynamicMemberLookup()) { return buildDynamicMemberLookupRef( expr, expr->getBase(), expr->getArgs()->getStartLoc(), SourceLoc(), - *overload, memberLocator); + overload, memberLocator); } return buildSubscript(expr->getBase(), expr->getArgs(), cs.getConstraintLocator(expr), memberLocator, expr->isImplicit(), expr->getAccessSemantics(), - *overload); + overload); } /// "Finish" an array expression by filling in the semantic expression. @@ -5321,15 +5285,8 @@ namespace { // If this is an unresolved link, make sure we resolved it. if (kind == KeyPathExpr::Component::Kind::UnresolvedMember || kind == KeyPathExpr::Component::Kind::UnresolvedSubscript) { - auto foundDecl = solution.getOverloadChoiceIfAvailable(calleeLoc); - if (!foundDecl) { - // If we couldn't resolve the component, leave it alone. - resolvedComponents.push_back(origComponent); - componentTy = origComponent.getComponentType(); - continue; - } - - isDynamicMember = foundDecl->choice.isAnyDynamicMemberLookup(); + auto foundDecl = solution.getOverloadChoice(calleeLoc); + isDynamicMember = foundDecl.choice.isAnyDynamicMemberLookup(); // If this was a @dynamicMemberLookup property, then we actually // form a subscript reference, so switch the kind. @@ -5368,11 +5325,9 @@ namespace { case KeyPathExpr::Component::Kind::OptionalChain: { didOptionalChain = true; // Chaining always forces the element to be an rvalue. + assert(!componentTy->hasUnresolvedType()); auto objectTy = componentTy->getWithoutSpecifierType()->getOptionalObjectType(); - if (componentTy->hasUnresolvedType() && !objectTy) { - objectTy = componentTy; - } assert(objectTy); auto loc = origComponent.getLoc(); @@ -5422,8 +5377,8 @@ namespace { } // Wrap a non-optional result if there was chaining involved. + assert(!componentTy->hasUnresolvedType()); if (didOptionalChain && componentTy && - !componentTy->hasUnresolvedType() && !componentTy->getWithoutSpecifierType()->isEqual(leafTy)) { auto component = KeyPathExpr::Component::forOptionalWrap(leafTy); resolvedComponents.push_back(component); @@ -5549,18 +5504,13 @@ namespace { // Unwrap the last component type, preserving @lvalue-ness. auto optionalTy = components.back().getComponentType(); + assert(!optionalTy->hasUnresolvedType()); Type objectTy; if (auto lvalue = optionalTy->getAs()) { objectTy = lvalue->getObjectType()->getOptionalObjectType(); - if (optionalTy->hasUnresolvedType() && !objectTy) { - objectTy = optionalTy; - } objectTy = LValueType::get(objectTy); } else { objectTy = optionalTy->getOptionalObjectType(); - if (optionalTy->hasUnresolvedType() && !objectTy) { - objectTy = optionalTy; - } } assert(objectTy); @@ -7160,12 +7110,10 @@ Expr *ExprRewriter::coerceExistential(Expr *expr, Type toType, Type openedFromInstanceType = openedFromType; // Look through metatypes. - while ((fromInstanceType->is() || - fromInstanceType->is()) && + while (fromInstanceType->is() && toInstanceType->is()) { - if (!fromInstanceType->is()) - fromInstanceType = fromInstanceType->getMetatypeInstanceType(); - if (openedFromInstanceType && !openedFromInstanceType->is()) + fromInstanceType = fromInstanceType->getMetatypeInstanceType(); + if (openedFromInstanceType) openedFromInstanceType = openedFromInstanceType->getMetatypeInstanceType(); toInstanceType = toInstanceType->getMetatypeInstanceType(); } @@ -7297,8 +7245,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, if (knownRestriction != solution.ConstraintRestrictions.end()) { switch (knownRestriction->second) { case ConversionRestrictionKind::DeepEquality: { - if (toType->hasUnresolvedType()) - break; + assert(!toType->hasUnresolvedType()); // HACK: Fix problem related to Swift 4 mode (with assertions), // since Swift 4 mode allows passing arguments with extra parens @@ -8172,9 +8119,8 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, } } - // Unresolved types come up in diagnostics for lvalue and inout types. - if (fromType->hasUnresolvedType() || toType->hasUnresolvedType()) - return cs.cacheType(new (ctx) UnresolvedTypeConversionExpr(expr, toType)); + assert(!fromType->hasUnresolvedType()); + assert(!toType->hasUnresolvedType()); ABORT([&](auto &out) { out << "Unhandled coercion:\n"; @@ -8723,11 +8669,7 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, // FIXME: Handle unwrapping everywhere else. - // If this is an UnresolvedType in the system, preserve it. - if (cs.getType(fn)->is()) { - cs.setType(apply, cs.getType(fn)); - return apply; - } + assert(!cs.getType(fn)->is()); // We have a type constructor. auto metaTy = cs.getType(fn)->castTo(); @@ -8754,22 +8696,16 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, auto *ctorLocator = cs.getConstraintLocator(locator, {ConstraintLocator::ApplyFunction, ConstraintLocator::ConstructorMember}); - auto selected = solution.getOverloadChoiceIfAvailable(ctorLocator); - if (!selected) { - assert(ty->hasError() || ty->hasUnresolvedType()); - cs.setType(apply, ty); - return apply; - } + auto selected = solution.getOverloadChoice(ctorLocator); assert(ty->getNominalOrBoundGenericNominal() || ty->is() || ty->isExistentialType() || ty->is()); // Consider the constructor decl reference expr 'implicit', but the // constructor call expr itself has the apply's 'implicitness'. - Expr *declRef = buildMemberRef(fn, /*dotLoc=*/SourceLoc(), *selected, - DeclNameLoc(fn->getEndLoc()), locator, - ctorLocator, /*implicit=*/true, - AccessSemantics::Ordinary); + Expr *declRef = buildMemberRef( + fn, /*dotLoc=*/SourceLoc(), selected, DeclNameLoc(fn->getEndLoc()), + locator, ctorLocator, /*implicit=*/true, AccessSemantics::Ordinary); if (!declRef) return nullptr; From 3484f63ca170a3a9b7ffc030946af6bd88129295 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Sun, 14 Sep 2025 11:33:29 +0100 Subject: [PATCH 5/5] [CS] Strengthen a couple of CSApply assertions Enforce that we don't ever encounter solutions that contain holes or error types. --- lib/Sema/CSApply.cpp | 59 ++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 35 deletions(-) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index e5fbbaeeaf0a1..c0d41b10160b4 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -3268,8 +3268,6 @@ namespace { auto type = simplifyType(openedType); cs.setType(expr, type); - assert(!type->is()); - Type conformingType = type; if (auto baseType = conformingType->getOptionalObjectType()) { // The type may be optional due to a failable initializer in the @@ -3457,14 +3455,7 @@ namespace { } Expr *visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) { - // If constraint solving resolved this to an UnresolvedType, then we're in - // an ambiguity tolerant mode used for diagnostic generation. Just leave - // this as an unresolved member reference. Type resultTy = simplifyType(cs.getType(expr)); - if (resultTy->hasUnresolvedType()) { - cs.setType(expr, resultTy); - return expr; - } // Find the selected member and base type. auto memberLocator = cs.getConstraintLocator( @@ -4935,7 +4926,6 @@ namespace { Expr *visitEditorPlaceholderExpr(EditorPlaceholderExpr *E) { simplifyExprType(E); auto valueType = cs.getType(E); - assert(!valueType->hasUnresolvedType()); // Synthesize a call to _undefined() of appropriate type. FuncDecl *undefinedDecl = ctx.getUndefined(); @@ -5264,13 +5254,6 @@ namespace { auto componentTy = baseTy; for (unsigned i : indices(E->getComponents())) { auto &origComponent = E->getMutableComponents()[i]; - - // If there were unresolved types, we may end up with a null base for - // following components. - if (!componentTy) { - resolvedComponents.push_back(origComponent); - continue; - } auto kind = origComponent.getKind(); auto componentLocator = @@ -5325,7 +5308,6 @@ namespace { case KeyPathExpr::Component::Kind::OptionalChain: { didOptionalChain = true; // Chaining always forces the element to be an rvalue. - assert(!componentTy->hasUnresolvedType()); auto objectTy = componentTy->getWithoutSpecifierType()->getOptionalObjectType(); assert(objectTy); @@ -5377,8 +5359,7 @@ namespace { } // Wrap a non-optional result if there was chaining involved. - assert(!componentTy->hasUnresolvedType()); - if (didOptionalChain && componentTy && + if (didOptionalChain && !componentTy->getWithoutSpecifierType()->isEqual(leafTy)) { auto component = KeyPathExpr::Component::forOptionalWrap(leafTy); resolvedComponents.push_back(component); @@ -5504,7 +5485,6 @@ namespace { // Unwrap the last component type, preserving @lvalue-ness. auto optionalTy = components.back().getComponentType(); - assert(!optionalTy->hasUnresolvedType()); Type objectTy; if (auto lvalue = optionalTy->getAs()) { objectTy = lvalue->getObjectType()->getOptionalObjectType(); @@ -7218,6 +7198,9 @@ Expr *ConstraintSystem::addImplicitLoadExpr(Expr *expr) { Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, ConstraintLocatorBuilder locator) { + ASSERT(toType && !toType->hasError() && !toType->hasUnresolvedType() && + !toType->hasTypeVariableOrPlaceholder()); + // Diagnose conversions to invalid function types that couldn't be performed // beforehand because of placeholders. if (auto *fnTy = toType->getAs()) { @@ -7245,8 +7228,6 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, if (knownRestriction != solution.ConstraintRestrictions.end()) { switch (knownRestriction->second) { case ConversionRestrictionKind::DeepEquality: { - assert(!toType->hasUnresolvedType()); - // HACK: Fix problem related to Swift 4 mode (with assertions), // since Swift 4 mode allows passing arguments with extra parens // to parameters which don't expect them, it should be supported @@ -8119,9 +8100,6 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, } } - assert(!fromType->hasUnresolvedType()); - assert(!toType->hasUnresolvedType()); - ABORT([&](auto &out) { out << "Unhandled coercion:\n"; fromType->dump(out); @@ -8224,13 +8202,6 @@ Expr *ExprRewriter::convertLiteralInPlace( Identifier literalType, DeclName literalFuncName, ProtocolDecl *builtinProtocol, DeclName builtinLiteralFuncName, Diag<> brokenProtocolDiag, Diag<> brokenBuiltinProtocolDiag) { - // If coercing a literal to an unresolved type, we don't try to look up the - // witness members, just do it. - if (type->is() || type->is()) { - cs.setType(literal, type); - return literal; - } - // Check whether this literal type conforms to the builtin protocol. If so, // initialize via the builtin protocol. if (builtinProtocol) { @@ -8669,8 +8640,6 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, // FIXME: Handle unwrapping everywhere else. - assert(!cs.getType(fn)->is()); - // We have a type constructor. auto metaTy = cs.getType(fn)->castTo(); auto ty = metaTy->getInstanceType(); @@ -10036,6 +10005,26 @@ ConstraintSystem::applySolution(Solution &solution, } } + // If the score indicates the solution is valid, ensure we don't have any + // unresolved types. + { + auto isValidType = [&](Type ty) { + return !ty->hasUnresolvedType() && !ty->hasError() && + !ty->hasTypeVariableOrPlaceholder(); + }; + for (auto &[_, type] : solution.typeBindings) { + ASSERT(isValidType(type) && "type binding has invalid type"); + } + for (auto &[_, type] : solution.nodeTypes) { + ASSERT(isValidType(solution.simplifyType(type)) && + "node type has invalid type"); + } + for (auto &[_, type] : solution.keyPathComponentTypes) { + ASSERT(isValidType(solution.simplifyType(type)) && + "key path type has invalid type"); + } + } + ExprRewriter rewriter(*this, solution, target, shouldSuppressDiagnostics()); ExprWalker walker(rewriter); auto resultTarget = walker.rewriteTarget(target);