Strip TypeLoc from EnumElementPattern

This commit is contained in:
Robert Widmann
2020-06-10 13:15:10 -07:00
parent fc9070c072
commit 2371e5c260
12 changed files with 159 additions and 126 deletions

View File

@@ -24,7 +24,6 @@
#include "swift/Basic/LLVM.h"
#include "swift/AST/Type.h"
#include "swift/AST/Types.h"
#include "swift/AST/TypeLoc.h"
#include "swift/AST/TypeAlignments.h"
#include "swift/Basic/InlineBitfield.h"
#include "swift/Basic/OptionSet.h"
@@ -35,6 +34,7 @@ namespace swift {
class Expr;
enum class CheckedCastKind : unsigned;
class TypeExpr;
class TypeLoc;
/// PatternKind - The classification of different kinds of
/// value-matching pattern.
@@ -503,7 +503,7 @@ public:
/// case, then the value is extracted. If there is a subpattern, it is then
/// matched against the associated value for the case.
class EnumElementPattern : public Pattern {
TypeLoc ParentType;
TypeExpr *ParentType;
SourceLoc DotLoc;
DeclNameLoc NameLoc;
DeclNameRef Name;
@@ -511,27 +511,23 @@ class EnumElementPattern : public Pattern {
Pattern /*nullable*/ *SubPattern;
public:
EnumElementPattern(TypeLoc ParentType, SourceLoc DotLoc, DeclNameLoc NameLoc,
DeclNameRef Name, EnumElementDecl *Element,
Pattern *SubPattern)
: Pattern(PatternKind::EnumElement),
ParentType(ParentType), DotLoc(DotLoc), NameLoc(NameLoc), Name(Name),
ElementDeclOrUnresolvedOriginalExpr(Element),
SubPattern(SubPattern) { }
EnumElementPattern(TypeExpr *ParentType, SourceLoc DotLoc,
DeclNameLoc NameLoc, DeclNameRef Name,
EnumElementDecl *Element, Pattern *SubPattern)
: Pattern(PatternKind::EnumElement), ParentType(ParentType),
DotLoc(DotLoc), NameLoc(NameLoc), Name(Name),
ElementDeclOrUnresolvedOriginalExpr(Element), SubPattern(SubPattern) {
assert(ParentType && "Missing parent type?");
}
/// Create an unresolved EnumElementPattern for a `.foo` pattern relying on
/// contextual type.
EnumElementPattern(SourceLoc DotLoc,
DeclNameLoc NameLoc,
DeclNameRef Name,
Pattern *SubPattern,
Expr *UnresolvedOriginalExpr)
: Pattern(PatternKind::EnumElement),
ParentType(), DotLoc(DotLoc), NameLoc(NameLoc), Name(Name),
EnumElementPattern(SourceLoc DotLoc, DeclNameLoc NameLoc, DeclNameRef Name,
Pattern *SubPattern, Expr *UnresolvedOriginalExpr)
: Pattern(PatternKind::EnumElement), ParentType(nullptr), DotLoc(DotLoc),
NameLoc(NameLoc), Name(Name),
ElementDeclOrUnresolvedOriginalExpr(UnresolvedOriginalExpr),
SubPattern(SubPattern) {
}
SubPattern(SubPattern) {}
bool hasSubPattern() const { return SubPattern; }
@@ -543,10 +539,6 @@ public:
return SubPattern;
}
bool isParentTypeImplicit() {
return !ParentType.hasLocation();
}
void setSubPattern(Pattern *p) { SubPattern = p; }
DeclNameRef getName() const { return Name; }
@@ -567,21 +559,14 @@ public:
DeclNameLoc getNameLoc() const { return NameLoc; }
SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); }
SourceLoc getStartLoc() const {
return ParentType.hasLocation() ? ParentType.getSourceRange().Start :
DotLoc.isValid() ? DotLoc
: NameLoc.getBaseNameLoc();
}
SourceLoc getEndLoc() const {
if (SubPattern && SubPattern->getSourceRange().isValid()) {
return SubPattern->getSourceRange().End;
}
return NameLoc.getEndLoc();
}
SourceLoc getStartLoc() const;
SourceLoc getEndLoc() const;
SourceRange getSourceRange() const { return {getStartLoc(), getEndLoc()}; }
TypeLoc &getParentType() { return ParentType; }
TypeLoc getParentType() const { return ParentType; }
TypeRepr *getParentTypeRepr() const;
void setParentType(Type ty);
Type getParentType() const;
static bool classof(const Pattern *P) {
return P->getKind() == PatternKind::EnumElement;

View File

@@ -514,8 +514,7 @@ namespace {
void visitEnumElementPattern(EnumElementPattern *P) {
printCommon(P, "pattern_enum_element");
OS << ' ';
P->getParentType().getType().print(
PrintWithColorRAII(OS, TypeColor).getOS());
P->getParentType().print(PrintWithColorRAII(OS, TypeColor).getOS());
PrintWithColorRAII(OS, IdentifierColor) << '.' << P->getName();
if (P->hasSubPattern()) {
OS << '\n';

View File

@@ -1698,8 +1698,8 @@ Pattern *Traversal::visitIsPattern(IsPattern *P) {
}
Pattern *Traversal::visitEnumElementPattern(EnumElementPattern *P) {
if (!P->isParentTypeImplicit())
if (doIt(P->getParentType()))
if (auto *TR = P->getParentTypeRepr())
if (doIt(TR))
return nullptr;
if (!P->hasSubPattern())

View File

@@ -466,6 +466,7 @@ SourceRange IsPattern::getSourceRange() const {
Type IsPattern::getCastType() const { return CastType->getInstanceType(); }
void IsPattern::setCastType(Type type) {
assert(type);
CastType->setType(MetatypeType::get(type));
}
@@ -479,6 +480,40 @@ ExprPattern::ExprPattern(Expr *e, bool isResolved, Expr *matchExpr,
assert(!matchExpr || e->isImplicit() == matchExpr->isImplicit());
}
SourceLoc EnumElementPattern::getStartLoc() const {
return (ParentType && !ParentType->isImplicit())
? ParentType->getSourceRange().Start
: DotLoc.isValid() ? DotLoc : NameLoc.getBaseNameLoc();
}
SourceLoc EnumElementPattern::getEndLoc() const {
if (SubPattern && SubPattern->getSourceRange().isValid()) {
return SubPattern->getSourceRange().End;
}
return NameLoc.getEndLoc();
}
TypeRepr *EnumElementPattern::getParentTypeRepr() const {
if (!ParentType)
return nullptr;
return ParentType->getTypeRepr();
}
Type EnumElementPattern::getParentType() const {
if (!ParentType)
return Type();
return ParentType->getInstanceType();
}
void EnumElementPattern::setParentType(Type type) {
assert(type);
if (ParentType) {
ParentType->setType(MetatypeType::get(type));
} else {
ParentType = TypeExpr::createImplicit(type, type->getASTContext());
}
}
SourceLoc ExprPattern::getLoc() const {
return getSubExpr()->getLoc();
}

View File

@@ -1481,11 +1481,6 @@ namespace {
Type resolveTypeReferenceInExpression(TypeRepr *repr,
TypeResolverContext resCtx) {
TypeLoc loc(repr);
return resolveTypeReferenceInExpression(loc, resCtx);
}
Type resolveTypeReferenceInExpression(TypeLoc &loc,
TypeResolverContext resCtx) {
TypeResolutionOptions options(resCtx);
options |= TypeResolutionFlags::AllowUnboundGenerics;
bool hadError = TypeChecker::validateType(
@@ -2581,10 +2576,16 @@ namespace {
CS.getConstraintLocator(locator),
TVO_CanBindToLValue | TVO_CanBindToNoEscape);
FunctionRefKind functionRefKind = FunctionRefKind::Compound;
if (!enumPattern->getParentType().isNull()) {
if (enumPattern->getParentType() || enumPattern->getParentTypeRepr()) {
// Resolve the parent type.
Type parentType = resolveTypeReferenceInExpression(
enumPattern->getParentType(), TypeResolverContext::InExpression);
Type parentType = [&]() -> Type {
if (auto preTy = enumPattern->getParentType()) {
return preTy;
}
return resolveTypeReferenceInExpression(
enumPattern->getParentTypeRepr(),
TypeResolverContext::InExpression);
}();
if (!parentType)
return Type();

View File

@@ -212,8 +212,8 @@ deriveBodyCodingKey_enum_stringValue(AbstractFunctionDecl *strValDecl, void *) {
} else {
SmallVector<ASTNode, 4> cases;
for (auto *elt : elements) {
auto *pat = new (C) EnumElementPattern(TypeLoc::withoutLoc(enumType),
SourceLoc(), DeclNameLoc(),
auto *baseTE = TypeExpr::createImplicit(enumType, C);
auto *pat = new (C) EnumElementPattern(baseTE, SourceLoc(), DeclNameLoc(),
DeclNameRef(), elt, nullptr);
pat->setImplicit();

View File

@@ -137,20 +137,20 @@ deriveBodyComparable_enum_hasAssociatedValues_lt(AbstractFunctionDecl *ltDecl, v
SmallVector<VarDecl*, 4> lhsPayloadVars;
auto lhsSubpattern = DerivedConformance::enumElementPayloadSubpattern(elt, 'l', ltDecl,
lhsPayloadVars);
auto lhsElemPat = new (C) EnumElementPattern(TypeLoc::withoutLoc(enumType),
SourceLoc(), DeclNameLoc(),
DeclNameRef(), elt,
lhsSubpattern);
auto *lhsBaseTE = TypeExpr::createImplicit(enumType, C);
auto lhsElemPat =
new (C) EnumElementPattern(lhsBaseTE, SourceLoc(), DeclNameLoc(),
DeclNameRef(), elt, lhsSubpattern);
lhsElemPat->setImplicit();
// .<elt>(let r0, let r1, ...)
SmallVector<VarDecl*, 4> rhsPayloadVars;
auto rhsSubpattern = DerivedConformance::enumElementPayloadSubpattern(elt, 'r', ltDecl,
rhsPayloadVars);
auto rhsElemPat = new (C) EnumElementPattern(TypeLoc::withoutLoc(enumType),
SourceLoc(), DeclNameLoc(),
DeclNameRef(), elt,
rhsSubpattern);
auto *rhsBaseTE = TypeExpr::createImplicit(enumType, C);
auto rhsElemPat =
new (C) EnumElementPattern(rhsBaseTE, SourceLoc(), DeclNameLoc(),
DeclNameRef(), elt, rhsSubpattern);
rhsElemPat->setImplicit();
auto hasBoundDecls = !lhsPayloadVars.empty();

View File

@@ -259,20 +259,20 @@ deriveBodyEquatable_enum_hasAssociatedValues_eq(AbstractFunctionDecl *eqDecl,
SmallVector<VarDecl*, 3> lhsPayloadVars;
auto lhsSubpattern = DerivedConformance::enumElementPayloadSubpattern(elt, 'l', eqDecl,
lhsPayloadVars);
auto lhsElemPat = new (C) EnumElementPattern(TypeLoc::withoutLoc(enumType),
SourceLoc(), DeclNameLoc(),
DeclNameRef(), elt,
lhsSubpattern);
auto *lhsBaseTE = TypeExpr::createImplicit(enumType, C);
auto lhsElemPat =
new (C) EnumElementPattern(lhsBaseTE, SourceLoc(), DeclNameLoc(),
DeclNameRef(), elt, lhsSubpattern);
lhsElemPat->setImplicit();
// .<elt>(let r0, let r1, ...)
SmallVector<VarDecl*, 3> rhsPayloadVars;
auto rhsSubpattern = DerivedConformance::enumElementPayloadSubpattern(elt, 'r', eqDecl,
rhsPayloadVars);
auto rhsElemPat = new (C) EnumElementPattern(TypeLoc::withoutLoc(enumType),
SourceLoc(), DeclNameLoc(),
DeclNameRef(), elt,
rhsSubpattern);
auto *rhsBaseTE = TypeExpr::createImplicit(enumType, C);
auto rhsElemPat =
new (C) EnumElementPattern(rhsBaseTE, SourceLoc(), DeclNameLoc(),
DeclNameRef(), elt, rhsSubpattern);
rhsElemPat->setImplicit();
auto hasBoundDecls = !lhsPayloadVars.empty();
@@ -748,12 +748,12 @@ deriveBodyHashable_enum_hasAssociatedValues_hashInto(
// case A, B(Int), C(String, Int)
// @derived func hash(into hasher: inout Hasher) {
// switch self {
// case A:
// case .A:
// hasher.combine(0)
// case B(let a0):
// case .B(let a0):
// hasher.combine(1)
// hasher.combine(a0)
// case C(let a0, let a1):
// case .C(let a0, let a1):
// hasher.combine(2)
// hasher.combine(a0)
// hasher.combine(a1)
@@ -783,10 +783,9 @@ deriveBodyHashable_enum_hasAssociatedValues_hashInto(
auto payloadPattern = DerivedConformance::enumElementPayloadSubpattern(elt, 'a', hashIntoDecl,
payloadVars);
auto pat = new (C) EnumElementPattern(TypeLoc::withoutLoc(enumType),
SourceLoc(), DeclNameLoc(),
DeclNameRef(elt->getBaseIdentifier()),
elt, payloadPattern);
auto pat = new (C) EnumElementPattern(
TypeExpr::createImplicit(enumType, C), SourceLoc(), DeclNameLoc(),
DeclNameRef(elt->getBaseIdentifier()), elt, payloadPattern);
pat->setImplicit();
auto labelItem = CaseLabelItem(pat);

View File

@@ -108,9 +108,9 @@ deriveBodyRawRepresentable_raw(AbstractFunctionDecl *toRawDecl, void *) {
SmallVector<ASTNode, 4> cases;
for (auto elt : enumDecl->getAllElements()) {
auto pat = new (C) EnumElementPattern(TypeLoc::withoutLoc(enumType),
SourceLoc(), DeclNameLoc(),
DeclNameRef(), elt, nullptr);
auto pat = new (C)
EnumElementPattern(TypeExpr::createImplicit(enumType, C), SourceLoc(),
DeclNameLoc(), DeclNameRef(), elt, nullptr);
pat->setImplicit();
auto labelItem = CaseLabelItem(pat);

View File

@@ -548,9 +548,9 @@ DeclRefExpr *DerivedConformance::convertEnumToIndex(SmallVectorImpl<ASTNode> &st
SmallVector<ASTNode, 4> cases;
for (auto elt : enumDecl->getAllElements()) {
// generate: case .<Case>:
auto pat = new (C) EnumElementPattern(TypeLoc::withoutLoc(enumType),
SourceLoc(), DeclNameLoc(),
DeclNameRef(), elt, nullptr);
auto pat = new (C)
EnumElementPattern(TypeExpr::createImplicit(enumType, C), SourceLoc(),
DeclNameLoc(), DeclNameRef(), elt, nullptr);
pat->setImplicit();
pat->setType(enumType);

View File

@@ -484,12 +484,12 @@ public:
if (!referencedElement)
return nullptr;
// Build a TypeRepr from the head of the full path.
TypeLoc loc(repr);
loc.setType(ty);
return new (Context) EnumElementPattern(
loc, ude->getDotLoc(), ude->getNameLoc(), ude->getName(),
referencedElement, nullptr);
auto *base =
TypeExpr::createForMemberDecl(repr, ude->getNameLoc(), enumDecl);
base->setType(MetatypeType::get(ty));
return new (Context)
EnumElementPattern(base, ude->getDotLoc(), ude->getNameLoc(),
ude->getName(), referencedElement, nullptr);
}
// A DeclRef 'E' that refers to an enum element forms an EnumElementPattern.
@@ -499,9 +499,10 @@ public:
return nullptr;
// Use the type of the enum from context.
TypeLoc loc = TypeLoc::withoutLoc(
elt->getParentEnum()->getDeclaredTypeInContext());
return new (Context) EnumElementPattern(loc, SourceLoc(), de->getNameLoc(),
auto enumTy = elt->getParentEnum()->getDeclaredTypeInContext();
auto *base = TypeExpr::createImplicit(enumTy, Context);
return new (Context) EnumElementPattern(base, SourceLoc(), de->getNameLoc(),
elt->createNameRef(), elt, nullptr);
}
Pattern *visitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *ude) {
@@ -515,11 +516,11 @@ public:
ude->getLoc())) {
auto *enumDecl = referencedElement->getParentEnum();
auto enumTy = enumDecl->getDeclaredTypeInContext();
TypeLoc loc = TypeLoc::withoutLoc(enumTy);
auto *base = TypeExpr::createImplicit(enumTy, Context);
return new (Context) EnumElementPattern(
loc, SourceLoc(), ude->getNameLoc(), ude->getName(),
referencedElement, nullptr);
return new (Context)
EnumElementPattern(base, SourceLoc(), ude->getNameLoc(),
ude->getName(), referencedElement, nullptr);
}
@@ -549,7 +550,7 @@ public:
auto tailComponent = components.pop_back_val();
EnumElementDecl *referencedElement = nullptr;
TypeLoc loc;
TypeExpr *baseTE = nullptr;
if (components.empty()) {
// Only one component. Try looking up an enum element in context.
@@ -560,7 +561,8 @@ public:
return nullptr;
auto *enumDecl = referencedElement->getParentEnum();
loc = TypeLoc::withoutLoc(enumDecl->getDeclaredTypeInContext());
baseTE = TypeExpr::createImplicit(enumDecl->getDeclaredTypeInContext(),
Context);
} else {
TypeResolutionOptions options = None;
options |= TypeResolutionFlags::AllowUnboundGenerics;
@@ -573,7 +575,8 @@ public:
// See first if the entire repr resolves to a type.
Type enumTy = TypeResolution::forContextual(DC, options)
.resolveType(prefixRepr);
if (!dyn_cast_or_null<EnumDecl>(enumTy->getAnyNominal()))
auto *enumDecl = dyn_cast_or_null<EnumDecl>(enumTy->getAnyNominal());
if (!enumDecl)
return nullptr;
referencedElement
@@ -583,18 +586,19 @@ public:
if (!referencedElement)
return nullptr;
loc = TypeLoc(prefixRepr);
loc.setType(enumTy);
baseTE = TypeExpr::createForMemberDecl(
prefixRepr, tailComponent->getNameLoc(), enumDecl);
baseTE->setType(MetatypeType::get(enumTy));
}
assert(baseTE && baseTE->getType() && "Didn't initialize base expression?");
assert(!isa<GenericIdentTypeRepr>(tailComponent) &&
"should be handled above");
auto *subPattern = getSubExprPattern(ce->getArg());
return new (Context) EnumElementPattern(
loc, SourceLoc(), tailComponent->getNameLoc(),
tailComponent->getNameRef(), referencedElement,
subPattern);
baseTE, SourceLoc(), tailComponent->getNameLoc(),
tailComponent->getNameRef(), referencedElement, subPattern);
}
};
@@ -1204,11 +1208,10 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
auto EP = cast<ExprPattern>(P);
if (auto *NLE = dyn_cast<NilLiteralExpr>(EP->getSubExpr())) {
auto *NoneEnumElement = Context.getOptionalNoneDecl();
P = new (Context) EnumElementPattern(TypeLoc::withoutLoc(type),
NLE->getLoc(),
DeclNameLoc(NLE->getLoc()),
NoneEnumElement->createNameRef(),
NoneEnumElement, nullptr);
auto *BaseTE = TypeExpr::createImplicit(type, Context);
P = new (Context) EnumElementPattern(
BaseTE, NLE->getLoc(), DeclNameLoc(NLE->getLoc()),
NoneEnumElement->createNameRef(), NoneEnumElement, nullptr);
return TypeChecker::coercePatternToType(
pattern.forSubPattern(P, /*retainTopLevel=*/true), type, options);
}
@@ -1238,24 +1241,25 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
SmallVector<Type, 2> castTypeOptionals;
castType->lookThroughAllOptionalTypes(castTypeOptionals);
// If we have extra optionals on the input type. Create ".Some" patterns
// wrapping the isa pattern to balance out the optionals.
// If we have extra optionals on the input type. Create ".some" patterns
// wrapping the is pattern to balance out the optionals.
int numExtraOptionals = inputTypeOptionals.size()-castTypeOptionals.size();
if (numExtraOptionals > 0) {
Pattern *sub = IP;
for (int i = 0; i < numExtraOptionals; ++i) {
auto extraOpts =
llvm::drop_begin(inputTypeOptionals, castTypeOptionals.size());
for (auto extraOptTy : llvm::reverse(extraOpts)) {
auto some = Context.getOptionalDecl()->getUniqueElement(/*hasVal*/true);
sub = new (Context) EnumElementPattern(TypeLoc(),
IP->getStartLoc(),
DeclNameLoc(IP->getEndLoc()),
some->createNameRef(),
nullptr, sub);
auto *base = TypeExpr::createImplicit(extraOptTy, Context);
sub = new (Context) EnumElementPattern(
base, IP->getStartLoc(), DeclNameLoc(IP->getEndLoc()),
some->createNameRef(), nullptr, sub);
sub->setImplicit();
}
P = sub;
return coercePatternToType(
pattern.forSubPattern(P, /*retainTopLevle=*/true), type, options);
pattern.forSubPattern(P, /*retainTopLevel=*/true), type, options);
}
CheckedCastKind castKind = TypeChecker::typeCheckCheckedCast(
@@ -1405,7 +1409,7 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
// coercing to.
assert(!EEP->getParentType().isNull()
&& "enum with resolved element doesn't specify parent type?!");
auto parentTy = EEP->getParentType().getType();
auto parentTy = EEP->getParentType();
// If the type matches exactly, use it.
if (parentTy->isEqual(type)) {
enumTy = type;
@@ -1519,11 +1523,7 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
EEP->setElementDecl(elt);
EEP->setType(enumTy);
// Ensure that the type of our TypeLoc is fully resolved. If an unbound
// generic type was spelled in the source (e.g. `case Optional.None:`) this
// will fill in the generic parameters.
EEP->getParentType().setType(enumTy);
EEP->setParentType(enumTy);
// If we needed a cast, wrap the pattern in a cast pattern.
if (castKind) {

View File

@@ -486,12 +486,26 @@ func rdar63510989() {
}
enum E {
case foo(P?)
case single(P?)
case double(P??)
case triple(P???)
}
func test(e: E) {
if case .foo(_ as Value) = e {} // Ok
if case .foo(let v as Value) = e {} // Ok
if case .single(_ as Value) = e {} // Ok
if case .single(let v as Value) = e {} // Ok
// expected-warning@-1 {{immutable value 'v' was never used; consider replacing with '_' or removing it}}
if case .double(_ as Value) = e {} // Ok
if case .double(let v as Value) = e {} // Ok
// expected-warning@-1 {{immutable value 'v' was never used; consider replacing with '_' or removing it}}
if case .double(let v as Value?) = e {} // Ok
// expected-warning@-1 {{immutable value 'v' was never used; consider replacing with '_' or removing it}}
if case .triple(_ as Value) = e {} // Ok
if case .triple(let v as Value) = e {} // Ok
// expected-warning@-1 {{immutable value 'v' was never used; consider replacing with '_' or removing it}}
if case .triple(let v as Value?) = e {} // Ok
// expected-warning@-1 {{immutable value 'v' was never used; consider replacing with '_' or removing it}}
if case .triple(let v as Value??) = e {} // Ok
// expected-warning@-1 {{immutable value 'v' was never used; consider replacing with '_' or removing it}}
}
}