Skip to content

Commit c141c48

Browse files
authored
Merge pull request #24797 from slavapestov/more-type-checked-accessors
More type checked accessors
2 parents 82928fd + 86f9ca7 commit c141c48

File tree

14 files changed

+292
-425
lines changed

14 files changed

+292
-425
lines changed

include/swift/AST/ProtocolConformanceRef.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ namespace llvm {
2828

2929
namespace swift {
3030

31+
class ConcreteDeclRef;
3132
class ProtocolConformance;
3233

3334
/// A ProtocolConformanceRef is a handle to a protocol conformance which
@@ -135,10 +136,15 @@ class ProtocolConformanceRef {
135136
return llvm::hash_value(conformance.Union.getOpaqueValue());
136137
}
137138

138-
static Type
139-
getTypeWitnessByName(Type type,
140-
ProtocolConformanceRef conformance,
141-
Identifier name);
139+
Type getTypeWitnessByName(Type type, Identifier name) const;
140+
141+
/// Find a particular named function witness for a type that conforms to
142+
/// the given protocol.
143+
///
144+
/// \param type The conforming type.
145+
///
146+
/// \param name The name of the requirement.
147+
ConcreteDeclRef getWitnessByName(Type type, DeclName name) const;
142148

143149
/// Determine whether this conformance is canonical.
144150
bool isCanonical() const;

lib/AST/ASTContext.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4225,8 +4225,7 @@ Type ASTContext::getBridgedToObjC(const DeclContext *dc, Type type,
42254225
*bridgedValueType = type;
42264226

42274227
// Find the Objective-C class type we bridge to.
4228-
return ProtocolConformanceRef::getTypeWitnessByName(
4229-
type, *conformance, Id_ObjectiveCType);
4228+
return conformance->getTypeWitnessByName(type, Id_ObjectiveCType);
42304229
}
42314230

42324231
// Do we conform to Error?

lib/AST/ProtocolConformance.cpp

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,15 +142,14 @@ ProtocolConformanceRef::subst(Type origType,
142142
}
143143

144144
Type
145-
ProtocolConformanceRef::getTypeWitnessByName(Type type,
146-
ProtocolConformanceRef conformance,
147-
Identifier name) {
148-
assert(!conformance.isInvalid());
145+
ProtocolConformanceRef::getTypeWitnessByName(Type type, Identifier name) const {
146+
assert(!isInvalid());
149147

150148
// Find the named requirement.
151-
ProtocolDecl *proto = conformance.getRequirement();
149+
ProtocolDecl *proto = getRequirement();
152150
AssociatedTypeDecl *assocType = nullptr;
153-
auto members = proto->lookupDirect(name);
151+
auto members = proto->lookupDirect(name,
152+
NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions);
154153
for (auto member : members) {
155154
assocType = dyn_cast<AssociatedTypeDecl>(member);
156155
if (assocType)
@@ -162,7 +161,35 @@ ProtocolConformanceRef::getTypeWitnessByName(Type type,
162161
return nullptr;
163162

164163
return assocType->getDeclaredInterfaceType().subst(
165-
SubstitutionMap::getProtocolSubstitutions(proto, type, conformance));
164+
SubstitutionMap::getProtocolSubstitutions(proto, type, *this));
165+
}
166+
167+
ConcreteDeclRef
168+
ProtocolConformanceRef::getWitnessByName(Type type, DeclName name) const {
169+
// Find the named requirement.
170+
auto *proto = getRequirement();
171+
auto results =
172+
proto->lookupDirect(name,
173+
NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions);
174+
175+
ValueDecl *requirement = nullptr;
176+
for (auto *result : results) {
177+
if (isa<ProtocolDecl>(result->getDeclContext()))
178+
requirement = result;
179+
}
180+
181+
if (requirement == nullptr)
182+
return ConcreteDeclRef();
183+
184+
// For a type with dependent conformance, just return the requirement from
185+
// the protocol. There are no protocol conformance tables.
186+
if (!isConcrete()) {
187+
auto subs = SubstitutionMap::getProtocolSubstitutions(proto, type, *this);
188+
return ConcreteDeclRef(requirement, subs);
189+
}
190+
191+
auto *resolver = proto->getASTContext().getLazyResolver();
192+
return getConcrete()->getWitnessDeclRef(requirement, resolver);
166193
}
167194

168195
void *ProtocolConformance::operator new(size_t bytes, ASTContext &context,

lib/PrintAsObjC/PrintAsObjC.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,10 +1377,9 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
13771377

13781378
// Dig out the Objective-C type.
13791379
auto conformance = conformances.front();
1380-
Type objcType = ProtocolConformanceRef::getTypeWitnessByName(
1381-
nominal->getDeclaredType(),
1382-
ProtocolConformanceRef(conformance),
1383-
ctx.Id_ObjectiveCType);
1380+
Type objcType = ProtocolConformanceRef(conformance).getTypeWitnessByName(
1381+
nominal->getDeclaredType(),
1382+
ctx.Id_ObjectiveCType);
13841383
if (!objcType) return nullptr;
13851384

13861385
// Dig out the Objective-C class.

lib/SIL/Bridging.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,8 @@ Type TypeConverter::getLoweredCBridgedType(AbstractionPattern pattern,
223223
auto conformance = foreignRepresentation.second;
224224
assert(conformance && "Missing conformance?");
225225
Type bridgedTy =
226-
ProtocolConformanceRef::getTypeWitnessByName(
227-
t, ProtocolConformanceRef(conformance),
228-
M.getASTContext().Id_ObjectiveCType);
226+
ProtocolConformanceRef(conformance).getTypeWitnessByName(
227+
t, M.getASTContext().Id_ObjectiveCType);
229228
assert(bridgedTy && "Missing _ObjectiveCType witness?");
230229
if (purpose == BridgedTypePurpose::ForResult && clangTy)
231230
bridgedTy = OptionalType::get(bridgedTy);

lib/Sema/CSApply.cpp

Lines changed: 23 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -99,67 +99,6 @@ SubstitutionMap Solution::computeSubstitutions(
9999
lookupConformanceFn);
100100
}
101101

102-
/// Find a particular named function witness for a type that conforms to
103-
/// the given protocol.
104-
///
105-
/// \param tc The type check we're using.
106-
///
107-
/// \param dc The context in which we need a witness.
108-
///
109-
/// \param type The type whose witness to find.
110-
///
111-
/// \param proto The protocol to which the type conforms.
112-
///
113-
/// \param name The name of the requirement.
114-
///
115-
/// \param diag The diagnostic to emit if the protocol definition doesn't
116-
/// have a requirement with the given name.
117-
///
118-
/// \returns The named witness, or an empty ConcreteDeclRef if no witness
119-
/// could be found.
120-
ConcreteDeclRef findNamedWitnessImpl(
121-
TypeChecker &tc, DeclContext *dc, Type type,
122-
ProtocolDecl *proto, DeclName name,
123-
Diag<> diag,
124-
Optional<ProtocolConformanceRef> conformance = None) {
125-
// Find the named requirement.
126-
ValueDecl *requirement = nullptr;
127-
for (auto member : proto->getMembers()) {
128-
auto d = dyn_cast<ValueDecl>(member);
129-
if (!d || !d->hasName())
130-
continue;
131-
132-
if (d->getFullName().matchesRef(name)) {
133-
requirement = d;
134-
break;
135-
}
136-
}
137-
138-
if (!requirement || requirement->isInvalid()) {
139-
tc.diagnose(proto->getLoc(), diag);
140-
return nullptr;
141-
}
142-
143-
// Find the member used to satisfy the named requirement.
144-
if (!conformance) {
145-
conformance = tc.conformsToProtocol(type, proto, dc,
146-
ConformanceCheckFlags::InExpression);
147-
if (!conformance)
148-
return nullptr;
149-
}
150-
151-
// For a type with dependent conformance, just return the requirement from
152-
// the protocol. There are no protocol conformance tables.
153-
if (!conformance->isConcrete()) {
154-
auto subMap = SubstitutionMap::getProtocolSubstitutions(proto, type,
155-
*conformance);
156-
return ConcreteDeclRef(requirement, subMap);
157-
}
158-
159-
auto concrete = conformance->getConcrete();
160-
return concrete->getWitnessDeclRef(requirement, &tc);
161-
}
162-
163102
static bool shouldAccessStorageDirectly(Expr *base, VarDecl *member,
164103
DeclContext *DC) {
165104
// This only matters for stored properties.
@@ -2974,10 +2913,8 @@ namespace {
29742913

29752914
DeclName name(tc.Context, DeclBaseName::createConstructor(),
29762915
{ tc.Context.Id_arrayLiteral });
2977-
29782916
ConcreteDeclRef witness =
2979-
findNamedWitnessImpl(tc, dc, arrayTy->getRValueType(), arrayProto,
2980-
name, diag::array_protocol_broken, conformance);
2917+
conformance->getWitnessByName(arrayTy->getRValueType(), name);
29812918
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
29822919
return nullptr;
29832920
expr->setInitializer(witness);
@@ -3330,8 +3267,20 @@ namespace {
33303267
return nullptr;
33313268

33323269
// Extract a Bool from the resulting expression.
3333-
return solution.convertOptionalToBool(result,
3334-
cs.getConstraintLocator(expr));
3270+
tc.requireOptionalIntrinsics(expr->getLoc());
3271+
3272+
// Match the optional value against its `Some` case.
3273+
auto &ctx = tc.Context;
3274+
auto *someDecl = tc.Context.getOptionalSomeDecl();
3275+
auto isSomeExpr = new (tc.Context) EnumIsCaseExpr(result, someDecl);
3276+
auto boolDecl = ctx.getBoolDecl();
3277+
3278+
if (!boolDecl) {
3279+
tc.diagnose(SourceLoc(), diag::broken_bool);
3280+
}
3281+
3282+
cs.setType(isSomeExpr, boolDecl ? boolDecl->getDeclaredType() : Type());
3283+
return isSomeExpr;
33353284
}
33363285

33373286
return expr;
@@ -3973,10 +3922,7 @@ namespace {
39733922
}
39743923

39753924
Expr *visitLazyInitializerExpr(LazyInitializerExpr *expr) {
3976-
// Since `LazyInitializerExpr` should always have a type set,
3977-
// there is no need to do anything here.
3978-
assert(cs.getType(expr)->isEqual(expr->getSubExpr()->getType()));
3979-
return expr;
3925+
llvm_unreachable("Already type-checked");
39803926
}
39813927

39823928
Expr *visitEditorPlaceholderExpr(EditorPlaceholderExpr *E) {
@@ -6845,10 +6791,8 @@ Expr *ExprRewriter::convertLiteralInPlace(Expr *literal,
68456791

68466792
// Find the witness that we'll use to initialize the type via a builtin
68476793
// literal.
6848-
auto witness = findNamedWitnessImpl(
6849-
tc, dc, type->getRValueType(), builtinProtocol,
6850-
builtinLiteralFuncName, brokenBuiltinProtocolDiag,
6851-
*builtinConformance);
6794+
auto witness = builtinConformance->getWitnessByName(type->getRValueType(),
6795+
builtinLiteralFuncName);
68526796
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
68536797
return nullptr;
68546798

@@ -6896,10 +6840,8 @@ Expr *ExprRewriter::convertLiteralInPlace(Expr *literal,
68966840
}
68976841

68986842
// Find the witness that we'll use to initialize the literal value.
6899-
auto witness = findNamedWitnessImpl(
6900-
tc, dc, type->getRValueType(), protocol,
6901-
literalFuncName, brokenProtocolDiag,
6902-
conformance);
6843+
auto witness = conformance->getWitnessByName(type->getRValueType(),
6844+
literalFuncName);
69036845
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
69046846
return nullptr;
69056847

@@ -7743,10 +7685,9 @@ Expr *TypeChecker::callWitness(Expr *base, DeclContext *dc,
77437685

77447686
if (auto metaType = type->getAs<AnyMetatypeType>())
77457687
type = metaType->getInstanceType();
7746-
7747-
auto witness = findNamedWitnessImpl(
7748-
*this, dc, type->getRValueType(), protocol,
7749-
name, brokenProtocolDiag);
7688+
7689+
// Find the member used to satisfy the named requirement.
7690+
auto witness = conformance.getWitnessByName(type, name);
77507691
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
77517692
return nullptr;
77527693

@@ -7853,22 +7794,3 @@ Expr *TypeChecker::callWitness(Expr *base, DeclContext *dc,
78537794
rewriter.finalize(result);
78547795
return result;
78557796
}
7856-
7857-
Expr *Solution::convertOptionalToBool(Expr *expr,
7858-
ConstraintLocator *locator) const {
7859-
auto &cs = getConstraintSystem();
7860-
auto &tc = cs.getTypeChecker();
7861-
tc.requireOptionalIntrinsics(expr->getLoc());
7862-
7863-
// Match the optional value against its `Some` case.
7864-
auto &ctx = tc.Context;
7865-
auto isSomeExpr = new (ctx) EnumIsCaseExpr(expr, ctx.getOptionalSomeDecl());
7866-
auto boolDecl = ctx.getBoolDecl();
7867-
7868-
if (!boolDecl) {
7869-
tc.diagnose(SourceLoc(), diag::broken_bool);
7870-
}
7871-
7872-
cs.setType(isSomeExpr, boolDecl ? boolDecl->getDeclaredType() : Type());
7873-
return isSomeExpr;
7874-
}

lib/Sema/CSDiag.cpp

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1740,8 +1740,8 @@ static Type isRawRepresentable(Type fromType, const ConstraintSystem &CS) {
17401740
if (!conformance)
17411741
return Type();
17421742

1743-
Type rawTy = ProtocolConformanceRef::getTypeWitnessByName(
1744-
fromType, *conformance, CS.getASTContext().Id_RawValue);
1743+
Type rawTy = conformance->getTypeWitnessByName(
1744+
fromType, CS.getASTContext().Id_RawValue);
17451745
return rawTy;
17461746
}
17471747

@@ -2119,9 +2119,9 @@ bool FailureDiagnosis::diagnoseContextualConversionError(
21192119
ConformanceCheckFlags::InExpression)) {
21202120
Type errorCodeType = CS.getType(expr);
21212121
Type errorType =
2122-
ProtocolConformanceRef::getTypeWitnessByName(errorCodeType, *conformance,
2123-
TC.Context.Id_ErrorType)
2124-
->getCanonicalType();
2122+
conformance->getTypeWitnessByName(errorCodeType,
2123+
TC.Context.Id_ErrorType)
2124+
->getCanonicalType();
21252125
if (errorType) {
21262126
auto diag = diagnose(expr->getLoc(), diag::cannot_throw_error_code,
21272127
errorCodeType, errorType);
@@ -6253,9 +6253,8 @@ bool FailureDiagnosis::visitArrayExpr(ArrayExpr *E) {
62536253
= CS.TC.conformsToProtocol(contextualType, ALC, CS.DC,
62546254
ConformanceCheckFlags::InExpression)) {
62556255
Type contextualElementType =
6256-
ProtocolConformanceRef::getTypeWitnessByName(
6257-
contextualType, *Conformance,
6258-
CS.getASTContext().Id_ArrayLiteralElement)
6256+
Conformance->getTypeWitnessByName(
6257+
contextualType, CS.getASTContext().Id_ArrayLiteralElement)
62596258
->getDesugaredType();
62606259

62616260
// Type check each of the subexpressions in place, passing down the contextual
@@ -6343,13 +6342,13 @@ bool FailureDiagnosis::visitDictionaryExpr(DictionaryExpr *E) {
63436342
}
63446343

63456344
contextualKeyType =
6346-
ProtocolConformanceRef::getTypeWitnessByName(
6347-
contextualType, *Conformance, CS.getASTContext().Id_Key)
6345+
Conformance->getTypeWitnessByName(
6346+
contextualType, CS.getASTContext().Id_Key)
63486347
->getDesugaredType();
63496348

63506349
contextualValueType =
6351-
ProtocolConformanceRef::getTypeWitnessByName(
6352-
contextualType, *Conformance, CS.getASTContext().Id_Value)
6350+
Conformance->getTypeWitnessByName(
6351+
contextualType, CS.getASTContext().Id_Value)
63536352
->getDesugaredType();
63546353

63556354
assert(contextualKeyType && contextualValueType &&

lib/Sema/CSGen.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2887,9 +2887,7 @@ namespace {
28872887
}
28882888

28892889
Type visitLazyInitializerExpr(LazyInitializerExpr *expr) {
2890-
auto type = expr->getType();
2891-
assert(type && "LazyInitializerExpr should always have type set");
2892-
return type;
2890+
llvm_unreachable("Already type-checked");
28932891
}
28942892

28952893
Type visitEditorPlaceholderExpr(EditorPlaceholderExpr *E) {

0 commit comments

Comments
 (0)