Skip to content

Commit 0eac6f0

Browse files
committed
Sema: Factor out some duplication in member type lookup
When resolving a nested identifier, we would take different code paths depending on whether the identifier already had a declaration bound or not. These two code paths had to diagnose the same set of problems, so unify them. This also lets us rip out similar checks in preCheckExpression(), which can now rely on the diagnostics being produced consistently when constructing TypeReprs with already-bound decls.
1 parent 0c474eb commit 0eac6f0

File tree

2 files changed

+79
-112
lines changed

2 files changed

+79
-112
lines changed

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,22 +1118,8 @@ TypeExpr *PreCheckExpression::simplifyNestedTypeExpr(UnresolvedDotExpr *UDE) {
11181118
// If there is no nested type with this name, we have a lookup of
11191119
// a non-type member, so leave the expression as-is.
11201120
if (Result.size() == 1) {
1121-
auto *NewDecl = Result.front().first;
1122-
// Filter out dicey cases that we diagnose or handle later:
1123-
//
1124-
// 1) Dependent typealias or associated type reference with
1125-
// protocol base.
1126-
if (NewDecl->getDeclaredInterfaceType()->hasTypeParameter() &&
1127-
BaseTy->isExistentialType())
1128-
return nullptr;
1129-
1130-
// 2) Generic typealias reference with unbound generic base.
1131-
if (isa<TypeAliasDecl>(NewDecl) &&
1132-
NewDecl->getDeclaredInterfaceType()->hasTypeParameter() &&
1133-
BaseTy->hasUnboundGenericType())
1134-
return nullptr;
1135-
1136-
return TypeExpr::createForMemberDecl(ITR, NameLoc, NewDecl);
1121+
return TypeExpr::createForMemberDecl(ITR, NameLoc,
1122+
Result.front().first);
11371123
}
11381124
}
11391125
}

lib/Sema/TypeCheckType.cpp

Lines changed: 77 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,22 +1279,20 @@ static Type resolveNestedIdentTypeComponent(
12791279
// associated type but the type itself was erroneous. We'll produce a
12801280
// diagnostic here if the diagnostic for the bad type witness would show up in
12811281
// a different context.
1282-
auto maybeDiagnoseBadConformanceRef = [&](AssociatedTypeDecl *assocType,
1283-
ProtocolConformance *conformance) {
1282+
auto maybeDiagnoseBadConformanceRef = [&](AssociatedTypeDecl *assocType) {
12841283
// If we aren't emitting any diagnostics, we're done.
12851284
if (!diagnoseErrors)
12861285
return;
12871286

12881287
// If we weren't given a conformance, go look it up.
1289-
if (!conformance) {
1290-
if (auto conformanceRef =
1291-
TC.conformsToProtocol(
1292-
parentTy, assocType->getProtocol(), DC,
1293-
(ConformanceCheckFlags::InExpression|
1294-
ConformanceCheckFlags::SuppressDependencyTracking))) {
1295-
if (conformanceRef->isConcrete())
1296-
conformance = conformanceRef->getConcrete();
1297-
}
1288+
ProtocolConformance *conformance = nullptr;
1289+
if (auto conformanceRef =
1290+
TC.conformsToProtocol(
1291+
parentTy, assocType->getProtocol(), DC,
1292+
(ConformanceCheckFlags::InExpression|
1293+
ConformanceCheckFlags::SuppressDependencyTracking))) {
1294+
if (conformanceRef->isConcrete())
1295+
conformance = conformanceRef->getConcrete();
12981296
}
12991297

13001298
// If there is a conformance and it comes from the same source file as type
@@ -1313,38 +1311,58 @@ static Type resolveNestedIdentTypeComponent(
13131311
assocType->getFullName(), parentTy);
13141312
};
13151313

1316-
// Short-circuiting.
1317-
if (comp->isInvalid()) return ErrorType::get(TC.Context);
1314+
auto maybeDiagnoseBadMemberType = [&](TypeDecl *member, Type memberType) {
1315+
// Diagnose invalid cases.
1316+
if (TC.isUnsupportedMemberTypeAccess(parentTy, member)) {
1317+
if (diagnoseErrors) {
1318+
if (parentTy->is<UnboundGenericType>())
1319+
diagnoseUnboundGenericType(TC, parentTy, parentRange.End);
1320+
else if (parentTy->isExistentialType() &&
1321+
isa<AssociatedTypeDecl>(member)) {
1322+
TC.diagnose(comp->getIdLoc(), diag::assoc_type_outside_of_protocol,
1323+
comp->getIdentifier());
1324+
} else if (parentTy->isExistentialType() &&
1325+
isa<TypeAliasDecl>(member)) {
1326+
TC.diagnose(comp->getIdLoc(), diag::typealias_outside_of_protocol,
1327+
comp->getIdentifier());
1328+
}
1329+
}
13181330

1319-
// If the parent is a type parameter, the member is a dependent member,
1320-
// and we skip much of the work below.
1321-
if (parentTy->isTypeParameter()) {
1322-
auto memberType = resolver->resolveDependentMemberType(parentTy, DC,
1323-
parentRange, comp);
1324-
assert(memberType && "Received null dependent member type");
1325-
return memberType;
1326-
}
1331+
return ErrorType::get(TC.Context);
1332+
}
13271333

1328-
// Phase 2: If a declaration has already been bound, use it.
1329-
if (auto *typeDecl = comp->getBoundDecl()) {
1330-
// Otherwise, simply substitute the parent type into the member.
1331-
auto memberType = TC.substMemberTypeWithBase(DC->getParentModule(),
1332-
typeDecl, parentTy);
1334+
// Only the last component of the underlying type of a type alias may
1335+
// be an unbound generic.
1336+
if (options & TR_TypeAliasUnderlyingType) {
1337+
if (parentTy->is<UnboundGenericType>()) {
1338+
if (diagnoseErrors)
1339+
diagnoseUnboundGenericType(TC, parentTy, parentRange.End);
13331340

1334-
// Diagnose the bad reference if we need to.
1335-
if (typeDecl && isa<AssociatedTypeDecl>(typeDecl) && memberType->hasError())
1336-
maybeDiagnoseBadConformanceRef(cast<AssociatedTypeDecl>(typeDecl), nullptr);
1341+
return ErrorType::get(TC.Context);
1342+
}
1343+
}
13371344

1338-
// Propagate failure.
1345+
// If we found a reference to an associated type or other member type that
1346+
// was marked invalid, just return ErrorType to silence downstream errors.
1347+
if (member->isInvalid())
1348+
return ErrorType::get(TC.Context);
1349+
1350+
// Diagnose a bad conformance reference if we need to.
1351+
if (isa<AssociatedTypeDecl>(member) &&
1352+
memberType &&
1353+
memberType->hasError())
1354+
maybeDiagnoseBadConformanceRef(cast<AssociatedTypeDecl>(member));
1355+
1356+
// At this point, we need to have resolved the type of the member.
13391357
if (!memberType || memberType->hasError()) return memberType;
13401358

13411359
// If there are generic arguments, apply them now.
13421360
if (auto genComp = dyn_cast<GenericIdentTypeRepr>(comp)) {
13431361
return TC.applyGenericArguments(
1344-
memberType, typeDecl, comp->getIdLoc(), DC, genComp,
1362+
memberType, member, comp->getIdLoc(), DC, genComp,
13451363
options, resolver, unsatisfiedDependency);
13461364
}
1347-
1365+
13481366
if (memberType->is<UnboundGenericType>() &&
13491367
!options.contains(TR_AllowUnboundGenerics) &&
13501368
!options.contains(TR_TypeAliasUnderlyingType) &&
@@ -1353,8 +1371,26 @@ static Type resolveNestedIdentTypeComponent(
13531371
return ErrorType::get(TC.Context);
13541372
}
13551373

1356-
// We're done.
13571374
return memberType;
1375+
};
1376+
1377+
// Short-circuiting.
1378+
if (comp->isInvalid()) return ErrorType::get(TC.Context);
1379+
1380+
// If the parent is a type parameter, the member is a dependent member,
1381+
// and we skip much of the work below.
1382+
if (parentTy->isTypeParameter()) {
1383+
auto memberType = resolver->resolveDependentMemberType(parentTy, DC,
1384+
parentRange, comp);
1385+
assert(memberType && "Received null dependent member type");
1386+
return memberType;
1387+
}
1388+
1389+
// Phase 2: If a declaration has already been bound, use it.
1390+
if (auto *typeDecl = comp->getBoundDecl()) {
1391+
auto memberType = TC.substMemberTypeWithBase(DC->getParentModule(),
1392+
typeDecl, parentTy);
1393+
return maybeDiagnoseBadMemberType(typeDecl, memberType);
13581394
}
13591395

13601396
// Phase 1: Find and bind the component decl.
@@ -1412,77 +1448,22 @@ static Type resolveNestedIdentTypeComponent(
14121448
if (!memberTypes) {
14131449
// If we're not allowed to complain or we couldn't fix the
14141450
// source, bail out.
1415-
if (!diagnoseErrors) {
1451+
if (!diagnoseErrors)
14161452
return ErrorType::get(TC.Context);
1417-
}
14181453

1419-
Type ty = diagnoseUnknownType(TC, DC, parentTy, parentRange, comp, options,
1420-
lookupOptions, resolver,
1421-
unsatisfiedDependency);
1422-
if (!ty || ty->hasError()) {
1423-
return ErrorType::get(TC.Context);
1424-
}
1425-
1426-
memberType = ty;
1454+
memberType = diagnoseUnknownType(TC, DC, parentTy, parentRange, comp,
1455+
options, lookupOptions, resolver,
1456+
unsatisfiedDependency);
14271457
member = comp->getBoundDecl();
1458+
if (!member)
1459+
return ErrorType::get(TC.Context);
14281460
} else {
14291461
memberType = memberTypes.back().second;
14301462
member = memberTypes.back().first;
1463+
comp->setValue(member);
14311464
}
14321465

1433-
// Diagnose invalid cases.
1434-
if (TC.isUnsupportedMemberTypeAccess(parentTy, member)) {
1435-
if (diagnoseErrors) {
1436-
if (parentTy->is<UnboundGenericType>())
1437-
diagnoseUnboundGenericType(TC, parentTy, parentRange.End);
1438-
else if (parentTy->isExistentialType() &&
1439-
isa<AssociatedTypeDecl>(member)) {
1440-
TC.diagnose(comp->getIdLoc(), diag::assoc_type_outside_of_protocol,
1441-
comp->getIdentifier());
1442-
} else if (parentTy->isExistentialType() &&
1443-
isa<TypeAliasDecl>(member)) {
1444-
TC.diagnose(comp->getIdLoc(), diag::typealias_outside_of_protocol,
1445-
comp->getIdentifier());
1446-
}
1447-
}
1448-
1449-
return ErrorType::get(TC.Context);
1450-
}
1451-
1452-
if (options & TR_TypeAliasUnderlyingType) {
1453-
if (parentTy->is<UnboundGenericType>()) {
1454-
if (diagnoseErrors)
1455-
diagnoseUnboundGenericType(TC, parentTy, parentRange.End);
1456-
1457-
return ErrorType::get(TC.Context);
1458-
}
1459-
}
1460-
1461-
// If there are generic arguments, apply them now.
1462-
if (auto genComp = dyn_cast<GenericIdentTypeRepr>(comp)) {
1463-
memberType = TC.applyGenericArguments(
1464-
memberType, member, comp->getIdLoc(), DC, genComp,
1465-
options, resolver, unsatisfiedDependency);
1466-
} else if (memberType->is<UnboundGenericType>() &&
1467-
!options.contains(TR_AllowUnboundGenerics) &&
1468-
!options.contains(TR_TypeAliasUnderlyingType) &&
1469-
!options.contains(TR_ResolveStructure)) {
1470-
diagnoseUnboundGenericType(TC, memberType, comp->getLoc());
1471-
memberType = ErrorType::get(TC.Context);
1472-
}
1473-
1474-
// If we found a reference to an associated type or other member type that
1475-
// was marked invalid, just return ErrorType to silence downstream errors.
1476-
if (member && member->isInvalid())
1477-
memberType = ErrorType::get(TC.Context);
1478-
1479-
// Diagnose the bad reference if we need to.
1480-
if (member && isa<AssociatedTypeDecl>(member) && memberType->hasError())
1481-
maybeDiagnoseBadConformanceRef(cast<AssociatedTypeDecl>(member), nullptr);
1482-
1483-
if (member)
1484-
comp->setValue(member);
1485-
return memberType;
1466+
return maybeDiagnoseBadMemberType(member, memberType);
14861467
}
14871468

14881469
static Type resolveIdentTypeComponent(

0 commit comments

Comments
 (0)