diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index ac78b00eb44a8..23ac2898abb70 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -7734,8 +7734,8 @@ class PlaceholderType : public TypeBase { // NOTE: If you add a new Type-based originator, you'll need to update the // recursive property logic in PlaceholderType::get. using Originator = - llvm::PointerUnion; + llvm::PointerUnion; Originator O; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index ef9aca690f6d0..32d700a948109 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3675,6 +3675,9 @@ Type PlaceholderType::get(ASTContext &ctx, Originator originator) { if (auto *depTy = originator.dyn_cast()) return depTy->getRecursiveProperties(); + if (auto *errTy = originator.dyn_cast()) + return errTy->getRecursiveProperties(); + return RecursiveTypeProperties(); }(); auto arena = getArena(originatorProps); diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 6613424422052..cf0772419ed15 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -6077,6 +6077,8 @@ namespace { Label::optional("originating_var"), DeclColor); } else if (isa(originator)) { printFlag("error_expr"); + } else if (auto *errTy = originator.dyn_cast()) { + printRec(errTy, Label::always("error_type")); } else if (auto *DMT = originator.dyn_cast()) { printRec(DMT, Label::always("dependent_member_type")); } else if (isa(originator)) { diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 40f93e347a4dd..6cb92ce1e1f76 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -6146,6 +6146,8 @@ class TypePrinter : public TypeVisitorgetName(); } else if (isa(originator)) { Printer << "error_expr"; + } else if (auto *errTy = originator.dyn_cast()) { + visit(errTy); } else if (auto *DMT = originator.dyn_cast()) { visit(DMT); } else if (isa(originator)) { diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 4bf8ffa39bfeb..13634185ec393 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1712,17 +1712,12 @@ namespace { const auto result = TypeResolution::resolveContextualType( repr, CS.DC, options, genericOpener, placeholderHandler, packElementOpener, requirementOpener); + // If we have an error, record a fix and produce a hole for the type. if (result->hasError()) { CS.recordFix( IgnoreInvalidASTNode::create(CS, CS.getConstraintLocator(locator))); - // Immediately bind the result to a hole since we know it's invalid and - // want it to propagate rather than allowing other type variables to - // become holes. - auto *tv = CS.createTypeVariable(CS.getConstraintLocator(repr), - TVO_CanBindToHole); - CS.recordTypeVariablesAsHoles(tv); - return tv; + return PlaceholderType::get(CS.getASTContext(), repr); } // Diagnose top-level usages of placeholder types. if (auto *ty = dyn_cast(repr->getWithoutParens())) { @@ -4901,18 +4896,6 @@ bool ConstraintSystem::generateConstraints( getConstraintLocator(expr, LocatorPathElt::ContextualType(ctp)); } - auto getLocator = [&](Type ty) -> ConstraintLocator * { - // If we have a placeholder originating from a PlaceholderTypeRepr, - // tack that on to the locator. - if (auto *placeholderTy = ty->getAs()) - if (auto *typeRepr = placeholderTy->getOriginator() - .dyn_cast()) - return getConstraintLocator( - convertTypeLocator, - LocatorPathElt::PlaceholderType(typeRepr)); - return convertTypeLocator; - }; - // If the contextual type has an error, we can't apply the solution. // Record a fix for an invalid AST node. if (convertType->hasError()) @@ -4921,18 +4904,30 @@ bool ConstraintSystem::generateConstraints( // Substitute type variables in for placeholder and error types. convertType = convertType.transformRec([&](Type type) -> std::optional { - if (!isa(type.getPointer())) - return std::nullopt; - - auto flags = TVO_CanBindToNoEscape | TVO_PrefersSubtypeBinding | - TVO_CanBindToHole; - auto tv = Type(createTypeVariable(getLocator(type), flags)); - // For ErrorTypes we want to eagerly bind to a hole since we - // know this is where the issue is. - if (isa(type.getPointer())) { - recordTypeVariablesAsHoles(tv); + auto *tyPtr = type.getPointer(); + // Open a type variable for a placeholder type repr. Note we don't + // do this for arbitrary placeholders since they may be existing + // holes when e.g generating the constraints for a ReturnStmt in a + // closure. + if (auto *placeholderTy = dyn_cast(tyPtr)) { + auto originator = placeholderTy->getOriginator(); + auto *typeRepr = originator.dyn_cast(); + if (!isa_and_nonnull(typeRepr)) + return std::nullopt; + + auto *loc = getConstraintLocator( + convertTypeLocator, + LocatorPathElt::PlaceholderType(typeRepr)); + return createTypeVariable(loc, TVO_CanBindToNoEscape | + TVO_PrefersSubtypeBinding | + TVO_CanBindToHole); } - return tv; + // For ErrorTypes we want to eagerly produce a hole since we know + // this is where the issue is. + if (auto *errTy = dyn_cast(tyPtr)) { + return PlaceholderType::get(getASTContext(), errTy); + } + return std::nullopt; }); addContextualConversionConstraint(expr, convertType, ctp, diff --git a/lib/Sema/TypeOfReference.cpp b/lib/Sema/TypeOfReference.cpp index 777821d323a92..ddfcdf4853784 100644 --- a/lib/Sema/TypeOfReference.cpp +++ b/lib/Sema/TypeOfReference.cpp @@ -274,11 +274,9 @@ class InferableTypeOpener final { } Type transformErrorType(ErrorType *errTy) { - // For ErrorTypes we want to eagerly bind to a hole since we know this is + // For ErrorTypes we want to eagerly produce a hole since we know this is // where the issue is. - auto *tv = createTypeVariable(cs.getConstraintLocator(locator)); - cs.recordTypeVariablesAsHoles(tv); - return tv; + return PlaceholderType::get(cs.getASTContext(), errTy); } Type transform(Type type) {