Skip to content

Commit b3f3dd7

Browse files
committed
Handle dynamically accessing the static member from type(of:)
1 parent b34b6e5 commit b3f3dd7

File tree

9 files changed

+120
-45
lines changed

9 files changed

+120
-45
lines changed

include/swift/AST/Expr.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1450,24 +1450,33 @@ class TypeExpr : public Expr {
14501450

14511451
class TypeValueExpr : public Expr {
14521452
GenericTypeParamDecl *paramDecl;
1453+
TypeRepr *repr;
14531454
DeclNameLoc loc;
14541455
Type paramType;
14551456

14561457
/// Create a \c TypeValueExpr from a given generic value param decl.
1457-
TypeValueExpr(DeclNameLoc loc, GenericTypeParamDecl *paramDecl) :
1458+
TypeValueExpr(TypeRepr *repr, DeclNameLoc loc, GenericTypeParamDecl *paramDecl) :
14581459
Expr(ExprKind::TypeValue, /*implicit*/ false), paramDecl(paramDecl),
1459-
loc(loc), paramType(nullptr) {}
1460+
repr(repr), loc(loc), paramType(nullptr) {}
14601461

14611462
public:
14621463
/// Create a \c TypeValueExpr for a given \c GenericTypeParamDecl.
14631464
///
14641465
/// The given location must be valid.
14651466
static TypeValueExpr *createForDecl(DeclNameLoc Loc, GenericTypeParamDecl *D);
14661467

1468+
/// Create a \c TypeValueExpr for a member of the given parent \c TypeRepr.
1469+
static TypeValueExpr *createForMemberDecl(TypeRepr *repr, DeclNameLoc loc,
1470+
GenericTypeParamDecl *d);
1471+
14671472
GenericTypeParamDecl *getParamDecl() const {
14681473
return paramDecl;
14691474
}
14701475

1476+
TypeRepr *getRepr() const {
1477+
return repr;
1478+
}
1479+
14711480
/// Retrieves the corresponding parameter type of the value referenced by this
14721481
/// expression.
14731482
Type getParamType() const {
@@ -1483,7 +1492,7 @@ class TypeValueExpr : public Expr {
14831492
/// Retrieves the underlying value type of the parameter type referenced by
14841493
/// this expression.
14851494
Type getValueType() const {
1486-
return valueType;
1495+
return paramDecl->getValueType();
14871496
}
14881497

14891498
SourceRange getSourceRange() const {

lib/AST/Expr.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2445,7 +2445,15 @@ TypeValueExpr *TypeValueExpr::createForDecl(DeclNameLoc loc,
24452445
GenericTypeParamDecl *paramDecl) {
24462446
auto &ctx = paramDecl->getASTContext();
24472447
ASSERT(loc.isValid());
2448-
return new (ctx) TypeValueExpr(loc, paramDecl);
2448+
return new (ctx) TypeValueExpr(/*repr*/ nullptr, loc, paramDecl);
2449+
}
2450+
2451+
TypeValueExpr *TypeValueExpr::createForMemberDecl(TypeRepr *repr,
2452+
DeclNameLoc loc,
2453+
GenericTypeParamDecl *paramDecl) {
2454+
auto &ctx = paramDecl->getASTContext();
2455+
ASSERT(loc.isValid());
2456+
return new (ctx) TypeValueExpr(repr, loc, paramDecl);
24492457
}
24502458

24512459
ExistentialArchetypeType *OpenExistentialExpr::getOpenedArchetype() const {

lib/Sema/CSApply.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1631,6 +1631,29 @@ namespace {
16311631
// Build a member reference.
16321632
auto memberRef = resolveConcreteDeclRef(member, memberLocator);
16331633

1634+
// If our member reference is a value generic, then the resulting
1635+
// expression is the type value one to access the underlying parameter's
1636+
// value.
1637+
//
1638+
// This can occur in code that does something like: 'type(of: x).a' where
1639+
// 'a' is the static value generic member.
1640+
if (auto gp = dyn_cast<GenericTypeParamDecl>(member)) {
1641+
if (gp->isValue()) {
1642+
auto refType = adjustedOpenedType;
1643+
auto ref = TypeValueExpr::createForDecl(memberLoc, gp);
1644+
cs.setType(ref, refType);
1645+
1646+
auto gpTy = gp->getDeclaredInterfaceType();
1647+
auto subs = baseTy->getContextSubstitutionMap();
1648+
ref->setParamType(gpTy.subst(subs));
1649+
1650+
auto result = new (ctx) DotSyntaxBaseIgnoredExpr(base, dotLoc, ref,
1651+
refType);
1652+
cs.setType(result, refType);
1653+
return result;
1654+
}
1655+
}
1656+
16341657
// If we're referring to a member type, it's just a type
16351658
// reference.
16361659
if (auto *TD = dyn_cast<TypeDecl>(member)) {

lib/Sema/CSGen.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,6 +1724,22 @@ namespace {
17241724

17251725
Type visitTypeValueExpr(TypeValueExpr *E) {
17261726
auto ty = E->getParamDecl()->getDeclaredInterfaceType();
1727+
1728+
// If we have a type representation for this type value, then we're in a
1729+
// context where we're statically accessing the generic parameter by name
1730+
// from a qualified name. E.g. 'A<123>.b'. This context may or may not
1731+
// have a generic environment from which we can map our parameter to.
1732+
if (auto repr = E->getRepr()) {
1733+
auto resolvedTy =
1734+
resolveTypeReferenceInExpression(repr,
1735+
TypeResolverContext::InExpression,
1736+
CS.getConstraintLocator(E));
1737+
1738+
auto paramType = ty.subst(resolvedTy->getContextSubstitutionMap());
1739+
E->setParamType(paramType);
1740+
return E->getParamDecl()->getValueType();
1741+
}
1742+
17271743
auto paramType = CS.DC->mapTypeIntoContext(ty);
17281744
E->setParamType(paramType);
17291745
return E->getParamDecl()->getValueType();

lib/Sema/PreCheckTarget.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,12 +1843,12 @@ Expr *PreCheckTarget::simplifyNestedTypeExpr(UnresolvedDotExpr *UDE) {
18431843
if (Result.size() == 1) {
18441844
auto resultDecl = Result.front().Member;
18451845

1846-
if (isa<GenericTypeParamDecl>(resultDecl) &&
1846+
if (resultDecl &&
1847+
isa<GenericTypeParamDecl>(resultDecl) &&
18471848
cast<GenericTypeParamDecl>(resultDecl)->isValue()) {
18481849
auto gtpd = cast<GenericTypeParamDecl>(resultDecl);
18491850
return TypeValueExpr::createForMemberDecl(InnerTypeRepr,
1850-
UDE->getNameLoc(),
1851-
gtpd);
1851+
UDE->getNameLoc(), gtpd);
18521852

18531853
} else {
18541854
return TypeExpr::createForMemberDecl(InnerTypeRepr, UDE->getNameLoc(),
@@ -1864,7 +1864,7 @@ TypeExpr *PreCheckTarget::simplifyUnresolvedSpecializeExpr(
18641864
UnresolvedSpecializeExpr *us) {
18651865
// If this is a reference type a specialized type, form a TypeExpr.
18661866
// The base should be a TypeExpr that we already resolved.
1867-
if (auto *te = dyn_cast<TypeExpr>(us->getSubExpr())) {
1867+
if (auto *te = dyn_cast_or_null<TypeExpr>(us->getSubExpr())) {
18681868
if (auto *declRefTR =
18691869
dyn_cast_or_null<DeclRefTypeRepr>(te->getTypeRepr())) {
18701870
return TypeExpr::createForSpecializedDecl(
@@ -2331,7 +2331,7 @@ Expr *PreCheckTarget::simplifyTypeExpr(Expr *E) {
23312331

23322332
// When simplifying a type expr like "(P1 & P2) -> (P3 & P4) -> Int",
23332333
// it may have been folded at the same time; recursively simplify it.
2334-
if (auto ArgsTypeExpr = dyn_cast<TypeExpr>(simplifyTypeExpr(E))) {
2334+
if (auto ArgsTypeExpr = dyn_cast_or_null<TypeExpr>(simplifyTypeExpr(E))) {
23352335
auto ArgRepr = ArgsTypeExpr->getTypeRepr();
23362336
if (auto *TTyRepr = dyn_cast<TupleTypeRepr>(ArgRepr))
23372337
return TTyRepr;
@@ -2352,7 +2352,7 @@ Expr *PreCheckTarget::simplifyTypeExpr(Expr *E) {
23522352

23532353
// When simplifying a type expr like "P1 & P2 -> P3 & P4 -> Int",
23542354
// it may have been folded at the same time; recursively simplify it.
2355-
if (auto ArgsTypeExpr = dyn_cast<TypeExpr>(simplifyTypeExpr(E)))
2355+
if (auto ArgsTypeExpr = dyn_cast_or_null<TypeExpr>(simplifyTypeExpr(E)))
23562356
return ArgsTypeExpr->getTypeRepr();
23572357
return nullptr;
23582358
};
@@ -2391,7 +2391,7 @@ Expr *PreCheckTarget::simplifyTypeExpr(Expr *E) {
23912391
// Fold '~P' into a composition type.
23922392
if (auto *unaryExpr = dyn_cast<PrefixUnaryExpr>(E)) {
23932393
if (isTildeOperator(unaryExpr->getFn())) {
2394-
if (auto operand = dyn_cast<TypeExpr>(
2394+
if (auto operand = dyn_cast_or_null<TypeExpr>(
23952395
simplifyTypeExpr(unaryExpr->getOperand()))) {
23962396
auto inverseTypeRepr = new (Ctx) InverseTypeRepr(
23972397
unaryExpr->getLoc(), operand->getTypeRepr());
@@ -2412,7 +2412,7 @@ Expr *PreCheckTarget::simplifyTypeExpr(Expr *E) {
24122412
// If the lhs is another binary expression, we have a multi element
24132413
// composition: 'A & B & C' is parsed as ((A & B) & C); we get
24142414
// the protocols from the lhs here
2415-
if (auto expr = dyn_cast<TypeExpr>(simplifyTypeExpr(lhsExpr)))
2415+
if (auto expr = dyn_cast_or_null<TypeExpr>(simplifyTypeExpr(lhsExpr)))
24162416
if (auto *repr = dyn_cast<CompositionTypeRepr>(expr->getTypeRepr()))
24172417
// add the protocols to our list
24182418
for (auto proto : repr->getTypes())

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,20 @@ CheckRedeclarationRequest::evaluate(Evaluator &eval, ValueDecl *current) const {
727727
auto found = nominal->lookupDirect(current->getBaseName(), SourceLoc(),
728728
flags);
729729
otherDefinitions.append(found.begin(), found.end());
730+
731+
// Look into the generics of the type. Value generic parameters can appear
732+
// as static members of the type.
733+
if (auto genericDC = static_cast<Decl *>(nominal)->getAsGenericContext()) {
734+
auto gpList = genericDC->getGenericParams();
735+
736+
if (gpList && !current->getBaseName().isSpecial()) {
737+
auto gp = gpList->lookUpGenericParam(current->getBaseIdentifier());
738+
739+
if (gp && gp->isValue()) {
740+
otherDefinitions.push_back(gp);
741+
}
742+
}
743+
}
730744
}
731745
} else if (currentDC->isLocalContext()) {
732746
if (!current->isImplicit()) {
@@ -1135,25 +1149,6 @@ CheckRedeclarationRequest::evaluate(Evaluator &eval, ValueDecl *current) const {
11351149
}
11361150
}
11371151

1138-
// Look to see if this type has a value generic with the same name and that
1139-
// the current value is a property.
1140-
if (currentDC->isTypeContext() && currentDC->isGenericContext() &&
1141-
isa<VarDecl>(current)) {
1142-
auto gpList = currentDC->getAsDecl()->getAsGenericContext()->getGenericParams();
1143-
1144-
if (gpList && !current->getBaseName().isSpecial()) {
1145-
auto gp = gpList->lookUpGenericParam(current->getBaseIdentifier());
1146-
1147-
if (gp && gp->isValue()) {
1148-
ctx.Diags.diagnoseWithNotes(
1149-
current->diagnose(diag::invalid_redecl, current), [&]() {
1150-
gp->diagnose(diag::invalid_redecl_prev, gp);
1151-
});
1152-
current->setInvalid();
1153-
}
1154-
}
1155-
}
1156-
11571152
return std::make_tuple<>();
11581153
}
11591154

lib/Sema/TypeOfReference.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,6 +1557,18 @@ DeclReferenceType ConstraintSystem::getTypeOfMemberReference(
15571557
// Wrap it in a metatype.
15581558
memberTy = MetatypeType::get(memberTy);
15591559

1560+
// However, if overload resolution finds a value generic decl from name
1561+
// lookup, replace the returned member type to be the underlying value type
1562+
// of the generic.
1563+
//
1564+
// This can occur in code that does something like: 'type(of: x).a' where
1565+
// 'a' is the static value generic member.
1566+
if (auto gp = dyn_cast<GenericTypeParamDecl>(typeDecl)) {
1567+
if (gp->isValue()) {
1568+
memberTy = gp->getValueType();
1569+
}
1570+
}
1571+
15601572
auto openedType = FunctionType::get({baseObjParam}, memberTy);
15611573
return { openedType, openedType, memberTy, memberTy, Type() };
15621574
}

stdlib/public/core/InlineArray.swift

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -272,14 +272,6 @@ extension InlineArray where Element: ~Copyable {
272272
@available(SwiftStdlib 6.2, *)
273273
public typealias Index = Int
274274

275-
// FIXME: Remove when SE-0452 "Integer Generic Parameters" is implemented.
276-
@available(SwiftStdlib 6.2, *)
277-
@_alwaysEmitIntoClient
278-
@_transparent
279-
public static var count: Int {
280-
count
281-
}
282-
283275
/// The number of elements in the array.
284276
///
285277
/// - Complexity: O(1)

test/Sema/value_generics.swift

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,16 +121,16 @@ func testC4<let T: Int>(with c: C<T, T>) {
121121
struct D<let N: Int & P> {} // expected-error {{non-protocol, non-class type 'Int' cannot be used within a protocol-constrained type}}
122122

123123
struct E<A, let b: Int> { // expected-note {{'b' previously declared here}}
124-
// expected-note@-1 {{'b' previously declared here}}
125124
static var b: Int { // expected-error {{invalid redeclaration of 'b'}}
126125
// expected-note@-1 {{'b' declared here}}
127126
123
128127
}
129128

130-
let b: String // expected-error {{invalid redeclaration of 'b'}}
129+
let b: String // expected-note {{'b' previously declared here}}
131130
// expected-note@-1 {{'b' declared here}}
132131

133-
func b() {} // expected-note {{'b' declared here}}
132+
func b() {} // expected-error {{invalid redeclaration of 'b()'}}
133+
// expected-note@-1 {{'b' declared here}}
134134
}
135135

136136
func testE1() -> Int {
@@ -141,15 +141,35 @@ func testE2() -> Int {
141141
E<Int, 123>.A // expected-error {{type 'E<Int, 123>' has no member 'A'}}
142142
}
143143

144-
func testE3<let c: Int>(_: E<Int, c>.Type = E<Int, c>.self) -> Int {
144+
func testE3<let c: Int>(_: E<Int, c>.Type) -> Int {
145145
E<Int, c>.b // OK
146146
}
147147

148148
func testShadowing<let a: Int>(_: A<a>) {
149-
var a: Int {
150-
123
149+
var a: String {
150+
"123"
151151
}
152152

153+
let x: String = a // OK
154+
let y: Int = a // expected-error {{cannot convert value of type 'String' to specified type 'Int'}}
155+
153156
print(a) // OK
154157
print(a.self) // OK
155158
}
159+
160+
class F<let n: Int> {}
161+
class G: F<3> {}
162+
163+
func hello() -> Int {
164+
G.n // OK
165+
}
166+
167+
func testTypeOf() -> Int {
168+
let x = E<Int, 123>(b: "")
169+
return type(of: x).b // OK
170+
}
171+
172+
func testTypeOf2<let c: Int>(_: E<Int, c>.Type) -> Int {
173+
let x = E<Int, c>(b: "")
174+
return type(of: x).b // OK
175+
}

0 commit comments

Comments
 (0)