Skip to content

Commit a766e6f

Browse files
authored
Merge pull request #2843 from ahoppen/SR-1236-errors
2 parents f4f8dc7 + 095a68b commit a766e6f

File tree

15 files changed

+132
-125
lines changed

15 files changed

+132
-125
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,9 @@ Swift 3.0
246246
`NS[Mutable]Dictionary` are still imported as nongeneric classes for
247247
the time being.
248248

249+
* [SE-0036](https://github.com/apple/swift-evolution/blob/master/proposals/0036-enum-dot.md):
250+
Enum elements can no longer be accessed as instance members in instance methods.
251+
249252
* As part of the changes for SE-0055 (see below), the *pointee* types of
250253
imported pointers (e.g. the `id` in `id *`) are no longer assumed to always
251254
be `_Nullable` even if annotated otherwise. However, an implicit or explicit

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,8 @@ ERROR(could_not_use_type_member,none,
9393
ERROR(could_not_use_type_member_on_instance,none,
9494
"static member %1 cannot be used on instance of type %0",
9595
(Type, DeclName))
96-
WARNING(could_not_use_enum_element_on_instance,none,
97-
"referencing enum element %0 as instance member is deprecated and will "
98-
"be removed in Swift 3",
96+
ERROR(could_not_use_enum_element_on_instance,none,
97+
"enum element %0 cannot be referenced as an instance member",
9998
(DeclName))
10099
ERROR(could_not_use_type_member_on_existential,none,
101100
"static member %1 cannot be used on protocol metatype %0",

include/swift/AST/Expr.h

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,13 +1031,6 @@ class TypeExpr : public Expr {
10311031
TypeLoc Info;
10321032
TypeExpr(Type Ty);
10331033
public:
1034-
/// Whether this type reference actually references an instance but has been
1035-
/// promoted to a type reference to access an enum element
1036-
///
1037-
/// This is purely transitional and will be removed when referencing enum
1038-
/// elements on instance members becomes an error
1039-
bool IsPromotedInstanceRef = false;
1040-
10411034
// Create a TypeExpr with location information.
10421035
TypeExpr(TypeLoc Ty);
10431036

@@ -1058,8 +1051,7 @@ class TypeExpr : public Expr {
10581051

10591052
/// Return a TypeExpr for a TypeDecl and the specified location.
10601053
static TypeExpr *createForDecl(SourceLoc Loc, TypeDecl *D,
1061-
bool isImplicit,
1062-
bool isPromotedInstanceRef = false);
1054+
bool isImplicit);
10631055
static TypeExpr *createForSpecializedDecl(SourceLoc Loc, TypeDecl *D,
10641056
ArrayRef<TypeRepr*> args,
10651057
SourceRange angleLocs);

include/swift/AST/NameLookup.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,6 @@ struct UnqualifiedLookupResult {
4141
ValueDecl *Value;
4242

4343
public:
44-
/// Whether this should actually reference an instance but has been promoted
45-
/// to a type reference to access an enum element
46-
///
47-
/// This is purely transitional and will be removed when referencing enum
48-
/// elements on instance members becomes an error
49-
bool IsPromotedInstanceRef = false;
50-
5144
UnqualifiedLookupResult(ValueDecl *value) : Base(nullptr), Value(value) { }
5245

5346
UnqualifiedLookupResult(ValueDecl *base, ValueDecl *value)

lib/AST/Expr.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,14 +1345,12 @@ Type TypeExpr::getInstanceType() const {
13451345

13461346
/// Return a TypeExpr for a simple identifier and the specified location.
13471347
TypeExpr *TypeExpr::createForDecl(SourceLoc Loc, TypeDecl *Decl,
1348-
bool isImplicit,
1349-
bool isPromotedInstanceRef) {
1348+
bool isImplicit) {
13501349
ASTContext &C = Decl->getASTContext();
13511350
assert(Loc.isValid());
13521351
auto *Repr = new (C) SimpleIdentTypeRepr(Loc, Decl->getName());
13531352
Repr->setValue(Decl);
13541353
auto result = new (C) TypeExpr(TypeLoc(Repr, Type()));
1355-
result->IsPromotedInstanceRef = isPromotedInstanceRef;
13561354
if (isImplicit)
13571355
result->setImplicit();
13581356
return result;

lib/AST/NameLookup.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -563,11 +563,7 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC,
563563
if (FD->isStatic() && !isMetatypeType)
564564
continue;
565565
} else if (isa<EnumElementDecl>(Result)) {
566-
auto lookupRes = UnqualifiedLookupResult(MetaBaseDecl, Result);
567-
if (!BaseDecl->getType()->is<MetatypeType>()) {
568-
lookupRes.IsPromotedInstanceRef = true;
569-
}
570-
Results.push_back(lookupRes);
566+
Results.push_back(UnqualifiedLookupResult(BaseDecl, Result));
571567
continue;
572568
}
573569

lib/Sema/CSApply.cpp

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2545,24 +2545,6 @@ namespace {
25452545

25462546
public:
25472547
Expr *visitUnresolvedDotExpr(UnresolvedDotExpr *expr) {
2548-
if (auto ty = dyn_cast<TypeExpr>(expr->getBase())) {
2549-
if (ty->IsPromotedInstanceRef) {
2550-
// An enum element was looked up on an instance. Issue a warning
2551-
auto enumMetatype = ty->getType()->castTo<AnyMetatypeType>();
2552-
auto enumType = enumMetatype->getInstanceType()->castTo<EnumType>();
2553-
2554-
SmallString<32> enumTypeName;
2555-
llvm::raw_svector_ostream typeNameStream(enumTypeName);
2556-
typeNameStream << enumType->getDecl()->getName();
2557-
typeNameStream << ".";
2558-
2559-
TypeChecker &tc = cs.getTypeChecker();
2560-
tc.diagnose(expr->getLoc(),
2561-
diag::could_not_use_enum_element_on_instance,
2562-
expr->getName())
2563-
.fixItInsert(expr->getLoc(), typeNameStream.str());
2564-
}
2565-
}
25662548
return applyMemberRefExpr(expr, expr->getBase(), expr->getDotLoc(),
25672549
expr->getNameLoc(), expr->isImplicit());
25682550
}

lib/Sema/CSDiag.cpp

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1859,6 +1859,11 @@ class FailureDiagnosis :public ASTVisitor<FailureDiagnosis, /*exprresult*/bool>{
18591859
/// the exact expression kind).
18601860
bool diagnoseGeneralMemberFailure(Constraint *constraint);
18611861

1862+
/// Diagnose the lookup of an enum element as instance member where only a
1863+
/// static member is allowed
1864+
void diagnoseEnumInstanceMemberLookup(EnumElementDecl *enumElementDecl,
1865+
SourceLoc loc);
1866+
18621867
/// Given a result of name lookup that had no viable results, diagnose the
18631868
/// unviable ones.
18641869
void diagnoseUnviableLookupResults(MemberLookupResult &lookupResults,
@@ -2228,6 +2233,70 @@ bool FailureDiagnosis::diagnoseGeneralMemberFailure(Constraint *constraint) {
22282233
return false;
22292234
}
22302235

2236+
void FailureDiagnosis::
2237+
diagnoseEnumInstanceMemberLookup(EnumElementDecl *enumElementDecl,
2238+
SourceLoc loc) {
2239+
auto diag = diagnose(loc, diag::could_not_use_enum_element_on_instance,
2240+
enumElementDecl->getName());
2241+
auto parentEnum = enumElementDecl->getParentEnum();
2242+
auto enumMetatype = parentEnum->getType()->castTo<AnyMetatypeType>();
2243+
2244+
// Determine the contextual type of the expression
2245+
Type contextualType;
2246+
for (auto iterateCS = CS;
2247+
contextualType.isNull() && iterateCS;
2248+
iterateCS = iterateCS->baseCS) {
2249+
contextualType = iterateCS->getContextualType();
2250+
}
2251+
2252+
// Try to provide a fix-it that only contains a '.'
2253+
if (contextualType) {
2254+
if (enumMetatype->getInstanceType()->isEqual(contextualType)) {
2255+
diag.fixItInsert(loc, ".");
2256+
return;
2257+
}
2258+
}
2259+
2260+
// Check if the expression is the matching operator ~=, most often used in
2261+
// case statements. If so, try to provide a single dot fix-it
2262+
const Expr *contextualTypeNode;
2263+
for (auto iterateCS = CS; iterateCS; iterateCS = iterateCS->baseCS) {
2264+
contextualTypeNode = iterateCS->getContextualTypeNode();
2265+
}
2266+
2267+
// The '~=' operator is an overloaded decl ref inside a binaryExpr
2268+
if (auto binaryExpr = dyn_cast<BinaryExpr>(contextualTypeNode)) {
2269+
if (auto overloadedFn
2270+
= dyn_cast<OverloadedDeclRefExpr>(binaryExpr->getFn())) {
2271+
if (overloadedFn->getDecls().size() > 0) {
2272+
// Fetch any declaration to check if the name is '~='
2273+
ValueDecl *decl0 = overloadedFn->getDecls()[0];
2274+
2275+
if (decl0->getName() == decl0->getASTContext().Id_MatchOperator) {
2276+
assert(binaryExpr->getArg()->getElements().size() == 2);
2277+
2278+
// If the rhs of '~=' is the enum type, a single dot suffices
2279+
// since the type can be inferred
2280+
Type secondArgType = binaryExpr->getArg()->getElement(1)->getType();
2281+
if (secondArgType->isEqual(enumMetatype->getInstanceType())) {
2282+
diag.fixItInsert(loc, ".");
2283+
return;
2284+
}
2285+
}
2286+
}
2287+
}
2288+
}
2289+
2290+
// Fall back to a fix-it with a full type qualifier
2291+
SmallString<32> enumTypeName;
2292+
llvm::raw_svector_ostream typeNameStream(enumTypeName);
2293+
typeNameStream << parentEnum->getName();
2294+
typeNameStream << ".";
2295+
2296+
diag.fixItInsert(loc, typeNameStream.str());
2297+
return;
2298+
}
2299+
22312300

22322301
/// Given a result of name lookup that had no viable results, diagnose the
22332302
/// unviable ones.
@@ -2377,6 +2446,21 @@ diagnoseUnviableLookupResults(MemberLookupResult &result, Type baseObjTy,
23772446
} else {
23782447
// Otherwise the static member lookup was invalid because it was
23792448
// called on an instance
2449+
2450+
// Handle enum element lookup on instance type
2451+
auto lookThroughBaseObjTy = baseObjTy->lookThroughAllAnyOptionalTypes();
2452+
if (lookThroughBaseObjTy->is<EnumType>()
2453+
|| lookThroughBaseObjTy->is<BoundGenericEnumType>()) {
2454+
for (auto cand : result.UnviableCandidates) {
2455+
ValueDecl *decl = cand.first;
2456+
if (auto enumElementDecl = dyn_cast<EnumElementDecl>(decl)) {
2457+
diagnoseEnumInstanceMemberLookup(enumElementDecl, loc);
2458+
return;
2459+
}
2460+
}
2461+
}
2462+
2463+
// Provide diagnostic other static member lookups on instance type
23802464
diagnose(loc, diag::could_not_use_type_member_on_instance,
23812465
baseObjTy, memberName)
23822466
.highlight(baseRange).highlight(nameLoc.getSourceRange());
@@ -3047,7 +3131,7 @@ typeCheckChildIndependently(Expr *subExpr, Type convertType,
30473131
bool hadError = CS->TC.typeCheckExpression(subExpr, CS->DC,
30483132
TypeLoc::withoutLoc(convertType),
30493133
convertTypePurpose, TCEOptions,
3050-
listener);
3134+
listener, CS);
30513135

30523136
// This is a terrible hack to get around the fact that typeCheckExpression()
30533137
// might change subExpr to point to a new OpenExistentialExpr. In that case,

lib/Sema/ConstraintSystem.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,9 @@ class ConstraintSystem {
899899
/// Note: this is only used to support ObjCSelectorExpr at the moment.
900900
llvm::SmallPtrSet<Expr *, 2> UnevaluatedRootExprs;
901901

902+
/// The original CS if this CS was created as a simplification of another CS
903+
ConstraintSystem *baseCS = nullptr;
904+
902905
private:
903906

904907
/// \brief Allocator used for all of the related constraint systems.
@@ -1248,6 +1251,10 @@ class ConstraintSystem {
12481251
return contextualType;
12491252
}
12501253

1254+
const Expr *getContextualTypeNode() const {
1255+
return contextualTypeNode;
1256+
}
1257+
12511258
ContextualTypePurpose getContextualTypePurpose() const {
12521259
return contextualTypePurpose;
12531260
}

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,6 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) {
551551

552552
ResultValues.clear();
553553
bool AllMemberRefs = true;
554-
bool PromotedInstanceRef = false;
555554
ValueDecl *Base = 0;
556555
for (auto Result : Lookup) {
557556
// Track the base for member declarations.
@@ -562,9 +561,6 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) {
562561
break;
563562
}
564563

565-
if (Result.IsPromotedInstanceRef) {
566-
PromotedInstanceRef = true;
567-
}
568564
Base = Result.Base;
569565
continue;
570566
}
@@ -576,8 +572,7 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) {
576572
if (AllMemberRefs) {
577573
Expr *BaseExpr;
578574
if (auto NTD = dyn_cast<NominalTypeDecl>(Base)) {
579-
BaseExpr = TypeExpr::createForDecl(Loc, NTD, /*implicit=*/true,
580-
PromotedInstanceRef);
575+
BaseExpr = TypeExpr::createForDecl(Loc, NTD, /*implicit=*/true);
581576
} else {
582577
BaseExpr = new (Context) DeclRefExpr(Base, UDRE->getNameLoc(),
583578
/*implicit=*/true);
@@ -1421,14 +1416,16 @@ bool TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
14211416
TypeLoc convertType,
14221417
ContextualTypePurpose convertTypePurpose,
14231418
TypeCheckExprOptions options,
1424-
ExprTypeCheckListener *listener) {
1419+
ExprTypeCheckListener *listener,
1420+
ConstraintSystem *baseCS) {
14251421
PrettyStackTraceExpr stackTrace(Context, "type-checking", expr);
14261422

14271423
// Construct a constraint system from this expression.
14281424
ConstraintSystemOptions csOptions = ConstraintSystemFlags::AllowFixes;
14291425
if (options.contains(TypeCheckExprFlags::PreferForceUnwrapToOptional))
14301426
csOptions |= ConstraintSystemFlags::PreferForceUnwrapToOptional;
14311427
ConstraintSystem cs(*this, dc, csOptions);
1428+
cs.baseCS = baseCS;
14321429
CleanupIllFormedExpressionRAII cleanup(Context, expr);
14331430
ExprCleanser cleanup2(expr);
14341431

lib/Sema/TypeCheckNameLookup.cpp

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,7 @@ namespace {
103103
///
104104
/// \param foundInType The type through which we found the
105105
/// declaration.
106-
///
107-
/// \param promotedInstanceRef true if the lookup result to be added was
108-
/// actually looked up on an instance but promted to a type to look up an
109-
/// enum element
110-
void add(ValueDecl *found, ValueDecl *base, Type foundInType,
111-
bool promotedInstanceRef = false) {
106+
void add(ValueDecl *found, ValueDecl *base, Type foundInType) {
112107
// If we only want types, AST name lookup should not yield anything else.
113108
assert(!Options.contains(NameLookupFlags::OnlyTypes) ||
114109
isa<TypeDecl>(found));
@@ -144,7 +139,7 @@ namespace {
144139
isa<GenericTypeParamDecl>(found) ||
145140
(isa<FuncDecl>(found) && cast<FuncDecl>(found)->isOperator())) {
146141
if (Known.insert({{found, base}, false}).second) {
147-
Result.add({found, base, promotedInstanceRef});
142+
Result.add({found, base});
148143
FoundDecls.push_back(found);
149144
}
150145
return;
@@ -177,7 +172,7 @@ namespace {
177172
// default implementations in protocols.
178173
if (witness && !isa<ProtocolDecl>(witness->getDeclContext())) {
179174
if (Known.insert({{witness, base}, false}).second) {
180-
Result.add({witness, base, promotedInstanceRef});
175+
Result.add({witness, base});
181176
FoundDecls.push_back(witness);
182177
}
183178
}
@@ -234,8 +229,7 @@ LookupResult TypeChecker::lookupUnqualified(DeclContext *dc, DeclName name,
234229
assert(foundInType && "bogus base declaration?");
235230
}
236231

237-
builder.add(found.getValueDecl(), found.getBaseDecl(), foundInType,
238-
found.IsPromotedInstanceRef);
232+
builder.add(found.getValueDecl(), found.getBaseDecl(), foundInType);
239233
}
240234
return result;
241235
}
@@ -572,7 +566,7 @@ void TypeChecker::performTypoCorrection(DeclContext *DC, DeclRefKind refKind,
572566
entries.filterMaxScoreRange(MaxCallEditDistanceFromBestCandidate);
573567

574568
for (auto &entry : entries)
575-
result.add({ entry.Value, nullptr, false });
569+
result.add({ entry.Value, nullptr });
576570
}
577571

578572
static InFlightDiagnostic

0 commit comments

Comments
 (0)