Skip to content

Commit 337501e

Browse files
Merge pull request #33227 from AnthonyLatsis/unbound-thinout-1
Sema: Make type resolution for EnumElementPattern less eager
2 parents 79ff5e3 + 9462de1 commit 337501e

File tree

5 files changed

+93
-93
lines changed

5 files changed

+93
-93
lines changed

include/swift/AST/NameLookup.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,14 @@ void recordLookupOfTopLevelName(DeclContext *topLevelContext, DeclName name,
512512

513513
} // end namespace namelookup
514514

515+
/// Retrieve the set of nominal type declarations that are directly
516+
/// referenced in the given \c typeRepr, looking through typealiases.
517+
///
518+
/// \param dc The \c DeclContext from which to perform lookup.
519+
TinyPtrVector<NominalTypeDecl *>
520+
getDirectlyReferencedNominalTypeDecls(ASTContext &ctx, TypeRepr *typeRepr,
521+
DeclContext *dc, bool &anyObject);
522+
515523
/// Retrieve the set of nominal type declarations that are directly
516524
/// "inherited" by the given declaration at a particular position in the
517525
/// list of "inherited" types.

lib/AST/NameLookup.cpp

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -861,18 +861,13 @@ SelfBounds SelfBoundsFromWhereClauseRequest::evaluate(
861861
continue;
862862

863863
// Resolve the right-hand side.
864-
DirectlyReferencedTypeDecls rhsDecls;
865-
if (auto typeRepr = req.getConstraintRepr()) {
866-
rhsDecls = directReferencesForTypeRepr(evaluator, ctx, typeRepr, lookupDC);
867-
}
864+
if (auto *const typeRepr = req.getConstraintRepr()) {
865+
const auto rhsNominals = getDirectlyReferencedNominalTypeDecls(
866+
ctx, typeRepr, lookupDC, result.anyObject);
868867

869-
SmallVector<ModuleDecl *, 2> modulesFound;
870-
auto rhsNominals = resolveTypeDeclsToNominal(evaluator, ctx, rhsDecls,
871-
modulesFound,
872-
result.anyObject);
873-
result.decls.insert(result.decls.end(),
874-
rhsNominals.begin(),
875-
rhsNominals.end());
868+
result.decls.insert(result.decls.end(), rhsNominals.begin(),
869+
rhsNominals.end());
870+
}
876871
}
877872

878873
return result;
@@ -2139,6 +2134,17 @@ static DirectlyReferencedTypeDecls directReferencesForType(Type type) {
21392134
return { };
21402135
}
21412136

2137+
TinyPtrVector<NominalTypeDecl *> swift::getDirectlyReferencedNominalTypeDecls(
2138+
ASTContext &ctx, TypeRepr *typeRepr, DeclContext *dc, bool &anyObject) {
2139+
const auto referenced =
2140+
directReferencesForTypeRepr(ctx.evaluator, ctx, typeRepr, dc);
2141+
2142+
// Resolve those type declarations to nominal type declarations.
2143+
SmallVector<ModuleDecl *, 2> modulesFound;
2144+
return resolveTypeDeclsToNominal(ctx.evaluator, ctx, referenced, modulesFound,
2145+
anyObject);
2146+
}
2147+
21422148
DirectlyReferencedTypeDecls InheritedDeclsReferencedRequest::evaluate(
21432149
Evaluator &evaluator,
21442150
llvm::PointerUnion<const TypeDecl *, const ExtensionDecl *> decl,
@@ -2260,16 +2266,10 @@ ExtendedNominalRequest::evaluate(Evaluator &evaluator,
22602266
// We must've seen 'extension { ... }' during parsing.
22612267
return nullptr;
22622268

2263-
ASTContext &ctx = ext->getASTContext();
2264-
DirectlyReferencedTypeDecls referenced =
2265-
directReferencesForTypeRepr(evaluator, ctx, typeRepr, ext->getParent());
2266-
22672269
// Resolve those type declarations to nominal type declarations.
2268-
SmallVector<ModuleDecl *, 2> modulesFound;
22692270
bool anyObject = false;
2270-
auto nominalTypes
2271-
= resolveTypeDeclsToNominal(evaluator, ctx, referenced, modulesFound,
2272-
anyObject);
2271+
const auto nominalTypes = getDirectlyReferencedNominalTypeDecls(
2272+
ext->getASTContext(), typeRepr, ext->getParent(), anyObject);
22732273

22742274
// If there is more than 1 element, we will emit a warning or an error
22752275
// elsewhere, so don't handle that case here.

lib/Sema/CSGen.cpp

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2501,31 +2501,23 @@ namespace {
25012501
if (enumPattern->getParentType() || enumPattern->getParentTypeRepr()) {
25022502
// Resolve the parent type.
25032503
Type parentType = [&]() -> Type {
2504-
if (auto preTy = enumPattern->getParentType()) {
2505-
return preTy;
2504+
if (const auto resolvedTy = enumPattern->getParentType()) {
2505+
assert(resolvedTy->hasUnboundGenericType() == false &&
2506+
"A pre-resolved type must be fully bound");
2507+
return resolvedTy;
25062508
}
25072509
return resolveTypeReferenceInExpression(
25082510
enumPattern->getParentTypeRepr(),
2509-
TypeResolverContext::InExpression, [](auto unboundTy) {
2510-
// FIXME: We ought to pass an OpenUnboundGenericType object
2511-
// rather than calling CS.openUnboundGenericType below, but
2512-
// sometimes the parent type is resolved eagerly in
2513-
// ResolvePattern::visitUnresolvedDotExpr, letting unbound
2514-
// generics escape.
2515-
return unboundTy;
2516-
});
2511+
TypeResolverContext::InExpression,
2512+
OpenUnboundGenericType(
2513+
CS, CS.getConstraintLocator(
2514+
locator, {LocatorPathElt::PatternMatch(pattern),
2515+
ConstraintLocator::ParentType})));
25172516
}();
25182517

25192518
if (!parentType)
25202519
return Type();
25212520

2522-
parentType = CS.openUnboundGenericTypes(
2523-
parentType, CS.getConstraintLocator(
2524-
locator, {LocatorPathElt::PatternMatch(pattern),
2525-
ConstraintLocator::ParentType}));
2526-
2527-
assert(parentType);
2528-
25292521
// Perform member lookup into the parent's metatype.
25302522
Type parentMetaType = MetatypeType::get(parentType);
25312523
CS.addValueMemberConstraint(
@@ -3038,21 +3030,14 @@ namespace {
30383030
Type visitCoerceExpr(CoerceExpr *expr) {
30393031
// Validate the resulting type.
30403032
auto *const repr = expr->getCastTypeRepr();
3041-
const auto type = resolveTypeReferenceInExpression(
3042-
repr, TypeResolverContext::ExplicitCastExpr, [](auto unboundTy) {
3043-
// FIXME: We ought to pass an OpenUnboundGenericType object rather
3044-
// than calling CS.openUnboundGenericType after resolving, but
3045-
// sometimes the type expression is resolved eagerly in
3046-
// PreCheckExpression::simplifyTypeConstructionWithLiteralArg,
3047-
// letting unbound generics escape.
3048-
return unboundTy;
3049-
});
3050-
if (!type)
3033+
const auto toType = resolveTypeReferenceInExpression(
3034+
repr, TypeResolverContext::ExplicitCastExpr,
3035+
// Introduce type variables for unbound generics.
3036+
OpenUnboundGenericType(CS, CS.getConstraintLocator(expr)));
3037+
if (!toType)
30513038
return nullptr;
30523039

3053-
// Open the type we're casting to.
3054-
const auto toType =
3055-
CS.openUnboundGenericTypes(type, CS.getConstraintLocator(expr));
3040+
// Cache the type we're casting to.
30563041
if (repr) CS.setType(repr, toType);
30573042

30583043
auto fromType = CS.getType(expr->getSubExpr());

lib/Sema/TypeCheckPattern.cpp

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -467,31 +467,26 @@ class ResolvePattern : public ASTVisitor<ResolvePattern,
467467
if (!ExprToIdentTypeRepr(components, Context).visit(ude->getBase()))
468468
return nullptr;
469469

470-
const auto options =
471-
TypeResolutionOptions(None) | TypeResolutionFlags::SilenceErrors;
470+
auto *const repr = IdentTypeRepr::create(Context, components);
472471

473-
auto *repr = IdentTypeRepr::create(Context, components);
472+
// See first if the repr unambiguously references an enum declaration.
473+
bool anyObject = false;
474+
const auto &referencedDecls =
475+
getDirectlyReferencedNominalTypeDecls(Context, repr, DC, anyObject);
476+
if (referencedDecls.size() != 1)
477+
return nullptr;
474478

475-
// See if the repr resolves to a type.
476-
const auto resolution =
477-
TypeResolution::forContextual(DC, options, [](auto unboundTy) {
478-
// FIXME: Don't let unbound generic types escape type resolution.
479-
// For now, just return the unbound generic type.
480-
return unboundTy;
481-
});
482-
const auto ty = resolution.resolveType(repr);
483-
auto *enumDecl = dyn_cast_or_null<EnumDecl>(ty->getAnyNominal());
479+
auto *const enumDecl = dyn_cast<EnumDecl>(referencedDecls.front());
484480
if (!enumDecl)
485481
return nullptr;
486482

487-
EnumElementDecl *referencedElement
488-
= lookupEnumMemberElement(DC, ty, ude->getName(), ude->getLoc());
483+
EnumElementDecl *referencedElement =
484+
lookupEnumMemberElement(DC, enumDecl->getDeclaredInterfaceType(),
485+
ude->getName(), ude->getLoc());
489486
if (!referencedElement)
490487
return nullptr;
491488

492-
auto *base =
493-
TypeExpr::createForMemberDecl(repr, ude->getNameLoc(), enumDecl);
494-
base->setType(MetatypeType::get(ty));
489+
auto *const base = new (Context) TypeExpr(repr);
495490
return new (Context)
496491
EnumElementPattern(base, ude->getDotLoc(), ude->getNameLoc(),
497492
ude->getName(), referencedElement, nullptr);
@@ -569,37 +564,31 @@ class ResolvePattern : public ASTVisitor<ResolvePattern,
569564
baseTE = TypeExpr::createImplicit(enumDecl->getDeclaredTypeInContext(),
570565
Context);
571566
} else {
572-
const auto options =
573-
TypeResolutionOptions(None) | TypeResolutionFlags::SilenceErrors;
574-
575567
// Otherwise, see whether we had an enum type as the penultimate
576568
// component, and look up an element inside it.
577-
auto *prefixRepr = IdentTypeRepr::create(Context, components);
578-
579-
// See first if the entire repr resolves to a type.
580-
const Type enumTy =
581-
TypeResolution::forContextual(DC, options, [](auto unboundTy) {
582-
// FIXME: Don't let unbound generic types escape type resolution.
583-
// For now, just return the unbound generic type.
584-
return unboundTy;
585-
}).resolveType(prefixRepr);
586-
auto *enumDecl = dyn_cast_or_null<EnumDecl>(enumTy->getAnyNominal());
569+
auto *const prefixRepr = IdentTypeRepr::create(Context, components);
570+
571+
// See first if the repr unambiguously references an enum declaration.
572+
bool anyObject = false;
573+
const auto &referencedDecls = getDirectlyReferencedNominalTypeDecls(
574+
Context, prefixRepr, DC, anyObject);
575+
if (referencedDecls.size() != 1)
576+
return nullptr;
577+
578+
auto *const enumDecl = dyn_cast<EnumDecl>(referencedDecls.front());
587579
if (!enumDecl)
588580
return nullptr;
589581

590-
referencedElement
591-
= lookupEnumMemberElement(DC, enumTy,
592-
tailComponent->getNameRef(),
593-
tailComponent->getLoc());
582+
referencedElement = lookupEnumMemberElement(
583+
DC, enumDecl->getDeclaredInterfaceType(), tailComponent->getNameRef(),
584+
tailComponent->getLoc());
594585
if (!referencedElement)
595586
return nullptr;
596587

597-
baseTE = TypeExpr::createForMemberDecl(
598-
prefixRepr, tailComponent->getNameLoc(), enumDecl);
599-
baseTE->setType(MetatypeType::get(enumTy));
588+
baseTE = new (Context) TypeExpr(prefixRepr);
600589
}
601590

602-
assert(baseTE && baseTE->getType() && "Didn't initialize base expression?");
591+
assert(baseTE && "Didn't initialize base expression?");
603592
assert(!isa<GenericIdentTypeRepr>(tailComponent) &&
604593
"should be handled above");
605594

@@ -1437,11 +1426,25 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
14371426

14381427
enumTy = type;
14391428
} else {
1429+
// Validate the parent type if we haven't done so yet.
1430+
if (EEP->getParentType().isNull()) {
1431+
const auto resolution =
1432+
TypeResolution::forContextual(dc, options, [](auto unboundTy) {
1433+
// FIXME: Don't let unbound generic types escape type resolution.
1434+
// For now, just return the unbound generic type.
1435+
return unboundTy;
1436+
});
1437+
const auto ty = resolution.resolveType(EEP->getParentTypeRepr());
1438+
EEP->setParentType(ty);
1439+
1440+
if (ty->hasError()) {
1441+
return nullptr;
1442+
}
1443+
}
1444+
14401445
// Check if the explicitly-written enum type matches the type we're
14411446
// coercing to.
1442-
assert(!EEP->getParentType().isNull()
1443-
&& "enum with resolved element doesn't specify parent type?!");
1444-
auto parentTy = EEP->getParentType();
1447+
const Type parentTy = EEP->getParentType();
14451448
// If the type matches exactly, use it.
14461449
if (parentTy->isEqual(type)) {
14471450
enumTy = type;

test/Constraints/patterns.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -343,10 +343,14 @@ func rdar32241441() {
343343

344344
// SR-6100
345345
struct One<Two> { // expected-note{{'Two' declared as parameter to type 'One'}}
346-
public enum E: Error {
347-
// if you remove associated value, everything works
348-
case SomeError(String)
346+
public enum E: Error {
347+
// if you remove associated value, everything works
348+
case SomeError(String)
349+
350+
static func foo(error: Error) {
351+
if case SomeError = error {}
349352
}
353+
}
350354
}
351355

352356
func testOne() {

0 commit comments

Comments
 (0)