Skip to content

Commit c522bb5

Browse files
committed
[GSB] Separate out "unresolved" and "direct" type requirement handling.
As we've done with layout requirements, introduce a new entry point (addTypeRequirement) that handles unresolved type requirements of the form `T: U`, resolves the types, and then can 1. Diagnose any immediate problems with the types, 2. Delay the type requirement if one of the types cannot be resolved, or 3. Break it into one or more "direct" requirements. This allows us to clean up and centralize a bunch of checking that was scattered/duplicated across the GSB and type checker.
1 parent 68efffd commit c522bb5

File tree

6 files changed

+163
-134
lines changed

6 files changed

+163
-134
lines changed

include/swift/AST/GenericSignatureBuilder.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,9 +270,18 @@ class GenericSignatureBuilder {
270270
private:
271271
/// \brief Add a new superclass requirement specifying that the given
272272
/// potential archetype has the given type as an ancestor.
273-
bool addSuperclassRequirement(PotentialArchetype *T,
274-
Type Superclass,
275-
const RequirementSource *Source);
273+
bool addSuperclassRequirementDirect(PotentialArchetype *T,
274+
Type Superclass,
275+
const RequirementSource *Source);
276+
277+
/// \brief Add a new type requirement specifying that the given
278+
/// type conforms-to or is a superclass of the second type.
279+
bool addTypeRequirement(UnresolvedType subject,
280+
UnresolvedType constraint,
281+
FloatingRequirementSource source,
282+
Type dependentType,
283+
llvm::SmallPtrSetImpl<ProtocolDecl *> *visited
284+
= nullptr);
276285

277286
/// \brief Add a new conformance requirement specifying that the given
278287
/// potential archetypes are equivalent.

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 146 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -832,9 +832,11 @@ SourceLoc FloatingRequirementSource::getLoc() const {
832832
bool FloatingRequirementSource::isExplicit() const {
833833
switch (kind) {
834834
case Explicit:
835-
case Inferred:
836835
return true;
837836

837+
case Inferred:
838+
return false;
839+
838840
case AbstractProtocol:
839841
switch (storage.get<const RequirementSource *>()->kind) {
840842
case RequirementSource::RequirementSignatureSelf:
@@ -853,13 +855,13 @@ bool FloatingRequirementSource::isExplicit() const {
853855
case Resolved:
854856
switch (storage.get<const RequirementSource *>()->kind) {
855857
case RequirementSource::Explicit:
856-
case RequirementSource::Inferred:
857858
return true;
858859

859860
case RequirementSource::ProtocolRequirement:
860861
return storage.get<const RequirementSource *>()->parent->kind
861862
== RequirementSource::RequirementSignatureSelf;
862863

864+
case RequirementSource::Inferred:
863865
case RequirementSource::RequirementSignatureSelf:
864866
case RequirementSource::Concrete:
865867
case RequirementSource::NestedTypeNameMatch:
@@ -1070,6 +1072,7 @@ struct GenericSignatureBuilder::ResolvedType {
10701072
}
10711073

10721074
bool isType() const { return paOrT.is<Type>(); }
1075+
bool isPotentialArchetype() const { return paOrT.is<PotentialArchetype *>(); }
10731076
};
10741077

10751078
/// If there is a same-type requirement to be added for the given nested type
@@ -2182,6 +2185,13 @@ bool GenericSignatureBuilder::addConformanceRequirement(PotentialArchetype *PAT,
21822185
if (!PAT->addConformance(Proto, Source, *this))
21832186
return false;
21842187

2188+
// FIXME: Ad hoc recursion breaking.
2189+
if (Visited.count(Proto)) {
2190+
markPotentialArchetypeRecursive(PAT, Proto, Source);
2191+
return true;
2192+
}
2193+
2194+
21852195
// Add the requirement to the representative.
21862196
auto T = PAT->getRepresentative();
21872197

@@ -2303,9 +2313,8 @@ bool GenericSignatureBuilder::addLayoutRequirement(
23032313
// If a layout requirement was explicitly written on a concrete type,
23042314
// complain.
23052315
if (source.isExplicit() && source.getLoc().isValid()) {
2306-
// FIXME: TypeLoc() is unfortunate here.
23072316
Diags.diagnose(source.getLoc(), diag::requires_not_suitable_archetype,
2308-
0, TypeLoc(), 0);
2317+
0, TypeLoc::withoutLoc(resolvedSubject->getType()), 0);
23092318
return true;
23102319
}
23112320

@@ -2390,7 +2399,7 @@ bool GenericSignatureBuilder::updateSuperclass(
23902399
return false;
23912400
}
23922401

2393-
bool GenericSignatureBuilder::addSuperclassRequirement(
2402+
bool GenericSignatureBuilder::addSuperclassRequirementDirect(
23942403
PotentialArchetype *T,
23952404
Type superclass,
23962405
const RequirementSource *source) {
@@ -2402,6 +2411,120 @@ bool GenericSignatureBuilder::addSuperclassRequirement(
24022411
return updateSuperclass(T, superclass, source);
24032412
}
24042413

2414+
/// Map an unresolved type to a requirement right-hand-side.
2415+
static GenericSignatureBuilder::RequirementRHS
2416+
toRequirementRHS(GenericSignatureBuilder::UnresolvedType unresolved) {
2417+
if (auto pa = unresolved.dyn_cast<PotentialArchetype *>())
2418+
return pa;
2419+
2420+
return unresolved.dyn_cast<Type>();
2421+
}
2422+
2423+
bool GenericSignatureBuilder::addTypeRequirement(
2424+
UnresolvedType subject,
2425+
UnresolvedType constraint,
2426+
FloatingRequirementSource source,
2427+
Type dependentType,
2428+
llvm::SmallPtrSetImpl<ProtocolDecl *> *visited) {
2429+
// Make sure we always have a "visited" set to pass down.
2430+
SmallPtrSet<ProtocolDecl *, 4> visitedSet;
2431+
if (!visited)
2432+
visited = &visitedSet;
2433+
2434+
// Resolve the constraint.
2435+
auto resolvedConstraint = resolve(constraint, source);
2436+
if (!resolvedConstraint) {
2437+
return recordUnresolvedRequirement(RequirementKind::Conformance, subject,
2438+
toRequirementRHS(constraint), source);
2439+
}
2440+
2441+
// The right-hand side needs to be concrete.
2442+
if (auto constraintPA = resolvedConstraint->getPotentialArchetype()) {
2443+
// The constraint type isn't a statically-known constraint.
2444+
if (source.getLoc().isValid()) {
2445+
auto constraintType =
2446+
constraintPA->getDependentType(Impl->GenericParams,
2447+
/*allowUnresolved=*/true);
2448+
Diags.diagnose(source.getLoc(), diag::requires_not_suitable_archetype,
2449+
1, TypeLoc::withoutLoc(constraintType), 0);
2450+
}
2451+
2452+
return true;
2453+
}
2454+
2455+
// Check whether we have a reasonable constraint type at all.
2456+
auto constraintType = resolvedConstraint->getType();
2457+
assert(constraintType && "Missing constraint type?");
2458+
if (!constraintType->isExistentialType() &&
2459+
!constraintType->getClassOrBoundGenericClass()) {
2460+
if (source.getLoc().isValid() && !constraintType->hasError()) {
2461+
Type subjectType = subject.dyn_cast<Type>();
2462+
if (!subjectType)
2463+
subjectType = subject.get<PotentialArchetype *>()
2464+
->getDependentType(Impl->GenericParams,
2465+
/*allowUnresolved=*/true);
2466+
2467+
Diags.diagnose(source.getLoc(), diag::requires_conformance_nonprotocol,
2468+
TypeLoc::withoutLoc(subjectType),
2469+
TypeLoc::withoutLoc(constraintType));
2470+
}
2471+
2472+
return true;
2473+
}
2474+
2475+
// Resolve the subject. If we can't, delay the constraint.
2476+
auto resolvedSubject = resolve(subject, source);
2477+
if (!resolvedSubject) {
2478+
auto recordedKind =
2479+
constraintType->isExistentialType()
2480+
? RequirementKind::Conformance
2481+
: RequirementKind::Superclass;
2482+
return recordUnresolvedRequirement(recordedKind, subject, constraintType,
2483+
source);
2484+
}
2485+
2486+
// If the resolved subject is a type, we can probably perform diagnostics
2487+
// here.
2488+
if (resolvedSubject->isType()) {
2489+
// One cannot explicitly write a constraint on a concrete type.
2490+
if (source.isExplicit()) {
2491+
if (source.getLoc().isValid()) {
2492+
Diags.diagnose(source.getLoc(), diag::requires_not_suitable_archetype,
2493+
0, TypeLoc::withoutLoc(resolvedSubject->getType()), 0);
2494+
}
2495+
2496+
return true;
2497+
}
2498+
2499+
// FIXME: Check the constraint now.
2500+
return false;
2501+
}
2502+
2503+
auto subjectPA = resolvedSubject->getPotentialArchetype();
2504+
assert(subjectPA && "No potential archetype?");
2505+
2506+
auto resolvedSource = source.getSource(subjectPA, dependentType);
2507+
2508+
// Protocol requirements.
2509+
if (constraintType->isExistentialType()) {
2510+
// FIXME: "Class" or arbitrary layout requirements.
2511+
SmallVector<ProtocolDecl *, 4> protocols;
2512+
(void)constraintType->getExistentialTypeProtocols(protocols);
2513+
bool anyErrors = false;
2514+
for (auto proto : protocols) {
2515+
if (addConformanceRequirement(subjectPA, proto, resolvedSource,
2516+
*visited))
2517+
anyErrors = true;
2518+
}
2519+
2520+
return anyErrors;
2521+
}
2522+
2523+
// Superclass constraint.
2524+
return addSuperclassRequirementDirect(subjectPA, constraintType,
2525+
resolvedSource);
2526+
}
2527+
24052528
void GenericSignatureBuilder::PotentialArchetype::addSameTypeConstraint(
24062529
PotentialArchetype *otherPA,
24072530
const RequirementSource *source) {
@@ -2636,15 +2759,6 @@ bool GenericSignatureBuilder::addSameTypeRequirementBetweenConcrete(
26362759
return !matcher.match(type1, type2);
26372760
}
26382761

2639-
/// Map an unresolved type to a requirement right-hand-side.
2640-
static GenericSignatureBuilder::RequirementRHS
2641-
toRequirementRHS(GenericSignatureBuilder::UnresolvedType unresolved) {
2642-
if (auto pa = unresolved.dyn_cast<PotentialArchetype *>())
2643-
return pa;
2644-
2645-
return unresolved.dyn_cast<Type>();
2646-
}
2647-
26482762
bool GenericSignatureBuilder::addSameTypeRequirement(
26492763
UnresolvedType paOrT1,
26502764
UnresolvedType paOrT2,
@@ -2776,30 +2890,8 @@ bool GenericSignatureBuilder::addInheritedRequirements(
27762890
};
27772891

27782892
// Protocol requirement.
2779-
if (auto protocolType = inheritedType->getAs<ProtocolType>()) {
2780-
if (visited.count(protocolType->getDecl())) {
2781-
markPotentialArchetypeRecursive(
2782-
pa, protocolType->getDecl(),
2783-
getFloatingSource().getSource(pa, dependentType));
2784-
2785-
return true;
2786-
}
2787-
2788-
return addConformanceRequirement(
2789-
pa, protocolType->getDecl(),
2790-
getFloatingSource().getSource(pa, dependentType),
2791-
visited);
2792-
}
2793-
2794-
// Superclass requirement.
2795-
if (inheritedType->getClassOrBoundGenericClass()) {
2796-
return addSuperclassRequirement(
2797-
pa, inheritedType,
2798-
getFloatingSource().getSource(pa, dependentType));
2799-
}
2800-
2801-
// Note: anything else is an error, to be diagnosed later.
2802-
return false;
2893+
return addTypeRequirement(pa, inheritedType, getFloatingSource(),
2894+
dependentType, &visited);
28032895
});
28042896
}
28052897

@@ -2819,48 +2911,16 @@ bool GenericSignatureBuilder::addRequirement(const RequirementRepr *Req,
28192911
return t;
28202912
};
28212913

2822-
28232914
switch (Req->getKind()) {
2824-
case RequirementReprKind::LayoutConstraint: {
2825-
if (addLayoutRequirement(subst(Req->getSubject()),
2826-
Req->getLayoutConstraint(),
2827-
source, Req->getSubject()))
2828-
return true;
2829-
2830-
return false;
2831-
}
2832-
2833-
case RequirementReprKind::TypeConstraint: {
2834-
PotentialArchetype *PA = resolveArchetype(subst(Req->getSubject()));
2835-
if (!PA) {
2836-
// FIXME: Poor location information.
2837-
// FIXME: Delay diagnostic until after type validation?
2838-
Diags.diagnose(Req->getColonLoc(), diag::requires_not_suitable_archetype,
2839-
0, Req->getSubjectLoc(), 0);
2840-
return true;
2841-
}
2915+
case RequirementReprKind::LayoutConstraint:
2916+
return addLayoutRequirement(subst(Req->getSubject()),
2917+
Req->getLayoutConstraint(),
2918+
source, Req->getSubject());
28422919

2843-
// Check whether this is a supertype requirement.
2844-
if (Req->getConstraint()->getClassOrBoundGenericClass()) {
2845-
return addSuperclassRequirement(PA, subst(Req->getConstraint()),
2846-
source.getSource(PA, Req->getSubject()));
2847-
}
2848-
2849-
if (!Req->getConstraint()->isExistentialType()) {
2850-
// FIXME: Diagnose this failure here, rather than over in type-checking.
2851-
return true;
2852-
}
2853-
2854-
// Add each of the protocols.
2855-
SmallVector<ProtocolDecl *, 4> ConformsTo;
2856-
Req->getConstraint()->getExistentialTypeProtocols(ConformsTo);
2857-
for (auto Proto : ConformsTo)
2858-
if (addConformanceRequirement(PA, Proto,
2859-
source.getSource(PA, Req->getSubject())))
2860-
return true;
2861-
2862-
return false;
2863-
}
2920+
case RequirementReprKind::TypeConstraint:
2921+
return addTypeRequirement(subst(Req->getSubject()),
2922+
subst(Req->getConstraint()),
2923+
source, Req->getSubject());
28642924

28652925
case RequirementReprKind::SameType:
28662926
// Require that at least one side of the requirement contain a type
@@ -2908,47 +2968,18 @@ bool GenericSignatureBuilder::addRequirement(
29082968

29092969

29102970
switch (req.getKind()) {
2911-
case RequirementKind::Superclass: {
2912-
// FIXME: Diagnose this.
2913-
PotentialArchetype *pa = resolveArchetype(subst(req.getFirstType()));
2914-
if (!pa) return false;
2915-
2916-
assert(req.getSecondType()->getClassOrBoundGenericClass());
2917-
return addSuperclassRequirement(pa, req.getSecondType(),
2918-
source.getSource(pa, req.getFirstType()));
2919-
}
2920-
2921-
case RequirementKind::Layout: {
2971+
case RequirementKind::Superclass:
2972+
case RequirementKind::Conformance:
2973+
return addTypeRequirement(subst(req.getFirstType()),
2974+
subst(req.getSecondType()),
2975+
source, req.getFirstType(),
2976+
&Visited);
2977+
2978+
case RequirementKind::Layout:
29222979
return addLayoutRequirement(subst(req.getFirstType()),
29232980
req.getLayoutConstraint(),
29242981
source,
29252982
req.getFirstType());
2926-
}
2927-
2928-
case RequirementKind::Conformance: {
2929-
// FIXME: Diagnose this.
2930-
PotentialArchetype *pa = resolveArchetype(subst(req.getFirstType()));
2931-
if (!pa) return false;
2932-
2933-
SmallVector<ProtocolDecl *, 4> conformsTo;
2934-
req.getSecondType()->getExistentialTypeProtocols(conformsTo);
2935-
2936-
// Add each of the protocols.
2937-
for (auto proto : conformsTo) {
2938-
if (Visited.count(proto)) {
2939-
markPotentialArchetypeRecursive(
2940-
pa, proto,
2941-
source.getSource(pa, req.getFirstType()));
2942-
continue;
2943-
}
2944-
if (addConformanceRequirement(pa, proto,
2945-
source.getSource(pa, req.getFirstType()),
2946-
Visited))
2947-
return true;
2948-
}
2949-
2950-
return false;
2951-
}
29522983

29532984
case RequirementKind::SameType:
29542985
return addSameTypeRequirement(

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -373,17 +373,6 @@ bool TypeChecker::validateRequirement(SourceLoc whereLoc, RequirementRepr &req,
373373
req.setInvalid();
374374
}
375375

376-
// FIXME: Feels too early to perform this check.
377-
if (!req.isInvalid() &&
378-
!req.getConstraint()->isExistentialType() &&
379-
!req.getConstraint()->getClassOrBoundGenericClass()) {
380-
diagnose(whereLoc, diag::requires_conformance_nonprotocol,
381-
req.getSubjectLoc(), req.getConstraintLoc());
382-
req.getConstraintLoc().setInvalidType(Context);
383-
req.setInvalid();
384-
return true;
385-
}
386-
387376
return req.isInvalid();
388377
}
389378

0 commit comments

Comments
 (0)